diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f8551f25b..87b51c3ab 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -29,7 +29,7 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots or even better a short video of the error happening to help explain your problem. Botty often automatically makes screenshots when something goes wrong. Add these also. **Logs** -Add the relevant part of the info.log in this section. Either upload it as a fail or copy-paste the relevant part in here. +Add the relevant part of the log/log_(time).txt in this section. Either upload it as a fail or copy-paste the relevant part in here. **Additional info** Add any other information about the problem here. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbc6edade..87b8acfe5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,16 +5,16 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v2 - - name: Setup Miniconda Python 3.9 + - name: Setup Miniconda Python 3.10 uses: actions/setup-python@v2 with: - python-version: 3.9 + python-version: '3.10' # TODO: The below setp only chaches conda packages, need to cache pip seperatly - name: Cache conda uses: actions/cache@v2 env: # Increase this value to reset cache if environment.yml has not changed - CACHE_NUMBER: 0 + CACHE_NUMBER: 1 with: path: ~/conda_pkgs_dir key: conda-${{ env.CACHE_NUMBER }}-${{hashFiles('environment.yml') }} @@ -22,14 +22,14 @@ jobs: uses: actions/cache@v2 env: # Increase this value to reset cache if environment.yml has not changed - CACHE_NUMBER: 0 + CACHE_NUMBER: 1 with: path: ~/pip key: pip-${{ env.CACHE_NUMBER }}-${{ hashFiles('environment.yml') }} - name: Install Miniconda uses: conda-incubator/setup-miniconda@v2 with: - python-version: 3.9 + python-version: '3.10' activate-environment: botty channel-priority: strict environment-file: environment.yml diff --git a/.gitignore b/.gitignore index b5d586d6f..1d42bf8bf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ __pycache__/ playground.py *.pyc *.pyo -*.log *.spec dist/ build/ @@ -16,16 +15,23 @@ botty_v*/ custom.ini config/custom.ini config/custom.*.ini -*info_log_parsed.txt -*info_*.png .vscode .vs/ -info_screenshots/ -loot_screenshots/ -stats/ +test/assets/ .venv *.bak .coverage htmlcov/ coverage.xml utils/live-view/ +config/bnip/* +!config/bnip/.gitkeep +stats/ +info_screenshots/ +item_error_screenshots/ +loot_screenshots/ +pickit_screenshots/ +*info_log_parsed.txt +*info_*.png +*.log +log/ diff --git a/README.md b/README.md index 319e58f02..0d8a598cb 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # -Pixelbot for Diablo 2 Resurrected. This project is for informational and educational purposes only and is not meant for online usage. Feel free to dig around, add stuff, make PRs, or ask questions should you get stuck! - -[**Download here**](https://github.com/aeon0/botty/releases) and got to have a [**Discord**](https://discord.gg/Jf3J8cuXWg) nowadays I guess :man_shrugging: +Pixelbot for Diablo 2 Resurrected. This project is for informational and educational purposes only. ## Getting started & Prerequisites - D2R needs to be in English Language, @@ -25,15 +23,39 @@ Open up D2R and wait till you are at the hero selection screen. Make sure the ch You can either run from python. Follow [development.md](development.md) for that. Or you download the a prebuilt release [here](https://github.com/aeon0/botty/releases) (the .rar file!). Start `main.exe` in the botty folder. Focus your D2R window and press the start key (default f11). You can always force stop botty with f12. Note: Botty will use the /nopickup command in the first game to avoid pickup up trash while traversing. This command will only allow item pickup when "show items" is active. +## Development + +Check out the [development.md](development.md) docu for infos on how to build from source and details of the project structure and code. + +## BNIP Pickit + +Botty NIP (BNIP) is an extended version of Njaguar's Item Parser (NIP). +BNIP is compatible with NIP (with some minor exceptions as discussed below). + +There is a default nip file that comes with botty called "default.nip" inside config folder, you can add your own nip files by putting them inside config/nip with a file extension of .nip. Creating your own nip file also turns off the default.nip. + +We suggest you read the NIP guide if you are unfamiliar with NIP https://github.com/blizzhackers/pickits/blob/master/NipGuide.md + +### New features in BNIP + +Poison damage is no longer calculated, but is now read as it's raw value. Example: Adds 5-10 poison damage over 1 seconds can be picked with `[poisonmindam] == 5 && [poisonmaxdam] == 10`. "313 Poison Damage over 5 seconds" can be picked with `[poisonmindam] == 313` or `[poisonmaxdam] == 313`. + +`[allres]` is a thing now. example: `[type] == amulet && [quality] == unique # [allres] == 30` will pick up Mara's + +`[idname]` can now be used for unique / set items. For example, `[idname] == thestoneofjordan` will pick up SoJ. Keep in mind, however, this forces the item to be ID'd so be careful if you want to keep unid items. + +`[maxquantity]` is not supported (yet). You can leave those tags in but they'll do nothing. + +If you have the discord webhook hooked up to alert you when the bot keeps items, you can suppress these alerts by adding a "@" in front of your expression. + +@[type] == ring = no notification +[type] == ring = notification + ## Graphic Debugger To check if you graphic settings are good and if the bot would pick up items there is a **Graphic Debugger Mode**. Start botty and press F10 (Default key). This will open up a (mostly black) window. Start a game in D2R and go to A5. You should see some templates with blue circles detected and scores printed out to the console. To check item finding, throw some items of different types on the ground. The debug window should show the item names with black background. If you throw an item on the ground that should be picked up, it will have a red circle. The console will print out the scores for each item that would be picked up. Scores should be well above 0.9 for these items.
-## Development - -Check out the [development.md](development.md) docu for infos on how to build from source and details of the project structure and code. - ## params.ini All botty configuration files are located in the __config__ folder. To ease the switch to new botty versions, you can also overwrite any of the .ini fields in a **custom.ini** file. When a new version of botty is released you just copy the file to the new version without having to port all your **params.ini** changes to the new version. Example: @@ -44,25 +66,29 @@ All botty configuration files are located in the __config__ folder. To ease the name=MyCustomName [routes] -order=run_pindle, run_eldritch +order=run_pindle, run_eldritch ``` | [general] | Descriptions | | -------------------- | --------------------------| +| difficulty | Set to `normal` `nightmare` or `hell` for game difficulty. | | name | Name used in terminal and discord messages. | -| custom_message_hook | Add your own message hook here to get messages about drops and botty status updates, discord webhook is default. | -| logger_lvl | Can be any of [info, debug] and determines how much output you see on the command line. | -| max_game_length_s | Max game length in seconds. Botty will attempt to stop whatever it's doing and try to restart a new game at specified interval. If this fails, botty will attempt to shut down D2R and Bnet. | -| max_consecutive_fails | Botty will stop making games if the number of consecutive fails reaches this max value. | | randomize_runs | Randomize the order of `[routes]` specified in `params.ini`. | -| difficulty | Set to `normal` `nightmare` or `hell` for game difficulty. | -| message_api_type | Which api to use to send botty messages. Supports "generic_api" (basic discord), or "discord" (discord embeds with images). | -| discord_status_count | Number of games between discord status messages being sent. Leave empty for no status reports. -| info_screenshots | If `1`, the bot takes a screenshot with timestamp on every stuck / chicken / timeout / inventory full event. This is 1 by Default, so remember to clean up the folder every once in a while. | -| loot_screenshots | If `1`, the bot takes a screenshot with timestamp everytime he presses `show_items` button and saves it to `loot_screenshots` folder. Remember to clear them once in a while... | | saved_games_folder | [Optional] Defaults to `~\Saved Games\Diablo II Resurrected`. Used to store configuration settings for `f9` / auto settings. | +| custom_loot_message_hook | Add your message hook here (such as Discord channel) to get info about loot | +| custom_message_hook | Add your message hook here (such as Discord channel) to get info about botty status updates, discord webhook is default. | +| discord_log_chicken | Set to `1` to enable messages about bot chickens, `0` to disable. | +| discord_status_count | Number of games between discord status messages being sent. Leave empty for no status reports. | +| message_api_type | Which api to use to send botty messages. Supports "generic_api" (basic discord), or "discord" (discord embeds with images). | +| break_length_m | Break for `break_length_m` minutes every `max_runtime_before_break_m` minutes | +| max_runtime_before_break_m | ^ | | d2r_path | [Optional] Path to `d2r.exe`. If not set, it will default to `C:\Program Files (x86)\Diablo II Resurrected\D2R.exe` when attempting to restart. | +| max_consecutive_fails | Botty will stop making games if the number of consecutive fails reaches this max value. | +| max_game_length_s | Max game length in seconds. Botty will attempt to stop whatever it's doing and try to restart a new game at specified interval. If this fails, botty will attempt to shut down D2R and Bnet. | | restart_d2r_when_stuck | Set to `1` and botty will attempt to restart d2r in the case that botty is unable to recover its state (e.g: game crash). | +| info_screenshots | If `1`, the bot takes a screenshot with timestamp on every stuck / chicken / timeout / inventory full event. This is 1 by Default, so remember to clean up the folder every once in a while. | +| pickit_screenshots | If `1`, the bot takes a screenshot with timestamp on every ground loot snapshot taken during pickit routine, can be useful for debugging. | +| loot_screenshots | If `1`, the bot takes a screenshot with timestamp everytime he presses `show_items` button and saves it to `loot_screenshots` folder. Remember to clear them once in a while... | | [routes] | Descriptions | | ------------ | ------------------------------------------------------------------------ | @@ -71,40 +97,44 @@ order=run_pindle, run_eldritch | [char] | Descriptions | | ------------------ | -------------------------------------------------------------------------------------------------| | type | Build type. Currently only "sorceress" or "hammerdin" is supported | +| belt_rows | Integer value of how many rows the char's belt has | | casting_frames | Depending on your char and fcr you will have a specific casting frame count. Check it here: https://diablo2.diablowiki.net/Breakpoints and fill in the right number. Determines how much delay there is after each teleport for example. If your system has some delay e.g. on vms, you might have to increase this value above the suggest value in the table! | +| cta_available | 0: no cta available, 1: cta is available and should be used during prebuff | +| safer_routines | Set to 1 to enable optional defensive maneuvers/etc during combat/runs at the cost of increased runtime (ex. hardcore players) | num_loot_columns | Number of columns in inventory used for loot (from left!). Remaining space can be used for charms | -| show_items | Hotkey for "show items" | -| inventory_screen | Hotkey to open inventory | | force_move | Hotkey for "force move" | -| stand_still | Hotkey for "stand still". Note this can not be the default shift key as it would interfere with the merc healing routine | -| tp | Hotkey for using a town | -| belt_rows | Integer value of how many rows the char's belt has | -| show_belt | Hotkey for "show belt" | +| inventory_screen | Hotkey to open inventory | | potion1 | Hotkey to take potion in slot 1 | | potion2 | Hotkey to take potion in slot 2 | | potion3 | Hotkey to take potion in slot 3 | | potion4 | Hotkey to take potion in slot 4 | -| cta_available | 0: no cta available, 1: cta is available and should be used during prebuff | +| show_belt | Hotkey for "show belt" | +| show_items | Hotkey for "show items" | +| stand_still | Hotkey for "stand still". Note this can not be the default shift key as it would interfere with the merc healing routine | +| teleport | Hotkey for teleport (set blank if your character can't teleport) | +| town_portal | Hotkey for town portal | | weapon_switch | Hotkey for "weapon switch" (only needed if cta_available=1) | | battle_order | Hotkey for battle orders from cta (only needed if cta_available=1) | | battle_command | Hotkey for battle command from cta (only needed if cta_available=1) | | stash_gold | Bool value to stash gold each time when stashing items | -| min_gold_to_pick | Minimum quantity of gold to pickup (also must set misc_gold=1 in pickit config) | | use_merc | Set to 1 for using merc. Set to 0 for not using merc (will not revive merc when dead), default = 1 | | atk_len_arc | Attack length for hdin/sorc fighting arcane | -| atk_len_trav | Attack length for hdin fighting trav (note this atk length will be applied in 4 different spots each) | -| atk_len_pindle | Attack length for hdin or number of attack sequences for sorc when fighting pindle | | atk_len_eldritch | Attack length for hdin or number of attack sequences for sorc when fighting eldritch | -| atk_len_shenk | Attack length for hdin or number of attack sequences for sorc when fighting shenk | | atk_len_nihlathak | Attack length for hdin or number of attack sequences for sorc when fighting nihlathak | +| atk_len_pindle | Attack length for hdin or number of attack sequences for sorc when fighting pindle | +| atk_len_shenk | Attack length for hdin or number of attack sequences for sorc when fighting shenk | +| atk_len_trav | Attack length for hdin fighting trav (note this atk length will be applied in 4 different spots each) | | atk_len_cs_trashmobs | Attack length for hdin or number of attack sequences when fighting Trash Mobs in Chaos Sanctuary (Diablo) | -| atk_len_diablo_vizier | Attack length for hdin or number of attack sequences when fighting Sealboss A "Vizier of Chaos" in Chaos Sanctuary (Diablo) | | atk_len_diablo_deseis | Attack length for hdin or number of attack sequences when fighting Sealboss B "Lord De Seis" in Chaos Sanctuary (Diablo) | | atk_len_diablo_infector | Attack length for hdin or number of attack sequences when fighting Sealboss C "Infector of Souls" in Chaos Sanctuary (Diablo) | -| atk_len_diablo_infector | Attack length for hdin or number of attack sequences when fighting Diablo in Chaos Sanctuary | -| kill_cs_trash | If 1, most Trash mob packs from Chaos Sancturay Entrance to Pentagram are cleared. If 0, the run starts at Pentagram and just kills Sealbosses & Diablo (default) | -| cs_town_visits | If 1, it will go to town, buy pots & stash items between clearing the seals, set 0 to deactivate (default) | +| atk_len_diablo_vizier | Attack length for hdin or number of attack sequences when fighting Sealboss A "Vizier of Chaos" in Chaos Sanctuary (Diablo) | +| atk_len_diablo | Attack length for hdin or number of attack sequences when fighting Diablo in Chaos Sanctuary | | cs_mob_detect | If 1, it will attempt to use holy freeze from merc / conviction aura / poison to detect nearby mobs to help speed-up CS run. +| cs_town_visits | CURRENTLY BROKEN, LEAVE AT 0 FOR NOW | +| kill_cs_trash | If 1, most Trash mob packs from Chaos Sancturay Entrance to Pentagram are cleared. If 0, the run starts at Pentagram and just kills Sealbosses & Diablo (default) | +| belt_hp_columns | Number of belt columns for healing potions | +| belt_mp_columns | Number of belt columns for mana potions | +| belt_rejuv_columns | Number of belt columns for rejuv potions | | take_health_potion | Health percentage when healing potion will be used. e.g. 0.6 = 60% helath | | take_mana_potion | Mana percentage when mana potion will be used | | take_rejuv_potion_health | Health percentag when rejuv potion will be used | @@ -113,39 +143,40 @@ order=run_pindle, run_eldritch | heal_rejuv_merc | Merc health percentage when giving rejuv potion to merc | | chicken | Will chicken (leave game) when player health percentage drops below set value, range 0 to 1. Set to 0 to not chicken. | | merc_chicken | Will chicken (leave game) when merc health percentage drops below set value, range 0 to 1. Set to 0 to not chicken. | -| belt_rejuv_columns | Number of belt columns for rejuv potions | -| belt_hp_columns | Number of belt columns for healing potions | -| belt_mp_columns | Number of belt columns for mana potions | -| pre_buff_every_run | 0: Will only prebuff on first run, 1: Will prebuff after each run/boss | -| runs_per_stash | 0: Will only stash after intentional item pickup, 1+: Will force stash after # of runs set here (recommend at least 4 in case of accidental pickups) | -| runs_per_repair | 0: Will only repair when needed, 1+: Will force repair after # of runs set here | -| id_items | Will identify items at cain before stashing them. Cain must be rescued for this to work.| -| open_chests | Open up chests in some places. E.g. on dead ends of arcane. Note: currently bad runtime. | +| enable_no_pickup | When enabled, will type `/nopickup` into chat at game start, which can help reduce accidental pickups especially for walking characters. | | fill_shared_stash_first | Fill stash tabs starting from right to left, filling personal stash last | | gamble_items | List of items to gamble when stash fills with gold. Leave blank to disable. Supported items currently include circlet, ring, coronet, talon, amulet +| open_chests | Open up chests in some places. E.g. on dead ends of arcane. | +| pre_buff_every_run | 0: Will only prebuff on first run, 1: Will prebuff after each run/boss | +| runs_per_repair | Force repair after `runs_per_repair` of runs. Set to 0 to repair only when needed. | +| runs_per_stash | 0: Will only stash after intentional item pickup, 1+: Will force stash after # of runs set here (recommend at least 4 in case of accidental pickups) | +| sell_junk | 0: Discard unwanted items by dropping them on ground. 1: Discard items by selling them at vendor. | | [transmute] | Descriptions | | ------------------ | -------------------------------------------------------------------------------------------------| -| transmute_every_x_game | How often to run transmute routine (currently transmutes flawless gems into perfect gems). Transmute routine depends on stashing routine it will only start after items stashing is done. E.g. so it could take more than X games to perform transmutes if there were no items to stash at the time. Default: 20 | | stash_destination | Stash tabs by priority to place the results of the transmute. Default: 3,2,1,0. (It means the result will be first placed in stash 3 untils it's full, then to stash 2, etc. 0 - personal tab) +| transmute | Add any or all of `chipped, flawed, standard, flawless` to trasmute gems of these types | +| transmute_every_x_game | How often to run transmute routine (currently transmutes flawless gems into perfect gems). Transmute routine depends on stashing routine it will only start after items stashing is done. E.g. so it could take more than X games to perform transmutes if there were no items to stash at the time. Default: 20 | ### Builds | [sorceress] | Descriptions | | ------------- | ----------------------------------------------------------------------------- | -| teleport | Required Hotkey for teleport | | frozen_armor | Optional Hotkey for frozen armor (or any of the other armors) | | energy_shield | Optional Hotkey for energy shield | | thunder_storm | Optional Hotkey for thunder storm | +| static_field | Optional Hotkey for static field | +| telekinesis | Optional Hotkey for telekinesis | | [light_sorc] | Descriptions | | ------------- | ----------------------------------------------------------------------------- | | chain_lightning | Optional Hotkey for chain_lightning (must be bound to left skill) | | lightning | Required Hotkey for lightning (must be bound to right skill) | +| frozen_orb | Optional Hotkey for frozen orb (must be bound to right skill) | | [blizz_sorc] | Descriptions | | ------------- | ----------------------------------------------------------------------------- | -| ice_blast | Optional Hotkey for ice_blast (must be bound to left skill) | | blizzard | Required Hotkey for Blizzard (must be bound to right skill) | +| ice_blast | Optional Hotkey for ice_blast (must be bound to left skill) | | [nova_sorc] | Descriptions | | ------------- | ----------------------------------------------------------------------------- | @@ -153,43 +184,49 @@ order=run_pindle, run_eldritch | [hydra_sorc] | Descriptions | | ------------- | ----------------------------------------------------------------------------- | -| fire_ball | Optional Hotkey for (must be bound to left skill) | +| alt_attack | Required Hotkey for any alternate attacking skill. Fireball,Lightning,Frozen Orb, etc. (must be bound to right skill) | | hydra | Required Hotkey for Hydra (must be bound to right skill) | -| [hammerdin] | Descriptions | +| [paladin] | Descriptions | | -------------- | ----------------------------------------------------------------------------------- | -| teleport | Optional Hotkey for teleport. If left empty hammerdin will run instead of teleport. | -| concentration | Required Hotkey for Concentration | +| cleansing | Optional Hotkey for Cleansing | | holy_shield | Required Hotkey for Holy Shield | -| blessed_hammer | Required Hotkey for Blessed Hammer. (must be bound to left skill!) | | redemption | Optional Hotkey for Redemption | | vigor | Optional Hotkey for Vigor | -| cleansing | Optional Hotkey for Cleansing | + +| [fohdin] | Descriptions | +| -------------- | ----------------------------------------------------------------------------------- | +| blessed_hammer | Hotkey for Blessed Hammer. (Optional. Bind to left skill) | +| concentration | Hotkey for Concentration | +| conviction | Hotkey for Conviction | +| foh | Hotkey for Fist of Heavens (Required) | +| holy_bolt | Hotkey for Holy Bolt (Required) | + + +| [hammerdin] | Descriptions | +| -------------- | ----------------------------------------------------------------------------------- | +| concentration | Required Hotkey for Concentration | +| blessed_hammer | Required Hotkey for Blessed Hammer. (must be bound to left skill!) | | [trapsin] | Descriptions | | -------------- | ----------------------------------------------------------------------------------- | -| teleport | Optional Hotkey for teleport. If left empty trapsin will run instead of teleport. | -| skill_left | Optional Hotkey for Left Skill | | burst_of_speed | Optional Hotkey for Burst of Speed | +| death_sentry | Required Hotkey for Death Sentry | | fade | Optional Hotkey for Fade | -| shadow_warrior | Optional Hotkey for Shadow Warrior | | lightning_sentry | Required Hotkey for Lightning Sentry | -| death_sentry | Required Hotkey for Death Sentry | -| cloak_of_shadows| Optional Hotkey for Cloak of Shadows | -| mind_blast | Optional Hotkey for Mind Blast | +| shadow_warrior | Optional Hotkey for Shadow Warrior | +| skill_left | Optional Hotkey for Left Skill | | [barbarian] | Descriptions | | -------------- | ----------------------------------------------------------------------------------- | -| teleport | Optional Hotkey for teleport. If left empty barb will run instead of teleport. | +| cry_frequency | Time in seconds between each cast of war_cry. Set to 0.0 if max fcr should be used | +| find_item | Optional Hotkey for Find Item | | leap | Required Hotkey for Leap | | shout | Required Hotkey for Shout | | war_cry | Required Hotkey for War Cry | -| find_item | Optional Hotkey for Find Item | -| cry_frequency | Time in seconds between each cast of war_cry. Set to 0.0 if max fcr should be used | | [Necro] | Descriptions | | -------------- | ----------------------------------------------------------------------------------- | -| teleport | leave this blank for now, teleport/static pathing is currently not supported | | skill_left | Required Hotkey for attack (bonespear/teeth) | | bone_armor | Required Hotkey for Bone Armor | | clay_golem | Required Hotkey for Clay Golem | @@ -198,19 +235,7 @@ order=run_pindle, run_eldritch | corpse_explosion | Required Hotkey Corpse Explosion | | raise_revive | Required Hotkey revive | | damage_scaling | Adjusts time spent casting attack skills. Ex: 2 will cast twice as long | -| clear_pindle_packs | clears mobs before pindle | - -| [dclone] | Descriptions | -| -------------------- | --------------------------------------------------------------------- | -| region_ips | Start of the region ip you want to filter for. e.g. EU Server = 37.244.11, 37.244.48 | -| dclone_hotip | Hot ip you are looking for. Botty will stay in game and message you if a message_hook is set | +| clear_pindle_packs | Clears mobs before pindle | | [advanced_options] | Descriptions | | -------------------- | --------------------------------------------------------------------- | -| pathing_delay_factor | A linear scaling factor, between 1 and 10, applied to pathing delays. | -| message_headers | Headers that are sent with each messages | -| message_body_template | Message body of the post message sent | - -## Support this project - -Support it by contributing in any technical way, giving feedback, bug reports or submitting PRs. diff --git a/assets/NTItemAlias.dbl b/assets/NTItemAlias.dbl new file mode 100644 index 000000000..282450f6c --- /dev/null +++ b/assets/NTItemAlias.dbl @@ -0,0 +1,1469 @@ +var NTIPAliasType = {}; +NTIPAliasType["shield"] = 2; +NTIPAliasType["armor"] = 3; +NTIPAliasType["gold"] = 4; +NTIPAliasType["bowquiver"] = 5; +NTIPAliasType["crossbowquiver"] = 6; +NTIPAliasType["playerbodypart"] = 7; +NTIPAliasType["herb"] = 8; +NTIPAliasType["potion"] = 9; +NTIPAliasType["ring"] = 10; +NTIPAliasType["elixir"] = 11; +NTIPAliasType["amulet"] = 12; +NTIPAliasType["charm"] = 13; +NTIPAliasType["notused"] = 14; +NTIPAliasType["boots"] = 15; +NTIPAliasType["gloves"] = 16; +NTIPAliasType["notused"] = 17; +NTIPAliasType["book"] = 18; +NTIPAliasType["belt"] = 19; +NTIPAliasType["gem"] = 20; +NTIPAliasType["torch"] = 21; +NTIPAliasType["scroll"] = 22; +NTIPAliasType["notused"] = 23; +NTIPAliasType["scepter"] = 24; +NTIPAliasType["wand"] = 25; +NTIPAliasType["staff"] = 26; +NTIPAliasType["bow"] = 27; +NTIPAliasType["axe"] = 28; +NTIPAliasType["club"] = 29; +NTIPAliasType["sword"] = 30; +NTIPAliasType["hammer"] = 31; +NTIPAliasType["knife"] = 32; +NTIPAliasType["spear"] = 33; +NTIPAliasType["polearm"] = 34; +NTIPAliasType["crossbow"] = 35; +NTIPAliasType["mace"] = 36; +NTIPAliasType["helm"] = 37; +NTIPAliasType["missilepotion"] = 38; +NTIPAliasType["quest"] = 39; +NTIPAliasType["bodypart"] = 40; +NTIPAliasType["key"] = 41; +NTIPAliasType["throwingknife"] = 42; +NTIPAliasType["throwingaxe"] = 43; +NTIPAliasType["javelin"] = 44; +NTIPAliasType["weapon"] = 45; +NTIPAliasType["meleeweapon"] = 46; +NTIPAliasType["missileweapon"] = 47; +NTIPAliasType["thrownweapon"] = 48; +NTIPAliasType["comboweapon"] = 49; +NTIPAliasType["anyarmor"] = 50; +NTIPAliasType["anyshield"] = 51; +NTIPAliasType["miscellaneous"] = 52; +NTIPAliasType["socketfiller"] = 53; +NTIPAliasType["secondhand"] = 54; +NTIPAliasType["stavesandrods"] = 55; +NTIPAliasType["missile"] = 56; +NTIPAliasType["blunt"] = 57; +NTIPAliasType["jewel"] = 58; +NTIPAliasType["classspecific"] = 59; +NTIPAliasType["amazonitem"] = 60; +NTIPAliasType["barbarianitem"] = 61; +NTIPAliasType["necromanceritem"] = 62; +NTIPAliasType["paladinitem"] = 63; +NTIPAliasType["sorceressitem"] = 64; +NTIPAliasType["assassinitem"] = 65; +NTIPAliasType["druiditem"] = 66; +NTIPAliasType["handtohand"] = 67; +NTIPAliasType["orb"] = 68; +NTIPAliasType["voodooheads"] = 69; +NTIPAliasType["auricshields"] = 70; +NTIPAliasType["primalhelm"] = 71; +NTIPAliasType["pelt"] = 72; +NTIPAliasType["cloak"] = 73; +NTIPAliasType["rune"] = 74; +NTIPAliasType["circlet"] = 75; +NTIPAliasType["healingpotion"] = 76; +NTIPAliasType["manapotion"] = 77; +NTIPAliasType["rejuvpotion"] = 78; +NTIPAliasType["staminapotion"] = 79; +NTIPAliasType["antidotepotion"] = 80; +NTIPAliasType["thawingpotion"] = 81; +NTIPAliasType["smallcharm"] = 82; +NTIPAliasType["mediumcharm"] = 83; +NTIPAliasType["largecharm"] = 84; +NTIPAliasType["amazonbow"] = 85; +NTIPAliasType["amazonspear"] = 86; +NTIPAliasType["amazonjavelin"] = 87; +NTIPAliasType["assassinclaw"] = 88; +NTIPAliasType["magicbowquiv"] = 89; +NTIPAliasType["magicxbowquiv"] = 90; +NTIPAliasType["chippedgem"] = 91; +NTIPAliasType["flawedgem"] = 92; +NTIPAliasType["standardgem"] = 93; +NTIPAliasType["flawlessgem"] = 94; +NTIPAliasType["perfectgem"] = 95; +NTIPAliasType["amethyst"] = 96; +NTIPAliasType["diamond"] = 97; +NTIPAliasType["emerald"] = 98; +NTIPAliasType["ruby"] = 99; +NTIPAliasType["sapphire"] = 100; +NTIPAliasType["topaz"] = 101; +NTIPAliasType["skull"] = 102; + +var NTIPAliasClassID = {}; +NTIPAliasClassID["hax"] = 0; NTIPAliasClassID["handaxe"] = 0; +NTIPAliasClassID["axe"] = 1; +NTIPAliasClassID["2ax"] = 2; NTIPAliasClassID["doubleaxe"] = 2; +NTIPAliasClassID["mpi"] = 3; NTIPAliasClassID["militarypick"] = 3; +NTIPAliasClassID["wax"] = 4; NTIPAliasClassID["waraxe"] = 4; +NTIPAliasClassID["lax"] = 5; NTIPAliasClassID["largeaxe"] = 5; +NTIPAliasClassID["bax"] = 6; NTIPAliasClassID["broadaxe"] = 6; +NTIPAliasClassID["btx"] = 7; NTIPAliasClassID["battleaxe"] = 7; +NTIPAliasClassID["gax"] = 8; NTIPAliasClassID["greataxe"] = 8; +NTIPAliasClassID["gix"] = 9; NTIPAliasClassID["giantaxe"] = 9; +NTIPAliasClassID["wnd"] = 10; NTIPAliasClassID["wand"] = 10; +NTIPAliasClassID["ywn"] = 11; NTIPAliasClassID["yewwand"] = 11; +NTIPAliasClassID["bwn"] = 12; NTIPAliasClassID["bonewand"] = 12; +NTIPAliasClassID["gwn"] = 13; NTIPAliasClassID["grimwand"] = 13; +NTIPAliasClassID["clb"] = 14; NTIPAliasClassID["club"] = 14; +NTIPAliasClassID["scp"] = 15; NTIPAliasClassID["scepter"] = 15; +NTIPAliasClassID["gsc"] = 16; NTIPAliasClassID["grandscepter"] = 16; +NTIPAliasClassID["wsp"] = 17; NTIPAliasClassID["warscepter"] = 17; +NTIPAliasClassID["spc"] = 18; NTIPAliasClassID["spikedclub"] = 18; +NTIPAliasClassID["mac"] = 19; NTIPAliasClassID["mace"] = 19; +NTIPAliasClassID["mst"] = 20; NTIPAliasClassID["morningstar"] = 20; +NTIPAliasClassID["fla"] = 21; NTIPAliasClassID["flail"] = 21; +NTIPAliasClassID["whm"] = 22; NTIPAliasClassID["warhammer"] = 22; +NTIPAliasClassID["mau"] = 23; NTIPAliasClassID["maul"] = 23; +NTIPAliasClassID["gma"] = 24; NTIPAliasClassID["greatmaul"] = 24; +NTIPAliasClassID["ssd"] = 25; NTIPAliasClassID["shortsword"] = 25; +NTIPAliasClassID["scm"] = 26; NTIPAliasClassID["scimitar"] = 26; +NTIPAliasClassID["sbr"] = 27; NTIPAliasClassID["sabre"] = 27; +NTIPAliasClassID["flc"] = 28; NTIPAliasClassID["falchion"] = 28; +NTIPAliasClassID["crs"] = 29; NTIPAliasClassID["crystalsword"] = 29; +NTIPAliasClassID["bsd"] = 30; NTIPAliasClassID["broadsword"] = 30; +NTIPAliasClassID["lsd"] = 31; NTIPAliasClassID["longsword"] = 31; +NTIPAliasClassID["wsd"] = 32; NTIPAliasClassID["warsword"] = 32; +NTIPAliasClassID["2hs"] = 33; NTIPAliasClassID["twohandedsword"] = 33; +NTIPAliasClassID["clm"] = 34; NTIPAliasClassID["claymore"] = 34; +NTIPAliasClassID["gis"] = 35; NTIPAliasClassID["giantsword"] = 35; +NTIPAliasClassID["bsw"] = 36; NTIPAliasClassID["bastardsword"] = 36; +NTIPAliasClassID["flb"] = 37; NTIPAliasClassID["flamberge"] = 37; +NTIPAliasClassID["gsd"] = 38; NTIPAliasClassID["greatsword"] = 38; +NTIPAliasClassID["dgr"] = 39; NTIPAliasClassID["dagger"] = 39; +NTIPAliasClassID["dir"] = 40; NTIPAliasClassID["dirk"] = 40; +NTIPAliasClassID["kri"] = 41; NTIPAliasClassID["kris"] = 41; +NTIPAliasClassID["bld"] = 42; NTIPAliasClassID["blade"] = 42; +NTIPAliasClassID["tkf"] = 43; NTIPAliasClassID["throwingknife"] = 43; +NTIPAliasClassID["tax"] = 44; NTIPAliasClassID["throwingaxe"] = 44; +NTIPAliasClassID["bkf"] = 45; NTIPAliasClassID["balancedknife"] = 45; +NTIPAliasClassID["bal"] = 46; NTIPAliasClassID["balancedaxe"] = 46; +NTIPAliasClassID["jav"] = 47; NTIPAliasClassID["javelin"] = 47; +NTIPAliasClassID["pil"] = 48; NTIPAliasClassID["pilum"] = 48; +NTIPAliasClassID["ssp"] = 49; NTIPAliasClassID["shortspear"] = 49; +NTIPAliasClassID["glv"] = 50; NTIPAliasClassID["glaive"] = 50; +NTIPAliasClassID["tsp"] = 51; NTIPAliasClassID["throwingspear"] = 51; +NTIPAliasClassID["spr"] = 52; NTIPAliasClassID["spear"] = 52; +NTIPAliasClassID["tri"] = 53; NTIPAliasClassID["trident"] = 53; +NTIPAliasClassID["brn"] = 54; NTIPAliasClassID["brandistock"] = 54; +NTIPAliasClassID["spt"] = 55; NTIPAliasClassID["spetum"] = 55; +NTIPAliasClassID["pik"] = 56; NTIPAliasClassID["pike"] = 56; +NTIPAliasClassID["bar"] = 57; NTIPAliasClassID["bardiche"] = 57; +NTIPAliasClassID["vou"] = 58; NTIPAliasClassID["voulge"] = 58; +NTIPAliasClassID["scy"] = 59; NTIPAliasClassID["scythe"] = 59; +NTIPAliasClassID["pax"] = 60; NTIPAliasClassID["poleaxe"] = 60; +NTIPAliasClassID["hal"] = 61; NTIPAliasClassID["halberd"] = 61; +NTIPAliasClassID["wsc"] = 62; NTIPAliasClassID["warscythe"] = 62; +NTIPAliasClassID["sst"] = 63; NTIPAliasClassID["shortstaff"] = 63; +NTIPAliasClassID["lst"] = 64; NTIPAliasClassID["longstaff"] = 64; +NTIPAliasClassID["cst"] = 65; NTIPAliasClassID["gnarledstaff"] = 65; +NTIPAliasClassID["bst"] = 66; NTIPAliasClassID["battlestaff"] = 66; +NTIPAliasClassID["wst"] = 67; NTIPAliasClassID["warstaff"] = 67; +NTIPAliasClassID["sbw"] = 68; NTIPAliasClassID["shortbow"] = 68; +NTIPAliasClassID["hbw"] = 69; NTIPAliasClassID["hunter'sbow"] = 69; +NTIPAliasClassID["lbw"] = 70; NTIPAliasClassID["longbow"] = 70; +NTIPAliasClassID["cbw"] = 71; NTIPAliasClassID["compositebow"] = 71; +NTIPAliasClassID["sbb"] = 72; NTIPAliasClassID["shortbattlebow"] = 72; +NTIPAliasClassID["lbb"] = 73; NTIPAliasClassID["longbattlebow"] = 73; +NTIPAliasClassID["swb"] = 74; NTIPAliasClassID["shortwarbow"] = 74; +NTIPAliasClassID["lwb"] = 75; NTIPAliasClassID["longwarbow"] = 75; +NTIPAliasClassID["lxb"] = 76; NTIPAliasClassID["lightcrossbow"] = 76; +NTIPAliasClassID["mxb"] = 77; NTIPAliasClassID["crossbow"] = 77; +NTIPAliasClassID["hxb"] = 78; NTIPAliasClassID["heavycrossbow"] = 78; +NTIPAliasClassID["rxb"] = 79; NTIPAliasClassID["repeatingcrossbow"] = 79; +NTIPAliasClassID["gps"] = 80; NTIPAliasClassID["rancidgaspotion"] = 80; +NTIPAliasClassID["ops"] = 81; NTIPAliasClassID["oilpotion"] = 81; +NTIPAliasClassID["gpm"] = 82; NTIPAliasClassID["chokinggaspotion"] = 82; +NTIPAliasClassID["opm"] = 83; NTIPAliasClassID["explodingpotion"] = 83; +NTIPAliasClassID["gpl"] = 84; NTIPAliasClassID["stranglinggaspotion"] = 84; +NTIPAliasClassID["opl"] = 85; NTIPAliasClassID["fulminatingpotion"] = 85; +NTIPAliasClassID["d33"] = 86; NTIPAliasClassID["decoygidbinn"] = 86; +NTIPAliasClassID["g33"] = 87; NTIPAliasClassID["thegidbinn"] = 87; +NTIPAliasClassID["leg"] = 88; NTIPAliasClassID["wirt'sleg"] = 88; +NTIPAliasClassID["hdm"] = 89; NTIPAliasClassID["horadricmalus"] = 89; +NTIPAliasClassID["hfh"] = 90; NTIPAliasClassID["hellforgehammer"] = 90; +NTIPAliasClassID["hst"] = 91; NTIPAliasClassID["horadricstaff"] = 91; +NTIPAliasClassID["msf"] = 92; NTIPAliasClassID["shaftofthehoradricstaff"] = 92; +NTIPAliasClassID["9ha"] = 93; NTIPAliasClassID["hatchet"] = 93; +NTIPAliasClassID["9ax"] = 94; NTIPAliasClassID["cleaver"] = 94; +NTIPAliasClassID["92a"] = 95; NTIPAliasClassID["twinaxe"] = 95; +NTIPAliasClassID["9mp"] = 96; NTIPAliasClassID["crowbill"] = 96; +NTIPAliasClassID["9wa"] = 97; NTIPAliasClassID["naga"] = 97; +NTIPAliasClassID["9la"] = 98; NTIPAliasClassID["militaryaxe"] = 98; +NTIPAliasClassID["9ba"] = 99; NTIPAliasClassID["beardedaxe"] = 99; +NTIPAliasClassID["9bt"] = 100; NTIPAliasClassID["tabar"] = 100; +NTIPAliasClassID["9ga"] = 101; NTIPAliasClassID["gothicaxe"] = 101; +NTIPAliasClassID["9gi"] = 102; NTIPAliasClassID["ancientaxe"] = 102; +NTIPAliasClassID["9wn"] = 103; NTIPAliasClassID["burntwand"] = 103; +NTIPAliasClassID["9yw"] = 104; NTIPAliasClassID["petrifiedwand"] = 104; +NTIPAliasClassID["9bw"] = 105; NTIPAliasClassID["tombwand"] = 105; +NTIPAliasClassID["9gw"] = 106; NTIPAliasClassID["gravewand"] = 106; +NTIPAliasClassID["9cl"] = 107; NTIPAliasClassID["cudgel"] = 107; +NTIPAliasClassID["9sc"] = 108; NTIPAliasClassID["runescepter"] = 108; +NTIPAliasClassID["9qs"] = 109; NTIPAliasClassID["holywatersprinkler"] = 109; +NTIPAliasClassID["9ws"] = 110; NTIPAliasClassID["divinescepter"] = 110; +NTIPAliasClassID["9sp"] = 111; NTIPAliasClassID["barbedclub"] = 111; +NTIPAliasClassID["9ma"] = 112; NTIPAliasClassID["flangedmace"] = 112; +NTIPAliasClassID["9mt"] = 113; NTIPAliasClassID["jaggedstar"] = 113; +NTIPAliasClassID["9fl"] = 114; NTIPAliasClassID["knout"] = 114; +NTIPAliasClassID["9wh"] = 115; NTIPAliasClassID["battlehammer"] = 115; +NTIPAliasClassID["9m9"] = 116; NTIPAliasClassID["warclub"] = 116; +NTIPAliasClassID["9gm"] = 117; NTIPAliasClassID["marteldefer"] = 117; +NTIPAliasClassID["9ss"] = 118; NTIPAliasClassID["gladius"] = 118; +NTIPAliasClassID["9sm"] = 119; NTIPAliasClassID["cutlass"] = 119; +NTIPAliasClassID["9sb"] = 120; NTIPAliasClassID["shamshir"] = 120; +NTIPAliasClassID["9fc"] = 121; NTIPAliasClassID["tulwar"] = 121; +NTIPAliasClassID["9cr"] = 122; NTIPAliasClassID["dimensionalblade"] = 122; +NTIPAliasClassID["9bs"] = 123; NTIPAliasClassID["battlesword"] = 123; +NTIPAliasClassID["9ls"] = 124; NTIPAliasClassID["runesword"] = 124; +NTIPAliasClassID["9wd"] = 125; NTIPAliasClassID["ancientsword"] = 125; +NTIPAliasClassID["92h"] = 126; NTIPAliasClassID["espandon"] = 126; +NTIPAliasClassID["9cm"] = 127; NTIPAliasClassID["dacianfalx"] = 127; +NTIPAliasClassID["9gs"] = 128; NTIPAliasClassID["tusksword"] = 128; +NTIPAliasClassID["9b9"] = 129; NTIPAliasClassID["gothicsword"] = 129; +NTIPAliasClassID["9fb"] = 130; NTIPAliasClassID["zweihander"] = 130; +NTIPAliasClassID["9gd"] = 131; NTIPAliasClassID["executionersword"] = 131; +NTIPAliasClassID["9dg"] = 132; NTIPAliasClassID["poignard"] = 132; +NTIPAliasClassID["9di"] = 133; NTIPAliasClassID["rondel"] = 133; +NTIPAliasClassID["9kr"] = 134; NTIPAliasClassID["cinquedeas"] = 134; +NTIPAliasClassID["9bl"] = 135; NTIPAliasClassID["stiletto"] = 135; +NTIPAliasClassID["9tk"] = 136; NTIPAliasClassID["battledart"] = 136; +NTIPAliasClassID["9ta"] = 137; NTIPAliasClassID["francisca"] = 137; +NTIPAliasClassID["9bk"] = 138; NTIPAliasClassID["wardart"] = 138; +NTIPAliasClassID["9b8"] = 139; NTIPAliasClassID["hurlbat"] = 139; +NTIPAliasClassID["9ja"] = 140; NTIPAliasClassID["warjavelin"] = 140; +NTIPAliasClassID["9pi"] = 141; NTIPAliasClassID["greatpilum"] = 141; +NTIPAliasClassID["9s9"] = 142; NTIPAliasClassID["simbilan"] = 142; +NTIPAliasClassID["9gl"] = 143; NTIPAliasClassID["spiculum"] = 143; +NTIPAliasClassID["9ts"] = 144; NTIPAliasClassID["harpoon"] = 144; +NTIPAliasClassID["9sr"] = 145; NTIPAliasClassID["warspear"] = 145; +NTIPAliasClassID["9tr"] = 146; NTIPAliasClassID["fuscina"] = 146; +NTIPAliasClassID["9br"] = 147; NTIPAliasClassID["warfork"] = 147; +NTIPAliasClassID["9st"] = 148; NTIPAliasClassID["yari"] = 148; +NTIPAliasClassID["9p9"] = 149; NTIPAliasClassID["lance"] = 149; +NTIPAliasClassID["9b7"] = 150; NTIPAliasClassID["lochaberaxe"] = 150; +NTIPAliasClassID["9vo"] = 151; NTIPAliasClassID["bill"] = 151; +NTIPAliasClassID["9s8"] = 152; NTIPAliasClassID["battlescythe"] = 152; +NTIPAliasClassID["9pa"] = 153; NTIPAliasClassID["partizan"] = 153; +NTIPAliasClassID["9h9"] = 154; NTIPAliasClassID["becdecorbin"] = 154; +NTIPAliasClassID["9wc"] = 155; NTIPAliasClassID["grimscythe"] = 155; +NTIPAliasClassID["8ss"] = 156; NTIPAliasClassID["jostaff"] = 156; +NTIPAliasClassID["8ls"] = 157; NTIPAliasClassID["quarterstaff"] = 157; +NTIPAliasClassID["8cs"] = 158; NTIPAliasClassID["cedarstaff"] = 158; +NTIPAliasClassID["8bs"] = 159; NTIPAliasClassID["gothicstaff"] = 159; +NTIPAliasClassID["8ws"] = 160; NTIPAliasClassID["runestaff"] = 160; +NTIPAliasClassID["8sb"] = 161; NTIPAliasClassID["edgebow"] = 161; +NTIPAliasClassID["8hb"] = 162; NTIPAliasClassID["razorbow"] = 162; +NTIPAliasClassID["8lb"] = 163; NTIPAliasClassID["cedarbow"] = 163; +NTIPAliasClassID["8cb"] = 164; NTIPAliasClassID["doublebow"] = 164; +NTIPAliasClassID["8s8"] = 165; NTIPAliasClassID["shortsiegebow"] = 165; +NTIPAliasClassID["8l8"] = 166; NTIPAliasClassID["largesiegebow"] = 166; +NTIPAliasClassID["8sw"] = 167; NTIPAliasClassID["runebow"] = 167; +NTIPAliasClassID["8lw"] = 168; NTIPAliasClassID["gothicbow"] = 168; +NTIPAliasClassID["8lx"] = 169; NTIPAliasClassID["arbalest"] = 169; +NTIPAliasClassID["8mx"] = 170; NTIPAliasClassID["siegecrossbow"] = 170; +NTIPAliasClassID["8hx"] = 171; NTIPAliasClassID["ballista"] = 171; +NTIPAliasClassID["8rx"] = 172; NTIPAliasClassID["chukonu"] = 172; +NTIPAliasClassID["qf1"] = 173; NTIPAliasClassID["khalim'sflail"] = 173; +NTIPAliasClassID["qf2"] = 174; NTIPAliasClassID["khalim'swill"] = 174; +NTIPAliasClassID["ktr"] = 175; NTIPAliasClassID["katar"] = 175; +NTIPAliasClassID["wrb"] = 176; NTIPAliasClassID["wristblade"] = 176; +NTIPAliasClassID["axf"] = 177; NTIPAliasClassID["hatchethands"] = 177; +NTIPAliasClassID["ces"] = 178; NTIPAliasClassID["cestus"] = 178; +NTIPAliasClassID["clw"] = 179; NTIPAliasClassID["claws"] = 179; +NTIPAliasClassID["btl"] = 180; NTIPAliasClassID["bladetalons"] = 180; +NTIPAliasClassID["skr"] = 181; NTIPAliasClassID["scissorskatar"] = 181; +NTIPAliasClassID["9ar"] = 182; NTIPAliasClassID["quhab"] = 182; +NTIPAliasClassID["9wb"] = 183; NTIPAliasClassID["wristspike"] = 183; +NTIPAliasClassID["9xf"] = 184; NTIPAliasClassID["fascia"] = 184; +NTIPAliasClassID["9cs"] = 185; NTIPAliasClassID["handscythe"] = 185; +NTIPAliasClassID["9lw"] = 186; NTIPAliasClassID["greaterclaws"] = 186; +NTIPAliasClassID["9tw"] = 187; NTIPAliasClassID["greatertalons"] = 187; +NTIPAliasClassID["9qr"] = 188; NTIPAliasClassID["scissorsquhab"] = 188; +NTIPAliasClassID["7ar"] = 189; NTIPAliasClassID["suwayyah"] = 189; +NTIPAliasClassID["7wb"] = 190; NTIPAliasClassID["wristsword"] = 190; +NTIPAliasClassID["7xf"] = 191; NTIPAliasClassID["warfist"] = 191; +NTIPAliasClassID["7cs"] = 192; NTIPAliasClassID["battlecestus"] = 192; +NTIPAliasClassID["7lw"] = 193; NTIPAliasClassID["feralclaws"] = 193; +NTIPAliasClassID["7tw"] = 194; NTIPAliasClassID["runictalons"] = 194; +NTIPAliasClassID["7qr"] = 195; NTIPAliasClassID["scissorssuwayyah"] = 195; +NTIPAliasClassID["7ha"] = 196; NTIPAliasClassID["tomahawk"] = 196; +NTIPAliasClassID["7ax"] = 197; NTIPAliasClassID["smallcrescent"] = 197; +NTIPAliasClassID["72a"] = 198; NTIPAliasClassID["ettinaxe"] = 198; +NTIPAliasClassID["7mp"] = 199; NTIPAliasClassID["warspike"] = 199; +NTIPAliasClassID["7wa"] = 200; NTIPAliasClassID["berserkeraxe"] = 200; +NTIPAliasClassID["7la"] = 201; NTIPAliasClassID["feralaxe"] = 201; +NTIPAliasClassID["7ba"] = 202; NTIPAliasClassID["silveredgedaxe"] = 202; +NTIPAliasClassID["7bt"] = 203; NTIPAliasClassID["decapitator"] = 203; +NTIPAliasClassID["7ga"] = 204; NTIPAliasClassID["championaxe"] = 204; +NTIPAliasClassID["7gi"] = 205; NTIPAliasClassID["gloriousaxe"] = 205; +NTIPAliasClassID["7wn"] = 206; NTIPAliasClassID["polishedwand"] = 206; +NTIPAliasClassID["7yw"] = 207; NTIPAliasClassID["ghostwand"] = 207; +NTIPAliasClassID["7bw"] = 208; NTIPAliasClassID["lichwand"] = 208; +NTIPAliasClassID["7gw"] = 209; NTIPAliasClassID["unearthedwand"] = 209; +NTIPAliasClassID["7cl"] = 210; NTIPAliasClassID["truncheon"] = 210; +NTIPAliasClassID["7sc"] = 211; NTIPAliasClassID["mightyscepter"] = 211; +NTIPAliasClassID["7qs"] = 212; NTIPAliasClassID["seraphrod"] = 212; +NTIPAliasClassID["7ws"] = 213; NTIPAliasClassID["caduceus"] = 213; +NTIPAliasClassID["7sp"] = 214; NTIPAliasClassID["tyrantclub"] = 214; +NTIPAliasClassID["7ma"] = 215; NTIPAliasClassID["reinforcedmace"] = 215; +NTIPAliasClassID["7mt"] = 216; NTIPAliasClassID["devilstar"] = 216; +NTIPAliasClassID["7fl"] = 217; NTIPAliasClassID["scourge"] = 217; +NTIPAliasClassID["7wh"] = 218; NTIPAliasClassID["legendarymallet"] = 218; +NTIPAliasClassID["7m7"] = 219; NTIPAliasClassID["ogremaul"] = 219; +NTIPAliasClassID["7gm"] = 220; NTIPAliasClassID["thundermaul"] = 220; +NTIPAliasClassID["7ss"] = 221; NTIPAliasClassID["falcata"] = 221; +NTIPAliasClassID["7sm"] = 222; NTIPAliasClassID["ataghan"] = 222; +NTIPAliasClassID["7sb"] = 223; NTIPAliasClassID["elegantblade"] = 223; +NTIPAliasClassID["7fc"] = 224; NTIPAliasClassID["hydraedge"] = 224; +NTIPAliasClassID["7cr"] = 225; NTIPAliasClassID["phaseblade"] = 225; +NTIPAliasClassID["7bs"] = 226; NTIPAliasClassID["conquestsword"] = 226; +NTIPAliasClassID["7ls"] = 227; NTIPAliasClassID["crypticsword"] = 227; +NTIPAliasClassID["7wd"] = 228; NTIPAliasClassID["mythicalsword"] = 228; +NTIPAliasClassID["72h"] = 229; NTIPAliasClassID["legendsword"] = 229; +NTIPAliasClassID["7cm"] = 230; NTIPAliasClassID["highlandblade"] = 230; +NTIPAliasClassID["7gs"] = 231; NTIPAliasClassID["balrogblade"] = 231; +NTIPAliasClassID["7b7"] = 232; NTIPAliasClassID["championsword"] = 232; +NTIPAliasClassID["7fb"] = 233; NTIPAliasClassID["colossussword"] = 233; +NTIPAliasClassID["7gd"] = 234; NTIPAliasClassID["colossusblade"] = 234; +NTIPAliasClassID["7dg"] = 235; NTIPAliasClassID["boneknife"] = 235; +NTIPAliasClassID["7di"] = 236; NTIPAliasClassID["mithrilpoint"] = 236; +NTIPAliasClassID["7kr"] = 237; NTIPAliasClassID["fangedknife"] = 237; +NTIPAliasClassID["7bl"] = 238; NTIPAliasClassID["legendspike"] = 238; +NTIPAliasClassID["7tk"] = 239; NTIPAliasClassID["flyingknife"] = 239; +NTIPAliasClassID["7ta"] = 240; NTIPAliasClassID["flyingaxe"] = 240; +NTIPAliasClassID["7bk"] = 241; NTIPAliasClassID["wingedknife"] = 241; +NTIPAliasClassID["7b8"] = 242; NTIPAliasClassID["wingedaxe"] = 242; +NTIPAliasClassID["7ja"] = 243; NTIPAliasClassID["hyperionjavelin"] = 243; +NTIPAliasClassID["7pi"] = 244; NTIPAliasClassID["stygianpilum"] = 244; +NTIPAliasClassID["7s7"] = 245; NTIPAliasClassID["balrogspear"] = 245; +NTIPAliasClassID["7gl"] = 246; NTIPAliasClassID["ghostglaive"] = 246; +NTIPAliasClassID["7ts"] = 247; NTIPAliasClassID["wingedharpoon"] = 247; +NTIPAliasClassID["7sr"] = 248; NTIPAliasClassID["hyperionspear"] = 248; +NTIPAliasClassID["7tr"] = 249; NTIPAliasClassID["stygianpike"] = 249; +NTIPAliasClassID["7br"] = 250; NTIPAliasClassID["mancatcher"] = 250; +NTIPAliasClassID["7st"] = 251; NTIPAliasClassID["ghostspear"] = 251; +NTIPAliasClassID["7p7"] = 252; NTIPAliasClassID["warpike"] = 252; +NTIPAliasClassID["7o7"] = 253; NTIPAliasClassID["ogreaxe"] = 253; +NTIPAliasClassID["7vo"] = 254; NTIPAliasClassID["colossusvoulge"] = 254; +NTIPAliasClassID["7s8"] = 255; NTIPAliasClassID["thresher"] = 255; +NTIPAliasClassID["7pa"] = 256; NTIPAliasClassID["crypticaxe"] = 256; +NTIPAliasClassID["7h7"] = 257; NTIPAliasClassID["greatpoleaxe"] = 257; +NTIPAliasClassID["7wc"] = 258; NTIPAliasClassID["giantthresher"] = 258; +NTIPAliasClassID["6ss"] = 259; NTIPAliasClassID["walkingstick"] = 259; +NTIPAliasClassID["6ls"] = 260; NTIPAliasClassID["stalagmite"] = 260; +NTIPAliasClassID["6cs"] = 261; NTIPAliasClassID["elderstaff"] = 261; +NTIPAliasClassID["6bs"] = 262; NTIPAliasClassID["shillelagh"] = 262; +NTIPAliasClassID["6ws"] = 263; NTIPAliasClassID["archonstaff"] = 263; +NTIPAliasClassID["6sb"] = 264; NTIPAliasClassID["spiderbow"] = 264; +NTIPAliasClassID["6hb"] = 265; NTIPAliasClassID["bladebow"] = 265; +NTIPAliasClassID["6lb"] = 266; NTIPAliasClassID["shadowbow"] = 266; +NTIPAliasClassID["6cb"] = 267; NTIPAliasClassID["greatbow"] = 267; +NTIPAliasClassID["6s7"] = 268; NTIPAliasClassID["diamondbow"] = 268; +NTIPAliasClassID["6l7"] = 269; NTIPAliasClassID["crusaderbow"] = 269; +NTIPAliasClassID["6sw"] = 270; NTIPAliasClassID["wardbow"] = 270; +NTIPAliasClassID["6lw"] = 271; NTIPAliasClassID["hydrabow"] = 271; +NTIPAliasClassID["6lx"] = 272; NTIPAliasClassID["pelletbow"] = 272; +NTIPAliasClassID["6mx"] = 273; NTIPAliasClassID["gorgoncrossbow"] = 273; +NTIPAliasClassID["6hx"] = 274; NTIPAliasClassID["colossuscrossbow"] = 274; +NTIPAliasClassID["6rx"] = 275; NTIPAliasClassID["demoncrossbow"] = 275; +NTIPAliasClassID["ob1"] = 276; NTIPAliasClassID["eagleorb"] = 276; +NTIPAliasClassID["ob2"] = 277; NTIPAliasClassID["sacredglobe"] = 277; +NTIPAliasClassID["ob3"] = 278; NTIPAliasClassID["smokedsphere"] = 278; +NTIPAliasClassID["ob4"] = 279; NTIPAliasClassID["claspedorb"] = 279; +NTIPAliasClassID["ob5"] = 280; NTIPAliasClassID["jared'sstone"] = 280; +NTIPAliasClassID["am1"] = 281; NTIPAliasClassID["stagbow"] = 281; +NTIPAliasClassID["am2"] = 282; NTIPAliasClassID["reflexbow"] = 282; +NTIPAliasClassID["am3"] = 283; NTIPAliasClassID["maidenspear"] = 283; +NTIPAliasClassID["am4"] = 284; NTIPAliasClassID["maidenpike"] = 284; +NTIPAliasClassID["am5"] = 285; NTIPAliasClassID["maidenjavelin"] = 285; +NTIPAliasClassID["ob6"] = 286; NTIPAliasClassID["glowingorb"] = 286; +NTIPAliasClassID["ob7"] = 287; NTIPAliasClassID["crystallineglobe"] = 287; +NTIPAliasClassID["ob8"] = 288; NTIPAliasClassID["cloudysphere"] = 288; +NTIPAliasClassID["ob9"] = 289; NTIPAliasClassID["sparklingball"] = 289; +NTIPAliasClassID["oba"] = 290; NTIPAliasClassID["swirlingcrystal"] = 290; +NTIPAliasClassID["am6"] = 291; NTIPAliasClassID["ashwoodbow"] = 291; +NTIPAliasClassID["am7"] = 292; NTIPAliasClassID["ceremonialbow"] = 292; +NTIPAliasClassID["am8"] = 293; NTIPAliasClassID["ceremonialspear"] = 293; +NTIPAliasClassID["am9"] = 294; NTIPAliasClassID["ceremonialpike"] = 294; +NTIPAliasClassID["ama"] = 295; NTIPAliasClassID["ceremonialjavelin"] = 295; +NTIPAliasClassID["obb"] = 296; NTIPAliasClassID["heavenlystone"] = 296; +NTIPAliasClassID["obc"] = 297; NTIPAliasClassID["eldritchorb"] = 297; +NTIPAliasClassID["obd"] = 298; NTIPAliasClassID["demonheart"] = 298; +NTIPAliasClassID["obe"] = 299; NTIPAliasClassID["vortexorb"] = 299; +NTIPAliasClassID["obf"] = 300; NTIPAliasClassID["dimensionalshard"] = 300; +NTIPAliasClassID["amb"] = 301; NTIPAliasClassID["matriarchalbow"] = 301; +NTIPAliasClassID["amc"] = 302; NTIPAliasClassID["grandmatronbow"] = 302; +NTIPAliasClassID["amd"] = 303; NTIPAliasClassID["matriarchalspear"] = 303; +NTIPAliasClassID["ame"] = 304; NTIPAliasClassID["matriarchalpike"] = 304; +NTIPAliasClassID["amf"] = 305; NTIPAliasClassID["matriarchaljavelin"] = 305; +NTIPAliasClassID["cap"] = 306; +NTIPAliasClassID["skp"] = 307; NTIPAliasClassID["skullcap"] = 307; +NTIPAliasClassID["hlm"] = 308; NTIPAliasClassID["helm"] = 308; +NTIPAliasClassID["fhl"] = 309; NTIPAliasClassID["fullhelm"] = 309; +NTIPAliasClassID["ghm"] = 310; NTIPAliasClassID["greathelm"] = 310; +NTIPAliasClassID["crn"] = 311; NTIPAliasClassID["crown"] = 311; +NTIPAliasClassID["msk"] = 312; NTIPAliasClassID["mask"] = 312; +NTIPAliasClassID["qui"] = 313; NTIPAliasClassID["quiltedarmor"] = 313; +NTIPAliasClassID["lea"] = 314; NTIPAliasClassID["leatherarmor"] = 314; +NTIPAliasClassID["hla"] = 315; NTIPAliasClassID["hardleatherarmor"] = 315; +NTIPAliasClassID["stu"] = 316; NTIPAliasClassID["studdedleather"] = 316; +NTIPAliasClassID["rng"] = 317; NTIPAliasClassID["ringmail"] = 317; +NTIPAliasClassID["scl"] = 318; NTIPAliasClassID["scalemail"] = 318; +NTIPAliasClassID["chn"] = 319; NTIPAliasClassID["chainmail"] = 319; +NTIPAliasClassID["brs"] = 320; NTIPAliasClassID["breastplate"] = 320; +NTIPAliasClassID["spl"] = 321; NTIPAliasClassID["splintmail"] = 321; +NTIPAliasClassID["plt"] = 322; NTIPAliasClassID["platemail"] = 322; +NTIPAliasClassID["fld"] = 323; NTIPAliasClassID["fieldplate"] = 323; +NTIPAliasClassID["gth"] = 324; NTIPAliasClassID["gothicplate"] = 324; +NTIPAliasClassID["ful"] = 325; NTIPAliasClassID["fullplatemail"] = 325; +NTIPAliasClassID["aar"] = 326; NTIPAliasClassID["ancientarmor"] = 326; +NTIPAliasClassID["ltp"] = 327; NTIPAliasClassID["lightplate"] = 327; +NTIPAliasClassID["buc"] = 328; NTIPAliasClassID["buckler"] = 328; +NTIPAliasClassID["sml"] = 329; NTIPAliasClassID["smallshield"] = 329; +NTIPAliasClassID["lrg"] = 330; NTIPAliasClassID["largeshield"] = 330; +NTIPAliasClassID["kit"] = 331; NTIPAliasClassID["kiteshield"] = 331; +NTIPAliasClassID["tow"] = 332; NTIPAliasClassID["towershield"] = 332; +NTIPAliasClassID["gts"] = 333; NTIPAliasClassID["gothicshield"] = 333; +NTIPAliasClassID["lgl"] = 334; NTIPAliasClassID["leathergloves"] = 334; +NTIPAliasClassID["vgl"] = 335; NTIPAliasClassID["heavygloves"] = 335; +NTIPAliasClassID["mgl"] = 336; NTIPAliasClassID["chaingloves"] = 336; +NTIPAliasClassID["tgl"] = 337; NTIPAliasClassID["lightgauntlets"] = 337; +NTIPAliasClassID["hgl"] = 338; NTIPAliasClassID["gauntlets"] = 338; +NTIPAliasClassID["lbt"] = 339; NTIPAliasClassID["boots"] = 339; +NTIPAliasClassID["vbt"] = 340; NTIPAliasClassID["heavyboots"] = 340; +NTIPAliasClassID["mbt"] = 341; NTIPAliasClassID["chainboots"] = 341; +NTIPAliasClassID["tbt"] = 342; NTIPAliasClassID["lightplatedboots"] = 342; +NTIPAliasClassID["hbt"] = 343; NTIPAliasClassID["greaves"] = 343; +NTIPAliasClassID["lbl"] = 344; NTIPAliasClassID["sash"] = 344; +NTIPAliasClassID["vbl"] = 345; NTIPAliasClassID["lightbelt"] = 345; +NTIPAliasClassID["mbl"] = 346; NTIPAliasClassID["belt"] = 346; +NTIPAliasClassID["tbl"] = 347; NTIPAliasClassID["heavybelt"] = 347; +NTIPAliasClassID["hbl"] = 348; NTIPAliasClassID["platedbelt"] = 348; +NTIPAliasClassID["bhm"] = 349; NTIPAliasClassID["bonehelm"] = 349; +NTIPAliasClassID["bsh"] = 350; NTIPAliasClassID["boneshield"] = 350; +NTIPAliasClassID["spk"] = 351; NTIPAliasClassID["spikedshield"] = 351; +NTIPAliasClassID["xap"] = 352; NTIPAliasClassID["warhat"] = 352; +NTIPAliasClassID["xkp"] = 353; NTIPAliasClassID["sallet"] = 353; +NTIPAliasClassID["xlm"] = 354; NTIPAliasClassID["casque"] = 354; +NTIPAliasClassID["xhl"] = 355; NTIPAliasClassID["basinet"] = 355; +NTIPAliasClassID["xhm"] = 356; NTIPAliasClassID["wingedhelm"] = 356; +NTIPAliasClassID["xrn"] = 357; NTIPAliasClassID["grandcrown"] = 357; +NTIPAliasClassID["xsk"] = 358; NTIPAliasClassID["deathmask"] = 358; +NTIPAliasClassID["xui"] = 359; NTIPAliasClassID["ghostarmor"] = 359; +NTIPAliasClassID["xea"] = 360; NTIPAliasClassID["serpentskinarmor"] = 360; +NTIPAliasClassID["xla"] = 361; NTIPAliasClassID["demonhidearmor"] = 361; +NTIPAliasClassID["xtu"] = 362; NTIPAliasClassID["trellisedarmor"] = 362; +NTIPAliasClassID["xng"] = 363; NTIPAliasClassID["linkedmail"] = 363; +NTIPAliasClassID["xcl"] = 364; NTIPAliasClassID["tigulatedmail"] = 364; +NTIPAliasClassID["xhn"] = 365; NTIPAliasClassID["mesharmor"] = 365; +NTIPAliasClassID["xrs"] = 366; NTIPAliasClassID["cuirass"] = 366; +NTIPAliasClassID["xpl"] = 367; NTIPAliasClassID["russetarmor"] = 367; +NTIPAliasClassID["xlt"] = 368; NTIPAliasClassID["templarcoat"] = 368; +NTIPAliasClassID["xld"] = 369; NTIPAliasClassID["sharktootharmor"] = 369; +NTIPAliasClassID["xth"] = 370; NTIPAliasClassID["embossedplate"] = 370; +NTIPAliasClassID["xul"] = 371; NTIPAliasClassID["chaosarmor"] = 371; +NTIPAliasClassID["xar"] = 372; NTIPAliasClassID["ornateplate"] = 372; +NTIPAliasClassID["xtp"] = 373; NTIPAliasClassID["mageplate"] = 373; +NTIPAliasClassID["xuc"] = 374; NTIPAliasClassID["defender"] = 374; +NTIPAliasClassID["xml"] = 375; NTIPAliasClassID["roundshield"] = 375; +NTIPAliasClassID["xrg"] = 376; NTIPAliasClassID["scutum"] = 376; +NTIPAliasClassID["xit"] = 377; NTIPAliasClassID["dragonshield"] = 377; +NTIPAliasClassID["xow"] = 378; NTIPAliasClassID["pavise"] = 378; +NTIPAliasClassID["xts"] = 379; NTIPAliasClassID["ancientshield"] = 379; +NTIPAliasClassID["xlg"] = 380; NTIPAliasClassID["demonhidegloves"] = 380; +NTIPAliasClassID["xvg"] = 381; NTIPAliasClassID["sharkskingloves"] = 381; +NTIPAliasClassID["xmg"] = 382; NTIPAliasClassID["heavybracers"] = 382; +NTIPAliasClassID["xtg"] = 383; NTIPAliasClassID["battlegauntlets"] = 383; +NTIPAliasClassID["xhg"] = 384; NTIPAliasClassID["wargauntlets"] = 384; +NTIPAliasClassID["xlb"] = 385; NTIPAliasClassID["demonhideboots"] = 385; +NTIPAliasClassID["xvb"] = 386; NTIPAliasClassID["sharkskinboots"] = 386; +NTIPAliasClassID["xmb"] = 387; NTIPAliasClassID["meshboots"] = 387; +NTIPAliasClassID["xtb"] = 388; NTIPAliasClassID["battleboots"] = 388; +NTIPAliasClassID["xhb"] = 389; NTIPAliasClassID["warboots"] = 389; +NTIPAliasClassID["zlb"] = 390; NTIPAliasClassID["demonhidesash"] = 390; +NTIPAliasClassID["zvb"] = 391; NTIPAliasClassID["sharkskinbelt"] = 391; +NTIPAliasClassID["zmb"] = 392; NTIPAliasClassID["meshbelt"] = 392; +NTIPAliasClassID["ztb"] = 393; NTIPAliasClassID["battlebelt"] = 393; +NTIPAliasClassID["zhb"] = 394; NTIPAliasClassID["warbelt"] = 394; +NTIPAliasClassID["xh9"] = 395; NTIPAliasClassID["grimhelm"] = 395; +NTIPAliasClassID["xsh"] = 396; NTIPAliasClassID["grimshield"] = 396; +NTIPAliasClassID["xpk"] = 397; NTIPAliasClassID["barbedshield"] = 397; +NTIPAliasClassID["dr1"] = 398; NTIPAliasClassID["wolfhead"] = 398; +NTIPAliasClassID["dr2"] = 399; NTIPAliasClassID["hawkhelm"] = 399; +NTIPAliasClassID["dr3"] = 400; NTIPAliasClassID["antlers"] = 400; +NTIPAliasClassID["dr4"] = 401; NTIPAliasClassID["falconmask"] = 401; +NTIPAliasClassID["dr5"] = 402; NTIPAliasClassID["spiritmask"] = 402; +NTIPAliasClassID["ba1"] = 403; NTIPAliasClassID["jawbonecap"] = 403; +NTIPAliasClassID["ba2"] = 404; NTIPAliasClassID["fangedhelm"] = 404; +NTIPAliasClassID["ba3"] = 405; NTIPAliasClassID["hornedhelm"] = 405; +NTIPAliasClassID["ba4"] = 406; NTIPAliasClassID["assaulthelmet"] = 406; +NTIPAliasClassID["ba5"] = 407; NTIPAliasClassID["avengerguard"] = 407; +NTIPAliasClassID["pa1"] = 408; NTIPAliasClassID["targe"] = 408; +NTIPAliasClassID["pa2"] = 409; NTIPAliasClassID["rondache"] = 409; +NTIPAliasClassID["pa3"] = 410; NTIPAliasClassID["heraldicshield"] = 410; +NTIPAliasClassID["pa4"] = 411; NTIPAliasClassID["aerinshield"] = 411; +NTIPAliasClassID["pa5"] = 412; NTIPAliasClassID["crownshield"] = 412; +NTIPAliasClassID["ne1"] = 413; NTIPAliasClassID["preservedhead"] = 413; +NTIPAliasClassID["ne2"] = 414; NTIPAliasClassID["zombiehead"] = 414; +NTIPAliasClassID["ne3"] = 415; NTIPAliasClassID["unravellerhead"] = 415; +NTIPAliasClassID["ne4"] = 416; NTIPAliasClassID["gargoylehead"] = 416; +NTIPAliasClassID["ne5"] = 417; NTIPAliasClassID["demonhead"] = 417; +NTIPAliasClassID["ci0"] = 418; NTIPAliasClassID["circlet"] = 418; +NTIPAliasClassID["ci1"] = 419; NTIPAliasClassID["coronet"] = 419; +NTIPAliasClassID["ci2"] = 420; NTIPAliasClassID["tiara"] = 420; +NTIPAliasClassID["ci3"] = 421; NTIPAliasClassID["diadem"] = 421; +NTIPAliasClassID["uap"] = 422; NTIPAliasClassID["shako"] = 422; +NTIPAliasClassID["ukp"] = 423; NTIPAliasClassID["hydraskull"] = 423; +NTIPAliasClassID["ulm"] = 424; NTIPAliasClassID["armet"] = 424; +NTIPAliasClassID["uhl"] = 425; NTIPAliasClassID["giantconch"] = 425; +NTIPAliasClassID["uhm"] = 426; NTIPAliasClassID["spiredhelm"] = 426; +NTIPAliasClassID["urn"] = 427; NTIPAliasClassID["corona"] = 427; +NTIPAliasClassID["usk"] = 428; NTIPAliasClassID["demonhead"] = 428; +NTIPAliasClassID["uui"] = 429; NTIPAliasClassID["duskshroud"] = 429; +NTIPAliasClassID["uea"] = 430; NTIPAliasClassID["wyrmhide"] = 430; +NTIPAliasClassID["ula"] = 431; NTIPAliasClassID["scarabhusk"] = 431; +NTIPAliasClassID["utu"] = 432; NTIPAliasClassID["wirefleece"] = 432; +NTIPAliasClassID["ung"] = 433; NTIPAliasClassID["diamondmail"] = 433; +NTIPAliasClassID["ucl"] = 434; NTIPAliasClassID["loricatedmail"] = 434; +NTIPAliasClassID["uhn"] = 435; NTIPAliasClassID["boneweave"] = 435; +NTIPAliasClassID["urs"] = 436; NTIPAliasClassID["greathauberk"] = 436; +NTIPAliasClassID["upl"] = 437; NTIPAliasClassID["balrogskin"] = 437; +NTIPAliasClassID["ult"] = 438; NTIPAliasClassID["hellforgeplate"] = 438; +NTIPAliasClassID["uld"] = 439; NTIPAliasClassID["krakenshell"] = 439; +NTIPAliasClassID["uth"] = 440; NTIPAliasClassID["lacqueredplate"] = 440; +NTIPAliasClassID["uul"] = 441; NTIPAliasClassID["shadowplate"] = 441; +NTIPAliasClassID["uar"] = 442; NTIPAliasClassID["sacredarmor"] = 442; +NTIPAliasClassID["utp"] = 443; NTIPAliasClassID["archonplate"] = 443; +NTIPAliasClassID["uuc"] = 444; NTIPAliasClassID["heater"] = 444; +NTIPAliasClassID["uml"] = 445; NTIPAliasClassID["luna"] = 445; +NTIPAliasClassID["urg"] = 446; NTIPAliasClassID["hyperion"] = 446; +NTIPAliasClassID["uit"] = 447; NTIPAliasClassID["monarch"] = 447; +NTIPAliasClassID["uow"] = 448; NTIPAliasClassID["aegis"] = 448; +NTIPAliasClassID["uts"] = 449; NTIPAliasClassID["ward"] = 449; +NTIPAliasClassID["ulg"] = 450; NTIPAliasClassID["bramblemitts"] = 450; +NTIPAliasClassID["uvg"] = 451; NTIPAliasClassID["vampirebonegloves"] = 451; +NTIPAliasClassID["umg"] = 452; NTIPAliasClassID["vambraces"] = 452; +NTIPAliasClassID["utg"] = 453; NTIPAliasClassID["crusadergauntlets"] = 453; +NTIPAliasClassID["uhg"] = 454; NTIPAliasClassID["ogregauntlets"] = 454; +NTIPAliasClassID["ulb"] = 455; NTIPAliasClassID["wyrmhideboots"] = 455; +NTIPAliasClassID["uvb"] = 456; NTIPAliasClassID["scarabshellboots"] = 456; +NTIPAliasClassID["umb"] = 457; NTIPAliasClassID["boneweaveboots"] = 457; +NTIPAliasClassID["utb"] = 458; NTIPAliasClassID["mirroredboots"] = 458; +NTIPAliasClassID["uhb"] = 459; NTIPAliasClassID["myrmidongreaves"] = 459; +NTIPAliasClassID["ulc"] = 460; NTIPAliasClassID["spiderwebsash"] = 460; +NTIPAliasClassID["uvc"] = 461; NTIPAliasClassID["vampirefangbelt"] = 461; +NTIPAliasClassID["umc"] = 462; NTIPAliasClassID["mithrilcoil"] = 462; +NTIPAliasClassID["utc"] = 463; NTIPAliasClassID["trollbelt"] = 463; +NTIPAliasClassID["uhc"] = 464; NTIPAliasClassID["colossusgirdle"] = 464; +NTIPAliasClassID["uh9"] = 465; NTIPAliasClassID["bonevisage"] = 465; +NTIPAliasClassID["ush"] = 466; NTIPAliasClassID["trollnest"] = 466; +NTIPAliasClassID["upk"] = 467; NTIPAliasClassID["bladebarrier"] = 467; +NTIPAliasClassID["dr6"] = 468; NTIPAliasClassID["alphahelm"] = 468; +NTIPAliasClassID["dr7"] = 469; NTIPAliasClassID["griffonheaddress"] = 469; +NTIPAliasClassID["dr8"] = 470; NTIPAliasClassID["hunter'sguise"] = 470; +NTIPAliasClassID["dr9"] = 471; NTIPAliasClassID["sacredfeathers"] = 471; +NTIPAliasClassID["dra"] = 472; NTIPAliasClassID["totemicmask"] = 472; +NTIPAliasClassID["ba6"] = 473; NTIPAliasClassID["jawbonevisor"] = 473; +NTIPAliasClassID["ba7"] = 474; NTIPAliasClassID["lionhelm"] = 474; +NTIPAliasClassID["ba8"] = 475; NTIPAliasClassID["ragemask"] = 475; +NTIPAliasClassID["ba9"] = 476; NTIPAliasClassID["savagehelmet"] = 476; +NTIPAliasClassID["baa"] = 477; NTIPAliasClassID["slayerguard"] = 477; +NTIPAliasClassID["pa6"] = 478; NTIPAliasClassID["akarantarge"] = 478; +NTIPAliasClassID["pa7"] = 479; NTIPAliasClassID["akaranrondache"] = 479; +NTIPAliasClassID["pa8"] = 480; NTIPAliasClassID["protectorshield"] = 480; +NTIPAliasClassID["pa9"] = 481; NTIPAliasClassID["gildedshield"] = 481; +NTIPAliasClassID["paa"] = 482; NTIPAliasClassID["royalshield"] = 482; +NTIPAliasClassID["ne6"] = 483; NTIPAliasClassID["mummifiedtrophy"] = 483; +NTIPAliasClassID["ne7"] = 484; NTIPAliasClassID["fetishtrophy"] = 484; +NTIPAliasClassID["ne8"] = 485; NTIPAliasClassID["sextontrophy"] = 485; +NTIPAliasClassID["ne9"] = 486; NTIPAliasClassID["cantortrophy"] = 486; +NTIPAliasClassID["nea"] = 487; NTIPAliasClassID["hierophanttrophy"] = 487; +NTIPAliasClassID["drb"] = 488; NTIPAliasClassID["bloodspirit"] = 488; +NTIPAliasClassID["drc"] = 489; NTIPAliasClassID["sunspirit"] = 489; +NTIPAliasClassID["drd"] = 490; NTIPAliasClassID["earthspirit"] = 490; +NTIPAliasClassID["dre"] = 491; NTIPAliasClassID["skyspirit"] = 491; +NTIPAliasClassID["drf"] = 492; NTIPAliasClassID["dreamspirit"] = 492; +NTIPAliasClassID["bab"] = 493; NTIPAliasClassID["carnagehelm"] = 493; +NTIPAliasClassID["bac"] = 494; NTIPAliasClassID["furyvisor"] = 494; +NTIPAliasClassID["bad"] = 495; NTIPAliasClassID["destroyerhelm"] = 495; +NTIPAliasClassID["bae"] = 496; NTIPAliasClassID["conquerorcrown"] = 496; +NTIPAliasClassID["baf"] = 497; NTIPAliasClassID["guardiancrown"] = 497; +NTIPAliasClassID["pab"] = 498; NTIPAliasClassID["sacredtarge"] = 498; +NTIPAliasClassID["pac"] = 499; NTIPAliasClassID["sacredrondache"] = 499; +NTIPAliasClassID["pad"] = 500; NTIPAliasClassID["kurastshield"] = 500; +NTIPAliasClassID["pae"] = 501; NTIPAliasClassID["zakarumshield"] = 501; +NTIPAliasClassID["paf"] = 502; NTIPAliasClassID["vortexshield"] = 502; +NTIPAliasClassID["neb"] = 503; NTIPAliasClassID["minionskull"] = 503; +NTIPAliasClassID["neg"] = 504; NTIPAliasClassID["hellspawnskull"] = 504; +NTIPAliasClassID["ned"] = 505; NTIPAliasClassID["overseerskull"] = 505; +NTIPAliasClassID["nee"] = 506; NTIPAliasClassID["succubusskull"] = 506; +NTIPAliasClassID["nef"] = 507; NTIPAliasClassID["bloodlordskull"] = 507; +NTIPAliasClassID["elx"] = 508; NTIPAliasClassID["elixir"] = 508; +NTIPAliasClassID["hpo"] = 509; +NTIPAliasClassID["mpo"] = 510; +NTIPAliasClassID["hpf"] = 511; +NTIPAliasClassID["mpf"] = 512; +NTIPAliasClassID["vps"] = 513; NTIPAliasClassID["staminapotion"] = 513; +NTIPAliasClassID["yps"] = 514; NTIPAliasClassID["antidotepotion"] = 514; +NTIPAliasClassID["rvs"] = 515; NTIPAliasClassID["rejuvenationpotion"] = 515; +NTIPAliasClassID["rvl"] = 516; NTIPAliasClassID["fullrejuvenationpotion"] = 516; +NTIPAliasClassID["wms"] = 517; NTIPAliasClassID["thawingpotion"] = 517; +NTIPAliasClassID["tbk"] = 518; NTIPAliasClassID["tomeoftownportal"] = 518; +NTIPAliasClassID["ibk"] = 519; NTIPAliasClassID["tomeofidentify"] = 519; +NTIPAliasClassID["amu"] = 520; NTIPAliasClassID["amulet"] = 520; +NTIPAliasClassID["vip"] = 521; NTIPAliasClassID["topofthehoradricstaff"] = 521; +NTIPAliasClassID["rin"] = 522; NTIPAliasClassID["ring"] = 522; +NTIPAliasClassID["gld"] = 523; NTIPAliasClassID["gold"] = 523; +NTIPAliasClassID["bks"] = 524; NTIPAliasClassID["scrollofinifuss"] = 524; +NTIPAliasClassID["bkd"] = 525; NTIPAliasClassID["keytothecairnstones"] = 525; +NTIPAliasClassID["aqv"] = 526; NTIPAliasClassID["arrows"] = 526; +NTIPAliasClassID["tch"] = 527; NTIPAliasClassID["torch"] = 527; +NTIPAliasClassID["cqv"] = 528; NTIPAliasClassID["bolts"] = 528; +NTIPAliasClassID["tsc"] = 529; NTIPAliasClassID["scrolloftownportal"] = 529; +NTIPAliasClassID["isc"] = 530; NTIPAliasClassID["scrollofidentify"] = 530; +NTIPAliasClassID["hrt"] = 531; NTIPAliasClassID["heart"] = 531; +NTIPAliasClassID["brz"] = 532; NTIPAliasClassID["brain"] = 532; +NTIPAliasClassID["jaw"] = 533; NTIPAliasClassID["jawbone"] = 533; +NTIPAliasClassID["eyz"] = 534; NTIPAliasClassID["eye"] = 534; +NTIPAliasClassID["hrn"] = 535; NTIPAliasClassID["horn"] = 535; +NTIPAliasClassID["tal"] = 536; NTIPAliasClassID["tail"] = 536; +NTIPAliasClassID["flg"] = 537; NTIPAliasClassID["flag"] = 537; +NTIPAliasClassID["fng"] = 538; NTIPAliasClassID["fang"] = 538; +NTIPAliasClassID["qll"] = 539; NTIPAliasClassID["quill"] = 539; +NTIPAliasClassID["sol"] = 540; NTIPAliasClassID["soul"] = 540; +NTIPAliasClassID["scz"] = 541; NTIPAliasClassID["scalp"] = 541; +NTIPAliasClassID["spe"] = 542; NTIPAliasClassID["spleen"] = 542; +NTIPAliasClassID["key"] = 543; +NTIPAliasClassID["luv"] = 544; NTIPAliasClassID["theblacktowerkey"] = 544; +NTIPAliasClassID["xyz"] = 545; NTIPAliasClassID["potionoflife"] = 545; +NTIPAliasClassID["j34"] = 546; NTIPAliasClassID["ajadefigurine"] = 546; +NTIPAliasClassID["g34"] = 547; NTIPAliasClassID["thegoldenbird"] = 547; +NTIPAliasClassID["bbb"] = 548; NTIPAliasClassID["lamesen'stome"] = 548; +NTIPAliasClassID["box"] = 549; NTIPAliasClassID["horadriccube"] = 549; +NTIPAliasClassID["tr1"] = 550; NTIPAliasClassID["horadricscroll"] = 550; +NTIPAliasClassID["mss"] = 551; NTIPAliasClassID["mephisto'ssoulstone"] = 551; +NTIPAliasClassID["ass"] = 552; NTIPAliasClassID["bookofskill"] = 552; +NTIPAliasClassID["qey"] = 553; NTIPAliasClassID["khalim'seye"] = 553; +NTIPAliasClassID["qhr"] = 554; NTIPAliasClassID["khalim'sheart"] = 554; +NTIPAliasClassID["qbr"] = 555; NTIPAliasClassID["khalim'sbrain"] = 555; +NTIPAliasClassID["ear"] = 556; +NTIPAliasClassID["gcv"] = 557; NTIPAliasClassID["chippedamethyst"] = 557; +NTIPAliasClassID["gfv"] = 558; NTIPAliasClassID["flawedamethyst"] = 558; +NTIPAliasClassID["gsv"] = 559; NTIPAliasClassID["amethyst"] = 559; +NTIPAliasClassID["gzv"] = 560; NTIPAliasClassID["flawlessamethyst"] = 560; +NTIPAliasClassID["gpv"] = 561; NTIPAliasClassID["perfectamethyst"] = 561; +NTIPAliasClassID["gcy"] = 562; NTIPAliasClassID["chippedtopaz"] = 562; +NTIPAliasClassID["gfy"] = 563; NTIPAliasClassID["flawedtopaz"] = 563; +NTIPAliasClassID["gsy"] = 564; NTIPAliasClassID["topaz"] = 564; +NTIPAliasClassID["gly"] = 565; NTIPAliasClassID["flawlesstopaz"] = 565; +NTIPAliasClassID["gpy"] = 566; NTIPAliasClassID["perfecttopaz"] = 566; +NTIPAliasClassID["gcb"] = 567; NTIPAliasClassID["chippedsapphire"] = 567; +NTIPAliasClassID["gfb"] = 568; NTIPAliasClassID["flawedsapphire"] = 568; +NTIPAliasClassID["gsb"] = 569; NTIPAliasClassID["sapphire"] = 569; +NTIPAliasClassID["glb"] = 570; NTIPAliasClassID["flawlesssapphire"] = 570; +NTIPAliasClassID["gpb"] = 571; NTIPAliasClassID["perfectsapphire"] = 571; +NTIPAliasClassID["gcg"] = 572; NTIPAliasClassID["chippedemerald"] = 572; +NTIPAliasClassID["gfg"] = 573; NTIPAliasClassID["flawedemerald"] = 573; +NTIPAliasClassID["gsg"] = 574; NTIPAliasClassID["emerald"] = 574; +NTIPAliasClassID["glg"] = 575; NTIPAliasClassID["flawlessemerald"] = 575; +NTIPAliasClassID["gpg"] = 576; NTIPAliasClassID["perfectemerald"] = 576; +NTIPAliasClassID["gcr"] = 577; NTIPAliasClassID["chippedruby"] = 577; +NTIPAliasClassID["gfr"] = 578; NTIPAliasClassID["flawedruby"] = 578; +NTIPAliasClassID["gsr"] = 579; NTIPAliasClassID["ruby"] = 579; +NTIPAliasClassID["glr"] = 580; NTIPAliasClassID["flawlessruby"] = 580; +NTIPAliasClassID["gpr"] = 581; NTIPAliasClassID["perfectruby"] = 581; +NTIPAliasClassID["gcw"] = 582; NTIPAliasClassID["chippeddiamond"] = 582; +NTIPAliasClassID["gfw"] = 583; NTIPAliasClassID["flaweddiamond"] = 583; +NTIPAliasClassID["gsw"] = 584; NTIPAliasClassID["diamond"] = 584; +NTIPAliasClassID["glw"] = 585; NTIPAliasClassID["flawlessdiamond"] = 585; +NTIPAliasClassID["gpw"] = 586; NTIPAliasClassID["perfectdiamond"] = 586; +NTIPAliasClassID["hp1"] = 587; NTIPAliasClassID["minorhealingpotion"] = 587; +NTIPAliasClassID["hp2"] = 588; NTIPAliasClassID["lighthealingpotion"] = 588; +NTIPAliasClassID["hp3"] = 589; NTIPAliasClassID["healingpotion"] = 589; +NTIPAliasClassID["hp4"] = 590; NTIPAliasClassID["greaterhealingpotion"] = 590; +NTIPAliasClassID["hp5"] = 591; NTIPAliasClassID["superhealingpotion"] = 591; +NTIPAliasClassID["mp1"] = 592; NTIPAliasClassID["minormanapotion"] = 592; +NTIPAliasClassID["mp2"] = 593; NTIPAliasClassID["lightmanapotion"] = 593; +NTIPAliasClassID["mp3"] = 594; NTIPAliasClassID["manapotion"] = 594; +NTIPAliasClassID["mp4"] = 595; NTIPAliasClassID["greatermanapotion"] = 595; +NTIPAliasClassID["mp5"] = 596; NTIPAliasClassID["supermanapotion"] = 596; +NTIPAliasClassID["skc"] = 597; NTIPAliasClassID["chippedskull"] = 597; +NTIPAliasClassID["skf"] = 598; NTIPAliasClassID["flawedskull"] = 598; +NTIPAliasClassID["sku"] = 599; NTIPAliasClassID["skull"] = 599; +NTIPAliasClassID["skl"] = 600; NTIPAliasClassID["flawlessskull"] = 600; +NTIPAliasClassID["skz"] = 601; NTIPAliasClassID["perfectskull"] = 601; +NTIPAliasClassID["hrb"] = 602; NTIPAliasClassID["herb"] = 602; +NTIPAliasClassID["cm1"] = 603; NTIPAliasClassID["smallcharm"] = 603; +NTIPAliasClassID["cm2"] = 604; NTIPAliasClassID["largecharm"] = 604; +NTIPAliasClassID["cm3"] = 605; NTIPAliasClassID["grandcharm"] = 605; +NTIPAliasClassID["rps"] = 606; +NTIPAliasClassID["rpl"] = 607; +NTIPAliasClassID["bps"] = 608; +NTIPAliasClassID["bpl"] = 609; +NTIPAliasClassID["r01"] = 610; NTIPAliasClassID["elrune"] = 610; +NTIPAliasClassID["r02"] = 611; NTIPAliasClassID["eldrune"] = 611; +NTIPAliasClassID["r03"] = 612; NTIPAliasClassID["tirrune"] = 612; +NTIPAliasClassID["r04"] = 613; NTIPAliasClassID["nefrune"] = 613; +NTIPAliasClassID["r05"] = 614; NTIPAliasClassID["ethrune"] = 614; +NTIPAliasClassID["r06"] = 615; NTIPAliasClassID["ithrune"] = 615; +NTIPAliasClassID["r07"] = 616; NTIPAliasClassID["talrune"] = 616; +NTIPAliasClassID["r08"] = 617; NTIPAliasClassID["ralrune"] = 617; +NTIPAliasClassID["r09"] = 618; NTIPAliasClassID["ortrune"] = 618; +NTIPAliasClassID["r10"] = 619; NTIPAliasClassID["thulrune"] = 619; +NTIPAliasClassID["r11"] = 620; NTIPAliasClassID["amnrune"] = 620; +NTIPAliasClassID["r12"] = 621; NTIPAliasClassID["solrune"] = 621; +NTIPAliasClassID["r13"] = 622; NTIPAliasClassID["shaelrune"] = 622; +NTIPAliasClassID["r14"] = 623; NTIPAliasClassID["dolrune"] = 623; +NTIPAliasClassID["r15"] = 624; NTIPAliasClassID["helrune"] = 624; +NTIPAliasClassID["r16"] = 625; NTIPAliasClassID["iorune"] = 625; +NTIPAliasClassID["r17"] = 626; NTIPAliasClassID["lumrune"] = 626; +NTIPAliasClassID["r18"] = 627; NTIPAliasClassID["korune"] = 627; +NTIPAliasClassID["r19"] = 628; NTIPAliasClassID["falrune"] = 628; +NTIPAliasClassID["r20"] = 629; NTIPAliasClassID["lemrune"] = 629; +NTIPAliasClassID["r21"] = 630; NTIPAliasClassID["pulrune"] = 630; +NTIPAliasClassID["r22"] = 631; NTIPAliasClassID["umrune"] = 631; +NTIPAliasClassID["r23"] = 632; NTIPAliasClassID["malrune"] = 632; +NTIPAliasClassID["r24"] = 633; NTIPAliasClassID["istrune"] = 633; +NTIPAliasClassID["r25"] = 634; NTIPAliasClassID["gulrune"] = 634; +NTIPAliasClassID["r26"] = 635; NTIPAliasClassID["vexrune"] = 635; +NTIPAliasClassID["r27"] = 636; NTIPAliasClassID["ohmrune"] = 636; +NTIPAliasClassID["r28"] = 637; NTIPAliasClassID["lorune"] = 637; +NTIPAliasClassID["r29"] = 638; NTIPAliasClassID["surrune"] = 638; +NTIPAliasClassID["r30"] = 639; NTIPAliasClassID["berrune"] = 639; +NTIPAliasClassID["r31"] = 640; NTIPAliasClassID["jahrune"] = 640; +NTIPAliasClassID["r32"] = 641; NTIPAliasClassID["chamrune"] = 641; +NTIPAliasClassID["r33"] = 642; NTIPAliasClassID["zodrune"] = 642; +NTIPAliasClassID["jew"] = 643; NTIPAliasClassID["jewel"] = 643; +NTIPAliasClassID["ice"] = 644; NTIPAliasClassID["malah'spotion"] = 644; +NTIPAliasClassID["0sc"] = 645; NTIPAliasClassID["scrollofknowledge"] = 645; +NTIPAliasClassID["tr2"] = 646; NTIPAliasClassID["scrollofresistance"] = 646; +NTIPAliasClassID["pk1"] = 647; NTIPAliasClassID["keyofterror"] = 647; +NTIPAliasClassID["pk2"] = 648; NTIPAliasClassID["keyofhate"] = 648; +NTIPAliasClassID["pk3"] = 649; NTIPAliasClassID["keyofdestruction"] = 649; +NTIPAliasClassID["dhn"] = 650; NTIPAliasClassID["diablo'shorn"] = 650; +NTIPAliasClassID["bey"] = 651; NTIPAliasClassID["baal'seye"] = 651; +NTIPAliasClassID["mbr"] = 652; NTIPAliasClassID["mephisto'sbrain"] = 652; +NTIPAliasClassID["toa"] = 653; NTIPAliasClassID["tokenofabsolution"] = 653; +NTIPAliasClassID["tes"] = 654; NTIPAliasClassID["twistedessenceofsuffering"] = 654; +NTIPAliasClassID["ceh"] = 655; NTIPAliasClassID["chargedessenceofhatred"] = 655; +NTIPAliasClassID["bet"] = 656; NTIPAliasClassID["burningessenceofterror"] = 656; +NTIPAliasClassID["fed"] = 657; NTIPAliasClassID["festeringessenceofdestruction"] = 657; +NTIPAliasClassID["std"] = 658; NTIPAliasClassID["standardofheroes"] = 658; + +var NTIPAliasClass = {}; +NTIPAliasClass["normal"] = 0; +NTIPAliasClass["exceptional"] = 1; +NTIPAliasClass["elite"] = 2; + +var NTIPAliasQuality = {}; +NTIPAliasQuality["lowquality"] = 1; +NTIPAliasQuality["normal"] = 2; +NTIPAliasQuality["superior"] = 3; +NTIPAliasQuality["magic"] = 4; +NTIPAliasQuality["set"] = 5; +NTIPAliasQuality["rare"] = 6; +NTIPAliasQuality["unique"] = 7; +NTIPAliasQuality["crafted"] = 8; + +var NTIPAliasFlag = {}; +NTIPAliasFlag["identified"] = 0x10; +NTIPAliasFlag["eth"] = 0x400000; NTIPAliasFlag["ethereal"] = 0x400000; +NTIPAliasFlag["runeword"] = 0x4000000; + +// rare item colors +var NTIPAliasColor = {}; +NTIPAliasColor["black"] = 3; +NTIPAliasColor["white"] = 20; +NTIPAliasColor["orange"] = 19; +NTIPAliasColor["lightyellow"] = 13; +NTIPAliasColor["lightred"] = 7; +NTIPAliasColor["lightgold"] = 15; +NTIPAliasColor["lightblue"] = 4; +NTIPAliasColor["lightpurple"] = 17; +NTIPAliasColor["crystalblue"] = 6; +NTIPAliasColor["crystalred"] = 9; +NTIPAliasColor["crystalgreen"] = 12; +NTIPAliasColor["darkyellow"] = 14; +NTIPAliasColor["darkred"] = 8; +NTIPAliasColor["darkgold"] = 16; +NTIPAliasColor["darkgreen"] = 11; +NTIPAliasColor["darkblue"] = 5; + +var NTIPAliasStat = {}; +NTIPAliasStat["strength"] = 0; +NTIPAliasStat["energy"] = 1; +NTIPAliasStat["dexterity"] = 2; +NTIPAliasStat["vitality"] = 3; +NTIPAliasStat["statpts"] = 4; +NTIPAliasStat["newskills"] = 5; +NTIPAliasStat["hitpoints"] = 6; +NTIPAliasStat["maxhp"] = 7; +NTIPAliasStat["mana"] = 8; +NTIPAliasStat["maxmana"] = 9; +NTIPAliasStat["stamina"] = 10; +NTIPAliasStat["maxstamina"] = 11; +NTIPAliasStat["level"] = 12; +NTIPAliasStat["experience"] = 13; +NTIPAliasStat["gold"] = 14; +NTIPAliasStat["goldbank"] = 15; +NTIPAliasStat["itemarmorpercent"] = [16,0]; NTIPAliasStat["enhanceddefense"] = [16,0]; +NTIPAliasStat["itemmaxdamagepercent"] = [17,0]; +NTIPAliasStat["itemmindamagepercent"] = [18,0]; NTIPAliasStat["enhanceddamage"] = [18,0]; +NTIPAliasStat["tohit"] = 19; +NTIPAliasStat["toblock"] = 20; +NTIPAliasStat["plusmindamage"] = [21, 1]; +NTIPAliasStat["mindamage"] = 21; +NTIPAliasStat["plusmaxdamage"] = [22, 1]; +NTIPAliasStat["maxdamage"] = 22; +NTIPAliasStat["secondarymindamage"] = 23; +NTIPAliasStat["secondarymaxdamage"] = 24; +NTIPAliasStat["damagepercent"] = 25; +NTIPAliasStat["manarecovery"] = 26; +NTIPAliasStat["manarecoverybonus"] = 27; +NTIPAliasStat["staminarecoverybonus"] = 28; +NTIPAliasStat["lastexp"] = 29; +NTIPAliasStat["nextexp"] = 30; + +NTIPAliasStat["armorclass"] = 31; NTIPAliasStat["defense"] = 31; +NTIPAliasStat["plusdefense"] = [31,0]; + +NTIPAliasStat["armorclassvsmissile"] = 32; +NTIPAliasStat["armorclassvshth"] = 33; +NTIPAliasStat["normaldamagereduction"] = 34; +NTIPAliasStat["magicdamagereduction"] = 35; +NTIPAliasStat["damageresist"] = 36; +NTIPAliasStat["magicresist"] = 37; +NTIPAliasStat["maxmagicresist"] = 38; +NTIPAliasStat["fireresist"] = 39; +NTIPAliasStat["maxfireresist"] = 40; +NTIPAliasStat["lightresist"] = 41; +NTIPAliasStat["maxlightresist"] = 42; +NTIPAliasStat["coldresist"] = 43; +NTIPAliasStat["maxcoldresist"] = 44; +NTIPAliasStat["poisonresist"] = 45; +NTIPAliasStat["maxpoisonresist"] = 46; +NTIPAliasStat["damageaura"] = 47; +NTIPAliasStat["firemindam"] = 48; +NTIPAliasStat["firemaxdam"] = 49; +NTIPAliasStat["lightmindam"] = 50; +NTIPAliasStat["lightmaxdam"] = 51; +NTIPAliasStat["magicmindam"] = 52; +NTIPAliasStat["magicmaxdam"] = 53; +NTIPAliasStat["coldmindam"] = 54; +NTIPAliasStat["coldmaxdam"] = 55; +NTIPAliasStat["coldlength"] = 56; +NTIPAliasStat["poisondamage"] = [57, 1]; +NTIPAliasStat["poisonmindam"] = 57; +NTIPAliasStat["poisonmaxdam"] = 58; +NTIPAliasStat["poisonlength"] = 59; +NTIPAliasStat["lifedrainmindam"] = 60; NTIPAliasStat["lifeleech"] = 60; +NTIPAliasStat["lifedrainmaxdam"] = 61; +NTIPAliasStat["manadrainmindam"] = 62; NTIPAliasStat["manaleech"] = 62; +NTIPAliasStat["manadrainmaxdam"] = 63; +NTIPAliasStat["stamdrainmindam"] = 64; +NTIPAliasStat["stamdrainmaxdam"] = 65; +NTIPAliasStat["stunlength"] = 66; +NTIPAliasStat["velocitypercent"] = 67; +NTIPAliasStat["attackrate"] = 68; +NTIPAliasStat["otheranimrate"] = 69; +NTIPAliasStat["quantity"] = 70; +NTIPAliasStat["value"] = 71; +NTIPAliasStat["durability"] = 72; +NTIPAliasStat["maxdurability"] = 73; +NTIPAliasStat["hpregen"] = 74; +NTIPAliasStat["itemmaxdurabilitypercent"] = 75; +NTIPAliasStat["itemmaxhppercent"] = 76; +NTIPAliasStat["itemmaxmanapercent"] = 77; +NTIPAliasStat["itemattackertakesdamage"] = 78; +NTIPAliasStat["itemgoldbonus"] = 79; +NTIPAliasStat["itemmagicbonus"] = 80; +NTIPAliasStat["itemknockback"] = 81; +NTIPAliasStat["itemtimeduration"] = 82; + +NTIPAliasStat["itemaddclassskills"] = 83; +NTIPAliasStat["itemaddamazonskills"] = [83,0]; NTIPAliasStat["amazonskills"] = [83,0]; +NTIPAliasStat["itemaddsorceressskills"] = [83,1]; NTIPAliasStat["sorceressskills"] = [83,1]; +NTIPAliasStat["itemaddnecromancerskills"] = [83,2]; NTIPAliasStat["necromancerskills"] = [83,2]; +NTIPAliasStat["itemaddpaladinskills"] = [83,3]; NTIPAliasStat["paladinskills"] = [83,3]; +NTIPAliasStat["itemaddbarbarianskills"] = [83,4]; NTIPAliasStat["barbarianskills"] = [83,4]; +NTIPAliasStat["itemadddruidskills"] = [83,5]; NTIPAliasStat["druidskills"] = [83,5]; +NTIPAliasStat["itemaddassassinskills"] = [83,6]; NTIPAliasStat["assassinskills"] = [83,6]; + +NTIPAliasStat["unsentparam1"] = 84; +NTIPAliasStat["itemaddexperience"] = 85; +NTIPAliasStat["itemhealafterkill"] = 86; +NTIPAliasStat["itemreducedprices"] = 87; +NTIPAliasStat["itemdoubleherbduration"] = 88; +NTIPAliasStat["itemlightradius"] = 89; +NTIPAliasStat["itemlightcolor"] = 90; +NTIPAliasStat["itemreqpercent"] = 91; +NTIPAliasStat["itemlevelreq"] = 92; +NTIPAliasStat["itemfasterattackrate"] = 93; NTIPAliasStat["ias"] = 93; +NTIPAliasStat["itemlevelreqpct"] = 94; +NTIPAliasStat["lastblockframe"] = 95; +NTIPAliasStat["itemfastermovevelocity"] = 96; NTIPAliasStat["frw"] = 96; + +// oskill +NTIPAliasStat["itemnonclassskill"] = 97; +// Amazon +NTIPAliasStat["plusskillcriticalstrike"] = [97,9]; +NTIPAliasStat["plusskillguidedarrow"] = [97,22]; +// Sorceress +NTIPAliasStat["plusskillteleport"] = [97,54]; +// Barbarian +NTIPAliasStat["plusskillbattleorders"] = [97,149]; +NTIPAliasStat["plusskillbattlecommand"] = [97,155]; +NTIPAliasStat["plusskillbattlecry"] = [97,146]; +// Druid +NTIPAliasStat["plusskillwerewolf"] = [97,223]; +NTIPAliasStat["plusskillshapeshifting"] = [97,224]; NTIPAliasStat["plusskilllycanthropy"] = [97,224]; +NTIPAliasStat["plusskillsummonspiritwolf"] = [97,227]; +NTIPAliasStat["plusskillferalrage"] = [97,232]; + +NTIPAliasStat["state"] = 98; +NTIPAliasStat["itemfastergethitrate"] = 99; NTIPAliasStat["fhr"] = 99; +NTIPAliasStat["monsterplayercount"] = 100; +NTIPAliasStat["skillpoisonoverridelength"] = 101; +NTIPAliasStat["itemfasterblockrate"] = 102; NTIPAliasStat["fbr"] = 102; +NTIPAliasStat["skillbypassundead"] = 103; +NTIPAliasStat["skillbypassdemons"] = 104; +NTIPAliasStat["itemfastercastrate"] = 105; NTIPAliasStat["fcr"] = 105; +NTIPAliasStat["skillbypassbeasts"] = 106; + +NTIPAliasStat["itemsingleskill"] = 107; +// Amazon skills +NTIPAliasStat["skillmagicarrow"] = [107,6]; +NTIPAliasStat["skillfirearrow"] = [107,7]; +NTIPAliasStat["skillinnersight"] = [107,8]; +NTIPAliasStat["skillcriticalstrike"] = [107,9]; +NTIPAliasStat["skilljab"] = [107,10]; +NTIPAliasStat["skillcoldarrow"] = [107,11]; +NTIPAliasStat["skillmultipleshot"] = [107,12]; +NTIPAliasStat["skilldodge"] = [107,13]; +NTIPAliasStat["skillpowerstrike"] = [107,14]; +NTIPAliasStat["skillpoisonjavelin"] = [107,15]; +NTIPAliasStat["skillexplodingarrow"] = [107,16]; +NTIPAliasStat["skillslowmissiles"] = [107,17]; +NTIPAliasStat["skillavoid"] = [107,18]; +NTIPAliasStat["skillimpale"] = [107,19]; +NTIPAliasStat["skilllightningbolt"] = [107,20]; +NTIPAliasStat["skillicearrow"] = [107,21]; +NTIPAliasStat["skillguidedarrow"] = [107,22]; +NTIPAliasStat["skillpenetrate"] = [107,23]; +NTIPAliasStat["skillchargedstrike"] = [107,24]; +NTIPAliasStat["skillplaguejavelin"] = [107,25]; +NTIPAliasStat["skillstrafe"] = [107,26]; +NTIPAliasStat["skillimmolationarrow"] = [107,27]; +NTIPAliasStat["skilldecoy"] = [107,28]; +NTIPAliasStat["skillevade"] = [107,29]; +NTIPAliasStat["skillfend"] = [107,30]; +NTIPAliasStat["skillfreezingarrow"] = [107,31]; +NTIPAliasStat["skillvalkyrie"] = [107,32]; +NTIPAliasStat["skillpierce"] = [107,33]; +NTIPAliasStat["skilllightningstrike"] = [107,34]; +NTIPAliasStat["skilllightningfury"] = [107,35]; +// Sorceress skills +NTIPAliasStat["skillfirebolt"] = [107,36]; +NTIPAliasStat["skillwarmth"] = [107,37]; +NTIPAliasStat["skillchargedbolt"] = [107,38]; +NTIPAliasStat["skillicebolt"] = [107,39]; +NTIPAliasStat["skillfrozenarmor"] = [107,40]; +NTIPAliasStat["skillinferno"] = [107,41]; +NTIPAliasStat["skillstaticfield"] = [107,42]; +NTIPAliasStat["skilltelekinesis"] = [107,43]; +NTIPAliasStat["skillfrostnova"] = [107,44]; +NTIPAliasStat["skilliceblast"] = [107,45]; +NTIPAliasStat["skillblaze"] = [107,46]; +NTIPAliasStat["skillfireball"] = [107,47]; +NTIPAliasStat["skillnova"] = [107,48]; +NTIPAliasStat["skilllightning"] = [107,49]; +NTIPAliasStat["skillshiverarmor"] = [107,50]; +NTIPAliasStat["skillfirewall"] = [107,51]; +NTIPAliasStat["skillenchant"] = [107,52]; +NTIPAliasStat["skillchainlightning"] = [107,53]; +NTIPAliasStat["skillteleport"] = [107,54]; +NTIPAliasStat["skillglacialspike"] = [107,55]; +NTIPAliasStat["skillmeteor"] = [107,56]; +NTIPAliasStat["skillthunderstorm"] = [107,57]; +NTIPAliasStat["skillenergyshield"] = [107,58]; +NTIPAliasStat["skillblizzard"] = [107,59]; +NTIPAliasStat["skillchillingarmor"] = [107,60]; +NTIPAliasStat["skillfiremastery"] = [107,61]; +NTIPAliasStat["skillhydra"] = [107,62]; +NTIPAliasStat["skilllightningmastery"] = [107,63]; +NTIPAliasStat["skillfrozenorb"] = [107,64]; +NTIPAliasStat["skillcoldmastery"] = [107,65]; +// Necromancer skills +NTIPAliasStat["skillamplifydamage"] = [107,66]; +NTIPAliasStat["skillteeth"] = [107,67]; +NTIPAliasStat["skillbonearmor"] = [107,68]; +NTIPAliasStat["skillskeletonmastery"] = [107,69]; +NTIPAliasStat["skillraiseskeleton"] = [107,70]; +NTIPAliasStat["skilldimvision"] = [107,71]; +NTIPAliasStat["skillweaken"] = [107,72]; +NTIPAliasStat["skillpoisondagger"] = [107,73]; +NTIPAliasStat["skillcorpseexplosion"] = [107,74]; +NTIPAliasStat["skillclaygolem"] = [107,75]; +NTIPAliasStat["skillironmaiden"] = [107,76]; +NTIPAliasStat["skillterror"] = [107,77]; +NTIPAliasStat["skillbonewall"] = [107,78]; +NTIPAliasStat["skillgolemmastery"] = [107,79]; +NTIPAliasStat["skillskeletalmage"] = [107,80]; +NTIPAliasStat["skillconfuse"] = [107,81]; +NTIPAliasStat["skilllifetap"] = [107,82]; +NTIPAliasStat["skillpoisonexplosion"] = [107,83]; +NTIPAliasStat["skillbonespear"] = [107,84]; +NTIPAliasStat["skillbloodgolem"] = [107,85]; +NTIPAliasStat["skillattract"] = [107,86]; +NTIPAliasStat["skilldecrepify"] = [107,87]; +NTIPAliasStat["skillboneprison"] = [107,88]; +NTIPAliasStat["skillsummonresist"] = [107,89]; +NTIPAliasStat["skillirongolem"] = [107,90]; +NTIPAliasStat["skilllowerresist"] = [107,91]; +NTIPAliasStat["skillpoisonnova"] = [107,92]; +NTIPAliasStat["skillbonespirit"] = [107,93]; +NTIPAliasStat["skillfiregolem"] = [107,94]; +NTIPAliasStat["skillrevive"] = [107,95]; +// Paladin skills +NTIPAliasStat["skillsacrifice"] = [107,96]; +NTIPAliasStat["skillsmite"] = [107,97]; +NTIPAliasStat["skillmight"] = [107,98]; +NTIPAliasStat["skillprayer"] = [107,99]; +NTIPAliasStat["skillresistfire"] = [107,100]; +NTIPAliasStat["skillholybolt"] = [107,101]; +NTIPAliasStat["skillholyfire"] = [107,102]; +NTIPAliasStat["skillthorns"] = [107,103]; +NTIPAliasStat["skilldefiance"] = [107,104]; +NTIPAliasStat["skillresistcold"] = [107,105]; +NTIPAliasStat["skillzeal"] = [107,106]; +NTIPAliasStat["skillcharge"] = [107,107]; +NTIPAliasStat["skillblessedaim"] = [107,108]; +NTIPAliasStat["skillcleansing"] = [107,109]; +NTIPAliasStat["skillresistlightning"] = [107,110]; +NTIPAliasStat["skillvengeance"] = [107,111]; +NTIPAliasStat["skillblessedhammer"] = [107,112]; +NTIPAliasStat["skillconcentration"] = [107,113]; +NTIPAliasStat["skillholyfreeze"] = [107,114]; +NTIPAliasStat["skillvigor"] = [107,115]; +NTIPAliasStat["skillconversion"] = [107,116]; +NTIPAliasStat["skillholyshield"] = [107,117]; +NTIPAliasStat["skillholyshock"] = [107,118]; +NTIPAliasStat["skillsanctuary"] = [107,119]; +NTIPAliasStat["skillmeditation"] = [107,120]; +NTIPAliasStat["skillfistoftheheavens"] = [107,121]; +NTIPAliasStat["skillfanaticism"] = [107,122]; +NTIPAliasStat["skillconviction"] = [107,123]; +NTIPAliasStat["skillredemption"] = [107,124]; +NTIPAliasStat["skillsalvation"] = [107,125]; +// Barbarian skills +NTIPAliasStat["skillbash"] = [107,126]; +NTIPAliasStat["skillswordmastery"] = [107,127]; +NTIPAliasStat["skillaxemastery"] = [107,128]; +NTIPAliasStat["skillmacemastery"] = [107,129]; +NTIPAliasStat["skillhowl"] = [107,130]; +NTIPAliasStat["skillfindpotion"] = [107,131]; +NTIPAliasStat["skillleap"] = [107,132]; +NTIPAliasStat["skilldoubleswing"] = [107,133]; +NTIPAliasStat["skillpolearmmastery"] = [107,134]; +NTIPAliasStat["skillthrowingmastery"] = [107,135]; +NTIPAliasStat["skillspearmastery"] = [107,136]; +NTIPAliasStat["skilltaunt"] = [107,137]; +NTIPAliasStat["skillshout"] = [107,138]; +NTIPAliasStat["skillstun"] = [107,139]; +NTIPAliasStat["skilldoublethrow"] = [107,140]; +NTIPAliasStat["skillincreasedstamina"] = [107,141]; +NTIPAliasStat["skillfinditem"] = [107,142]; +NTIPAliasStat["skillleapattack"] = [107,143]; +NTIPAliasStat["skillconcentrate"] = [107,144]; +NTIPAliasStat["skillironskin"] = [107,145]; +NTIPAliasStat["skillbattlecry"] = [107,146]; +NTIPAliasStat["skillfrenzy"] = [107,147]; +NTIPAliasStat["skillincreasedspeed"] = [107,148]; +NTIPAliasStat["skillbattleorders"] = [107,149]; +NTIPAliasStat["skillgrimward"] = [107,150]; +NTIPAliasStat["skillwhirlwind"] = [107,151]; +NTIPAliasStat["skillberserk"] = [107,152]; +NTIPAliasStat["skillnaturalresistance"] = [107,153]; +NTIPAliasStat["skillwarcry"] = [107,154]; +NTIPAliasStat["skillbattlecommand"] = [107,155]; +// Druid skills +NTIPAliasStat["skillraven"] = [107,221]; +NTIPAliasStat["skillpoisoncreeper"] = [107,222]; +NTIPAliasStat["skillwerewolf"] = [107,223]; +NTIPAliasStat["skilllycanthropy"] = [107,224]; +NTIPAliasStat["skillfirestorm"] = [107,225]; +NTIPAliasStat["skilloaksage"] = [107,226]; +NTIPAliasStat["skillsummonspiritwolf"] = [107,227]; +NTIPAliasStat["skillwerebear"] = [107,228]; +NTIPAliasStat["skillmoltenboulder"] = [107,229]; +NTIPAliasStat["skillarcticblast"] = [107,230]; +NTIPAliasStat["skillcarrionvine"] = [107,231]; +NTIPAliasStat["skillferalrage"] = [107,232]; +NTIPAliasStat["skillmaul"] = [107,233]; +NTIPAliasStat["skillfissure"] = [107,234]; +NTIPAliasStat["skillcyclonearmor"] = [107,235]; +NTIPAliasStat["skillheartofwolverine"] = [107,236]; +NTIPAliasStat["skillsummondirewolf"] = [107,237]; +NTIPAliasStat["skillrabies"] = [107,238]; +NTIPAliasStat["skillfireclaws"] = [107,239]; +NTIPAliasStat["skilltwister"] = [107,240]; +NTIPAliasStat["skillsolarcreeper"] = [107,241]; +NTIPAliasStat["skillhunger"] = [107,242]; +NTIPAliasStat["skillshockwave"] = [107,243]; +NTIPAliasStat["skillvolcano"] = [107,244]; +NTIPAliasStat["skilltornado"] = [107,245]; +NTIPAliasStat["skillspiritofbarbs"] = [107,246]; +NTIPAliasStat["skillsummongrizzly"] = [107,247]; +NTIPAliasStat["skillfury"] = [107,248]; +NTIPAliasStat["skillarmageddon"] = [107,249]; +NTIPAliasStat["skillhurricane"] = [107,250]; +// Assassin skills +NTIPAliasStat["skillfireblast"] = [107,251]; +NTIPAliasStat["skillclawmastery"] = [107,252]; +NTIPAliasStat["skillpsychichammer"] = [107,253]; +NTIPAliasStat["skilltigerstrike"] = [107,254]; +NTIPAliasStat["skilldragontalon"] = [107,255]; +NTIPAliasStat["skillshockweb"] = [107,256]; +NTIPAliasStat["skillbladesentinel"] = [107,257]; +NTIPAliasStat["skillburstofspeed"] = [107,258]; +NTIPAliasStat["skillfistsoffire"] = [107,259]; +NTIPAliasStat["skilldragonclaw"] = [107,260]; +NTIPAliasStat["skillchargedboltsentry"] = [107,261]; +NTIPAliasStat["skillwakeoffire"] = [107,262]; +NTIPAliasStat["skillweaponblock"] = [107,263]; +NTIPAliasStat["skillcloakofshadows"] = [107,264]; +NTIPAliasStat["skillcobrastrike"] = [107,265]; +NTIPAliasStat["skillbladefury"] = [107,266]; +NTIPAliasStat["skillfade"] = [107,267]; +NTIPAliasStat["skillshadowwarrior"] = [107,268]; +NTIPAliasStat["skillclawsofthunder"] = [107,269]; +NTIPAliasStat["skilldragontail"] = [107,270]; +NTIPAliasStat["skilllightningsentry"] = [107,271]; +NTIPAliasStat["skillwakeofinferno"] = [107,272]; +NTIPAliasStat["skillmindblast"] = [107,273]; +NTIPAliasStat["skillbladesofice"] = [107,274]; +NTIPAliasStat["skilldragonflight"] = [107,275]; +NTIPAliasStat["skilldeathsentry"] = [107,276]; +NTIPAliasStat["skillbladeshield"] = [107,277]; +NTIPAliasStat["skillvenom"] = [107,278]; +NTIPAliasStat["skillshadowmaster"] = [107,279]; +NTIPAliasStat["skillphoenixstrike"] = [107,280]; + +NTIPAliasStat["itemrestinpeace"] = 108; +NTIPAliasStat["curseresistance"] = 109; +NTIPAliasStat["itempoisonlengthresist"] = 110; +NTIPAliasStat["itemnormaldamage"] = 111; +NTIPAliasStat["itemhowl"] = 112; +NTIPAliasStat["itemstupidity"] = 113; +NTIPAliasStat["itemdamagetomana"] = 114; +NTIPAliasStat["itemignoretargetac"] = 115; +NTIPAliasStat["itemfractionaltargetac"] = 116; +NTIPAliasStat["itempreventheal"] = 117; +NTIPAliasStat["itemhalffreezeduration"] = 118; +NTIPAliasStat["itemtohitpercent"] = 119; +NTIPAliasStat["itemdamagetargetac"] = 120; +NTIPAliasStat["itemdemondamagepercent"] = 121; +NTIPAliasStat["itemundeaddamagepercent"] = 122; +NTIPAliasStat["itemdemontohit"] = 123; +NTIPAliasStat["itemundeadtohit"] = 124; +NTIPAliasStat["itemthrowable"] = 125; +NTIPAliasStat["itemelemskill"] = 126; +NTIPAliasStat["itemallskills"] = 127; +NTIPAliasStat["itemattackertakeslightdamage"] = 128; +NTIPAliasStat["ironmaidenlevel"] = 129; +NTIPAliasStat["lifetaplevel"] = 130; +NTIPAliasStat["thornspercent"] = 131; +NTIPAliasStat["bonearmor"] = 132; +NTIPAliasStat["bonearmormax"] = 133; +NTIPAliasStat["itemfreeze"] = 134; +NTIPAliasStat["itemopenwounds"] = 135; +NTIPAliasStat["itemcrushingblow"] = 136; +NTIPAliasStat["itemkickdamage"] = 137; +NTIPAliasStat["itemmanaafterkill"] = 138; +NTIPAliasStat["itemhealafterdemonkill"] = 139; +NTIPAliasStat["itemextrablood"] = 140; +NTIPAliasStat["itemdeadlystrike"] = 141; +NTIPAliasStat["itemabsorbfirepercent"] = 142; +NTIPAliasStat["itemabsorbfire"] = 143; +NTIPAliasStat["itemabsorblightpercent"] = 144; +NTIPAliasStat["itemabsorblight"] = 145; +NTIPAliasStat["itemabsorbmagicpercent"] = 146; +NTIPAliasStat["itemabsorbmagic"] = 147; +NTIPAliasStat["itemabsorbcoldpercent"] = 148; +NTIPAliasStat["itemabsorbcold"] = 149; +NTIPAliasStat["itemslow"] = 150; + +NTIPAliasStat["itemaura"] = 151; +NTIPAliasStat["mightaura"] = [151,98]; +NTIPAliasStat["holyfireaura"] = [151,102]; +NTIPAliasStat["thornsaura"] = [151,103]; +NTIPAliasStat["defianceaura"] = [151,104]; +NTIPAliasStat["concentrationaura"] = [151,113]; +NTIPAliasStat["holyfreezeaura"] = [151,114]; +NTIPAliasStat["vigoraura"] = [151,115]; +NTIPAliasStat["holyshockaura"] = [151,118]; +NTIPAliasStat["sanctuaryaura"] = [151,119]; +NTIPAliasStat["meditationaura"] = [151,120]; +NTIPAliasStat["fanaticismaura"] = [151,122]; +NTIPAliasStat["convictionaura"] = [151,123]; +NTIPAliasStat["redemptionaura"] = [151,124]; + +NTIPAliasStat["itemindestructible"] = 152; +NTIPAliasStat["itemcannotbefrozen"] = 153; +NTIPAliasStat["itemstaminadrainpct"] = 154; +NTIPAliasStat["itemreanimate"] = 155; +NTIPAliasStat["itempierce"] = 156; +NTIPAliasStat["itemmagicarrow"] = 157; +NTIPAliasStat["itemexplosivearrow"] = 158; +NTIPAliasStat["itemthrowmindamage"] = 159; +NTIPAliasStat["itemthrowmaxdamage"] = 160; +NTIPAliasStat["itemskillhandofathena"] = 161; +NTIPAliasStat["itemskillstaminapercent"] = 162; +NTIPAliasStat["itemskillpassivestaminapercent"] = 163; +NTIPAliasStat["itemskillconcentration"] = 164; +NTIPAliasStat["itemskillenchant"] = 165; +NTIPAliasStat["itemskillpierce"] = 166; +NTIPAliasStat["itemskillconviction"] = 167; +NTIPAliasStat["itemskillchillingarmor"] = 168; +NTIPAliasStat["itemskillfrenzy"] = 169; +NTIPAliasStat["itemskilldecrepify"] = 170; +NTIPAliasStat["itemskillarmorpercent"] = 171; +NTIPAliasStat["alignment"] = 172; +NTIPAliasStat["target0"] = 173; +NTIPAliasStat["target1"] = 174; +NTIPAliasStat["goldlost"] = 175; +NTIPAliasStat["conversionlevel"] = 176; +NTIPAliasStat["conversionmaxhp"] = 177; +NTIPAliasStat["unitdooverlay"] = 178; +NTIPAliasStat["attackvsmontype"] = 179; +NTIPAliasStat["damagevsmontype"] = 180; +NTIPAliasStat["fade"] = 181; +NTIPAliasStat["armoroverridepercent"] = 182; +NTIPAliasStat["unused183"] = 183; +NTIPAliasStat["unused184"] = 184; +NTIPAliasStat["unused185"] = 185; +NTIPAliasStat["unused186"] = 186; +NTIPAliasStat["unused187"] = 187; + +NTIPAliasStat["itemaddskilltab"] = 188; +NTIPAliasStat["itemaddbowandcrossbowskilltab"] = [188,0]; NTIPAliasStat["bowandcrossbowskilltab"] = [188,0]; +NTIPAliasStat["itemaddpassiveandmagicskilltab"] = [188,1]; NTIPAliasStat["passiveandmagicskilltab"] = [188,1]; +NTIPAliasStat["itemaddjavelinandspearskilltab"] = [188,2]; NTIPAliasStat["javelinandspearskilltab"] = [188,2]; +NTIPAliasStat["itemaddfireskilltab"] = [188,8]; NTIPAliasStat["fireskilltab"] = [188,8]; +NTIPAliasStat["itemaddlightningskilltab"] = [188,9]; NTIPAliasStat["lightningskilltab"] = [188,9]; +NTIPAliasStat["itemaddcoldskilltab"] = [188,10]; NTIPAliasStat["coldskilltab"] = [188,10]; +NTIPAliasStat["itemaddcursesskilltab"] = [188,16]; NTIPAliasStat["cursesskilltab"] = [188,16]; +NTIPAliasStat["itemaddpoisonandboneskilltab"] = [188,17]; NTIPAliasStat["poisonandboneskilltab"] = [188,17]; +NTIPAliasStat["itemaddnecromancersummoningskilltab"] = [188,18]; NTIPAliasStat["necromancersummoningskilltab"] = [188,18]; +NTIPAliasStat["itemaddpalicombatskilltab"] = [188,24]; NTIPAliasStat["palicombatskilltab"] = [188,24]; +NTIPAliasStat["itemaddoffensiveaurasskilltab"] = [188,25]; NTIPAliasStat["offensiveaurasskilltab"] = [188,25]; +NTIPAliasStat["itemadddefensiveaurasskilltab"] = [188,26]; NTIPAliasStat["defensiveaurasskilltab"] = [188,26]; +NTIPAliasStat["itemaddbarbcombatskilltab"] = [188,32]; NTIPAliasStat["barbcombatskilltab"] = [188,32]; +NTIPAliasStat["itemaddmasteriesskilltab"] = [188,33]; NTIPAliasStat["masteriesskilltab"] = [188,33]; +NTIPAliasStat["itemaddwarcriesskilltab"] = [188,34]; NTIPAliasStat["warcriesskilltab"] = [188,34]; +NTIPAliasStat["itemadddruidsummoningskilltab"] = [188,40]; NTIPAliasStat["druidsummoningskilltab"] = [188,40]; +NTIPAliasStat["itemaddshapeshiftingskilltab"] = [188,41]; NTIPAliasStat["shapeshiftingskilltab"] = [188,41]; +NTIPAliasStat["itemaddelementalskilltab"] = [188,42]; NTIPAliasStat["elementalskilltab"] = [188,42]; +NTIPAliasStat["itemaddtrapsskilltab"] = [188,48]; NTIPAliasStat["trapsskilltab"] = [188,48]; +NTIPAliasStat["itemaddshadowdisciplinesskilltab"] = [188,49]; NTIPAliasStat["shadowdisciplinesskilltab"] = [188,49]; +NTIPAliasStat["itemaddmartialartsskilltab"] = [188,50]; NTIPAliasStat["martialartsskilltab"] = [188,50]; + +NTIPAliasStat["unused189"] = 189; +NTIPAliasStat["unused190"] = 190; +NTIPAliasStat["unused191"] = 191; +NTIPAliasStat["unused192"] = 192; +NTIPAliasStat["unused193"] = 193; +NTIPAliasStat["itemnumsockets"] = 194; NTIPAliasStat["sockets"] = 194; +NTIPAliasStat["itemskillonattack"] = [195, 1]; +NTIPAliasStat["itemskillonattacklevel"] = [195, 2]; +NTIPAliasStat["itemskillonkill"] = [196, 1]; +NTIPAliasStat["itemskillonkilllevel"] = [196, 2]; +NTIPAliasStat["itemskillondeath"] = [197, 1]; +NTIPAliasStat["itemskillondeathlevel"] = [197, 2]; + +NTIPAliasStat["itemskillonhit"] = [198, 1]; +NTIPAliasStat["itemskillonhitlevel"] = [198, 2]; +NTIPAliasStat["amplifydamageonhit"] = [198,4225]; + +NTIPAliasStat["itemskillonlevelup"] = [199, 1]; +NTIPAliasStat["itemskillonleveluplevel"] = [199, 2]; +NTIPAliasStat["unused200"] = 200; +NTIPAliasStat["itemskillongethit"] = [201, 1]; +NTIPAliasStat["itemskillongethitlevel"] = [201, 2]; +NTIPAliasStat["unused202"] = 202; +NTIPAliasStat["unused203"] = 203; + +NTIPAliasStat["itemchargedskill"] = [204, 1]; +NTIPAliasStat["itemchargedskilllevel"] = [204, 2]; +NTIPAliasStat["teleportcharges"] = [204,3461]; + +NTIPAliasStat["unused204"] = 205; +NTIPAliasStat["unused205"] = 206; +NTIPAliasStat["unused206"] = 207; +NTIPAliasStat["unused207"] = 208; +NTIPAliasStat["unused208"] = 209; +NTIPAliasStat["unused209"] = 210; +NTIPAliasStat["unused210"] = 211; +NTIPAliasStat["unused211"] = 212; +NTIPAliasStat["unused212"] = 213; +NTIPAliasStat["itemarmorperlevel"] = 214; +NTIPAliasStat["itemarmorpercentperlevel"] = 215; +NTIPAliasStat["itemhpperlevel"] = 216; +NTIPAliasStat["itemmanaperlevel"] = 217; +NTIPAliasStat["itemmaxdamageperlevel"] = 218; +NTIPAliasStat["itemmaxdamagepercentperlevel"] = 219; +NTIPAliasStat["itemstrengthperlevel"] = 220; +NTIPAliasStat["itemdexterityperlevel"] = 221; +NTIPAliasStat["itemenergyperlevel"] = 222; +NTIPAliasStat["itemvitalityperlevel"] = 223; +NTIPAliasStat["itemtohitperlevel"] = 224; +NTIPAliasStat["itemtohitpercentperlevel"] = 225; +NTIPAliasStat["itemcolddamagemaxperlevel"] = 226; +NTIPAliasStat["itemfiredamagemaxperlevel"] = 227; +NTIPAliasStat["itemltngdamagemaxperlevel"] = 228; +NTIPAliasStat["itempoisdamagemaxperlevel"] = 229; +NTIPAliasStat["itemresistcoldperlevel"] = 230; +NTIPAliasStat["itemresistfireperlevel"] = 231; +NTIPAliasStat["itemresistltngperlevel"] = 232; +NTIPAliasStat["itemresistpoisperlevel"] = 233; +NTIPAliasStat["itemabsorbcoldperlevel"] = 234; +NTIPAliasStat["itemabsorbfireperlevel"] = 235; +NTIPAliasStat["itemabsorbltngperlevel"] = 236; +NTIPAliasStat["itemabsorbpoisperlevel"] = 237; +NTIPAliasStat["itemthornsperlevel"] = 238; +NTIPAliasStat["itemfindgoldperlevel"] = 239; +NTIPAliasStat["itemfindmagicperlevel"] = 240; +NTIPAliasStat["itemregenstaminaperlevel"] = 241; +NTIPAliasStat["itemstaminaperlevel"] = 242; +NTIPAliasStat["itemdamagedemonperlevel"] = 243; +NTIPAliasStat["itemdamageundeadperlevel"] = 244; +NTIPAliasStat["itemtohitdemonperlevel"] = 245; +NTIPAliasStat["itemtohitundeadperlevel"] = 246; +NTIPAliasStat["itemcrushingblowperlevel"] = 247; +NTIPAliasStat["itemopenwoundsperlevel"] = 248; +NTIPAliasStat["itemkickdamageperlevel"] = 249; +NTIPAliasStat["itemdeadlystrikeperlevel"] = 250; +NTIPAliasStat["itemfindgemsperlevel"] = 251; +NTIPAliasStat["itemreplenishdurability"] = 252; +NTIPAliasStat["itemreplenishquantity"] = 253; +NTIPAliasStat["itemextrastack"] = 254; +NTIPAliasStat["itemfinditem"] = 255; +NTIPAliasStat["itemslashdamage"] = 256; +NTIPAliasStat["itemslashdamagepercent"] = 257; +NTIPAliasStat["itemcrushdamage"] = 258; +NTIPAliasStat["itemcrushdamagepercent"] = 259; +NTIPAliasStat["itemthrustdamage"] = 260; +NTIPAliasStat["itemthrustdamagepercent"] = 261; +NTIPAliasStat["itemabsorbslash"] = 262; +NTIPAliasStat["itemabsorbcrush"] = 263; +NTIPAliasStat["itemabsorbthrust"] = 264; +NTIPAliasStat["itemabsorbslashpercent"] = 265; +NTIPAliasStat["itemabsorbcrushpercent"] = 266; +NTIPAliasStat["itemabsorbthrustpercent"] = 267; +NTIPAliasStat["itemarmorbytime"] = 268; +NTIPAliasStat["itemarmorpercentbytime"] = 269; +NTIPAliasStat["itemhpbytime"] = 270; +NTIPAliasStat["itemmanabytime"] = 271; +NTIPAliasStat["itemmaxdamagebytime"] = 272; +NTIPAliasStat["itemmaxdamagepercentbytime"] = 273; +NTIPAliasStat["itemstrengthbytime"] = 274; +NTIPAliasStat["itemdexteritybytime"] = 275; +NTIPAliasStat["itemenergybytime"] = 276; +NTIPAliasStat["itemvitalitybytime"] = 277; +NTIPAliasStat["itemtohitbytime"] = 278; +NTIPAliasStat["itemtohitpercentbytime"] = 279; +NTIPAliasStat["itemcolddamagemaxbytime"] = 280; +NTIPAliasStat["itemfiredamagemaxbytime"] = 281; +NTIPAliasStat["itemltngdamagemaxbytime"] = 282; +NTIPAliasStat["itempoisdamagemaxbytime"] = 283; +NTIPAliasStat["itemresistcoldbytime"] = 284; +NTIPAliasStat["itemresistfirebytime"] = 285; +NTIPAliasStat["itemresistltngbytime"] = 286; +NTIPAliasStat["itemresistpoisbytime"] = 287; +NTIPAliasStat["itemabsorbcoldbytime"] = 288; +NTIPAliasStat["itemabsorbfirebytime"] = 289; +NTIPAliasStat["itemabsorbltngbytime"] = 290; +NTIPAliasStat["itemabsorbpoisbytime"] = 291; +NTIPAliasStat["itemfindgoldbytime"] = 292; +NTIPAliasStat["itemfindmagicbytime"] = 293; +NTIPAliasStat["itemregenstaminabytime"] = 294; +NTIPAliasStat["itemstaminabytime"] = 295; +NTIPAliasStat["itemdamagedemonbytime"] = 296; +NTIPAliasStat["itemdamageundeadbytime"] = 297; +NTIPAliasStat["itemtohitdemonbytime"] = 298; +NTIPAliasStat["itemtohitundeadbytime"] = 299; +NTIPAliasStat["itemcrushingblowbytime"] = 300; +NTIPAliasStat["itemopenwoundsbytime"] = 301; +NTIPAliasStat["itemkickdamagebytime"] = 302; +NTIPAliasStat["itemdeadlystrikebytime"] = 303; +NTIPAliasStat["itemfindgemsbytime"] = 304; +NTIPAliasStat["itempiercecold"] = 305; +NTIPAliasStat["itempiercefire"] = 306; +NTIPAliasStat["itempierceltng"] = 307; +NTIPAliasStat["itempiercepois"] = 308; +NTIPAliasStat["itemdamagevsmonster"] = 309; +NTIPAliasStat["itemdamagepercentvsmonster"] = 310; +NTIPAliasStat["itemtohitvsmonster"] = 311; +NTIPAliasStat["itemtohitpercentvsmonster"] = 312; +NTIPAliasStat["itemacvsmonster"] = 313; +NTIPAliasStat["itemacpercentvsmonster"] = 314; +NTIPAliasStat["firelength"] = 315; +NTIPAliasStat["burningmin"] = 316; +NTIPAliasStat["burningmax"] = 317; +NTIPAliasStat["progressivedamage"] = 318; +NTIPAliasStat["progressivesteal"] = 319; +NTIPAliasStat["progressiveother"] = 320; +NTIPAliasStat["progressivefire"] = 321; +NTIPAliasStat["progressivecold"] = 322; +NTIPAliasStat["progressivelightning"] = 323; +NTIPAliasStat["itemextracharges"] = 324; +NTIPAliasStat["progressivetohit"] = 325; +NTIPAliasStat["poisoncount"] = 326; +NTIPAliasStat["damageframerate"] = 327; +NTIPAliasStat["pierceidx"] = 328; +NTIPAliasStat["passivefiremastery"] = 329; +NTIPAliasStat["passiveltngmastery"] = 330; +NTIPAliasStat["passivecoldmastery"] = 331; +NTIPAliasStat["passivepoismastery"] = 332; +NTIPAliasStat["passivefirepierce"] = 333; +NTIPAliasStat["passiveltngpierce"] = 334; +NTIPAliasStat["passivecoldpierce"] = 335; +NTIPAliasStat["passivepoispierce"] = 336; +NTIPAliasStat["passivecriticalstrike"] = 337; +NTIPAliasStat["passivedodge"] = 338; +NTIPAliasStat["passiveavoid"] = 339; +NTIPAliasStat["passiveevade"] = 340; +NTIPAliasStat["passivewarmth"] = 341; +NTIPAliasStat["passivemasterymeleeth"] = 342; +NTIPAliasStat["passivemasterymeleedmg"] = 343; +NTIPAliasStat["passivemasterymeleecrit"] = 344; +NTIPAliasStat["passivemasterythrowth"] = 345; +NTIPAliasStat["passivemasterythrowdmg"] = 346; +NTIPAliasStat["passivemasterythrowcrit"] = 347; +NTIPAliasStat["passiveweaponblock"] = 348; +NTIPAliasStat["passivesummonresist"] = 349; +NTIPAliasStat["modifierlistskill"] = 350; +NTIPAliasStat["modifierlistlevel"] = 351; +NTIPAliasStat["lastsenthppct"] = 352; +NTIPAliasStat["sourceunittype"] = 353; +NTIPAliasStat["sourceunitid"] = 354; +NTIPAliasStat["shortparam1"] = 355; +NTIPAliasStat["questitemdifficulty"] = 356; +NTIPAliasStat["passivemagmastery"] = 357; +NTIPAliasStat["passivemagpierce"] = 358; + + +// Doesnt really exists, but is calculated in getStatEx +NTIPAliasStat["allres"] = 555; \ No newline at end of file diff --git a/assets/chests/chest_label.png b/assets/chests/chest_label.png index 537a6dc82..f80f695c4 100644 Binary files a/assets/chests/chest_label.png and b/assets/chests/chest_label.png differ diff --git a/assets/chests/locked.png b/assets/chests/locked.png index c53c8004f..f0e6061fa 100644 Binary files a/assets/chests/locked.png and b/assets/chests/locked.png differ diff --git a/assets/gamble/no_gold.png b/assets/gamble/no_gold.png deleted file mode 100644 index 600666d04..000000000 Binary files a/assets/gamble/no_gold.png and /dev/null differ diff --git a/assets/gamble/refresh_text.png b/assets/gamble/refresh_text.png deleted file mode 100644 index 3811fbba1..000000000 Binary files a/assets/gamble/refresh_text.png and /dev/null differ diff --git a/assets/hud_mask.png b/assets/hud_mask.png index 08e28a38a..36d9c912d 100644 Binary files a/assets/hud_mask.png and b/assets/hud_mask.png differ diff --git a/assets/item_properties/15_enhanced_damage.png b/assets/item_properties/15_enhanced_damage.png deleted file mode 100644 index ce7df360e..000000000 Binary files a/assets/item_properties/15_enhanced_damage.png and /dev/null differ diff --git a/assets/item_properties/15_enhanced_defense.png b/assets/item_properties/15_enhanced_defense.png deleted file mode 100644 index 88bd7a7ec..000000000 Binary files a/assets/item_properties/15_enhanced_defense.png and /dev/null differ diff --git a/assets/item_properties/15_fire_absorb.png b/assets/item_properties/15_fire_absorb.png deleted file mode 100644 index 80e10d719..000000000 Binary files a/assets/item_properties/15_fire_absorb.png and /dev/null differ diff --git a/assets/item_properties/15_increased_attack_speed.png b/assets/item_properties/15_increased_attack_speed.png deleted file mode 100644 index 35ad53eed..000000000 Binary files a/assets/item_properties/15_increased_attack_speed.png and /dev/null differ diff --git a/assets/item_properties/1_all_skills.png b/assets/item_properties/1_all_skills.png deleted file mode 100644 index d47d48aee..000000000 Binary files a/assets/item_properties/1_all_skills.png and /dev/null differ diff --git a/assets/item_properties/20_attack_rating.png b/assets/item_properties/20_attack_rating.png deleted file mode 100644 index 0b124f7ff..000000000 Binary files a/assets/item_properties/20_attack_rating.png and /dev/null differ diff --git a/assets/item_properties/20_faster_cast_rate.png b/assets/item_properties/20_faster_cast_rate.png deleted file mode 100644 index efa7c2e46..000000000 Binary files a/assets/item_properties/20_faster_cast_rate.png and /dev/null differ diff --git a/assets/item_properties/20_increased_attack_speed.png b/assets/item_properties/20_increased_attack_speed.png deleted file mode 100644 index 249d79811..000000000 Binary files a/assets/item_properties/20_increased_attack_speed.png and /dev/null differ diff --git a/assets/item_properties/20_life.png b/assets/item_properties/20_life.png deleted file mode 100644 index c428b1fe6..000000000 Binary files a/assets/item_properties/20_life.png and /dev/null differ diff --git a/assets/item_properties/2_Druid_skills.png b/assets/item_properties/2_Druid_skills.png deleted file mode 100644 index 1d9b88700..000000000 Binary files a/assets/item_properties/2_Druid_skills.png and /dev/null differ diff --git a/assets/item_properties/2_all_skills.png b/assets/item_properties/2_all_skills.png deleted file mode 100644 index 8bcf6a260..000000000 Binary files a/assets/item_properties/2_all_skills.png and /dev/null differ diff --git a/assets/item_properties/2_amazon_skills.png b/assets/item_properties/2_amazon_skills.png deleted file mode 100644 index bcf5f81c9..000000000 Binary files a/assets/item_properties/2_amazon_skills.png and /dev/null differ diff --git a/assets/item_properties/2_assasin_skills.png b/assets/item_properties/2_assasin_skills.png deleted file mode 100644 index 6c6f0bea4..000000000 Binary files a/assets/item_properties/2_assasin_skills.png and /dev/null differ diff --git a/assets/item_properties/2_barbarian_skills.png b/assets/item_properties/2_barbarian_skills.png deleted file mode 100644 index e33c8ee46..000000000 Binary files a/assets/item_properties/2_barbarian_skills.png and /dev/null differ diff --git a/assets/item_properties/2_javalin_spears.png b/assets/item_properties/2_javalin_spears.png deleted file mode 100644 index cac0c785f..000000000 Binary files a/assets/item_properties/2_javalin_spears.png and /dev/null differ diff --git a/assets/item_properties/2_necromancer_skills.png b/assets/item_properties/2_necromancer_skills.png deleted file mode 100644 index 076c7c36c..000000000 Binary files a/assets/item_properties/2_necromancer_skills.png and /dev/null differ diff --git a/assets/item_properties/2_paladin_skills.png b/assets/item_properties/2_paladin_skills.png deleted file mode 100644 index 10626568c..000000000 Binary files a/assets/item_properties/2_paladin_skills.png and /dev/null differ diff --git a/assets/item_properties/2_sorceress_skills.png b/assets/item_properties/2_sorceress_skills.png deleted file mode 100644 index 2268d50a5..000000000 Binary files a/assets/item_properties/2_sorceress_skills.png and /dev/null differ diff --git a/assets/item_properties/30_faster_run_walk.png b/assets/item_properties/30_faster_run_walk.png deleted file mode 100644 index 1c5f8a87a..000000000 Binary files a/assets/item_properties/30_faster_run_walk.png and /dev/null differ diff --git a/assets/item_properties/3_Elemental_skills.png b/assets/item_properties/3_Elemental_skills.png deleted file mode 100644 index 35c5b0b0e..000000000 Binary files a/assets/item_properties/3_Elemental_skills.png and /dev/null differ diff --git a/assets/item_properties/3_blessed_hammer.png b/assets/item_properties/3_blessed_hammer.png deleted file mode 100644 index 39c7c5788..000000000 Binary files a/assets/item_properties/3_blessed_hammer.png and /dev/null differ diff --git a/assets/item_properties/3_bone_spear.png b/assets/item_properties/3_bone_spear.png deleted file mode 100644 index e7dca3939..000000000 Binary files a/assets/item_properties/3_bone_spear.png and /dev/null differ diff --git a/assets/item_properties/3_bone_spirit.png b/assets/item_properties/3_bone_spirit.png deleted file mode 100644 index d4ffae1c2..000000000 Binary files a/assets/item_properties/3_bone_spirit.png and /dev/null differ diff --git a/assets/item_properties/3_bow_skills.png b/assets/item_properties/3_bow_skills.png deleted file mode 100644 index b18335fbd..000000000 Binary files a/assets/item_properties/3_bow_skills.png and /dev/null differ diff --git a/assets/item_properties/3_chilling_armor.png b/assets/item_properties/3_chilling_armor.png deleted file mode 100644 index 5cf5e6909..000000000 Binary files a/assets/item_properties/3_chilling_armor.png and /dev/null differ diff --git a/assets/item_properties/3_cold_skills.png b/assets/item_properties/3_cold_skills.png deleted file mode 100644 index 13ac6089b..000000000 Binary files a/assets/item_properties/3_cold_skills.png and /dev/null differ diff --git a/assets/item_properties/3_concentration.png b/assets/item_properties/3_concentration.png deleted file mode 100644 index b7c0dcca8..000000000 Binary files a/assets/item_properties/3_concentration.png and /dev/null differ diff --git a/assets/item_properties/3_conviction.png b/assets/item_properties/3_conviction.png deleted file mode 100644 index 697a41c28..000000000 Binary files a/assets/item_properties/3_conviction.png and /dev/null differ diff --git a/assets/item_properties/3_energy_shield.png b/assets/item_properties/3_energy_shield.png deleted file mode 100644 index bb95154ca..000000000 Binary files a/assets/item_properties/3_energy_shield.png and /dev/null differ diff --git a/assets/item_properties/3_fanaticism.png b/assets/item_properties/3_fanaticism.png deleted file mode 100644 index b1113f38b..000000000 Binary files a/assets/item_properties/3_fanaticism.png and /dev/null differ diff --git a/assets/item_properties/3_fire_skills.png b/assets/item_properties/3_fire_skills.png deleted file mode 100644 index ed7d5032d..000000000 Binary files a/assets/item_properties/3_fire_skills.png and /dev/null differ diff --git a/assets/item_properties/3_fist_of_the_heavens.png b/assets/item_properties/3_fist_of_the_heavens.png deleted file mode 100644 index fc13f11bf..000000000 Binary files a/assets/item_properties/3_fist_of_the_heavens.png and /dev/null differ diff --git a/assets/item_properties/3_holy_shield.png b/assets/item_properties/3_holy_shield.png deleted file mode 100644 index 706318465..000000000 Binary files a/assets/item_properties/3_holy_shield.png and /dev/null differ diff --git a/assets/item_properties/3_javelin_skills.png b/assets/item_properties/3_javelin_skills.png deleted file mode 100644 index 1c797460d..000000000 Binary files a/assets/item_properties/3_javelin_skills.png and /dev/null differ diff --git a/assets/item_properties/3_lightning_sentry.png b/assets/item_properties/3_lightning_sentry.png deleted file mode 100644 index 59eb40306..000000000 Binary files a/assets/item_properties/3_lightning_sentry.png and /dev/null differ diff --git a/assets/item_properties/3_lightning_skills.png b/assets/item_properties/3_lightning_skills.png deleted file mode 100644 index e5b46f1ae..000000000 Binary files a/assets/item_properties/3_lightning_skills.png and /dev/null differ diff --git a/assets/item_properties/3_maximum_damage.png b/assets/item_properties/3_maximum_damage.png deleted file mode 100644 index a57dca0ba..000000000 Binary files a/assets/item_properties/3_maximum_damage.png and /dev/null differ diff --git a/assets/item_properties/3_pcombat.png b/assets/item_properties/3_pcombat.png deleted file mode 100644 index 8603dba52..000000000 Binary files a/assets/item_properties/3_pcombat.png and /dev/null differ diff --git a/assets/item_properties/3_percent.png b/assets/item_properties/3_percent.png deleted file mode 100644 index 395ee5d8f..000000000 Binary files a/assets/item_properties/3_percent.png and /dev/null differ diff --git a/assets/item_properties/3_shiver_armor.png b/assets/item_properties/3_shiver_armor.png deleted file mode 100644 index bd32fe439..000000000 Binary files a/assets/item_properties/3_shiver_armor.png and /dev/null differ diff --git a/assets/item_properties/3_sorceress_skills.png b/assets/item_properties/3_sorceress_skills.png deleted file mode 100644 index be2e6b126..000000000 Binary files a/assets/item_properties/3_sorceress_skills.png and /dev/null differ diff --git a/assets/item_properties/3_thunder_storm.png b/assets/item_properties/3_thunder_storm.png deleted file mode 100644 index 17098e1a1..000000000 Binary files a/assets/item_properties/3_thunder_storm.png and /dev/null differ diff --git a/assets/item_properties/3_tornado.png b/assets/item_properties/3_tornado.png deleted file mode 100644 index d6d4cc76a..000000000 Binary files a/assets/item_properties/3_tornado.png and /dev/null differ diff --git a/assets/item_properties/3_venom.png b/assets/item_properties/3_venom.png deleted file mode 100644 index 5528c2aec..000000000 Binary files a/assets/item_properties/3_venom.png and /dev/null differ diff --git a/assets/item_properties/3_warcries.png b/assets/item_properties/3_warcries.png deleted file mode 100644 index 0bd35c760..000000000 Binary files a/assets/item_properties/3_warcries.png and /dev/null differ diff --git a/assets/item_properties/3_zeal.png b/assets/item_properties/3_zeal.png deleted file mode 100644 index 10a5f604c..000000000 Binary files a/assets/item_properties/3_zeal.png and /dev/null differ diff --git a/assets/item_properties/40_all_resist.png b/assets/item_properties/40_all_resist.png deleted file mode 100644 index 7f899d110..000000000 Binary files a/assets/item_properties/40_all_resist.png and /dev/null differ diff --git a/assets/item_properties/45_all_resist.png b/assets/item_properties/45_all_resist.png deleted file mode 100644 index 835b2607a..000000000 Binary files a/assets/item_properties/45_all_resist.png and /dev/null differ diff --git a/assets/item_properties/4_percent.png b/assets/item_properties/4_percent.png deleted file mode 100644 index 6d2d3aac1..000000000 Binary files a/assets/item_properties/4_percent.png and /dev/null differ diff --git a/assets/item_properties/5_all_resist.png b/assets/item_properties/5_all_resist.png deleted file mode 100644 index e81f2f5ec..000000000 Binary files a/assets/item_properties/5_all_resist.png and /dev/null differ diff --git a/assets/item_properties/7_magicfind.png b/assets/item_properties/7_magicfind.png deleted file mode 100644 index 4c90754eb..000000000 Binary files a/assets/item_properties/7_magicfind.png and /dev/null differ diff --git a/assets/item_properties/Amazonskiller.png b/assets/item_properties/Amazonskiller.png deleted file mode 100644 index 67358f2f4..000000000 Binary files a/assets/item_properties/Amazonskiller.png and /dev/null differ diff --git a/assets/item_properties/Assasinskiller.png b/assets/item_properties/Assasinskiller.png deleted file mode 100644 index cd945bd62..000000000 Binary files a/assets/item_properties/Assasinskiller.png and /dev/null differ diff --git a/assets/item_properties/Barbarianskiller.png b/assets/item_properties/Barbarianskiller.png deleted file mode 100644 index 8f8775f49..000000000 Binary files a/assets/item_properties/Barbarianskiller.png and /dev/null differ diff --git a/assets/item_properties/Druidskiller.png b/assets/item_properties/Druidskiller.png deleted file mode 100644 index 6476f0f8d..000000000 Binary files a/assets/item_properties/Druidskiller.png and /dev/null differ diff --git a/assets/item_properties/Mana.png b/assets/item_properties/Mana.png deleted file mode 100644 index 76dfcd3c1..000000000 Binary files a/assets/item_properties/Mana.png and /dev/null differ diff --git a/assets/item_properties/Necromancerskiller.png b/assets/item_properties/Necromancerskiller.png deleted file mode 100644 index b4ae591c7..000000000 Binary files a/assets/item_properties/Necromancerskiller.png and /dev/null differ diff --git a/assets/item_properties/Paladinskiller.png b/assets/item_properties/Paladinskiller.png deleted file mode 100644 index 1fb493c53..000000000 Binary files a/assets/item_properties/Paladinskiller.png and /dev/null differ diff --git a/assets/item_properties/Sorceressskiller.png b/assets/item_properties/Sorceressskiller.png deleted file mode 100644 index 7f865a0d3..000000000 Binary files a/assets/item_properties/Sorceressskiller.png and /dev/null differ diff --git a/assets/item_properties/all_resist.png b/assets/item_properties/all_resist.png deleted file mode 100644 index 0b8567ec1..000000000 Binary files a/assets/item_properties/all_resist.png and /dev/null differ diff --git a/assets/item_properties/all_resist_45.png b/assets/item_properties/all_resist_45.png deleted file mode 100644 index 835b2607a..000000000 Binary files a/assets/item_properties/all_resist_45.png and /dev/null differ diff --git a/assets/item_properties/all_resist_gt40.png b/assets/item_properties/all_resist_gt40.png deleted file mode 100644 index 7f899d110..000000000 Binary files a/assets/item_properties/all_resist_gt40.png and /dev/null differ diff --git a/assets/item_properties/all_skills.png b/assets/item_properties/all_skills.png deleted file mode 100644 index 6fbab9feb..000000000 Binary files a/assets/item_properties/all_skills.png and /dev/null differ diff --git a/assets/item_properties/attack_rating.png b/assets/item_properties/attack_rating.png deleted file mode 100644 index 59c358f81..000000000 Binary files a/assets/item_properties/attack_rating.png and /dev/null differ diff --git a/assets/item_properties/cannot_be_frozen.png b/assets/item_properties/cannot_be_frozen.png deleted file mode 100644 index 2db425967..000000000 Binary files a/assets/item_properties/cannot_be_frozen.png and /dev/null differ diff --git a/assets/item_properties/cold_resist.png b/assets/item_properties/cold_resist.png deleted file mode 100644 index ec5cbe7c4..000000000 Binary files a/assets/item_properties/cold_resist.png and /dev/null differ diff --git a/assets/item_properties/dexterity.png b/assets/item_properties/dexterity.png deleted file mode 100644 index eff0d2a60..000000000 Binary files a/assets/item_properties/dexterity.png and /dev/null differ diff --git a/assets/item_properties/enhanced_damage.png b/assets/item_properties/enhanced_damage.png deleted file mode 100644 index a737679b3..000000000 Binary files a/assets/item_properties/enhanced_damage.png and /dev/null differ diff --git a/assets/item_properties/enhanced_damage_15.png b/assets/item_properties/enhanced_damage_15.png deleted file mode 100644 index ce7df360e..000000000 Binary files a/assets/item_properties/enhanced_damage_15.png and /dev/null differ diff --git a/assets/item_properties/enhanced_defense.png b/assets/item_properties/enhanced_defense.png deleted file mode 100644 index 33aeabcce..000000000 Binary files a/assets/item_properties/enhanced_defense.png and /dev/null differ diff --git a/assets/item_properties/enhanced_defense_15.png b/assets/item_properties/enhanced_defense_15.png deleted file mode 100644 index 88bd7a7ec..000000000 Binary files a/assets/item_properties/enhanced_defense_15.png and /dev/null differ diff --git a/assets/item_properties/ethereal.png b/assets/item_properties/ethereal.png deleted file mode 100644 index f37286f18..000000000 Binary files a/assets/item_properties/ethereal.png and /dev/null differ diff --git a/assets/item_properties/faster_cast_rate.png b/assets/item_properties/faster_cast_rate.png deleted file mode 100644 index 7973dc96d..000000000 Binary files a/assets/item_properties/faster_cast_rate.png and /dev/null differ diff --git a/assets/item_properties/faster_run_walk.png b/assets/item_properties/faster_run_walk.png deleted file mode 100644 index 9dacd5278..000000000 Binary files a/assets/item_properties/faster_run_walk.png and /dev/null differ diff --git a/assets/item_properties/fcr.png b/assets/item_properties/fcr.png deleted file mode 100644 index 01c2b554b..000000000 Binary files a/assets/item_properties/fcr.png and /dev/null differ diff --git a/assets/item_properties/fire_resist.png b/assets/item_properties/fire_resist.png deleted file mode 100644 index dfb16a44c..000000000 Binary files a/assets/item_properties/fire_resist.png and /dev/null differ diff --git a/assets/item_properties/getting_magic_items.png b/assets/item_properties/getting_magic_items.png deleted file mode 100644 index 667d5ca2e..000000000 Binary files a/assets/item_properties/getting_magic_items.png and /dev/null differ diff --git a/assets/item_properties/increased_attack_speed.png b/assets/item_properties/increased_attack_speed.png deleted file mode 100644 index bff980dc0..000000000 Binary files a/assets/item_properties/increased_attack_speed.png and /dev/null differ diff --git a/assets/item_properties/javalin_spears.png b/assets/item_properties/javalin_spears.png deleted file mode 100644 index 7fe25d62e..000000000 Binary files a/assets/item_properties/javalin_spears.png and /dev/null differ diff --git a/assets/item_properties/life.png b/assets/item_properties/life.png deleted file mode 100644 index 2e0225b1d..000000000 Binary files a/assets/item_properties/life.png and /dev/null differ diff --git a/assets/item_properties/life_stolen.png b/assets/item_properties/life_stolen.png deleted file mode 100644 index ff0242421..000000000 Binary files a/assets/item_properties/life_stolen.png and /dev/null differ diff --git a/assets/item_properties/lightning_resist.png b/assets/item_properties/lightning_resist.png deleted file mode 100644 index d7705840f..000000000 Binary files a/assets/item_properties/lightning_resist.png and /dev/null differ diff --git a/assets/item_properties/lightning_sentry.png b/assets/item_properties/lightning_sentry.png deleted file mode 100644 index eab9f15b9..000000000 Binary files a/assets/item_properties/lightning_sentry.png and /dev/null differ diff --git a/assets/item_properties/magicfind.png b/assets/item_properties/magicfind.png deleted file mode 100644 index 34588f4bf..000000000 Binary files a/assets/item_properties/magicfind.png and /dev/null differ diff --git a/assets/item_properties/mana_stolen.png b/assets/item_properties/mana_stolen.png deleted file mode 100644 index dd2166931..000000000 Binary files a/assets/item_properties/mana_stolen.png and /dev/null differ diff --git a/assets/item_properties/maximum_damage.png b/assets/item_properties/maximum_damage.png deleted file mode 100644 index 4621f3dc4..000000000 Binary files a/assets/item_properties/maximum_damage.png and /dev/null differ diff --git a/assets/item_properties/poison_resist.png b/assets/item_properties/poison_resist.png deleted file mode 100644 index d8c1100f1..000000000 Binary files a/assets/item_properties/poison_resist.png and /dev/null differ diff --git a/assets/item_properties/socketed.png b/assets/item_properties/socketed.png deleted file mode 100644 index d6d06fd30..000000000 Binary files a/assets/item_properties/socketed.png and /dev/null differ diff --git a/assets/item_properties/socketed_1.png b/assets/item_properties/socketed_1.png deleted file mode 100644 index 79e6580e1..000000000 Binary files a/assets/item_properties/socketed_1.png and /dev/null differ diff --git a/assets/item_properties/socketed_2.png b/assets/item_properties/socketed_2.png deleted file mode 100644 index 440121c78..000000000 Binary files a/assets/item_properties/socketed_2.png and /dev/null differ diff --git a/assets/item_properties/socketed_3.png b/assets/item_properties/socketed_3.png deleted file mode 100644 index 0f1335140..000000000 Binary files a/assets/item_properties/socketed_3.png and /dev/null differ diff --git a/assets/item_properties/socketed_4.png b/assets/item_properties/socketed_4.png deleted file mode 100644 index 6deda9174..000000000 Binary files a/assets/item_properties/socketed_4.png and /dev/null differ diff --git a/assets/item_properties/socketed_5.png b/assets/item_properties/socketed_5.png deleted file mode 100644 index 1d4016814..000000000 Binary files a/assets/item_properties/socketed_5.png and /dev/null differ diff --git a/assets/item_properties/socketed_6.png b/assets/item_properties/socketed_6.png deleted file mode 100644 index 4d70e65ed..000000000 Binary files a/assets/item_properties/socketed_6.png and /dev/null differ diff --git a/assets/item_properties/strenght.png b/assets/item_properties/strenght.png deleted file mode 100644 index c6ea4325b..000000000 Binary files a/assets/item_properties/strenght.png and /dev/null differ diff --git a/assets/item_properties/traps.png b/assets/item_properties/traps.png deleted file mode 100644 index 74127c583..000000000 Binary files a/assets/item_properties/traps.png and /dev/null differ diff --git a/assets/item_properties/unidentified.png b/assets/item_properties/unidentified.png deleted file mode 100644 index ab47df968..000000000 Binary files a/assets/item_properties/unidentified.png and /dev/null differ diff --git a/assets/items/bl__magic_boneweave.png b/assets/items/bl__magic_boneweave.png deleted file mode 100644 index 41e547638..000000000 Binary files a/assets/items/bl__magic_boneweave.png and /dev/null differ diff --git a/assets/items/bl__morning_star.PNG b/assets/items/bl__morning_star.PNG deleted file mode 100644 index 06c7c93ce..000000000 Binary files a/assets/items/bl__morning_star.PNG and /dev/null differ diff --git a/assets/items/bl__rare_boneweave.png b/assets/items/bl__rare_boneweave.png deleted file mode 100644 index 9c5fe2fb2..000000000 Binary files a/assets/items/bl__rare_boneweave.png and /dev/null differ diff --git a/assets/items/bl__rare_flameberge.png b/assets/items/bl__rare_flameberge.png deleted file mode 100644 index 1d0380649..000000000 Binary files a/assets/items/bl__rare_flameberge.png and /dev/null differ diff --git a/assets/items/bl__rare_ring_mail.png b/assets/items/bl__rare_ring_mail.png deleted file mode 100644 index ae1c2486f..000000000 Binary files a/assets/items/bl__rare_ring_mail.png and /dev/null differ diff --git a/assets/items/bl__rare_short_battle_bow.png b/assets/items/bl__rare_short_battle_bow.png deleted file mode 100644 index b09f10b08..000000000 Binary files a/assets/items/bl__rare_short_battle_bow.png and /dev/null differ diff --git a/assets/items/bl__superior_flameberge.png b/assets/items/bl__superior_flameberge.png deleted file mode 100644 index 50908efba..000000000 Binary files a/assets/items/bl__superior_flameberge.png and /dev/null differ diff --git a/assets/items/bl__uniq_morning_star.png b/assets/items/bl__uniq_morning_star.png deleted file mode 100644 index 375bad6de..000000000 Binary files a/assets/items/bl__uniq_morning_star.png and /dev/null differ diff --git a/assets/items/bl__unique_ring_mail.png b/assets/items/bl__unique_ring_mail.png deleted file mode 100644 index dd40d3ee8..000000000 Binary files a/assets/items/bl__unique_ring_mail.png and /dev/null differ diff --git a/assets/items/gray_akaran_rondache.png b/assets/items/gray_akaran_rondache.png deleted file mode 100644 index 45cc71099..000000000 Binary files a/assets/items/gray_akaran_rondache.png and /dev/null differ diff --git a/assets/items/gray_akaran_targe.png b/assets/items/gray_akaran_targe.png deleted file mode 100644 index 2fd484a25..000000000 Binary files a/assets/items/gray_akaran_targe.png and /dev/null differ diff --git a/assets/items/gray_antlers.png b/assets/items/gray_antlers.png deleted file mode 100644 index 03833c1d0..000000000 Binary files a/assets/items/gray_antlers.png and /dev/null differ diff --git a/assets/items/gray_archon_staff.png b/assets/items/gray_archon_staff.png deleted file mode 100644 index eff8ced9f..000000000 Binary files a/assets/items/gray_archon_staff.png and /dev/null differ diff --git a/assets/items/gray_armor_archon_plate.png b/assets/items/gray_armor_archon_plate.png deleted file mode 100644 index a077df661..000000000 Binary files a/assets/items/gray_armor_archon_plate.png and /dev/null differ diff --git a/assets/items/gray_armor_balrog.png b/assets/items/gray_armor_balrog.png deleted file mode 100644 index 57ceaea04..000000000 Binary files a/assets/items/gray_armor_balrog.png and /dev/null differ diff --git a/assets/items/gray_armor_boneweave.png b/assets/items/gray_armor_boneweave.png deleted file mode 100644 index 3129b1b62..000000000 Binary files a/assets/items/gray_armor_boneweave.png and /dev/null differ diff --git a/assets/items/gray_armor_dusk_shroud.png b/assets/items/gray_armor_dusk_shroud.png deleted file mode 100644 index 0bc6df0a3..000000000 Binary files a/assets/items/gray_armor_dusk_shroud.png and /dev/null differ diff --git a/assets/items/gray_armor_great_hauberk.png b/assets/items/gray_armor_great_hauberk.png deleted file mode 100644 index 6f4ea6c90..000000000 Binary files a/assets/items/gray_armor_great_hauberk.png and /dev/null differ diff --git a/assets/items/gray_armor_hellforge.png b/assets/items/gray_armor_hellforge.png deleted file mode 100644 index 6da2f039f..000000000 Binary files a/assets/items/gray_armor_hellforge.png and /dev/null differ diff --git a/assets/items/gray_armor_kraken.png b/assets/items/gray_armor_kraken.png deleted file mode 100644 index a588d8a0a..000000000 Binary files a/assets/items/gray_armor_kraken.png and /dev/null differ diff --git a/assets/items/gray_armor_lacquered_plate.png b/assets/items/gray_armor_lacquered_plate.png deleted file mode 100644 index aaa0f204e..000000000 Binary files a/assets/items/gray_armor_lacquered_plate.png and /dev/null differ diff --git a/assets/items/gray_armor_light_plate.png b/assets/items/gray_armor_light_plate.png deleted file mode 100644 index 6d9a38a2e..000000000 Binary files a/assets/items/gray_armor_light_plate.png and /dev/null differ diff --git a/assets/items/gray_armor_mage_plate.png b/assets/items/gray_armor_mage_plate.png deleted file mode 100644 index 236b80c18..000000000 Binary files a/assets/items/gray_armor_mage_plate.png and /dev/null differ diff --git a/assets/items/gray_armor_sacred_armor.png b/assets/items/gray_armor_sacred_armor.png deleted file mode 100644 index ccb856897..000000000 Binary files a/assets/items/gray_armor_sacred_armor.png and /dev/null differ diff --git a/assets/items/gray_armor_shadow_plate.png b/assets/items/gray_armor_shadow_plate.png deleted file mode 100644 index 5f682c55a..000000000 Binary files a/assets/items/gray_armor_shadow_plate.png and /dev/null differ diff --git a/assets/items/gray_armor_wyrmhide.png b/assets/items/gray_armor_wyrmhide.png deleted file mode 100644 index a92c94d4f..000000000 Binary files a/assets/items/gray_armor_wyrmhide.png and /dev/null differ diff --git a/assets/items/gray_assault_helmet.png b/assets/items/gray_assault_helmet.png deleted file mode 100644 index 7ee827231..000000000 Binary files a/assets/items/gray_assault_helmet.png and /dev/null differ diff --git a/assets/items/gray_avenger_guard.png b/assets/items/gray_avenger_guard.png deleted file mode 100644 index ca15b5136..000000000 Binary files a/assets/items/gray_avenger_guard.png and /dev/null differ diff --git a/assets/items/gray_blood_spirit.png b/assets/items/gray_blood_spirit.png deleted file mode 100644 index 8c3e23aab..000000000 Binary files a/assets/items/gray_blood_spirit.png and /dev/null differ diff --git a/assets/items/gray_caduceus.png b/assets/items/gray_caduceus.png deleted file mode 100644 index cb8549543..000000000 Binary files a/assets/items/gray_caduceus.png and /dev/null differ diff --git a/assets/items/gray_carnage_helm.png b/assets/items/gray_carnage_helm.png deleted file mode 100644 index e84893312..000000000 Binary files a/assets/items/gray_carnage_helm.png and /dev/null differ diff --git a/assets/items/gray_cedar_staff.png b/assets/items/gray_cedar_staff.png deleted file mode 100644 index b6113e294..000000000 Binary files a/assets/items/gray_cedar_staff.png and /dev/null differ diff --git a/assets/items/gray_conqueror_crown.png b/assets/items/gray_conqueror_crown.png deleted file mode 100644 index 20822f7e4..000000000 Binary files a/assets/items/gray_conqueror_crown.png and /dev/null differ diff --git a/assets/items/gray_destroyer_helm.png b/assets/items/gray_destroyer_helm.png deleted file mode 100644 index e27133088..000000000 Binary files a/assets/items/gray_destroyer_helm.png and /dev/null differ diff --git a/assets/items/gray_divine_scepter.png b/assets/items/gray_divine_scepter.png deleted file mode 100644 index 198160f61..000000000 Binary files a/assets/items/gray_divine_scepter.png and /dev/null differ diff --git a/assets/items/gray_dream_spirit.png b/assets/items/gray_dream_spirit.png deleted file mode 100644 index d3536ad78..000000000 Binary files a/assets/items/gray_dream_spirit.png and /dev/null differ diff --git a/assets/items/gray_earth_spirit.png b/assets/items/gray_earth_spirit.png deleted file mode 100644 index b343d0fb9..000000000 Binary files a/assets/items/gray_earth_spirit.png and /dev/null differ diff --git a/assets/items/gray_elder_staff.png b/assets/items/gray_elder_staff.png deleted file mode 100644 index 9baea1cc2..000000000 Binary files a/assets/items/gray_elder_staff.png and /dev/null differ diff --git a/assets/items/gray_fury_visor.png b/assets/items/gray_fury_visor.png deleted file mode 100644 index 2c227d849..000000000 Binary files a/assets/items/gray_fury_visor.png and /dev/null differ diff --git a/assets/items/gray_ghost_wand.png b/assets/items/gray_ghost_wand.png deleted file mode 100644 index abd2af98f..000000000 Binary files a/assets/items/gray_ghost_wand.png and /dev/null differ diff --git a/assets/items/gray_gothic_staff.png b/assets/items/gray_gothic_staff.png deleted file mode 100644 index 7cf2eadbb..000000000 Binary files a/assets/items/gray_gothic_staff.png and /dev/null differ diff --git a/assets/items/gray_guardian_crown.png b/assets/items/gray_guardian_crown.png deleted file mode 100644 index d33f2d39e..000000000 Binary files a/assets/items/gray_guardian_crown.png and /dev/null differ diff --git a/assets/items/gray_helm_bone_visage.png b/assets/items/gray_helm_bone_visage.png deleted file mode 100644 index 0ce52a0e4..000000000 Binary files a/assets/items/gray_helm_bone_visage.png and /dev/null differ diff --git a/assets/items/gray_helm_corona.png b/assets/items/gray_helm_corona.png deleted file mode 100644 index bf0ea3e65..000000000 Binary files a/assets/items/gray_helm_corona.png and /dev/null differ diff --git a/assets/items/gray_helm_demonhead.png b/assets/items/gray_helm_demonhead.png deleted file mode 100644 index 9939466d0..000000000 Binary files a/assets/items/gray_helm_demonhead.png and /dev/null differ diff --git a/assets/items/gray_helm_diadem.png b/assets/items/gray_helm_diadem.png deleted file mode 100644 index 5bc8fb433..000000000 Binary files a/assets/items/gray_helm_diadem.png and /dev/null differ diff --git a/assets/items/gray_helm_giant_conch.png b/assets/items/gray_helm_giant_conch.png deleted file mode 100644 index 1373f0a89..000000000 Binary files a/assets/items/gray_helm_giant_conch.png and /dev/null differ diff --git a/assets/items/gray_helm_shako.png b/assets/items/gray_helm_shako.png deleted file mode 100644 index 94f059685..000000000 Binary files a/assets/items/gray_helm_shako.png and /dev/null differ diff --git a/assets/items/gray_hunters_guise.png b/assets/items/gray_hunters_guise.png deleted file mode 100644 index 8b55f9d1e..000000000 Binary files a/assets/items/gray_hunters_guise.png and /dev/null differ diff --git a/assets/items/gray_kurast_shield.png b/assets/items/gray_kurast_shield.png deleted file mode 100644 index dbb92e45f..000000000 Binary files a/assets/items/gray_kurast_shield.png and /dev/null differ diff --git a/assets/items/gray_lich_wand.png b/assets/items/gray_lich_wand.png deleted file mode 100644 index 7c042a768..000000000 Binary files a/assets/items/gray_lich_wand.png and /dev/null differ diff --git a/assets/items/gray_polished_wand.png b/assets/items/gray_polished_wand.png deleted file mode 100644 index 8ff1b798c..000000000 Binary files a/assets/items/gray_polished_wand.png and /dev/null differ diff --git a/assets/items/gray_royal_shield.png b/assets/items/gray_royal_shield.png deleted file mode 100644 index 4969b3465..000000000 Binary files a/assets/items/gray_royal_shield.png and /dev/null differ diff --git a/assets/items/gray_rune_staff.png b/assets/items/gray_rune_staff.png deleted file mode 100644 index 505818df2..000000000 Binary files a/assets/items/gray_rune_staff.png and /dev/null differ diff --git a/assets/items/gray_sacred_rondache.png b/assets/items/gray_sacred_rondache.png deleted file mode 100644 index 87e7bb04d..000000000 Binary files a/assets/items/gray_sacred_rondache.png and /dev/null differ diff --git a/assets/items/gray_sacred_targe.png b/assets/items/gray_sacred_targe.png deleted file mode 100644 index 4cc593e24..000000000 Binary files a/assets/items/gray_sacred_targe.png and /dev/null differ diff --git a/assets/items/gray_savage_helmet.png b/assets/items/gray_savage_helmet.png deleted file mode 100644 index 0dc8edd12..000000000 Binary files a/assets/items/gray_savage_helmet.png and /dev/null differ diff --git a/assets/items/gray_shield_monarch.png b/assets/items/gray_shield_monarch.png deleted file mode 100644 index 7bd364169..000000000 Binary files a/assets/items/gray_shield_monarch.png and /dev/null differ diff --git a/assets/items/gray_shield_troll_nest.png b/assets/items/gray_shield_troll_nest.png deleted file mode 100644 index c6788bc7b..000000000 Binary files a/assets/items/gray_shield_troll_nest.png and /dev/null differ diff --git a/assets/items/gray_shillelagh.png b/assets/items/gray_shillelagh.png deleted file mode 100644 index 79cebaff1..000000000 Binary files a/assets/items/gray_shillelagh.png and /dev/null differ diff --git a/assets/items/gray_sky_spirit.png b/assets/items/gray_sky_spirit.png deleted file mode 100644 index d6265b52c..000000000 Binary files a/assets/items/gray_sky_spirit.png and /dev/null differ diff --git a/assets/items/gray_slayer_guard.png b/assets/items/gray_slayer_guard.png deleted file mode 100644 index 862a5743e..000000000 Binary files a/assets/items/gray_slayer_guard.png and /dev/null differ diff --git a/assets/items/gray_sun_spirit.png b/assets/items/gray_sun_spirit.png deleted file mode 100644 index 47fc4e131..000000000 Binary files a/assets/items/gray_sun_spirit.png and /dev/null differ diff --git a/assets/items/gray_superior_akaran_rondache.png b/assets/items/gray_superior_akaran_rondache.png deleted file mode 100644 index bdb39bb3d..000000000 Binary files a/assets/items/gray_superior_akaran_rondache.png and /dev/null differ diff --git a/assets/items/gray_superior_akaran_targe.png b/assets/items/gray_superior_akaran_targe.png deleted file mode 100644 index fcf4fc40a..000000000 Binary files a/assets/items/gray_superior_akaran_targe.png and /dev/null differ diff --git a/assets/items/gray_superior_archon_plate.png b/assets/items/gray_superior_archon_plate.png deleted file mode 100644 index fe3cde111..000000000 Binary files a/assets/items/gray_superior_archon_plate.png and /dev/null differ diff --git a/assets/items/gray_superior_berserker_axe.png b/assets/items/gray_superior_berserker_axe.png deleted file mode 100644 index e26c2af49..000000000 Binary files a/assets/items/gray_superior_berserker_axe.png and /dev/null differ diff --git a/assets/items/gray_superior_boneweave.png b/assets/items/gray_superior_boneweave.png deleted file mode 100644 index ccbee9a35..000000000 Binary files a/assets/items/gray_superior_boneweave.png and /dev/null differ diff --git a/assets/items/gray_superior_crystal_sword.png b/assets/items/gray_superior_crystal_sword.png deleted file mode 100644 index 60f14cec5..000000000 Binary files a/assets/items/gray_superior_crystal_sword.png and /dev/null differ diff --git a/assets/items/gray_superior_dusk_shroud.png b/assets/items/gray_superior_dusk_shroud.png deleted file mode 100644 index 3430abb60..000000000 Binary files a/assets/items/gray_superior_dusk_shroud.png and /dev/null differ diff --git a/assets/items/gray_superior_flail.png b/assets/items/gray_superior_flail.png deleted file mode 100644 index 95342c20d..000000000 Binary files a/assets/items/gray_superior_flail.png and /dev/null differ diff --git a/assets/items/gray_superior_great_hauberk.png b/assets/items/gray_superior_great_hauberk.png deleted file mode 100644 index 7995f4169..000000000 Binary files a/assets/items/gray_superior_great_hauberk.png and /dev/null differ diff --git a/assets/items/gray_superior_kurast_shield.png b/assets/items/gray_superior_kurast_shield.png deleted file mode 100644 index d3fe18860..000000000 Binary files a/assets/items/gray_superior_kurast_shield.png and /dev/null differ diff --git a/assets/items/gray_superior_lacquered_plate.png b/assets/items/gray_superior_lacquered_plate.png deleted file mode 100644 index 9ae0be271..000000000 Binary files a/assets/items/gray_superior_lacquered_plate.png and /dev/null differ diff --git a/assets/items/gray_superior_light_plate.png b/assets/items/gray_superior_light_plate.png deleted file mode 100644 index 7082d7364..000000000 Binary files a/assets/items/gray_superior_light_plate.png and /dev/null differ diff --git a/assets/items/gray_superior_mage_plate.png b/assets/items/gray_superior_mage_plate.png deleted file mode 100644 index 08fe82098..000000000 Binary files a/assets/items/gray_superior_mage_plate.png and /dev/null differ diff --git a/assets/items/gray_superior_phase_blade.png b/assets/items/gray_superior_phase_blade.png deleted file mode 100644 index e4f4bf9c6..000000000 Binary files a/assets/items/gray_superior_phase_blade.png and /dev/null differ diff --git a/assets/items/gray_superior_royal_shield.png b/assets/items/gray_superior_royal_shield.png deleted file mode 100644 index 4baacc7fc..000000000 Binary files a/assets/items/gray_superior_royal_shield.png and /dev/null differ diff --git a/assets/items/gray_superior_sacred_armor.png b/assets/items/gray_superior_sacred_armor.png deleted file mode 100644 index 71476c254..000000000 Binary files a/assets/items/gray_superior_sacred_armor.png and /dev/null differ diff --git a/assets/items/gray_superior_sacred_rondache.png b/assets/items/gray_superior_sacred_rondache.png deleted file mode 100644 index b6b9b29b6..000000000 Binary files a/assets/items/gray_superior_sacred_rondache.png and /dev/null differ diff --git a/assets/items/gray_superior_sacred_targe.png b/assets/items/gray_superior_sacred_targe.png deleted file mode 100644 index 873168600..000000000 Binary files a/assets/items/gray_superior_sacred_targe.png and /dev/null differ diff --git a/assets/items/gray_superior_shadow_plate.png b/assets/items/gray_superior_shadow_plate.png deleted file mode 100644 index 251be0a78..000000000 Binary files a/assets/items/gray_superior_shadow_plate.png and /dev/null differ diff --git a/assets/items/gray_superior_vortex_shield.png b/assets/items/gray_superior_vortex_shield.png deleted file mode 100644 index 46990ce0d..000000000 Binary files a/assets/items/gray_superior_vortex_shield.png and /dev/null differ diff --git a/assets/items/gray_superior_wyrmhide.png b/assets/items/gray_superior_wyrmhide.png deleted file mode 100644 index 0880a6b1a..000000000 Binary files a/assets/items/gray_superior_wyrmhide.png and /dev/null differ diff --git a/assets/items/gray_superior_zakarum_shield.png b/assets/items/gray_superior_zakarum_shield.png deleted file mode 100644 index 6a179f23d..000000000 Binary files a/assets/items/gray_superior_zakarum_shield.png and /dev/null differ diff --git a/assets/items/gray_unearthed_wand.png b/assets/items/gray_unearthed_wand.png deleted file mode 100644 index 19f04a9e3..000000000 Binary files a/assets/items/gray_unearthed_wand.png and /dev/null differ diff --git a/assets/items/gray_vortex_shield.png b/assets/items/gray_vortex_shield.png deleted file mode 100644 index b0bac4f4b..000000000 Binary files a/assets/items/gray_vortex_shield.png and /dev/null differ diff --git a/assets/items/gray_war_staff.png b/assets/items/gray_war_staff.png deleted file mode 100644 index 51460c4dd..000000000 Binary files a/assets/items/gray_war_staff.png and /dev/null differ diff --git a/assets/items/gray_weapon_berserker_axe.png b/assets/items/gray_weapon_berserker_axe.png deleted file mode 100644 index b4fba158d..000000000 Binary files a/assets/items/gray_weapon_berserker_axe.png and /dev/null differ diff --git a/assets/items/gray_weapon_colossus_voulge.png b/assets/items/gray_weapon_colossus_voulge.png deleted file mode 100644 index c71ac7526..000000000 Binary files a/assets/items/gray_weapon_colossus_voulge.png and /dev/null differ diff --git a/assets/items/gray_weapon_cryptic_axe.png b/assets/items/gray_weapon_cryptic_axe.png deleted file mode 100644 index 94a0f1f06..000000000 Binary files a/assets/items/gray_weapon_cryptic_axe.png and /dev/null differ diff --git a/assets/items/gray_weapon_crystal_sword.png b/assets/items/gray_weapon_crystal_sword.png deleted file mode 100644 index 816ae5b54..000000000 Binary files a/assets/items/gray_weapon_crystal_sword.png and /dev/null differ diff --git a/assets/items/gray_weapon_flail.png b/assets/items/gray_weapon_flail.png deleted file mode 100644 index 4a6d04c01..000000000 Binary files a/assets/items/gray_weapon_flail.png and /dev/null differ diff --git a/assets/items/gray_weapon_ghost_spear.png b/assets/items/gray_weapon_ghost_spear.png deleted file mode 100644 index f5addbccf..000000000 Binary files a/assets/items/gray_weapon_ghost_spear.png and /dev/null differ diff --git a/assets/items/gray_weapon_giant_thresher.png b/assets/items/gray_weapon_giant_thresher.png deleted file mode 100644 index 18ed09789..000000000 Binary files a/assets/items/gray_weapon_giant_thresher.png and /dev/null differ diff --git a/assets/items/gray_weapon_grand_matron_bow.png b/assets/items/gray_weapon_grand_matron_bow.png deleted file mode 100644 index 36ce60da6..000000000 Binary files a/assets/items/gray_weapon_grand_matron_bow.png and /dev/null differ diff --git a/assets/items/gray_weapon_great_poleaxe.png b/assets/items/gray_weapon_great_poleaxe.png deleted file mode 100644 index 049244ce6..000000000 Binary files a/assets/items/gray_weapon_great_poleaxe.png and /dev/null differ diff --git a/assets/items/gray_weapon_phase_blade.png b/assets/items/gray_weapon_phase_blade.png deleted file mode 100644 index 7df0c671b..000000000 Binary files a/assets/items/gray_weapon_phase_blade.png and /dev/null differ diff --git a/assets/items/gray_weapon_superior_colossus_voulge.png b/assets/items/gray_weapon_superior_colossus_voulge.png deleted file mode 100644 index c40e300c3..000000000 Binary files a/assets/items/gray_weapon_superior_colossus_voulge.png and /dev/null differ diff --git a/assets/items/gray_weapon_superior_cryptic_axe.png b/assets/items/gray_weapon_superior_cryptic_axe.png deleted file mode 100644 index 99dac6c88..000000000 Binary files a/assets/items/gray_weapon_superior_cryptic_axe.png and /dev/null differ diff --git a/assets/items/gray_weapon_superior_giant_thresher.png b/assets/items/gray_weapon_superior_giant_thresher.png deleted file mode 100644 index 5c828ecd8..000000000 Binary files a/assets/items/gray_weapon_superior_giant_thresher.png and /dev/null differ diff --git a/assets/items/gray_weapon_superior_grand_matron_bow.png b/assets/items/gray_weapon_superior_grand_matron_bow.png deleted file mode 100644 index f9493a2d3..000000000 Binary files a/assets/items/gray_weapon_superior_grand_matron_bow.png and /dev/null differ diff --git a/assets/items/gray_weapon_superior_thresher.png b/assets/items/gray_weapon_superior_thresher.png deleted file mode 100644 index 572c856c6..000000000 Binary files a/assets/items/gray_weapon_superior_thresher.png and /dev/null differ diff --git a/assets/items/gray_weapon_thresher.png b/assets/items/gray_weapon_thresher.png deleted file mode 100644 index da7dcc626..000000000 Binary files a/assets/items/gray_weapon_thresher.png and /dev/null differ diff --git a/assets/items/gray_weapon_war_pike.png b/assets/items/gray_weapon_war_pike.png deleted file mode 100644 index f3ba1392c..000000000 Binary files a/assets/items/gray_weapon_war_pike.png and /dev/null differ diff --git a/assets/items/gray_weapon_war_scepter.png b/assets/items/gray_weapon_war_scepter.png deleted file mode 100644 index eac03b221..000000000 Binary files a/assets/items/gray_weapon_war_scepter.png and /dev/null differ diff --git a/assets/items/gray_zakarum_shield.png b/assets/items/gray_zakarum_shield.png deleted file mode 100644 index f41428254..000000000 Binary files a/assets/items/gray_zakarum_shield.png and /dev/null differ diff --git a/assets/items/magic_amulet.png b/assets/items/magic_amulet.png deleted file mode 100644 index 751953900..000000000 Binary files a/assets/items/magic_amulet.png and /dev/null differ diff --git a/assets/items/magic_archon_plate.png b/assets/items/magic_archon_plate.png deleted file mode 100644 index 9408bd782..000000000 Binary files a/assets/items/magic_archon_plate.png and /dev/null differ diff --git a/assets/items/magic_blood_spirit.png b/assets/items/magic_blood_spirit.png deleted file mode 100644 index 935c42621..000000000 Binary files a/assets/items/magic_blood_spirit.png and /dev/null differ diff --git a/assets/items/magic_bramble_mitts.png b/assets/items/magic_bramble_mitts.png deleted file mode 100644 index 035c828ff..000000000 Binary files a/assets/items/magic_bramble_mitts.png and /dev/null differ diff --git a/assets/items/magic_ceremonial_javelin.png b/assets/items/magic_ceremonial_javelin.png deleted file mode 100644 index f82c0ef75..000000000 Binary files a/assets/items/magic_ceremonial_javelin.png and /dev/null differ diff --git a/assets/items/magic_circlet.png b/assets/items/magic_circlet.png deleted file mode 100644 index e342aa731..000000000 Binary files a/assets/items/magic_circlet.png and /dev/null differ diff --git a/assets/items/magic_conqueror_crown.png b/assets/items/magic_conqueror_crown.png deleted file mode 100644 index b9b1674e8..000000000 Binary files a/assets/items/magic_conqueror_crown.png and /dev/null differ diff --git a/assets/items/magic_coronet.png b/assets/items/magic_coronet.png deleted file mode 100644 index 895e8b968..000000000 Binary files a/assets/items/magic_coronet.png and /dev/null differ diff --git a/assets/items/magic_crusader_gauntlets.png b/assets/items/magic_crusader_gauntlets.png deleted file mode 100644 index 288cb0759..000000000 Binary files a/assets/items/magic_crusader_gauntlets.png and /dev/null differ diff --git a/assets/items/magic_destroyer_helm.png b/assets/items/magic_destroyer_helm.png deleted file mode 100644 index 19d62ddeb..000000000 Binary files a/assets/items/magic_destroyer_helm.png and /dev/null differ diff --git a/assets/items/magic_diadem.png b/assets/items/magic_diadem.png deleted file mode 100644 index 62c6dcb6d..000000000 Binary files a/assets/items/magic_diadem.png and /dev/null differ diff --git a/assets/items/magic_dream_spirit.png b/assets/items/magic_dream_spirit.png deleted file mode 100644 index 25cae0fea..000000000 Binary files a/assets/items/magic_dream_spirit.png and /dev/null differ diff --git a/assets/items/magic_dusk_shroud.png b/assets/items/magic_dusk_shroud.png deleted file mode 100644 index 6ae335e66..000000000 Binary files a/assets/items/magic_dusk_shroud.png and /dev/null differ diff --git a/assets/items/magic_earth_spirit.png b/assets/items/magic_earth_spirit.png deleted file mode 100644 index 05ec0ada8..000000000 Binary files a/assets/items/magic_earth_spirit.png and /dev/null differ diff --git a/assets/items/magic_feral_claws.png b/assets/items/magic_feral_claws.png deleted file mode 100644 index fff8f4103..000000000 Binary files a/assets/items/magic_feral_claws.png and /dev/null differ diff --git a/assets/items/magic_gg_club.png b/assets/items/magic_gg_club.png deleted file mode 100644 index a2241e76c..000000000 Binary files a/assets/items/magic_gg_club.png and /dev/null differ diff --git a/assets/items/magic_ghost_wand.png b/assets/items/magic_ghost_wand.png deleted file mode 100644 index 08095784a..000000000 Binary files a/assets/items/magic_ghost_wand.png and /dev/null differ diff --git a/assets/items/magic_grand_charm.png b/assets/items/magic_grand_charm.png deleted file mode 100644 index 007d2d777..000000000 Binary files a/assets/items/magic_grand_charm.png and /dev/null differ diff --git a/assets/items/magic_greater_claws.png b/assets/items/magic_greater_claws.png deleted file mode 100644 index 15db16ce7..000000000 Binary files a/assets/items/magic_greater_claws.png and /dev/null differ diff --git a/assets/items/magic_greater_talons.png b/assets/items/magic_greater_talons.png deleted file mode 100644 index dd39eb7c0..000000000 Binary files a/assets/items/magic_greater_talons.png and /dev/null differ diff --git a/assets/items/magic_guardian_crown.png b/assets/items/magic_guardian_crown.png deleted file mode 100644 index f19a1a656..000000000 Binary files a/assets/items/magic_guardian_crown.png and /dev/null differ diff --git a/assets/items/magic_jewel.png b/assets/items/magic_jewel.png deleted file mode 100644 index 063f6b393..000000000 Binary files a/assets/items/magic_jewel.png and /dev/null differ diff --git a/assets/items/magic_kurast_shield.png b/assets/items/magic_kurast_shield.png deleted file mode 100644 index 76aff14a9..000000000 Binary files a/assets/items/magic_kurast_shield.png and /dev/null differ diff --git a/assets/items/magic_large_charm.png b/assets/items/magic_large_charm.png deleted file mode 100644 index 462d8e212..000000000 Binary files a/assets/items/magic_large_charm.png and /dev/null differ diff --git a/assets/items/magic_lich_wand.png b/assets/items/magic_lich_wand.png deleted file mode 100644 index 297bf616b..000000000 Binary files a/assets/items/magic_lich_wand.png and /dev/null differ diff --git a/assets/items/magic_light_plate.png b/assets/items/magic_light_plate.png deleted file mode 100644 index 991e1f587..000000000 Binary files a/assets/items/magic_light_plate.png and /dev/null differ diff --git a/assets/items/magic_mage_plate.png b/assets/items/magic_mage_plate.png deleted file mode 100644 index ae1a5a264..000000000 Binary files a/assets/items/magic_mage_plate.png and /dev/null differ diff --git a/assets/items/magic_matriarchal_javelin.png b/assets/items/magic_matriarchal_javelin.png deleted file mode 100644 index e128fe374..000000000 Binary files a/assets/items/magic_matriarchal_javelin.png and /dev/null differ diff --git a/assets/items/magic_monarch.png b/assets/items/magic_monarch.png deleted file mode 100644 index b1695eaad..000000000 Binary files a/assets/items/magic_monarch.png and /dev/null differ diff --git a/assets/items/magic_ogre_gauntlets.png b/assets/items/magic_ogre_gauntlets.png deleted file mode 100644 index fff358ebf..000000000 Binary files a/assets/items/magic_ogre_gauntlets.png and /dev/null differ diff --git a/assets/items/magic_polished_wand.png b/assets/items/magic_polished_wand.png deleted file mode 100644 index 96e30ece6..000000000 Binary files a/assets/items/magic_polished_wand.png and /dev/null differ diff --git a/assets/items/magic_runic_talons.png b/assets/items/magic_runic_talons.png deleted file mode 100644 index 8fa14a0ba..000000000 Binary files a/assets/items/magic_runic_talons.png and /dev/null differ diff --git a/assets/items/magic_sacred_rondache.png b/assets/items/magic_sacred_rondache.png deleted file mode 100644 index 53d42bd92..000000000 Binary files a/assets/items/magic_sacred_rondache.png and /dev/null differ diff --git a/assets/items/magic_sacred_targe.png b/assets/items/magic_sacred_targe.png deleted file mode 100644 index 47638aaec..000000000 Binary files a/assets/items/magic_sacred_targe.png and /dev/null differ diff --git a/assets/items/magic_scarab_husk.png b/assets/items/magic_scarab_husk.png deleted file mode 100644 index ae648e36f..000000000 Binary files a/assets/items/magic_scarab_husk.png and /dev/null differ diff --git a/assets/items/magic_sky_spirit.png b/assets/items/magic_sky_spirit.png deleted file mode 100644 index ffc036db6..000000000 Binary files a/assets/items/magic_sky_spirit.png and /dev/null differ diff --git a/assets/items/magic_small_charm.png b/assets/items/magic_small_charm.png deleted file mode 100644 index ee7055852..000000000 Binary files a/assets/items/magic_small_charm.png and /dev/null differ diff --git a/assets/items/magic_sun_spirit.png b/assets/items/magic_sun_spirit.png deleted file mode 100644 index 3d89a262c..000000000 Binary files a/assets/items/magic_sun_spirit.png and /dev/null differ diff --git a/assets/items/magic_suwayyah.png b/assets/items/magic_suwayyah.png deleted file mode 100644 index 8a8e2bce3..000000000 Binary files a/assets/items/magic_suwayyah.png and /dev/null differ diff --git a/assets/items/magic_tiara.png b/assets/items/magic_tiara.png deleted file mode 100644 index 9f571a099..000000000 Binary files a/assets/items/magic_tiara.png and /dev/null differ diff --git a/assets/items/magic_unearthed_wand.png b/assets/items/magic_unearthed_wand.png deleted file mode 100644 index 8aac81d05..000000000 Binary files a/assets/items/magic_unearthed_wand.png and /dev/null differ diff --git a/assets/items/magic_vambraces.png b/assets/items/magic_vambraces.png deleted file mode 100644 index 889e068f5..000000000 Binary files a/assets/items/magic_vambraces.png and /dev/null differ diff --git a/assets/items/magic_vampirebone_gloves.png b/assets/items/magic_vampirebone_gloves.png deleted file mode 100644 index 2d0b8f588..000000000 Binary files a/assets/items/magic_vampirebone_gloves.png and /dev/null differ diff --git a/assets/items/magic_vortex_shield.png b/assets/items/magic_vortex_shield.png deleted file mode 100644 index 7ff877406..000000000 Binary files a/assets/items/magic_vortex_shield.png and /dev/null differ diff --git a/assets/items/magic_wire_fleece.png b/assets/items/magic_wire_fleece.png deleted file mode 100644 index 34e113caf..000000000 Binary files a/assets/items/magic_wire_fleece.png and /dev/null differ diff --git a/assets/items/magic_wyrmhide.png b/assets/items/magic_wyrmhide.png deleted file mode 100644 index a1d500495..000000000 Binary files a/assets/items/magic_wyrmhide.png and /dev/null differ diff --git a/assets/items/magic_zakarum_shield.png b/assets/items/magic_zakarum_shield.png deleted file mode 100644 index 4abc49092..000000000 Binary files a/assets/items/magic_zakarum_shield.png and /dev/null differ diff --git a/assets/items/misc_amethyst.png b/assets/items/misc_amethyst.png deleted file mode 100644 index 5101d46db..000000000 Binary files a/assets/items/misc_amethyst.png and /dev/null differ diff --git a/assets/items/misc_chipped_amethyst.png b/assets/items/misc_chipped_amethyst.png deleted file mode 100644 index a401b313b..000000000 Binary files a/assets/items/misc_chipped_amethyst.png and /dev/null differ diff --git a/assets/items/misc_chipped_diamond.png b/assets/items/misc_chipped_diamond.png deleted file mode 100644 index b78ea9dcb..000000000 Binary files a/assets/items/misc_chipped_diamond.png and /dev/null differ diff --git a/assets/items/misc_chipped_emerald.png b/assets/items/misc_chipped_emerald.png deleted file mode 100644 index 67b67cad5..000000000 Binary files a/assets/items/misc_chipped_emerald.png and /dev/null differ diff --git a/assets/items/misc_chipped_ruby.png b/assets/items/misc_chipped_ruby.png deleted file mode 100644 index 4b4f71e22..000000000 Binary files a/assets/items/misc_chipped_ruby.png and /dev/null differ diff --git a/assets/items/misc_chipped_sapphire.png b/assets/items/misc_chipped_sapphire.png deleted file mode 100644 index 4a61f1e0b..000000000 Binary files a/assets/items/misc_chipped_sapphire.png and /dev/null differ diff --git a/assets/items/misc_chipped_skull.png b/assets/items/misc_chipped_skull.png deleted file mode 100644 index ac7bb447f..000000000 Binary files a/assets/items/misc_chipped_skull.png and /dev/null differ diff --git a/assets/items/misc_chipped_topaz.png b/assets/items/misc_chipped_topaz.png deleted file mode 100644 index 6a61cabf9..000000000 Binary files a/assets/items/misc_chipped_topaz.png and /dev/null differ diff --git a/assets/items/misc_diamond.png b/assets/items/misc_diamond.png deleted file mode 100644 index 4a7686305..000000000 Binary files a/assets/items/misc_diamond.png and /dev/null differ diff --git a/assets/items/misc_emerald.png b/assets/items/misc_emerald.png deleted file mode 100644 index 82cf8323b..000000000 Binary files a/assets/items/misc_emerald.png and /dev/null differ diff --git a/assets/items/misc_essence_of_terror.png b/assets/items/misc_essence_of_terror.png deleted file mode 100644 index 9d6e9c9c3..000000000 Binary files a/assets/items/misc_essence_of_terror.png and /dev/null differ diff --git a/assets/items/misc_flawed_amethyst.png b/assets/items/misc_flawed_amethyst.png deleted file mode 100644 index 561757a65..000000000 Binary files a/assets/items/misc_flawed_amethyst.png and /dev/null differ diff --git a/assets/items/misc_flawed_diamond.png b/assets/items/misc_flawed_diamond.png deleted file mode 100644 index dc1d57b2f..000000000 Binary files a/assets/items/misc_flawed_diamond.png and /dev/null differ diff --git a/assets/items/misc_flawed_emerald.png b/assets/items/misc_flawed_emerald.png deleted file mode 100644 index 7eed44cbe..000000000 Binary files a/assets/items/misc_flawed_emerald.png and /dev/null differ diff --git a/assets/items/misc_flawed_ruby.png b/assets/items/misc_flawed_ruby.png deleted file mode 100644 index 7773dde61..000000000 Binary files a/assets/items/misc_flawed_ruby.png and /dev/null differ diff --git a/assets/items/misc_flawed_sapphire.png b/assets/items/misc_flawed_sapphire.png deleted file mode 100644 index 071659cb9..000000000 Binary files a/assets/items/misc_flawed_sapphire.png and /dev/null differ diff --git a/assets/items/misc_flawed_skull.png b/assets/items/misc_flawed_skull.png deleted file mode 100644 index 9f5831cf8..000000000 Binary files a/assets/items/misc_flawed_skull.png and /dev/null differ diff --git a/assets/items/misc_flawed_topaz.png b/assets/items/misc_flawed_topaz.png deleted file mode 100644 index e68aad846..000000000 Binary files a/assets/items/misc_flawed_topaz.png and /dev/null differ diff --git a/assets/items/misc_flawless_amethyst.png b/assets/items/misc_flawless_amethyst.png deleted file mode 100644 index 324042c6c..000000000 Binary files a/assets/items/misc_flawless_amethyst.png and /dev/null differ diff --git a/assets/items/misc_flawless_diamond.png b/assets/items/misc_flawless_diamond.png deleted file mode 100644 index 922684c62..000000000 Binary files a/assets/items/misc_flawless_diamond.png and /dev/null differ diff --git a/assets/items/misc_flawless_emerald.png b/assets/items/misc_flawless_emerald.png deleted file mode 100644 index 7878c54eb..000000000 Binary files a/assets/items/misc_flawless_emerald.png and /dev/null differ diff --git a/assets/items/misc_flawless_ruby.png b/assets/items/misc_flawless_ruby.png deleted file mode 100644 index 118a0d8dd..000000000 Binary files a/assets/items/misc_flawless_ruby.png and /dev/null differ diff --git a/assets/items/misc_flawless_sapphire.png b/assets/items/misc_flawless_sapphire.png deleted file mode 100644 index 8f9027707..000000000 Binary files a/assets/items/misc_flawless_sapphire.png and /dev/null differ diff --git a/assets/items/misc_flawless_skull.png b/assets/items/misc_flawless_skull.png deleted file mode 100644 index cca2db788..000000000 Binary files a/assets/items/misc_flawless_skull.png and /dev/null differ diff --git a/assets/items/misc_flawless_topaz.png b/assets/items/misc_flawless_topaz.png deleted file mode 100644 index 073072bda..000000000 Binary files a/assets/items/misc_flawless_topaz.png and /dev/null differ diff --git a/assets/items/misc_full_rejuvenation_potion.PNG b/assets/items/misc_full_rejuvenation_potion.PNG deleted file mode 100644 index 3fc9dfa05..000000000 Binary files a/assets/items/misc_full_rejuvenation_potion.PNG and /dev/null differ diff --git a/assets/items/misc_gold.png b/assets/items/misc_gold.png deleted file mode 100644 index 7428bc3e6..000000000 Binary files a/assets/items/misc_gold.png and /dev/null differ diff --git a/assets/items/misc_greater_healing_potion.png b/assets/items/misc_greater_healing_potion.png deleted file mode 100644 index 9aa56fa5f..000000000 Binary files a/assets/items/misc_greater_healing_potion.png and /dev/null differ diff --git a/assets/items/misc_greater_mana_potion.png b/assets/items/misc_greater_mana_potion.png deleted file mode 100644 index f3ebaddff..000000000 Binary files a/assets/items/misc_greater_mana_potion.png and /dev/null differ diff --git a/assets/items/misc_key.png b/assets/items/misc_key.png deleted file mode 100644 index 9c398c7ff..000000000 Binary files a/assets/items/misc_key.png and /dev/null differ diff --git a/assets/items/misc_key_of_destruction.png b/assets/items/misc_key_of_destruction.png deleted file mode 100644 index b522485ac..000000000 Binary files a/assets/items/misc_key_of_destruction.png and /dev/null differ diff --git a/assets/items/misc_key_of_hate.png b/assets/items/misc_key_of_hate.png deleted file mode 100644 index 4b2a376ce..000000000 Binary files a/assets/items/misc_key_of_hate.png and /dev/null differ diff --git a/assets/items/misc_key_of_terror.png b/assets/items/misc_key_of_terror.png deleted file mode 100644 index 6d70f2d53..000000000 Binary files a/assets/items/misc_key_of_terror.png and /dev/null differ diff --git a/assets/items/misc_rejuvenation_potion.PNG b/assets/items/misc_rejuvenation_potion.PNG deleted file mode 100644 index 26f8fd802..000000000 Binary files a/assets/items/misc_rejuvenation_potion.PNG and /dev/null differ diff --git a/assets/items/misc_ruby.png b/assets/items/misc_ruby.png deleted file mode 100644 index 93136ea21..000000000 Binary files a/assets/items/misc_ruby.png and /dev/null differ diff --git a/assets/items/misc_sapphire.png b/assets/items/misc_sapphire.png deleted file mode 100644 index 403f9d78f..000000000 Binary files a/assets/items/misc_sapphire.png and /dev/null differ diff --git a/assets/items/misc_scroll_id.png b/assets/items/misc_scroll_id.png deleted file mode 100644 index 8fc264b0d..000000000 Binary files a/assets/items/misc_scroll_id.png and /dev/null differ diff --git a/assets/items/misc_scroll_tp.png b/assets/items/misc_scroll_tp.png deleted file mode 100644 index 143f56176..000000000 Binary files a/assets/items/misc_scroll_tp.png and /dev/null differ diff --git a/assets/items/misc_skull.png b/assets/items/misc_skull.png deleted file mode 100644 index bae683297..000000000 Binary files a/assets/items/misc_skull.png and /dev/null differ diff --git a/assets/items/misc_super_healing_potion.png b/assets/items/misc_super_healing_potion.png deleted file mode 100644 index 903fbe8d8..000000000 Binary files a/assets/items/misc_super_healing_potion.png and /dev/null differ diff --git a/assets/items/misc_super_mana_potion.png b/assets/items/misc_super_mana_potion.png deleted file mode 100644 index 967006bca..000000000 Binary files a/assets/items/misc_super_mana_potion.png and /dev/null differ diff --git a/assets/items/misc_topaz.png b/assets/items/misc_topaz.png deleted file mode 100644 index 63c2f731f..000000000 Binary files a/assets/items/misc_topaz.png and /dev/null differ diff --git a/assets/items/rare_alpha_helm.png b/assets/items/rare_alpha_helm.png deleted file mode 100644 index c0b632593..000000000 Binary files a/assets/items/rare_alpha_helm.png and /dev/null differ diff --git a/assets/items/rare_amulet.png b/assets/items/rare_amulet.png deleted file mode 100644 index c83db887f..000000000 Binary files a/assets/items/rare_amulet.png and /dev/null differ diff --git a/assets/items/rare_ancient_armor.png b/assets/items/rare_ancient_armor.png deleted file mode 100644 index 4cb855959..000000000 Binary files a/assets/items/rare_ancient_armor.png and /dev/null differ diff --git a/assets/items/rare_ancient_axe.png b/assets/items/rare_ancient_axe.png deleted file mode 100644 index 1163b1ffa..000000000 Binary files a/assets/items/rare_ancient_axe.png and /dev/null differ diff --git a/assets/items/rare_ancient_sword.png b/assets/items/rare_ancient_sword.png deleted file mode 100644 index 27028f3fa..000000000 Binary files a/assets/items/rare_ancient_sword.png and /dev/null differ diff --git a/assets/items/rare_antlers.png b/assets/items/rare_antlers.png deleted file mode 100644 index b2fc8f0a1..000000000 Binary files a/assets/items/rare_antlers.png and /dev/null differ diff --git a/assets/items/rare_archon_plate.png b/assets/items/rare_archon_plate.png deleted file mode 100644 index 70a171564..000000000 Binary files a/assets/items/rare_archon_plate.png and /dev/null differ diff --git a/assets/items/rare_armet.png b/assets/items/rare_armet.png deleted file mode 100644 index 075e83d1c..000000000 Binary files a/assets/items/rare_armet.png and /dev/null differ diff --git a/assets/items/rare_ashwood_bow.png b/assets/items/rare_ashwood_bow.png deleted file mode 100644 index 94d9a0ecf..000000000 Binary files a/assets/items/rare_ashwood_bow.png and /dev/null differ diff --git a/assets/items/rare_assault_helm.png b/assets/items/rare_assault_helm.png deleted file mode 100644 index 2a2de68ef..000000000 Binary files a/assets/items/rare_assault_helm.png and /dev/null differ diff --git a/assets/items/rare_ataghan.png b/assets/items/rare_ataghan.png deleted file mode 100644 index 0dbfec0c3..000000000 Binary files a/assets/items/rare_ataghan.png and /dev/null differ diff --git a/assets/items/rare_avenger_guard.png b/assets/items/rare_avenger_guard.png deleted file mode 100644 index 83ec742ef..000000000 Binary files a/assets/items/rare_avenger_guard.png and /dev/null differ diff --git a/assets/items/rare_axe.png b/assets/items/rare_axe.png deleted file mode 100644 index 620a23f3b..000000000 Binary files a/assets/items/rare_axe.png and /dev/null differ diff --git a/assets/items/rare_balanced_axe.png b/assets/items/rare_balanced_axe.png deleted file mode 100644 index 73c0eee25..000000000 Binary files a/assets/items/rare_balanced_axe.png and /dev/null differ diff --git a/assets/items/rare_balanced_knife.png b/assets/items/rare_balanced_knife.png deleted file mode 100644 index d3b3096b6..000000000 Binary files a/assets/items/rare_balanced_knife.png and /dev/null differ diff --git a/assets/items/rare_balrog_blade.png b/assets/items/rare_balrog_blade.png deleted file mode 100644 index e1723de78..000000000 Binary files a/assets/items/rare_balrog_blade.png and /dev/null differ diff --git a/assets/items/rare_balrog_skin.png b/assets/items/rare_balrog_skin.png deleted file mode 100644 index f50b2cb7f..000000000 Binary files a/assets/items/rare_balrog_skin.png and /dev/null differ diff --git a/assets/items/rare_balrog_spear.png b/assets/items/rare_balrog_spear.png deleted file mode 100644 index e7a2a5561..000000000 Binary files a/assets/items/rare_balrog_spear.png and /dev/null differ diff --git a/assets/items/rare_barbed_club.png b/assets/items/rare_barbed_club.png deleted file mode 100644 index a251a8354..000000000 Binary files a/assets/items/rare_barbed_club.png and /dev/null differ diff --git a/assets/items/rare_bardiche.png b/assets/items/rare_bardiche.png deleted file mode 100644 index f2b3be4b2..000000000 Binary files a/assets/items/rare_bardiche.png and /dev/null differ diff --git a/assets/items/rare_bastard_sword.png b/assets/items/rare_bastard_sword.png deleted file mode 100644 index 6886e238d..000000000 Binary files a/assets/items/rare_bastard_sword.png and /dev/null differ diff --git a/assets/items/rare_battle_axe.png b/assets/items/rare_battle_axe.png deleted file mode 100644 index 95dd24bc5..000000000 Binary files a/assets/items/rare_battle_axe.png and /dev/null differ diff --git a/assets/items/rare_battle_belt.png b/assets/items/rare_battle_belt.png deleted file mode 100644 index 79f7be93c..000000000 Binary files a/assets/items/rare_battle_belt.png and /dev/null differ diff --git a/assets/items/rare_battle_boots.png b/assets/items/rare_battle_boots.png deleted file mode 100644 index 1787119e0..000000000 Binary files a/assets/items/rare_battle_boots.png and /dev/null differ diff --git a/assets/items/rare_battle_cestus.png b/assets/items/rare_battle_cestus.png deleted file mode 100644 index a495e8e79..000000000 Binary files a/assets/items/rare_battle_cestus.png and /dev/null differ diff --git a/assets/items/rare_battle_dart.png b/assets/items/rare_battle_dart.png deleted file mode 100644 index 38474e4ad..000000000 Binary files a/assets/items/rare_battle_dart.png and /dev/null differ diff --git a/assets/items/rare_battle_gauntlets.png b/assets/items/rare_battle_gauntlets.png deleted file mode 100644 index e1d05acdd..000000000 Binary files a/assets/items/rare_battle_gauntlets.png and /dev/null differ diff --git a/assets/items/rare_battle_hammer.png b/assets/items/rare_battle_hammer.png deleted file mode 100644 index ab01b3014..000000000 Binary files a/assets/items/rare_battle_hammer.png and /dev/null differ diff --git a/assets/items/rare_battle_scythe.png b/assets/items/rare_battle_scythe.png deleted file mode 100644 index 7bdc60c94..000000000 Binary files a/assets/items/rare_battle_scythe.png and /dev/null differ diff --git a/assets/items/rare_battle_sword.png b/assets/items/rare_battle_sword.png deleted file mode 100644 index a76894b82..000000000 Binary files a/assets/items/rare_battle_sword.png and /dev/null differ diff --git a/assets/items/rare_bearded_axe.png b/assets/items/rare_bearded_axe.png deleted file mode 100644 index c4afb82a2..000000000 Binary files a/assets/items/rare_bearded_axe.png and /dev/null differ diff --git a/assets/items/rare_bec_de_corbin.png b/assets/items/rare_bec_de_corbin.png deleted file mode 100644 index 3fd7c941f..000000000 Binary files a/assets/items/rare_bec_de_corbin.png and /dev/null differ diff --git a/assets/items/rare_berserker_axe.png b/assets/items/rare_berserker_axe.png deleted file mode 100644 index 8101082ef..000000000 Binary files a/assets/items/rare_berserker_axe.png and /dev/null differ diff --git a/assets/items/rare_bill.png b/assets/items/rare_bill.png deleted file mode 100644 index 9eac7de3f..000000000 Binary files a/assets/items/rare_bill.png and /dev/null differ diff --git a/assets/items/rare_blade_barrier.png b/assets/items/rare_blade_barrier.png deleted file mode 100644 index 29bebbc14..000000000 Binary files a/assets/items/rare_blade_barrier.png and /dev/null differ diff --git a/assets/items/rare_blade_bow.png b/assets/items/rare_blade_bow.png deleted file mode 100644 index 24071dedc..000000000 Binary files a/assets/items/rare_blade_bow.png and /dev/null differ diff --git a/assets/items/rare_blade_talons.png b/assets/items/rare_blade_talons.png deleted file mode 100644 index 9c7a24005..000000000 Binary files a/assets/items/rare_blade_talons.png and /dev/null differ diff --git a/assets/items/rare_blood_spirit.png b/assets/items/rare_blood_spirit.png deleted file mode 100644 index 43cc9b2b2..000000000 Binary files a/assets/items/rare_blood_spirit.png and /dev/null differ diff --git a/assets/items/rare_bone_visage.png b/assets/items/rare_bone_visage.png deleted file mode 100644 index 6bd59fd04..000000000 Binary files a/assets/items/rare_bone_visage.png and /dev/null differ diff --git a/assets/items/rare_boneweave.png b/assets/items/rare_boneweave.png deleted file mode 100644 index 985d5f47f..000000000 Binary files a/assets/items/rare_boneweave.png and /dev/null differ diff --git a/assets/items/rare_boneweave_boots.png b/assets/items/rare_boneweave_boots.png deleted file mode 100644 index 98533a944..000000000 Binary files a/assets/items/rare_boneweave_boots.png and /dev/null differ diff --git a/assets/items/rare_boots.png b/assets/items/rare_boots.png deleted file mode 100644 index 5ee6b93e4..000000000 Binary files a/assets/items/rare_boots.png and /dev/null differ diff --git a/assets/items/rare_bramble_mitts.png b/assets/items/rare_bramble_mitts.png deleted file mode 100644 index f604a199d..000000000 Binary files a/assets/items/rare_bramble_mitts.png and /dev/null differ diff --git a/assets/items/rare_brandistock.png b/assets/items/rare_brandistock.png deleted file mode 100644 index 98688cf4e..000000000 Binary files a/assets/items/rare_brandistock.png and /dev/null differ diff --git a/assets/items/rare_breast_plate.png b/assets/items/rare_breast_plate.png deleted file mode 100644 index 62e5e1086..000000000 Binary files a/assets/items/rare_breast_plate.png and /dev/null differ diff --git a/assets/items/rare_broad_axe.png b/assets/items/rare_broad_axe.png deleted file mode 100644 index 0b8067f48..000000000 Binary files a/assets/items/rare_broad_axe.png and /dev/null differ diff --git a/assets/items/rare_broad_sword.png b/assets/items/rare_broad_sword.png deleted file mode 100644 index d5be5f75a..000000000 Binary files a/assets/items/rare_broad_sword.png and /dev/null differ diff --git a/assets/items/rare_carnage_helm.png b/assets/items/rare_carnage_helm.png deleted file mode 100644 index f61c9d915..000000000 Binary files a/assets/items/rare_carnage_helm.png and /dev/null differ diff --git a/assets/items/rare_ceremonial_javelin.png b/assets/items/rare_ceremonial_javelin.png deleted file mode 100644 index 67ddb3b78..000000000 Binary files a/assets/items/rare_ceremonial_javelin.png and /dev/null differ diff --git a/assets/items/rare_ceremonial_pike.png b/assets/items/rare_ceremonial_pike.png deleted file mode 100644 index 0718c7035..000000000 Binary files a/assets/items/rare_ceremonial_pike.png and /dev/null differ diff --git a/assets/items/rare_ceremonial_spear.png b/assets/items/rare_ceremonial_spear.png deleted file mode 100644 index 5f6daf97d..000000000 Binary files a/assets/items/rare_ceremonial_spear.png and /dev/null differ diff --git a/assets/items/rare_cestus.png b/assets/items/rare_cestus.png deleted file mode 100644 index 2791b0e6a..000000000 Binary files a/assets/items/rare_cestus.png and /dev/null differ diff --git a/assets/items/rare_chain_boots.png b/assets/items/rare_chain_boots.png deleted file mode 100644 index 7854236d8..000000000 Binary files a/assets/items/rare_chain_boots.png and /dev/null differ diff --git a/assets/items/rare_chain_gloves.png b/assets/items/rare_chain_gloves.png deleted file mode 100644 index 0384e482a..000000000 Binary files a/assets/items/rare_chain_gloves.png and /dev/null differ diff --git a/assets/items/rare_chain_mail.png b/assets/items/rare_chain_mail.png deleted file mode 100644 index 9550701f1..000000000 Binary files a/assets/items/rare_chain_mail.png and /dev/null differ diff --git a/assets/items/rare_champion_axe.png b/assets/items/rare_champion_axe.png deleted file mode 100644 index 249bbf3c5..000000000 Binary files a/assets/items/rare_champion_axe.png and /dev/null differ diff --git a/assets/items/rare_champion_sword.png b/assets/items/rare_champion_sword.png deleted file mode 100644 index d268b2a14..000000000 Binary files a/assets/items/rare_champion_sword.png and /dev/null differ diff --git a/assets/items/rare_chaos_armor.png b/assets/items/rare_chaos_armor.png deleted file mode 100644 index a69ef7f7e..000000000 Binary files a/assets/items/rare_chaos_armor.png and /dev/null differ diff --git a/assets/items/rare_circlet.png b/assets/items/rare_circlet.png deleted file mode 100644 index 99c8bfc42..000000000 Binary files a/assets/items/rare_circlet.png and /dev/null differ diff --git a/assets/items/rare_clasped_orb.png b/assets/items/rare_clasped_orb.png deleted file mode 100644 index 564fa0545..000000000 Binary files a/assets/items/rare_clasped_orb.png and /dev/null differ diff --git a/assets/items/rare_claws.png b/assets/items/rare_claws.png deleted file mode 100644 index feaf327e3..000000000 Binary files a/assets/items/rare_claws.png and /dev/null differ diff --git a/assets/items/rare_claymore.png b/assets/items/rare_claymore.png deleted file mode 100644 index 9da9f41db..000000000 Binary files a/assets/items/rare_claymore.png and /dev/null differ diff --git a/assets/items/rare_cleaver.png b/assets/items/rare_cleaver.png deleted file mode 100644 index 381a2422e..000000000 Binary files a/assets/items/rare_cleaver.png and /dev/null differ diff --git a/assets/items/rare_cloudy_sphere.png b/assets/items/rare_cloudy_sphere.png deleted file mode 100644 index 1c618355c..000000000 Binary files a/assets/items/rare_cloudy_sphere.png and /dev/null differ diff --git a/assets/items/rare_club.png b/assets/items/rare_club.png deleted file mode 100644 index a1ae306ac..000000000 Binary files a/assets/items/rare_club.png and /dev/null differ diff --git a/assets/items/rare_colossus_blade.png b/assets/items/rare_colossus_blade.png deleted file mode 100644 index b37777174..000000000 Binary files a/assets/items/rare_colossus_blade.png and /dev/null differ diff --git a/assets/items/rare_colossus_girdle.png b/assets/items/rare_colossus_girdle.png deleted file mode 100644 index 2408c8ea8..000000000 Binary files a/assets/items/rare_colossus_girdle.png and /dev/null differ diff --git a/assets/items/rare_colossus_sword.png b/assets/items/rare_colossus_sword.png deleted file mode 100644 index ea233a784..000000000 Binary files a/assets/items/rare_colossus_sword.png and /dev/null differ diff --git a/assets/items/rare_colossus_voulge.png b/assets/items/rare_colossus_voulge.png deleted file mode 100644 index cad6af4d4..000000000 Binary files a/assets/items/rare_colossus_voulge.png and /dev/null differ diff --git a/assets/items/rare_conqueror_crown.png b/assets/items/rare_conqueror_crown.png deleted file mode 100644 index c0f83c424..000000000 Binary files a/assets/items/rare_conqueror_crown.png and /dev/null differ diff --git a/assets/items/rare_conquest_sword.png b/assets/items/rare_conquest_sword.png deleted file mode 100644 index b3594dadd..000000000 Binary files a/assets/items/rare_conquest_sword.png and /dev/null differ diff --git a/assets/items/rare_coronet.png b/assets/items/rare_coronet.png deleted file mode 100644 index b0a52b9bf..000000000 Binary files a/assets/items/rare_coronet.png and /dev/null differ diff --git a/assets/items/rare_crowbill.png b/assets/items/rare_crowbill.png deleted file mode 100644 index d2aa5d0ac..000000000 Binary files a/assets/items/rare_crowbill.png and /dev/null differ diff --git a/assets/items/rare_crusader_gauntlets.png b/assets/items/rare_crusader_gauntlets.png deleted file mode 100644 index 0839089bc..000000000 Binary files a/assets/items/rare_crusader_gauntlets.png and /dev/null differ diff --git a/assets/items/rare_cryptic_axe.png b/assets/items/rare_cryptic_axe.png deleted file mode 100644 index c2328970e..000000000 Binary files a/assets/items/rare_cryptic_axe.png and /dev/null differ diff --git a/assets/items/rare_cryptic_sword.png b/assets/items/rare_cryptic_sword.png deleted file mode 100644 index 7a5ffb2d7..000000000 Binary files a/assets/items/rare_cryptic_sword.png and /dev/null differ diff --git a/assets/items/rare_crystal_sword.png b/assets/items/rare_crystal_sword.png deleted file mode 100644 index 7a75637df..000000000 Binary files a/assets/items/rare_crystal_sword.png and /dev/null differ diff --git a/assets/items/rare_crystalline_globe.png b/assets/items/rare_crystalline_globe.png deleted file mode 100644 index a4affc785..000000000 Binary files a/assets/items/rare_crystalline_globe.png and /dev/null differ diff --git a/assets/items/rare_cudgel.png b/assets/items/rare_cudgel.png deleted file mode 100644 index 7839ed497..000000000 Binary files a/assets/items/rare_cudgel.png and /dev/null differ diff --git a/assets/items/rare_cuirass.png b/assets/items/rare_cuirass.png deleted file mode 100644 index 3ba4ba382..000000000 Binary files a/assets/items/rare_cuirass.png and /dev/null differ diff --git a/assets/items/rare_cutlass.png b/assets/items/rare_cutlass.png deleted file mode 100644 index 3350080a7..000000000 Binary files a/assets/items/rare_cutlass.png and /dev/null differ diff --git a/assets/items/rare_dacian_falx.png b/assets/items/rare_dacian_falx.png deleted file mode 100644 index acf4058dd..000000000 Binary files a/assets/items/rare_dacian_falx.png and /dev/null differ diff --git a/assets/items/rare_decapitator.png b/assets/items/rare_decapitator.png deleted file mode 100644 index faf998cf2..000000000 Binary files a/assets/items/rare_decapitator.png and /dev/null differ diff --git a/assets/items/rare_demon_heart.png b/assets/items/rare_demon_heart.png deleted file mode 100644 index 945b712ad..000000000 Binary files a/assets/items/rare_demon_heart.png and /dev/null differ diff --git a/assets/items/rare_demonhead.png b/assets/items/rare_demonhead.png deleted file mode 100644 index ab8102e4f..000000000 Binary files a/assets/items/rare_demonhead.png and /dev/null differ diff --git a/assets/items/rare_demonhide_armor.png b/assets/items/rare_demonhide_armor.png deleted file mode 100644 index a923834f7..000000000 Binary files a/assets/items/rare_demonhide_armor.png and /dev/null differ diff --git a/assets/items/rare_demonhide_boots.png b/assets/items/rare_demonhide_boots.png deleted file mode 100644 index 94ba0ee03..000000000 Binary files a/assets/items/rare_demonhide_boots.png and /dev/null differ diff --git a/assets/items/rare_demonhide_gloves.png b/assets/items/rare_demonhide_gloves.png deleted file mode 100644 index 038679c48..000000000 Binary files a/assets/items/rare_demonhide_gloves.png and /dev/null differ diff --git a/assets/items/rare_demonhide_sash.png b/assets/items/rare_demonhide_sash.png deleted file mode 100644 index 3defd32ac..000000000 Binary files a/assets/items/rare_demonhide_sash.png and /dev/null differ diff --git a/assets/items/rare_destroyer_helm.png b/assets/items/rare_destroyer_helm.png deleted file mode 100644 index c861bf794..000000000 Binary files a/assets/items/rare_destroyer_helm.png and /dev/null differ diff --git a/assets/items/rare_devil_star.png b/assets/items/rare_devil_star.png deleted file mode 100644 index cf6d74d3b..000000000 Binary files a/assets/items/rare_devil_star.png and /dev/null differ diff --git a/assets/items/rare_diadem.png b/assets/items/rare_diadem.png deleted file mode 100644 index 94ec71b0c..000000000 Binary files a/assets/items/rare_diadem.png and /dev/null differ diff --git a/assets/items/rare_diamond_bow.png b/assets/items/rare_diamond_bow.png deleted file mode 100644 index ff0be0470..000000000 Binary files a/assets/items/rare_diamond_bow.png and /dev/null differ diff --git a/assets/items/rare_diamond_mail.png b/assets/items/rare_diamond_mail.png deleted file mode 100644 index fbaa63c8b..000000000 Binary files a/assets/items/rare_diamond_mail.png and /dev/null differ diff --git a/assets/items/rare_dimensional_blade.png b/assets/items/rare_dimensional_blade.png deleted file mode 100644 index 407889465..000000000 Binary files a/assets/items/rare_dimensional_blade.png and /dev/null differ diff --git a/assets/items/rare_dimensional_shard.png b/assets/items/rare_dimensional_shard.png deleted file mode 100644 index 96690a7c0..000000000 Binary files a/assets/items/rare_dimensional_shard.png and /dev/null differ diff --git a/assets/items/rare_double_axe.png b/assets/items/rare_double_axe.png deleted file mode 100644 index 4e86180d0..000000000 Binary files a/assets/items/rare_double_axe.png and /dev/null differ diff --git a/assets/items/rare_double_bow.png b/assets/items/rare_double_bow.png deleted file mode 100644 index 861634306..000000000 Binary files a/assets/items/rare_double_bow.png and /dev/null differ diff --git a/assets/items/rare_dream_spirit.png b/assets/items/rare_dream_spirit.png deleted file mode 100644 index a4d638881..000000000 Binary files a/assets/items/rare_dream_spirit.png and /dev/null differ diff --git a/assets/items/rare_dusk_shroud.png b/assets/items/rare_dusk_shroud.png deleted file mode 100644 index feac44808..000000000 Binary files a/assets/items/rare_dusk_shroud.png and /dev/null differ diff --git a/assets/items/rare_eagle_orb.png b/assets/items/rare_eagle_orb.png deleted file mode 100644 index 16ef25b86..000000000 Binary files a/assets/items/rare_eagle_orb.png and /dev/null differ diff --git a/assets/items/rare_earth_spirit.png b/assets/items/rare_earth_spirit.png deleted file mode 100644 index e1767827d..000000000 Binary files a/assets/items/rare_earth_spirit.png and /dev/null differ diff --git a/assets/items/rare_eldritch_orb.png b/assets/items/rare_eldritch_orb.png deleted file mode 100644 index de2df4a24..000000000 Binary files a/assets/items/rare_eldritch_orb.png and /dev/null differ diff --git a/assets/items/rare_elegant_blade.png b/assets/items/rare_elegant_blade.png deleted file mode 100644 index 2cb1bfa69..000000000 Binary files a/assets/items/rare_elegant_blade.png and /dev/null differ diff --git a/assets/items/rare_embossed_plate.png b/assets/items/rare_embossed_plate.png deleted file mode 100644 index a174c956d..000000000 Binary files a/assets/items/rare_embossed_plate.png and /dev/null differ diff --git a/assets/items/rare_espandon.png b/assets/items/rare_espandon.png deleted file mode 100644 index 957fb574b..000000000 Binary files a/assets/items/rare_espandon.png and /dev/null differ diff --git a/assets/items/rare_ettin_axe.png b/assets/items/rare_ettin_axe.png deleted file mode 100644 index 8e4c5ae1b..000000000 Binary files a/assets/items/rare_ettin_axe.png and /dev/null differ diff --git a/assets/items/rare_executioner_sword.png b/assets/items/rare_executioner_sword.png deleted file mode 100644 index 625f11498..000000000 Binary files a/assets/items/rare_executioner_sword.png and /dev/null differ diff --git a/assets/items/rare_falcata.png b/assets/items/rare_falcata.png deleted file mode 100644 index 695f53107..000000000 Binary files a/assets/items/rare_falcata.png and /dev/null differ diff --git a/assets/items/rare_falchion.png b/assets/items/rare_falchion.png deleted file mode 100644 index 579c183cb..000000000 Binary files a/assets/items/rare_falchion.png and /dev/null differ diff --git a/assets/items/rare_falcon_mask.png b/assets/items/rare_falcon_mask.png deleted file mode 100644 index 0b5b41291..000000000 Binary files a/assets/items/rare_falcon_mask.png and /dev/null differ diff --git a/assets/items/rare_fanged_helm.png b/assets/items/rare_fanged_helm.png deleted file mode 100644 index c986c8f44..000000000 Binary files a/assets/items/rare_fanged_helm.png and /dev/null differ diff --git a/assets/items/rare_feral_axe.png b/assets/items/rare_feral_axe.png deleted file mode 100644 index bc0e915d2..000000000 Binary files a/assets/items/rare_feral_axe.png and /dev/null differ diff --git a/assets/items/rare_feral_claws.png b/assets/items/rare_feral_claws.png deleted file mode 100644 index 093016ce7..000000000 Binary files a/assets/items/rare_feral_claws.png and /dev/null differ diff --git a/assets/items/rare_field_plate.png b/assets/items/rare_field_plate.png deleted file mode 100644 index b9e5c5044..000000000 Binary files a/assets/items/rare_field_plate.png and /dev/null differ diff --git a/assets/items/rare_flamberge.png b/assets/items/rare_flamberge.png deleted file mode 100644 index 34093fbf1..000000000 Binary files a/assets/items/rare_flamberge.png and /dev/null differ diff --git a/assets/items/rare_flanged_mace.png b/assets/items/rare_flanged_mace.png deleted file mode 100644 index bb67a1a89..000000000 Binary files a/assets/items/rare_flanged_mace.png and /dev/null differ diff --git a/assets/items/rare_flying_axe.png b/assets/items/rare_flying_axe.png deleted file mode 100644 index 80a33e4e4..000000000 Binary files a/assets/items/rare_flying_axe.png and /dev/null differ diff --git a/assets/items/rare_flying_knife.png b/assets/items/rare_flying_knife.png deleted file mode 100644 index 47a02151e..000000000 Binary files a/assets/items/rare_flying_knife.png and /dev/null differ diff --git a/assets/items/rare_francisca.png b/assets/items/rare_francisca.png deleted file mode 100644 index c4d736f98..000000000 Binary files a/assets/items/rare_francisca.png and /dev/null differ diff --git a/assets/items/rare_full_plate_mail.png b/assets/items/rare_full_plate_mail.png deleted file mode 100644 index c18e51590..000000000 Binary files a/assets/items/rare_full_plate_mail.png and /dev/null differ diff --git a/assets/items/rare_fury_visor.png b/assets/items/rare_fury_visor.png deleted file mode 100644 index e233b67fa..000000000 Binary files a/assets/items/rare_fury_visor.png and /dev/null differ diff --git a/assets/items/rare_fuscina.png b/assets/items/rare_fuscina.png deleted file mode 100644 index b213b6df1..000000000 Binary files a/assets/items/rare_fuscina.png and /dev/null differ diff --git a/assets/items/rare_gauntlets.png b/assets/items/rare_gauntlets.png deleted file mode 100644 index e6beee578..000000000 Binary files a/assets/items/rare_gauntlets.png and /dev/null differ diff --git a/assets/items/rare_ghost_armor.png b/assets/items/rare_ghost_armor.png deleted file mode 100644 index ead5677b7..000000000 Binary files a/assets/items/rare_ghost_armor.png and /dev/null differ diff --git a/assets/items/rare_ghost_glaive.png b/assets/items/rare_ghost_glaive.png deleted file mode 100644 index 604cadaaf..000000000 Binary files a/assets/items/rare_ghost_glaive.png and /dev/null differ diff --git a/assets/items/rare_ghost_spear.png b/assets/items/rare_ghost_spear.png deleted file mode 100644 index 4ed5bf8c0..000000000 Binary files a/assets/items/rare_ghost_spear.png and /dev/null differ diff --git a/assets/items/rare_giant_axe.png b/assets/items/rare_giant_axe.png deleted file mode 100644 index ab8f30610..000000000 Binary files a/assets/items/rare_giant_axe.png and /dev/null differ diff --git a/assets/items/rare_giant_conch.png b/assets/items/rare_giant_conch.png deleted file mode 100644 index 154666b9d..000000000 Binary files a/assets/items/rare_giant_conch.png and /dev/null differ diff --git a/assets/items/rare_giant_sword.png b/assets/items/rare_giant_sword.png deleted file mode 100644 index c6282f07a..000000000 Binary files a/assets/items/rare_giant_sword.png and /dev/null differ diff --git a/assets/items/rare_giant_thresher.png b/assets/items/rare_giant_thresher.png deleted file mode 100644 index 26a1e85e1..000000000 Binary files a/assets/items/rare_giant_thresher.png and /dev/null differ diff --git a/assets/items/rare_gladius.png b/assets/items/rare_gladius.png deleted file mode 100644 index 72c5ca2bb..000000000 Binary files a/assets/items/rare_gladius.png and /dev/null differ diff --git a/assets/items/rare_glaive.png b/assets/items/rare_glaive.png deleted file mode 100644 index 2af38ac78..000000000 Binary files a/assets/items/rare_glaive.png and /dev/null differ diff --git a/assets/items/rare_glorious_axe.png b/assets/items/rare_glorious_axe.png deleted file mode 100644 index e942ddb8c..000000000 Binary files a/assets/items/rare_glorious_axe.png and /dev/null differ diff --git a/assets/items/rare_glowing_orb.png b/assets/items/rare_glowing_orb.png deleted file mode 100644 index defe2a563..000000000 Binary files a/assets/items/rare_glowing_orb.png and /dev/null differ diff --git a/assets/items/rare_gothic_axe.png b/assets/items/rare_gothic_axe.png deleted file mode 100644 index 6e8846511..000000000 Binary files a/assets/items/rare_gothic_axe.png and /dev/null differ diff --git a/assets/items/rare_gothic_plate.png b/assets/items/rare_gothic_plate.png deleted file mode 100644 index 907b264e5..000000000 Binary files a/assets/items/rare_gothic_plate.png and /dev/null differ diff --git a/assets/items/rare_gothic_sword.png b/assets/items/rare_gothic_sword.png deleted file mode 100644 index aeadec30d..000000000 Binary files a/assets/items/rare_gothic_sword.png and /dev/null differ diff --git a/assets/items/rare_grand_matron_bow.png b/assets/items/rare_grand_matron_bow.png deleted file mode 100644 index 36e776f9b..000000000 Binary files a/assets/items/rare_grand_matron_bow.png and /dev/null differ diff --git a/assets/items/rare_great_axe.png b/assets/items/rare_great_axe.png deleted file mode 100644 index d6d211b28..000000000 Binary files a/assets/items/rare_great_axe.png and /dev/null differ diff --git a/assets/items/rare_great_bow.png b/assets/items/rare_great_bow.png deleted file mode 100644 index 7109d8dce..000000000 Binary files a/assets/items/rare_great_bow.png and /dev/null differ diff --git a/assets/items/rare_great_hauberk.png b/assets/items/rare_great_hauberk.png deleted file mode 100644 index 1ae972117..000000000 Binary files a/assets/items/rare_great_hauberk.png and /dev/null differ diff --git a/assets/items/rare_great_maul.png b/assets/items/rare_great_maul.png deleted file mode 100644 index b6301dc9a..000000000 Binary files a/assets/items/rare_great_maul.png and /dev/null differ diff --git a/assets/items/rare_great_pilum.png b/assets/items/rare_great_pilum.png deleted file mode 100644 index 4b827558e..000000000 Binary files a/assets/items/rare_great_pilum.png and /dev/null differ diff --git a/assets/items/rare_great_poleaxe.png b/assets/items/rare_great_poleaxe.png deleted file mode 100644 index ccdcc976d..000000000 Binary files a/assets/items/rare_great_poleaxe.png and /dev/null differ diff --git a/assets/items/rare_great_sword.png b/assets/items/rare_great_sword.png deleted file mode 100644 index 377402298..000000000 Binary files a/assets/items/rare_great_sword.png and /dev/null differ diff --git a/assets/items/rare_greater_claws.png b/assets/items/rare_greater_claws.png deleted file mode 100644 index 8e674a538..000000000 Binary files a/assets/items/rare_greater_claws.png and /dev/null differ diff --git a/assets/items/rare_greater_talons.png b/assets/items/rare_greater_talons.png deleted file mode 100644 index 67b3889ca..000000000 Binary files a/assets/items/rare_greater_talons.png and /dev/null differ diff --git a/assets/items/rare_greaves.png b/assets/items/rare_greaves.png deleted file mode 100644 index 8b7d881ba..000000000 Binary files a/assets/items/rare_greaves.png and /dev/null differ diff --git a/assets/items/rare_griffon_headdress.png b/assets/items/rare_griffon_headdress.png deleted file mode 100644 index 0fceccffb..000000000 Binary files a/assets/items/rare_griffon_headdress.png and /dev/null differ diff --git a/assets/items/rare_grim_scythe.png b/assets/items/rare_grim_scythe.png deleted file mode 100644 index 909390f51..000000000 Binary files a/assets/items/rare_grim_scythe.png and /dev/null differ diff --git a/assets/items/rare_guardian_crown.png b/assets/items/rare_guardian_crown.png deleted file mode 100644 index 180f10ad7..000000000 Binary files a/assets/items/rare_guardian_crown.png and /dev/null differ diff --git a/assets/items/rare_halberd.png b/assets/items/rare_halberd.png deleted file mode 100644 index 07d79eae0..000000000 Binary files a/assets/items/rare_halberd.png and /dev/null differ diff --git a/assets/items/rare_hand_axe.png b/assets/items/rare_hand_axe.png deleted file mode 100644 index 1d1b03cf9..000000000 Binary files a/assets/items/rare_hand_axe.png and /dev/null differ diff --git a/assets/items/rare_hand_scythe.png b/assets/items/rare_hand_scythe.png deleted file mode 100644 index 1cac1ab86..000000000 Binary files a/assets/items/rare_hand_scythe.png and /dev/null differ diff --git a/assets/items/rare_hard_leather_armor.png b/assets/items/rare_hard_leather_armor.png deleted file mode 100644 index d0afb6f9e..000000000 Binary files a/assets/items/rare_hard_leather_armor.png and /dev/null differ diff --git a/assets/items/rare_harpoon.png b/assets/items/rare_harpoon.png deleted file mode 100644 index b6eeb0b2f..000000000 Binary files a/assets/items/rare_harpoon.png and /dev/null differ diff --git a/assets/items/rare_hatchet.png b/assets/items/rare_hatchet.png deleted file mode 100644 index 2a75a2163..000000000 Binary files a/assets/items/rare_hatchet.png and /dev/null differ diff --git a/assets/items/rare_hawk_helm.png b/assets/items/rare_hawk_helm.png deleted file mode 100644 index dc6bfcd59..000000000 Binary files a/assets/items/rare_hawk_helm.png and /dev/null differ diff --git a/assets/items/rare_heavenly_stone.png b/assets/items/rare_heavenly_stone.png deleted file mode 100644 index 10de30732..000000000 Binary files a/assets/items/rare_heavenly_stone.png and /dev/null differ diff --git a/assets/items/rare_heavy_boots.png b/assets/items/rare_heavy_boots.png deleted file mode 100644 index af1003dc8..000000000 Binary files a/assets/items/rare_heavy_boots.png and /dev/null differ diff --git a/assets/items/rare_heavy_bracers.png b/assets/items/rare_heavy_bracers.png deleted file mode 100644 index 1f5b716c9..000000000 Binary files a/assets/items/rare_heavy_bracers.png and /dev/null differ diff --git a/assets/items/rare_heavy_gloves.png b/assets/items/rare_heavy_gloves.png deleted file mode 100644 index 875553bd5..000000000 Binary files a/assets/items/rare_heavy_gloves.png and /dev/null differ diff --git a/assets/items/rare_hellforge_plate.png b/assets/items/rare_hellforge_plate.png deleted file mode 100644 index cbd61b9cc..000000000 Binary files a/assets/items/rare_hellforge_plate.png and /dev/null differ diff --git a/assets/items/rare_highland_blade.png b/assets/items/rare_highland_blade.png deleted file mode 100644 index 02ca5ba59..000000000 Binary files a/assets/items/rare_highland_blade.png and /dev/null differ diff --git a/assets/items/rare_horned_helm.png b/assets/items/rare_horned_helm.png deleted file mode 100644 index 9adc37c40..000000000 Binary files a/assets/items/rare_horned_helm.png and /dev/null differ diff --git a/assets/items/rare_hunter_guise.png b/assets/items/rare_hunter_guise.png deleted file mode 100644 index 0a3240fb9..000000000 Binary files a/assets/items/rare_hunter_guise.png and /dev/null differ diff --git a/assets/items/rare_hurlbat.png b/assets/items/rare_hurlbat.png deleted file mode 100644 index 7ee54ed19..000000000 Binary files a/assets/items/rare_hurlbat.png and /dev/null differ diff --git a/assets/items/rare_hydra_edge.png b/assets/items/rare_hydra_edge.png deleted file mode 100644 index 950388d79..000000000 Binary files a/assets/items/rare_hydra_edge.png and /dev/null differ diff --git a/assets/items/rare_hydraskull.png b/assets/items/rare_hydraskull.png deleted file mode 100644 index 0e2682c04..000000000 Binary files a/assets/items/rare_hydraskull.png and /dev/null differ diff --git a/assets/items/rare_hyperion_javelin.png b/assets/items/rare_hyperion_javelin.png deleted file mode 100644 index 5ddbebd67..000000000 Binary files a/assets/items/rare_hyperion_javelin.png and /dev/null differ diff --git a/assets/items/rare_hyperion_spear.png b/assets/items/rare_hyperion_spear.png deleted file mode 100644 index 9590e49df..000000000 Binary files a/assets/items/rare_hyperion_spear.png and /dev/null differ diff --git a/assets/items/rare_jagged_star.png b/assets/items/rare_jagged_star.png deleted file mode 100644 index 5f3ced9bb..000000000 Binary files a/assets/items/rare_jagged_star.png and /dev/null differ diff --git a/assets/items/rare_jareds_stone.png b/assets/items/rare_jareds_stone.png deleted file mode 100644 index 19547f7e7..000000000 Binary files a/assets/items/rare_jareds_stone.png and /dev/null differ diff --git a/assets/items/rare_jawbone_cap.png b/assets/items/rare_jawbone_cap.png deleted file mode 100644 index 247d46529..000000000 Binary files a/assets/items/rare_jawbone_cap.png and /dev/null differ diff --git a/assets/items/rare_jawbone_visor.png b/assets/items/rare_jawbone_visor.png deleted file mode 100644 index ce3540b9d..000000000 Binary files a/assets/items/rare_jawbone_visor.png and /dev/null differ diff --git a/assets/items/rare_jewel.png b/assets/items/rare_jewel.png deleted file mode 100644 index c2b3db329..000000000 Binary files a/assets/items/rare_jewel.png and /dev/null differ diff --git a/assets/items/rare_kraken_shell.png b/assets/items/rare_kraken_shell.png deleted file mode 100644 index fbe01bace..000000000 Binary files a/assets/items/rare_kraken_shell.png and /dev/null differ diff --git a/assets/items/rare_lacquered_plate.png b/assets/items/rare_lacquered_plate.png deleted file mode 100644 index 000484c89..000000000 Binary files a/assets/items/rare_lacquered_plate.png and /dev/null differ diff --git a/assets/items/rare_lance.png b/assets/items/rare_lance.png deleted file mode 100644 index 61a6ad3be..000000000 Binary files a/assets/items/rare_lance.png and /dev/null differ diff --git a/assets/items/rare_large_axe.png b/assets/items/rare_large_axe.png deleted file mode 100644 index 901e2c524..000000000 Binary files a/assets/items/rare_large_axe.png and /dev/null differ diff --git a/assets/items/rare_leather_armor.png b/assets/items/rare_leather_armor.png deleted file mode 100644 index 3b5b89b0b..000000000 Binary files a/assets/items/rare_leather_armor.png and /dev/null differ diff --git a/assets/items/rare_leather_gloves.png b/assets/items/rare_leather_gloves.png deleted file mode 100644 index 2321a68e6..000000000 Binary files a/assets/items/rare_leather_gloves.png and /dev/null differ diff --git a/assets/items/rare_legend_sword.png b/assets/items/rare_legend_sword.png deleted file mode 100644 index cef721d50..000000000 Binary files a/assets/items/rare_legend_sword.png and /dev/null differ diff --git a/assets/items/rare_legendary_mallet.png b/assets/items/rare_legendary_mallet.png deleted file mode 100644 index 3a3e8aeef..000000000 Binary files a/assets/items/rare_legendary_mallet.png and /dev/null differ diff --git a/assets/items/rare_light_gauntlets.png b/assets/items/rare_light_gauntlets.png deleted file mode 100644 index 2830d301d..000000000 Binary files a/assets/items/rare_light_gauntlets.png and /dev/null differ diff --git a/assets/items/rare_light_plate.png b/assets/items/rare_light_plate.png deleted file mode 100644 index 4305d76be..000000000 Binary files a/assets/items/rare_light_plate.png and /dev/null differ diff --git a/assets/items/rare_light_plated_boots.png b/assets/items/rare_light_plated_boots.png deleted file mode 100644 index cc916907a..000000000 Binary files a/assets/items/rare_light_plated_boots.png and /dev/null differ diff --git a/assets/items/rare_linked_mail.png b/assets/items/rare_linked_mail.png deleted file mode 100644 index 82534fb45..000000000 Binary files a/assets/items/rare_linked_mail.png and /dev/null differ diff --git a/assets/items/rare_lion_helm.png b/assets/items/rare_lion_helm.png deleted file mode 100644 index 1b8050b6b..000000000 Binary files a/assets/items/rare_lion_helm.png and /dev/null differ diff --git a/assets/items/rare_lochaber_axe.png b/assets/items/rare_lochaber_axe.png deleted file mode 100644 index 95b1cae19..000000000 Binary files a/assets/items/rare_lochaber_axe.png and /dev/null differ diff --git a/assets/items/rare_long_sword.png b/assets/items/rare_long_sword.png deleted file mode 100644 index ba481d38e..000000000 Binary files a/assets/items/rare_long_sword.png and /dev/null differ diff --git a/assets/items/rare_loricated_mail.png b/assets/items/rare_loricated_mail.png deleted file mode 100644 index 5767aeaf2..000000000 Binary files a/assets/items/rare_loricated_mail.png and /dev/null differ diff --git a/assets/items/rare_mace.png b/assets/items/rare_mace.png deleted file mode 100644 index bdf549c71..000000000 Binary files a/assets/items/rare_mace.png and /dev/null differ diff --git a/assets/items/rare_mage_plate.png b/assets/items/rare_mage_plate.png deleted file mode 100644 index 62d2452ed..000000000 Binary files a/assets/items/rare_mage_plate.png and /dev/null differ diff --git a/assets/items/rare_maiden_javelin.png b/assets/items/rare_maiden_javelin.png deleted file mode 100644 index 2cd675c63..000000000 Binary files a/assets/items/rare_maiden_javelin.png and /dev/null differ diff --git a/assets/items/rare_maiden_pike.png b/assets/items/rare_maiden_pike.png deleted file mode 100644 index b12025a8d..000000000 Binary files a/assets/items/rare_maiden_pike.png and /dev/null differ diff --git a/assets/items/rare_maiden_spear.png b/assets/items/rare_maiden_spear.png deleted file mode 100644 index 91417663a..000000000 Binary files a/assets/items/rare_maiden_spear.png and /dev/null differ diff --git a/assets/items/rare_mancatcher.png b/assets/items/rare_mancatcher.png deleted file mode 100644 index 5126e59b4..000000000 Binary files a/assets/items/rare_mancatcher.png and /dev/null differ diff --git a/assets/items/rare_martel_de_fer.png b/assets/items/rare_martel_de_fer.png deleted file mode 100644 index f7a58cfe0..000000000 Binary files a/assets/items/rare_martel_de_fer.png and /dev/null differ diff --git a/assets/items/rare_matriarchal_bow.png b/assets/items/rare_matriarchal_bow.png deleted file mode 100644 index c98c1c32d..000000000 Binary files a/assets/items/rare_matriarchal_bow.png and /dev/null differ diff --git a/assets/items/rare_matriarchal_javelin.png b/assets/items/rare_matriarchal_javelin.png deleted file mode 100644 index 397c6803e..000000000 Binary files a/assets/items/rare_matriarchal_javelin.png and /dev/null differ diff --git a/assets/items/rare_matriarchal_pike.png b/assets/items/rare_matriarchal_pike.png deleted file mode 100644 index 42d34bb1a..000000000 Binary files a/assets/items/rare_matriarchal_pike.png and /dev/null differ diff --git a/assets/items/rare_matriarchal_spear.png b/assets/items/rare_matriarchal_spear.png deleted file mode 100644 index 4e5d84e3f..000000000 Binary files a/assets/items/rare_matriarchal_spear.png and /dev/null differ diff --git a/assets/items/rare_maul.png b/assets/items/rare_maul.png deleted file mode 100644 index b7fc0bf2a..000000000 Binary files a/assets/items/rare_maul.png and /dev/null differ diff --git a/assets/items/rare_mesh_armor.png b/assets/items/rare_mesh_armor.png deleted file mode 100644 index afe9717ef..000000000 Binary files a/assets/items/rare_mesh_armor.png and /dev/null differ diff --git a/assets/items/rare_mesh_belt.png b/assets/items/rare_mesh_belt.png deleted file mode 100644 index b3bf00f17..000000000 Binary files a/assets/items/rare_mesh_belt.png and /dev/null differ diff --git a/assets/items/rare_mesh_boots.png b/assets/items/rare_mesh_boots.png deleted file mode 100644 index 9d197a04f..000000000 Binary files a/assets/items/rare_mesh_boots.png and /dev/null differ diff --git a/assets/items/rare_military_axe.png b/assets/items/rare_military_axe.png deleted file mode 100644 index be9e9aa2a..000000000 Binary files a/assets/items/rare_military_axe.png and /dev/null differ diff --git a/assets/items/rare_military_pick.png b/assets/items/rare_military_pick.png deleted file mode 100644 index 4b128dcea..000000000 Binary files a/assets/items/rare_military_pick.png and /dev/null differ diff --git a/assets/items/rare_mirrored_boots.png b/assets/items/rare_mirrored_boots.png deleted file mode 100644 index 0a21723b0..000000000 Binary files a/assets/items/rare_mirrored_boots.png and /dev/null differ diff --git a/assets/items/rare_mithril_coil.png b/assets/items/rare_mithril_coil.png deleted file mode 100644 index 787f03ce5..000000000 Binary files a/assets/items/rare_mithril_coil.png and /dev/null differ diff --git a/assets/items/rare_monarch.png b/assets/items/rare_monarch.png deleted file mode 100644 index 58abd7ece..000000000 Binary files a/assets/items/rare_monarch.png and /dev/null differ diff --git a/assets/items/rare_morning_star.png b/assets/items/rare_morning_star.png deleted file mode 100644 index 2ac363a9a..000000000 Binary files a/assets/items/rare_morning_star.png and /dev/null differ diff --git a/assets/items/rare_myrmidon_greaves.png b/assets/items/rare_myrmidon_greaves.png deleted file mode 100644 index 748a182a5..000000000 Binary files a/assets/items/rare_myrmidon_greaves.png and /dev/null differ diff --git a/assets/items/rare_mythical_sword.png b/assets/items/rare_mythical_sword.png deleted file mode 100644 index 9b80f897b..000000000 Binary files a/assets/items/rare_mythical_sword.png and /dev/null differ diff --git a/assets/items/rare_naga.png b/assets/items/rare_naga.png deleted file mode 100644 index 95774224f..000000000 Binary files a/assets/items/rare_naga.png and /dev/null differ diff --git a/assets/items/rare_ogre_axe.png b/assets/items/rare_ogre_axe.png deleted file mode 100644 index bf2390338..000000000 Binary files a/assets/items/rare_ogre_axe.png and /dev/null differ diff --git a/assets/items/rare_ogre_gauntlets.png b/assets/items/rare_ogre_gauntlets.png deleted file mode 100644 index f153830cc..000000000 Binary files a/assets/items/rare_ogre_gauntlets.png and /dev/null differ diff --git a/assets/items/rare_ogre_maul.png b/assets/items/rare_ogre_maul.png deleted file mode 100644 index 0fe2f8ecf..000000000 Binary files a/assets/items/rare_ogre_maul.png and /dev/null differ diff --git a/assets/items/rare_ornate_plate.png b/assets/items/rare_ornate_plate.png deleted file mode 100644 index 12e289f37..000000000 Binary files a/assets/items/rare_ornate_plate.png and /dev/null differ diff --git a/assets/items/rare_partizan.png b/assets/items/rare_partizan.png deleted file mode 100644 index 1d5f65d24..000000000 Binary files a/assets/items/rare_partizan.png and /dev/null differ diff --git a/assets/items/rare_phase_blade.png b/assets/items/rare_phase_blade.png deleted file mode 100644 index 1a1e67c12..000000000 Binary files a/assets/items/rare_phase_blade.png and /dev/null differ diff --git a/assets/items/rare_pike.png b/assets/items/rare_pike.png deleted file mode 100644 index 5cd85c731..000000000 Binary files a/assets/items/rare_pike.png and /dev/null differ diff --git a/assets/items/rare_pilum.png b/assets/items/rare_pilum.png deleted file mode 100644 index 37b64f55b..000000000 Binary files a/assets/items/rare_pilum.png and /dev/null differ diff --git a/assets/items/rare_plate_mail.png b/assets/items/rare_plate_mail.png deleted file mode 100644 index 3e2078e8b..000000000 Binary files a/assets/items/rare_plate_mail.png and /dev/null differ diff --git a/assets/items/rare_poleaxe.png b/assets/items/rare_poleaxe.png deleted file mode 100644 index 8598a9f38..000000000 Binary files a/assets/items/rare_poleaxe.png and /dev/null differ diff --git a/assets/items/rare_quilted_armor.png b/assets/items/rare_quilted_armor.png deleted file mode 100644 index 1d88cb6b4..000000000 Binary files a/assets/items/rare_quilted_armor.png and /dev/null differ diff --git a/assets/items/rare_rage_mask.png b/assets/items/rare_rage_mask.png deleted file mode 100644 index 19d159ee2..000000000 Binary files a/assets/items/rare_rage_mask.png and /dev/null differ diff --git a/assets/items/rare_razor_bow.png b/assets/items/rare_razor_bow.png deleted file mode 100644 index 9e83b4e82..000000000 Binary files a/assets/items/rare_razor_bow.png and /dev/null differ diff --git a/assets/items/rare_reinforced_mace.png b/assets/items/rare_reinforced_mace.png deleted file mode 100644 index f8160a85f..000000000 Binary files a/assets/items/rare_reinforced_mace.png and /dev/null differ diff --git a/assets/items/rare_ring.png b/assets/items/rare_ring.png deleted file mode 100644 index 40cba99e4..000000000 Binary files a/assets/items/rare_ring.png and /dev/null differ diff --git a/assets/items/rare_ring_mail.png b/assets/items/rare_ring_mail.png deleted file mode 100644 index bfa2fdbea..000000000 Binary files a/assets/items/rare_ring_mail.png and /dev/null differ diff --git a/assets/items/rare_rune_bow.png b/assets/items/rare_rune_bow.png deleted file mode 100644 index c1005d435..000000000 Binary files a/assets/items/rare_rune_bow.png and /dev/null differ diff --git a/assets/items/rare_rune_sword.png b/assets/items/rare_rune_sword.png deleted file mode 100644 index dc2b0b263..000000000 Binary files a/assets/items/rare_rune_sword.png and /dev/null differ diff --git a/assets/items/rare_runic_talons.png b/assets/items/rare_runic_talons.png deleted file mode 100644 index 9e0dd1266..000000000 Binary files a/assets/items/rare_runic_talons.png and /dev/null differ diff --git a/assets/items/rare_russet_armor.png b/assets/items/rare_russet_armor.png deleted file mode 100644 index 304baf005..000000000 Binary files a/assets/items/rare_russet_armor.png and /dev/null differ diff --git a/assets/items/rare_sabre.png b/assets/items/rare_sabre.png deleted file mode 100644 index dc848dca3..000000000 Binary files a/assets/items/rare_sabre.png and /dev/null differ diff --git a/assets/items/rare_sacred_armor.png b/assets/items/rare_sacred_armor.png deleted file mode 100644 index f35e554e2..000000000 Binary files a/assets/items/rare_sacred_armor.png and /dev/null differ diff --git a/assets/items/rare_sacred_feathers.png b/assets/items/rare_sacred_feathers.png deleted file mode 100644 index e065cf224..000000000 Binary files a/assets/items/rare_sacred_feathers.png and /dev/null differ diff --git a/assets/items/rare_sacred_globe.png b/assets/items/rare_sacred_globe.png deleted file mode 100644 index 99a798f4b..000000000 Binary files a/assets/items/rare_sacred_globe.png and /dev/null differ diff --git a/assets/items/rare_savage_helmet.png b/assets/items/rare_savage_helmet.png deleted file mode 100644 index 27584f981..000000000 Binary files a/assets/items/rare_savage_helmet.png and /dev/null differ diff --git a/assets/items/rare_scale_mail.png b/assets/items/rare_scale_mail.png deleted file mode 100644 index 4f3f71fae..000000000 Binary files a/assets/items/rare_scale_mail.png and /dev/null differ diff --git a/assets/items/rare_scarab_husk.png b/assets/items/rare_scarab_husk.png deleted file mode 100644 index 7f0306757..000000000 Binary files a/assets/items/rare_scarab_husk.png and /dev/null differ diff --git a/assets/items/rare_scarabshell_boots.png b/assets/items/rare_scarabshell_boots.png deleted file mode 100644 index 31986b232..000000000 Binary files a/assets/items/rare_scarabshell_boots.png and /dev/null differ diff --git a/assets/items/rare_scimitar.png b/assets/items/rare_scimitar.png deleted file mode 100644 index 063dfaa77..000000000 Binary files a/assets/items/rare_scimitar.png and /dev/null differ diff --git a/assets/items/rare_scissors_quhab.png b/assets/items/rare_scissors_quhab.png deleted file mode 100644 index 5c3633dac..000000000 Binary files a/assets/items/rare_scissors_quhab.png and /dev/null differ diff --git a/assets/items/rare_scissors_suwayyah.png b/assets/items/rare_scissors_suwayyah.png deleted file mode 100644 index f236d9c94..000000000 Binary files a/assets/items/rare_scissors_suwayyah.png and /dev/null differ diff --git a/assets/items/rare_scythe.png b/assets/items/rare_scythe.png deleted file mode 100644 index 1b6f9f3c8..000000000 Binary files a/assets/items/rare_scythe.png and /dev/null differ diff --git a/assets/items/rare_serpentskin_armor.png b/assets/items/rare_serpentskin_armor.png deleted file mode 100644 index 58110a02c..000000000 Binary files a/assets/items/rare_serpentskin_armor.png and /dev/null differ diff --git a/assets/items/rare_shadow_bow.png b/assets/items/rare_shadow_bow.png deleted file mode 100644 index 2c2fc0c1f..000000000 Binary files a/assets/items/rare_shadow_bow.png and /dev/null differ diff --git a/assets/items/rare_shadow_plate.png b/assets/items/rare_shadow_plate.png deleted file mode 100644 index 71e060494..000000000 Binary files a/assets/items/rare_shadow_plate.png and /dev/null differ diff --git a/assets/items/rare_shamshir.png b/assets/items/rare_shamshir.png deleted file mode 100644 index 8390117e9..000000000 Binary files a/assets/items/rare_shamshir.png and /dev/null differ diff --git a/assets/items/rare_sharkskin_belt.png b/assets/items/rare_sharkskin_belt.png deleted file mode 100644 index d1722c382..000000000 Binary files a/assets/items/rare_sharkskin_belt.png and /dev/null differ diff --git a/assets/items/rare_sharkskin_boots.png b/assets/items/rare_sharkskin_boots.png deleted file mode 100644 index f6a18a3c3..000000000 Binary files a/assets/items/rare_sharkskin_boots.png and /dev/null differ diff --git a/assets/items/rare_sharkskin_gloves.png b/assets/items/rare_sharkskin_gloves.png deleted file mode 100644 index ccf6eb6a3..000000000 Binary files a/assets/items/rare_sharkskin_gloves.png and /dev/null differ diff --git a/assets/items/rare_sharktooth_armor.png b/assets/items/rare_sharktooth_armor.png deleted file mode 100644 index f4382623b..000000000 Binary files a/assets/items/rare_sharktooth_armor.png and /dev/null differ diff --git a/assets/items/rare_short_spear.png b/assets/items/rare_short_spear.png deleted file mode 100644 index cc0a3c2c9..000000000 Binary files a/assets/items/rare_short_spear.png and /dev/null differ diff --git a/assets/items/rare_short_sword.png b/assets/items/rare_short_sword.png deleted file mode 100644 index b001e7c71..000000000 Binary files a/assets/items/rare_short_sword.png and /dev/null differ diff --git a/assets/items/rare_silver_edged_axe.png b/assets/items/rare_silver_edged_axe.png deleted file mode 100644 index f847a3c77..000000000 Binary files a/assets/items/rare_silver_edged_axe.png and /dev/null differ diff --git a/assets/items/rare_simbilan.png b/assets/items/rare_simbilan.png deleted file mode 100644 index 7f2852f34..000000000 Binary files a/assets/items/rare_simbilan.png and /dev/null differ diff --git a/assets/items/rare_sky_spirit.png b/assets/items/rare_sky_spirit.png deleted file mode 100644 index 3e2312248..000000000 Binary files a/assets/items/rare_sky_spirit.png and /dev/null differ diff --git a/assets/items/rare_slayer_guard.png b/assets/items/rare_slayer_guard.png deleted file mode 100644 index 1f5ef1454..000000000 Binary files a/assets/items/rare_slayer_guard.png and /dev/null differ diff --git a/assets/items/rare_small_crescent.png b/assets/items/rare_small_crescent.png deleted file mode 100644 index 79c604c9f..000000000 Binary files a/assets/items/rare_small_crescent.png and /dev/null differ diff --git a/assets/items/rare_smoked_sphere.png b/assets/items/rare_smoked_sphere.png deleted file mode 100644 index b94d32c24..000000000 Binary files a/assets/items/rare_smoked_sphere.png and /dev/null differ diff --git a/assets/items/rare_sparkling_ball.png b/assets/items/rare_sparkling_ball.png deleted file mode 100644 index b54846926..000000000 Binary files a/assets/items/rare_sparkling_ball.png and /dev/null differ diff --git a/assets/items/rare_spear.png b/assets/items/rare_spear.png deleted file mode 100644 index 67c5a77b3..000000000 Binary files a/assets/items/rare_spear.png and /dev/null differ diff --git a/assets/items/rare_spetum.png b/assets/items/rare_spetum.png deleted file mode 100644 index de07a4f5f..000000000 Binary files a/assets/items/rare_spetum.png and /dev/null differ diff --git a/assets/items/rare_spiculum.png b/assets/items/rare_spiculum.png deleted file mode 100644 index 7898d75fc..000000000 Binary files a/assets/items/rare_spiculum.png and /dev/null differ diff --git a/assets/items/rare_spiderweb_sash.png b/assets/items/rare_spiderweb_sash.png deleted file mode 100644 index 0043f062e..000000000 Binary files a/assets/items/rare_spiderweb_sash.png and /dev/null differ diff --git a/assets/items/rare_spiked_club.png b/assets/items/rare_spiked_club.png deleted file mode 100644 index 2328477c1..000000000 Binary files a/assets/items/rare_spiked_club.png and /dev/null differ diff --git a/assets/items/rare_spirit_mask.png b/assets/items/rare_spirit_mask.png deleted file mode 100644 index c7e20c8df..000000000 Binary files a/assets/items/rare_spirit_mask.png and /dev/null differ diff --git a/assets/items/rare_splint_mail.png b/assets/items/rare_splint_mail.png deleted file mode 100644 index d3861f2a4..000000000 Binary files a/assets/items/rare_splint_mail.png and /dev/null differ diff --git a/assets/items/rare_stag_bow.png b/assets/items/rare_stag_bow.png deleted file mode 100644 index 8b68a0d80..000000000 Binary files a/assets/items/rare_stag_bow.png and /dev/null differ diff --git a/assets/items/rare_studded_leather.png b/assets/items/rare_studded_leather.png deleted file mode 100644 index dbfcc6f04..000000000 Binary files a/assets/items/rare_studded_leather.png and /dev/null differ diff --git a/assets/items/rare_stygian_pike.png b/assets/items/rare_stygian_pike.png deleted file mode 100644 index 7eff299d0..000000000 Binary files a/assets/items/rare_stygian_pike.png and /dev/null differ diff --git a/assets/items/rare_stygian_pilum.png b/assets/items/rare_stygian_pilum.png deleted file mode 100644 index 836c9e124..000000000 Binary files a/assets/items/rare_stygian_pilum.png and /dev/null differ diff --git a/assets/items/rare_sun_spirit.png b/assets/items/rare_sun_spirit.png deleted file mode 100644 index d0d40845f..000000000 Binary files a/assets/items/rare_sun_spirit.png and /dev/null differ diff --git a/assets/items/rare_suwayyah.png b/assets/items/rare_suwayyah.png deleted file mode 100644 index 2e5f29aea..000000000 Binary files a/assets/items/rare_suwayyah.png and /dev/null differ diff --git a/assets/items/rare_swirling_crystal.png b/assets/items/rare_swirling_crystal.png deleted file mode 100644 index 540d1979b..000000000 Binary files a/assets/items/rare_swirling_crystal.png and /dev/null differ diff --git a/assets/items/rare_tabar.png b/assets/items/rare_tabar.png deleted file mode 100644 index 5a1ef736b..000000000 Binary files a/assets/items/rare_tabar.png and /dev/null differ diff --git a/assets/items/rare_templar_coat.png b/assets/items/rare_templar_coat.png deleted file mode 100644 index 27312d81b..000000000 Binary files a/assets/items/rare_templar_coat.png and /dev/null differ diff --git a/assets/items/rare_thresher.png b/assets/items/rare_thresher.png deleted file mode 100644 index 9832a5f1f..000000000 Binary files a/assets/items/rare_thresher.png and /dev/null differ diff --git a/assets/items/rare_throwing_axe.png b/assets/items/rare_throwing_axe.png deleted file mode 100644 index 09301e98c..000000000 Binary files a/assets/items/rare_throwing_axe.png and /dev/null differ diff --git a/assets/items/rare_throwing_knife.png b/assets/items/rare_throwing_knife.png deleted file mode 100644 index 9ab16adf4..000000000 Binary files a/assets/items/rare_throwing_knife.png and /dev/null differ diff --git a/assets/items/rare_throwing_spear.png b/assets/items/rare_throwing_spear.png deleted file mode 100644 index 7da44e1fb..000000000 Binary files a/assets/items/rare_throwing_spear.png and /dev/null differ diff --git a/assets/items/rare_thunder_maul.png b/assets/items/rare_thunder_maul.png deleted file mode 100644 index af096915b..000000000 Binary files a/assets/items/rare_thunder_maul.png and /dev/null differ diff --git a/assets/items/rare_tiara.png b/assets/items/rare_tiara.png deleted file mode 100644 index 797f6dc5c..000000000 Binary files a/assets/items/rare_tiara.png and /dev/null differ diff --git a/assets/items/rare_tigulated_mail.png b/assets/items/rare_tigulated_mail.png deleted file mode 100644 index 1643e8669..000000000 Binary files a/assets/items/rare_tigulated_mail.png and /dev/null differ diff --git a/assets/items/rare_tomahawk.png b/assets/items/rare_tomahawk.png deleted file mode 100644 index 291b1700a..000000000 Binary files a/assets/items/rare_tomahawk.png and /dev/null differ diff --git a/assets/items/rare_totemic_mask.png b/assets/items/rare_totemic_mask.png deleted file mode 100644 index 43e0f34e4..000000000 Binary files a/assets/items/rare_totemic_mask.png and /dev/null differ diff --git a/assets/items/rare_trellised_armor.png b/assets/items/rare_trellised_armor.png deleted file mode 100644 index fdaaafd78..000000000 Binary files a/assets/items/rare_trellised_armor.png and /dev/null differ diff --git a/assets/items/rare_trident.png b/assets/items/rare_trident.png deleted file mode 100644 index 4fdec33a2..000000000 Binary files a/assets/items/rare_trident.png and /dev/null differ diff --git a/assets/items/rare_troll_belt.png b/assets/items/rare_troll_belt.png deleted file mode 100644 index faecce3b0..000000000 Binary files a/assets/items/rare_troll_belt.png and /dev/null differ diff --git a/assets/items/rare_troll_nest.png b/assets/items/rare_troll_nest.png deleted file mode 100644 index 17ad9f760..000000000 Binary files a/assets/items/rare_troll_nest.png and /dev/null differ diff --git a/assets/items/rare_truncheon.png b/assets/items/rare_truncheon.png deleted file mode 100644 index 93b031822..000000000 Binary files a/assets/items/rare_truncheon.png and /dev/null differ diff --git a/assets/items/rare_tulwar.png b/assets/items/rare_tulwar.png deleted file mode 100644 index 942ee92a6..000000000 Binary files a/assets/items/rare_tulwar.png and /dev/null differ diff --git a/assets/items/rare_tusk_sword.png b/assets/items/rare_tusk_sword.png deleted file mode 100644 index 63046401a..000000000 Binary files a/assets/items/rare_tusk_sword.png and /dev/null differ diff --git a/assets/items/rare_twin_axe.png b/assets/items/rare_twin_axe.png deleted file mode 100644 index a2506ff84..000000000 Binary files a/assets/items/rare_twin_axe.png and /dev/null differ diff --git a/assets/items/rare_two_handed_sword.png b/assets/items/rare_two_handed_sword.png deleted file mode 100644 index 616ce54b5..000000000 Binary files a/assets/items/rare_two_handed_sword.png and /dev/null differ diff --git a/assets/items/rare_tyrant_club.png b/assets/items/rare_tyrant_club.png deleted file mode 100644 index 5f7850f10..000000000 Binary files a/assets/items/rare_tyrant_club.png and /dev/null differ diff --git a/assets/items/rare_vambraces.png b/assets/items/rare_vambraces.png deleted file mode 100644 index 675c5adb0..000000000 Binary files a/assets/items/rare_vambraces.png and /dev/null differ diff --git a/assets/items/rare_vampirebone_gloves.png b/assets/items/rare_vampirebone_gloves.png deleted file mode 100644 index ee4d9b3a7..000000000 Binary files a/assets/items/rare_vampirebone_gloves.png and /dev/null differ diff --git a/assets/items/rare_vampirefang_belt.png b/assets/items/rare_vampirefang_belt.png deleted file mode 100644 index f05f69a48..000000000 Binary files a/assets/items/rare_vampirefang_belt.png and /dev/null differ diff --git a/assets/items/rare_vortex_orb.png b/assets/items/rare_vortex_orb.png deleted file mode 100644 index 0c1164b7c..000000000 Binary files a/assets/items/rare_vortex_orb.png and /dev/null differ diff --git a/assets/items/rare_voulge.png b/assets/items/rare_voulge.png deleted file mode 100644 index effdca80b..000000000 Binary files a/assets/items/rare_voulge.png and /dev/null differ diff --git a/assets/items/rare_war_axe.png b/assets/items/rare_war_axe.png deleted file mode 100644 index d8470bf43..000000000 Binary files a/assets/items/rare_war_axe.png and /dev/null differ diff --git a/assets/items/rare_war_belt.png b/assets/items/rare_war_belt.png deleted file mode 100644 index 395b5c61e..000000000 Binary files a/assets/items/rare_war_belt.png and /dev/null differ diff --git a/assets/items/rare_war_boots.png b/assets/items/rare_war_boots.png deleted file mode 100644 index d3e711204..000000000 Binary files a/assets/items/rare_war_boots.png and /dev/null differ diff --git a/assets/items/rare_war_club.png b/assets/items/rare_war_club.png deleted file mode 100644 index f932b1732..000000000 Binary files a/assets/items/rare_war_club.png and /dev/null differ diff --git a/assets/items/rare_war_dart.png b/assets/items/rare_war_dart.png deleted file mode 100644 index 6fac59d6c..000000000 Binary files a/assets/items/rare_war_dart.png and /dev/null differ diff --git a/assets/items/rare_war_fist.png b/assets/items/rare_war_fist.png deleted file mode 100644 index e9974282a..000000000 Binary files a/assets/items/rare_war_fist.png and /dev/null differ diff --git a/assets/items/rare_war_fork.png b/assets/items/rare_war_fork.png deleted file mode 100644 index 34725d524..000000000 Binary files a/assets/items/rare_war_fork.png and /dev/null differ diff --git a/assets/items/rare_war_gauntlets.png b/assets/items/rare_war_gauntlets.png deleted file mode 100644 index ad4c73689..000000000 Binary files a/assets/items/rare_war_gauntlets.png and /dev/null differ diff --git a/assets/items/rare_war_hammer.png b/assets/items/rare_war_hammer.png deleted file mode 100644 index 0d78753a3..000000000 Binary files a/assets/items/rare_war_hammer.png and /dev/null differ diff --git a/assets/items/rare_war_pike.png b/assets/items/rare_war_pike.png deleted file mode 100644 index e94731fb5..000000000 Binary files a/assets/items/rare_war_pike.png and /dev/null differ diff --git a/assets/items/rare_war_scythe.png b/assets/items/rare_war_scythe.png deleted file mode 100644 index b658e182e..000000000 Binary files a/assets/items/rare_war_scythe.png and /dev/null differ diff --git a/assets/items/rare_war_spear.png b/assets/items/rare_war_spear.png deleted file mode 100644 index 528df0979..000000000 Binary files a/assets/items/rare_war_spear.png and /dev/null differ diff --git a/assets/items/rare_war_spike.png b/assets/items/rare_war_spike.png deleted file mode 100644 index 1df879d8c..000000000 Binary files a/assets/items/rare_war_spike.png and /dev/null differ diff --git a/assets/items/rare_war_sword.png b/assets/items/rare_war_sword.png deleted file mode 100644 index 092737fa4..000000000 Binary files a/assets/items/rare_war_sword.png and /dev/null differ diff --git a/assets/items/rare_ward_bow.png b/assets/items/rare_ward_bow.png deleted file mode 100644 index 5f84a8049..000000000 Binary files a/assets/items/rare_ward_bow.png and /dev/null differ diff --git a/assets/items/rare_winged_axe.png b/assets/items/rare_winged_axe.png deleted file mode 100644 index c474a8e5d..000000000 Binary files a/assets/items/rare_winged_axe.png and /dev/null differ diff --git a/assets/items/rare_winged_harpoon.png b/assets/items/rare_winged_harpoon.png deleted file mode 100644 index 104d4356d..000000000 Binary files a/assets/items/rare_winged_harpoon.png and /dev/null differ diff --git a/assets/items/rare_winged_knife.png b/assets/items/rare_winged_knife.png deleted file mode 100644 index 694ec51f2..000000000 Binary files a/assets/items/rare_winged_knife.png and /dev/null differ diff --git a/assets/items/rare_wire_fleece.png b/assets/items/rare_wire_fleece.png deleted file mode 100644 index 3e1242e02..000000000 Binary files a/assets/items/rare_wire_fleece.png and /dev/null differ diff --git a/assets/items/rare_wolf_head.png b/assets/items/rare_wolf_head.png deleted file mode 100644 index 05f2fd597..000000000 Binary files a/assets/items/rare_wolf_head.png and /dev/null differ diff --git a/assets/items/rare_wrist_sword.png b/assets/items/rare_wrist_sword.png deleted file mode 100644 index 9167f224f..000000000 Binary files a/assets/items/rare_wrist_sword.png and /dev/null differ diff --git a/assets/items/rare_wyrmhide.png b/assets/items/rare_wyrmhide.png deleted file mode 100644 index b20f31f41..000000000 Binary files a/assets/items/rare_wyrmhide.png and /dev/null differ diff --git a/assets/items/rare_wyrmhide_boots.png b/assets/items/rare_wyrmhide_boots.png deleted file mode 100644 index d35565fdd..000000000 Binary files a/assets/items/rare_wyrmhide_boots.png and /dev/null differ diff --git a/assets/items/rare_yari.png b/assets/items/rare_yari.png deleted file mode 100644 index e8763e9ad..000000000 Binary files a/assets/items/rare_yari.png and /dev/null differ diff --git a/assets/items/rare_zweihander.png b/assets/items/rare_zweihander.png deleted file mode 100644 index 686d9ea7e..000000000 Binary files a/assets/items/rare_zweihander.png and /dev/null differ diff --git a/assets/items/rune_10_thul.png b/assets/items/rune_10_thul.png deleted file mode 100644 index 2893f5373..000000000 Binary files a/assets/items/rune_10_thul.png and /dev/null differ diff --git a/assets/items/rune_11_amn.png b/assets/items/rune_11_amn.png deleted file mode 100644 index 758954865..000000000 Binary files a/assets/items/rune_11_amn.png and /dev/null differ diff --git a/assets/items/rune_12_sol.png b/assets/items/rune_12_sol.png deleted file mode 100644 index dc72f53ad..000000000 Binary files a/assets/items/rune_12_sol.png and /dev/null differ diff --git a/assets/items/rune_13_shael.png b/assets/items/rune_13_shael.png deleted file mode 100644 index 8e5da9cba..000000000 Binary files a/assets/items/rune_13_shael.png and /dev/null differ diff --git a/assets/items/rune_14_dol.png b/assets/items/rune_14_dol.png deleted file mode 100644 index 19f85ed67..000000000 Binary files a/assets/items/rune_14_dol.png and /dev/null differ diff --git a/assets/items/rune_15_hel.png b/assets/items/rune_15_hel.png deleted file mode 100644 index 6b0476b81..000000000 Binary files a/assets/items/rune_15_hel.png and /dev/null differ diff --git a/assets/items/rune_16_io.png b/assets/items/rune_16_io.png deleted file mode 100644 index fbd7a7d86..000000000 Binary files a/assets/items/rune_16_io.png and /dev/null differ diff --git a/assets/items/rune_17_lum.png b/assets/items/rune_17_lum.png deleted file mode 100644 index 1ea14a3b0..000000000 Binary files a/assets/items/rune_17_lum.png and /dev/null differ diff --git a/assets/items/rune_18_ko.png b/assets/items/rune_18_ko.png deleted file mode 100644 index 422878842..000000000 Binary files a/assets/items/rune_18_ko.png and /dev/null differ diff --git a/assets/items/rune_19_fal.png b/assets/items/rune_19_fal.png deleted file mode 100644 index 468e409bb..000000000 Binary files a/assets/items/rune_19_fal.png and /dev/null differ diff --git a/assets/items/rune_1_el.png b/assets/items/rune_1_el.png deleted file mode 100644 index 32dfb6aa8..000000000 Binary files a/assets/items/rune_1_el.png and /dev/null differ diff --git a/assets/items/rune_20_lem.png b/assets/items/rune_20_lem.png deleted file mode 100644 index 27bd91036..000000000 Binary files a/assets/items/rune_20_lem.png and /dev/null differ diff --git a/assets/items/rune_21_pul.png b/assets/items/rune_21_pul.png deleted file mode 100644 index c05e7506b..000000000 Binary files a/assets/items/rune_21_pul.png and /dev/null differ diff --git a/assets/items/rune_22_um.png b/assets/items/rune_22_um.png deleted file mode 100644 index 153ad6132..000000000 Binary files a/assets/items/rune_22_um.png and /dev/null differ diff --git a/assets/items/rune_23_mal.png b/assets/items/rune_23_mal.png deleted file mode 100644 index f2f536da7..000000000 Binary files a/assets/items/rune_23_mal.png and /dev/null differ diff --git a/assets/items/rune_24_ist.png b/assets/items/rune_24_ist.png deleted file mode 100644 index 888da8e0f..000000000 Binary files a/assets/items/rune_24_ist.png and /dev/null differ diff --git a/assets/items/rune_25_gul.png b/assets/items/rune_25_gul.png deleted file mode 100644 index eaa1786e4..000000000 Binary files a/assets/items/rune_25_gul.png and /dev/null differ diff --git a/assets/items/rune_26_vex.png b/assets/items/rune_26_vex.png deleted file mode 100644 index b9c7861d4..000000000 Binary files a/assets/items/rune_26_vex.png and /dev/null differ diff --git a/assets/items/rune_27_ohm.png b/assets/items/rune_27_ohm.png deleted file mode 100644 index 91c948436..000000000 Binary files a/assets/items/rune_27_ohm.png and /dev/null differ diff --git a/assets/items/rune_28_lo.png b/assets/items/rune_28_lo.png deleted file mode 100644 index 64971d7ab..000000000 Binary files a/assets/items/rune_28_lo.png and /dev/null differ diff --git a/assets/items/rune_29_sur.png b/assets/items/rune_29_sur.png deleted file mode 100644 index 862c7b34b..000000000 Binary files a/assets/items/rune_29_sur.png and /dev/null differ diff --git a/assets/items/rune_2_eld.png b/assets/items/rune_2_eld.png deleted file mode 100644 index aa47f68fa..000000000 Binary files a/assets/items/rune_2_eld.png and /dev/null differ diff --git a/assets/items/rune_30_ber.png b/assets/items/rune_30_ber.png deleted file mode 100644 index 4edd6eb9e..000000000 Binary files a/assets/items/rune_30_ber.png and /dev/null differ diff --git a/assets/items/rune_31_jah.png b/assets/items/rune_31_jah.png deleted file mode 100644 index c25ce02d5..000000000 Binary files a/assets/items/rune_31_jah.png and /dev/null differ diff --git a/assets/items/rune_32_cham.png b/assets/items/rune_32_cham.png deleted file mode 100644 index e7803f483..000000000 Binary files a/assets/items/rune_32_cham.png and /dev/null differ diff --git a/assets/items/rune_33_zod.png b/assets/items/rune_33_zod.png deleted file mode 100644 index 52f005e07..000000000 Binary files a/assets/items/rune_33_zod.png and /dev/null differ diff --git a/assets/items/rune_3_tir.png b/assets/items/rune_3_tir.png deleted file mode 100644 index e36de94b4..000000000 Binary files a/assets/items/rune_3_tir.png and /dev/null differ diff --git a/assets/items/rune_4_nef.png b/assets/items/rune_4_nef.png deleted file mode 100644 index 37adbd01c..000000000 Binary files a/assets/items/rune_4_nef.png and /dev/null differ diff --git a/assets/items/rune_5_eth.png b/assets/items/rune_5_eth.png deleted file mode 100644 index d339b1af6..000000000 Binary files a/assets/items/rune_5_eth.png and /dev/null differ diff --git a/assets/items/rune_6_ith.png b/assets/items/rune_6_ith.png deleted file mode 100644 index 56536dd65..000000000 Binary files a/assets/items/rune_6_ith.png and /dev/null differ diff --git a/assets/items/rune_7_tal.png b/assets/items/rune_7_tal.png deleted file mode 100644 index a56715c53..000000000 Binary files a/assets/items/rune_7_tal.png and /dev/null differ diff --git a/assets/items/rune_8_ral.png b/assets/items/rune_8_ral.png deleted file mode 100644 index e8ef5a037..000000000 Binary files a/assets/items/rune_8_ral.png and /dev/null differ diff --git a/assets/items/rune_9_ort.png b/assets/items/rune_9_ort.png deleted file mode 100644 index 3865ad14e..000000000 Binary files a/assets/items/rune_9_ort.png and /dev/null differ diff --git a/assets/items/set_aldur_advance.png b/assets/items/set_aldur_advance.png deleted file mode 100644 index b0759467c..000000000 Binary files a/assets/items/set_aldur_advance.png and /dev/null differ diff --git a/assets/items/set_aldurs_armor.png b/assets/items/set_aldurs_armor.png deleted file mode 100644 index 93cb362fc..000000000 Binary files a/assets/items/set_aldurs_armor.png and /dev/null differ diff --git a/assets/items/set_aldurs_pelt.png b/assets/items/set_aldurs_pelt.png deleted file mode 100644 index df1ca1eb8..000000000 Binary files a/assets/items/set_aldurs_pelt.png and /dev/null differ diff --git a/assets/items/set_bul_kathos_sword.png b/assets/items/set_bul_kathos_sword.png deleted file mode 100644 index 5a39df991..000000000 Binary files a/assets/items/set_bul_kathos_sword.png and /dev/null differ diff --git a/assets/items/set_cleglaws_pincers.png b/assets/items/set_cleglaws_pincers.png deleted file mode 100644 index eb398e8ec..000000000 Binary files a/assets/items/set_cleglaws_pincers.png and /dev/null differ diff --git a/assets/items/set_cow_king_armor.png b/assets/items/set_cow_king_armor.png deleted file mode 100644 index c78331604..000000000 Binary files a/assets/items/set_cow_king_armor.png and /dev/null differ diff --git a/assets/items/set_cow_king_boots.png b/assets/items/set_cow_king_boots.png deleted file mode 100644 index 9b1156144..000000000 Binary files a/assets/items/set_cow_king_boots.png and /dev/null differ diff --git a/assets/items/set_cow_king_helm.png b/assets/items/set_cow_king_helm.png deleted file mode 100644 index 2bdc2206a..000000000 Binary files a/assets/items/set_cow_king_helm.png and /dev/null differ diff --git a/assets/items/set_deaths_belt.png b/assets/items/set_deaths_belt.png deleted file mode 100644 index 29e002fe1..000000000 Binary files a/assets/items/set_deaths_belt.png and /dev/null differ diff --git a/assets/items/set_deaths_gloves.png b/assets/items/set_deaths_gloves.png deleted file mode 100644 index 6cdc180a1..000000000 Binary files a/assets/items/set_deaths_gloves.png and /dev/null differ diff --git a/assets/items/set_griswold_valor.png b/assets/items/set_griswold_valor.png deleted file mode 100644 index 92cd9536d..000000000 Binary files a/assets/items/set_griswold_valor.png and /dev/null differ diff --git a/assets/items/set_griswolds_armor.png b/assets/items/set_griswolds_armor.png deleted file mode 100644 index 42a3915b3..000000000 Binary files a/assets/items/set_griswolds_armor.png and /dev/null differ diff --git a/assets/items/set_griswolds_scepter.png b/assets/items/set_griswolds_scepter.png deleted file mode 100644 index a454a8192..000000000 Binary files a/assets/items/set_griswolds_scepter.png and /dev/null differ diff --git a/assets/items/set_griswolds_shield.png b/assets/items/set_griswolds_shield.png deleted file mode 100644 index b126de482..000000000 Binary files a/assets/items/set_griswolds_shield.png and /dev/null differ diff --git a/assets/items/set_guillaume_face.png b/assets/items/set_guillaume_face.png deleted file mode 100644 index 7ac718d8a..000000000 Binary files a/assets/items/set_guillaume_face.png and /dev/null differ diff --git a/assets/items/set_hsarus_belt.png b/assets/items/set_hsarus_belt.png deleted file mode 100644 index df5f9f7a0..000000000 Binary files a/assets/items/set_hsarus_belt.png and /dev/null differ diff --git a/assets/items/set_hsarus_shield.png b/assets/items/set_hsarus_shield.png deleted file mode 100644 index 311778676..000000000 Binary files a/assets/items/set_hsarus_shield.png and /dev/null differ diff --git a/assets/items/set_immortal_king_belt.png b/assets/items/set_immortal_king_belt.png deleted file mode 100644 index fcae05199..000000000 Binary files a/assets/items/set_immortal_king_belt.png and /dev/null differ diff --git a/assets/items/set_immortal_king_boots.png b/assets/items/set_immortal_king_boots.png deleted file mode 100644 index 7890efc73..000000000 Binary files a/assets/items/set_immortal_king_boots.png and /dev/null differ diff --git a/assets/items/set_immortal_king_gauntlets.png b/assets/items/set_immortal_king_gauntlets.png deleted file mode 100644 index 3e4be24d3..000000000 Binary files a/assets/items/set_immortal_king_gauntlets.png and /dev/null differ diff --git a/assets/items/set_immortal_king_maul.png b/assets/items/set_immortal_king_maul.png deleted file mode 100644 index 2b2195d24..000000000 Binary files a/assets/items/set_immortal_king_maul.png and /dev/null differ diff --git a/assets/items/set_immortal_king_soul_cage.png b/assets/items/set_immortal_king_soul_cage.png deleted file mode 100644 index 7bba61a58..000000000 Binary files a/assets/items/set_immortal_king_soul_cage.png and /dev/null differ diff --git a/assets/items/set_immortal_king_will.png b/assets/items/set_immortal_king_will.png deleted file mode 100644 index fd9a71cc9..000000000 Binary files a/assets/items/set_immortal_king_will.png and /dev/null differ diff --git a/assets/items/set_laying_of_hands.png b/assets/items/set_laying_of_hands.png deleted file mode 100644 index c6d14122d..000000000 Binary files a/assets/items/set_laying_of_hands.png and /dev/null differ diff --git a/assets/items/set_mavinas_armor.png b/assets/items/set_mavinas_armor.png deleted file mode 100644 index c8e964374..000000000 Binary files a/assets/items/set_mavinas_armor.png and /dev/null differ diff --git a/assets/items/set_mavinas_belt.png b/assets/items/set_mavinas_belt.png deleted file mode 100644 index 3da4587cd..000000000 Binary files a/assets/items/set_mavinas_belt.png and /dev/null differ diff --git a/assets/items/set_mavinas_caster.png b/assets/items/set_mavinas_caster.png deleted file mode 100644 index 1c7642cf6..000000000 Binary files a/assets/items/set_mavinas_caster.png and /dev/null differ diff --git a/assets/items/set_mavinas_gauntlets.png b/assets/items/set_mavinas_gauntlets.png deleted file mode 100644 index 1e34cff18..000000000 Binary files a/assets/items/set_mavinas_gauntlets.png and /dev/null differ diff --git a/assets/items/set_mavinas_true_sight.png b/assets/items/set_mavinas_true_sight.png deleted file mode 100644 index 1b9f86fcd..000000000 Binary files a/assets/items/set_mavinas_true_sight.png and /dev/null differ diff --git a/assets/items/set_milabregas_shield.png b/assets/items/set_milabregas_shield.png deleted file mode 100644 index dc4daff12..000000000 Binary files a/assets/items/set_milabregas_shield.png and /dev/null differ diff --git a/assets/items/set_misc_amulets.png b/assets/items/set_misc_amulets.png deleted file mode 100644 index 927c6b2b3..000000000 Binary files a/assets/items/set_misc_amulets.png and /dev/null differ diff --git a/assets/items/set_natalya_armor.png b/assets/items/set_natalya_armor.png deleted file mode 100644 index 553b601e8..000000000 Binary files a/assets/items/set_natalya_armor.png and /dev/null differ diff --git a/assets/items/set_natalya_helm.png b/assets/items/set_natalya_helm.png deleted file mode 100644 index 7f4a8bdff..000000000 Binary files a/assets/items/set_natalya_helm.png and /dev/null differ diff --git a/assets/items/set_natalya_scissors.png b/assets/items/set_natalya_scissors.png deleted file mode 100644 index d7ec3245a..000000000 Binary files a/assets/items/set_natalya_scissors.png and /dev/null differ diff --git a/assets/items/set_natalya_soul.png b/assets/items/set_natalya_soul.png deleted file mode 100644 index c5def2d08..000000000 Binary files a/assets/items/set_natalya_soul.png and /dev/null differ diff --git a/assets/items/set_offhand_cleglawsclaw.png b/assets/items/set_offhand_cleglawsclaw.png deleted file mode 100644 index e1674dd29..000000000 Binary files a/assets/items/set_offhand_cleglawsclaw.png and /dev/null differ diff --git a/assets/items/set_ondals_almighty.png b/assets/items/set_ondals_almighty.png deleted file mode 100644 index 11489ffbb..000000000 Binary files a/assets/items/set_ondals_almighty.png and /dev/null differ diff --git a/assets/items/set_ring.png b/assets/items/set_ring.png deleted file mode 100644 index 168f46ff0..000000000 Binary files a/assets/items/set_ring.png and /dev/null differ diff --git a/assets/items/set_sanders_helm.png b/assets/items/set_sanders_helm.png deleted file mode 100644 index 740a516e3..000000000 Binary files a/assets/items/set_sanders_helm.png and /dev/null differ diff --git a/assets/items/set_sazabi_armor.png b/assets/items/set_sazabi_armor.png deleted file mode 100644 index b65263db6..000000000 Binary files a/assets/items/set_sazabi_armor.png and /dev/null differ diff --git a/assets/items/set_sigon_armor.png b/assets/items/set_sigon_armor.png deleted file mode 100644 index 5091dfce7..000000000 Binary files a/assets/items/set_sigon_armor.png and /dev/null differ diff --git a/assets/items/set_sigon_belt.png b/assets/items/set_sigon_belt.png deleted file mode 100644 index 972c63ae0..000000000 Binary files a/assets/items/set_sigon_belt.png and /dev/null differ diff --git a/assets/items/set_sigon_boots.png b/assets/items/set_sigon_boots.png deleted file mode 100644 index 768b324ca..000000000 Binary files a/assets/items/set_sigon_boots.png and /dev/null differ diff --git a/assets/items/set_sigon_gloves.png b/assets/items/set_sigon_gloves.png deleted file mode 100644 index 89058a5c4..000000000 Binary files a/assets/items/set_sigon_gloves.png and /dev/null differ diff --git a/assets/items/set_sigon_helm.png b/assets/items/set_sigon_helm.png deleted file mode 100644 index 14f3262f4..000000000 Binary files a/assets/items/set_sigon_helm.png and /dev/null differ diff --git a/assets/items/set_sigon_shield.png b/assets/items/set_sigon_shield.png deleted file mode 100644 index 030486b77..000000000 Binary files a/assets/items/set_sigon_shield.png and /dev/null differ diff --git a/assets/items/set_taebaeks_glory.png b/assets/items/set_taebaeks_glory.png deleted file mode 100644 index 704c0badd..000000000 Binary files a/assets/items/set_taebaeks_glory.png and /dev/null differ diff --git a/assets/items/set_tal_rasha_fine-spun_cloth.png b/assets/items/set_tal_rasha_fine-spun_cloth.png deleted file mode 100644 index 5e1560e98..000000000 Binary files a/assets/items/set_tal_rasha_fine-spun_cloth.png and /dev/null differ diff --git a/assets/items/set_tal_rasha_guardianship.png b/assets/items/set_tal_rasha_guardianship.png deleted file mode 100644 index 4d1dc002e..000000000 Binary files a/assets/items/set_tal_rasha_guardianship.png and /dev/null differ diff --git a/assets/items/set_tal_rasha_horadric_crest.png b/assets/items/set_tal_rasha_horadric_crest.png deleted file mode 100644 index 9460e61d1..000000000 Binary files a/assets/items/set_tal_rasha_horadric_crest.png and /dev/null differ diff --git a/assets/items/set_tal_rasha_lidless_eye.png b/assets/items/set_tal_rasha_lidless_eye.png deleted file mode 100644 index 434bf3428..000000000 Binary files a/assets/items/set_tal_rasha_lidless_eye.png and /dev/null differ diff --git a/assets/items/set_trang-oul_claws.png b/assets/items/set_trang-oul_claws.png deleted file mode 100644 index 83dddf143..000000000 Binary files a/assets/items/set_trang-oul_claws.png and /dev/null differ diff --git a/assets/items/set_trang-oul_girth.png b/assets/items/set_trang-oul_girth.png deleted file mode 100644 index 4dadb4c21..000000000 Binary files a/assets/items/set_trang-oul_girth.png and /dev/null differ diff --git a/assets/items/set_trang-oul_shield.png b/assets/items/set_trang-oul_shield.png deleted file mode 100644 index 02a82164e..000000000 Binary files a/assets/items/set_trang-oul_shield.png and /dev/null differ diff --git a/assets/items/set_trang_oul_armor.png b/assets/items/set_trang_oul_armor.png deleted file mode 100644 index e69afa472..000000000 Binary files a/assets/items/set_trang_oul_armor.png and /dev/null differ diff --git a/assets/items/set_trang_oul_helm.png b/assets/items/set_trang_oul_helm.png deleted file mode 100644 index 5089dff71..000000000 Binary files a/assets/items/set_trang_oul_helm.png and /dev/null differ diff --git a/assets/items/set_whistans_guard.png b/assets/items/set_whistans_guard.png deleted file mode 100644 index 20b567fbc..000000000 Binary files a/assets/items/set_whistans_guard.png and /dev/null differ diff --git a/assets/items/uniq_alma_negra.png b/assets/items/uniq_alma_negra.png deleted file mode 100644 index b132b2908..000000000 Binary files a/assets/items/uniq_alma_negra.png and /dev/null differ diff --git a/assets/items/uniq_arkaines_valor.png b/assets/items/uniq_arkaines_valor.png deleted file mode 100644 index 51dd69e2c..000000000 Binary files a/assets/items/uniq_arkaines_valor.png and /dev/null differ diff --git a/assets/items/uniq_arm_of_king_leoric.png b/assets/items/uniq_arm_of_king_leoric.png deleted file mode 100644 index 5d1572855..000000000 Binary files a/assets/items/uniq_arm_of_king_leoric.png and /dev/null differ diff --git a/assets/items/uniq_armor_atmas_wail.png b/assets/items/uniq_armor_atmas_wail.png deleted file mode 100644 index 0680b8819..000000000 Binary files a/assets/items/uniq_armor_atmas_wail.png and /dev/null differ diff --git a/assets/items/uniq_armor_black_hades.png b/assets/items/uniq_armor_black_hades.png deleted file mode 100644 index d2afbf7d8..000000000 Binary files a/assets/items/uniq_armor_black_hades.png and /dev/null differ diff --git a/assets/items/uniq_armor_centurion.png b/assets/items/uniq_armor_centurion.png deleted file mode 100644 index 247d4d823..000000000 Binary files a/assets/items/uniq_armor_centurion.png and /dev/null differ diff --git a/assets/items/uniq_armor_crow_caw.png b/assets/items/uniq_armor_crow_caw.png deleted file mode 100644 index e6e3ff585..000000000 Binary files a/assets/items/uniq_armor_crow_caw.png and /dev/null differ diff --git a/assets/items/uniq_armor_duriel_shell.png b/assets/items/uniq_armor_duriel_shell.png deleted file mode 100644 index 814bcd7e5..000000000 Binary files a/assets/items/uniq_armor_duriel_shell.png and /dev/null differ diff --git a/assets/items/uniq_armor_greyform.png b/assets/items/uniq_armor_greyform.png deleted file mode 100644 index 14e846f43..000000000 Binary files a/assets/items/uniq_armor_greyform.png and /dev/null differ diff --git a/assets/items/uniq_armor_guardian_angel.png b/assets/items/uniq_armor_guardian_angel.png deleted file mode 100644 index 4795f29be..000000000 Binary files a/assets/items/uniq_armor_guardian_angel.png and /dev/null differ diff --git a/assets/items/uniq_armor_iron_pelt.png b/assets/items/uniq_armor_iron_pelt.png deleted file mode 100644 index c3f1d62a1..000000000 Binary files a/assets/items/uniq_armor_iron_pelt.png and /dev/null differ diff --git a/assets/items/uniq_armor_ormus_robes.png b/assets/items/uniq_armor_ormus_robes.png deleted file mode 100644 index 40defe6ba..000000000 Binary files a/assets/items/uniq_armor_ormus_robes.png and /dev/null differ diff --git a/assets/items/uniq_armor_shaftstop.png b/assets/items/uniq_armor_shaftstop.png deleted file mode 100644 index dd5006388..000000000 Binary files a/assets/items/uniq_armor_shaftstop.png and /dev/null differ diff --git a/assets/items/uniq_armor_skin_of_the_flayed_one.png b/assets/items/uniq_armor_skin_of_the_flayed_one.png deleted file mode 100644 index a68cf0ee7..000000000 Binary files a/assets/items/uniq_armor_skin_of_the_flayed_one.png and /dev/null differ diff --git a/assets/items/uniq_armor_skin_of_the_vipermagi.png b/assets/items/uniq_armor_skin_of_the_vipermagi.png deleted file mode 100644 index 898f87e10..000000000 Binary files a/assets/items/uniq_armor_skin_of_the_vipermagi.png and /dev/null differ diff --git a/assets/items/uniq_armor_skullder_ire.png b/assets/items/uniq_armor_skullder_ire.png deleted file mode 100644 index d88c43f86..000000000 Binary files a/assets/items/uniq_armor_skullder_ire.png and /dev/null differ diff --git a/assets/items/uniq_armor_spirit_forge.png b/assets/items/uniq_armor_spirit_forge.png deleted file mode 100644 index d3982ed74..000000000 Binary files a/assets/items/uniq_armor_spirit_forge.png and /dev/null differ diff --git a/assets/items/uniq_armor_steel_carapace.png b/assets/items/uniq_armor_steel_carapace.png deleted file mode 100644 index eacf4a760..000000000 Binary files a/assets/items/uniq_armor_steel_carapace.png and /dev/null differ diff --git a/assets/items/uniq_armor_toothrow.png b/assets/items/uniq_armor_toothrow.png deleted file mode 100644 index f01bb72cc..000000000 Binary files a/assets/items/uniq_armor_toothrow.png and /dev/null differ diff --git a/assets/items/uniq_bartucs_talons.png b/assets/items/uniq_bartucs_talons.png deleted file mode 100644 index db98be1cc..000000000 Binary files a/assets/items/uniq_bartucs_talons.png and /dev/null differ diff --git a/assets/items/uniq_belt_arachnid_mesh.png b/assets/items/uniq_belt_arachnid_mesh.png deleted file mode 100644 index 811c4f18e..000000000 Binary files a/assets/items/uniq_belt_arachnid_mesh.png and /dev/null differ diff --git a/assets/items/uniq_belt_goldwrap.png b/assets/items/uniq_belt_goldwrap.png deleted file mode 100644 index 71476a75e..000000000 Binary files a/assets/items/uniq_belt_goldwrap.png and /dev/null differ diff --git a/assets/items/uniq_belt_nosferatus_coil.png b/assets/items/uniq_belt_nosferatus_coil.png deleted file mode 100644 index 42a848522..000000000 Binary files a/assets/items/uniq_belt_nosferatus_coil.png and /dev/null differ diff --git a/assets/items/uniq_belt_razortail.png b/assets/items/uniq_belt_razortail.png deleted file mode 100644 index e1a2eeba2..000000000 Binary files a/assets/items/uniq_belt_razortail.png and /dev/null differ diff --git a/assets/items/uniq_belt_snowclash.png b/assets/items/uniq_belt_snowclash.png deleted file mode 100644 index f51e34b9a..000000000 Binary files a/assets/items/uniq_belt_snowclash.png and /dev/null differ diff --git a/assets/items/uniq_belt_string_of_ears.png b/assets/items/uniq_belt_string_of_ears.png deleted file mode 100644 index d9770f1ac..000000000 Binary files a/assets/items/uniq_belt_string_of_ears.png and /dev/null differ diff --git a/assets/items/uniq_belt_thundergod_vigor.png b/assets/items/uniq_belt_thundergod_vigor.png deleted file mode 100644 index d09f00c2b..000000000 Binary files a/assets/items/uniq_belt_thundergod_vigor.png and /dev/null differ diff --git a/assets/items/uniq_belt_verdungo_hearty_cord.png b/assets/items/uniq_belt_verdungo_hearty_cord.png deleted file mode 100644 index 469878289..000000000 Binary files a/assets/items/uniq_belt_verdungo_hearty_cord.png and /dev/null differ diff --git a/assets/items/uniq_bloodfist.png b/assets/items/uniq_bloodfist.png deleted file mode 100644 index 3a3e5c58b..000000000 Binary files a/assets/items/uniq_bloodfist.png and /dev/null differ diff --git a/assets/items/uniq_boots_goblin_toe.png b/assets/items/uniq_boots_goblin_toe.png deleted file mode 100644 index 1232cc2f6..000000000 Binary files a/assets/items/uniq_boots_goblin_toe.png and /dev/null differ diff --git a/assets/items/uniq_boots_gore_rider.png b/assets/items/uniq_boots_gore_rider.png deleted file mode 100644 index f9df37f5b..000000000 Binary files a/assets/items/uniq_boots_gore_rider.png and /dev/null differ diff --git a/assets/items/uniq_boots_marrowwalk.png b/assets/items/uniq_boots_marrowwalk.png deleted file mode 100644 index 3e2deaa41..000000000 Binary files a/assets/items/uniq_boots_marrowwalk.png and /dev/null differ diff --git a/assets/items/uniq_boots_sandstorm_trek.png b/assets/items/uniq_boots_sandstorm_trek.png deleted file mode 100644 index e4e037ba5..000000000 Binary files a/assets/items/uniq_boots_sandstorm_trek.png and /dev/null differ diff --git a/assets/items/uniq_boots_shadow_dancer.png b/assets/items/uniq_boots_shadow_dancer.png deleted file mode 100644 index 94afe1885..000000000 Binary files a/assets/items/uniq_boots_shadow_dancer.png and /dev/null differ diff --git a/assets/items/uniq_boots_silkweave.png b/assets/items/uniq_boots_silkweave.png deleted file mode 100644 index 1bdf4a576..000000000 Binary files a/assets/items/uniq_boots_silkweave.png and /dev/null differ diff --git a/assets/items/uniq_boots_war_traveler.png b/assets/items/uniq_boots_war_traveler.png deleted file mode 100644 index 9675d68a6..000000000 Binary files a/assets/items/uniq_boots_war_traveler.png and /dev/null differ diff --git a/assets/items/uniq_boots_waterwalk.png b/assets/items/uniq_boots_waterwalk.png deleted file mode 100644 index 6e46dd045..000000000 Binary files a/assets/items/uniq_boots_waterwalk.png and /dev/null differ diff --git a/assets/items/uniq_corpsemourn.png b/assets/items/uniq_corpsemourn.png deleted file mode 100644 index fed7a4a5a..000000000 Binary files a/assets/items/uniq_corpsemourn.png and /dev/null differ diff --git a/assets/items/uniq_crown_of_thieves.png b/assets/items/uniq_crown_of_thieves.png deleted file mode 100644 index 282035bd3..000000000 Binary files a/assets/items/uniq_crown_of_thieves.png and /dev/null differ diff --git a/assets/items/uniq_demonhorns_edge.png b/assets/items/uniq_demonhorns_edge.png deleted file mode 100644 index f59f70c23..000000000 Binary files a/assets/items/uniq_demonhorns_edge.png and /dev/null differ diff --git a/assets/items/uniq_dragonscale.png b/assets/items/uniq_dragonscale.png deleted file mode 100644 index 0b2cd0d53..000000000 Binary files a/assets/items/uniq_dragonscale.png and /dev/null differ diff --git a/assets/items/uniq_firelizards_talons.png b/assets/items/uniq_firelizards_talons.png deleted file mode 100644 index 96915795d..000000000 Binary files a/assets/items/uniq_firelizards_talons.png and /dev/null differ diff --git a/assets/items/uniq_gheeds_fortune.png b/assets/items/uniq_gheeds_fortune.png deleted file mode 100644 index e6770c9d3..000000000 Binary files a/assets/items/uniq_gheeds_fortune.png and /dev/null differ diff --git a/assets/items/uniq_glooms_trap.png b/assets/items/uniq_glooms_trap.png deleted file mode 100644 index fb12cbff0..000000000 Binary files a/assets/items/uniq_glooms_trap.png and /dev/null differ diff --git a/assets/items/uniq_gloves_chance_guards.png b/assets/items/uniq_gloves_chance_guards.png deleted file mode 100644 index 30abafcf5..000000000 Binary files a/assets/items/uniq_gloves_chance_guards.png and /dev/null differ diff --git a/assets/items/uniq_gloves_dracul_grasp.png b/assets/items/uniq_gloves_dracul_grasp.png deleted file mode 100644 index c2f936061..000000000 Binary files a/assets/items/uniq_gloves_dracul_grasp.png and /dev/null differ diff --git a/assets/items/uniq_gloves_frostburn.png b/assets/items/uniq_gloves_frostburn.png deleted file mode 100644 index 15328f9ce..000000000 Binary files a/assets/items/uniq_gloves_frostburn.png and /dev/null differ diff --git a/assets/items/uniq_gloves_ghoulhide.png b/assets/items/uniq_gloves_ghoulhide.png deleted file mode 100644 index 23f7e73e5..000000000 Binary files a/assets/items/uniq_gloves_ghoulhide.png and /dev/null differ diff --git a/assets/items/uniq_gloves_gravepalm.png b/assets/items/uniq_gloves_gravepalm.png deleted file mode 100644 index 136ea7151..000000000 Binary files a/assets/items/uniq_gloves_gravepalm.png and /dev/null differ diff --git a/assets/items/uniq_gloves_hand_of_broc.png b/assets/items/uniq_gloves_hand_of_broc.png deleted file mode 100644 index bac3e3133..000000000 Binary files a/assets/items/uniq_gloves_hand_of_broc.png and /dev/null differ diff --git a/assets/items/uniq_gloves_hellmouth.png b/assets/items/uniq_gloves_hellmouth.png deleted file mode 100644 index 7bd0dd307..000000000 Binary files a/assets/items/uniq_gloves_hellmouth.png and /dev/null differ diff --git a/assets/items/uniq_gloves_lava_gout.png b/assets/items/uniq_gloves_lava_gout.png deleted file mode 100644 index b10ced037..000000000 Binary files a/assets/items/uniq_gloves_lava_gout.png and /dev/null differ diff --git a/assets/items/uniq_gloves_magefist.png b/assets/items/uniq_gloves_magefist.png deleted file mode 100644 index c796d59c1..000000000 Binary files a/assets/items/uniq_gloves_magefist.png and /dev/null differ diff --git a/assets/items/uniq_gloves_steelrend.png b/assets/items/uniq_gloves_steelrend.png deleted file mode 100644 index 605730a7f..000000000 Binary files a/assets/items/uniq_gloves_steelrend.png and /dev/null differ diff --git a/assets/items/uniq_gloves_venom_grip.png b/assets/items/uniq_gloves_venom_grip.png deleted file mode 100644 index 405e8e776..000000000 Binary files a/assets/items/uniq_gloves_venom_grip.png and /dev/null differ diff --git a/assets/items/uniq_gul_dagger.png b/assets/items/uniq_gul_dagger.png deleted file mode 100644 index e5c3a3a15..000000000 Binary files a/assets/items/uniq_gul_dagger.png and /dev/null differ diff --git a/assets/items/uniq_halaberds_reign.png b/assets/items/uniq_halaberds_reign.png deleted file mode 100644 index f9a727b87..000000000 Binary files a/assets/items/uniq_halaberds_reign.png and /dev/null differ diff --git a/assets/items/uniq_hand_of_blessed_light.png b/assets/items/uniq_hand_of_blessed_light.png deleted file mode 100644 index 1ed741411..000000000 Binary files a/assets/items/uniq_hand_of_blessed_light.png and /dev/null differ diff --git a/assets/items/uniq_heavens_light.png b/assets/items/uniq_heavens_light.png deleted file mode 100644 index 8171744e7..000000000 Binary files a/assets/items/uniq_heavens_light.png and /dev/null differ diff --git a/assets/items/uniq_helm_andariel_visage.png b/assets/items/uniq_helm_andariel_visage.png deleted file mode 100644 index 5d3caea8d..000000000 Binary files a/assets/items/uniq_helm_andariel_visage.png and /dev/null differ diff --git a/assets/items/uniq_helm_arreat_face.png b/assets/items/uniq_helm_arreat_face.png deleted file mode 100644 index d1a2e8766..000000000 Binary files a/assets/items/uniq_helm_arreat_face.png and /dev/null differ diff --git a/assets/items/uniq_helm_biggins_bonnet.png b/assets/items/uniq_helm_biggins_bonnet.png deleted file mode 100644 index d31c36c27..000000000 Binary files a/assets/items/uniq_helm_biggins_bonnet.png and /dev/null differ diff --git a/assets/items/uniq_helm_blackhorns_face.png b/assets/items/uniq_helm_blackhorns_face.png deleted file mode 100644 index 6df3bd5bc..000000000 Binary files a/assets/items/uniq_helm_blackhorns_face.png and /dev/null differ diff --git a/assets/items/uniq_helm_cerebus_bite.png b/assets/items/uniq_helm_cerebus_bite.png deleted file mode 100644 index 2c88b2d22..000000000 Binary files a/assets/items/uniq_helm_cerebus_bite.png and /dev/null differ diff --git a/assets/items/uniq_helm_crown_of_ages.png b/assets/items/uniq_helm_crown_of_ages.png deleted file mode 100644 index c02f614de..000000000 Binary files a/assets/items/uniq_helm_crown_of_ages.png and /dev/null differ diff --git a/assets/items/uniq_helm_darksight_helm.png b/assets/items/uniq_helm_darksight_helm.png deleted file mode 100644 index 68787492e..000000000 Binary files a/assets/items/uniq_helm_darksight_helm.png and /dev/null differ diff --git a/assets/items/uniq_helm_giant_skull.png b/assets/items/uniq_helm_giant_skull.png deleted file mode 100644 index 6af91d29c..000000000 Binary files a/assets/items/uniq_helm_giant_skull.png and /dev/null differ diff --git a/assets/items/uniq_helm_griffon_eye.png b/assets/items/uniq_helm_griffon_eye.png deleted file mode 100644 index 7b5e40297..000000000 Binary files a/assets/items/uniq_helm_griffon_eye.png and /dev/null differ diff --git a/assets/items/uniq_helm_harlequin_crest.png b/assets/items/uniq_helm_harlequin_crest.png deleted file mode 100644 index 98afe8517..000000000 Binary files a/assets/items/uniq_helm_harlequin_crest.png and /dev/null differ diff --git a/assets/items/uniq_helm_jalal_mane.png b/assets/items/uniq_helm_jalal_mane.png deleted file mode 100644 index 4f34b483f..000000000 Binary files a/assets/items/uniq_helm_jalal_mane.png and /dev/null differ diff --git a/assets/items/uniq_helm_kira_guardian.png b/assets/items/uniq_helm_kira_guardian.png deleted file mode 100644 index 4e89fb7d1..000000000 Binary files a/assets/items/uniq_helm_kira_guardian.png and /dev/null differ diff --git a/assets/items/uniq_helm_nightwing_veil.png b/assets/items/uniq_helm_nightwing_veil.png deleted file mode 100644 index 33adcfae9..000000000 Binary files a/assets/items/uniq_helm_nightwing_veil.png and /dev/null differ diff --git a/assets/items/uniq_helm_rockstopper.png b/assets/items/uniq_helm_rockstopper.png deleted file mode 100644 index 7ce1b7264..000000000 Binary files a/assets/items/uniq_helm_rockstopper.png and /dev/null differ diff --git a/assets/items/uniq_helm_stealskull.png b/assets/items/uniq_helm_stealskull.png deleted file mode 100644 index d09251b37..000000000 Binary files a/assets/items/uniq_helm_stealskull.png and /dev/null differ diff --git a/assets/items/uniq_helm_steel_shade.png b/assets/items/uniq_helm_steel_shade.png deleted file mode 100644 index d8b1609aa..000000000 Binary files a/assets/items/uniq_helm_steel_shade.png and /dev/null differ diff --git a/assets/items/uniq_helm_valkyrie_wing.png b/assets/items/uniq_helm_valkyrie_wing.png deleted file mode 100644 index fc244ac43..000000000 Binary files a/assets/items/uniq_helm_valkyrie_wing.png and /dev/null differ diff --git a/assets/items/uniq_helm_vampire_gaze.png b/assets/items/uniq_helm_vampire_gaze.png deleted file mode 100644 index ca2ba484f..000000000 Binary files a/assets/items/uniq_helm_vampire_gaze.png and /dev/null differ diff --git a/assets/items/uniq_herald_of_zakarum.png b/assets/items/uniq_herald_of_zakarum.png deleted file mode 100644 index ba3077310..000000000 Binary files a/assets/items/uniq_herald_of_zakarum.png and /dev/null differ diff --git a/assets/items/uniq_hotspur.png b/assets/items/uniq_hotspur.png deleted file mode 100644 index d22a8d3ad..000000000 Binary files a/assets/items/uniq_hotspur.png and /dev/null differ diff --git a/assets/items/uniq_infernostride.png b/assets/items/uniq_infernostride.png deleted file mode 100644 index abab6c1d4..000000000 Binary files a/assets/items/uniq_infernostride.png and /dev/null differ diff --git a/assets/items/uniq_jade_talon.png b/assets/items/uniq_jade_talon.png deleted file mode 100644 index a2df5393e..000000000 Binary files a/assets/items/uniq_jade_talon.png and /dev/null differ diff --git a/assets/items/uniq_lenymo.png b/assets/items/uniq_lenymo.png deleted file mode 100644 index 3b209cc47..000000000 Binary files a/assets/items/uniq_lenymo.png and /dev/null differ diff --git a/assets/items/uniq_leviathan.png b/assets/items/uniq_leviathan.png deleted file mode 100644 index e5fd6d3c4..000000000 Binary files a/assets/items/uniq_leviathan.png and /dev/null differ diff --git a/assets/items/uniq_lidless_wall.png b/assets/items/uniq_lidless_wall.png deleted file mode 100644 index fc2c1bc2d..000000000 Binary files a/assets/items/uniq_lidless_wall.png and /dev/null differ diff --git a/assets/items/uniq_misc_amulets.png b/assets/items/uniq_misc_amulets.png deleted file mode 100644 index 33e01da84..000000000 Binary files a/assets/items/uniq_misc_amulets.png and /dev/null differ diff --git a/assets/items/uniq_misc_rainbow_facet.png b/assets/items/uniq_misc_rainbow_facet.png deleted file mode 100644 index bb2b1726b..000000000 Binary files a/assets/items/uniq_misc_rainbow_facet.png and /dev/null differ diff --git a/assets/items/uniq_misc_rings.png b/assets/items/uniq_misc_rings.png deleted file mode 100644 index 23f4feb5b..000000000 Binary files a/assets/items/uniq_misc_rings.png and /dev/null differ diff --git a/assets/items/uniq_mosers_blessed_circle.png b/assets/items/uniq_mosers_blessed_circle.png deleted file mode 100644 index 434135a82..000000000 Binary files a/assets/items/uniq_mosers_blessed_circle.png and /dev/null differ diff --git a/assets/items/uniq_nightsmoke.png b/assets/items/uniq_nightsmoke.png deleted file mode 100644 index 500c1b073..000000000 Binary files a/assets/items/uniq_nightsmoke.png and /dev/null differ diff --git a/assets/items/uniq_offhand_blackoak_shield.png b/assets/items/uniq_offhand_blackoak_shield.png deleted file mode 100644 index dcf37604d..000000000 Binary files a/assets/items/uniq_offhand_blackoak_shield.png and /dev/null differ diff --git a/assets/items/uniq_offhand_boneflame.png b/assets/items/uniq_offhand_boneflame.png deleted file mode 100644 index 16773cddc..000000000 Binary files a/assets/items/uniq_offhand_boneflame.png and /dev/null differ diff --git a/assets/items/uniq_offhand_darkforce_spawn.png b/assets/items/uniq_offhand_darkforce_spawn.png deleted file mode 100644 index d9aa1e964..000000000 Binary files a/assets/items/uniq_offhand_darkforce_spawn.png and /dev/null differ diff --git a/assets/items/uniq_offhand_gerkes_sanctuary.png b/assets/items/uniq_offhand_gerkes_sanctuary.png deleted file mode 100644 index da49b4d5a..000000000 Binary files a/assets/items/uniq_offhand_gerkes_sanctuary.png and /dev/null differ diff --git a/assets/items/uniq_offhand_head_hunter_glory.png b/assets/items/uniq_offhand_head_hunter_glory.png deleted file mode 100644 index 218b9977c..000000000 Binary files a/assets/items/uniq_offhand_head_hunter_glory.png and /dev/null differ diff --git a/assets/items/uniq_offhand_head_hunters_glory.png b/assets/items/uniq_offhand_head_hunters_glory.png deleted file mode 100644 index b12101a23..000000000 Binary files a/assets/items/uniq_offhand_head_hunters_glory.png and /dev/null differ diff --git a/assets/items/uniq_offhand_homunculus.png b/assets/items/uniq_offhand_homunculus.png deleted file mode 100644 index b47f9d9df..000000000 Binary files a/assets/items/uniq_offhand_homunculus.png and /dev/null differ diff --git a/assets/items/uniq_offhand_lance_guard.png b/assets/items/uniq_offhand_lance_guard.png deleted file mode 100644 index 8d2ed407b..000000000 Binary files a/assets/items/uniq_offhand_lance_guard.png and /dev/null differ diff --git a/assets/items/uniq_offhand_medusas_gaze.png b/assets/items/uniq_offhand_medusas_gaze.png deleted file mode 100644 index eaa22f3e4..000000000 Binary files a/assets/items/uniq_offhand_medusas_gaze.png and /dev/null differ diff --git a/assets/items/uniq_offhand_spike_thorn.png b/assets/items/uniq_offhand_spike_thorn.png deleted file mode 100644 index fc5853a36..000000000 Binary files a/assets/items/uniq_offhand_spike_thorn.png and /dev/null differ diff --git a/assets/items/uniq_offhand_spirit_ward.png b/assets/items/uniq_offhand_spirit_ward.png deleted file mode 100644 index 7acf31f78..000000000 Binary files a/assets/items/uniq_offhand_spirit_ward.png and /dev/null differ diff --git a/assets/items/uniq_offhand_stormchaser.png b/assets/items/uniq_offhand_stormchaser.png deleted file mode 100644 index d43f11b14..000000000 Binary files a/assets/items/uniq_offhand_stormchaser.png and /dev/null differ diff --git a/assets/items/uniq_offhand_stormshield.png b/assets/items/uniq_offhand_stormshield.png deleted file mode 100644 index 319b96f40..000000000 Binary files a/assets/items/uniq_offhand_stormshield.png and /dev/null differ diff --git a/assets/items/uniq_offhand_tiamats_rebuke.png b/assets/items/uniq_offhand_tiamats_rebuke.png deleted file mode 100644 index cba90c4e1..000000000 Binary files a/assets/items/uniq_offhand_tiamats_rebuke.png and /dev/null differ diff --git a/assets/items/uniq_peasant_crown.png b/assets/items/uniq_peasant_crown.png deleted file mode 100644 index 07078ce6c..000000000 Binary files a/assets/items/uniq_peasant_crown.png and /dev/null differ diff --git a/assets/items/uniq_pelta_lunata.png b/assets/items/uniq_pelta_lunata.png deleted file mode 100644 index eebbf2c40..000000000 Binary files a/assets/items/uniq_pelta_lunata.png and /dev/null differ diff --git a/assets/items/uniq_que_hagens_wisdom.png b/assets/items/uniq_que_hagens_wisdom.png deleted file mode 100644 index 910182809..000000000 Binary files a/assets/items/uniq_que_hagens_wisdom.png and /dev/null differ diff --git a/assets/items/uniq_ravenlore.png b/assets/items/uniq_ravenlore.png deleted file mode 100644 index fb977ed25..000000000 Binary files a/assets/items/uniq_ravenlore.png and /dev/null differ diff --git a/assets/items/uniq_rune_master.png b/assets/items/uniq_rune_master.png deleted file mode 100644 index 4647c0227..000000000 Binary files a/assets/items/uniq_rune_master.png and /dev/null differ diff --git a/assets/items/uniq_shadow_killer.png b/assets/items/uniq_shadow_killer.png deleted file mode 100644 index 3dff3e483..000000000 Binary files a/assets/items/uniq_shadow_killer.png and /dev/null differ diff --git a/assets/items/uniq_silks_of_victor.png b/assets/items/uniq_silks_of_victor.png deleted file mode 100644 index 020c33b4b..000000000 Binary files a/assets/items/uniq_silks_of_victor.png and /dev/null differ diff --git a/assets/items/uniq_soul_drainer.png b/assets/items/uniq_soul_drainer.png deleted file mode 100644 index 9b79a6486..000000000 Binary files a/assets/items/uniq_soul_drainer.png and /dev/null differ diff --git a/assets/items/uniq_spirit_keeper.png b/assets/items/uniq_spirit_keeper.png deleted file mode 100644 index e032521aa..000000000 Binary files a/assets/items/uniq_spirit_keeper.png and /dev/null differ diff --git a/assets/items/uniq_spirit_shroud.png b/assets/items/uniq_spirit_shroud.png deleted file mode 100644 index e7d891c64..000000000 Binary files a/assets/items/uniq_spirit_shroud.png and /dev/null differ diff --git a/assets/items/uniq_suicide_branch.png b/assets/items/uniq_suicide_branch.png deleted file mode 100644 index 87241c2a7..000000000 Binary files a/assets/items/uniq_suicide_branch.png and /dev/null differ diff --git a/assets/items/uniq_tarnhelm.png b/assets/items/uniq_tarnhelm.png deleted file mode 100644 index af3682733..000000000 Binary files a/assets/items/uniq_tarnhelm.png and /dev/null differ diff --git a/assets/items/uniq_the_gladiators_bane.png b/assets/items/uniq_the_gladiators_bane.png deleted file mode 100644 index effa93c4a..000000000 Binary files a/assets/items/uniq_the_gladiators_bane.png and /dev/null differ diff --git a/assets/items/uniq_torch_of_iro.png b/assets/items/uniq_torch_of_iro.png deleted file mode 100644 index c76cdad43..000000000 Binary files a/assets/items/uniq_torch_of_iro.png and /dev/null differ diff --git a/assets/items/uniq_twitchthroe.png b/assets/items/uniq_twitchthroe.png deleted file mode 100644 index edb3b3a29..000000000 Binary files a/assets/items/uniq_twitchthroe.png and /dev/null differ diff --git a/assets/items/uniq_tyraels_might.png b/assets/items/uniq_tyraels_might.png deleted file mode 100644 index 9c6e810a7..000000000 Binary files a/assets/items/uniq_tyraels_might.png and /dev/null differ diff --git a/assets/items/uniq_umes_lament.png b/assets/items/uniq_umes_lament.png deleted file mode 100644 index a3aacb01a..000000000 Binary files a/assets/items/uniq_umes_lament.png and /dev/null differ diff --git a/assets/items/uniq_visceratuant.png b/assets/items/uniq_visceratuant.png deleted file mode 100644 index d55de0649..000000000 Binary files a/assets/items/uniq_visceratuant.png and /dev/null differ diff --git a/assets/items/uniq_weapon_astreons_iron_ward.png b/assets/items/uniq_weapon_astreons_iron_ward.png deleted file mode 100644 index 2eb65aae2..000000000 Binary files a/assets/items/uniq_weapon_astreons_iron_ward.png and /dev/null differ diff --git a/assets/items/uniq_weapon_bane_ash.png b/assets/items/uniq_weapon_bane_ash.png deleted file mode 100644 index f3b66da72..000000000 Binary files a/assets/items/uniq_weapon_bane_ash.png and /dev/null differ diff --git a/assets/items/uniq_weapon_black_hand_key.png b/assets/items/uniq_weapon_black_hand_key.png deleted file mode 100644 index ab7e86a49..000000000 Binary files a/assets/items/uniq_weapon_black_hand_key.png and /dev/null differ diff --git a/assets/items/uniq_weapon_blade_of_ali_baba.png b/assets/items/uniq_weapon_blade_of_ali_baba.png deleted file mode 100644 index 0dee2613c..000000000 Binary files a/assets/items/uniq_weapon_blade_of_ali_baba.png and /dev/null differ diff --git a/assets/items/uniq_weapon_blood_ravens_charge.png b/assets/items/uniq_weapon_blood_ravens_charge.png deleted file mode 100644 index 3ef1831f3..000000000 Binary files a/assets/items/uniq_weapon_blood_ravens_charge.png and /dev/null differ diff --git a/assets/items/uniq_weapon_bonehew.png b/assets/items/uniq_weapon_bonehew.png deleted file mode 100644 index 7e61cb646..000000000 Binary files a/assets/items/uniq_weapon_bonehew.png and /dev/null differ diff --git a/assets/items/uniq_weapon_boneshade.png b/assets/items/uniq_weapon_boneshade.png deleted file mode 100644 index a871bf550..000000000 Binary files a/assets/items/uniq_weapon_boneshade.png and /dev/null differ diff --git a/assets/items/uniq_weapon_chromatic_ire.png b/assets/items/uniq_weapon_chromatic_ire.png deleted file mode 100644 index 19308a205..000000000 Binary files a/assets/items/uniq_weapon_chromatic_ire.png and /dev/null differ diff --git a/assets/items/uniq_weapon_cranebeak.png b/assets/items/uniq_weapon_cranebeak.png deleted file mode 100644 index 3a8682be2..000000000 Binary files a/assets/items/uniq_weapon_cranebeak.png and /dev/null differ diff --git a/assets/items/uniq_weapon_death_cleaver.png b/assets/items/uniq_weapon_death_cleaver.png deleted file mode 100644 index fe7aab2ca..000000000 Binary files a/assets/items/uniq_weapon_death_cleaver.png and /dev/null differ diff --git a/assets/items/uniq_weapon_death_fathom.png b/assets/items/uniq_weapon_death_fathom.png deleted file mode 100644 index aa24cf46f..000000000 Binary files a/assets/items/uniq_weapon_death_fathom.png and /dev/null differ diff --git a/assets/items/uniq_weapon_death_web.png b/assets/items/uniq_weapon_death_web.png deleted file mode 100644 index 9dde3a321..000000000 Binary files a/assets/items/uniq_weapon_death_web.png and /dev/null differ diff --git a/assets/items/uniq_weapon_doombringer.png b/assets/items/uniq_weapon_doombringer.png deleted file mode 100644 index ea9ede92a..000000000 Binary files a/assets/items/uniq_weapon_doombringer.png and /dev/null differ diff --git a/assets/items/uniq_weapon_dragon_chang.png b/assets/items/uniq_weapon_dragon_chang.png deleted file mode 100644 index 5ec5c6d3c..000000000 Binary files a/assets/items/uniq_weapon_dragon_chang.png and /dev/null differ diff --git a/assets/items/uniq_weapon_eaglehorn.png b/assets/items/uniq_weapon_eaglehorn.png deleted file mode 100644 index 0d5142762..000000000 Binary files a/assets/items/uniq_weapon_eaglehorn.png and /dev/null differ diff --git a/assets/items/uniq_weapon_eschuta_temper.png b/assets/items/uniq_weapon_eschuta_temper.png deleted file mode 100644 index c721f19be..000000000 Binary files a/assets/items/uniq_weapon_eschuta_temper.png and /dev/null differ diff --git a/assets/items/uniq_weapon_felloak.png b/assets/items/uniq_weapon_felloak.png deleted file mode 100644 index 7872048e2..000000000 Binary files a/assets/items/uniq_weapon_felloak.png and /dev/null differ diff --git a/assets/items/uniq_weapon_flesh_ripper.png b/assets/items/uniq_weapon_flesh_ripper.png deleted file mode 100644 index 9ac689d6c..000000000 Binary files a/assets/items/uniq_weapon_flesh_ripper.png and /dev/null differ diff --git a/assets/items/uniq_weapon_frostwind.png b/assets/items/uniq_weapon_frostwind.png deleted file mode 100644 index ab368f3b2..000000000 Binary files a/assets/items/uniq_weapon_frostwind.png and /dev/null differ diff --git a/assets/items/uniq_weapon_gargoyles_bite.png b/assets/items/uniq_weapon_gargoyles_bite.png deleted file mode 100644 index cf37a2c67..000000000 Binary files a/assets/items/uniq_weapon_gargoyles_bite.png and /dev/null differ diff --git a/assets/items/uniq_weapon_ghostflame.png b/assets/items/uniq_weapon_ghostflame.png deleted file mode 100644 index 0e1f6f857..000000000 Binary files a/assets/items/uniq_weapon_ghostflame.png and /dev/null differ diff --git a/assets/items/uniq_weapon_gimmershred.png b/assets/items/uniq_weapon_gimmershred.png deleted file mode 100644 index a720eed69..000000000 Binary files a/assets/items/uniq_weapon_gimmershred.png and /dev/null differ diff --git a/assets/items/uniq_weapon_gnasher.png b/assets/items/uniq_weapon_gnasher.png deleted file mode 100644 index 841f60c3f..000000000 Binary files a/assets/items/uniq_weapon_gnasher.png and /dev/null differ diff --git a/assets/items/uniq_weapon_grandfather.png b/assets/items/uniq_weapon_grandfather.png deleted file mode 100644 index 6dffa771b..000000000 Binary files a/assets/items/uniq_weapon_grandfather.png and /dev/null differ diff --git a/assets/items/uniq_weapon_gut_siphon.png b/assets/items/uniq_weapon_gut_siphon.png deleted file mode 100644 index 521e4aa60..000000000 Binary files a/assets/items/uniq_weapon_gut_siphon.png and /dev/null differ diff --git a/assets/items/uniq_weapon_honesundan.png b/assets/items/uniq_weapon_honesundan.png deleted file mode 100644 index c6dd213e8..000000000 Binary files a/assets/items/uniq_weapon_honesundan.png and /dev/null differ diff --git a/assets/items/uniq_weapon_iron_jang_bong.png b/assets/items/uniq_weapon_iron_jang_bong.png deleted file mode 100644 index a44bd9cf6..000000000 Binary files a/assets/items/uniq_weapon_iron_jang_bong.png and /dev/null differ diff --git a/assets/items/uniq_weapon_knellstriker.png b/assets/items/uniq_weapon_knellstriker.png deleted file mode 100644 index e6ab7bdf3..000000000 Binary files a/assets/items/uniq_weapon_knellstriker.png and /dev/null differ diff --git a/assets/items/uniq_weapon_lacerator.png b/assets/items/uniq_weapon_lacerator.png deleted file mode 100644 index 4ff7fe141..000000000 Binary files a/assets/items/uniq_weapon_lacerator.png and /dev/null differ diff --git a/assets/items/uniq_weapon_lightsabre.png b/assets/items/uniq_weapon_lightsabre.png deleted file mode 100644 index 33e2b8db0..000000000 Binary files a/assets/items/uniq_weapon_lightsabre.png and /dev/null differ diff --git a/assets/items/uniq_weapon_lycanders_aim.png b/assets/items/uniq_weapon_lycanders_aim.png deleted file mode 100644 index 123edc3ad..000000000 Binary files a/assets/items/uniq_weapon_lycanders_aim.png and /dev/null differ diff --git a/assets/items/uniq_weapon_mang_song_lesson.png b/assets/items/uniq_weapon_mang_song_lesson.png deleted file mode 100644 index c8b0653c5..000000000 Binary files a/assets/items/uniq_weapon_mang_song_lesson.png and /dev/null differ diff --git a/assets/items/uniq_weapon_ondal_wisdom.png b/assets/items/uniq_weapon_ondal_wisdom.png deleted file mode 100644 index 2bcda753a..000000000 Binary files a/assets/items/uniq_weapon_ondal_wisdom.png and /dev/null differ diff --git a/assets/items/uniq_weapon_pluckeye.png b/assets/items/uniq_weapon_pluckeye.png deleted file mode 100644 index 943c84450..000000000 Binary files a/assets/items/uniq_weapon_pluckeye.png and /dev/null differ diff --git a/assets/items/uniq_weapon_pus_spitter.png b/assets/items/uniq_weapon_pus_spitter.png deleted file mode 100644 index bdd69c0f6..000000000 Binary files a/assets/items/uniq_weapon_pus_spitter.png and /dev/null differ diff --git a/assets/items/uniq_weapon_razorswitch.png b/assets/items/uniq_weapon_razorswitch.png deleted file mode 100644 index 2d6687970..000000000 Binary files a/assets/items/uniq_weapon_razorswitch.png and /dev/null differ diff --git a/assets/items/uniq_weapon_ribcracker.png b/assets/items/uniq_weapon_ribcracker.png deleted file mode 100644 index 329b16a4a..000000000 Binary files a/assets/items/uniq_weapon_ribcracker.png and /dev/null differ diff --git a/assets/items/uniq_weapon_rixotskeen.png b/assets/items/uniq_weapon_rixotskeen.png deleted file mode 100644 index 726c876a5..000000000 Binary files a/assets/items/uniq_weapon_rixotskeen.png and /dev/null differ diff --git a/assets/items/uniq_weapon_schaefer_hammer.png b/assets/items/uniq_weapon_schaefer_hammer.png deleted file mode 100644 index 1be81f5da..000000000 Binary files a/assets/items/uniq_weapon_schaefer_hammer.png and /dev/null differ diff --git a/assets/items/uniq_weapon_skull_collector.png b/assets/items/uniq_weapon_skull_collector.png deleted file mode 100644 index e0b6c811c..000000000 Binary files a/assets/items/uniq_weapon_skull_collector.png and /dev/null differ diff --git a/assets/items/uniq_weapon_spire_of_honor.png b/assets/items/uniq_weapon_spire_of_honor.png deleted file mode 100644 index 68101a127..000000000 Binary files a/assets/items/uniq_weapon_spire_of_honor.png and /dev/null differ diff --git a/assets/items/uniq_weapon_steelpillar.png b/assets/items/uniq_weapon_steelpillar.png deleted file mode 100644 index 36db11b52..000000000 Binary files a/assets/items/uniq_weapon_steelpillar.png and /dev/null differ diff --git a/assets/items/uniq_weapon_stonecrusher.png b/assets/items/uniq_weapon_stonecrusher.png deleted file mode 100644 index f51537a9d..000000000 Binary files a/assets/items/uniq_weapon_stonecrusher.png and /dev/null differ diff --git a/assets/items/uniq_weapon_stormlash.png b/assets/items/uniq_weapon_stormlash.png deleted file mode 100644 index ab9193e30..000000000 Binary files a/assets/items/uniq_weapon_stormlash.png and /dev/null differ diff --git a/assets/items/uniq_weapon_the_cranium_basher.png b/assets/items/uniq_weapon_the_cranium_basher.png deleted file mode 100644 index 8aea55eef..000000000 Binary files a/assets/items/uniq_weapon_the_cranium_basher.png and /dev/null differ diff --git a/assets/items/uniq_weapon_the_oculus.png b/assets/items/uniq_weapon_the_oculus.png deleted file mode 100644 index 56cc3037f..000000000 Binary files a/assets/items/uniq_weapon_the_oculus.png and /dev/null differ diff --git a/assets/items/uniq_weapon_the_reaper_toll.png b/assets/items/uniq_weapon_the_reaper_toll.png deleted file mode 100644 index 7c7ed9b2d..000000000 Binary files a/assets/items/uniq_weapon_the_reaper_toll.png and /dev/null differ diff --git a/assets/items/uniq_weapon_thunderstroke.png b/assets/items/uniq_weapon_thunderstroke.png deleted file mode 100644 index 21875d2c4..000000000 Binary files a/assets/items/uniq_weapon_thunderstroke.png and /dev/null differ diff --git a/assets/items/uniq_weapon_titan_revenge.png b/assets/items/uniq_weapon_titan_revenge.png deleted file mode 100644 index bfe5ea47f..000000000 Binary files a/assets/items/uniq_weapon_titan_revenge.png and /dev/null differ diff --git a/assets/items/uniq_weapon_tomb_reaver.png b/assets/items/uniq_weapon_tomb_reaver.png deleted file mode 100644 index 0429d144d..000000000 Binary files a/assets/items/uniq_weapon_tomb_reaver.png and /dev/null differ diff --git a/assets/items/uniq_weapon_warpspear.png b/assets/items/uniq_weapon_warpspear.png deleted file mode 100644 index e776c1a65..000000000 Binary files a/assets/items/uniq_weapon_warpspear.png and /dev/null differ diff --git a/assets/items/uniq_weapon_warshrike.png b/assets/items/uniq_weapon_warshrike.png deleted file mode 100644 index 9733b3862..000000000 Binary files a/assets/items/uniq_weapon_warshrike.png and /dev/null differ diff --git a/assets/items/uniq_weapon_widowmaker.png b/assets/items/uniq_weapon_widowmaker.png deleted file mode 100644 index 7cf3e6356..000000000 Binary files a/assets/items/uniq_weapon_widowmaker.png and /dev/null differ diff --git a/assets/items/uniq_weapon_windforce.png b/assets/items/uniq_weapon_windforce.png deleted file mode 100644 index 4f30c0371..000000000 Binary files a/assets/items/uniq_weapon_windforce.png and /dev/null differ diff --git a/assets/items/uniq_weapon_wizardspike.png b/assets/items/uniq_weapon_wizardspike.png deleted file mode 100644 index 594ffe393..000000000 Binary files a/assets/items/uniq_weapon_wizardspike.png and /dev/null differ diff --git a/assets/items/uniq_wolfhowl.png b/assets/items/uniq_wolfhowl.png deleted file mode 100644 index d854ce756..000000000 Binary files a/assets/items/uniq_wolfhowl.png and /dev/null differ diff --git a/assets/items/white_akaran_rondache.png b/assets/items/white_akaran_rondache.png deleted file mode 100644 index cf2b589be..000000000 Binary files a/assets/items/white_akaran_rondache.png and /dev/null differ diff --git a/assets/items/white_akaran_targe.png b/assets/items/white_akaran_targe.png deleted file mode 100644 index b059b6611..000000000 Binary files a/assets/items/white_akaran_targe.png and /dev/null differ diff --git a/assets/items/white_alpha_helm.png b/assets/items/white_alpha_helm.png deleted file mode 100644 index 4188b3194..000000000 Binary files a/assets/items/white_alpha_helm.png and /dev/null differ diff --git a/assets/items/white_antlers.png b/assets/items/white_antlers.png deleted file mode 100644 index e3f2fc7f2..000000000 Binary files a/assets/items/white_antlers.png and /dev/null differ diff --git a/assets/items/white_archon_plate.png b/assets/items/white_archon_plate.png deleted file mode 100644 index efd77af53..000000000 Binary files a/assets/items/white_archon_plate.png and /dev/null differ diff --git a/assets/items/white_archon_staff.png b/assets/items/white_archon_staff.png deleted file mode 100644 index 5725831bc..000000000 Binary files a/assets/items/white_archon_staff.png and /dev/null differ diff --git a/assets/items/white_assault_helmet.png b/assets/items/white_assault_helmet.png deleted file mode 100644 index e0c2e6ad3..000000000 Binary files a/assets/items/white_assault_helmet.png and /dev/null differ diff --git a/assets/items/white_avenger_guard.png b/assets/items/white_avenger_guard.png deleted file mode 100644 index 106ce3598..000000000 Binary files a/assets/items/white_avenger_guard.png and /dev/null differ diff --git a/assets/items/white_berserker_axe.png b/assets/items/white_berserker_axe.png deleted file mode 100644 index beffe1dda..000000000 Binary files a/assets/items/white_berserker_axe.png and /dev/null differ diff --git a/assets/items/white_blood_spirit.png b/assets/items/white_blood_spirit.png deleted file mode 100644 index 40090df67..000000000 Binary files a/assets/items/white_blood_spirit.png and /dev/null differ diff --git a/assets/items/white_bloodlord_skull.png b/assets/items/white_bloodlord_skull.png deleted file mode 100644 index 2299bb68d..000000000 Binary files a/assets/items/white_bloodlord_skull.png and /dev/null differ diff --git a/assets/items/white_caduceus.png b/assets/items/white_caduceus.png deleted file mode 100644 index fcc870dbc..000000000 Binary files a/assets/items/white_caduceus.png and /dev/null differ diff --git a/assets/items/white_carnage_helm.png b/assets/items/white_carnage_helm.png deleted file mode 100644 index f98d73efa..000000000 Binary files a/assets/items/white_carnage_helm.png and /dev/null differ diff --git a/assets/items/white_cedar_staff.png b/assets/items/white_cedar_staff.png deleted file mode 100644 index 4b9eece04..000000000 Binary files a/assets/items/white_cedar_staff.png and /dev/null differ diff --git a/assets/items/white_conqueror_crown.png b/assets/items/white_conqueror_crown.png deleted file mode 100644 index 8eb5a421f..000000000 Binary files a/assets/items/white_conqueror_crown.png and /dev/null differ diff --git a/assets/items/white_crown_shield.png b/assets/items/white_crown_shield.png deleted file mode 100644 index 6b0a114cb..000000000 Binary files a/assets/items/white_crown_shield.png and /dev/null differ diff --git a/assets/items/white_crystal_sword.png b/assets/items/white_crystal_sword.png deleted file mode 100644 index b550e9eb1..000000000 Binary files a/assets/items/white_crystal_sword.png and /dev/null differ diff --git a/assets/items/white_demon_head.png b/assets/items/white_demon_head.png deleted file mode 100644 index 1475f3c11..000000000 Binary files a/assets/items/white_demon_head.png and /dev/null differ diff --git a/assets/items/white_destroyer_helm.png b/assets/items/white_destroyer_helm.png deleted file mode 100644 index f43f984d4..000000000 Binary files a/assets/items/white_destroyer_helm.png and /dev/null differ diff --git a/assets/items/white_divine_scepter.png b/assets/items/white_divine_scepter.png deleted file mode 100644 index fddc3ff83..000000000 Binary files a/assets/items/white_divine_scepter.png and /dev/null differ diff --git a/assets/items/white_dream_spirit.png b/assets/items/white_dream_spirit.png deleted file mode 100644 index dd7fa279b..000000000 Binary files a/assets/items/white_dream_spirit.png and /dev/null differ diff --git a/assets/items/white_dusk_shroud.png b/assets/items/white_dusk_shroud.png deleted file mode 100644 index be91bd403..000000000 Binary files a/assets/items/white_dusk_shroud.png and /dev/null differ diff --git a/assets/items/white_earth_spirit.png b/assets/items/white_earth_spirit.png deleted file mode 100644 index 0c8bce20e..000000000 Binary files a/assets/items/white_earth_spirit.png and /dev/null differ diff --git a/assets/items/white_elder_staff.png b/assets/items/white_elder_staff.png deleted file mode 100644 index e8ff6c22a..000000000 Binary files a/assets/items/white_elder_staff.png and /dev/null differ diff --git a/assets/items/white_falcon_mask.png b/assets/items/white_falcon_mask.png deleted file mode 100644 index d0d120b13..000000000 Binary files a/assets/items/white_falcon_mask.png and /dev/null differ diff --git a/assets/items/white_fanged_helm.png b/assets/items/white_fanged_helm.png deleted file mode 100644 index 7829e9146..000000000 Binary files a/assets/items/white_fanged_helm.png and /dev/null differ diff --git a/assets/items/white_feral_claws.png b/assets/items/white_feral_claws.png deleted file mode 100644 index debc50136..000000000 Binary files a/assets/items/white_feral_claws.png and /dev/null differ diff --git a/assets/items/white_flail.png b/assets/items/white_flail.png deleted file mode 100644 index c4b5ab7a8..000000000 Binary files a/assets/items/white_flail.png and /dev/null differ diff --git a/assets/items/white_fury_visor.png b/assets/items/white_fury_visor.png deleted file mode 100644 index 3a376fdb1..000000000 Binary files a/assets/items/white_fury_visor.png and /dev/null differ diff --git a/assets/items/white_ghost_wand.png b/assets/items/white_ghost_wand.png deleted file mode 100644 index b3153f3ff..000000000 Binary files a/assets/items/white_ghost_wand.png and /dev/null differ diff --git a/assets/items/white_gothic_staff.png b/assets/items/white_gothic_staff.png deleted file mode 100644 index 5d27f8ec1..000000000 Binary files a/assets/items/white_gothic_staff.png and /dev/null differ diff --git a/assets/items/white_great_hauberk.png b/assets/items/white_great_hauberk.png deleted file mode 100644 index 83b42cb15..000000000 Binary files a/assets/items/white_great_hauberk.png and /dev/null differ diff --git a/assets/items/white_greater_claws.png b/assets/items/white_greater_claws.png deleted file mode 100644 index 933e089f8..000000000 Binary files a/assets/items/white_greater_claws.png and /dev/null differ diff --git a/assets/items/white_greater_talons.png b/assets/items/white_greater_talons.png deleted file mode 100644 index e4aa981b8..000000000 Binary files a/assets/items/white_greater_talons.png and /dev/null differ diff --git a/assets/items/white_griffon_headdress.png b/assets/items/white_griffon_headdress.png deleted file mode 100644 index 058a03e30..000000000 Binary files a/assets/items/white_griffon_headdress.png and /dev/null differ diff --git a/assets/items/white_guardian_crown.png b/assets/items/white_guardian_crown.png deleted file mode 100644 index 0e05f3c89..000000000 Binary files a/assets/items/white_guardian_crown.png and /dev/null differ diff --git a/assets/items/white_hawk_helm.png b/assets/items/white_hawk_helm.png deleted file mode 100644 index 249040dfc..000000000 Binary files a/assets/items/white_hawk_helm.png and /dev/null differ diff --git a/assets/items/white_hellspawn_skull.png b/assets/items/white_hellspawn_skull.png deleted file mode 100644 index 0e0d19cc6..000000000 Binary files a/assets/items/white_hellspawn_skull.png and /dev/null differ diff --git a/assets/items/white_helm_demonhead.png b/assets/items/white_helm_demonhead.png deleted file mode 100644 index ea5c8e997..000000000 Binary files a/assets/items/white_helm_demonhead.png and /dev/null differ diff --git a/assets/items/white_horned_helm.png b/assets/items/white_horned_helm.png deleted file mode 100644 index 8c93dda9d..000000000 Binary files a/assets/items/white_horned_helm.png and /dev/null differ diff --git a/assets/items/white_hunters_guise.png b/assets/items/white_hunters_guise.png deleted file mode 100644 index 755e69206..000000000 Binary files a/assets/items/white_hunters_guise.png and /dev/null differ diff --git a/assets/items/white_jawbone_cap.png b/assets/items/white_jawbone_cap.png deleted file mode 100644 index d4897a6f0..000000000 Binary files a/assets/items/white_jawbone_cap.png and /dev/null differ diff --git a/assets/items/white_jawbone_visor.png b/assets/items/white_jawbone_visor.png deleted file mode 100644 index 563deccfe..000000000 Binary files a/assets/items/white_jawbone_visor.png and /dev/null differ diff --git a/assets/items/white_kurast_shield.png b/assets/items/white_kurast_shield.png deleted file mode 100644 index f3af4560c..000000000 Binary files a/assets/items/white_kurast_shield.png and /dev/null differ diff --git a/assets/items/white_lich_wand.png b/assets/items/white_lich_wand.png deleted file mode 100644 index c32272366..000000000 Binary files a/assets/items/white_lich_wand.png and /dev/null differ diff --git a/assets/items/white_light_plate.png b/assets/items/white_light_plate.png deleted file mode 100644 index eb93992d2..000000000 Binary files a/assets/items/white_light_plate.png and /dev/null differ diff --git a/assets/items/white_lion_helm.png b/assets/items/white_lion_helm.png deleted file mode 100644 index ee33e8751..000000000 Binary files a/assets/items/white_lion_helm.png and /dev/null differ diff --git a/assets/items/white_mage_plate.png b/assets/items/white_mage_plate.png deleted file mode 100644 index e16add8dc..000000000 Binary files a/assets/items/white_mage_plate.png and /dev/null differ diff --git a/assets/items/white_minion_skull.png b/assets/items/white_minion_skull.png deleted file mode 100644 index 1e8ce777a..000000000 Binary files a/assets/items/white_minion_skull.png and /dev/null differ diff --git a/assets/items/white_monarch.png b/assets/items/white_monarch.png deleted file mode 100644 index 362e7b335..000000000 Binary files a/assets/items/white_monarch.png and /dev/null differ diff --git a/assets/items/white_overseer_skull.png b/assets/items/white_overseer_skull.png deleted file mode 100644 index 5a2f1eeef..000000000 Binary files a/assets/items/white_overseer_skull.png and /dev/null differ diff --git a/assets/items/white_phase_blade.png b/assets/items/white_phase_blade.png deleted file mode 100644 index f9b63232d..000000000 Binary files a/assets/items/white_phase_blade.png and /dev/null differ diff --git a/assets/items/white_polished_wand.png b/assets/items/white_polished_wand.png deleted file mode 100644 index fe2d14d89..000000000 Binary files a/assets/items/white_polished_wand.png and /dev/null differ diff --git a/assets/items/white_preserved_head.png b/assets/items/white_preserved_head.png deleted file mode 100644 index 97d585982..000000000 Binary files a/assets/items/white_preserved_head.png and /dev/null differ diff --git a/assets/items/white_rage_mask.png b/assets/items/white_rage_mask.png deleted file mode 100644 index 3446da90d..000000000 Binary files a/assets/items/white_rage_mask.png and /dev/null differ diff --git a/assets/items/white_royal_shield.png b/assets/items/white_royal_shield.png deleted file mode 100644 index b59d74a20..000000000 Binary files a/assets/items/white_royal_shield.png and /dev/null differ diff --git a/assets/items/white_rune_staff.png b/assets/items/white_rune_staff.png deleted file mode 100644 index 21b9081ea..000000000 Binary files a/assets/items/white_rune_staff.png and /dev/null differ diff --git a/assets/items/white_runic_talons.png b/assets/items/white_runic_talons.png deleted file mode 100644 index 301f08cfc..000000000 Binary files a/assets/items/white_runic_talons.png and /dev/null differ diff --git a/assets/items/white_sacred_feathers.png b/assets/items/white_sacred_feathers.png deleted file mode 100644 index 48372e277..000000000 Binary files a/assets/items/white_sacred_feathers.png and /dev/null differ diff --git a/assets/items/white_sacred_rondache.png b/assets/items/white_sacred_rondache.png deleted file mode 100644 index 1caf314b6..000000000 Binary files a/assets/items/white_sacred_rondache.png and /dev/null differ diff --git a/assets/items/white_sacred_targe.png b/assets/items/white_sacred_targe.png deleted file mode 100644 index af9abb6ba..000000000 Binary files a/assets/items/white_sacred_targe.png and /dev/null differ diff --git a/assets/items/white_savage_helmet.png b/assets/items/white_savage_helmet.png deleted file mode 100644 index 4d7505b29..000000000 Binary files a/assets/items/white_savage_helmet.png and /dev/null differ diff --git a/assets/items/white_scarab_husk.png b/assets/items/white_scarab_husk.png deleted file mode 100644 index c291eb73c..000000000 Binary files a/assets/items/white_scarab_husk.png and /dev/null differ diff --git a/assets/items/white_shillelagh.png b/assets/items/white_shillelagh.png deleted file mode 100644 index 609126671..000000000 Binary files a/assets/items/white_shillelagh.png and /dev/null differ diff --git a/assets/items/white_sky_spirit.png b/assets/items/white_sky_spirit.png deleted file mode 100644 index 61e347247..000000000 Binary files a/assets/items/white_sky_spirit.png and /dev/null differ diff --git a/assets/items/white_slayer_guard.png b/assets/items/white_slayer_guard.png deleted file mode 100644 index 31af3acfa..000000000 Binary files a/assets/items/white_slayer_guard.png and /dev/null differ diff --git a/assets/items/white_spirit_mask.png b/assets/items/white_spirit_mask.png deleted file mode 100644 index 00be6483b..000000000 Binary files a/assets/items/white_spirit_mask.png and /dev/null differ diff --git a/assets/items/white_succubus_skull.png b/assets/items/white_succubus_skull.png deleted file mode 100644 index fa1dcdb21..000000000 Binary files a/assets/items/white_succubus_skull.png and /dev/null differ diff --git a/assets/items/white_sun_spirit.png b/assets/items/white_sun_spirit.png deleted file mode 100644 index f320f54fd..000000000 Binary files a/assets/items/white_sun_spirit.png and /dev/null differ diff --git a/assets/items/white_superior_akaran_rondache.png b/assets/items/white_superior_akaran_rondache.png deleted file mode 100644 index 0c512767e..000000000 Binary files a/assets/items/white_superior_akaran_rondache.png and /dev/null differ diff --git a/assets/items/white_superior_akaran_targe.png b/assets/items/white_superior_akaran_targe.png deleted file mode 100644 index 83746b68a..000000000 Binary files a/assets/items/white_superior_akaran_targe.png and /dev/null differ diff --git a/assets/items/white_superior_archon_plate.png b/assets/items/white_superior_archon_plate.png deleted file mode 100644 index d84f4f828..000000000 Binary files a/assets/items/white_superior_archon_plate.png and /dev/null differ diff --git a/assets/items/white_superior_berserker_axe.png b/assets/items/white_superior_berserker_axe.png deleted file mode 100644 index f9742982f..000000000 Binary files a/assets/items/white_superior_berserker_axe.png and /dev/null differ diff --git a/assets/items/white_superior_crown_shield.png b/assets/items/white_superior_crown_shield.png deleted file mode 100644 index f102765e0..000000000 Binary files a/assets/items/white_superior_crown_shield.png and /dev/null differ diff --git a/assets/items/white_superior_crystal_sword.png b/assets/items/white_superior_crystal_sword.png deleted file mode 100644 index fecdf4c64..000000000 Binary files a/assets/items/white_superior_crystal_sword.png and /dev/null differ diff --git a/assets/items/white_superior_dusk_shroud.png b/assets/items/white_superior_dusk_shroud.png deleted file mode 100644 index d746bb0c5..000000000 Binary files a/assets/items/white_superior_dusk_shroud.png and /dev/null differ diff --git a/assets/items/white_superior_flail.png b/assets/items/white_superior_flail.png deleted file mode 100644 index a6b87b504..000000000 Binary files a/assets/items/white_superior_flail.png and /dev/null differ diff --git a/assets/items/white_superior_great_hauberk.png b/assets/items/white_superior_great_hauberk.png deleted file mode 100644 index 83ec388cd..000000000 Binary files a/assets/items/white_superior_great_hauberk.png and /dev/null differ diff --git a/assets/items/white_superior_kurast_shield.png b/assets/items/white_superior_kurast_shield.png deleted file mode 100644 index 5fa84e96b..000000000 Binary files a/assets/items/white_superior_kurast_shield.png and /dev/null differ diff --git a/assets/items/white_superior_light_plate.png b/assets/items/white_superior_light_plate.png deleted file mode 100644 index 78f9fc2c8..000000000 Binary files a/assets/items/white_superior_light_plate.png and /dev/null differ diff --git a/assets/items/white_superior_mage_plate.png b/assets/items/white_superior_mage_plate.png deleted file mode 100644 index 5ec6e7fc2..000000000 Binary files a/assets/items/white_superior_mage_plate.png and /dev/null differ diff --git a/assets/items/white_superior_monarch.png b/assets/items/white_superior_monarch.png deleted file mode 100644 index 3bf881828..000000000 Binary files a/assets/items/white_superior_monarch.png and /dev/null differ diff --git a/assets/items/white_superior_phase_blade.png b/assets/items/white_superior_phase_blade.png deleted file mode 100644 index e387ea6e4..000000000 Binary files a/assets/items/white_superior_phase_blade.png and /dev/null differ diff --git a/assets/items/white_superior_royal_shield.png b/assets/items/white_superior_royal_shield.png deleted file mode 100644 index a58d7ade0..000000000 Binary files a/assets/items/white_superior_royal_shield.png and /dev/null differ diff --git a/assets/items/white_superior_sacred_rondache.png b/assets/items/white_superior_sacred_rondache.png deleted file mode 100644 index c20597521..000000000 Binary files a/assets/items/white_superior_sacred_rondache.png and /dev/null differ diff --git a/assets/items/white_superior_sacred_targe.png b/assets/items/white_superior_sacred_targe.png deleted file mode 100644 index 6c0f733da..000000000 Binary files a/assets/items/white_superior_sacred_targe.png and /dev/null differ diff --git a/assets/items/white_superior_scarab_husk.png b/assets/items/white_superior_scarab_husk.png deleted file mode 100644 index ecc08667b..000000000 Binary files a/assets/items/white_superior_scarab_husk.png and /dev/null differ diff --git a/assets/items/white_superior_vortex_shield.png b/assets/items/white_superior_vortex_shield.png deleted file mode 100644 index f15e75b80..000000000 Binary files a/assets/items/white_superior_vortex_shield.png and /dev/null differ diff --git a/assets/items/white_superior_wire_fleece.png b/assets/items/white_superior_wire_fleece.png deleted file mode 100644 index 8800d4909..000000000 Binary files a/assets/items/white_superior_wire_fleece.png and /dev/null differ diff --git a/assets/items/white_superior_wyrmhide.png b/assets/items/white_superior_wyrmhide.png deleted file mode 100644 index a69ffe561..000000000 Binary files a/assets/items/white_superior_wyrmhide.png and /dev/null differ diff --git a/assets/items/white_superior_zakarum_shield.png b/assets/items/white_superior_zakarum_shield.png deleted file mode 100644 index 55d00d4ce..000000000 Binary files a/assets/items/white_superior_zakarum_shield.png and /dev/null differ diff --git a/assets/items/white_suwayyah.png b/assets/items/white_suwayyah.png deleted file mode 100644 index c17af266a..000000000 Binary files a/assets/items/white_suwayyah.png and /dev/null differ diff --git a/assets/items/white_totemic_mask.png b/assets/items/white_totemic_mask.png deleted file mode 100644 index b4a26a02c..000000000 Binary files a/assets/items/white_totemic_mask.png and /dev/null differ diff --git a/assets/items/white_unearthed_wand.png b/assets/items/white_unearthed_wand.png deleted file mode 100644 index 1a2ed576e..000000000 Binary files a/assets/items/white_unearthed_wand.png and /dev/null differ diff --git a/assets/items/white_vortex_shield.png b/assets/items/white_vortex_shield.png deleted file mode 100644 index ecf0254d8..000000000 Binary files a/assets/items/white_vortex_shield.png and /dev/null differ diff --git a/assets/items/white_war_scepter.png b/assets/items/white_war_scepter.png deleted file mode 100644 index d4fb4f389..000000000 Binary files a/assets/items/white_war_scepter.png and /dev/null differ diff --git a/assets/items/white_war_staff.png b/assets/items/white_war_staff.png deleted file mode 100644 index 413841c5b..000000000 Binary files a/assets/items/white_war_staff.png and /dev/null differ diff --git a/assets/items/white_wire_fleece.png b/assets/items/white_wire_fleece.png deleted file mode 100644 index a45881a94..000000000 Binary files a/assets/items/white_wire_fleece.png and /dev/null differ diff --git a/assets/items/white_wolf_head.png b/assets/items/white_wolf_head.png deleted file mode 100644 index d04014ffa..000000000 Binary files a/assets/items/white_wolf_head.png and /dev/null differ diff --git a/assets/items/white_wrist_sword.png b/assets/items/white_wrist_sword.png deleted file mode 100644 index a80a0205e..000000000 Binary files a/assets/items/white_wrist_sword.png and /dev/null differ diff --git a/assets/items/white_wyrmhide.png b/assets/items/white_wyrmhide.png deleted file mode 100644 index a5d8883ae..000000000 Binary files a/assets/items/white_wyrmhide.png and /dev/null differ diff --git a/assets/items/white_zakarum_shield.png b/assets/items/white_zakarum_shield.png deleted file mode 100644 index 55964e72d..000000000 Binary files a/assets/items/white_zakarum_shield.png and /dev/null differ diff --git a/assets/mods/botty/botty.mpq/data/hd/ui/fonts/exocetblizzardot-medium.otf b/assets/mods/botty/botty.mpq/data/hd/ui/fonts/exocetblizzardot-medium.otf new file mode 100644 index 000000000..e675de65a Binary files /dev/null and b/assets/mods/botty/botty.mpq/data/hd/ui/fonts/exocetblizzardot-medium.otf differ diff --git a/assets/mods/botty/botty.mpq/data/local/lng/strings/item-nameaffixes.json b/assets/mods/botty/botty.mpq/data/local/lng/strings/item-nameaffixes.json index e40946ffb..b2510bebe 100644 --- a/assets/mods/botty/botty.mpq/data/local/lng/strings/item-nameaffixes.json +++ b/assets/mods/botty/botty.mpq/data/local/lng/strings/item-nameaffixes.json @@ -3453,7 +3453,7 @@ { "id": 2215, "Key": "gld", - "enUS": "Gold ", + "enUS": "Gold ", "zhTW": "金幣", "deDE": "Gold", "esES": "de oro", diff --git a/assets/mods/botty/botty.mpq/data/local/lng/strings/item-names.json b/assets/mods/botty/botty.mpq/data/local/lng/strings/item-names.json index 71ca40a16..f22c6380a 100644 --- a/assets/mods/botty/botty.mpq/data/local/lng/strings/item-names.json +++ b/assets/mods/botty/botty.mpq/data/local/lng/strings/item-names.json @@ -2,7 +2,7 @@ { "id": 1060, "Key": "qf1", - "enUS": " Khalim's Flail ", + "enUS": "Khalim's Flail ", "zhTW": "克林姆的連枷", "deDE": "Khalims Kultflegel", "esES": "Rompecabezas de Khalim", @@ -19,7 +19,7 @@ { "id": 1061, "Key": "qf2", - "enUS": " Khalim's Will ", + "enUS": "Khalim's Will ", "zhTW": "克林姆的遺願", "deDE": "Khalims Wille", "esES": "Voluntad de Khalim", @@ -36,7 +36,7 @@ { "id": 1062, "Key": "KhalimFlail", - "enUS": " Khalim's Flail ", + "enUS": "Khalim's Flail ", "zhTW": "克林姆的連枷", "deDE": "Khalims Kultflegel", "esES": "Rompecabezas de Khalim", @@ -53,7 +53,7 @@ { "id": 1063, "Key": "SuperKhalimFlail", - "enUS": " Khalim's Will ", + "enUS": "Khalim's Will ", "zhTW": "克林姆的遺願", "deDE": "Khalims Wille", "esES": "Voluntad de Khalim", @@ -70,7 +70,7 @@ { "id": 1064, "Key": "qey", - "enUS": " Khalim's Eye ", + "enUS": "Khalim's Eye ", "zhTW": "克林姆的眼球", "deDE": "Khalims Auge", "esES": "Ojo de Khalim", @@ -87,7 +87,7 @@ { "id": 1065, "Key": "qbr", - "enUS": " Khalim's Brain ", + "enUS": "Khalim's Brain ", "zhTW": "克林姆的大腦", "deDE": "Khalims Gehirn", "esES": "Cerebro de Khalim", @@ -104,7 +104,7 @@ { "id": 1066, "Key": "qhr", - "enUS": " Khalim's Heart ", + "enUS": "Khalim's Heart ", "zhTW": "克林姆的心臟", "deDE": "Khalims Herz", "esES": "Corazón de Khalim", @@ -121,7 +121,7 @@ { "id": 1751, "Key": "Skillful", - "enUS": " Skillful ", + "enUS": "Skillful ", "zhTW": "熟練", "deDE": "[fs]geschickte[ms]geschickter[ns]geschicktes[pl]geschickte", "esES": "[fs]hábil[ms]hábil[fp]hábiles[mp]hábiles", @@ -138,7 +138,7 @@ { "id": 1930, "Key": "cap", - "enUS": " Cap ", + "enUS": "Cap ", "zhTW": "便帽", "deDE": "[fs]Kappe", "esES": "[ms]Gorro", @@ -155,7 +155,7 @@ { "id": 1931, "Key": "skp", - "enUS": " Skull Cap ", + "enUS": "Skull Cap ", "zhTW": "顱帽", "deDE": "[ms]Eisenhut", "esES": "[ms]Capacete", @@ -172,7 +172,7 @@ { "id": 1932, "Key": "hlm", - "enUS": " Helm ", + "enUS": "Helm ", "zhTW": "頭盔", "deDE": "[ms]Helm", "esES": "[ms]Yelmo", @@ -189,7 +189,7 @@ { "id": 1933, "Key": "fhl", - "enUS": " Full Helm ", + "enUS": "Full Helm ", "zhTW": "全罩盔", "deDE": "[ms]Vollhelm", "esES": "[ms]Yelmo completo", @@ -206,7 +206,7 @@ { "id": 1934, "Key": "ghm", - "enUS": " Great Helm ", + "enUS": "Great Helm ", "zhTW": "重盔", "deDE": "[ms]Großhelm", "esES": "[ms]Gran yelmo", @@ -223,7 +223,7 @@ { "id": 1935, "Key": "crn", - "enUS": " Crown ", + "enUS": "Crown ", "zhTW": "王冠", "deDE": "[fs]Krone", "esES": "[fs]Corona", @@ -240,7 +240,7 @@ { "id": 1936, "Key": "msk", - "enUS": " Mask ", + "enUS": "Mask ", "zhTW": "面具", "deDE": "[fs]Maske", "esES": "[fs]Máscara", @@ -257,7 +257,7 @@ { "id": 1937, "Key": "qui", - "enUS": " Quilted Armor ", + "enUS": "Quilted Armor ", "zhTW": "棉布甲", "deDE": "[fs]leichte Rüstung", "esES": "[fs]Armadura acolchada", @@ -274,7 +274,7 @@ { "id": 1938, "Key": "lea", - "enUS": " Leather Armor ", + "enUS": "Leather Armor ", "zhTW": "皮革甲", "deDE": "[fs]Lederrüstung", "esES": "[fs]Armadura de cuero", @@ -291,7 +291,7 @@ { "id": 1939, "Key": "hla", - "enUS": " Hard Leather Armor ", + "enUS": "Hard Leather Armor ", "zhTW": "硬皮甲", "deDE": "[ns]gehärtetes Leder", "esES": "[fs]Armadura de cuero duro", @@ -308,7 +308,7 @@ { "id": 1940, "Key": "stu", - "enUS": " Studded Leather ", + "enUS": "Studded Leather ", "zhTW": "鑲釘皮甲", "deDE": "[ns]beschlagenes Leder", "esES": "[ms]Cuero tachonado", @@ -325,7 +325,7 @@ { "id": 1941, "Key": "rng", - "enUS": " Ring Mail ", + "enUS": "Ring Mail ", "zhTW": "環甲", "deDE": "[ms]Ringpanzer", "esES": "[fs]Cota de anillos", @@ -342,7 +342,7 @@ { "id": 1942, "Key": "scl", - "enUS": " Scale Mail ", + "enUS": "Scale Mail ", "zhTW": "鱗甲", "deDE": "[ms]Schuppenpanzer", "esES": "[fs]Cota de escamas", @@ -359,7 +359,7 @@ { "id": 1943, "Key": "chn", - "enUS": " Chain Mail ", + "enUS": "Chain Mail ", "zhTW": "鎖鍊甲", "deDE": "[ms]Kettenpanzer", "esES": "[fs]Cota de malla", @@ -376,7 +376,7 @@ { "id": 1944, "Key": "brs", - "enUS": " Breast Plate ", + "enUS": "Breast Plate ", "zhTW": "胸鎧", "deDE": "[ms]Brustpanzer", "esES": "[fs]Coraza blindada", @@ -393,7 +393,7 @@ { "id": 1945, "Key": "spl", - "enUS": " Splint Mail ", + "enUS": "Splint Mail ", "zhTW": "板甲", "deDE": "[fs]Bänderrüstung", "esES": "[fs]Cota de láminas", @@ -410,7 +410,7 @@ { "id": 1946, "Key": "plt", - "enUS": " Plate Mail ", + "enUS": "Plate Mail ", "zhTW": "鎧甲", "deDE": "[ms]Plattenharnisch", "esES": "[fs]Cota de placas", @@ -427,7 +427,7 @@ { "id": 1947, "Key": "fld", - "enUS": " Field Plate ", + "enUS": "Field Plate ", "zhTW": "野戰鎧甲", "deDE": "[ms]Feldharnisch", "esES": "[fs]Coraza de campaña", @@ -444,7 +444,7 @@ { "id": 1948, "Key": "gth", - "enUS": " Gothic Plate ", + "enUS": "Gothic Plate ", "zhTW": "哥德鎧甲", "deDE": "[ms]Prunkharnisch", "esES": "[fs]Coraza gótica", @@ -461,7 +461,7 @@ { "id": 1949, "Key": "ful", - "enUS": " Full Plate Mail ", + "enUS": "Full Plate Mail ", "zhTW": "全身鎧甲", "deDE": "[ms]voller Harnisch", "esES": "[fs]Cota de placas completa", @@ -478,7 +478,7 @@ { "id": 1950, "Key": "aar", - "enUS": " Ancient Armor ", + "enUS": "Ancient Armor ", "zhTW": "上古鎧甲", "deDE": "[fs]alte Rüstung", "esES": "[fs]Armadura antigua", @@ -495,7 +495,7 @@ { "id": 1951, "Key": "ltp", - "enUS": " Light Plate ", + "enUS": "Light Plate ", "zhTW": "輕型鎧甲", "deDE": "[fs]leichte Plattenrüstung", "esES": "[fs]Coraza ligera", @@ -512,7 +512,7 @@ { "id": 1952, "Key": "buc", - "enUS": " Buckler ", + "enUS": "Buckler ", "zhTW": "小圓盾", "deDE": "[ms]Beschützer", "esES": "[ms]Broquel", @@ -529,7 +529,7 @@ { "id": 1953, "Key": "sml", - "enUS": " Small Shield ", + "enUS": "Small Shield ", "zhTW": "小型盾", "deDE": "[ms]kleiner Schild", "esES": "[ms]Escudo pequeño", @@ -546,7 +546,7 @@ { "id": 1954, "Key": "lrg", - "enUS": " Large Shield ", + "enUS": "Large Shield ", "zhTW": "大型盾", "deDE": "[ms]großer Schild", "esES": "[ms]Escudo grande", @@ -563,7 +563,7 @@ { "id": 1955, "Key": "kit", - "enUS": " Kite Shield ", + "enUS": "Kite Shield ", "zhTW": "鳶盾", "deDE": "[ms]eckiger Schild", "esES": "[ms]Escudo de lágrima", @@ -580,7 +580,7 @@ { "id": 1956, "Key": "tow", - "enUS": " Tower Shield ", + "enUS": "Tower Shield ", "zhTW": "塔盾", "deDE": "[ms]hoher Schild", "esES": "[fs]Tarja", @@ -597,7 +597,7 @@ { "id": 1957, "Key": "gts", - "enUS": " Gothic Shield ", + "enUS": "Gothic Shield ", "zhTW": "哥德盾", "deDE": "[ms]Prunkschild", "esES": "[ms]Escudo gótico", @@ -614,7 +614,7 @@ { "id": 1958, "Key": "lgl", - "enUS": " Leather Gloves ", + "enUS": "Leather Gloves ", "zhTW": "皮革手套", "deDE": "[pl]Lederhandschuhe", "esES": "[mp]Guantes de cuero", @@ -631,7 +631,7 @@ { "id": 1959, "Key": "vgl", - "enUS": " Heavy Gloves ", + "enUS": "Heavy Gloves ", "zhTW": "厚皮手套", "deDE": "[pl]schwere Handschuhe", "esES": "[mp]Guantes pesados", @@ -648,7 +648,7 @@ { "id": 1960, "Key": "mgl", - "enUS": " Chain Gloves ", + "enUS": "Chain Gloves ", "zhTW": "鍊甲手套", "deDE": "[pl]Kettenhandschuhe", "esES": "[mp]Guantes de malla", @@ -665,7 +665,7 @@ { "id": 1961, "Key": "tgl", - "enUS": " Light Gauntlets ", + "enUS": "Light Gauntlets ", "zhTW": "輕型護手", "deDE": "[pl]leichte Panzerhandschuhe", "esES": "[mp]Guanteletes ligeros", @@ -682,7 +682,7 @@ { "id": 1962, "Key": "hgl", - "enUS": " Gauntlets ", + "enUS": "Gauntlets ", "zhTW": "鋼鐵護手", "deDE": "[pl]Panzerhandschuhe", "esES": "[mp]Guanteletes", @@ -699,7 +699,7 @@ { "id": 1963, "Key": "lbt", - "enUS": " Boots ", + "enUS": "Boots ", "zhTW": "皮靴", "deDE": "[pl]Stiefel", "esES": "[fp]Botas", @@ -716,7 +716,7 @@ { "id": 1964, "Key": "vbt", - "enUS": " Heavy Boots ", + "enUS": "Heavy Boots ", "zhTW": "重靴", "deDE": "[pl]schwere Stiefel", "esES": "[fp]Botas pesadas", @@ -733,7 +733,7 @@ { "id": 1965, "Key": "mbt", - "enUS": " Chain Boots ", + "enUS": "Chain Boots ", "zhTW": "鎖鍊靴", "deDE": "[pl]Kettenstiefel", "esES": "[fp]Botas de malla", @@ -750,7 +750,7 @@ { "id": 1966, "Key": "tbt", - "enUS": " Light Plated Boots ", + "enUS": "Light Plated Boots ", "zhTW": "輕鎧靴", "deDE": "[pl]leichte Plattenstiefel", "esES": "[fp]Botas de placas ligeras", @@ -767,7 +767,7 @@ { "id": 1967, "Key": "hbt", - "enUS": " Greaves ", + "enUS": "Greaves ", "zhTW": "護脛", "deDE": "[pl]Beinschienen", "esES": "[fp]Grebas", @@ -784,7 +784,7 @@ { "id": 1968, "Key": "lbl", - "enUS": " Sash ", + "enUS": "Sash ", "zhTW": "束帶", "deDE": "[fs]Schärpe", "esES": "[ms]Fajín", @@ -801,7 +801,7 @@ { "id": 1969, "Key": "vbl", - "enUS": " Light Belt ", + "enUS": "Light Belt ", "zhTW": "輕腰帶", "deDE": "[ms]leichter Gürtel", "esES": "[ms]Cinturón ligero", @@ -818,7 +818,7 @@ { "id": 1970, "Key": "mbl", - "enUS": " Belt ", + "enUS": "Belt ", "zhTW": "腰帶", "deDE": "[ms]Gürtel", "esES": "[ms]Cinturón", @@ -835,7 +835,7 @@ { "id": 1971, "Key": "tbl", - "enUS": " Heavy Belt ", + "enUS": "Heavy Belt ", "zhTW": "厚腰帶", "deDE": "[ms]schwerer Gürtel", "esES": "[ms]Cinturón pesado", @@ -852,7 +852,7 @@ { "id": 1972, "Key": "hbl", - "enUS": " Plated Belt ", + "enUS": "Plated Belt ", "zhTW": "鎧甲腰帶", "deDE": "[ms]Plattengürtel", "esES": "[ms]Cinturón de placas", @@ -869,7 +869,7 @@ { "id": 1973, "Key": "bhm", - "enUS": " Bone Helm ", + "enUS": "Bone Helm ", "zhTW": "骸骨頭盔", "deDE": "[ms]Knochenhelm", "esES": "[ms]Yelmo de hueso", @@ -886,7 +886,7 @@ { "id": 1974, "Key": "bsh", - "enUS": " Bone Shield ", + "enUS": "Bone Shield ", "zhTW": "骨盾", "deDE": "[ms]Knochenschild", "esES": "[ms]Escudo de hueso", @@ -903,7 +903,7 @@ { "id": 1975, "Key": "spk", - "enUS": " Spiked Shield ", + "enUS": "Spiked Shield ", "zhTW": "尖刺盾", "deDE": "[ms]Dornenschild", "esES": "[ms]Escudo con pinchos", @@ -920,7 +920,7 @@ { "id": 1976, "Key": "hax", - "enUS": " Hand Axe ", + "enUS": "Hand Axe ", "zhTW": "手斧", "deDE": "[fs]Handaxt", "esES": "[fs]Hacha de mano", @@ -937,7 +937,7 @@ { "id": 1977, "Key": "axe", - "enUS": " Axe ", + "enUS": "Axe ", "zhTW": "斧", "deDE": "[fs]Axt", "esES": "[fs]Hacha", @@ -954,7 +954,7 @@ { "id": 1978, "Key": "2ax", - "enUS": " Double Axe ", + "enUS": "Double Axe ", "zhTW": "雙刃斧", "deDE": "[fs]Doppelaxt", "esES": "[fs]Hacha doble", @@ -971,7 +971,7 @@ { "id": 1979, "Key": "mpi", - "enUS": " Military Pick ", + "enUS": "Military Pick ", "zhTW": "軍用鎬", "deDE": "[fs]Militärpicke", "esES": "[ms]Pico militar", @@ -988,7 +988,7 @@ { "id": 1980, "Key": "wax", - "enUS": " War Axe ", + "enUS": "War Axe ", "zhTW": "征戰斧", "deDE": "[fs]Kriegsaxt", "esES": "[fs]Hacha de guerra", @@ -1005,7 +1005,7 @@ { "id": 1981, "Key": "lax", - "enUS": " Large Axe ", + "enUS": "Large Axe ", "zhTW": "重斧", "deDE": "[fs]große Axt", "esES": "[fs]Hacha grande", @@ -1022,7 +1022,7 @@ { "id": 1982, "Key": "bax", - "enUS": " Broad Axe ", + "enUS": "Broad Axe ", "zhTW": "闊斧", "deDE": "[fs]Breitaxt", "esES": "[fs]Hacha ancha", @@ -1039,7 +1039,7 @@ { "id": 1983, "Key": "btx", - "enUS": " Battle Axe ", + "enUS": "Battle Axe ", "zhTW": "戰斧", "deDE": "[fs]Kampfaxt", "esES": "[fs]Hacha de batalla", @@ -1056,7 +1056,7 @@ { "id": 1984, "Key": "gax", - "enUS": " Great Axe ", + "enUS": "Great Axe ", "zhTW": "巨斧", "deDE": "[fs]schwere Axt", "esES": "[fs]Gran hacha", @@ -1073,7 +1073,7 @@ { "id": 1985, "Key": "gix", - "enUS": " Giant Axe ", + "enUS": "Giant Axe ", "zhTW": "巨人斧", "deDE": "[fs]Riesenaxt", "esES": "[fs]Hacha gigante", @@ -1090,7 +1090,7 @@ { "id": 1986, "Key": "wnd", - "enUS": " Wand ", + "enUS": "Wand ", "zhTW": "魔杖", "deDE": "[ms]Stab", "esES": "[fs]Vara", @@ -1107,7 +1107,7 @@ { "id": 1987, "Key": "ywn", - "enUS": " Yew Wand ", + "enUS": "Yew Wand ", "zhTW": "紫杉魔杖", "deDE": "[ms]Eibenstab", "esES": "[fs]Vara de tejo", @@ -1124,7 +1124,7 @@ { "id": 1988, "Key": "bwn", - "enUS": " Bone Wand ", + "enUS": "Bone Wand ", "zhTW": "骸骨魔杖", "deDE": "[ms]Knochenstab", "esES": "[fs]Vara de hueso", @@ -1141,7 +1141,7 @@ { "id": 1989, "Key": "gwn", - "enUS": " Grim Wand ", + "enUS": "Grim Wand ", "zhTW": "陰森魔杖", "deDE": "[ms]Schlagstab", "esES": "[fs]Vara lúgubre", @@ -1158,7 +1158,7 @@ { "id": 1990, "Key": "clb", - "enUS": " Club ", + "enUS": "Club ", "zhTW": "短棒", "deDE": "[fs]Keule", "esES": "[fs]Porra", @@ -1175,7 +1175,7 @@ { "id": 1991, "Key": "scp", - "enUS": " Scepter ", + "enUS": "Scepter ", "zhTW": "權杖", "deDE": "[ns]Szepter", "esES": "[ms]Cetro", @@ -1192,7 +1192,7 @@ { "id": 1992, "Key": "gsc", - "enUS": " Grand Scepter ", + "enUS": "Grand Scepter ", "zhTW": "莊嚴權杖", "deDE": "[ns]großes Szepter", "esES": "[ms]Gran cetro", @@ -1209,7 +1209,7 @@ { "id": 1993, "Key": "wsp", - "enUS": " War Scepter ", + "enUS": "War Scepter ", "zhTW": "征戰權杖", "deDE": "[ns]Kriegsszepter", "esES": "[ms]Cetro de guerra", @@ -1226,7 +1226,7 @@ { "id": 1994, "Key": "spc", - "enUS": " Spiked Club ", + "enUS": "Spiked Club ", "zhTW": "狼牙棒", "deDE": "[fs]Dornenkeule", "esES": "[fs]Porra con pinchos", @@ -1243,7 +1243,7 @@ { "id": 1995, "Key": "mac", - "enUS": " Mace ", + "enUS": "Mace ", "zhTW": "釘鎚", "deDE": "[ms]Knüppel", "esES": "[fs]Maza", @@ -1260,7 +1260,7 @@ { "id": 1996, "Key": "mst", - "enUS": " Morning Star ", + "enUS": "Morning Star ", "zhTW": "釘頭鎚", "deDE": "[ms]Morgenstern", "esES": "[fs]Estrella del alba", @@ -1277,7 +1277,7 @@ { "id": 1997, "Key": "fla", - "enUS": " Flail ", + "enUS": "Flail ", "zhTW": "連枷", "deDE": "[ms]Flegel", "esES": "[ms]Mangual", @@ -1294,7 +1294,7 @@ { "id": 1998, "Key": "whm", - "enUS": " War Hammer ", + "enUS": "War Hammer ", "zhTW": "戰鎚", "deDE": "[ms]Kriegshammer", "esES": "[ms]Martillo de guerra", @@ -1311,7 +1311,7 @@ { "id": 1999, "Key": "mau", - "enUS": " Maul ", + "enUS": "Maul ", "zhTW": "重鎚", "deDE": "[ms]Holzhammer", "esES": "[fs]Almádena", @@ -1328,7 +1328,7 @@ { "id": 2000, "Key": "gma", - "enUS": " Great Maul ", + "enUS": "Great Maul ", "zhTW": "巨型重鎚", "deDE": "[ms]großer Holzhammer", "esES": "[fs]Gran almádena", @@ -1345,7 +1345,7 @@ { "id": 2001, "Key": "ssd", - "enUS": " Short Sword ", + "enUS": "Short Sword ", "zhTW": "短劍", "deDE": "[ns]Kurzschwert", "esES": "[fs]Espada corta", @@ -1362,7 +1362,7 @@ { "id": 2002, "Key": "scm", - "enUS": " Scimitar ", + "enUS": "Scimitar ", "zhTW": "彎刀", "deDE": "[ms]Krummsäbel", "esES": "[fs]Cimitarra", @@ -1379,7 +1379,7 @@ { "id": 2003, "Key": "sbr", - "enUS": " Sabre ", + "enUS": "Sabre ", "zhTW": "軍刀", "deDE": "[ms]Säbel", "esES": "[ms]Sable", @@ -1396,7 +1396,7 @@ { "id": 2004, "Key": "flc", - "enUS": " Falchion ", + "enUS": "Falchion ", "zhTW": "彎刃大刀", "deDE": "[ns]Krummschwert", "esES": "[ms]Chafarote", @@ -1413,7 +1413,7 @@ { "id": 2005, "Key": "crs", - "enUS": " Crystal Sword ", + "enUS": "Crystal Sword ", "zhTW": "水晶劍", "deDE": "[ns]Kristallschwert", "esES": "[fs]Espada de cristal", @@ -1430,7 +1430,7 @@ { "id": 2006, "Key": "bsd", - "enUS": " Broad Sword ", + "enUS": "Broad Sword ", "zhTW": "闊劍", "deDE": "[ns]Breitschwert", "esES": "[fs]Espada ancha", @@ -1447,7 +1447,7 @@ { "id": 2007, "Key": "lsd", - "enUS": " Long Sword ", + "enUS": "Long Sword ", "zhTW": "長劍", "deDE": "[ns]Langschwert", "esES": "[fs]Espada larga", @@ -1464,7 +1464,7 @@ { "id": 2008, "Key": "wsd", - "enUS": " War Sword ", + "enUS": "War Sword ", "zhTW": "征戰劍", "deDE": "[ns]Kriegsschwert", "esES": "[fs]Espada de guerra", @@ -1481,7 +1481,7 @@ { "id": 2009, "Key": "2hs", - "enUS": " Two-Handed Sword ", + "enUS": "Two-Handed Sword ", "zhTW": "雙手劍", "deDE": "[ns]Zweihänderschwert", "esES": "[ms]Mandoble", @@ -1498,7 +1498,7 @@ { "id": 2010, "Key": "clm", - "enUS": " Claymore ", + "enUS": "Claymore ", "zhTW": "闊刃大劍", "deDE": "[ns]Schottenschwert", "esES": "[ms]Claymore", @@ -1515,7 +1515,7 @@ { "id": 2011, "Key": "gis", - "enUS": " Giant Sword ", + "enUS": "Giant Sword ", "zhTW": "大劍", "deDE": "[ns]Riesenschwert", "esES": "[fs]Espada gigante", @@ -1532,7 +1532,7 @@ { "id": 2012, "Key": "bsw", - "enUS": " Bastard Sword ", + "enUS": "Bastard Sword ", "zhTW": "重劍", "deDE": "[ns]Bastardschwert", "esES": "[fs]Espada bastarda", @@ -1549,7 +1549,7 @@ { "id": 2013, "Key": "flb", - "enUS": " Flamberge ", + "enUS": "Flamberge ", "zhTW": "焰形劍", "deDE": "[ms]Flamberg", "esES": "[ms]Flamberge", @@ -1566,7 +1566,7 @@ { "id": 2014, "Key": "gsd", - "enUS": " Great Sword ", + "enUS": "Great Sword ", "zhTW": "巨劍", "deDE": "[ns]Großschwert", "esES": "[fs]Gran espada", @@ -1583,7 +1583,7 @@ { "id": 2015, "Key": "dgr", - "enUS": " Dagger ", + "enUS": "Dagger ", "zhTW": "匕首", "deDE": "[ms]Dolch", "esES": "[fs]Daga", @@ -1600,7 +1600,7 @@ { "id": 2016, "Key": "dir", - "enUS": " Dirk ", + "enUS": "Dirk ", "zhTW": "長匕首", "deDE": "[ns]Dolchmesser", "esES": "[ms]Dirk", @@ -1617,7 +1617,7 @@ { "id": 2017, "Key": "kri", - "enUS": " Kris ", + "enUS": "Kris ", "zhTW": "波刃匕首", "deDE": "[ms]Kris", "esES": "[ms]Kris", @@ -1634,7 +1634,7 @@ { "id": 2018, "Key": "bld", - "enUS": " Blade ", + "enUS": "Blade ", "zhTW": "利刃匕首", "deDE": "[ns]messer", "esES": "[fs]Navaja", @@ -1651,7 +1651,7 @@ { "id": 2019, "Key": "tkf", - "enUS": " Throwing Knife ", + "enUS": "Throwing Knife ", "zhTW": "飛刀", "deDE": "[ns]Wurfmesser", "esES": "[ms]Cuchillo arrojadizo", @@ -1668,7 +1668,7 @@ { "id": 2020, "Key": "tax", - "enUS": " Throwing Axe ", + "enUS": "Throwing Axe ", "zhTW": "飛斧", "deDE": "[fs]Wurfaxt", "esES": "[fs]Hacha arrojadiza", @@ -1685,7 +1685,7 @@ { "id": 2021, "Key": "bkf", - "enUS": " Balanced Knife ", + "enUS": "Balanced Knife ", "zhTW": "平衡飛刀", "deDE": "[ns]Zwillingsmesser", "esES": "[ms]Cuchillo equilibrado", @@ -1702,7 +1702,7 @@ { "id": 2022, "Key": "bal", - "enUS": " Balanced Axe ", + "enUS": "Balanced Axe ", "zhTW": "平衡飛斧", "deDE": "[fs]Zweifachaxt", "esES": "[fs]Hacha equilibrada", @@ -1719,7 +1719,7 @@ { "id": 2023, "Key": "jav", - "enUS": " Javelin ", + "enUS": "Javelin ", "zhTW": "標槍", "deDE": "[ms]Wurfspieß", "esES": "[fs]Jabalina", @@ -1736,7 +1736,7 @@ { "id": 2024, "Key": "pil", - "enUS": " Pilum ", + "enUS": "Pilum ", "zhTW": "長標槍", "deDE": "[ms]Spieß", "esES": "[ms]Pilum", @@ -1753,7 +1753,7 @@ { "id": 2025, "Key": "ssp", - "enUS": " Short Spear ", + "enUS": "Short Spear ", "zhTW": "短矛", "deDE": "[ms]Kurzspeer", "esES": "[fs]Lanza corta", @@ -1770,7 +1770,7 @@ { "id": 2026, "Key": "glv", - "enUS": " Glaive ", + "enUS": "Glaive ", "zhTW": "長刃槍", "deDE": "[fs]Gleve", "esES": "[fs]Guja", @@ -1787,7 +1787,7 @@ { "id": 2027, "Key": "tsp", - "enUS": " Throwing Spear ", + "enUS": "Throwing Spear ", "zhTW": "飛矛", "deDE": "[ms]Wurfspeer", "esES": "[fs]Lanza arrojadiza", @@ -1804,7 +1804,7 @@ { "id": 2028, "Key": "spr", - "enUS": " Spear ", + "enUS": "Spear ", "zhTW": "長矛", "deDE": "[ms]Speer", "esES": "[fs]Lanza", @@ -1821,7 +1821,7 @@ { "id": 2029, "Key": "tri", - "enUS": " Trident ", + "enUS": "Trident ", "zhTW": "三叉戟", "deDE": "[ms]Dreizack", "esES": "[ms]Tridente", @@ -1838,7 +1838,7 @@ { "id": 2030, "Key": "brn", - "enUS": " Brandistock ", + "enUS": "Brandistock ", "zhTW": "三叉槍", "deDE": "[fs]Forke", "esES": "[fs]Roncona", @@ -1855,7 +1855,7 @@ { "id": 2031, "Key": "spt", - "enUS": " Spetum ", + "enUS": "Spetum ", "zhTW": "勾刃槍", "deDE": "[ns]Spetum", "esES": "[ms]Spetum", @@ -1872,7 +1872,7 @@ { "id": 2032, "Key": "pik", - "enUS": " Pike ", + "enUS": "Pike ", "zhTW": "步戰矛", "deDE": "[fs]Pike", "esES": "[fs]Pica", @@ -1889,7 +1889,7 @@ { "id": 2033, "Key": "bar", - "enUS": " Bardiche ", + "enUS": "Bardiche ", "zhTW": "月牙砍刀", "deDE": "[fs]Bardike", "esES": "[ms]Bardiche", @@ -1906,7 +1906,7 @@ { "id": 2034, "Key": "vou", - "enUS": " Voulge ", + "enUS": "Voulge ", "zhTW": "槍斧", "deDE": "[ms]Landsknechtsspieß", "esES": "[ms]Voulge", @@ -1923,7 +1923,7 @@ { "id": 2035, "Key": "scy", - "enUS": " Scythe ", + "enUS": "Scythe ", "zhTW": "鐮刀", "deDE": "[fs]Sense", "esES": "[fs]Guadaña", @@ -1940,7 +1940,7 @@ { "id": 2036, "Key": "pax", - "enUS": " Poleaxe ", + "enUS": "Poleaxe ", "zhTW": "長柄斧", "deDE": "[ms]Schwengel", "esES": "[fs]Hacha larga", @@ -1957,7 +1957,7 @@ { "id": 2037, "Key": "hal", - "enUS": " Halberd ", + "enUS": "Halberd ", "zhTW": "長戟", "deDE": "[fs]Hellebarde", "esES": "[fs]Alabarda", @@ -1974,7 +1974,7 @@ { "id": 2038, "Key": "wsc", - "enUS": " War Scythe ", + "enUS": "War Scythe ", "zhTW": "征戰鐮刀", "deDE": "[fs]Kriegssense", "esES": "[fs]Guadaña de guerra", @@ -1991,7 +1991,7 @@ { "id": 2039, "Key": "sst", - "enUS": " Short Staff ", + "enUS": "Short Staff ", "zhTW": "短杖", "deDE": "[ms]Kurzstab", "esES": "[ms]Bastón corto", @@ -2008,7 +2008,7 @@ { "id": 2040, "Key": "lst", - "enUS": " Long Staff ", + "enUS": "Long Staff ", "zhTW": "長杖", "deDE": "[ms]Langstab", "esES": "[ms]Bastón largo", @@ -2025,7 +2025,7 @@ { "id": 2041, "Key": "cst", - "enUS": " Gnarled Staff ", + "enUS": "Gnarled Staff ", "zhTW": "木節法杖", "deDE": "[ms]Knorrenstab", "esES": "[ms]Bastón nudoso", @@ -2042,7 +2042,7 @@ { "id": 2042, "Key": "bst", - "enUS": " Battle Staff ", + "enUS": "Battle Staff ", "zhTW": "戰鬥法杖", "deDE": "[ms]Kriegsstab", "esES": "[ms]Bastón de batalla", @@ -2059,7 +2059,7 @@ { "id": 2043, "Key": "wst", - "enUS": " War Staff ", + "enUS": "War Staff ", "zhTW": "征戰法杖", "deDE": "[ms]Schlachtenstab", "esES": "[ms]Bastón de guerra", @@ -2076,7 +2076,7 @@ { "id": 2044, "Key": "sbw", - "enUS": " Short Bow ", + "enUS": "Short Bow ", "zhTW": "短弓", "deDE": "[ms]Kurzbogen", "esES": "[ms]Arco corto", @@ -2093,7 +2093,7 @@ { "id": 2045, "Key": "hbw", - "enUS": " Hunter's Bow ", + "enUS": "Hunter's Bow ", "zhTW": "獵弓", "deDE": "[ms]Jagdbogen", "esES": "[ms]Arco de cazador", @@ -2110,7 +2110,7 @@ { "id": 2046, "Key": "lbw", - "enUS": " Long Bow ", + "enUS": "Long Bow ", "zhTW": "長弓", "deDE": "[ms]Langbogen", "esES": "[ms]Arco largo", @@ -2127,7 +2127,7 @@ { "id": 2047, "Key": "cbw", - "enUS": " Composite Bow ", + "enUS": "Composite Bow ", "zhTW": "複合弓", "deDE": "[ms]Kompositbogen", "esES": "[ms]Arco compuesto", @@ -2144,7 +2144,7 @@ { "id": 2048, "Key": "sbb", - "enUS": " Short Battle Bow ", + "enUS": "Short Battle Bow ", "zhTW": "戰鬥短弓", "deDE": "[ms]kurzer Kampfbogen", "esES": "[ms]Arco corto de batalla", @@ -2161,7 +2161,7 @@ { "id": 2049, "Key": "lbb", - "enUS": " Long Battle Bow ", + "enUS": "Long Battle Bow ", "zhTW": "戰鬥長弓", "deDE": "[ms]langer Kampfbogen", "esES": "[ms]Arco largo de batalla", @@ -2178,7 +2178,7 @@ { "id": 2050, "Key": "swb", - "enUS": " Short War Bow ", + "enUS": "Short War Bow ", "zhTW": "征戰短弓", "deDE": "[ms]kurzer Kriegsbogen", "esES": "[ms]Arco corto de guerra", @@ -2195,7 +2195,7 @@ { "id": 2051, "Key": "lwb", - "enUS": " Long War Bow ", + "enUS": "Long War Bow ", "zhTW": "征戰長弓", "deDE": "[ms]langer Kriegsbogen", "esES": "[ms]Arco largo de guerra", @@ -2212,7 +2212,7 @@ { "id": 2052, "Key": "lxb", - "enUS": " Light Crossbow ", + "enUS": "Light Crossbow ", "zhTW": "輕弩", "deDE": "[fs]leichte Armbrust", "esES": "[fs]Ballesta ligera", @@ -2229,7 +2229,7 @@ { "id": 2053, "Key": "mxb", - "enUS": " Crossbow ", + "enUS": "Crossbow ", "zhTW": "弩", "deDE": "[fs]Armbrust", "esES": "[fs]Ballesta", @@ -2246,7 +2246,7 @@ { "id": 2054, "Key": "hxb", - "enUS": " Heavy Crossbow ", + "enUS": "Heavy Crossbow ", "zhTW": "重弩", "deDE": "[fs]schwere Armbrust", "esES": "[fs]Ballesta pesada", @@ -2263,7 +2263,7 @@ { "id": 2055, "Key": "rxb", - "enUS": " Repeating Crossbow ", + "enUS": "Repeating Crossbow ", "zhTW": "連弩", "deDE": "[fs]Repetierarmbrust", "esES": "[fs]Ballesta de repetición", @@ -2280,7 +2280,7 @@ { "id": 2056, "Key": "xpk", - "enUS": " Barbed Shield ", + "enUS": "Barbed Shield ", "zhTW": "倒刺盾", "deDE": "[ms]Stachelschild", "esES": "[ms]Escudo con púas", @@ -2297,7 +2297,7 @@ { "id": 2057, "Key": "xsh", - "enUS": " Grim Shield ", + "enUS": "Grim Shield ", "zhTW": "陰森盾牌", "deDE": "[ms]Kampfschild", "esES": "[ms]Escudo lúgubre", @@ -2314,7 +2314,7 @@ { "id": 2058, "Key": "xh9", - "enUS": " Grim Helm ", + "enUS": "Grim Helm ", "zhTW": "陰森頭盔", "deDE": "[ms]Kampfhelm", "esES": "[ms]Yelmo lúgubre", @@ -2331,7 +2331,7 @@ { "id": 2059, "Key": "zhb", - "enUS": " War Belt ", + "enUS": "War Belt ", "zhTW": "征戰腰帶", "deDE": "[ms]Kriegsgürtel", "esES": "[ms]Cinturón de guerra", @@ -2348,7 +2348,7 @@ { "id": 2060, "Key": "ztb", - "enUS": " Battle Belt ", + "enUS": "Battle Belt ", "zhTW": "戰鬥腰帶", "deDE": "[ms]Kampfgürtel", "esES": "[ms]Cinturón de batalla", @@ -2365,7 +2365,7 @@ { "id": 2061, "Key": "zmb", - "enUS": " Mesh Belt ", + "enUS": "Mesh Belt ", "zhTW": "鐵網腰帶", "deDE": "[ms]Kettengürtel", "esES": "[ms]Cinturón mallado", @@ -2382,7 +2382,7 @@ { "id": 2062, "Key": "zvb", - "enUS": " Sharkskin Belt ", + "enUS": "Sharkskin Belt ", "zhTW": "鯊皮腰帶", "deDE": "[ms]Hailedergürtel", "esES": "[ms]Cinturón de piel de tiburón", @@ -2399,7 +2399,7 @@ { "id": 2063, "Key": "zlb", - "enUS": " Demonhide Sash ", + "enUS": "Demonhide Sash ", "zhTW": "魔皮束帶", "deDE": "[fs]Dämonenlederschärpe", "esES": "[ms]Fajín de cuero de demonio", @@ -2416,7 +2416,7 @@ { "id": 2064, "Key": "xhb", - "enUS": " War Boots ", + "enUS": "War Boots ", "zhTW": "征戰靴", "deDE": "[pl]Kriegsstiefel", "esES": "[fp]Botas de guerra", @@ -2433,7 +2433,7 @@ { "id": 2065, "Key": "xtb", - "enUS": " Battle Boots ", + "enUS": "Battle Boots ", "zhTW": "戰鬥靴", "deDE": "[pl]Kampfstiefel", "esES": "[fp]Botas de batalla", @@ -2450,7 +2450,7 @@ { "id": 2066, "Key": "xmb", - "enUS": " Mesh Boots ", + "enUS": "Mesh Boots ", "zhTW": "鐵網靴", "deDE": "[pl]Ringstiefel", "esES": "[fp]Botas malladas", @@ -2467,7 +2467,7 @@ { "id": 2067, "Key": "xvb", - "enUS": " Sharkskin Boots ", + "enUS": "Sharkskin Boots ", "zhTW": "鯊皮靴", "deDE": "[pl]Hailederstiefel", "esES": "[fp]Botas de piel de tiburón", @@ -2484,7 +2484,7 @@ { "id": 2068, "Key": "xlb", - "enUS": " Demonhide Boots ", + "enUS": "Demonhide Boots ", "zhTW": "魔皮長靴", "deDE": "[pl]Dämonenlederstiefel", "esES": "[fp]Botas de cuero de demonio", @@ -2501,7 +2501,7 @@ { "id": 2070, "Key": "xtg", - "enUS": " Battle Gauntlets ", + "enUS": "Battle Gauntlets ", "zhTW": "戰鬥護手", "deDE": "[pl]Kampfpanzerhandschuhe", "esES": "[mp]Guanteletes de batalla", @@ -2518,7 +2518,7 @@ { "id": 2071, "Key": "xmg", - "enUS": " Heavy Bracers ", + "enUS": "Heavy Bracers ", "zhTW": "重型護腕", "deDE": "[pl]schwere Armschienen", "esES": "[mp]Brazales pesados", @@ -2535,7 +2535,7 @@ { "id": 2072, "Key": "xvg", - "enUS": " Sharkskin Gloves ", + "enUS": "Sharkskin Gloves ", "zhTW": "鯊皮手套", "deDE": "[pl]Hailederhandschuhe", "esES": "[mp]Guantes de piel de tiburón", @@ -2552,7 +2552,7 @@ { "id": 2073, "Key": "xlg", - "enUS": " Demonhide Gloves ", + "enUS": "Demonhide Gloves ", "zhTW": "魔皮手套", "deDE": "[pl]Dämonenlederhandschuhe", "esES": "[mp]Guantes de cuero de demonio", @@ -2569,7 +2569,7 @@ { "id": 2074, "Key": "xts", - "enUS": " Ancient Shield ", + "enUS": "Ancient Shield ", "zhTW": "上古盾", "deDE": "[ms]alter Schild", "esES": "[ms]Escudo antiguo", @@ -2586,7 +2586,7 @@ { "id": 2075, "Key": "xow", - "enUS": " Pavise ", + "enUS": "Pavise ", "zhTW": "大盾", "deDE": "[ms]Pavese", "esES": "[ms]Pavés", @@ -2603,7 +2603,7 @@ { "id": 2076, "Key": "xit", - "enUS": " Dragon Shield ", + "enUS": "Dragon Shield ", "zhTW": "龍盾", "deDE": "[ms]Drachenschild", "esES": "[ms]Escudo de dragón", @@ -2620,7 +2620,7 @@ { "id": 2077, "Key": "xrg", - "enUS": " Scutum ", + "enUS": "Scutum ", "zhTW": "大圓盾", "deDE": "[ms]Scutum", "esES": "[ms]Scutum", @@ -2637,7 +2637,7 @@ { "id": 2078, "Key": "xml", - "enUS": " Round Shield ", + "enUS": "Round Shield ", "zhTW": "圓型盾", "deDE": "[ms]Rundschild", "esES": "[ms]Escudo redondo", @@ -2654,7 +2654,7 @@ { "id": 2079, "Key": "xuc", - "enUS": " Defender ", + "enUS": "Defender ", "zhTW": "防禦盾", "deDE": "[ms]Verteidiger", "esES": "[ms]Defensor", @@ -2671,7 +2671,7 @@ { "id": 2080, "Key": "xtp", - "enUS": " Mage Plate ", + "enUS": "Mage Plate ", "zhTW": "法師鎧甲", "deDE": "[fs]Magierplattenrüstung", "esES": "[fs]Coraza de mago", @@ -2688,7 +2688,7 @@ { "id": 2081, "Key": "xar", - "enUS": " Ornate Plate ", + "enUS": "Ornate Plate ", "zhTW": "華麗戰甲", "deDE": "[fs]verzierte Plattenrüstung", "esES": "[fs]Coraza ornada", @@ -2705,7 +2705,7 @@ { "id": 2082, "Key": "xul", - "enUS": " Chaos Armor ", + "enUS": "Chaos Armor ", "zhTW": "混沌戰甲", "deDE": "[fs]Chaosrüstung", "esES": "[fs]Armadura del caos", @@ -2722,7 +2722,7 @@ { "id": 2083, "Key": "xth", - "enUS": " Embossed Plate ", + "enUS": "Embossed Plate ", "zhTW": "雕紋戰甲", "deDE": "[fs]gravierte Plattenrüstung", "esES": "[fs]Coraza repujada", @@ -2739,7 +2739,7 @@ { "id": 2084, "Key": "xld", - "enUS": " Sharktooth Armor ", + "enUS": "Sharktooth Armor ", "zhTW": "鯊齒戰甲", "deDE": "[fs]Haizahnrüstung", "esES": "[fs]Armadura de dientes de tiburón", @@ -2756,7 +2756,7 @@ { "id": 2085, "Key": "xlt", - "enUS": " Templar Coat ", + "enUS": "Templar Coat ", "zhTW": "聖堂騎士戰甲", "deDE": "[ms]Templermantel", "esES": "[fs]Cota templaria", @@ -2773,7 +2773,7 @@ { "id": 2086, "Key": "xpl", - "enUS": " Russet Armor ", + "enUS": "Russet Armor ", "zhTW": "赤褐戰甲", "deDE": "[fs]Eisenrüstung", "esES": "[fs]Armadura rojiza", @@ -2790,7 +2790,7 @@ { "id": 2087, "Key": "xrs", - "enUS": " Cuirass ", + "enUS": "Cuirass ", "zhTW": "護胸甲", "deDE": "[ms]Harnisch", "esES": "[ms]Peto", @@ -2807,7 +2807,7 @@ { "id": 2088, "Key": "xhn", - "enUS": " Mesh Armor ", + "enUS": "Mesh Armor ", "zhTW": "鐵網戰甲", "deDE": "[fs]Kettenrüstung", "esES": "[fs]Armadura mallada", @@ -2824,7 +2824,7 @@ { "id": 2089, "Key": "xcl", - "enUS": " Tigulated Mail ", + "enUS": "Tigulated Mail ", "zhTW": "鎖鱗戰甲", "deDE": "[ns]Komplettpanzerhemd", "esES": "[fs]Cota articulada", @@ -2841,7 +2841,7 @@ { "id": 2090, "Key": "xng", - "enUS": " Linked Mail ", + "enUS": "Linked Mail ", "zhTW": "鍊扣戰甲", "deDE": "[ns]Verbundkettenhemd", "esES": "[fs]Cota eslabonada", @@ -2858,7 +2858,7 @@ { "id": 2091, "Key": "xtu", - "enUS": " Trellised Armor ", + "enUS": "Trellised Armor ", "zhTW": "格網護甲", "deDE": "[fs]Bänderrüstung", "esES": "[fs]Armadura enrejada", @@ -2875,7 +2875,7 @@ { "id": 2092, "Key": "xla", - "enUS": " Demonhide Armor ", + "enUS": "Demonhide Armor ", "zhTW": "魔皮護甲", "deDE": "[fs]Dämonenlederrüstung", "esES": "[fs]Armadura de cuero de demonio", @@ -2892,7 +2892,7 @@ { "id": 2093, "Key": "xea", - "enUS": " Serpentskin Armor ", + "enUS": "Serpentskin Armor ", "zhTW": "海蛇皮甲", "deDE": "[fs]Schlangenlederrüstung", "esES": "[fs]Armadura de piel de serpiente", @@ -2909,7 +2909,7 @@ { "id": 2094, "Key": "xui", - "enUS": " Ghost Armor ", + "enUS": "Ghost Armor ", "zhTW": "鬼魂戰衣", "deDE": "[fs]Geisterrüstung", "esES": "[fs]Armadura fantasmal", @@ -2926,7 +2926,7 @@ { "id": 2095, "Key": "xsk", - "enUS": " Death Mask ", + "enUS": "Death Mask ", "zhTW": "死亡面具", "deDE": "[fs]Totenmaske", "esES": "[fs]Máscara de la muerte", @@ -2943,7 +2943,7 @@ { "id": 2096, "Key": "xrn", - "enUS": " Grand Crown ", + "enUS": "Grand Crown ", "zhTW": "莊嚴王冠", "deDE": "[fs]große Krone", "esES": "[fs]Gran corona", @@ -2960,7 +2960,7 @@ { "id": 2098, "Key": "xhl", - "enUS": " Basinet ", + "enUS": "Basinet ", "zhTW": "輕盔", "deDE": "[ms]Kesselhelm", "esES": "[ms]Bacinete", @@ -2977,7 +2977,7 @@ { "id": 2099, "Key": "xlm", - "enUS": " Casque ", + "enUS": "Casque ", "zhTW": "兜盔", "deDE": "[ms]Spitzhelm", "esES": "[ms]Morrión", @@ -2994,7 +2994,7 @@ { "id": 2100, "Key": "xkp", - "enUS": " Sallet ", + "enUS": "Sallet ", "zhTW": "便盔", "deDE": "[ms]Schaller", "esES": "[fs]Celada", @@ -3011,7 +3011,7 @@ { "id": 2101, "Key": "xap", - "enUS": " War Hat ", + "enUS": "War Hat ", "zhTW": "戰帽", "deDE": "[ms]Kriegshut", "esES": "[fs]Cofia de guerra", @@ -3028,7 +3028,7 @@ { "id": 2102, "Key": "8rx", - "enUS": " Chu-Ko-Nu ", + "enUS": "Chu-Ko-Nu ", "zhTW": "諸葛弩", "deDE": "[fs]Chu-Ko-Nu", "esES": "[ms]Chu-ko-nu", @@ -3045,7 +3045,7 @@ { "id": 2103, "Key": "8hx", - "enUS": " Ballista ", + "enUS": "Ballista ", "zhTW": "砲弩", "deDE": "[fs]Balliste", "esES": "[fs]Balista", @@ -3062,7 +3062,7 @@ { "id": 2104, "Key": "8mx", - "enUS": " Siege Crossbow ", + "enUS": "Siege Crossbow ", "zhTW": "攻城弩", "deDE": "[fs]Belagerungsarmbrust", "esES": "[fs]Ballesta de asedio", @@ -3079,7 +3079,7 @@ { "id": 2105, "Key": "8lx", - "enUS": " Arbalest ", + "enUS": "Arbalest ", "zhTW": "鋼弩", "deDE": "[fs]Arbaleste", "esES": "[fs]Arbalesta", @@ -3096,7 +3096,7 @@ { "id": 2106, "Key": "8lw", - "enUS": " Gothic Bow ", + "enUS": "Gothic Bow ", "zhTW": "哥德弓", "deDE": "[ms]Prunkbogen", "esES": "[ms]Arco gótico", @@ -3113,7 +3113,7 @@ { "id": 2107, "Key": "8sw", - "enUS": " Rune Bow ", + "enUS": "Rune Bow ", "zhTW": "符文弓", "deDE": "[ms]Runenbogen", "esES": "[ms]Arco rúnico", @@ -3130,7 +3130,7 @@ { "id": 2108, "Key": "8l8", - "enUS": " Large Siege Bow ", + "enUS": "Large Siege Bow ", "zhTW": "攻城長弓", "deDE": "[ms]langer Belagerungsbogen", "esES": "[ms]Arco grande de asedio", @@ -3147,7 +3147,7 @@ { "id": 2109, "Key": "8s8", - "enUS": " Short Siege Bow ", + "enUS": "Short Siege Bow ", "zhTW": "攻城短弓", "deDE": "[ms]kurzer Belagerungsbogen", "esES": "[ms]Arco corto de asedio", @@ -3164,7 +3164,7 @@ { "id": 2110, "Key": "8cb", - "enUS": " Double Bow ", + "enUS": "Double Bow ", "zhTW": "雙曲弓", "deDE": "[ms]Doppelbogen", "esES": "[ms]Arco doble", @@ -3181,7 +3181,7 @@ { "id": 2111, "Key": "8lb", - "enUS": " Cedar Bow ", + "enUS": "Cedar Bow ", "zhTW": "杉木弓", "deDE": "[ms]Zedernbogen", "esES": "[ms]Arco de cedro", @@ -3198,7 +3198,7 @@ { "id": 2112, "Key": "8hb", - "enUS": " Razor Bow ", + "enUS": "Razor Bow ", "zhTW": "剃刀弓", "deDE": "[ms]Klingenbogen", "esES": "[ms]Arco de cuchilla", @@ -3215,7 +3215,7 @@ { "id": 2113, "Key": "8sb", - "enUS": " Edge Bow ", + "enUS": "Edge Bow ", "zhTW": "銳弓", "deDE": "[ms]Schneidebogen", "esES": "[ms]Arco afilado", @@ -3232,7 +3232,7 @@ { "id": 2114, "Key": "8ws", - "enUS": " Rune Staff ", + "enUS": "Rune Staff ", "zhTW": "符文法杖", "deDE": "[ms]Runenstab", "esES": "[ms]Bastón rúnico", @@ -3249,7 +3249,7 @@ { "id": 2115, "Key": "8bs", - "enUS": " Gothic Staff ", + "enUS": "Gothic Staff ", "zhTW": "哥德法杖", "deDE": "[ms]Prunkstab", "esES": "[ms]Bastón gótico", @@ -3266,7 +3266,7 @@ { "id": 2116, "Key": "8cs", - "enUS": " Cedar Staff ", + "enUS": "Cedar Staff ", "zhTW": "杉木法杖", "deDE": "[ms]Zedernstab", "esES": "[ms]Bastón de cedro", @@ -3283,7 +3283,7 @@ { "id": 2117, "Key": "8ls", - "enUS": " Quarterstaff ", + "enUS": "Quarterstaff ", "zhTW": "長棍", "deDE": "[ms]Kampfstab", "esES": "[ms]Bastón de mando", @@ -3300,7 +3300,7 @@ { "id": 2118, "Key": "8ss", - "enUS": " Jo Staff ", + "enUS": "Jo Staff ", "zhTW": "棍杖", "deDE": "[ms]Schlagstab", "esES": "[ms]Bastón de jo", @@ -3317,7 +3317,7 @@ { "id": 2119, "Key": "9wc", - "enUS": " Grim Scythe ", + "enUS": "Grim Scythe ", "zhTW": "陰森鐮刀", "deDE": "[fs]Schlachtensense", "esES": "[fs]Guadaña lúgubre", @@ -3334,7 +3334,7 @@ { "id": 2120, "Key": "9h9", - "enUS": " Bec-de-Corbin ", + "enUS": "Bec-de-Corbin ", "zhTW": "渡鴉喙", "deDE": "[fs]Helmbarte", "esES": "[ms]Bec de corbin", @@ -3351,7 +3351,7 @@ { "id": 2121, "Key": "9pa", - "enUS": " Partizan ", + "enUS": "Partizan ", "zhTW": "闊頭槍", "deDE": "[fs]Partisane", "esES": "[fs]Partesana", @@ -3368,7 +3368,7 @@ { "id": 2122, "Key": "9s8", - "enUS": " Battle Scythe ", + "enUS": "Battle Scythe ", "zhTW": "戰鬥鐮刀", "deDE": "[fs]Kampfsense", "esES": "[fs]Guadaña de batalla", @@ -3385,7 +3385,7 @@ { "id": 2123, "Key": "9vo", - "enUS": " Bill ", + "enUS": "Bill ", "zhTW": "長柄鍥", "deDE": "[fs]Pinne", "esES": "[ms]Hocino", @@ -3402,7 +3402,7 @@ { "id": 2124, "Key": "9b7", - "enUS": " Lochaber Axe ", + "enUS": "Lochaber Axe ", "zhTW": "鉤斧", "deDE": "[fs]Lochaberaxt", "esES": "[fs]Hacha de Lochaber", @@ -3419,7 +3419,7 @@ { "id": 2125, "Key": "9p9", - "enUS": " Lance ", + "enUS": "Lance ", "zhTW": "長槍", "deDE": "[fs]Lanze", "esES": "[fs]Asta", @@ -3436,7 +3436,7 @@ { "id": 2126, "Key": "9st", - "enUS": " Yari ", + "enUS": "Yari ", "zhTW": "三尖槍", "deDE": "[fs]Yari", "esES": "[ms]Yari", @@ -3453,7 +3453,7 @@ { "id": 2127, "Key": "9br", - "enUS": " War Fork ", + "enUS": "War Fork ", "zhTW": "征戰軍叉", "deDE": "[fs]Kriegsforke", "esES": "[fs]Horquilla de guerra", @@ -3470,7 +3470,7 @@ { "id": 2128, "Key": "9tr", - "enUS": " Fuscina ", + "enUS": "Fuscina ", "zhTW": "矛叉", "deDE": "[ms]Kampfdreizack", "esES": "[fs]Fuscina", @@ -3487,7 +3487,7 @@ { "id": 2129, "Key": "9sr", - "enUS": " War Spear ", + "enUS": "War Spear ", "zhTW": "征戰長矛", "deDE": "[ms]Kampfspeer", "esES": "[fs]Lanza de guerra", @@ -3504,7 +3504,7 @@ { "id": 2130, "Key": "9ts", - "enUS": " Harpoon ", + "enUS": "Harpoon ", "zhTW": "魚叉", "deDE": "[fs]Harpune", "esES": "[ms]Arpón", @@ -3521,7 +3521,7 @@ { "id": 2131, "Key": "9gl", - "enUS": " Spiculum ", + "enUS": "Spiculum ", "zhTW": "尖刃槍", "deDE": "[ms]Wurfstock", "esES": "[ms]Spiculum", @@ -3538,7 +3538,7 @@ { "id": 2132, "Key": "9s9", - "enUS": " Simbilan ", + "enUS": "Simbilan ", "zhTW": "銳矛標槍", "deDE": "[ms]Simbilan", "esES": "[ms]Simbilan", @@ -3555,7 +3555,7 @@ { "id": 2133, "Key": "9pi", - "enUS": " Great Pilum ", + "enUS": "Great Pilum ", "zhTW": "重型標槍", "deDE": "[ms]großer Spieß", "esES": "[ms]Gran pilum", @@ -3572,7 +3572,7 @@ { "id": 2134, "Key": "9ja", - "enUS": " War Javelin ", + "enUS": "War Javelin ", "zhTW": "征戰標槍", "deDE": "[ms]Kriegswurfspieß", "esES": "[fs]Jabalina de guerra", @@ -3589,7 +3589,7 @@ { "id": 2135, "Key": "9b8", - "enUS": " Hurlbat ", + "enUS": "Hurlbat ", "zhTW": "投斧", "deDE": "[fs]Saufeder", "esES": "[ms]Hurlbat", @@ -3606,7 +3606,7 @@ { "id": 2136, "Key": "9bk", - "enUS": " War Dart ", + "enUS": "War Dart ", "zhTW": "征戰飛鏢", "deDE": "[ms]Kriegspfeil", "esES": "[ms]Dardo de guerra", @@ -3623,7 +3623,7 @@ { "id": 2137, "Key": "9ta", - "enUS": " Francisca ", + "enUS": "Francisca ", "zhTW": "法蘭西飛斧", "deDE": "[fs]Frankenaxt", "esES": "[fs]Francisca", @@ -3640,7 +3640,7 @@ { "id": 2138, "Key": "9tk", - "enUS": " Battle Dart ", + "enUS": "Battle Dart ", "zhTW": "戰鬥飛鏢", "deDE": "[ms]Kurzpfeil", "esES": "[ms]Dardo de batalla", @@ -3657,7 +3657,7 @@ { "id": 2140, "Key": "9kr", - "enUS": " Cinquedeas ", + "enUS": "Cinquedeas ", "zhTW": "闊身短劍", "deDE": "[ms]Cinquedea", "esES": "[fs]Cinquedea", @@ -3674,7 +3674,7 @@ { "id": 2141, "Key": "9di", - "enUS": " Rondel ", + "enUS": "Rondel ", "zhTW": "圓柄匕首", "deDE": "[ms]Langdolch", "esES": "[ms]Rondel", @@ -3691,7 +3691,7 @@ { "id": 2142, "Key": "9dg", - "enUS": " Poignard ", + "enUS": "Poignard ", "zhTW": "刺擊短劍", "deDE": "[ms]Poignard", "esES": "[ms]Puñal", @@ -3708,7 +3708,7 @@ { "id": 2143, "Key": "9gd", - "enUS": " Executioner Sword ", + "enUS": "Executioner Sword ", "zhTW": "處刑劍", "deDE": "[ns]Scharfrichterschwert", "esES": "[fs]Espada de ejecución", @@ -3725,7 +3725,7 @@ { "id": 2144, "Key": "9fb", - "enUS": " Zweihander ", + "enUS": "Zweihander ", "zhTW": "日耳曼大劍", "deDE": "[ms]Bidenhänder", "esES": "[fs]Zweihänder", @@ -3742,7 +3742,7 @@ { "id": 2145, "Key": "9gs", - "enUS": " Tusk Sword ", + "enUS": "Tusk Sword ", "zhTW": "長牙劍", "deDE": "[ns]Stoßschwert", "esES": "[fs]Espada de colmillo", @@ -3759,7 +3759,7 @@ { "id": 2146, "Key": "9cm", - "enUS": " Dacian Falx ", + "enUS": "Dacian Falx ", "zhTW": "達西安長刀", "deDE": "[fs]dakische Sichel", "esES": "[fs]Falx dacia", @@ -3776,7 +3776,7 @@ { "id": 2147, "Key": "92h", - "enUS": " Espandon ", + "enUS": "Espandon ", "zhTW": "雙手重劍", "deDE": "[ns]Espandon", "esES": "[ms]Espadón", @@ -3793,7 +3793,7 @@ { "id": 2148, "Key": "9wd", - "enUS": " Ancient Sword ", + "enUS": "Ancient Sword ", "zhTW": "上古劍", "deDE": "[ns]altes Schwert", "esES": "[fs]Espada antigua", @@ -3810,7 +3810,7 @@ { "id": 2149, "Key": "9ls", - "enUS": " Rune Sword ", + "enUS": "Rune Sword ", "zhTW": "符文劍", "deDE": "[ns]Runenschwert", "esES": "[fs]Espada rúnica", @@ -3827,7 +3827,7 @@ { "id": 2150, "Key": "9bs", - "enUS": " Battle Sword ", + "enUS": "Battle Sword ", "zhTW": "戰鬥長劍", "deDE": "[ns]Kampfschwert", "esES": "[fs]Espada de batalla", @@ -3844,7 +3844,7 @@ { "id": 2151, "Key": "9cr", - "enUS": " Dimensional Blade ", + "enUS": "Dimensional Blade ", "zhTW": "次元刃", "deDE": "[fs]Dimensionenklinge", "esES": "[fs]Espada dimensional", @@ -3861,7 +3861,7 @@ { "id": 2152, "Key": "9fc", - "enUS": " Tulwar ", + "enUS": "Tulwar ", "zhTW": "印度彎刀", "deDE": "[ns]Tulwar", "esES": "[ms]Tulwar", @@ -3878,7 +3878,7 @@ { "id": 2153, "Key": "9sb", - "enUS": " Shamshir ", + "enUS": "Shamshir ", "zhTW": "波斯彎刀", "deDE": "[ns]Schamschir", "esES": "[ms]Shamshir", @@ -3895,7 +3895,7 @@ { "id": 2154, "Key": "9sm", - "enUS": " Cutlass ", + "enUS": "Cutlass ", "zhTW": "水手刀", "deDE": "[ms]Hacksäbel", "esES": "[ms]Alfanje", @@ -3912,7 +3912,7 @@ { "id": 2155, "Key": "9ss", - "enUS": " Gladius ", + "enUS": "Gladius ", "zhTW": "羅馬短劍", "deDE": "[ms]Gladius", "esES": "[ms]Gladius", @@ -3929,7 +3929,7 @@ { "id": 2156, "Key": "9gm", - "enUS": " Martel de Fer ", + "enUS": "Martel de Fer ", "zhTW": "長柄戰鎚", "deDE": "[ms]Eisenhammer", "esES": "[ms]Martel de fer", @@ -3946,7 +3946,7 @@ { "id": 2157, "Key": "9m9", - "enUS": " War Club ", + "enUS": "War Club ", "zhTW": "征戰重鎚", "deDE": "[fs]Kriegskeule", "esES": "[fs]Porra de guerra", @@ -3963,7 +3963,7 @@ { "id": 2158, "Key": "9wh", - "enUS": " Battle Hammer ", + "enUS": "Battle Hammer ", "zhTW": "戰鬥鐵鎚", "deDE": "[ms]Kampfhammer", "esES": "[ms]Martillo de batalla", @@ -3980,7 +3980,7 @@ { "id": 2159, "Key": "9fl", - "enUS": " Knout ", + "enUS": "Knout ", "zhTW": "刑罪連枷", "deDE": "[fs]Knute", "esES": "[ms]Knut", @@ -3997,7 +3997,7 @@ { "id": 2160, "Key": "9mt", - "enUS": " Jagged Star ", + "enUS": "Jagged Star ", "zhTW": "鋸齒釘頭鎚", "deDE": "[ms]Zackenstern", "esES": "[fs]Estrella dentada", @@ -4014,7 +4014,7 @@ { "id": 2161, "Key": "9ma", - "enUS": " Flanged Mace ", + "enUS": "Flanged Mace ", "zhTW": "凸緣釘鎚", "deDE": "[ms]Kriegsknüppel", "esES": "[fs]Maza rebordeada", @@ -4031,7 +4031,7 @@ { "id": 2162, "Key": "9sp", - "enUS": " Barbed Club ", + "enUS": "Barbed Club ", "zhTW": "倒刺棍棒", "deDE": "[fs]Stachelkeule", "esES": "[fs]Porra con púas", @@ -4048,7 +4048,7 @@ { "id": 2163, "Key": "9ws", - "enUS": " Divine Scepter ", + "enUS": "Divine Scepter ", "zhTW": "聖恩權杖", "deDE": "[ns]göttliches Szepter", "esES": "[ms]Cetro divino", @@ -4065,7 +4065,7 @@ { "id": 2164, "Key": "9qs", - "enUS": " Holy Water Sprinkler ", + "enUS": "Holy Water Sprinkler ", "zhTW": "聖水禮杖", "deDE": "[ms]Weihwasserstab", "esES": "[ms]Hisopo de agua bendita", @@ -4082,7 +4082,7 @@ { "id": 2165, "Key": "9sc", - "enUS": " Rune Scepter ", + "enUS": "Rune Scepter ", "zhTW": "符文權杖", "deDE": "[ns]Runenszepter", "esES": "[ms]Cetro rúnico", @@ -4099,7 +4099,7 @@ { "id": 2166, "Key": "9cl", - "enUS": " Cudgel ", + "enUS": "Cudgel ", "zhTW": "鬥棍", "deDE": "[ms]Knüttel", "esES": "[ms]Garrote", @@ -4116,7 +4116,7 @@ { "id": 2167, "Key": "9gw", - "enUS": " Grave Wand ", + "enUS": "Grave Wand ", "zhTW": "墓地魔杖", "deDE": "[ms]Gruftstab", "esES": "[fs]Vara sepulcral", @@ -4133,7 +4133,7 @@ { "id": 2168, "Key": "9bw", - "enUS": " Tomb Wand ", + "enUS": "Tomb Wand ", "zhTW": "古墓魔杖", "deDE": "[ms]Grabesstab", "esES": "[fs]Vara fúnebre", @@ -4150,7 +4150,7 @@ { "id": 2169, "Key": "9yw", - "enUS": " Petrified Wand ", + "enUS": "Petrified Wand ", "zhTW": "石木魔杖", "deDE": "[ms]versteinerter Stab", "esES": "[fs]Vara petrificada", @@ -4167,7 +4167,7 @@ { "id": 2170, "Key": "9wn", - "enUS": " Burnt Wand ", + "enUS": "Burnt Wand ", "zhTW": "焦木魔杖", "deDE": "[ms]verbrannter Stab", "esES": "[fs]Vara quemada", @@ -4184,7 +4184,7 @@ { "id": 2171, "Key": "9gi", - "enUS": " Ancient Axe ", + "enUS": "Ancient Axe ", "zhTW": "上古斧", "deDE": "[fs]alte Axt", "esES": "[fs]Hacha antigua", @@ -4201,7 +4201,7 @@ { "id": 2172, "Key": "9ga", - "enUS": " Gothic Axe ", + "enUS": "Gothic Axe ", "zhTW": "哥德斧", "deDE": "[fs]Prunkaxt", "esES": "[fs]Hacha gótica", @@ -4218,7 +4218,7 @@ { "id": 2173, "Key": "9bt", - "enUS": " Tabar ", + "enUS": "Tabar ", "zhTW": "長戰斧", "deDE": "[ms]Tabar", "esES": "[ms]Tabar", @@ -4235,7 +4235,7 @@ { "id": 2174, "Key": "9ba", - "enUS": " Bearded Axe ", + "enUS": "Bearded Axe ", "zhTW": "鉤斧", "deDE": "[fs]Schlagaxt", "esES": "[fs]Hacha barbuda", @@ -4252,7 +4252,7 @@ { "id": 2175, "Key": "9la", - "enUS": " Military Axe ", + "enUS": "Military Axe ", "zhTW": "軍斧", "deDE": "[fs]Militäraxt", "esES": "[fs]Hacha militar", @@ -4269,7 +4269,7 @@ { "id": 2176, "Key": "9wa", - "enUS": " Naga ", + "enUS": "Naga ", "zhTW": "那伽斧", "deDE": "[fs]Dao", "esES": "[fs]Naga", @@ -4286,7 +4286,7 @@ { "id": 2177, "Key": "9mp", - "enUS": " Crowbill ", + "enUS": "Crowbill ", "zhTW": "鴉嘴鎬", "deDE": "[fs]Bogenpicke", "esES": "[ms]Pico de cuervo", @@ -4303,7 +4303,7 @@ { "id": 2178, "Key": "92a", - "enUS": " Twin Axe ", + "enUS": "Twin Axe ", "zhTW": "雙面斧", "deDE": "[fs]Zwillingsaxt", "esES": "[fs]Hacha gemela", @@ -4320,7 +4320,7 @@ { "id": 2179, "Key": "9ax", - "enUS": " Cleaver ", + "enUS": "Cleaver ", "zhTW": "斬斧", "deDE": "[fs]Spaltaxt", "esES": "[fs]Tajadera", @@ -4337,7 +4337,7 @@ { "id": 2180, "Key": "9ha", - "enUS": " Hatchet ", + "enUS": "Hatchet ", "zhTW": "短斧", "deDE": "[ns]Kriegsbeil", "esES": "[fs]Hachuela", @@ -4354,7 +4354,7 @@ { "id": 2181, "Key": "9b9", - "enUS": " Gothic Sword ", + "enUS": "Gothic Sword ", "zhTW": "哥德劍", "deDE": "[ns]Prunkschwert", "esES": "[fs]Espada gótica", @@ -4371,7 +4371,7 @@ { "id": 2182, "Key": "gpl", - "enUS": " Strangling Gas Potion ", + "enUS": "Strangling Gas Potion ", "zhTW": "刺鼻毒氣藥水", "deDE": "Erstickungsgaselixier", "esES": "[fs]Poción de gas sofocante", @@ -4388,7 +4388,7 @@ { "id": 2183, "Key": "opl", - "enUS": " Fulminating Potion ", + "enUS": "Fulminating Potion ", "zhTW": "烈性藥水", "deDE": "Knallelixier", "esES": "[fs]Poción fulminante", @@ -4405,7 +4405,7 @@ { "id": 2184, "Key": "gpm", - "enUS": " Choking Gas Potion ", + "enUS": "Choking Gas Potion ", "zhTW": "窒息毒氣藥水", "deDE": "Würgegaselixier", "esES": "[fs]Poción de gas estrangulante", @@ -4422,7 +4422,7 @@ { "id": 2185, "Key": "opm", - "enUS": " Exploding Potion ", + "enUS": "Exploding Potion ", "zhTW": "爆炸藥水", "deDE": "Explosivelixier", "esES": "[fs]Poción explosiva", @@ -4439,7 +4439,7 @@ { "id": 2186, "Key": "gps", - "enUS": " Rancid Gas Potion ", + "enUS": "Rancid Gas Potion ", "zhTW": "腐臭毒氣藥水", "deDE": "Stinkgaselixier", "esES": "[fs]Poción de gas rancio", @@ -4456,7 +4456,7 @@ { "id": 2187, "Key": "ops", - "enUS": " Oil Potion ", + "enUS": "Oil Potion ", "zhTW": "火油藥水", "deDE": "Ölelixier", "esES": "[fs]Poción de aceite", @@ -4473,7 +4473,7 @@ { "id": 2188, "Key": "gidbinn", - "enUS": " Gidbinn ", + "enUS": "Gidbinn ", "zhTW": "吉德賓", "deDE": "Gidbinn", "esES": "[fs]Gidbinn", @@ -4490,7 +4490,7 @@ { "id": 2189, "Key": "g33", - "enUS": " The Gidbinn ", + "enUS": "The Gidbinn ", "zhTW": "吉德賓", "deDE": "der Gidbinn", "esES": "Gidbinn", @@ -4507,7 +4507,7 @@ { "id": 2190, "Key": "d33", - "enUS": " Decoy Gidbinn ", + "enUS": "Decoy Gidbinn ", "zhTW": "吉德賓誘餌", "deDE": "falscher Gidbinn", "esES": "Gidbinn señuelo", @@ -4524,7 +4524,7 @@ { "id": 2191, "Key": "leg", - "enUS": " Wirt's Leg ", + "enUS": "Wirt's Leg ", "zhTW": "維特的腿", "deDE": "[ns]Wirts Bein", "esES": "[fs]Pierna de Wirt", @@ -4541,7 +4541,7 @@ { "id": 2192, "Key": "Malus", - "enUS": " Horadric Malus ", + "enUS": "Horadric Malus ", "zhTW": "赫拉迪姆之鎚", "deDE": "Horadrimmalus", "esES": "[ms]Malaise horádrico", @@ -4558,7 +4558,7 @@ { "id": 2193, "Key": "hdm", - "enUS": " Horadric Malus ", + "enUS": "Horadric Malus ", "zhTW": "赫拉迪姆之鎚", "deDE": "Horadrimmalus", "esES": "[ms]Malaise horádrico", @@ -4575,7 +4575,7 @@ { "id": 2194, "Key": "hfh", - "enUS": " Hell Forge Hammer ", + "enUS": "Hell Forge Hammer ", "zhTW": "地獄熔爐之鎚", "deDE": "Hammer der Höllenschmiede", "esES": "Martillo de la Fragua del Infierno", @@ -4592,7 +4592,7 @@ { "id": 2195, "Key": "hst", - "enUS": " Horadric Staff ", + "enUS": "Horadric Staff ", "zhTW": "赫拉迪姆之杖", "deDE": "Horadrimstab", "esES": "Bastón horádrico", @@ -4609,7 +4609,7 @@ { "id": 2196, "Key": "msf", - "enUS": " Shaft of the Horadric Staff ", + "enUS": "Shaft of the Horadric Staff ", "zhTW": "赫拉迪姆之杖的杖身", "deDE": "Schaft des Horadrimstabes", "esES": "Vara del bastón horádrico", @@ -4626,7 +4626,7 @@ { "id": 2198, "Key": "elx", - "enUS": " Elixir ", + "enUS": "Elixir ", "zhTW": "靈藥", "deDE": "Elixier", "esES": "Elixir", @@ -4643,7 +4643,7 @@ { "id": 2199, "Key": "tbk", - "enUS": " Tome of Town Portal ", + "enUS": "Tome of Town Portal ", "zhTW": "城鎮傳送之書", "deDE": "Foliant des Stadtportals", "esES": "Tomo del portal de la ciudad", @@ -4660,7 +4660,7 @@ { "id": 2200, "Key": "tsc", - "enUS": " Scroll of Town Portal ", + "enUS": "Scroll of Town Portal ", "zhTW": "城鎮傳送卷軸", "deDE": "Schriftrolle des Stadtportals", "esES": "Pergamino del portal de la ciudad", @@ -4677,7 +4677,7 @@ { "id": 2201, "Key": "ibk", - "enUS": " Tome of Identify ", + "enUS": "Tome of Identify ", "zhTW": "鑑定之書", "deDE": "Foliant der Identifikation", "esES": "Tomo de identificación", @@ -4694,7 +4694,7 @@ { "id": 2202, "Key": "isc", - "enUS": " Scroll of Identify ", + "enUS": "Scroll of Identify ", "zhTW": "鑑定卷軸", "deDE": "Schriftrolle der Identifikation", "esES": "Pergamino de identificación", @@ -4711,7 +4711,7 @@ { "id": 2207, "Key": "vps", - "enUS": " Stamina Potion ", + "enUS": "Stamina Potion ", "zhTW": "精力藥水", "deDE": "Ausdauerelixier", "esES": "Poción de aguante", @@ -4728,7 +4728,7 @@ { "id": 2208, "Key": "yps", - "enUS": " Antidote Potion ", + "enUS": "Antidote Potion ", "zhTW": "解毒藥水", "deDE": "Gegengiftelixier", "esES": "Poción antídoto", @@ -4745,7 +4745,7 @@ { "id": 2209, "Key": "rvs", - "enUS": " Rejuvenation Potion ", + "enUS": "Rejuvenation Potion ", "zhTW": "活力藥水", "deDE": "Regenerationstrank", "esES": "Poción rejuvenecedora", @@ -4762,7 +4762,7 @@ { "id": 2210, "Key": "rvl", - "enUS": " Full Rejuvenation Potion ", + "enUS": "Full Rejuvenation Potion ", "zhTW": "全效活力藥水", "deDE": "starker Regenerationstrank", "esES": "Poción rejuvenecedora total", @@ -4779,7 +4779,7 @@ { "id": 2211, "Key": "wms", - "enUS": " Thawing Potion ", + "enUS": "Thawing Potion ", "zhTW": "融冰藥水", "deDE": "Auftauelixier", "esES": "Poción descongelante", @@ -4796,7 +4796,7 @@ { "id": 2212, "Key": "amu", - "enUS": " Amulet ", + "enUS": "Amulet ", "zhTW": "護身符", "deDE": "[ns]Amulett", "esES": "[ms]Amuleto", @@ -4813,7 +4813,7 @@ { "id": 2213, "Key": "vip", - "enUS": " Top of the Horadric Staff ", + "enUS": "Top of the Horadric Staff ", "zhTW": "赫拉迪姆之杖的杖頂", "deDE": "Spitze des Horadrimstabes", "esES": "Empuñadura del bastón horádrico", @@ -4830,7 +4830,7 @@ { "id": 2214, "Key": "rin", - "enUS": " Ring ", + "enUS": "Ring ", "zhTW": "戒指", "deDE": "[ms]Ring", "esES": "[ms]Anillo", @@ -4847,7 +4847,7 @@ { "id": 2216, "Key": "bks", - "enUS": " Scroll of Inifuss ", + "enUS": "Scroll of Inifuss ", "zhTW": "艾尼弗斯卷軸", "deDE": "Inifussschriftrolle", "esES": "Pergamino de Inifuss", @@ -4864,7 +4864,7 @@ { "id": 2217, "Key": "bkd", - "enUS": " Key to the Cairn Stones ", + "enUS": "Key to the Cairn Stones ", "zhTW": "石陣之鑰", "deDE": "Schlüssel zu den Monolithen", "esES": "Llave de las piedras de Cairn", @@ -4881,7 +4881,7 @@ { "id": 2218, "Key": "aqv", - "enUS": " Arrows ", + "enUS": "Arrows ", "zhTW": "弓矢", "deDE": "Pfeile", "esES": "[fp]Flechas", @@ -4898,7 +4898,7 @@ { "id": 2219, "Key": "tch", - "enUS": " Torch ", + "enUS": "Torch ", "zhTW": "火炬", "deDE": "Fackel", "esES": "[fs]Antorcha", @@ -4915,7 +4915,7 @@ { "id": 2220, "Key": "cqv", - "enUS": " Bolts ", + "enUS": "Bolts ", "zhTW": "弩箭", "deDE": "Bolzen", "esES": "[fp]Saetas", @@ -4932,7 +4932,7 @@ { "id": 2221, "Key": "Key", - "enUS": " Key ", + "enUS": "Key ", "zhTW": "鑰匙", "deDE": "Schlüssel", "esES": "[fs]Llave", @@ -4949,7 +4949,7 @@ { "id": 2222, "Key": "key", - "enUS": " Key ", + "enUS": "Key ", "zhTW": "鑰匙", "deDE": "Schlüssel", "esES": "[fs]Llave", @@ -4966,7 +4966,7 @@ { "id": 2223, "Key": "luv", - "enUS": " The Black Tower Key ", + "enUS": "The Black Tower Key ", "zhTW": "黑塔之鑰", "deDE": "der Schlüssel des schwarzen Turmes", "esES": "Llave de la Torre Ennegrecida", @@ -4983,7 +4983,7 @@ { "id": 2227, "Key": "j34", - "enUS": " A Jade Figurine ", + "enUS": "A Jade Figurine ", "zhTW": "翠玉塑像", "deDE": "Jadefigur", "esES": "Una estatuilla de jade", @@ -5000,7 +5000,7 @@ { "id": 2228, "Key": "g34", - "enUS": " The Golden Bird ", + "enUS": "The Golden Bird ", "zhTW": "黃金鳥", "deDE": "der goldene Vogel", "esES": "Pájaro dorado", @@ -5017,7 +5017,7 @@ { "id": 2229, "Key": "bbb", - "enUS": " Lam Esen's Tome ", + "enUS": "Lam Esen's Tome ", "zhTW": "藍伊森之書", "deDE": "Lam Esens Foliant", "esES": "Tomo de Lam Esen", @@ -5034,7 +5034,7 @@ { "id": 2230, "Key": "LamTome", - "enUS": " Lam Esen's Tome ", + "enUS": "Lam Esen's Tome ", "zhTW": "藍伊森之書", "deDE": "Lam Esens Foliant", "esES": "Tomo de Lam Esen", @@ -5051,7 +5051,7 @@ { "id": 2231, "Key": "box", - "enUS": " Horadric Cube ", + "enUS": "Horadric Cube ", "zhTW": "赫拉迪姆方塊", "deDE": "Horadrimwürfel", "esES": "Cubo horádrico", @@ -5068,7 +5068,7 @@ { "id": 2232, "Key": "tr1", - "enUS": " Horadric Scroll ", + "enUS": "Horadric Scroll ", "zhTW": "赫拉迪姆卷軸", "deDE": "Horadrimschriftrolle", "esES": "Pergamino horádrico", @@ -5085,7 +5085,7 @@ { "id": 2233, "Key": "mss", - "enUS": " Mephisto's Soulstone ", + "enUS": "Mephisto's Soulstone ", "zhTW": "墨菲斯托的靈魂石", "deDE": "Mephistos Seelenstein", "esES": "Piedra de alma de Mefisto", @@ -5102,7 +5102,7 @@ { "id": 2235, "Key": "ear", - "enUS": " Ear ", + "enUS": "Ear ", "zhTW": "耳朵", "deDE": "Ohr", "esES": "[fs]Oreja", @@ -5119,7 +5119,7 @@ { "id": 2236, "Key": "gcv", - "enUS": " Chipped Amethyst ", + "enUS": "Chipped Amethyst ", "zhTW": "碎裂紫寶石", "deDE": "lädierter Amethyst", "esES": "Amatista fragmentada", @@ -5136,7 +5136,7 @@ { "id": 2237, "Key": "gfv", - "enUS": " Flawed Amethyst ", + "enUS": "Flawed Amethyst ", "zhTW": "瑕疵紫寶石", "deDE": "fehlerhafter Amethyst", "esES": "Amatista estropeada", @@ -5153,7 +5153,7 @@ { "id": 2238, "Key": "gsv", - "enUS": " Amethyst ", + "enUS": "Amethyst ", "zhTW": "紫寶石", "deDE": "Amethyst", "esES": "Amatista", @@ -5170,7 +5170,7 @@ { "id": 2239, "Key": "gzv", - "enUS": " Flawless Amethyst ", + "enUS": "Flawless Amethyst ", "zhTW": "無瑕紫寶石", "deDE": "makelloser Amethyst", "esES": "Amatista sin defectos", @@ -5187,7 +5187,7 @@ { "id": 2240, "Key": "gpv", - "enUS": " Perfect Amethyst ", + "enUS": "Perfect Amethyst ", "zhTW": "完美紫寶石", "deDE": "perfekter Amethyst", "esES": "Amatista perfecta", @@ -5204,7 +5204,7 @@ { "id": 2241, "Key": "gcy", - "enUS": " Chipped Topaz ", + "enUS": "Chipped Topaz ", "zhTW": "碎裂黃寶石", "deDE": "lädierter Topas", "esES": "Topacio fragmentado", @@ -5221,7 +5221,7 @@ { "id": 2242, "Key": "gfy", - "enUS": " Flawed Topaz ", + "enUS": "Flawed Topaz ", "zhTW": "瑕疵黃寶石", "deDE": "fehlerhafter Topas", "esES": "Topacio estropeado", @@ -5238,7 +5238,7 @@ { "id": 2243, "Key": "gsy", - "enUS": " Topaz ", + "enUS": "Topaz ", "zhTW": "黃寶石", "deDE": "Topas", "esES": "Topacio", @@ -5255,7 +5255,7 @@ { "id": 2244, "Key": "gly", - "enUS": " Flawless Topaz ", + "enUS": "Flawless Topaz ", "zhTW": "無瑕黃寶石", "deDE": "makelloser Topas", "esES": "Topacio sin defectos", @@ -5272,7 +5272,7 @@ { "id": 2245, "Key": "gpy", - "enUS": " Perfect Topaz ", + "enUS": "Perfect Topaz ", "zhTW": "完美黃寶石", "deDE": "perfekter Topas", "esES": "Topacio perfecto", @@ -5289,7 +5289,7 @@ { "id": 2246, "Key": "gcb", - "enUS": " Chipped Sapphire ", + "enUS": "Chipped Sapphire ", "zhTW": "碎裂藍寶石", "deDE": "lädierter Saphir", "esES": "Zafiro fragmentado", @@ -5306,7 +5306,7 @@ { "id": 2247, "Key": "gfb", - "enUS": " Flawed Sapphire ", + "enUS": "Flawed Sapphire ", "zhTW": "瑕疵藍寶石", "deDE": "fehlerhafter Saphir", "esES": "Zafiro estropeado", @@ -5323,7 +5323,7 @@ { "id": 2249, "Key": "glb", - "enUS": " Flawless Sapphire ", + "enUS": "Flawless Sapphire ", "zhTW": "無暇藍寶石", "deDE": "makelloser Saphir", "esES": "Zafiro sin defectos", @@ -5340,7 +5340,7 @@ { "id": 2250, "Key": "gpb", - "enUS": " Perfect Sapphire ", + "enUS": "Perfect Sapphire ", "zhTW": "完美藍寶石", "deDE": "perfekter Saphir", "esES": "Zafiro perfecto", @@ -5357,7 +5357,7 @@ { "id": 2251, "Key": "gcg", - "enUS": " Chipped Emerald ", + "enUS": "Chipped Emerald ", "zhTW": "碎裂綠寶石", "deDE": "lädierter Smaragd", "esES": "Esmeralda fragmentada", @@ -5374,7 +5374,7 @@ { "id": 2252, "Key": "gfg", - "enUS": " Flawed Emerald ", + "enUS": "Flawed Emerald ", "zhTW": "瑕疵綠寶石", "deDE": "fehlerhafter Smaragd", "esES": "Esmeralda estropeada", @@ -5391,7 +5391,7 @@ { "id": 2253, "Key": "glg", - "enUS": " Flawless Emerald ", + "enUS": "Flawless Emerald ", "zhTW": "無瑕綠寶石", "deDE": "makelloser Smaragd", "esES": "Esmeralda sin defectos", @@ -5408,7 +5408,7 @@ { "id": 2255, "Key": "gpg", - "enUS": " Perfect Emerald ", + "enUS": "Perfect Emerald ", "zhTW": "完美綠寶石", "deDE": "perfekter Smaragd", "esES": "Esmeralda perfecta", @@ -5425,7 +5425,7 @@ { "id": 2256, "Key": "gcr", - "enUS": " Chipped Ruby ", + "enUS": "Chipped Ruby ", "zhTW": "碎裂紅寶石", "deDE": "lädierter Rubin", "esES": "Rubí fragmentado", @@ -5442,7 +5442,7 @@ { "id": 2257, "Key": "gfr", - "enUS": " Flawed Ruby ", + "enUS": "Flawed Ruby ", "zhTW": "瑕疵紅寶石", "deDE": "fehlerhafter Rubin", "esES": "Rubí estropeado", @@ -5459,7 +5459,7 @@ { "id": 2259, "Key": "glr", - "enUS": " Flawless Ruby ", + "enUS": "Flawless Ruby ", "zhTW": "無瑕紅寶石", "deDE": "makelloser Rubin", "esES": "Rubí sin defectos", @@ -5476,7 +5476,7 @@ { "id": 2260, "Key": "gpr", - "enUS": " Perfect Ruby ", + "enUS": "Perfect Ruby ", "zhTW": "完美紅寶石", "deDE": "perfekter Rubin", "esES": "Rubí perfecto", @@ -5493,7 +5493,7 @@ { "id": 2261, "Key": "gcw", - "enUS": " Chipped Diamond ", + "enUS": "Chipped Diamond ", "zhTW": "碎裂鑽石", "deDE": "lädierter Diamant", "esES": "Diamante fragmentado", @@ -5510,7 +5510,7 @@ { "id": 2262, "Key": "gfw", - "enUS": " Flawed Diamond ", + "enUS": "Flawed Diamond ", "zhTW": "瑕疵鑽石", "deDE": "fehlerhafter Diamant", "esES": "Diamante estropeado", @@ -5527,7 +5527,7 @@ { "id": 2264, "Key": "glw", - "enUS": " Flawless Diamond ", + "enUS": "Flawless Diamond ", "zhTW": "無暇鑽石", "deDE": "makelloser Diamant", "esES": "Diamante sin defectos", @@ -5544,7 +5544,7 @@ { "id": 2265, "Key": "gpw", - "enUS": " Perfect Diamond ", + "enUS": "Perfect Diamond ", "zhTW": "完美鑽石", "deDE": "perfekter Diamant", "esES": "Diamante perfecto", @@ -5561,7 +5561,7 @@ { "id": 2266, "Key": "hp1", - "enUS": " Minor Healing Potion ", + "enUS": "Minor Healing Potion ", "zhTW": "弱效生命藥水", "deDE": "schwacher Heiltrank", "esES": "Poción de salud menor", @@ -5578,7 +5578,7 @@ { "id": 2267, "Key": "hp2", - "enUS": " Light Healing Potion ", + "enUS": "Light Healing Potion ", "zhTW": "輕效生命藥水", "deDE": "leichter Heiltrank", "esES": "Poción de salud ligera", @@ -5595,7 +5595,7 @@ { "id": 2268, "Key": "hp3", - "enUS": " Healing Potion ", + "enUS": "Healing Potion ", "zhTW": "生命藥水", "deDE": "Heiltrank", "esES": "Poción de salud", @@ -5612,7 +5612,7 @@ { "id": 2269, "Key": "hp4", - "enUS": " Greater Healing Potion ", + "enUS": "Greater Healing Potion ", "zhTW": "強效生命藥水", "deDE": "guter Heiltrank", "esES": "Poción de salud superior", @@ -5629,7 +5629,7 @@ { "id": 2270, "Key": "hp5", - "enUS": " Super Healing Potion ", + "enUS": "Super Healing Potion ", "zhTW": "特效生命藥水", "deDE": "starker Heiltrank", "esES": "Superpoción de salud", @@ -5646,7 +5646,7 @@ { "id": 2271, "Key": "mp1", - "enUS": " Minor Mana Potion ", + "enUS": "Minor Mana Potion ", "zhTW": "弱效法力藥水", "deDE": "schwacher Manatrank", "esES": "Poción de maná menor", @@ -5663,7 +5663,7 @@ { "id": 2272, "Key": "mp2", - "enUS": " Light Mana Potion ", + "enUS": "Light Mana Potion ", "zhTW": "輕效法力藥水", "deDE": "leichter Manatrank", "esES": "Poción de maná ligera", @@ -5680,7 +5680,7 @@ { "id": 2273, "Key": "mp3", - "enUS": " Mana Potion ", + "enUS": "Mana Potion ", "zhTW": "法力藥水", "deDE": "Manatrank", "esES": "Poción de maná", @@ -5697,7 +5697,7 @@ { "id": 2274, "Key": "mp4", - "enUS": " Greater Mana Potion ", + "enUS": "Greater Mana Potion ", "zhTW": "強效法力藥水", "deDE": "guter Manatrank", "esES": "Poción de maná superior", @@ -5714,7 +5714,7 @@ { "id": 2275, "Key": "mp5", - "enUS": " Super Mana Potion ", + "enUS": "Super Mana Potion ", "zhTW": "特效法力藥水", "deDE": "starker Manatrank", "esES": "Superpoción de maná", @@ -5731,7 +5731,7 @@ { "id": 2277, "Key": "skc", - "enUS": " Chipped Skull ", + "enUS": "Chipped Skull ", "zhTW": "碎裂骷髏石", "deDE": "lädierter Schädel", "esES": "Cráneo fragmentado", @@ -5748,7 +5748,7 @@ { "id": 2278, "Key": "skf", - "enUS": " Flawed Skull ", + "enUS": "Flawed Skull ", "zhTW": "瑕疵骷髏石", "deDE": "fehlerhafter Schädel", "esES": "Cráneo estropeado", @@ -5765,7 +5765,7 @@ { "id": 2279, "Key": "sku", - "enUS": " Skull ", + "enUS": "Skull ", "zhTW": "骷髏石", "deDE": "Schädel", "esES": "Cráneo", @@ -5782,7 +5782,7 @@ { "id": 2280, "Key": "skl", - "enUS": " Flawless Skull ", + "enUS": "Flawless Skull ", "zhTW": "無暇骷髏石", "deDE": "makelloser Schädel", "esES": "Cráneo sin defectos", @@ -5799,7 +5799,7 @@ { "id": 2281, "Key": "skz", - "enUS": " Perfect Skull ", + "enUS": "Perfect Skull ", "zhTW": "完美骷髏石", "deDE": "perfekter Schädel", "esES": "Cráneo perfecto", @@ -5816,7 +5816,7 @@ { "id": 2284, "Key": "Raven", - "enUS": " Raven ", + "enUS": "Raven", "zhTW": "掠鴉", "deDE": "Rabe", "esES": "[fs]del cuervo[ms]del cuervo[fp]del cuervo[mp]del cuervo", @@ -5833,7 +5833,7 @@ { "id": 2308, "Key": "Imp", - "enUS": " Imp ", + "enUS": "Imp", "zhTW": "小惡魔", "deDE": "der Kobolde", "esES": "de diablillo", @@ -5850,7 +5850,7 @@ { "id": 2317, "Key": "Holocaust", - "enUS": " Armageddon ", + "enUS": "Armageddon", "zhTW": "末世", "deDE": "von Armageddon", "esES": "de armagedón", @@ -5867,7 +5867,7 @@ { "id": 2334, "Key": "saw", - "enUS": " Saw ", + "enUS": "Saw ", "zhTW": "之鋸", "deDE": "Säge", "esES": "[fs]Sierra", @@ -5884,7 +5884,7 @@ { "id": 2379, "Key": "cry", - "enUS": " Cry ", + "enUS": "Cry ", "zhTW": "哭喊", "deDE": "Schrei", "esES": "[ms]Grito", @@ -5901,7 +5901,7 @@ { "id": 2384, "Key": "visage", - "enUS": " Visage ", + "enUS": "Visage ", "zhTW": "面容", "deDE": "Gesicht", "esES": "[ms]Semblante", @@ -5918,7 +5918,7 @@ { "id": 2385, "Key": "crest", - "enUS": " Crest ", + "enUS": "Crest ", "zhTW": "飾章", "deDE": "Kamm", "esES": "[fs]Cimera", @@ -5935,7 +5935,7 @@ { "id": 2386, "Key": "circlet", - "enUS": " Circlet ", + "enUS": "Circlet ", "zhTW": "飾環", "deDE": "Diadem", "esES": "[fs]Aureola", @@ -5952,7 +5952,7 @@ { "id": 2387, "Key": "veil", - "enUS": " Veil ", + "enUS": "Veil ", "zhTW": "面紗", "deDE": "Schleier", "esES": "[ms]Velo", @@ -5969,7 +5969,7 @@ { "id": 2388, "Key": "hood", - "enUS": " Hood ", + "enUS": "Hood ", "zhTW": "兜帽", "deDE": "Kapuze", "esES": "[fs]Capucha", @@ -5986,7 +5986,7 @@ { "id": 2389, "Key": "mask", - "enUS": " Mask ", + "enUS": "Mask ", "zhTW": "面具", "deDE": "Maske", "esES": "[fs]Máscara", @@ -6003,7 +6003,7 @@ { "id": 2390, "Key": "brow", - "enUS": " Brow ", + "enUS": "Brow ", "zhTW": "之額", "deDE": "Stirn", "esES": "[fs]Frente", @@ -6020,7 +6020,7 @@ { "id": 2391, "Key": "casque", - "enUS": " Casque ", + "enUS": "Casque ", "zhTW": "兜盔", "deDE": "Spitzhelm", "esES": "[ms]Morrión", @@ -6037,7 +6037,7 @@ { "id": 2392, "Key": "visor", - "enUS": " Visor ", + "enUS": "Visor ", "zhTW": "護面", "deDE": "Visier", "esES": "[fs]Visera", @@ -6054,7 +6054,7 @@ { "id": 2393, "Key": "cowl", - "enUS": " Cowl ", + "enUS": "Cowl ", "zhTW": "風帽", "deDE": "Kappe", "esES": "[ms]Capuchón", @@ -6071,7 +6071,7 @@ { "id": 2394, "Key": "hide", - "enUS": " Hide ", + "enUS": "Hide ", "zhTW": "毛皮", "deDE": "Leder", "esES": "[ms]Cuero", @@ -6088,7 +6088,7 @@ { "id": 2395, "Key": "Pelt", - "enUS": " Pelt ", + "enUS": "Pelt ", "zhTW": "獸皮", "deDE": "Fell", "esES": "[fs]Piel", @@ -6105,7 +6105,7 @@ { "id": 2396, "Key": "carapace", - "enUS": " Carapace ", + "enUS": "Carapace ", "zhTW": "甲殼", "deDE": "Hülle", "esES": "[ms]Caparazón", @@ -6122,7 +6122,7 @@ { "id": 2397, "Key": "coat", - "enUS": " Coat ", + "enUS": "Coat ", "zhTW": "外袍", "deDE": "Mantel", "esES": "[fs]Sobreveste", @@ -6139,7 +6139,7 @@ { "id": 2398, "Key": "wrap", - "enUS": " Wrap ", + "enUS": "Wrap ", "zhTW": "裹護", "deDE": "Umhang", "esES": "[ms]Cinto", @@ -6156,7 +6156,7 @@ { "id": 2399, "Key": "suit", - "enUS": " Suit ", + "enUS": "Suit ", "zhTW": "衣裝", "deDE": "Anzug", "esES": "[ms]Traje", @@ -6173,7 +6173,7 @@ { "id": 2400, "Key": "cloak", - "enUS": " Cloak ", + "enUS": "Cloak ", "zhTW": "斗蓬", "deDE": "Cape", "esES": "[fs]Capa", @@ -6190,7 +6190,7 @@ { "id": 2401, "Key": "shroud", - "enUS": " Shroud ", + "enUS": "Shroud ", "zhTW": "罩衣", "deDE": "Schleier", "esES": "[ms]Sudario", @@ -6207,7 +6207,7 @@ { "id": 2402, "Key": "jack", - "enUS": " Jack ", + "enUS": "Jack ", "zhTW": "水兵", "deDE": "Koller", "esES": "[ms]Justillo", @@ -6224,7 +6224,7 @@ { "id": 2403, "Key": "mantle", - "enUS": " Mantle ", + "enUS": "Mantle ", "zhTW": "披風", "deDE": "Überwurf", "esES": "[ms]Manto", @@ -6241,7 +6241,7 @@ { "id": 2404, "Key": "guard", - "enUS": " Guard ", + "enUS": "Guard ", "zhTW": "守衛", "deDE": "Wächter", "esES": "[fs]Protección", @@ -6258,7 +6258,7 @@ { "id": 2405, "Key": "badge", - "enUS": " Badge ", + "enUS": "Badge ", "zhTW": "徽章", "deDE": "Abzeichen", "esES": "[fs]Insignia", @@ -6275,7 +6275,7 @@ { "id": 2406, "Key": "rock", - "enUS": " Rock ", + "enUS": "Rock ", "zhTW": "之岩", "deDE": "Felsen", "esES": "[ms]Peñasco", @@ -6292,7 +6292,7 @@ { "id": 2407, "Key": "aegis", - "enUS": " Aegis ", + "enUS": "Aegis ", "zhTW": "之禦", "deDE": "Ägis", "esES": "[fs]Égida", @@ -6309,7 +6309,7 @@ { "id": 2408, "Key": "ward", - "enUS": " Ward ", + "enUS": "Ward ", "zhTW": "守護", "deDE": "Schutz", "esES": "[fs]Custodia", @@ -6326,7 +6326,7 @@ { "id": 2409, "Key": "tower", - "enUS": " Tower ", + "enUS": "Tower ", "zhTW": "之塔", "deDE": "Turm", "esES": "[fs]Tarja", @@ -6343,7 +6343,7 @@ { "id": 2410, "Key": "shield", - "enUS": " Shield ", + "enUS": "Shield ", "zhTW": "之盾", "deDE": "Schild", "esES": "[ms]Escudo", @@ -6360,7 +6360,7 @@ { "id": 2411, "Key": "wing", - "enUS": " Wing ", + "enUS": "Wing ", "zhTW": "之翼", "deDE": "Flügel", "esES": "[fs]Ala", @@ -6377,7 +6377,7 @@ { "id": 2412, "Key": "mark", - "enUS": " Mark ", + "enUS": "Mark ", "zhTW": "標記", "deDE": "Zeichen", "esES": "[fs]Marca", @@ -6394,7 +6394,7 @@ { "id": 2413, "Key": "emblem", - "enUS": " Emblem ", + "enUS": "Emblem ", "zhTW": "紋章", "deDE": "Emblem", "esES": "[ms]Emblema", @@ -6411,7 +6411,7 @@ { "id": 2414, "Key": "hand", - "enUS": " Hand ", + "enUS": "Hand ", "zhTW": "手", "deDE": "Hand", "esES": "[fs]Mano", @@ -6428,7 +6428,7 @@ { "id": 2415, "Key": "fist", - "enUS": " Fist ", + "enUS": "Fist ", "zhTW": "之拳", "deDE": "Faust", "esES": "[ms]Puño", @@ -6445,7 +6445,7 @@ { "id": 2416, "Key": "claw", - "enUS": " Claw ", + "enUS": "Claw ", "zhTW": "爪", "deDE": "Klaue", "esES": "[fs]Garra", @@ -6462,7 +6462,7 @@ { "id": 2417, "Key": "clutches", - "enUS": " Clutches ", + "enUS": "Clutches ", "zhTW": "之握", "deDE": "Klauen", "esES": "[fp]Zarpas", @@ -6479,7 +6479,7 @@ { "id": 2418, "Key": "grip", - "enUS": " Grip ", + "enUS": "Grip ", "zhTW": "抓握", "deDE": "Griff", "esES": "[ms]Apretón", @@ -6496,7 +6496,7 @@ { "id": 2419, "Key": "grasp", - "enUS": " Grasp ", + "enUS": "Grasp ", "zhTW": "之握", "deDE": "Greifer", "esES": "[ms]Control", @@ -6513,7 +6513,7 @@ { "id": 2420, "Key": "hold", - "enUS": " Hold ", + "enUS": "Hold ", "zhTW": "之握", "deDE": "Halt", "esES": "[ms]Agarre", @@ -6530,7 +6530,7 @@ { "id": 2421, "Key": "touch", - "enUS": " Touch ", + "enUS": "Touch ", "zhTW": "之觸", "deDE": "Berührung", "esES": "[ms]Tacto", @@ -6547,7 +6547,7 @@ { "id": 2422, "Key": "finger", - "enUS": " Finger ", + "enUS": "Finger ", "zhTW": "手指", "deDE": "Finger", "esES": "[ms]Dedo", @@ -6564,7 +6564,7 @@ { "id": 2423, "Key": "knuckle", - "enUS": " Knuckle ", + "enUS": "Knuckle ", "zhTW": "指節", "deDE": "Knöchel", "esES": "[ms]Nudillo", @@ -6581,7 +6581,7 @@ { "id": 2424, "Key": "shank", - "enUS": " Shank ", + "enUS": "Shank ", "zhTW": "尖鑽", "deDE": "Schenkel", "esES": "[fs]Espinilla", @@ -6598,7 +6598,7 @@ { "id": 2425, "Key": "spur", - "enUS": " Spur ", + "enUS": "Spur ", "zhTW": "驅刺", "deDE": "Sporen", "esES": "[fs]Espuela", @@ -6615,7 +6615,7 @@ { "id": 2426, "Key": "tread", - "enUS": " Tread ", + "enUS": "Tread ", "zhTW": "步履", "deDE": "Schritt", "esES": "[fs]Huella", @@ -6632,7 +6632,7 @@ { "id": 2427, "Key": "stalker", - "enUS": " Stalker ", + "enUS": "Stalker ", "zhTW": "潛獵者", "deDE": "Schleicher", "esES": "[fs]Zanca", @@ -6649,7 +6649,7 @@ { "id": 2428, "Key": "greave", - "enUS": " Greaves ", + "enUS": "Greaves ", "zhTW": "護脛", "deDE": "Beinschienen", "esES": "[fp]Grebas", @@ -6666,7 +6666,7 @@ { "id": 2429, "Key": "blazer", - "enUS": " Blazer ", + "enUS": "Blazer ", "zhTW": "炎光", "deDE": "Fährte", "esES": "[fs]Pionera", @@ -6683,7 +6683,7 @@ { "id": 2430, "Key": "nails", - "enUS": " Nails ", + "enUS": "Nails ", "zhTW": "尖釘", "deDE": "Nägel", "esES": "[fp]Uñas", @@ -6700,7 +6700,7 @@ { "id": 2431, "Key": "trample", - "enUS": " Trample ", + "enUS": "Trample ", "zhTW": "蹂躪", "deDE": "Pfad", "esES": "[ms]Pisoteo", @@ -6717,7 +6717,7 @@ { "id": 2432, "Key": "Brogues", - "enUS": " Brogues ", + "enUS": "Brogues ", "zhTW": "粗皮鞋", "deDE": "Schnürschuhe", "esES": "[mp]Botines", @@ -6734,7 +6734,7 @@ { "id": 2433, "Key": "track", - "enUS": " Track ", + "enUS": "Track ", "zhTW": "蹤跡", "deDE": "Weg", "esES": "[ms]Rastro", @@ -6751,7 +6751,7 @@ { "id": 2434, "Key": "slippers", - "enUS": " Slippers ", + "enUS": "Slippers ", "zhTW": "便鞋", "deDE": "Schlupf", "esES": "[fp]Zapatillas", @@ -6768,7 +6768,7 @@ { "id": 2435, "Key": "clasp", - "enUS": " Clasp ", + "enUS": "Clasp ", "zhTW": "之扣", "deDE": "Schnalle", "esES": "[ms]Broche", @@ -6785,7 +6785,7 @@ { "id": 2436, "Key": "buckle", - "enUS": " Buckle ", + "enUS": "Buckle ", "zhTW": "釦帶", "deDE": "Spange", "esES": "[fs]Hebilla", @@ -6802,7 +6802,7 @@ { "id": 2437, "Key": "harness", - "enUS": " Harness ", + "enUS": "Harness ", "zhTW": "裝束", "deDE": "Harnisch", "esES": "[ms]Arnés", @@ -6819,7 +6819,7 @@ { "id": 2438, "Key": "lock", - "enUS": " Lock ", + "enUS": "Lock ", "zhTW": "鎖扣", "deDE": "Schloss", "esES": "[ms]Cierre", @@ -6836,7 +6836,7 @@ { "id": 2439, "Key": "fringe", - "enUS": " Fringe ", + "enUS": "Fringe ", "zhTW": "邊飾", "deDE": "Fransen", "esES": "[ms]Ribete", @@ -6853,7 +6853,7 @@ { "id": 2440, "Key": "winding", - "enUS": " Winding ", + "enUS": "Winding ", "zhTW": "繞捲", "deDE": "Umschlingung", "esES": "[fs]Lazada", @@ -6870,7 +6870,7 @@ { "id": 2441, "Key": "chain", - "enUS": " Chain ", + "enUS": "Chain ", "zhTW": "之鏈", "deDE": "Kette", "esES": "[fs]Cadena", @@ -6887,7 +6887,7 @@ { "id": 2443, "Key": "lash", - "enUS": " Lash ", + "enUS": "Lash ", "zhTW": "鞭笞", "deDE": "Riemen", "esES": "[ms]Látigo", @@ -6904,7 +6904,7 @@ { "id": 2444, "Key": "cord", - "enUS": " Cord ", + "enUS": "Cord ", "zhTW": "捆繩", "deDE": "Band", "esES": "[ms]Cordón", @@ -6921,7 +6921,7 @@ { "id": 2445, "Key": "knot", - "enUS": " Knot ", + "enUS": "Knot ", "zhTW": "之結", "deDE": "Knoten", "esES": "[ms]Nudo", @@ -6938,7 +6938,7 @@ { "id": 2446, "Key": "circle", - "enUS": " Circle ", + "enUS": "Circle ", "zhTW": "之環", "deDE": "Kreis", "esES": "[ms]Círculo", @@ -6955,7 +6955,7 @@ { "id": 2447, "Key": "loop", - "enUS": " Loop ", + "enUS": "Loop ", "zhTW": "之圈", "deDE": "Schleife", "esES": "[ms]Aro", @@ -6972,7 +6972,7 @@ { "id": 2448, "Key": "eye", - "enUS": " Eye ", + "enUS": "Eye ", "zhTW": "之眼", "deDE": "Auge", "esES": "[ms]Ojo", @@ -6989,7 +6989,7 @@ { "id": 2449, "Key": "turn", - "enUS": " Turn ", + "enUS": "Turn ", "zhTW": "轉迴", "deDE": "Dreh", "esES": "[fs]Vuelta", @@ -7006,7 +7006,7 @@ { "id": 2450, "Key": "spiral", - "enUS": " Spiral ", + "enUS": "Spiral ", "zhTW": "螺旋", "deDE": "Spirale", "esES": "[fs]Espiral", @@ -7023,7 +7023,7 @@ { "id": 2451, "Key": "coil", - "enUS": " Coil ", + "enUS": "Coil ", "zhTW": "盤繞", "deDE": "Rolle", "esES": "[fs]Rosca", @@ -7040,7 +7040,7 @@ { "id": 2452, "Key": "gyre", - "enUS": " Gyre ", + "enUS": "Gyre ", "zhTW": "旋迴", "deDE": "Windung", "esES": "[ms]Remolino", @@ -7057,7 +7057,7 @@ { "id": 2453, "Key": "band", - "enUS": " Band ", + "enUS": "Band ", "zhTW": "之箍", "deDE": "Band", "esES": "[fs]Sortija", @@ -7074,7 +7074,7 @@ { "id": 2454, "Key": "whorl", - "enUS": " Whorl ", + "enUS": "Whorl ", "zhTW": "旋螺", "deDE": "Spindel", "esES": "[fs]Espira", @@ -7091,7 +7091,7 @@ { "id": 2455, "Key": "talisman", - "enUS": " Talisman ", + "enUS": "Talisman ", "zhTW": "護符", "deDE": "Talisman", "esES": "[ms]Talismán", @@ -7108,7 +7108,7 @@ { "id": 2456, "Key": "heart", - "enUS": " Heart ", + "enUS": "Heart ", "zhTW": "之心", "deDE": "Herz", "esES": "[ms]Corazón", @@ -7125,7 +7125,7 @@ { "id": 2457, "Key": "noose", - "enUS": " Noose ", + "enUS": "Noose ", "zhTW": "套索", "deDE": "Schlinge", "esES": "[ms]Dogal", @@ -7142,7 +7142,7 @@ { "id": 2458, "Key": "necklace", - "enUS": " Necklace ", + "enUS": "Necklace ", "zhTW": "項鍊", "deDE": "Halskette", "esES": "[ms]Collar", @@ -7159,7 +7159,7 @@ { "id": 2459, "Key": "collar", - "enUS": " Collar ", + "enUS": "Collar ", "zhTW": "項圈", "deDE": "Kragen", "esES": "[fs]Gargantilla", @@ -7176,7 +7176,7 @@ { "id": 2460, "Key": "beads", - "enUS": " Beads ", + "enUS": "Beads ", "zhTW": "串珠", "deDE": "Perlen", "esES": "[fp]Cuentas", @@ -7193,7 +7193,7 @@ { "id": 2461, "Key": "torc", - "enUS": " Torc ", + "enUS": "Torc ", "zhTW": "頸飾", "deDE": "Armreif", "esES": "[ms]Torque", @@ -7210,7 +7210,7 @@ { "id": 2462, "Key": "gorget", - "enUS": " Gorget ", + "enUS": "Gorget ", "zhTW": "頸甲", "deDE": "Halsband", "esES": "[fs]Gorguera", @@ -7227,7 +7227,7 @@ { "id": 2464, "Key": "wood", - "enUS": " Wood ", + "enUS": "Wood ", "zhTW": "之木", "deDE": "Holz", "esES": "[fs]Madera", @@ -7244,7 +7244,7 @@ { "id": 2465, "Key": "brand", - "enUS": " Brand ", + "enUS": "Brand ", "zhTW": "烙印", "deDE": "Brand", "esES": "[ms]Tizón", @@ -7261,7 +7261,7 @@ { "id": 2466, "Key": "bludgeon", - "enUS": " Bludgeon ", + "enUS": "Bludgeon ", "zhTW": "棍棒", "deDE": "Prügel", "esES": "[fs]Cachiporra", @@ -7278,7 +7278,7 @@ { "id": 2467, "Key": "cudgel", - "enUS": " Cudgel ", + "enUS": "Cudgel ", "zhTW": "鬥棍", "deDE": "Knüttel", "esES": "[ms]Garrote", @@ -7295,7 +7295,7 @@ { "id": 2468, "Key": "loom", - "enUS": " Loom ", + "enUS": "Loom ", "zhTW": "隱現", "deDE": "Sehne", "esES": "[ms]Telar", @@ -7312,7 +7312,7 @@ { "id": 2469, "Key": "harp", - "enUS": " Harp ", + "enUS": "Harp ", "zhTW": "豎琴", "deDE": "Harfe", "esES": "[fs]Arpa", @@ -7329,7 +7329,7 @@ { "id": 2470, "Key": "master", - "enUS": " Master ", + "enUS": "Master ", "zhTW": "主宰", "deDE": "Meister", "esES": "[ms]Señor", @@ -7346,7 +7346,7 @@ { "id": 2471, "Key": "barRI", - "enUS": " Bar ", + "enUS": "Bar ", "zhTW": "柵欄", "deDE": "Stange", "esES": "[fs]Barra", @@ -7363,7 +7363,7 @@ { "id": 2472, "Key": "hew", - "enUS": " Hew ", + "enUS": "Hew ", "zhTW": "劈斬", "deDE": "Hauer", "esES": "[fs]Talla", @@ -7380,7 +7380,7 @@ { "id": 2473, "Key": "crook", - "enUS": " Crook ", + "enUS": "Crook ", "zhTW": "彎鉤", "deDE": "Haken", "esES": "[ms]Báculo", @@ -7397,7 +7397,7 @@ { "id": 2474, "Key": "mar", - "enUS": " Mar ", + "enUS": "Mar ", "zhTW": "毀損", "deDE": "Schänder", "esES": "[fs]Ruina", @@ -7414,7 +7414,7 @@ { "id": 2475, "Key": "shell", - "enUS": " Shell ", + "enUS": "Shell ", "zhTW": "殼甲", "deDE": "Schale", "esES": "[fs]Concha", @@ -7431,7 +7431,7 @@ { "id": 2476, "Key": "stake", - "enUS": " Stake ", + "enUS": "Stake ", "zhTW": "樁棍", "deDE": "Pfahl", "esES": "[fs]Estaca", @@ -7448,7 +7448,7 @@ { "id": 2477, "Key": "picket", - "enUS": " Picket ", + "enUS": "Picket ", "zhTW": "尖樁", "deDE": "Latte", "esES": "[ms]Piquete", @@ -7465,7 +7465,7 @@ { "id": 2478, "Key": "pale", - "enUS": " Pale ", + "enUS": "Pale ", "zhTW": "蒼白", "deDE": "Pfosten", "esES": "[fs]Rama", @@ -7482,7 +7482,7 @@ { "id": 2479, "Key": "flange", - "enUS": " Flange ", + "enUS": "Flange ", "zhTW": "凸緣", "deDE": "Rand", "esES": "[ms]Remate", @@ -7499,7 +7499,7 @@ { "id": 2480, "Key": "Civerb's Vestments", - "enUS": " Civerb's Vestments ", + "enUS": "Civerb's Vestments ", "zhTW": "克維雷布的法衣", "deDE": "Civerbs Trachten", "esES": "Vestimentas de Civerb", @@ -7516,7 +7516,7 @@ { "id": 2481, "Key": "Hsarus' Trim", - "enUS": " Hsaru's Defense ", + "enUS": "Hsaru's Defense ", "zhTW": "海沙魯的鐵禦", "deDE": "Hsarus Verteidigung", "esES": "Defensa de Hsarus", @@ -7533,7 +7533,7 @@ { "id": 2482, "Key": "Cleglaw's Brace", - "enUS": " Cleglaw's Brace ", + "enUS": "Cleglaw's Brace ", "zhTW": "克雷德勞的防備", "deDE": "Cleglaws Armschmuck", "esES": "Refuerzo de Cleglaw", @@ -7550,7 +7550,7 @@ { "id": 2483, "Key": "Iratha's Finery", - "enUS": " Iratha's Finery ", + "enUS": "Iratha's Finery ", "zhTW": "依雷撒的華服", "deDE": "Irathas Putzmacherei", "esES": "Galas de Iratha", @@ -7567,7 +7567,7 @@ { "id": 2484, "Key": "Isenhart's Armory", - "enUS": " Isenhart's Armory ", + "enUS": "Isenhart's Armory ", "zhTW": "依森哈特的軍械", "deDE": "Isenharts Waffen", "esES": "Armamento de Isenhart", @@ -7584,7 +7584,7 @@ { "id": 2485, "Key": "Vidala's Rig", - "enUS": " Vidala's Rig ", + "enUS": "Vidala's Rig ", "zhTW": "維達拉的配備", "deDE": "Vidalas Ausrüstung", "esES": "Equipo de Vidala", @@ -7601,7 +7601,7 @@ { "id": 2486, "Key": "Milabrega's Regalia", - "enUS": " Milabrega's Regalia ", + "enUS": "Milabrega's Regalia ", "zhTW": "米拉伯佳戰裝", "deDE": "Milebregas Sonntagsstaat", "esES": "Insignias de Milabrega", @@ -7618,7 +7618,7 @@ { "id": 2487, "Key": "Cathan's Traps", - "enUS": " Cathan's Traps ", + "enUS": "Cathan's Traps ", "zhTW": "卡珊的衣著", "deDE": "Cathans Fallen", "esES": "Trampas de Cathan", @@ -7635,7 +7635,7 @@ { "id": 2488, "Key": "Tancred's Battlegear", - "enUS": " Tancred's Battlegear ", + "enUS": "Tancred's Battlegear ", "zhTW": "坦克雷的戰裝", "deDE": "Tankreds Kampfausrüstung", "esES": "Equipo de batalla de Tancred", @@ -7652,7 +7652,7 @@ { "id": 2489, "Key": "Sigon's Complete Steel", - "enUS": " Sigon's Complete Steel ", + "enUS": "Sigon's Complete Steel ", "zhTW": "西剛的全套鋼甲", "deDE": "Signons Stahl total", "esES": "Acero completo de Sigon", @@ -7669,7 +7669,7 @@ { "id": 2490, "Key": "Infernal Tools", - "enUS": " Infernal Tools ", + "enUS": "Infernal Tools ", "zhTW": "煉獄器具", "deDE": "Infernos Werkzeuge", "esES": "Herramientas infernales", @@ -7686,7 +7686,7 @@ { "id": 2491, "Key": "Berserker's Garb", - "enUS": " Berserker's Arsenal ", + "enUS": "Berserker's Arsenal ", "zhTW": "狂戰士的武裝", "deDE": "Berserkerarsenal", "esES": "Arsenal del berserker", @@ -7703,7 +7703,7 @@ { "id": 2492, "Key": "Death's Disguise", - "enUS": " Death's Disguise ", + "enUS": "Death's Disguise ", "zhTW": "死亡的偽裝", "deDE": "Tod und Teufel", "esES": "Disfraz de la muerte", @@ -7720,7 +7720,7 @@ { "id": 2493, "Key": "Angelical Raiment", - "enUS": " Angelic Raiment ", + "enUS": "Angelic Raiment ", "zhTW": "天使的衣裝", "deDE": "Himmlische Hüllen", "esES": "Atuendo angelical", @@ -7737,7 +7737,7 @@ { "id": 2494, "Key": "Arctic Gear", - "enUS": " Arctic Gear ", + "enUS": "Arctic Gear ", "zhTW": "北極裝備", "deDE": "Arktisausrüstung", "esES": "Equipo ártico", @@ -7754,7 +7754,7 @@ { "id": 2495, "Key": "Arcanna's Tricks", - "enUS": " Arcanna's Tricks ", + "enUS": "Arcanna's Tricks ", "zhTW": "阿卡娜的詭計", "deDE": "Arcannas Tricks", "esES": "Trucos de Arcanna", @@ -7771,7 +7771,7 @@ { "id": 2512, "Key": "Ward", - "enUS": " Ward ", + "enUS": "Ward ", "zhTW": "防護", "deDE": "Schutz", "esES": "[fs]Custodia", @@ -7788,7 +7788,7 @@ { "id": 2513, "Key": "Iron Heel", - "enUS": " Iron Heel ", + "enUS": "Iron Heel ", "zhTW": "鐵跟", "deDE": "Eisenferse", "esES": "[ms]Talón de hierro", @@ -7805,7 +7805,7 @@ { "id": 2514, "Key": "Tooth", - "enUS": " Tooth ", + "enUS": "Tooth ", "zhTW": "之牙", "deDE": "Zahn", "esES": "[ms]Diente", @@ -7822,7 +7822,7 @@ { "id": 2515, "Key": "Collar", - "enUS": " Collar ", + "enUS": "Collar ", "zhTW": "項圈", "deDE": "Kragen", "esES": "[fs]Gargantilla", @@ -7839,7 +7839,7 @@ { "id": 2516, "Key": "Lightbrand", - "enUS": " Lightbrand ", + "enUS": "Lightbrand ", "zhTW": "光之烙鐵", "deDE": "Lichtbrand", "esES": "[ms]Tizón de luz", @@ -7856,7 +7856,7 @@ { "id": 2517, "Key": "Barb", - "enUS": " Barb ", + "enUS": "Barb ", "zhTW": "倒刺", "deDE": "Dorn", "esES": "[fs]Púa", @@ -7873,7 +7873,7 @@ { "id": 2518, "Key": "Orb", - "enUS": " Orb ", + "enUS": "Orb ", "zhTW": "之球", "deDE": "Kugel", "esES": "Orbe", @@ -7890,7 +7890,7 @@ { "id": 2519, "Key": "Rule", - "enUS": " Rule ", + "enUS": "Rule", "zhTW": "尺杖", "deDE": "Regel", "esES": "[ms]Mando", @@ -7907,7 +7907,7 @@ { "id": 2520, "Key": "Crowbill", - "enUS": " Crowbill ", + "enUS": "Crowbill ", "zhTW": "鴉嘴鎬", "deDE": "Bogenpicke", "esES": "[ms]Pico de cuervo", @@ -7924,7 +7924,7 @@ { "id": 2521, "Key": "Visor", - "enUS": " Visor ", + "enUS": "Visor ", "zhTW": "護面", "deDE": "Visier", "esES": "[fs]Visera", @@ -7941,7 +7941,7 @@ { "id": 2522, "Key": "Cranium", - "enUS": " Cranium ", + "enUS": "Cranium ", "zhTW": "頭骨", "deDE": "Schädel", "esES": "[fs]Calavera", @@ -7958,7 +7958,7 @@ { "id": 2523, "Key": "Headgear", - "enUS": " Headgear ", + "enUS": "Headgear ", "zhTW": "頭盔", "deDE": "Kopfbedeckung", "esES": "[ms]Casco", @@ -7975,7 +7975,7 @@ { "id": 2524, "Key": "Hand", - "enUS": " Hand ", + "enUS": "Hand ", "zhTW": "之手", "deDE": "Hand", "esES": "[fs]Mano", @@ -7992,7 +7992,7 @@ { "id": 2525, "Key": "Sickle", - "enUS": " Sickle ", + "enUS": "Sickle ", "zhTW": "鐮刀", "deDE": "Sichel", "esES": "[fs]Hoz", @@ -8009,7 +8009,7 @@ { "id": 2526, "Key": "Horn", - "enUS": " Horn ", + "enUS": "Horn ", "zhTW": "號角", "deDE": "Horn", "esES": "[ms]Cuerno", @@ -8026,7 +8026,7 @@ { "id": 2527, "Key": "Sign", - "enUS": " Sign ", + "enUS": "Sign ", "zhTW": "符印", "deDE": "Schild", "esES": "[ms]Símbolo", @@ -8043,7 +8043,7 @@ { "id": 2528, "Key": "Icon", - "enUS": " Icon ", + "enUS": "Icon ", "zhTW": "聖像", "deDE": "Bild", "esES": "Icono", @@ -8060,7 +8060,7 @@ { "id": 2529, "Key": "Iron Fist", - "enUS": " Iron Fist ", + "enUS": "Iron Fist ", "zhTW": "鐵拳", "deDE": "Eisenfaust", "esES": "[ms]Puño de hierro", @@ -8077,7 +8077,7 @@ { "id": 2530, "Key": "Claw", - "enUS": " Claw ", + "enUS": "Claw ", "zhTW": "爪", "deDE": "Klaue", "esES": "[fs]Garra", @@ -8094,7 +8094,7 @@ { "id": 2531, "Key": "Cuff", - "enUS": " Cuff ", + "enUS": "Cuff ", "zhTW": "袖銬", "deDE": "Ärmelaufschläge", "esES": "[fp]Esposas", @@ -8111,7 +8111,7 @@ { "id": 2532, "Key": "Parry", - "enUS": " Parry ", + "enUS": "Parry ", "zhTW": "招架", "deDE": "Parade", "esES": "[fs]Evasión", @@ -8128,7 +8128,7 @@ { "id": 2533, "Key": "Fetlock", - "enUS": " Fetlock ", + "enUS": "Fetlock ", "zhTW": "足距", "deDE": "Pferdedecke", "esES": "[ms]Espolón", @@ -8145,7 +8145,7 @@ { "id": 2534, "Key": "Rod", - "enUS": " Rod ", + "enUS": "Rod ", "zhTW": "節杖", "deDE": "Angel", "esES": "[fs]Vara", @@ -8162,7 +8162,7 @@ { "id": 2535, "Key": "Mesh", - "enUS": " Mesh ", + "enUS": "Mesh ", "zhTW": "網衣", "deDE": "Netz", "esES": "[fs]Malla", @@ -8179,7 +8179,7 @@ { "id": 2536, "Key": "Spine", - "enUS": " Spine ", + "enUS": "Spine ", "zhTW": "脊柱", "deDE": "Stachel", "esES": "[ms]Espinazo", @@ -8196,7 +8196,7 @@ { "id": 2537, "Key": "Shelter", - "enUS": " Shelter ", + "enUS": "Shelter ", "zhTW": "庇護", "deDE": "Schutz", "esES": "[ms]Refugio", @@ -8213,7 +8213,7 @@ { "id": 2538, "Key": "Torch", - "enUS": " Torch ", + "enUS": "Torch ", "zhTW": "火炬", "deDE": "Fackel", "esES": "[fs]Antorcha", @@ -8230,7 +8230,7 @@ { "id": 2539, "Key": "Hauberk", - "enUS": " Hauberk ", + "enUS": "Hauberk ", "zhTW": "鎖子甲", "deDE": "Halsberge", "esES": "[fs]Loriga", @@ -8247,7 +8247,7 @@ { "id": 2540, "Key": "Guard", - "enUS": " Guard ", + "enUS": "Guard ", "zhTW": "護", "deDE": "Wächter", "esES": "Protección", @@ -8264,7 +8264,7 @@ { "id": 2541, "Key": "Mantle", - "enUS": " Mantle ", + "enUS": "Mantle ", "zhTW": "披風", "deDE": "Überwurf", "esES": "[ms]Manto", @@ -8281,7 +8281,7 @@ { "id": 2542, "Key": "Furs", - "enUS": " Furs ", + "enUS": "Furs ", "zhTW": "毛皮", "deDE": "Pelze", "esES": "[fp]Pieles", @@ -8298,7 +8298,7 @@ { "id": 2543, "Key": "Deathwand", - "enUS": " Deathwand ", + "enUS": "Deathwand ", "zhTW": "死亡之杖", "deDE": "Todesstab", "esES": "[fs]Vara de la muerte", @@ -8315,7 +8315,7 @@ { "id": 2544, "Key": "CudgelSI3S", - "enUS": " Cudgel ", + "enUS": "Cudgel ", "zhTW": "短棍", "deDE": "Knüttel", "esES": "[ms]Garrote", @@ -8332,7 +8332,7 @@ { "id": 2545, "Key": "Iron Stay", - "enUS": " Iron Stay ", + "enUS": "Iron Stay ", "zhTW": "鐵扣", "deDE": "Eisenstütze", "esES": "[ms]Cinturón de hierro", @@ -8349,7 +8349,7 @@ { "id": 2546, "Key": "Pincers", - "enUS": " Pincers ", + "enUS": "Pincers ", "zhTW": "之鉗", "deDE": "Kneifzange", "esES": "[fp]Pinzas", @@ -8366,7 +8366,7 @@ { "id": 2547, "Key": "Coil", - "enUS": " Coil ", + "enUS": "Coil ", "zhTW": "盤頂", "deDE": "Rolle", "esES": "[fs]Rosca", @@ -8383,7 +8383,7 @@ { "id": 2548, "Key": "Case", - "enUS": " Case ", + "enUS": "Case ", "zhTW": "外殼", "deDE": "Kiste", "esES": "[fs]Funda", @@ -8400,7 +8400,7 @@ { "id": 2549, "Key": "Ambush", - "enUS": " Ambush ", + "enUS": "Ambush ", "zhTW": "突擊", "deDE": "Hinterhalt", "esES": "[fs]Emboscada", @@ -8417,7 +8417,7 @@ { "id": 2550, "Key": "Diadem", - "enUS": " Diadem ", + "enUS": "Diadem ", "zhTW": "權冠", "deDE": "Diadem", "esES": "[fs]Diadema", @@ -8434,7 +8434,7 @@ { "id": 2551, "Key": "Visage", - "enUS": " Visage ", + "enUS": "Visage ", "zhTW": "容貌", "deDE": "Gesicht", "esES": "[ms]Semblante", @@ -8451,7 +8451,7 @@ { "id": 2552, "Key": "Hobnails", - "enUS": " Hobnails ", + "enUS": "Hobnails ", "zhTW": "釘靴", "deDE": "Schuhnägel", "esES": "[fp]Tachuelas", @@ -8468,7 +8468,7 @@ { "id": 2553, "Key": "Gage", - "enUS": " Gage ", + "enUS": "Gage ", "zhTW": "挑戰", "deDE": "Maß", "esES": "[ms]Reto", @@ -8485,7 +8485,7 @@ { "id": 2554, "Key": "SignSI3S", - "enUS": " Buckle ", + "enUS": "Buckle ", "zhTW": "扣帶", "deDE": "Spange", "esES": "[fs]Hebilla", @@ -8502,7 +8502,7 @@ { "id": 2555, "Key": "Hatchet", - "enUS": " Hatchet ", + "enUS": "Hatchet ", "zhTW": "手斧", "deDE": "Kriegsbeil", "esES": "[fs]Hachuela", @@ -8519,7 +8519,7 @@ { "id": 2556, "Key": "Touch", - "enUS": " Touch ", + "enUS": "Touch ", "zhTW": "觸", "deDE": "Berührung", "esES": "[ms]Tacto", @@ -8536,7 +8536,7 @@ { "id": 2557, "Key": "Halo", - "enUS": " Halo ", + "enUS": "Halo ", "zhTW": "光暈", "deDE": "Heiligenschein", "esES": "[ms]Halo", @@ -8553,7 +8553,7 @@ { "id": 2558, "Key": "Binding", - "enUS": " Binding ", + "enUS": "Binding ", "zhTW": "捆索", "deDE": "Bindung", "esES": "Correa", @@ -8570,7 +8570,7 @@ { "id": 2559, "Key": "Head", - "enUS": " Head ", + "enUS": "Head ", "zhTW": "頭", "deDE": "Kopf", "esES": "Cabeza", @@ -8587,7 +8587,7 @@ { "id": 2560, "Key": "Horns", - "enUS": " Horns ", + "enUS": "Horns ", "zhTW": "角盔", "deDE": "Hörner", "esES": "[mp]Cuernos", @@ -8604,7 +8604,7 @@ { "id": 2561, "Key": "Snare", - "enUS": " Snare ", + "enUS": "Snare ", "zhTW": "圈套", "deDE": "Schlinge", "esES": "[ms]Cepo", @@ -8621,7 +8621,7 @@ { "id": 2562, "Key": "Robe", - "enUS": " Robe ", + "enUS": "Robe ", "zhTW": "外袍", "deDE": "Robe", "esES": "[fs]Toga", @@ -8638,7 +8638,7 @@ { "id": 2563, "Key": "Sigil", - "enUS": " Sigil ", + "enUS": "Sigil ", "zhTW": "魔咒", "deDE": "Magisches Siegel", "esES": "[ms]Sigilo", @@ -8655,7 +8655,7 @@ { "id": 2565, "Key": "Sabot", - "enUS": " Sabot ", + "enUS": "Sabot ", "zhTW": "硬靴", "deDE": "Schuh", "esES": "[mp]Zuecos", @@ -8672,7 +8672,7 @@ { "id": 2566, "Key": "Wings", - "enUS": " Wings ", + "enUS": "Wings ", "zhTW": "翅膀", "deDE": "Flügel", "esES": "[fp]Alas", @@ -8689,7 +8689,7 @@ { "id": 2567, "Key": "Mitts", - "enUS": " Mitts ", + "enUS": "Mitts ", "zhTW": "手套", "deDE": "Fäustlinge", "esES": "[mp]Mitones", @@ -8706,7 +8706,7 @@ { "id": 2568, "Key": "Flesh", - "enUS": " Flesh ", + "enUS": "Flesh ", "zhTW": "血肉", "deDE": "Fleisch", "esES": "[fs]Carne", @@ -8723,7 +8723,7 @@ { "id": 2569, "Key": "Cord", - "enUS": " Cord ", + "enUS": "Cord ", "zhTW": "腰繩", "deDE": "Band", "esES": "[ms]Cordón", @@ -8740,7 +8740,7 @@ { "id": 2570, "Key": "Seal", - "enUS": " Seal ", + "enUS": "Seal ", "zhTW": "封印", "deDE": "Siegel", "esES": "Sello", @@ -8757,14 +8757,14 @@ { "id": 2571, "Key": "SkullSI5S", - "enUS": " Skull ", + "enUS": "Skull ", "zhTW": "顱骨", "deDE": "Schädel", "esES": "[ms]Cráneo", "frFR": "Crâne", "itIT": "Teschio", "koKR": "해골", - "plPL": "Czaszka ", + "plPL": "Czaszka ", "esMX": "Cráneo", "jaJP": "頭蓋骨", "ptBR": "Caveira", @@ -8774,7 +8774,7 @@ { "id": 2572, "Key": "Wrap", - "enUS": " Wrap ", + "enUS": "Wrap ", "zhTW": "裹腰", "deDE": "Umhang", "esES": "[ms]Cinto", @@ -8791,7 +8791,7 @@ { "id": 2573, "Key": "GuardSI6S", - "enUS": " Guard ", + "enUS": "Guard ", "zhTW": "守護", "deDE": "Wächter", "esES": "Cubierta de protección", @@ -8808,7 +8808,7 @@ { "id": 2574, "Key": "The Gnasher", - "enUS": " The Gnasher ", + "enUS": "The Gnasher ", "zhTW": "噬咬者", "deDE": "der Knirscher", "esES": "La despedazadora", @@ -8825,7 +8825,7 @@ { "id": 2575, "Key": "Deathspade", - "enUS": " Deathspade ", + "enUS": "Deathspade ", "zhTW": "死亡之鏟", "deDE": "Todesspaten", "esES": "Pica de la muerte", @@ -8842,7 +8842,7 @@ { "id": 2576, "Key": "Bladebone", - "enUS": " Bladebone ", + "enUS": "Bladebone ", "zhTW": "肩胛骨", "deDE": "Klingenknochen", "esES": "Filo óseo", @@ -8859,7 +8859,7 @@ { "id": 2577, "Key": "Mindrend", - "enUS": " Skull Splitter ", + "enUS": "Skull Splitter ", "zhTW": "劈顱斧", "deDE": "Schädelspalter", "esES": "Partecalaveras", @@ -8876,7 +8876,7 @@ { "id": 2578, "Key": "Rakescar", - "enUS": " Rakescar ", + "enUS": "Rakescar ", "zhTW": "耙痕", "deDE": "Teufelsnarbe", "esES": "Rastreador", @@ -8893,7 +8893,7 @@ { "id": 2579, "Key": "Fechmars Axe", - "enUS": " Axe of Fechmar ", + "enUS": "Axe of Fechmar ", "zhTW": "費屈瑪之斧", "deDE": "Axt von Fechmar", "esES": "Hacha de Fechmar", @@ -8910,7 +8910,7 @@ { "id": 2580, "Key": "Goreshovel", - "enUS": " Goreshovel ", + "enUS": "Goreshovel ", "zhTW": "血鍬", "deDE": "Müllschaufel", "esES": "Pala sangrienta", @@ -8927,7 +8927,7 @@ { "id": 2581, "Key": "The Chieftan", - "enUS": " The Chieftain ", + "enUS": "The Chieftain ", "zhTW": "酋長", "deDE": "der Häuptling", "esES": "El cacique", @@ -8944,7 +8944,7 @@ { "id": 2582, "Key": "Brainhew", - "enUS": " Brainhew ", + "enUS": "Brainhew ", "zhTW": "劈腦", "deDE": "Hirnhacke", "esES": "Cortacerebros", @@ -8961,7 +8961,7 @@ { "id": 2583, "Key": "The Humongous", - "enUS": " Humongous ", + "enUS": "Humongous ", "zhTW": "巨無霸", "deDE": "Riese", "esES": "Demoledora", @@ -8978,7 +8978,7 @@ { "id": 2584, "Key": "Iros Torch", - "enUS": " Torch of Iro ", + "enUS": "Torch of Iro ", "zhTW": "伊洛的火炬", "deDE": "Fackel von Iro", "esES": "Antorcha de Iro", @@ -8995,11 +8995,11 @@ { "id": 2585, "Key": "Maelstromwrath", - "enUS": " Maelstrom ", + "enUS": "Maelstrom ", "zhTW": "漩渦", "deDE": "Mahlstrom", "esES": "Vorágine", - "frFR": "Maelström ", + "frFR": "Maelström ", "itIT": "Maelstrom", "koKR": "소용돌이", "plPL": "Cyklon", @@ -9012,7 +9012,7 @@ { "id": 2586, "Key": "Gravenspine", - "enUS": " Gravenspine ", + "enUS": "Gravenspine ", "zhTW": "墓穴之脊", "deDE": "Grabknochen", "esES": "Espina de la tumba", @@ -9029,7 +9029,7 @@ { "id": 2587, "Key": "Umes Lament", - "enUS": " Ume's Lament ", + "enUS": "Ume's Lament ", "zhTW": "梅花嘆", "deDE": "Umes Trauer", "esES": "Lamento de Ume", @@ -9046,7 +9046,7 @@ { "id": 2588, "Key": "Felloak", - "enUS": " Felloak ", + "enUS": "Felloak ", "zhTW": "魔橡樹", "deDE": "Falleiche", "esES": "Roble siniestro", @@ -9063,7 +9063,7 @@ { "id": 2589, "Key": "Knell Striker", - "enUS": " Knell Striker ", + "enUS": "Knell Striker ", "zhTW": "喪鐘敲擊者", "deDE": "Totenglöckner", "esES": "Badajo", @@ -9080,7 +9080,7 @@ { "id": 2590, "Key": "Rusthandle", - "enUS": " Rusthandle ", + "enUS": "Rusthandle ", "zhTW": "鏽蝕把手", "deDE": "Rostgriff", "esES": "Mango oxidado", @@ -9097,7 +9097,7 @@ { "id": 2591, "Key": "Stormeye", - "enUS": " Stormeye ", + "enUS": "Stormeye ", "zhTW": "暴風眼", "deDE": "Sturmauge", "esES": "Ojo de la tormenta", @@ -9114,7 +9114,7 @@ { "id": 2592, "Key": "Stoutnail", - "enUS": " Stoutnail ", + "enUS": "Stoutnail ", "zhTW": "特粗鐵釘", "deDE": "Festnagel", "esES": "Clavo sólido", @@ -9131,7 +9131,7 @@ { "id": 2593, "Key": "Crushflange", - "enUS": " Crushflange ", + "enUS": "Crushflange ", "zhTW": "碎擊釘錘", "deDE": "Malmknüppel", "esES": "Remate machacador", @@ -9148,7 +9148,7 @@ { "id": 2594, "Key": "Bloodrise", - "enUS": " Bloodrise ", + "enUS": "Bloodrise ", "zhTW": "血升", "deDE": "Blutrausch", "esES": "Ascenso sangriento", @@ -9165,7 +9165,7 @@ { "id": 2595, "Key": "The Generals Tan Do Li Ga", - "enUS": " The General's Tan Do Li Ga ", + "enUS": "The General's Tan Do Li Ga ", "zhTW": "將軍的連枷", "deDE": "das Tan-Do-Li-Ga des Generals", "esES": "Tan do li ga del general", @@ -9182,7 +9182,7 @@ { "id": 2596, "Key": "Ironstone", - "enUS": " Ironstone ", + "enUS": "Ironstone ", "zhTW": "鐵石", "deDE": "Eisenstein", "esES": "Piedra de hierro", @@ -9199,7 +9199,7 @@ { "id": 2597, "Key": "Bonesob", - "enUS": " Bonesnap ", + "enUS": "Bonesnap ", "zhTW": "碎骨", "deDE": "Knochenbrecher", "esES": "Rompehuesos", @@ -9216,7 +9216,7 @@ { "id": 2598, "Key": "Steeldriver", - "enUS": " Steeldriver ", + "enUS": "Steeldriver ", "zhTW": "打鋼鎚", "deDE": "Stahlschläger", "esES": "Clavadora de aceros", @@ -9233,7 +9233,7 @@ { "id": 2599, "Key": "Rixots Keen", - "enUS": " Rixot's Keen ", + "enUS": "Rixot's Keen ", "zhTW": "瑞克塞斯的利刃", "deDE": "Rixots Auge", "esES": "Lamento de Rixot", @@ -9250,7 +9250,7 @@ { "id": 2600, "Key": "Blood Crescent", - "enUS": " Blood Crescent ", + "enUS": "Blood Crescent ", "zhTW": "血紅新月", "deDE": "Blutmond", "esES": "Medialuna sangrienta", @@ -9267,7 +9267,7 @@ { "id": 2601, "Key": "Krintizs Skewer", - "enUS": " Skewer of Krintiz ", + "enUS": "Skewer of Krintiz ", "zhTW": "克里維茲的肉叉", "deDE": "Spieß von Krintis", "esES": "Lanceta de Krintiz", @@ -9284,7 +9284,7 @@ { "id": 2602, "Key": "Gleamscythe", - "enUS": " Gleamscythe ", + "enUS": "Gleamscythe ", "zhTW": "閃耀鐮刀", "deDE": "Sichelglanz", "esES": "Guadaña reluciente", @@ -9301,7 +9301,7 @@ { "id": 2603, "Key": "Azurewrath", - "enUS": " Azurewrath ", + "enUS": "Azurewrath ", "zhTW": "碧藍怒火", "deDE": "Blauzorn", "esES": "Ira celeste", @@ -9318,7 +9318,7 @@ { "id": 2604, "Key": "Griswolds Edge", - "enUS": " Griswold's Edge ", + "enUS": "Griswold's Edge ", "zhTW": "格里斯瓦德之刃", "deDE": "Griswolds Schneide", "esES": "Filo de Griswold", @@ -9335,7 +9335,7 @@ { "id": 2605, "Key": "Hellplague", - "enUS": " Hellplague ", + "enUS": "Hellplague ", "zhTW": "地獄瘟疫", "deDE": "Höllenpest", "esES": "Plaga infernal", @@ -9352,7 +9352,7 @@ { "id": 2606, "Key": "Culwens Point", - "enUS": " Culwen's Point ", + "enUS": "Culwen's Point ", "zhTW": "庫爾溫的尖刃", "deDE": "Culwens Spitze", "esES": "Puya de Culwen", @@ -9369,7 +9369,7 @@ { "id": 2607, "Key": "Shadowfang", - "enUS": " Shadowfang ", + "enUS": "Shadowfang ", "zhTW": "暗影之牙", "deDE": "Schattenzahn", "esES": "Colmillo sombrío", @@ -9386,7 +9386,7 @@ { "id": 2608, "Key": "Soulflay", - "enUS": " Soulflay ", + "enUS": "Soulflay ", "zhTW": "剝魂", "deDE": "Seelenschinder", "esES": "Desollamiento del alma", @@ -9403,7 +9403,7 @@ { "id": 2609, "Key": "Kinemils Awl", - "enUS": " Kinemil's Awl ", + "enUS": "Kinemil's Awl ", "zhTW": "金麥爾的鑽錐", "deDE": "Kinemils Ahle", "esES": "Punzón de Kinemil", @@ -9420,7 +9420,7 @@ { "id": 2610, "Key": "Blacktongue", - "enUS": " Blacktongue ", + "enUS": "Blacktongue ", "zhTW": "黑舌", "deDE": "Schwarzzunge", "esES": "Lengua negra", @@ -9437,7 +9437,7 @@ { "id": 2611, "Key": "Ripsaw", - "enUS": " Ripsaw ", + "enUS": "Ripsaw ", "zhTW": "齒鋸", "deDE": "Sägezahn", "esES": "Sierra de corte", @@ -9454,7 +9454,7 @@ { "id": 2612, "Key": "The Patriarch", - "enUS": " The Patriarch ", + "enUS": "The Patriarch ", "zhTW": "尊父", "deDE": "der Patriarch", "esES": "El patriarca", @@ -9471,7 +9471,7 @@ { "id": 2613, "Key": "Gull", - "enUS": " Gull ", + "enUS": "Gull ", "zhTW": "海鷗", "deDE": "Möwe", "esES": "Gaviota", @@ -9488,7 +9488,7 @@ { "id": 2614, "Key": "The Diggler", - "enUS": " The Diggler ", + "enUS": "The Diggler ", "zhTW": "迪格勒", "deDE": "der Gräber", "esES": "Diggler", @@ -9505,7 +9505,7 @@ { "id": 2615, "Key": "The Jade Tan Do", - "enUS": " The Jade Tan Do ", + "enUS": "The Jade Tan Do ", "zhTW": "玉匕", "deDE": "das Jade-Tan-Do", "esES": "Tan do de jade", @@ -9522,7 +9522,7 @@ { "id": 2616, "Key": "Irices Shard", - "enUS": " Spectral Shard ", + "enUS": "Spectral Shard ", "zhTW": "虹彩裂片", "deDE": "Geisterscherbe", "esES": "Esquirla espectral", @@ -9539,7 +9539,7 @@ { "id": 2617, "Key": "The Dragon Chang", - "enUS": " The Dragon Chang ", + "enUS": "The Dragon Chang ", "zhTW": "龍槍", "deDE": "der Drachen-Chang", "esES": "Chang de dragón", @@ -9556,7 +9556,7 @@ { "id": 2618, "Key": "Razortine", - "enUS": " Razortine ", + "enUS": "Razortine ", "zhTW": "剃刀叉", "deDE": "Blitzklinge", "esES": "Diente de cuchilla", @@ -9573,7 +9573,7 @@ { "id": 2619, "Key": "Bloodthief", - "enUS": " Bloodthief ", + "enUS": "Bloodthief ", "zhTW": "血賊", "deDE": "Blutdieb", "esES": "Ladrón sangriento", @@ -9590,7 +9590,7 @@ { "id": 2620, "Key": "Lance of Yaggai", - "enUS": " Lance of Yaggai ", + "enUS": "Lance of Yaggai ", "zhTW": "雅該長矛", "deDE": "Lanze von Yagai", "esES": "Lanza de Yaggai", @@ -9607,7 +9607,7 @@ { "id": 2621, "Key": "The Tannr Gorerod", - "enUS": " The Tannr Gorerod ", + "enUS": "The Tannr Gorerod ", "zhTW": "坦納血杖", "deDE": "der Tannr-Blutstab", "esES": "Caña sangrienta de Tannr", @@ -9624,7 +9624,7 @@ { "id": 2622, "Key": "Dimoaks Hew", - "enUS": " Dimoak's Hew ", + "enUS": "Dimoak's Hew ", "zhTW": "迪馬克的砍刀", "deDE": "Dummeiches Haudrauf", "esES": "Talla de Dimoak", @@ -9641,7 +9641,7 @@ { "id": 2623, "Key": "Steelgoad", - "enUS": " Steelgoad ", + "enUS": "Steelgoad ", "zhTW": "鐵刺棒", "deDE": "Stahlsucher", "esES": "Aguijón de acero", @@ -9658,7 +9658,7 @@ { "id": 2624, "Key": "Soul Harvest", - "enUS": " Soul Harvest ", + "enUS": "Soul Harvest ", "zhTW": "靈魂收割者", "deDE": "Seelenernte", "esES": "Cosechadora de almas", @@ -9675,7 +9675,7 @@ { "id": 2625, "Key": "The Battlebranch", - "enUS": " The Battlebranch ", + "enUS": "The Battlebranch ", "zhTW": "戰鬥枝椏", "deDE": "der Kampfast", "esES": "Rama de la batalla", @@ -9692,7 +9692,7 @@ { "id": 2626, "Key": "Woestave", - "enUS": " Woestave ", + "enUS": "Woestave ", "zhTW": "悲哀護杖", "deDE": "Elendsstab", "esES": "Asta de la congoja", @@ -9709,7 +9709,7 @@ { "id": 2627, "Key": "The Grim Reaper", - "enUS": " The Grim Reaper ", + "enUS": "The Grim Reaper ", "zhTW": "猙獰奪魂者", "deDE": "Gevatter Tod", "esES": "Segador implacable", @@ -9726,7 +9726,7 @@ { "id": 2628, "Key": "Bane Ash", - "enUS": " Bane Ash ", + "enUS": "Bane Ash ", "zhTW": "禍根之灰", "deDE": "Giftasche", "esES": "Ceniza funesta", @@ -9743,7 +9743,7 @@ { "id": 2629, "Key": "Serpent Lord", - "enUS": " Serpent Lord ", + "enUS": "Serpent Lord ", "zhTW": "海蛇之王", "deDE": "Natternfürst", "esES": "Señor de la serpiente", @@ -9760,7 +9760,7 @@ { "id": 2630, "Key": "Lazarus Spire", - "enUS": " Spire of Lazarus ", + "enUS": "Spire of Lazarus ", "zhTW": "拉撒雷茲之杖", "deDE": "Spitze von Lazarus", "esES": "Aguja de Lázaro", @@ -9777,7 +9777,7 @@ { "id": 2631, "Key": "The Salamander", - "enUS": " The Salamander ", + "enUS": "The Salamander ", "zhTW": "火精靈", "deDE": "der Salamander", "esES": "La salamandra", @@ -9794,7 +9794,7 @@ { "id": 2632, "Key": "The Iron Jang Bong", - "enUS": " The Iron Jang Bong ", + "enUS": "The Iron Jang Bong ", "zhTW": "鐵長棒", "deDE": "das Eisen-Jang-Bong", "esES": "Jang bong de hierro", @@ -9811,7 +9811,7 @@ { "id": 2633, "Key": "Pluckeye", - "enUS": " Pluckeye ", + "enUS": "Pluckeye ", "zhTW": "奪人目", "deDE": "Reißauge", "esES": "Sacaojos", @@ -9828,7 +9828,7 @@ { "id": 2634, "Key": "Witherstring", - "enUS": " Witherstring ", + "enUS": "Witherstring ", "zhTW": "凋萎之弦", "deDE": "Todesband", "esES": "Cuerda marchitadora", @@ -9845,7 +9845,7 @@ { "id": 2635, "Key": "Rimeraven", - "enUS": " Raven Claw ", + "enUS": "Raven Claw ", "zhTW": "掠鴉之爪", "deDE": "Rabenklaue", "esES": "Garra del cuervo", @@ -9862,7 +9862,7 @@ { "id": 2636, "Key": "Piercerib", - "enUS": " Rogue's Bow ", + "enUS": "Rogue's Bow ", "zhTW": "俠盜之弓", "deDE": "Jägerbogen", "esES": "Arco de la arpía", @@ -9879,7 +9879,7 @@ { "id": 2637, "Key": "Pullspite", - "enUS": " Stormstrike ", + "enUS": "Stormstrike ", "zhTW": "暴風之擊", "deDE": "Sturmschlag", "esES": "Golpe de tormenta", @@ -9896,7 +9896,7 @@ { "id": 2638, "Key": "Wizendraw", - "enUS": " Wizendraw ", + "enUS": "Wizendraw ", "zhTW": "凋謝弓弦", "deDE": "Runzelrübe", "esES": "Tensión marchita", @@ -9913,7 +9913,7 @@ { "id": 2639, "Key": "Hellclap", - "enUS": " Hellclap ", + "enUS": "Hellclap ", "zhTW": "地獄轟鳴", "deDE": "Höllenknall", "esES": "Trueno infernal", @@ -9930,7 +9930,7 @@ { "id": 2640, "Key": "Blastbark", - "enUS": " Blastbark ", + "enUS": "Blastbark ", "zhTW": "爆裂咆哮", "deDE": "Knallrinde", "esES": "Corteza explosiva", @@ -9947,7 +9947,7 @@ { "id": 2641, "Key": "Leadcrow", - "enUS": " Leadcrow ", + "enUS": "Leadcrow ", "zhTW": "鉛烏鴉", "deDE": "Bleikrähe", "esES": "Cuervo de plomo", @@ -9964,7 +9964,7 @@ { "id": 2642, "Key": "Ichorsting", - "enUS": " Ichorsting ", + "enUS": "Ichorsting ", "zhTW": "膿毒之刺", "deDE": "Säurebrand", "esES": "Aguijón de Ichor", @@ -9981,7 +9981,7 @@ { "id": 2643, "Key": "Hellcast", - "enUS": " Hellcast ", + "enUS": "Hellcast ", "zhTW": "地獄擲弩", "deDE": "Höllenherz", "esES": "Rastro infernal", @@ -9998,7 +9998,7 @@ { "id": 2644, "Key": "Doomspittle", - "enUS": " Doomslinger ", + "enUS": "Doomslinger ", "zhTW": "毀滅投索", "deDE": "Verdammnisbringer", "esES": "Honda de la perdición", @@ -10015,7 +10015,7 @@ { "id": 2645, "Key": "War Bonnet", - "enUS": " Biggin's Bonnet ", + "enUS": "Biggin's Bonnet ", "zhTW": "畢格因的軟帽", "deDE": "Higgis Haube", "esES": "Gorra de Biggin", @@ -10032,7 +10032,7 @@ { "id": 2646, "Key": "Tarnhelm", - "enUS": " Tarnhelm ", + "enUS": "Tarnhelm ", "zhTW": "塔因頭盔", "deDE": "Tarnhelm", "esES": "Yelmo de la laguna", @@ -10049,7 +10049,7 @@ { "id": 2647, "Key": "Coif of Glory", - "enUS": " Coif of Glory ", + "enUS": "Coif of Glory ", "zhTW": "光榮罩盔", "deDE": "Glorienkappe", "esES": "Toca de gloria", @@ -10066,7 +10066,7 @@ { "id": 2648, "Key": "Duskdeep", - "enUS": " Duskdeep ", + "enUS": "Duskdeep ", "zhTW": "黃昏深處", "deDE": "Dämmertief", "esES": "Profundidad del crepúsculo", @@ -10083,7 +10083,7 @@ { "id": 2649, "Key": "Wormskull", - "enUS": " Wormskull ", + "enUS": "Wormskull ", "zhTW": "蠕蟲頭骨", "deDE": "Wurmschädel", "esES": "Cráneo de gusano", @@ -10100,7 +10100,7 @@ { "id": 2650, "Key": "Howltusk", - "enUS": " Howltusk ", + "enUS": "Howltusk ", "zhTW": "怒號長牙", "deDE": "Heulhauer", "esES": "Colmillo del aullido", @@ -10117,7 +10117,7 @@ { "id": 2651, "Key": "Undead Crown", - "enUS": " Undead Crown ", + "enUS": "Undead Crown ", "zhTW": "不死皇冠", "deDE": "Untote Krone", "esES": "Corona viviente", @@ -10134,7 +10134,7 @@ { "id": 2652, "Key": "The Face of Horror", - "enUS": " The Face of Horror ", + "enUS": "The Face of Horror ", "zhTW": "恐懼之臉", "deDE": "das Gesicht des Horrors", "esES": "El rostro del horror", @@ -10151,7 +10151,7 @@ { "id": 2653, "Key": "Greyform", - "enUS": " Greyform ", + "enUS": "Greyform ", "zhTW": "灰暮之形", "deDE": "Grauform", "esES": "Forma grisácea", @@ -10168,7 +10168,7 @@ { "id": 2654, "Key": "Blinkbats Form", - "enUS": " Blinkbat's Form ", + "enUS": "Blinkbat's Form ", "zhTW": "閃蝠之軀", "deDE": "Blinkers Form", "esES": "Murciélago destellante", @@ -10185,7 +10185,7 @@ { "id": 2655, "Key": "The Centurion", - "enUS": " The Centurion ", + "enUS": "The Centurion ", "zhTW": "百夫長", "deDE": "Der Zenturio", "esES": "El centurión", @@ -10202,7 +10202,7 @@ { "id": 2656, "Key": "Twitchthroe", - "enUS": " Twitchthroe ", + "enUS": "Twitchthroe ", "zhTW": "抽動掙扎", "deDE": "Zuckzappel", "esES": "Agonía temblorosa", @@ -10219,7 +10219,7 @@ { "id": 2657, "Key": "Darkglow", - "enUS": " Darkglow ", + "enUS": "Darkglow ", "zhTW": "暗光", "deDE": "Dunkelglüh", "esES": "Resplandor de oscuridad", @@ -10236,7 +10236,7 @@ { "id": 2658, "Key": "Hawkmail", - "enUS": " Hawkmail ", + "enUS": "Hawkmail ", "zhTW": "鷹甲", "deDE": "Falkenhemd", "esES": "Cota del gerifalte", @@ -10253,7 +10253,7 @@ { "id": 2659, "Key": "Sparking Mail", - "enUS": " Sparking Mail ", + "enUS": "Sparking Mail ", "zhTW": "電光之甲", "deDE": "Funkenhemd", "esES": "Cota chispeante", @@ -10270,7 +10270,7 @@ { "id": 2660, "Key": "Venomsward", - "enUS": " Venom Ward ", + "enUS": "Venom Ward ", "zhTW": "毒之守禦", "deDE": "Giftschutz", "esES": "Custodia de la ponzoña", @@ -10287,7 +10287,7 @@ { "id": 2661, "Key": "Iceblink", - "enUS": " Iceblink ", + "enUS": "Iceblink ", "zhTW": "冰晶", "deDE": "Eisblinker", "esES": "Destello gélido", @@ -10304,7 +10304,7 @@ { "id": 2662, "Key": "Boneflesh", - "enUS": " Boneflesh ", + "enUS": "Boneflesh ", "zhTW": "骨肉", "deDE": "Knochenfleisch", "esES": "Carne de hueso", @@ -10321,7 +10321,7 @@ { "id": 2663, "Key": "Rockfleece", - "enUS": " Rockfleece ", + "enUS": "Rockfleece ", "zhTW": "石羊毛", "deDE": "Felsenfell", "esES": "Lana de roca", @@ -10338,7 +10338,7 @@ { "id": 2664, "Key": "Rattlecage", - "enUS": " Rattlecage ", + "enUS": "Rattlecage ", "zhTW": "震骨", "deDE": "Klapperkäfig", "esES": "Jaula vibradora", @@ -10355,7 +10355,7 @@ { "id": 2665, "Key": "Goldskin", - "enUS": " Goldskin ", + "enUS": "Goldskin ", "zhTW": "黃金之膚", "deDE": "Goldhaut", "esES": "Piel áurea", @@ -10372,7 +10372,7 @@ { "id": 2666, "Key": "Victors Silk", - "enUS": " Silks of the Victor ", + "enUS": "Silks of the Victor ", "zhTW": "勝利者的絲綢", "deDE": "Seide des Siegers", "esES": "Sedas del victorioso", @@ -10389,7 +10389,7 @@ { "id": 2667, "Key": "Heavenly Garb", - "enUS": " Heavenly Garb ", + "enUS": "Heavenly Garb ", "zhTW": "天堂裝束", "deDE": "Himmlisches Gewand", "esES": "Vestido celestial", @@ -10406,7 +10406,7 @@ { "id": 2668, "Key": "Pelta Lunata", - "enUS": " Pelta Lunata ", + "enUS": "Pelta Lunata ", "zhTW": "新月小盾", "deDE": "Pelta Lunata", "esES": "Pelta lunata", @@ -10423,7 +10423,7 @@ { "id": 2669, "Key": "Umbral Disk", - "enUS": " Umbral Disk ", + "enUS": "Umbral Disk ", "zhTW": "陰影圓盤", "deDE": "Schattenscheibe", "esES": "Disco umbrío", @@ -10440,7 +10440,7 @@ { "id": 2670, "Key": "Stormguild", - "enUS": " Stormguild ", + "enUS": "Stormguild ", "zhTW": "風暴同盟", "deDE": "Sturmgilde", "esES": "Gremio de la tormenta", @@ -10457,7 +10457,7 @@ { "id": 2671, "Key": "Wall of the Eyeless", - "enUS": " Wall of the Eyeless ", + "enUS": "Wall of the Eyeless ", "zhTW": "無眼者之牆", "deDE": "Wand der Augenlosen", "esES": "Muro de los sin ojos", @@ -10474,7 +10474,7 @@ { "id": 2672, "Key": "Swordback Hold", - "enUS": " Swordback Hold ", + "enUS": "Swordback Hold ", "zhTW": "劍棘之盾", "deDE": "Schwerthalter", "esES": "Contención de espadas", @@ -10491,7 +10491,7 @@ { "id": 2673, "Key": "Steelclash", - "enUS": " Steelclash ", + "enUS": "Steelclash ", "zhTW": "鋼鐵衝擊", "deDE": "Stahlklang", "esES": "Fragor de acero", @@ -10508,7 +10508,7 @@ { "id": 2674, "Key": "Bverrit Keep", - "enUS": " Bverrit Keep ", + "enUS": "Bverrit Keep ", "zhTW": "布雷維特要塞", "deDE": "Bverritturm", "esES": "Torreón de Bverrit", @@ -10525,7 +10525,7 @@ { "id": 2675, "Key": "The Ward", - "enUS": " The Ward ", + "enUS": "The Ward ", "zhTW": "庇護結界", "deDE": "der Schutz", "esES": "La custodia", @@ -10542,7 +10542,7 @@ { "id": 2676, "Key": "The Hand of Broc", - "enUS": " The Hand of Broc ", + "enUS": "The Hand of Broc ", "zhTW": "柏克之手", "deDE": "die Hand von Broc", "esES": "La mano de Broc", @@ -10559,7 +10559,7 @@ { "id": 2677, "Key": "Bloodfist", - "enUS": " Bloodfist ", + "enUS": "Bloodfist ", "zhTW": "血拳", "deDE": "Blutfaust", "esES": "Puño sangriento", @@ -10576,7 +10576,7 @@ { "id": 2678, "Key": "Chance Guards", - "enUS": " Chance Guards ", + "enUS": "Chance Guards ", "zhTW": "運氣守護", "deDE": "Wächtertreu", "esES": "Protección de la suerte", @@ -10593,7 +10593,7 @@ { "id": 2679, "Key": "Magefist", - "enUS": " Magefist ", + "enUS": "Magefist ", "zhTW": "法師之拳", "deDE": "Magierfaust", "esES": "Puño del mago", @@ -10610,7 +10610,7 @@ { "id": 2680, "Key": "Frostburn", - "enUS": " Frostburn ", + "enUS": "Frostburn ", "zhTW": "霜燃", "deDE": "Frostbrand", "esES": "Quemadura glacial", @@ -10627,7 +10627,7 @@ { "id": 2681, "Key": "Hotspur", - "enUS": " Hotspur ", + "enUS": "Hotspur ", "zhTW": "熱靴刺", "deDE": "Heißsporn", "esES": "Espuela ardiente", @@ -10644,7 +10644,7 @@ { "id": 2682, "Key": "Gorefoot", - "enUS": " Gorefoot ", + "enUS": "Gorefoot ", "zhTW": "血腳", "deDE": "Schmutzfuß", "esES": "Pie sangriento", @@ -10661,7 +10661,7 @@ { "id": 2683, "Key": "Treads of Cthon", - "enUS": " Treads of Cthon ", + "enUS": "Treads of Cthon ", "zhTW": "凱松的足靴", "deDE": "Spuren von Cthon", "esES": "Huellas de Cthon", @@ -10678,7 +10678,7 @@ { "id": 2684, "Key": "Goblin Toe", - "enUS": " Goblin Toe ", + "enUS": "Goblin Toe ", "zhTW": "哥布林腳趾", "deDE": "Goblinzeh", "esES": "Dedo de goblin", @@ -10695,7 +10695,7 @@ { "id": 2685, "Key": "Tearhaunch", - "enUS": " Tearhaunch ", + "enUS": "Tearhaunch ", "zhTW": "裂臀", "deDE": "Tränenkeule", "esES": "Anca desgarrada", @@ -10712,7 +10712,7 @@ { "id": 2686, "Key": "Lenyms Cord", - "enUS": " Lenymo ", + "enUS": "Lenymo ", "zhTW": "雷尼摩", "deDE": "Lenymo", "esES": "Lenymo", @@ -10729,7 +10729,7 @@ { "id": 2687, "Key": "Snakecord", - "enUS": " Snakecord ", + "enUS": "Snakecord ", "zhTW": "蛇索", "deDE": "Schlangenband", "esES": "Cordón de culebra", @@ -10746,7 +10746,7 @@ { "id": 2688, "Key": "Nightsmoke", - "enUS": " Nightsmoke ", + "enUS": "Nightsmoke ", "zhTW": "夜煙", "deDE": "Nachtrauch", "esES": "Humo nocturno", @@ -10763,7 +10763,7 @@ { "id": 2689, "Key": "Goldwrap", - "enUS": " Goldwrap ", + "enUS": "Goldwrap ", "zhTW": "黃金裹腰", "deDE": "Goldträger", "esES": "Cinto de oro", @@ -10780,7 +10780,7 @@ { "id": 2690, "Key": "Bladebuckle", - "enUS": " Bladebuckle ", + "enUS": "Bladebuckle ", "zhTW": "刀鋒扣帶", "deDE": "Klingengurt", "esES": "Hebilla de espada", @@ -10797,7 +10797,7 @@ { "id": 2691, "Key": "Nokozan Relic", - "enUS": " Nokozan Relic ", + "enUS": "Nokozan Relic ", "zhTW": "諾科藍遺物", "deDE": "Nokozanrelikt", "esES": "Reliquia de Nokozan", @@ -10814,7 +10814,7 @@ { "id": 2692, "Key": "The Eye of Etlich", - "enUS": " The Eye of Etlich ", + "enUS": "The Eye of Etlich ", "zhTW": "艾利曲之眼", "deDE": "das Auge von Ettlich", "esES": "Ojo de Etlich", @@ -10831,7 +10831,7 @@ { "id": 2693, "Key": "The Mahim-Oak Curio", - "enUS": " The Mahim-Oak Curio ", + "enUS": "The Mahim-Oak Curio ", "zhTW": "瑪哈姆橡木古董", "deDE": "das Mahim-Eiche-Kurio", "esES": "Curiosidad de roble mahim", @@ -10848,7 +10848,7 @@ { "id": 2694, "Key": "Nagelring", - "enUS": " Nagelring ", + "enUS": "Nagelring ", "zhTW": "拿各的戒指", "deDE": "Nagelring", "esES": "Anillo de Naguel", @@ -10865,7 +10865,7 @@ { "id": 2695, "Key": "Manald Heal", - "enUS": " Manald Heal ", + "enUS": "Manald Heal ", "zhTW": "瑪那德的治療", "deDE": "Manaldheilung", "esES": "Curación de Manald", @@ -10882,7 +10882,7 @@ { "id": 2696, "Key": "Gorgethroat", - "enUS": " Gorgethroat ", + "enUS": "Gorgethroat ", "zhTW": "吞喉", "deDE": "Enghals", "esES": "[fs]Garganta engullidora", @@ -10899,7 +10899,7 @@ { "id": 2697, "Key": "Amulet of the Viper", - "enUS": " Amulet of the Viper ", + "enUS": "Amulet of the Viper ", "zhTW": "蝮蛇護符", "deDE": "Vipernamulett", "esES": "Amuleto de la víbora", @@ -10916,7 +10916,7 @@ { "id": 2698, "Key": "Staff of Kings", - "enUS": " Staff of Kings ", + "enUS": "Staff of Kings ", "zhTW": "國王之杖", "deDE": "Königsstab", "esES": "Bastón de los reyes", @@ -10933,7 +10933,7 @@ { "id": 2699, "Key": "Horadric Staff", - "enUS": " Horadric Staff ", + "enUS": "Horadric Staff ", "zhTW": "赫拉迪姆之杖", "deDE": "Horadrimstab", "esES": "Bastón horádrico", @@ -10950,7 +10950,7 @@ { "id": 2700, "Key": "Hell Forge Hammer", - "enUS": " Hell Forge Hammer ", + "enUS": "Hell Forge Hammer ", "zhTW": "地獄熔爐之鎚", "deDE": "Hammer der Höllenschmiede", "esES": "Martillo de la Fragua del Infierno", @@ -10967,7 +10967,7 @@ { "id": 2701, "Key": "The Stone of Jordan", - "enUS": " The Stone of Jordan ", + "enUS": "The Stone of Jordan ", "zhTW": "喬丹之石", "deDE": "Der Stein von Jordan", "esES": "Piedra de Jordán", @@ -10984,7 +10984,7 @@ { "id": 3245, "Key": "Gibbet", - "enUS": " Cain's Gibbet ", + "enUS": "Cain's Gibbet ", "zhTW": "凱恩的絞架", "deDE": "Cains Galgen", "esES": "Cadalso de Caín", @@ -11001,7 +11001,7 @@ { "id": 3263, "Key": "HorazonsJournal", - "enUS": " Horazon's Journal ", + "enUS": "Horazon's Journal ", "zhTW": "赫拉森的日誌", "deDE": "Horazons Tagebuch", "esES": "[ms]Diario de Horazón", @@ -11018,7 +11018,7 @@ { "id": 3277, "Key": "jug", - "enUS": " Jug ", + "enUS": "Jug ", "zhTW": "罐子", "deDE": "Krug", "esES": "Jarrón", @@ -11035,7 +11035,7 @@ { "id": 3279, "Key": "ratnest", - "enUS": " Rat's Nest ", + "enUS": "Rat's Nest ", "zhTW": "老鼠窩", "deDE": "Rattennest", "esES": "Nido de ratas", @@ -11052,7 +11052,7 @@ { "id": 3289, "Key": "bed", - "enUS": " Bed ", + "enUS": "Bed ", "zhTW": "床", "deDE": "Bett", "esES": "Cama", @@ -11069,7 +11069,7 @@ { "id": 3304, "Key": "Tome", - "enUS": " Horazon's Journal ", + "enUS": "Horazon's Journal ", "zhTW": "赫拉森的日誌", "deDE": "Horazons Tagebuch", "esES": "Diario de Horazón", @@ -11086,7 +11086,7 @@ { "id": 3314, "Key": "wirt's body", - "enUS": " Wirt's body ", + "enUS": "Wirt's body ", "zhTW": "維特的屍體", "deDE": "Wirts Leiche", "esES": "Cuerpo de Wirt", @@ -11103,7 +11103,7 @@ { "id": 10000, "Key": "Cutthroat1", - "enUS": " Bartuc's Cut-Throat ", + "enUS": "Bartuc's Cut-Throat ", "zhTW": "霸圖克的割喉爪", "deDE": "Bartucs Halsabschneider", "esES": "Degolladera de Bartuc", @@ -11120,7 +11120,7 @@ { "id": 10021, "Key": "xhm", - "enUS": " Winged Helm ", + "enUS": "Winged Helm ", "zhTW": "翼盔", "deDE": "Flügelhelm", "esES": "[ms]Yelmo alado", @@ -11137,7 +11137,7 @@ { "id": 10022, "Key": "Hsarus' Defense", - "enUS": " Hsarus' Defense ", + "enUS": "Hsarus' Defense ", "zhTW": "海沙魯的鐵禦", "deDE": "Hsarus' Verteidigung", "esES": "Defensa de Hsarus", @@ -11154,7 +11154,7 @@ { "id": 10122, "Key": "Civerb's Ward", - "enUS": " Civerb's Ward ", + "enUS": "Civerb's Ward ", "zhTW": "克維雷布的防護", "deDE": "Civerbs Schutz", "esES": "Custodia de Civerb", @@ -11171,7 +11171,7 @@ { "id": 10123, "Key": "Civerb's Icon", - "enUS": " Civerb's Icon ", + "enUS": "Civerb's Icon ", "zhTW": "克維雷布的聖像", "deDE": "Civerbs Symbol", "esES": "Icono de Civerb", @@ -11188,7 +11188,7 @@ { "id": 10124, "Key": "Civerb's Cudgel", - "enUS": " Civerb's Cudgel ", + "enUS": "Civerb's Cudgel ", "zhTW": "克維雷布的短棍", "deDE": "Civerbs Knüttel", "esES": "Garrote de Civerb", @@ -11205,7 +11205,7 @@ { "id": 10125, "Key": "Hsarus' Iron Heel", - "enUS": " Hsarus' Iron Heel ", + "enUS": "Hsarus' Iron Heel ", "zhTW": "海沙魯的鐵跟", "deDE": "Hsarus' Eisenferse", "esES": "Talón de hierro de Hsarus", @@ -11222,7 +11222,7 @@ { "id": 10126, "Key": "Hsarus' Iron Fist", - "enUS": " Hsarus' Iron Fist ", + "enUS": "Hsarus' Iron Fist ", "zhTW": "海沙魯的鐵拳", "deDE": "Hsarus' Eisenfaust", "esES": "Puño de hierro de Hsarus", @@ -11239,7 +11239,7 @@ { "id": 10127, "Key": "Hsarus' Iron Stay", - "enUS": " Hsarus' Iron Stay ", + "enUS": "Hsarus' Iron Stay ", "zhTW": "海沙魯的鐵扣", "deDE": "Hsarus' Eisenstütze", "esES": "Cinturón de hierro de Hsarus", @@ -11256,7 +11256,7 @@ { "id": 10128, "Key": "Cleglaw's Tooth", - "enUS": " Cleglaw's Tooth ", + "enUS": "Cleglaw's Tooth ", "zhTW": "克雷德勞之牙", "deDE": "Cleglaws Zahn", "esES": "Diente de Cleglaw", @@ -11273,7 +11273,7 @@ { "id": 10129, "Key": "Cleglaw's Claw", - "enUS": " Cleglaw's Claw ", + "enUS": "Cleglaw's Claw ", "zhTW": "克雷德勞之爪", "deDE": "Cleglaws Kralle", "esES": "Garra de Cleglaw", @@ -11290,7 +11290,7 @@ { "id": 10130, "Key": "Cleglaw's Pincers", - "enUS": " Cleglaw's Pincers ", + "enUS": "Cleglaw's Pincers ", "zhTW": "克雷德勞之鉗", "deDE": "Cleglaws Kneifer", "esES": "Pinzas de Cleglaw", @@ -11307,7 +11307,7 @@ { "id": 10131, "Key": "Iratha's Cord", - "enUS": " Iratha's Cord ", + "enUS": "Iratha's Cord ", "zhTW": "依雷撒的腰繩", "deDE": "Irathas Band", "esES": "Cordón de Iratha", @@ -11324,7 +11324,7 @@ { "id": 10132, "Key": "Iratha's Coil", - "enUS": " Iratha's Coil ", + "enUS": "Iratha's Coil ", "zhTW": "依雷撒的盤頂", "deDE": "Irathas Rolle", "esES": "Rosca de Iratha", @@ -11341,7 +11341,7 @@ { "id": 10133, "Key": "Iratha's Cuff", - "enUS": " Iratha's Cuff ", + "enUS": "Iratha's Cuff ", "zhTW": "依雷撒的袖銬", "deDE": "Irathas Ärmelaufschläge", "esES": "Esposas de Iratha", @@ -11358,7 +11358,7 @@ { "id": 10134, "Key": "Iratha's Collar", - "enUS": " Iratha's Collar ", + "enUS": "Iratha's Collar ", "zhTW": "依雷撒的項圈", "deDE": "Irathas Kragen", "esES": "Gargantilla de Iratha", @@ -11375,7 +11375,7 @@ { "id": 10135, "Key": "Isenhart's Horns", - "enUS": " Isenhart's Horns ", + "enUS": "Isenhart's Horns ", "zhTW": "依森哈特的角盔", "deDE": "Isenharts Hörner", "esES": "Cuernos de Isenhart", @@ -11392,7 +11392,7 @@ { "id": 10136, "Key": "Isenhart's Case", - "enUS": " Isenhart's Case ", + "enUS": "Isenhart's Case ", "zhTW": "依森哈特的外殼", "deDE": "Isenharts Kiste", "esES": "Funda de Isenhart", @@ -11409,7 +11409,7 @@ { "id": 10137, "Key": "Isenhart's Parry", - "enUS": " Isenhart's Parry ", + "enUS": "Isenhart's Parry ", "zhTW": "依森哈特的招架", "deDE": "Isenharts Parade", "esES": "Evasión de Isenhart", @@ -11426,7 +11426,7 @@ { "id": 10138, "Key": "Isenhart's Lightbrand", - "enUS": " Isenhart's Lightbrand ", + "enUS": "Isenhart's Lightbrand ", "zhTW": "依森哈特的光之烙鐵", "deDE": "Isenharts Lichtbrand", "esES": "Tizón de luz de Isenhart", @@ -11443,7 +11443,7 @@ { "id": 10139, "Key": "Vidala's Snare", - "enUS": " Vidala's Snare ", + "enUS": "Vidala's Snare ", "zhTW": "維達拉的圈套", "deDE": "Vidalas Schlinge", "esES": "Cepo de Vidala", @@ -11460,7 +11460,7 @@ { "id": 10140, "Key": "Vidala's Ambush", - "enUS": " Vidala's Ambush ", + "enUS": "Vidala's Ambush ", "zhTW": "維達拉的突襲", "deDE": "Vidalas Hinterhalt", "esES": "Emboscada de Vidala", @@ -11477,7 +11477,7 @@ { "id": 10141, "Key": "Vidala's Fetlock", - "enUS": " Vidala's Fetlock ", + "enUS": "Vidala's Fetlock ", "zhTW": "維達拉的足距", "deDE": "Vidalas Behang", "esES": "Espolón de Vidala", @@ -11494,7 +11494,7 @@ { "id": 10142, "Key": "Vidala's Barb", - "enUS": " Vidala's Barb ", + "enUS": "Vidala's Barb ", "zhTW": "維達拉的倒刺", "deDE": "Vidalas Dorn", "esES": "Púa de Vidala", @@ -11511,7 +11511,7 @@ { "id": 10143, "Key": "Milabrega's Robe", - "enUS": " Milabrega's Robe ", + "enUS": "Milabrega's Robe ", "zhTW": "米拉伯佳外袍", "deDE": "Milabregas Robe", "esES": "Toga de Milabrega", @@ -11528,7 +11528,7 @@ { "id": 10144, "Key": "Milabrega's Diadem", - "enUS": " Milabrega's Diadem ", + "enUS": "Milabrega's Diadem ", "zhTW": "米拉伯佳權冠", "deDE": "Milabregas Diadem", "esES": "Diadema de Milabrega", @@ -11545,7 +11545,7 @@ { "id": 10145, "Key": "Milabrega's Rod", - "enUS": " Milabrega's Rod ", + "enUS": "Milabrega's Rod ", "zhTW": "米拉伯佳節杖", "deDE": "Milabregas Stab", "esES": "Vara de Milabrega", @@ -11562,7 +11562,7 @@ { "id": 10146, "Key": "Milabrega's Orb", - "enUS": " Milabrega's Orb ", + "enUS": "Milabrega's Orb ", "zhTW": "米拉伯佳之球", "deDE": "Milabregas Kugel", "esES": "Orbe de Milabrega", @@ -11579,7 +11579,7 @@ { "id": 10147, "Key": "Cathan's Seal", - "enUS": " Cathan's Seal ", + "enUS": "Cathan's Seal ", "zhTW": "卡珊的封印", "deDE": "Cathans Siegel", "esES": "Sello de Cathan", @@ -11596,7 +11596,7 @@ { "id": 10148, "Key": "Cathan's Sigil", - "enUS": " Cathan's Sigil ", + "enUS": "Cathan's Sigil ", "zhTW": "卡珊的魔咒", "deDE": "Cathans Siegelring", "esES": "Sigilo de Cathan", @@ -11613,7 +11613,7 @@ { "id": 10149, "Key": "Cathan's Visage", - "enUS": " Cathan's Visage ", + "enUS": "Cathan's Visage ", "zhTW": "卡珊的容貌", "deDE": "Cathans Fratze", "esES": "Semblante de Cathan", @@ -11630,7 +11630,7 @@ { "id": 10150, "Key": "Cathan's Mesh", - "enUS": " Cathan's Mesh ", + "enUS": "Cathan's Mesh ", "zhTW": "卡珊的網衣", "deDE": "Cathans Kettenrüstung", "esES": "Malla de Cathan", @@ -11647,7 +11647,7 @@ { "id": 10151, "Key": "Cathan's Rule", - "enUS": " Cathan's Rule ", + "enUS": "Cathan's Rule ", "zhTW": "卡珊的尺杖", "deDE": "Cathans Herrschaft", "esES": "Mando de Cathan", @@ -11664,7 +11664,7 @@ { "id": 10152, "Key": "Tancred's Crowbill", - "enUS": " Tancred's Crowbill ", + "enUS": "Tancred's Crowbill ", "zhTW": "坦克雷的鴉嘴鎬", "deDE": "Tankreds Bogenpicke", "esES": "Pico de cuervo de Tancred", @@ -11681,7 +11681,7 @@ { "id": 10153, "Key": "Tancred's Spine", - "enUS": " Tancred's Spine ", + "enUS": "Tancred's Spine ", "zhTW": "坦克雷的脊柱", "deDE": "Tankreds Stachel", "esES": "Espinazo de Tancred", @@ -11698,7 +11698,7 @@ { "id": 10154, "Key": "Tancred's Hobnails", - "enUS": " Tancred's Hobnails ", + "enUS": "Tancred's Hobnails ", "zhTW": "坦克雷的釘靴", "deDE": "Tankreds Schuhnägel", "esES": "Tachuelas de Tancred", @@ -11715,7 +11715,7 @@ { "id": 10155, "Key": "Tancred's Weird", - "enUS": " Tancred's Weird ", + "enUS": "Tancred's Weird ", "zhTW": "坦克雷的怪誕", "deDE": "Tankreds Bann", "esES": "Misterio de Tancred", @@ -11732,7 +11732,7 @@ { "id": 10156, "Key": "Tancred's Skull", - "enUS": " Tancred's Skull ", + "enUS": "Tancred's Skull ", "zhTW": "坦克雷的顱骨", "deDE": "Tankreds Schädel", "esES": "Cráneo de Tancred", @@ -11749,7 +11749,7 @@ { "id": 10157, "Key": "Sigon's Visor", - "enUS": " Sigon's Visor ", + "enUS": "Sigon's Visor ", "zhTW": "西剛的護面", "deDE": "Sigons Visier", "esES": "Visera de Sigon", @@ -11766,7 +11766,7 @@ { "id": 10158, "Key": "Sigon's Shelter", - "enUS": " Sigon's Shelter ", + "enUS": "Sigon's Shelter ", "zhTW": "西剛的庇護", "deDE": "Sigons Schutz", "esES": "Refugio de Sigon", @@ -11783,7 +11783,7 @@ { "id": 10159, "Key": "Sigon's Gage", - "enUS": " Sigon's Gage ", + "enUS": "Sigon's Gage ", "zhTW": "西剛的挑戰", "deDE": "Sigons Messgerät", "esES": "Reto de Sigon", @@ -11800,7 +11800,7 @@ { "id": 10160, "Key": "Sigon's Sabot", - "enUS": " Sigon's Sabot ", + "enUS": "Sigon's Sabot ", "zhTW": "西剛的硬靴", "deDE": "Sigons Schuh", "esES": "Zuecos de Sigon", @@ -11817,7 +11817,7 @@ { "id": 10161, "Key": "Sigon's Wrap", - "enUS": " Sigon's Wrap ", + "enUS": "Sigon's Wrap ", "zhTW": "西剛的裹腰", "deDE": "Sigons Umhang", "esES": "Cinto de Sigon", @@ -11834,7 +11834,7 @@ { "id": 10162, "Key": "Sigon's Guard", - "enUS": " Sigon's Guard ", + "enUS": "Sigon's Guard ", "zhTW": "西剛的守護", "deDE": "Sigons Wächter", "esES": "Protección de Sigon", @@ -11851,7 +11851,7 @@ { "id": 10163, "Key": "Infernal Cranium", - "enUS": " Infernal Cranium ", + "enUS": "Infernal Cranium ", "zhTW": "煉獄頭骨", "deDE": "Infernos Schädel", "esES": "Cráneo infernal", @@ -11868,7 +11868,7 @@ { "id": 10164, "Key": "Infernal Torch", - "enUS": " Infernal Torch ", + "enUS": "Infernal Torch ", "zhTW": "煉獄火炬", "deDE": "Infernos Fackel", "esES": "Antorcha infernal", @@ -11885,7 +11885,7 @@ { "id": 10165, "Key": "Infernal Sign", - "enUS": " Infernal Sign ", + "enUS": "Infernal Sign ", "zhTW": "煉獄符印", "deDE": "Infernos Zeichen", "esES": "Símbolo infernal", @@ -11902,7 +11902,7 @@ { "id": 10166, "Key": "Berserker's Headgear", - "enUS": " Berserker's Headgear ", + "enUS": "Berserker's Headgear ", "zhTW": "狂戰士頭盔", "deDE": "Berserkers Kopfschmuck", "esES": "Casco del berserker", @@ -11919,7 +11919,7 @@ { "id": 10167, "Key": "Berserker's Hauberk", - "enUS": " Berserker's Hauberk ", + "enUS": "Berserker's Hauberk ", "zhTW": "狂戰士鎖子甲", "deDE": "Berserkers Halsberge", "esES": "Loriga del berserker", @@ -11936,7 +11936,7 @@ { "id": 10168, "Key": "Berserker's Hatchet", - "enUS": " Berserker's Hatchet ", + "enUS": "Berserker's Hatchet ", "zhTW": "狂戰士手斧", "deDE": "Berserkers Kriegsbeil", "esES": "Hachuela del berserker", @@ -11953,7 +11953,7 @@ { "id": 10169, "Key": "Death's Hand", - "enUS": " Death's Hand ", + "enUS": "Death's Hand ", "zhTW": "死亡之手", "deDE": "Hand des Todes", "esES": "Mano de la muerte", @@ -11970,7 +11970,7 @@ { "id": 10170, "Key": "Death's Guard", - "enUS": " Death's Guard ", + "enUS": "Death's Guard ", "zhTW": "死亡之護", "deDE": "Wächter des Todes", "esES": "Protección de la muerte", @@ -11987,7 +11987,7 @@ { "id": 10171, "Key": "Death's Touch", - "enUS": " Death's Touch ", + "enUS": "Death's Touch ", "zhTW": "死亡之觸", "deDE": "Berührung des Todes", "esES": "Toque de la muerte", @@ -12004,7 +12004,7 @@ { "id": 10172, "Key": "Angelic Sickle", - "enUS": " Angelic Sickle ", + "enUS": "Angelic Sickle ", "zhTW": "天使的鐮刀", "deDE": "Himmlische Sichel", "esES": "Hoz angelical", @@ -12021,7 +12021,7 @@ { "id": 10173, "Key": "Angelic Mantle", - "enUS": " Angelic Mantle ", + "enUS": "Angelic Mantle ", "zhTW": "天使的披風", "deDE": "Himmlischer Überwurf", "esES": "Manto angelical", @@ -12038,7 +12038,7 @@ { "id": 10174, "Key": "Angelic Halo", - "enUS": " Angelic Halo ", + "enUS": "Angelic Halo ", "zhTW": "天使的光暈", "deDE": "Himmlischer Heiligenschein", "esES": "Halo angelical", @@ -12055,7 +12055,7 @@ { "id": 10175, "Key": "Angelic Wings", - "enUS": " Angelic Wings ", + "enUS": "Angelic Wings ", "zhTW": "天使的翅膀", "deDE": "Himmlische Flügel", "esES": "Alas angelicales", @@ -12072,7 +12072,7 @@ { "id": 10176, "Key": "Arctic Horn", - "enUS": " Arctic Horn ", + "enUS": "Arctic Horn ", "zhTW": "北極號角", "deDE": "Arktisches Horn", "esES": "Cuerno ártico", @@ -12089,7 +12089,7 @@ { "id": 10177, "Key": "Arctic Furs", - "enUS": " Arctic Furs ", + "enUS": "Arctic Furs ", "zhTW": "北極毛皮", "deDE": "Arktische Pelze", "esES": "Pieles árticas", @@ -12106,7 +12106,7 @@ { "id": 10178, "Key": "Arctic Binding", - "enUS": " Arctic Binding ", + "enUS": "Arctic Binding ", "zhTW": "北極捆索", "deDE": "Arktische Bindung", "esES": "Correa ártica", @@ -12123,7 +12123,7 @@ { "id": 10179, "Key": "Arctic Mitts", - "enUS": " Arctic Mitts ", + "enUS": "Arctic Mitts ", "zhTW": "北極手套", "deDE": "Arktische Handschuhe", "esES": "Mitones árticos", @@ -12140,7 +12140,7 @@ { "id": 10180, "Key": "Arcanna's Sign", - "enUS": " Arcanna's Sign ", + "enUS": "Arcanna's Sign ", "zhTW": "阿卡娜的符印", "deDE": "Arcannas Zeichen", "esES": "Símbolo de Arcanna", @@ -12157,7 +12157,7 @@ { "id": 10181, "Key": "Arcanna's Deathwand", - "enUS": " Arcanna's Deathwand ", + "enUS": "Arcanna's Deathwand ", "zhTW": "阿卡娜的死亡之杖", "deDE": "Arcannas Todesstab", "esES": "Vara de la muerte de Arcanna", @@ -12174,7 +12174,7 @@ { "id": 10182, "Key": "Arcanna's Head", - "enUS": " Arcanna's Head ", + "enUS": "Arcanna's Head ", "zhTW": "阿卡娜的頭", "deDE": "Arcannas Kopf", "esES": "Cabeza de Arcanna", @@ -12191,7 +12191,7 @@ { "id": 10183, "Key": "Arcanna's Flesh", - "enUS": " Arcanna's Flesh ", + "enUS": "Arcanna's Flesh ", "zhTW": "阿卡娜的血肉", "deDE": "Arcannas Fleisch", "esES": "Carne de Arcanna", @@ -12208,7 +12208,7 @@ { "id": 10911, "Key": "Whichwild String", - "enUS": " Witchwild String ", + "enUS": "Witchwild String ", "zhTW": "狂巫之弦", "deDE": "Wilde Kette", "esES": "Cuerda salvaje", @@ -12225,7 +12225,7 @@ { "id": 11006, "Key": "neg", - "enUS": " Hellspawn Skull ", + "enUS": "Hellspawn Skull ", "zhTW": "地獄爪牙顱骨", "deDE": "[ms]Höllenbrutschädel", "esES": "[ms]Cráneo del averno", @@ -12242,7 +12242,7 @@ { "id": 11008, "Key": "uhf", - "enUS": " Legendary Mallet ", + "enUS": "Legendary Mallet ", "zhTW": "傳說戰鎚", "deDE": "[ms]Legendärer Hammer", "esES": "[ms]Mazo legendario", @@ -12259,7 +12259,7 @@ { "id": 11010, "Key": "7wa", - "enUS": " Berserker Axe ", + "enUS": "Berserker Axe ", "zhTW": "狂戰斧", "deDE": "[fs]Berserkeraxt", "esES": "[fs]Hacha de berserker", @@ -12276,7 +12276,7 @@ { "id": 11012, "Key": "xhg", - "enUS": " War Gauntlets ", + "enUS": "War Gauntlets ", "zhTW": "征戰護手", "deDE": "Kriegspanzerhandschuhe", "esES": "[mp]Guanteletes de guerra", @@ -12293,7 +12293,7 @@ { "id": 11028, "Key": "9bl", - "enUS": " Stiletto ", + "enUS": "Stiletto ", "zhTW": "窄刃匕首", "deDE": "[ns]Stilett", "esES": "[ms]Stiletto", @@ -12310,7 +12310,7 @@ { "id": 11146, "Key": "pk1", - "enUS": " Key of Terror ", + "enUS": "Key of Terror ", "zhTW": "恐懼之鑰", "deDE": "Schlüssel des Terrors", "esES": "Llave del terror", @@ -12327,7 +12327,7 @@ { "id": 11147, "Key": "pk2", - "enUS": " Key of Hate ", + "enUS": "Key of Hate ", "zhTW": "憎恨之鑰", "deDE": "Schlüssel des Hasses", "esES": "Llave del odio", @@ -12344,7 +12344,7 @@ { "id": 11148, "Key": "pk3", - "enUS": " Key of Destruction ", + "enUS": "Key of Destruction ", "zhTW": "毀滅之鑰", "deDE": "Schlüssel der Zerstörung", "esES": "Llave de la destrucción", @@ -12361,7 +12361,7 @@ { "id": 11149, "Key": "dhn", - "enUS": " Diablo's Horn ", + "enUS": "Diablo's Horn ", "zhTW": "迪亞布羅之角", "deDE": "Diablos Horn", "esES": "Cuerno de Diablo", @@ -12378,7 +12378,7 @@ { "id": 11150, "Key": "bey", - "enUS": " Baal's Eye ", + "enUS": "Baal's Eye ", "zhTW": "巴爾之眼", "deDE": "Baals Auge", "esES": "Ojo de Baal", @@ -12395,7 +12395,7 @@ { "id": 11151, "Key": "mbr", - "enUS": " Mephisto's Brain ", + "enUS": "Mephisto's Brain ", "zhTW": "墨菲斯托之腦", "deDE": "Mephistos Gehirn", "esES": "Cerebro de Mefisto", @@ -12412,7 +12412,7 @@ { "id": 11152, "Key": "std", - "enUS": " Standard of Heroes ", + "enUS": "Standard of Heroes ", "zhTW": "英雄旗幟", "deDE": "Standarte der Helden", "esES": "Estandarte de los héroes", @@ -12429,7 +12429,7 @@ { "id": 11153, "Key": "Hellfire Torch", - "enUS": " Hellfire Torch ", + "enUS": "Hellfire Torch ", "zhTW": "地獄火炬", "deDE": "Höllenfeuerfackel", "esES": "Antorcha de fuego infernal", @@ -12446,7 +12446,7 @@ { "id": 11164, "Key": "tes", - "enUS": " Twisted Essence of Suffering ", + "enUS": "Twisted Essence of Suffering ", "zhTW": "扭曲的苦怨精華", "deDE": "Verdorbene Essenz des Leidens", "esES": "Esencia del sufrimiento retorcida", @@ -12463,7 +12463,7 @@ { "id": 11165, "Key": "ceh", - "enUS": " Charged Essence of Hatred ", + "enUS": "Charged Essence of Hatred ", "zhTW": "充盈的憎恨精華", "deDE": "Geladene Essenz des Hasses", "esES": "Esencia del odio cargada", @@ -12480,7 +12480,7 @@ { "id": 11166, "Key": "bet", - "enUS": " Burning Essence of Terror ", + "enUS": "Burning Essence of Terror ", "zhTW": "燃燒的恐懼精華", "deDE": "Brennende Essenz des Schreckens", "esES": "Esencia del terror ardiente", @@ -12497,7 +12497,7 @@ { "id": 11167, "Key": "fed", - "enUS": " Festering Essence of Destruction ", + "enUS": "Festering Essence of Destruction ", "zhTW": "潰爛的毀滅精華", "deDE": "Eiternde Essenz der Zerstörung", "esES": "Esencia de la destrucción infecta", @@ -12514,7 +12514,7 @@ { "id": 20181, "Key": "ktr", - "enUS": " Katar ", + "enUS": "Katar ", "zhTW": "拳刃", "deDE": "[ms]Katar", "esES": "[ms]Katar", @@ -12531,7 +12531,7 @@ { "id": 20182, "Key": "wrb", - "enUS": " Wrist Blade ", + "enUS": "Wrist Blade ", "zhTW": "腕刃", "deDE": "[fs]Unterarmklinge", "esES": "[fs]Cuchilla de muñeca", @@ -12548,7 +12548,7 @@ { "id": 20183, "Key": "ces", - "enUS": " Cestus ", + "enUS": "Cestus ", "zhTW": "刃拳", "deDE": "[ms]Cestus", "esES": "[ms]Cestus", @@ -12565,7 +12565,7 @@ { "id": 20184, "Key": "clw", - "enUS": " Claws ", + "enUS": "Claws ", "zhTW": "爪", "deDE": "[pl]Klauen", "esES": "[fp]Garras", @@ -12582,7 +12582,7 @@ { "id": 20185, "Key": "btl", - "enUS": " Blade Talons ", + "enUS": "Blade Talons ", "zhTW": "刃爪", "deDE": "[pl]Klingenklauen", "esES": "[fp]Garfas tajantes", @@ -12599,7 +12599,7 @@ { "id": 20186, "Key": "skr", - "enUS": " Scissors Katar ", + "enUS": "Scissors Katar ", "zhTW": "剪刃", "deDE": "[ms]Scherenkatar", "esES": "[ms]Katar tijera", @@ -12616,7 +12616,7 @@ { "id": 20187, "Key": "9ar", - "enUS": " Quhab ", + "enUS": "Quhab ", "zhTW": "格鬥刃", "deDE": "[ns]Quhab", "esES": "[ms]Quhab", @@ -12633,7 +12633,7 @@ { "id": 20188, "Key": "9wb", - "enUS": " Wrist Spike ", + "enUS": "Wrist Spike ", "zhTW": "腕刺", "deDE": "[ms]Unterarmdorn", "esES": "[fs]Punta de muñeca", @@ -12650,7 +12650,7 @@ { "id": 20189, "Key": "9xf", - "enUS": " Fascia ", + "enUS": "Fascia ", "zhTW": "格鬥爪", "deDE": "[fs]Faszie", "esES": "[fs]Fascia", @@ -12667,7 +12667,7 @@ { "id": 20190, "Key": "9cs", - "enUS": " Hand Scythe ", + "enUS": "Hand Scythe ", "zhTW": "手鐮", "deDE": "[fs]Handsichel", "esES": "[fs]Guadaña de mano", @@ -12684,7 +12684,7 @@ { "id": 20191, "Key": "9lw", - "enUS": " Greater Claws ", + "enUS": "Greater Claws ", "zhTW": "巨爪", "deDE": "[pl]Großkrallen", "esES": "[fp]Garras enormes", @@ -12701,7 +12701,7 @@ { "id": 20192, "Key": "9tw", - "enUS": " Greater Talons ", + "enUS": "Greater Talons ", "zhTW": "巨鷹爪", "deDE": "[pl]Großklauen", "esES": "[fp]Garfas enormes", @@ -12718,7 +12718,7 @@ { "id": 20193, "Key": "9qr", - "enUS": " Scissors Quhab ", + "enUS": "Scissors Quhab ", "zhTW": "格鬥剪刃", "deDE": "[ns]Scherenquhab", "esES": "[ms]Quhab tijera", @@ -12735,7 +12735,7 @@ { "id": 20194, "Key": "7ar", - "enUS": " Suwayyah ", + "enUS": "Suwayyah ", "zhTW": "穿擊拳刃", "deDE": "[ns]Suwayyah", "esES": "[ms]Suwayyah", @@ -12752,7 +12752,7 @@ { "id": 20195, "Key": "7wb", - "enUS": " Wrist Sword ", + "enUS": "Wrist Sword ", "zhTW": "腕劍", "deDE": "[ns]Unterarmschwert", "esES": "[fs]Espada de muñeca", @@ -12769,7 +12769,7 @@ { "id": 20196, "Key": "7xf", - "enUS": " War Fist ", + "enUS": "War Fist ", "zhTW": "征戰拳套", "deDE": "[fs]Kriegsfaust", "esES": "[ms]Puño de guerra", @@ -12786,7 +12786,7 @@ { "id": 20197, "Key": "7cs", - "enUS": " Battle Cestus ", + "enUS": "Battle Cestus ", "zhTW": "戰鬥刃拳", "deDE": "[ms]Kampfcestus", "esES": "[ms]Cestus de batalla", @@ -12803,7 +12803,7 @@ { "id": 20198, "Key": "7lw", - "enUS": " Feral Claws ", + "enUS": "Feral Claws ", "zhTW": "蠻獸爪", "deDE": "[pl]Barbarenkrallen", "esES": "[fp]Garras ferales", @@ -12820,7 +12820,7 @@ { "id": 20199, "Key": "7tw", - "enUS": " Runic Talons ", + "enUS": "Runic Talons ", "zhTW": "符紋爪", "deDE": "[pl]Runenklauen", "esES": "[fp]Garfas rúnicas", @@ -12837,7 +12837,7 @@ { "id": 20200, "Key": "7qr", - "enUS": " Scissors Suwayyah ", + "enUS": "Scissors Suwayyah ", "zhTW": "穿擊剪刃", "deDE": "[ns]Scherensuwayyah", "esES": "[ms]Suwayyah tijera", @@ -12854,7 +12854,7 @@ { "id": 20201, "Key": "7ha", - "enUS": " Tomahawk ", + "enUS": "Tomahawk ", "zhTW": "輕斧", "deDE": "[ns]Tomahawk", "esES": "[ms]Tomahawk", @@ -12871,7 +12871,7 @@ { "id": 20202, "Key": "7ax", - "enUS": " Small Crescent ", + "enUS": "Small Crescent ", "zhTW": "彎月斧", "deDE": "[fs]Kleine Sichel", "esES": "[fs]Medialuna pequeña", @@ -12888,7 +12888,7 @@ { "id": 20203, "Key": "72a", - "enUS": " Ettin Axe ", + "enUS": "Ettin Axe ", "zhTW": "雙頭斧", "deDE": "[fs]Ettinaxt", "esES": "[fs]Hacha de Ettin", @@ -12905,7 +12905,7 @@ { "id": 20204, "Key": "7mp", - "enUS": " War Spike ", + "enUS": "War Spike ", "zhTW": "征戰鎬", "deDE": "[ms]Kriegsdorn", "esES": "[fs]Punta de guerra", @@ -12922,7 +12922,7 @@ { "id": 20206, "Key": "7la", - "enUS": " Feral Axe ", + "enUS": "Feral Axe ", "zhTW": "蠻野斧", "deDE": "[fs]Barbarenaxt", "esES": "[fs]Hacha feral", @@ -12939,7 +12939,7 @@ { "id": 20207, "Key": "7ba", - "enUS": " Silver-edged Axe ", + "enUS": "Silver-edged Axe ", "zhTW": "銀刃斧", "deDE": "Versilberte Axt", "esES": "[fs]Hacha de filo plateado", @@ -12956,7 +12956,7 @@ { "id": 20208, "Key": "7bt", - "enUS": " Decapitator ", + "enUS": "Decapitator ", "zhTW": "斬首斧", "deDE": "[ms]Enthaupter", "esES": "[fs]Decapitadora", @@ -12973,7 +12973,7 @@ { "id": 20209, "Key": "7ga", - "enUS": " Champion Axe ", + "enUS": "Champion Axe ", "zhTW": "豪傑斧", "deDE": "[fs]Heldenaxt", "esES": "[fs]Hacha del campeón", @@ -12990,7 +12990,7 @@ { "id": 20210, "Key": "7gi", - "enUS": " Glorious Axe ", + "enUS": "Glorious Axe ", "zhTW": "榮光斧", "deDE": "[fs]Ruhmesaxt", "esES": "[fs]Hacha gloriosa", @@ -13007,7 +13007,7 @@ { "id": 20211, "Key": "7wn", - "enUS": " Polished Wand ", + "enUS": "Polished Wand ", "zhTW": "拋光魔杖", "deDE": "[ms]Polierter Stab", "esES": "[fs]Vara pulida", @@ -13024,7 +13024,7 @@ { "id": 20212, "Key": "7yw", - "enUS": " Ghost Wand ", + "enUS": "Ghost Wand ", "zhTW": "鬼魂魔杖", "deDE": "[ms]Geisterstab", "esES": "[fs]Vara fantasmal", @@ -13041,7 +13041,7 @@ { "id": 20213, "Key": "7bw", - "enUS": " Lich Wand ", + "enUS": "Lich Wand ", "zhTW": "巫妖魔杖", "deDE": "[ms]Lichstab", "esES": "[fs]Vara de exánime", @@ -13058,7 +13058,7 @@ { "id": 20214, "Key": "7gw", - "enUS": " Unearthed Wand ", + "enUS": "Unearthed Wand ", "zhTW": "埋骨魔杖", "deDE": "[ms]Ausgegrabener Stab", "esES": "[fs]Vara desenterrada", @@ -13075,7 +13075,7 @@ { "id": 20215, "Key": "7cl", - "enUS": " Truncheon ", + "enUS": "Truncheon ", "zhTW": "打擊棍", "deDE": "[ms]Schlagstock", "esES": "[fs]Tranca", @@ -13092,7 +13092,7 @@ { "id": 20216, "Key": "7sc", - "enUS": " Mighty Scepter ", + "enUS": "Mighty Scepter ", "zhTW": "強威權杖", "deDE": "[ns]Mächtiges Szepter", "esES": "[ms]Cetro poderoso", @@ -13109,7 +13109,7 @@ { "id": 20217, "Key": "7qs", - "enUS": " Seraph Rod ", + "enUS": "Seraph Rod ", "zhTW": "熾天使節杖", "deDE": "[ms]Seraphimstab", "esES": "[fs]Vara de serafín", @@ -13126,7 +13126,7 @@ { "id": 20218, "Key": "7ws", - "enUS": " Caduceus ", + "enUS": "Caduceus ", "zhTW": "神使權杖", "deDE": "[ms]Schlangenstab", "esES": "[ms]Caduceo", @@ -13143,7 +13143,7 @@ { "id": 20219, "Key": "7sp", - "enUS": " Tyrant Club ", + "enUS": "Tyrant Club ", "zhTW": "暴君棍棒", "deDE": "[ms]Tyrannentöter", "esES": "[fs]Porra de tirano", @@ -13160,7 +13160,7 @@ { "id": 20220, "Key": "7ma", - "enUS": " Reinforced Mace ", + "enUS": "Reinforced Mace ", "zhTW": "強化釘鎚", "deDE": "[ms]Verstärkter Streitkolben", "esES": "[fs]Maza reforzada", @@ -13177,7 +13177,7 @@ { "id": 20221, "Key": "7mt", - "enUS": " Devil Star ", + "enUS": "Devil Star ", "zhTW": "妖鬼釘頭鎚", "deDE": "[ms]Teufelsstern", "esES": "[fs]Estrella diabólica", @@ -13194,7 +13194,7 @@ { "id": 20222, "Key": "7fl", - "enUS": " Scourge ", + "enUS": "Scourge ", "zhTW": "罪罰連枷", "deDE": "[fs]Geißel", "esES": "[ms]Azote", @@ -13211,7 +13211,7 @@ { "id": 20223, "Key": "7wh", - "enUS": " Legendary Mallet ", + "enUS": "Legendary Mallet ", "zhTW": "傳說戰鎚", "deDE": "[ms]Legendärer Hammer", "esES": "[ms]Mazo legendario", @@ -13228,7 +13228,7 @@ { "id": 20224, "Key": "7m7", - "enUS": " Ogre Maul ", + "enUS": "Ogre Maul ", "zhTW": "巨魔重鎚", "deDE": "[ms]Ogerhammer", "esES": "[fs]Almádena de ogro", @@ -13245,7 +13245,7 @@ { "id": 20225, "Key": "7gm", - "enUS": " Thunder Maul ", + "enUS": "Thunder Maul ", "zhTW": "雷霆重鎚", "deDE": "[ms]Donnerhammer", "esES": "[fs]Almádena del trueno", @@ -13262,7 +13262,7 @@ { "id": 20226, "Key": "7ss", - "enUS": " Falcata ", + "enUS": "Falcata ", "zhTW": "法卡塔劍", "deDE": "[fs]Falkata", "esES": "[fs]Falcata", @@ -13279,7 +13279,7 @@ { "id": 20227, "Key": "7sm", - "enUS": " Ataghan ", + "enUS": "Ataghan ", "zhTW": "土耳其彎刀", "deDE": "[ns]Yatagan", "esES": "[ms]Yatagán", @@ -13296,7 +13296,7 @@ { "id": 20228, "Key": "7sb", - "enUS": " Elegant Blade ", + "enUS": "Elegant Blade ", "zhTW": "典雅彎刀", "deDE": "[fs]Elegante Klinge", "esES": "[fs]Espada elegante", @@ -13313,7 +13313,7 @@ { "id": 20229, "Key": "7fc", - "enUS": " Hydra Edge ", + "enUS": "Hydra Edge ", "zhTW": "多頭蛇刃", "deDE": "[fs]Hydraschneide", "esES": "[ms]Filo de hidra", @@ -13330,7 +13330,7 @@ { "id": 20230, "Key": "7cr", - "enUS": " Phase Blade ", + "enUS": "Phase Blade ", "zhTW": "幻化之刃", "deDE": "[fs]Phasenklinge", "esES": "[fs]Espada de fase", @@ -13347,7 +13347,7 @@ { "id": 20231, "Key": "7bs", - "enUS": " Conquest Sword ", + "enUS": "Conquest Sword ", "zhTW": "征服之劍", "deDE": "[ns]Erobererschwert", "esES": "[fs]Espada de la conquista", @@ -13364,7 +13364,7 @@ { "id": 20232, "Key": "7ls", - "enUS": " Cryptic Sword ", + "enUS": "Cryptic Sword ", "zhTW": "絕秘劍", "deDE": "[ns]Rätselhaftes Schwert", "esES": "[fs]Espada críptica", @@ -13381,7 +13381,7 @@ { "id": 20233, "Key": "7wd", - "enUS": " Mythical Sword ", + "enUS": "Mythical Sword ", "zhTW": "秘儀劍", "deDE": "[ns]Mythisches Schwert", "esES": "[fs]Espada mítica", @@ -13398,7 +13398,7 @@ { "id": 20234, "Key": "72h", - "enUS": " Legend Sword ", + "enUS": "Legend Sword ", "zhTW": "傳說劍", "deDE": "[ns]Legendenschwert", "esES": "[fs]Espada de leyenda", @@ -13415,7 +13415,7 @@ { "id": 20235, "Key": "7cm", - "enUS": " Highland Blade ", + "enUS": "Highland Blade ", "zhTW": "高地劍", "deDE": "[fs]Hochlandklinge", "esES": "[fs]Espada de las Tierras Altas", @@ -13432,7 +13432,7 @@ { "id": 20236, "Key": "7gs", - "enUS": " Balrog Blade ", + "enUS": "Balrog Blade ", "zhTW": "炎魔之刃", "deDE": "[fs]Balrogklinge", "esES": "[fs]Espada de Balrog", @@ -13449,7 +13449,7 @@ { "id": 20237, "Key": "7b7", - "enUS": " Champion Sword ", + "enUS": "Champion Sword ", "zhTW": "豪傑大劍", "deDE": "[ns]Heldenschwert", "esES": "[fs]Espada del campeón", @@ -13466,7 +13466,7 @@ { "id": 20238, "Key": "7fb", - "enUS": " Colossus Sword ", + "enUS": "Colossus Sword ", "zhTW": "巨神劍", "deDE": "Kolossschwert", "esES": "[fs]Espada del coloso", @@ -13483,7 +13483,7 @@ { "id": 20239, "Key": "7gd", - "enUS": " Colossus Blade ", + "enUS": "Colossus Blade ", "zhTW": "巨神刃", "deDE": "[fs]Kolossklinge", "esES": "[fs]Hoja del coloso", @@ -13500,7 +13500,7 @@ { "id": 20240, "Key": "7dg", - "enUS": " Bone Knife ", + "enUS": "Bone Knife ", "zhTW": "骸骨小刀", "deDE": "[ns]Knochenmesser", "esES": "[ms]Cuchillo de hueso", @@ -13517,7 +13517,7 @@ { "id": 20241, "Key": "7di", - "enUS": " Mithril Point ", + "enUS": "Mithril Point ", "zhTW": "秘銀尖刀", "deDE": "[fs]Mithrilspitze", "esES": "[fs]Puya de mithril", @@ -13534,7 +13534,7 @@ { "id": 20242, "Key": "7kr", - "enUS": " Fanged Knife ", + "enUS": "Fanged Knife ", "zhTW": "尖齒小刀", "deDE": "[ns]Fangzahnmesser", "esES": "[ms]Cuchillo canino", @@ -13551,7 +13551,7 @@ { "id": 20243, "Key": "7bl", - "enUS": " Legend Spike ", + "enUS": "Legend Spike ", "zhTW": "傳說尖刀", "deDE": "[ms]Legendendorn", "esES": "[fs]Punta de leyenda", @@ -13568,7 +13568,7 @@ { "id": 20244, "Key": "7tk", - "enUS": " Flying Knife ", + "enUS": "Flying Knife ", "zhTW": "高速飛刀", "deDE": "[ns]Wurfmesser", "esES": "[ms]Cuchillo volador", @@ -13585,7 +13585,7 @@ { "id": 20245, "Key": "7ta", - "enUS": " Flying Axe ", + "enUS": "Flying Axe ", "zhTW": "高速飛斧", "deDE": "[fs]Flugaxt", "esES": "[fs]Hacha voladora", @@ -13602,7 +13602,7 @@ { "id": 20246, "Key": "7bk", - "enUS": " Winged Knife ", + "enUS": "Winged Knife ", "zhTW": "刃翼飛刀", "deDE": "[ms]Schwingendolch", "esES": "[ms]Cuchillo alado", @@ -13619,7 +13619,7 @@ { "id": 20247, "Key": "7b8", - "enUS": " Winged Axe ", + "enUS": "Winged Axe ", "zhTW": "刃翼飛斧", "deDE": "[fs]Schwingenaxt", "esES": "[fs]Hacha alada", @@ -13636,7 +13636,7 @@ { "id": 20248, "Key": "7ja", - "enUS": " Hyperion Javelin ", + "enUS": "Hyperion Javelin ", "zhTW": "亥伯龍標槍", "deDE": "[ms]Hyperionwurfspieß", "esES": "[fs]Jabalina de Hiperión", @@ -13653,7 +13653,7 @@ { "id": 20249, "Key": "7pi", - "enUS": " Stygian Pilum ", + "enUS": "Stygian Pilum ", "zhTW": "冥河標槍", "deDE": "[ms]Stygischer Spieß", "esES": "[ms]Pilum estigio", @@ -13670,7 +13670,7 @@ { "id": 20250, "Key": "7s7", - "enUS": " Balrog Spear ", + "enUS": "Balrog Spear ", "zhTW": "炎魔長矛", "deDE": "[ms]Balrogspeer", "esES": "[fs]Lanza de Balrog", @@ -13687,7 +13687,7 @@ { "id": 20251, "Key": "7gl", - "enUS": " Ghost Glaive ", + "enUS": "Ghost Glaive ", "zhTW": "鬼魂刃槍", "deDE": "[fs]Geistergleve", "esES": "[fs]Guja fantasmal", @@ -13704,7 +13704,7 @@ { "id": 20252, "Key": "7ts", - "enUS": " Winged Harpoon ", + "enUS": "Winged Harpoon ", "zhTW": "飛翼魚叉", "deDE": "[fs]Geflügelte Harpune", "esES": "[ms]Arpón alado", @@ -13721,7 +13721,7 @@ { "id": 20253, "Key": "7sr", - "enUS": " Hyperion Spear ", + "enUS": "Hyperion Spear ", "zhTW": "亥伯龍矛", "deDE": "[ms]Hyperionspeer", "esES": "[fs]Lanza de Hiperión", @@ -13738,7 +13738,7 @@ { "id": 20254, "Key": "7tr", - "enUS": " Stygian Pike ", + "enUS": "Stygian Pike ", "zhTW": "冥河戰矛", "deDE": "[fs]Stygische Pike", "esES": "[fs]Pica estigia", @@ -13755,7 +13755,7 @@ { "id": 20255, "Key": "7br", - "enUS": " Mancatcher ", + "enUS": "Mancatcher ", "zhTW": "捕人叉", "deDE": "[ms]Menschenfänger", "esES": "[ms]Cazahombres", @@ -13772,7 +13772,7 @@ { "id": 20256, "Key": "7st", - "enUS": " Ghost Spear ", + "enUS": "Ghost Spear ", "zhTW": "鬼魂長矛", "deDE": "[ms]Geisterspeer", "esES": "[fs]Lanza fantasmal", @@ -13789,7 +13789,7 @@ { "id": 20257, "Key": "7p7", - "enUS": " War Pike ", + "enUS": "War Pike ", "zhTW": "征戰長槍", "deDE": "[fs]Kriegspike", "esES": "[fs]Pica de guerra", @@ -13806,7 +13806,7 @@ { "id": 20258, "Key": "7o7", - "enUS": " Ogre Axe ", + "enUS": "Ogre Axe ", "zhTW": "巨魔斧", "deDE": "[fs]Ogeraxt", "esES": "[fs]Hacha de ogro", @@ -13823,7 +13823,7 @@ { "id": 20259, "Key": "7vo", - "enUS": " Colossus Voulge ", + "enUS": "Colossus Voulge ", "zhTW": "巨神長柄斧", "deDE": "[fs]Kolossvulge", "esES": "[ms]Voulge del coloso", @@ -13840,7 +13840,7 @@ { "id": 20260, "Key": "7s8", - "enUS": " Thresher ", + "enUS": "Thresher ", "zhTW": "斬鐮", "deDE": "[ms]Drescher", "esES": "[fs]Trilladora", @@ -13857,7 +13857,7 @@ { "id": 20261, "Key": "7pa", - "enUS": " Cryptic Axe ", + "enUS": "Cryptic Axe ", "zhTW": "絕秘斧", "deDE": "[fs]Rätselhafte Axt", "esES": "[fs]Hacha críptica", @@ -13874,7 +13874,7 @@ { "id": 20262, "Key": "7h7", - "enUS": " Great Poleaxe ", + "enUS": "Great Poleaxe ", "zhTW": "巨型長柄斧", "deDE": "[fs]Große Stangenaxt", "esES": "[fs]Gran hacha larga", @@ -13891,7 +13891,7 @@ { "id": 20263, "Key": "7wc", - "enUS": " Giant Thresher ", + "enUS": "Giant Thresher ", "zhTW": "巨型斬鐮", "deDE": "[ms]Riesendrescher", "esES": "[fs]Trilladora gigante", @@ -13908,7 +13908,7 @@ { "id": 20264, "Key": "6ss", - "enUS": " Walking Stick ", + "enUS": "Walking Stick ", "zhTW": "手杖", "deDE": "[ms]Gehstock", "esES": "[ms]Bordón", @@ -13925,7 +13925,7 @@ { "id": 20265, "Key": "6ls", - "enUS": " Stalagmite ", + "enUS": "Stalagmite ", "zhTW": "鐘乳石杖", "deDE": "[ms]Stalagmit", "esES": "[fs]Estalagmita", @@ -13942,7 +13942,7 @@ { "id": 20266, "Key": "6cs", - "enUS": " Elder Staff ", + "enUS": "Elder Staff ", "zhTW": "長者法杖", "deDE": "[ms]Ältestenstab", "esES": "[ms]Bastón de anciano", @@ -13959,7 +13959,7 @@ { "id": 20267, "Key": "6bs", - "enUS": " Shillelagh ", + "enUS": "Shillelagh ", "zhTW": "節瘤木杖", "deDE": "Shillelagh", "esES": "[ms]Shillelagh", @@ -13976,7 +13976,7 @@ { "id": 20268, "Key": "6ws", - "enUS": " Archon Staff ", + "enUS": "Archon Staff ", "zhTW": "統御者法杖", "deDE": "[ms]Archonstab", "esES": "[ms]Bastón de arconte", @@ -13993,7 +13993,7 @@ { "id": 20269, "Key": "6sb", - "enUS": " Spider Bow ", + "enUS": "Spider Bow ", "zhTW": "蜘蛛弓", "deDE": "[ms]Spinnenbogen", "esES": "[ms]Arco de araña", @@ -14010,7 +14010,7 @@ { "id": 20270, "Key": "6hb", - "enUS": " Blade Bow ", + "enUS": "Blade Bow ", "zhTW": "刀鋒弓", "deDE": "[ms]Klingenbogen", "esES": "[ms]Arco tajante", @@ -14027,7 +14027,7 @@ { "id": 20271, "Key": "6lb", - "enUS": " Shadow Bow ", + "enUS": "Shadow Bow ", "zhTW": "暗影弓", "deDE": "[ms]Schattenbogen", "esES": "[ms]Arco sombrío", @@ -14044,7 +14044,7 @@ { "id": 20272, "Key": "6cb", - "enUS": " Great Bow ", + "enUS": "Great Bow ", "zhTW": "巨弓", "deDE": "[ms]Langbogen", "esES": "[ms]Gran arco", @@ -14061,7 +14061,7 @@ { "id": 20273, "Key": "6s7", - "enUS": " Diamond Bow ", + "enUS": "Diamond Bow ", "zhTW": "鑽石弓", "deDE": "[ms]Diamantbogen", "esES": "[ms]Arco de diamante", @@ -14078,7 +14078,7 @@ { "id": 20274, "Key": "6l7", - "enUS": " Crusader Bow ", + "enUS": "Crusader Bow ", "zhTW": "聖教軍長弓", "deDE": "[ms]Kreuzritterbogen", "esES": "[ms]Arco de cruzada", @@ -14095,7 +14095,7 @@ { "id": 20275, "Key": "6sw", - "enUS": " Ward Bow ", + "enUS": "Ward Bow ", "zhTW": "庇護弓", "deDE": "[ms]Wächterbogen", "esES": "[ms]Arco de custodia", @@ -14112,7 +14112,7 @@ { "id": 20276, "Key": "6lw", - "enUS": " Hydra Bow ", + "enUS": "Hydra Bow ", "zhTW": "多頭蛇弓", "deDE": "[ms]Hydrabogen", "esES": "[ms]Arco de hidra", @@ -14129,7 +14129,7 @@ { "id": 20277, "Key": "6lx", - "enUS": " Pellet Bow ", + "enUS": "Pellet Bow ", "zhTW": "彈丸弩", "deDE": "[ms]Kugelbogen", "esES": "[ms]Arco de perdigones", @@ -14146,7 +14146,7 @@ { "id": 20278, "Key": "6mx", - "enUS": " Gorgon Crossbow ", + "enUS": "Gorgon Crossbow ", "zhTW": "蛇魔弩", "deDE": "[fs]Gorgonenarmbrust", "esES": "[fs]Ballesta de gorgona", @@ -14163,7 +14163,7 @@ { "id": 20279, "Key": "6hx", - "enUS": " Colossus Crossbow ", + "enUS": "Colossus Crossbow ", "zhTW": "巨神弩", "deDE": "[fs]Kolossarmbrust", "esES": "[fs]Ballesta del coloso", @@ -14180,7 +14180,7 @@ { "id": 20280, "Key": "6rx", - "enUS": " Demon Crossbow ", + "enUS": "Demon Crossbow ", "zhTW": "惡魔弩", "deDE": "[fs]Dämonenarmbrust", "esES": "[fs]Ballesta del demonio", @@ -14197,7 +14197,7 @@ { "id": 20281, "Key": "ob1", - "enUS": " Eagle Orb ", + "enUS": "Eagle Orb ", "zhTW": "鷹之法珠", "deDE": "[fs]Adlerkugel", "esES": "[ms]Orbe del águila", @@ -14214,7 +14214,7 @@ { "id": 20282, "Key": "ob2", - "enUS": " Sacred Globe ", + "enUS": "Sacred Globe ", "zhTW": "神聖天球", "deDE": "[fs]Heilige Kugel", "esES": "[ms]Globo sacro", @@ -14231,7 +14231,7 @@ { "id": 20283, "Key": "ob3", - "enUS": " Smoked Sphere ", + "enUS": "Smoked Sphere ", "zhTW": "攏煙之球", "deDE": "[fs]Rauchkugel", "esES": "[fs]Esfera ahumada", @@ -14248,7 +14248,7 @@ { "id": 20284, "Key": "ob4", - "enUS": " Clasped Orb ", + "enUS": "Clasped Orb ", "zhTW": "握扣法珠", "deDE": "[fs]Klammerkugel", "esES": "[ms]Orbe aferrado", @@ -14265,7 +14265,7 @@ { "id": 20285, "Key": "as1", - "enUS": " Wraps ", + "enUS": "Wraps ", "zhTW": "纏布", "deDE": "[pl]Umhänge", "esES": "[ms]Cinto", @@ -14282,7 +14282,7 @@ { "id": 20286, "Key": "as2", - "enUS": " Knuckles ", + "enUS": "Knuckles ", "zhTW": "手指虎", "deDE": "[ms]Schlagring", "esES": "[mp]Nudillos", @@ -14299,7 +14299,7 @@ { "id": 20287, "Key": "as3", - "enUS": " Slashers ", + "enUS": "Slashers ", "zhTW": "斬刃", "deDE": "[ms]Schlitzer", "esES": "[mp]Látigos", @@ -14316,7 +14316,7 @@ { "id": 20288, "Key": "as4", - "enUS": " Splay ", + "enUS": "Splay ", "zhTW": "展戟刃", "deDE": "[ms]Verspritzer", "esES": "[fs]Extensión", @@ -14333,7 +14333,7 @@ { "id": 20289, "Key": "as5", - "enUS": " Hook ", + "enUS": "Hook ", "zhTW": "勾", "deDE": "[ms]Haken", "esES": "[ms]Garfio", @@ -14350,7 +14350,7 @@ { "id": 20290, "Key": "as6", - "enUS": " Shank ", + "enUS": "Shank ", "zhTW": "鑽", "deDE": "[ms]Schaft", "esES": "[fs]Espinilla", @@ -14367,7 +14367,7 @@ { "id": 20291, "Key": "as7", - "enUS": " Claws ", + "enUS": "Claws ", "zhTW": "爪", "deDE": "[pl]Klauen", "esES": "[fp]Garras", @@ -14384,7 +14384,7 @@ { "id": 20292, "Key": "am1", - "enUS": " Stag Bow ", + "enUS": "Stag Bow ", "zhTW": "獵鹿弓", "deDE": "[ms]Hirschbogen", "esES": "[ms]Arco de ciervo", @@ -14401,7 +14401,7 @@ { "id": 20293, "Key": "am2", - "enUS": " Reflex Bow ", + "enUS": "Reflex Bow ", "zhTW": "反射弓", "deDE": "[ms]Reflexbogen", "esES": "[ms]Arco de reflejos", @@ -14418,7 +14418,7 @@ { "id": 20294, "Key": "am3", - "enUS": " Maiden Spear ", + "enUS": "Maiden Spear ", "zhTW": "女戰長矛", "deDE": "[ms]Jungfernspeer", "esES": "[fs]Lanza doncella", @@ -14435,7 +14435,7 @@ { "id": 20295, "Key": "am4", - "enUS": " Maiden Pike ", + "enUS": "Maiden Pike ", "zhTW": "女戰長槍", "deDE": "[fs]Jungfernpike", "esES": "[fs]Pica doncella", @@ -14452,7 +14452,7 @@ { "id": 20296, "Key": "am5", - "enUS": " Maiden Javelin ", + "enUS": "Maiden Javelin ", "zhTW": "女戰標槍", "deDE": "[ms]Jungfernwurfspieß", "esES": "[fs]Jabalina doncella", @@ -14469,7 +14469,7 @@ { "id": 20297, "Key": "ob6", - "enUS": " Glowing Orb ", + "enUS": "Glowing Orb ", "zhTW": "靈光法珠", "deDE": "[fs]Leuchtkugel", "esES": "[ms]Orbe encendido", @@ -14486,7 +14486,7 @@ { "id": 20298, "Key": "ob7", - "enUS": " Crystalline Globe ", + "enUS": "Crystalline Globe ", "zhTW": "水晶天球", "deDE": "[fs]Kristallkugel", "esES": "[ms]Globo cristalino", @@ -14503,7 +14503,7 @@ { "id": 20299, "Key": "ob8", - "enUS": " Cloudy Sphere ", + "enUS": "Cloudy Sphere ", "zhTW": "雲霧之球", "deDE": "[fs]Wolkenkugel", "esES": "[fs]Esfera turbia", @@ -14520,7 +14520,7 @@ { "id": 20300, "Key": "ob9", - "enUS": " Sparkling Ball ", + "enUS": "Sparkling Ball ", "zhTW": "閃耀之球", "deDE": "[ms]Funkelball", "esES": "[fs]Bola centelleante", @@ -14537,7 +14537,7 @@ { "id": 20301, "Key": "oba", - "enUS": " Swirling Crystal ", + "enUS": "Swirling Crystal ", "zhTW": "渦流水晶", "deDE": "[ms]Wirbelnder Kristall", "esES": "[ms]Cristal turbulento", @@ -14554,7 +14554,7 @@ { "id": 20302, "Key": "am6", - "enUS": " Ashwood Bow ", + "enUS": "Ashwood Bow ", "zhTW": "梣木弓", "deDE": "[ms]Eschenholzbogen", "esES": "[ms]Arco de Ashwood", @@ -14571,7 +14571,7 @@ { "id": 20303, "Key": "am7", - "enUS": " Ceremonial Bow ", + "enUS": "Ceremonial Bow ", "zhTW": "儀禮弓", "deDE": "[ms]Zeremonialbogen", "esES": "[ms]Arco ceremonial", @@ -14588,7 +14588,7 @@ { "id": 20304, "Key": "am8", - "enUS": " Ceremonial Spear ", + "enUS": "Ceremonial Spear ", "zhTW": "儀禮長矛", "deDE": "[ms]Zeremonialspeer", "esES": "[fs]Lanza ceremonial", @@ -14605,7 +14605,7 @@ { "id": 20305, "Key": "am9", - "enUS": " Ceremonial Pike ", + "enUS": "Ceremonial Pike ", "zhTW": "儀禮長槍", "deDE": "[fs]Zeremonialpike", "esES": "[fs]Pica ceremonial", @@ -14622,7 +14622,7 @@ { "id": 20306, "Key": "ama", - "enUS": " Ceremonial Javelin ", + "enUS": "Ceremonial Javelin ", "zhTW": "儀禮標槍", "deDE": "[ms]Zeremonialwurfspieß", "esES": "[fs]Jabalina ceremonial", @@ -14639,7 +14639,7 @@ { "id": 20307, "Key": "obb", - "enUS": " Heavenly Stone ", + "enUS": "Heavenly Stone ", "zhTW": "天堂之石", "deDE": "Himmelsstein", "esES": "[fs]Piedra celestial", @@ -14656,7 +14656,7 @@ { "id": 20308, "Key": "obc", - "enUS": " Eldritch Orb ", + "enUS": "Eldritch Orb ", "zhTW": "異能法珠", "deDE": "[fs]Heidenkugel", "esES": "[ms]Orbe sobrenatural", @@ -14673,7 +14673,7 @@ { "id": 20309, "Key": "obd", - "enUS": " Demon Heart ", + "enUS": "Demon Heart ", "zhTW": "惡魔心石", "deDE": "[ns]Dämonenherz", "esES": "[ms]Corazón del demonio", @@ -14690,7 +14690,7 @@ { "id": 20310, "Key": "obe", - "enUS": " Vortex Orb ", + "enUS": "Vortex Orb ", "zhTW": "漩渦法珠", "deDE": "[fs]Wirbelkugel", "esES": "[ms]Orbe vórtice", @@ -14707,7 +14707,7 @@ { "id": 20311, "Key": "obf", - "enUS": " Dimensional Shard ", + "enUS": "Dimensional Shard ", "zhTW": "次元法珠", "deDE": "[fs]Dimensionsscherbe", "esES": "[fs]Esquirla dimensional", @@ -14724,7 +14724,7 @@ { "id": 20312, "Key": "amb", - "enUS": " Matriarchal Bow ", + "enUS": "Matriarchal Bow ", "zhTW": "女傑之弓", "deDE": "[ms]Matriarchenbogen", "esES": "[ms]Arco matriarcal", @@ -14741,7 +14741,7 @@ { "id": 20313, "Key": "amc", - "enUS": " Grand Matron Bow ", + "enUS": "Grand Matron Bow ", "zhTW": "主母之弓", "deDE": "[ms]Großer Matronenbogen", "esES": "[ms]Arco de la gran matrona", @@ -14758,7 +14758,7 @@ { "id": 20314, "Key": "amd", - "enUS": " Matriarchal Spear ", + "enUS": "Matriarchal Spear ", "zhTW": "女傑長矛", "deDE": "[ms]Matriarchenspeer", "esES": "[fs]Lanza matriarcal", @@ -14775,7 +14775,7 @@ { "id": 20315, "Key": "ame", - "enUS": " Matriarchal Pike ", + "enUS": "Matriarchal Pike ", "zhTW": "女傑長槍", "deDE": "[fs]Matriarchenpike", "esES": "[fs]Pica matriarcal", @@ -14792,7 +14792,7 @@ { "id": 20316, "Key": "amf", - "enUS": " Matriarchal Javelin ", + "enUS": "Matriarchal Javelin ", "zhTW": "女傑標槍", "deDE": "[ms]Matriarchenwurfspieß", "esES": "[fs]Jabalina matriarcal", @@ -14809,7 +14809,7 @@ { "id": 20317, "Key": "dr4", - "enUS": " Falcon Mask ", + "enUS": "Falcon Mask ", "zhTW": "獵鷹面具", "deDE": "[fs]Falkenmaske", "esES": "[fs]Máscara del halcón", @@ -14826,7 +14826,7 @@ { "id": 20318, "Key": "dr2", - "enUS": " Hawk Helm ", + "enUS": "Hawk Helm ", "zhTW": "飛鷹頭盔", "deDE": "[ms]Falkenhelm", "esES": "[ms]Yelmo del gerifalte", @@ -14843,7 +14843,7 @@ { "id": 20319, "Key": "dr3", - "enUS": " Antlers ", + "enUS": "Antlers ", "zhTW": "巨角獸帽", "deDE": "[ns]Geweih", "esES": "[fs]Cornamenta", @@ -14860,7 +14860,7 @@ { "id": 20320, "Key": "dr1", - "enUS": " Wolf Head ", + "enUS": "Wolf Head ", "zhTW": "狼頭獸帽", "deDE": "[ms]Wolfskopf", "esES": "[fs]Cabeza de lobo", @@ -14877,7 +14877,7 @@ { "id": 20321, "Key": "dr5", - "enUS": " Spirit Mask ", + "enUS": "Spirit Mask ", "zhTW": "靈狼面具", "deDE": "[fs]Geistermaske", "esES": "[fs]Máscara espiritual", @@ -14894,7 +14894,7 @@ { "id": 20322, "Key": "ba1", - "enUS": " Jawbone Cap ", + "enUS": "Jawbone Cap ", "zhTW": "顎骨帽", "deDE": "[ms]Kieferknochenhut", "esES": "[ms]Casco de mandíbula", @@ -14911,7 +14911,7 @@ { "id": 20323, "Key": "ba2", - "enUS": " Fanged Helm ", + "enUS": "Fanged Helm ", "zhTW": "尖牙頭盔", "deDE": "[ms]Stoßzahnhelm", "esES": "[ms]Yelmo canino", @@ -14928,7 +14928,7 @@ { "id": 20324, "Key": "ba3", - "enUS": " Horned Helm ", + "enUS": "Horned Helm ", "zhTW": "尖角頭盔", "deDE": "[ms]Gehörnter Helm", "esES": "[ms]Yelmo enastado", @@ -14945,7 +14945,7 @@ { "id": 20325, "Key": "ba4", - "enUS": " Assault Helmet ", + "enUS": "Assault Helmet ", "zhTW": "突擊頭盔", "deDE": "[ms]Angriffshelm", "esES": "[ms]Casco de asalto", @@ -14962,7 +14962,7 @@ { "id": 20326, "Key": "ba5", - "enUS": " Avenger Guard ", + "enUS": "Avenger Guard ", "zhTW": "復仇者護盔", "deDE": "[ms]Rächender Wächter", "esES": "[fs]Protección vengadora", @@ -14979,7 +14979,7 @@ { "id": 20327, "Key": "pa1", - "enUS": " Targe ", + "enUS": "Targe ", "zhTW": "小盾", "deDE": "[fs]Targe", "esES": "[fs]Adarga", @@ -14996,7 +14996,7 @@ { "id": 20328, "Key": "pa2", - "enUS": " Rondache ", + "enUS": "Rondache ", "zhTW": "輕圓盾", "deDE": "[fs]Rondache", "esES": "[fs]Rodela", @@ -15013,7 +15013,7 @@ { "id": 20329, "Key": "pa3", - "enUS": " Heraldic Shield ", + "enUS": "Heraldic Shield ", "zhTW": "紋章盾", "deDE": "[ms]Wappenschild", "esES": "[ms]Escudo heráldico", @@ -15030,7 +15030,7 @@ { "id": 20330, "Key": "pa4", - "enUS": " Aerin Shield ", + "enUS": "Aerin Shield ", "zhTW": "艾文之盾", "deDE": "[ms]Aerins Schild", "esES": "[ms]Escudo aerin", @@ -15047,7 +15047,7 @@ { "id": 20331, "Key": "pa5", - "enUS": " Crown Shield ", + "enUS": "Crown Shield ", "zhTW": "冠冕之盾", "deDE": "[ms]Kronenschild", "esES": "[ms]Escudo de la corona", @@ -15064,7 +15064,7 @@ { "id": 20332, "Key": "ne1", - "enUS": " Preserved Head ", + "enUS": "Preserved Head ", "zhTW": "防腐頭顱", "deDE": "[ms]Konservierter Kopf", "esES": "[fs]Cabeza preservada", @@ -15081,7 +15081,7 @@ { "id": 20333, "Key": "ne2", - "enUS": " Zombie Head ", + "enUS": "Zombie Head ", "zhTW": "殭屍頭顱", "deDE": "[ms]Zombiekopf", "esES": "[fs]Cabeza de zombi", @@ -15098,7 +15098,7 @@ { "id": 20334, "Key": "ne3", - "enUS": " Unraveller Head ", + "enUS": "Unraveller Head ", "zhTW": "解繃者頭顱", "deDE": "[ms]Zersetzerkopf", "esES": "[fs]Cabeza de desenredador", @@ -15115,7 +15115,7 @@ { "id": 20335, "Key": "ne4", - "enUS": " Gargoyle Head ", + "enUS": "Gargoyle Head ", "zhTW": "石像鬼頭顱", "deDE": "[ms]Gargoylekopf", "esES": "[fs]Cabeza de gárgola", @@ -15132,7 +15132,7 @@ { "id": 20336, "Key": "ne5", - "enUS": " Demon Head ", + "enUS": "Demon Head ", "zhTW": "惡魔頭顱", "deDE": "[ms]Dämonenkopf", "esES": "[fs]Cabeza de demonio", @@ -15149,7 +15149,7 @@ { "id": 20337, "Key": "ci0", - "enUS": " Circlet ", + "enUS": "Circlet ", "zhTW": "頭環", "deDE": "[ms]Reif", "esES": "[fs]Aureola", @@ -15166,7 +15166,7 @@ { "id": 20338, "Key": "ci1", - "enUS": " Coronet ", + "enUS": "Coronet ", "zhTW": "寶冠", "deDE": "[ns]Krönchen", "esES": "[fs]Coronilla", @@ -15183,7 +15183,7 @@ { "id": 20339, "Key": "ci2", - "enUS": " Tiara ", + "enUS": "Tiara ", "zhTW": "頭冠", "deDE": "[fs]Tiara", "esES": "[fs]Tiara", @@ -15200,7 +15200,7 @@ { "id": 20340, "Key": "ci3", - "enUS": " Diadem ", + "enUS": "Diadem ", "zhTW": "權冠", "deDE": "[ns]Diadem", "esES": "[fs]Diadema", @@ -15217,7 +15217,7 @@ { "id": 20341, "Key": "uap", - "enUS": " Shako ", + "enUS": "Shako ", "zhTW": "軍帽", "deDE": "[ms]Tschako", "esES": "[ms]Chacó", @@ -15234,7 +15234,7 @@ { "id": 20342, "Key": "ukp", - "enUS": " Hydraskull ", + "enUS": "Hydraskull ", "zhTW": "多頭蛇顱盔", "deDE": "[ms]Hydraschädel", "esES": "[ms]Cráneo de hidra", @@ -15251,7 +15251,7 @@ { "id": 20343, "Key": "ulm", - "enUS": " Armet ", + "enUS": "Armet ", "zhTW": "覆頰盔", "deDE": "[ns]Armet", "esES": "[ms]Almete", @@ -15268,7 +15268,7 @@ { "id": 20344, "Key": "uhl", - "enUS": " Giant Conch ", + "enUS": "Giant Conch ", "zhTW": "巨螺盔", "deDE": "[fs]Riesenmuschel", "esES": "[fs]Valva gigante", @@ -15285,7 +15285,7 @@ { "id": 20345, "Key": "uhm", - "enUS": " Spired Helm ", + "enUS": "Spired Helm ", "zhTW": "巨角頭盔", "deDE": "[ms]Spitzhelm", "esES": "[ms]Yelmo de agujas", @@ -15302,7 +15302,7 @@ { "id": 20346, "Key": "urn", - "enUS": " Corona ", + "enUS": "Corona ", "zhTW": "日冕之冠", "deDE": "[fs]Korona", "esES": "[fs]Corona", @@ -15319,7 +15319,7 @@ { "id": 20347, "Key": "usk", - "enUS": " Demonhead ", + "enUS": "Demonhead ", "zhTW": "惡魔頭骨", "deDE": "[ms]Dämonenschädel", "esES": "[fs]Faz del demonio", @@ -15336,7 +15336,7 @@ { "id": 20348, "Key": "uui", - "enUS": " Dusk Shroud ", + "enUS": "Dusk Shroud ", "zhTW": "灰暮罩衣", "deDE": "[ms]Dämmerschleier", "esES": "[fs]Mortaja del crepúsculo", @@ -15353,7 +15353,7 @@ { "id": 20349, "Key": "uea", - "enUS": " Wyrmhide ", + "enUS": "Wyrmhide ", "zhTW": "龍皮甲", "deDE": "[ns]Wyrmleder", "esES": "[ms]Cuero de vermis", @@ -15370,7 +15370,7 @@ { "id": 20350, "Key": "ula", - "enUS": " Scarab Husk ", + "enUS": "Scarab Husk ", "zhTW": "聖甲蟲殼皮甲", "deDE": "[fs]Skarabäusschale", "esES": "[mp]Élitros de alfazaque", @@ -15387,7 +15387,7 @@ { "id": 20351, "Key": "utu", - "enUS": " Wire Fleece ", + "enUS": "Wire Fleece ", "zhTW": "鋼線毛皮甲", "deDE": "[ns]Drahtvlies", "esES": "[fs]Lana de alambre", @@ -15404,7 +15404,7 @@ { "id": 20352, "Key": "ung", - "enUS": " Diamond Mail ", + "enUS": "Diamond Mail ", "zhTW": "鑽石鎖甲", "deDE": "[ns]Diamantpanzerhemd", "esES": "[fs]Cota de diamante", @@ -15421,7 +15421,7 @@ { "id": 20353, "Key": "ucl", - "enUS": " Loricated Mail ", + "enUS": "Loricated Mail ", "zhTW": "綴鱗戰甲", "deDE": "[ns]Kürasspanzerhemd", "esES": "[fs]Cota lorigada", @@ -15438,7 +15438,7 @@ { "id": 20354, "Key": "uhn", - "enUS": " Boneweave ", + "enUS": "Boneweave ", "zhTW": "骸骨網甲", "deDE": "[ns]Knochengespinst", "esES": "[ms]Malla de hueso", @@ -15455,7 +15455,7 @@ { "id": 20355, "Key": "urs", - "enUS": " Great Hauberk ", + "enUS": "Great Hauberk ", "zhTW": "鱗鎧胸甲", "deDE": "[fs]Große Halsberge", "esES": "[fs]Gran loriga", @@ -15472,7 +15472,7 @@ { "id": 20356, "Key": "upl", - "enUS": " Balrog Skin ", + "enUS": "Balrog Skin ", "zhTW": "炎魔皮板甲", "deDE": "[ns]Balrogleder", "esES": "[fs]Piel de Balrog", @@ -15489,7 +15489,7 @@ { "id": 20357, "Key": "ult", - "enUS": " Hellforge Plate ", + "enUS": "Hellforge Plate ", "zhTW": "地獄鍛甲", "deDE": "[fs]Höllenschmiedenplattenrüstung", "esES": "[fs]Coraza de la Fragua del Infierno", @@ -15506,7 +15506,7 @@ { "id": 20358, "Key": "uld", - "enUS": " Kraken Shell ", + "enUS": "Kraken Shell ", "zhTW": "海怪之殼", "deDE": "[fs]Krakenschale", "esES": "[fs]Concha de kraken", @@ -15523,7 +15523,7 @@ { "id": 20359, "Key": "uth", - "enUS": " Lacquered Plate ", + "enUS": "Lacquered Plate ", "zhTW": "漆護鎧甲", "deDE": "[fs]Lackierte Plattenrüstung", "esES": "[fs]Coraza lacada", @@ -15540,7 +15540,7 @@ { "id": 20360, "Key": "uul", - "enUS": " Shadow Plate ", + "enUS": "Shadow Plate ", "zhTW": "暗影鎧甲", "deDE": "[fs]Schattenplattenrüstung", "esES": "[fs]Coraza sombría", @@ -15557,7 +15557,7 @@ { "id": 20361, "Key": "uar", - "enUS": " Sacred Armor ", + "enUS": "Sacred Armor ", "zhTW": "神聖戰甲", "deDE": "[fs]Heilige Rüstung", "esES": "[fs]Armadura sacra", @@ -15574,7 +15574,7 @@ { "id": 20362, "Key": "utp", - "enUS": " Archon Plate ", + "enUS": "Archon Plate ", "zhTW": "統御者鎧甲", "deDE": "[fs]Archonplattenrüstung", "esES": "[fs]Coraza de arconte", @@ -15591,7 +15591,7 @@ { "id": 20363, "Key": "uuc", - "enUS": " Heater ", + "enUS": "Heater ", "zhTW": "斗盾", "deDE": "[ms]Manesseschild", "esES": "[ms]Calentador", @@ -15608,7 +15608,7 @@ { "id": 20364, "Key": "uml", - "enUS": " Luna ", + "enUS": "Luna ", "zhTW": "圓月盾", "deDE": "[fs]Luna", "esES": "[fs]Luna", @@ -15625,7 +15625,7 @@ { "id": 20365, "Key": "urg", - "enUS": " Hyperion ", + "enUS": "Hyperion ", "zhTW": "亥伯龍盾", "deDE": "[ms]Hyperion", "esES": "[ms]Hiperión", @@ -15642,7 +15642,7 @@ { "id": 20366, "Key": "uit", - "enUS": " Monarch ", + "enUS": "Monarch ", "zhTW": "君主盾", "deDE": "[ms]Monarch", "esES": "[ms]Monarca", @@ -15659,7 +15659,7 @@ { "id": 20367, "Key": "uow", - "enUS": " Aegis ", + "enUS": "Aegis ", "zhTW": "禦塔盾", "deDE": "[fs]Ägis", "esES": "[fs]Égida", @@ -15676,7 +15676,7 @@ { "id": 20368, "Key": "uts", - "enUS": " Ward ", + "enUS": "Ward ", "zhTW": "庇護盾", "deDE": "[ms]Schutz", "esES": "[fs]Custodia", @@ -15693,7 +15693,7 @@ { "id": 20369, "Key": "ulg", - "enUS": " Bramble Mitts ", + "enUS": "Bramble Mitts ", "zhTW": "荊棘手套", "deDE": "[pl]Dornenhandschuhe", "esES": "[mp]Mitones de zarza", @@ -15710,7 +15710,7 @@ { "id": 20370, "Key": "uvg", - "enUS": " Vampirebone Gloves ", + "enUS": "Vampirebone Gloves ", "zhTW": "吸血鬼骸骨手套", "deDE": "[pl]Vampirknochenhandschuhe", "esES": "[mp]Guantes de hueso de vampiro", @@ -15727,7 +15727,7 @@ { "id": 20371, "Key": "umg", - "enUS": " Vambraces ", + "enUS": "Vambraces ", "zhTW": "護臂", "deDE": "[pl]Vampirschienen", "esES": "[mp]Avambrazos", @@ -15744,7 +15744,7 @@ { "id": 20372, "Key": "utg", - "enUS": " Crusader Gauntlets ", + "enUS": "Crusader Gauntlets ", "zhTW": "聖教軍護手", "deDE": "[pl]Kreuzritterhandschuhe", "esES": "[mp]Guanteletes de cruzada", @@ -15761,7 +15761,7 @@ { "id": 20373, "Key": "uhg", - "enUS": " Ogre Gauntlets ", + "enUS": "Ogre Gauntlets ", "zhTW": "巨魔護手", "deDE": "[pl]Ogerhandschuhe", "esES": "[mp]Guanteletes de ogro", @@ -15778,7 +15778,7 @@ { "id": 20374, "Key": "ulb", - "enUS": " Wyrmhide Boots ", + "enUS": "Wyrmhide Boots ", "zhTW": "龍皮靴", "deDE": "[pl]Wyrmlederstiefel", "esES": "[fp]Botas de cuero de vermis", @@ -15795,7 +15795,7 @@ { "id": 20375, "Key": "uvb", - "enUS": " Scarabshell Boots ", + "enUS": "Scarabshell Boots ", "zhTW": "聖甲蟲殼皮靴", "deDE": "[pl]Skarabäusschalenstiefel", "esES": "[fp]Botas de élitro de alfazaque", @@ -15812,7 +15812,7 @@ { "id": 20376, "Key": "umb", - "enUS": " Boneweave Boots ", + "enUS": "Boneweave Boots ", "zhTW": "骸骨網靴", "deDE": "[pl]Knochengespinststiefel", "esES": "[fp]Botas de hueso", @@ -15829,7 +15829,7 @@ { "id": 20377, "Key": "utb", - "enUS": " Mirrored Boots ", + "enUS": "Mirrored Boots ", "zhTW": "幻鏡戰靴", "deDE": "[pl]Verspiegelte Stiefel", "esES": "[fp]Botas de espejo", @@ -15846,7 +15846,7 @@ { "id": 20378, "Key": "uhb", - "enUS": " Myrmidon Greaves ", + "enUS": "Myrmidon Greaves ", "zhTW": "勇士護脛", "deDE": "[fs]Myrmidonbeinschienen", "esES": "[fp]Grebas de mirmidón", @@ -15863,7 +15863,7 @@ { "id": 20379, "Key": "ulc", - "enUS": " Spiderweb Sash ", + "enUS": "Spiderweb Sash ", "zhTW": "蛛網束帶", "deDE": "[fs]Spinnennetzschärpe", "esES": "[ms]Fajín de tela de araña", @@ -15880,7 +15880,7 @@ { "id": 20380, "Key": "uvc", - "enUS": " Vampirefang Belt ", + "enUS": "Vampirefang Belt ", "zhTW": "吸血鬼牙腰帶", "deDE": "[ms]Vampirzahngürtel", "esES": "[ms]Cinturón de colmillo de vampiro", @@ -15897,7 +15897,7 @@ { "id": 20381, "Key": "umc", - "enUS": " Mithril Coil ", + "enUS": "Mithril Coil ", "zhTW": "秘銀腰帶", "deDE": "[fs]Mithrilrolle", "esES": "[fs]Rosca de mithril", @@ -15914,7 +15914,7 @@ { "id": 20382, "Key": "utc", - "enUS": " Troll Belt ", + "enUS": "Troll Belt ", "zhTW": "食人妖腰帶", "deDE": "[ms]Trollgürtel", "esES": "[ms]Cinturón de trol", @@ -15931,7 +15931,7 @@ { "id": 20383, "Key": "uhc", - "enUS": " Colossus Girdle ", + "enUS": "Colossus Girdle ", "zhTW": "巨神腰帶", "deDE": "[ms]Kolossgurt", "esES": "[fs]Faja del coloso", @@ -15948,7 +15948,7 @@ { "id": 20384, "Key": "uh9", - "enUS": " Bone Visage ", + "enUS": "Bone Visage ", "zhTW": "骸骨面罩", "deDE": "[fs]Knochenfratze", "esES": "[ms]Semblante de hueso", @@ -15965,7 +15965,7 @@ { "id": 20385, "Key": "ush", - "enUS": " Troll Nest ", + "enUS": "Troll Nest ", "zhTW": "食人妖骨盾", "deDE": "[ns]Trollnest", "esES": "[ms]Nido de troles", @@ -15982,7 +15982,7 @@ { "id": 20386, "Key": "upk", - "enUS": " Blade Barrier ", + "enUS": "Blade Barrier ", "zhTW": "刀刃刺盾", "deDE": "[fs]Klingenbarriere", "esES": "[fs]Barrera tajante", @@ -15999,7 +15999,7 @@ { "id": 20387, "Key": "dr9", - "enUS": " Sacred Feathers ", + "enUS": "Sacred Feathers ", "zhTW": "聖羽頭飾", "deDE": "[pl]Heilige Federn", "esES": "[fp]Plumas sacras", @@ -16016,7 +16016,7 @@ { "id": 20388, "Key": "dr7", - "enUS": " Griffon Headdress ", + "enUS": "Griffon Headdress ", "zhTW": "獅鷲獸頭飾", "deDE": "[ms]Greifenkopfschmuck", "esES": "[ms]Tocado de grifo", @@ -16033,7 +16033,7 @@ { "id": 20389, "Key": "dr8", - "enUS": " Hunter's Guise ", + "enUS": "Hunter's Guise ", "zhTW": "獵人面罩", "deDE": "[fs]Jägerverkleidung", "esES": "[ms]Aspecto del cazador", @@ -16050,7 +16050,7 @@ { "id": 20390, "Key": "dr6", - "enUS": " Alpha Helm ", + "enUS": "Alpha Helm ", "zhTW": "猛狼頭盔", "deDE": "[ms]Alphahelm", "esES": "[ms]Yelmo alfa", @@ -16067,7 +16067,7 @@ { "id": 20391, "Key": "dra", - "enUS": " Totemic Mask ", + "enUS": "Totemic Mask ", "zhTW": "圖騰面具", "deDE": "[fs]Totemmaske", "esES": "[fs]Máscara totémica", @@ -16084,7 +16084,7 @@ { "id": 20392, "Key": "ba6", - "enUS": " Jawbone Visor ", + "enUS": "Jawbone Visor ", "zhTW": "顎骨面甲", "deDE": "[ns]Kieferknochenvisier", "esES": "[fs]Visera de mandíbula", @@ -16101,7 +16101,7 @@ { "id": 20393, "Key": "ba7", - "enUS": " Lion Helm ", + "enUS": "Lion Helm ", "zhTW": "獅牙頭盔", "deDE": "[ms]Löwenhelm", "esES": "[ms]Yelmo del león", @@ -16118,7 +16118,7 @@ { "id": 20394, "Key": "ba8", - "enUS": " Rage Mask ", + "enUS": "Rage Mask ", "zhTW": "狂怒面具", "deDE": "[fs]Wutmaske", "esES": "[fs]Máscara de la cólera", @@ -16135,7 +16135,7 @@ { "id": 20395, "Key": "ba9", - "enUS": " Savage Helmet ", + "enUS": "Savage Helmet ", "zhTW": "凶蠻頭盔", "deDE": "[ms]Wildenhelm", "esES": "[ms]Casco salvaje", @@ -16152,7 +16152,7 @@ { "id": 20396, "Key": "baa", - "enUS": " Slayer Guard ", + "enUS": "Slayer Guard ", "zhTW": "殺手護盔", "deDE": "[ms]Schlächterschutz", "esES": "[fs]Protección exterminadora", @@ -16169,7 +16169,7 @@ { "id": 20397, "Key": "pa6", - "enUS": " Akaran Targe ", + "enUS": "Akaran Targe ", "zhTW": "阿卡拉圓盾", "deDE": "Akarantarge", "esES": "[fs]Adarga de Akaran", @@ -16186,7 +16186,7 @@ { "id": 20398, "Key": "pa7", - "enUS": " Akaran Rondache ", + "enUS": "Akaran Rondache ", "zhTW": "阿卡拉輕圓盾", "deDE": "[fs]Akaranrondache", "esES": "[fs]Rodela de Akaran", @@ -16203,7 +16203,7 @@ { "id": 20399, "Key": "pa8", - "enUS": " Protector Shield ", + "enUS": "Protector Shield ", "zhTW": "守護之盾", "deDE": "[ms]Schutzschild", "esES": "[ms]Escudo protector", @@ -16220,7 +16220,7 @@ { "id": 20400, "Key": "pa9", - "enUS": " Gilded Shield ", + "enUS": "Gilded Shield ", "zhTW": "金紋盾", "deDE": "[ms]Vergoldeter Schild", "esES": "[ms]Escudo dorado", @@ -16237,7 +16237,7 @@ { "id": 20401, "Key": "paa", - "enUS": " Royal Shield ", + "enUS": "Royal Shield ", "zhTW": "皇家盾", "deDE": "[ms]Königlicher Schild", "esES": "[ms]Escudo real", @@ -16254,7 +16254,7 @@ { "id": 20402, "Key": "ne6", - "enUS": " Mummified Trophy ", + "enUS": "Mummified Trophy ", "zhTW": "木乃伊首級", "deDE": "[fs]Mumifizierte Trophäe", "esES": "[ms]Trofeo momificado", @@ -16271,7 +16271,7 @@ { "id": 20403, "Key": "ne7", - "enUS": " Fetish Trophy ", + "enUS": "Fetish Trophy ", "zhTW": "鬼娃首級", "deDE": "[fs]Fetischtrophäe", "esES": "[ms]Trofeo de fetiche", @@ -16288,7 +16288,7 @@ { "id": 20404, "Key": "ne8", - "enUS": " Sexton Trophy ", + "enUS": "Sexton Trophy ", "zhTW": "司事首級", "deDE": "[fs]Sextontrophäe", "esES": "[ms]Trofeo de sacristán", @@ -16305,7 +16305,7 @@ { "id": 20405, "Key": "ne9", - "enUS": " Cantor Trophy ", + "enUS": "Cantor Trophy ", "zhTW": "領唱者首級", "deDE": "[fs]Kantortrophäe", "esES": "[ms]Trofeo de cantor", @@ -16322,7 +16322,7 @@ { "id": 20406, "Key": "nea", - "enUS": " Hierophant Trophy ", + "enUS": "Hierophant Trophy ", "zhTW": "祭司首級", "deDE": "Hierophanttrophäe", "esES": "[ms]Trofeo de hierofante", @@ -16339,7 +16339,7 @@ { "id": 20407, "Key": "dre", - "enUS": " Sky Spirit ", + "enUS": "Sky Spirit ", "zhTW": "天翔靈獸帽", "deDE": "[ms]Himmelsgeist", "esES": "[ms]Espíritu del cielo", @@ -16356,7 +16356,7 @@ { "id": 20408, "Key": "drc", - "enUS": " Sun Spirit ", + "enUS": "Sun Spirit ", "zhTW": "日陽靈獸帽", "deDE": "[ms]Sonnengeist", "esES": "[ms]Espíritu del sol", @@ -16373,7 +16373,7 @@ { "id": 20409, "Key": "drd", - "enUS": " Earth Spirit ", + "enUS": "Earth Spirit ", "zhTW": "地土靈獸帽", "deDE": "[ms]Erdgeist", "esES": "[ms]Espíritu de la tierra", @@ -16390,7 +16390,7 @@ { "id": 20410, "Key": "drb", - "enUS": " Blood Spirit ", + "enUS": "Blood Spirit ", "zhTW": "血系靈獸帽", "deDE": "[ms]Blutgeist", "esES": "[ms]Espíritu de la sangre", @@ -16407,7 +16407,7 @@ { "id": 20411, "Key": "drf", - "enUS": " Dream Spirit ", + "enUS": "Dream Spirit ", "zhTW": "幽夢靈獸帽", "deDE": "[ms]Traumgeist", "esES": "[ms]Espíritu del sueño", @@ -16424,7 +16424,7 @@ { "id": 20412, "Key": "bab", - "enUS": " Carnage Helm ", + "enUS": "Carnage Helm ", "zhTW": "屠殺頭盔", "deDE": "[ms]Gemetzelhelm", "esES": "[ms]Yelmo de carnicería", @@ -16441,7 +16441,7 @@ { "id": 20413, "Key": "bac", - "enUS": " Fury Visor ", + "enUS": "Fury Visor ", "zhTW": "暴怒面甲", "deDE": "[ns]Wutvisier", "esES": "[fs]Visera de furia", @@ -16458,7 +16458,7 @@ { "id": 20414, "Key": "bad", - "enUS": " Destroyer Helm ", + "enUS": "Destroyer Helm ", "zhTW": "毀滅者頭盔", "deDE": "[ms]Zerstörerhelm", "esES": "[ms]Yelmo destructor", @@ -16475,7 +16475,7 @@ { "id": 20415, "Key": "bae", - "enUS": " Conqueror Crown ", + "enUS": "Conqueror Crown ", "zhTW": "征服者盔冠", "deDE": "Erobererkrone", "esES": "[fs]Corona conquistadora", @@ -16492,7 +16492,7 @@ { "id": 20416, "Key": "baf", - "enUS": " Guardian Crown ", + "enUS": "Guardian Crown ", "zhTW": "守護者盔冠", "deDE": "[fs]Wächterkrone", "esES": "[fs]Corona guardiana", @@ -16509,7 +16509,7 @@ { "id": 20417, "Key": "pab", - "enUS": " Sacred Targe ", + "enUS": "Sacred Targe ", "zhTW": "神聖小盾", "deDE": "[fs]Heilige Targe", "esES": "[fs]Adarga sacra", @@ -16526,7 +16526,7 @@ { "id": 20418, "Key": "pac", - "enUS": " Sacred Rondache ", + "enUS": "Sacred Rondache ", "zhTW": "神聖輕圓盾", "deDE": "[fs]Heilige Rondache", "esES": "[fs]Rodela sacra", @@ -16543,7 +16543,7 @@ { "id": 20419, "Key": "pae", - "enUS": " Zakarum Shield ", + "enUS": "Zakarum Shield ", "zhTW": "撒卡蘭姆盾", "deDE": "[ms]Zakarumschild", "esES": "[ms]Escudo de Zakarum", @@ -16560,7 +16560,7 @@ { "id": 20420, "Key": "paf", - "enUS": " Vortex Shield ", + "enUS": "Vortex Shield ", "zhTW": "渦旋盾", "deDE": "[ms]Wirbelschild", "esES": "[ms]Escudo vórtice", @@ -16577,7 +16577,7 @@ { "id": 20421, "Key": "neb", - "enUS": " Minion Skull ", + "enUS": "Minion Skull ", "zhTW": "僕從顱骨", "deDE": "[ms]Dienerschädel", "esES": "[ms]Cráneo de esbirro", @@ -16594,7 +16594,7 @@ { "id": 20422, "Key": "nec", - "enUS": " Hellspawn Skull ", + "enUS": "Hellspawn Skull ", "zhTW": "地獄爪牙顱骨", "deDE": "[ms]Höllenbrutschädel", "esES": "[ms]Cráneo del averno", @@ -16611,7 +16611,7 @@ { "id": 20423, "Key": "ned", - "enUS": " Overseer Skull ", + "enUS": "Overseer Skull ", "zhTW": "督軍顱骨", "deDE": "[ms]Aufseherschädel", "esES": "[ms]Cráneo de supervisor", @@ -16628,7 +16628,7 @@ { "id": 20424, "Key": "nee", - "enUS": " Succubus Skull ", + "enUS": "Succubus Skull ", "zhTW": "魅魔顱骨", "deDE": "Sukkubusschädel", "esES": "[ms]Cráneo de súcubo", @@ -16645,7 +16645,7 @@ { "id": 20425, "Key": "nef", - "enUS": " Bloodlord Skull ", + "enUS": "Bloodlord Skull ", "zhTW": "鮮血之王顱骨", "deDE": "[ms]Blutlordschädel", "esES": "[ms]Cráneo de señor de la sangre", @@ -16662,7 +16662,7 @@ { "id": 20433, "Key": "jew", - "enUS": " Jewel ", + "enUS": "Jewel ", "zhTW": "珠寶", "deDE": "[ns]Juwel", "esES": "[fs]Joya", @@ -16679,7 +16679,7 @@ { "id": 20434, "Key": "hrb", - "enUS": " Herb ", + "enUS": "Herb ", "zhTW": "藥草", "deDE": "[ns]Kraut", "esES": "[fs]Hierba", @@ -16696,7 +16696,7 @@ { "id": 20435, "Key": "cm1", - "enUS": " Small Charm ", + "enUS": "Small Charm ", "zhTW": "小型咒符", "deDE": "[ms]Kleiner Zauber", "esES": "[ms]Dije pequeño", @@ -16713,7 +16713,7 @@ { "id": 20436, "Key": "cm2", - "enUS": " Large Charm ", + "enUS": "Large Charm ", "zhTW": "大型咒符", "deDE": "[ms]Großer Zauber", "esES": "[ms]Dije grande", @@ -16730,7 +16730,7 @@ { "id": 20437, "Key": "cm3", - "enUS": " Grand Charm ", + "enUS": "Grand Charm ", "zhTW": "特大咒符", "deDE": "[ms]Riesenzauber", "esES": "[ms]Dije enorme", @@ -16747,7 +16747,7 @@ { "id": 20676, "Key": "spe", - "enUS": " Spleen ", + "enUS": "Spleen ", "zhTW": "脾臟", "deDE": "[fs]Milz", "esES": "[ms]Bazo", @@ -16764,7 +16764,7 @@ { "id": 20677, "Key": "scz", - "enUS": " Scalp ", + "enUS": "Scalp ", "zhTW": "頭皮", "deDE": "[ms]Skalp", "esES": "[fs]Cabellera", @@ -16781,7 +16781,7 @@ { "id": 20678, "Key": "sol", - "enUS": " Soul ", + "enUS": "Soul ", "zhTW": "靈魂", "deDE": "[fs]Seele", "esES": "[fs]Alma", @@ -16798,7 +16798,7 @@ { "id": 20679, "Key": "qll", - "enUS": " Quill ", + "enUS": "Quill ", "zhTW": "刺針", "deDE": "[ms]Stachel", "esES": "[ms]Cálamo", @@ -16815,7 +16815,7 @@ { "id": 20680, "Key": "fng", - "enUS": " Fang ", + "enUS": "Fang ", "zhTW": "尖牙", "deDE": "[ms]Hauer", "esES": "[ms]Colmillo", @@ -16832,7 +16832,7 @@ { "id": 20681, "Key": "flg", - "enUS": " Flag ", + "enUS": "Flag ", "zhTW": "旗幟", "deDE": "[fs]Flagge", "esES": "[fs]Bandera", @@ -16849,7 +16849,7 @@ { "id": 20682, "Key": "tal", - "enUS": " Tail ", + "enUS": "Tail ", "zhTW": "尾巴", "deDE": "[ms]Schwanz", "esES": "[fs]Cola", @@ -16866,7 +16866,7 @@ { "id": 20683, "Key": "hrn", - "enUS": " Horn ", + "enUS": "Horn ", "zhTW": "尖角", "deDE": "[ns]Horn", "esES": "[ms]Cuerno", @@ -16883,7 +16883,7 @@ { "id": 20684, "Key": "eyz", - "enUS": " Eye ", + "enUS": "Eye ", "zhTW": "眼球", "deDE": "[ns]Auge", "esES": "[ms]Ojo", @@ -16900,7 +16900,7 @@ { "id": 20685, "Key": "jaw", - "enUS": " Jawbone ", + "enUS": "Jawbone ", "zhTW": "顎骨", "deDE": "[ms]Kiefer", "esES": "[fs]Mandíbula", @@ -16917,7 +16917,7 @@ { "id": 20686, "Key": "brz", - "enUS": " Brain ", + "enUS": "Brain ", "zhTW": "腦", "deDE": "[ns]Gehirn", "esES": "[ms]Cerebro", @@ -16934,7 +16934,7 @@ { "id": 20687, "Key": "hrt", - "enUS": " Heart ", + "enUS": "Heart ", "zhTW": "心臟", "deDE": "[ns]Herz", "esES": "[ms]Corazón", @@ -16951,7 +16951,7 @@ { "id": 21286, "Key": "Coldkill", - "enUS": " Coldkill ", + "enUS": "Coldkill ", "zhTW": "冷殺", "deDE": "Kältetod", "esES": "Sanguinaria", @@ -16968,7 +16968,7 @@ { "id": 21287, "Key": "Butchers Cleaver", - "enUS": " Butcher's Cleaver ", + "enUS": "Butcher's Cleaver ", "zhTW": "屠夫切肉刀", "deDE": "Schlachtermesser", "esES": "Tajadera del carnicero", @@ -16985,7 +16985,7 @@ { "id": 21288, "Key": "Butcher's Pupil", - "enUS": " Butcher's Pupil ", + "enUS": "Butcher's Pupil ", "zhTW": "屠夫的徒弟", "deDE": "Schlachtergeselle", "esES": "Discípula del carnicero", @@ -17002,7 +17002,7 @@ { "id": 21289, "Key": "Islestrike", - "enUS": " Islestrike ", + "enUS": "Islestrike ", "zhTW": "島擊", "deDE": "Inselschlag", "esES": "Azote de la isla", @@ -17019,7 +17019,7 @@ { "id": 21290, "Key": "Pompe's Wrath", - "enUS": " Pompeii's Wrath ", + "enUS": "Pompeii's Wrath ", "zhTW": "龐貝之怒", "deDE": "Pompejis Zorn", "esES": "Ira de Pompeya", @@ -17036,7 +17036,7 @@ { "id": 21291, "Key": "Guardian Naga", - "enUS": " Guardian Naga ", + "enUS": "Guardian Naga ", "zhTW": "那伽守護者", "deDE": "Wächter-Dao", "esES": "Naga guardiana", @@ -17053,7 +17053,7 @@ { "id": 21292, "Key": "Warlord's Trust", - "enUS": " Warlord's Trust ", + "enUS": "Warlord's Trust ", "zhTW": "戰爵之證", "deDE": "Glaube des Kriegsherrn", "esES": "Confianza del caudillo", @@ -17070,7 +17070,7 @@ { "id": 21293, "Key": "Spellsteel", - "enUS": " Spellsteel ", + "enUS": "Spellsteel ", "zhTW": "鋼鐵魔咒", "deDE": "Zauberstahl", "esES": "Hechizo de acero", @@ -17087,7 +17087,7 @@ { "id": 21294, "Key": "Stormrider", - "enUS": " Stormrider ", + "enUS": "Stormrider ", "zhTW": "暴風騎士", "deDE": "Sturmreiter", "esES": "Jinete de la tormenta", @@ -17104,7 +17104,7 @@ { "id": 21295, "Key": "Boneslayer Blade", - "enUS": " Boneslayer Blade ", + "enUS": "Boneslayer Blade ", "zhTW": "斬骨者之斧", "deDE": "Knochenschlächterklinge", "esES": "Hacha inmolahuesos", @@ -17121,7 +17121,7 @@ { "id": 21296, "Key": "The Minotaur", - "enUS": " The Minotaur ", + "enUS": "The Minotaur ", "zhTW": "牛頭怪", "deDE": "Der Minotaurus", "esES": "El minotauro", @@ -17138,7 +17138,7 @@ { "id": 21297, "Key": "Suicide Branch", - "enUS": " Suicide Branch ", + "enUS": "Suicide Branch ", "zhTW": "自殘枝椏", "deDE": "Selbstmordzweig", "esES": "Rama del suicidio", @@ -17155,7 +17155,7 @@ { "id": 21298, "Key": "Cairn Shard", - "enUS": " Cairn Shard ", + "enUS": "Cairn Shard ", "zhTW": "凱林碎片", "deDE": "Monolithensplitter", "esES": "Esquirla de Cairn", @@ -17172,7 +17172,7 @@ { "id": 21299, "Key": "Arm of King Leoric", - "enUS": " Arm of King Leoric ", + "enUS": "Arm of King Leoric ", "zhTW": "李奧瑞克王的手骨", "deDE": "Arm von König Leoric", "esES": "Brazo del rey Leoric", @@ -17189,7 +17189,7 @@ { "id": 21300, "Key": "Blackhand Key", - "enUS": " Blackhand Key ", + "enUS": "Blackhand Key ", "zhTW": "黑手之鑰", "deDE": "Schwarzhandschlüssel", "esES": "Llave de la mano negra", @@ -17206,7 +17206,7 @@ { "id": 21301, "Key": "Dark Clan Crusher", - "enUS": " Dark Clan Crusher ", + "enUS": "Dark Clan Crusher ", "zhTW": "闇族碎滅者", "deDE": "Zerschmetterer des Dunkelclans", "esES": "Aplastador del clan oscuro", @@ -17223,7 +17223,7 @@ { "id": 21302, "Key": "Drulan's Tongue", - "enUS": " Drulan's Tongue ", + "enUS": "Drulan's Tongue ", "zhTW": "杜蘭之舌", "deDE": "Drulans Zunge", "esES": "Lengua de Drulan", @@ -17240,7 +17240,7 @@ { "id": 21303, "Key": "Zakrum's Hand", - "enUS": " Zakarum's Hand ", + "enUS": "Zakarum's Hand ", "zhTW": "撒卡蘭姆之手", "deDE": "Zakarums Hand", "esES": "Mano de Zakarum", @@ -17257,7 +17257,7 @@ { "id": 21304, "Key": "The Fetid Sprinkler", - "enUS": " The Fetid Sprinkler ", + "enUS": "The Fetid Sprinkler ", "zhTW": "惡臭散佈者", "deDE": "Der Stinksprinkler", "esES": "Hisopo fétido", @@ -17274,7 +17274,7 @@ { "id": 21305, "Key": "Hand of Blessed Light", - "enUS": " Hand of Blessed Light ", + "enUS": "Hand of Blessed Light ", "zhTW": "聖光之手", "deDE": "Hand des gesegneten Lichtes", "esES": "Mano de luz bendita", @@ -17291,7 +17291,7 @@ { "id": 21306, "Key": "Fleshrender", - "enUS": " Fleshrender ", + "enUS": "Fleshrender ", "zhTW": "血肉撕裂者", "deDE": "Fleischwolf", "esES": "Desgarrador de carne", @@ -17308,7 +17308,7 @@ { "id": 21307, "Key": "Sureshrill Frost", - "enUS": " Sureshrill Frost ", + "enUS": "Sureshrill Frost ", "zhTW": "尖嘯冰霜", "deDE": "Schrillfrost", "esES": "Escarcha estridente", @@ -17325,7 +17325,7 @@ { "id": 21308, "Key": "Moonfall", - "enUS": " Moonfall ", + "enUS": "Moonfall ", "zhTW": "月落", "deDE": "Mondfall", "esES": "Caída de la luna", @@ -17342,7 +17342,7 @@ { "id": 21309, "Key": "Baezils Vortex", - "enUS": " Baezil's Vortex ", + "enUS": "Baezil's Vortex ", "zhTW": "貝西爾的漩渦", "deDE": "Baezils Wirbel", "esES": "Vórtice de Baezil", @@ -17359,7 +17359,7 @@ { "id": 21310, "Key": "Earthshaker", - "enUS": " Earthshaker ", + "enUS": "Earthshaker ", "zhTW": "震地者", "deDE": "Erderschütterer", "esES": "Creador de conmociones", @@ -17376,7 +17376,7 @@ { "id": 21311, "Key": "Bloodtree Stump", - "enUS": " Bloodtree Stump ", + "enUS": "Bloodtree Stump ", "zhTW": "血樹殘株", "deDE": "Blutbaumstumpf", "esES": "Cepa del árbol sangriento", @@ -17393,7 +17393,7 @@ { "id": 21312, "Key": "The Gavel of Pain", - "enUS": " The Gavel of Pain ", + "enUS": "The Gavel of Pain ", "zhTW": "痛苦之槌", "deDE": "Der Hammer der Schmerzen", "esES": "Mazo del dolor", @@ -17410,7 +17410,7 @@ { "id": 21313, "Key": "Bloodletter", - "enUS": " Bloodletter ", + "enUS": "Bloodletter ", "zhTW": "放血者", "deDE": "Blutvergießer", "esES": "Flebotomista", @@ -17427,7 +17427,7 @@ { "id": 21314, "Key": "Coldsteal Eye", - "enUS": " Coldsteal Eye ", + "enUS": "Coldsteal Eye ", "zhTW": "竊冷之眼", "deDE": "Kälteraubauge", "esES": "Ojo de acero frío", @@ -17444,7 +17444,7 @@ { "id": 21315, "Key": "Hexfire", - "enUS": " Hexfire ", + "enUS": "Hexfire ", "zhTW": "妖火", "deDE": "Hexenfeuer", "esES": "Fuego maléfico", @@ -17461,7 +17461,7 @@ { "id": 21316, "Key": "Blade of Ali Baba", - "enUS": " Blade of Ali Baba ", + "enUS": "Blade of Ali Baba ", "zhTW": "阿里巴巴之刃", "deDE": "Klinge des Ali Baba", "esES": "Espada de Alí Babá", @@ -17478,7 +17478,7 @@ { "id": 21317, "Key": "Riftslash", - "enUS": " Riftslash ", + "enUS": "Riftslash ", "zhTW": "烈斬", "deDE": "Spaltenschnitter", "esES": "Tajofalla", @@ -17495,7 +17495,7 @@ { "id": 21318, "Key": "Headstriker", - "enUS": " Headstriker ", + "enUS": "Headstriker ", "zhTW": "擊頭者", "deDE": "Kopfhauer", "esES": "Hiendecabezas", @@ -17512,7 +17512,7 @@ { "id": 21319, "Key": "Plague Bearer", - "enUS": " Plague Bearer ", + "enUS": "Plague Bearer ", "zhTW": "疫病帶原者", "deDE": "Pestbringer", "esES": "Portadora de la plaga", @@ -17529,7 +17529,7 @@ { "id": 21320, "Key": "The Atlantien", - "enUS": " The Atlantean ", + "enUS": "The Atlantean ", "zhTW": "亞特蘭提恩", "deDE": "Der Atlantide", "esES": "La atlante", @@ -17546,7 +17546,7 @@ { "id": 21321, "Key": "Crainte Vomir", - "enUS": " Crainte Vomir ", + "enUS": "Crainte Vomir ", "zhTW": "恐懼之嘔", "deDE": "Crainte Vomir", "esES": "Crainte Vomir", @@ -17563,7 +17563,7 @@ { "id": 21322, "Key": "Bing Sz Wang", - "enUS": " Bing Sz Wang ", + "enUS": "Bing Sz Wang ", "zhTW": "冰之王", "deDE": "Bing Sz Wang", "esES": "Bing Sz Wang", @@ -17580,7 +17580,7 @@ { "id": 21323, "Key": "The Vile Husk", - "enUS": " The Vile Husk ", + "enUS": "The Vile Husk ", "zhTW": "兇邪軀殼", "deDE": "Die böse Schale", "esES": "Élitro vil", @@ -17597,7 +17597,7 @@ { "id": 21324, "Key": "Cloudcrack", - "enUS": " Cloudcrack ", + "enUS": "Cloudcrack ", "zhTW": "雲裂", "deDE": "Wolkenbrecher", "esES": "Grieta de nube", @@ -17614,11 +17614,11 @@ { "id": 21325, "Key": "Todesfaelle Flamme", - "enUS": " Todesfaelle Flamme ", + "enUS": "Todesfaelle Flamme ", "zhTW": "死落之火", "deDE": "Todesfallenflamme", "esES": "Todesflamme", - "frFR": "Flamme de Todesfaelle ", + "frFR": "Flamme de Todesfaelle ", "itIT": "Todesfaelle Flamme", "koKR": "죽음나락 불길", "plPL": "Płomień Todesfaelle", @@ -17631,7 +17631,7 @@ { "id": 21326, "Key": "Swordguard", - "enUS": " Swordguard ", + "enUS": "Swordguard ", "zhTW": "劍衛", "deDE": "Schwertwache", "esES": "Espada guardiana", @@ -17648,7 +17648,7 @@ { "id": 21327, "Key": "Spineripper", - "enUS": " Spineripper ", + "enUS": "Spineripper ", "zhTW": "裂脊者", "deDE": "Rückenbrecher", "esES": "Desgarramédulas", @@ -17665,11 +17665,11 @@ { "id": 21328, "Key": "Heart Carver", - "enUS": " Heart Carver ", + "enUS": "Heart Carver ", "zhTW": "刨心者", "deDE": "Herzausreißer", "esES": "Trinchacorazones", - "frFR": "Perce-cœur ", + "frFR": "Perce-cœur ", "itIT": "Spaccacuore", "koKR": "심장 도리개", "plPL": "Wyrżniserce", @@ -17682,7 +17682,7 @@ { "id": 21329, "Key": "Blackbog's Sharp", - "enUS": " Blackbog's Sharp ", + "enUS": "Blackbog's Sharp ", "zhTW": "黑沼之鋒", "deDE": "Blackbogs Spitze", "esES": "Aguja de la ciénaga negra", @@ -17699,7 +17699,7 @@ { "id": 21330, "Key": "Stormspike", - "enUS": " Stormspike ", + "enUS": "Stormspike ", "zhTW": "暴風尖刺", "deDE": "Sturmdorn", "esES": "Punta de la tormenta", @@ -17716,7 +17716,7 @@ { "id": 21331, "Key": "The Impaler", - "enUS": " The Impaler ", + "enUS": "The Impaler ", "zhTW": "刺穿者", "deDE": "Der Aufspießer", "esES": "La empaladora", @@ -17733,7 +17733,7 @@ { "id": 21332, "Key": "Kelpie Snare", - "enUS": " Kelpie Snare ", + "enUS": "Kelpie Snare ", "zhTW": "水魔陷阱", "deDE": "Kelpiefalle", "esES": "Cepo de kelpies", @@ -17750,7 +17750,7 @@ { "id": 21333, "Key": "Soulfeast Tine", - "enUS": " Soulfeast Tine ", + "enUS": "Soulfeast Tine ", "zhTW": "噬魂叉", "deDE": "Seelenernter", "esES": "Diente devoraalmas", @@ -17767,7 +17767,7 @@ { "id": 21334, "Key": "Hone Sundan", - "enUS": " Hone Sundan ", + "enUS": "Hone Sundan ", "zhTW": "骨寸斷", "deDE": "Hone Sundan", "esES": "Hone sundan", @@ -17784,7 +17784,7 @@ { "id": 21335, "Key": "Spire of Honor", - "enUS": " Spire of Honor ", + "enUS": "Spire of Honor ", "zhTW": "榮耀尖塔", "deDE": "Spitze der Ehre", "esES": "Aguja de honor", @@ -17801,7 +17801,7 @@ { "id": 21336, "Key": "The Meat Scraper", - "enUS": " The Meat Scraper ", + "enUS": "The Meat Scraper ", "zhTW": "刮肉者", "deDE": "Der Beinschaber", "esES": "Espátula de carne", @@ -17818,7 +17818,7 @@ { "id": 21337, "Key": "Blackleach Blade", - "enUS": " Blackleach Blade ", + "enUS": "Blackleach Blade ", "zhTW": "黑蛭長刀", "deDE": "Schwarzegelklinge", "esES": "Hoja de filo negro", @@ -17835,7 +17835,7 @@ { "id": 21338, "Key": "Athena's Wrath", - "enUS": " Athena's Wrath ", + "enUS": "Athena's Wrath ", "zhTW": "雅典娜之怒", "deDE": "Athenes Zorn", "esES": "Ira de Atenea", @@ -17852,7 +17852,7 @@ { "id": 21339, "Key": "Pierre Tombale Couant", - "enUS": " Pierre Tombale Couant ", + "enUS": "Pierre Tombale Couant ", "zhTW": "墓石長戟", "deDE": "Pierre Tombale Couant", "esES": "Pierre tombale couant", @@ -17869,7 +17869,7 @@ { "id": 21340, "Key": "Husoldal Evo", - "enUS": " Husoldal Evo ", + "enUS": "Husoldal Evo ", "zhTW": "血肉吞食者", "deDE": "Husoldal Evo", "esES": "Husoldal evo", @@ -17886,7 +17886,7 @@ { "id": 21341, "Key": "Grim's Burning Dead", - "enUS": " Grim's Burning Dead ", + "enUS": "Grim's Burning Dead ", "zhTW": "懼焰亡靈", "deDE": "Grims Brennender Tod", "esES": "La segadora ardiente", @@ -17903,7 +17903,7 @@ { "id": 21342, "Key": "Ribcracker", - "enUS": " Ribcracker ", + "enUS": "Ribcracker ", "zhTW": "肋骨粉碎者", "deDE": "Rippenbrecher", "esES": "Aplastacostillas", @@ -17920,7 +17920,7 @@ { "id": 21343, "Key": "Chromatic Ire", - "enUS": " Chromatic Ire ", + "enUS": "Chromatic Ire ", "zhTW": "炫彩之怒", "deDE": "Wallender Zorn", "esES": "Ira cromática", @@ -17937,7 +17937,7 @@ { "id": 21344, "Key": "Warpspear", - "enUS": " Warpspear ", + "enUS": "Warpspear ", "zhTW": "扭曲之矛", "deDE": "Warpspeer", "esES": "Asta de distorsión", @@ -17954,7 +17954,7 @@ { "id": 21345, "Key": "Skullcollector", - "enUS": " Skull Collector ", + "enUS": "Skull Collector ", "zhTW": "骷髏收集者", "deDE": "Schädelsammler", "esES": "Coleccionista de cráneos", @@ -17971,7 +17971,7 @@ { "id": 21346, "Key": "Skystrike", - "enUS": " Skystrike ", + "enUS": "Skystrike ", "zhTW": "天擊", "deDE": "Himmelsschlag", "esES": "Azote celestial", @@ -17988,7 +17988,7 @@ { "id": 21347, "Key": "Kuko Shakaku", - "enUS": " Kuko Shakaku ", + "enUS": "Kuko Shakaku ", "zhTW": "社角久子", "deDE": "Kuko Shakaku", "esES": "Kuko shakaku", @@ -18005,7 +18005,7 @@ { "id": 21348, "Key": "Endlessshail", - "enUS": " Endlesshail ", + "enUS": "Endlesshail ", "zhTW": "無盡冰雹", "deDE": "Endloshagel", "esES": "Granizo eterno", @@ -18022,7 +18022,7 @@ { "id": 21350, "Key": "Godstrike Arch", - "enUS": " Goldstrike Arch ", + "enUS": "Goldstrike Arch ", "zhTW": "金擊之拱", "deDE": "Goldschlagbogen", "esES": "Arco del azote áureo", @@ -18039,7 +18039,7 @@ { "id": 21351, "Key": "Langer Briser", - "enUS": " Langer Briser ", + "enUS": "Langer Briser ", "zhTW": "蘭古布利薩", "deDE": "Langer Briser", "esES": "Langer Briser", @@ -18056,7 +18056,7 @@ { "id": 21352, "Key": "Pus Spiter", - "enUS": " Pus Spitter ", + "enUS": "Pus Spitter ", "zhTW": "吐膿毒弩", "deDE": "Eiterspeier", "esES": "Maldad de pus", @@ -18073,7 +18073,7 @@ { "id": 21353, "Key": "Buriza-Do Kyanon", - "enUS": " Buriza-Do Kyanon ", + "enUS": "Buriza-Do Kyanon ", "zhTW": "暴雪砲弩", "deDE": "Buriza-Do Kyanon", "esES": "Buriza-do kyanon", @@ -18090,7 +18090,7 @@ { "id": 21354, "Key": "Vampiregaze", - "enUS": " Vampire Gaze ", + "enUS": "Vampire Gaze ", "zhTW": "吸血鬼的凝視", "deDE": "Vampirblick", "esES": "Mirada de vampiro", @@ -18107,7 +18107,7 @@ { "id": 21355, "Key": "String of Ears", - "enUS": " String of Ears ", + "enUS": "String of Ears ", "zhTW": "長串之耳", "deDE": "Ohrenkette", "esES": "Cordel de orejas", @@ -18124,7 +18124,7 @@ { "id": 21356, "Key": "Gorerider", - "enUS": " Gore Rider ", + "enUS": "Gore Rider ", "zhTW": "蝕肉騎士", "deDE": "Blutreiter", "esES": "Jinete sangriento", @@ -18141,7 +18141,7 @@ { "id": 21357, "Key": "Lavagout", - "enUS": " Lava Gout ", + "enUS": "Lava Gout ", "zhTW": "熔岩之痛", "deDE": "Lavastoß", "esES": "Gotas de lava", @@ -18158,7 +18158,7 @@ { "id": 21358, "Key": "Venom Grip", - "enUS": " Venom Grip ", + "enUS": "Venom Grip ", "zhTW": "劇毒之握", "deDE": "Giftgriff", "esES": "Apretón de la ponzoña", @@ -18175,7 +18175,7 @@ { "id": 21359, "Key": "Visceratuant", - "enUS": " Visceratuant ", + "enUS": "Visceratuant ", "zhTW": "維斯爾坦特", "deDE": "Eingeweidebeißer", "esES": "Visceratuant", @@ -18192,7 +18192,7 @@ { "id": 21360, "Key": "Guardian Angle", - "enUS": " Guardian Angel ", + "enUS": "Guardian Angel ", "zhTW": "守護天使", "deDE": "Schutzengel", "esES": "Ángel guardián", @@ -18209,7 +18209,7 @@ { "id": 21361, "Key": "Shaftstop", - "enUS": " Shaftstop ", + "enUS": "Shaftstop ", "zhTW": "箭止", "deDE": "Schaftstopper", "esES": "Óbice troncal", @@ -18226,7 +18226,7 @@ { "id": 21362, "Key": "Skin of the Vipermagi", - "enUS": " Skin of the Vipermagi ", + "enUS": "Skin of the Vipermagi ", "zhTW": "蛇魔法師之皮", "deDE": "Haut des Vipernmagiers", "esES": "Piel de mago viperino", @@ -18243,7 +18243,7 @@ { "id": 21363, "Key": "Blackhorn", - "enUS": " Blackhorn ", + "enUS": "Blackhorn ", "zhTW": "黑角", "deDE": "Schwarzhorn", "esES": "Cuerno negro", @@ -18260,7 +18260,7 @@ { "id": 21364, "Key": "Valkiry Wing", - "enUS": " Valkyrie Wing ", + "enUS": "Valkyrie Wing ", "zhTW": "女武神之翼", "deDE": "Walkürenflügel", "esES": "Ala de valquiria", @@ -18277,7 +18277,7 @@ { "id": 21365, "Key": "Peasent Crown", - "enUS": " Peasant Crown ", + "enUS": "Peasant Crown ", "zhTW": "農夫王冠", "deDE": "Bauernkrone", "esES": "Corona campesina", @@ -18294,7 +18294,7 @@ { "id": 21366, "Key": "Demon Machine", - "enUS": " Demon Machine ", + "enUS": "Demon Machine ", "zhTW": "惡魔機弩", "deDE": "Dämonenmaschine", "esES": "Máquina demoníaca", @@ -18311,7 +18311,7 @@ { "id": 21367, "Key": "Magewrath", - "enUS": " Magewrath ", + "enUS": "Magewrath ", "zhTW": "巫師之怒", "deDE": "Magierzorn", "esES": "Ira del mago", @@ -18328,7 +18328,7 @@ { "id": 21368, "Key": "Cliffkiller", - "enUS": " Cliffkiller ", + "enUS": "Cliffkiller ", "zhTW": "懸崖殺手", "deDE": "Klippentöter", "esES": "Asesino del acantilado", @@ -18345,7 +18345,7 @@ { "id": 21369, "Key": "Riphook", - "enUS": " Riphook ", + "enUS": "Riphook ", "zhTW": "撕裂之鉤", "deDE": "Reißhaken", "esES": "Garfio desgarrador", @@ -18362,7 +18362,7 @@ { "id": 21370, "Key": "Razorswitch", - "enUS": " Razorswitch ", + "enUS": "Razorswitch ", "zhTW": "剃刀杖", "deDE": "Klingenreißer", "esES": "Pértiga de cuchilla", @@ -18379,7 +18379,7 @@ { "id": 21371, "Key": "Meatscrape", - "enUS": " Meatscrape ", + "enUS": "Meatscrape ", "zhTW": "削肉", "deDE": "Beinschaber", "esES": "raspacarne", @@ -18396,7 +18396,7 @@ { "id": 21372, "Key": "Coldsteel Eye", - "enUS": " Coldsteel Eye ", + "enUS": "Coldsteel Eye ", "zhTW": "冰鋼之眼", "deDE": "Kältestahlauge", "esES": "Ojo de acero frío", @@ -18413,7 +18413,7 @@ { "id": 21373, "Key": "Pitblood Thirst", - "enUS": " Pitblood Thirst ", + "enUS": "Pitblood Thirst ", "zhTW": "血之狂慾", "deDE": "Blutdurst", "esES": "Sed de sangre de foso", @@ -18430,7 +18430,7 @@ { "id": 21374, "Key": "Gaya Wand", - "enUS": " Gaya Wand ", + "enUS": "Gaya Wand ", "zhTW": "加耶魔杖", "deDE": "Gayastab", "esES": "Vara de Gaya", @@ -18447,7 +18447,7 @@ { "id": 21375, "Key": "Ondal's Wisdom", - "enUS": " Ondal's Wisdom ", + "enUS": "Ondal's Wisdom ", "zhTW": "溫達的智慧", "deDE": "Ondals Weisheit", "esES": "Sabiduría de Ondal", @@ -18464,7 +18464,7 @@ { "id": 21376, "Key": "Geronimo's Fury", - "enUS": " Geronimo's Fury ", + "enUS": "Geronimo's Fury ", "zhTW": "吉拉尼莫的忿怒", "deDE": "Geronimos Wut", "esES": "Furia de Gerónimo", @@ -18481,7 +18481,7 @@ { "id": 21377, "Key": "Charsi's Favor", - "enUS": " Charsi's Favor ", + "enUS": "Charsi's Favor ", "zhTW": "恰西的恩惠", "deDE": "Charsis Gefälligkeit", "esES": "Favor de Charsi", @@ -18498,7 +18498,7 @@ { "id": 21378, "Key": "Doppleganger's Shadow", - "enUS": " Doppleganger's Shadow ", + "enUS": "Doppleganger's Shadow ", "zhTW": "變形怪之影", "deDE": "Doppelgängers Schatten", "esES": "Sombra de sosia", @@ -18515,7 +18515,7 @@ { "id": 21379, "Key": "Deathbit", - "enUS": " Deathbit ", + "enUS": "Deathbit ", "zhTW": "死亡尖鑽", "deDE": "Todesbiss", "esES": "Trozo de muerte", @@ -18532,7 +18532,7 @@ { "id": 21380, "Key": "Warshrike", - "enUS": " Warshrike ", + "enUS": "Warshrike ", "zhTW": "戰爭之鳥", "deDE": "Kriegswürger", "esES": "Alcaudón guerrero", @@ -18549,7 +18549,7 @@ { "id": 21381, "Key": "Gutsiphon", - "enUS": " Gut Siphon ", + "enUS": "Gut Siphon ", "zhTW": "內臟吸管", "deDE": "Gedärmesauger", "esES": "Sifón de tripas", @@ -18566,7 +18566,7 @@ { "id": 21382, "Key": "Razoredge", - "enUS": " Razor's Edge ", + "enUS": "Razor's Edge ", "zhTW": "剃刀銳斧", "deDE": "Messers Schneide", "esES": "Filo de cuchilla", @@ -18583,7 +18583,7 @@ { "id": 21383, "Key": "Stonerattle", - "enUS": " Stone Rattle ", + "enUS": "Stone Rattle ", "zhTW": "響石", "deDE": "Steinrassler", "esES": "Cascabel de piedra", @@ -18600,7 +18600,7 @@ { "id": 21384, "Key": "Marrowgrinder", - "enUS": " Marrow Grinder ", + "enUS": "Marrow Grinder ", "zhTW": "磨髓者", "deDE": "Knochenschleifer", "esES": "Asolador de tuétanos", @@ -18617,7 +18617,7 @@ { "id": 21385, "Key": "Gore Ripper", - "enUS": " Gore Ripper ", + "enUS": "Gore Ripper ", "zhTW": "血腥撕裂者", "deDE": "Aufschlitzer", "esES": "Descuartizador sangriento", @@ -18634,7 +18634,7 @@ { "id": 21386, "Key": "Bush Wacker", - "enUS": " Bush Wacker ", + "enUS": "Bush Wacker ", "zhTW": "伐木刀", "deDE": "Buschhauer", "esES": "zarza de la locura", @@ -18651,7 +18651,7 @@ { "id": 21387, "Key": "Demonlimb", - "enUS": " Demon Limb ", + "enUS": "Demon Limb ", "zhTW": "惡魔肢體", "deDE": "Dämonenglied", "esES": "Extremidad demoníaca", @@ -18668,7 +18668,7 @@ { "id": 21388, "Key": "Steelshade", - "enUS": " Steel Shade ", + "enUS": "Steel Shade ", "zhTW": "鋼影", "deDE": "Stahlschatten", "esES": "Sombra de acero", @@ -18685,7 +18685,7 @@ { "id": 21389, "Key": "Tomb Reaver", - "enUS": " Tomb Reaver ", + "enUS": "Tomb Reaver ", "zhTW": "盜墓者", "deDE": "Grabräuber", "esES": "Asaltatumbas", @@ -18702,7 +18702,7 @@ { "id": 21390, "Key": "Death's Web", - "enUS": " Death's Web ", + "enUS": "Death's Web ", "zhTW": "死亡之網", "deDE": "Todesnetz", "esES": "Red de la muerte", @@ -18719,7 +18719,7 @@ { "id": 21391, "Key": "Gaia's Wrath", - "enUS": " Gaia's Wrath ", + "enUS": "Gaia's Wrath ", "zhTW": "蓋亞之怒", "deDE": "Gaias Zorn", "esES": "Ira de Gaia", @@ -18736,7 +18736,7 @@ { "id": 21392, "Key": "Khalim's Vengance", - "enUS": " Khalim's Vengeance ", + "enUS": "Khalim's Vengeance ", "zhTW": "克林姆的復仇", "deDE": "Khalims Rache", "esES": "Venganza de Khalim", @@ -18753,7 +18753,7 @@ { "id": 21393, "Key": "Angel's Song", - "enUS": " Angel's Song ", + "enUS": "Angel's Song ", "zhTW": "天使之歌", "deDE": "Engelslied", "esES": "Canción del ángel", @@ -18770,7 +18770,7 @@ { "id": 21394, "Key": "The Reedeemer", - "enUS": " The Redeemer ", + "enUS": "The Redeemer ", "zhTW": "懺悔者", "deDE": "Der Erlöser", "esES": "El redentor", @@ -18787,7 +18787,7 @@ { "id": 21395, "Key": "Fleshbone", - "enUS": " Fleshbone ", + "enUS": "Fleshbone ", "zhTW": "血肉之骨", "deDE": "Fleischknochen", "esES": "Hueso de carne", @@ -18804,7 +18804,7 @@ { "id": 21396, "Key": "Odium", - "enUS": " Odium ", + "enUS": "Odium ", "zhTW": "厭憎", "deDE": "Hass", "esES": "Odium", @@ -18821,7 +18821,7 @@ { "id": 21397, "Key": "Blood Comet", - "enUS": " Blood Comet ", + "enUS": "Blood Comet ", "zhTW": "血彗星", "deDE": "Blutkomet", "esES": "Cometa de sangre", @@ -18838,7 +18838,7 @@ { "id": 21398, "Key": "Bonehew", - "enUS": " Bonehew ", + "enUS": "Bonehew ", "zhTW": "破骨", "deDE": "Knochenhacker", "esES": "Tallahuesos", @@ -18855,7 +18855,7 @@ { "id": 21399, "Key": "Steelrend", - "enUS": " Steelrend ", + "enUS": "Steelrend ", "zhTW": "碎鋼", "deDE": "Stahlhäcksler", "esES": "Desgarradores de acero", @@ -18872,7 +18872,7 @@ { "id": 21400, "Key": "Stone Crusher", - "enUS": " Stone Crusher ", + "enUS": "Stone Crusher ", "zhTW": "碎石者", "deDE": "Zermalmer", "esES": "Machacapiedras", @@ -18889,7 +18889,7 @@ { "id": 21401, "Key": "Bul-Kathos' Might", - "enUS": " Bul-Kathos' Might ", + "enUS": "Bul-Kathos' Might ", "zhTW": "布爾凱索之力", "deDE": "Bul-Kathos' Macht", "esES": "Poderío de Bul-Kathos", @@ -18906,7 +18906,7 @@ { "id": 21402, "Key": "Arioc's Needle", - "enUS": " Arioc's Needle ", + "enUS": "Arioc's Needle ", "zhTW": "愛理歐克之針", "deDE": "Ariocs Nadel", "esES": "Aguja de Arioc", @@ -18923,7 +18923,7 @@ { "id": 21403, "Key": "Shadowdancer", - "enUS": " Shadow Dancer ", + "enUS": "Shadow Dancer ", "zhTW": "影舞者", "deDE": "Schattentänzer", "esES": "Bailarín sombrío", @@ -18940,7 +18940,7 @@ { "id": 21404, "Key": "Indiego's Fancy", - "enUS": " Indiego's Fancy ", + "enUS": "Indiego's Fancy ", "zhTW": "印地哥的幻想", "deDE": "Indiegos Phantasie", "esES": "Capricho de Indiego", @@ -18957,7 +18957,7 @@ { "id": 21405, "Key": "Aladdin's Eviserator", - "enUS": " Aladdin's Eviscerator ", + "enUS": "Aladdin's Eviscerator ", "zhTW": "阿拉丁的刈骨刀", "deDE": "Aladins Verstümmler", "esES": "Eviscerador de Aladino", @@ -18974,7 +18974,7 @@ { "id": 21406, "Key": "Tyrael's Mercy", - "enUS": " Tyrael's Mercy ", + "enUS": "Tyrael's Mercy ", "zhTW": "泰瑞爾的慈悲", "deDE": "Tyraels Gnade", "esES": "Piedad de Tyrael", @@ -18991,7 +18991,7 @@ { "id": 21407, "Key": "Souldrain", - "enUS": " Soul Drainer ", + "enUS": "Soul Drainer ", "zhTW": "吸魂者", "deDE": "Seelensauger", "esES": "Drenadores de almas", @@ -19008,7 +19008,7 @@ { "id": 21408, "Key": "Runemaster", - "enUS": " Rune Master ", + "enUS": "Rune Master ", "zhTW": "符文大師", "deDE": "Runenmeister", "esES": "Maestra rúnica", @@ -19025,7 +19025,7 @@ { "id": 21409, "Key": "Deathcleaver", - "enUS": " Death Cleaver ", + "enUS": "Death Cleaver ", "zhTW": "死亡劈斧", "deDE": "Todesbeil", "esES": "Tajadera mortal", @@ -19042,7 +19042,7 @@ { "id": 21410, "Key": "Executioner's Justice", - "enUS": " Executioner's Justice ", + "enUS": "Executioner's Justice ", "zhTW": "劊子手的裁決", "deDE": "Henkers Gerechtigkeit", "esES": "Justicia del verdugo", @@ -19059,7 +19059,7 @@ { "id": 21411, "Key": "Wallace's Tear", - "enUS": " Wallace's Tear ", + "enUS": "Wallace's Tear ", "zhTW": "華萊士之淚", "deDE": "Wallaces Träne", "esES": "Lágrima de Wallace", @@ -19076,7 +19076,7 @@ { "id": 21412, "Key": "Leviathan", - "enUS": " Leviathan ", + "enUS": "Leviathan ", "zhTW": "利維坦", "deDE": "Leviathan", "esES": "Leviatán", @@ -19093,7 +19093,7 @@ { "id": 21413, "Key": "The Wanderer's Blade", - "enUS": " The Wanderer's Blade ", + "enUS": "The Wanderer's Blade ", "zhTW": "流浪者之刃", "deDE": "Die Klinge des Wanderers", "esES": "Cuchilla del vagabundo", @@ -19110,7 +19110,7 @@ { "id": 21414, "Key": "Qual'Kek's Enforcer", - "enUS": " Qual-Khek's Enforcer ", + "enUS": "Qual-Khek's Enforcer ", "zhTW": "夸爾凱克執法者", "deDE": "Qua-Kheks Vollstrecker", "esES": "Castigador de Qual-Kehk", @@ -19127,7 +19127,7 @@ { "id": 21415, "Key": "Dawnbringer", - "enUS": " Dawn Bringer ", + "enUS": "Dawn Bringer ", "zhTW": "黃昏降臨者", "deDE": "Herold der Morgendämmerung", "esES": "Portador del alba", @@ -19144,7 +19144,7 @@ { "id": 21416, "Key": "Dragontooth", - "enUS": " Dragontooth ", + "enUS": "Dragontooth ", "zhTW": "龍牙", "deDE": "Drachenzahn", "esES": "Diente de dragón", @@ -19161,7 +19161,7 @@ { "id": 21417, "Key": "Wisp", - "enUS": " Wisp Projector ", + "enUS": "Wisp Projector ", "zhTW": "鬼火投射者", "deDE": "Irrlichtprojektor", "esES": "Proyector de fuego fatuo", @@ -19178,7 +19178,7 @@ { "id": 21418, "Key": "Gargoyle's Bite", - "enUS": " Gargoyle's Bite ", + "enUS": "Gargoyle's Bite ", "zhTW": "石像鬼之噬", "deDE": "Gargoylebiss", "esES": "Mordisco de la gárgola", @@ -19195,7 +19195,7 @@ { "id": 21419, "Key": "Lacerator", - "enUS": " Lacerator ", + "enUS": "Lacerator ", "zhTW": "撕裂者", "deDE": "Zerfleischer", "esES": "Laceradora", @@ -19212,7 +19212,7 @@ { "id": 21420, "Key": "Mang Song's Lesson", - "enUS": " Mang Song's Lesson ", + "enUS": "Mang Song's Lesson ", "zhTW": "曼宋的教誨", "deDE": "Mang Songs Lektion", "esES": "Lección de Mang Song", @@ -19229,7 +19229,7 @@ { "id": 21421, "Key": "Viperfork", - "enUS": " Viperfork ", + "enUS": "Viperfork ", "zhTW": "蛇魔叉", "deDE": "Viperngabel", "esES": "Horquilla viperina", @@ -19246,7 +19246,7 @@ { "id": 21422, "Key": "Blood Chalice", - "enUS": " Blood Chalice ", + "enUS": "Blood Chalice ", "zhTW": "血杯", "deDE": "Blutkelch", "esES": "Cáliz de sangre", @@ -19263,7 +19263,7 @@ { "id": 21423, "Key": "El Espiritu", - "enUS": " El Espiritu ", + "enUS": "El Espiritu ", "zhTW": "魂靈", "deDE": "El Espiritu", "esES": "El espíritu", @@ -19280,7 +19280,7 @@ { "id": 21424, "Key": "The Long Rod", - "enUS": " The Longest Rod ", + "enUS": "The Longest Rod ", "zhTW": "極長之棍", "deDE": "Der längste Stab", "esES": "La vara más larga", @@ -19297,7 +19297,7 @@ { "id": 21425, "Key": "Demonhorn's Edge", - "enUS": " Demonhorn's Edge ", + "enUS": "Demonhorn's Edge ", "zhTW": "惡魔角尖", "deDE": "Dämonenhorns Schneide", "esES": "Filo del cuerno del demonio", @@ -19314,7 +19314,7 @@ { "id": 21426, "Key": "The Ensanguinator", - "enUS": " The Ensanguinator ", + "enUS": "The Ensanguinator ", "zhTW": "染血者", "deDE": "Der Ausbluter", "esES": "El ensangrentador", @@ -19331,7 +19331,7 @@ { "id": 21427, "Key": "The Reaper's Toll", - "enUS": " The Reaper's Toll ", + "enUS": "The Reaper's Toll ", "zhTW": "死神喪鐘", "deDE": "Schnitters Tribut", "esES": "El peaje del segador", @@ -19348,7 +19348,7 @@ { "id": 21428, "Key": "Spiritkeeper", - "enUS": " Spirit Keeper ", + "enUS": "Spirit Keeper ", "zhTW": "魂靈守衛者", "deDE": "Geistwächter", "esES": "Guardián de los espíritus", @@ -19365,7 +19365,7 @@ { "id": 21429, "Key": "Hellrack", - "enUS": " Hellrack ", + "enUS": "Hellrack ", "zhTW": "地獄刑具", "deDE": "Höllenplage", "esES": "Potro infernal", @@ -19382,7 +19382,7 @@ { "id": 21430, "Key": "Alma Negra", - "enUS": " Alma Negra ", + "enUS": "Alma Negra ", "zhTW": "黑魂", "deDE": "Alma Negra", "esES": "Alma negra", @@ -19399,7 +19399,7 @@ { "id": 21431, "Key": "Darkforge Spawn", - "enUS": " Darkforce Spawn ", + "enUS": "Darkforce Spawn ", "zhTW": "魔力肇生", "deDE": "Brut der Dunkelmacht", "esES": "Engendro de fuerza oscura", @@ -19416,7 +19416,7 @@ { "id": 21432, "Key": "Rockhew", - "enUS": " Rockhew ", + "enUS": "Rockhew ", "zhTW": "削石", "deDE": "Felshauer", "esES": "extractor de roca", @@ -19433,7 +19433,7 @@ { "id": 21433, "Key": "Sankenkur's Resurrection", - "enUS": " Sankekur's Resurrection ", + "enUS": "Sankekur's Resurrection ", "zhTW": "桑克庫爾的復活", "deDE": "Sankekurs Auferstehung", "esES": "Resurrección de Sankekur", @@ -19450,7 +19450,7 @@ { "id": 21434, "Key": "Erion's Bonehandle", - "enUS": " Erion's Bonehandle ", + "enUS": "Erion's Bonehandle ", "zhTW": "愛力恩的骨柄", "deDE": "Erions Knochengriff", "esES": "Empuñadura ósea de Erion", @@ -19467,7 +19467,7 @@ { "id": 21435, "Key": "The Archon Magus", - "enUS": " The Achron Magus ", + "enUS": "The Achron Magus ", "zhTW": "大法師", "deDE": "Der Achronmagier", "esES": "El mago de Achron", @@ -19484,7 +19484,7 @@ { "id": 21436, "Key": "Widow maker", - "enUS": " Widowmaker ", + "enUS": "Widowmaker ", "zhTW": "絕命", "deDE": "Witwenmacher", "esES": "Enviudador", @@ -19501,7 +19501,7 @@ { "id": 21437, "Key": "Catgut", - "enUS": " Catgut ", + "enUS": "Catgut ", "zhTW": "腸線", "deDE": "Katzendarm", "esES": "Tripas de gato", @@ -19518,7 +19518,7 @@ { "id": 21438, "Key": "Ghostflame", - "enUS": " Ghostflame ", + "enUS": "Ghostflame ", "zhTW": "鬼火", "deDE": "Geisterflamme", "esES": "Llama fantasmal", @@ -19535,7 +19535,7 @@ { "id": 21439, "Key": "Shadowkiller", - "enUS": " Shadow Killer ", + "enUS": "Shadow Killer ", "zhTW": "影殺者", "deDE": "Schattentöter", "esES": "Asesino sombrío", @@ -19552,7 +19552,7 @@ { "id": 21440, "Key": "Bling Bling", - "enUS": " Bling Bling ", + "enUS": "Bling Bling ", "zhTW": "閃亮亮", "deDE": "Bling-Bling", "esES": "Bling Bling", @@ -19569,7 +19569,7 @@ { "id": 21441, "Key": "Nebucaneezer's Storm", - "enUS": " Nebuchadnezzar's Storm ", + "enUS": "Nebuchadnezzar's Storm ", "zhTW": "尼布甲尼撒的風暴", "deDE": "Nebukadnezars Sturm", "esES": "Tormenta de Nabucodonosor", @@ -19586,7 +19586,7 @@ { "id": 21442, "Key": "Griffon's Eye", - "enUS": " Griffon's Eye ", + "enUS": "Griffon's Eye ", "zhTW": "獅鷲之眼", "deDE": "Greifenauge", "esES": "Ojo del grifo", @@ -19603,7 +19603,7 @@ { "id": 21443, "Key": "Eaglewind", - "enUS": " Eaglewind ", + "enUS": "Eaglewind ", "zhTW": "鷹之風", "deDE": "Adlerwind", "esES": "viento águila", @@ -19620,7 +19620,7 @@ { "id": 21444, "Key": "Windhammer", - "enUS": " Windhammer ", + "enUS": "Windhammer ", "zhTW": "風之鎚", "deDE": "Windhammer", "esES": "Martillo de viento", @@ -19637,7 +19637,7 @@ { "id": 21445, "Key": "Thunderstroke", - "enUS": " Thunderstroke ", + "enUS": "Thunderstroke ", "zhTW": "雷霆之擊", "deDE": "Donnerschlag", "esES": "Azote de trueno", @@ -19654,7 +19654,7 @@ { "id": 21446, "Key": "Giantmaimer", - "enUS": " Giant Maimer ", + "enUS": "Giant Maimer ", "zhTW": "重殘", "deDE": "Riesenverstümmler", "esES": "Desfigurador gigante", @@ -19671,7 +19671,7 @@ { "id": 21447, "Key": "Demon's Arch", - "enUS": " Demon's Arch ", + "enUS": "Demon's Arch ", "zhTW": "惡魔之拱", "deDE": "Dämonenspeer", "esES": "Arco del demonio", @@ -19688,7 +19688,7 @@ { "id": 21448, "Key": "The Scalper", - "enUS": " The Scalper ", + "enUS": "The Scalper ", "zhTW": "頭皮剝斧", "deDE": "Der Skalpierer", "esES": "Arrancacabelleras", @@ -19705,7 +19705,7 @@ { "id": 21449, "Key": "Bloodmoon", - "enUS": " Bloodmoon ", + "enUS": "Bloodmoon ", "zhTW": "血月", "deDE": "Blutmond", "esES": "Luna sangrienta", @@ -19722,7 +19722,7 @@ { "id": 21450, "Key": "Djinnslayer", - "enUS": " Djinn Slayer ", + "enUS": "Djinn Slayer ", "zhTW": "巨靈殺手", "deDE": "Dschinnschlächter", "esES": "Exterminagenios", @@ -19739,7 +19739,7 @@ { "id": 21451, "Key": "Cranebeak", - "enUS": " Cranebeak ", + "enUS": "Cranebeak ", "zhTW": "鶴嘴", "deDE": "Kranichschnabel", "esES": "Pico de grulla", @@ -19756,7 +19756,7 @@ { "id": 21452, "Key": "Iansang's Frenzy", - "enUS": " Iansang's Frenzy ", + "enUS": "Iansang's Frenzy ", "zhTW": "伊安森的狂怒", "deDE": "Lansangs Raserei", "esES": "Frenesí de Iansang", @@ -19773,7 +19773,7 @@ { "id": 21453, "Key": "Warhound", - "enUS": " Warhound ", + "enUS": "Warhound ", "zhTW": "戰爭獵犬", "deDE": "Haudegen", "esES": "Sabueso de guerra", @@ -19790,7 +19790,7 @@ { "id": 21454, "Key": "Gulletwound", - "enUS": " Gulletwound ", + "enUS": "Gulletwound ", "zhTW": "咽喉之傷", "deDE": "Schlundwunde", "esES": "Herida de gola", @@ -19807,7 +19807,7 @@ { "id": 21455, "Key": "Headhunter's Glory", - "enUS": " Head Hunter's Glory ", + "enUS": "Head Hunter's Glory ", "zhTW": "獵頭者的榮耀", "deDE": "Kopfjägers Ruhm", "esES": "Gloria del cazarrecompensas", @@ -19824,7 +19824,7 @@ { "id": 21456, "Key": "Mordoc's marauder", - "enUS": " Mordoc's Marauder ", + "enUS": "Mordoc's Marauder ", "zhTW": "馬德克的掠奪者", "deDE": "Mordocs Marodeur", "esES": "Maleante de Mordoc", @@ -19841,7 +19841,7 @@ { "id": 21457, "Key": "Talberd's Law", - "enUS": " Talberd's Law ", + "enUS": "Talberd's Law ", "zhTW": "泰爾柏德的律法", "deDE": "Talberds Gesetz", "esES": "Ley de Talberd", @@ -19858,7 +19858,7 @@ { "id": 21458, "Key": "Amodeus's Manipulator", - "enUS": " Amodeus' Manipulator ", + "enUS": "Amodeus' Manipulator ", "zhTW": "阿姆德思的操弄者", "deDE": "Amodeus' Manipulator", "esES": "Manipulador de Amodeus", @@ -19875,7 +19875,7 @@ { "id": 21459, "Key": "Darksoul", - "enUS": " Darksoul ", + "enUS": "Darksoul ", "zhTW": "幽闇魔靈", "deDE": "Dunkelseele", "esES": "Almanegra", @@ -19892,7 +19892,7 @@ { "id": 21460, "Key": "The Black Adder", - "enUS": " The Black Adder ", + "enUS": "The Black Adder ", "zhTW": "闇蛇", "deDE": "Die schwarze Natter", "esES": "La víbora negra", @@ -19909,7 +19909,7 @@ { "id": 21461, "Key": "Earthshifter", - "enUS": " Earth Shifter ", + "enUS": "Earth Shifter ", "zhTW": "撼地者", "deDE": "Erdschieber", "esES": "Desplazatierras", @@ -19926,7 +19926,7 @@ { "id": 21462, "Key": "Nature's Peace", - "enUS": " Nature's Peace ", + "enUS": "Nature's Peace ", "zhTW": "自然祥和", "deDE": "Friede der Natur", "esES": "Paz de la naturaleza", @@ -19943,7 +19943,7 @@ { "id": 21463, "Key": "Horazon's Chalice", - "enUS": " Horazon's Chalice ", + "enUS": "Horazon's Chalice ", "zhTW": "赫拉森之杯", "deDE": "Horazons Becher", "esES": "Cáliz de Horazón", @@ -19960,7 +19960,7 @@ { "id": 21464, "Key": "Seraph's Hymn", - "enUS": " Seraph's Hymn ", + "enUS": "Seraph's Hymn ", "zhTW": "熾天使之韻", "deDE": "Seraphims Psalm", "esES": "Himno del serafín", @@ -19977,7 +19977,7 @@ { "id": 21465, "Key": "Zakarum's Salvation", - "enUS": " Zakarum's Salvation ", + "enUS": "Zakarum's Salvation ", "zhTW": "撒卡蘭姆的救贖", "deDE": "Zakarums Erlösung", "esES": "Salvación de Zakarum", @@ -19994,7 +19994,7 @@ { "id": 21466, "Key": "Fleshripper", - "enUS": " Fleshripper ", + "enUS": "Fleshripper ", "zhTW": "裂肉者", "deDE": "Fleischreißer", "esES": "Desgarracarnes", @@ -20011,7 +20011,7 @@ { "id": 21467, "Key": "Stonerage", - "enUS": " Stonerage ", + "enUS": "Stonerage ", "zhTW": "石之狂怒", "deDE": "Steinwut", "esES": "Piedrafuria", @@ -20028,7 +20028,7 @@ { "id": 21468, "Key": "Blood Rain", - "enUS": " Blood Rain ", + "enUS": "Blood Rain ", "zhTW": "血雨", "deDE": "Blutregen", "esES": "Lluvia de sangre", @@ -20045,7 +20045,7 @@ { "id": 21469, "Key": "Horizon's Tornado", - "enUS": " Horizon's Tornado ", + "enUS": "Horizon's Tornado ", "zhTW": "地平線的龍捲風", "deDE": "Horazons Tornado", "esES": "Tornado en el horizonte", @@ -20062,7 +20062,7 @@ { "id": 21470, "Key": "Nord's Tenderizer", - "enUS": " Nord's Tenderizer ", + "enUS": "Nord's Tenderizer ", "zhTW": "北地肉鎚", "deDE": "Nords Weichklopfer", "esES": "Ablandadora de Nord", @@ -20079,7 +20079,7 @@ { "id": 21471, "Key": "Wrath of Cain", - "enUS": " Wrath of Cain ", + "enUS": "Wrath of Cain ", "zhTW": "凱恩之怒", "deDE": "Zorn des Cain", "esES": "Ira de Caín", @@ -20096,7 +20096,7 @@ { "id": 21472, "Key": "Siren's call", - "enUS": " Siren's Call ", + "enUS": "Siren's Call ", "zhTW": "賽蓮的呼喚", "deDE": "Sirenenruf", "esES": "Canto de sirena", @@ -20113,7 +20113,7 @@ { "id": 21473, "Key": "Jadetalon", - "enUS": " Jade Talon ", + "enUS": "Jade Talon ", "zhTW": "碧玉爪", "deDE": "Jadeklaue", "esES": "Garfa de jade", @@ -20130,7 +20130,7 @@ { "id": 21474, "Key": "Wraithfang", - "enUS": " Wraithfang ", + "enUS": "Wraithfang ", "zhTW": "怨靈之牙", "deDE": "Gespensterzahn", "esES": "Colmillánima", @@ -20147,7 +20147,7 @@ { "id": 21475, "Key": "Blademaster", - "enUS": " Blade Master ", + "enUS": "Blade Master ", "zhTW": "刀刃之王", "deDE": "Klingenmeister", "esES": "Maestro de la cuchilla", @@ -20164,7 +20164,7 @@ { "id": 21476, "Key": "Cerebus", - "enUS": " Cerebus' Bite ", + "enUS": "Cerebus' Bite ", "zhTW": "地獄犬之咬", "deDE": "Zerebus' Biss", "esES": "Mordisco de Cerebus", @@ -20181,7 +20181,7 @@ { "id": 21477, "Key": "Archangel's Deliverance", - "enUS": " Arch-angel's Deliverance ", + "enUS": "Arch-angel's Deliverance ", "zhTW": "大天使的救助", "deDE": "Erzengels Erlösung", "esES": "Liberación del arcángel", @@ -20198,7 +20198,7 @@ { "id": 21478, "Key": "Sinblade", - "enUS": " Sinblade ", + "enUS": "Sinblade ", "zhTW": "原罪之刃", "deDE": "Sündenschwert", "esES": "Cuchilla del pecado", @@ -20215,7 +20215,7 @@ { "id": 21479, "Key": "Runeslayer", - "enUS": " Rune Slayer ", + "enUS": "Rune Slayer ", "zhTW": "符文殺手", "deDE": "Runenschlächter", "esES": "Exterminador de las runas", @@ -20232,7 +20232,7 @@ { "id": 21480, "Key": "Excalibur", - "enUS": " Excalibur ", + "enUS": "Excalibur ", "zhTW": "石中劍", "deDE": "Excalibur", "esES": "Excalibur", @@ -20249,7 +20249,7 @@ { "id": 21481, "Key": "Fuego Del Sol", - "enUS": " Fuego Del Sol ", + "enUS": "Fuego Del Sol ", "zhTW": "日火", "deDE": "Fuego Del Sol", "esES": "Fuego del sol", @@ -20266,7 +20266,7 @@ { "id": 21482, "Key": "Stoneraven", - "enUS": " Stoneraven ", + "enUS": "Stoneraven ", "zhTW": "石鴉", "deDE": "Steinrabe", "esES": "Cuervo de piedra", @@ -20283,7 +20283,7 @@ { "id": 21483, "Key": "El Infierno", - "enUS": " El Infierno ", + "enUS": "El Infierno ", "zhTW": "妖獄之火", "deDE": "El Infierno", "esES": "El infierno", @@ -20300,7 +20300,7 @@ { "id": 21484, "Key": "Moonrend", - "enUS": " Moonrend ", + "enUS": "Moonrend ", "zhTW": "碎月", "deDE": "Mondreißer", "esES": "Rasgalunas", @@ -20317,11 +20317,11 @@ { "id": 21485, "Key": "Larzuk's Champion", - "enUS": " Larzuk's Champion ", + "enUS": "Larzuk's Champion ", "zhTW": "拉蘇克的鬥士", "deDE": "Larzuks Held", "esES": "Campeón de Larzuk", - "frFR": "Champion de Larzuk ", + "frFR": "Champion de Larzuk ", "itIT": "Campione di Larzuk", "koKR": "라르주크의 용사", "plPL": "Czempion Larzuka", @@ -20334,7 +20334,7 @@ { "id": 21486, "Key": "Nightsummon", - "enUS": " Nightsummon ", + "enUS": "Nightsummon ", "zhTW": "夜之召喚", "deDE": "Nachtbeschwörung", "esES": "Invocación nocturna", @@ -20351,7 +20351,7 @@ { "id": 21487, "Key": "Bonescapel", - "enUS": " Bonescalpel ", + "enUS": "Bonescalpel ", "zhTW": "骨刀", "deDE": "Knochensäge", "esES": "Escalpelo de hueso", @@ -20368,7 +20368,7 @@ { "id": 21488, "Key": "Rabbit Slayer", - "enUS": " Rabbit Slayer ", + "enUS": "Rabbit Slayer ", "zhTW": "白兔殺手", "deDE": "Kaninchenschlächter", "esES": "Mataconejos", @@ -20385,7 +20385,7 @@ { "id": 21489, "Key": "Pagan's Athame", - "enUS": " Pagan's Athame ", + "enUS": "Pagan's Athame ", "zhTW": "異教儀式刀", "deDE": "Heidenathame", "esES": "Athame del pagano", @@ -20402,7 +20402,7 @@ { "id": 21490, "Key": "The Swashbuckler", - "enUS": " The Swashbuckler ", + "enUS": "The Swashbuckler ", "zhTW": "暴徒", "deDE": "Der Säbelrassler", "esES": "El espadachín", @@ -20419,7 +20419,7 @@ { "id": 21491, "Key": "Kang's Virtue", - "enUS": " Kang's Virtue ", + "enUS": "Kang's Virtue ", "zhTW": "坎格的美德", "deDE": "Kangs Tugend", "esES": "Virtud de Kang", @@ -20436,7 +20436,7 @@ { "id": 21492, "Key": "Snaketongue", - "enUS": " Snake Tongue ", + "enUS": "Snake Tongue ", "zhTW": "蛇信", "deDE": "Schlangenzunge", "esES": "Lengua de culebra", @@ -20453,7 +20453,7 @@ { "id": 21493, "Key": "Lifechoke", - "enUS": " Lifechoke ", + "enUS": "Lifechoke ", "zhTW": "生命之扼", "deDE": "Lebenswürger", "esES": "Ahogavidas", @@ -20470,7 +20470,7 @@ { "id": 21494, "Key": "Ethereal edge", - "enUS": " Ethereal Edge ", + "enUS": "Ethereal Edge ", "zhTW": "無形之刃", "deDE": "Ätherschneide", "esES": "Filo etéreo", @@ -20487,7 +20487,7 @@ { "id": 21495, "Key": "Palo Grande", - "enUS": " Palo Grande ", + "enUS": "Palo Grande ", "zhTW": "派羅‧格蘭德", "deDE": "Palo Grande", "esES": "Palo grande", @@ -20504,7 +20504,7 @@ { "id": 21496, "Key": "Carnageleaver", - "enUS": " Carnage Leaver ", + "enUS": "Carnage Leaver ", "zhTW": "屠殺遺留者", "deDE": "Schlachtbringer", "esES": "Creacarnicerías", @@ -20521,7 +20521,7 @@ { "id": 21497, "Key": "Ghostleach", - "enUS": " Ghost Leach ", + "enUS": "Ghost Leach ", "zhTW": "濾魂", "deDE": "Geisteregel", "esES": "Lixiviador fantasmal", @@ -20538,7 +20538,7 @@ { "id": 21498, "Key": "Soulreaper", - "enUS": " Soul Reaper ", + "enUS": "Soul Reaper ", "zhTW": "奪魂者", "deDE": "Seelenschnitter", "esES": "Segador de almas", @@ -20555,7 +20555,7 @@ { "id": 21499, "Key": "Samual's Caretaker", - "enUS": " Samuel's Caretaker ", + "enUS": "Samuel's Caretaker ", "zhTW": "山姆的照護者", "deDE": "Samuels Hausmeister", "esES": "Cuidador de Samuel", @@ -20572,7 +20572,7 @@ { "id": 21500, "Key": "Hell's Whisper", - "enUS": " Hell Whisper ", + "enUS": "Hell Whisper ", "zhTW": "地獄呢喃", "deDE": "Höllenflüstern", "esES": "Susurro infernal", @@ -20589,7 +20589,7 @@ { "id": 21501, "Key": "The Harvester", - "enUS": " The Harvester ", + "enUS": "The Harvester ", "zhTW": "收割者", "deDE": "Der Schnitter", "esES": "La cosechadora", @@ -20606,7 +20606,7 @@ { "id": 21502, "Key": "Raiden's Crutch", - "enUS": " Raiden's Crutch ", + "enUS": "Raiden's Crutch ", "zhTW": "雷電拐杖", "deDE": "Raidens Krücke", "esES": "Muleta de Raiden", @@ -20623,7 +20623,7 @@ { "id": 21503, "Key": "The TreeEnt", - "enUS": " The Treentster ", + "enUS": "The Treentster ", "zhTW": "崔恩斯特", "deDE": "Der Baument", "esES": "el Señor de los Treents", @@ -20640,7 +20640,7 @@ { "id": 21504, "Key": "Stormwillow", - "enUS": " Stormwillow ", + "enUS": "Stormwillow ", "zhTW": "暴風柳木", "deDE": "Sturmweide", "esES": "Sauce de la tormenta", @@ -20657,7 +20657,7 @@ { "id": 21505, "Key": "Moonshadow", - "enUS": " Moon Shadow ", + "enUS": "Moon Shadow ", "zhTW": "月之影", "deDE": "Mondschatten", "esES": "Sombra de la luna", @@ -20674,7 +20674,7 @@ { "id": 21507, "Key": "Demonweb", - "enUS": " Demonweb ", + "enUS": "Demonweb ", "zhTW": "惡魔之網", "deDE": "Dämonennetz", "esES": "Red del demonio", @@ -20691,7 +20691,7 @@ { "id": 21508, "Key": "Bloodraven's Charge", - "enUS": " Blood Raven's Charge ", + "enUS": "Blood Raven's Charge ", "zhTW": "血鴉之擊", "deDE": "Blutrabes Ansturm", "esES": "Carga de Cuervo Sangriento", @@ -20708,7 +20708,7 @@ { "id": 21509, "Key": "Shadefalcon", - "enUS": " Shade Falcon ", + "enUS": "Shade Falcon ", "zhTW": "陰影之鷹", "deDE": "Schattenfalke", "esES": "Halcón de la sombra", @@ -20725,7 +20725,7 @@ { "id": 21510, "Key": "Robin's Yolk", - "enUS": " Robin's Yolk ", + "enUS": "Robin's Yolk ", "zhTW": "知更之卵", "deDE": "Rotkehlchendotter", "esES": "Vitelo de Robin", @@ -20742,7 +20742,7 @@ { "id": 21511, "Key": "Glimmershred", - "enUS": " Glimmershred ", + "enUS": "Glimmershred ", "zhTW": "微光裂片", "deDE": "Glimmerscherbe", "esES": "Brizna de luz", @@ -20759,7 +20759,7 @@ { "id": 21512, "Key": "Wraithflight", - "enUS": " Wraith Flight ", + "enUS": "Wraith Flight ", "zhTW": "死靈夜翔", "deDE": "Gespensterflucht", "esES": "Vuelo del ánima", @@ -20776,7 +20776,7 @@ { "id": 21513, "Key": "Lestron's Mark", - "enUS": " Lestron's Mark ", + "enUS": "Lestron's Mark ", "zhTW": "里斯崙的印記", "deDE": "Lestrons Zeichen", "esES": "Marca de Lestron", @@ -20793,7 +20793,7 @@ { "id": 21514, "Key": "Banshee's Wail", - "enUS": " Banshee's Wail ", + "enUS": "Banshee's Wail ", "zhTW": "女妖嚎哭", "deDE": "Bansheeklage", "esES": "Gemido de alma en pena", @@ -20810,7 +20810,7 @@ { "id": 21515, "Key": "Windstrike", - "enUS": " Windstrike ", + "enUS": "Windstrike ", "zhTW": "風之擊", "deDE": "Windschlag", "esES": "Azote de viento", @@ -20827,7 +20827,7 @@ { "id": 21516, "Key": "Medusa's Gaze", - "enUS": " Medusa's Gaze ", + "enUS": "Medusa's Gaze ", "zhTW": "梅杜莎的凝視", "deDE": "Medusas Blick", "esES": "Mirada de Medusa", @@ -20844,7 +20844,7 @@ { "id": 21517, "Key": "Titanfist", - "enUS": " Titan's Fist ", + "enUS": "Titan's Fist ", "zhTW": "泰坦之拳", "deDE": "Titans Faust", "esES": "Puño de Titán", @@ -20861,7 +20861,7 @@ { "id": 21518, "Key": "Hadeshorn", - "enUS": " Hadeshorn ", + "enUS": "Hadeshorn ", "zhTW": "黑帝斯號角", "deDE": "Hadeshorn", "esES": "cuerno de Hades", @@ -20878,7 +20878,7 @@ { "id": 21519, "Key": "Rockstopper", - "enUS": " Rockstopper ", + "enUS": "Rockstopper ", "zhTW": "石禦", "deDE": "Felsstopper", "esES": "Pararrocas", @@ -20895,7 +20895,7 @@ { "id": 21520, "Key": "Stealskull", - "enUS": " Stealskull ", + "enUS": "Stealskull ", "zhTW": "盜竊顱盔", "deDE": "Raubschädel", "esES": "Cráneo de acero", @@ -20912,7 +20912,7 @@ { "id": 21521, "Key": "Darksight Helm", - "enUS": " Darksight Helm ", + "enUS": "Darksight Helm ", "zhTW": "暗視之盔", "deDE": "Dunkelsichthelm", "esES": "Yelmo de vista oscura", @@ -20929,7 +20929,7 @@ { "id": 21522, "Key": "Crown of Thieves", - "enUS": " Crown of Thieves ", + "enUS": "Crown of Thieves ", "zhTW": "盜賊皇冠", "deDE": "Krone der Diebe", "esES": "Corona de ladrones", @@ -20946,7 +20946,7 @@ { "id": 21523, "Key": "Blackhorn's Face", - "enUS": " Blackhorn's Face ", + "enUS": "Blackhorn's Face ", "zhTW": "黑荊角面具", "deDE": "Schwarzhorns Gesicht", "esES": "Cara del cuerno negro", @@ -20963,7 +20963,7 @@ { "id": 21524, "Key": "The Spirit Shroud", - "enUS": " The Spirit Shroud ", + "enUS": "The Spirit Shroud ", "zhTW": "靈魂帷幕", "deDE": "Der Geisterschleier", "esES": "Mortaja del espíritu", @@ -20980,7 +20980,7 @@ { "id": 21525, "Key": "Skin of the Flayed One", - "enUS": " Skin of Flayed One ", + "enUS": "Skin of Flayed One ", "zhTW": "剝皮者之皮", "deDE": "Haut des Geschundenen", "esES": "Piel de azotado", @@ -20997,7 +20997,7 @@ { "id": 21526, "Key": "Ironpelt", - "enUS": " Iron Pelt ", + "enUS": "Iron Pelt ", "zhTW": "鋼鐵獸皮", "deDE": "Eisenpelz", "esES": "Cuero de hierro", @@ -21014,7 +21014,7 @@ { "id": 21527, "Key": "Spiritforge", - "enUS": " Spirit Forge ", + "enUS": "Spirit Forge ", "zhTW": "靈魂熔爐", "deDE": "Geisterschmiede", "esES": "Fragua espiritual", @@ -21031,7 +21031,7 @@ { "id": 21528, "Key": "Crow Caw", - "enUS": " Crow Caw ", + "enUS": "Crow Caw ", "zhTW": "鴉啼", "deDE": "Krähenkrächzen", "esES": "Graznido del cuervo", @@ -21048,7 +21048,7 @@ { "id": 21529, "Key": "Duriel's Shell", - "enUS": " Duriel's Shell ", + "enUS": "Duriel's Shell ", "zhTW": "都瑞爾之殼", "deDE": "Duriels Schale", "esES": "Concha de Duriel", @@ -21065,7 +21065,7 @@ { "id": 21530, "Key": "Skullder's Ire", - "enUS": " Skullder's Ire ", + "enUS": "Skullder's Ire ", "zhTW": "斯寇德的憤怒", "deDE": "Skullders Zorn", "esES": "Ira del skullder", @@ -21082,7 +21082,7 @@ { "id": 21531, "Key": "Toothrow", - "enUS": " Toothrow ", + "enUS": "Toothrow ", "zhTW": "排齒", "deDE": "Zahnreihe", "esES": "Fila de dientes", @@ -21099,7 +21099,7 @@ { "id": 21532, "Key": "Atma's Wail", - "enUS": " Atma's Wail ", + "enUS": "Atma's Wail ", "zhTW": "亞特瑪的哭喊", "deDE": "Atmas Wehklagen", "esES": "Gemido de Atma", @@ -21116,7 +21116,7 @@ { "id": 21533, "Key": "Black Hades", - "enUS": " Black Hades ", + "enUS": "Black Hades ", "zhTW": "黑色黑帝斯", "deDE": "Schwarzer Hades", "esES": "Hades negro", @@ -21133,7 +21133,7 @@ { "id": 21534, "Key": "Corpsemourn", - "enUS": " Corpsemourn ", + "enUS": "Corpsemourn ", "zhTW": "屍慟", "deDE": "Leichentrauer", "esES": "Luto de cadáver", @@ -21150,7 +21150,7 @@ { "id": 21535, "Key": "Que-hegan's Wisdom", - "enUS": " Que-Hegan's Wisdom ", + "enUS": "Que-Hegan's Wisdom ", "zhTW": "教宗的智慧", "deDE": "Que-Hegans Weisheit", "esES": "Sabiduría de Que-Hegan", @@ -21167,7 +21167,7 @@ { "id": 21536, "Key": "Moser's Blessed Circle", - "enUS": " Moser's Blessed Circle ", + "enUS": "Moser's Blessed Circle ", "zhTW": "摩瑟的祝福之圓", "deDE": "Mosars gesegneter Kreis", "esES": "Círculo bendito de Moser", @@ -21184,7 +21184,7 @@ { "id": 21537, "Key": "Stormchaser", - "enUS": " Stormchaser ", + "enUS": "Stormchaser ", "zhTW": "風暴追逐者", "deDE": "Sturmjäger", "esES": "Cazador de tormentas", @@ -21201,7 +21201,7 @@ { "id": 21538, "Key": "Tiamat's Rebuke", - "enUS": " Tiamat's Rebuke ", + "enUS": "Tiamat's Rebuke ", "zhTW": "魔龍的非難", "deDE": "Tiamats Rüge", "esES": "Reprimenda de Tiamat", @@ -21218,7 +21218,7 @@ { "id": 21539, "Key": "Gerke's Sanctuary", - "enUS": " Gerke's Sanctuary ", + "enUS": "Gerke's Sanctuary ", "zhTW": "基爾克的聖堂", "deDE": "Gerkes Zuflucht", "esES": "Santuario de Gerke", @@ -21235,7 +21235,7 @@ { "id": 21540, "Key": "Radimant's Sphere", - "enUS": " Radament's Sphere ", + "enUS": "Radament's Sphere ", "zhTW": "羅達門特的領域", "deDE": "Radaments Kugel", "esES": "Esfera de Radament", @@ -21252,7 +21252,7 @@ { "id": 21541, "Key": "Gravepalm", - "enUS": " Gravepalm ", + "enUS": "Gravepalm ", "zhTW": "墓穴手掌", "deDE": "Grabpalme", "esES": "Palmas sepulcrales", @@ -21269,7 +21269,7 @@ { "id": 21542, "Key": "Ghoulhide", - "enUS": " Ghoulhide ", + "enUS": "Ghoulhide ", "zhTW": "食屍鬼之皮", "deDE": "Ghulleder", "esES": "Pieles de necrófago", @@ -21286,7 +21286,7 @@ { "id": 21543, "Key": "Hellmouth", - "enUS": " Hellmouth ", + "enUS": "Hellmouth ", "zhTW": "地獄之口", "deDE": "Höllenschlund", "esES": "Boca del infierno", @@ -21303,7 +21303,7 @@ { "id": 21544, "Key": "Infernostride", - "enUS": " Infernostride ", + "enUS": "Infernostride ", "zhTW": "地獄闊步", "deDE": "Infernosprung", "esES": "Paso del averno", @@ -21320,7 +21320,7 @@ { "id": 21545, "Key": "Waterwalk", - "enUS": " Waterwalk ", + "enUS": "Waterwalk ", "zhTW": "水上飄", "deDE": "Wasserwanderung", "esES": "Paseo de agua", @@ -21337,7 +21337,7 @@ { "id": 21546, "Key": "Silkweave", - "enUS": " Silkweave ", + "enUS": "Silkweave ", "zhTW": "紗織", "deDE": "Seidenweberei", "esES": "Tejido de seda", @@ -21354,7 +21354,7 @@ { "id": 21547, "Key": "Wartraveler", - "enUS": " War Traveler ", + "enUS": "War Traveler ", "zhTW": "戰爭旅者", "deDE": "Kriegsreisender", "esES": "Viajante de la guerra", @@ -21371,7 +21371,7 @@ { "id": 21548, "Key": "Razortail", - "enUS": " Razortail ", + "enUS": "Razortail ", "zhTW": "剃刀之尾", "deDE": "Klingenschweif", "esES": "Cola de cuchilla", @@ -21388,7 +21388,7 @@ { "id": 21549, "Key": "Gloomstrap", - "enUS": " Gloom's Trap ", + "enUS": "Gloom's Trap ", "zhTW": "陰影陷阱", "deDE": "Düsterfalle", "esES": "Trampa de la penumbra", @@ -21405,7 +21405,7 @@ { "id": 21550, "Key": "Snowclash", - "enUS": " Snowclash ", + "enUS": "Snowclash ", "zhTW": "冰雪交織", "deDE": "Schneeklopfer", "esES": "Fragor de nieve", @@ -21422,7 +21422,7 @@ { "id": 21551, "Key": "Thudergod's Vigor", - "enUS": " Thundergod's Vigor ", + "enUS": "Thundergod's Vigor ", "zhTW": "雷神之力", "deDE": "Donnergotts Gedeihen", "esES": "Vigor del dios de los truenos", @@ -21439,7 +21439,7 @@ { "id": 21552, "Key": "Lidless Wall", - "enUS": " Lidless Wall ", + "enUS": "Lidless Wall ", "zhTW": "警戒之牆", "deDE": "Lidlose Wand", "esES": "Muro vigilante", @@ -21456,7 +21456,7 @@ { "id": 21553, "Key": "Lanceguard", - "enUS": " Lance Guard ", + "enUS": "Lance Guard ", "zhTW": "長槍守衛", "deDE": "Lanzenwache", "esES": "Protección lancera", @@ -21473,7 +21473,7 @@ { "id": 21554, "Key": "Squire's Cover", - "enUS": " Squire's Cover ", + "enUS": "Squire's Cover ", "zhTW": "侍從的掩護", "deDE": "Junkers Mantel", "esES": "Guarida del escudero", @@ -21490,7 +21490,7 @@ { "id": 21555, "Key": "Boneflame", - "enUS": " Boneflame ", + "enUS": "Boneflame ", "zhTW": "骨焰", "deDE": "Knochenflamme", "esES": "Llama ósea", @@ -21507,7 +21507,7 @@ { "id": 21556, "Key": "Steelpillar", - "enUS": " Steel Pillar ", + "enUS": "Steel Pillar ", "zhTW": "鋼鐵之柱", "deDE": "Stahlsäule", "esES": "Pilar de acero", @@ -21524,7 +21524,7 @@ { "id": 21557, "Key": "Nightwing's Veil", - "enUS": " Nightwing's Veil ", + "enUS": "Nightwing's Veil ", "zhTW": "夜翼面紗", "deDE": "Nachtschwinges Schleier", "esES": "Velo de alanoche", @@ -21541,7 +21541,7 @@ { "id": 21558, "Key": "Hightower's Watch", - "enUS": " Hightower's Watch ", + "enUS": "Hightower's Watch ", "zhTW": "高塔哨衛", "deDE": "Turmes Wacht", "esES": "Guardia de la torre alta", @@ -21558,7 +21558,7 @@ { "id": 21559, "Key": "Crown of Ages", - "enUS": " Crown of Ages ", + "enUS": "Crown of Ages ", "zhTW": "歲月之冠", "deDE": "Krone der Äonen", "esES": "Corona de las edades", @@ -21575,7 +21575,7 @@ { "id": 21560, "Key": "Andariel's Visage", - "enUS": " Andariel's Visage ", + "enUS": "Andariel's Visage ", "zhTW": "安達莉爾的面貌", "deDE": "Andariels Antlitz", "esES": "Semblante de Andariel", @@ -21592,7 +21592,7 @@ { "id": 21561, "Key": "Darkfear", - "enUS": " Darkfear ", + "enUS": "Darkfear ", "zhTW": "黑暗恐懼", "deDE": "Dunkelfurcht", "esES": "Miedo oscuro", @@ -21609,7 +21609,7 @@ { "id": 21562, "Key": "Dragonscale", - "enUS": " Dragonscale ", + "enUS": "Dragonscale ", "zhTW": "龍鱗", "deDE": "Drachenschuppen", "esES": "Escama de dragón", @@ -21626,7 +21626,7 @@ { "id": 21563, "Key": "Steel Carapice", - "enUS": " Steel Carapace ", + "enUS": "Steel Carapace ", "zhTW": "鋼鐵甲殼", "deDE": "Stahlrückenschild", "esES": "Caparazón de acero", @@ -21643,7 +21643,7 @@ { "id": 21564, "Key": "Ashrera's Wired Frame", - "enUS": " Asheara's Wired Frame ", + "enUS": "Asheara's Wired Frame ", "zhTW": "艾席拉的金屬框", "deDE": "Ascharas Drahtfalle", "esES": "Armazón de Asheara", @@ -21660,7 +21660,7 @@ { "id": 21565, "Key": "Rainbow Facet", - "enUS": " Rainbow Facet ", + "enUS": "Rainbow Facet ", "zhTW": "彩虹刻面", "deDE": "Regenbogenfacette", "esES": "Faceta de arcoíris", @@ -21677,7 +21677,7 @@ { "id": 21566, "Key": "Ravenlore", - "enUS": " Ravenlore ", + "enUS": "Ravenlore ", "zhTW": "掠鴉之王", "deDE": "Rabengarn", "esES": "Acervo del cuervo", @@ -21694,7 +21694,7 @@ { "id": 21567, "Key": "Boneshade", - "enUS": " Boneshade ", + "enUS": "Boneshade ", "zhTW": "骸骨陰影", "deDE": "Knochenschatten", "esES": "Sombra ósea", @@ -21711,7 +21711,7 @@ { "id": 21568, "Key": "Nethercrow", - "enUS": " Nethercrow ", + "enUS": "Nethercrow ", "zhTW": "冥府烏鴉", "deDE": "Niederkrähe", "esES": "Cuervo abismal", @@ -21728,7 +21728,7 @@ { "id": 21569, "Key": "Hellwarden's Husk", - "enUS": " Hell Warden's Husk ", + "enUS": "Hell Warden's Husk ", "zhTW": "地獄刑長之殼", "deDE": "Höllenwärters Hülle", "esES": "Élitro del alcaide infernal", @@ -21745,7 +21745,7 @@ { "id": 21570, "Key": "Flamebellow", - "enUS": " Flamebellow ", + "enUS": "Flamebellow ", "zhTW": "火嚎", "deDE": "Flammenbeller", "esES": "Bramido flamígero", @@ -21762,7 +21762,7 @@ { "id": 21571, "Key": "Fathom", - "enUS": " Death's Fathom ", + "enUS": "Death's Fathom ", "zhTW": "死亡深度", "deDE": "Klafter des Todes", "esES": "Profundidad de la muerte", @@ -21779,7 +21779,7 @@ { "id": 21572, "Key": "Wolfhowl", - "enUS": " Wolfhowl ", + "enUS": "Wolfhowl ", "zhTW": "狼嚎", "deDE": "Wolfsgeheul", "esES": "Aullido de lobo", @@ -21796,7 +21796,7 @@ { "id": 21573, "Key": "Spirit Ward", - "enUS": " Spirit Ward ", + "enUS": "Spirit Ward ", "zhTW": "魂系結界", "deDE": "Geisterschutz", "esES": "Custodia espiritual", @@ -21813,7 +21813,7 @@ { "id": 21574, "Key": "Kira's Guardian", - "enUS": " Kira's Guardian ", + "enUS": "Kira's Guardian ", "zhTW": "奇拉的守護", "deDE": "Kiras Wächter", "esES": "Guardián de Kira", @@ -21830,7 +21830,7 @@ { "id": 21575, "Key": "Orumus' Robes", - "enUS": " Ormus' Robe ", + "enUS": "Ormus' Robe ", "zhTW": "奧瑪斯之袍", "deDE": "Ormus' Gewand", "esES": "Toga de Ormus", @@ -21847,7 +21847,7 @@ { "id": 21576, "Key": "Gheed's Fortune", - "enUS": " Gheed's Fortune ", + "enUS": "Gheed's Fortune ", "zhTW": "基德的財運", "deDE": "Gheeds Glück", "esES": "Fortuna de Gheed", @@ -21864,7 +21864,7 @@ { "id": 21577, "Key": "The Vicar", - "enUS": " The Vicar ", + "enUS": "The Vicar ", "zhTW": "代牧者", "deDE": "Der Vikar", "esES": "El vicario", @@ -21881,7 +21881,7 @@ { "id": 21578, "Key": "Stormlash", - "enUS": " Stormlash ", + "enUS": "Stormlash ", "zhTW": "暴風之鞭", "deDE": "Sturmgeißel", "esES": "Látigo de tormenta", @@ -21898,7 +21898,7 @@ { "id": 21579, "Key": "Halaberd's Reign", - "enUS": " Halaberd's Reign ", + "enUS": "Halaberd's Reign ", "zhTW": "海拉柏德的國度", "deDE": "Halaberds Herrschaft", "esES": "Reinado de Halaberd", @@ -21915,7 +21915,7 @@ { "id": 21580, "Key": "Parkersor's Calm", - "enUS": " Parkersor's Calm ", + "enUS": "Parkersor's Calm ", "zhTW": "派克索爾的冷靜", "deDE": "Parkersors Ruhe", "esES": "Calma de Parkersor", @@ -21932,7 +21932,7 @@ { "id": 21581, "Key": "Warriv's Warder", - "enUS": " Warriv's Warder ", + "enUS": "Warriv's Warder ", "zhTW": "瓦瑞夫的護盾", "deDE": "Warrivs Wächter", "esES": "Guardián de Warriv", @@ -21949,7 +21949,7 @@ { "id": 21582, "Key": "Spike Thorn", - "enUS": " Spike Thorn ", + "enUS": "Spike Thorn ", "zhTW": "尖刺荊棘", "deDE": "Stacheldorn", "esES": "Espina de puntas", @@ -21966,11 +21966,11 @@ { "id": 21583, "Key": "Dracul's Grasp", - "enUS": " Dracul's Grasp ", + "enUS": "Dracul's Grasp ", "zhTW": "德古拉之握", "deDE": "Draculs Griff", "esES": "Control de Drácula", - "frFR": "Poigne de Drakul ", + "frFR": "Poigne de Drakul ", "itIT": "Stretta di Dracul", "koKR": "드라쿨의 손아귀", "plPL": "Chwyt Drakuli", @@ -21983,11 +21983,11 @@ { "id": 21584, "Key": "Frostwind", - "enUS": " Frostwind ", + "enUS": "Frostwind ", "zhTW": "霜風", "deDE": "Frostwind", "esES": "Airescarcha", - "frFR": " Ventebise", + "frFR": "Ventebise", "itIT": "Ventogelo", "koKR": "서리바람", "plPL": "Lodowy Wiatr", @@ -22000,7 +22000,7 @@ { "id": 21585, "Key": "Templar's Might", - "enUS": " Templar's Might ", + "enUS": "Templar's Might ", "zhTW": "聖堂騎士之力", "deDE": "Templers Macht", "esES": "Poderío del templario", @@ -22017,7 +22017,7 @@ { "id": 21586, "Key": "Eschuta's temper", - "enUS": " Eschuta's Temper ", + "enUS": "Eschuta's Temper ", "zhTW": "艾斯屈塔的憤怒", "deDE": "Eschutas Temperament", "esES": "Temperamento de Eschuta", @@ -22034,7 +22034,7 @@ { "id": 21587, "Key": "Firelizard's Talons", - "enUS": " Firelizard's Talons ", + "enUS": "Firelizard's Talons ", "zhTW": "火蜥蜴之爪", "deDE": "Klauen der Feuerechse", "esES": "Garfas del lagarto de fuego", @@ -22051,7 +22051,7 @@ { "id": 21588, "Key": "Sandstorm Trek", - "enUS": " Sandstorm Trek ", + "enUS": "Sandstorm Trek ", "zhTW": "沙暴之旅", "deDE": "Sandsturmtreck", "esES": "Caminata en tormenta de arena", @@ -22068,7 +22068,7 @@ { "id": 21589, "Key": "Marrowwalk", - "enUS": " Marrowwalk ", + "enUS": "Marrowwalk ", "zhTW": "骨髓行走", "deDE": "Knochensteig", "esES": "Paseo de tuétano", @@ -22085,7 +22085,7 @@ { "id": 21590, "Key": "Heaven's Light", - "enUS": " Heaven's Light ", + "enUS": "Heaven's Light ", "zhTW": "天堂之光", "deDE": "Himmlisches Licht", "esES": "Luz de los cielos", @@ -22102,7 +22102,7 @@ { "id": 21591, "Key": "Merman's Speed", - "enUS": " Merman's Sprocket ", + "enUS": "Merman's Sprocket ", "zhTW": "人魚的鍊輪靴", "deDE": "Wassermanns Zahnrad", "esES": "Piñón de Merman", @@ -22119,7 +22119,7 @@ { "id": 21592, "Key": "Arachnid Mesh", - "enUS": " Arachnid Mesh ", + "enUS": "Arachnid Mesh ", "zhTW": "蜘蛛之網", "deDE": "Spinnenmonsternetz", "esES": "Malla arácnida", @@ -22136,7 +22136,7 @@ { "id": 21593, "Key": "Nosferatu's Coil", - "enUS": " Nosferatu's Coil ", + "enUS": "Nosferatu's Coil ", "zhTW": "吸血鬼王之圈", "deDE": "Nosferatus Rolle", "esES": "Rosca de Nosferatu", @@ -22153,7 +22153,7 @@ { "id": 21594, "Key": "Metalgird", - "enUS": " Metalite's Girth ", + "enUS": "Metalite's Girth ", "zhTW": "梅塔萊特的束腰", "deDE": "Metalites Gürtel", "esES": "Cincha de Metalite", @@ -22170,7 +22170,7 @@ { "id": 21595, "Key": "Verdugo's Hearty Cord", - "enUS": " Verdungo's Hearty Cord ", + "enUS": "Verdungo's Hearty Cord ", "zhTW": "伐頓戈的強韌腰索", "deDE": "Verdungos Herzensband", "esES": "Cordón robusto de Verdungo", @@ -22187,7 +22187,7 @@ { "id": 21596, "Key": "Sigurd's Staunch", - "enUS": " Siggard's Stealth ", + "enUS": "Siggard's Stealth ", "zhTW": "席嘉德的隱藏", "deDE": "Siggards Verstohlenheit", "esES": "Sigilo de Sigard", @@ -22204,7 +22204,7 @@ { "id": 21597, "Key": "Carrion Wind", - "enUS": " Carrion Wind ", + "enUS": "Carrion Wind ", "zhTW": "腐肉之風", "deDE": "Aaswind", "esES": "Viento de carroña", @@ -22221,7 +22221,7 @@ { "id": 21598, "Key": "Giantskull", - "enUS": " Giant Skull ", + "enUS": "Giant Skull ", "zhTW": "巨大顱骨", "deDE": "Riesenschädel", "esES": "Cráneo gigante", @@ -22238,7 +22238,7 @@ { "id": 21599, "Key": "Ironward", - "enUS": " Astreon's Iron Ward ", + "enUS": "Astreon's Iron Ward ", "zhTW": "愛斯特龍的鐵衛", "deDE": "Astreons Eisenschutz", "esES": "Custodia de hierro de Astreon", @@ -22255,7 +22255,7 @@ { "id": 21600, "Key": "Gillian's Brazier", - "enUS": " Gillian's Brazier ", + "enUS": "Gillian's Brazier ", "zhTW": "吉莉安的火盆", "deDE": "Gillians Kohlebecken", "esES": "Brasero de Gillian", @@ -22272,7 +22272,7 @@ { "id": 21601, "Key": "Drakeflame", - "enUS": " Drakeflame ", + "enUS": "Drakeflame ", "zhTW": "龍獸之焰", "deDE": "Drachenflamme", "esES": "Dracollama", @@ -22289,7 +22289,7 @@ { "id": 21602, "Key": "Dust Storm", - "enUS": " Dust Storm ", + "enUS": "Dust Storm ", "zhTW": "沙塵暴", "deDE": "Staubsturm", "esES": "Tormenta de polvo", @@ -22306,7 +22306,7 @@ { "id": 21603, "Key": "Skulltred", - "enUS": " Skulltred ", + "enUS": "Skulltred ", "zhTW": "史古塔得", "deDE": "Schädler", "esES": "hacedor de cráneos", @@ -22323,7 +22323,7 @@ { "id": 21604, "Key": "Alma's Reflection", - "enUS": " Alma's Reflection ", + "enUS": "Alma's Reflection ", "zhTW": "靈魂殘影", "deDE": "Almas Spiegelbild", "esES": "Reflexión de Alma", @@ -22340,7 +22340,7 @@ { "id": 21605, "Key": "Drulan's Tounge", - "enUS": " Drulan's Tongue ", + "enUS": "Drulan's Tongue ", "zhTW": "杜蘭之舌", "deDE": "Drulans Zunge", "esES": "Lengua de Drulan", @@ -22357,7 +22357,7 @@ { "id": 21606, "Key": "Sacred Charge", - "enUS": " Sacred Charge ", + "enUS": "Sacred Charge ", "zhTW": "神聖職責", "deDE": "Heiliger Ansturm", "esES": "Carga sacra", @@ -22374,7 +22374,7 @@ { "id": 21607, "Key": "Bul-Kathos", - "enUS": " Bul-Kathos ", + "enUS": "Bul-Kathos ", "zhTW": "布爾凱索", "deDE": "Bul-Kathos", "esES": "Bul-Kathos", @@ -22391,7 +22391,7 @@ { "id": 21608, "Key": "Saracen's Chance", - "enUS": " Saracen's Chance ", + "enUS": "Saracen's Chance ", "zhTW": "薩拉森的機會", "deDE": "Sarazenenglück", "esES": "Suerte del sarraceno", @@ -22408,7 +22408,7 @@ { "id": 21609, "Key": "Highlord's Wrath", - "enUS": " Highlord's Wrath ", + "enUS": "Highlord's Wrath ", "zhTW": "大君之怒", "deDE": "Zorn des Hohen Fürsten", "esES": "Ira del gran señor", @@ -22425,7 +22425,7 @@ { "id": 21610, "Key": "Raven Frost", - "enUS": " Raven Frost ", + "enUS": "Raven Frost ", "zhTW": "烏鴉之霜", "deDE": "Rabenfrost", "esES": "Escarcha del cuervo", @@ -22442,7 +22442,7 @@ { "id": 21611, "Key": "Dwarf Star", - "enUS": " Dwarf Star ", + "enUS": "Dwarf Star ", "zhTW": "矮人之星", "deDE": "Zwergenstern", "esES": "Estrella enana", @@ -22459,7 +22459,7 @@ { "id": 21612, "Key": "Atma's Scarab", - "enUS": " Atma's Scarab ", + "enUS": "Atma's Scarab ", "zhTW": "亞特瑪的聖甲蟲", "deDE": "Atmas Skarabäus", "esES": "Alfazaque de Atma", @@ -22476,7 +22476,7 @@ { "id": 21613, "Key": "Mara's Kaleidoscope", - "enUS": " Mara's Kaleidoscope ", + "enUS": "Mara's Kaleidoscope ", "zhTW": "馬拉的萬花筒", "deDE": "Maras Kaleidoskop", "esES": "Caleidoscopio de Mara", @@ -22493,7 +22493,7 @@ { "id": 21614, "Key": "Crescent Moon", - "enUS": " Crescent Moon ", + "enUS": "Crescent Moon ", "zhTW": "新月", "deDE": "Mondsichel", "esES": "Luna creciente", @@ -22510,7 +22510,7 @@ { "id": 21615, "Key": "The Rising Sun", - "enUS": " The Rising Sun ", + "enUS": "The Rising Sun ", "zhTW": "旭日東升", "deDE": "Die aufgehende Sonne", "esES": "El sol naciente", @@ -22527,7 +22527,7 @@ { "id": 21616, "Key": "The Cat's Eye", - "enUS": " The Cat's Eye ", + "enUS": "The Cat's Eye ", "zhTW": "貓眼", "deDE": "Das Katzenauge", "esES": "El ojo de gato", @@ -22544,7 +22544,7 @@ { "id": 21617, "Key": "Bul Katho's Wedding Band", - "enUS": " Bul-Kathos' Wedding Band ", + "enUS": "Bul-Kathos' Wedding Band ", "zhTW": "布爾凱索的婚戒", "deDE": "Bul Kathos' Hochzeitsring", "esES": "Alianza de Bul-Kathos", @@ -22561,7 +22561,7 @@ { "id": 21618, "Key": "Rings", - "enUS": " Rings ", + "enUS": "Rings ", "zhTW": "指環", "deDE": "Ringe", "esES": "Anillos", @@ -22578,7 +22578,7 @@ { "id": 21619, "Key": "Metalgrid", - "enUS": " Metalgrid ", + "enUS": "Metalgrid ", "zhTW": "金屬網格", "deDE": "Metallgitter", "esES": "Rejilla metálica", @@ -22595,7 +22595,7 @@ { "id": 21621, "Key": "Stormshield", - "enUS": " Stormshield ", + "enUS": "Stormshield ", "zhTW": "暴風之盾", "deDE": "Sturmschild", "esES": "Escudo de tormenta", @@ -22612,7 +22612,7 @@ { "id": 21622, "Key": "Blackoak Shield", - "enUS": " Blackoak Shield ", + "enUS": "Blackoak Shield ", "zhTW": "黑橡樹盾", "deDE": "Schwarzeichenschild", "esES": "Escudo de roble negro", @@ -22629,7 +22629,7 @@ { "id": 21623, "Key": "Ormus' Robes", - "enUS": " Ormus' Robes ", + "enUS": "Ormus' Robes ", "zhTW": "奧瑪斯之袍", "deDE": "Ormus' Gewänder", "esES": "Togas de Ormus", @@ -22646,7 +22646,7 @@ { "id": 21624, "Key": "Arkaine's Valor", - "enUS": " Arkaine's Valor ", + "enUS": "Arkaine's Valor ", "zhTW": "阿凱尼的榮耀", "deDE": "Arkaines Heldenmut", "esES": "Valor de Arkaine", @@ -22663,7 +22663,7 @@ { "id": 21625, "Key": "The Gladiator's Bane", - "enUS": " The Gladiator's Bane ", + "enUS": "The Gladiator's Bane ", "zhTW": "鬥士之禍", "deDE": "Der Fluch des Gladiators", "esES": "La pesadilla del gladiador", @@ -22680,7 +22680,7 @@ { "id": 21626, "Key": "Veil of Steel", - "enUS": " Veil of Steel ", + "enUS": "Veil of Steel ", "zhTW": "鋼鐵面紗", "deDE": "Schleier aus Stahl", "esES": "Velo de acero", @@ -22697,7 +22697,7 @@ { "id": 21627, "Key": "Harlequin Crest", - "enUS": " Harlequin Crest ", + "enUS": "Harlequin Crest ", "zhTW": "諧角之冠", "deDE": "Harlekinskrone", "esES": "Cimera de arlequín", @@ -22714,7 +22714,7 @@ { "id": 21628, "Key": "Lance Guard", - "enUS": " Lance Guard ", + "enUS": "Lance Guard ", "zhTW": "長槍守衛", "deDE": "Lanzenwache", "esES": "Protección lancera", @@ -22731,7 +22731,7 @@ { "id": 21629, "Key": "Kerke's Sanctuary", - "enUS": " Gerke's Sanctuary ", + "enUS": "Gerke's Sanctuary ", "zhTW": "基爾克的聖堂", "deDE": "Gerkes Zuflucht", "esES": "Santuario de Gerke", @@ -22748,7 +22748,7 @@ { "id": 21630, "Key": "Mosers Blessed Circle", - "enUS": " Moser's Blessed Circle ", + "enUS": "Moser's Blessed Circle ", "zhTW": "摩瑟的祝福之圓", "deDE": "Mosars gesegneter Kreis", "esES": "Círculo bendito de Moser", @@ -22765,7 +22765,7 @@ { "id": 21631, "Key": "Que-Hegan's Wisdon", - "enUS": " Que-Hegan's Wisdom ", + "enUS": "Que-Hegan's Wisdom ", "zhTW": "教宗的智慧", "deDE": "Que-Hegans Weisheit", "esES": "Sabiduría de Que-Hegan", @@ -22782,7 +22782,7 @@ { "id": 21632, "Key": "Guardian Angel", - "enUS": " Guardian Angel ", + "enUS": "Guardian Angel ", "zhTW": "守護天使", "deDE": "Schutzengel", "esES": "Ángel guardián", @@ -22799,7 +22799,7 @@ { "id": 21633, "Key": "Skin of the Flayerd One", - "enUS": " Skin of the Flayed One ", + "enUS": "Skin of the Flayed One ", "zhTW": "剝皮者之皮", "deDE": "Haut des Geschundenen", "esES": "Piel del azotado", @@ -22816,7 +22816,7 @@ { "id": 21634, "Key": "Armor", - "enUS": " Armor ", + "enUS": "Armor ", "zhTW": "護甲", "deDE": "Rüstung", "esES": "Armadura", @@ -22833,7 +22833,7 @@ { "id": 21635, "Key": "Windforce", - "enUS": " Windforce ", + "enUS": "Windforce ", "zhTW": "風之力", "deDE": "Windmacht", "esES": "Fuerza del viento", @@ -22850,7 +22850,7 @@ { "id": 21636, "Key": "Eaglehorn", - "enUS": " Eaglehorn ", + "enUS": "Eaglehorn ", "zhTW": "鷹角弓", "deDE": "Adlerhorn", "esES": "Cuerno de águila", @@ -22867,7 +22867,7 @@ { "id": 21637, "Key": "Gimmershred", - "enUS": " Gimmershred ", + "enUS": "Gimmershred ", "zhTW": "吉默削斧", "deDE": "Glimmerscherbe", "esES": "Trasquiladora", @@ -22884,7 +22884,7 @@ { "id": 21638, "Key": "Widowmaker", - "enUS": " Widowmaker ", + "enUS": "Widowmaker ", "zhTW": "絕命", "deDE": "Witwenmacher", "esES": "Enviudador", @@ -22901,7 +22901,7 @@ { "id": 21639, "Key": "Stormspire", - "enUS": " Stormspire ", + "enUS": "Stormspire ", "zhTW": "暴風尖塔", "deDE": "Sturmspitze", "esES": "Aguja de la tormenta", @@ -22918,7 +22918,7 @@ { "id": 21640, "Key": "Naj's Puzzler", - "enUS": " Naj's Puzzler ", + "enUS": "Naj's Puzzler ", "zhTW": "娜吉的解謎杖", "deDE": "Najs Rätsler", "esES": "Enigma de Naj", @@ -22935,7 +22935,7 @@ { "id": 21641, "Key": "Ethereal Edge", - "enUS": " Ethereal Edge ", + "enUS": "Ethereal Edge ", "zhTW": "無形之刃", "deDE": "Ätherschneide", "esES": "Filo etéreo", @@ -22952,7 +22952,7 @@ { "id": 21642, "Key": "Wizardspike", - "enUS": " Wizardspike ", + "enUS": "Wizardspike ", "zhTW": "巫師之刺", "deDE": "Zauberdorn", "esES": "Punta mágica", @@ -22969,7 +22969,7 @@ { "id": 21643, "Key": "The Grandfather", - "enUS": " The Grandfather ", + "enUS": "The Grandfather ", "zhTW": "高祖", "deDE": "Der Großvater", "esES": "El padrino", @@ -22986,7 +22986,7 @@ { "id": 21644, "Key": "Doombringer", - "enUS": " Doombringer ", + "enUS": "Doombringer ", "zhTW": "末日使者", "deDE": "Todbringer", "esES": "Portador de fatalidad", @@ -23003,7 +23003,7 @@ { "id": 21645, "Key": "Tyrael's Might", - "enUS": " Tyrael's Might ", + "enUS": "Tyrael's Might ", "zhTW": "泰瑞爾之力", "deDE": "Tyraels Macht", "esES": "Poderío de Tyrael", @@ -23020,7 +23020,7 @@ { "id": 21646, "Key": "Lightsabre", - "enUS": " Lightsabre ", + "enUS": "Lightsabre ", "zhTW": "光之軍刀", "deDE": "Lichtsäbel", "esES": "Sable de la luz", @@ -23037,7 +23037,7 @@ { "id": 21647, "Key": "The Cranium Basher", - "enUS": " The Cranium Basher ", + "enUS": "The Cranium Basher ", "zhTW": "碎腦鎚", "deDE": "Der Schädelhauer", "esES": "Destrozacráneos", @@ -23054,7 +23054,7 @@ { "id": 21648, "Key": "Schaefer's Hammer", - "enUS": " Schaefer's Hammer ", + "enUS": "Schaefer's Hammer ", "zhTW": "史恰佛之鎚", "deDE": "Schaefers Hammer", "esES": "Martillo de Schaefer", @@ -23071,7 +23071,7 @@ { "id": 21649, "Key": "Baranar's Star", - "enUS": " Baranar's Star ", + "enUS": "Baranar's Star ", "zhTW": "巴拉那之星", "deDE": "Baranars Stern", "esES": "Estrella de Baranar", @@ -23088,7 +23088,7 @@ { "id": 21650, "Key": "Deaths's Web", - "enUS": " Death's Web ", + "enUS": "Death's Web ", "zhTW": "死亡之網", "deDE": "Todesnetz", "esES": "Red de la muerte", @@ -23105,7 +23105,7 @@ { "id": 21651, "Key": "Messerschmidt's Reaver", - "enUS": " Messerschmidt's Reaver ", + "enUS": "Messerschmidt's Reaver ", "zhTW": "梅希斯密特之劫掠者", "deDE": "Messerschmidts Räuber", "esES": "Destripador de Messerschmidt", @@ -23122,7 +23122,7 @@ { "id": 21652, "Key": "Hellslayer", - "enUS": " Hellslayer ", + "enUS": "Hellslayer ", "zhTW": "地獄殺戮者", "deDE": "Höllenschlächter", "esES": "Exterminadora infernal", @@ -23139,7 +23139,7 @@ { "id": 21653, "Key": "Endlesshail", - "enUS": " Endlesshail ", + "enUS": "Endlesshail ", "zhTW": "無盡冰雹", "deDE": "Endloshagel", "esES": "Granizo eterno", @@ -23156,7 +23156,7 @@ { "id": 21654, "Key": "The Atlantian", - "enUS": " The Atlantean ", + "enUS": "The Atlantean ", "zhTW": "亞特蘭提恩", "deDE": "Der Atlantide", "esES": "La atlante", @@ -23173,7 +23173,7 @@ { "id": 21655, "Key": "Riftlash", - "enUS": " Riftlash ", + "enUS": "Riftlash ", "zhTW": "破裂之鞭", "deDE": "Risspeitscher", "esES": "Fustafalla", @@ -23190,7 +23190,7 @@ { "id": 21656, "Key": "Baezil's Vortex", - "enUS": " Baezil's Vortex ", + "enUS": "Baezil's Vortex ", "zhTW": "貝西爾的漩渦", "deDE": "Baezils Wirbel", "esES": "Vórtice de Baezil", @@ -23207,7 +23207,7 @@ { "id": 21657, "Key": "Zakarum's Hand", - "enUS": " Zakarum's Hand ", + "enUS": "Zakarum's Hand ", "zhTW": "撒卡蘭姆之手", "deDE": "Zakarums Hand", "esES": "Mano de Zakarum", @@ -23224,7 +23224,7 @@ { "id": 21658, "Key": "Carin Shard", - "enUS": " Carin Shard ", + "enUS": "Carin Shard ", "zhTW": "凱林碎片", "deDE": "Monolithensplitter", "esES": "Esquirla de Cairn", @@ -23241,7 +23241,7 @@ { "id": 21659, "Key": "The Minataur", - "enUS": " The Minotaur ", + "enUS": "The Minotaur ", "zhTW": "牛頭怪", "deDE": "Der Minotaurus", "esES": "El minotauro", @@ -23258,7 +23258,7 @@ { "id": 21660, "Key": "Trang-Oul's Avatar", - "enUS": " Trang-Oul's Avatar ", + "enUS": "Trang-Oul's Avatar ", "zhTW": "塔格奧的化身", "deDE": "Trang-Ouls Avatar", "esES": "Avatar de Trang-Oul", @@ -23275,7 +23275,7 @@ { "id": 21661, "Key": "Trang-Oul's Guise", - "enUS": " Trang-Oul's Guise ", + "enUS": "Trang-Oul's Guise ", "zhTW": "塔格奧之容", "deDE": "Trang-Ouls Verkleidung", "esES": "Guisa de Trang-Oul", @@ -23292,7 +23292,7 @@ { "id": 21662, "Key": "Trang-Oul's Wing", - "enUS": " Trang-Oul's Wing ", + "enUS": "Trang-Oul's Wing ", "zhTW": "塔格奧之翼", "deDE": "Trang-Ouls Flügel", "esES": "Ala de Trang-Oul", @@ -23309,7 +23309,7 @@ { "id": 21663, "Key": "Trang-Oul's Mask", - "enUS": " Trang-Oul's Mask ", + "enUS": "Trang-Oul's Mask ", "zhTW": "塔格奧面具", "deDE": "Trang-Ouls Maske", "esES": "Máscara de Trang-Oul", @@ -23326,7 +23326,7 @@ { "id": 21664, "Key": "Trang-Oul's Scales", - "enUS": " Trang-Oul's Scales ", + "enUS": "Trang-Oul's Scales ", "zhTW": "塔格奧之鱗", "deDE": "Trang-Ouls Schuppen", "esES": "Escamas de Trang-Oul", @@ -23343,7 +23343,7 @@ { "id": 21665, "Key": "Trang-Oul's Claws", - "enUS": " Trang-Oul's Claws ", + "enUS": "Trang-Oul's Claws ", "zhTW": "塔格奧之爪", "deDE": "Trang-Ouls Krallen", "esES": "Garras de Trang-Oul", @@ -23360,7 +23360,7 @@ { "id": 21666, "Key": "Trang-Oul's Girth", - "enUS": " Trang-Oul's Girth ", + "enUS": "Trang-Oul's Girth ", "zhTW": "塔格奧之腹", "deDE": "Trang-Ouls Gurt", "esES": "Cincha de Trang-Oul", @@ -23377,7 +23377,7 @@ { "id": 21667, "Key": "Natalya's Odium", - "enUS": " Natalya's Odium ", + "enUS": "Natalya's Odium ", "zhTW": "娜塔亞的非難", "deDE": "Natalyas Hass", "esES": "Odium de Natalya", @@ -23394,7 +23394,7 @@ { "id": 21668, "Key": "Natalya's Totem", - "enUS": " Natalya's Totem ", + "enUS": "Natalya's Totem ", "zhTW": "娜塔亞的圖騰", "deDE": "Natalyas Totem", "esES": "Tótem de Natalya", @@ -23411,7 +23411,7 @@ { "id": 21669, "Key": "Natalya's Mark", - "enUS": " Natalya's Mark ", + "enUS": "Natalya's Mark ", "zhTW": "娜塔亞的印記", "deDE": "Natalyas Mal", "esES": "Marca de Natalya", @@ -23428,7 +23428,7 @@ { "id": 21670, "Key": "Natalya's Shadow", - "enUS": " Natalya's Shadow ", + "enUS": "Natalya's Shadow ", "zhTW": "娜塔亞的影子", "deDE": "Natalyas Schatten", "esES": "Sombra de Natalya", @@ -23445,7 +23445,7 @@ { "id": 21671, "Key": "Natalya's Soul", - "enUS": " Natalya's Soul ", + "enUS": "Natalya's Soul ", "zhTW": "娜塔亞的靈魂", "deDE": "Natalyas Seele", "esES": "Alma de Natalya", @@ -23462,7 +23462,7 @@ { "id": 21672, "Key": "Griswold's Legacy", - "enUS": " Griswold's Legacy ", + "enUS": "Griswold's Legacy ", "zhTW": "格里斯瓦德的傳奇", "deDE": "Griswolds Erbe", "esES": "Legado de Griswold", @@ -23479,7 +23479,7 @@ { "id": 21673, "Key": "Griswolds's Redemption", - "enUS": " Griswold's Redemption ", + "enUS": "Griswold's Redemption ", "zhTW": "格里斯瓦德的救贖", "deDE": "Griswolds Erlösung", "esES": "Redención de Griswold", @@ -23496,7 +23496,7 @@ { "id": 21674, "Key": "Griswold's Honor", - "enUS": " Griswold's Honor ", + "enUS": "Griswold's Honor ", "zhTW": "格里斯瓦德的榮耀", "deDE": "Griswolds Ehre", "esES": "Honor de Griswold", @@ -23513,7 +23513,7 @@ { "id": 21675, "Key": "Griswold's Heart", - "enUS": " Griswold's Heart ", + "enUS": "Griswold's Heart ", "zhTW": "格里斯瓦德之心", "deDE": "Griswolds Herz", "esES": "Corazón de Griswold", @@ -23530,7 +23530,7 @@ { "id": 21676, "Key": "Griswold's Valor", - "enUS": " Griswold's Valor ", + "enUS": "Griswold's Valor ", "zhTW": "格里斯瓦德的勇氣", "deDE": "Griswolds Heldenmut", "esES": "Valor de Griswold", @@ -23547,7 +23547,7 @@ { "id": 21677, "Key": "Tang's Imperial Robes", - "enUS": " Tang's Imperial Robes ", + "enUS": "Tang's Imperial Robes ", "zhTW": "唐帝的皇袍", "deDE": "Tangs Kaisergewand", "esES": "Togas imperiales de Tang", @@ -23564,7 +23564,7 @@ { "id": 21678, "Key": "Tang's Fore-Fathers", - "enUS": " Tang's Fore-Fathers ", + "enUS": "Tang's Fore-Fathers ", "zhTW": "唐帝的祖先", "deDE": "Tangs Vorväter", "esES": "Antepasados de Tang", @@ -23581,7 +23581,7 @@ { "id": 21679, "Key": "Tang's Rule", - "enUS": " Tang's Rule ", + "enUS": "Tang's Rule ", "zhTW": "唐帝的法則", "deDE": "Tangs Herrschaft", "esES": "Mando de Tang", @@ -23598,7 +23598,7 @@ { "id": 21680, "Key": "Tang's Throne", - "enUS": " Tang's Throne ", + "enUS": "Tang's Throne ", "zhTW": "唐帝的王座", "deDE": "Tangs Thron", "esES": "Trono de Tang", @@ -23615,7 +23615,7 @@ { "id": 21681, "Key": "Tang's Battle Standard", - "enUS": " Tang's Battle Standard ", + "enUS": "Tang's Battle Standard ", "zhTW": "唐帝的戰旗", "deDE": "Tangs Gefechtsstandarte", "esES": "Estandarte de batalla de Tang", @@ -23632,7 +23632,7 @@ { "id": 21682, "Key": "Ogun's Fierce Visage", - "enUS": " Ogun's Fierce Visage ", + "enUS": "Ogun's Fierce Visage ", "zhTW": "奧崗的殘暴面孔", "deDE": "Oguns tückische Fratze", "esES": "Semblante fiero de Ogun", @@ -23649,7 +23649,7 @@ { "id": 21683, "Key": "Ogun's Shadow", - "enUS": " Ogun's Shadow ", + "enUS": "Ogun's Shadow ", "zhTW": "奧崗之影", "deDE": "Oguns Schatten", "esES": "Sombra de Ogun", @@ -23666,7 +23666,7 @@ { "id": 21684, "Key": "Ogun's Lash", - "enUS": " Ogun's Lash ", + "enUS": "Ogun's Lash ", "zhTW": "奧崗之鞭", "deDE": "Oguns Peitsche", "esES": "Látigo de Ogun", @@ -23683,11 +23683,11 @@ { "id": 21685, "Key": "Ogun's Vengeance", - "enUS": " Ogun's Vengeance ", + "enUS": "Ogun's Vengeance ", "zhTW": "奧崗的復仇", "deDE": "Oguns Rache", "esES": "Venganza de Ogun", - "frFR": "Vengeance d’Ogun ", + "frFR": "Vengeance d’Ogun ", "itIT": "Vendetta di Ogun", "koKR": "오군의 복수", "plPL": "Zemsta Oguna", @@ -23700,7 +23700,7 @@ { "id": 21686, "Key": "Bul-Kathos' Warden", - "enUS": " Bul-Kathos' Warden ", + "enUS": "Bul-Kathos' Warden ", "zhTW": "布爾凱索看守者", "deDE": "Bul-Kathos' Wächter", "esES": "Alcaide de Bul-Kathos", @@ -23717,7 +23717,7 @@ { "id": 21687, "Key": "Bul-Kathos' Children", - "enUS": " Bul-Kathos' Children ", + "enUS": "Bul-Kathos' Children ", "zhTW": "布爾凱索的子嗣", "deDE": "Bul-Kathos' Kinder", "esES": "Descendientes de Bul-Kathos", @@ -23734,7 +23734,7 @@ { "id": 21688, "Key": "Bul-Kathos' Sacred Charge", - "enUS": " Bul-Kathos' Sacred Charge ", + "enUS": "Bul-Kathos' Sacred Charge ", "zhTW": "布爾凱索的神聖職責", "deDE": "Bul-Kathos' heiliger Ansturm", "esES": "Carga sacra de Bul-Kathos", @@ -23751,7 +23751,7 @@ { "id": 21689, "Key": "Bul-Kathos' Tribal Guardian", - "enUS": " Bul-Kathos' Tribal Guardian ", + "enUS": "Bul-Kathos' Tribal Guardian ", "zhTW": "布爾凱索的部族守護", "deDE": "Bul-Kathos' Stammeswächter", "esES": "Guardián tribal de Bul-Kathos", @@ -23768,7 +23768,7 @@ { "id": 21690, "Key": "Bul-Kathos' Custodian", - "enUS": " Bul-Kathos' Custodian ", + "enUS": "Bul-Kathos' Custodian ", "zhTW": "布爾凱索捍衛者", "deDE": "Bul-Kathos' Aufseher", "esES": "Custodio de Bul-Kathos", @@ -23785,7 +23785,7 @@ { "id": 21691, "Key": "Flowkrad's Howl", - "enUS": " Flowkrad's Howl ", + "enUS": "Flowkrad's Howl ", "zhTW": "夫羅卡德的狂嚎", "deDE": "Flowkrads Heulen", "esES": "Aullido de Flowkrad", @@ -23802,7 +23802,7 @@ { "id": 21692, "Key": "Flowkrad's Grin", - "enUS": " Flowkrad's Grin ", + "enUS": "Flowkrad's Grin ", "zhTW": "夫羅卡德的尖牙", "deDE": "Flowkrads Grinsen", "esES": "Mueca de Flowkrad", @@ -23819,7 +23819,7 @@ { "id": 21693, "Key": "Flowkrad's Fur", - "enUS": " Flowkrad's Fur ", + "enUS": "Flowkrad's Fur ", "zhTW": "夫羅卡德的毛皮", "deDE": "Flowkrads Fell", "esES": "Piel de Flowkrad", @@ -23836,7 +23836,7 @@ { "id": 21694, "Key": "Flowkrad's Paws", - "enUS": " Flowkrad's Paws ", + "enUS": "Flowkrad's Paws ", "zhTW": "夫羅卡德的腳掌", "deDE": "Flowkrads Pfoten", "esES": "Patas de Flowkrad", @@ -23853,7 +23853,7 @@ { "id": 21695, "Key": "Flowkrad's Sinew", - "enUS": " Flowkrad's Sinew ", + "enUS": "Flowkrad's Sinew ", "zhTW": "夫羅卡德的肌腱", "deDE": "Flowkrads Sehne", "esES": "Tendón de Flowkrad", @@ -23870,7 +23870,7 @@ { "id": 21696, "Key": "Aldur's Watchtower", - "enUS": " Aldur's Watchtower ", + "enUS": "Aldur's Watchtower ", "zhTW": "艾爾多的守衛", "deDE": "Aldurs Wachturm", "esES": "Torre de vigilancia de Aldur", @@ -23887,7 +23887,7 @@ { "id": 21697, "Key": "Aldur's Stony Gaze", - "enUS": " Aldur's Stony Gaze ", + "enUS": "Aldur's Stony Gaze ", "zhTW": "艾爾多的冷酷凝視", "deDE": "Aldurs Steinblick", "esES": "Mirada de piedra de Aldur", @@ -23904,7 +23904,7 @@ { "id": 21698, "Key": "Aldur's Deception", - "enUS": " Aldur's Deception ", + "enUS": "Aldur's Deception ", "zhTW": "艾爾多的欺暪", "deDE": "Aldurs Täuschung", "esES": "Engaño de Aldur", @@ -23921,7 +23921,7 @@ { "id": 21699, "Key": "Aldur's Guantlet", - "enUS": " Aldur's Gauntlet ", + "enUS": "Aldur's Gauntlet ", "zhTW": "艾爾多的護手", "deDE": "Aldurs Handschuh", "esES": "Guantelete de Aldur", @@ -23938,7 +23938,7 @@ { "id": 21700, "Key": "Aldur's Advance", - "enUS": " Aldur's Advance ", + "enUS": "Aldur's Advance ", "zhTW": "艾爾多的進擊", "deDE": "Aldurs Vormarsch", "esES": "Avance de Aldur", @@ -23955,7 +23955,7 @@ { "id": 21701, "Key": "M'avina's Battle Hymn", - "enUS": " M'avina's Battle Hymn ", + "enUS": "M'avina's Battle Hymn ", "zhTW": "馬維娜之戰鬥詩歌", "deDE": "M'avinas Kriegsgesang", "esES": "Himno de batalla de M'avina", @@ -23972,7 +23972,7 @@ { "id": 21702, "Key": "M'avina's True Sight", - "enUS": " M'avina's True Sight ", + "enUS": "M'avina's True Sight ", "zhTW": "馬維娜的真實之眼", "deDE": "M'avinas Wahre Sicht", "esES": "Visión verdadera de M'avina", @@ -23989,7 +23989,7 @@ { "id": 21703, "Key": "M'avina's Embrace", - "enUS": " M'avina's Embrace ", + "enUS": "M'avina's Embrace ", "zhTW": "馬維娜的擁抱", "deDE": "M'avinas Umarmung", "esES": "Abrazo de M'avina", @@ -24006,7 +24006,7 @@ { "id": 21704, "Key": "M'avina's Icy Clutch", - "enUS": " M'avina's Icy Clutch ", + "enUS": "M'avina's Icy Clutch ", "zhTW": "馬維娜的冰握", "deDE": "M'avinas Eisige Umklammerung", "esES": "Zarpas heladas de M'avina", @@ -24023,7 +24023,7 @@ { "id": 21705, "Key": "M'avina's Tenet", - "enUS": " M'avina's Tenet ", + "enUS": "M'avina's Tenet ", "zhTW": "馬維娜的教義", "deDE": "M'avinas Grundsatz", "esES": "Principio de M'avina", @@ -24040,7 +24040,7 @@ { "id": 21706, "Key": "M'avina's Caster", - "enUS": " M'avina's Caster ", + "enUS": "M'avina's Caster ", "zhTW": "馬維娜的強弓", "deDE": "M'avinas Besitzer", "esES": "Asaeteador de M'avina", @@ -24057,7 +24057,7 @@ { "id": 21707, "Key": "Sazabi's Grand Tribute", - "enUS": " Sazabi's Grand Tribute ", + "enUS": "Sazabi's Grand Tribute ", "zhTW": "沙薩比的崇高禮讚", "deDE": "Sazabis Großer Tribut", "esES": "Gran tributo de Sazabi", @@ -24074,7 +24074,7 @@ { "id": 21708, "Key": "Sazabi's Cobalt Redeemer", - "enUS": " Sazabi's Cobalt Redeemer ", + "enUS": "Sazabi's Cobalt Redeemer ", "zhTW": "沙薩比的救贖鈷劍", "deDE": "Sazabis Kobalterlöser", "esES": "Redentora de cobalto de Sazabi", @@ -24091,7 +24091,7 @@ { "id": 21709, "Key": "Sazabi's Ghost Liberator", - "enUS": " Sazabi's Ghost Liberator ", + "enUS": "Sazabi's Ghost Liberator ", "zhTW": "沙薩比的解靈框體", "deDE": "Sazabis Geisterbefreier", "esES": "Liberador de fantasmas de Sazabi", @@ -24108,7 +24108,7 @@ { "id": 21710, "Key": "Sazabi's Mental Sheath", - "enUS": " Sazabi's Mental Sheath ", + "enUS": "Sazabi's Mental Sheath ", "zhTW": "沙薩比的精神護罩", "deDE": "Sazabis Geisteshülle", "esES": "Funda mental de Sazabi", @@ -24125,7 +24125,7 @@ { "id": 21711, "Key": "Hwanin's Majesty", - "enUS": " Hwanin's Majesty ", + "enUS": "Hwanin's Majesty ", "zhTW": "桓因的威嚴", "deDE": "Hwanins Majestät", "esES": "Majestad de Hwanin", @@ -24142,11 +24142,11 @@ { "id": 21712, "Key": "Hwanin's Justice", - "enUS": " Hwanin's Justice ", + "enUS": "Hwanin's Justice ", "zhTW": "桓因的制裁", "deDE": "Hwanins Gerechtigkeit", "esES": "Justicia de Hwanin", - "frFR": "Justice de Hwanin ", + "frFR": "Justice de Hwanin ", "itIT": "Giustizia di Hwanin", "koKR": "환인의 정의", "plPL": "Sprawiedliwość Hwanina", @@ -24159,7 +24159,7 @@ { "id": 21713, "Key": "Hwanin's Splendor", - "enUS": " Hwanin's Splendor ", + "enUS": "Hwanin's Splendor ", "zhTW": "桓因的光輝", "deDE": "Hwanins Pracht", "esES": "Esplendor de Hwanin", @@ -24176,7 +24176,7 @@ { "id": 21714, "Key": "Hwanin's Refuge", - "enUS": " Hwanin's Refuge ", + "enUS": "Hwanin's Refuge ", "zhTW": "桓因的庇佑", "deDE": "Hwanins Zuflucht", "esES": "Refugio de Hwanin", @@ -24193,7 +24193,7 @@ { "id": 21715, "Key": "Hwanin's Cordon", - "enUS": " Hwanin's Cordon ", + "enUS": "Hwanin's Cordon ", "zhTW": "桓因的飾帶", "deDE": "Hwanins Kette", "esES": "Cordón de Hwanin", @@ -24210,7 +24210,7 @@ { "id": 21716, "Key": "The Disciple", - "enUS": " The Disciple ", + "enUS": "The Disciple ", "zhTW": "門徒", "deDE": "Der Schüler", "esES": "El discípulo", @@ -24227,7 +24227,7 @@ { "id": 21717, "Key": "Telling of Beads", - "enUS": " Telling of Beads ", + "enUS": "Telling of Beads ", "zhTW": "誦唸珠", "deDE": "Perlenorakel", "esES": "Rezo de rosario", @@ -24244,7 +24244,7 @@ { "id": 21718, "Key": "Laying of Hands", - "enUS": " Laying of Hands ", + "enUS": "Laying of Hands ", "zhTW": "按手禮", "deDE": "Hände auflegen", "esES": "Puesta de manos", @@ -24261,7 +24261,7 @@ { "id": 21719, "Key": "Rite of Passage", - "enUS": " Rite of Passage ", + "enUS": "Rite of Passage ", "zhTW": "入門式", "deDE": "Initiationsritus", "esES": "Rito iniciático", @@ -24278,7 +24278,7 @@ { "id": 21720, "Key": "Spiritual Custodian", - "enUS": " Dark Adherent ", + "enUS": "Dark Adherent ", "zhTW": "隱門徒", "deDE": "Dunkler Anhänger", "esES": "Adepto oscuro", @@ -24295,7 +24295,7 @@ { "id": 21721, "Key": "Credendum", - "enUS": " Credendum ", + "enUS": "Credendum ", "zhTW": "守信條", "deDE": "Credendum", "esES": "Credendum", @@ -24312,7 +24312,7 @@ { "id": 21722, "Key": "Cow King's Leathers", - "enUS": " Cow King's Leathers ", + "enUS": "Cow King's Leathers ", "zhTW": "牛王皮甲", "deDE": "Leder des Rinderkönigs", "esES": "Pieles del Rey de las Vacas", @@ -24329,7 +24329,7 @@ { "id": 21723, "Key": "Cow King's Horns", - "enUS": " Cow King's Horns ", + "enUS": "Cow King's Horns ", "zhTW": "牛王之角", "deDE": "Hörner des Rinderkönigs", "esES": "Cuernos del Rey de las Vacas", @@ -24346,7 +24346,7 @@ { "id": 21724, "Key": "Cow King's Hide", - "enUS": " Cow King's Hide ", + "enUS": "Cow King's Hide ", "zhTW": "牛王之皮", "deDE": "Fell des Rinderkönigs", "esES": "Cuero del Rey de las Vacas", @@ -24363,7 +24363,7 @@ { "id": 21725, "Key": "Cow King's Hoofs", - "enUS": " Cow King's Hooves ", + "enUS": "Cow King's Hooves ", "zhTW": "牛王之蹄", "deDE": "Hufe des Rinderkönigs", "esES": "Pezuñas del Rey de las Vacas", @@ -24380,7 +24380,7 @@ { "id": 21726, "Key": "Aragon's Masterpiece", - "enUS": " Aragon's Masterpiece ", + "enUS": "Aragon's Masterpiece ", "zhTW": "亞拉崗的曠世之作", "deDE": "Aragons Meisterwerk", "esES": "Obra maestra de Aragon", @@ -24397,7 +24397,7 @@ { "id": 21727, "Key": "Aragon's Sunfire", - "enUS": " Aragon's Sunfire ", + "enUS": "Aragon's Sunfire ", "zhTW": "亞拉崗的太陽之火", "deDE": "Aragons Sonnenfeuer", "esES": "Fuego solar de Aragon", @@ -24414,7 +24414,7 @@ { "id": 21728, "Key": "Aragon's Icy Stare", - "enUS": " Aragon's Icy Stare ", + "enUS": "Aragon's Icy Stare ", "zhTW": "亞拉崗的冰寒之視", "deDE": "Aragons Eisblick", "esES": "Mirada gélida de Aragon", @@ -24431,7 +24431,7 @@ { "id": 21729, "Key": "Aragon's Storm Cloud", - "enUS": " Aragon's Storm Cloud ", + "enUS": "Aragon's Storm Cloud ", "zhTW": "亞拉崗的暴風之雲", "deDE": "Aragons Sturmwolke", "esES": "Nube de tormenta de Aragon", @@ -24448,7 +24448,7 @@ { "id": 21730, "Key": "Orphan's Call", - "enUS": " Orphan's Call ", + "enUS": "Orphan's Call ", "zhTW": "孤兒的呼喚", "deDE": "Waisenruf", "esES": "Llamada de orfandad", @@ -24465,7 +24465,7 @@ { "id": 21731, "Key": "Guillaume's Face", - "enUS": " Guillaume's Face ", + "enUS": "Guillaume's Face ", "zhTW": "吉永之臉", "deDE": "Guillaumes Gesicht", "esES": "Cara de Guillaume", @@ -24482,7 +24482,7 @@ { "id": 21732, "Key": "Willhelm's Pride", - "enUS": " Willhelm's Pride ", + "enUS": "Willhelm's Pride ", "zhTW": "魏爾海姆的自尊", "deDE": "Willhelms Stolz", "esES": "Orgullo de Willhelm", @@ -24499,7 +24499,7 @@ { "id": 21733, "Key": "Magnus' Skin", - "enUS": " Magnus' Skin ", + "enUS": "Magnus' Skin ", "zhTW": "馬格納斯之皮", "deDE": "Magnus' Haut", "esES": "Piel de Magnus", @@ -24516,7 +24516,7 @@ { "id": 21734, "Key": "Wihtstan's Guard", - "enUS": " Whitstan's Guard ", + "enUS": "Whitstan's Guard ", "zhTW": "惠斯坦的守護", "deDE": "Whitstans Wache", "esES": "Protección de Whitstan", @@ -24533,7 +24533,7 @@ { "id": 21735, "Key": "Titan's Revenge", - "enUS": " Titan's Revenge ", + "enUS": "Titan's Revenge ", "zhTW": "泰坦的復仇", "deDE": "Titans Rache", "esES": "Revancha de Titán", @@ -24550,7 +24550,7 @@ { "id": 21736, "Key": "Shakabra's Crux", - "enUS": " Shakabra's Crux ", + "enUS": "Shakabra's Crux ", "zhTW": "賽可伯的謎題", "deDE": "Shakabras Crux", "esES": "Cruz de Shakabra", @@ -24567,7 +24567,7 @@ { "id": 21737, "Key": "Lycander's Aim", - "enUS": " Lycander's Aim ", + "enUS": "Lycander's Aim ", "zhTW": "萊坎德的準頭", "deDE": "Lycanders Ziel", "esES": "Tino de Lycander", @@ -24584,7 +24584,7 @@ { "id": 21738, "Key": "Shadow's Touch", - "enUS": " Shadow Touch ", + "enUS": "Shadow Touch ", "zhTW": "影之觸", "deDE": "Schattenberührung", "esES": "Toque de sombra", @@ -24601,7 +24601,7 @@ { "id": 21739, "Key": "The Prowler", - "enUS": " The Prowler ", + "enUS": "The Prowler ", "zhTW": "遊盪者", "deDE": "Der Schleicher", "esES": "El merodeador", @@ -24618,7 +24618,7 @@ { "id": 21740, "Key": "Mortal Crescent", - "enUS": " Mortal Crescent ", + "enUS": "Mortal Crescent ", "zhTW": "死亡新月", "deDE": "Halbmond der Sterblichen", "esES": "Medialuna mortal", @@ -24635,7 +24635,7 @@ { "id": 21741, "Key": "Cutthroat", - "enUS": " Bartuc's Chop Chop ", + "enUS": "Bartuc's Chop Chop ", "zhTW": "霸圖克的猛擊", "deDE": "Bartucs Chop-Chop", "esES": "Hachazo de Bartuc", @@ -24652,7 +24652,7 @@ { "id": 21742, "Key": "Sarmichian Justice", - "enUS": " Samurai Justice ", + "enUS": "Samurai Justice ", "zhTW": "武士的正義", "deDE": "Samuraigerechtigkeit", "esES": "Justicia samurái", @@ -24669,7 +24669,7 @@ { "id": 21743, "Key": "Annihilus", - "enUS": " Annihilus ", + "enUS": "Annihilus ", "zhTW": "滅絕", "deDE": "Vernichtikus", "esES": "Annihilus", @@ -24686,7 +24686,7 @@ { "id": 21744, "Key": "Arreat's Face", - "enUS": " Arreat's Face ", + "enUS": "Arreat's Face ", "zhTW": "亞瑞特的面容", "deDE": "Arreats Antlitz", "esES": "Cara de Arreat", @@ -24703,7 +24703,7 @@ { "id": 21745, "Key": "The Harbinger", - "enUS": " The Harbinger ", + "enUS": "The Harbinger ", "zhTW": "先兆", "deDE": "Der Vorbote", "esES": "El precursor", @@ -24720,7 +24720,7 @@ { "id": 21746, "Key": "Doomseer", - "enUS": " Doomseer ", + "enUS": "Doomseer ", "zhTW": "末日先知", "deDE": "Schwarzseher", "esES": "Profeta de fatalidad", @@ -24737,7 +24737,7 @@ { "id": 21747, "Key": "Howling Visage", - "enUS": " Howling Visage ", + "enUS": "Howling Visage ", "zhTW": "狂號面孔", "deDE": "Heulende Fratze", "esES": "Semblante aullante", @@ -24754,7 +24754,7 @@ { "id": 21748, "Key": "Terra", - "enUS": " Terra's Guardian ", + "enUS": "Terra's Guardian ", "zhTW": "提拉守護者", "deDE": "Terras Wächter", "esES": "Guardián de Terra", @@ -24771,7 +24771,7 @@ { "id": 21749, "Key": "Syrian", - "enUS": " Triad's Foliage ", + "enUS": "Triad's Foliage ", "zhTW": "三重葉", "deDE": "Triadenlaub", "esES": "Follaje de la tríada", @@ -24788,7 +24788,7 @@ { "id": 21750, "Key": "Jalal's Mane", - "enUS": " Jalal's Mane ", + "enUS": "Jalal's Mane ", "zhTW": "加爾的鬃毛", "deDE": "Jalals Mähne", "esES": "Crin de Jalal", @@ -24805,7 +24805,7 @@ { "id": 21751, "Key": "Malignant", - "enUS": " Malignant Skull ", + "enUS": "Malignant Skull ", "zhTW": "邪心骨", "deDE": "Heimtückischer Schädel", "esES": "Cráneo maligno", @@ -24822,7 +24822,7 @@ { "id": 21752, "Key": "Apothecary's Tote", - "enUS": " Apothecary's Tote ", + "enUS": "Apothecary's Tote ", "zhTW": "藥劑師的袋子", "deDE": "Apothekers Last", "esES": "Bolso del boticario", @@ -24839,7 +24839,7 @@ { "id": 21753, "Key": "Apocrypha", - "enUS": " Apocrypha ", + "enUS": "Apocrypha ", "zhTW": "離經叛道", "deDE": "Apokryphen", "esES": "Apocrypha", @@ -24856,7 +24856,7 @@ { "id": 21754, "Key": "Foci of Visjerei", - "enUS": " Foci of the Vizjerei ", + "enUS": "Foci of the Vizjerei ", "zhTW": "費斯傑利的焦點", "deDE": "Fokus der Vizjerei", "esES": "Focos de los Vizjerei", @@ -24873,7 +24873,7 @@ { "id": 21755, "Key": "Homunculus", - "enUS": " Homunculus ", + "enUS": "Homunculus ", "zhTW": "魔胎", "deDE": "Homunkulus", "esES": "Homúnculo", @@ -24890,7 +24890,7 @@ { "id": 21756, "Key": "Aurora's Guard", - "enUS": " Aurora's Guard ", + "enUS": "Aurora's Guard ", "zhTW": "奧羅拉的守護", "deDE": "Auroras Wache", "esES": "Guardia de la aurora", @@ -24907,7 +24907,7 @@ { "id": 21757, "Key": "Crest of Morn", - "enUS": " Crest of Morn ", + "enUS": "Crest of Morn ", "zhTW": "黎明徽章", "deDE": "Gefieder des Morgens", "esES": "Cresta de la mañana", @@ -24924,7 +24924,7 @@ { "id": 21758, "Key": "Herald of Zakarum", - "enUS": " Herald of Zakarum ", + "enUS": "Herald of Zakarum ", "zhTW": "撒卡蘭姆使者", "deDE": "Herold von Zakarum", "esES": "Heraldo de Zakarum", @@ -24941,7 +24941,7 @@ { "id": 21759, "Key": "Akarat's Protector", - "enUS": " Akarat's Protector ", + "enUS": "Akarat's Protector ", "zhTW": "阿卡拉特的保護者", "deDE": "Akarats Beschützer", "esES": "Protector de Akarat", @@ -24958,7 +24958,7 @@ { "id": 21760, "Key": "Ancient Eye", - "enUS": " Ancient Eye ", + "enUS": "Ancient Eye ", "zhTW": "古代之眼", "deDE": "Uraltes Auge", "esES": "Ojo antiguo", @@ -24975,7 +24975,7 @@ { "id": 21761, "Key": "Globe of Visjerei", - "enUS": " Globe of the Vizjerei ", + "enUS": "Globe of the Vizjerei ", "zhTW": "費斯傑利之球", "deDE": "Kugel der Vizjerei", "esES": "Globo de los Vizjerei", @@ -24992,7 +24992,7 @@ { "id": 21762, "Key": "The Oculus", - "enUS": " The Oculus ", + "enUS": "The Oculus ", "zhTW": "核瞳", "deDE": "Das Auge", "esES": "El óculo", @@ -25009,7 +25009,7 @@ { "id": 21763, "Key": "Phoenix Egg", - "enUS": " Phoenix Egg ", + "enUS": "Phoenix Egg ", "zhTW": "鳳凰蛋", "deDE": "Ei des Phönix", "esES": "Huevo de fénix", @@ -25026,7 +25026,7 @@ { "id": 21764, "Key": "Xenos", - "enUS": " Xenos ", + "enUS": "Xenos ", "zhTW": "異鄉", "deDE": "Xenos", "esES": "Xenos", @@ -25043,7 +25043,7 @@ { "id": 21765, "Key": "Nagas", - "enUS": " Nagas ", + "enUS": "Nagas ", "zhTW": "蛇龍", "deDE": "Daos", "esES": "Nagas", @@ -25060,7 +25060,7 @@ { "id": 21766, "Key": "Wyvern's Head", - "enUS": " Wyvern's Head ", + "enUS": "Wyvern's Head ", "zhTW": "飛龍首", "deDE": "Wyvernkopf", "esES": "Cabeza de wyvern", @@ -25077,7 +25077,7 @@ { "id": 21767, "Key": "Sightless Veil", - "enUS": " Sightless Veil ", + "enUS": "Sightless Veil ", "zhTW": "目盲面紗", "deDE": "Blinder Schleier", "esES": "Velo ciego", @@ -25094,7 +25094,7 @@ { "id": 21768, "Key": "ChampionFormatX", - "enUS": " %0 %1 ", + "enUS": "%0 %1 ", "zhTW": "%0%1", "deDE": "a0n1:%0 %1", "esES": "a0n1:%1 %0", @@ -25111,7 +25111,7 @@ { "id": 21778, "Key": "ob5", - "enUS": " Jared's Stone ", + "enUS": "Jared's Stone ", "zhTW": "傑瑞德之石", "deDE": "Jareds Stein", "esES": "Piedra de Jared", @@ -25128,7 +25128,7 @@ { "id": 21779, "Key": "pad", - "enUS": " Kurast Shield ", + "enUS": "Kurast Shield ", "zhTW": "庫拉斯特盾", "deDE": "Kurastschild", "esES": "Escudo de Kurast", @@ -25145,7 +25145,7 @@ { "id": 21780, "Key": "axf", - "enUS": " Hatchet Hands ", + "enUS": "Hatchet Hands ", "zhTW": "斧手", "deDE": "Axthände", "esES": "[fp]Manos de hachuela", @@ -25162,7 +25162,7 @@ { "id": 21784, "Key": "Class Specific", - "enUS": " Class-specific ", + "enUS": "Class-specific ", "zhTW": "限定職業", "deDE": "Klassenspezifisch", "esES": "Específico de una clase", @@ -25179,7 +25179,7 @@ { "id": 21785, "Key": "fana", - "enUS": " Frozen Anya ", + "enUS": "Frozen Anya ", "zhTW": "冰凍的安亞", "deDE": "Anya, eingefroren", "esES": "Anya congelada", @@ -25196,7 +25196,7 @@ { "id": 21805, "Key": "0sc", - "enUS": " Scroll of Knowledge ", + "enUS": "Scroll of Knowledge ", "zhTW": "知識卷軸", "deDE": "Schriftrolle des Wissens", "esES": "Pergamino de conocimiento", @@ -25213,7 +25213,7 @@ { "id": 21815, "Key": "Tal Rasha's Wrappings", - "enUS": " Tal Rasha's Wrappings ", + "enUS": "Tal Rasha's Wrappings ", "zhTW": "塔拉夏的外袍", "deDE": "Tal Rashas Hüllen", "esES": "Vestiduras de Tal Rasha", @@ -25230,7 +25230,7 @@ { "id": 21816, "Key": "Tal Rasha's Fire-Spun Cloth", - "enUS": " Tal Rasha's Fine-Spun Cloth ", + "enUS": "Tal Rasha's Fine-Spun Cloth ", "zhTW": "塔拉夏的精織腰布", "deDE": "Tal Rashas feine Kleidung", "esES": "Tela fina de Tal Rasha", @@ -25247,7 +25247,7 @@ { "id": 21817, "Key": "Tal Rasha's Adjudication", - "enUS": " Tal Rasha's Adjudication ", + "enUS": "Tal Rasha's Adjudication ", "zhTW": "塔拉夏的判決", "deDE": "Tal Rashas Urteil", "esES": "Decisión de Tal Rasha", @@ -25264,7 +25264,7 @@ { "id": 21818, "Key": "Tal Rasha's Howling Wind", - "enUS": " Tal Rasha's Guardianship ", + "enUS": "Tal Rasha's Guardianship ", "zhTW": "塔拉夏的守護", "deDE": "Tal Rashas Obhut", "esES": "Custodia de Tal Rasha", @@ -25281,7 +25281,7 @@ { "id": 21819, "Key": "Tal Rasha's Lidless Eye", - "enUS": " Tal Rasha's Lidless Eye ", + "enUS": "Tal Rasha's Lidless Eye ", "zhTW": "塔拉夏的警惕之眼", "deDE": "Tal Rashas lidloses Auge", "esES": "Ojo sin párpado de Tal Rasha", @@ -25298,7 +25298,7 @@ { "id": 21820, "Key": "Tal Rasha's Horadric Crest", - "enUS": " Tal Rasha's Horadric Crest ", + "enUS": "Tal Rasha's Horadric Crest ", "zhTW": "塔拉夏的赫拉迪姆之冠", "deDE": "Tal Rashas Horadrimwappen", "esES": "Cimera horádrica de Tal Rasha", @@ -25315,7 +25315,7 @@ { "id": 21821, "Key": "Hwanin's Seal", - "enUS": " Hwanin's Blessing ", + "enUS": "Hwanin's Blessing ", "zhTW": "桓因的祝福", "deDE": "Hwanins Segen", "esES": "Bendición de Hwanin", @@ -25332,7 +25332,7 @@ { "id": 21822, "Key": "Heaven's Brethren", - "enUS": " Heaven's Brethren ", + "enUS": "Heaven's Brethren ", "zhTW": "天堂的同胞", "deDE": "Brüder des Himmels", "esES": "Hermanos de los cielos", @@ -25349,7 +25349,7 @@ { "id": 21823, "Key": "Dangoon's Teaching", - "enUS": " Dangoon's Teaching ", + "enUS": "Dangoon's Teaching ", "zhTW": "檀君的教導", "deDE": "Dangoons Lehre", "esES": "Enseñanza de Dangoon", @@ -25366,7 +25366,7 @@ { "id": 21824, "Key": "Ondal's Almighty", - "enUS": " Ondal's Almighty ", + "enUS": "Ondal's Almighty ", "zhTW": "溫達的全靈", "deDE": "Ondals Allmacht", "esES": "Poder supremo de Ondal", @@ -25383,7 +25383,7 @@ { "id": 21825, "Key": "Heaven's Taebaek", - "enUS": " Taebaek's Glory ", + "enUS": "Taebaek's Glory ", "zhTW": "太白山的榮光", "deDE": "Taebaeks Ruhm", "esES": "Gloria de Taebaek", @@ -25400,7 +25400,7 @@ { "id": 21826, "Key": "Haemosu's Adament", - "enUS": " Haemosu's Adamant ", + "enUS": "Haemosu's Adamant ", "zhTW": "解慕漱的堅決", "deDE": "Haemosus Willenskraft", "esES": "Convicción de Haemosu", @@ -25417,7 +25417,7 @@ { "id": 21827, "Key": "Lycander's Flank", - "enUS": " Lycander's Flank ", + "enUS": "Lycander's Flank ", "zhTW": "萊坎德的側翼", "deDE": "Lycanders Flanke", "esES": "Costado de Lycander", @@ -25434,7 +25434,7 @@ { "id": 21828, "Key": "Constricting Ring", - "enUS": " Constricting Ring ", + "enUS": "Constricting Ring ", "zhTW": "束縛之戒", "deDE": "Ring der Einschnürung", "esES": "Anillo constrictor", @@ -25451,7 +25451,7 @@ { "id": 21829, "Key": "Ginther's Rift", - "enUS": " Ginther's Rift ", + "enUS": "Ginther's Rift ", "zhTW": "金瑟的裂隙", "deDE": "Ginthers Zerrissenheit", "esES": "Falla de Ginther", @@ -25468,7 +25468,7 @@ { "id": 21830, "Key": "Naj's Ancient Set", - "enUS": " Naj's Ancient Vestige ", + "enUS": "Naj's Ancient Vestige ", "zhTW": "娜吉的上古遺物", "deDE": "Najs alte Spur", "esES": "Vestigio antiguo de Naj", @@ -25485,7 +25485,7 @@ { "id": 21831, "Key": "Naj's Light Plate", - "enUS": " Naj's Light Plate ", + "enUS": "Naj's Light Plate ", "zhTW": "娜吉的輕鎧", "deDE": "Najs leichte Rüstung", "esES": "Coraza ligera de Naj", @@ -25502,7 +25502,7 @@ { "id": 21832, "Key": "Naj's Circlet", - "enUS": " Naj's Circlet ", + "enUS": "Naj's Circlet ", "zhTW": "娜吉的頭環", "deDE": "Najs Reif", "esES": "Aureola de Naj", @@ -25519,7 +25519,7 @@ { "id": 21833, "Key": "Sander's Superstition", - "enUS": " McAuley's Superstition ", + "enUS": "McAuley's Superstition ", "zhTW": "麥克奧雷的迷信", "deDE": "McAuleys Aberglaube", "esES": "Superstición de McAuley", @@ -25536,7 +25536,7 @@ { "id": 21834, "Key": "Sander's Taboo", - "enUS": " McAuley's Taboo ", + "enUS": "McAuley's Taboo ", "zhTW": "麥克奧雷的禁忌", "deDE": "McAuleys Tabu", "esES": "Tabú de McAuley", @@ -25553,7 +25553,7 @@ { "id": 21835, "Key": "Sander's Basis", - "enUS": " McAuley's Basis ", + "enUS": "McAuley's Basis ", "zhTW": "麥克奧雷的碎石", "deDE": "McAuleys Basis", "esES": "Base de McAuley", @@ -25570,7 +25570,7 @@ { "id": 21836, "Key": "Sander's Derby", - "enUS": " McAuley's Pledge ", + "enUS": "McAuley's Pledge ", "zhTW": "麥克奧雷的契約", "deDE": "McAuleys Versprechen", "esES": "Promesa de McAuley", @@ -25587,7 +25587,7 @@ { "id": 21837, "Key": "Sander's Court Jester", - "enUS": " McAuley's Folly ", + "enUS": "McAuley's Folly ", "zhTW": "麥克奧雷的愚行", "deDE": "McAuleys Dummheit", "esES": "Locura de McAuley", @@ -25604,7 +25604,7 @@ { "id": 21838, "Key": "Ghost Liberator", - "enUS": " Ghost Liberator ", + "enUS": "Ghost Liberator ", "zhTW": "鬼魂解放者", "deDE": "Geisterbefreier", "esES": "Liberador de fantasmas", @@ -25621,7 +25621,7 @@ { "id": 21839, "Key": "Wilhelm's Pride", - "enUS": " Wilhelm's Pride ", + "enUS": "Wilhelm's Pride ", "zhTW": "威廉的自尊", "deDE": "Wilhelms Stolz", "esES": "Orgullo de Wilhelm", @@ -25638,7 +25638,7 @@ { "id": 21840, "Key": "Immortal King's Stone Crusher", - "enUS": " Immortal King's Stone Crusher ", + "enUS": "Immortal King's Stone Crusher ", "zhTW": "不朽之王的碎魂者", "deDE": "Steintrümmerer des unsterblichen Königs", "esES": "Machacapiedras del rey inmortal", @@ -25655,7 +25655,7 @@ { "id": 21841, "Key": "Immortal King's Pillar", - "enUS": " Immortal King's Pillar ", + "enUS": "Immortal King's Pillar ", "zhTW": "不朽之王之柱", "deDE": "Säule des unsterblichen Königs", "esES": "Pilar del rey inmortal", @@ -25672,7 +25672,7 @@ { "id": 21842, "Key": "Immortal King's Forge", - "enUS": " Immortal King's Forge ", + "enUS": "Immortal King's Forge ", "zhTW": "不朽之王的熔爐", "deDE": "Schmiede des unsterblichen Königs", "esES": "Fragua del rey inmortal", @@ -25689,7 +25689,7 @@ { "id": 21843, "Key": "Immortal King's Detail", - "enUS": " Immortal King's Detail ", + "enUS": "Immortal King's Detail ", "zhTW": "不朽之王的扈從", "deDE": "Trupp des unsterblichen Königs", "esES": "Destacamento del rey inmortal", @@ -25706,7 +25706,7 @@ { "id": 21844, "Key": "Immortal King's Soul Cage", - "enUS": " Immortal King's Soul Cage ", + "enUS": "Immortal King's Soul Cage ", "zhTW": "不朽之王的靈魂牢籠", "deDE": "Seelenkäfig des unsterblichen Königs", "esES": "Jaula de almas del rey inmortal", @@ -25723,7 +25723,7 @@ { "id": 21845, "Key": "Immortal King's Will", - "enUS": " Immortal King's Will ", + "enUS": "Immortal King's Will ", "zhTW": "不朽之王的意志", "deDE": "Wille des unsterblichen Königs", "esES": "Voluntad del rey inmortal", @@ -25740,7 +25740,7 @@ { "id": 21846, "Key": "Immortal King", - "enUS": " Immortal King ", + "enUS": "Immortal King ", "zhTW": "不朽之王", "deDE": "Unsterblicher König", "esES": "Rey inmortal", @@ -25757,7 +25757,7 @@ { "id": 21847, "Key": "Aldur's Gauntlet", - "enUS": " Aldur's Rhythm ", + "enUS": "Aldur's Rhythm ", "zhTW": "艾爾多的律動", "deDE": "Aldurs Rhythmus", "esES": "Ritmo de Aldur", @@ -25774,7 +25774,7 @@ { "id": 21848, "Key": "Ancient Statue 3", - "enUS": " Korlic the Protector ", + "enUS": "Korlic the Protector ", "zhTW": "保衛者科力克", "deDE": "Korlic der Beschützer", "esES": "Korlic el Protector", @@ -25791,7 +25791,7 @@ { "id": 21849, "Key": "Ancient Statue 2", - "enUS": " Madawc the Guardian ", + "enUS": "Madawc the Guardian ", "zhTW": "守護者馬道克", "deDE": "Madawc der Wächter", "esES": "Madawc el Guardián", @@ -25808,7 +25808,7 @@ { "id": 21850, "Key": "Ancient Statue 1", - "enUS": " Talic the Defender ", + "enUS": "Talic the Defender ", "zhTW": "防禦者塔力克", "deDE": "Talic der Verteidiger", "esES": "Talic el Defensor", @@ -25825,7 +25825,7 @@ { "id": 21856, "Key": "Baal Subject 6", - "enUS": " The Butcher ", + "enUS": "The Butcher ", "zhTW": "屠夫", "deDE": "Der Metzger", "esES": "El carnicero", @@ -25842,7 +25842,7 @@ { "id": 21857, "Key": "Baal Subject 6a", - "enUS": " The Baker ", + "enUS": "The Baker ", "zhTW": "烘烤者", "deDE": "Der Bäcker", "esES": "El panadero", @@ -25859,7 +25859,7 @@ { "id": 21858, "Key": "Baal Subject 6b", - "enUS": " The Candlestick Maker ", + "enUS": "The Candlestick Maker ", "zhTW": "燭台製作者", "deDE": "Der Kerzenmacher", "esES": "El candelero", @@ -25876,7 +25876,7 @@ { "id": 21861, "Key": "BaalColdMage", - "enUS": " Death Mage ", + "enUS": "Death Mage ", "zhTW": "死亡法師", "deDE": "Todesmagier", "esES": "Mago de la muerte", @@ -25893,7 +25893,7 @@ { "id": 21863, "Key": "Baal Tentacle", - "enUS": " Festering Appendages ", + "enUS": "Festering Appendages ", "zhTW": "腐潰觸手", "deDE": "Eiternde Glieder", "esES": "Apéndices infectos", @@ -25910,7 +25910,7 @@ { "id": 21875, "Key": "McAuley's Superstition", - "enUS": " Sander's Superstition ", + "enUS": "Sander's Superstition ", "zhTW": "山德的迷信", "deDE": "Sanders Aberglaube", "esES": "Superstición de Sander", @@ -25927,7 +25927,7 @@ { "id": 21876, "Key": "McAuley's Taboo", - "enUS": " Sander's Taboo ", + "enUS": "Sander's Taboo ", "zhTW": "山德的禁忌", "deDE": "Sanders Tabu", "esES": "Tabú de Sander", @@ -25944,7 +25944,7 @@ { "id": 21877, "Key": "McAuley's Riprap", - "enUS": " Sander's Riprap ", + "enUS": "Sander's Riprap ", "zhTW": "山德的碎石", "deDE": "Sanders Riprap", "esES": "Escollera de Sander", @@ -25961,7 +25961,7 @@ { "id": 21878, "Key": "McAuley's Paragon", - "enUS": " Sander's Paragon ", + "enUS": "Sander's Paragon ", "zhTW": "山德的模範", "deDE": "Sanders Vorbild", "esES": "Excelencia de Sander", @@ -25978,7 +25978,7 @@ { "id": 21879, "Key": "McAuley's Folly", - "enUS": " Sander's Folly ", + "enUS": "Sander's Folly ", "zhTW": "山德的愚行", "deDE": "Sanders Dummheit", "esES": "Locura de Sander", @@ -25995,7 +25995,7 @@ { "id": 22485, "Key": "Moe", - "enUS": " Moe ", + "enUS": "Moe ", "zhTW": "莫", "deDE": "Moe", "esES": "Moe", diff --git a/assets/mods/botty/botty.mpq/data/local/lng/strings/item-runes.json b/assets/mods/botty/botty.mpq/data/local/lng/strings/item-runes.json index 4933b3dc4..7cd760bc0 100644 --- a/assets/mods/botty/botty.mpq/data/local/lng/strings/item-runes.json +++ b/assets/mods/botty/botty.mpq/data/local/lng/strings/item-runes.json @@ -2,9 +2,9 @@ { "id": 10902, "Key": "r16", - "enUS": " Io Rune ", + "enUS": "Io Rune ", "zhTW": "符文:埃歐", - "deDE": "[fs]Io-Rune", + "deDE": "[fs]Io-Rune ", "esES": "Runa Io", "frFR": "[fs]Rune Io", "itIT": "[fs]Runa Io", @@ -19,7 +19,7 @@ { "id": 10903, "Key": "r16L", - "enUS": " Io ", + "enUS": "Io", "zhTW": "埃歐", "deDE": "Io", "esES": "Io", @@ -36,9 +36,9 @@ { "id": 10904, "Key": "r13", - "enUS": " Shael Rune ", + "enUS": "Shael Rune ", "zhTW": "符文:夏", - "deDE": "[fs]Shael-Rune", + "deDE": "[fs]Shael-Rune ", "esES": "Runa Shael", "frFR": "[fs]Rune Shael", "itIT": "[fs]Runa Shael", @@ -53,7 +53,7 @@ { "id": 10905, "Key": "r13L", - "enUS": " Shael ", + "enUS": "Shael", "zhTW": "夏", "deDE": "Shael", "esES": "Shael", @@ -70,9 +70,9 @@ { "id": 10906, "Key": "r31", - "enUS": " Jah Rune ", + "enUS": "Jah Rune ", "zhTW": "符文:喬", - "deDE": "[fs]Jah-Rune", + "deDE": "[fs]Jah-Rune ", "esES": "Runa Jah", "frFR": "[fs]Rune Jah", "itIT": "[fs]Runa Jah", @@ -87,7 +87,7 @@ { "id": 10907, "Key": "r31L", - "enUS": " Jah ", + "enUS": "Jah", "zhTW": "喬", "deDE": "Jah", "esES": "Jah", @@ -104,7 +104,7 @@ { "id": 10910, "Key": "Runeword22", - "enUS": " Delirium ", + "enUS": "Delirium", "zhTW": "精神錯亂", "deDE": "Delirium", "esES": "Delirio", @@ -121,9 +121,9 @@ { "id": 20440, "Key": "r33", - "enUS": " Zod Rune ", + "enUS": "Zod Rune ", "zhTW": "符文:薩德", - "deDE": "[fs]Zod-Rune", + "deDE": "[fs]Zod-Rune ", "esES": "Runa Zod", "frFR": "[fs]Rune Zod", "itIT": "[fs]Runa Zod", @@ -138,9 +138,9 @@ { "id": 20441, "Key": "r32", - "enUS": " Cham Rune ", + "enUS": "Cham Rune ", "zhTW": "符文:查姆", - "deDE": "[fs]Cham-Rune", + "deDE": "[fs]Cham-Rune ", "esES": "Runa Cham", "frFR": "[fs]Rune Cham", "itIT": "[fs]Runa Cham", @@ -155,9 +155,9 @@ { "id": 20443, "Key": "r30", - "enUS": " Ber Rune ", + "enUS": "Ber Rune ", "zhTW": "符文:貝", - "deDE": "[fs]Ber-Rune", + "deDE": "[fs]Ber-Rune ", "esES": "Runa Ber", "frFR": "[fs]Rune Ber", "itIT": "[fs]Runa Ber", @@ -172,9 +172,9 @@ { "id": 20444, "Key": "r29", - "enUS": " Sur Rune ", + "enUS": "Sur Rune ", "zhTW": "符文:瑟", - "deDE": "[fs]Sur-Rune", + "deDE": "[fs]Sur-Rune ", "esES": "Runa Sur", "frFR": "[fs]Rune Sur", "itIT": "[fs]Runa Sur", @@ -189,9 +189,9 @@ { "id": 20445, "Key": "r28", - "enUS": " Lo Rune ", + "enUS": "Lo Rune ", "zhTW": "符文:羅", - "deDE": "[fs]Lo-Rune", + "deDE": "[fs]Lo-Rune ", "esES": "Runa Lo", "frFR": "[fs]Rune Lo", "itIT": "[fs]Runa Lo", @@ -206,9 +206,9 @@ { "id": 20446, "Key": "r27", - "enUS": " Ohm Rune ", + "enUS": "Ohm Rune ", "zhTW": "符文:歐姆", - "deDE": "[fs]Ohm-Rune", + "deDE": "[fs]Ohm-Rune ", "esES": "Runa Ohm", "frFR": "[fs]Rune Ohm", "itIT": "[fs]Runa Ohm", @@ -223,9 +223,9 @@ { "id": 20447, "Key": "r26", - "enUS": " Vex Rune ", + "enUS": "Vex Rune ", "zhTW": "符文:伐克斯", - "deDE": "[fs]Vex-Rune", + "deDE": "[fs]Vex-Rune ", "esES": "Runa Vex", "frFR": "[fs]Rune Vex", "itIT": "[fs]Runa Vex", @@ -240,9 +240,9 @@ { "id": 20448, "Key": "r25", - "enUS": " Gul Rune ", + "enUS": "Gul Rune ", "zhTW": "符文:古爾", - "deDE": "[fs]Gul-Rune", + "deDE": "[fs]Gul-Rune ", "esES": "Runa Gul", "frFR": "[fs]Rune Gul", "itIT": "[fs]Runa Gul", @@ -257,9 +257,9 @@ { "id": 20449, "Key": "r24", - "enUS": " Ist Rune ", + "enUS": "Ist Rune ", "zhTW": "符文:伊司特", - "deDE": "[fs]Ist-Rune", + "deDE": "[fs]Ist-Rune ", "esES": "Runa Ist", "frFR": "[fs]Rune Ist", "itIT": "[fs]Runa Ist", @@ -274,9 +274,9 @@ { "id": 20450, "Key": "r23", - "enUS": " Mal Rune ", + "enUS": "Mal Rune ", "zhTW": "符文:馬爾", - "deDE": "[fs]Mal-Rune", + "deDE": "[fs]Mal-Rune ", "esES": "Runa Mal", "frFR": "[fs]Rune Mal", "itIT": "[fs]Runa Mal", @@ -291,9 +291,9 @@ { "id": 20451, "Key": "r22", - "enUS": " Um Rune ", + "enUS": "Um Rune ", "zhTW": "符文:烏姆", - "deDE": "[fs]Um-Rune", + "deDE": "[fs]Um-Rune ", "esES": "Runa Um", "frFR": "[fs]Rune Um", "itIT": "[fs]Runa Um", @@ -308,9 +308,9 @@ { "id": 20452, "Key": "r21", - "enUS": " Pul Rune ", + "enUS": "Pul Rune ", "zhTW": "符文:普爾", - "deDE": "[fs]Pul-Rune", + "deDE": "[fs]Pul-Rune ", "esES": "Runa Pul", "frFR": "[fs]Rune Pul", "itIT": "[fs]Runa Pul", @@ -325,9 +325,9 @@ { "id": 20453, "Key": "r20", - "enUS": " Lem Rune ", + "enUS": "Lem Rune ", "zhTW": "符文:藍姆", - "deDE": "[fs]Lem-Rune", + "deDE": "[fs]Lem-Rune ", "esES": "Runa Lem", "frFR": "[fs]Rune Lem", "itIT": "[fs]Runa Lem", @@ -342,9 +342,9 @@ { "id": 20454, "Key": "r19", - "enUS": " Fal Rune ", + "enUS": "Fal Rune ", "zhTW": "符文:法爾", - "deDE": "[fs]Fal-Rune", + "deDE": "[fs]Fal-Rune ", "esES": "Runa Fal", "frFR": "[fs]Rune Fal", "itIT": "[fs]Runa Fal", @@ -359,9 +359,9 @@ { "id": 20455, "Key": "r18", - "enUS": " Ko Rune ", + "enUS": "Ko Rune ", "zhTW": "符文:科", - "deDE": "[fs]Ko-Rune", + "deDE": "[fs]Ko-Rune ", "esES": "Runa Ko", "frFR": "[fs]Rune Ko", "itIT": "[fs]Runa Ko", @@ -376,9 +376,9 @@ { "id": 20456, "Key": "r17", - "enUS": " Lum Rune ", + "enUS": "Lum Rune ", "zhTW": "符文:盧姆", - "deDE": "[fs]Lum-Rune", + "deDE": "[fs]Lum-Rune ", "esES": "Runa Lum", "frFR": "[fs]Rune Lum", "itIT": "[fs]Runa Lum", @@ -393,9 +393,9 @@ { "id": 20458, "Key": "r15", - "enUS": " Hel Rune ", + "enUS": "Hel Rune ", "zhTW": "符文:海爾", - "deDE": "[fs]Hel-Rune", + "deDE": "[fs]Hel-Rune ", "esES": "Runa Hel", "frFR": "[fs]Rune Hel", "itIT": "[fs]Runa Hel", @@ -410,9 +410,9 @@ { "id": 20459, "Key": "r14", - "enUS": " Dol Rune ", + "enUS": "Dol Rune ", "zhTW": "符文:多爾", - "deDE": "[fs]Dol-Rune", + "deDE": "[fs]Dol-Rune ", "esES": "Runa Dol", "frFR": "[fs]Rune Dol", "itIT": "[fs]Runa Dol", @@ -427,9 +427,9 @@ { "id": 20461, "Key": "r12", - "enUS": " Sol Rune ", + "enUS": "Sol Rune ", "zhTW": "符文:索爾", - "deDE": "[fs]Sol-Rune", + "deDE": "[fs]Sol-Rune ", "esES": "Runa Sol", "frFR": "[fs]Rune Sol", "itIT": "[fs]Runa Sol", @@ -444,9 +444,9 @@ { "id": 20462, "Key": "r11", - "enUS": " Amn Rune ", + "enUS": "Amn Rune ", "zhTW": "符文:安姆", - "deDE": "[fs]Amn-Rune", + "deDE": "[fs]Amn-Rune ", "esES": "Runa Amn", "frFR": "[fs]Rune Amn", "itIT": "[fs]Runa Amn", @@ -461,9 +461,9 @@ { "id": 20463, "Key": "r10", - "enUS": " Thul Rune ", + "enUS": "Thul Rune ", "zhTW": "符文:書爾", - "deDE": "[fs]Thul-Rune", + "deDE": "[fs]Thul-Rune ", "esES": "Runa Thul", "frFR": "[fs]Rune Thul", "itIT": "[fs]Runa Thul", @@ -478,9 +478,9 @@ { "id": 20464, "Key": "r09", - "enUS": " Ort Rune ", + "enUS": "Ort Rune ", "zhTW": "符文:歐特", - "deDE": "[fs]Ort-Rune", + "deDE": "[fs]Ort-Rune ", "esES": "Runa Ort", "frFR": "[fs]Rune Ort", "itIT": "[fs]Runa Ort", @@ -495,9 +495,9 @@ { "id": 20465, "Key": "r08", - "enUS": " Ral Rune ", + "enUS": "Ral Rune ", "zhTW": "符文:拉爾", - "deDE": "[fs]Ral-Rune", + "deDE": "[fs]Ral-Rune ", "esES": "Runa Ral", "frFR": "[fs]Rune Ral", "itIT": "[fs]Runa Ral", @@ -512,9 +512,9 @@ { "id": 20466, "Key": "r07", - "enUS": " Tal Rune ", + "enUS": "Tal Rune ", "zhTW": "符文:塔爾", - "deDE": "[fs]Tal-Rune", + "deDE": "[fs]Tal-Rune ", "esES": "Runa Tal", "frFR": "[fs]Rune Tal", "itIT": "[fs]Runa Tal", @@ -529,9 +529,9 @@ { "id": 20467, "Key": "r06", - "enUS": " Ith Rune ", + "enUS": "Ith Rune ", "zhTW": "符文:伊司", - "deDE": "[fs]Ith-Rune", + "deDE": "[fs]Ith-Rune ", "esES": "Runa Ith", "frFR": "[fs]Rune Ith", "itIT": "[fs]Runa Ith", @@ -546,9 +546,9 @@ { "id": 20468, "Key": "r05", - "enUS": " Eth Rune ", + "enUS": "Eth Rune ", "zhTW": "符文:愛斯", - "deDE": "[fs]Eth-Rune", + "deDE": "[fs]Eth-Rune ", "esES": "Runa Eth", "frFR": "[fs]Rune Eth", "itIT": "[fs]Runa Eth", @@ -563,9 +563,9 @@ { "id": 20469, "Key": "r04", - "enUS": " Nef Rune ", + "enUS": "Nef Rune ", "zhTW": "符文:那夫", - "deDE": "[fs]Nef-Rune", + "deDE": "[fs]Nef-Rune ", "esES": "Runa Nef", "frFR": "[fs]Rune Nef", "itIT": "[fs]Runa Nef", @@ -580,9 +580,9 @@ { "id": 20470, "Key": "r03", - "enUS": " Tir Rune ", + "enUS": "Tir Rune ", "zhTW": "符文:特爾", - "deDE": "[fs]Tir-Rune", + "deDE": "[fs]Tir-Rune ", "esES": "Runa Tir", "frFR": "[fs]Rune Tir", "itIT": "[fs]Runa Tir", @@ -597,9 +597,9 @@ { "id": 20471, "Key": "r02", - "enUS": " Eld Rune ", + "enUS": "Eld Rune ", "zhTW": "符文:艾德", - "deDE": "[fs]Eld-Rune", + "deDE": "[fs]Eld-Rune ", "esES": "Runa Eld", "frFR": "[fs]Rune Eld", "itIT": "[fs]Runa Eld", @@ -614,9 +614,9 @@ { "id": 20472, "Key": "r01", - "enUS": " El Rune ", + "enUS": "El Rune ", "zhTW": "符文:艾爾", - "deDE": "[fs]El-Rune", + "deDE": "[fs]El-Rune ", "esES": "Runa El", "frFR": "[fs]Rune El", "itIT": "[fs]Runa El", @@ -631,7 +631,7 @@ { "id": 20473, "Key": "r33L", - "enUS": " Zod ", + "enUS": "Zod", "zhTW": "薩德", "deDE": "Zod", "esES": "Zod", @@ -648,7 +648,7 @@ { "id": 20474, "Key": "r32L", - "enUS": " Cham ", + "enUS": "Cham", "zhTW": "查姆", "deDE": "Cham", "esES": "Cham", @@ -665,7 +665,7 @@ { "id": 20476, "Key": "r30L", - "enUS": " Ber ", + "enUS": "Ber", "zhTW": "貝", "deDE": "Ber", "esES": "Ber", @@ -682,7 +682,7 @@ { "id": 20477, "Key": "r29L", - "enUS": " Sur ", + "enUS": "Sur", "zhTW": "瑟", "deDE": "Sur", "esES": "Sur", @@ -699,7 +699,7 @@ { "id": 20478, "Key": "r28L", - "enUS": " Lo ", + "enUS": "Lo", "zhTW": "羅", "deDE": "Lo", "esES": "Lo", @@ -716,7 +716,7 @@ { "id": 20479, "Key": "r27L", - "enUS": " Ohm ", + "enUS": "Ohm", "zhTW": "歐姆", "deDE": "Ohm", "esES": "Ohm", @@ -733,7 +733,7 @@ { "id": 20480, "Key": "r26L", - "enUS": " Vex ", + "enUS": "Vex", "zhTW": "伐克斯", "deDE": "Vex", "esES": "Vex", @@ -750,7 +750,7 @@ { "id": 20481, "Key": "r25L", - "enUS": " Gul ", + "enUS": "Gul", "zhTW": "古爾", "deDE": "Gul", "esES": "Gul", @@ -767,7 +767,7 @@ { "id": 20482, "Key": "r24L", - "enUS": " Ist ", + "enUS": "Ist", "zhTW": "伊司特", "deDE": "Ist", "esES": "Ist", @@ -784,7 +784,7 @@ { "id": 20483, "Key": "r23L", - "enUS": " Mal ", + "enUS": "Mal", "zhTW": "馬爾", "deDE": "Mal", "esES": "Mal", @@ -801,7 +801,7 @@ { "id": 20484, "Key": "r22L", - "enUS": " Um ", + "enUS": "Um", "zhTW": "烏姆", "deDE": "Um", "esES": "Um", @@ -818,7 +818,7 @@ { "id": 20485, "Key": "r21L", - "enUS": " Pul ", + "enUS": "Pul", "zhTW": "普爾", "deDE": "Pul", "esES": "Pul", @@ -835,7 +835,7 @@ { "id": 20486, "Key": "r20L", - "enUS": " Lem ", + "enUS": "Lem", "zhTW": "藍姆", "deDE": "Lem", "esES": "Lem", @@ -852,7 +852,7 @@ { "id": 20487, "Key": "r19L", - "enUS": " Fal ", + "enUS": "Fal", "zhTW": "法爾", "deDE": "Fal", "esES": "Fal", @@ -869,7 +869,7 @@ { "id": 20488, "Key": "r18L", - "enUS": " Ko ", + "enUS": "Ko", "zhTW": "科", "deDE": "Ko", "esES": "Ko", @@ -886,7 +886,7 @@ { "id": 20489, "Key": "r17L", - "enUS": " Lum ", + "enUS": "Lum", "zhTW": "盧姆", "deDE": "Lum", "esES": "Lum", @@ -903,7 +903,7 @@ { "id": 20491, "Key": "r15L", - "enUS": " Hel ", + "enUS": "Hel", "zhTW": "海爾", "deDE": "Hel", "esES": "Hel", @@ -920,7 +920,7 @@ { "id": 20492, "Key": "r14L", - "enUS": " Dol ", + "enUS": "Dol", "zhTW": "多爾", "deDE": "Dol", "esES": "Dol", @@ -937,7 +937,7 @@ { "id": 20494, "Key": "r12L", - "enUS": " Sol ", + "enUS": "Sol", "zhTW": "索爾", "deDE": "Sol", "esES": "Sol", @@ -954,7 +954,7 @@ { "id": 20495, "Key": "r11L", - "enUS": " Amn ", + "enUS": "Amn", "zhTW": "安姆", "deDE": "Amn", "esES": "Amn", @@ -971,7 +971,7 @@ { "id": 20496, "Key": "r10L", - "enUS": " Thul ", + "enUS": "Thul", "zhTW": "書爾", "deDE": "Thul", "esES": "Thul", @@ -988,7 +988,7 @@ { "id": 20497, "Key": "r09L", - "enUS": " Ort ", + "enUS": "Ort", "zhTW": "歐特", "deDE": "Ort", "esES": "Ort", @@ -1005,7 +1005,7 @@ { "id": 20498, "Key": "r08L", - "enUS": " Ral ", + "enUS": "Ral", "zhTW": "拉爾", "deDE": "Ral", "esES": "Ral", @@ -1022,7 +1022,7 @@ { "id": 20499, "Key": "r07L", - "enUS": " Tal ", + "enUS": "Tal", "zhTW": "塔爾", "deDE": "Tal", "esES": "Tal", @@ -1039,7 +1039,7 @@ { "id": 20500, "Key": "r06L", - "enUS": " Ith ", + "enUS": "Ith", "zhTW": "伊司", "deDE": "Ith", "esES": "Ith", @@ -1056,7 +1056,7 @@ { "id": 20501, "Key": "r05L", - "enUS": " Eth ", + "enUS": "Eth", "zhTW": "愛斯", "deDE": "Eth", "esES": "Eth", @@ -1073,7 +1073,7 @@ { "id": 20502, "Key": "r04L", - "enUS": " Nef ", + "enUS": "Nef", "zhTW": "那夫", "deDE": "Nef", "esES": "Nef", @@ -1090,7 +1090,7 @@ { "id": 20503, "Key": "r03L", - "enUS": " Tir ", + "enUS": "Tir", "zhTW": "特爾", "deDE": "Tir", "esES": "Tir", @@ -1107,7 +1107,7 @@ { "id": 20504, "Key": "r02L", - "enUS": " Eld ", + "enUS": "Eld", "zhTW": "艾德", "deDE": "Eld", "esES": "Eld", @@ -1124,7 +1124,7 @@ { "id": 20505, "Key": "r01L", - "enUS": " El ", + "enUS": "El", "zhTW": "艾爾", "deDE": "El", "esES": "El", @@ -1141,7 +1141,7 @@ { "id": 20506, "Key": "RuneQuote", - "enUS": " ' ", + "enUS": "'", "zhTW": "'", "deDE": "'", "esES": "'", @@ -1158,7 +1158,7 @@ { "id": 20507, "Key": "Runeword1", - "enUS": " Ancients' Pledge ", + "enUS": "Ancients' Pledge", "zhTW": "先祖之契", "deDE": "Schwur der Urahnen", "esES": "Promesa de los Antiguos", @@ -1175,7 +1175,7 @@ { "id": 20508, "Key": "Runeword2", - "enUS": " Armageddon ", + "enUS": "Armageddon", "zhTW": "毀天滅地", "deDE": "Armageddon", "esES": "Armagedón", @@ -1192,7 +1192,7 @@ { "id": 20509, "Key": "Runeword3", - "enUS": " Authority ", + "enUS": "Authority", "zhTW": "權威", "deDE": "Macht", "esES": "Autoridad", @@ -1209,7 +1209,7 @@ { "id": 20510, "Key": "Runeword4", - "enUS": " Beast ", + "enUS": "Beast", "zhTW": "野獸", "deDE": "Bestie", "esES": "Bestia", @@ -1226,7 +1226,7 @@ { "id": 20511, "Key": "Runeword5", - "enUS": " Beauty ", + "enUS": "Beauty", "zhTW": "美貌", "deDE": "Schönheit", "esES": "Belleza", @@ -1243,7 +1243,7 @@ { "id": 20512, "Key": "Runeword6", - "enUS": " Black ", + "enUS": "Black", "zhTW": "黑錘", "deDE": "Schwärze", "esES": "Negrura", @@ -1260,7 +1260,7 @@ { "id": 20513, "Key": "Runeword7", - "enUS": " Blood ", + "enUS": "Blood", "zhTW": "鮮血", "deDE": "Blut", "esES": "Sangre", @@ -1277,7 +1277,7 @@ { "id": 20514, "Key": "Runeword8", - "enUS": " Bone ", + "enUS": "Bone", "zhTW": "骸骨", "deDE": "Knochen", "esES": "Hueso", @@ -1294,7 +1294,7 @@ { "id": 20515, "Key": "Runeword9", - "enUS": " Bramble ", + "enUS": "Bramble", "zhTW": "刺藤", "deDE": "Dornen", "esES": "Zarza", @@ -1311,7 +1311,7 @@ { "id": 20516, "Key": "Runeword10", - "enUS": " Brand ", + "enUS": "Brand", "zhTW": "烙印", "deDE": "Brand", "esES": "Tizón", @@ -1328,7 +1328,7 @@ { "id": 20517, "Key": "Runeword11", - "enUS": " Breath of the Dying ", + "enUS": "Breath of the Dying", "zhTW": "死亡呼吸", "deDE": "Odem der Sterbenden", "esES": "Aliento de los muertos", @@ -1345,7 +1345,7 @@ { "id": 20518, "Key": "Runeword12", - "enUS": " Broken Promise ", + "enUS": "Broken Promise", "zhTW": "破碎誓言", "deDE": "Gebrochenes Versprechen", "esES": "Promesa rota", @@ -1362,7 +1362,7 @@ { "id": 20519, "Key": "Runeword13", - "enUS": " Call to Arms ", + "enUS": "Call to Arms", "zhTW": "戰爭召喚", "deDE": "Ruf zu den Waffen", "esES": "Llamada a las armas", @@ -1379,7 +1379,7 @@ { "id": 20520, "Key": "Runeword14", - "enUS": " Chains of Honor ", + "enUS": "Chains of Honor", "zhTW": "榮耀之鍊", "deDE": "Ketten der Ehre", "esES": "Cadenas de honor", @@ -1396,7 +1396,7 @@ { "id": 20521, "Key": "Runeword15", - "enUS": " Chance ", + "enUS": "Chance", "zhTW": "機會", "deDE": "Zufall", "esES": "Casualidad", @@ -1413,7 +1413,7 @@ { "id": 20522, "Key": "Runeword16", - "enUS": " Chaos ", + "enUS": "Chaos", "zhTW": "混沌", "deDE": "Chaos", "esES": "Caos", @@ -1430,7 +1430,7 @@ { "id": 20523, "Key": "Runeword17", - "enUS": " Crescent Moon ", + "enUS": "Crescent Moon", "zhTW": "新月", "deDE": "Mondsichel", "esES": "Luna creciente", @@ -1447,7 +1447,7 @@ { "id": 20524, "Key": "Runeword18", - "enUS": " Darkness ", + "enUS": "Darkness", "zhTW": "黑暗", "deDE": "Dunkelheit", "esES": "Oscuridad", @@ -1464,7 +1464,7 @@ { "id": 20525, "Key": "Runeword19", - "enUS": " Daylight ", + "enUS": "Daylight", "zhTW": "白晝", "deDE": "Tageslicht", "esES": "Luz", @@ -1481,7 +1481,7 @@ { "id": 20526, "Key": "Runeword20", - "enUS": " Death ", + "enUS": "Death", "zhTW": "死神", "deDE": "Tod", "esES": "Muerte", @@ -1498,7 +1498,7 @@ { "id": 20527, "Key": "Runeword21", - "enUS": " Deception ", + "enUS": "Deception", "zhTW": "欺暪", "deDE": "Täuschung", "esES": "Engaño", @@ -1515,7 +1515,7 @@ { "id": 20529, "Key": "Runeword23", - "enUS": " Desire ", + "enUS": "Desire", "zhTW": "渴望", "deDE": "Begierde", "esES": "Deseo", @@ -1532,7 +1532,7 @@ { "id": 20530, "Key": "Runeword24", - "enUS": " Despair ", + "enUS": "Despair", "zhTW": "絕望", "deDE": "Verzweiflung", "esES": "Desesperación", @@ -1549,7 +1549,7 @@ { "id": 20531, "Key": "Runeword25", - "enUS": " Destruction ", + "enUS": "Destruction", "zhTW": "毀滅", "deDE": "Zerstörung", "esES": "Destrucción", @@ -1566,7 +1566,7 @@ { "id": 20532, "Key": "Runeword26", - "enUS": " Doom ", + "enUS": "Doom", "zhTW": "末日", "deDE": "Verdammnis", "esES": "Fatalidad", @@ -1583,7 +1583,7 @@ { "id": 20533, "Key": "Runeword27", - "enUS": " Dragon ", + "enUS": "Dragon", "zhTW": "飛龍", "deDE": "Drachen", "esES": "Dragón", @@ -1600,7 +1600,7 @@ { "id": 20534, "Key": "Runeword28", - "enUS": " Dread ", + "enUS": "Dread", "zhTW": "恐懼", "deDE": "Schrecken", "esES": "Pavor", @@ -1617,7 +1617,7 @@ { "id": 20535, "Key": "Runeword29", - "enUS": " Dream ", + "enUS": "Dream", "zhTW": "夢境", "deDE": "Traum", "esES": "Sueño", @@ -1634,7 +1634,7 @@ { "id": 20536, "Key": "Runeword30", - "enUS": " Duress ", + "enUS": "Duress", "zhTW": "強制", "deDE": "Nötigung", "esES": "Coacción", @@ -1651,7 +1651,7 @@ { "id": 20537, "Key": "Runeword31", - "enUS": " Edge ", + "enUS": "Edge", "zhTW": "邊緣", "deDE": "Schneide", "esES": "Filo", @@ -1668,7 +1668,7 @@ { "id": 20538, "Key": "Runeword32", - "enUS": " Elation ", + "enUS": "Elation", "zhTW": "興高彩烈", "deDE": "Erregung", "esES": "Júbilo", @@ -1685,7 +1685,7 @@ { "id": 20539, "Key": "Runeword33", - "enUS": " Enigma ", + "enUS": "Enigma", "zhTW": "謎團", "deDE": "Rätsel", "esES": "Enigma", @@ -1702,7 +1702,7 @@ { "id": 20540, "Key": "Runeword34", - "enUS": " Enlightenment ", + "enUS": "Enlightenment", "zhTW": "教化", "deDE": "Erleuchtung", "esES": "Ilustración", @@ -1719,7 +1719,7 @@ { "id": 20541, "Key": "Runeword35", - "enUS": " Envy ", + "enUS": "Envy", "zhTW": "羨慕", "deDE": "Neid", "esES": "Envidia", @@ -1736,7 +1736,7 @@ { "id": 20542, "Key": "Runeword36", - "enUS": " Eternity ", + "enUS": "Eternity", "zhTW": "永恆", "deDE": "Ewigkeit", "esES": "Eternidad", @@ -1753,7 +1753,7 @@ { "id": 20543, "Key": "Runeword37", - "enUS": " Exile ", + "enUS": "Exile", "zhTW": "流亡", "deDE": "Exil", "esES": "Exilio", @@ -1770,7 +1770,7 @@ { "id": 20544, "Key": "Runeword38", - "enUS": " Faith ", + "enUS": "Faith", "zhTW": "信心", "deDE": "Glaube", "esES": "Fe", @@ -1787,7 +1787,7 @@ { "id": 20545, "Key": "Runeword39", - "enUS": " Famine ", + "enUS": "Famine", "zhTW": "饑荒", "deDE": "Hungersnot", "esES": "Hambruna", @@ -1804,7 +1804,7 @@ { "id": 20546, "Key": "Runeword40", - "enUS": " Flickering Flame ", + "enUS": "Flickering Flame", "zhTW": "搖曳焰火", "deDE": "Flamme", "esES": "Llama trémula", @@ -1821,7 +1821,7 @@ { "id": 20547, "Key": "Runeword41", - "enUS": " Fortitude ", + "enUS": "Fortitude", "zhTW": "剛毅", "deDE": "Stärke", "esES": "Fortaleza", @@ -1838,7 +1838,7 @@ { "id": 20548, "Key": "Runeword42", - "enUS": " Fortune ", + "enUS": "Fortune", "zhTW": "機運", "deDE": "Glück", "esES": "Fortuna", @@ -1855,7 +1855,7 @@ { "id": 20549, "Key": "Runeword43", - "enUS": " Friendship ", + "enUS": "Friendship", "zhTW": "友情", "deDE": "Freundschaft", "esES": "Amistad", @@ -1872,7 +1872,7 @@ { "id": 20550, "Key": "Runeword44", - "enUS": " Fury ", + "enUS": "Fury", "zhTW": "狂怒", "deDE": "Wut", "esES": "Furia", @@ -1889,7 +1889,7 @@ { "id": 20551, "Key": "Runeword45", - "enUS": " Gloom ", + "enUS": "Gloom", "zhTW": "幽暗", "deDE": "Düsternis", "esES": "Melancolía", @@ -1906,7 +1906,7 @@ { "id": 20552, "Key": "Runeword46", - "enUS": " Glory ", + "enUS": "Glory", "zhTW": "榮譽", "deDE": "Ruhm", "esES": "Gloria", @@ -1923,7 +1923,7 @@ { "id": 20553, "Key": "Runeword47", - "enUS": " Grief ", + "enUS": "Grief", "zhTW": "悔恨", "deDE": "Trauer", "esES": "Dolor", @@ -1940,7 +1940,7 @@ { "id": 20554, "Key": "Runeword48", - "enUS": " Hand of Justice ", + "enUS": "Hand of Justice", "zhTW": "正義之手", "deDE": "Hand der Gerechtigkeit", "esES": "Mano justiciera", @@ -1957,7 +1957,7 @@ { "id": 20555, "Key": "Runeword49", - "enUS": " Harmony ", + "enUS": "Harmony", "zhTW": "和諧", "deDE": "Harmonie", "esES": "Armonía", @@ -1974,7 +1974,7 @@ { "id": 20556, "Key": "Runeword50", - "enUS": " Hatred ", + "enUS": "Hatred", "zhTW": "憎恨", "deDE": "Hass", "esES": "Odio", @@ -1991,7 +1991,7 @@ { "id": 20557, "Key": "Runeword51", - "enUS": " Heart of the Oak ", + "enUS": "Heart of the Oak", "zhTW": "橡樹之心", "deDE": "Herz der Eiche", "esES": "Corazón de roble", @@ -2008,7 +2008,7 @@ { "id": 20558, "Key": "Runeword52", - "enUS": " Heaven's Will ", + "enUS": "Heaven's Will", "zhTW": "天堂意志", "deDE": "Himmlischer Wille", "esES": "Voluntad del cielo", @@ -2025,7 +2025,7 @@ { "id": 20559, "Key": "Runeword53", - "enUS": " Holy Tears ", + "enUS": "Holy Tears", "zhTW": "神聖之淚", "deDE": "Heilige Tränen", "esES": "Lágrimas sagradas", @@ -2042,7 +2042,7 @@ { "id": 20560, "Key": "Runeword54", - "enUS": " Holy Thunder ", + "enUS": "Holy Thunder", "zhTW": "神聖雷擊", "deDE": "Heiliger Donner", "esES": "Trueno sagrado", @@ -2059,7 +2059,7 @@ { "id": 20561, "Key": "Runeword55", - "enUS": " Honor ", + "enUS": "Honor", "zhTW": "榮耀", "deDE": "Ehre", "esES": "Honor", @@ -2076,7 +2076,7 @@ { "id": 20562, "Key": "Runeword56", - "enUS": " Revenge ", + "enUS": "Revenge", "zhTW": "報復", "deDE": "Rache", "esES": "Revancha", @@ -2093,7 +2093,7 @@ { "id": 20563, "Key": "Runeword57", - "enUS": " Humility ", + "enUS": "Humility", "zhTW": "謙恭", "deDE": "Demut", "esES": "Humildad", @@ -2110,7 +2110,7 @@ { "id": 20564, "Key": "Runeword58", - "enUS": " Hunger ", + "enUS": "Hunger", "zhTW": "飢餓", "deDE": "Hunger", "esES": "Hambre", @@ -2127,7 +2127,7 @@ { "id": 20565, "Key": "Runeword59", - "enUS": " Ice ", + "enUS": "Ice", "zhTW": "寒冰", "deDE": "Eis", "esES": "Hielo", @@ -2144,7 +2144,7 @@ { "id": 20566, "Key": "Runeword60", - "enUS": " Infinity ", + "enUS": "Infinity", "zhTW": "無限", "deDE": "Unendlichkeit", "esES": "Infinito", @@ -2161,7 +2161,7 @@ { "id": 20567, "Key": "Runeword61", - "enUS": " Innocence ", + "enUS": "Innocence", "zhTW": "純真", "deDE": "Unschuld", "esES": "Inocencia", @@ -2178,7 +2178,7 @@ { "id": 20568, "Key": "Runeword62", - "enUS": " Insight ", + "enUS": "Insight", "zhTW": "靈光", "deDE": "Einsicht", "esES": "Perspicacia", @@ -2195,7 +2195,7 @@ { "id": 20569, "Key": "Runeword63", - "enUS": " Jealousy ", + "enUS": "Jealousy", "zhTW": "妒忌", "deDE": "Eifersucht", "esES": "Celos", @@ -2212,7 +2212,7 @@ { "id": 20570, "Key": "Runeword64", - "enUS": " Judgement ", + "enUS": "Judgement", "zhTW": "審判", "deDE": "Urteil", "esES": "Sentencia", @@ -2229,7 +2229,7 @@ { "id": 20571, "Key": "Runeword65", - "enUS": " King's Grace ", + "enUS": "King's Grace", "zhTW": "王者的慈悲", "deDE": "Königliche Gnade", "esES": "Gracia del rey", @@ -2246,7 +2246,7 @@ { "id": 20572, "Key": "Runeword66", - "enUS": " Kingslayer ", + "enUS": "Kingslayer", "zhTW": "弒王者", "deDE": "Königsmord", "esES": "Regicida", @@ -2263,7 +2263,7 @@ { "id": 20573, "Key": "Runeword67", - "enUS": " Knight's Vigil ", + "enUS": "Knight's Vigil", "zhTW": "騎士守望", "deDE": "Ritters Wacht", "esES": "Vela del caballero", @@ -2280,7 +2280,7 @@ { "id": 20574, "Key": "Runeword68", - "enUS": " Knowledge ", + "enUS": "Knowledge", "zhTW": "學識", "deDE": "Wissen", "esES": "Saber", @@ -2297,7 +2297,7 @@ { "id": 20575, "Key": "Runeword69", - "enUS": " Last Wish ", + "enUS": "Last Wish", "zhTW": "最後遺願", "deDE": "Letzter Wunsch", "esES": "Último deseo", @@ -2314,7 +2314,7 @@ { "id": 20576, "Key": "Runeword70", - "enUS": " Law ", + "enUS": "Law", "zhTW": "律法", "deDE": "Gesetz", "esES": "Ley", @@ -2331,7 +2331,7 @@ { "id": 20577, "Key": "Runeword71", - "enUS": " Lawbringer ", + "enUS": "Lawbringer", "zhTW": "執法者", "deDE": "Gesetzesbringer", "esES": "Jurista", @@ -2348,7 +2348,7 @@ { "id": 20578, "Key": "Runeword72", - "enUS": " Leaf ", + "enUS": "Leaf", "zhTW": "葉子", "deDE": "Blatt", "esES": "Hoja", @@ -2365,7 +2365,7 @@ { "id": 20579, "Key": "Runeword73", - "enUS": " Lightning ", + "enUS": "Lightning", "zhTW": "閃電", "deDE": "Blitzschlag", "esES": "Rayo", @@ -2382,7 +2382,7 @@ { "id": 20580, "Key": "Runeword74", - "enUS": " Lionheart ", + "enUS": "Lionheart", "zhTW": "獅子心", "deDE": "Löwenherz", "esES": "Corazón de león", @@ -2399,7 +2399,7 @@ { "id": 20581, "Key": "Runeword75", - "enUS": " Lore ", + "enUS": "Lore", "zhTW": "知識", "deDE": "Überlieferung", "esES": "Acervo", @@ -2416,7 +2416,7 @@ { "id": 20582, "Key": "Runeword76", - "enUS": " Love ", + "enUS": "Love", "zhTW": "愛情", "deDE": "Liebe", "esES": "Amor", @@ -2433,7 +2433,7 @@ { "id": 20583, "Key": "Runeword77", - "enUS": " Loyalty ", + "enUS": "Loyalty", "zhTW": "忠誠", "deDE": "Treue", "esES": "Lealtad", @@ -2450,7 +2450,7 @@ { "id": 20584, "Key": "Runeword78", - "enUS": " Lust ", + "enUS": "Lust", "zhTW": "慾望", "deDE": "Lust", "esES": "Lujuria", @@ -2467,7 +2467,7 @@ { "id": 20585, "Key": "Runeword79", - "enUS": " Madness ", + "enUS": "Madness", "zhTW": "瘋狂", "deDE": "Wahnsinn", "esES": "Locura", @@ -2484,7 +2484,7 @@ { "id": 20586, "Key": "Runeword81", - "enUS": " Malice ", + "enUS": "Malice", "zhTW": "怨恨", "deDE": "Boshaftigkeit", "esES": "Maldad", @@ -2501,7 +2501,7 @@ { "id": 20587, "Key": "Runeword82", - "enUS": " Melody ", + "enUS": "Melody", "zhTW": "旋律", "deDE": "Melodie", "esES": "Melodía", @@ -2518,7 +2518,7 @@ { "id": 20588, "Key": "Runeword83", - "enUS": " Memory ", + "enUS": "Memory", "zhTW": "記憶", "deDE": "Erinnerung", "esES": "Memoria", @@ -2535,7 +2535,7 @@ { "id": 20589, "Key": "Runeword84", - "enUS": " Mist ", + "enUS": "Mist", "zhTW": "迷霧", "deDE": "Nebel", "esES": "Bruma", @@ -2552,7 +2552,7 @@ { "id": 20590, "Key": "Runeword85", - "enUS": " Morning ", + "enUS": "Morning", "zhTW": "清晨", "deDE": "Morgen", "esES": "Mañana", @@ -2569,7 +2569,7 @@ { "id": 20591, "Key": "Runeword86", - "enUS": " Mystery ", + "enUS": "Mystery", "zhTW": "神秘", "deDE": "Geheimnis", "esES": "Misterio", @@ -2586,7 +2586,7 @@ { "id": 20592, "Key": "Runeword87", - "enUS": " Myth ", + "enUS": "Myth", "zhTW": "神話", "deDE": "Mythos", "esES": "Mito", @@ -2603,7 +2603,7 @@ { "id": 20593, "Key": "Runeword88", - "enUS": " Nadir ", + "enUS": "Nadir", "zhTW": "天底", "deDE": "Nadir", "esES": "Nadir", @@ -2620,7 +2620,7 @@ { "id": 20594, "Key": "Runeword89", - "enUS": " Nature's Kingdom ", + "enUS": "Nature's Kingdom", "zhTW": "自然王國", "deDE": "Königreich der Natur", "esES": "Reino de la naturaleza", @@ -2637,7 +2637,7 @@ { "id": 20595, "Key": "Runeword90", - "enUS": " Night ", + "enUS": "Night", "zhTW": "夜晚", "deDE": "Nacht", "esES": "Noche", @@ -2654,7 +2654,7 @@ { "id": 20596, "Key": "Runeword91", - "enUS": " Oath ", + "enUS": "Oath", "zhTW": "誓約", "deDE": "Eid", "esES": "Juramento", @@ -2671,11 +2671,11 @@ { "id": 20597, "Key": "Runeword92", - "enUS": " Obedience ", + "enUS": "Obedience", "zhTW": "遵從", "deDE": "Gehorsam", "esES": "Obediencia", - "frFR": "Obéissance ", + "frFR": "Obéissance", "itIT": "Obbedienza", "koKR": "순종", "plPL": "Posłuszeństwo", @@ -2688,7 +2688,7 @@ { "id": 20598, "Key": "Runeword93", - "enUS": " Oblivion ", + "enUS": "Oblivion", "zhTW": "湮沒", "deDE": "Nichts", "esES": "Olvido", @@ -2705,7 +2705,7 @@ { "id": 20599, "Key": "Runeword94", - "enUS": " Obsession ", + "enUS": "Obsession", "zhTW": "著魔", "deDE": "Besessenheit", "esES": "Obsesión", @@ -2722,7 +2722,7 @@ { "id": 20600, "Key": "Runeword95", - "enUS": " Passion ", + "enUS": "Passion", "zhTW": "熱情", "deDE": "Leidenschaft", "esES": "Pasión", @@ -2739,7 +2739,7 @@ { "id": 20601, "Key": "Runeword96", - "enUS": " Patience ", + "enUS": "Patience", "zhTW": "耐心", "deDE": "Geduld", "esES": "Paciencia", @@ -2756,7 +2756,7 @@ { "id": 20602, "Key": "Runeword97", - "enUS": " Pattern ", + "enUS": "Pattern", "zhTW": "樣式", "deDE": "Prasseln", "esES": "Patrón", @@ -2773,7 +2773,7 @@ { "id": 20603, "Key": "Runeword98", - "enUS": " Peace ", + "enUS": "Peace", "zhTW": "和平", "deDE": "Frieden", "esES": "Paz", @@ -2790,7 +2790,7 @@ { "id": 20604, "Key": "Runeword99", - "enUS": " Voice of Reason ", + "enUS": "Voice of Reason", "zhTW": "理性之聲", "deDE": "Stimme der Vernunft", "esES": "Voz de la razón", @@ -2807,7 +2807,7 @@ { "id": 20605, "Key": "Runeword100", - "enUS": " Penitence ", + "enUS": "Penitence", "zhTW": "懺悔", "deDE": "Reue", "esES": "Penitencia", @@ -2824,7 +2824,7 @@ { "id": 20606, "Key": "Runeword101", - "enUS": " Peril ", + "enUS": "Peril", "zhTW": "危害", "deDE": "Gefahr", "esES": "Peligro", @@ -2841,7 +2841,7 @@ { "id": 20607, "Key": "Runeword102", - "enUS": " Pestilence ", + "enUS": "Pestilence", "zhTW": "疫病", "deDE": "Pestilenz", "esES": "Pestilencia", @@ -2858,7 +2858,7 @@ { "id": 20608, "Key": "Runeword103", - "enUS": " Phoenix ", + "enUS": "Phoenix", "zhTW": "鳳凰", "deDE": "Phönix", "esES": "Fénix", @@ -2875,7 +2875,7 @@ { "id": 20609, "Key": "Runeword104", - "enUS": " Piety ", + "enUS": "Piety", "zhTW": "虔誠", "deDE": "Frömmigkeit", "esES": "Piedad", @@ -2892,7 +2892,7 @@ { "id": 20610, "Key": "Runeword105", - "enUS": " Pillar of Faith ", + "enUS": "Pillar of Faith", "zhTW": "信念之柱", "deDE": "Säule des Glaubens", "esES": "Pilar de fe", @@ -2909,7 +2909,7 @@ { "id": 20611, "Key": "Runeword106", - "enUS": " Plague ", + "enUS": "Plague", "zhTW": "瘟疫", "deDE": "Pest", "esES": "Peste", @@ -2926,7 +2926,7 @@ { "id": 20612, "Key": "Runeword107", - "enUS": " Praise ", + "enUS": "Praise", "zhTW": "頌揚", "deDE": "Lobpreisung", "esES": "Alabanza", @@ -2943,7 +2943,7 @@ { "id": 20613, "Key": "Runeword108", - "enUS": " Prayer ", + "enUS": "Prayer", "zhTW": "祈禱", "deDE": "Gebet", "esES": "Oración", @@ -2960,7 +2960,7 @@ { "id": 20614, "Key": "Runeword109", - "enUS": " Pride ", + "enUS": "Pride", "zhTW": "驕傲", "deDE": "Stolz", "esES": "Orgullo", @@ -2977,7 +2977,7 @@ { "id": 20615, "Key": "Runeword110", - "enUS": " Principle ", + "enUS": "Principle", "zhTW": "原則", "deDE": "Prinzip", "esES": "Principio", @@ -2994,7 +2994,7 @@ { "id": 20616, "Key": "Runeword111", - "enUS": " Prowess in Battle ", + "enUS": "Prowess in Battle", "zhTW": "勇戰之力", "deDE": "Tapferkeit im Kampf", "esES": "Habilidad en combate", @@ -3011,7 +3011,7 @@ { "id": 20617, "Key": "Runeword112", - "enUS": " Prudence ", + "enUS": "Prudence", "zhTW": "謹慎", "deDE": "Besonnenheit", "esES": "Prudencia", @@ -3028,7 +3028,7 @@ { "id": 20618, "Key": "Runeword113", - "enUS": " Punishment ", + "enUS": "Punishment", "zhTW": "懲罰", "deDE": "Strafe", "esES": "Castigo", @@ -3045,7 +3045,7 @@ { "id": 20619, "Key": "Runeword114", - "enUS": " Purity ", + "enUS": "Purity", "zhTW": "純潔", "deDE": "Reinheit", "esES": "Pureza", @@ -3062,7 +3062,7 @@ { "id": 20620, "Key": "Runeword115", - "enUS": " Question ", + "enUS": "Question", "zhTW": "疑問", "deDE": "Frage", "esES": "Duda", @@ -3079,7 +3079,7 @@ { "id": 20621, "Key": "Runeword116", - "enUS": " Radiance ", + "enUS": "Radiance", "zhTW": "光輝", "deDE": "Glanz", "esES": "Resplandor", @@ -3096,7 +3096,7 @@ { "id": 20622, "Key": "Runeword117", - "enUS": " Rain ", + "enUS": "Rain", "zhTW": "降雨", "deDE": "Regen", "esES": "Lluvia", @@ -3113,7 +3113,7 @@ { "id": 20623, "Key": "Runeword118", - "enUS": " Reason ", + "enUS": "Reason", "zhTW": "理由", "deDE": "Vernunft", "esES": "Razón", @@ -3130,7 +3130,7 @@ { "id": 20624, "Key": "Runeword119", - "enUS": " Red ", + "enUS": "Red", "zhTW": "鮮紅", "deDE": "Röte", "esES": "Rojez", @@ -3147,7 +3147,7 @@ { "id": 20625, "Key": "Runeword120", - "enUS": " Rhyme ", + "enUS": "Rhyme", "zhTW": "聲韻", "deDE": "Reim", "esES": "Rima", @@ -3164,7 +3164,7 @@ { "id": 20626, "Key": "Runeword121", - "enUS": " Rift ", + "enUS": "Rift", "zhTW": "裂隙", "deDE": "Zerrissenheit", "esES": "Grieta", @@ -3181,7 +3181,7 @@ { "id": 20627, "Key": "Runeword122", - "enUS": " Sanctuary ", + "enUS": "Sanctuary", "zhTW": "聖堂", "deDE": "Zuflucht", "esES": "Santuario", @@ -3198,7 +3198,7 @@ { "id": 20628, "Key": "Runeword123", - "enUS": " Serendipity ", + "enUS": "Serendipity", "zhTW": "機緣", "deDE": "Glückseligkeit", "esES": "Serendipia", @@ -3215,7 +3215,7 @@ { "id": 20629, "Key": "Runeword124", - "enUS": " Shadow ", + "enUS": "Shadow", "zhTW": "暗影", "deDE": "Schatten", "esES": "Sombra", @@ -3232,7 +3232,7 @@ { "id": 20630, "Key": "Runeword125", - "enUS": " Shadow of Doubt ", + "enUS": "Shadow of Doubt", "zhTW": "懷疑之影", "deDE": "Schatten des Zweifels", "esES": "Sombra de duda", @@ -3249,7 +3249,7 @@ { "id": 20631, "Key": "Runeword126", - "enUS": " Silence ", + "enUS": "Silence", "zhTW": "寂靜", "deDE": "Stille", "esES": "Silencio", @@ -3266,7 +3266,7 @@ { "id": 20632, "Key": "Runeword127", - "enUS": " Siren's Song ", + "enUS": "Siren's Song", "zhTW": "賽蓮之歌", "deDE": "Sirenengesang", "esES": "Canto de sirena", @@ -3283,7 +3283,7 @@ { "id": 20633, "Key": "Runeword128", - "enUS": " Smoke ", + "enUS": "Smoke", "zhTW": "煙霧", "deDE": "Rauch", "esES": "Humo", @@ -3300,7 +3300,7 @@ { "id": 20634, "Key": "Runeword129", - "enUS": " Sorrow ", + "enUS": "Sorrow", "zhTW": "哀傷", "deDE": "Traurigkeit", "esES": "Tristeza", @@ -3317,7 +3317,7 @@ { "id": 20635, "Key": "Runeword130", - "enUS": " Spirit ", + "enUS": "Spirit", "zhTW": "精神", "deDE": "Geist", "esES": "Espíritu", @@ -3334,7 +3334,7 @@ { "id": 20636, "Key": "Runeword131", - "enUS": " Splendor ", + "enUS": "Splendor", "zhTW": "燦爛", "deDE": "Pracht", "esES": "Esplendor", @@ -3351,7 +3351,7 @@ { "id": 20637, "Key": "Runeword132", - "enUS": " Starlight ", + "enUS": "Starlight", "zhTW": "星光", "deDE": "Sternenlicht", "esES": "Luz de las estrellas", @@ -3368,7 +3368,7 @@ { "id": 20638, "Key": "Runeword133", - "enUS": " Stealth ", + "enUS": "Stealth", "zhTW": "隱密", "deDE": "Verstohlenheit", "esES": "Sigilo", @@ -3385,7 +3385,7 @@ { "id": 20639, "Key": "Runeword134", - "enUS": " Steel ", + "enUS": "Steel", "zhTW": "鋼鐵", "deDE": "Stahl", "esES": "Acero", @@ -3402,7 +3402,7 @@ { "id": 20640, "Key": "Runeword135", - "enUS": " Still Water ", + "enUS": "Still Water", "zhTW": "寂靜之水", "deDE": "Stilles Wasser", "esES": "Aguas tranquilas", @@ -3419,7 +3419,7 @@ { "id": 20641, "Key": "Runeword136", - "enUS": " Sting ", + "enUS": "Sting", "zhTW": "螫刺", "deDE": "Stachel", "esES": "Aguijón", @@ -3436,7 +3436,7 @@ { "id": 20642, "Key": "Runeword137", - "enUS": " Stone ", + "enUS": "Stone", "zhTW": "石塊", "deDE": "Stein", "esES": "Roca", @@ -3453,7 +3453,7 @@ { "id": 20643, "Key": "Runeword138", - "enUS": " Storm ", + "enUS": "Storm", "zhTW": "風暴", "deDE": "Sturm", "esES": "Tormenta", @@ -3470,7 +3470,7 @@ { "id": 20644, "Key": "Runeword139", - "enUS": " Strength ", + "enUS": "Strength", "zhTW": "力量", "deDE": "Stärke", "esES": "Fuerza", @@ -3487,7 +3487,7 @@ { "id": 20645, "Key": "Runeword140", - "enUS": " Tempest ", + "enUS": "Tempest", "zhTW": "暴風雨", "deDE": "Orkan", "esES": "Tempestad", @@ -3504,7 +3504,7 @@ { "id": 20646, "Key": "Runeword141", - "enUS": " Temptation ", + "enUS": "Temptation", "zhTW": "誘惑", "deDE": "Versuchung", "esES": "Tentación", @@ -3521,7 +3521,7 @@ { "id": 20647, "Key": "Runeword142", - "enUS": " Terror ", + "enUS": "Terror", "zhTW": "恐佈", "deDE": "Terror", "esES": "Terror", @@ -3538,7 +3538,7 @@ { "id": 20648, "Key": "Runeword143", - "enUS": " Thirst ", + "enUS": "Thirst", "zhTW": "飢渴", "deDE": "Durst", "esES": "Sed", @@ -3555,7 +3555,7 @@ { "id": 20649, "Key": "Runeword144", - "enUS": " Thought ", + "enUS": "Thought", "zhTW": "思維", "deDE": "Gedanke", "esES": "Pensamiento", @@ -3572,7 +3572,7 @@ { "id": 20650, "Key": "Runeword145", - "enUS": " Thunder ", + "enUS": "Thunder", "zhTW": "雷霆", "deDE": "Donner", "esES": "Trueno", @@ -3589,7 +3589,7 @@ { "id": 20651, "Key": "Runeword146", - "enUS": " Time ", + "enUS": "Time", "zhTW": "時間", "deDE": "Zeit", "esES": "Tiempo", @@ -3606,7 +3606,7 @@ { "id": 20652, "Key": "Runeword147", - "enUS": " Tradition ", + "enUS": "Tradition", "zhTW": "傳統", "deDE": "Tradition", "esES": "Tradición", @@ -3623,7 +3623,7 @@ { "id": 20653, "Key": "Runeword148", - "enUS": " Treachery ", + "enUS": "Treachery", "zhTW": "背信", "deDE": "Verrat", "esES": "Traición", @@ -3640,7 +3640,7 @@ { "id": 20654, "Key": "Runeword149", - "enUS": " Trust ", + "enUS": "Trust", "zhTW": "信任", "deDE": "Vertrauen", "esES": "Confianza", @@ -3657,7 +3657,7 @@ { "id": 20655, "Key": "Runeword150", - "enUS": " Truth ", + "enUS": "Truth", "zhTW": "真理", "deDE": "Wahrheit", "esES": "Verdad", @@ -3674,7 +3674,7 @@ { "id": 20656, "Key": "Runeword151", - "enUS": " Unbending Will ", + "enUS": "Unbending Will", "zhTW": "堅定意志", "deDE": "Unbeugsamer Wille", "esES": "Voluntad de hierro", @@ -3691,7 +3691,7 @@ { "id": 20657, "Key": "Runeword152", - "enUS": " Valor ", + "enUS": "Valor", "zhTW": "英勇", "deDE": "Heldenmut", "esES": "Valor", @@ -3708,7 +3708,7 @@ { "id": 20658, "Key": "Runeword153", - "enUS": " Vengeance ", + "enUS": "Vengeance", "zhTW": "復仇", "deDE": "Rache", "esES": "Venganza", @@ -3725,7 +3725,7 @@ { "id": 20659, "Key": "Runeword154", - "enUS": " Venom ", + "enUS": "Venom", "zhTW": "劇毒", "deDE": "Geifer", "esES": "Ponzoña", @@ -3742,7 +3742,7 @@ { "id": 20660, "Key": "Runeword155", - "enUS": " Victory ", + "enUS": "Victory", "zhTW": "勝利", "deDE": "Sieg", "esES": "Victoria", @@ -3759,7 +3759,7 @@ { "id": 20661, "Key": "Runeword156", - "enUS": " Voice ", + "enUS": "Voice", "zhTW": "聲音", "deDE": "Stimme", "esES": "Voz", @@ -3776,7 +3776,7 @@ { "id": 20662, "Key": "Runeword157", - "enUS": " Void ", + "enUS": "Void", "zhTW": "虛無", "deDE": "[ms]leerer[fs]leere[ns]leeres[pl]leere", "esES": "Vacío", @@ -3793,7 +3793,7 @@ { "id": 20663, "Key": "Runeword158", - "enUS": " War ", + "enUS": "War", "zhTW": "戰爭", "deDE": "Krieg", "esES": "Guerra", @@ -3810,7 +3810,7 @@ { "id": 20664, "Key": "Runeword159", - "enUS": " Water ", + "enUS": "Water", "zhTW": "清水", "deDE": "Wasser", "esES": "Agua", @@ -3827,7 +3827,7 @@ { "id": 20665, "Key": "Runeword160", - "enUS": " Wealth ", + "enUS": "Wealth", "zhTW": "財富", "deDE": "Wohlstand", "esES": "Riqueza", @@ -3844,7 +3844,7 @@ { "id": 20666, "Key": "Runeword161", - "enUS": " Whisper ", + "enUS": "Whisper", "zhTW": "低語", "deDE": "Flüstern", "esES": "Susurro", @@ -3861,7 +3861,7 @@ { "id": 20667, "Key": "Runeword162", - "enUS": " White ", + "enUS": "White", "zhTW": "蒼白", "deDE": "Weiß", "esES": "Blancura", @@ -3878,7 +3878,7 @@ { "id": 20668, "Key": "Runeword163", - "enUS": " Wind ", + "enUS": "Wind", "zhTW": "輕風", "deDE": "Wind", "esES": "Viento", @@ -3895,7 +3895,7 @@ { "id": 20669, "Key": "Runeword164", - "enUS": " Wings of Hope ", + "enUS": "Wings of Hope", "zhTW": "希望之翼", "deDE": "Schwingen der Hoffnung", "esES": "Alas de esperanza", @@ -3912,7 +3912,7 @@ { "id": 20670, "Key": "Runeword165", - "enUS": " Wisdom ", + "enUS": "Wisdom", "zhTW": "智慧", "deDE": "Weisheit", "esES": "Sabiduría", @@ -3929,7 +3929,7 @@ { "id": 20671, "Key": "Runeword166", - "enUS": " Woe ", + "enUS": "Woe", "zhTW": "悲痛", "deDE": "Unglück", "esES": "Aflicción", @@ -3946,7 +3946,7 @@ { "id": 20672, "Key": "Runeword167", - "enUS": " Wonder ", + "enUS": "Wonder", "zhTW": "驚奇", "deDE": "Wunder", "esES": "Asombro", @@ -3963,7 +3963,7 @@ { "id": 20673, "Key": "Runeword168", - "enUS": " Wrath ", + "enUS": "Wrath", "zhTW": "憤怒", "deDE": "Wut", "esES": "Ira", @@ -3980,7 +3980,7 @@ { "id": 20674, "Key": "Runeword169", - "enUS": " Youth ", + "enUS": "Youth", "zhTW": "年輕", "deDE": "Jugend", "esES": "Juventud", @@ -3997,7 +3997,7 @@ { "id": 20675, "Key": "Runeword170", - "enUS": " Zephyr ", + "enUS": "Zephyr", "zhTW": "和風", "deDE": "Zephyr", "esES": "Céfiro", diff --git a/assets/mods/botty/botty.mpq/modinfo.json b/assets/mods/botty/botty.mpq/modinfo.json index 0de7aa9e4..f2770a58f 100644 --- a/assets/mods/botty/botty.mpq/modinfo.json +++ b/assets/mods/botty/botty.mpq/modinfo.json @@ -1,7 +1,4 @@ { - -"name": "botty", - -"savepath": "../" - -} + "name": "botty", + "savepath": "../" +} \ No newline at end of file diff --git a/assets/npc/action_btn/cancel.png b/assets/npc/action_btn/cancel.png index de6f2e0ad..3c786e37b 100644 Binary files a/assets/npc/action_btn/cancel.png and b/assets/npc/action_btn/cancel.png differ diff --git a/assets/npc/action_btn/gamble.png b/assets/npc/action_btn/gamble.png index c6fdf2a0d..4d10358ee 100644 Binary files a/assets/npc/action_btn/gamble.png and b/assets/npc/action_btn/gamble.png differ diff --git a/assets/npc/action_btn/gamble_blue.png b/assets/npc/action_btn/gamble_blue.png index 89a3064b0..d916c53c5 100644 Binary files a/assets/npc/action_btn/gamble_blue.png and b/assets/npc/action_btn/gamble_blue.png differ diff --git a/assets/npc/action_btn/identify.png b/assets/npc/action_btn/identify.png index 422ac60fc..ecb658775 100644 Binary files a/assets/npc/action_btn/identify.png and b/assets/npc/action_btn/identify.png differ diff --git a/assets/npc/action_btn/identify_blue.png b/assets/npc/action_btn/identify_blue.png index ce7bb8056..cc666f86d 100644 Binary files a/assets/npc/action_btn/identify_blue.png and b/assets/npc/action_btn/identify_blue.png differ diff --git a/assets/npc/action_btn/npc_dialogue.png b/assets/npc/action_btn/npc_dialogue.png index 68cda2245..81f3285df 100644 Binary files a/assets/npc/action_btn/npc_dialogue.png and b/assets/npc/action_btn/npc_dialogue.png differ diff --git a/assets/npc/action_btn/resurrect.png b/assets/npc/action_btn/resurrect.png index 8711721ab..b85fb3193 100644 Binary files a/assets/npc/action_btn/resurrect.png and b/assets/npc/action_btn/resurrect.png differ diff --git a/assets/npc/action_btn/resurrect_blue.png b/assets/npc/action_btn/resurrect_blue.png index f51837149..6cdf56953 100644 Binary files a/assets/npc/action_btn/resurrect_blue.png and b/assets/npc/action_btn/resurrect_blue.png differ diff --git a/assets/npc/action_btn/talk.png b/assets/npc/action_btn/talk.png index 482a018dc..da51c088f 100644 Binary files a/assets/npc/action_btn/talk.png and b/assets/npc/action_btn/talk.png differ diff --git a/assets/npc/action_btn/trade.png b/assets/npc/action_btn/trade.png index 7fcaa2e73..2500290b2 100644 Binary files a/assets/npc/action_btn/trade.png and b/assets/npc/action_btn/trade.png differ diff --git a/assets/npc/action_btn/trade_blue.png b/assets/npc/action_btn/trade_blue.png index f49b9b3d8..c4b1b7533 100644 Binary files a/assets/npc/action_btn/trade_blue.png and b/assets/npc/action_btn/trade_blue.png differ diff --git a/assets/npc/action_btn/trade_repair.png b/assets/npc/action_btn/trade_repair.png index 8d4ba5afa..d831a1208 100644 Binary files a/assets/npc/action_btn/trade_repair.png and b/assets/npc/action_btn/trade_repair.png differ diff --git a/assets/npc/action_btn/trade_repair_blue.png b/assets/npc/action_btn/trade_repair_blue.png index a801a6e89..4d12df9f9 100644 Binary files a/assets/npc/action_btn/trade_repair_blue.png and b/assets/npc/action_btn/trade_repair_blue.png differ diff --git a/assets/npc/akara/akara_name_tag_gold.png b/assets/npc/akara/akara_name_tag_gold.png index 74d46679e..a6512f74b 100644 Binary files a/assets/npc/akara/akara_name_tag_gold.png and b/assets/npc/akara/akara_name_tag_gold.png differ diff --git a/assets/npc/akara/akara_name_tag_white.png b/assets/npc/akara/akara_name_tag_white.png index 0e095125a..5012f6a51 100644 Binary files a/assets/npc/akara/akara_name_tag_white.png and b/assets/npc/akara/akara_name_tag_white.png differ diff --git a/assets/npc/anya/anya_name_tag_gold.png b/assets/npc/anya/anya_name_tag_gold.png index afcc9ba73..884ba949a 100644 Binary files a/assets/npc/anya/anya_name_tag_gold.png and b/assets/npc/anya/anya_name_tag_gold.png differ diff --git a/assets/npc/anya/anya_name_tag_white.png b/assets/npc/anya/anya_name_tag_white.png index cc467467a..cf9760158 100644 Binary files a/assets/npc/anya/anya_name_tag_white.png and b/assets/npc/anya/anya_name_tag_white.png differ diff --git a/assets/npc/cain/cain_name_tag_gold.png b/assets/npc/cain/cain_name_tag_gold.png index f3b6f55e4..49d40ac0d 100644 Binary files a/assets/npc/cain/cain_name_tag_gold.png and b/assets/npc/cain/cain_name_tag_gold.png differ diff --git a/assets/npc/cain/cain_name_tag_white.png b/assets/npc/cain/cain_name_tag_white.png index a9976af66..4516defe7 100644 Binary files a/assets/npc/cain/cain_name_tag_white.png and b/assets/npc/cain/cain_name_tag_white.png differ diff --git a/assets/npc/charsi/charsi_name_tag_gold.png b/assets/npc/charsi/charsi_name_tag_gold.png index 36c809b62..2a10cd034 100644 Binary files a/assets/npc/charsi/charsi_name_tag_gold.png and b/assets/npc/charsi/charsi_name_tag_gold.png differ diff --git a/assets/npc/charsi/charsi_name_tag_white.png b/assets/npc/charsi/charsi_name_tag_white.png index 6089527e7..e6d10db14 100644 Binary files a/assets/npc/charsi/charsi_name_tag_white.png and b/assets/npc/charsi/charsi_name_tag_white.png differ diff --git a/assets/npc/drognan/drognan_name_tag_gold.png b/assets/npc/drognan/drognan_name_tag_gold.png index d80688509..826b06aaa 100644 Binary files a/assets/npc/drognan/drognan_name_tag_gold.png and b/assets/npc/drognan/drognan_name_tag_gold.png differ diff --git a/assets/npc/drognan/drognan_name_tag_white.png b/assets/npc/drognan/drognan_name_tag_white.png index ef29a349b..4d34d8618 100644 Binary files a/assets/npc/drognan/drognan_name_tag_white.png and b/assets/npc/drognan/drognan_name_tag_white.png differ diff --git a/assets/npc/fara/fara_name_tag_gold.png b/assets/npc/fara/fara_name_tag_gold.png index eabe1d9ba..85b39af6e 100644 Binary files a/assets/npc/fara/fara_name_tag_gold.png and b/assets/npc/fara/fara_name_tag_gold.png differ diff --git a/assets/npc/fara/fara_name_tag_white.png b/assets/npc/fara/fara_name_tag_white.png index 8d275c581..b576452c9 100644 Binary files a/assets/npc/fara/fara_name_tag_white.png and b/assets/npc/fara/fara_name_tag_white.png differ diff --git a/assets/npc/halbu/halbu_name_tag_gold.png b/assets/npc/halbu/halbu_name_tag_gold.png index cc27d874e..526aaa5af 100644 Binary files a/assets/npc/halbu/halbu_name_tag_gold.png and b/assets/npc/halbu/halbu_name_tag_gold.png differ diff --git a/assets/npc/halbu/halbu_name_tag_white.png b/assets/npc/halbu/halbu_name_tag_white.png index 981d6ea0a..18990c467 100644 Binary files a/assets/npc/halbu/halbu_name_tag_white.png and b/assets/npc/halbu/halbu_name_tag_white.png differ diff --git a/assets/npc/jamella/jamella_name_tag_gold.png b/assets/npc/jamella/jamella_name_tag_gold.png index 31f11ca90..9a4c96f25 100644 Binary files a/assets/npc/jamella/jamella_name_tag_gold.png and b/assets/npc/jamella/jamella_name_tag_gold.png differ diff --git a/assets/npc/jamella/jamella_name_tag_white.png b/assets/npc/jamella/jamella_name_tag_white.png index 59b485321..2735333f4 100644 Binary files a/assets/npc/jamella/jamella_name_tag_white.png and b/assets/npc/jamella/jamella_name_tag_white.png differ diff --git a/assets/npc/kashya/kashya_name_tag_gold.png b/assets/npc/kashya/kashya_name_tag_gold.png index 329e671cb..615f26de1 100644 Binary files a/assets/npc/kashya/kashya_name_tag_gold.png and b/assets/npc/kashya/kashya_name_tag_gold.png differ diff --git a/assets/npc/kashya/kashya_name_tag_white.png b/assets/npc/kashya/kashya_name_tag_white.png index c5fc6036d..65f55078a 100644 Binary files a/assets/npc/kashya/kashya_name_tag_white.png and b/assets/npc/kashya/kashya_name_tag_white.png differ diff --git a/assets/npc/larzuk/larzuk_name_tag_gold.png b/assets/npc/larzuk/larzuk_name_tag_gold.png index 483d6d794..ce4e28026 100644 Binary files a/assets/npc/larzuk/larzuk_name_tag_gold.png and b/assets/npc/larzuk/larzuk_name_tag_gold.png differ diff --git a/assets/npc/larzuk/larzuk_name_tag_white.png b/assets/npc/larzuk/larzuk_name_tag_white.png index 2626dc227..85296bdde 100644 Binary files a/assets/npc/larzuk/larzuk_name_tag_white.png and b/assets/npc/larzuk/larzuk_name_tag_white.png differ diff --git a/assets/npc/lysander/lysander_name_tag_gold.png b/assets/npc/lysander/lysander_name_tag_gold.png index 1d8695aef..100ec45ff 100644 Binary files a/assets/npc/lysander/lysander_name_tag_gold.png and b/assets/npc/lysander/lysander_name_tag_gold.png differ diff --git a/assets/npc/lysander/lysander_name_tag_white.png b/assets/npc/lysander/lysander_name_tag_white.png index 6ebf7007a..66313995b 100644 Binary files a/assets/npc/lysander/lysander_name_tag_white.png and b/assets/npc/lysander/lysander_name_tag_white.png differ diff --git a/assets/npc/malah/malah_name_tag_gold.png b/assets/npc/malah/malah_name_tag_gold.png index a98a81cd8..e18c75a59 100644 Binary files a/assets/npc/malah/malah_name_tag_gold.png and b/assets/npc/malah/malah_name_tag_gold.png differ diff --git a/assets/npc/malah/malah_name_tag_white.png b/assets/npc/malah/malah_name_tag_white.png index d68a6d720..93435c109 100644 Binary files a/assets/npc/malah/malah_name_tag_white.png and b/assets/npc/malah/malah_name_tag_white.png differ diff --git a/assets/npc/ormus/ormus_name_tag_gold.png b/assets/npc/ormus/ormus_name_tag_gold.png index 604b1ebca..d7f0644e5 100644 Binary files a/assets/npc/ormus/ormus_name_tag_gold.png and b/assets/npc/ormus/ormus_name_tag_gold.png differ diff --git a/assets/npc/ormus/ormus_name_tag_white.png b/assets/npc/ormus/ormus_name_tag_white.png index 6dcdf8d29..6095e0912 100644 Binary files a/assets/npc/ormus/ormus_name_tag_white.png and b/assets/npc/ormus/ormus_name_tag_white.png differ diff --git a/assets/npc/qual_kehk/qual_name_tag_gold.png b/assets/npc/qual_kehk/qual_name_tag_gold.png index aa44ef9ff..72c97f1d2 100644 Binary files a/assets/npc/qual_kehk/qual_name_tag_gold.png and b/assets/npc/qual_kehk/qual_name_tag_gold.png differ diff --git a/assets/npc/qual_kehk/qual_name_tag_white.png b/assets/npc/qual_kehk/qual_name_tag_white.png index 0431b5705..591d62c37 100644 Binary files a/assets/npc/qual_kehk/qual_name_tag_white.png and b/assets/npc/qual_kehk/qual_name_tag_white.png differ diff --git a/assets/npc/tyrael/tyrael_name_tag_gold.png b/assets/npc/tyrael/tyrael_name_tag_gold.png index bec3bc05a..fa2e5406e 100644 Binary files a/assets/npc/tyrael/tyrael_name_tag_gold.png and b/assets/npc/tyrael/tyrael_name_tag_gold.png differ diff --git a/assets/npc/tyrael/tyrael_name_tag_white.png b/assets/npc/tyrael/tyrael_name_tag_white.png index 407f9a6ba..e2adbf6f6 100644 Binary files a/assets/npc/tyrael/tyrael_name_tag_white.png and b/assets/npc/tyrael/tyrael_name_tag_white.png differ diff --git a/assets/templates/a2_town/a2_town_20.png b/assets/templates/a2_town/a2_town_20.png index 84a8a819d..d56c5e1a2 100644 Binary files a/assets/templates/a2_town/a2_town_20.png and b/assets/templates/a2_town/a2_town_20.png differ diff --git a/assets/templates/dia_seal_mouseover.png b/assets/templates/dia_seal_mouseover.png index d0825b947..7b364a880 100644 Binary files a/assets/templates/dia_seal_mouseover.png and b/assets/templates/dia_seal_mouseover.png differ diff --git a/assets/templates/inventory/deposit_btn.png b/assets/templates/inventory/deposit_btn.png index a313dd65b..894080daa 100644 Binary files a/assets/templates/inventory/deposit_btn.png and b/assets/templates/inventory/deposit_btn.png differ diff --git a/assets/templates/inventory/deposit_btn_bright.png b/assets/templates/inventory/deposit_btn_bright.png index eb46e4180..e665e3c94 100644 Binary files a/assets/templates/inventory/deposit_btn_bright.png and b/assets/templates/inventory/deposit_btn_bright.png differ diff --git a/assets/templates/inventory/inventory_amethyst_chipped.png b/assets/templates/inventory/inventory_amethyst_chipped.png new file mode 100644 index 000000000..c94669417 Binary files /dev/null and b/assets/templates/inventory/inventory_amethyst_chipped.png differ diff --git a/assets/templates/inventory/inventory_amethyst_flawed.png b/assets/templates/inventory/inventory_amethyst_flawed.png new file mode 100644 index 000000000..ecddde745 Binary files /dev/null and b/assets/templates/inventory/inventory_amethyst_flawed.png differ diff --git a/assets/templates/inventory/inventory_amethyst_standard.png b/assets/templates/inventory/inventory_amethyst_standard.png new file mode 100644 index 000000000..d49b3aa57 Binary files /dev/null and b/assets/templates/inventory/inventory_amethyst_standard.png differ diff --git a/assets/templates/inventory/inventory_bg_pattern.png b/assets/templates/inventory/inventory_bg_pattern.png new file mode 100644 index 000000000..2c58f4df1 Binary files /dev/null and b/assets/templates/inventory/inventory_bg_pattern.png differ diff --git a/assets/templates/inventory/inventory_diamond_chipped.png b/assets/templates/inventory/inventory_diamond_chipped.png new file mode 100644 index 000000000..535c71490 Binary files /dev/null and b/assets/templates/inventory/inventory_diamond_chipped.png differ diff --git a/assets/templates/inventory/inventory_diamond_flawed.png b/assets/templates/inventory/inventory_diamond_flawed.png new file mode 100644 index 000000000..834601bc0 Binary files /dev/null and b/assets/templates/inventory/inventory_diamond_flawed.png differ diff --git a/assets/templates/inventory/inventory_diamond_standard.png b/assets/templates/inventory/inventory_diamond_standard.png new file mode 100644 index 000000000..68bb85d2d Binary files /dev/null and b/assets/templates/inventory/inventory_diamond_standard.png differ diff --git a/assets/templates/inventory/inventory_emerald_chipped.png b/assets/templates/inventory/inventory_emerald_chipped.png new file mode 100644 index 000000000..c336ccf29 Binary files /dev/null and b/assets/templates/inventory/inventory_emerald_chipped.png differ diff --git a/assets/templates/inventory/inventory_emerald_flawed.png b/assets/templates/inventory/inventory_emerald_flawed.png new file mode 100644 index 000000000..2f4a37a3e Binary files /dev/null and b/assets/templates/inventory/inventory_emerald_flawed.png differ diff --git a/assets/templates/inventory/inventory_emerald_standard.png b/assets/templates/inventory/inventory_emerald_standard.png new file mode 100644 index 000000000..85b89e62e Binary files /dev/null and b/assets/templates/inventory/inventory_emerald_standard.png differ diff --git a/assets/templates/inventory/inventory_no_gold.png b/assets/templates/inventory/inventory_no_gold.png index e62654db1..c192c9ec1 100644 Binary files a/assets/templates/inventory/inventory_no_gold.png and b/assets/templates/inventory/inventory_no_gold.png differ diff --git a/assets/templates/inventory/inventory_ruby_chipped.png b/assets/templates/inventory/inventory_ruby_chipped.png new file mode 100644 index 000000000..e72cd678a Binary files /dev/null and b/assets/templates/inventory/inventory_ruby_chipped.png differ diff --git a/assets/templates/inventory/inventory_ruby_flawed.png b/assets/templates/inventory/inventory_ruby_flawed.png new file mode 100644 index 000000000..0128b8909 Binary files /dev/null and b/assets/templates/inventory/inventory_ruby_flawed.png differ diff --git a/assets/templates/inventory/inventory_ruby_standard.png b/assets/templates/inventory/inventory_ruby_standard.png new file mode 100644 index 000000000..880d1922c Binary files /dev/null and b/assets/templates/inventory/inventory_ruby_standard.png differ diff --git a/assets/templates/inventory/inventory_sapphire_chipped.png b/assets/templates/inventory/inventory_sapphire_chipped.png new file mode 100644 index 000000000..957f74e5a Binary files /dev/null and b/assets/templates/inventory/inventory_sapphire_chipped.png differ diff --git a/assets/templates/inventory/inventory_sapphire_flawed.png b/assets/templates/inventory/inventory_sapphire_flawed.png new file mode 100644 index 000000000..6478d9487 Binary files /dev/null and b/assets/templates/inventory/inventory_sapphire_flawed.png differ diff --git a/assets/templates/inventory/inventory_sapphire_standard.png b/assets/templates/inventory/inventory_sapphire_standard.png new file mode 100644 index 000000000..af8ed6339 Binary files /dev/null and b/assets/templates/inventory/inventory_sapphire_standard.png differ diff --git a/assets/templates/inventory/inventory_skull_chipped.png b/assets/templates/inventory/inventory_skull_chipped.png new file mode 100644 index 000000000..ee745c5d2 Binary files /dev/null and b/assets/templates/inventory/inventory_skull_chipped.png differ diff --git a/assets/templates/inventory/inventory_skull_flawed.png b/assets/templates/inventory/inventory_skull_flawed.png new file mode 100644 index 000000000..97694b287 Binary files /dev/null and b/assets/templates/inventory/inventory_skull_flawed.png differ diff --git a/assets/templates/inventory/inventory_skull_standard.png b/assets/templates/inventory/inventory_skull_standard.png new file mode 100644 index 000000000..f4c241c6e Binary files /dev/null and b/assets/templates/inventory/inventory_skull_standard.png differ diff --git a/assets/templates/inventory/inventory_topaz_chipped.png b/assets/templates/inventory/inventory_topaz_chipped.png new file mode 100644 index 000000000..1e9211780 Binary files /dev/null and b/assets/templates/inventory/inventory_topaz_chipped.png differ diff --git a/assets/templates/inventory/inventory_topaz_flawed.png b/assets/templates/inventory/inventory_topaz_flawed.png new file mode 100644 index 000000000..c07a978a2 Binary files /dev/null and b/assets/templates/inventory/inventory_topaz_flawed.png differ diff --git a/assets/templates/inventory/inventory_topaz_standard.png b/assets/templates/inventory/inventory_topaz_standard.png new file mode 100644 index 000000000..d689f62b4 Binary files /dev/null and b/assets/templates/inventory/inventory_topaz_standard.png differ diff --git a/assets/templates/inventory/not_enough_gold.png b/assets/templates/inventory/not_enough_gold.png index e38ea1058..b7d77f5f3 100644 Binary files a/assets/templates/inventory/not_enough_gold.png and b/assets/templates/inventory/not_enough_gold.png differ diff --git a/assets/templates/inventory/stash_0_active.png b/assets/templates/inventory/stash_0_active.png index 299ac75c1..42d6efb19 100644 Binary files a/assets/templates/inventory/stash_0_active.png and b/assets/templates/inventory/stash_0_active.png differ diff --git a/assets/templates/inventory/stash_1_active.png b/assets/templates/inventory/stash_1_active.png index 6ddd4c331..89acc6154 100644 Binary files a/assets/templates/inventory/stash_1_active.png and b/assets/templates/inventory/stash_1_active.png differ diff --git a/assets/templates/inventory/stash_2_active.png b/assets/templates/inventory/stash_2_active.png index ef8057a0a..9d4e2b195 100644 Binary files a/assets/templates/inventory/stash_2_active.png and b/assets/templates/inventory/stash_2_active.png differ diff --git a/assets/templates/inventory/stash_3_active.png b/assets/templates/inventory/stash_3_active.png index 04431a464..b80240d11 100644 Binary files a/assets/templates/inventory/stash_3_active.png and b/assets/templates/inventory/stash_3_active.png differ diff --git a/assets/templates/inventory/to_tooltip.png b/assets/templates/inventory/to_tooltip.png index 2dcfcb4db..b83692333 100644 Binary files a/assets/templates/inventory/to_tooltip.png and b/assets/templates/inventory/to_tooltip.png differ diff --git a/assets/templates/inventory/unidentified.png b/assets/templates/inventory/unidentified.png new file mode 100644 index 000000000..dde16f0a3 Binary files /dev/null and b/assets/templates/inventory/unidentified.png differ diff --git a/assets/templates/necro_trav/TO_TRAV_0.png b/assets/templates/necro_trav/TO_TRAV_0.png index 144dbe37e..295264db4 100644 Binary files a/assets/templates/necro_trav/TO_TRAV_0.png and b/assets/templates/necro_trav/TO_TRAV_0.png differ diff --git a/assets/templates/ni2_search_2.png b/assets/templates/ni2_search_2.png index 267564eca..4201ac405 100644 Binary files a/assets/templates/ni2_search_2.png and b/assets/templates/ni2_search_2.png differ diff --git a/assets/templates/nihl_bar.png b/assets/templates/nihl_bar.png index f7c440e43..8b48aa12d 100644 Binary files a/assets/templates/nihl_bar.png and b/assets/templates/nihl_bar.png differ diff --git a/assets/templates/nihlatak/NI2_SEARCH_1.png b/assets/templates/nihlatak/NI2_SEARCH_1.png index 0e39e8d55..503870ea7 100644 Binary files a/assets/templates/nihlatak/NI2_SEARCH_1.png and b/assets/templates/nihlatak/NI2_SEARCH_1.png differ diff --git a/assets/templates/nihlatak/ni1_stairs_3.png b/assets/templates/nihlatak/ni1_stairs_3.png index 3368b4757..b3e56768c 100644 Binary files a/assets/templates/nihlatak/ni1_stairs_3.png and b/assets/templates/nihlatak/ni1_stairs_3.png differ diff --git a/assets/templates/summons/mage_1.png b/assets/templates/summons/mage_1.png index fdb7c51f5..0d9ba7bf3 100644 Binary files a/assets/templates/summons/mage_1.png and b/assets/templates/summons/mage_1.png differ diff --git a/assets/templates/summons/rev_1.png b/assets/templates/summons/rev_1.png index 8fb21e2fe..9d8729f56 100644 Binary files a/assets/templates/summons/rev_1.png and b/assets/templates/summons/rev_1.png differ diff --git a/assets/templates/summons/rev_10.png b/assets/templates/summons/rev_10.png index 483130eb6..4a7f4cd17 100644 Binary files a/assets/templates/summons/rev_10.png and b/assets/templates/summons/rev_10.png differ diff --git a/assets/templates/summons/rev_11.png b/assets/templates/summons/rev_11.png index 72ed24435..f137d53a9 100644 Binary files a/assets/templates/summons/rev_11.png and b/assets/templates/summons/rev_11.png differ diff --git a/assets/templates/summons/rev_12.png b/assets/templates/summons/rev_12.png index 62a235c12..744322df3 100644 Binary files a/assets/templates/summons/rev_12.png and b/assets/templates/summons/rev_12.png differ diff --git a/assets/templates/summons/rev_13.png b/assets/templates/summons/rev_13.png index c58a36f39..f46303bbc 100644 Binary files a/assets/templates/summons/rev_13.png and b/assets/templates/summons/rev_13.png differ diff --git a/assets/templates/summons/rev_14.png b/assets/templates/summons/rev_14.png new file mode 100644 index 000000000..13d4bc12e Binary files /dev/null and b/assets/templates/summons/rev_14.png differ diff --git a/assets/templates/summons/rev_15.png b/assets/templates/summons/rev_15.png new file mode 100644 index 000000000..c2328693a Binary files /dev/null and b/assets/templates/summons/rev_15.png differ diff --git a/assets/templates/summons/rev_16.png b/assets/templates/summons/rev_16.png new file mode 100644 index 000000000..76d904d92 Binary files /dev/null and b/assets/templates/summons/rev_16.png differ diff --git a/assets/templates/summons/rev_17.png b/assets/templates/summons/rev_17.png new file mode 100644 index 000000000..fb3e3e86e Binary files /dev/null and b/assets/templates/summons/rev_17.png differ diff --git a/assets/templates/summons/rev_18.png b/assets/templates/summons/rev_18.png new file mode 100644 index 000000000..885ecd022 Binary files /dev/null and b/assets/templates/summons/rev_18.png differ diff --git a/assets/templates/summons/rev_19.png b/assets/templates/summons/rev_19.png new file mode 100644 index 000000000..129301104 Binary files /dev/null and b/assets/templates/summons/rev_19.png differ diff --git a/assets/templates/summons/rev_2.png b/assets/templates/summons/rev_2.png index cce18b654..b45dc8dcc 100644 Binary files a/assets/templates/summons/rev_2.png and b/assets/templates/summons/rev_2.png differ diff --git a/assets/templates/summons/rev_20.png b/assets/templates/summons/rev_20.png new file mode 100644 index 000000000..c2cee5f64 Binary files /dev/null and b/assets/templates/summons/rev_20.png differ diff --git a/assets/templates/summons/rev_21.png b/assets/templates/summons/rev_21.png new file mode 100644 index 000000000..0e26e9688 Binary files /dev/null and b/assets/templates/summons/rev_21.png differ diff --git a/assets/templates/summons/rev_22.png b/assets/templates/summons/rev_22.png new file mode 100644 index 000000000..c3f3b1685 Binary files /dev/null and b/assets/templates/summons/rev_22.png differ diff --git a/assets/templates/summons/rev_3.png b/assets/templates/summons/rev_3.png index 53329db76..d418dd587 100644 Binary files a/assets/templates/summons/rev_3.png and b/assets/templates/summons/rev_3.png differ diff --git a/assets/templates/summons/rev_4.png b/assets/templates/summons/rev_4.png index 72ce8d49a..56ac1abdc 100644 Binary files a/assets/templates/summons/rev_4.png and b/assets/templates/summons/rev_4.png differ diff --git a/assets/templates/summons/rev_5.png b/assets/templates/summons/rev_5.png index 8bd85f51a..0492e0abd 100644 Binary files a/assets/templates/summons/rev_5.png and b/assets/templates/summons/rev_5.png differ diff --git a/assets/templates/summons/rev_6.png b/assets/templates/summons/rev_6.png index 4f22cf27d..965bb536f 100644 Binary files a/assets/templates/summons/rev_6.png and b/assets/templates/summons/rev_6.png differ diff --git a/assets/templates/summons/rev_7.png b/assets/templates/summons/rev_7.png index 6503b79df..0ae8f28f2 100644 Binary files a/assets/templates/summons/rev_7.png and b/assets/templates/summons/rev_7.png differ diff --git a/assets/templates/summons/rev_8.png b/assets/templates/summons/rev_8.png index 1337c861e..d71b9ac8a 100644 Binary files a/assets/templates/summons/rev_8.png and b/assets/templates/summons/rev_8.png differ diff --git a/assets/templates/summons/rev_9.png b/assets/templates/summons/rev_9.png index 54dd77e09..7d60aa27d 100644 Binary files a/assets/templates/summons/rev_9.png and b/assets/templates/summons/rev_9.png differ diff --git a/assets/templates/summons/rev_base.png b/assets/templates/summons/rev_base.png index 05573246e..6dcaa159e 100644 Binary files a/assets/templates/summons/rev_base.png and b/assets/templates/summons/rev_base.png differ diff --git a/assets/templates/summons/skele_1.png b/assets/templates/summons/skele_1.png index 0c4a629c8..d0f2bf091 100644 Binary files a/assets/templates/summons/skele_1.png and b/assets/templates/summons/skele_1.png differ diff --git a/assets/templates/summons/skele_10.png b/assets/templates/summons/skele_10.png index a52a72776..93cda1390 100644 Binary files a/assets/templates/summons/skele_10.png and b/assets/templates/summons/skele_10.png differ diff --git a/assets/templates/summons/skele_11.png b/assets/templates/summons/skele_11.png index a53a2524e..595f91cdf 100644 Binary files a/assets/templates/summons/skele_11.png and b/assets/templates/summons/skele_11.png differ diff --git a/assets/templates/summons/skele_12.png b/assets/templates/summons/skele_12.png index ace632ff1..2b1cf5d63 100644 Binary files a/assets/templates/summons/skele_12.png and b/assets/templates/summons/skele_12.png differ diff --git a/assets/templates/summons/skele_13.png b/assets/templates/summons/skele_13.png index 5a4421a02..127dfb624 100644 Binary files a/assets/templates/summons/skele_13.png and b/assets/templates/summons/skele_13.png differ diff --git a/assets/templates/summons/skele_14.png b/assets/templates/summons/skele_14.png new file mode 100644 index 000000000..e4d7a8e72 Binary files /dev/null and b/assets/templates/summons/skele_14.png differ diff --git a/assets/templates/summons/skele_2.png b/assets/templates/summons/skele_2.png index 633741286..f345fd8f7 100644 Binary files a/assets/templates/summons/skele_2.png and b/assets/templates/summons/skele_2.png differ diff --git a/assets/templates/summons/skele_3.png b/assets/templates/summons/skele_3.png index cb58ac4be..5b4075736 100644 Binary files a/assets/templates/summons/skele_3.png and b/assets/templates/summons/skele_3.png differ diff --git a/assets/templates/summons/skele_4.png b/assets/templates/summons/skele_4.png index f75e1ec7a..38628250e 100644 Binary files a/assets/templates/summons/skele_4.png and b/assets/templates/summons/skele_4.png differ diff --git a/assets/templates/summons/skele_5.png b/assets/templates/summons/skele_5.png index c11d39c84..a00598611 100644 Binary files a/assets/templates/summons/skele_5.png and b/assets/templates/summons/skele_5.png differ diff --git a/assets/templates/summons/skele_6.png b/assets/templates/summons/skele_6.png index 12e63b0b7..7c958374e 100644 Binary files a/assets/templates/summons/skele_6.png and b/assets/templates/summons/skele_6.png differ diff --git a/assets/templates/summons/skele_7.png b/assets/templates/summons/skele_7.png index 75d3a8cb3..7027d918b 100644 Binary files a/assets/templates/summons/skele_7.png and b/assets/templates/summons/skele_7.png differ diff --git a/assets/templates/summons/skele_8.png b/assets/templates/summons/skele_8.png index 5b539ae80..82e0ee0b4 100644 Binary files a/assets/templates/summons/skele_8.png and b/assets/templates/summons/skele_8.png differ diff --git a/assets/templates/summons/skele_9.png b/assets/templates/summons/skele_9.png index a3feacf2e..a310e07f6 100644 Binary files a/assets/templates/summons/skele_9.png and b/assets/templates/summons/skele_9.png differ diff --git a/assets/templates/summons/skele_base.png b/assets/templates/summons/skele_base.png index 2a26a201e..1448e9ad0 100644 Binary files a/assets/templates/summons/skele_base.png and b/assets/templates/summons/skele_base.png differ diff --git a/assets/templates/trav/TRAV_225_V3_0.png b/assets/templates/trav/TRAV_225_V3_0.png new file mode 100644 index 000000000..af4529c3c Binary files /dev/null and b/assets/templates/trav/TRAV_225_V3_0.png differ diff --git a/assets/templates/trav/TRAV_225_V3_1.png b/assets/templates/trav/TRAV_225_V3_1.png new file mode 100644 index 000000000..951e3d9a9 Binary files /dev/null and b/assets/templates/trav/TRAV_225_V3_1.png differ diff --git a/assets/templates/trav/TRAV_225_V3_2.png b/assets/templates/trav/TRAV_225_V3_2.png new file mode 100644 index 000000000..6c4663585 Binary files /dev/null and b/assets/templates/trav/TRAV_225_V3_2.png differ diff --git a/assets/templates/trav/TRAV_225_V3_3.png b/assets/templates/trav/TRAV_225_V3_3.png new file mode 100644 index 000000000..cdd3231ed Binary files /dev/null and b/assets/templates/trav/TRAV_225_V3_3.png differ diff --git a/assets/templates/trav/TRAV_225_V3_7.png b/assets/templates/trav/TRAV_225_V3_7.png new file mode 100644 index 000000000..f79786a29 Binary files /dev/null and b/assets/templates/trav/TRAV_225_V3_7.png differ diff --git a/assets/templates/ui/character_select/character_active.png b/assets/templates/ui/character_select/character_active.png index 6789e9063..6ae719c8e 100644 Binary files a/assets/templates/ui/character_select/character_active.png and b/assets/templates/ui/character_select/character_active.png differ diff --git a/assets/templates/ui/character_select/character_state_offline.png b/assets/templates/ui/character_select/character_state_offline.png index 423c78ca6..58a9d4da0 100644 Binary files a/assets/templates/ui/character_select/character_state_offline.png and b/assets/templates/ui/character_select/character_state_offline.png differ diff --git a/assets/templates/ui/character_select/character_state_online.png b/assets/templates/ui/character_select/character_state_online.png index f4ae490c1..4275df67d 100644 Binary files a/assets/templates/ui/character_select/character_state_online.png and b/assets/templates/ui/character_select/character_state_online.png differ diff --git a/assets/templates/ui/error_screens/server_issues.png b/assets/templates/ui/error_screens/server_issues.png index 16eaac324..a4ec6aa5a 100644 Binary files a/assets/templates/ui/error_screens/server_issues.png and b/assets/templates/ui/error_screens/server_issues.png differ diff --git a/assets/templates/ui/ingame_menu/game_menu_highlight.png b/assets/templates/ui/ingame_menu/game_menu_highlight.png deleted file mode 100644 index 7acd08a0b..000000000 Binary files a/assets/templates/ui/ingame_menu/game_menu_highlight.png and /dev/null differ diff --git a/assets/templates/ui/ingame_menu/save_and_exit_highlight.png b/assets/templates/ui/ingame_menu/save_and_exit_highlight.png new file mode 100644 index 000000000..61a7367b4 Binary files /dev/null and b/assets/templates/ui/ingame_menu/save_and_exit_highlight.png differ diff --git a/assets/templates/ui/ingame_menu/save_and_exit_no_highlight.png b/assets/templates/ui/ingame_menu/save_and_exit_no_highlight.png new file mode 100644 index 000000000..9f7117771 Binary files /dev/null and b/assets/templates/ui/ingame_menu/save_and_exit_no_highlight.png differ diff --git a/assets/templates/ui/loading/creating_game.png b/assets/templates/ui/loading/creating_game.png index 7523fd8ea..e17b004b7 100644 Binary files a/assets/templates/ui/loading/creating_game.png and b/assets/templates/ui/loading/creating_game.png differ diff --git a/assets/templates/ui/loading/loading.png b/assets/templates/ui/loading/loading.png index e030b73d9..5e7b38af8 100644 Binary files a/assets/templates/ui/loading/loading.png and b/assets/templates/ui/loading/loading.png differ diff --git a/assets/templates/ui/main_menu/play_btn.png b/assets/templates/ui/main_menu/play_btn.png index b6db9bb77..cf5152056 100644 Binary files a/assets/templates/ui/main_menu/play_btn.png and b/assets/templates/ui/main_menu/play_btn.png differ diff --git a/assets/templates/ui/main_menu/play_btn_gray.png b/assets/templates/ui/main_menu/play_btn_gray.png index 641d53dcf..59bbdca6c 100644 Binary files a/assets/templates/ui/main_menu/play_btn_gray.png and b/assets/templates/ui/main_menu/play_btn_gray.png differ diff --git a/assets/templates/ui/view/bind_skill.png b/assets/templates/ui/view/bind_skill.png index 48740c7c5..a26ed26d6 100644 Binary files a/assets/templates/ui/view/bind_skill.png and b/assets/templates/ui/view/bind_skill.png differ diff --git a/assets/templates/ui/view/corpse.png b/assets/templates/ui/view/corpse.png index f3acd8644..0993cdba5 100644 Binary files a/assets/templates/ui/view/corpse.png and b/assets/templates/ui/view/corpse.png differ diff --git a/assets/templates/ui/view/corpse_2.png b/assets/templates/ui/view/corpse_2.png new file mode 100644 index 000000000..118b95cf8 Binary files /dev/null and b/assets/templates/ui/view/corpse_2.png differ diff --git a/assets/templates/ui/view/hidden_stash.png b/assets/templates/ui/view/hidden_stash.png index fdfbb7bbe..7970cd9a2 100644 Binary files a/assets/templates/ui/view/hidden_stash.png and b/assets/templates/ui/view/hidden_stash.png differ diff --git a/assets/templates/ui/view/shrine.png b/assets/templates/ui/view/shrine.png index 2454486b5..688e9a972 100644 Binary files a/assets/templates/ui/view/shrine.png and b/assets/templates/ui/view/shrine.png differ diff --git a/assets/templates/ui/view/skull_pile.png b/assets/templates/ui/view/skull_pile.png index 484520b10..cd274bcfb 100644 Binary files a/assets/templates/ui/view/skull_pile.png and b/assets/templates/ui/view/skull_pile.png differ diff --git a/assets/templates/ui/view/you_have_died.png b/assets/templates/ui/view/you_have_died.png index 1f0a28727..f7b36d44b 100644 Binary files a/assets/templates/ui/view/you_have_died.png and b/assets/templates/ui/view/you_have_died.png differ diff --git a/assets/templates/ui/waypoint/label_waypoint.png b/assets/templates/ui/waypoint/label_waypoint.png index 4fcf77723..8b5bb8faf 100644 Binary files a/assets/templates/ui/waypoint/label_waypoint.png and b/assets/templates/ui/waypoint/label_waypoint.png differ diff --git a/assets/templates/ui/waypoint/wp_a1_active.png b/assets/templates/ui/waypoint/wp_a1_active.png index f45601ddf..145804021 100644 Binary files a/assets/templates/ui/waypoint/wp_a1_active.png and b/assets/templates/ui/waypoint/wp_a1_active.png differ diff --git a/assets/templates/ui/waypoint/wp_a2_active.png b/assets/templates/ui/waypoint/wp_a2_active.png index 82f41aef9..8267cb7aa 100644 Binary files a/assets/templates/ui/waypoint/wp_a2_active.png and b/assets/templates/ui/waypoint/wp_a2_active.png differ diff --git a/assets/templates/ui/waypoint/wp_a3_active.png b/assets/templates/ui/waypoint/wp_a3_active.png index 9956c5434..810598d15 100644 Binary files a/assets/templates/ui/waypoint/wp_a3_active.png and b/assets/templates/ui/waypoint/wp_a3_active.png differ diff --git a/assets/templates/ui/waypoint/wp_a4_active.png b/assets/templates/ui/waypoint/wp_a4_active.png index 025c71356..d6f6b2303 100644 Binary files a/assets/templates/ui/waypoint/wp_a4_active.png and b/assets/templates/ui/waypoint/wp_a4_active.png differ diff --git a/assets/templates/ui/waypoint/wp_a5_active.png b/assets/templates/ui/waypoint/wp_a5_active.png index d69d43959..ff335c4b7 100644 Binary files a/assets/templates/ui/waypoint/wp_a5_active.png and b/assets/templates/ui/waypoint/wp_a5_active.png differ diff --git a/assets/tessdata/__init__.py b/assets/tessdata/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/assets/tessdata/eng.traineddata b/assets/tessdata/eng.traineddata deleted file mode 100644 index 176dc3220..000000000 Binary files a/assets/tessdata/eng.traineddata and /dev/null differ diff --git a/assets/tessdata/engd2r_inv_th.traineddata b/assets/tessdata/engd2r_inv_th.traineddata deleted file mode 100644 index 7233a3ba0..000000000 Binary files a/assets/tessdata/engd2r_inv_th.traineddata and /dev/null differ diff --git a/assets/tessdata/engd2r_inv_th_fast.traineddata b/assets/tessdata/engd2r_inv_th_fast.traineddata deleted file mode 100644 index 523190811..000000000 Binary files a/assets/tessdata/engd2r_inv_th_fast.traineddata and /dev/null differ diff --git a/assets/tessdata/engd2r_ui.traineddata b/assets/tessdata/engd2r_ui.traineddata deleted file mode 100644 index d41eac120..000000000 Binary files a/assets/tessdata/engd2r_ui.traineddata and /dev/null differ diff --git a/assets/tessdata/engd2r_ui_fast.traineddata b/assets/tessdata/engd2r_ui_fast.traineddata deleted file mode 100644 index 52bbc3c03..000000000 Binary files a/assets/tessdata/engd2r_ui_fast.traineddata and /dev/null differ diff --git a/assets/tessdata/ground-eng_inconsolata_inv_th_fast.traineddata b/assets/tessdata/ground-eng_inconsolata_inv_th_fast.traineddata new file mode 100644 index 000000000..7e643717e Binary files /dev/null and b/assets/tessdata/ground-eng_inconsolata_inv_th_fast.traineddata differ diff --git a/assets/tessdata/hover-eng_inconsolata_inv_th_fast.traineddata b/assets/tessdata/hover-eng_inconsolata_inv_th_fast.traineddata new file mode 100644 index 000000000..2f9ef2063 Binary files /dev/null and b/assets/tessdata/hover-eng_inconsolata_inv_th_fast.traineddata differ diff --git a/assets/tessdata/ocr_errors.csv b/assets/tessdata/ocr_errors.csv deleted file mode 100644 index 3c7dff3fe..000000000 --- a/assets/tessdata/ocr_errors.csv +++ /dev/null @@ -1,20 +0,0 @@ -SHIFLD, SHIELD -SPFAR, SPEAR -GLOVFS, GLOVES -GOLP, GOLD -TELEFORT, TELEPORT -TROPHV, TROPHY -CLAVMORE, CLAYMORE -MAKIMUM, MAXIMUM -DEKTERITY, DEXTERITY -DERTERITY, DEXTERITY -QUAHTITY, QUANTITY -DEFERSE, DEFENSE -ARMGR, ARMOR -ARMER, ARMOR -COMDAT, COMBAT -WEAPORS, WEAPONS -AXECLASS, AXE CLASS -IOX%, 10% -IO%, 10% -TWYO, TWO \ No newline at end of file diff --git a/assets/tessdata/word_lists/all_strings.txt b/assets/word_lists/all_words.txt similarity index 82% rename from assets/tessdata/word_lists/all_strings.txt rename to assets/word_lists/all_words.txt index 59475df7a..d7adcc4e8 100644 --- a/assets/tessdata/word_lists/all_strings.txt +++ b/assets/word_lists/all_words.txt @@ -1,6 +1,21 @@ +(AMAZON +(ASSASSIN +(BARBARIAN +(BASE: +(BASED +(CANNOT +(DRUID +(INCREASES +(ITEM) +(NECROMANCER +(OPTIONAL) +(PALADIN +(SORCERESS A ABADDON ABHAYA +ABILITY +ABLE ABOMINABLE ABOUT ABRASION @@ -11,31 +26,49 @@ ABSORBS ABSORPTION ABYSS ACCELERATION +ACCEPT +ACCESS +ACCOUNT +ACCUMULATED ACCURACY ACHERON ACHMEL ACHRON ACROBATIC ACT +ACTIONS +ACTIVATE +ACTIVATED ACTIVATING ACTIVE +ACTIVE, ADAMANT ADD +ADDED. ADDER +ADDING ADDS ADHERENT ADJUDICATION +ADJUST ADMIRATION ADROIT ADVANCE +ADVANCED +ADVENTURING AEGIS AERIN AFFLICT AFFLICTED AFTER +AGAIN +AGAIN. AGAINST AGES +AGO AGONY +AGREE +AGREEMENT AHSAB AIM AJHEED @@ -54,11 +87,16 @@ ALI ALIZA ALKOR ALL +ALL: +ALLOWING +ALLOWS ALMA ALMA'S ALMIGHTY ALPHA +ALSO ALTAR +ALWAYS AMAZON AMBER AMBERGRIS @@ -79,6 +117,7 @@ ANCIENT'S ANCIENTS ANCIENTS' AND +AND/OR ANDARIEL ANDARIEL'S ANGEL @@ -88,12 +127,16 @@ ANGUISH ANNIHILATOR ANNIHILUS ANNOR +ANOTHER +ANOTHER. ANTHRAX ANTIDOTE ANTIMAGIC ANTLERS +ANY ANYA ANYA'S +ANYONE APE APOCRYPHA APOTHECARY'S @@ -115,6 +158,7 @@ ARCHER'S ARCHON ARCING ARCTIC +ARE ARGENT ARIOC'S ARKAINE'S @@ -122,6 +166,7 @@ ARM ARMAGEDDON ARMET ARMOR +ARMOR: ARMORER ARMORY ARMS @@ -136,7 +181,9 @@ ARTFUL ARTIFACTS ARTISAN'S ARTS +ARTS, AS +AS: ASH ASHEARA ASHEARA'S @@ -168,6 +215,7 @@ AURAS AUREOLIC AURORA'S AUTHORITY +AUTO AVARICE AVATAR AVENGER @@ -215,9 +263,11 @@ BARRIER BARTUC BARTUC'S BASANTI +BASED BASH BASHER BASHING +BASIC BASINET BASIS BASKET @@ -236,13 +286,19 @@ BEARDED BEARER BEARS BEAST +BEASTS BEAUTY BEC-DE-CORBIN +BECAUSE +BECOME +BECOMES BED +BEEN BEETLE BEETLEBURST BEFORE BELLE +BELOW BELT BENDER BENEATH @@ -251,13 +307,17 @@ BERSERK BERSERKER BERSERKER'S BERYL +BEST BETRAYAL BETTER +BETWEEN BEWARE +BEWARE! BIGGIN'S BILE BILL BINDING +BINDINGS BING BIRD BISHIBOSH @@ -284,10 +344,12 @@ BLASTBARK BLAZE BLAZER BLAZING +BLENDED BLESSED BLESSING BLIGHT BLIGHTING +BLIND BLINDS BLING BLINKBAT'S @@ -296,8 +358,10 @@ BLISTER BLITZEN BLIZZARD BLOCK +BLOCK: BLOCKED BLOCKING +BLOCKING: BLOOD BLOODFIST BLOODLETTER @@ -311,6 +375,8 @@ BLOODY BLOW BLUDGEON BLUNDERBORE +BOAR +BODIES BODY BOG BOHDAN @@ -331,6 +397,7 @@ BONEWEAVE BONG BONNET BONUS +BONUS: BONUSES BOOK BOOKSHELF @@ -338,6 +405,7 @@ BOOTS BOREAL BORS BOULDER +BOUND BOVINE BOW BOWL @@ -381,6 +449,7 @@ BRUTAL BRUTE BUCKLE BUCKLER +BUG BUGS BUL-KATHOS BUL-KATHOS' @@ -416,6 +485,9 @@ CALLING CALM CAMEL CAMPHOR +CAN +CAN'T +CANCEL CANDLES CANDLESTICK CANNIBAL @@ -424,6 +496,8 @@ CANOPIC CANTOR CANYON CAP +CAPACITY +CAPACITY: CAPTAIN'S CAPTIVE CARAPACE @@ -441,6 +515,7 @@ CASE CASKET CASQUE CAST +CAST: CASTER CAT CAT'S @@ -449,6 +524,8 @@ CATAPULT CATGUT CATHAN'S CATHEDRAL +CAUSE +CAUSED CAUSES CAUSEWAY CAVE @@ -458,6 +535,7 @@ CEDAR CELESTIAL CELLAR CENTAUR +CENTER CENTURION CEREBUS' CEREMONIAL @@ -473,6 +551,8 @@ CHAMPION CHANCE CHANDELIER CHANG +CHANNEL. +CHANNEL: CHANT CHAOS CHAOTIC @@ -481,9 +561,12 @@ CHARGE CHARGE-UP CHARGED CHARGES +CHARGES) +CHARGES: CHARM CHARSI CHARSI'S +CHAT CHEST CHESTNUT CHIEFTAIN @@ -492,9 +575,12 @@ CHILLED CHILLING CHIPPED CHOICE +CHOICES CHOIR CHOKING +CHOOSE CHOP +CHOSEN CHROMATIC CHU-KO-NU CINNABAR @@ -508,18 +594,24 @@ CLASP CLASPED CLASS CLASS-SPECIFIC +CLASSES +CLASSIC CLAW CLAWS CLAY CLAYMORE CLEANSING +CLEARED CLEAVER CLEGLAW'S CLICK +CLICKING CLIFF CLIFFKILLER CLOAK CLOISTER +CLOSE +CLOSE-QUARTERS CLOSED CLOTH CLOUD @@ -532,10 +624,12 @@ COAT COBALT COBRA COCOON +CODE: COFFIN COIF COIL COLD +COLD: COLDCROW COLDKILL COLDSTEAL @@ -544,17 +638,25 @@ COLDWORM COLENZO COLLAR COLLECTOR +COLOR COLORFUL COLOSSUS COMBAT COMBATANT +COME COMET COMMAND COMMANDER'S +COMMANDING +COMMON COMMUNAL COMPACT +COMPARE COMPELLING COMPLETE +COMPLETED +COMPLETED. +COMPLETED: COMPOSITE CONCENTRATE CONCENTRATION @@ -568,15 +670,25 @@ CONQUEST CONSECRATED CONSTRICTING CONSULT +CONSUMED +CONTACT, +CONTAINS +CONTENT CONTINUE +CONTINUOUS CONTROL CONTROLS CONVERSION +CONVERT +CONVERT: +CONVERTING +CONVERTS CONVICTION COOLNESS CORAL CORD CORDON +CORNERS CORONA CORONET CORPORAL @@ -586,10 +698,13 @@ CORPSEMOURN CORPSES CORPULENT CORROSIVE +CORRUPTED. CORRUPTION CORSPES COST +COST: COUANT +COULD COUNCIL COUNTESS COVER @@ -604,6 +719,8 @@ CRANEBEAK CRANIUM CRATE CRAWLER +CREATES +CREATION CREATURE CREDENDUM CREDIT @@ -623,6 +740,7 @@ CRUDE CRUEL CRUELTY CRUSADER +CRUSH CRUSHER CRUSHFLANGE CRUSHING @@ -634,6 +752,7 @@ CRYPTIC CRYSTAL CRYSTALLINE CTHON +CTRL CUBE CUDGEL CUFF @@ -642,10 +761,14 @@ CULWEN'S CUNNING CURIO CURLY +CURRENT +CURRENTLY +CURSE CURSED CURSES CURSING CUSTODIAN +CUSTOM CUT-THROAT CUTLASS CYCLE @@ -654,7 +777,11 @@ DAC DACIAN DAGGER DAMAGE +DAMAGE, +DAMAGE: DAMAGED +DAMAGES: +DAMAGING DAMIEN DAMNED DANCER @@ -671,15 +798,22 @@ DARKSOUL DARKWING DART DAWN +DAWN) +DAY DAYLIGHT +DAYS +DAYS. DAYTIME +DAYTIME) DAZZLING DE +DEACTIVATED DEAD DEADLY DEATH DEATH'S DEATHBIT +DEATHLY DEATHSPADE DEATHWAND DEBI @@ -689,16 +823,18 @@ DECAYED DECAYING DECEPTION DECKARD +DECLARE DECOY DECREPIFY DEFEAT DEFENDER DEFENSE +DEFENSE: DEFENSIVE DEFIANCE +DEFILED DEFILER DEFLECTING -DEL DELIRIUM DELIVERANCE DEMON @@ -707,41 +843,69 @@ DEMONHEAD DEMONHIDE DEMONHORN'S DEMONS +DEMONS, DEMONWEB DEN DENSE +DEPOSIT +DEPOSIT? DESERT DESIRE DESPAIR +DESTINATION DESTROY DESTROYER DESTRUCTION +DESTRUCTION'S +DESTRUCTION. DETAIL +DETAILS. +DETECT +DETECTED, DEVAK DEVIL DEVILKIN DEVIOUS DEVOURER DEXTERITY +DEXTERITY: DIABLO DIABLO'S DIADEM +DIALOGUE DIAMOND DIANE +DIE +DIED +DIES, +DIFFERENCE +DIFFERENCE. +DIFFERENCE: +DIFFERENT +DIFFICULTY +DIFFICULTY: DIGGLER DIM DIMENSIONAL DIMOAK'S DIRE +DIRECTLY DIRK +DISABLED. +DISAGREE +DISCARD DISCIPLE DISCIPLINE DISCIPLINES +DISCONNECTED DISEASE DISFIGURED DISGUISE DISK +DISMISS DISPATCH +DISPLAY +DISPLAY: DISUSED DIVER DIVINE @@ -751,18 +915,22 @@ DO DOCKS DOCTOR DODGE +DOES DOG DOL DOLL DOLLS +DON'T DOOM DOOMBRINGER DOOMSEER DOOMSLINGER DOOR +DOOR. DOPPLEGANGER'S DOUBLE DOUBT +DOWN DRACUL'S DRAGON DRAGON'S @@ -782,31 +950,40 @@ DRINKER DROGNAN DROOL DROP +DROP? +DROPPED +DROPPED. DROWNED DRUID DRULAN'S DRUS DRY +DUE DUN DUNE DUNES DUNG DUNGEON DURABILITY +DURABILITY: DURANCE DURATION +DURATION: DURESS DURGA DURIEL DURIEL'S DURING DUSK +DUSK) DUSKDEEP DUST DUSTY DWARF +DWELL DWELLER DYING +DYNAMIC DYNAMO EACH EADGILS @@ -815,6 +992,7 @@ EAGLEEYE EAGLEHORN EAGLEWIND EAR +EARNED EARS EARTH EARTHSHAKER @@ -824,15 +1002,20 @@ EATS EBURINE ECHOING EDGE +EFFECT EFREETI EGG EGGS EGTHEOW +EITHER EL +ELAPSED ELATION ELD ELDER ELDRITCH +ELECTRICAL +ELECTRICITY ELEGANT ELEMENTAL ELEMENTS @@ -851,35 +1034,55 @@ EMBRACE EMERALD EMILIO EMPOWERING +EMPTY EMPYRIAN EMUND +ENABLE +ENABLED. ENCAMPMENT +ENCAMPMENT. ENCHANT ENCHANTED ENCHANTMENT +ENCHANTS +ENCOUNTERING END ENDLESSHAIL ENDUGU ENDURING ENEMIES +ENEMIES: ENEMY ENERGIZING ENERGY ENFORCER ENHANCED +ENHANCES ENIGMA ENIRHS ENLIGHTENED ENLIGHTENMENT ENNUI +ENOUGH ENSANGUINATOR +ENSLAVED +ENTER +ENTIRE ENTRAPPING ENTROPY +ENTRY +ENVIRONMENT ENVY +EPILOGUE EQUILIBRIUM EQUIP +EQUIPMENT: +EQUIPPED ERION'S EROSION +ERROR +ERRORS. +ESC ESCHUTA'S ESEN'S ESPANDON @@ -897,17 +1100,35 @@ EVE EVERLASTING EVERY EVIL +EVILS EVISCERATION EVISCERATOR EVO EXCALIBUR +EXCEEDED. EXCELLENCE EXCHANGE EXECUTIONER EXECUTIONER'S EXILE +EXIST. +EXISTING +EXISTS +EXISTS. +EXIT +EXITED +EXPANSION +EXPANSION, EXPERIENCE +EXPERIENCE, +EXPERIENCE: EXPERT'S +EXPIRE +EXPIRE. +EXPIRED +EXPIRED. +EXPIRES +EXPLODES EXPLODING EXPLORE EXPLOSION @@ -919,6 +1140,8 @@ EYELESS FACE FACET FADE +FAILED +FAILURE FAITH FAITHFUL FAL @@ -939,6 +1162,7 @@ FANGED FANGSKIN FAR FARA +FARM FARREN FASCIA FASCINATING @@ -974,20 +1198,26 @@ FIERCE FIERY FIGHTER FIGURINE +FILL FINAL FIND FINE FINE-SPUN FINERY FINGER +FINISH FINISHING FIONA FIRE +FIRE, +FIRE: FIREBOLTS FIRELIZARD'S FIRES FIRESTORM FIRESTORMS +FIREWALL +FIRST FISHER FISSURE FIST @@ -1019,6 +1249,7 @@ FLESHRENDER FLESHRIPPER FLETCH FLETCHER'S +FLICKERING FLIGHT FLORIA FLOWKRAD'S @@ -1028,15 +1259,21 @@ FLYING FOCI FOGGY FOLCWALD +FOLEY FOLIAGE FOLLY FOOL'S FOOTHILLS +FOOTSTEPS FOR +FORCE FORCEFUL +FORCES FORE-FATHERS FOREST FORGE +FORGET +FORGOT FORGOTTEN FORK FORKED @@ -1049,14 +1286,17 @@ FORTUITOUS FORTUNE FOUL FOULDOG +FOUND FOX FRAME FRANCISCA FRANTIC +FREE FREEDOM FREEZE FREEZES FREEZING +FRENZIED FRENZY FRIENDSHIP FRIGID @@ -1064,6 +1304,7 @@ FRIGIDITY FRINGE FRISIAN FROM +FROM: FROST FROSTBURN FROSTWIND @@ -1072,6 +1313,7 @@ FROZEN FROZENSTEIN FUEGO FULL +FULL. FULMINATING FUNGAL FUR @@ -1088,6 +1330,8 @@ GAILE GAIN GAINED GALE +GAMBLE +GAME GAMMA GARB GARGANTUAN @@ -1108,9 +1352,12 @@ GEAR GEGLASH GELEB GEM +GEM. GEMMED +GENERAL GENERAL'S GENERATOR +GENERIC GERKE'S GERONIMO'S GESHEF @@ -1139,6 +1386,7 @@ GLACIER GLADIATOR'S GLADIUS GLAIVE +GLASS GLEAMSCYTHE GLIMMERING GLIMMERSHRED @@ -1164,6 +1412,8 @@ GOBLIN GODLY GOES GOLD +GOLD. +GOLD: GOLDEN GOLDSKIN GOLDSTRIKE @@ -1188,6 +1438,7 @@ GRAND GRANDE GRANDFATHER GRANDMASTER'S +GRANTED GRASP GRASSY GRAVE @@ -1202,6 +1453,7 @@ GREAVES GREED GREEN GREIZ +GREMLIN GREYFORM GRIEF GRIFFON @@ -1218,6 +1470,8 @@ GRIZZLY GROTESQUE GROUNDING GROUNDS +GROUPS +GROW GROWLER GRUMBLE GUARD @@ -1256,14 +1510,17 @@ HALLS HALO HAMMER HAND +HANDLE HANDS HANNAH HAPHET HARBINGER HARD +HARDCORE HARDY HAREM HARLEQUIN +HARLOT HARMFUL HARMONY HARNESS @@ -1281,6 +1538,7 @@ HATCHET HATE HATRED HAUBERK +HAVE HAVOC HAWK HAWKEYE @@ -1288,6 +1546,7 @@ HAWKMAIL HAZADE HAZE HAZY +HE HEAD HEADDRESS HEADGEAR @@ -1299,6 +1558,7 @@ HEALED HEALFDANE HEALING HEALS +HEALS: HEALTH HEART HEARTY @@ -1326,23 +1586,30 @@ HELLRACK HELLSLAYER HELLSPAWN HELM +HELM: HELMET HELMS +HELMS: HELP +HELP. HENGEST HEOROGAR HEPHASTO +HER HERALD HERALDIC HERB +HERE. HEREMOD HERMETIC +HERO HEROES HEW HEXFIRE HEXING HIBERNAL HIDDEN +HIDDEN. HIDE HIDING HIEROPHANT @@ -1355,8 +1622,11 @@ HIGHTOWER'S HILD HILLS HIRE +HIRE. +HIREABLES HIS HIT +HITS HNAEF HOBNAILS HOKU @@ -1386,7 +1656,10 @@ HORNED HORNS HORROR HORSE +HOSTILE +HOSTILITY HOTSPUR +HOURS HOWL HOWLER HOWLING @@ -1419,6 +1692,7 @@ I IANSANG'S IANTHA ICE +ICE. ICEBLINK ICEBOLT ICEFIST @@ -1429,16 +1703,22 @@ ICON ICY IDENTIFY IDIOT +IF IGNORE ILLUSION ILZAN IMBECILE +IMBUE +IMBUED? +IMMEDIATELY IMMOLATING IMMOLATION IMMORTAL IMMUNE IMMUNITY IMP +IMPACT +IMPACTS IMPALE IMPALER IMPALING @@ -1447,8 +1727,10 @@ IMPERIAL IMPROVED IN INCINERATION +INCLUDING INCREASE INCREASED +INCREASES INDESTRUCTIBLE INDIEGO'S INDIGO @@ -1467,12 +1749,15 @@ INFORMATION INIFUSS INNER INNOCENCE +INSANE INSERT +INSERTED INSIDIOUS INSIGHT INSULATION INTO INVADER +INVALID INVENTORY INVISIBILITY INVISO @@ -1484,18 +1769,25 @@ IRO IRON IRONSTONE IRRESISTIBLE +IS +IS: ISENHART'S ISLESTRIKE ISMAIL ISOLDE +ISSUE IST IT ITCHIES ITEM +ITEM. ITEMS +ITEMS. +ITEMS: ITH ITHERA ITONYA +ITS IVORY IZUAL IZUAL'S @@ -1524,16 +1816,20 @@ JERHYN JESTER'S JEWEL JEWELER'S +JEWELRY +JEWELRY. JO JOKER'S JORDAN JOURNAL +JOURNEY JOY JOYFULNESS JUDGEMENT JUG JUJUBE JUNGLE +JUST JUSTICE KAA KAELAN @@ -1551,6 +1847,8 @@ KEEPER'S KELPIE KENSHI'S KEY +KEYS +KEYS. KHALEEL KHALIM'S KHAN @@ -1582,6 +1880,7 @@ KNOCKBACK KNOT KNOUT KNOWLEDGE +KNOWN KNUCKLE KNUCKLES KO @@ -1596,8 +1895,10 @@ KURAST KYANON KYLE KYOKO +LABEL LACERATOR LACQUERED +LADDER LADEN LADY LAIR @@ -1609,13 +1910,16 @@ LANCE LANCER LANCER'S LANGER +LANGUAGE LANTH LAPIS LARGE LARRY +LARVA LARZUK LARZUK'S LASH +LASHER LAST LASTING LAVA @@ -1632,6 +1936,8 @@ LEAF LEAP LEAPER LEARN +LEARNED +LEAST LEATHER LEATHERS LEAVER @@ -1645,11 +1951,15 @@ LEGENDARY LEHARAS LEM LENGTH +LENGTH: LENYMO LEORIC LESSON LESTRON'S LEVEL +LEVEL) +LEVEL-UP +LEVEL: LEVELS LEVER LEVIATHAN @@ -1661,38 +1971,64 @@ LIDLESS LIEF LIENE LIFE +LIFE/MANA +LIFE: LIFECHOKE LIGHT LIGHTBRAND +LIGHTING LIGHTNING +LIGHTNING, +LIGHTNING: LIGHTSABRE +LIKE LILAC LILITH LILLY LIMB +LIMIT +LINE +LINK LINKED LION LIONHEART +LIST +LISTENING LISTER +LIVE +LIVE. LIZARD'S LO +LOAD +LOADING LOATH +LOBBY +LOCALLY +LOCATION, LOCHABER LOCK LOCKED LOCUST LOCUSTS LOG +LOGGED +LOGGING +LOGIN +LOGO LONG +LONGER LONGEST LOOK LOOM LOOP LOOSE +LOOT +LOOTED LORD LORD'S LORE LORICATED +LOSING LOST LOVE LOW @@ -1702,6 +2038,7 @@ LOYALTY LUCK LUCKY LUM +LUMINANCE LUNA LUNAR LUNATA @@ -1728,7 +2065,11 @@ MAGEWRATH MAGGOT MAGGOTS MAGI +MAGI: MAGIC +MAGIC, +MAGICALLY +MAGICKS MAGMA MAGNUS MAGNUS' @@ -1744,6 +2085,7 @@ MAIMING MAIN MAJESTIC MAJESTY +MAKE MAKER MAL MALAH @@ -1756,6 +2098,7 @@ MALUS MAMMOTH MAN MANA +MANA: MANALD MANCATCHER MANE @@ -1763,6 +2106,8 @@ MANG MANGLER MANIPULATOR MANTLE +MANY +MAP MAR MARA'S MARAUDER @@ -1779,6 +2124,7 @@ MASK MASSIVE MASTER MASTER'S +MASTERED MASTERIES MASTERPIECE MASTERY @@ -1789,13 +2135,18 @@ MAUL MAULER MAUSOLEUM MAW +MAX +MAX. +MAX: MAXIMUM +MAY MCAULEY'S MEASURE MEAT MEATSCRAPE MECHANIC'S MEDITATION +MEDIUM MEDUSA'S MEGHAN MELEE @@ -1808,12 +2159,18 @@ MENTALIST'S MENU MEPHISTO MEPHISTO'S +MERCENARIES +MERCENARIES. +MERCENARY +MERCENARY? MERCHANTS MERCILESS MERCY MERMAN'S MESH MESHIF +MESSAGE +MESSAGES MESSERSCHMIDT'S MET METALGRID @@ -1827,17 +2184,24 @@ MILITARY MIND MINIMUM MINION +MINIONS MINOR MINOTAUR +MINUTES. MIRRORED +MISC +MISS MISSHAPEN MISSILE MISSILES +MISSING MIST MITHRIL MITTS MIZAN MNEMONIC +MODE +MODES MOE MOJO MOLD @@ -1846,13 +2210,19 @@ MOLECH MOLTEN MONARCH MONASTERY +MONASTERY. MONK'S MONSTER +MONSTER: MONSTERS +MONSTERS: +MONTHS MONUMENTAL +MOO MOON MOONFALL MOONREND +MOOOOOOOO! MOOR MORDOC'S MORE @@ -1863,6 +2233,7 @@ MORTAL MOSER'S MOSQUITO MOUNT +MOUSE MOVE MUCH MULE @@ -1871,6 +2242,7 @@ MUMMIFIED MUMMY MUSCULAR MUSIC +MUST MUSTY MYRMIDON MYSTERY @@ -1882,26 +2254,36 @@ NAGAS NAGELRING NAILS NAJ'S +NAME +NAMED +NAMES NARPHET NATALYA NATALYA'S NATURAL NATURE'S +NATURE, NEAR +NEARBY NEBUCHADNEZZAR'S NECKLACE NECROMAGE NECROMANCER NECROMANCER'S NECROSKELETON +NEED +NEEDED NEEDLE NEERAJ NEF NEGATION +NEGLECTED NEGRA NEST NETHERCROW NEUTRAL +NEVER +NEW NEWS NEXT NICKEL @@ -1910,6 +2292,7 @@ NIGHTMARE NIGHTSMOKE NIGHTSUMMON NIGHTTIME +NIGHTTIME) NIGHTWING'S NIHLATHAK NIHLATHAK'S @@ -1918,6 +2301,7 @@ NO NOBILITY NOCK NOKOZAN +NONE NOOSE NORD'S NORMAL @@ -1926,7 +2310,9 @@ NOT NOVA NOW NOXIOUS +NPC NULL +NUMBER OAK OASIS OATH @@ -1940,10 +2326,13 @@ OBSIDIAN OCEAN OCHER OCULUS +ODDITY ODIFEROUS ODIUM OF +OFF OFFENSIVE +OFFER OGRE OGUN'S OHM @@ -1951,15 +2340,18 @@ OIL OLD OLENA OMNISCIENT -ON +ONCE ONDAL'S ONE ONE-HAND ONELA ONES ONLY +ONLY) OOZE OPEN +OPENS +OPTIMAL OR ORANGE ORB @@ -1974,14 +2366,21 @@ ORNATE ORPHAN'S ORT OSLAF +OTHER OTHERS +OUR +OUT OUTER OVER +OVERALL +OVERLORD +OVERRIDDEN OVERSEER OX PACING PAD PAGAN'S +PAGE PAIGE PAIN PALACE @@ -1999,9 +2398,12 @@ PASSAGE PASSION PASSIVE PAST +PATCH PATIENCE PATRIARCH PATTER +PATTERN +PAUSED PAVISE PAWS PEACE @@ -2012,26 +2414,37 @@ PELT PELTA PENETRATE PENITENCE +PEOPLE PER PERCENT PERFECT PERFECTION PERFORMANCE PERIL +PERMANENT +PERMANENT. PERMANENTLY PERNICIOUS PERPETUAL +PERSISTENT +PERSON +PERSONAL +PERSONALIZE +PERSONALIZED +PERSPECTIVE PESTILENCE PESTILENT PET PETRIFIED PETS +PETS: PHAET PHASE PHOENIX PHYSICAL PICK PICKET +PICKUP PIERCE PIERCING PIERRE @@ -2046,19 +2459,27 @@ PINDLESKIN PIT PITBLOOD PITSPAWN +PLACED PLAGUE PLAINS PLATE PLATEAU PLATED PLATINUM +PLAY +PLAYED PLAYER +PLAYER. +PLAYERS +PLAYERS. +PLAYERS: PLEDGE PLUCKEYE PLUS POIGNARD POINT POINTS +POINTS: POISON POLE POLEARM @@ -2066,8 +2487,11 @@ POLEAXE POLISHED POMPEII'S POPPY +PORT PORTAL PORTRAIT +PORTRAITS. +POSITION POSSESSED POTION POWER @@ -2080,6 +2504,7 @@ PRECISION PRECOCIOUS PRESERVED PRESERVER'S +PRESS PREVENT PREVIOUS PRICES @@ -2091,21 +2516,26 @@ PRISMATIC PRISON PRIVATE PROCEED +PROCESS PROD +PROFANE PROJECTOR PROLOGUE PROMISE +PROPERLY PROPOGATION PROSPERITY PROTECTION PROTECTOR PROWESS PROWLER +PROWLING PRUDENCE PSYCHIC PUKE PUL PULSE +PULSES PUNCTURING PUNISHING PUNISHMENT @@ -2120,18 +2550,25 @@ QUAL-KEHK QUAL-KHEK'S QUALITY QUANTITY +QUANTITY: QUARREL QUARTERSTAFF QUE-HEGAN'S QUEEN QUENCHING +QUEST +QUEST. QUESTION +QUESTS +QUESTS. +QUEUE QUHAB QUICK QUICKENING QUICKNESS QUILL QUILTED +QUIT QUIXOTIC QUOTA RABBIT @@ -2141,6 +2578,7 @@ RADAMENT RADAMENT'S RADIANCE RADIUS +RADIUS: RAGE RAGING RAGNAR @@ -2157,9 +2595,13 @@ RAKESCAR RAL RALDIN RANCID +RANGE: +RANGED RANGER RANK RAPTOR +RARE, +RASCAL RASHA RASHA'A RASHA'S @@ -2167,15 +2609,19 @@ RAT RAT'S RATCHEST RATE +RATE: RATING +RATING: RATMAN RATMEN RATTLE RATTLECAGE RAVEN RAVEN'S +RAVEN: RAVENLORE RAVENS +RAVENS: RAZAN RAZOR RAZOR'S @@ -2183,18 +2629,29 @@ RAZORS RAZORSWITCH RAZORTAIL RAZORTINE +REACH +REACHED READ READINESS REALGAR +REALM REANIMATE +REANIMATED REAPER REAPER'S REASON REAVER REBUKE +RECEIVE +RECEIVED. +RECEIVES +RECENTLY RECHARGE RECLUSIVE +RECOMMENDED +RECOVER RECOVERED +RECOVERED: RECOVERY RECTIFIER RED @@ -2206,42 +2663,82 @@ REDUCES REFILLING REFLECTION REFLEX +REFRESH +REFRESHING REFUGE REGALIA REGENERATE REGENERATION REGROWTH +REGULAR +REHIRE REIGN REINFORCED +REJECT +REJECTED REJUVENATION RELIC RELICS RELIGION RELIQUARY REMAINING +REMAINS REMEDY +REMEMBERED REMORSE +REMOVE +REMOVED. REND RENDER REPAIR +REPAIRED +REPAIRED) +REPAIRED), +REPAIRED. +REPAIRING +REPAIRS REPEATING +REPLACE REPLENISH REPLENISHES REPLENISHING +REPRESENT +REPRESENTS REPULSIVE +REQUEST +REQUEST. REQUIRED REQUIREMENTS +REQUIREMENTS. +REQUIRES RESCUE +RESCUED +RESERVED +RESERVED. +RESET RESILIENT RESIST RESISTANCE RESISTANCES +RESISTANCES: RESISTANT RESONANT +RESSURECTED REST RESTORATION RESTORE +RESTRICT +RESTRICTED +RESTRICTION +RESTRICTIONS +RESUME +RESURRECT +RESURRECT. +RESURRECTED RESURRECTION +RETRIEVING +RETRY +RETRY. RETURN RETURNED REVENGE @@ -2261,6 +2758,7 @@ RIFTWING RIFTWRAITH RIG RIGHT +RIGHT-CLICK RIGHTEOUS RING RINGS @@ -2270,6 +2768,7 @@ RIPRAP RIPSAW RISING RITE +RITUAL RIVER RIXOT'S ROBE @@ -2288,6 +2787,7 @@ ROGUE ROGUE'S RONDACHE RONDEL +ROOM ROSE ROT ROTTING @@ -2299,6 +2799,7 @@ RUDE RUGGED RUINED RULE +RUN RUN/WALK RUNE RUNES @@ -2310,6 +2811,7 @@ RUSTY RYANN SABER SABOT +SABOTAGE SABRE SACRED SACRIFICE @@ -2319,6 +2821,8 @@ SAINTLY SALAMANDER SALLET SALVATION +SAME +SAME. SAMUEL'S SAMURAI SANCTUARY @@ -2336,6 +2840,7 @@ SARINA SASH SAVAGE SAW +SAY SAZABI'S SCALE SCALES @@ -2348,6 +2853,7 @@ SCARLET SCAVENGER SCEPTER SCHAEFER'S +SCHOOLED SCIMITAR SCINTILLATING SCIROCCO @@ -2359,6 +2865,7 @@ SCOUT SCRAPER SCRATCH SCREAMING +SCREEN SCROLL SCROLLS SCUTUM @@ -2368,15 +2875,25 @@ SEAL SEARCH SEARING SEC +SEC. SECOND SECONDS SECRET +SECURE SEE +SEEKER SEETHE +SEIGE SEIS +SELECT +SELECTED +SELF SELF-REPAIR SELL +SEND +SEND. SENSEI'S +SENT SENTINEL SENTRY SEPTIC @@ -2387,9 +2904,13 @@ SERPENT SERPENT'S SERPENTSKIN SERRATED +SERVICE +SET SEVEN SEVENTH SEVER +SEVERAL +SEVERE SEWER SEWERS SEXTON @@ -2410,18 +2931,25 @@ SHANK SHAPE SHAPE-SHIFTING SHARD +SHARED SHARKSKIN SHARKTOOTH SHARP +SHARPENING SHARPTOOTH SHARYN SHATTER +SHE SHEATH SHELL SHELTER SHENK SHIELD +SHIELD'S +SHIELD: SHIELDS +SHIELDS: +SHIFT SHIFTER SHIFTING SHIKHA @@ -2436,6 +2964,7 @@ SHOOTS SHORT SHOT SHOTS +SHOULD SHOUT SHOW SHREWD @@ -2443,6 +2972,7 @@ SHRINE SHROUD SHRUB SICKLE +SIDE. SIEGE SIGEMUND SIGGARD'S @@ -2463,17 +2993,25 @@ SIN SINBLADE SINEW SINGING +SINISTER SIPHON +SIREN SIREN'S +SISTER'S SIX SIZE +SIZE: SKELETAL SKELETON +SKELETONS +SKELETONS: SKEWER SKILL +SKILLED SKILLFUL SKILLS SKIN +SKIP SKULL SKULLDER'S SKULLPILE @@ -2482,19 +3020,24 @@ SKULLTRED SKY SKYSTRIKE SLAIN +SLAIN. SLASHER SLASHERS SLAUGHTER SLAYER SLAYER'S SLAYING +SLAYING: SLIGHTLY SLIME SLINGER SLIPPERS +SLOTS SLOW +SLOWED SLOWER SLOWEST +SLOWING SLOWS SLUDGE SMALL @@ -2519,21 +3062,29 @@ SNOT SNOW SNOWCLASH SNOWY +SO +SOCIAL SOCKET SOCKETED +SOCKETED, SOCKETS +SOCKETS. SOL SOLAR SOLD SOLDIER SOLDIER'S SOLDIERS +SOLO +SOMETHING SONG SONG'S SORCERESS SORCERY SORROW +SORT SOUL +SOUL: SOULFEAST SOULFLAY SOULLESS @@ -2542,6 +3093,9 @@ SOULSTONE SOUND SOUNDING SOURCE +SPACE +SPACING +SPANISH SPARKFIST SPARKING SPARKLING @@ -2552,10 +3106,15 @@ SPEAK SPEAR SPEARMAIDEN'S SPEARWOMAN +SPECIAL SPECTER SPECTRAL +SPEECH SPEED +SPEED, +SPEED: SPELL +SPELLS SPELLSTEEL SPETUM SPHERE @@ -2566,6 +3125,7 @@ SPIKE SPIKED SPIKEFIST SPIKES +SPIKES: SPINE SPINERIPPER SPINNER @@ -2583,9 +3143,12 @@ SPLENDOR SPLINT SPLITTER SPOT +SPREAD SPRINKLER +SPRITE SPROCKET SPUR +SQUARES SQUID SQUIRE'S SSZARK @@ -2593,6 +3156,7 @@ STABILITY STACK STAFF STAG +STAINED STAIR STAIRS STAKE @@ -2600,22 +3164,33 @@ STALAGMITE STALKER STALWART STAMINA +STAMINA: STAND STANDARD STAR STARE STARLIGHT STARS +STARS: STASH +STASH. +STASH: STAT +STAT/SKILL +STATE STATIC +STATS STATURE +STATUS STAY STEAL +STEAL: +STEALER STEALING STEALS STEALSKULL STEALTH +STEED STEEL STEELCLASH STEELDRIVER @@ -2637,6 +3212,8 @@ STONERAVEN STONES STONY STOP +STORED +STORES STORM STORMCHASER STORMEYE @@ -2659,18 +3236,26 @@ STRANGLING STRAP STREAM STRENGTH +STRENGTH: STRENGTHENING STRIKE STRIKER +STRIKING STRING STRONG STRONGER +STRONGER. +STRUCK STUDDED +STUFF STUMP STUN +STUN: STURDY +STUTTERS STYGIAN SUCCUBUS +SUCH SUCKER SUFFERING SUICIDE @@ -2680,6 +3265,7 @@ SUMMON SUMMONER SUMMONER'S SUMMONING +SUMMONS SUN SUNDAN SUNDER @@ -2689,6 +3275,7 @@ SUPER SUPERIOR SUPERSTITION SUR +SURE SURESHRILL SUSTENANCE SUWAYYAH @@ -2702,12 +3289,12 @@ SWIFTNESS SWING SWINGING SWIRLING +SWITCH SWORD SWORDBACK SWORDGUARD SWORDS SYMBOL -SZ TABAR TABOO TAEBAEK'S @@ -2716,6 +3303,8 @@ TAINTBREEDER TAINTED TAKE TAKEN +TAKEN. +TAKEN: TAKES TAL TALBERD'S @@ -2734,6 +3323,8 @@ TAP TARGE TARGET TARGET'S +TARGET: +TARGETS TARNHELM TAUNT TEACHING @@ -2746,6 +3337,7 @@ TELEKINESIS TELEPORT TELEPORTATION TELLING +TELLS TEMPER TEMPEST TEMPLAR @@ -2756,17 +3348,28 @@ TEMPTATION TEMPTRESS TENDERIZER TENET +TERMINAL TERRA'S TERRENE TERROR TERROR'S THADAR +THAN +THANK THARR THAT +THAT, +THAT. THAW THAWING THE +THEIR +THEM? +THEN THEODORIC +THERE +THESE +THEY THIEF THIEVES THIN @@ -2775,8 +3378,12 @@ THIS THORN THORNED THORNS +THOSE THOUGHT THRASHER +THREATENING +THREATENS +THREATS THREE THRESH THRESHER @@ -2794,6 +3401,7 @@ TIARA TIGER TIGULATED TIME +TIME: TIMELESS TIMES TIN @@ -2805,6 +3413,8 @@ TITAN'S TO TODESFAELLE TOE +TOGGLE +TOGGLES TOKEN TOLL TOMAHAWK @@ -2812,7 +3422,9 @@ TOMB TOMBALE TOMBS TOME +TOME. TONGUE +TOO TOOLS TOORC TOOTH @@ -2827,6 +3439,7 @@ TORMENTOR TORNADO TORQUER TOSTIG +TOTAL TOTE TOTEM TOTEMIC @@ -2836,8 +3449,13 @@ TOWER TOWN TOWNPORTAL TOWNSFOLK +TOWNSPEOPLE TOXIC TRACK +TRADE +TRADE/REPAIR +TRADED +TRADED. TRADITION TRAIL TRAINER'S @@ -2857,6 +3475,7 @@ TREACHERY TREAD TREADS TREE +TREE. TREEHEAD TREENTSTER TREK @@ -2865,8 +3484,10 @@ TRIAD'S TRIBAL TRIBUTE TRICKS +TRICKSTER TRICKSTER'S TRIDENT +TRIED TRISTRAM TRIUMPHANT TROLL @@ -2875,21 +3496,26 @@ TRUE TRUNCHEON TRUST TRUTH +TRY TRYNEUS TULWAR TUNDRA TUNNELS TURN TURQUOISE +TURRET TUSK TWILIGHT TWIN TWISTED TWISTER TWITCHTHROE +TWO TWO-HAND TWO-HANDED TYLENA +TYPE +TYPING TYRAEL TYRAEL'S TYRANT @@ -2897,46 +3523,66 @@ TYREAL TYREAL'S ULF ULRIC +ULTRA UM UMBRAL UME'S +UNABLE +UNAVAILABLE UNBENDING UNCLEAN UNDEAD +UNDEAD: UNDEFILED UNDER UNDERGROUND UNEARTHED UNEARTHLY +UNEQUALED UNFERTH UNHOLY UNICORN UNIDENTIFIED +UNINTERRUPTABLE: +UNIQUE, +UNKNOWN UNLEASHED UNRAVELER UNRAVELLER +UNSAFE. UNSUMMON +UNTIL +UNUSED UP +UPON UPPER URDAR URGENT URN +US USE +USED +USING UTHER VALHALLA +VALID VALKYRIE VALKYRIE'S VALLEY VALOR +VALUE +VALUE: VAMBRACES VAMPIRE VAMPIREBONE VAMPIREFANG VANJI +VANQUISHED VARAYA VASE VAUGHT VEIL +VELOCITY: VENDOR VENGEANCE VENGENCE @@ -2944,8 +3590,11 @@ VENOM VENOMOUS VENTAR VERDUNGO'S +VERIFY VERMILION +VERSATILE VERSUS +VERTICAL VERY VESTIGE VESTMENTS @@ -2957,6 +3606,7 @@ VICTOR VICTORIOUS VICTORY VIDALA'S +VIEW VIGIL VIGOR VIGOROUS @@ -2981,6 +3631,7 @@ VISALA VISCERATUANT VISION VISIONARY +VISIT VISOR VITA VITAL @@ -2989,6 +3640,7 @@ VIVID VIZIER VIZJEREI VOICE +VOICES VOID VOIDBRINGER VOLCANIC @@ -2997,14 +3649,20 @@ VOMIR VORTEX VOULGE VS +VS. VULPINE VULTURE WACKER WAHEED WAIL WAILING +WAIT +WAITING +WAITING. WAKE +WALK WALK/RUN +WALKER WALKING WALKS WALL @@ -3014,6 +3672,7 @@ WAND WANDERER WANDERER'S WANG +WANT WAR WARCRIES WARCRY @@ -3026,14 +3685,18 @@ WARHOUND WARLORD'S WARMING WARMTH +WARNING: WARP WARPED +WARPS WARPSPEAR WARRIOR WARRIOR'S +WARRIOR. WARRIV WARRIV'S WARSHRIKE +WAS WASTE WATCH WATCHER @@ -3043,10 +3706,17 @@ WATERWALK WAVE WAY WAYPOINT +WAYPOINTS WEAKEN +WEAKEN. +WEAKENS WEALTH WEAPON +WEAPON: WEAPONS +WEAPONS, +WEAPONS. +WEAPONS: WEAVER WEB WEDDING @@ -3054,14 +3724,20 @@ WEDER WEIRD WELL WENDY +WERE WEREBEAR WEREWOLF WHALE +WHAT +WHEEL WHEN +WHICH +WHIP WHIRLWIND WHISPER WHITE WHITSTAN'S +WHO WHORL WICKED WIDOW @@ -3086,6 +3762,7 @@ WIRED WIRT'S WISDOM WISH +WISH. WISP WITCH WITCH-HUNTER'S @@ -3100,18 +3777,23 @@ WIZENDRAW WOE WOESTAVE WOLF +WOLF: WOLFHOWL WOLFRIDER WOLVERINE WOLVES +WOLVES: WONDER WOOD WOODEN WOODFIST +WORLD +WORLD. WORLDSTONE WORM WORMSKULL WORTH +WOULD WOUND WOUNDS WRACK @@ -3123,6 +3805,8 @@ WRAPS WRATH WRETCHED WRIST +WRITE +WRONG WULF WULFGAR WULFSTAN @@ -3133,15 +3817,24 @@ WYRMHIDE WYVERN'S XENOS YAGGAI +YARD YARDS YARI YASHIED YATIRAJ YELLING +YELLOW +YES +YESTERDAY +YET YETI YEW YOLK YOU +YOU'VE +YOU, +YOU. +YOU: YOUNG YOUR YOUTH @@ -3156,4 +3849,5 @@ ZEPHYR ZIRCON ZOD ZOMBIE +ZONES ZWEIHANDER \ No newline at end of file diff --git a/assets/word_lists/base_items.txt b/assets/word_lists/base_items.txt new file mode 100644 index 000000000..0bb38bff5 --- /dev/null +++ b/assets/word_lists/base_items.txt @@ -0,0 +1,647 @@ +AEGIS +AERIN SHIELD +AKARAN RONDACHE +AKARAN TARGE +ALPHA HELM +ANCIENT ARMOR +ANCIENT SHIELD +ANTLERS +ARCHON PLATE +ARMET +ASSAULT HELMET +AVENGER GUARD +BALROG SKIN +BARBED SHIELD +BASINET +BATTLE BELT +BATTLE BOOTS +BATTLE GAUNTLETS +BELT +BLADE BARRIER +BLOOD SPIRIT +BLOODLORD SKULL +BONE HELM +BONE SHIELD +BONE VISAGE +BONEWEAVE +BONEWEAVE BOOTS +BOOTS +BRAMBLE MITTS +BREAST PLATE +BUCKLER +CANTOR TROPHY +CAP +CARNAGE HELM +CASQUE +CHAIN BOOTS +CHAIN GLOVES +CHAIN MAIL +CHAOS ARMOR CIRCLET +COLOSSUS GIRDLE +CONQUEROR CROWN +CORONA +CORONET +CROWN +CROWN SHIELD +CRUSADER GAUNTLETS +CUIRASS +DEATH MASK +DEFENDER +DEMON HEAD +DEMONHEAD +DEMONHIDE ARMOR +DEMONHIDE BOOTS +DEMONHIDE GLOVES +DEMONHIDE SASH +DESTROYER HELM +DIADEM +DIAMOND MAIL +DRAGON SHIELD +DREAM SPIRIT +DUSK SHROUD +EARTH SPIRIT +EMBOSSED PLATE +FALCON MASK +FANGED HELM +FETISH TROPHY +FIELD PLATE +FULL HELM +FULL PLATE MAIL +FURY VISOR +GARGOYLE HEAD +GAUNTLETS +GHOST ARMOR +GIANT CONCH +GILDED SHIELD +GOTHIC PLATE +GOTHIC SHIELD +GRAND CROWN +GREAT HAUBERK +GREAT HELM +GREAVES +GRIFFON HEADDRESS +GRIM HELM +GRIM SHIELD +GUARDIAN CROWN +HARD LEATHER ARMOR +HAWK HELM +HEATER +HEAVY BELT +HEAVY BOOTS +HEAVY BRACERS +HEAVY GLOVES +HELLFORGE PLATE +HELLSPAWN SKULL +HELM +HERALDIC SHIELD +HIEROPHANT TROPHY +HORNED HELM +HUNTER'S GUISE +HYDRASKULL +HYPERION +JAWBONE CAP +JAWBONE VISOR +KITE SHIELD +KRAKEN SHELL +KURAST SHIELD +LACQUERED PLATE +LARGE SHIELD +LEATHER ARMOR +LEATHER GLOVES +LIGHT BELT +LIGHT GAUNTLETS +LIGHT PLATE +LIGHT PLATED BOOTS +LINKED MAIL +LION HELM +LORICATED MAIL +LUNA +MAGE PLATE +MASK +MESH ARMOR +MESH BELT +MESH BOOTS +MINION SKULL +MIRRORED BOOTS +MITHRIL COIL +MONARCH +MUMMIFIED TROPHY +MYRMIDON GREAVES +OGRE GAUNTLETS +ORNATE PLATE +OVERSEER SKULL +PAVISE +PLATE MAIL +PLATED BELT +PRESERVED HEAD +PROTECTOR SHIELD +QUILTED ARMOR +RAGE MASK +RING MAIL +RONDACHE +ROUND SHIELD +ROYAL SHIELD +RUSSET ARMOR +SACRED ARMOR +SACRED FEATHERS +SACRED RONDACHE +SACRED TARGE +SALLET +SASH +SAVAGE HELMET +SCALE MAIL +SCARAB HUSK +SCARABSHELL BOOTS +SCUTUM +SERPENTSKIN ARMOR +SEXTON TROPHY +SHADOW PLATE +SHAKO +SHARKSKIN BELT +SHARKSKIN BOOTS +SHARKSKIN GLOVES +SHARKTOOTH ARMOR +SKULL CAP +SKY SPIRIT +SLAYER GUARD +SMALL SHIELD +SPIDERWEB SASH +SPIKED SHIELD +SPIRED HELM +SPIRIT MASK +SPLINT MAIL +STUDDED LEATHER +SUCCUBUS SKULL +SUN SPIRIT +TARGE +TEMPLAR COAT +TIARA +TIGULATED MAIL +TOTEMIC MASK +TOWER SHIELD +TRELLISED ARMOR +TROLL BELT +TROLL NEST +UNRAVELLER HEAD +VAMBRACES +VAMPIREBONE GLOVES +VAMPIREFANG BELT +VORTEX SHIELD +ZAKARUM SHIELD +ZOMBIE HEAD +ANCIENT AXE +ANCIENT SWORD +ARBALEST +ARCHON STAFF +ASHWOOD BOW +ATAGHAN +AXE +BALANCED AXE +BALANCED KNIFE +BALLISTA +BALROG BLADE +BALROG SPEAR +BARBED CLUB +BARDICHE +BASTARD SWORD +BATTLE AXE +BATTLE CESTUS +BATTLE DART +BATTLE HAMMER +BATTLE SCYTHE +BATTLE STAFF +BATTLE SWORD +BEARDED AXE +BEC-DE-CORBIN +BERSERKER AXE +BILL +BLADE +BLADE BOW +BLADE TALONS +BONE KNIFE +BONE WAND +BRANDISTOCK +BROAD AXE +BROAD SWORD +BURNT WAND +CADUCEUS +CEDAR BOW +CEDAR STAFF +CEREMONIAL BOW +CEREMONIAL JAVELIN +CEREMONIAL PIKE +CEREMONIAL SPEAR +CESTUS +CHAMPION AXE +CHAMPION SWORD +CHOKING GAS POTION +CHU-KO-NU +CINQUEDEAS +CLASPED ORB +CLAWS +CLAYMORE +CLEAVER +CLOUDY SPHERE +CLUB +COLOSSUS BLADE +COLOSSUS CROSSBOW +COLOSSUS SWORD +COLOSSUS VOULGE +COMPOSITE BOW +CONQUEST SWORD +CROSSBOW +CROWBILL +CRUSADER BOW +CRYPTIC AXE +CRYPTIC SWORD +CRYSTAL SWORD +CRYSTALLINE GLOBE +CUDGEL +CUTLASS +DACIAN FALX +DAGGER +DECAPITATOR +DECOY GIDBINN +DEMON CROSSBOW +DEMON HEART +DEVIL STAR +DIAMOND BOW +DIMENSIONAL BLADE +DIMENSIONAL SHARD +DIRK +DIVINE SCEPTER +DOUBLE AXE +DOUBLE BOW +EAGLE ORB +EDGE BOW +ELDER STAFF +ELDRITCH ORB +ELEGANT BLADE +ESPANDON +ETTIN AXE +EXECUTIONER SWORD +EXPLODING POTION +FALCATA +FALCHION +FANGED KNIFE +FASCIA +FERAL AXE +FERAL CLAWS +FLAIL +FLAMBERGE +FLANGED MACE +FLYING AXE +FLYING KNIFE +FRANCISCA +FULMINATING POTION +FUSCINA +GHOST GLAIVE +GHOST SPEAR +GHOST WAND +GIANT AXE +GIANT SWORD +GIANT THRESHER +GLADIUS +GLAIVE +GLORIOUS AXE +GLOWING ORB +GNARLED STAFF +GORGON CROSSBOW +GOTHIC AXE +GOTHIC BOW +GOTHIC STAFF +GOTHIC SWORD +GRAND MATRON BOW +GRAND SCEPTER +GRAVE WAND +GREAT AXE +GREAT BOW +GREAT MAUL +GREAT PILUM +GREAT POLEAXE +GREAT SWORD +GREATER CLAWS +GREATER TALONS +GRIM SCYTHE +GRIM WAND +HALBERD +HAND AXE +HAND SCYTHE +HARPOON +HATCHET +HATCHET HANDS +HEAVENLY STONE +HEAVY CROSSBOW +HELL FORGE HAMMER +HIGHLAND BLADE +HOLY WATER SPRINKLER +HORADRIC MALUS +HORADRIC STAFF +HUNTER'S BOW +HURLBAT +HYDRA BOW +HYDRA EDGE +HYPERION JAVELIN +HYPERION SPEAR +JAGGED STAR +JARED'S STONE +JAVELIN +JO STAFF +KATAR +KHALIM'S FLAIL +KHALIM'S WILL +KNOUT +KRIS +LANCE +LARGE AXE +LARGE SIEGE BOW +LEGEND SPIKE +LEGEND SWORD +LEGENDARY MALLET +LICH WAND +LIGHT CROSSBOW +LOCHABER AXE +LONG BATTLE BOW +LONG BOW +LONG STAFF +LONG SWORD +LONG WAR BOW +MACE +MAIDEN JAVELIN +MAIDEN PIKE +MAIDEN SPEAR +MANCATCHER +MARTEL DE FER +MATRIARCHAL BOW +MATRIARCHAL JAVELIN +MATRIARCHAL PIKE +MATRIARCHAL SPEAR +MAUL +MIGHTY SCEPTER +MILITARY AXE +MILITARY PICK +MITHRIL POINT +MORNING STAR +MYTHICAL SWORD +NAGA +OGRE AXE +OGRE MAUL +OIL POTION +PARTIZAN +PELLET BOW +PETRIFIED WAND +PHASE BLADE +PIKE +PILUM +POIGNARD +POLEAXE +POLISHED WAND +QUARTERSTAFF +QUHAB +RANCID GAS POTION +RAZOR BOW +REFLEX BOW +REINFORCED MACE +REPEATING CROSSBOW +RONDEL +RUNE BOW +RUNE SCEPTER +RUNE STAFF +RUNE SWORD +RUNIC TALONS +SABRE +SACRED GLOBE +SCEPTER +SCIMITAR +SCISSORS KATAR +SCISSORS QUHAB +SCISSORS SUWAYYAH +SCOURGE +SCYTHE +SERAPH ROD +SHADOW BOW +SHAFT OF THE HORADRIC STAFF +SHAMSHIR +SHILLELAGH +SHORT BATTLE BOW +SHORT BOW +SHORT SIEGE BOW +SHORT SPEAR +SHORT STAFF +SHORT SWORD +SHORT WAR BOW +SIEGE CROSSBOW +SILVER-EDGED AXE +SIMBILAN +SMALL CRESCENT +SMOKED SPHERE +SPARKLING BALL +SPEAR +SPETUM +SPICULUM +SPIDER BOW +SPIKED CLUB +STAG BOW +STALAGMITE +STILETTO +STRANGLING GAS POTION +STYGIAN PIKE +STYGIAN PILUM +SUWAYYAH +SWIRLING CRYSTAL +TABAR +THE GIDBINN +THRESHER +THROWING AXE +THROWING KNIFE +THROWING SPEAR +THUNDER MAUL +TOMAHAWK +TOMB WAND +TRIDENT +TRUNCHEON +TULWAR +TUSK SWORD +TWIN AXE +TWO-HANDED SWORD +TYRANT CLUB +UNEARTHED WAND +VORTEX ORB +VOULGE +WALKING STICK +WAND +WAR AXE +WAR CLUB +WAR DART +WAR FIST +WAR FORK +WAR HAMMER +WAR JAVELIN +WAR PIKE +WAR SCEPTER +WAR SCYTHE +WAR SPEAR +WAR SPIKE +WAR STAFF +WAR SWORD +WARD BOW +WINGED AXE +WINGED HARPOON +WINGED KNIFE +WIRT'S LEG +WRIST BLADE +WRIST SPIKE +WRIST SWORD +YARI +YEW WAND +ZWEIHANDER +A JADE FIGURINE +AMETHYST +AMN RUNE +AMULET +ANTIDOTE POTION +ARROWS +BAAL'S EYE +BER RUNE +BOLTS +BRAIN +BURNING ESSENCE OF TERROR +CHAM RUNE +CHARGED ESSENCE OF HATRED +CHIPPED AMETHYST +CHIPPED DIAMOND +CHIPPED EMERALD +CHIPPED RUBY +CHIPPED SAPPHIRE +CHIPPED SKULL +CHIPPED TOPAZ +DIABLO'S HORN +DIAMOND +DOL RUNE +EAR +EL RUNE +ELD RUNE +ELIXIR +EMERALD +ETH RUNE +EYE +FAL RUNE +FANG +FESTERING ESSENCE OF DESTRUCTION +FLAG +FLAWED AMETHYST +FLAWED DIAMOND +FLAWED EMERALD +FLAWED RUBY +FLAWED SAPPHIRE +FLAWED SKULL +FLAWED TOPAZ +FLAWLESS AMETHYST +FLAWLESS DIAMOND +FLAWLESS EMERALD +FLAWLESS RUBY +FLAWLESS SAPPHIRE +FLAWLESS SKULL +FLAWLESS TOPAZ +FULL REJUVENATION POTION +GOLD +GRAND CHARM +GREATER HEALING POTION +GREATER MANA POTION +GUL RUNE +HEALING POTION +HEART +HEL RUNE +HERB +HORADRIC CUBE +HORADRIC SCROLL +HORN +IO RUNE +IST RUNE +ITH RUNE +JAH RUNE +JAWBONE +JEWEL +KEY +KEY OF DESTRUCTION +KEY OF HATE +KEY OF TERROR +KEY TO THE CAIRN STONES +KHALIM'S BRAIN +KHALIM'S EYE +KHALIM'S HEART +KO RUNE +LAM ESEN'S TOME +LARGE CHARM +LEM RUNE +LIGHT HEALING POTION +LIGHT MANA POTION +LO RUNE +LUM RUNE +MAL RUNE +MANA POTION +MEPHISTO'S BRAIN +MEPHISTO'S SOULSTONE +MINOR HEALING POTION +MINOR MANA POTION +NEF RUNE +OHM RUNE +ORT RUNE +PERFECT AMETHYST +PERFECT DIAMOND +PERFECT EMERALD +PERFECT RUBY +PERFECT SAPPHIRE +PERFECT SKULL +PERFECT TOPAZ +PUL RUNE +QUILL +RAL RUNE +REJUVENATION POTION +RING +RUBY +SAPPHIRE +SCALP +SCROLL OF IDENTIFY +SCROLL OF INIFUSS +SCROLL OF KNOWLEDGE +SCROLL OF TOWN PORTAL +SHAEL RUNE +SKULL +SMALL CHARM +SOL RUNE +SOUL +SPLEEN +STAMINA POTION +STANDARD OF HEROES +SUPER HEALING POTION +SUPER MANA POTION +SUR RUNE +TAIL +TAL RUNE +THAWING POTION +THE BLACK TOWER KEY +THE GOLDEN BIRD +THUL RUNE +TIR RUNE +TOME OF IDENTIFY +TOME OF TOWN PORTAL +TOP OF THE HORADRIC STAFF +TOPAZ +TORCH +TWISTED ESSENCE OF SUFFERING +UM RUNE +VEX RUNE +ZOD RUNE +CHAOS ARMOR +CIRCLET +WAR BELT +WAR BOOTS +WAR GAUNTLETS +WAR HAT +WARD +WINGED HELM +WIRE FLEECE +WOLF HEAD +WYRMHIDE +WYRMHIDE BOOTS \ No newline at end of file diff --git a/assets/word_lists/magic_prefixes.txt b/assets/word_lists/magic_prefixes.txt new file mode 100644 index 000000000..da7a72f5d --- /dev/null +++ b/assets/word_lists/magic_prefixes.txt @@ -0,0 +1,613 @@ +LOWQUALITY +DAMAGED +CRACKED +SUPERIOR +GEMMED +RESILIENT +STURDY +STRONG +GLORIOUS +BLESSED +SAINTLY +HOLY +DEVIOUS +FORTIFIED +URGENT +FLEET +MUSCULAR +JAGGED +DEADLY +VICIOUS +BRUTAL +MASSIVE +SAVAGE +MERCILESS +VULPINE +SWIFT +ARTFUL +ADROIT +TIRELESS +RUGGED +BRONZE +IRON +STEEL +SILVER +GOLD +PLATINUM +METEORIC +SHARP +FINE +WARRIORS +SOLDIERS +KNIGHTS +LORDS +KINGS +HOWLING +FORTUITOUS +BRILLIANT +OMNISCIENT +SAGE +SHREWD +VIVID +GLIMMERING +GLOWING +BRIGHT +SOLAR +LIZARDS +FORCEFUL +SNAKES +SERPENTS +DRAKES +DRAGONS +WYRMS +DAZZLING +FASCINATING +PRISMATIC +AZURE +LAPIS +COBALT +INDIGO +SAPPHIRE +CERULEAN +RED +CRIMSON +BURGUNDY +GARNET +RUSSET +RUBY +VERMILION +ORANGE +OCHER +TANGERINE +CORAL +CRACKLING +AMBER +FORKED +BERYL +JADE +VIRIDIAN +VITAL +EMERALD +ENDURING +FLETCHERS +ARCHERS +MONKS +PRIESTS +SUMMONERS +NECROMANCERS +ANGELS +ARCH-ANGELS +SLAYERS +BERSERKERS +KICKING +TRIUMPHANT +MIGHTY +ENERGIZING +EMPOWERING +BRISK +TOUGH +HARDY +ROBUST +GOLD +SAPPHIRE +EMERALD +RUBY +DIAMOND +BEAST +EAGLE +VIPER +SKULL +BLOOD +DREAD +DOOM +GRIM +BONE +DEATH +SHADOW +STORM +RUNE +PLAGUE +STONE +SPIRIT +DEMON +CRUEL +EMPYRIAN +BRAMBLE +PAIN +LOATH +GLYPH +HAILSTONE +GALE +DIRE +SOUL +BRIMSTONE +CORPSE +CARRION +HAVOC +BITTER +ENTROPY +CHAOS +ORDER +RIFT +CORRUPTION +BITE +SCRATCH +SCALPEL +FANG +GUTTER +THIRST +RAZOR +SCYTHE +EDGE +SPLITTER +CLEAVER +SEVER +SUNDER +REND +MANGLER +SLAYER +REAVER +SPAWN +GNASH +STAR +BLOW +SMASHER +BANE +BREAKER +GRINDER +CRACK +MALLET +KNELL +LANCE +SPIKE +IMPALER +SKEWER +PROD +SCOURGE +WAND +WRACK +BARB +NEEDLE +DART +BOLT +QUARREL +FLETCH +FLIGHT +NOCK +HORN +STINGER +QUILL +GOAD +BRANCH +SPIRE +SONG +CALL +SPELL +CHANT +WEAVER +GNARL +CIVERBS +HSARUS +CLEGLAWS +IRATHAS +ISENHARTS +VIDALAS +MILABREGAS +CATHANS +TANCREDS +SIGONS +INFERNAL +DEATHS +ANGELIC +ARCTIC +ARCANNAS +WEIRD +GLOOM +GRAY +DIRE +BLACK +SHADOW +HAZE +WIND +STORM +WARP +NIGHT +MOON +STAR +PIT +FLAME +ICE +SEETHE +SHARP +ASH +BLADE +STEEL +STONE +RUST +MOLD +BLIGHT +PLAGUE +ROT +OOZE +PUKE +SNOT +BILE +BLOOD +PULSE +GUT +GORE +FLESH +BONE +SPINE +MIND +SPIRIT +SOUL +WRATH +GRIEF +FOUL +VILE +SIN +CHAOS +DREAD +DOOM +BANE +DEATH +VIPER +DRAGON +DEVIL +TOUCH +SPELL +FEAST +WOUND +GRIN +MAIM +HACK +BITE +REND +BURN +RIPPER +KILL +CALL +VEX +JADE +WEB +SHIELD +KILLER +RAZOR +DRINKER +SHIFTER +CRAWLER +DANCER +BENDER +WEAVER +EATER +WIDOW +MAGGOT +SPAWN +WIGHT +GRUMBLE +GROWLER +SNARL +WOLF +CROW +RAVEN +HAWK +CLOUD +BANG +HEAD +SKULL +BROW +EYE +MAW +TONGUE +FANG +HORN +THORN +CLAW +FIST +HEART +SHANK +SKIN +WING +POX +FESTER +BLISTER +PUS +SLIME +DROOL +FROTH +SLUDGE +VENOM +POISON +BREAK +SHARD +FLAME +MAUL +THIRST +LUST +THEHAMMER +THEAXE +THESHARP +THEJAGGED +THEFLAYER +THESLASHER +THEIMPALER +THEHUNTER +THESLAYER +THEMAULER +THEDESTROYER +THEQUICK +THEWITCH +THEMAD +THEWRAITH +THESHADE +THEDEAD +THEUNHOLY +THEHOWLER +THEGRIM +THEDARK +THETAINTED +THEUNCLEAN +THEHUNGRY +THECOLD +CHAMPION +VALKYRIES +MAIDENS +VOID +FANATIC +BERSERKER +STOUT +ANTIMAGIC +NULL +GODLY +IVORY +EBURINE +BLANCHED +STALWART +BURLY +DENSE +THIN +COMPACT +WITCH-HUNTERS +MAGEKILLERS +HIEROPHANTS +SHAMANS +PESTILENT +TOXIC +CORROSIVE +FOUL +SEPTIC +SHOCKING +ARCING +BUZZING +STATIC +CONDENSING +FLAMING +SMOKING +SMOLDERING +FIERY +HIBERNAL +BOREAL +SHIVERING +SNOWY +MNEMONIC +VISIONARY +EAGLEEYE +HAWKEYE +FALCONEYE +SPARROWEYE +ROBINEYE +PARADOX +HOWLING +YELLING +CALLING +ALARMING +FOOLS +JOKERS +JESTERS +JACKS +KNAVES +FAITHFUL +RIGHTEOUS +HONORABLE +ENLIGHTENED +KENSHIS +SENSEIS +SHOGUKUSHAS +PSYCHIC +MENTALISTS +CUNNING +TRICKSTERS +ENTRAPPING +GAEAN +TERRENE +NATURAL +COMMUNAL +FERAL +SPIRITUAL +KEEPERS +CARETAKERS +TRAINERS +VETERANS +EXPERTS +FURIOUS +RAGING +ECHOING +RESONANT +SOUNDING +GUARDIANS +WARDENS +PRESERVERS +MARSHALS +COMMANDERS +CAPTAINS +ROSEBRANDED +HAWKBRANDED +LIONBRANDED +GOLEMLORDS +MOJO +GRAVEROBBERS +VENOMOUS +NOXIOUS +FUNGAL +CURSING +BLIGHTING +HEXING +GLACIAL +FREEZING +CHILLING +POWERED +CHARGED +SPARKING +VOLCANIC +BLAZING +BURNING +LANCERS +SPEARMAIDENS +HARPOONISTS +ATHLETIC +GYMNASTIC +ACROBATIC +BOWYERS +DIAMOND +CELESTIAL +ELYSIAN +ASTRAL +UNEARTHLY +ARCADIAN +JEWELERS +ARTISANS +MECHANICS +AUREOLIC +VICTORIOUS +AMBERGRIS +CAMPHOR +LAPISLAZULI +CHROMATIC +SCINTILLATING +TURQUOISE +JACINTH +ZIRCON +BAHAMUTS +GREATWYRMS +FELICITOUS +LUCKY +WAILING +SCREAMING +GRANDMASTERS +MASTERS +ARGENT +TIN +NICKEL +MAROON +CHESTNUT +VIGOROUS +BROWN +DUN +REALGAR +RUSTY +CINNABAR +VERMILION +CARMINE +CARBUNCLE +SERRATED +SCARLET +BLOODY +SANGUINARY +PEARL +DIVINE +HALLOWED +SACRED +PURE +CONSECRATED +LUNAR +FRANTIC +HELLACIOUS +QUIXOTIC +SMITING +STELLAR +STINGING +SINGING +TIMELESS +ORIGINAL +CORPORAL +LAWFUL +CHAOTIC +FIERCE +FEROCIOUS +PERPETUAL +EVERLASTING +LADEN +PERNICIOUS +HARMFUL +EVIL +INSIDIOUS +MALICIOUS +SPITEFUL +PRECOCIOUS +MAJESTIC +SANGUINE +MONUMENTAL +IRRESISTIBLE +FESTERING +MUSTY +DUSTY +DECAYING +ROTTING +INFECTIOUS +FOGGY +CLOUDY +HAZY +PUNISHING +OBSIDIAN +ROYAL +FRIGID +MOLDY +GAUDY +IMPECCABLE +SOULLESS +HEATED +LASTING +SCORCHED +MARRED +LILAC +ROSE +SHIMMERING +GREEN +WICKED +STRANGE +REPULSIVE +RECLUSIVE +CRUDE +RUDE +HERMETIC +RAINBOW +COLORFUL +ODIFEROUS +GRINDING +SELF-REPAIR +SHADOW +GHOSTLY +FANATIC +POSSESSED +BERSERKER diff --git a/assets/word_lists/magic_suffixes.txt b/assets/word_lists/magic_suffixes.txt new file mode 100644 index 000000000..fdb894199 --- /dev/null +++ b/assets/word_lists/magic_suffixes.txt @@ -0,0 +1,391 @@ +OFHEALTH +OFPROTECTION +OFABSORPTION +OFWARDING +OFTHESENTINEL +OFGUARDING +OFNEGATION +OFPIERCING +OFBASHING +OFPUNCTURING +OFTHORNS +OFSPIKES +OFREADINESS +OFALACRITY +OFSWIFTNESS +OFQUICKNESS +OFBLOCKING +OFDEFLECTING +OFTHEAPPRENTICE +OFTHEMAGUS +OFFROST +OFTHEGLACIER +OFTHAWING +OFFLAME +OFFIRE +OFBURNING +OFSHOCK +OFLIGHTNING +OFTHUNDER +OFCRAFTMANSHIP +OFQUALITY +OFMAIMING +OFSLAYING +OFGORE +OFCARNAGE +OFSLAUGHTER +OFWORTH +OFMEASURE +OFEXCELLENCE +OFPERFORMANCE +OFBLIGHT +OFVENOM +OFPESTILENCE +OFDEXTERITY +OFSKILL +OFACCURACY +OFPRECISION +OFPERFECTION +OFBALANCE +OFSTABILITY +OFTHEHORSE +OFREGENERATION +OFREGROWTH +OFVILENESS +OFGREED +OFWEALTH +OFCHANCE +OFFORTUNE +OFENERGY +OFTHEMIND +OFBRILLIANCE +OFSORCERY +OFWIZARDRY +OFTHEBEAR +OFLIGHT +OFRADIANCE +OFTHESUN +OFLIFE +OFTHEJACKAL +OFTHEFOX +OFTHEWOLF +OFTHETIGER +OFTHEMAMMOTH +OFTHECOLOSSUS +OFTHELEECH +OFTHELOCUST +OFTHEBAT +OFTHEVAMPIRE +OFDEFIANCE +OFREMEDY +OFAMELIORATION +OFICE +OFSIMPLICITY +OFEASE +OFTHEMULE +OFSTRENGTH +OFMIGHT +OFTHEOX +OFTHEGIANT +OFTHETITAN +OFPACING +OFHASTE +OFSPEED +OFTHEWRAITH +OFEQUILIBRIUM +OFWARMING +OFSTOICISM +OFTHEDYNAMO +OFGROUNDING +OFINSULATION +OFRESISTANCE +OFFAITH +OFQUENCHING +OFAMIANTHUS +OFINFLAMMABILITY +OFCOOLNESS +OFAMICAE +OFLIFEEVERLASTING +OFSUNLIGHT +OFFROZENORB +OFHYDRASHIELD +OFCHILLINGARMOR +OFBLIZZARD +OFENERGYSHIELD +OFTHUNDERSTORM +OFMETEOR +OFGLACIALSPIKE +OFTELEPORTSHIELD +OFCHAINLIGHTNING +OFENCHANT +OFFIREWALL +OFSHIVERARMOR +OFNOVASHIELD +OFNOVA +OFFIREBALL +OFBLAZE +OFICEBLAST +OFFROSTSHIELD +OFTELEKINESIS +OFSTATICFIELD +OFFROZENARMOR +OFICEBOLT +OFCHARGEDBOLT +OFFIREBOLTS +OFTHEELEMENTS +OFTHECOBRA +OFTHEEFREETI +OFTHEPHOENIX +OFTHEYETI +OFGRACEANDPOWER +OFGRACE +OFPOWER +OFTHEELEPHANT +OFMEMORY +OFTHEKRAKEN +OFPROPOGATION +OFREPLENISHING +OFAGES +OFRESTORATION +OFSELF-REPAIR +OFACCELERATION +OFTRANSPORTATION +OFVIRILITY +OFATLAS +OFFREEDOM +OFTHELAMPREY +OFHOPE +OFSPIRIT +OFVITA +OFSUSTENANCE +OFTHEWHALE +OFTHESQUID +OFTHECOLOSSUS +OFKNOWLEDGE +OFENLIGHTENMENT +OFPROSPERITY +OFGOODLUCK +OFLUCK +OFAVARICE +OFHONOR +OFREVIVIFICATION +OFTRUTH +OFDARING +OFNIRVANA +OFENVY +OFANTHRAX +OFBLISS +OFJOY +OFTRANSCENDENCE +OFWRATH +OFIRE +OFEVISCERATION +OFBUTCHERY +OFENNUI +OFSTORMS +OFPASSION +OFINCINERATION +OFFRIGIDITY +OFWINTER +OFTHEICICLE +OFFERVOR +OFMALICE +OFSWORDS +OFRAZORS +OFDESIRE +OFTHESCIROCCO +OFTHEDUNES +OFTHAWING +OFTHECHOIR +OFTHESNIPER +OFTHESTILETTO +OFBILE +OFBLITZEN +OFCREMATION +OFDARKNESS +OFDISEASE +OFREMORSE +OFTERROR +OFTHESKY +OFVALHALLA +OFWASTE +OFNOBILITY +OFKARMA +OFGROUNDING +OFTHERIVER +OFTHELAKE +OFTHEOCEAN +OFTHEBAYOU +OFTHESTREAM +OFTHELADY +OFTHEMAIDEN +OFTHEVIRGIN +OFTHEHAG +OFTHEWITCH +OFJUDGEMENT +OFILLUSION +OFELUDING +OFCOMBAT +OFATTRITION +OFABRASION +OFEROSION +OFSEARING +OFSTONE +OFSTATURE +OFFORTIFICATION +OFQUICKENING +OFDISPATCH +OFDARING +OFDREAD +OFSUFFERING +OFDOOM +OFVENGENCE +OFREDEMPTION +OFLUCK +OFTHEAVENGER +OFTHESPECTER +OFTHEGHOST +OFTHEINFANTRY +OFTHEMOSQUITO +OFTHEGNAT +OFTHEFLY +OFTHEPLAGUE +OFTWILIGHT +OFDUSK +OFDAWN +OFTHEIMBECILE +OFTHEIDIOT +OFTHEMORON +OFTHEJUJUBE +OFTHEOBSCENE +OFTHEQUOTA +OFMAGGOTS +OFHORROR +OFTHEABYSS +OFTHEBEAST +OFCRUELTY +OFBADNESS +OFTHEHORDE +OFTHEFOREST +OFTHELILLY +OFTHEGRASSYGNOLL +OFTHESTARS +OFTHEMOON +OFLOVE +OFTHEUNICORN +OFTHEWALRUS +OFTHEEARTH +OFVINES +OFHONOR +OFTRIBUTE +OFCREDIT +OFADMIRATION +OFSWEETNESS +OFBEAUTY +OFPILFERING +OFAMPLIFYDAMAGE +OFHURRICANE +OFARMAGEDDON +OFTORNADO +OFVOLCANO +OFTWISTER +OFCYCLONEARMOR +OFFISSURE +OFMOLTENBOULDER +OFFIRESTORMS +OFBATTLECOMMAND +OFWARCRY +OFGRIMWARD +OFBATTLEORDERS +OFBATTLECRY +OFCONCENTRATION +OFFINDITEM +OFSTUN +OFSHOUT +OFTAUNT +OFFINDPOTION +OFHOWL +OFFISTOFTHEHEAVENS +OFHOLYSHIELD +OFCONVERSION +OFBLESSEDHAMMER +OFVENGEANCE +OFCHARGE +OFZEAL +OFHOLYBOLT +OFSACRIFICE +OFFIREGOLEM +OFBONESPIRIT +OFPOISONNOVA +OFLOWERRESISTANCE +OFIRONGOLEM +OFBONEPRISON +OFDECREPIFY +OFATTRACT +OFBLOODGOLEM +OFBONESPEAR +OFPOISONEXPLOSION +OFLIFETAP +OFCONFUSION +OFSKELETALMAGES +OFBONEWALL +OFTERROR +OFIRONMAIDEN +OFCLAYGOLEM +OFCORPSEEXPLOSION +OFPOISONDAGGER +OFWEAKEN +OFDIMVISION +OFRAISESKELETON +OFBONEARMOR +OFTEETH +OFAMPLIFYDAMAGE +OFFROZENORB +OFHYDRA +OFBLIZZARD +OFMETEOR +OFGLACIALSPIKE +OFTELEPORTATION +OFENCHANTMENT +OFFIREWALL +OFNOVA +OFFIREBALL +OFBLAZING +OFICEBLAST +OFFROSTNOVA +OFICEBOLT +OFCHARGEDBOLT +OFFIREBOLT +OFLIGHTNINGFURY +OFLIGHTNINGSPEAR +OFFREEZINGARROW +OFFENDING +OFIMMOLATINGARROW +OFPLAGUEJAVELIN +OFCHARGEDSPEAR +OFGUIDEDARROW +OFICEARROW +OFLIGHTNINGJAVELIN +OFIMPALINGSPEAR +OFSLOWMISSILE +OFEXPLODINGARROW +OFPOISONJAVELIN +OFPOWERSPEAR +OFMULTIPLESHOT +OFCOLDARROW +OFJAB +OFINNERSIGHT +OFFIREARROW +OFMAGICARROW +OFDAWN +OFINERTIA +OFJOYFULNESS +OFLIGHTNINGSTRIKE +OFPLAGUEJAB +OFCHARGEDSTRIKE +OFIMPALINGSTRIKE +OFPOISONJAB +OFPOWERSTRIKE +OFTHEGARGANTUAN +OFTHECENTAUR +OFTHEPLAGUE diff --git a/build.py b/build.py index aa4b6f142..dc3b1cf2d 100644 --- a/build.py +++ b/build.py @@ -76,7 +76,7 @@ def clean_up(): if args.use_key: key = Fernet.generate_key().decode("utf-8") key_cmd = " --key " + key - installer_cmd = f"pyinstaller --onefile --distpath {botty_dir}{key_cmd} --exclude-module graphviz --paths .\\src --paths {args.conda_path}\\envs\\botty\\lib\\site-packages src\\{exe}" + installer_cmd = f"pyinstaller --onefile --distpath {botty_dir}{key_cmd} --exclude-module graphviz --paths .\\src --paths {args.conda_path}\\envs\\botty\\Lib\\site-packages src\\{exe}" os.system(installer_cmd) os.system(f"cd {botty_dir} && mkdir config && cd ..") @@ -85,8 +85,9 @@ def clean_up(): f.write("; Add parameters you want to overwrite from param.ini here") shutil.copy("config/game.ini", f"{botty_dir}/config/") shutil.copy("config/params.ini", f"{botty_dir}/config/") - shutil.copy("config/pickit.ini", f"{botty_dir}/config/") shutil.copy("config/shop.ini", f"{botty_dir}/config/") + shutil.copy("config/default.bnip", f"{botty_dir}/config/") + os.makedirs(f"{botty_dir}/config/bnip", exist_ok=True) shutil.copy("README.md", f"{botty_dir}/") shutil.copytree("assets", f"{botty_dir}/assets") clean_up() diff --git a/config/bnip/.gitkeep b/config/bnip/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/config/default.bnip b/config/default.bnip new file mode 100644 index 000000000..366fb2a59 --- /dev/null +++ b/config/default.bnip @@ -0,0 +1,1680 @@ +// Revised V6 +// By Sosa, Gleed, Legit + +//==================================================================// +//<<<<<<<<<<<<<<<<<<<<<<<<<<++++ Misc ++++>>>>>>>>>>>>>>>>>>>>>>>>>>// +//==================================================================// + +//------------------------------------------ +//================= Utility ================ +//------------------------------------------ + +[Type] == Gold # [Gold] >= 5000 +[Name] == Scrolloftownportal +[Name] == Scrollofidentify + +//------------------------------------------------ +//================= Unique Charms ================ +//------------------------------------------------ + +//[Name] == Grandcharm && [Quality] == Unique // Gheed's Fortune +//[Name] == Smallcharm && [Quality] == Unique // Annihilus Charm + +//------------------------------------------ +//================= Potions ================ +//------------------------------------------ + +//[Name] == Greaterhealingpotion +//[Name] == Greatermanapotion +[Name] == Superhealingpotion +[Name] == Supermanapotion +//[Name] == Rejuvenationpotion +[Name] == Fullrejuvenationpotion + +//---------------------------------------- +//================= Ubers ================ +//---------------------------------------- + +[Name] == Keyofterror +[Name] == Keyofhate +[Name] == Keyofdestruction + +//----------------------------------------- +//================= Tokens ================ +//----------------------------------------- + +[Name] == Twistedessenceofsuffering +[Name] == Chargedessenceofhatred +[Name] == Burningessenceofterror +[Name] == Festeringessenceofdestruction + +//---------------------------------------- +//================= Runes ================ +//---------------------------------------- + +[Name] >= Lumrune && [Name] <= Zodrune +//[Name] == Elrune +//[Name] == Eldrune +//[Name] == Tirrune +//[Name] == Nefrune +//[Name] == Ethrune +//[Name] == Ithrune +//[Name] == Talrune +//[Name] == Ralrune +//[Name] == Ortrune +//[Name] == Thulrune +//[Name] == Amnrune +//[Name] == Solrune +//[Name] == Shaelrune +//[Name] == Dolrune +//[Name] == Helrune +//[Name] == Iorune +//[Name] == Lumrune +//[Name] == Korune +//[Name] == Falrune +//[Name] == Lemrune +//[Name] == Pulrune +//[Name] == Umrune +//[Name] == Malrune +//[Name] == Istrune +//[Name] == Gulrune +//[Name] == Vexrune +//[Name] == Ohmrune +//[Name] == Lorune +//[Name] == Surrune +//[Name] == Berrune +//[Name] == Jahrune +//[Name] == Chamrune +//[Name] == Zodrune + +//--------------------------------------- +//================= Gems ================ +//--------------------------------------- + +//[Name] == Chippedamethyst +//[Name] == Chippeddiamond +//[Name] == Chippedemerald +//[Name] == Chippedruby +//[Name] == Chippedsapphire +//[Name] == Chippedskull +//[Name] == Chippedtopaz +//[Name] == Flawedamethyst +//[Name] == Flaweddiamond +//[Name] == Flawedemerald +//[Name] == Flawedruby +//[Name] == Flawedsapphire +//[Name] == Flawedskull +//[Name] == Flawedtopaz +//[Name] == Amethyst +//[Name] == Diamond +//[Name] == Emerald +//[Name] == Ruby +//[Name] == Skull +//[Name] == Sapphire +//[Name] == Topaz +//[Name] == Flawlessamethyst +//[Name] == Flawlessdiamond +//[Name] == Flawlessemerald +//[Name] == Flawlessruby +//[Name] == Flawlesssapphire +//[Name] == Flawlessskull +//[Name] == Flawlesstopaz +//[Name] == Perfectamethyst +//[Name] == Perfectdiamond +//[Name] == Perfectemerald +//[Name] == Perfectruby +//[Name] == Perfectsapphire +//[Name] == Perfectskull +//[Name] == Perfecttopaz + +//=========================================================================// +//<<<<<<<<<<<<<<<<<<<<<<<<<<++++ Magic Items ++++>>>>>>>>>>>>>>>>>>>>>>>>>>// +//=========================================================================// + +//----------------------------------------------- +//================= Grand Charms ================ +//----------------------------------------------- + +[Name] == Grandcharm && [Quality] == Magic # [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 60 // Plain +15 All Res +[Name] == Grandcharm && [Quality] == Magic # [Itemaddskilltab] >= 1 // All Plain Skillers +//[Name] == Grandcharm && [Quality] == Magic # ([Coldresist] >= 30 || [Fireresist] >= 30 || [Lightresist] >= 30 || [Poisonresist] >= 30) // All +30 Single Res Gc +//[Name] == Grandcharm && [Quality] == Magic && [Flag] != Ethereal # [Maxhp] >= 40 // All +40 Max Hp Gc +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Itemaddskilltab] >= 1 // All Plain Fhr Skillers +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Itemaddskilltab] >= 1 // All Plain Frw Skillers + + +// <<<<<<<<< [ Plain Skillers ] >>>>>>>>> +//[Name] == Grandcharm && [Quality] == Magic # [Fireskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Coldskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Lightningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Trapsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Shadowdisciplinesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Martialartsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Javelinandspearskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Passiveandmagicskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Bowandcrossbowskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Palicombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Defensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Offensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Elementalskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Shapeshiftingskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Druidsummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Warcriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Masteriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Barbcombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Poisonandboneskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Necromancersummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Cursesskilltab] >= 1 + +// <<<<<<<<< [ +Fhr Skillers ] >>>>>>>>> +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Fireskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Coldskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Lightningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Trapsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Shadowdisciplinesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Martialartsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Javelinandspearskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Passiveandmagicskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Bowandcrossbowskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Palicombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Defensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Offensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Elementalskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Shapeshiftingskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Druidsummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Warcriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Masteriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Barbcombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Poisonandboneskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Necromancersummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Fhr] >= 12 && [Cursesskilltab] >= 1 + +// <<<<<<<<< [ +Frw Skillers ] >>>>>>>>> +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Fireskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Coldskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Lightningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Trapsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Shadowdisciplinesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Martialartsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Javelinandspearskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Passiveandmagicskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Bowandcrossbowskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Palicombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Defensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Offensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Elementalskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Shapeshiftingskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Druidsummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Warcriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Masteriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Barbcombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Poisonandboneskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Necromancersummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Frw] >= 7 && [Cursesskilltab] >= 1 + +// <<<<<<<<< [ +35 Hp Skillers ] >>>>>>>>> +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Fireskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Coldskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Lightningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Trapsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Shadowdisciplinesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Martialartsskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Javelinandspearskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Passiveandmagicskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Bowandcrossbowskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Palicombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Defensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Offensiveaurasskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Elementalskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Shapeshiftingskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Druidsummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Warcriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Masteriesskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Barbcombatskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Poisonandboneskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Necromancersummoningskilltab] >= 1 +//[Name] == Grandcharm && [Quality] == Magic # [Maxhp] >= 35 && [Cursesskilltab] >= 1 + +// <<<<<<<<< [ All Res Grand Charms ] >>>>>>>>> +//[Name] == Grandcharm && [Quality] == Magic # [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 60 && [Frw] >= 7 +//[Name] == Grandcharm && [Quality] == Magic # [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 60 && [Fhr] >= 12 +//[Name] == Grandcharm && [Quality] == Magic # [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 60 && [Maxhp] >= 35 + +// <<<<<<<<< [ Melee Grand Charms ] >>>>>>>>> +[Name] == Grandcharm && [Quality] == Magic # [Tohit] >= 76 && [Maxdamage] >= 14 +[Name] == Grandcharm && [Quality] == Magic # [Tohit] >= 76 && [Maxdamage] >= 10 && [Frw] >= 7 +[Name] == Grandcharm && [Quality] == Magic # [Tohit] >= 76 && [Maxdamage] >= 10 && [Fhr] >= 12 +[Name] == Grandcharm && [Quality] == Magic # [Tohit] >= 76 && [Maxdamage] >= 10 && [Maxhp] >= 35 +[Name] == Grandcharm && [Quality] == Magic # [Tohit] >= 132 && [Maxhp] >= 35 + +//----------------------------------------------- +//================= Small Charms ================ +//----------------------------------------------- + +[Name] == Smallcharm && [Quality] == Magic # [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 20 // +5 All Res +[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 15 // Plain +Hp +[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 // Plain +Magic Find +[Name] == Smallcharm && [Quality] == Magic # [Coldresist] >= 11 // Plain +Cold Res +[Name] == Smallcharm && [Quality] == Magic # [Fireresist] >= 11 // Plain +Fire Res +[Name] == Smallcharm && [Quality] == Magic # [Lightresist] >= 11 // Plain +Light Res +[Name] == Smallcharm && [Quality] == Magic # [Poisonresist] >= 11 // Plain +Poison Res +[Name] == Smallcharm && [Quality] == Magic # [Poisonmindam] >= 100 // Plain +100 Poison Dmg + +// Melee Small Charms ] >>>>>>>>> +[Name] == Smallcharm && [Quality] == Magic # [Firemindam] >= 26 && [Firemaxdam] >= 42 +[Name] == Smallcharm && [Quality] == Magic # [Lightmaxdam] >= 99 +[Name] == Smallcharm && [Quality] == Magic # [Coldmindam] >= 15 && [Coldmaxdam] >= 29 +[Name] == Smallcharm && [Quality] == Magic # [Poisonmaxdam] >= 385 // 451 +[Name] == Smallcharm && [Quality] == Magic # [Maxdamage] >= 4 && [Tohit] >= 20 + +// <<<<<<<<< [ +Life Small Charms ] >>>>>>>>> +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Maxmana] >= 17 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Fireresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Coldresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Lightresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Poisonresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 15 && [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 20 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 15 && [Tohit] >= 15 && [Maxdamage] >= 3 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] == 15 && [Tohit] >= 20 && [Maxdamage] >= 3 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] == 20 && [Tohit] >= 20 && [Maxdamage] >= 3 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Tohit] >= 36 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Firemindam] >= 19 && [Firemaxdam] >= 29 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Lightmaxdam] >= 71 +//[Name] == Smallcharm && [Quality] == Magic # [Maxhp] >= 20 && [Coldmindam] >= 10 && [Coldmaxdam] >= 20 + +// <<<<<<<<< [ +Magic Find Small Charms ] >>>>>>>>> +//[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 && [Fireresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 && [Coldresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 && [Lightresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 && [Poisonresist] >= 11 +//[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 && [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 20 +//[Name] == Smallcharm && [Quality] == Magic # [Itemmagicbonus] >= 7 && [Maxdamage] >= 3 && [Tohit] >= 20 + +// <<<<<<<<< [ +Frw Small Charms ] >>>>>>>>> +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Fireresist] >= 9 +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Coldresist] >= 9 +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Lightresist] >= 9 +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Poisonresist] >= 9 +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 15 +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Tohit] >= 20 && [Maxdamage] >= 3 +[Name] == Smallcharm && [Quality] == Magic # [Frw] >= 3 && [Tohit] >= 36 + +// <<<<<<<<< [ +Fhr Small Charms ] >>>>>>>>> +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Fireresist] >= 11 +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Coldresist] >= 11 +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Lightresist] >= 11 +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Poisonresist] >= 11 +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 20 +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Tohit] >= 20 && [Maxdamage] >= 3 +[Name] == Smallcharm && [Quality] == Magic # [Fhr] >= 5 && [Tohit] >= 36 + +//------------------------------------------ +//================= Jewelry ================ +//------------------------------------------ + +// <<<<<<<<< [ Magic Jewels ] >>>>>>>>> +[Name] == Jewel && [Quality] == Magic # [Enhanceddamage] >= 35 && ([Ias] == 15 || [Itemreqpercent] <= -15 || [Fireresist] >= 30 || [Mindamage] >= 10 || [Maxdamage] >= 15) // Ruby Jewel Of X +[Name] == Jewel && [Quality] == Magic # [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60 && [Ias] >= 15 // Scintillating Jewel Of Fervor +[Name] == Jewel && [Quality] == Magic # [Tohit] >= 100 && [Ias] >= 15 // Argent Jewel Of Fervor +[Name] == Jewel && [Quality] == Magic # [Maxdamage] >= 30 // Vermilion Jewel Of Carnage +[Name] == Jewel && [Quality] == Magic # [Maxdamage] >= 15 && ([Itemreqpercent] <= -15 || [Ias] >= 15) // Vermilion Jewel Of X +[Name] == Jewel && [Quality] == Magic # [Mindamage] >= 8 && [Maxdamage] >= 15 // Crimson Jewel Of Carnage +[Name] == Jewel && [Quality] == Magic # [Maxdamage] >= 24 // Carmine Jewel Of Carnage (Lld) +[Name] == Jewel && [Quality] == Magic # [Enhanceddamage] >= 20 && [Maxdamage] >= 15 // Rusty Jewel Of Carnage (Lld) +[Name] == Jewel && [Quality] == Magic # [Enhanceddamage] >= 20 && [Maxdamage] >= 9 // Rusty Jewel Of Wrath (Lld) +[Name] == Jewel && [Quality] == Magic # [Poisonmindam] >= 103 // Jewel Of Envy (Vlld) + +// <<<<<<<<< [ Magic Amulets ] >>>>>>>>> +//[Name] == Amulet && [Quality] == Magic # [Itemchargedskill] == 54 // Tele Amulet +//[Type] == Amulet && [Quality] == Magic # [Itemaddskilltab] >= 3 && ([Fcr] >= 10 || [Itemmagicbonus] >= 35) // +3 Skill Fcr/Mf Amulet + +//------------------------------------------- +//================= Circlets ================ +//------------------------------------------- + +[Type] == Circlet && [Quality] == Magic && [Flag] != Ethereal # [Itemchargedskill] == 54 // Tele Circlet +[Type] == Circlet && [Quality] == Magic && [Flag] != Ethereal # [Barbarianskills] == 2 && [Itemgoldbonus] >= 70 // Gf Barb +[Type] == Circlet && [Quality] == Magic && [Flag] != Ethereal # [Sockets] == 3 && ([Frw] == 30 || [Strength] >= 25 || [Dexterity] >= 25 || [Itemmagicbonus] == 35 || [Maxhp] == 100 || [Fcr] == 20 || [Normaldamagereduction] == 25) // Artisan's Circlet Of X +[Type] == Circlet && [Quality] == Magic && [Flag] != Ethereal # [Maxmana] == 120 && [Normaldamagereduction] == 25 // Bahamut's Circlet Of Life Everlasting +[Type] == Circlet && [Quality] == Magic && [Flag] != Ethereal # ([Itemaddclassskills] >= 2 || [Itemaddskilltab] == 3) && [Fcr] >= 20 // X Circlet Of The Magus + +//------------------------------------------ +//================= Helmets ================ +//------------------------------------------ + +// <<<<<<<<< [ Magic Visionary Helms ] >>>>>>>>> +//([Name] == Demonhead || [Name] == Bonevisage || [Name] == Spiredhelm || [Name] == Corona) && [Quality] == Magic # [Itemtohitpercentperlevel] >= 1 && ([Fhr] == 10 || [Maxhp] >= 30) + +// <<<<<<<<< [ Magic Barbarian Helmets ] >>>>>>>>> +//[Type] == Primalhelm && [Quality] == Magic && [Flag] != Ethereal # ([Barbarianskills] == 2 || [Warcriesskilltab] >= 2) && [Skillbattleorders] >= 3 // All B.O Helms +([Name] == Assaulthelmet || [Name] == Avengerguard || [Name] == Savagehelmet || [Name] == Slayerguard || [Name] == Conquerorcrown || [Name] == Guardiancrown) && [Quality] == Magic # ([Barbarianskills]+[Skillbattleorders] >= 5 || [Warcriesskilltab]+[Skillbattleorders] >= 6) // 5-6 B.O Arreat Style + +// <<<<<<<<< [ Magic Druid Pelts ] >>>>>>>>> +//[Type] == Pelt && [Quality] == Magic && [Flag] != Ethereal # [Skilltornado]+[Druidskills] >= 5 // Windy Druid Pelt +//[Type] == Pelt && [Quality] == Magic && [Flag] != Ethereal # [Skilltornado]+[Elementalskilltab] >= 5 // Windy Druid Pelt +//[Type] == Pelt && [Quality] == Magic && [Flag] != Ethereal # [Skillfissure]+[Druidskills] >= 5 // Fissure Druid Pelt +//[Type] == Pelt && [Quality] == Magic && [Flag] != Ethereal # [Skillfissure]+[Elementalskilltab] >= 5 // Fissure Druid Pelt + +//------------------------------------------ +//================= Shields ================ +//------------------------------------------ + +// <<<<<<<<< [ Magic Socketed Shields ] >>>>>>>>> +[Name] == Monarch && [Quality] == Magic # [Sockets] == 4 && [Itemfasterblockrate] == 30 // Jmod +[Name] == Monarch && [Quality] == Magic # [Sockets] == 4 && [Fhr] == 17 // Jmoe +[Name] == Monarch && [Quality] == Magic # [Sockets] == 4 && [Maxhp] >= 60 // Jmoc +[Name] == Monarch && [Quality] == Magic # [Sockets] == 4 && [Itemreqpercent] == -30 // Jmos +//([Name] == Crownshield || [Name] == Royalshield || [Name] == Sacredtarge || [Name] == Sacredrondache) && [Quality] == Magic # [Sockets] == 4 && [Fhr] == 17 // Paladin Jmod +//([Name] == Crownshield || [Name] == Royalshield || [Name] == Sacredtarge || [Name] == Sacredrondache) && [Quality] == Magic # [Sockets] == 4 && [Itemfasterblockrate] == 30 // Paladin Jmoe +//([Name] == Crownshield || [Name] == Royalshield || [Name] == Sacredtarge || [Name] == Sacredrondache) && [Quality] == Magic # [Sockets] == 4 && [Maxhp] >= 60 // Paladin Jmoc +//([Name] == Crownshield || [Name] == Royalshield || [Name] == Sacredtarge || [Name] == Sacredrondache) && [Quality] == Magic # [Sockets] == 4 && [Itemreqpercent] == -30 // Paladin Jmos +//[Type] == Voodooheads && [Quality] == Magic && [Class] >= Exceptional && [Flag] != Ethereal # ([Necromancerskills] >= 1 || [Poisonandboneskilltab] >= 1) && [Fbr] >= 30 && [Skillbonespear] >= 1 + +//------------------------------------------ +//================= Weapons ================ +//------------------------------------------ + +// <<<<<<<<< [ B.O Sticks ] >>>>>>>>> +//[Name] == Throwingspear && [Quality] == Magic # [Warcriesskilltab] >= 3 + +// <<<<<<<<< [ Gg Club ] >>>>>>>>> +([Name] == Club || [Name] == Spikedclub) && [Quality] == Magic # [Warcriesskilltab] >= 3 && [Strength] > 0 + +// <<<<<<<<< [ Magic Scepters ] >>>>>>>>> +//[Type] == Scepter && [Quality] == Magic # [Paladinskills]+[Skillblessedhammer] >= 5 && ([Skillconcentration] >= 3 || [Fcr] >= 10 && [Skillconcentration] >= 2) +//[Type] == Scepter && [Quality] == Magic # [Paladinskills]+[Skillfistoftheheavens] >= 5 && ([Skillconviction] >= 3 || [Fcr] >= 10 && [Skillconviction] >= 2) +//[Type] == Scepter && [Quality] == Magic # [Palicombatskilltab]+[Skillblessedhammer] >= 6 && ([Skillconcentration] >= 3 || [Fcr] >= 10 && [Skillconcentration] >= 2) +//[Type] == Scepter && [Quality] == Magic # [Palicombatskilltab]+[Skillfistoftheheavens] >= 6 && ([Skillconviction] >= 3 || [Fcr] >= 10 && [Skillconviction] >= 2) + +// <<<<<<<<< [ Magic Sorceress Orbs ] >>>>>>>>> +//[Type] == Orb && [Quality] == Magic # [Sorceressskills]+[Skilllightning] >= 5 && ([Fcr] >= 20 && [Skilllightningmastery] >= 1 || [Skilllightningmastery] >= 3) // Light Orb +//[Type] == Orb && [Quality] == Magic # [Lightningskilltab]+[Skilllightning] >= 6 && ([Fcr] >= 20 && [Skilllightningmastery] >= 1 || [Skilllightningmastery] >= 3) // Light Orb +//[Type] == Orb && [Quality] == Magic # ([Sorceressskills]+[Skillfrozenorb] >= 5 || [Sorceressskills]+[Skillblizzard] >= 5) && ([Fcr] >= 20 && [Skillcoldmastery] >= 1 || [Skillcoldmastery] >= 3) // Cold Orb +//[Type] == Orb && [Quality] == Magic # ([Coldskilltab]+[Skillfrozenorb] >= 6 || [Coldskilltab]+[Skillblizzard] >= 6) && ([Fcr] >= 20 && [Skillcoldmastery] >= 1 || [Skillcoldmastery] >= 3) // Cold Orb +//[Type] == Orb && [Quality] == Magic # [Sorceressskills]+[Skillfireball] >= 5 && (([Fcr] >= 20 && [Skillfiremastery] >= 1) || [Skillfiremastery] >= 3) // Fire Orb +//[Type] == Orb && [Quality] == Magic # ([Fireskilltab]+[Skillenchant] >= 6 || [Fireskilltab]+[Skillfireball] >= 6) && ([Fcr] >= 20 && [Skillfiremastery] >= 1 || [Skillfiremastery] >= 3) // Fire Orb +//[Type] == Orb && [Quality] == Magic # [Fireskilltab]+[Skillhydra] >= 6 && [Skillfiremastery] >= 2 // Hydra Orb + +// <<<<<<<<< [ Magic Javelins ] >>>>>>>>> +([Name] == Maidenjavelin || [Name] == Ceremonialjavelin || [Name] == Matriarchaljavelin) && [Quality] == Magic # [Amazonskills] == 2 && [Javelinandspearskilltab] >= 2 && [Ias] >= 30 +([Name] == Maidenjavelin || [Name] == Ceremonialjavelin || [Name] == Matriarchaljavelin) && [Quality] == Magic # [Javelinandspearskilltab] >= 4 && [Ias] >= 30 +([Name] == Maidenjavelin || [Name] == Ceremonialjavelin || [Name] == Matriarchaljavelin) && [Quality] == Magic # [Amazonskills] >= 2 && [Javelinandspearskilltab] >= 2 && [Ias] >= 30 +([Name] == Maidenjavelin || [Name] == Ceremonialjavelin || [Name] == Matriarchaljavelin) && [Quality] == Magic # [Javelinandspearskilltab] >= 4 && [Ias] >= 30 + +// <<<<<<<<< [ Magic Claws ] >>>>>>>>> +//([Name] == Greatertalons || [Name] == Feralclaws || [Name] == Greaterclaws || [Name] == Runictalons) && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 40 && [Skilllightningsentry] >= 3 +//([Name] == Greatertalons || [Name] == Feralclaws || [Name] == Greaterclaws || [Name] == Runictalons) && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 40 && [Skillwakeoffire] >= 3 +([Name] == Greatertalons || [Name] == Feralclaws || [Name] == Greaterclaws || [Name] == Runictalons) && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 40 && [Skilllightningsentry]+[Assassinskills] >= 5 +([Name] == Greatertalons || [Name] == Feralclaws || [Name] == Greaterclaws || [Name] == Runictalons) && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 40 && [Skilllightningsentry]+[Trapsskilltab] >= 6 +([Name] == Greatertalons || [Name] == Feralclaws || [Name] == Greaterclaws || [Name] == Runictalons) && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 40 && [Skillwakeoffire]+[Assassinskills] >= 5 +([Name] == Greatertalons || [Name] == Feralclaws || [Name] == Greaterclaws || [Name] == Runictalons) && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 40 && [Skillwakeoffire]+[Trapsskilltab] >= 6 + +//------------------------------------------ +//================= Armors ================ +//------------------------------------------ + +//([Name] == Archonplate || [Name] == Duskshroud || [Name] == Wirefleece || [Name] == Greathauberk || [Name] == Sacredarmor) && [Quality] == Magic && [Flag] != Ethereal # [Sockets] == 4 && [Maxhp] >= 85 // Jeweler's Armor Of The Whale +//([Name] == Archonplate || [Name] == Duskshroud || [Name] == Wirefleece || [Name] == Greathauberk || [Name] == Sacredarmor) && [Quality] == Magic && [Flag] != Ethereal # [Sockets] == 4 && [Fhr] >= 24 // Jeweler's Armor Of Stability +//([Name] == Archonplate || [Name] == Duskshroud || [Name] == Wirefleece || [Name] == Greathauberk || [Name] == Sacredarmor) && [Quality] == Magic && [Flag] != Ethereal # [Sockets] == 4 && [Itemfasterblockrate] == 30 // Jeweler's Armor Of Deflecting +//([Name] == Mageplate || [Name] == Breastplate || [Name] == Lightplate) && [Quality] == Magic # [Sockets] == 3 && ([Maxhp] == 80 || [Itemlevelreq] <= 30) // Artisan's Armor Of X + +//------------------------------------------ +//================= Gloves ================= +//------------------------------------------ + +//[Type] == Gloves && [Quality] == Magic && [Flag] != Ethereal # [Ias] >= 20 && ([Javelinandspearskilltab] == 3 || [Bowandcrossbowskilltab] == 3 || [Martialartsskilltab] == 3) // 3/20 Gloves + +//========================================================================// +//<<<<<<<<<<<<<<<<<<<<<<<<<<<< Rare Items >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// +//========================================================================// + +//------------------------------------------ +//================= Jewelry ================ +//------------------------------------------ + +// <<<<<<<<< [ Rare Misc. Amulets ] >>>>>>>>> +//[Type] == Amulet && [Quality] == Rare # [Itemchargedskill] == 54 // Rare Tele Amulet +[Type] == Amulet && [Quality] == Rare # [Barbarianskills] == 2 && ([Itemgoldbonus] >= 70 && [Itemmagicbonus] >= 15 || [Itemgoldbonus] >= 80) // Gf Amulet + +// <<<<<<<<< [ Rare Caster Amulet ] >>>>>>>>> +//[Type] == Amulet && [Quality] == Rare # [Itemaddclassskills] >= 2 && [Fcr] >= 10 // All 2/10 Amulets +[Type] == Amulet && [Quality] == Rare # [Itemaddclassskills] == 2 && [Fcr] == 10 && ([Strength]+[Maxhp]+[Maxmana] >= 60 || [Dexterity]+[Maxhp]+[Maxmana] >= 60 || [Strength]+[Dexterity]+[Maxhp] >= 50 || [Strength]+[Dexterity]+[Maxmana] >= 55) // Fcr Stat Amulet +//[Type] == Amulet && [Quality] == Rare # [Druidskills] == 2 && [Fcr] == 10 && ([Strength] >= 10 || [Dexterity] >= 10 || [Strength]+[Dexterity] >= 20) && ([Maxhp] >= 30 || [Maxmana] >= 50 || [Itemmagicbonus] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +//[Type] == Amulet && [Quality] == Rare # [Barbarianskills] == 2 && [Fcr] == 10 && ([Strength] >= 10 || [Dexterity] >= 10 || [Strength]+[Dexterity] >= 20) && ([Maxhp] >= 30 || [Maxmana] >= 50 || [Itemmagicbonus] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +//[Type] == Amulet && [Quality] == Rare # [Necromancerskills] == 2 && [Fcr] == 10 && ([Strength] >= 10 || [Dexterity] >= 10 || [Strength]+[Dexterity] >= 20) && ([Maxhp] >= 30 || [Maxmana] >= 50 || [Itemmagicbonus] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +//[Type] == Amulet && [Quality] == Rare # [Paladinskills] == 2 && [Fcr] == 10 && ([Strength] >= 10 || [Dexterity] >= 10 || [Strength]+[Dexterity] >= 20) && ([Maxhp] >= 30 || [Maxmana] >= 50 || [Itemmagicbonus] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +//[Type] == Amulet && [Quality] == Rare # [Assassinskills] == 2 && [Fcr] == 10 && ([Strength] >= 10 || [Dexterity] >= 10 || [Strength]+[Dexterity] >= 20) && ([Maxhp] >= 30 || [Maxmana] >= 50 || [Itemmagicbonus] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +//[Type] == Amulet && [Quality] == Rare # [Sorceressskills] == 2 && [Fcr] == 10 && ([Strength] >= 10 || [Dexterity] >= 10 || [Strength]+[Dexterity] >= 20) && ([Maxhp] >= 30 || [Maxmana] >= 50 || [Itemmagicbonus] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) + +// <<<<<<<<< [ Rare Stat Amulet ] >>>>>>>>> +//[Type] == Amulet && [Quality] == Rare # [Itemaddclassskills] == 2 && [Strength]+[Dexterity] >= 15 && ([Maxhp] >= 35 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +[Type] == Amulet && [Quality] == Rare # [Paladinskills] == 2 && [Strength]+[Dexterity] >= 15 && ([Maxhp] >= 35 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +[Type] == Amulet && [Quality] == Rare # [Amazonskills] == 2 && [Strength]+[Dexterity] >= 15 && ([Maxhp] >= 35 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +[Type] == Amulet && [Quality] == Rare # [Druidskills] == 2 && [Strength]+[Dexterity] >= 15 && ([Maxhp] >= 35 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +[Type] == Amulet && [Quality] == Rare # [Assassinskills] == 2 && [Strength]+[Dexterity] >= 15 && ([Maxhp] >= 35 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) +[Type] == Amulet && [Quality] == Rare # [Barbarianskills] == 2 && [Strength]+[Dexterity] >= 15 && ([Maxhp] >= 35 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) + +// <<<<<<<<< [ Rare V/Lld Amulet ] >>>>>>>>> +[Type] == Amulet && [Quality] == Rare # [Itemaddskilltab] >= 2 && [Fcr] == 10 && [Strength] >= 6 && [Dexterity] >= 6 && ([Maxhp] >= 25 || [Maxmana] >= 60 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 20 || [Itemdamagetomana] >= 12) + +// <<<<<<<<< [ Rare Rings ] >>>>>>>>> +[Type] == Ring && [Quality] == Rare # [Fcr] >= 10 && [Strength] >= 15 && [Dexterity] >= 10 && ([Maxmana] >= 65 || [Hpregen] >= 5 || [Maxhp] >= 20 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) // Caster Ring +[Type] == Ring && [Quality] == Rare # [Tohit] >= 100 && [Lifeleech]+[Manaleech] >= 9 // Melee Dual Leech Ring +[Type] == Ring && [Quality] == Rare # [Tohit] >= 100 && [Strength] >= 15 && [Dexterity] >= 10 && ([Maxhp] >= 30 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) // Melee Dual Stat Ring +[Type] == Ring && [Quality] == Rare # [Tohit] >= 100 && ([Mindamage] > 7 || [Maxdamage] > 9) && ([Strength]+[Dexterity] >= 10 || [Maxhp] >= 30 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 20) // Bva Ring +[Type] == Ring && [Quality] == Rare # [Fcr] == 10 && [Tohit] >= 80 && ([Maxhp] >= 20 && [Maxmana] >= 20 || [Maxmana] >= 60 || [Maxhp] >= 40) // Bvc Ring +[Type] == Ring && [Quality] == Rare # [Fcr] >= 10 && [Hpregen] >= 5 && [Maxmana] >= 25 && [Strength] >= 0 // Lld Caster Ring + +// <<<<<<<<< [ Rare Jewels ] >>>>>>>>> +//[Type] == Jewel && [Quality] == Rare # [Maxdamage] >= 18 && [Mindamage] >= 18 // Impossible 18/18 Jewel +[Type] == Jewel && [Quality] == Rare # [Maxdamage] >= 12 && [Mindamage] >= 12 // Min/Max Damage Jewel +[Type] == Jewel && [Quality] == Rare # [Strength] >= 7 && [Dexterity] >= 7 && ([Fhr] >= 7 || [Enhanceddamage] >= 30 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30 || [Itemreqpercent] <= -15) // Stat Jewel +[Type] == Jewel && [Quality] == Rare # [Enhanceddamage] >= 30 && ([Mindamage]+[Maxdamage] >= 10 || [Strength] >= 15) && ([Dexterity] >= 10 || [Strength]+[Dexterity] >= 25 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) // Ed Jewel +[Type] == Jewel && [Quality] == Rare # [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 40 && ([Strength] >= 7 || [Dexterity] >= 7 || [Fhr] == 7 || [Itemreqpercent] == -15) // 40% Res Jewel +[Type] == Jewel && [Quality] == Rare # [Fhr] == 7 && ([Strength] >= 6 || [Dexterity] >= 7 || [Strength]+[Dexterity] >= 10 || [Itemreqpercent] == -15) && ([Maxmana] >= 20 || [Maxhp] >= 20 || [Fireresist]+[Lightresist]+[Coldresist]+[Poisonresist] >= 30) // Fhr Jewel +[Type] == Jewel && [Quality] == Rare # [Enhanceddamage] >= 20 && [Strength] >= 5 && [Dexterity] >= 5 // Lld + +//------------------------------------------- +//================= Circlets ================ +//------------------------------------------- + +// <<<<<<<<< [ Rare Misc. Circlets ] >>>>>>>>> +//[Type] == Circlet && [Quality] == Rare # [Itemchargedskill] == 54 // Rare Tele Circlet +//[Type] == Circlet && [Quality] == Rare # [Barbarianskills] == 2 && [Itemgoldbonus] == 70 && [Sockets] >= 0 // Gf Barb +//[Type] == Circlet && [Quality] == Rare # [Itemaddclassskills] >= 2 && [Fcr] >= 20 && [Sockets] == 2 // All 2 Class Skills/20/2 Fcr Circlets +//[Type] == Circlet && [Quality] == Rare # [Itemaddskilltab] >= 2 && [Fcr] >= 20 && [Sockets] == 2 // All 2 Tree Skills/20/2 Fcr Circlets + +// <<<<<<<<< [ Rare Caster Circlets ] >>>>>>>>> +[Type] == Circlet && [Quality] == Rare # [Druidskills] == 2 && [Fcr] == 20 && ([Dexterity] >= 15 || [Strength] >= 15) && ([Maxhp] >= 30 || [Maxmana] >= 60 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Fcr Stat Circlet +[Type] == Circlet && [Quality] == Rare # [Sorceressskills] == 2 && [Fcr] == 20 && ([Dexterity] >= 15 || [Strength] >= 15) && ([Maxhp] >= 30 || [Maxmana] >= 60 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Fcr Stat Circlet +[Type] == Circlet && [Quality] == Rare # [Assassinskills] == 2 && [Fcr] == 20 && ([Dexterity] >= 15 || [Strength] >= 15) && ([Maxhp] >= 30 || [Maxmana] >= 60 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Fcr Stat Circlet +[Type] == Circlet && [Quality] == Rare # [Paladinskills] == 2 && [Fcr] == 20 && ([Dexterity] >= 15 || [Strength] >= 15) && ([Maxhp] >= 30 || [Maxmana] >= 60 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Fcr Stat Circlet +[Type] == Circlet && [Quality] == Rare # [Barbarianskills] == 2 && [Fcr] == 20 && ([Dexterity] >= 15 || [Strength] >= 15) && ([Maxhp] >= 30 || [Maxmana] >= 60 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Fcr Stat Circlet + +// <<<<<<<<< [ Rare Frw Circlets ] >>>>>>>>> +[Type] == Circlet && [Quality] == Rare # [Necromancerskills] == 2 && [Fcr] == 20 && ([Dexterity] >= 15 || [Strength] >= 15) && ([Maxhp] >= 30 || [Maxmana] >= 60 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Fcr Stat Circlet +[Type] == Circlet && [Quality] == Rare # [Amazonskills] == 2 && [Frw] >= 30 && ([Dexterity] >= 10 || [Strength] >= 15) && ([Manaleech] >= 6 || [Lifeleech] >= 7 || [Maxhp] >= 60 || [Coldresist] >= 20 && [Lightresist] >= 20 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Frw Circlet +[Type] == Circlet && [Quality] == Rare # [Assassinskills] == 2 && [Frw] >= 30 && ([Dexterity] >= 10 || [Strength] >= 15) && ([Maxhp] >= 60 || [Coldresist] >= 20 && [Lightresist] >= 20 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Frw Circlet +[Type] == Circlet && [Quality] == Rare # [Barbarianskills] == 2 && [Frw] >= 30 && ([Dexterity] >= 10 || [Strength] >= 15) && ([Manaleech] >= 0 || [Maxhp] >= 30 || [Coldresist] >= 20 && [Lightresist] >= 20 || [Fireresist]+[Coldresist]+[Lightresist]+[Poisonresist] >= 60) && [Sockets] >= 0 // Frw Circlet + +// <<<<<<<<< [ Rare Visionary Circlets ] >>>>>>>>> +[Type] == Circlet && [Quality] == Rare # ([Itemaddclassskills] >= 2 || [Itemaddskilltab] >= 2) && [Itemtohitpercentperlevel] >= 1 && [Fhr] >= 10 && ([Fcr] >= 20 || [Strength] >= 15 && [Dexterity] >= 10 || [Manaleech] >= 5 || [Lifeleech] >= 5 || [Maxdamage] >= 7) && [Sockets] >= 0 // Visionary Circlet + +//------------------------------------------ +//================= Helmets ================ +//------------------------------------------ + +// <<<<<<<<< [ Elite/Visionary Helms ] >>>>>>>>> +//[Type] == Helm && [Quality] == Rare && [Class] == Elite && [Flag] == Ethereal # [Itemtohitpercentperlevel] >= 1 && [Sockets] == 2 && [Itemreplenishdurability] >= 1 && ([Enhanceddefense] >= 100 || [Maxhp] >= 20 || [Fhr] == 10 || [Itempoisonlengthresist] == 25 || [Palicombatskilltab] == 2) +//[Type] == Helm && [Quality] == Rare && [Flag] != Ethereal # [Itemtohitpercentperlevel] >= 1 && [Maxhp] >= 30 && ([Enhanceddefense] >= 100 || [Fhr] == 10 || [Itempoisonlengthresist] == 25 || [Palicombatskilltab] == 2) && [Sockets] == 2 +//[Type] == Helm && [Quality] == Rare && [Flag] != Ethereal # [Itemtohitpercentperlevel] >= 1 && [Fhr] == 10 && ([Enhanceddefense] >= 100 || [Itempoisonlengthresist] == 25 || [Palicombatskilltab] == 2) && [Sockets] == 2 +//[Type] == Helm && [Quality] == Rare && [Flag] != Ethereal # [Itemtohitpercentperlevel] >= 1 && [Enhanceddefense] >= 100 && ([Itempoisonlengthresist] == 25 || [Palicombatskilltab] == 2) && [Sockets] == 2 +//[Type] == Helm && [Quality] == Rare && [Flag] != Ethereal # [Itemtohitpercentperlevel] >= 1 && [Itempoisonlengthresist] == 25 && [Palicombatskilltab] == 2 && [Sockets] == 2 +//[Name] == Bonevisage && [Quality] == Rare # [Itemtohitpercentperlevel] >= 1 && [Itemtohitpercent] >= 5 && [Sockets] == 2 +//[Name] == Corona && [Quality] == Rare # [Itemtohitpercentperlevel] >= 1 && [Itemtohitpercent] >= 5 && [Sockets] == 2 + +// <<<<<<<<< [ Rare Barb Helms ] >>>>>>>>> +[Type] == Primalhelm && [Quality] == Rare # ([Skillbattleorders] >= 2 && [Warcriesskilltab] == 3 || [Skillbattleorders] == 3 && [Barbarianskills] == 2) && [Sockets] >= 0 +[Type] == Primalhelm && [Quality] == Rare && [Flag] != Ethereal # [Barbarianskills]+[Skillbattleorders] >= 5 && ([Maxhp] >= 20 || [Itemtohitpercentperlevel] >= 1) && [Sockets] >= 0 +[Type] == Primalhelm && [Quality] == Rare && [Flag] == Ethereal # [Barbarianskills]+[Skillbattleorders] >= 5 && ([Maxhp] >= 20 || [Itemtohitpercentperlevel] >= 1 || [Itemreplenishdurability] >= 1) && [Sockets] >= 0 +[Type] == Primalhelm && [Quality] == Rare && [Flag] == Ethereal # [Enhanceddefense] >= 180 && ([Itemreplenishdurability] >= 1 || [Itemtohitpercentperlevel] >= 1) && [Sockets] >= 0 + +// <<<<<<<<< [ Rare Druid Pelts ] >>>>>>>>> +[Type] == Pelt && [Quality] == Rare && [Flag] != Ethereal # ([Druidskills] >= 2 || [Elementalskilltab] >= 2) && [Skilltornado] == 3 && [Sockets] >= 0 +[Type] == Pelt && [Quality] == Rare && [Flag] != Ethereal # ([Druidskills] >= 2 || [Shapeshiftingskilltab] == 2) && [Itemtohitpercentperlevel] >= 1 && ([Skillfireclaws] == 3 || [Skillfury] == 3) && [Sockets] >= 0 +[Type] == Pelt && [Quality] == Rare && [Flag] != Ethereal # ([Druidskills] == 2 || [Elementalskilltab] >= 2) && ([Skilltornado] >= 3 || [Skillfissure] == 3) && [Sockets] >= 0 +[Type] == Pelt && [Quality] == Rare && [Flag] != Ethereal # ([Druidskills] == 2 || [Druidsummoningskilltab] >= 2) && [Skillsummongrizzly] >= 3 && [Sockets] >= 0 + +//------------------------------------------ +//================= Shields ================ +//------------------------------------------ + +//[Type] == Shield && [Quality] == Rare && [Flag] == Ethereal # [Enhanceddefense] >= 150 && [Itemreplenishdurability] >= 1 && [Sockets] == 2 +//[Type] == Shield && [Quality] == Rare && [Flag] != Ethereal # [Fhr] >= 17 && [Fbr] >= 30 && ([Maxhp] >= 30 || [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 40) && [Sockets] == 2 +//[Type] == Shield && [Quality] == Rare && [Flag] == Ethereal # [Fhr] >= 17 && [Fbr] >= 30 && ([Maxhp] >= 30 || [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 40) && [Itemreplenishdurability] >= 1 && [Sockets] == 2 +//[Type] == Shield && [Quality] == Rare && [Flag] != Ethereal # [Maxhp] >= 30 && [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 40 && [Fbr] >= 30 && [Sockets] == 2 +//[Type] == Shield && [Quality] == Rare && [Flag] == Ethereal # [Maxhp] >= 30 && [Coldresist]+[Fireresist]+[Lightresist]+[Poisonresist] >= 40 && [Fbr] >= 30 && [Itemreplenishdurability] >= 1 && [Sockets] == 2 +//[Type] == Voodooheads && [Quality] == Rare # [Necromancerskills] == 2 && ([Skillbonespear] >= 3 || [Skillpoisonnova] >= 3) && [Fbr] >= 30 && [Fhr] >= 17 && [Sockets] >= 2 +//[Type] == Auricshields && [Quality] == Rare && [Flag] != Ethereal # [Paladinskills] >= 2 && [Fbr] == 30 && [Sockets] == 2 +//[Type] == Auricshields && [Quality] == Rare && [Flag] == Ethereal # [Paladinskills] >= 2 && [Fbr] >= 15 && [Itemreplenishdurability] >= 1 && [Sockets] == 2 + +//------------------------------------------ +//================= Weapons ================ +//------------------------------------------ + +// <<<<<<<<< [ Rare Claws ] +++++++++ +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare # ([Assassinskills]+[Skilllightningsentry] >= 5 || [Assassinskills]+[Skillwakeoffire] >= 5 || [Trapsskilltab]+[Skilllightningsentry] >= 5 || [Trapsskilltab]+[Skillwakeoffire] >= 5) && [Ias] >= 20 && [Sockets] >= 0 +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare # ([Assassinskills]+[Skilllightningsentry] >= 5 || [Assassinskills]+[Skillwakeoffire] >= 5 || [Trapsskilltab]+[Skilllightningsentry] >= 5 || [Trapsskilltab]+[Skillwakeoffire] >= 5) && [Ias] >= 40 && [Sockets] >= 0 +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare # ([Assassinskills]+[Skilllightningsentry] >= 5 || [Assassinskills]+[Skillwakeoffire] >= 5 || [Trapsskilltab]+[Skilllightningsentry] >= 5 || [Trapsskilltab]+[Skillwakeoffire] >= 5) && [Ias] >= 30 && [Sockets] >= 0 +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare # ([Assassinskills]+[Skilllightningsentry] >= 5 || [Assassinskills]+[Skillwakeoffire] >= 5 || [Trapsskilltab]+[Skilllightningsentry] >= 5 || [Trapsskilltab]+[Skillwakeoffire] >= 5) && [Ias] >= 30 && [Sockets] >= 0 +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare && [Flag] == Ethereal # [Enhanceddamage] >= 300 && [Itemskillonattack] == 66 && [Ias] >= 20 && [Sockets] >= 0 +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare && [Flag] == Ethereal # [Ias] >= 20 && ([Enhanceddamage] >= 400 || ([Enhanceddamage] >= 275 && [Itemtohitperlevel] >= 1)) && [Sockets] >= 0 +(([Type] == Assassinclaw && [Class] == Elite) || [Name] == Greatertalons || [Name] == Greaterclaws) && [Quality] == Rare && [Flag] == Ethereal # [Ias] >= 40 && ([Enhanceddamage] >= 350 || ([Enhanceddamage] >= 250 && [Itemtohitperlevel] >= 1)) && [Sockets] >= 0 + +// <<<<<<<<< [ Rare Sorceress Orbs ] >>>>>>>>> +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skillfireball] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skillmeteor] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skillblizzard] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skillfrozenorb] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skilllightning] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skillchainlightning] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Sorceressskills] >= 2 && [Skillnova] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Fireskilltab] >= 2 && [Skillfireball] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Fireskilltab] >= 2 && [Skillmeteor] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Coldskilltab] >= 2 && [Skillblizzard] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Coldskilltab] >= 2 && [Skillfrozenorb] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Lightningskilltab] >= 2 && [Skilllightning] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Lightningskilltab] >= 2 && [Skillchainlightning] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 +[Type] == Orb && [Quality] == Rare # [Lightningskilltab] >= 2 && [Skillnova] >= 3 && [Fcr] >= 20 && ([Maxmana] >= 50 || [Energy] >= 12 && [Maxmana] >= 35) && [Sockets] >= 0 + +// <<<<<<<<< [ Rare Enchant Orbs ] >>>>>>>>> +//[Type] == Orb && [Quality] <= Rare # [Skillenchant] >= 2 && [Fireskilltab] == 3 +//[Type] == Orb && [Quality] <= Rare # [Skillenchant] == 3 && [Fireskilltab] >= 2 +//[Type] == Orb && [Quality] <= Rare # [Skillenchant] == 3 && [Sorceressskills] == 2 + +// <<<<<<<<< [ Rare Javelins ] >>>>>>>>> +([Name] == Ceremonialjavelin || [Name] == Matriarchaljavelin || [Name] == Maidenjavelin) && [Quality] == Rare # [Javelinandspearskilltab] >= 2 && [Amazonskills] >= 2 && [Ias] >= 30 +([Name] == Ceremonialjavelin || [Name] == Matriarchaljavelin || [Name] == Maidenjavelin) && [Quality] == Rare # [Javelinandspearskilltab] >= 4 && [Ias] >= 30 + + +// <<<<<<<<< [ Rare Bows ] >>>>>>>>> +//[Type] == Bow && [Quality] == Rare # [Itemskillonattack] == 66 && ([Enhanceddamage] >= 400 || ([Enhanceddamage] >= 300 && [Itemtohitperlevel] >= 1)) +//[Type] == Bow && [Quality] == Rare # ([Enhanceddamage] >= 400 || ([Enhanceddamage] >= 250 && [Itemskillonattack] == 66) || ([Enhanceddamage] >= 300 && [Itemtohitperlevel] >= 1)) && [Sockets] >= 0 +//[Type] == Bow && [Quality] == Rare # [Ias] >= 20 && ([Enhanceddamage] >= 300 || ([Enhanceddamage] >= 225 && [Itemskillonattack] == 66) || ([Enhanceddamage] >= 250 && [Itemtohitperlevel] >= 1)) && [Sockets] >= 0 + +//---------------------------------------- +//================= Belts ================ +//---------------------------------------- + +[Type] == Belt && [Quality] == Rare && [Flag] != Ethereal # [Fhr] >= 24 && [Strength] >= 20 && ([Maxhp] >= 40 || [Itemgoldbonus] >= 75 || [Lightresist] >= 20 && [Fireresist] >= 20 && [Coldresist] >= 20 || [Fireresist]+[Coldresist] >= 40 || [Fireresist]+[Lightresist] >= 40 || [Lightresist]+[Coldresist] >= 40) +[Type] == Belt && [Quality] == Rare && [Flag] == Ethereal # [Enhanceddefense] >= 90 && [Itemreplenishdurability] >= 1 && ([Fhr] >= 17 || [Coldresist]+[Fireresist]+[Lightresist] >= 25 || [Strength]+[Dexterity] >= 10 || [Maxhp] >= 20 || [Fireresist]+[Coldresist] >= 40 || [Fireresist]+[Lightresist] >= 40 || [Lightresist]+[Coldresist] >= 40) +[Type] == Belt && [Quality] == Rare && [Flag] == Ethereal # [Fhr] == 24 && [Strength] >= 20 && [Maxhp] >= 55 && [Itemreplenishdurability] >= 1 + +//---------------------------------------- +//================= Boots ================ +//---------------------------------------- + +[Type] == Boots && [Quality] == Rare && [Flag] != Ethereal # [Frw] >= 30 && [Fhr] >= 10 && [Dexterity] >= 8 && ([Lightresist]+[Fireresist] >= 35 || [Coldresist]+[Lightresist] >= 35 || [Fireresist]+[Coldresist] >= 35) // Dual Res +[Type] == Boots && [Quality] == Rare && [Flag] != Ethereal # [Frw] >= 30 && [Fhr] >= 10 && [Dexterity] >= 8 && [Coldresist] >= 20 && [Fireresist] >= 20 && [Lightresist] >= 20 // Tri Res +[Type] == Boots && [Quality] == Rare && [Flag] == Ethereal # [Frw] >= 20 && [Fhr] >= 10 && [Dexterity] >= 8 && [Fireresist]+[Lightresist]+[Coldresist] >= 60 && [Itemreplenishdurability] >= 1 // Eth Rep + +//----------------------------------------- +//================= Gloves ================ +//----------------------------------------- + +//[Type] == Gloves && [Quality] == Rare && [Flag] != Ethereal # [Dexterity]+[Strength] >= 25 && [Coldresist]+[Fireresist]+[Lightresist] >= 55 +//[Type] == Gloves && [Quality] == Rare && [Flag] != Ethereal # [Ias] >= 20 && [Dexterity]+[Strength] >= 20 && ([Bowandcrossbowskilltab] == 2 || [Passiveandmagicskilltab] == 2 || [Javelinandspearskilltab] == 2 || [Coldresist]+[Fireresist]+[Lightresist] >= 35 || [Coldresist]+[Fireresist] >= 40 || [Coldresist]+[Lightresist] >= 40 || [Fireresist]+[Lightresist] >= 40) +[Type] == Gloves && [Quality] == Rare && [Flag] != Ethereal # [Ias] >= 20 && ([Bowandcrossbowskilltab] == 2 || [Passiveandmagicskilltab] == 2 || [Javelinandspearskilltab] == 2) && ([Dexterity] >= 10 || [Strength] >= 10 || [Strength]+[Dexterity] >= 20 || [Dexterity] >= 12 && [Coldresist]+[Fireresist]+[Lightresist] >= 25 || [Lifeleech]+[Manaleech] >= 6) +[Type] == Gloves && [Quality] == Rare && [Flag] != Ethereal # [Ias] >= 20 && ([Dexterity]+[Strength] >= 20) && ([Coldresist]+[Fireresist]+[Lightresist] >= 35 || [Coldresist]+[Fireresist] >= 40 || [Coldresist]+[Lightresist] >= 40 || [Fireresist]+[Lightresist] >= 40) // Dual Stat Resistance Gloves +[Type] == Gloves && [Quality] == Rare && [Flag] == Ethereal # [Ias] >= 20 && ([Dexterity] >= 12 || [Strength] >= 12) && ([Bowandcrossbowskilltab] == 2 || [Passiveandmagicskilltab] == 2 || [Javelinandspearskilltab] == 2) && [Coldresist]+[Fireresist]+[Lightresist] >= 25 && [Itemreplenishdurability] >= 1 +[Type] == Gloves && [Quality] == Rare && [Flag] == Ethereal # [Enhanceddefense] >= 180 && [Itemreplenishdurability] >= 1 && ([Bowandcrossbowskilltab] == 2 || [Passiveandmagicskilltab] == 2 || [Javelinandspearskilltab] == 2) && ([Ias] >= 10 || [Dexterity]+[Strength] >= 10 || [Coldresist]+[Fireresist]+[Lightresist] >= 20) +[Type] == Gloves && [Quality] == Rare && [Flag] == Ethereal # [Ias] >= 20 && [Dexterity]+[Strength] >= 20 && ([Coldresist]+[Fireresist]+[Lightresist] >= 35 || [Coldresist]+[Fireresist] >= 40 || [Coldresist]+[Lightresist] >= 40 || [Fireresist]+[Lightresist] >= 40) && [Itemreplenishdurability] >= 1 +[Type] == Gloves && [Quality] == Rare && [Flag] == Ethereal # [Ias] >= 20 && [Dexterity]+[Strength] >= 20 && ([Bowandcrossbowskilltab] == 2 || [Passiveandmagicskilltab] == 2 || [Javelinandspearskilltab] == 2) && [Itemreplenishdurability] >= 1 + +//=======================================================================================// +//<<<<<<<<<<<<<<<<<<<<<<<<<< White/Eth/Superior/Socketed Bases >>>>>>>>>>>>>>>>>>>>>>>>>>// +//=======================================================================================// + +//---------------------------------------------- +//================= Armor Bases ================ +//---------------------------------------------- + +// <<<<<<<<< [ Non-Ethereal Non-Socketed Armor ] >>>>>>>>> +//[Name] == Archonplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Duskshroud && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Mageplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Greathauberk && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Wirefleece && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Scarabhusk && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Wyrmhide && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Lightplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Shadowplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Sacredarmor && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain + +// <<<<<<<<< [ Non-Ethereal Socketed Armor ] >>>>>>>>> +//[Name] == Archonplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Duskshroud && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Mageplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Greathauberk && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Wirefleece && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Scarabhusk && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Wyrmhide && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Lightplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 3 // Socketed +//[Name] == Shadowplate && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Sacredarmor && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed + +// <<<<<<<<< [ Non-Ethereal Superior Non-Socketed Armor ] >>>>>>>>> +[Name] == Archonplate && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +[Name] == Duskshroud && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +[Name] == Mageplate && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +[Name] == Greathauberk && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +[Name] == Wirefleece && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +[Name] == Scarabhusk && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +[Name] == Wyrmhide && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +//[Name] == Lightplate && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +//[Name] == Shadowplate && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior +//[Name] == Sacredarmor && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 // Plain Superior + +// <<<<<<<<< [ Non-Ethereal Superior Socketed Armor ] >>>>>>>>> +[Name] == Archonplate && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +[Name] == Duskshroud && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +[Name] == Mageplate && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +[Name] == Greathauberk && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +[Name] == Wirefleece && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +[Name] == Scarabhusk && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +[Name] == Wyrmhide && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +//[Name] == Lightplate && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 3 // Socketed Sup +//[Name] == Shadowplate && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 4 // Socketed Sup +//[Name] == Sacredarmor && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] >= 4 // Socketed Sup + +// <<<<<<<<< [ Ethereal Socketed/Non-Socketed Armor ] >>>>>>>>> +[Name] == Archonplate && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +[Name] == Duskshroud && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +//[Name] == Mageplate && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 3) // Socketed Eth +//[Name] == Greathauberk && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +[Name] == Wirefleece && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +[Name] == Scarabhusk && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +[Name] == Wyrmhide && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +//[Name] == Lightplate && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) // Socketed Eth +[Name] == Shadowplate && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 4) // Socketed Eth +[Name] == Sacredarmor && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 4) // Socketed Eth + +// <<<<<<<<< [ Ethereal Superior Socketed/Non-Socketed Armor ] >>>>>>>>> +[Name] == Archonplate && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Duskshroud && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Mageplate && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Greathauberk && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Wirefleece && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Scarabhusk && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Wyrmhide && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Lightplate && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 3) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Shadowplate && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddefense] >= 10 // Socketed Eth Sup +[Name] == Sacredarmor && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddefense] >= 10 // Socketed Eth Sup + +//----------------------------------------------- +//================= Helmet Bases ================ +//----------------------------------------------- +//([Name] == Corona || [Name] == Demonhead || [Name] == Bonevisage || [Name] == Diadem) && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 +//([Name] == Corona || [Name] == Demonhead || [Name] == Bonevisage || [Name] == Diadem) && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 3 // 3os Socketed +([Name] == Corona || [Name] == Demonhead || [Name] == Bonevisage || [Name] == Diadem) && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] == 0 // Delirium Or Dream Perfect +([Name] == Corona || [Name] == Demonhead || [Name] == Bonevisage || [Name] == Diadem) && [Quality] == Superior && [Flag] != Ethereal # [Enhanceddefense] >= 10 && [Sockets] == 3 // 3os Socketed Delirium Or Dream Perfect + +//------------------------------------------------------- +//================= Barbarian Helm Bases ================ +//------------------------------------------------------- + +// <<<<<<<<< [ Non-Ethereal Socketed/Non-Socketed Barbarian Helms ] >>>>>>>>> +[Type] == Primalhelm && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skillbattleorders]+[Skillbattlecommand] >= 4 || [Skillbattleorders]+[Skillfinditem] >= 4 || [Skillbattleorders]+[Skillshout] >= 4) && [Sockets] == 0 +[Type] == Primalhelm && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skillbattleorders]+[Skillbattlecommand] >= 4 || [Skillbattleorders]+[Skillfinditem] >= 4 || [Skillbattleorders]+[Skillshout] >= 4) && [Sockets] == 3 // Socketed + +//--------------------------------------------------- +//================= Druid Pelt Bases ================ +//--------------------------------------------------- + +// <<<<<<<<< [ Non-Ethereal Socketed/Non-Socketed Superior/Non-Superior Druid Pelts ] >>>>>>>>> +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 0 +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 3 // Socketed +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 0 +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 3 // Socketed +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 0 +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 3 // Socketed +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 0 +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 3 // Socketed +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 0 +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 3 // Socketed +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 0 +[Type] == Pelt && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 3 // Socketed + + +//----------------------------------------------- +//================= Shield Bases ================ +//----------------------------------------------- + +// <<<<<<<<< [ White/Eth Superior/Non-Superior Socketed/Non-Socketed Shields ] >>>>>>>>> +//([Name] == Akarantarge || [Name] == Akaranrondache || [Name] == Crownshield) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Allresist] >= 40 // V/Lld Paladin Shield Base +//[Name] == Monarch && [Quality] == Normal # [Sockets] == 0 // Plain Monarch +[Name] == Monarch && [Quality] == Normal # [Sockets] == 4 //4os Monarch +[Name] == Monarch && [Quality] == Superior # [Enhanceddefense] >= 10 && [Sockets] == 0 //Superior Plain Monarch +[Name] == Monarch && [Quality] == Superior # [Enhanceddefense] >= 10 && [Sockets] == 4 //4os Superior Monarch +[Name] == Monarch && [Quality] == Superior && [Flag] == Ethereal # [Enhanceddefense] >= 10 && ([Sockets] == 0 || [Sockets] == 4) //4os Eth Monarch +[Name] == Monarch && [Quality] == Superior && [Flag] == Ethereal # [Enhanceddefense] >= 15 && ([Sockets] == 0 || [Sockets] == 4) // 4os Eth Superior Monarch +[Type] == Auricshields && [Quality] == Normal && [Class] == Elite # [Allresist] >= 40 && [Sockets] == 0 // Plain 40+ All Res+ Paladin Shield +[Type] == Auricshields && [Quality] == Normal && [Class] == Elite # [Allresist] >= 40 && [Sockets] >= 3 // 3os+ 40 All Res+ Paladin Shield +[Type] == Auricshields && [Quality] == Superior && [Class] == Elite # [Allresist] >= 40 && [Enhanceddefense] >= 10 && [Sockets] == 0 // 40+ All Res+ Superior Paladin Shield +[Type] == Auricshields && [Quality] == Superior && [Class] == Elite # [Allresist] >= 40 && [Enhanceddefense] >= 10 && [Sockets] >= 3 // 3os+ 40 All Res+ Superior Paladin Shield +[Type] == Auricshields && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # [Allresist] >= 40 && ([Sockets] == 0 || [Sockets] >= 4) // Eth Exile +[Type] == Auricshields && [Quality] == Superior && [Flag] == Ethereal # [Enhanceddefense] > 10 && [Allresist] >= 40 && ([Sockets] == 0 || [Sockets] >= 4) // Superior Eth Exile + +//------------------------------------------------------------ +//================= Necromancer Offhand Bases ================ +//------------------------------------------------------------ + +// <<<<<<<<< [ Non-Ethereal Socketed/Non-Socketed Superior/Non-Superior Necro Offhands ] >>>>>>>>> +[Type] == Voodooheads && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skillbonespear]+[Skillbonespirit] >= 6 || [Skillpoisonexplosion]+[Skillpoisonnova] >= 6) && [Sockets] == 0 +[Type] == Voodooheads && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skillbonespear]+[Skillbonespirit] >= 6 || [Skillpoisonexplosion]+[Skillpoisonnova] >= 6) && [Sockets] == 3 // Socketed + +//----------------------------------------------------- +//================= 1h Weapon Bases ================ +//----------------------------------------------------- + +// <<<<<<<<< [ Non-Ethereal 1h Non-Socketed Weapons ] >>>>>>>>> +//[Name] == Berserkeraxe && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Crystalsword && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Flail && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Phaseblade && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Warscepter && [Quality] == Normal && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 0 // Plain +//[Name] == Divinescepter && [Quality] == Normal && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 0 // Plain +//[Name] == Crypticsword && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Mythicalsword && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain + +// <<<<<<<<< [ Non-Ethereal Superior 1h Non-Socketed Weapons ] >>>>>>>>> +[Name] == Berserkeraxe && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +[Name] == Crystalsword && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +[Name] == Flail && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +[Name] == Phaseblade && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +[Name] == Warscepter && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Enhanceddamage] >= 0 // Plain Superior +[Name] == Divinescepter && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Enhanceddamage] >= 0 // Plain Superior +[Name] == Caduceus && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Enhanceddamage] >= 0 // Plain Superior +[Name] == Crypticsword && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +[Name] == Mythicalsword && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior + +// <<<<<<<<< [ Non-Ethereal 1h Socketed Weapons ] >>>>>>>>> +//[Name] == Berserkeraxe && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 5 // Socketed +//[Name] == Crystalsword && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Flail && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Phaseblade && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 5 // Socketed +//[Name] == Warscepter && [Quality] == Normal && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 // Socketed +//[Name] == Divinescepter && [Quality] == Normal && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 // Socketed +//[Name] == Caduceus && [Quality] == Normal && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) // Socketed +//[Name] == Caduceus && [Quality] == Normal && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 // Socketed +//[Name] == Crypticsword && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 3 // Socketed +//[Name] == Mythicalsword && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 3 // Socketed + +// <<<<<<<<< [ Non-Ethereal Superior 1h Socketed Weapons ] >>>>>>>>> +[Name] == Berserkeraxe && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 5 && [Enhanceddamage] >= 10 // Socketed Superior +[Name] == Crystalsword && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Superiro +[Name] == Flail && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 14 // Socketed Superior +[Name] == Phaseblade && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 5 && [Enhanceddamage] >= 10 // Socketed Superior +[Name] == Warscepter && [Quality] == Superior && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 && [Enhanceddamage] >= 0 // Socketed Superior +[Name] == Divinescepter && [Quality] == Superior && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 && [Enhanceddamage] >= 0 // Socketed Superior +[Name] == Caduceus && [Quality] == Superior && [Flag] != Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 && [Enhanceddamage] >= 0 // Socketed Superior +[Name] == Crypticsword && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 3 // Socketed Superior +[Name] == Mythicalsword && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 3 // Socketed Superior + +// <<<<<<<<< [ Ethereal 1h Superior/Non-Superior Socketed/Non-Socketed Weapons ] >>>>>>>>> +[Name] == Berserkeraxe && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 5) // Socketed Eth +[Name] == Crystalsword && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Flail && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Phaseblade && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 5) // Socketed Eth +[Name] == Warscepter && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && ([Sockets] == 0 || [Sockets] == 5) // Socketed Eth +[Name] == Divinescepter && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && ([Sockets] == 0 || [Sockets] == 5) // Socketed Eth +[Name] == Caduceus && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && ([Sockets] == 0 || [Sockets] == 5) // Socketed Eth +[Name] == Crypticsword && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 3) // Socketed Eth +[Name] == Mythicalsword && ([Quality] == Normal || [Quality] == Superior) && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] == 3) // Socketed Eth + +// <<<<<<<<< [ Ethereal Superior 1h Socketed/Non-Socketed Weapons ] >>>>>>>>> +[Name] == Berserkeraxe && [Quality] == Superior && [Flag] == Ethereal # [Enhanceddamage] >= 10 && ([Sockets] == 0 || [Sockets] >= 5) // Socketed Eth Sup //Death, Ebotd + +//----------------------------------------------------- +//================= 2h Weapon Bases ================ +//----------------------------------------------------- + +// <<<<<<<<< [Non-Ethereal 2h Non-Superior Non-Socketed Weapons ] >>>>>>>>> +//[Name] == Warpike && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Colossusvoulge && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Thresher && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Giantthresher && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Crypticaxe && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Greatpoleaxe && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Ghostspear && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain +//[Name] == Mancatcher && [Quality] == Normal && [Flag] != Ethereal # [Sockets] == 0 // Plain + +// <<<<<<<<< [ Non-Ethereal 2h Non-Superior Socketed Weapons ] >>>>>>>>> +//[Name] == Warpike && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Colossusvoulge && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Thresher && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Giantthresher && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Crypticaxe && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Greatpoleaxe && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Ghostspear && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed +//[Name] == Mancatcher && [Quality] == Normal && [Flag] != Ethereal # [Sockets] >= 4 // Socketed + + +// <<<<<<<<< [ Non-Ethereal 2h Superior Non Socketed Weapons ] >>>>>>>>> +//[Name] == Warpike && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Colossusvoulge && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Thresher && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Giantthresher && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Crypticaxe && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Greatpoleaxe && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Ghostspear && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior +//[Name] == Mancatcher && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddamage] >= 10 // Plain Superior + + +// <<<<<<<<< [ Non-Ethereal 2h Superior Socketed Weapons ] >>>>>>>>> +//[Name] == Warpike && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Colossusvoulge && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Thresher && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Giantthresher && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Crypticaxe && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Greatpoleaxe && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Ghostspear && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup +//[Name] == Mancatcher && [Quality] == Superior && [Flag] != Ethereal # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup + +// <<<<<<<<< [ Ethereal 2h Socketed/Non-Socketed Weapons ] >>>>>>>>> +[Name] == Warpike && [Quality] == Normal && [Flag] == Ethereal # [Sockets] == 6 +[Name] == Colossusvoulge && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Thresher && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Giantthresher && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Crypticaxe && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Greatpoleaxe && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Ghostspear && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth +[Name] == Mancatcher && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth + +// <<<<<<<<< [ Ethereal Superior 2h Socketed/Non-Socketed Weapons ] >>>>>>>>> +[Name] == Warpike && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Colossusvoulge && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Thresher && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Giantthresher && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Crypticaxe && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Greatpoleaxe && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Ghostspear && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup +[Name] == Mancatcher && [Quality] == Superior && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) && [Enhanceddamage] >= 10 // Socketed Eth Sup + +//------------------------------------------------------ +//================= Assassin Claw Bases ================ +//------------------------------------------------------ + +// <<<<<<<<< [ Non-Ethereal Superior/Non-Superior Assassin Claws ] >>>>>>>>> +([Name] == Suwayyah || [Name] == FeralClaws || [Name] == RunicTalons || [Name] == GreaterTalons || [Name] == GreaterClaws) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [SkillLightningsentry] >= 3 && [Skillfade] >= 3 && ([Skillbladeshield] >= 3 || [Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillvenom] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos +([Name] == Suwayyah || [Name] == FeralClaws || [Name] == RunicTalons || [Name] == GreaterTalons || [Name] == GreaterClaws) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [SkillLightningsentry] >= 3 && [Skillfade] >= 3 && ([Skillbladeshield] >= 3 || [Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillvenom] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed +([Name] == Suwayyah || [Name] == FeralClaws || [Name] == RunicTalons || [Name] == GreaterTalons || [Name] == GreaterClaws) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [SkillLightningsentry] >= 3 && [Skillmindblast] >= 3 && ([Skillweaponblock] >= 2 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2) && [Sockets] == 0 // Chaos +([Name] == Suwayyah || [Name] == FeralClaws || [Name] == RunicTalons || [Name] == GreaterTalons || [Name] == GreaterClaws) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [SkillLightningsentry] >= 3 && [Skillmindblast] >= 3 && ([Skillweaponblock] >= 2 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2) && [Sockets] == 3 // Chaos Socketed +([Name] == Suwayyah || [Name] == FeralClaws || [Name] == RunicTalons || [Name] == GreaterTalons || [Name] == GreaterClaws) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [SkillLightningsentry] >= 3 && [Skillvenom] >= 3 && ([Skillweaponblock] >= 2 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos +([Name] == Suwayyah || [Name] == FeralClaws || [Name] == RunicTalons || [Name] == GreaterTalons || [Name] == GreaterClaws) && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [SkillLightningsentry] >= 3 && [Skillvenom] >= 3 && ([Skillweaponblock] >= 2 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed + +//----------------------------------------------- +//================= Staves Bases ================ +//----------------------------------------------- + +// <<<<<<<<< [ Ethereal/Non-Ethereal Superior/Non-Superior Socketed/Non-Socketed Staves ] >>>>>>>>> +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenergyshield] >= 3 && ([Skillchillingarmor] >= 2 || [skillthunderstorm] >= 2) && [Sockets] == 0 // Energy Shield Memory +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenergyshield] >= 3 && ([Skillchillingarmor] >= 2 || [skillthunderstorm] >= 2) && [Sockets] >= 4 // Energy Shield Memory Socketed +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillthunderstorm] >= 3 && ([Skillenergyshield] >= 2 || [Skillchillingarmor] >= 2) && [Sockets] == 0 // Thunderstorm Memory +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillthunderstorm] >= 3 && ([Skillenergyshield] >= 2 || [Skillchillingarmor] >= 2) && [Sockets] >= 4 // Thunderstorm Memory Socketed +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillchillingarmor] >= 3 && ([Skillthunderstorm] >= 2 || [Skillenergyshield] >= 2) && [Sockets] == 0 // Chilling armor Memory +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillchillingarmor] >= 3 && ([Skillthunderstorm] >= 2 || [Skillenergyshield] >= 2) && [Sockets] >= 4 // Chilling armor Memory Socketed +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenchant] >= 3 && [Skillwarmth] == 2 && [Sockets] == 0 // Enchant Memory +([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenchant] >= 3 && [Skillwarmth] == 2 && [Sockets] >= 4 // Enchant Memory Socketed +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillchillingarmor] >= 2 && [Skillthunderstorm] >= 2 && ([Skillenergyshield] >= 2 || [Skillenchant] >= 2) && [Sockets] == 0 // Cta +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillchillingarmor] >= 2 && [Skillthunderstorm] >= 2 && ([Skillenergyshield] >= 2 || [Skillenchant] >= 2) && [Sockets] == 5 // Cta Socketed +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillchainlightning] >= 3 && ([Skilllightningmastery] >= 2 || [Skilllightning] >= 2 || [Skillthunderstorm] >= 2) && [Skillenergyshield] >= 0 && [Sockets] == 0 // Lightning Obsession +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillchainlightning] >= 3 && ([Skilllightningmastery] >= 2 || [Skilllightning] >= 2 || [Skillthunderstorm] >= 2) && [Skillenergyshield] >= 0 && [Sockets] == 6 // Lightning Obsession socketed +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillblizzard] >= 3 && ([Skilliceblast] >= 2 || [Skillfrozenorb] >= 2 || [Skillwarmth] >= 2) && [Skillchillingarmor] >= 0 && [Sockets] >= 0 // Blizzard Obsession +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillblizzard] >= 3 && ([Skilliceblast] >= 2 || [Skillfrozenorb] >= 2 || [Skillwarmth] >= 2) && [Skillchillingarmor] >= 0 && [Sockets] >= 6 // Obsession Socketed +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillfireball] >= 3 && ([Skillmeteor] >= 2 || [Skillfirebolt] >= 2 || [Skillwarmth] >= 2) && [Skillchillingarmor] >= 0 && [Sockets] >= 0 // Fireball Obsession +([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillfireball] >= 3 && ([Skillmeteor] >= 2 || [Skillfirebolt] >= 2 || [Skillwarmth] >= 2) && [Skillchillingarmor] >= 0 && [Sockets] >= 6 // Fireball Obsession socketed + +//--------------------------------------------------------- +//================= Necromancer Wand Bases ================ +//--------------------------------------------------------- + +// <<<<<<<<< [ Ethereal/Non-Ethereal Superior/Non-Superior Socketed/Non-Socketed Necromancer Wands ] >>>>>>>>> +[Type] == Wand && ([Quality] == Normal || [Quality] == Superior) # [Skillbonespear] >= 3 && ([Skillbonespirit] >= 3 || [Skillteeth] >= 3 || [Skillpoisonnova] >= 3 || [Skilldecrepify] >= 3) && ([Skilldecrepify] >= 1 || [Skillironmaiden] >= 1 || [Skillteeth] >= 1 || [Skillbonearmor] >= 1 || [Skilllowerresist] >= 1) && [Sockets] == 0 // White Wand +[Type] == Wand && ([Quality] == Normal || [Quality] == Superior) # [Skillbonespear] >= 3 && ([Skillbonespirit] >= 3 || [Skillteeth] >= 3 || [Skillpoisonnova] >= 3 || [Skilldecrepify] >= 3) && ([Skilldecrepify] >= 1 || [Skillironmaiden] >= 1 || [Skillteeth] >= 1 || [Skillbonearmor] >= 1 || [Skilllowerresist] >= 1) && [Sockets] == 2 // White Wand Socketed + +//--------------------------------------------------- +//================= Amazon Bow Bases ================ +//--------------------------------------------------- + +// <<<<<<<<< [ Socketed Amazon Bows ] >>>>>>>>> +//[Type] == Bow && [Class] == Elite && [Quality] == Normal # [Sockets] == 0 // Faith +[Type] == Bow && [Class] == Elite && [Quality] == Normal # [Sockets] >= 4 // Faith/Mist Socketed +//[Type] == Amazonbow && [Class] == Elite && [Quality] == Normal # [Bowandcrossbowskilltab] == 3 && [Sockets] == 0 // Faith +[Type] == Amazonbow && [Class] == Elite && [Quality] == Normal # [Bowandcrossbowskilltab] == 3 && [Sockets] >= 4 // Faith/Mist Socketed + +// <<<<<<<<< [ Superior Socketed Amazon Bows ] >>>>>>>>> +//[Type] == Bow && [Class] == Elite && [Quality] == Normal # [Enhanceddamage] > 10 && [Sockets] == 0 // Faith +[Type] == Bow && [Class] == Elite && [Quality] == Superior # [Enhanceddamage] > 10 && [Sockets] == 4 // Faith +//[Type] == Amazonbow && [Class] == Elite && [Quality] == Superior # [Bowandcrossbowskilltab] == 3 && [Enhanceddamage] > 10 && [Sockets] == 0 // Faith +[Type] == Amazonbow && [Class] == Elite && [Quality] == Superior # [Bowandcrossbowskilltab] == 3 && [Enhanceddamage] > 10 && [Sockets] == 4 // Faith + +//=======================================================================// +//<<<<<<<<<<<<<<<<<<<<<<<<<<<< Set Items >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// +//=======================================================================// + +//-------------------------------------------------- +//================= Angelic Raiment ================ +//-------------------------------------------------- + +//[Name] == Ringmail && [Quality] == Set // Angelic Mantle +//[Name] == Sabre && [Quality] == Set // Angelic Sickle +//[Type] == Ring && [Quality] == Set # [Maxhp] == 20 // Angelic Halo +//[Type] == Amulet && [Quality] == Set # [Itemlightradius] == 3 && [Itemdamagetomana] == 20 // Angelic Wings + +//--------------------------------------------------- +//================= Arcanna's Tricks ================ +//--------------------------------------------------- + +//[Type] == Amulet && [Quality] == Set # [Maxmana] == 15 // Arcanna's Sign +//[Name] == Skullcap && [Quality] == Set // Arcanna's Head +//[Name] == Lightplate && [Quality] == Set // Arcanna's Flesh +//[Name] == Warstaff && [Quality] == Set // Arcanna's Deathwand + +//---------------------------------------------- +//================= Arctic Gear ================ +//---------------------------------------------- + +//[Name] == Quiltedarmor && [Quality] == Set // Arctic Furs +//[Name] == Lightbelt && [Quality] == Set // Arctic Binding +//[Name] == Lightgauntlets && [Quality] == Set # [Maxhp] == 20 && [Ias] == 10 // Arctic Mitts +//[Name] == Shortwarbow && [Quality] == Set // Arctic Horn + +//------------------------------------------------------ +//================= Berserker's Arsenal ================ +//------------------------------------------------------ + +//[Name] == Helm && [Quality] == Set // Berserker's Headgear +//[Name] == Splintmail && [Quality] == Set // Berserker's Hauberk +//[Name] == Doubleaxe && [Quality] == Set // Berserker's Hatchet + +//------------------------------------------------- +//================= Cathan's Traps ================ +//------------------------------------------------- + +//[Type] == Ring && [Quality] == Set # [Lifeleech] == 6 && [Normaldamagereduction] == 2 // Cathan's Seal +//[Type] == Amulet && [Quality] == Set # [Fhr] == 10 && [Lightmaxdam] == 5 // Cathan's Sigil +//[Name] == Chainmail && [Quality] == Set // Cathan's Mesh +//[Name] == Mask && [Quality] == Set // Cathan's Visage + +//---------------------------------------------------- +//================= Civerb's Vestment ================ +//---------------------------------------------------- + +//[Name] == Grandscepter && [Quality] == Set // Civerb's Cudgel +//[Type] == Amulet && [Quality] == Set # [Manarecovery] == 40 && [Hpregen] == 4 // Civerb's Icon +//[Name] == Largeshield && [Quality] == Set // Civerb's Ward + +//--------------------------------------------------- +//================= Cleglaw's Braces ================ +//--------------------------------------------------- + +//[Name] == Longsword && [Quality] == Set // Cleglaw's Tooth +//[Name] == Chaingloves && [Quality] == Set // Cleglaw's Pincers +//[Name] == Smallshield && [Quality] == Set // Cleglaw's Claw + +//------------------------------------------------ +//================= Death's Guise ================ +//------------------------------------------------ + +//[Name] == Warsword && [Quality] == Set // Death's Touch +//[Name] == Leathergloves && [Quality] == Set // Death's Hand +//[Name] == Sash && [Quality] == Set // Death's Guard + +//-------------------------------------------------- +//================= Hsaru's Defense ================ +//-------------------------------------------------- + +//[Name] == Buckler && [Quality] == Set // Hsarus' Iron Fist +//[Name] == Belt && [Quality] == Set # [Coldresist] == 20 && [Maxhp] == 20 // Hsarus' Iron Stay +//[Name] == Chainboots && [Quality] == Set // Hsarus' Iron Heel + +//------------------------------------------------- +//================= Infernal Tools ================ +//------------------------------------------------- + +//[Name] == Cap && [Quality] == Set # [Fireresist] == 10 && [Lightresist] == 10 && [Coldresist] == 10 && [Poisonresist] == 10 // Infernal Cranium +//[Name] == Grimwand && [Quality] == Set // Infernal Touch +//[Name] == Heavybelt && [Quality] == Set # [Maxhp] == 20 && [Enhanceddefense] == 25 // Infernal Sign + +//-------------------------------------------------- +//================= Iratha's Finery ================ +//-------------------------------------------------- + +//[Name] == Heavybelt && [Quality] == Set # [Mindamage] == 5 // Iratha's Cord +//[Name] == Crown && [Quality] == Set # [Fireresist] == 30 && [Lightresist] == 30 // Iratha's Coil +//[Type] == Amulet && [Quality] == Set # [Poisonresist] == 30 && [Poisonlength] == -75 // Iratha's Collar +//[Name] == Lightgauntlets && [Quality] == Set # [Coldresist] == 30 // Iratha's Cuff + +//---------------------------------------------------- +//================= Isenhart's Armory ================ +//---------------------------------------------------- + +//[Name] == Broadsword && [Quality] == Set // Isenhart's Lightbrand +//[Name] == Fullhelm && [Quality] == Set // Isenhart's Horns +//[Name] == Breastplate && [Quality] == Set // Isenhart's Case +//[Name] == Gothicshield && [Quality] == Set // Isenhart's Parry + +//------------------------------------------------------ +//================= Milabrega's Regalia ================ +//------------------------------------------------------ + +//[Name] == Kiteshield && [Quality] == Set // Milabrega's Orb +//[Name] == Ancientarmor && [Quality] == Set // Milabrega's Robe +//[Name] == Warscepter && [Quality] == Set // Milabrega's Rod +//[Name] == Crown && [Quality] == Set # [Maxhp] == 15 && [Maxmana] == 15 // Milabrega's Diadem + +//------------------------------------------------ +//================= Sigon's Steel ================ +//------------------------------------------------ + +//[Name] == Greathelm && [Quality] == Set // Sigon's Visor +//[Name] == Gothicplate && [Quality] == Set // Sigon's Shelter +//[Name] == Greaves && [Quality] == Set // Sigon's Sabot +//[Name] == Towershield && [Quality] == Set // Sigon's Guard +//[Name] == Platedbelt && [Quality] == Set // Sigon's Warp +//[Name] == Gauntlets && [Quality] == Set // Sigon's Gage + +//------------------------------------------------------- +//================= Tancred's Battlegear ================ +//------------------------------------------------------- + +//[Name] == Bonehelm && [Quality] == Set // Tancred's Skull +//[Name] == Fullplatemail && [Quality] == Set // Tancred's Spine +//[Name] == Boots && [Quality] == Set # [Staminarecoverybonus] == 25 && [Dexterity] == 10 // Tancred's Hobnails +//[Name] == Militarypick && [Quality] == Set // Tancred's Crowbill +//[Type] == Amulet && [Quality] == Set # [Magicdamagereduction] == 1 && [Normaldamagereduction] == 2 // Tancred's Weird + +//----------------------------------------------- +//================= Vidala's Rig ================ +//----------------------------------------------- + +//[Type] == Amulet && [Quality] == Set # [Coldresist] == 20 && [Maxmana] == 15 // Vidala's Snare +//[Name] == Longbattlebow && [Quality] == Set // Vidala's Barb +//[Name] == Leatherarmor && [Quality] == Set // Vidala's Ambush +//[Name] == Lightplatedboots && [Quality] == Set // Vidala's Fetlock + +//----------------------------------------------------- +//================= Aldur's Watchtower ================ +//----------------------------------------------------- + +//[Name] == Huntersguise && [Quality] == Set // Aldur's Stony Gaze +//[Name] == Battleboots && [Quality] == Set // Aldur's Advance +//[Name] == Shadowplate && [Quality] == Set // Aldur's Deception +//[Name] == Jaggedstar && [Quality] == Set // Aldur's Rhythm + +//------------------------------------------------------- +//================= Bul-Katho's Children ================ +//------------------------------------------------------- + +//[Name] == Colossusblade && [Quality] == Set // Bul-Kathos' Sacred Charge +//[Name] == Mythicalsword && [Quality] == Set // Bul-Kathos' Tribal Guardian + +//------------------------------------------------------ +//================= Cow King's Leathers ================ +//------------------------------------------------------ + +//[Name] == Warhat && [Quality] == Set // Cow King's Horns +//[Name] == Studdedleather && [Quality] == Set // Cow King's Hide +//[Name] == Heavyboots && [Quality] == Set # [Dexterity] == 20 && [Itemmagicbonus] == 25 // Cow King's Hooves + +//----------------------------------------------- +//================= The Disciple ================ +//----------------------------------------------- + +//[Type] == Amulet && [Quality] == Set # [Itemallskills] == 1 && [Coldresist] == 18 // Telling Of Beads +//[Name] == Bramblemitts && [Quality] == Set // Laying Of Hands +//[Name] == Duskshroud && [Quality] == Set // Dark Adherent +//[Name] == Demonhideboots && [Quality] == Set // Rite Of Passage +//[Name] == Mithrilcoil && [Quality] == Set //Credendum + +//---------------------------------------------------- +//================= Griswold's Legacy ================ +//---------------------------------------------------- + +//[Name] == Ornateplate && [Quality] == Set // Griswold's Heart +//[Name] == Corona && [Quality] == Set # [Itemmagicbonus] >= 20 // Griswold's Valor +//[Name] == Corona && [Quality] == Set # [Itemmagicbonus] >= 30 && [Enhanceddefense] >= 75 // Griswold's Valor Perfect +//[Name] == Caduceus && [Quality] == Set # [Sockets] >= 3 && [Enhanceddamage] >= 200 // Griswold's Redemption +//[Name] == Caduceus && [Quality] == Set # [Sockets] >= 4 && [Enhanceddamage] >= 240 // Griswold's Redemption Perfect +//[Name] == Vortexshield && [Quality] == Set // Griswold's Honor +//[Name] == Vortexshield && [Quality] == Set # [Defense] >= 330 // Griswold's Honor Perfect + + +//----------------------------------------------------- +//================= Heaven's Bretheren ================ +//----------------------------------------------------- + +//[Name] == Cuirass && [Quality] == Set // Haemosu's Adamant +//[Name] == Reinforcedmace && [Quality] == Set // Dangoon's Teaching +//[Name] == Ward && [Quality] == Set // Taebaek's Glory +//[Name] == Spiredhelm && [Quality] == Set // Ondal's Almighty + +//--------------------------------------------------- +//================= Hwanin's Majesty ================ +//--------------------------------------------------- + +//[Name] == Grandcrown && [Quality] == Set // Hwanin's Splendor +//[Name] == Bill && [Quality] == Set // Hwanin's Justice +//[Name] == Tigulatedmail && [Quality] == Set // Hwanin's Refuge +//[Name] == Belt && [Quality] == Set # [Lightmindam] == 3 && [Lightmaxdam] == 33 // Hwanin's Blessing + +//------------------------------------------------ +//================= Immortal King ================ +//------------------------------------------------ + +//[Name] == Warbelt && [Quality] == Set // Immortal King's Detail +//[Name] == Avengerguard && [Quality] == Set // Immortal King's Will +//[Name] == Ogremaul && [Quality] == Set // Immortal King's Stone Crusher +[Name] == Sacredarmor && [Quality] == Set // Immortal King's Soul Cage +//[Name] == Wargauntlets && [Quality] == Set // Immortal King's Forge +//[Name] == Warboots && [Quality] == Set // Immortal King's Pillar + +//-------------------------------------------------------- +//================= M'Avina's Battle Hymn ================ +//-------------------------------------------------------- + +// M'Avina's Battle Hymn +//[Name] == Diadem && [Quality] == Set // M'Avina's True Sight +//[Name] == Grandmatronbow && [Quality] == Set // M'Avina's Caster +//[Name] == Krakenshell && [Quality] == Set // M'Avina's Embrace +//[Name] == Battlegauntlets && [Quality] == Set // M'Avina's Icy Clutch +//[Name] == Sharkskinbelt && [Quality] == Set // M'Avina's Tenet + +//-------------------------------------------------- +//================= Natalya's Odium ================ +//-------------------------------------------------- +// Natalya's Odium +//[Name] == Grimhelm && [Quality] == Set // Natalya's Totem +//[Name] == Scissorssuwayyah && [Quality] == Set // Natalya's Mark +//[Name] == Loricatedmail && [Quality] == Set # [Defense] >= 721 && [Sockets] >= 3 // Natalya's Shadow +//[Name] == Meshboots && [Quality] == Set # [Lightresist] >= 25 && [Coldresist] >= 25 // Natalya's Soul + +//-------------------------------------------------------- +//================= Naj's Ancient Vestege ================ +//-------------------------------------------------------- + +//[Name] == Circlet && [Quality] == Set // Naj's Circlet +//[Name] == Hellforgeplate && [Quality] == Set // Naj's Light Plate +//[Name] == Elderstaff && [Quality] == Set // Naj's Puzzler + +//------------------------------------------------ +//================= Orphan's Call ================ +//------------------------------------------------ + +//[Name] == Wingedhelm && [Quality] == Set // Guillaume's Face +//[Name] == Roundshield && [Quality] == Set // Whistan's Guard +//[Name] == Sharkskingloves && [Quality] == Set // Magnus' Skin +//[Name] == Battlebelt && [Quality] == Set // Wilhelm's Pride + +//------------------------------------------------- +//================= Sander's Folly ================ +//------------------------------------------------- + +//[Name] == Cap && [Quality] == Set # [Itemmagicbonus] == 35 // Sander's Paragon +//[Name] == Bonewand && [Quality] == Set //Sander's Superstition +//[Name] == Heavygloves && [Quality] == Set # [Maxhp] == 40 // Sander's Taboo +//[Name] == Heavyboots && [Quality] == Set # [Dexterity] == 10 && [Strength] == 5 // Sander's Riprap + +//--------------------------------------------------------- +//================= Sazabi's Grand Tribute ================ +//--------------------------------------------------------- + +//[Name] == Basinet && [Quality] == Set // Sazabi's Mental Sheath +//[Name] == Crypticsword && [Quality] == Set // Sazabi's Cobalt Redeemer +//[Name] == Balrogskin && [Quality] == Set // Sazabi's Ghost Liberator + +//-------------------------------------------------------- +//================= Tal-Rasha's Wrappings ================ +//-------------------------------------------------------- + +[Name] == Swirlingcrystal && [Quality] == Set // Tal Rasha's Lidless Eye +//[Name] == Swirlingcrystal && [Quality] == Set # [Plusskillcoldmastery] == 2 && [Plusskillfiremastery] == 2 && [Plusskilllightningmastery] == 2 // Tal Rasha's Lidless Eye Perfect +//[Name] == Deathmask && [Quality] == Set // Tal Rasha's Horadric Crest +[Name] == Lacqueredplate && [Quality] == Set // Tal Rasha's Guardianship +//[Name] == Lacqueredplate && [Quality] == Set # [Defense] >= 941 // Tal Rasha's Guardianship Perfect +[Type] == Amulet && [Quality] == Set # [Sorceressskills] == 2 // Tal Rasha's Adjucation +[Name] == Meshbelt && [Quality] == Set # [Itemmagicbonus] >= 10 // Tal Rasha's Fine-Spun Cloth +//[Name] == Meshbelt && [Quality] == Set # [Itemmagicbonus] == 15 // Tal Rasha's Fine-Spun Cloth Perfect + +//---------------------------------------------------- +//================= Trang-Ouls Avatar ================ +//---------------------------------------------------- + +//[Name] == Bonevisage && [Quality] == Set // Trang-Oul's Guise +//[Name] == Chaosarmor && [Quality] == Set // Trang-Oul's Scales +//[Name] == Cantortrophy && [Quality] == Set // Trang-Oul's Wing +//[Name] == Trollbelt && [Quality] == Set // Trang-Oul's Girth +[Name] == Heavybracers && [Quality] == Set // Trang-Oul's Claws + +//==========================================================================// +//<<<<<<<<<<<<<<<<<<<<<<<<<<<< Unique Items >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// +//==========================================================================// + +//----------------------------------------------- +//================= Unique Rings ================ +//----------------------------------------------- + +[Type] == Ring && [Quality] == Unique # [Itemmagicbonus] >= 15 // Nagelring +//[Type] == Ring && [Quality] == Unique # [Itemmagicbonus] == 30 && [Tohit] == 75 // Nagelring Perfect +//[Type] == Ring && [Quality] == Unique # [Hpregen] >= 5 && [Manaleech] >= 4 // Manald Heal +//[Type] == Ring && [Quality] == Unique # [Hpregen] == 8 && [Manaleech] == 7 // Manald Heal Perfect +[Type] == Ring && [Quality] == Unique # [Itemmaxmanapercent] >= 25 // Stone Of Jordan +[Type] == Ring && [Quality] == Unique # [Maxhp] >= 35 && [Magicdamagereduction] >= 12 // Dwarf Star +//[Type] == Ring && [Quality] == Unique # [Maxhp] >= 35 && [Magicdamagereduction] == 15 // Dwarf Star Perfect +[Type] == Ring && [Quality] == Unique # [Dexterity] >= 15 && [Tohit] >= 150 // Raven Frost +//[Type] == Ring && [Quality] == Unique # [Dexterity] == 20 && [Tohit] == 250 // Raven Frost Perfect +[Type] == Ring && [Quality] == Unique # [Lifeleech] >= 3 && [Itemallskills] == 1 // Bul-Kathos' Wedding Band +//[Type] == Ring && [Quality] == Unique # [Lifeleech] == 5 && [Itemallskills] == 1 // Bul-Kathos' Wedding Band Perfect +[Type] == Ring && [Quality] == Unique # [Poisonresist] >= 20 && [Normaldamagereduction] >= 7 // Nature's Peace +//[Type] == Ring && [Quality] == Unique # [Poisonresist] == 30 && [Normaldamagereduction] == 11 // Nature's Peace Perfect +[Type] == Ring && [Quality] == Unique # [Itemabsorblightpercent] >= 10 && [Itemmagicbonus] >= 10 // Wisp Protector +//[Type] == Ring && [Quality] == Unique # [Itemabsorblightpercent] == 20 && [Itemmagicbonus] == 20 // Wisp Protector Perfect +[Type] == Ring && [Quality] == Unique # [Lifeleech] >= 6 && [Armorclassvsmissile] >= 100 // Carrion Wind +//[Type] == Ring && [Quality] == Unique # [Lifeleech] == 9 && [Armorclassvsmissile] == 160 // Carrion Wind Perfect + +//------------------------------------------------- +//================= Unique Amulets ================ +//------------------------------------------------- + +//[Type] == Amulet && [Quality] == Unique # [Fireresist] >= 50 // Nokozan Relic +//[Type] == Amulet && [Quality] == Unique # [Lifeleech] >= 3 && [Armorclassvsmissile] >= 10 // The Eye Of Etlitch +//[Type] == Amulet && [Quality] == Unique # [Lifeleech] >= 7 && [Armorclassvsmissile] >= 40 // The Eye Of Etlitch Perfect +//[Type] == Amulet && [Quality] == Unique # [Allres] >= 10 && [Enhanceddefense] >= 10 // The Mahim-Oak Curio +//[Type] == Amulet && [Quality] == Unique # [Allres] >= 15 && [Strength] >= 12 // Saracen's Chance +//[Type] == Amulet && [Quality] == Unique # [Allres] == 25 && [Strength] >= 12 // Saracen's Chance Perfect +//[Type] == Amulet && [Quality] == Unique # [Dexterity] >= 25 && [Ias] >= 20 // The Cat's Eye +//[Type] == Amulet && [Quality] == Unique # [Lifeleech] >= 3 && [Manaleech] >= 11 // Crescent Moon +//[Type] == Amulet && [Quality] == Unique # [Lifeleech] == 6 && [Manaleech] == 15 // Crescent Moon Perfect +[Type] == Amulet && [Quality] == Unique # [Lightresist] >= 35 // Highlord's Wrath +//[Type] == Amulet && [Quality] == Unique # [Poisonresist] >= 75 // Atma's Scarab +[Type] == Amulet && [Quality] == Unique # [Hpregen] >= 10 && [Fireskilltab] >= 2 // The Rising Sun +[Type] == Amulet && [Quality] == Unique # [Itemallskills] == 2 && [Allresist] >= 20 // Mara's Kaleidoscope +//[Type] == Amulet && [Quality] == Unique # [Itemallskills] == 2 && [Allresist] == 30 // Mara's Kaleidoscope Perfect +//[Type] == Amulet && [Quality] == Unique # [Defensiveaurasskilltab] >= 1 // Seraph's Hymn +//[Type] == Amulet && [Quality] == Unique # [Defensiveaurasskilltab] == 2 && [Itemdemondamagepercent] == 50 && [Itemundeaddamagepercent] == 50 && [Itemdemontohit] == 250 && [Itemundeadtohit] == 250 // Seraph's Hymn Perfect +[Type] == Amulet && [Quality] == Unique # [Coldresist] >= 35 && [Plusdefense] >= 300 && [Allres] >= 25 && [Tohit] >= 400 // Metalgrid +//[Type] == Amulet && [Quality] == Unique # [Coldresist] == 45 && [Plusdefense] == 350 && [Allres] == 35 && [Tohit] == 450 // Metalgrid Perfect + +//------------------------------------------------ +//================= Unique Jewels ================ +//------------------------------------------------ + +[Name] == Jewel && [Quality] == Unique # [Passivecoldmastery] + [Passivecoldpierce] >= 9 // Rainbow Facet Cold +[Name] == Jewel && [Quality] == Unique # [Passivefiremastery] + [Passivefirepierce] >= 9 // Rainbow Facet Fire +[Name] == Jewel && [Quality] == Unique # [Passiveltngmastery] + [Passiveltngpierce] >= 9 // Rainbow Facet Light +[Name] == Jewel && [Quality] == Unique # [Passivepoismastery] + [Passivepoispierce] >= 9 // Rainbow Facet Poison + +//------------------------------------------------ +//================= Unique Gloves ================ +//------------------------------------------------ + +//[Name] == Heavygloves && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 10 // Bloodfist +//[Name] == Heavygloves && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 20 // Bloodfist Perfect +[Name] == Chaingloves && [Quality] == Unique && [Flag] != Ethereal # [Itemmagicbonus] >= 25 // Chance Guards +//[Name] == Chaingloves && [Quality] == Unique && [Flag] != Ethereal # [Itemmagicbonus] >= 40 && [Enhanceddefense] >= 30 // Chance Guards Perfect +[Name] == Lightgauntlets && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 20 // Magefist +//[Name] == Lightgauntlets && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 30 // Magefist Perfect +//[Name] == Gauntlets && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 10 // Frostburn +//[Name] == Gauntlets && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 20 // Frostburn Perfect +[Name] == Vampirebonegloves && [Quality] == Unique && [Flag] != Ethereal # [Strength] == 10 // Dracul's Grasp +//[Name] == Vampirebonegloves && [Quality] == Unique && [Flag] != Ethereal # [Strength] == 15 && [Lifeleech] >= 10 && [Enhanceddefense] >= 120 // Dracul's Grasp Perfect +[Name] == Ogregauntlets && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 30 && [Strength] >= 15 && [Plusdefense] >= 170 // Steelrend +//[Name] == Ogregauntlets && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 60 && [Strength] >= 20 && [Plusdefense] >= 210 // Steelrend Perfect + +//----------------------------------------------- +//================= Unique Belts ================ +//----------------------------------------------- + +//[Name] == Heavybelt && [Quality] == Unique && [Flag] != Ethereal # [Itemgoldbonus] >= 50 // Goldwrap +//[Name] == Heavybelt && [Quality] == Unique && [Flag] != Ethereal # [Itemgoldbonus] >= 80 && [Enhanceddefense] >= 60 // Goldwrap Perfect +//[Name] == Demonhidesash && [Quality] == Unique && [Flag] != Ethereal # [Lifeleech] >= 6 && [Damageresist] >= 12 && [Magicdamagereduction] >= 12 && [Enhanceddefense] >= 150 // String Of Ears +//[Name] == Demonhidesash && [Quality] == Unique && [Flag] != Ethereal # [Lifeleech] >= 8 && [Damageresist] >= 15 && [Magicdamagereduction] >= 15 && [Enhanceddefense] >= 180 // String Of Ears Perfect +//[Name] == Sharkskinbelt && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Plusdefense] >= 15 // Razortail +//[Name] == Sharkskinbelt && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Plusdefense] >= 15 // Razortail Perfect +//[Name] == Battlebelt && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 130 // Snowclash +//[Name] == Battlebelt && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 170 // Snowclash Perfect +[Name] == Warbelt && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 160 // Thundergod's Vigor +//[Name] == Warbelt && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 200 // Thundergod's Vigor Perfect +[Name] == Spiderwebsash && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 90 // Arachnid Mesh +//[Name] == Spiderwebsash && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 // Arachnid Mesh Perfect +//[Name] == Vampirefangbelt && [Quality] == Unique && [Flag] != Ethereal # [Lifeleech] >= 5 && [Defense] >= 50 // Nosferatu's Coil +//[Name] == Vampirefangbelt && [Quality] == Unique && [Flag] != Ethereal # [Lifeleech] >= 7 && [Defense] >= 60 // Nosferatu's Coil Perfect +[Name] == Mithrilcoil && [Quality] == Unique && [Flag] != Ethereal # [Damageresist] >= 10 && [Enhanceddefense] >= 90 && [Hpregen] >= 10 // Verdungo's Hearty Cord +//[Name] == Mithrilcoil && [Quality] == Unique && [Flag] != Ethereal # [Damageresist] >= 15 && [Enhanceddefense] >= 140 && [Hpregen] >= 13 // Verdungo's Hearty Cord Perfect + +//----------------------------------------------- +//================= Unique Boots ================ +//----------------------------------------------- + +//[Name] == Boots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 10 // Hotspurs +//[Name] == Boots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 20 // Hotspurs Perfect +//[Name] == Lightplatedboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 50 // Goblin Toes +//[Name] == Lightplatedboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 60 // Goblin Toes Perfect +//[Name] == Demonhideboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Itemgoldbonus] >= 40 // Infernostride +[Name] == Demonhideboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 150 && [Itemgoldbonus] == 70 // Infernostride Perfect +//[Name] == Sharkskinboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 180 // Waterwalk +//[Name] == Sharkskinboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 210 // Waterwalk Perfect +//[Name] == Meshboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 // Silkweave +//[Name] == Meshboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 190 // Silkweave Perfect +[Name] == Battleboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Itemgoldbonus] >= 30 // War Traveler +//[Name] == Battleboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 190 && [Itemgoldbonus] == 50 // War Traveler Perfect +//[Name] == Warboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 160 // Gore Rider +[Name] == Warboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 // Gore Rider Perfect +[Name] == Scarabshellboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 140 && [Strength] >= 10 && [Vitality] >= 10 && [Poisonresist] >= 40 // Sandstorm Trek +[Name] == Scarabshellboots && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 140 && [Strength] >= 10 && [Vitality] >= 10 && [Poisonresist] >= 40 // Eth Sandstorm Trek +//[Name] == Scarabshellboots && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 170 && [Strength] == 15 && [Vitality] == 15 && [Poisonresist] == 70 // Eth Sandstorm Trek Perfect +//[Name] == Boneweaveboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 170 && [Strength] >= 10 && [Skillskeletonmastery] >= 1 // Marrowwalk +//[Name] == Boneweaveboots && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 && [Strength] == 20 && [Skillskeletonmastery] == 2 // Marrowwalk Perfect +[Name] == Myrmidongreaves && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 70 && [Shadowdisciplinesskilltab] >= 2 && [Dexterity] >= 20 // Shadow Dancer +//[Name] == Myrmidongreaves && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 100 && [Shadowdisciplinesskilltab] == 2 && [Dexterity] == 25 // Shadow Dancer Perfect + +//------------------------------------------------- +//================= Unique Helmets ================ +//------------------------------------------------- + +//[Name] == Skullcap && [Quality] == Unique && [Flag] != Ethereal # [Itemmagicbonus] >= 25 // Tarnhelm +//[Name] == Skullcap && [Quality] == Unique && [Flag] != Ethereal # [Itemmagicbonus] == 30 // Tarnhelm Perfect +//[Name] == Warhat && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 100 // Peasant Crown +//[Name] == Sallet && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 160 && [Coldresist]+[Lightresist]+[Fireresist] >= 60 // Rockstopper +//[Name] == Sallet && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 160 && [Coldresist]+[Lightresist]+[Fireresist] >= 60 // Eth Rockstopper +//[Name] == Sallet && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 220 && [Coldresist]+[Lightresist]+[Fireresist] == 130 // Eth Rockstopper Perfect +//[Name] == Wingedhelm && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Amazonskills] >= 1 // Valkyrie Wing +//[Name] == Wingedhelm && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 && [Amazonskills] == 2 // Valkyrie Wing Perfect +[Name] == Grandcrown && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 160 && [Lifeleech] >= 9 && [Itemgoldbonus] >= 80 // Crown Of Thieves +[Name] == Grandcrown && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 160 && [Lifeleech] >= 9 && [Itemgoldbonus] >= 80 // Eth Crown Of Thieves +//[Name] == Grandcrown && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 && [Lifeleech] == 12 && [Itemgoldbonus] == 100 // Eth Crown Of Thieves Perfect +[Name] == Grimhelm && [Quality] == Unique && [Flag] != Ethereal # [Lifeleech] >= 6 && [Manaleech] >= 6 && [Magicdamagereduction] >= 10 && [Damageresist] >= 15 // Vampire Gaze +[Name] == Grimhelm && [Quality] == Unique && [Flag] == Ethereal # [Lifeleech] >= 6 && [Manaleech] >= 6 && [Magicdamagereduction] >= 10 && [Damageresist] >= 15 // Eth Vampire Gaze +//[Name] == Grimhelm && [Quality] == Unique && [Flag] == Ethereal # [Lifeleech] == 8 && [Manaleech] == 8 && [Magicdamagereduction] == 15 && [Damageresist] == 20 // Eth Vampire Gaze Perfect +[Name] == Shako && [Quality] == Unique && [Flag] != Ethereal # [Defense] >= 98 // Harlequin Crest Shako +//[Name] == Shako && [Quality] == Unique && [Flag] != Ethereal # [Defense] >= 141 // Harlequin Crest Shako Perfect +//[Name] == Armet && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 100 && [Manaleech] >= 4 // Steel Shade +//[Name] == Spiredhelm && [Quality] == Unique && [Flag] != Ethereal # [Allres] >= 50 // Veil Of Steel +[Name] == Spiredhelm && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 90 && [Dexterity] >= 10 && [Itemabsorbcold] >= 5 && [Passivecoldmastery] >= 8 // Nightwing's Veil +//[Name] == Spiredhelm && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 120 && [Dexterity] == 20 && [Itemabsorbcold] == 9 && [Passivecoldmastery] == 15 // Nightwing's Veil Perfect +[Name] == Demonhead && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 100 && [Lifeleech] >= 8 && [Strength] >= 25 // Andariel's Visage +[Name] == Demonhead && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 100 && [Lifeleech] >= 8 && [Strength] >= 25 // Eth Andariel's Visage +//[Name] == Demonhead && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 150 && [Lifeleech] == 10 && [Strength] == 30 // Eth Andariel's Visage Perfect +[Name] == Corona && [Quality] == Unique && [Flag] != Ethereal # [Plusdefense] >= 100 && [DamageResist] >= 10 && [Allres] >= 20 && [Sockets] >= 1 // Crown Of Ages +//[Name] == Corona && [Quality] == Unique && [Flag] != Ethereal # [Plusdefense] == 150 && [DamageResist] == 15 && [Allres] == 30 && [Sockets] == 2 // Crown Of Ages Perfect +//[Name] == Bonevisage && [Quality] == Unique && [Flag] != Ethereal # [Plusdefense] >= 250 && [Strength] >= 25 && [Sockets] >= 1 // Giant Skull +//[Name] == Bonevisage && [Quality] == Unique && [Flag] != Ethereal # [Plusdefense] == 320 && [Strength] == 35 && [Sockets] == 2 // Giant Skull Perfect +[Name] == Bonevisage && [Quality] == Unique && [Flag] == Ethereal # [Plusdefense] == 320 && [Strength] == 35 && [Sockets] == 2 // Eth Giant Skull Perfect +[Name] == Diadem && [Quality] == Unique && [Flag] != Ethereal // Griffon's Eye +//[Name] == Diadem && [Quality] == Unique && [Flag] != Ethereal # [Passiveltngpierce] >= 20 && [Passiveltngmastery] >= 15 // Griffon's Eye Perfect +//[Name] == Tiara && [Quality] == Unique && [Flag] != Ethereal # [Allres] >= 50 // Kira's Guardian +//[Name] == Tiara && [Quality] == Unique && [Flag] != Ethereal # [Allres] == 70 // Kira's Guardian Perfect +//[Name] == Tiara && [Quality] == Unique && [Flag] == Ethereal # [Allres] == 70 // Eth Kira's Guardian Perfect + +//----------------------------------------------- +//================= Unique Armor ================ +//----------------------------------------------- + +//[Name] == Studdedleather && [Quality] == Unique && [Flag] != Ethereal # [Dexterity] == 10 // Twitchthroe +//[Name] == Studdedleather && [Quality] == Unique && [Flag] != Ethereal # [Defense] == 60 // Twitchthroe Perfect +//[Name] == Ghostarmor && [Quality] == Unique && [Flag] != Ethereal # [Magicdamagereduction] >= 7 // The Spirit Shroud +//[Name] == Ghostarmor && [Quality] == Unique && [Flag] != Ethereal # [Magicdamagereduction] == 11 // The Spirit Shroud Perfect +[Name] == Serpentskinarmor && [Quality] == Unique && [Flag] != Ethereal # [Magicdamagereduction] >= 9 && [Allres] >= 20 // Skin Of The Vipermagi +//[Name] == Serpentskinarmor && [Quality] == Unique && [Flag] != Ethereal # [Magicdamagereduction] == 13 && [Allres] == 35 // Skin Of The Vipermagi Perfect +//[Name] == Cuirass && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 160 // Duriel's Shell +[Name] == Cuirass && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 160 // Eth Duriel's Shell +[Name] == Cuirass && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 // Duriel's Shell Perfect +//[Name] == Cuirass && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 200 // Eth Duriel's Shell Perfect +//[Name] == Mesharmor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 180 // Shaftstop +[Name] == Mesharmor && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 180 // Eth Shaftstop +[Name] == Mesharmor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 220 // Shaftstop Perfect +//[Name] == Mesharmor && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 220 // Eth Shaftstop Perfect +[Name] == Russetarmor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 160 // Skullder's Ire +[Name] == Russetarmor && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 160 // Eth Skullder's Ire +//[Name] == Russetarmor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 // Skullder's Ire Perfect +//[Name] == Russetarmor && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 200 // Eth Skullder's Ire Perfect +//[Name] == Mageplate && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 140 && [Magicdamagereduction] >= 6 // Que-Hegan's Wisdom +//[Name] == Mageplate && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 160 && [Magicdamagereduction] == 10 // Que-Hegan's Wisdom Perfect +[Name] == Templarcoat && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 180 // Guardian Angel +[Name] == Templarcoat && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 180 // Eth Guardian Angel +//[Name] == Templarcoat && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 // Guardian Angel Perfect +//[Name] == Templarcoat && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 200 // Eth Guardian Angel Perfect +[Name] == Duskshroud && [Quality] == Unique && [Flag] != Ethereal # [Passiveltngmastery] >= 15 && ([Skilllightning] >= 3 || [Skillnova] >= 3 || [Skillenergyshield] >= 3) // Light Ormus' Robes +[Name] == Duskshroud && [Quality] == Unique && [Flag] != Ethereal # [Passivecoldmastery] >= 15 && [Skillblizzard] >= 3 || [Skilliceblast] >= 3 // Cold Ormus' Robes +[Name] == Duskshroud && [Quality] == Unique && [Flag] != Ethereal # [Passivefiremastery] >= 15 && ([Skillfireball] >= 3 || [Skillfirebolt] >= 3 || [Skillhydra] >= 3 || [Skillmeteor] >= 3) // Fire Ormus' Robes +//[Name] == Wirefleece && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Normaldamagereduction] >= 15 && [Magicdamagereduction] >= 15 // The Gladiator's Bane +[Name] == Wirefleece && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 150 && [Normaldamagereduction] >= 15 && [Magicdamagereduction] >= 15 // Eth The Gladiator's Bane +[Name] == Wirefleece && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 180 && [Normaldamagereduction] == 20 && [Magicdamagereduction] == 20 // The Gladiator's Bane Perfect +//[Name] == Wirefleece && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 180 && [Normaldamagereduction] == 20 && [Magicdamagereduction] == 20 // Eth The Gladiator's Bane Perfect +//[Name] == Balrogskin && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Normaldamagereduction] >= 10 // Arkaine's Valor +//[Name] == Balrogskin && [Quality] == Unique && [Flag] != Ethereal # [Itemallskills] == 2 && [Enhanceddefense] == 180 && [Normaldamagereduction] == 15 // Arkaine's Valor Perfect +//[Name] == Krakenshell && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 170 && [Plusdefense] >= 100 && [Strength] >= 40 // Leviathan +//[Name] == Krakenshell && [Quality] == Unique && [Flag] != Ethereal # [DamageResist] == 25 && [Enhanceddefense] == 200 && [Plusdefense] == 150 && [Strength] == 50 // Leviathan Perfect +//[Name] == Sacredarmor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Strength] >= 20 && [Allres] >= 20 // Tyrael's Might +[Name] == Sacredarmor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 150 && [Strength] == 30 && [Allres] == 30 && [Itemdemondamagepercent] == 100 // Tyrael's Might Perfect + + +//------------------------------------------------- +//================= Unique Shields ================ +//------------------------------------------------- + +//[Name] == Buckler && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 30 // Pelta Lunata +//[Name] == Buckler && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 40 // Pelta Lunata Perfect +//[Name] == Towershield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 80 // Bverrit Keep +//[Name] == Towershield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 120 // Bverrit Keep Perfect +//[Name] == Roundshield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 180 // Moser's Blessed Circle +//[Name] == Roundshield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 220 // Moser's Blessed Circle Perfect +[Name] == Pavise && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 180 && [Allres] >= 20 // Gerke's Sanctuary +//[Name] == Pavise && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 240 && [Allres] == 30 // Gerke's Sanctuary Perfect +//[Name] == Grimshield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 80 && [Manarecovery] >= 3 // Lidless Wall +//[Name] == Grimshield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 130 && [Manarecovery] == 5 // Lidless Wall Perfect +[Name] == Monarch && [Quality] == Unique && [Flag] != Ethereal # [DamageResist] >= 35 // Stormshield +//[Name] == Monarch && [Quality] == Unique && [Flag] != Ethereal # [Defense] == 148 // Stormshield Perfect +//[Name] == Aegis && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Lifeleech] >= 5 && [Coldresist] >= 40 // Medusa's Gaze +//[Name] == Aegis && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 180 && [Lifeleech] == 9 && [Coldresist] == 80 // Medusa's Gaze Perfect + +//------------------------------------------------- +//================= Unique Daggers ================ +//------------------------------------------------- + +[Name] == Boneknife && [Quality] == Unique && [Flag] != Ethereal # [Allres] == 75 // Wizardspike +//[Name] == Dagger && [Quality] == Unique && [Flag] != Ethereal # [Itemgoldbonus] == 100 // Gull +//[Name] == Blade && [Quality] == Unique && [Flag] != Ethereal # [Fcr] == 50 && [Allres] == 10 // Spectral Shard +//[Name] == Rondel && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 190 // Heart Carver +//[Idname] == Fleshripper // Fleshripper + +//------------------------------------------------ +//================= Unique Swords ================ +//------------------------------------------------ + +//[Idname] == Rixotskeen // Rixot's Keen +//[Idname] == Bloodcrescent // Blood Crescent +//[Idname] == Bloodletter // Bloodletter +//[Idname] == Coldsteeleye // Coldsteel Eye +//[Idname] == Hexfire // Hexfire +//[Idname] == Bladeofalibaba # [Dexterity] >= 5 // Blade Of Ali Baba +[Idname] == Bladeofalibaba # [Dexterity] >= 15 // Blade Of Ali Baba Perfect Dex +//[Idname] == Ginthersrift // Ginther's Rift +//[Name] == Battlesword && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 150 // Headstriker +[Name] == Battlesword && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 150 // Eth Headstriker +//[Name] == Phaseblade && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 150 && [Manaleech] >= 5 // Lightsabre +//[Name] == Phaseblade && [Quality] == Unique && [Flag] != Ethereal # [Ias] == 30 && [Enhanceddamage] >= 230 // Azurewrath +//[Idname] == Doombringer // Doombringer +//[Idname] == Thegrandfather // The Grandfather + +//---------------------------------------------- +//================= Unique Axes ================ +//---------------------------------------------- + +//[Idname] == Deathcleaver // Death Cleaver +//[Idname] == Butcherspupil // Butcher's Pupil +//[Idname] == Runemaster // Rune Master +//[Idname] == Spellsteel // Spellsteel +//[Idname] == Islestrike // Islestrike +//[Idname] == Razorsedge // Razor's Edge +//[Idname] == Cranebeak // Cranebeak + +//---------------------------------------------------------- +//================= Unique Bows & Crossbows ================ +//---------------------------------------------------------- + +[Name] == Hydrabow && [Quality] == Unique && [Flag] != Ethereal # [Manaleech] >= 6 // Windforce +//[Name] == Hydrabow && [Quality] == Unique && [Flag] != Ethereal # [Manaleech] == 8 // Windforce Perfect +//[Name] == Ballista && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 150 && [Plusdefense] >= 75 // Buriza-Do Kyanon +//[Idname] == Kukoshakaku // Kuko Shakaku +//[Idname] == Goldstrikearch // Goldstrike Arch +//[Idname] == Skystrike // Skystrike +//[Idname] == Witchwildstring // Witchwild String + +//----------------------------------------------- +//================= Unique Maces ================ +//----------------------------------------------- + +//[Idname] == Bonesnap // Bonesnap +//[Idname] == Steeldriver // Steeldriver +//[Idname] == Nordstenderizer // Nord's Tenderizer +[Name] == Scourge && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 240 && [Itemabsorblight] >= 3 // Stormlash +[Name] == Marteldefer && [Quality] == Unique # [Enhanceddamage] >= 130 // The Gavel Of Pain (Wc Gf Barb Offhand) +//[Idname] == Tyrantclub // Demon Limb +//[Idname] == Fleshrender // Fleshrender +//[Idname] == Baranarsstar // Baranar's Star +//[Idname] == Thegeneralstandoliga // The General's Tan Do Li Ga +//[Idname] == Shaefershammer // Schaefer's Hammer + +//-------------------------------------------------- +//================= Unique Polearms ================ +//-------------------------------------------------- + +//[Name] == Ogreaxe && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 270 // Bonehew +//[Name] == Ogreaxe && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 270 // Eth Bonehew +[Name] == Ogreaxe && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 320 // Eth Bonehew Perfect +//[Name] == Thresher && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 190 // The Reaper's Toll +[Name] == Thresher && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 190 // Eth The Reaper's Toll +//[Name] == Thresher && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 240 && [Lifeleech] == 15 // Eth The Reaper's Toll Perfect +//[Name] == Crypticaxe && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 200 && [Sockets] >= 1 // Tomb Reaver +[Name] == Crypticaxe && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 200 && [Sockets] >= 1 // Eth Tomb Reaver +//[Name] == Crypticaxe && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 280 && [Sockets] == 3 && [Hpregen] == 14 && [Allres] == 50 // Eth Tomb Reaver Perfect + +//-------------------------------------------------- +//================= Unique Scepters ================ +//-------------------------------------------------- + +//[Idname] == Heavenslight // Heaven's Light +//[Idname] == Knellstriker // Knell Striker +//[Idname] == Zakarumshand // Zakarum's Hand +//[Idname] == Handofblessedlight // Hand Of Blessed Light +//[Idname] == Theredeemer // The Redeemer + +//------------------------------------------------ +//================= Unique Spears ================ +//------------------------------------------------ + +//[Name] == Hyperionspear && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 180 && [Itemaddskilltab] >= 2 // Arioc's Needle +[Name] == Hyperionspear && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 180 && [Itemaddskilltab] >= 2 // Eth Arioc's Needle Sundan +//[Name] == Hyperionspear && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 230 && [Itemaddskilltab] == 4 // Eth Arioc's Needle Sundan Perfect +//[Name] == Yari && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 160 // Hone Sundan +//[Name] == Yari && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 160 // Eth Hone Sundan +//[Name] == Yari && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 200 // Eth Hone Sundan Perfect +//[Idname] == Kelpiesnare // Kelpie Snare + +//------------------------------------------------ +//================= Unique Staves ================ +//------------------------------------------------ + +//[Name] == Quarterstaff && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 200 // Ribcracker +//[Name] == Quarterstaff && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 200 // Eth Ribcracker +[Name] == Quarterstaff && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] == 300 // Eth Ribcracker Perfect +//[Name] == Elderstaff && [Quality] == Unique # [Itemaddskilltab] >= 2 // Ondal's Wisdom (Eth/Non-Eth) +[Name] == Elderstaff && [Quality] == Unique # [Itemaddskilltab] == 4 && [Magicdamagereduction] == 8 && [Energy] == 50 && [Plusdefense] == 550 // Ondal's Wisdom (Eth/Non-Eth) Perfect +//[Idname] == Mangsongslesson // Mang Song's Lesson + +//---------------------------------------------------------- +//================= Unique Throwing Weapons ================ +//---------------------------------------------------------- + +//[Idname] == Deathbit // Deathbit +[Name] == Battledart && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 180 && [Lifeleech] >= 9 && [Manaleech] >= 6 && [Tohit] >= 450 // Eth Deathbit Perfect +//[Idname] == Thescalper // The Scalper +[Name] == Francisca && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 200 && [Lifeleech] >= 6 // Eth The Scalper Perfect +//[Idname] == Warshrike // Warshrike +[Name] == Wingedknife && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 250 // Eth Warshrike Perfect +//[Idname] == Gimmershred // Gimmershred +//[Idname] == Lacerator // Lacerator +[Name] == Wingedaxe && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 210 // Eth Lacerator Perfect + +//----------------------------------------------- +//================= Unique Wands ================ +//----------------------------------------------- + +//[Idname] == Umeslament // Ume's Lament +//[Idname] == Suicidebranch // Suicide Branch +//[Idname] == Carinshard // Carin Shard +//[Idname] == Armofkingleoric // Arm Of King Leoric +[Name] == Unearthedwand && [Quality] == Unique && [Flag] != Ethereal # [Poisonandboneskilltab] >= 1 && [Passivepoispierce] >= 40 // Death's Web +[Name] == Unearthedwand && [Quality] == Unique && [Flag] == Ethereal # [Poisonandboneskilltab] >= 1 && [Passivepoispierce] >= 40 // Eth Death's Web +//[Name] == Unearthedwand && [Quality] == Unique && [Flag] == Ethereal # [Poisonandboneskilltab] == 2 && [Passivepoispierce] == 50 && [Manarecovery] == 12 && [Hpregen] == 12 // Eth Death's Web Perfect + +//--------------------------------------------------------- +//================= Unique Amazon Specific ================ +//--------------------------------------------------------- + +//[Idname] == Lycandersflank // Lycander's Flank +//[Idname] == Lycandersaim // Lycander's Aim +//[Name] == Ceremonialbow && [Quality] == Unique # [Enhanceddamage] >= 190 && [Manaleech] >= 8 // Lycander's Aim Perfect +[Idname] == Titansrevenge // Titan's Revenge +[Name] == Ceremonialjavelin && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 150 && [Lifeleech] >= 6 // Eth Titan's Revenge +//[Idname] == Thunderstroke // Thunderstroke +[Name] == Matriarchaljavelin && [Quality] == Unique && [Flag] != Ethereal # [Javelinandspearskilltab] >= 4 && [Enhanceddamage] >= 200 // Thunderstroke Perfect + +//----------------------------------------------------------- +//================= Unique Assassin Specific ================ +//----------------------------------------------------------- + +//[Idname] == Shadowkiller // Shadow Killer +//[Name] == Greatertalons && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddamage] >= 120 && [Lifeleech] >= 5 // Bartuc's Cut-Throat +//[Name] == Greatertalons && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 120 && [Lifeleech] >= 5 // Eth Bartuc's Cut-Throat +//[Idname] == Jadetalon // Jade Talon +//[Name] == Feralclaws && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 270 && [Martialartsskilltab] >= 3 && [Skillwakeofinferno] >= 2 && [Skillwakeoffire] >= 2 && [Fireresist] >= 70 // Eth Firelizard's Talons Perfect +//[Name] == Wristsword && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddamage] >= 240 && [Martialartsskilltab] >= 2 && [Shadowdisciplinesskilltab] >= 2 && [Manaleech] >= 15 && [Fireresist] >= 50 // Eth Jade Talon Perfect + +//-------------------------------------------------------------- +//================= Unique Necromancer Specific ================ +//-------------------------------------------------------------- + +//[Name] == Hierophanttrophy && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 // Homunculus +//[Name] == Succubusskull && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Necromancerskills] >= 1 && [Allresist] >= 20 // Boneflame +//[Name] == Bloodlordskull && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 140 && [Necromancersummoningskilltab] >= 1 && [Poisonandboneskilltab] >= 1 && [Cursesskilltab] >= 1 // Darkforce Spawn + +//------------------------------------------------------------ +//================= Unique Barbarian Specific ================ +//------------------------------------------------------------ + +[Name] == Slayerguard && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Lifeleech] >= 3 // Arreat's Face +[Name] == Slayerguard && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 150 && [Lifeleech] >= 3 // Eth Arreat's Face +//[Name] == Slayerguard && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 200 && [Lifeleech] == 6 // Eth Arreat's Face Perfect +//[Name] == Furyvisor && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Warcriesskilltab] >= 2 && [Skillferalrage] >= 3 && [Skilllycanthropy] >= 3 && [Skillwerewolf] >= 3 && [Strength] >= 8 && [Dexterity] >= 8 && [Vitality] >= 8 // Wolfhowl +//[Name] == Furyvisor && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 120 && [Warcriesskilltab] >= 2 && [Skillferalrage] >= 3 && [Skilllycanthropy] >= 3 && [Skillwerewolf] >= 3 && [Strength] >= 8 && [Dexterity] >= 8 && [Vitality] >= 8 // Eth Wolfhowl +//[Name] == Conquerorcrown && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 140 && [Hpregen] >= 15 && [Skillbattleorders] >= 1 && [Skillbattlecommand] >= 1 // Halaberd's Reign +//[Name] == Conquerorcrown && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 140 && [Hpregen] >= 15 && [Skillbattleorders] >= 1 && [Skillbattlecommand] >= 1 // Eth Halaberd's Reign +//[Name] == Destroyerhelm && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Lifeleech] > 0 && [Itemattackertakesdamage] > 0 && [Warcriesskilltab] >= 1 && [Masteriesskilltab] >= 1 && [Barbcombatskilltab] >= 1 // Demonhorn's Edge +//[Name] == Destroyerhelm && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 120 && [Lifeleech] > 0 && [Itemattackertakesdamage] > 0 && [Warcriesskilltab] >= 1 && [Masteriesskilltab] >= 1 && [Barbcombatskilltab] >= 1 // Eth Demonhorn's Edge + + +//-------------------------------------------------------- +//================= Unique Sorceress Orbs ================ +//-------------------------------------------------------- + +[Name] == Eldritchorb && [Quality] == Unique # [Sorceressskills] >= 2 && [Passivefiremastery] >= 10 && [Passiveltngmastery] >= 10 // Eschuta's Temper +//[Name] == Eldritchorb && [Quality] == Unique # [Sorceressskills] == 3 && [Passivefiremastery] == 20 && [Passiveltngmastery] == 20 && [Energy] == 30 // Eschuta's Temper Perfect +[Name] == Dimensionalshard && [Quality] == Unique # [Passivecoldpierce] >= 15 && [Lightresist] >= 25 // Death's Fathom +//[Name] == Dimensionalshard && [Quality] == Unique # [Passivecoldpierce] == 30 && [Lightresist] == 40 // Death's Fathom Perfect +[Name] == Swirlingcrystal && [Quality] == Unique # [Sorceressskills] >= 3 // The Oculus + +//----------------------------------------------------- +//================= Unique Druid Pelts ================ +//----------------------------------------------------- + +//[Name] == Totemicmask && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 // Jalal's Mane +//[Name] == Totemicmask && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 200 // Jalal's Mane Perfect +//[Name] == Bloodspirit && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 130 && [Itemtohitpercent] >= 60 && [Lifeleech] >= 7 && [Shapeshiftingskilltab] >= 2 && [Skillferalrage] >= 1 // Cerebus' Bite +//[Name] == Bloodspirit && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 140 && [Itemtohitpercent] == 120 && [Lifeleech] == 10 && [Shapeshiftingskilltab] == 4 && [Skillferalrage] == 2 // Cerebus' Bite Perfect +[Name] == Skyspirit && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 120 && [Passivefirepierce] >= 10 && [Fireresist] >= 15 // Ravenlore +//[Name] == Skyspirit && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] == 150 && [Passivefirepierce] == 20 && [Fireresist] == 25 // Ravenlore Perfect +//[Idname] == Spiritkeeper // Spirit Keeper + +//--------------------------------------------------------- +//================= Unique Paladin Shields ================ +//--------------------------------------------------------- + +//[Name] == Sacredrondache && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 && [Enhanceddamage] >= 60 && [Paladinskills] >= 2 && [Itemtohitpercent] >= 60 && [Magicdamagereduction] >= 6 // Alma Negra +[Name] == Gildedshield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 150 // Herald Of Zakarum +//[Name] == Gildedshield && [Quality] == Unique && [Flag] != Ethereal # [Enhanceddefense] >= 200 // Herald Of Zakarum Perfect +[Name] == Gildedshield && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] >= 150 // Eth Herald Of Zakarum +//[Name] == Gildedshield && [Quality] == Unique && [Flag] == Ethereal # [Enhanceddefense] == 200 // Eth Herald Of Zakarum Perfect +//[Name] == Zakarumshield && [Quality] == Unique # [Enhanceddefense] >= 150 && [Itemabsorbfirepercent] >= 15 && [Strength] >= 20 // Dragonscale diff --git a/config/game.ini b/config/game.ini index 75d3e788f..3e6a2887b 100644 --- a/config/game.ini +++ b/config/game.ini @@ -4,9 +4,9 @@ black=0,0,0,180,255,15 gold_numbers=0,0,65,180,255,255 item_highlight=90,235,130,115,255,160 -white=0,0,150,180,20,255 +white=0,0,230,180,20,255 gray=0,0,90,180,20,130 -blue=114,100,190,125,132,255 +blue=114,100,165,125,132,255 green=56,190,190,63,255,255 yellow=27,110,190,33,145,255 gold=20,75,140,26,95,230 @@ -84,7 +84,6 @@ xp_bar_y=665 ; all rois are in [left, top, width, height] format chat_line_1=12,537,391,25 save_and_exit=500,233,273,173 -game_menu_left=530,250,20,134 play_btn=426,616,320,71 difficulty_select=536,236,210,320 gold_btn=997,521,20,18 @@ -102,7 +101,7 @@ reduce_to_center=120,60,1040,540 search_npcs=120,0,1040,620 merc_icon=0,0,100,100 loading_left_black=0,0,350,720 -death=513,193,253,50 +death=444,198,397,71 tp_search=353,120,547,400 repair_btn=318,473,90,80 left_inventory=35,92,378,378 @@ -121,7 +120,7 @@ shrine_check=500,50,350,100 character_select=1033, 44, 226, 554 character_online_status=1033, 19, 226, 25 ; character_sub_roi is with respect to matched active character template -character_name_sub_roi=8, 22, 192, 32 +character_name_sub_roi=2, 20, 194, 22 cube_area_roi=167,209,113,152 cube_btn_roi=160,368,125,57 xp_bar_text=369,630,554,34 @@ -136,6 +135,7 @@ left_inventory_tabs=31,62,385,28 tab_indicator=31,82,385,14 deposit_btn=454,365,186,43 equipped_inventory_area=861,59,387,287 +inventory_bg_pattern=21,622,1236,75 [path] ; static pathes in format: x0,y0, x1,y1, x2,y2, ... @@ -210,6 +210,7 @@ dia_a2y_sealfake_sealboss=1194, 57 dia_a2y_hop_622=1020,147 dia_b1s_layout2_seal=1125,102, 1125,102, 1125,102, 1171,576, 651,584 dia_b1s_seal_deseis=302,128, 267,193, 395,502 +dia_b1s_seal_deseis_foh=302,128, 267,193 dia_c1f_651_654=1250,328, 1250,328 dia_c1f_654_651=100,413, 100,413 dia_c1f_651_652=1261,402 diff --git a/config/params.ini b/config/params.ini index 8a493d6ad..21d5949ee 100644 --- a/config/params.ini +++ b/config/params.ini @@ -1,24 +1,32 @@ ; There is detailed documentation for each parameter in the README.md [general] +difficulty=hell name=Botty -message_api_type=discord -custom_message_hook= -max_game_length_s=380 -max_consecutive_fails=0 -max_runtime_before_break_m=0 -break_length_m=0 randomize_runs=0 -difficulty=hell -info_screenshots=1 -loot_screenshots=0 -discord_status_count=20 -discord_log_chicken=1 saved_games_folder= + +; messaging +custom_loot_message_hook= +custom_message_hook= +discord_log_chicken=1 +discord_status_count=20 +message_api_type=discord + +; breaks +break_length_m=0 +max_runtime_before_break_m=0 + +; timers / fail handling d2r_path=C:\Program Files (x86)\Diablo II Resurrected -; if you set this field to 1, botty will save the top-most visible character template just after -; the online/offline tab and upon restart will attempt to find the same template to select the char +max_consecutive_fails=5 +max_game_length_s=380 +; if you set this field to 1, botty will attempt to restart d2 after a crash or failure restart_d2r_when_stuck=0 +; screenshots +info_screenshots=1 +loot_screenshots=0 +pickit_screenshots=0 [routes] ; Add these possible routes to "order" to run them: @@ -37,54 +45,67 @@ order=run_pindle, run_eldritch_shenk ; ========================== ; These configs have to be alligned with your d2r settings and char build type=light_sorc +belt_rows=4 casting_frames=10 -show_items=alt -inventory_screen=i -tp=f9 -;Note: loot columns are counted from left to right. Items on the left side of inventory will be considered lootable. +cta_available=0 +; safer_routines: enable for optional defensive maneuvers/etc during combat/runs at the cost of increased runtime (ex. hardcore players) +safer_routines=0 + +; num_loot_columns: Number of empty columns from left to right of inventory to be used for looting. +; Store charms, etc. to the right of the inventory. num_loot_columns=5 + +; game hotkeys: force_move=e -;Note: stand_still can not be the default "shift" as it would interfere with merc healing -stand_still=capslock -;Note: this is different from the default hotkey as "~" is for many keyboards not reachable without also pressing altgr -show_belt=k -belt_rows=4 +inventory_screen=i potion1=1 potion2=2 potion3=3 potion4=4 -cta_available=0 +; show_belt is different from the default hotkey as "~" is for many keyboards not reachable without also pressing altgr +show_belt=k +show_items=alt +; stand_still cannot be the default "shift" as it would interfere with merc healing +stand_still=capslock +; teleport: leave empty if you can't use +teleport= +town_portal=f9 +; call to arms settings: weapon_switch=x battle_orders=f7 battle_command=f8 + ; ========================== ; ==== Optional configs ==== ; ========================== stash_gold=1 -min_gold_to_pick=1000 use_merc=1 + ; Attack length for barbarians should be as high as 8-10 and even 10-12 for trav/shenk atk_len_arc=2.5 -atk_len_trav=3.0 -atk_len_pindle=3.0 atk_len_eldritch=3.0 -atk_len_shenk=4.0 atk_len_nihlathak=4.0 +atk_len_pindle=3.0 +atk_len_shenk=4.0 +atk_len_trav=3.0 -;######################### -;Diablo & Chaos Sanctuary +; Chaos Sanctuary settings atk_len_cs_trashmobs=1.5 atk_len_diablo_deseis=5.0 atk_len_diablo_infector=4.0 atk_len_diablo_vizier=2.0 atk_len_diablo=3.0 -kill_cs_trash=0 -cs_town_visits=0 cs_mob_detect=1 -; DIABLO END -;######################### +; cs_town_visits is currently broken, ignore for now +cs_town_visits=0 +kill_cs_trash=0 + +; Belt settings +belt_hp_columns=1 +belt_mp_columns=1 +belt_rejuv_columns=2 -;Pots +; Potion/chicken settings take_health_potion=0.8 take_mana_potion=0.5 take_rejuv_potion_health=0.4 @@ -93,24 +114,25 @@ heal_merc=0.7 heal_rejuv_merc=0.2 chicken=0.35 merc_chicken=0 -belt_rejuv_columns=2 -belt_hp_columns=1 -belt_mp_columns=1 -;Further Options + +; Misc. +; helps reduce accidental pickups when enabled especially on walking characters +enable_no_pickup=1 +fill_shared_stash_first=0 +; to gamble, add any/all of the following: circlet, ring, coronet, talon, amulet +gamble_items= +open_chests=1 pre_buff_every_run=1 runs_per_repair=0 runs_per_stash=4 -always_repair=0 -id_items=1 sell_junk=0 -open_chests=1 -fill_shared_stash_first=0 -; to gamble, add any/all of the following: circlet, ring, coronet, talon, amulet -gamble_items= [transmute] ;stash tabs by priority where to put transmuted gems stash_destination=3,2,1,0 +; Add these possible gems to "transmute" to transmute them: +; chipped, flawed, standard, flawless +transmute=flawless ;how often we want to run transmute routine(e.g. every 100 games) transmute_every_x_game=20 @@ -118,12 +140,11 @@ transmute_every_x_game=20 ; ==== Builds: Sorceress ==== ; =========================== [sorceress] -teleport= -frozen_armor= energy_shield= -thunder_storm= -telekinesis= +frozen_armor= static_field= +telekinesis= +thunder_storm= [light_sorc] ; chain_lightning must be bound to left skill (hotkey optional as it shouldnt change) @@ -134,46 +155,55 @@ lightning= frozen_orb= [blizz_sorc] -; ice_blast must be left skill (hotkey optional as it shouldnt change) -ice_blast= ; blizzard must be right skill, hotkey required blizzard= +; ice_blast must be left skill (hotkey optional as it shouldnt change) +ice_blast= [nova_sorc] ; nova must be right skill, hotkey required -nova=f2 +nova= [hydra_sorc] ; only supports Pindle and Eldritch currently ; alt_attack is any alternate attacking right skill. Fireball,Lightning,Frozen Orb, hotkey required -alt_attack=f3 +alt_attack= ; hydra must be right skill, hotkey required -hydra=f2 +hydra= ; ========================= ; ==== Builds: Paladin ==== ; ========================= -[hammerdin] -teleport= -concentration= +[paladin] +cleansing= holy_shield= -blessed_hammer= -vigor= redemption= -cleansing= +vigor= + +[fohdin] +; foh must be left skill, hotkey required +blessed_hammer= +concentration= +conviction= +foh= +holy_bolt= + +[hammerdin] +blessed_hammer= +concentration= + ; ========================== ; ==== Builds: Assassin ==== ; ========================== ; Currently no Trav implementaiton! [trapsin] -teleport= -skill_left= burst_of_speed= +death_sentry= fade= -shadow_warrior= lightning_sentry= -death_sentry= +shadow_warrior= +skill_left= ; =========================== @@ -183,12 +213,11 @@ death_sentry= ; Make sure leap hotkey is set if you do not have Enigma ; Ensure Battle Order/Command hotkeys are set above in the [char] section [barbarian] -teleport= +cry_frequency=0.7 +find_item= leap= shout= war_cry= -find_item= -cry_frequency=0.7 ; ========================== @@ -202,102 +231,90 @@ cry_frequency=0.7 ;recomended to set skeleton mage to same as revive hot hey ;skeleton mages cause pathing issues not ideal to use yet [necro] -teleport= -skill_left= +amp_dmg= bone_armor= clay_golem= -raise_skeleton= -raise_mage= -raise_revive= -amp_dmg= -corpse_explosion= clear_pindle_pack= +corpse_explosion= heart_of_wolverine= +raise_mage= +raise_revive= +raise_skeleton= +skill_left= [poison_necro] -teleport= -poison_nova= -# Not Required -skill_left= bone_armor= # Can use any golem clay_golem= -raise_skeleton= -raise_mage= -raise_revive= -# Can Use any curse -lower_res= -corpse_explosion= clear_pindle_pack= +corpse_explosion= heart_of_wolverine= +# Can Use any curse +lower_res= +poison_nova= +raise_mage= +raise_revive= +raise_skeleton= +# Not Required +skill_left= [bone_necro] -teleport= -teeth= bone_armor= -clay_golem= -bone_wall= bone_spear= bone_spirit= -; Damage scaling. One setting to adjust kill speed to account for better/worse gear. +bone_wall= +clay_golem= +teeth= +; Damage scaling. One setting to adjust kill speed to account for better/worse gear. ; ex: 2 will cast all attack skills twice a long, .5 half as long. Currently only used by bone necro damage_scaling=1 -; =========================== + ; ==== Builds: Basic ==== -; =========================== ; Supported runs: UNTESTED (this is your job!) ; this will basically continuously left attack, unless right attack is available. -;if the buffs are not set they are not used (they are part of the prebuff setup) +; if the buffs are not set they are not used (they are part of the prebuff setup) [basic] -teleport= left_attack= right_attack= buff_1= buff_2= -; =========================== ; ==== Builds: Basic Ranged==== -; =========================== ; Supported runs: UNTESTED (this is your job!) ; this will basically continuously left attack, unless right attack is available. -;if the buffs are not set they are not used (they are part of the prebuff setup) +; if the buffs are not set they are not used (they are part of the prebuff setup) [basic_ranged] -teleport= left_attack= right_attack= buff_1= buff_2= -[dclone] -; Normally have known region IP (that we didn't block) for ip hunting -; eg: EU Server expected IP would be 37.244.11.xxx or 37.244.48.xxx and US Server expected IP would be 158.115.222.xxx or 158.115.221.xxx -; region_ips=37.244.11, 37.244.48 (EU) or region_ips=158.115.222, 158.115.221 (US) -region_ips= -; This is the hot ip that we want to get -dclone_hotip= - [advanced_options] -;use "can_teleport_natively" or "can_teleport_with_charges" if you want to force certain behavior in case autodetection isn't working properly -override_capabilities= -pathing_delay_factor=4 -message_headers= -message_body_template={{"content": "{msg}"}} -graphic_debugger_layer_creator=0 -logg_lvl=debug +; startup hotkeys restore_settings_from_backup_key=f7 settings_backup_key=f8 auto_settings_key=f9 graphic_debugger_key=f10 resume_key=f11 exit_key=f12 -hwnd_window_title= + +; etc. +graphic_debugger_layer_creator=0 hwnd_window_process=D2R\.exe +hwnd_window_title= +; launch_options: will replace with setting for [general] "name" above +launch_options=-mod -txt +logg_lvl=debug +message_body_template={{"content": "{msg}"}} +message_headers= +ocr_during_pickit=0 +;use "can_teleport_natively" or "can_teleport_with_charges" if you want to force certain behavior in case autodetection isn't working properly +override_capabilities= +pathing_delay_factor=4 ;If you want to control Hyper-V window from host use 0,51 here window_client_area_offset=0,0 -ocr_during_pickit=0 -launch_options= diff --git a/config/pickit.ini b/config/pickit.ini deleted file mode 100644 index 967267b13..000000000 --- a/config/pickit.ini +++ /dev/null @@ -1,1473 +0,0 @@ -; format: item_name=pickit_type, (optional list of properties to require), (optional list of properties to discard) - -; pickit_type: -; 0: item will not be picked up -; 1: item will be picked up -; 2: item will be picked up and a message will be sent to you (if message endpoint is set e.g. discord hook) - -; see images in assets/item_properties for current supported properties -; supports identified properties (id_items need to be set to 1 to support magic, rare, uniqs, and sets) -; default behavior of grouped properties (a, b) is "OR". You can use and(a, b) for "AND" boolean logic -; everything following item_name= is case insensitive - -; regarding ethereal items: -; if you want to keep ONLY ethereal, add ethereal after the first comma (not contained within parenthesis) like `item=1, ethereal` -; if you want to discard ethereal, add ethereal after the second comma (not contained within parenthesis) like `item=1,, ethereal` -; if you want both ethereal and non-ethereal items, do not use the ethereal property - -; examples: -; "item_name=pickit_type, required_properties, discarded_properties" *blueprint example* -; "rare_blade_talons=2" will pickup and send a discord message for all rare blade talons -; "uniq_helm_harlequin_crest=1,, ethereal" has no required properties; will discard ethereal -; "gray_berserker_axe=1, (socketed_5, socketed_6)" requires either 5 OR 6-socketed berserker axes -; "gray_thresher=1, and(ethereal, socketed_4)" requires ethereal AND 4-sockets -; "gray_thresher=1, ethereal, (socketed_1, socketed_2, socketed_3)" requires ethereal; -; will discard any with 1-3 sockets. This will pickup non-socketed ethereal's. -; "gray_weapon_grand_matron_bow=1, and(3_bow_skills, enhanced_damage, socketed_4)" will pickup but stash -; only GMB that have 3+ bow skills AND enhanced damage modifier AND 4 sockets - -;=============================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<<<< Advanced Pickit >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;=============================================================================; -; since the advanced pickit PR you are now able to use nested filters for your include and/or exclude properties -; if you add an "OR" property like described above the nested part will be treated as "AND". -; if you add an "AND" property the nested part will be treated as "OR" -; therefore you are now able to keep items if they match one of the specified property lists -; for example you can keep magic smallcharms that have all resist, 7 mf or (3 maximum damage and attack_rating) - -;examples -; keeps small charms with resi, 7_mf or 3 max_AD and AR -; magic_small_charm=1, (and(resi, 7_mf), and(3_maximum_damage, attack_rating) -; magic_small_charm=1, (all_resist, 7_magicfind, and(3_maximum_damage, attack_rating)) -; keeps all Skiller or (Life, max_AD, Life) GC -; magic_grand_charm=1, (Amazonskiller, Assasinskiller, Barbarianskiller, Druidskiller, Necromancerskiller, Paladinskiller, Sorceressskiller, (Life, maximum_damage, attack_rating)) -; keeps greater talons with (2 Assa Skills + 3 lightning sentry) or (+Traps skills and + lightning sentry) -; magic_greater_talons=1, ((2_assasin_skills, 3_lightning_sentry), (traps, lightning_sentry)) - - -; you can also create and use variables for filters you use often -; make sure it's under the [variables] section - -;examples -; creates a variable called has_skiller -; has_skiller=Amazonskiller, Assasinskiller, Barbarianskiller, Druidskiller, Necromancerskiller, Paladinskiller, Sorceressskiller -; use the has_skiller variable -; magic_grand_charm=1, (has_skiller, (Life, maximum_damage, attack_rating)) - -[variables] -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<<<< Variables >>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -has_skiller=Amazonskiller, Assasinskiller, Barbarianskiller, Druidskiller, Necromancerskiller, Paladinskiller, Sorceressskiller -lightning_fire_cold_res=and(lightning_resist, fire_resist, cold_resist) - -[items] -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<<<< MISC >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -;potions -misc_rejuvenation_potion=0 -misc_full_rejuvenation_potion=1 -misc_super_healing_potion=1 -misc_super_mana_potion=1 -misc_greater_healing_potion=0 -misc_greater_mana_potion=0 - -;misc -misc_gold=0 -misc_key_of_destruction=1 -misc_key_of_hate=1 -misc_key_of_terror=1 -misc_essence_of_terror=1 -misc_scroll_tp=1 -misc_scroll_id=1 -misc_key=1 - -;---------------------------------------; -;================= GEMS ================; -;---------------------------------------; - -;chipped gems -misc_chipped_amethyst=0 -misc_chipped_ruby=0 -misc_chipped_diamond=0 -misc_chipped_topaz=0 -misc_chipped_emerald=0 -misc_chipped_sapphire=0 -misc_chipped_skull=0 - -;flawed gems -misc_flawed_amethyst=0 -misc_flawed_ruby=0 -misc_flawed_diamond=0 -misc_flawed_topaz=0 -misc_flawed_emerald=0 -misc_flawed_sapphire=0 -misc_flawed_skull=0 - -;normal gems -misc_amethyst=0 -misc_ruby=0 -misc_diamond=0 -misc_topaz=0 -misc_emerald=0 -misc_sapphire=0 -misc_skull=0 - -;flawless gems -misc_flawless_amethyst=0 -misc_flawless_ruby=0 -misc_flawless_diamond=0 -misc_flawless_topaz=0 -misc_flawless_emerald=0 -misc_flawless_sapphire=0 -misc_flawless_skull=0 - -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<< RUNES >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -rune_1_el=0 -rune_2_eld=0 -rune_3_tir=0 -rune_4_nef=0 -rune_5_eth=0 -rune_6_ith=0 -rune_7_tal=0 -rune_8_ral=0 -rune_9_ort=0 -rune_10_thul=0 -rune_11_amn=0 -rune_12_sol=0 -rune_13_shael=0 -rune_14_dol=0 -rune_15_hel=0 -rune_16_io=0 -rune_17_lum=0 -rune_18_ko=0 -rune_19_fal=1 -rune_20_lem=1 -rune_21_pul=1 -rune_22_um=1 -rune_23_mal=2 -rune_24_ist=2 -rune_25_gul=2 -rune_26_vex=2 -rune_27_ohm=2 -rune_28_lo=2 -rune_29_sur=2 -rune_30_ber=2 -rune_31_jah=2 -rune_32_cham=2 -rune_33_zod=2 - -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<< MAGIC ITEMS >>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -;magic charms -magic_grand_charm=1, (has_skiller, (Life, maximum_damage, attack_rating)) -magic_large_charm=0 -magic_small_charm=1, (all_resist, 7_magicfind, 20_life, and(3_maximum_damage, attack_rating)) - -;magic jewelry -magic_jewel=1, (all_resist, fire_resist, and(15_increased_attack_speed, enhanced_damage)) -magic_amulet=0 - -;magic helmets -magic_circlet=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (3_pcombat, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal -magic_coronet=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (3_pcombat, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal -magic_diadem=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (3_pcombat, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal -magic_tiara=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (3_pcombat, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal - -;magic shields -magic_monarch=1, socketed_4, ethereal - -;magic weapons -magic_gg_club=1 - -;magic paladin shields -magic_sacred_targe=0 -magic_sacred_rondache=0 -magic_kurast_shield=0 -magic_zakarum_shield=0 -magic_vortex_shield=0 - -;magic barbarian helmets -magic_guardian_crown=0 -magic_conqueror_crown=0 -magic_destroyer_helm=0 - -;magic druid pelts -magic_dream_spirit=0 -magic_sky_spirit=0 -magic_earth_spirit=0 -magic_sun_spirit=0 -magic_blood_spirit=0 - -;magic wands -magic_polished_wand=0 -magic_ghost_wand=0 -magic_lich_wand=0 -magic_unearthed_wand=0 - -;magic assassin claws -magic_greater_claws=0 -magic_greater_talons=1, ((2_assasin_skills, 3_lightning_sentry), (traps, lightning_sentry)) -magic_feral_claws=0 -magic_runic_talons=1, ((2_assasin_skills, 3_lightning_sentry), (traps, lightning_sentry)) -magic_suwayyah=0 - -;magic javelins -magic_matriarchal_javelin=0 -magic_ceremonial_javelin=0 - -;magic armor -magic_light_plate=0 -magic_mage_plate=0 -magic_dusk_shroud=0 -magic_wyrmhide=0 -magic_wire_fleece=0 -magic_scarab_husk=0 -magic_archon_plate=0 - -;magic gloves -magic_bramble_mitts=0 -magic_vampirebone_gloves=0 -magic_vambraces=0 -magic_crusader_gauntlets=0 -magic_ogre_gauntlets=0 - -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< RARES >>>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -;rare jewelry -rare_amulet=1, (2_amazon_skills, 2_all_skills, 2_assasin_skills, 2_barbarian_skills, 2_Druid_skills, 2_necromancer_skills, 2_paladin_skills, 2_sorceress_skills) -rare_jewel=1 -rare_ring=1 - -;rare circlets -rare_circlet=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal -rare_coronet=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal -rare_diadem=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal -rare_tiara=1, ((faster_cast_rate, 2_amazon_skills), (faster_cast_rate, 2_assasin_skills), (faster_cast_rate, 2_barbarian_skills), (faster_cast_rate, 2_Druid_skills), (faster_cast_rate, 2_necromancer_skills), (faster_cast_rate, 2_paladin_skills), (faster_cast_rate, 2_sorceress_skills), (2_all_skills, faster_cast_rate), (faster_run_walk, 2_amazon_skills), (faster_run_walk, 2_all_skills), (faster_run_walk, 2_assasin_skills), (faster_run_walk, 2_barbarian_skills), (faster_run_walk, 2_Druid_skills)), ethereal - -;rare helmets -rare_bone_visage=0 -rare_demonhead=0 -rare_hydraskull=0 -rare_armet=0 -rare_giant_conch=0 - -;rare shields -rare_monarch=0 -rare_blade_barrier=0 -rare_troll_nest=0 - -;---------------------------------------; -;============== RARE CLAWS =============; -;---------------------------------------; - -;rare claws -rare_claws=0 -rare_cestus=0 -rare_blade_talons=0 - -;exceptional rare claws -rare_greater_claws=0 -rare_greater_talons=1, 2_assasin_skills -rare_hand_scythe=0 -rare_scissors_quhab=0 - -;elite rare claws -rare_feral_claws=0 -rare_runic_talons=1, 2_assasin_skills -rare_suwayyah=0 -rare_wrist_sword=0 -rare_war_fist=0 -rare_battle_cestus=0 -rare_scissors_suwayyah=0 - -;---------------------------------------; -;============== RARE PELTS =============; -;---------------------------------------; - -;normal rare pelts -rare_antlers=0 -rare_spirit_mask=0 -rare_falcon_mask=0 -rare_hawk_helm=0 -rare_wolf_head=0 - -;exceptional rare pelts -rare_hunter_guise=0 -rare_totemic_mask=0 -rare_sacred_feathers=0 -rare_griffon_headdress=0 -rare_alpha_helm=0 - -;elite rare pelts -rare_earth_spirit=0 -rare_dream_spirit=0 -rare_sky_spirit=0 -rare_sun_spirit=0 -rare_blood_spirit=0 - -;---------------------------------------; -;============== RARE BOWS ==============; -;---------------------------------------; - -;normal rare bows -rare_stag_bow=0 -rare_ashwood_bow=0 -rare_matriarchal_bow=0 -rare_grand_matron_bow=0 - -;exceptional rare bows -rare_rune_bow=0 -rare_double_bow=0 -rare_razor_bow=0 - -;elite rare bows -rare_ward_bow=0 -rare_shadow_bow=0 -rare_diamond_bow=0 -rare_great_bow=0 -rare_blade_bow=0 - -;---------------------------------------; -;============== RARE BELTS =============; -;---------------------------------------; - -;exceptional rare belts -rare_demonhide_sash=0,, ethereal -rare_sharkskin_belt=0,, ethereal -rare_mesh_belt=0,, ethereal -rare_battle_belt=0,, ethereal -rare_war_belt=0,, ethereal - -;elite rare belts -rare_spiderweb_sash=0,, ethereal -rare_vampirefang_belt=0,, ethereal -rare_mithril_coil=0,, ethereal -rare_troll_belt=0,, ethereal -rare_colossus_girdle=0,, ethereal - -;---------------------------------------; -;============== RARE BOOTS =============; -;---------------------------------------; - -;normal rare boots -rare_greaves=1, lightning_fire_cold_res, ethereal -rare_boots=1, lightning_fire_cold_res, ethereal -rare_chain_boots=1, lightning_fire_cold_res, ethereal -rare_light_plated_boots=1, lightning_fire_cold_res, ethereal -rare_heavy_boots=1, lightning_fire_cold_res, ethereal - -;exceptional rare boots -rare_war_boots=1, lightning_fire_cold_res, ethereal -rare_battle_boots=1, lightning_fire_cold_res, ethereal -rare_mesh_boots=1, lightning_fire_cold_res, ethereal -rare_sharkskin_boots=1, lightning_fire_cold_res, ethereal -rare_demonhide_boots=1, lightning_fire_cold_res, ethereal - -;elite rare boots -rare_myrmidon_greaves=1, lightning_fire_cold_res, ethereal -rare_mirrored_boots=1, lightning_fire_cold_res, ethereal -rare_boneweave_boots=1, lightning_fire_cold_res, ethereal -rare_scarabshell_boots=1, lightning_fire_cold_res, ethereal -rare_wyrmhide_boots=1, lightning_fire_cold_res, ethereal - -;---------------------------------------; -;============= RARE GLOVES =============; -;---------------------------------------; - -;normal rare gloves -rare_leather_gloves=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_heavy_gloves=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_chain_gloves=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_light_gauntlets=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_gauntlets=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal - -;exceptional rare gloves -rare_demonhide_gloves=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_sharkskin_gloves=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_heavy_bracers=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_battle_gauntlets=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_war_gauntlets=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal - -;elite rare gloves -rare_bramble_mitts=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_vampirebone_gloves=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_vambraces=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_crusader_gauntlets=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal -rare_ogre_gauntlets=1, and(20_increased_attack_speed, 2_javalin_spears), ethereal - -;---------------------------------------; -;======= RARE BARBARIAN HELMETS ========; -;---------------------------------------; - -;normal rare barb helms -rare_avenger_guard=0 -rare_assault_helm=0 -rare_horned_helm=0 -rare_fanged_helm=0 -rare_jawbone_cap=0 - -;exceptional rare barb helms -rare_slayer_guard=0 -rare_savage_helmet=0 -rare_rage_mask=0 -rare_lion_helm=0 -rare_jawbone_visor=0 - -;elite barb helms -rare_guardian_crown=0 -rare_conqueror_crown=0 -rare_destroyer_helm=0 -rare_fury_visor=0 -rare_carnage_helm=0 - -;---------------------------------------; -;========= RARE SORCERESS ORBS =========; -;---------------------------------------; - -;normal -rare_eagle_orb=0 -rare_sacred_globe=0 -rare_smoked_sphere=0 -rare_clasped_orb=0 -rare_jareds_stone=1 - -;exceptional -rare_glowing_orb=0 -rare_crystalline_globe=0 -rare_cloudy_sphere=0 -rare_sparkling_ball=0 -rare_swirling_crystal=1 - -;elite -rare_heavenly_stone=0 -rare_eldritch_orb=0 -rare_demon_heart=0 -rare_vortex_orb=0 -rare_dimensional_shard=1 - -;---------------------------------------; -;============ RARE JAVELINS ============; -;---------------------------------------; - -rare_matriarchal_javelin=0 -rare_ceremonial_javelin=0 -rare_maiden_javelin=0 - -;==================================================================; -;<<<<<<<<<<<<<<<<<< WHITE/ETHERAL/SOCKETED ARMOR >>>>>>>>>>>>>>>>>>; -;==================================================================; - -;---------------------------------------; -;==== WHITE/SUPERIOR ARMOR ====; -;---------------------------------------; - -;white armor -white_archon_plate=0 -white_dusk_shroud=0 -white_mage_plate=0 -white_great_hauberk=0 -white_wire_fleece=0 -white_scarab_husk=0 -white_wyrmhide=0 -white_light_plate=0 - -;white/superior armor -white_superior_archon_plate=1, enhanced_defense -white_superior_dusk_shroud=1, enhanced_defense -white_superior_mage_plate=1, enhanced_defense -white_superior_wire_fleece=1, enhanced_defense -white_superior_scarab_husk=1, enhanced_defense -white_superior_wyrmhide=1, enhanced_defense -white_superior_great_hauberk=0, enhanced_defense -white_superior_light_plate=0, enhanced_defense - -;---------------------------------------; -;======= WHITE SOCKETED ARMORS ========; -;---------------------------------------; - -;white/socketed armor -gray_armor_archon_plate=1, (socketed_3, socketed_4) -gray_armor_dusk_shroud=1, (socketed_3, socketed_4), ethereal -gray_armor_mage_plate=1, (socketed_3, socketed_4), ethereal -gray_armor_light_plate=0, (socketed_3, socketed_4), ethereal -gray_armor_great_hauberk=0, (socketed_3, socketed_4), ethereal -gray_armor_wyrmhide=0, (socketed_3, socketed_4), ethereal -gray_armor_boneweave=0, (socketed_3, socketed_4), ethereal - -;white/superior/socketed armor -gray_superior_archon_plate=1, and(enhanced_defense, socketed), (socketed_1, socketed_2) -gray_superior_dusk_shroud=1, and(enhanced_defense, socketed), (ethereal, socketed_1, socketed_2) -gray_superior_mage_plate=1, and(enhanced_defense, socketed), (ethereal, socketed_1, socketed_2) -gray_superior_light_plate=0, and(enhanced_defense, socketed), (ethereal, socketed_1, socketed_2) -gray_superior_wyrmhide=0, and(enhanced_defense, socketed), (ethereal, socketed_1, socketed_2) -gray_superior_boneweave=0, and(enhanced_defense, socketed), (ethereal, socketed_1, socketed_2) -gray_superior_great_hauberk=0, and(enhanced_defense, socketed), (ethereal, socketed_1, socketed_2) - -;---------------------------------------; -;===== ETHEREAL SOCKETED ARMOR =====; -;---------------------------------------; - -;ethereal+socketed armor -gray_armor_sacred_armor=1, ethereal, (socketed_1, socketed_2) -gray_armor_shadow_plate=0, ethereal, (socketed_1, socketed_2) -gray_armor_balrog=0, ethereal, (socketed_1, socketed_2) -gray_armor_lacquered_plate=1, ethereal, (socketed_1, socketed_2) -gray_armor_hellforge=0, ethereal, (socketed_1, socketed_2) -gray_armor_kraken=0, ethereal, (socketed_1, socketed_2) - -;ethereal+superior+socketed armor -gray_superior_sacred_armor=1, and(ethereal, enhanced_defense), (socketed_1, socketed_2) -gray_superior_shadow_plate=1, and(ethereal, enhanced_defense), (socketed_1, socketed_2) -gray_superior_lacquered_plate=1, and(ethereal, enhanced_defense), (socketed_1, socketed_2) - -;---------------------------------------; -;==== ETH/NON ETH SOCKETED HELMETS ====; -;---------------------------------------; - -;both eth/non eth socketed helmets -gray_helm_bone_visage=1, and(socketed_3, enhanced_defense) -gray_helm_demonhead=1, and(socketed_3, enhanced_defense) -gray_helm_corona=0, and(socketed_3, enhanced_defense) -gray_helm_diadem=1, and(socketed_3, enhanced_defense) -gray_helm_giant_conch=0, and(socketed_3, enhanced_defense) -gray_helm_shako=0 - -;----------------------------------------; -;==== WHITE-ETHERAL-SOCKETED SHIELDS ====; -;----------------------------------------; - -;white shields -white_monarch=0 - -;superior white shields -white_superior_monarch=1, enhanced_defense - -;non eth socketed shields -gray_shield_monarch=1, socketed_4, ethereal -gray_shield_troll_nest=0,, (ethereal, socketed_1, socketed_2, socketed_3) - -;----------------------------------------------; -;=== WHITE PALADIN SHIELDS ===; -;----------------------------------------------; - -;white paladin shields -white_royal_shield=1, all_resist_45 -white_sacred_rondache=1, all_resist_45 -white_kurast_shield=1, all_resist_45 -white_zakarum_shield=1, all_resist_45 -white_sacred_targe=1, all_resist_gt40 -white_vortex_shield=1, all_resist_45 - -;lld white paladin shields -white_crown_shield=0, all_resist_45 -white_akaran_targe=0, all_resist_45 -white_akaran_rondache=0, all_resist_45 - - -;white superior paladin shields -white_superior_royal_shield=1, and(all_resist_gt40, enhanced_defense) -white_superior_sacred_rondache=1, and(all_resist_gt40, enhanced_defense) -white_superior_kurast_shield=1, and(all_resist_gt40, enhanced_defense) -white_superior_zakarum_shield=1, and(all_resist_gt40, enhanced_defense) -white_superior_sacred_targe=1, and(all_resist_gt40, enhanced_defense) -white_superior_vortex_shield=1, and(all_resist_gt40, enhanced_defense) - -;lld white superior paladin shields -white_superior_akaran_targe=0, and(all_resist_gt40, enhanced_defense) -white_superior_akaran_rondache=0, and(all_resist_gt40, enhanced_defense) -white_superior_crown_shield=0, and(all_resist_gt40, enhanced_defense) - -;---------------------------------------; -;=== ETH/SOCKETED PALADIN SHIELD =======; -;---------------------------------------; - -;both eth/non eth socketed paladin shield -gray_royal_shield=1, all_resist_45, (socketed_1, socketed_2) -gray_sacred_rondache=1, all_resist_45, (socketed_1, socketed_2) -gray_kurast_shield=1, all_resist_45, (socketed_1, socketed_2) -gray_zakarum_shield=1, all_resist_45, (socketed_1, socketed_2) -gray_sacred_targe=1, all_resist_gt40, (socketed_1, socketed_2) -gray_vortex_shield=1, all_resist_45, (socketed_1, socketed_2) - -;lld both eth/non eth socketed shields -gray_akaran_targe=0, (socketed_1, socketed_2) -gray_akaran_rondache=0, (socketed_1, socketed_2) - -;both eth/non eth superior socketed shields. -gray_superior_vortex_shield=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_royal_shield=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_sacred_targe=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_sacred_rondache=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_kurast_shield=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_zakarum_shield=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_akaran_targe=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) -gray_superior_akaran_rondache=1, and(all_resist_gt40, enhanced_defense), (socketed_1, socketed_2) - -;----------------------------------------------; -;============ WHITE BARBARIAN HELMS ===========; -;----------------------------------------------; - -;normal white barb helms -white_fanged_helm=1, 3_warcries -white_jawbone_cap=1, 3_warcries -white_horned_helm=1, 3_warcries -white_assault_helmet=1, 3_warcries -white_avenger_guard=1, 3_warcries - -;exceptional white barb helms -white_lion_helm=1, 3_warcries -white_rage_mask=1, 3_warcries -white_jawbone_visor=1, 3_warcries -white_savage_helmet=1, 3_warcries -white_slayer_guard=1, 3_warcries - -;elite white barb helms -white_destroyer_helm=1, 3_warcries -white_fury_visor=1, 3_warcries -white_carnage_helm=1, 3_warcries -white_conqueror_crown=1, 3_warcries -white_guardian_crown=1, 3_warcries - -;socketed barb helms -gray_assault_helmet=1, 3_warcries -gray_avenger_guard=1, 3_warcries -gray_carnage_helm=1, 3_warcries -gray_conqueror_crown=1, 3_warcries -gray_destroyer_helm=1, 3_warcries -gray_fury_visor=1, 3_warcries -gray_guardian_crown=1, 3_warcries -gray_savage_helmet=1, 3_warcries -gray_slayer_guard=1, 3_warcries - -;----------------------------------------------; -;=============== WHITE DRUID PELTS ============; -;----------------------------------------------; - -;normal white druid pelts -white_antlers=1, 3_tornado -white_wolf_head=1, 3_tornado -white_hawk_helm=1, 3_tornado -white_spirit_mask=1, 3_tornado -white_falcon_mask=1, 3_tornado - -;exceptional white druid pelts -white_hunters_guise=1, 3_tornado -white_sacred_feathers=1, 3_tornado -white_alpha_helm=1, 3_tornado -white_griffon_headdress=1, 3_tornado -white_totemic_mask=1, 3_tornado - -;elite white druid pelts -white_earth_spirit=1, 3_tornado -white_blood_spirit=1, 3_tornado -white_dream_spirit=1, 3_tornado -white_sky_spirit=1, 3_tornado -white_sun_spirit=1, 3_tornado - -;socketed druid pelts -gray_antlers=1, 3_tornado -gray_blood_spirit=1, 3_tornado -gray_dream_spirit=1, 3_tornado -gray_earth_spirit=1, 3_tornado -gray_hunters_guise=1, 3_tornado -gray_sky_spirit=1, 3_tornado -gray_sun_spirit=1, 3_tornado - -;----------------------------------------------; -;========= WHITE NECROMANCER SHIELDS =+========; -;----------------------------------------------; - -;white necromancers shields -white_preserved_head=1, and(3_bone_spear, 3_bone_spirit), socketed_1 -white_overseer_skull=1, and(3_bone_spear, 3_bone_spirit), socketed_1 -white_succubus_skull=1, and(3_bone_spear, 3_bone_spirit), socketed_1 -white_demon_head=1, and(3_bone_spear, 3_bone_spirit), socketed_1 -white_hellspawn_skull=1, and(3_bone_spear, 3_bone_spirit), socketed_1 -white_bloodlord_skull=1, and(3_bone_spear, 3_bone_spirit), socketed_1 -white_minion_skull=1, and(3_bone_spear, 3_bone_spirit), socketed_1 - -;==================================================================; -;<<<<<<<<<<<<<<< WHITE-ETHEREAL-SOCKETED WEAPONS >>>>>>>>>>>>>>>>>>; -;==================================================================; - -;-----------------------------------------; -;=========== WHITE 1H WEAPONS ==========; -;-----------------------------------------; - -;white weapons -white_berserker_axe=0 -white_crystal_sword=0 -white_flail=0 -white_phase_blade=0 -white_war_scepter=1, (3_blessed_hammer, 3_conviction, 3_zeal, 3_concentration, 3_fist_of_the_heavens, 3_holy_shield, 3_fanaticism) -white_divine_scepter=1, (3_blessed_hammer, 3_conviction, 3_zeal, 3_concentration, 3_fist_of_the_heavens, 3_holy_shield, 3_fanaticism) -white_caduceus=1, (3_blessed_hammer, 3_conviction, 3_zeal, 3_concentration, 3_fist_of_the_heavens, 3_holy_shield, 3_fanaticism) - -;white superior weapons -white_superior_berserker_axe=0 -white_superior_crystal_sword=1,enhanced_damage_15 -white_superior_flail=1,enhanced_damage_15 -white_superior_phase_blade=0 - -;-----------------------------------------; -;===== WHITE/ETH/SOCKETED 1H WEAPONS =====; -;-----------------------------------------; - -;eth/non eth/socketed weapons -gray_weapon_berserker_axe=0,, (socketed_1, socketed_2, socketed_3, socketed_4) -gray_weapon_crystal_sword=0,, (ethereal, socketed_1, socketed_2, socketed_3) -gray_weapon_flail=0,, (ethereal, socketed_1, socketed_2, socketed_3) -gray_weapon_phase_blade=0,, (ethereal, socketed_1, socketed_2, socketed_3, socketed_4, socketed_6) -gray_weapon_war_scepter=1,, (ethereal, socketed_1, socketed_2, socketed_3, socketed_4) -gray_divine_scepter=1,, (ethereal, socketed_1, socketed_2, socketed_3, socketed_4) -gray_caduceus=1,, (ethereal, socketed_1, socketed_2, socketed_3, socketed_4) -gray_weapon_war_pike=0,, (socketed_1, socketed_2, socketed_3, socketed_4, socketed_5) - -;superior ethereal -gray_superior_berserker_axe=1, enhanced_damage, (socketed_1, socketed_2, socketed_3, socketed_4) -gray_superior_crystal_sword=1, and(enhanced_damage, socketed_4), ethereal -gray_superior_flail=1, enhanced_damage, (ethereal, socketed_1, socketed_2, socketed_3) -gray_superior_phase_blade=1, enhanced_damage, (ethereal, socketed_1, socketed_2, socketed_3, socketed_4) - -;-----------------------------------------; -;==== WHITE ASSASSIN CLAWS ====; -;-----------------------------------------; - -; white assassin claws -white_feral_claws=1, (3_venom, 3_lightning_sentry) -white_greater_claws=1, (3_venom, 3_lightning_sentry) -white_greater_talons=1, (3_venom, 3_lightning_sentry) -white_runic_talons=1, (3_venom, 3_lightning_sentry) -white_suwayyah=1, (3_venom, 3_lightning_sentry) -white_wrist_sword=1, (3_venom, 3_lightning_sentry) - -;to-do: include gray assassin claws - -;-----------------------------------------; -;==== WHITE-ETHERAL-SOCKETED POLEARMS ====; -;-----------------------------------------; - -;ethereal polearms -gray_weapon_colossus_voulge=1, and(ethereal, socketed_4) -;gray_weapon_colossus_voulge=1,, ethereal -gray_weapon_thresher=1, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_giant_thresher=1, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_cryptic_axe=1, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_great_poleaxe=0, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_ghost_spear=0, ethereal, (socketed_1, socketed_2, socketed_3, socketed_5) - -;superior ethereal -gray_weapon_superior_colossus_voulge=1, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_superior_cryptic_axe=1, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_superior_thresher=1, ethereal, (socketed_1, socketed_2, socketed_3) -gray_weapon_superior_giant_thresher=1, ethereal, (socketed_1, socketed_2, socketed_3) - -;-----------------------------------------; -;==== WHITE-ETHEREAL-SOCKETED STAVES =====; -;-----------------------------------------; - -;white battle staff (cta) -white_archon_staff=0 -white_war_staff=0 -white_rune_staff=0 - -;white staff (memory) -white_shillelagh=0 -white_elder_staff=0 -white_gothic_staff=0 -white_cedar_staff=0 - -;socketed staff (cta) -gray_archon_staff=1, (socketed_5, 3_energy_shield) -gray_war_staff=1, (socketed_5, 3_energy_shield) -gray_rune_staff=1, (socketed_5, 3_energy_shield) - -;socketed staff (memory) -gray_shillelagh=1, (3_energy_shield, 3_shiver_armor, 3_chilling_armor, 3_thunder_storm), (socketed_1, socketed_2, socketed_3) -gray_elder_staff=1, (3_energy_shield, 3_shiver_armor, 3_chilling_armor, 3_thunder_storm), (socketed_1, socketed_2, socketed_3) -gray_gothic_staff=1, (3_energy_shield, 3_shiver_armor, 3_chilling_armor 3_thunder_storm), (socketed_1, socketed_2, socketed_3) -gray_cedar_staff=1, (3_energy_shield, 3_shiver_armor, 3_chilling_armor, 3_thunder_storm), (socketed_1, socketed_2, socketed_3) - -;-----------------------------------------; -;===== WHITE-ETHEREAL-SOCKETED WANDS =====; -;-----------------------------------------; - -;white -white_polished_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 -white_ghost_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 -white_lich_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 -white_unearthed_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 - -;ethereal-socketed -gray_polished_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 -gray_ghost_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 -gray_lich_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 -gray_unearthed_wand=1, (3_bone_spear, 3_bone_spirit), socketed_1 - -;-----------------------------------------; -;============ SOCKETED BOWS ==============; -;-----------------------------------------; - -;to-do: include white bows - -;ethereal -gray_weapon_grand_matron_bow=1, and(3_bow_skills, enhanced_damage, socketed_4) -gray_weapon_superior_grand_matron_bow=1, and(3_bow_skills, enhanced_damage, socketed_4) - -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<<< SETS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -;------------------------------; -;====== AMULETS / RINGS =======; -;------------------------------; - -set_misc_amulets=2, 2_sorceress_skills -set_ring=0 - -;------------------------------; -;===== ALDUR'S WATCHTOWER =====; -;------------------------------; - -set_aldur_advance=0 -set_aldurs_pelt=0 -set_aldurs_armor=0 - -;------------------------------; -;==== BUL-KATHOS' CHILDREN ====; -;------------------------------; - -set_bul_kathos_sword=0 - -;------------------------------; -;====== GRISWOLD'S LEGACY =====; -;------------------------------; - -set_griswold_valor=0 -set_griswolds_scepter=0 -set_griswolds_shield=0 -set_griswolds_armor=0 - -;------------------------------; -;======== ORPHAN'S CALL =======; -;------------------------------; - -set_guillaume_face=0 -set_whistans_guard=0 - -;------------------------------; -;======== IMMORTAL KING =======; -;------------------------------; - -set_immortal_king_soul_cage=0 -set_immortal_king_will=0 -set_immortal_king_gauntlets=0 -set_immortal_king_boots=0 -set_immortal_king_maul=0 -set_immortal_king_belt=0 - -;------------------------------; -;======== THE DISCIPLE ========; -;------------------------------; - -set_laying_of_hands=0 - -;------------------------------; -;===== HEAVEN'S BRETHREN ======; -;------------------------------; - -set_ondals_almighty=0 -set_taebaeks_glory=0 - -;------------------------------; -;=== M'AVINA'S BATTLE HYMN ====; -;------------------------------; - -set_mavinas_caster=0 -set_mavinas_true_sight=0 -set_mavinas_armor=0 -set_mavinas_gauntlets=0 -set_mavinas_belt=0 - -;------------------------------; -;======= NATALYA'S ODIUM ======; -;------------------------------; - -set_natalya_soul=0 -set_natalya_armor=0 -set_natalya_scissors=0 -set_natalya_helm=0 - -;------------------------------; -;==== TAL RASHA'S WRAPPINGS ===; -;------------------------------; - -set_tal_rasha_lidless_eye=1 -set_tal_rasha_fine-spun_cloth=1 -set_tal_rasha_guardianship=2 -set_tal_rasha_horadric_crest=0 - -;------------------------------; -;===== TRANG-OUL'S AVATAR =====; -;------------------------------; - -set_trang-oul_claws=0 -set_trang-oul_girth=0 -set_trang-oul_shield=0 -set_trang_oul_helm=0 -set_trang_oul_armor=0 - -;------------------------------; -;======= CLEGLAW'S BRACE ======; -;------------------------------; - -set_cleglaws_pincers=0 -set_offhand_cleglawsclaw=0 - -;------------------------------; -;====== DEATH'S DISGUISE ======; -;------------------------------; - -set_deaths_gloves=0 -set_deaths_belt=0 - -;------------------------------; -;===== MILABREGA'S REGALIA ====; -;------------------------------; - -set_milabregas_shield=0 - -;------------------------------; -;=== SIGON'S COMPLETE STEEL ===; -;------------------------------; - -set_sigon_helm=0 -set_sigon_armor=0 -set_sigon_boots=0 -set_sigon_shield=0 -set_sigon_belt=0 -set_sigon_gloves=0 - -;------------------------------; -;==== COW KING'S LEATHERS =====; -;------------------------------; - -set_cow_king_boots=0 -set_cow_king_armor=0 -set_cow_king_helm=0 - -;------------------------------; -;=== SAZABI'S GRAND TRIBUTE ===; -;------------------------------; - -set_sazabi_armor=0 - -;------------------------------; -;====== HSARUS' DEFENSE ======; -;------------------------------; - -set_hsarus_shield=0 -set_hsarus_belt=0 - -;------------------------------; -;====== SANDER'S FOLLY ========; -;------------------------------; - -set_sanders_helm=0 - -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<<<<< UNIQUES >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -;------------------------------; -;===== UNIQUE BODY ARMOR ======; -;------------------------------; - -uniq_armor_crow_caw=0 -uniq_armor_steel_carapace=0 -uniq_armor_iron_pelt=0 -uniq_armor_skin_of_the_flayed_one=0 -uniq_armor_spirit_forge=0 -uniq_armor_black_hades=0 -uniq_twitchthroe=0 -uniq_silks_of_victor=0 -uniq_spirit_shroud=0 -uniq_que_hagens_wisdom=0 -uniq_corpsemourn=0 -uniq_the_gladiators_bane=1, ethereal -uniq_leviathan=1, ethereal -uniq_arkaines_valor=1, ethereal -uniq_tyraels_might=1 -uniq_armor_duriel_shell=1, ethereal -uniq_armor_guardian_angel=1, ethereal -uniq_armor_ormus_robes=1,, ethereal -uniq_armor_shaftstop=1, ethereal -uniq_armor_skin_of_the_vipermagi=0 -uniq_armor_skullder_ire=1, ethereal -uniq_armor_toothrow=0 -uniq_armor_atmas_wail=0 -uniq_armor_centurion=0 -uniq_armor_greyform=0 - -;------------------------------; -;======== UNIQUE BELTS ========; -;------------------------------; - -uniq_lenymo=0 -uniq_nightsmoke=0 -uniq_glooms_trap=0 -uniq_belt_nosferatus_coil=0 -uniq_belt_goldwrap=0 -uniq_belt_razortail=0 -uniq_belt_snowclash=0 -uniq_belt_string_of_ears=0 -uniq_belt_thundergod_vigor=0 -uniq_belt_arachnid_mesh=2,, ethereal -uniq_belt_verdungo_hearty_cord=1,, ethereal - -;------------------------------; -;======== UNIQUE BOOTS ========; -;------------------------------; - -uniq_infernostride=0,, ethereal -uniq_boots_goblin_toe=0,, ethereal -uniq_boots_marrowwalk=0,, ethereal -uniq_boots_silkweave=0,, ethereal -uniq_boots_waterwalk=0,, ethereal -uniq_boots_shadow_dancer=1,, ethereal -uniq_boots_gore_rider=1,, ethereal -uniq_boots_war_traveler=2,, ethereal -uniq_boots_sandstorm_trek=2 -uniq_hotspur=0,, ethereal - -;------------------------------; -;======= UNIQUE GLOVES ========; -;------------------------------; - -uniq_bloodfist=0 -uniq_gloves_chance_guards=1,, ethereal -uniq_gloves_dracul_grasp=1,, ethereal -uniq_gloves_frostburn=0 -uniq_gloves_magefist=0 -uniq_gloves_steelrend=1,, ethereal -uniq_soul_drainer=0 -uniq_gloves_venom_grip=0 -uniq_gloves_gravepalm=0 -uniq_gloves_ghoulhide=0 -uniq_gloves_lava_gout=0 -uniq_gloves_hellmouth=0 -uniq_gloves_hand_of_broc=0 - -;------------------------------; -;======= UNIQUE HELMETS =======; -;------------------------------; - -uniq_tarnhelm=0,, ethereal -uniq_peasant_crown=1,, ethereal -uniq_crown_of_thieves=1, ethereal -uniq_helm_giant_skull=1, ethereal -uniq_helm_nightwing_veil=2,, ethereal -uniq_helm_andariel_visage=2 -uniq_helm_crown_of_ages=2 -uniq_helm_griffon_eye=2 -uniq_helm_harlequin_crest=2,, ethereal -uniq_helm_kira_guardian=0 -uniq_helm_stealskull=0 -uniq_helm_vampire_gaze=1 -uniq_helm_valkyrie_wing=1 -uniq_helm_darksight_helm=0 -uniq_helm_steel_shade=0 -uniq_helm_blackhorns_face=0 -uniq_helm_rockstopper=0 -uniq_helm_biggins_bonnet=0 - -;------------------------------; -;== UNIQUE BARBARIAN HELMETS ==; -;------------------------------; - -uniq_helm_arreat_face=1 -uniq_wolfhowl=0,, ethereal -uniq_demonhorns_edge=0,, ethereal -uniq_halaberds_reign=0,, ethereal - -;------------------------------; -;===== UNIQUE DRUID PELTS =====; -;------------------------------; - -uniq_helm_cerebus_bite=0,, ethereal -uniq_helm_jalal_mane=1,, ethereal -uniq_spirit_keeper=0,, ethereal -uniq_ravenlore=1,, ethereal - -;------------------------------; -;== UNIQUE JEWELRY - CHARMS ===; -;------------------------------; - -uniq_misc_amulets=2 -uniq_misc_rings=2, (1_all_skills, 15_fire_absorb, cannot_be_frozen, magicfind) -uniq_misc_rainbow_facet=2,, 3_percent -uniq_gheeds_fortune=1 - -;------------------------------; -;= UNIQUE NECROMANCER SHIELDS =; -;------------------------------; - -uniq_offhand_boneflame=0,, ethereal -uniq_offhand_darkforce_spawn=0,, ethereal -uniq_offhand_homunculus=1,, ethereal - -;------------------------------; -;== UNIQUE NECROMANCER WANDS ==; -;------------------------------; - -uniq_torch_of_iro=0 -uniq_umes_lament=0 -uniq_arm_of_king_leoric=0 -uniq_suicide_branch=0 -uniq_weapon_boneshade=0 -uniq_weapon_death_web=2 -uniq_weapon_black_hand_key=0 - -;------------------------------; -;======= UNIQUE SHIELDS =======; -;------------------------------; - -uniq_pelta_lunata=0 -uniq_visceratuant=0 -uniq_mosers_blessed_circle=0 -uniq_lidless_wall=0 -uniq_offhand_head_hunter_glory=1, ethereal -uniq_offhand_stormshield=0 -uniq_offhand_blackoak_shield=0 -uniq_offhand_lance_guard=0 -uniq_offhand_spike_thorn=0 -uniq_offhand_stormchaser=0 -uniq_offhand_medusas_gaze=0 -uniq_offhand_head_hunters_glory=0 -uniq_offhand_tiamats_rebuke=0 -uniq_offhand_spirit_ward=0 -uniq_offhand_gerkes_sanctuary=0 - -;------------------------------; -;=== UNIQUE PALADIN SHIELDS ===; -;------------------------------; - -uniq_dragonscale=0,, ethereal -uniq_alma_negra=1, ethereal -uniq_herald_of_zakarum=2 - -;------------------------------; -;======= UNIQUE WEAPONS =======; -;------------------------------; -uniq_weapon_lacerator=0,, ethereal -uniq_weapon_warshrike=0, ethereal -uniq_weapon_gimmershred=0,, ethereal -uniq_weapon_stormlash=0, ethereal -uniq_weapon_wizardspike=0,, ethereal -uniq_gul_dagger=0,, ethereal -uniq_weapon_the_cranium_basher=1, ethereal -uniq_weapon_schaefer_hammer=1, ethereal -uniq_weapon_blade_of_ali_baba=0,, ethereal -uniq_weapon_lightsabre=1,, ethereal -uniq_weapon_ondal_wisdom=1 -uniq_weapon_mang_song_lesson=1 -uniq_weapon_ribcracker=1, ethereal -uniq_hand_of_blessed_light=1,, ethereal -uniq_heavens_light=1,, ethereal -uniq_rune_master=1, ethereal -uniq_weapon_flesh_ripper=0 -uniq_weapon_frostwind=0 -uniq_weapon_cranebeak=0 -uniq_weapon_death_cleaver=0 -uniq_weapon_astreons_iron_ward=0 -uniq_weapon_grandfather=0 -uniq_weapon_ghostflame=0 -uniq_weapon_steelpillar=0 -uniq_weapon_gnasher=0 -uniq_weapon_gargoyles_bite=0 -uniq_weapon_felloak=0 -uniq_weapon_stonecrusher=0 -uniq_weapon_spire_of_honor=0 -uniq_weapon_doombringer=0 -uniq_weapon_knellstriker=0 -uniq_weapon_dragon_chang=0 -uniq_weapon_rixotskeen=0 - -;------------------------------; -;======= UNIQUE BOWS ==========; -;------------------------------; - -uniq_weapon_pluckeye=0 -uniq_weapon_gut_siphon=0 -uniq_weapon_pus_spitter=0 -uniq_weapon_eaglehorn=0 -uniq_weapon_widowmaker=0 -uniq_weapon_windforce=2 -uniq_weapon_lycanders_aim=0 - -;------------------------------; -;=== UNIQUE SORCERESS ORBS ====; -;------------------------------; - -uniq_weapon_death_fathom=2 -uniq_weapon_eschuta_temper=2, 3_sorceress_skills -uniq_weapon_the_oculus=1 - -;------------------------------; -;====== UNIQUE POLEARMS =======; -;------------------------------; - -uniq_weapon_the_reaper_toll=1, ethereal -uniq_weapon_tomb_reaver=1, ethereal -uniq_weapon_bonehew=1, ethereal - -;------------------------------; -;=== UNIQUE AMAZON WEAPONS ====; -;------------------------------; - -uniq_weapon_thunderstroke=0,, ethereal -uniq_weapon_titan_revenge=1 -uniq_weapon_blood_ravens_charge=0 - -;------------------------------; -;=== UNIQUE ASSASSIN WEAPONS ==; -;------------------------------; - -uniq_shadow_killer=0 -uniq_bartucs_talons=1 -uniq_jade_talon=0 -uniq_firelizards_talons=0 - -;------------------------------; -;====== UNIQUE STAVES =========; -;------------------------------; - -uniq_weapon_chromatic_ire=0 -uniq_weapon_razorswitch=0 -uniq_weapon_bane_ash=0 -uniq_weapon_skull_collector=0 -uniq_weapon_iron_jang_bong=0 - -;==================================================================; -;<<<<<<<<<<<<<<<<<<<<<<<< RARE ETHEREALS >>>>>>>>>>>>>>>>>>>>>>>>>; -;==================================================================; - -;armors -rare_ancient_armor=0, ethereal -rare_archon_plate=0, ethereal -rare_breast_plate=0, ethereal -rare_boneweave=0, ethereal -rare_chain_mail=0, ethereal -rare_chaos_armor=0, ethereal -rare_cuirass=0, ethereal -rare_demonhide_armor=0, ethereal -rare_diamond_mail=0, ethereal -rare_dusk_shroud=0, ethereal -rare_embossed_plate=0, ethereal -rare_full_plate_mail=0, ethereal -rare_ghost_armor=0, ethereal -rare_gothic_plate=0, ethereal -rare_great_hauberk=0, ethereal -rare_field_plate=0, ethereal -rare_hard_leather_armor=0, ethereal -rare_kraken_shell=0, ethereal -rare_lacquered_plate=0, ethereal -rare_light_plate=0, ethereal -rare_linked_mail=0, ethereal -rare_leather_armor=0, ethereal -rare_loricated_mail=0, ethereal -rare_mage_plate=0, ethereal -rare_mesh_armor=0, ethereal -rare_ornate_plate=0, ethereal -rare_plate_mail=0, ethereal -rare_quilted_armor=0, ethereal -rare_sacred_armor=0, ethereal -rare_scale_mail=0, ethereal -rare_scarab_husk=0, ethereal -rare_ring_mail=0, ethereal -rare_russet_armor=0, ethereal -rare_hellforge_plate=0, ethereal -rare_serpentskin_armor=0, ethereal -rare_shadow_plate=0, ethereal -rare_sharktooth_armor=0, ethereal -rare_splint_mail=0, ethereal -rare_studded_leather=0, ethereal -rare_tigulated_mail=0, ethereal -rare_trellised_armor=0, ethereal -rare_wyrmhide=0, ethereal -rare_balrog_skin=0, ethereal -rare_templar_coat=0, ethereal -rare_wire_fleece=0, ethereal - -;axes -rare_ancient_axe=0, ethereal -rare_ettin_axe=0, ethereal -rare_axe=0, ethereal -rare_battle_axe=0, ethereal -rare_bearded_axe=0, ethereal -rare_berserker_axe=0, ethereal -rare_lochaber_axe=0, ethereal -rare_broad_axe=0, ethereal -rare_decapitator=0, ethereal -rare_double_axe=0, ethereal -rare_feral_axe=0, ethereal -rare_giant_axe=0, ethereal -rare_great_axe=0, ethereal -rare_hand_axe=0, ethereal -rare_military_axe=0, ethereal -rare_war_axe=0, ethereal -rare_twin_axe=0, ethereal -rare_champion_axe=0, ethereal -rare_cleaver=0, ethereal -rare_crowbill=0, ethereal -rare_glorious_axe=0, ethereal -rare_gothic_axe=0, ethereal -rare_hatchet=0, ethereal -rare_large_axe=0, ethereal -rare_military_pick=0, ethereal -rare_naga=0, ethereal -rare_silver_edged_axe=0, ethereal -rare_tabar=0, ethereal -rare_tomahawk=0, ethereal - -;swords -rare_ancient_sword=0, ethereal -rare_ataghan=0, ethereal -rare_balrog_blade=0, ethereal -rare_bastard_sword=0, ethereal -rare_battle_sword=0, ethereal -rare_broad_sword=0, ethereal -rare_champion_sword=0, ethereal -rare_claymore=0, ethereal -rare_colossus_blade=0, ethereal -rare_colossus_sword=0, ethereal -rare_conquest_sword=0, ethereal -rare_cutlass=0, ethereal -rare_dacian_falx=0, ethereal -rare_cryptic_sword=0, ethereal -rare_crystal_sword=0, ethereal -rare_dimensional_blade=0, ethereal -rare_elegant_blade=0, ethereal -rare_espandon=0, ethereal -rare_executioner_sword=0, ethereal -rare_falcata=0, ethereal -rare_falchion=0, ethereal -rare_flamberge=0, ethereal -rare_francisca=0, ethereal -rare_giant_sword=0, ethereal -rare_gladius=0, ethereal -rare_gothic_sword=0, ethereal -rare_great_sword=0, ethereal -rare_highland_blade=0, ethereal -rare_hydra_edge=0, ethereal -rare_legend_sword=0, ethereal -rare_long_sword=0, ethereal -rare_mythical_sword=0, ethereal -rare_phase_blade=0, ethereal -rare_rune_sword=0, ethereal -rare_sabre=0, ethereal -rare_scimitar=0, ethereal -rare_shamshir=0, ethereal -rare_short_sword=0, ethereal -rare_tulwar=0, ethereal -rare_tusk_sword=0, ethereal -rare_two_handed_sword=0, ethereal -rare_zweihander=0, ethereal -rare_war_sword=0, ethereal - -;polearm/spears -rare_bardiche=0, ethereal -rare_bec_de_corbin=0, ethereal -rare_bill=0, ethereal -rare_brandistock=0, ethereal -rare_ceremonial_spear=0, ethereal -rare_battle_scythe=0, ethereal -rare_colossus_voulge=0, ethereal -rare_giant_thresher=0, ethereal -rare_cryptic_axe=0, ethereal -rare_great_poleaxe=0, ethereal -rare_grim_scythe=0, ethereal -rare_halberd=0, ethereal -rare_hyperion_spear=0, ethereal -rare_lance=0, ethereal -rare_maiden_pike=0, ethereal -rare_maiden_spear=0, ethereal -rare_mancatcher=0, ethereal -rare_matriarchal_pike=0, ethereal -rare_partizan=0, ethereal -rare_spear=0, ethereal -rare_pike=0, ethereal -rare_poleaxe=0, ethereal -rare_scythe=0, ethereal -rare_spetum=0, ethereal -rare_stygian_pike=0, ethereal -rare_trident=0, ethereal -rare_thresher=0, ethereal -rare_voulge=0, ethereal -rare_war_fork=0, ethereal -rare_war_pike=0, ethereal -rare_war_scythe=0, ethereal -rare_war_spear=0, ethereal -rare_war_spike=0, ethereal -rare_yari=0, ethereal -rare_fuscina=0, ethereal - -;throwing -rare_balanced_knife=0, ethereal -rare_flying_axe=0, ethereal -rare_battle_dart=0, ethereal -rare_flying_knife=0, ethereal -rare_balanced_axe=0, ethereal -rare_great_pilum=0, ethereal -rare_glaive=0, ethereal -rare_ghost_glaive=0, ethereal -rare_ghost_spear=0, ethereal -rare_harpoon=0, ethereal -rare_hurlbat=0, ethereal -rare_pilum=0, ethereal -rare_simbilan=0, ethereal -rare_small_crescent=0, ethereal -rare_short_spear=0, ethereal -rare_spiculum=0, ethereal -rare_throwing_axe=0, ethereal -rare_throwing_knife=0, ethereal -rare_throwing_spear=0, ethereal -rare_war_dart=0, ethereal -rare_winged_axe=0, ethereal -rare_winged_harpoon=0, ethereal -rare_winged_knife=0, ethereal - -;mace/clubs/mauls -rare_club=0, ethereal -rare_cudgel=0, ethereal -rare_devil_star=0, ethereal -rare_battle_hammer=0, ethereal -rare_barbed_club=0, ethereal -rare_flanged_mace=0, ethereal -rare_great_maul=0, ethereal -rare_jagged_star=0, ethereal -rare_legendary_mallet=0, ethereal -rare_mace=0, ethereal -rare_martel_de_fer=0, ethereal -rare_maul=0, ethereal -rare_morning_star=0, ethereal -rare_ogre_axe=0, ethereal -rare_ogre_maul=0, ethereal -rare_reinforced_mace=0, ethereal -rare_spiked_club=0, ethereal -rare_thunder_maul=0, ethereal -rare_truncheon=0, ethereal -rare_tyrant_club=0, ethereal -rare_war_club=0, ethereal -rare_war_hammer=0, ethereal \ No newline at end of file diff --git a/dependencies/tesserocr-2.5.2-cp310-cp310-win_amd64.whl b/dependencies/tesserocr-2.5.2-cp310-cp310-win_amd64.whl new file mode 100644 index 000000000..75e38170f Binary files /dev/null and b/dependencies/tesserocr-2.5.2-cp310-cp310-win_amd64.whl differ diff --git a/dependencies/tesserocr-2.5.2-cp39-cp39-win_amd64.whl b/dependencies/tesserocr-2.5.2-cp39-cp39-win_amd64.whl deleted file mode 100644 index 96e41b8bb..000000000 Binary files a/dependencies/tesserocr-2.5.2-cp39-cp39-win_amd64.whl and /dev/null differ diff --git a/development.md b/development.md index 2b2423c10..2afff8458 100644 --- a/development.md +++ b/development.md @@ -6,7 +6,7 @@ ## Getting started ```bash -git clone https://github.com/aeon0/botty.git +git clone https://github.com/bottytools/botty.git cd botty conda env create environment.yml conda activate botty @@ -75,6 +75,6 @@ There are different coordinate systems used and I tried my best to add these to If you installed your miniconda in another location you will of course have ot change it for that one. ```bash # Adapt new version with x.x.x, build .exe and bundeling all needed resource into one folder -python release.py x.x.x +python build.py x.x.x ``` For changelog run: `git log ..HEAD --oneline --decorate` diff --git a/environment.yml b/environment.yml index 86c3c02c2..4bd39633c 100644 --- a/environment.yml +++ b/environment.yml @@ -2,15 +2,16 @@ name: botty channels: - conda-forge dependencies: - - python=3.9 + - python=3.10 - pywin32 - pip - leptonica - - tesseract>=5.0.1 + - tesseract=5.1.0 - pkg-config + - rapidfuzz - pip: - pyinstaller - - opencv-python + - opencv-python==4.5.5.64 - transitions - mss - numpy @@ -23,13 +24,14 @@ dependencies: - pytest - pytest-env - pytest-pythonpath + - pytest-mock - graphviz - psutil - cryptography - pillow - discord.py - parse - - dependencies/tesserocr-2.5.2-cp39-cp39-win_amd64.whl + - dependencies/tesserocr-2.5.2-cp310-cp310-win_amd64.whl - typing_extensions - - rapidfuzz - - colorama \ No newline at end of file + - colorama + - dataclasses-json \ No newline at end of file diff --git a/src/bnip/BNipExceptions.py b/src/bnip/BNipExceptions.py new file mode 100644 index 000000000..945b82d63 --- /dev/null +++ b/src/bnip/BNipExceptions.py @@ -0,0 +1,22 @@ +from colorama import init, Fore + +init() + +class BNipError(Exception): + def __init__(self, error_code: str | int, error_message: str, additional_info: str): + self.error_code = error_code + self.error_message = error_message + self.additional_info = additional_info + + def __str__(self): + self.additional_info = ":" + self.additional_info if self.additional_info else "" + return f"{Fore.RED}{self.error_code}:{Fore.CYAN}{self.error_message}{Fore.YELLOW}{self.additional_info}{Fore.RESET}" + + +class BNipSyntaxError(BNipError): + def __init__(self, error_code: str | int, error_message: str, expression: str): + super().__init__(error_code, error_message, expression.strip()) + +class BNipWarning(BNipError): + def __init__(self, error_code: str | int, error_message: str, expression: str): + super().__init__(error_code, error_message, expression.strip()) diff --git a/src/bnip/NTIPAliasClass.py b/src/bnip/NTIPAliasClass.py new file mode 100644 index 000000000..bbc814714 --- /dev/null +++ b/src/bnip/NTIPAliasClass.py @@ -0,0 +1,5 @@ +NTIPAliasClass = {} +NTIPAliasClass["normal"]="0" +NTIPAliasClass["exceptional"]="1" +NTIPAliasClass["elite"]="2" + diff --git a/src/bnip/NTIPAliasClassID.py b/src/bnip/NTIPAliasClassID.py new file mode 100644 index 000000000..79adfd651 --- /dev/null +++ b/src/bnip/NTIPAliasClassID.py @@ -0,0 +1,1307 @@ +NTIPAliasClassID = {} +NTIPAliasClassID["hax"]="0" +NTIPAliasClassID["handaxe"]="0" +NTIPAliasClassID["axe"]="1" +NTIPAliasClassID["2ax"]="2" +NTIPAliasClassID["doubleaxe"]="2" +NTIPAliasClassID["mpi"]="3" +NTIPAliasClassID["militarypick"]="3" +NTIPAliasClassID["wax"]="4" +NTIPAliasClassID["waraxe"]="4" +NTIPAliasClassID["lax"]="5" +NTIPAliasClassID["largeaxe"]="5" +NTIPAliasClassID["bax"]="6" +NTIPAliasClassID["broadaxe"]="6" +NTIPAliasClassID["btx"]="7" +NTIPAliasClassID["battleaxe"]="7" +NTIPAliasClassID["gax"]="8" +NTIPAliasClassID["greataxe"]="8" +NTIPAliasClassID["gix"]="9" +NTIPAliasClassID["giantaxe"]="9" +NTIPAliasClassID["wnd"]="10" +NTIPAliasClassID["wand"]="10" +NTIPAliasClassID["ywn"]="11" +NTIPAliasClassID["yewwand"]="11" +NTIPAliasClassID["bwn"]="12" +NTIPAliasClassID["bonewand"]="12" +NTIPAliasClassID["gwn"]="13" +NTIPAliasClassID["grimwand"]="13" +NTIPAliasClassID["clb"]="14" +NTIPAliasClassID["club"]="14" +NTIPAliasClassID["scp"]="15" +NTIPAliasClassID["scepter"]="15" +NTIPAliasClassID["gsc"]="16" +NTIPAliasClassID["grandscepter"]="16" +NTIPAliasClassID["wsp"]="17" +NTIPAliasClassID["warscepter"]="17" +NTIPAliasClassID["spc"]="18" +NTIPAliasClassID["spikedclub"]="18" +NTIPAliasClassID["mac"]="19" +NTIPAliasClassID["mace"]="19" +NTIPAliasClassID["mst"]="20" +NTIPAliasClassID["morningstar"]="20" +NTIPAliasClassID["fla"]="21" +NTIPAliasClassID["flail"]="21" +NTIPAliasClassID["whm"]="22" +NTIPAliasClassID["warhammer"]="22" +NTIPAliasClassID["mau"]="23" +NTIPAliasClassID["maul"]="23" +NTIPAliasClassID["gma"]="24" +NTIPAliasClassID["greatmaul"]="24" +NTIPAliasClassID["ssd"]="25" +NTIPAliasClassID["shortsword"]="25" +NTIPAliasClassID["scm"]="26" +NTIPAliasClassID["scimitar"]="26" +NTIPAliasClassID["sbr"]="27" +NTIPAliasClassID["sabre"]="27" +NTIPAliasClassID["flc"]="28" +NTIPAliasClassID["falchion"]="28" +NTIPAliasClassID["crs"]="29" +NTIPAliasClassID["crystalsword"]="29" +NTIPAliasClassID["bsd"]="30" +NTIPAliasClassID["broadsword"]="30" +NTIPAliasClassID["lsd"]="31" +NTIPAliasClassID["longsword"]="31" +NTIPAliasClassID["wsd"]="32" +NTIPAliasClassID["warsword"]="32" +NTIPAliasClassID["2hs"]="33" +NTIPAliasClassID["twohandedsword"]="33" +NTIPAliasClassID["clm"]="34" +NTIPAliasClassID["claymore"]="34" +NTIPAliasClassID["gis"]="35" +NTIPAliasClassID["giantsword"]="35" +NTIPAliasClassID["bsw"]="36" +NTIPAliasClassID["bastardsword"]="36" +NTIPAliasClassID["flb"]="37" +NTIPAliasClassID["flamberge"]="37" +NTIPAliasClassID["gsd"]="38" +NTIPAliasClassID["greatsword"]="38" +NTIPAliasClassID["dgr"]="39" +NTIPAliasClassID["dagger"]="39" +NTIPAliasClassID["dir"]="40" +NTIPAliasClassID["dirk"]="40" +NTIPAliasClassID["kri"]="41" +NTIPAliasClassID["kris"]="41" +NTIPAliasClassID["bld"]="42" +NTIPAliasClassID["blade"]="42" +NTIPAliasClassID["tkf"]="43" +NTIPAliasClassID["throwingknife"]="43" +NTIPAliasClassID["tax"]="44" +NTIPAliasClassID["throwingaxe"]="44" +NTIPAliasClassID["bkf"]="45" +NTIPAliasClassID["balancedknife"]="45" +NTIPAliasClassID["bal"]="46" +NTIPAliasClassID["balancedaxe"]="46" +NTIPAliasClassID["jav"]="47" +NTIPAliasClassID["javelin"]="47" +NTIPAliasClassID["pil"]="48" +NTIPAliasClassID["pilum"]="48" +NTIPAliasClassID["ssp"]="49" +NTIPAliasClassID["shortspear"]="49" +NTIPAliasClassID["glv"]="50" +NTIPAliasClassID["glaive"]="50" +NTIPAliasClassID["tsp"]="51" +NTIPAliasClassID["throwingspear"]="51" +NTIPAliasClassID["spr"]="52" +NTIPAliasClassID["spear"]="52" +NTIPAliasClassID["tri"]="53" +NTIPAliasClassID["trident"]="53" +NTIPAliasClassID["brn"]="54" +NTIPAliasClassID["brandistock"]="54" +NTIPAliasClassID["spt"]="55" +NTIPAliasClassID["spetum"]="55" +NTIPAliasClassID["pik"]="56" +NTIPAliasClassID["pike"]="56" +NTIPAliasClassID["bar"]="57" +NTIPAliasClassID["bardiche"]="57" +NTIPAliasClassID["vou"]="58" +NTIPAliasClassID["voulge"]="58" +NTIPAliasClassID["scy"]="59" +NTIPAliasClassID["scythe"]="59" +NTIPAliasClassID["pax"]="60" +NTIPAliasClassID["poleaxe"]="60" +NTIPAliasClassID["hal"]="61" +NTIPAliasClassID["halberd"]="61" +NTIPAliasClassID["wsc"]="62" +NTIPAliasClassID["warscythe"]="62" +NTIPAliasClassID["sst"]="63" +NTIPAliasClassID["shortstaff"]="63" +NTIPAliasClassID["lst"]="64" +NTIPAliasClassID["longstaff"]="64" +NTIPAliasClassID["cst"]="65" +NTIPAliasClassID["gnarledstaff"]="65" +NTIPAliasClassID["bst"]="66" +NTIPAliasClassID["battlestaff"]="66" +NTIPAliasClassID["wst"]="67" +NTIPAliasClassID["warstaff"]="67" +NTIPAliasClassID["sbw"]="68" +NTIPAliasClassID["shortbow"]="68" +NTIPAliasClassID["hbw"]="69" +NTIPAliasClassID["huntersbow"]="69" +NTIPAliasClassID["lbw"]="70" +NTIPAliasClassID["longbow"]="70" +NTIPAliasClassID["cbw"]="71" +NTIPAliasClassID["compositebow"]="71" +NTIPAliasClassID["sbb"]="72" +NTIPAliasClassID["shortbattlebow"]="72" +NTIPAliasClassID["lbb"]="73" +NTIPAliasClassID["longbattlebow"]="73" +NTIPAliasClassID["swb"]="74" +NTIPAliasClassID["shortwarbow"]="74" +NTIPAliasClassID["lwb"]="75" +NTIPAliasClassID["longwarbow"]="75" +NTIPAliasClassID["lxb"]="76" +NTIPAliasClassID["lightcrossbow"]="76" +NTIPAliasClassID["mxb"]="77" +NTIPAliasClassID["crossbow"]="77" +NTIPAliasClassID["hxb"]="78" +NTIPAliasClassID["heavycrossbow"]="78" +NTIPAliasClassID["rxb"]="79" +NTIPAliasClassID["repeatingcrossbow"]="79" +NTIPAliasClassID["gps"]="80" +NTIPAliasClassID["rancidgaspotion"]="80" +NTIPAliasClassID["ops"]="81" +NTIPAliasClassID["oilpotion"]="81" +NTIPAliasClassID["gpm"]="82" +NTIPAliasClassID["chokinggaspotion"]="82" +NTIPAliasClassID["opm"]="83" +NTIPAliasClassID["explodingpotion"]="83" +NTIPAliasClassID["gpl"]="84" +NTIPAliasClassID["stranglinggaspotion"]="84" +NTIPAliasClassID["opl"]="85" +NTIPAliasClassID["fulminatingpotion"]="85" +NTIPAliasClassID["d33"]="86" +NTIPAliasClassID["decoygidbinn"]="86" +NTIPAliasClassID["g33"]="87" +NTIPAliasClassID["thegidbinn"]="87" +NTIPAliasClassID["leg"]="88" +NTIPAliasClassID["wirtsleg"]="88" +NTIPAliasClassID["hdm"]="89" +NTIPAliasClassID["horadricmalus"]="89" +NTIPAliasClassID["hfh"]="90" +NTIPAliasClassID["hellforgehammer"]="90" +NTIPAliasClassID["hst"]="91" +NTIPAliasClassID["horadricstaff"]="91" +NTIPAliasClassID["msf"]="92" +NTIPAliasClassID["shaftofthehoradricstaff"]="92" +NTIPAliasClassID["9ha"]="93" +NTIPAliasClassID["hatchet"]="93" +NTIPAliasClassID["9ax"]="94" +NTIPAliasClassID["cleaver"]="94" +NTIPAliasClassID["92a"]="95" +NTIPAliasClassID["twinaxe"]="95" +NTIPAliasClassID["9mp"]="96" +NTIPAliasClassID["crowbill"]="96" +NTIPAliasClassID["9wa"]="97" +NTIPAliasClassID["naga"]="97" +NTIPAliasClassID["9la"]="98" +NTIPAliasClassID["militaryaxe"]="98" +NTIPAliasClassID["9ba"]="99" +NTIPAliasClassID["beardedaxe"]="99" +NTIPAliasClassID["9bt"]="100" +NTIPAliasClassID["tabar"]="100" +NTIPAliasClassID["9ga"]="101" +NTIPAliasClassID["gothicaxe"]="101" +NTIPAliasClassID["9gi"]="102" +NTIPAliasClassID["ancientaxe"]="102" +NTIPAliasClassID["9wn"]="103" +NTIPAliasClassID["burntwand"]="103" +NTIPAliasClassID["9yw"]="104" +NTIPAliasClassID["petrifiedwand"]="104" +NTIPAliasClassID["9bw"]="105" +NTIPAliasClassID["tombwand"]="105" +NTIPAliasClassID["9gw"]="106" +NTIPAliasClassID["gravewand"]="106" +NTIPAliasClassID["9cl"]="107" +NTIPAliasClassID["cudgel"]="107" +NTIPAliasClassID["9sc"]="108" +NTIPAliasClassID["runescepter"]="108" +NTIPAliasClassID["9qs"]="109" +NTIPAliasClassID["holywatersprinkler"]="109" +NTIPAliasClassID["9ws"]="110" +NTIPAliasClassID["divinescepter"]="110" +NTIPAliasClassID["9sp"]="111" +NTIPAliasClassID["barbedclub"]="111" +NTIPAliasClassID["9ma"]="112" +NTIPAliasClassID["flangedmace"]="112" +NTIPAliasClassID["9mt"]="113" +NTIPAliasClassID["jaggedstar"]="113" +NTIPAliasClassID["9fl"]="114" +NTIPAliasClassID["knout"]="114" +NTIPAliasClassID["9wh"]="115" +NTIPAliasClassID["battlehammer"]="115" +NTIPAliasClassID["9m9"]="116" +NTIPAliasClassID["warclub"]="116" +NTIPAliasClassID["9gm"]="117" +NTIPAliasClassID["marteldefer"]="117" +NTIPAliasClassID["9ss"]="118" +NTIPAliasClassID["gladius"]="118" +NTIPAliasClassID["9sm"]="119" +NTIPAliasClassID["cutlass"]="119" +NTIPAliasClassID["9sb"]="120" +NTIPAliasClassID["shamshir"]="120" +NTIPAliasClassID["9fc"]="121" +NTIPAliasClassID["tulwar"]="121" +NTIPAliasClassID["9cr"]="122" +NTIPAliasClassID["dimensionalblade"]="122" +NTIPAliasClassID["9bs"]="123" +NTIPAliasClassID["battlesword"]="123" +NTIPAliasClassID["9ls"]="124" +NTIPAliasClassID["runesword"]="124" +NTIPAliasClassID["9wd"]="125" +NTIPAliasClassID["ancientsword"]="125" +NTIPAliasClassID["92h"]="126" +NTIPAliasClassID["espandon"]="126" +NTIPAliasClassID["9cm"]="127" +NTIPAliasClassID["dacianfalx"]="127" +NTIPAliasClassID["9gs"]="128" +NTIPAliasClassID["tusksword"]="128" +NTIPAliasClassID["9b9"]="129" +NTIPAliasClassID["gothicsword"]="129" +NTIPAliasClassID["9fb"]="130" +NTIPAliasClassID["zweihander"]="130" +NTIPAliasClassID["9gd"]="131" +NTIPAliasClassID["executionersword"]="131" +NTIPAliasClassID["9dg"]="132" +NTIPAliasClassID["poignard"]="132" +NTIPAliasClassID["9di"]="133" +NTIPAliasClassID["rondel"]="133" +NTIPAliasClassID["9kr"]="134" +NTIPAliasClassID["cinquedeas"]="134" +NTIPAliasClassID["9bl"]="135" +NTIPAliasClassID["stiletto"]="135" +NTIPAliasClassID["9tk"]="136" +NTIPAliasClassID["battledart"]="136" +NTIPAliasClassID["9ta"]="137" +NTIPAliasClassID["francisca"]="137" +NTIPAliasClassID["9bk"]="138" +NTIPAliasClassID["wardart"]="138" +NTIPAliasClassID["9b8"]="139" +NTIPAliasClassID["hurlbat"]="139" +NTIPAliasClassID["9ja"]="140" +NTIPAliasClassID["warjavelin"]="140" +NTIPAliasClassID["9pi"]="141" +NTIPAliasClassID["greatpilum"]="141" +NTIPAliasClassID["9s9"]="142" +NTIPAliasClassID["simbilan"]="142" +NTIPAliasClassID["9gl"]="143" +NTIPAliasClassID["spiculum"]="143" +NTIPAliasClassID["9ts"]="144" +NTIPAliasClassID["harpoon"]="144" +NTIPAliasClassID["9sr"]="145" +NTIPAliasClassID["warspear"]="145" +NTIPAliasClassID["9tr"]="146" +NTIPAliasClassID["fuscina"]="146" +NTIPAliasClassID["9br"]="147" +NTIPAliasClassID["warfork"]="147" +NTIPAliasClassID["9st"]="148" +NTIPAliasClassID["yari"]="148" +NTIPAliasClassID["9p9"]="149" +NTIPAliasClassID["lance"]="149" +NTIPAliasClassID["9b7"]="150" +NTIPAliasClassID["lochaberaxe"]="150" +NTIPAliasClassID["9vo"]="151" +NTIPAliasClassID["bill"]="151" +NTIPAliasClassID["9s8"]="152" +NTIPAliasClassID["battlescythe"]="152" +NTIPAliasClassID["9pa"]="153" +NTIPAliasClassID["partizan"]="153" +NTIPAliasClassID["9h9"]="154" +NTIPAliasClassID["becdecorbin"]="154" +NTIPAliasClassID["9wc"]="155" +NTIPAliasClassID["grimscythe"]="155" +NTIPAliasClassID["8ss"]="156" +NTIPAliasClassID["jostaff"]="156" +NTIPAliasClassID["8ls"]="157" +NTIPAliasClassID["quarterstaff"]="157" +NTIPAliasClassID["8cs"]="158" +NTIPAliasClassID["cedarstaff"]="158" +NTIPAliasClassID["8bs"]="159" +NTIPAliasClassID["gothicstaff"]="159" +NTIPAliasClassID["8ws"]="160" +NTIPAliasClassID["runestaff"]="160" +NTIPAliasClassID["8sb"]="161" +NTIPAliasClassID["edgebow"]="161" +NTIPAliasClassID["8hb"]="162" +NTIPAliasClassID["razorbow"]="162" +NTIPAliasClassID["8lb"]="163" +NTIPAliasClassID["cedarbow"]="163" +NTIPAliasClassID["8cb"]="164" +NTIPAliasClassID["doublebow"]="164" +NTIPAliasClassID["8s8"]="165" +NTIPAliasClassID["shortsiegebow"]="165" +NTIPAliasClassID["8l8"]="166" +NTIPAliasClassID["largesiegebow"]="166" +NTIPAliasClassID["8sw"]="167" +NTIPAliasClassID["runebow"]="167" +NTIPAliasClassID["8lw"]="168" +NTIPAliasClassID["gothicbow"]="168" +NTIPAliasClassID["8lx"]="169" +NTIPAliasClassID["arbalest"]="169" +NTIPAliasClassID["8mx"]="170" +NTIPAliasClassID["siegecrossbow"]="170" +NTIPAliasClassID["8hx"]="171" +NTIPAliasClassID["ballista"]="171" +NTIPAliasClassID["8rx"]="172" +NTIPAliasClassID["chukonu"]="172" +NTIPAliasClassID["qf1"]="173" +NTIPAliasClassID["khalimsflail"]="173" +NTIPAliasClassID["qf2"]="174" +NTIPAliasClassID["khalimswill"]="174" +NTIPAliasClassID["ktr"]="175" +NTIPAliasClassID["katar"]="175" +NTIPAliasClassID["wrb"]="176" +NTIPAliasClassID["wristblade"]="176" +NTIPAliasClassID["axf"]="177" +NTIPAliasClassID["hatchethands"]="177" +NTIPAliasClassID["ces"]="178" +NTIPAliasClassID["cestus"]="178" +NTIPAliasClassID["clw"]="179" +NTIPAliasClassID["claws"]="179" +NTIPAliasClassID["btl"]="180" +NTIPAliasClassID["bladetalons"]="180" +NTIPAliasClassID["skr"]="181" +NTIPAliasClassID["scissorskatar"]="181" +NTIPAliasClassID["9ar"]="182" +NTIPAliasClassID["quhab"]="182" +NTIPAliasClassID["9wb"]="183" +NTIPAliasClassID["wristspike"]="183" +NTIPAliasClassID["9xf"]="184" +NTIPAliasClassID["fascia"]="184" +NTIPAliasClassID["9cs"]="185" +NTIPAliasClassID["handscythe"]="185" +NTIPAliasClassID["9lw"]="186" +NTIPAliasClassID["greaterclaws"]="186" +NTIPAliasClassID["9tw"]="187" +NTIPAliasClassID["greatertalons"]="187" +NTIPAliasClassID["9qr"]="188" +NTIPAliasClassID["scissorsquhab"]="188" +NTIPAliasClassID["7ar"]="189" +NTIPAliasClassID["suwayyah"]="189" +NTIPAliasClassID["7wb"]="190" +NTIPAliasClassID["wristsword"]="190" +NTIPAliasClassID["7xf"]="191" +NTIPAliasClassID["warfist"]="191" +NTIPAliasClassID["7cs"]="192" +NTIPAliasClassID["battlecestus"]="192" +NTIPAliasClassID["7lw"]="193" +NTIPAliasClassID["feralclaws"]="193" +NTIPAliasClassID["7tw"]="194" +NTIPAliasClassID["runictalons"]="194" +NTIPAliasClassID["7qr"]="195" +NTIPAliasClassID["scissorssuwayyah"]="195" +NTIPAliasClassID["7ha"]="196" +NTIPAliasClassID["tomahawk"]="196" +NTIPAliasClassID["7ax"]="197" +NTIPAliasClassID["smallcrescent"]="197" +NTIPAliasClassID["72a"]="198" +NTIPAliasClassID["ettinaxe"]="198" +NTIPAliasClassID["7mp"]="199" +NTIPAliasClassID["warspike"]="199" +NTIPAliasClassID["7wa"]="200" +NTIPAliasClassID["berserkeraxe"]="200" +NTIPAliasClassID["7la"]="201" +NTIPAliasClassID["feralaxe"]="201" +NTIPAliasClassID["7ba"]="202" +NTIPAliasClassID["silveredgedaxe"]="202" +NTIPAliasClassID["7bt"]="203" +NTIPAliasClassID["decapitator"]="203" +NTIPAliasClassID["7ga"]="204" +NTIPAliasClassID["championaxe"]="204" +NTIPAliasClassID["7gi"]="205" +NTIPAliasClassID["gloriousaxe"]="205" +NTIPAliasClassID["7wn"]="206" +NTIPAliasClassID["polishedwand"]="206" +NTIPAliasClassID["7yw"]="207" +NTIPAliasClassID["ghostwand"]="207" +NTIPAliasClassID["7bw"]="208" +NTIPAliasClassID["lichwand"]="208" +NTIPAliasClassID["7gw"]="209" +NTIPAliasClassID["unearthedwand"]="209" +NTIPAliasClassID["7cl"]="210" +NTIPAliasClassID["truncheon"]="210" +NTIPAliasClassID["7sc"]="211" +NTIPAliasClassID["mightyscepter"]="211" +NTIPAliasClassID["7qs"]="212" +NTIPAliasClassID["seraphrod"]="212" +NTIPAliasClassID["7ws"]="213" +NTIPAliasClassID["caduceus"]="213" +NTIPAliasClassID["7sp"]="214" +NTIPAliasClassID["tyrantclub"]="214" +NTIPAliasClassID["7ma"]="215" +NTIPAliasClassID["reinforcedmace"]="215" +NTIPAliasClassID["7mt"]="216" +NTIPAliasClassID["devilstar"]="216" +NTIPAliasClassID["7fl"]="217" +NTIPAliasClassID["scourge"]="217" +NTIPAliasClassID["7wh"]="218" +NTIPAliasClassID["legendarymallet"]="218" +NTIPAliasClassID["7m7"]="219" +NTIPAliasClassID["ogremaul"]="219" +NTIPAliasClassID["7gm"]="220" +NTIPAliasClassID["thundermaul"]="220" +NTIPAliasClassID["7ss"]="221" +NTIPAliasClassID["falcata"]="221" +NTIPAliasClassID["7sm"]="222" +NTIPAliasClassID["ataghan"]="222" +NTIPAliasClassID["7sb"]="223" +NTIPAliasClassID["elegantblade"]="223" +NTIPAliasClassID["7fc"]="224" +NTIPAliasClassID["hydraedge"]="224" +NTIPAliasClassID["7cr"]="225" +NTIPAliasClassID["phaseblade"]="225" +NTIPAliasClassID["7bs"]="226" +NTIPAliasClassID["conquestsword"]="226" +NTIPAliasClassID["7ls"]="227" +NTIPAliasClassID["crypticsword"]="227" +NTIPAliasClassID["7wd"]="228" +NTIPAliasClassID["mythicalsword"]="228" +NTIPAliasClassID["72h"]="229" +NTIPAliasClassID["legendsword"]="229" +NTIPAliasClassID["7cm"]="230" +NTIPAliasClassID["highlandblade"]="230" +NTIPAliasClassID["7gs"]="231" +NTIPAliasClassID["balrogblade"]="231" +NTIPAliasClassID["7b7"]="232" +NTIPAliasClassID["championsword"]="232" +NTIPAliasClassID["7fb"]="233" +NTIPAliasClassID["colossussword"]="233" +NTIPAliasClassID["7gd"]="234" +NTIPAliasClassID["colossusblade"]="234" +NTIPAliasClassID["7dg"]="235" +NTIPAliasClassID["boneknife"]="235" +NTIPAliasClassID["7di"]="236" +NTIPAliasClassID["mithrilpoint"]="236" +NTIPAliasClassID["7kr"]="237" +NTIPAliasClassID["fangedknife"]="237" +NTIPAliasClassID["7bl"]="238" +NTIPAliasClassID["legendspike"]="238" +NTIPAliasClassID["7tk"]="239" +NTIPAliasClassID["flyingknife"]="239" +NTIPAliasClassID["7ta"]="240" +NTIPAliasClassID["flyingaxe"]="240" +NTIPAliasClassID["7bk"]="241" +NTIPAliasClassID["wingedknife"]="241" +NTIPAliasClassID["7b8"]="242" +NTIPAliasClassID["wingedaxe"]="242" +NTIPAliasClassID["7ja"]="243" +NTIPAliasClassID["hyperionjavelin"]="243" +NTIPAliasClassID["7pi"]="244" +NTIPAliasClassID["stygianpilum"]="244" +NTIPAliasClassID["7s7"]="245" +NTIPAliasClassID["balrogspear"]="245" +NTIPAliasClassID["7gl"]="246" +NTIPAliasClassID["ghostglaive"]="246" +NTIPAliasClassID["7ts"]="247" +NTIPAliasClassID["wingedharpoon"]="247" +NTIPAliasClassID["7sr"]="248" +NTIPAliasClassID["hyperionspear"]="248" +NTIPAliasClassID["7tr"]="249" +NTIPAliasClassID["stygianpike"]="249" +NTIPAliasClassID["7br"]="250" +NTIPAliasClassID["mancatcher"]="250" +NTIPAliasClassID["7st"]="251" +NTIPAliasClassID["ghostspear"]="251" +NTIPAliasClassID["7p7"]="252" +NTIPAliasClassID["warpike"]="252" +NTIPAliasClassID["7o7"]="253" +NTIPAliasClassID["ogreaxe"]="253" +NTIPAliasClassID["7vo"]="254" +NTIPAliasClassID["colossusvoulge"]="254" +NTIPAliasClassID["7s8"]="255" +NTIPAliasClassID["thresher"]="255" +NTIPAliasClassID["7pa"]="256" +NTIPAliasClassID["crypticaxe"]="256" +NTIPAliasClassID["7h7"]="257" +NTIPAliasClassID["greatpoleaxe"]="257" +NTIPAliasClassID["7wc"]="258" +NTIPAliasClassID["giantthresher"]="258" +NTIPAliasClassID["6ss"]="259" +NTIPAliasClassID["walkingstick"]="259" +NTIPAliasClassID["6ls"]="260" +NTIPAliasClassID["stalagmite"]="260" +NTIPAliasClassID["6cs"]="261" +NTIPAliasClassID["elderstaff"]="261" +NTIPAliasClassID["6bs"]="262" +NTIPAliasClassID["shillelagh"]="262" +NTIPAliasClassID["6ws"]="263" +NTIPAliasClassID["archonstaff"]="263" +NTIPAliasClassID["6sb"]="264" +NTIPAliasClassID["spiderbow"]="264" +NTIPAliasClassID["6hb"]="265" +NTIPAliasClassID["bladebow"]="265" +NTIPAliasClassID["6lb"]="266" +NTIPAliasClassID["shadowbow"]="266" +NTIPAliasClassID["6cb"]="267" +NTIPAliasClassID["greatbow"]="267" +NTIPAliasClassID["6s7"]="268" +NTIPAliasClassID["diamondbow"]="268" +NTIPAliasClassID["6l7"]="269" +NTIPAliasClassID["crusaderbow"]="269" +NTIPAliasClassID["6sw"]="270" +NTIPAliasClassID["wardbow"]="270" +NTIPAliasClassID["6lw"]="271" +NTIPAliasClassID["hydrabow"]="271" +NTIPAliasClassID["6lx"]="272" +NTIPAliasClassID["pelletbow"]="272" +NTIPAliasClassID["6mx"]="273" +NTIPAliasClassID["gorgoncrossbow"]="273" +NTIPAliasClassID["6hx"]="274" +NTIPAliasClassID["colossuscrossbow"]="274" +NTIPAliasClassID["6rx"]="275" +NTIPAliasClassID["demoncrossbow"]="275" +NTIPAliasClassID["ob1"]="276" +NTIPAliasClassID["eagleorb"]="276" +NTIPAliasClassID["ob2"]="277" +NTIPAliasClassID["sacredglobe"]="277" +NTIPAliasClassID["ob3"]="278" +NTIPAliasClassID["smokedsphere"]="278" +NTIPAliasClassID["ob4"]="279" +NTIPAliasClassID["claspedorb"]="279" +NTIPAliasClassID["ob5"]="280" +NTIPAliasClassID["jaredsstone"]="280" +NTIPAliasClassID["am1"]="281" +NTIPAliasClassID["stagbow"]="281" +NTIPAliasClassID["am2"]="282" +NTIPAliasClassID["reflexbow"]="282" +NTIPAliasClassID["am3"]="283" +NTIPAliasClassID["maidenspear"]="283" +NTIPAliasClassID["am4"]="284" +NTIPAliasClassID["maidenpike"]="284" +NTIPAliasClassID["am5"]="285" +NTIPAliasClassID["maidenjavelin"]="285" +NTIPAliasClassID["ob6"]="286" +NTIPAliasClassID["glowingorb"]="286" +NTIPAliasClassID["ob7"]="287" +NTIPAliasClassID["crystallineglobe"]="287" +NTIPAliasClassID["ob8"]="288" +NTIPAliasClassID["cloudysphere"]="288" +NTIPAliasClassID["ob9"]="289" +NTIPAliasClassID["sparklingball"]="289" +NTIPAliasClassID["oba"]="290" +NTIPAliasClassID["swirlingcrystal"]="290" +NTIPAliasClassID["am6"]="291" +NTIPAliasClassID["ashwoodbow"]="291" +NTIPAliasClassID["am7"]="292" +NTIPAliasClassID["ceremonialbow"]="292" +NTIPAliasClassID["am8"]="293" +NTIPAliasClassID["ceremonialspear"]="293" +NTIPAliasClassID["am9"]="294" +NTIPAliasClassID["ceremonialpike"]="294" +NTIPAliasClassID["ama"]="295" +NTIPAliasClassID["ceremonialjavelin"]="295" +NTIPAliasClassID["obb"]="296" +NTIPAliasClassID["heavenlystone"]="296" +NTIPAliasClassID["obc"]="297" +NTIPAliasClassID["eldritchorb"]="297" +NTIPAliasClassID["obd"]="298" +NTIPAliasClassID["demonheart"]="298" +NTIPAliasClassID["obe"]="299" +NTIPAliasClassID["vortexorb"]="299" +NTIPAliasClassID["obf"]="300" +NTIPAliasClassID["dimensionalshard"]="300" +NTIPAliasClassID["amb"]="301" +NTIPAliasClassID["matriarchalbow"]="301" +NTIPAliasClassID["amc"]="302" +NTIPAliasClassID["grandmatronbow"]="302" +NTIPAliasClassID["amd"]="303" +NTIPAliasClassID["matriarchalspear"]="303" +NTIPAliasClassID["ame"]="304" +NTIPAliasClassID["matriarchalpike"]="304" +NTIPAliasClassID["amf"]="305" +NTIPAliasClassID["matriarchaljavelin"]="305" +NTIPAliasClassID["cap"]="306" +NTIPAliasClassID["skp"]="307" +NTIPAliasClassID["skullcap"]="307" +NTIPAliasClassID["hlm"]="308" +NTIPAliasClassID["helm"]="308" +NTIPAliasClassID["fhl"]="309" +NTIPAliasClassID["fullhelm"]="309" +NTIPAliasClassID["ghm"]="310" +NTIPAliasClassID["greathelm"]="310" +NTIPAliasClassID["crn"]="311" +NTIPAliasClassID["crown"]="311" +NTIPAliasClassID["msk"]="312" +NTIPAliasClassID["mask"]="312" +NTIPAliasClassID["qui"]="313" +NTIPAliasClassID["quiltedarmor"]="313" +NTIPAliasClassID["lea"]="314" +NTIPAliasClassID["leatherarmor"]="314" +NTIPAliasClassID["hla"]="315" +NTIPAliasClassID["hardleatherarmor"]="315" +NTIPAliasClassID["stu"]="316" +NTIPAliasClassID["studdedleather"]="316" +NTIPAliasClassID["rng"]="317" +NTIPAliasClassID["ringmail"]="317" +NTIPAliasClassID["scl"]="318" +NTIPAliasClassID["scalemail"]="318" +NTIPAliasClassID["chn"]="319" +NTIPAliasClassID["chainmail"]="319" +NTIPAliasClassID["brs"]="320" +NTIPAliasClassID["breastplate"]="320" +NTIPAliasClassID["spl"]="321" +NTIPAliasClassID["splintmail"]="321" +NTIPAliasClassID["plt"]="322" +NTIPAliasClassID["platemail"]="322" +NTIPAliasClassID["fld"]="323" +NTIPAliasClassID["fieldplate"]="323" +NTIPAliasClassID["gth"]="324" +NTIPAliasClassID["gothicplate"]="324" +NTIPAliasClassID["ful"]="325" +NTIPAliasClassID["fullplatemail"]="325" +NTIPAliasClassID["aar"]="326" +NTIPAliasClassID["ancientarmor"]="326" +NTIPAliasClassID["ltp"]="327" +NTIPAliasClassID["lightplate"]="327" +NTIPAliasClassID["buc"]="328" +NTIPAliasClassID["buckler"]="328" +NTIPAliasClassID["sml"]="329" +NTIPAliasClassID["smallshield"]="329" +NTIPAliasClassID["lrg"]="330" +NTIPAliasClassID["largeshield"]="330" +NTIPAliasClassID["kit"]="331" +NTIPAliasClassID["kiteshield"]="331" +NTIPAliasClassID["tow"]="332" +NTIPAliasClassID["towershield"]="332" +NTIPAliasClassID["gts"]="333" +NTIPAliasClassID["gothicshield"]="333" +NTIPAliasClassID["lgl"]="334" +NTIPAliasClassID["leathergloves"]="334" +NTIPAliasClassID["vgl"]="335" +NTIPAliasClassID["heavygloves"]="335" +NTIPAliasClassID["mgl"]="336" +NTIPAliasClassID["chaingloves"]="336" +NTIPAliasClassID["tgl"]="337" +NTIPAliasClassID["lightgauntlets"]="337" +NTIPAliasClassID["hgl"]="338" +NTIPAliasClassID["gauntlets"]="338" +NTIPAliasClassID["lbt"]="339" +NTIPAliasClassID["boots"]="339" +NTIPAliasClassID["vbt"]="340" +NTIPAliasClassID["heavyboots"]="340" +NTIPAliasClassID["mbt"]="341" +NTIPAliasClassID["chainboots"]="341" +NTIPAliasClassID["tbt"]="342" +NTIPAliasClassID["lightplatedboots"]="342" +NTIPAliasClassID["hbt"]="343" +NTIPAliasClassID["greaves"]="343" +NTIPAliasClassID["lbl"]="344" +NTIPAliasClassID["sash"]="344" +NTIPAliasClassID["vbl"]="345" +NTIPAliasClassID["lightbelt"]="345" +NTIPAliasClassID["mbl"]="346" +NTIPAliasClassID["belt"]="346" +NTIPAliasClassID["tbl"]="347" +NTIPAliasClassID["heavybelt"]="347" +NTIPAliasClassID["hbl"]="348" +NTIPAliasClassID["platedbelt"]="348" +NTIPAliasClassID["bhm"]="349" +NTIPAliasClassID["bonehelm"]="349" +NTIPAliasClassID["bsh"]="350" +NTIPAliasClassID["boneshield"]="350" +NTIPAliasClassID["spk"]="351" +NTIPAliasClassID["spikedshield"]="351" +NTIPAliasClassID["xap"]="352" +NTIPAliasClassID["warhat"]="352" +NTIPAliasClassID["xkp"]="353" +NTIPAliasClassID["sallet"]="353" +NTIPAliasClassID["xlm"]="354" +NTIPAliasClassID["casque"]="354" +NTIPAliasClassID["xhl"]="355" +NTIPAliasClassID["basinet"]="355" +NTIPAliasClassID["xhm"]="356" +NTIPAliasClassID["wingedhelm"]="356" +NTIPAliasClassID["xrn"]="357" +NTIPAliasClassID["grandcrown"]="357" +NTIPAliasClassID["xsk"]="358" +NTIPAliasClassID["deathmask"]="358" +NTIPAliasClassID["xui"]="359" +NTIPAliasClassID["ghostarmor"]="359" +NTIPAliasClassID["xea"]="360" +NTIPAliasClassID["serpentskinarmor"]="360" +NTIPAliasClassID["xla"]="361" +NTIPAliasClassID["demonhidearmor"]="361" +NTIPAliasClassID["xtu"]="362" +NTIPAliasClassID["trellisedarmor"]="362" +NTIPAliasClassID["xng"]="363" +NTIPAliasClassID["linkedmail"]="363" +NTIPAliasClassID["xcl"]="364" +NTIPAliasClassID["tigulatedmail"]="364" +NTIPAliasClassID["xhn"]="365" +NTIPAliasClassID["mesharmor"]="365" +NTIPAliasClassID["xrs"]="366" +NTIPAliasClassID["cuirass"]="366" +NTIPAliasClassID["xpl"]="367" +NTIPAliasClassID["russetarmor"]="367" +NTIPAliasClassID["xlt"]="368" +NTIPAliasClassID["templarcoat"]="368" +NTIPAliasClassID["xld"]="369" +NTIPAliasClassID["sharktootharmor"]="369" +NTIPAliasClassID["xth"]="370" +NTIPAliasClassID["embossedplate"]="370" +NTIPAliasClassID["xul"]="371" +NTIPAliasClassID["chaosarmor"]="371" +NTIPAliasClassID["xar"]="372" +NTIPAliasClassID["ornateplate"]="372" +NTIPAliasClassID["xtp"]="373" +NTIPAliasClassID["mageplate"]="373" +NTIPAliasClassID["xuc"]="374" +NTIPAliasClassID["defender"]="374" +NTIPAliasClassID["xml"]="375" +NTIPAliasClassID["roundshield"]="375" +NTIPAliasClassID["xrg"]="376" +NTIPAliasClassID["scutum"]="376" +NTIPAliasClassID["xit"]="377" +NTIPAliasClassID["dragonshield"]="377" +NTIPAliasClassID["xow"]="378" +NTIPAliasClassID["pavise"]="378" +NTIPAliasClassID["xts"]="379" +NTIPAliasClassID["ancientshield"]="379" +NTIPAliasClassID["xlg"]="380" +NTIPAliasClassID["demonhidegloves"]="380" +NTIPAliasClassID["xvg"]="381" +NTIPAliasClassID["sharkskingloves"]="381" +NTIPAliasClassID["xmg"]="382" +NTIPAliasClassID["heavybracers"]="382" +NTIPAliasClassID["xtg"]="383" +NTIPAliasClassID["battlegauntlets"]="383" +NTIPAliasClassID["xhg"]="384" +NTIPAliasClassID["wargauntlets"]="384" +NTIPAliasClassID["xlb"]="385" +NTIPAliasClassID["demonhideboots"]="385" +NTIPAliasClassID["xvb"]="386" +NTIPAliasClassID["sharkskinboots"]="386" +NTIPAliasClassID["xmb"]="387" +NTIPAliasClassID["meshboots"]="387" +NTIPAliasClassID["xtb"]="388" +NTIPAliasClassID["battleboots"]="388" +NTIPAliasClassID["xhb"]="389" +NTIPAliasClassID["warboots"]="389" +NTIPAliasClassID["zlb"]="390" +NTIPAliasClassID["demonhidesash"]="390" +NTIPAliasClassID["zvb"]="391" +NTIPAliasClassID["sharkskinbelt"]="391" +NTIPAliasClassID["zmb"]="392" +NTIPAliasClassID["meshbelt"]="392" +NTIPAliasClassID["ztb"]="393" +NTIPAliasClassID["battlebelt"]="393" +NTIPAliasClassID["zhb"]="394" +NTIPAliasClassID["warbelt"]="394" +NTIPAliasClassID["xh9"]="395" +NTIPAliasClassID["grimhelm"]="395" +NTIPAliasClassID["xsh"]="396" +NTIPAliasClassID["grimshield"]="396" +NTIPAliasClassID["xpk"]="397" +NTIPAliasClassID["barbedshield"]="397" +NTIPAliasClassID["dr1"]="398" +NTIPAliasClassID["wolfhead"]="398" +NTIPAliasClassID["dr2"]="399" +NTIPAliasClassID["hawkhelm"]="399" +NTIPAliasClassID["dr3"]="400" +NTIPAliasClassID["antlers"]="400" +NTIPAliasClassID["dr4"]="401" +NTIPAliasClassID["falconmask"]="401" +NTIPAliasClassID["dr5"]="402" +NTIPAliasClassID["spiritmask"]="402" +NTIPAliasClassID["ba1"]="403" +NTIPAliasClassID["jawbonecap"]="403" +NTIPAliasClassID["ba2"]="404" +NTIPAliasClassID["fangedhelm"]="404" +NTIPAliasClassID["ba3"]="405" +NTIPAliasClassID["hornedhelm"]="405" +NTIPAliasClassID["ba4"]="406" +NTIPAliasClassID["assaulthelmet"]="406" +NTIPAliasClassID["ba5"]="407" +NTIPAliasClassID["avengerguard"]="407" +NTIPAliasClassID["pa1"]="408" +NTIPAliasClassID["targe"]="408" +NTIPAliasClassID["pa2"]="409" +NTIPAliasClassID["rondache"]="409" +NTIPAliasClassID["pa3"]="410" +NTIPAliasClassID["heraldicshield"]="410" +NTIPAliasClassID["pa4"]="411" +NTIPAliasClassID["aerinshield"]="411" +NTIPAliasClassID["pa5"]="412" +NTIPAliasClassID["crownshield"]="412" +NTIPAliasClassID["ne1"]="413" +NTIPAliasClassID["preservedhead"]="413" +NTIPAliasClassID["ne2"]="414" +NTIPAliasClassID["zombiehead"]="414" +NTIPAliasClassID["ne3"]="415" +NTIPAliasClassID["unravellerhead"]="415" +NTIPAliasClassID["ne4"]="416" +NTIPAliasClassID["gargoylehead"]="416" +NTIPAliasClassID["ne5"]="417" +NTIPAliasClassID["demonhead"]="428" +NTIPAliasClassID["ci0"]="418" +NTIPAliasClassID["circlet"]="418" +NTIPAliasClassID["ci1"]="419" +NTIPAliasClassID["coronet"]="419" +NTIPAliasClassID["ci2"]="420" +NTIPAliasClassID["tiara"]="420" +NTIPAliasClassID["ci3"]="421" +NTIPAliasClassID["diadem"]="421" +NTIPAliasClassID["uap"]="422" +NTIPAliasClassID["shako"]="422" +NTIPAliasClassID["ukp"]="423" +NTIPAliasClassID["hydraskull"]="423" +NTIPAliasClassID["ulm"]="424" +NTIPAliasClassID["armet"]="424" +NTIPAliasClassID["uhl"]="425" +NTIPAliasClassID["giantconch"]="425" +NTIPAliasClassID["uhm"]="426" +NTIPAliasClassID["spiredhelm"]="426" +NTIPAliasClassID["urn"]="427" +NTIPAliasClassID["corona"]="427" +NTIPAliasClassID["usk"]="428" +NTIPAliasClassID["uui"]="429" +NTIPAliasClassID["duskshroud"]="429" +NTIPAliasClassID["uea"]="430" +NTIPAliasClassID["wyrmhide"]="430" +NTIPAliasClassID["ula"]="431" +NTIPAliasClassID["scarabhusk"]="431" +NTIPAliasClassID["utu"]="432" +NTIPAliasClassID["wirefleece"]="432" +NTIPAliasClassID["ung"]="433" +NTIPAliasClassID["diamondmail"]="433" +NTIPAliasClassID["ucl"]="434" +NTIPAliasClassID["loricatedmail"]="434" +NTIPAliasClassID["uhn"]="435" +NTIPAliasClassID["boneweave"]="435" +NTIPAliasClassID["urs"]="436" +NTIPAliasClassID["greathauberk"]="436" +NTIPAliasClassID["upl"]="437" +NTIPAliasClassID["balrogskin"]="437" +NTIPAliasClassID["ult"]="438" +NTIPAliasClassID["hellforgeplate"]="438" +NTIPAliasClassID["uld"]="439" +NTIPAliasClassID["krakenshell"]="439" +NTIPAliasClassID["uth"]="440" +NTIPAliasClassID["lacqueredplate"]="440" +NTIPAliasClassID["uul"]="441" +NTIPAliasClassID["shadowplate"]="441" +NTIPAliasClassID["uar"]="442" +NTIPAliasClassID["sacredarmor"]="442" +NTIPAliasClassID["utp"]="443" +NTIPAliasClassID["archonplate"]="443" +NTIPAliasClassID["uuc"]="444" +NTIPAliasClassID["heater"]="444" +NTIPAliasClassID["uml"]="445" +NTIPAliasClassID["luna"]="445" +NTIPAliasClassID["urg"]="446" +NTIPAliasClassID["hyperion"]="446" +NTIPAliasClassID["uit"]="447" +NTIPAliasClassID["monarch"]="447" +NTIPAliasClassID["uow"]="448" +NTIPAliasClassID["aegis"]="448" +NTIPAliasClassID["uts"]="449" +NTIPAliasClassID["ward"]="449" +NTIPAliasClassID["ulg"]="450" +NTIPAliasClassID["bramblemitts"]="450" +NTIPAliasClassID["uvg"]="451" +NTIPAliasClassID["vampirebonegloves"]="451" +NTIPAliasClassID["umg"]="452" +NTIPAliasClassID["vambraces"]="452" +NTIPAliasClassID["utg"]="453" +NTIPAliasClassID["crusadergauntlets"]="453" +NTIPAliasClassID["uhg"]="454" +NTIPAliasClassID["ogregauntlets"]="454" +NTIPAliasClassID["ulb"]="455" +NTIPAliasClassID["wyrmhideboots"]="455" +NTIPAliasClassID["uvb"]="456" +NTIPAliasClassID["scarabshellboots"]="456" +NTIPAliasClassID["umb"]="457" +NTIPAliasClassID["boneweaveboots"]="457" +NTIPAliasClassID["utb"]="458" +NTIPAliasClassID["mirroredboots"]="458" +NTIPAliasClassID["uhb"]="459" +NTIPAliasClassID["myrmidongreaves"]="459" +NTIPAliasClassID["ulc"]="460" +NTIPAliasClassID["spiderwebsash"]="460" +NTIPAliasClassID["uvc"]="461" +NTIPAliasClassID["vampirefangbelt"]="461" +NTIPAliasClassID["umc"]="462" +NTIPAliasClassID["mithrilcoil"]="462" +NTIPAliasClassID["utc"]="463" +NTIPAliasClassID["trollbelt"]="463" +NTIPAliasClassID["uhc"]="464" +NTIPAliasClassID["colossusgirdle"]="464" +NTIPAliasClassID["uh9"]="465" +NTIPAliasClassID["bonevisage"]="465" +NTIPAliasClassID["ush"]="466" +NTIPAliasClassID["trollnest"]="466" +NTIPAliasClassID["upk"]="467" +NTIPAliasClassID["bladebarrier"]="467" +NTIPAliasClassID["dr6"]="468" +NTIPAliasClassID["alphahelm"]="468" +NTIPAliasClassID["dr7"]="469" +NTIPAliasClassID["griffonheaddress"]="469" +NTIPAliasClassID["dr8"]="470" +NTIPAliasClassID["huntersguise"]="470" +NTIPAliasClassID["dr9"]="471" +NTIPAliasClassID["sacredfeathers"]="471" +NTIPAliasClassID["dra"]="472" +NTIPAliasClassID["totemicmask"]="472" +NTIPAliasClassID["ba6"]="473" +NTIPAliasClassID["jawbonevisor"]="473" +NTIPAliasClassID["ba7"]="474" +NTIPAliasClassID["lionhelm"]="474" +NTIPAliasClassID["ba8"]="475" +NTIPAliasClassID["ragemask"]="475" +NTIPAliasClassID["ba9"]="476" +NTIPAliasClassID["savagehelmet"]="476" +NTIPAliasClassID["baa"]="477" +NTIPAliasClassID["slayerguard"]="477" +NTIPAliasClassID["pa6"]="478" +NTIPAliasClassID["akarantarge"]="478" +NTIPAliasClassID["pa7"]="479" +NTIPAliasClassID["akaranrondache"]="479" +NTIPAliasClassID["pa8"]="480" +NTIPAliasClassID["protectorshield"]="480" +NTIPAliasClassID["pa9"]="481" +NTIPAliasClassID["gildedshield"]="481" +NTIPAliasClassID["paa"]="482" +NTIPAliasClassID["royalshield"]="482" +NTIPAliasClassID["ne6"]="483" +NTIPAliasClassID["mummifiedtrophy"]="483" +NTIPAliasClassID["ne7"]="484" +NTIPAliasClassID["fetishtrophy"]="484" +NTIPAliasClassID["ne8"]="485" +NTIPAliasClassID["sextontrophy"]="485" +NTIPAliasClassID["ne9"]="486" +NTIPAliasClassID["cantortrophy"]="486" +NTIPAliasClassID["nea"]="487" +NTIPAliasClassID["hierophanttrophy"]="487" +NTIPAliasClassID["drb"]="488" +NTIPAliasClassID["bloodspirit"]="488" +NTIPAliasClassID["drc"]="489" +NTIPAliasClassID["sunspirit"]="489" +NTIPAliasClassID["drd"]="490" +NTIPAliasClassID["earthspirit"]="490" +NTIPAliasClassID["dre"]="491" +NTIPAliasClassID["skyspirit"]="491" +NTIPAliasClassID["drf"]="492" +NTIPAliasClassID["dreamspirit"]="492" +NTIPAliasClassID["bab"]="493" +NTIPAliasClassID["carnagehelm"]="493" +NTIPAliasClassID["bac"]="494" +NTIPAliasClassID["furyvisor"]="494" +NTIPAliasClassID["bad"]="495" +NTIPAliasClassID["destroyerhelm"]="495" +NTIPAliasClassID["bae"]="496" +NTIPAliasClassID["conquerorcrown"]="496" +NTIPAliasClassID["baf"]="497" +NTIPAliasClassID["guardiancrown"]="497" +NTIPAliasClassID["pab"]="498" +NTIPAliasClassID["sacredtarge"]="498" +NTIPAliasClassID["pac"]="499" +NTIPAliasClassID["sacredrondache"]="499" +NTIPAliasClassID["pad"]="500" +NTIPAliasClassID["kurastshield"]="500" +NTIPAliasClassID["pae"]="501" +NTIPAliasClassID["zakarumshield"]="501" +NTIPAliasClassID["paf"]="502" +NTIPAliasClassID["vortexshield"]="502" +NTIPAliasClassID["neb"]="503" +NTIPAliasClassID["minionskull"]="503" +NTIPAliasClassID["neg"]="504" +NTIPAliasClassID["hellspawnskull"]="504" +NTIPAliasClassID["ned"]="505" +NTIPAliasClassID["overseerskull"]="505" +NTIPAliasClassID["nee"]="506" +NTIPAliasClassID["succubusskull"]="506" +NTIPAliasClassID["nef"]="507" +NTIPAliasClassID["bloodlordskull"]="507" +NTIPAliasClassID["elx"]="508" +NTIPAliasClassID["elixir"]="508" +NTIPAliasClassID["hpo"]="509" +NTIPAliasClassID["mpo"]="510" +NTIPAliasClassID["hpf"]="511" +NTIPAliasClassID["mpf"]="512" +NTIPAliasClassID["vps"]="513" +NTIPAliasClassID["staminapotion"]="513" +NTIPAliasClassID["yps"]="514" +NTIPAliasClassID["antidotepotion"]="514" +NTIPAliasClassID["rvs"]="515" +NTIPAliasClassID["rejuvenationpotion"]="515" +NTIPAliasClassID["rvl"]="516" +NTIPAliasClassID["fullrejuvenationpotion"]="516" +NTIPAliasClassID["wms"]="517" +NTIPAliasClassID["thawingpotion"]="517" +NTIPAliasClassID["tbk"]="518" +NTIPAliasClassID["tomeoftownportal"]="518" +NTIPAliasClassID["ibk"]="519" +NTIPAliasClassID["tomeofidentify"]="519" +NTIPAliasClassID["amu"]="520" +NTIPAliasClassID["amulet"]="520" +NTIPAliasClassID["vip"]="521" +NTIPAliasClassID["topofthehoradricstaff"]="521" +NTIPAliasClassID["rin"]="522" +NTIPAliasClassID["ring"]="522" +NTIPAliasClassID["gld"]="523" +NTIPAliasClassID["gold"]="523" +NTIPAliasClassID["bks"]="524" +NTIPAliasClassID["scrollofinifuss"]="524" +NTIPAliasClassID["bkd"]="525" +NTIPAliasClassID["keytothecairnstones"]="525" +NTIPAliasClassID["aqv"]="526" +NTIPAliasClassID["arrows"]="526" +NTIPAliasClassID["tch"]="527" +NTIPAliasClassID["torch"]="527" +NTIPAliasClassID["cqv"]="528" +NTIPAliasClassID["bolts"]="528" +NTIPAliasClassID["tsc"]="529" +NTIPAliasClassID["scrolloftownportal"]="529" +NTIPAliasClassID["isc"]="530" +NTIPAliasClassID["scrollofidentify"]="530" +NTIPAliasClassID["hrt"]="531" +NTIPAliasClassID["heart"]="531" +NTIPAliasClassID["brz"]="532" +NTIPAliasClassID["brain"]="532" +NTIPAliasClassID["jaw"]="533" +NTIPAliasClassID["jawbone"]="533" +NTIPAliasClassID["eyz"]="534" +NTIPAliasClassID["eye"]="534" +NTIPAliasClassID["hrn"]="535" +NTIPAliasClassID["horn"]="535" +NTIPAliasClassID["tal"]="536" +NTIPAliasClassID["tail"]="536" +NTIPAliasClassID["flg"]="537" +NTIPAliasClassID["flag"]="537" +NTIPAliasClassID["fng"]="538" +NTIPAliasClassID["fang"]="538" +NTIPAliasClassID["qll"]="539" +NTIPAliasClassID["quill"]="539" +NTIPAliasClassID["sol"]="540" +NTIPAliasClassID["soul"]="540" +NTIPAliasClassID["scz"]="541" +NTIPAliasClassID["scalp"]="541" +NTIPAliasClassID["spe"]="542" +NTIPAliasClassID["spleen"]="542" +NTIPAliasClassID["key"]="543" +NTIPAliasClassID["luv"]="544" +NTIPAliasClassID["theblacktowerkey"]="544" +NTIPAliasClassID["xyz"]="545" +NTIPAliasClassID["potionoflife"]="545" +NTIPAliasClassID["j34"]="546" +NTIPAliasClassID["ajadefigurine"]="546" +NTIPAliasClassID["g34"]="547" +NTIPAliasClassID["thegoldenbird"]="547" +NTIPAliasClassID["bbb"]="548" +NTIPAliasClassID["lamesenstome"]="548" +NTIPAliasClassID["box"]="549" +NTIPAliasClassID["horadriccube"]="549" +NTIPAliasClassID["tr1"]="550" +NTIPAliasClassID["horadricscroll"]="550" +NTIPAliasClassID["mss"]="551" +NTIPAliasClassID["mephistossoulstone"]="551" +NTIPAliasClassID["ass"]="552" +NTIPAliasClassID["bookofskill"]="552" +NTIPAliasClassID["qey"]="553" +NTIPAliasClassID["khalimseye"]="553" +NTIPAliasClassID["qhr"]="554" +NTIPAliasClassID["khalimsheart"]="554" +NTIPAliasClassID["qbr"]="555" +NTIPAliasClassID["khalimsbrain"]="555" +NTIPAliasClassID["ear"]="556" +NTIPAliasClassID["gcv"]="557" +NTIPAliasClassID["chippedamethyst"]="557" +NTIPAliasClassID["gfv"]="558" +NTIPAliasClassID["flawedamethyst"]="558" +NTIPAliasClassID["gsv"]="559" +NTIPAliasClassID["amethyst"]="559" +NTIPAliasClassID["gzv"]="560" +NTIPAliasClassID["flawlessamethyst"]="560" +NTIPAliasClassID["gpv"]="561" +NTIPAliasClassID["perfectamethyst"]="561" +NTIPAliasClassID["gcy"]="562" +NTIPAliasClassID["chippedtopaz"]="562" +NTIPAliasClassID["gfy"]="563" +NTIPAliasClassID["flawedtopaz"]="563" +NTIPAliasClassID["gsy"]="564" +NTIPAliasClassID["topaz"]="564" +NTIPAliasClassID["gly"]="565" +NTIPAliasClassID["flawlesstopaz"]="565" +NTIPAliasClassID["gpy"]="566" +NTIPAliasClassID["perfecttopaz"]="566" +NTIPAliasClassID["gcb"]="567" +NTIPAliasClassID["chippedsapphire"]="567" +NTIPAliasClassID["gfb"]="568" +NTIPAliasClassID["flawedsapphire"]="568" +NTIPAliasClassID["gsb"]="569" +NTIPAliasClassID["sapphire"]="569" +NTIPAliasClassID["glb"]="570" +NTIPAliasClassID["flawlesssapphire"]="570" +NTIPAliasClassID["gpb"]="571" +NTIPAliasClassID["perfectsapphire"]="571" +NTIPAliasClassID["gcg"]="572" +NTIPAliasClassID["chippedemerald"]="572" +NTIPAliasClassID["gfg"]="573" +NTIPAliasClassID["flawedemerald"]="573" +NTIPAliasClassID["gsg"]="574" +NTIPAliasClassID["emerald"]="574" +NTIPAliasClassID["glg"]="575" +NTIPAliasClassID["flawlessemerald"]="575" +NTIPAliasClassID["gpg"]="576" +NTIPAliasClassID["perfectemerald"]="576" +NTIPAliasClassID["gcr"]="577" +NTIPAliasClassID["chippedruby"]="577" +NTIPAliasClassID["gfr"]="578" +NTIPAliasClassID["flawedruby"]="578" +NTIPAliasClassID["gsr"]="579" +NTIPAliasClassID["ruby"]="579" +NTIPAliasClassID["glr"]="580" +NTIPAliasClassID["flawlessruby"]="580" +NTIPAliasClassID["gpr"]="581" +NTIPAliasClassID["perfectruby"]="581" +NTIPAliasClassID["gcw"]="582" +NTIPAliasClassID["chippeddiamond"]="582" +NTIPAliasClassID["gfw"]="583" +NTIPAliasClassID["flaweddiamond"]="583" +NTIPAliasClassID["gsw"]="584" +NTIPAliasClassID["diamond"]="584" +NTIPAliasClassID["glw"]="585" +NTIPAliasClassID["flawlessdiamond"]="585" +NTIPAliasClassID["gpw"]="586" +NTIPAliasClassID["perfectdiamond"]="586" +NTIPAliasClassID["hp1"]="587" +NTIPAliasClassID["minorhealingpotion"]="587" +NTIPAliasClassID["hp2"]="588" +NTIPAliasClassID["lighthealingpotion"]="588" +NTIPAliasClassID["hp3"]="589" +NTIPAliasClassID["healingpotion"]="589" +NTIPAliasClassID["hp4"]="590" +NTIPAliasClassID["greaterhealingpotion"]="590" +NTIPAliasClassID["hp5"]="591" +NTIPAliasClassID["superhealingpotion"]="591" +NTIPAliasClassID["mp1"]="592" +NTIPAliasClassID["minormanapotion"]="592" +NTIPAliasClassID["mp2"]="593" +NTIPAliasClassID["lightmanapotion"]="593" +NTIPAliasClassID["mp3"]="594" +NTIPAliasClassID["manapotion"]="594" +NTIPAliasClassID["mp4"]="595" +NTIPAliasClassID["greatermanapotion"]="595" +NTIPAliasClassID["mp5"]="596" +NTIPAliasClassID["supermanapotion"]="596" +NTIPAliasClassID["skc"]="597" +NTIPAliasClassID["chippedskull"]="597" +NTIPAliasClassID["skf"]="598" +NTIPAliasClassID["flawedskull"]="598" +NTIPAliasClassID["sku"]="599" +NTIPAliasClassID["skull"]="599" +NTIPAliasClassID["skl"]="600" +NTIPAliasClassID["flawlessskull"]="600" +NTIPAliasClassID["skz"]="601" +NTIPAliasClassID["perfectskull"]="601" +NTIPAliasClassID["hrb"]="602" +NTIPAliasClassID["herb"]="602" +NTIPAliasClassID["cm1"]="603" +NTIPAliasClassID["smallcharm"]="603" +NTIPAliasClassID["cm2"]="604" +NTIPAliasClassID["largecharm"]="604" +NTIPAliasClassID["cm3"]="605" +NTIPAliasClassID["grandcharm"]="605" +NTIPAliasClassID["rps"]="606" +NTIPAliasClassID["rpl"]="607" +NTIPAliasClassID["bps"]="608" +NTIPAliasClassID["bpl"]="609" +NTIPAliasClassID["r01"]="610" +NTIPAliasClassID["elrune"]="610" +NTIPAliasClassID["r02"]="611" +NTIPAliasClassID["eldrune"]="611" +NTIPAliasClassID["r03"]="612" +NTIPAliasClassID["tirrune"]="612" +NTIPAliasClassID["r04"]="613" +NTIPAliasClassID["nefrune"]="613" +NTIPAliasClassID["r05"]="614" +NTIPAliasClassID["ethrune"]="614" +NTIPAliasClassID["r06"]="615" +NTIPAliasClassID["ithrune"]="615" +NTIPAliasClassID["r07"]="616" +NTIPAliasClassID["talrune"]="616" +NTIPAliasClassID["r08"]="617" +NTIPAliasClassID["ralrune"]="617" +NTIPAliasClassID["r09"]="618" +NTIPAliasClassID["ortrune"]="618" +NTIPAliasClassID["r10"]="619" +NTIPAliasClassID["thulrune"]="619" +NTIPAliasClassID["r11"]="620" +NTIPAliasClassID["amnrune"]="620" +NTIPAliasClassID["r12"]="621" +NTIPAliasClassID["solrune"]="621" +NTIPAliasClassID["r13"]="622" +NTIPAliasClassID["shaelrune"]="622" +NTIPAliasClassID["r14"]="623" +NTIPAliasClassID["dolrune"]="623" +NTIPAliasClassID["r15"]="624" +NTIPAliasClassID["helrune"]="624" +NTIPAliasClassID["r16"]="625" +NTIPAliasClassID["iorune"]="625" +NTIPAliasClassID["r17"]="626" +NTIPAliasClassID["lumrune"]="626" +NTIPAliasClassID["r18"]="627" +NTIPAliasClassID["korune"]="627" +NTIPAliasClassID["r19"]="628" +NTIPAliasClassID["falrune"]="628" +NTIPAliasClassID["r20"]="629" +NTIPAliasClassID["lemrune"]="629" +NTIPAliasClassID["r21"]="630" +NTIPAliasClassID["pulrune"]="630" +NTIPAliasClassID["r22"]="631" +NTIPAliasClassID["umrune"]="631" +NTIPAliasClassID["r23"]="632" +NTIPAliasClassID["malrune"]="632" +NTIPAliasClassID["r24"]="633" +NTIPAliasClassID["istrune"]="633" +NTIPAliasClassID["r25"]="634" +NTIPAliasClassID["gulrune"]="634" +NTIPAliasClassID["r26"]="635" +NTIPAliasClassID["vexrune"]="635" +NTIPAliasClassID["r27"]="636" +NTIPAliasClassID["ohmrune"]="636" +NTIPAliasClassID["r28"]="637" +NTIPAliasClassID["lorune"]="637" +NTIPAliasClassID["r29"]="638" +NTIPAliasClassID["surrune"]="638" +NTIPAliasClassID["r30"]="639" +NTIPAliasClassID["berrune"]="639" +NTIPAliasClassID["r31"]="640" +NTIPAliasClassID["jahrune"]="640" +NTIPAliasClassID["r32"]="641" +NTIPAliasClassID["chamrune"]="641" +NTIPAliasClassID["r33"]="642" +NTIPAliasClassID["zodrune"]="642" +NTIPAliasClassID["jew"]="643" +NTIPAliasClassID["jewel"]="643" +NTIPAliasClassID["ice"]="644" +NTIPAliasClassID["malahspotion"]="644" +NTIPAliasClassID["0sc"]="645" +NTIPAliasClassID["scrollofknowledge"]="645" +NTIPAliasClassID["tr2"]="646" +NTIPAliasClassID["scrollofresistance"]="646" +NTIPAliasClassID["pk1"]="647" +NTIPAliasClassID["keyofterror"]="647" +NTIPAliasClassID["pk2"]="648" +NTIPAliasClassID["keyofhate"]="648" +NTIPAliasClassID["pk3"]="649" +NTIPAliasClassID["keyofdestruction"]="649" +NTIPAliasClassID["dhn"]="650" +NTIPAliasClassID["diabloshorn"]="650" +NTIPAliasClassID["bey"]="651" +NTIPAliasClassID["baalseye"]="651" +NTIPAliasClassID["mbr"]="652" +NTIPAliasClassID["mephistosbrain"]="652" +NTIPAliasClassID["toa"]="653" +NTIPAliasClassID["tokenofabsolution"]="653" +NTIPAliasClassID["tes"]="654" +NTIPAliasClassID["twistedessenceofsuffering"]="654" +NTIPAliasClassID["ceh"]="655" +NTIPAliasClassID["chargedessenceofhatred"]="655" +NTIPAliasClassID["bet"]="656" +NTIPAliasClassID["burningessenceofterror"]="656" +NTIPAliasClassID["fed"]="657" +NTIPAliasClassID["festeringessenceofdestruction"]="657" +NTIPAliasClassID["std"]="658" +NTIPAliasClassID["standardofheroes"]="658" + diff --git a/src/bnip/NTIPAliasFlag.py b/src/bnip/NTIPAliasFlag.py new file mode 100644 index 000000000..87f34581e --- /dev/null +++ b/src/bnip/NTIPAliasFlag.py @@ -0,0 +1,6 @@ +NTIPAliasFlag = {} +NTIPAliasFlag["identified"]="0x10" +NTIPAliasFlag["eth"]="0x400000" +NTIPAliasFlag["ethereal"]="0x400000" +NTIPAliasFlag["runeword"]="0x4000000" + diff --git a/src/bnip/NTIPAliasQuality.py b/src/bnip/NTIPAliasQuality.py new file mode 100644 index 000000000..c8ac31604 --- /dev/null +++ b/src/bnip/NTIPAliasQuality.py @@ -0,0 +1,10 @@ +NTIPAliasQuality = {} +NTIPAliasQuality["lowquality"]="1" +NTIPAliasQuality["normal"]="2" +NTIPAliasQuality["superior"]="3" +NTIPAliasQuality["magic"]="4" +NTIPAliasQuality["set"]="5" +NTIPAliasQuality["rare"]="6" +NTIPAliasQuality["unique"]="7" +NTIPAliasQuality["crafted"]="8" + diff --git a/src/bnip/NTIPAliasStat.py b/src/bnip/NTIPAliasStat.py new file mode 100644 index 000000000..17b64addb --- /dev/null +++ b/src/bnip/NTIPAliasStat.py @@ -0,0 +1,1209 @@ +NTIPAliasStat = {} + +NTIPAliasStat['strength']='0' +NTIPAliasStat['energy']='1' +NTIPAliasStat['dexterity']='2' +NTIPAliasStat['vitality']='3' +NTIPAliasStat['statpts']='4' +NTIPAliasStat['newskills']='5' +NTIPAliasStat['hitpoints']='6' +NTIPAliasStat['maxhp']='7' +NTIPAliasStat['mana']='8' +NTIPAliasStat['maxmana']='9' +NTIPAliasStat['stamina']='10' +NTIPAliasStat['maxstamina']='11' +NTIPAliasStat['level']='12' +NTIPAliasStat['experience']='13' +NTIPAliasStat['gold']='14' +NTIPAliasStat['goldbank']='15' +NTIPAliasStat['itemarmorpercent']='16' +NTIPAliasStat['enhanceddefense']='16' +NTIPAliasStat['itemmaxdamagepercent']='17' +NTIPAliasStat['itemmindamagepercent']='18' +NTIPAliasStat['tohit']='19' +NTIPAliasStat['toblock']='20' +NTIPAliasStat['mindamage']='21' +NTIPAliasStat['maxdamage']='22' +NTIPAliasStat['secondarymindamage']='23' +NTIPAliasStat['secondarymaxdamage']='24' +NTIPAliasStat['damagepercent']='25' +NTIPAliasStat['manarecovery']='26' +NTIPAliasStat['manarecoverybonus']='27' +NTIPAliasStat['staminarecoverybonus']='28' +NTIPAliasStat['lastexp']='29' +NTIPAliasStat['nextexp']='30' +NTIPAliasStat['armorclass']='31' +NTIPAliasStat['defense']='31' +NTIPAliasStat['armorclassvsmissile']='32' +NTIPAliasStat['armorclassvshth']='33' +NTIPAliasStat['normaldamagereduction']='34' +NTIPAliasStat['magicdamagereduction']='35' +NTIPAliasStat['damageresist']='36' +NTIPAliasStat['magicresist']='37' +NTIPAliasStat['maxmagicresist']='38' +NTIPAliasStat['fireresist']='39' +NTIPAliasStat['maxfireresist']='40' +NTIPAliasStat['lightresist']='41' +NTIPAliasStat['maxlightresist']='42' +NTIPAliasStat['coldresist']='43' +NTIPAliasStat['maxcoldresist']='44' +NTIPAliasStat['poisonresist']='45' +NTIPAliasStat['maxpoisonresist']='46' +NTIPAliasStat['damageaura']='47' +NTIPAliasStat['firemindam']='48' +NTIPAliasStat['firemaxdam']='49' +NTIPAliasStat['lightmindam']='50' +NTIPAliasStat['lightmaxdam']='51' +NTIPAliasStat['magicmindam']='52' +NTIPAliasStat['magicmaxdam']='53' +NTIPAliasStat['coldmindam']='54' +NTIPAliasStat['coldmaxdam']='55' +NTIPAliasStat['coldlength']='56' +NTIPAliasStat['poisonmindam']='57' +NTIPAliasStat['poisonmaxdam']='58' +NTIPAliasStat['poisonlength']='59' +NTIPAliasStat['lifedrainmindam']='60' +NTIPAliasStat['lifeleech']='60' +NTIPAliasStat['lifedrainmaxdam']='61' +NTIPAliasStat['manadrainmindam']='62' +NTIPAliasStat['manaleech']='62' +NTIPAliasStat['manadrainmaxdam']='63' +NTIPAliasStat['stamdrainmindam']='64' +NTIPAliasStat['stamdrainmaxdam']='65' +NTIPAliasStat['stunlength']='66' +NTIPAliasStat['velocitypercent']='67' +NTIPAliasStat['attackrate']='68' +NTIPAliasStat['otheranimrate']='69' +NTIPAliasStat['quantity']='70' +NTIPAliasStat['value']='71' +NTIPAliasStat['durability']='72' +NTIPAliasStat['maxdurability']='73' +NTIPAliasStat['hpregen']='74' +NTIPAliasStat['itemmaxdurabilitypercent']='75' +NTIPAliasStat['itemmaxhppercent']='76' +NTIPAliasStat['itemmaxmanapercent']='77' +NTIPAliasStat['itemattackertakesdamage']='78' +NTIPAliasStat['itemgoldbonus']='79' +NTIPAliasStat['itemmagicbonus']='80' +NTIPAliasStat['itemknockback']='81' +NTIPAliasStat['itemtimeduration']='82' +NTIPAliasStat['itemaddclassskills']='83' +NTIPAliasStat['amazonskills']='83,0' +NTIPAliasStat['paladinskills']='83,3' +NTIPAliasStat['necromancerskills']='83,2' +NTIPAliasStat['sorceressskills']='83,1' +NTIPAliasStat['barbarianskills']='83,4' +NTIPAliasStat['druidskills']='83,5' +NTIPAliasStat['assassinskills']='83,6' +NTIPAliasStat['itemaddamazonskills']='83,0' +NTIPAliasStat['amaskills']='83,0' +NTIPAliasStat['itemaddamaskills']='83,0' +NTIPAliasStat['zonskills']='83,0' +NTIPAliasStat['itemaddzonskills']='83,0' +NTIPAliasStat['itemaddsorceressskills']='83,1' +NTIPAliasStat['sorskills']='83,1' +NTIPAliasStat['itemaddsorskills']='83,1' +NTIPAliasStat['sorcskills']='83,1' +NTIPAliasStat['itemaddsorcskills']='83,1' +NTIPAliasStat['itemaddnecromancerskills']='83,2' +NTIPAliasStat['necskills']='83,2' +NTIPAliasStat['itemaddnecskills']='83,2' +NTIPAliasStat['necroskills']='83,2' +NTIPAliasStat['itemaddnecroskills']='83,2' +NTIPAliasStat['itemaddpaladinskills']='83,3' +NTIPAliasStat['palskills']='83,3' +NTIPAliasStat['itemaddpalskills']='83,3' +NTIPAliasStat['paliskills']='83,3' +NTIPAliasStat['itemaddpaliskills']='83,3' +NTIPAliasStat['itemaddbarbarianskills']='83,4' +NTIPAliasStat['barskills']='83,4' +NTIPAliasStat['itemaddbarskills']='83,4' +NTIPAliasStat['barbskills']='83,4' +NTIPAliasStat['itemaddbarbskills']='83,4' +NTIPAliasStat['itemadddruidskills']='83,5' +NTIPAliasStat['druskills']='83,5' +NTIPAliasStat['itemadddruskills']='83,5' +NTIPAliasStat['itemaddassassinskills']='83,6' +NTIPAliasStat['assskills']='83,6' +NTIPAliasStat['itemaddassskills']='83,6' +NTIPAliasStat['sinskills']='83,6' +NTIPAliasStat['itemaddsinskills']='83,6' +NTIPAliasStat['unsentparam1']='84' +NTIPAliasStat['itemaddexperience']='85' +NTIPAliasStat['itemhealafterkill']='86' +NTIPAliasStat['itemreducedprices']='87' +NTIPAliasStat['itemdoubleherbduration']='88' +NTIPAliasStat['itemlightradius']='89' +NTIPAliasStat['itemlightcolor']='90' +NTIPAliasStat['itemreqpercent']='91' +NTIPAliasStat['itemlevelreq']='92' +NTIPAliasStat['itemfasterattackrate']='93' +NTIPAliasStat['ias']='93' +NTIPAliasStat['itemlevelreqpct']='94' +NTIPAliasStat['lastblockframe']='95' +NTIPAliasStat['itemfastermovevelocity']='96' +NTIPAliasStat['frw']='96' +NTIPAliasStat['plusskillmagicarrow']='97,6' +NTIPAliasStat['plusskillfirearrow']='97,7' +NTIPAliasStat['plusskillinnersight']='97,8' +NTIPAliasStat['plusskillcriticalstrike']='97,9' +NTIPAliasStat['plusskilljab']='97,10' +NTIPAliasStat['plusskillcoldarrow']='97,11' +NTIPAliasStat['plusskillmultipleshot']='97,12' +NTIPAliasStat['plusskilldodge']='97,13' +NTIPAliasStat['plusskillpowerstrike']='97,14' +NTIPAliasStat['plusskillpoisonjavelin']='97,15' +NTIPAliasStat['plusskillexplodingarrow']='97,16' +NTIPAliasStat['plusskillslowmissiles']='97,17' +NTIPAliasStat['plusskillavoid']='97,18' +NTIPAliasStat['plusskillimpale']='97,19' +NTIPAliasStat['plusskilllightningbolt']='97,20' +NTIPAliasStat['plusskillicearrow']='97,21' +NTIPAliasStat['plusskillguidedarrow']='97,22' +NTIPAliasStat['plusskillpenetrate']='97,23' +NTIPAliasStat['plusskillchargedstrike']='97,24' +NTIPAliasStat['plusskillplaguejavelin']='97,25' +NTIPAliasStat['plusskillstrafe']='97,26' +NTIPAliasStat['plusskillimmolationarrow']='97,27' +NTIPAliasStat['plusskilldecoy']='97,28' +NTIPAliasStat['plusskillevade']='97,29' +NTIPAliasStat['plusskillfend']='97,30' +NTIPAliasStat['plusskillfreezingarrow']='97,31' +NTIPAliasStat['plusskillvalkyrie']='97,32' +NTIPAliasStat['plusskillpierce']='97,33' +NTIPAliasStat['plusskilllightningstrike']='97,34' +NTIPAliasStat['plusskilllightningfury']='97,35' +NTIPAliasStat['plusskillfirebolt']='97,36' +NTIPAliasStat['plusskillwarmth']='97,37' +NTIPAliasStat['plusskillchargedbolt']='97,38' +NTIPAliasStat['plusskillicebolt']='97,39' +NTIPAliasStat['plusskillfrozenarmor']='97,40' +NTIPAliasStat['plusskillinferno']='97,41' +NTIPAliasStat['plusskillstaticfield']='97,42' +NTIPAliasStat['plusskilltelekinesis']='97,43' +NTIPAliasStat['plusskillfrostnova']='97,44' +NTIPAliasStat['plusskilliceblast']='97,45' +NTIPAliasStat['plusskillblaze']='97,46' +NTIPAliasStat['plusskillfireball']='97,47' +NTIPAliasStat['plusskillnova']='97,48' +NTIPAliasStat['plusskilllightning']='97,49' +NTIPAliasStat['plusskillshiverarmor']='97,50' +NTIPAliasStat['plusskillfirewall']='97,51' +NTIPAliasStat['plusskillenchant']='97,52' +NTIPAliasStat['plusskillchainlightning']='97,53' +NTIPAliasStat['plusskillteleport']='97,54' +NTIPAliasStat['plusskillglacialspike']='97,55' +NTIPAliasStat['plusskillmeteor']='97,56' +NTIPAliasStat['plusskillthunderstorm']='97,57' +NTIPAliasStat['plusskillenergyshield']='97,58' +NTIPAliasStat['plusskillblizzard']='97,59' +NTIPAliasStat['plusskillchillingarmor']='97,60' +NTIPAliasStat['plusskillfiremastery']='97,61' +NTIPAliasStat['plusskillhydra']='97,62' +NTIPAliasStat['plusskilllightningmastery']='97,63' +NTIPAliasStat['plusskillfrozenorb']='97,64' +NTIPAliasStat['plusskillcoldmastery']='97,65' +NTIPAliasStat['plusskillamplifydamage']='97,66' +NTIPAliasStat['plusskillteeth']='97,67' +NTIPAliasStat['plusskillbonearmor']='97,68' +NTIPAliasStat['plusskillskeletonmastery']='97,69' +NTIPAliasStat['plusskillraiseskeleton']='97,70' +NTIPAliasStat['plusskilldimvision']='97,71' +NTIPAliasStat['plusskillweaken']='97,72' +NTIPAliasStat['plusskillpoisondagger']='97,73' +NTIPAliasStat['plusskillcorpseexplosion']='97,74' +NTIPAliasStat['plusskillclaygolem']='97,75' +NTIPAliasStat['plusskillironmaiden']='97,76' +NTIPAliasStat['plusskillterror']='97,77' +NTIPAliasStat['plusskillbonewall']='97,78' +NTIPAliasStat['plusskillgolemmastery']='97,79' +NTIPAliasStat['plusskillraiseskeletalmage']='97,80' +NTIPAliasStat['plusskillconfuse']='97,81' +NTIPAliasStat['plusskilllifetap']='97,82' +NTIPAliasStat['plusskillpoisonexplosion']='97,83' +NTIPAliasStat['plusskillbonespear']='97,84' +NTIPAliasStat['plusskillbloodgolem']='97,85' +NTIPAliasStat['plusskillattract']='97,86' +NTIPAliasStat['plusskilldecrepify']='97,87' +NTIPAliasStat['plusskillboneprison']='97,88' +NTIPAliasStat['plusskillsummonresist']='97,89' +NTIPAliasStat['plusskillirongolem']='97,90' +NTIPAliasStat['plusskilllowerresist']='97,91' +NTIPAliasStat['plusskillpoisonnova']='97,92' +NTIPAliasStat['plusskillbonespirit']='97,93' +NTIPAliasStat['plusskillfiregolem']='97,94' +NTIPAliasStat['plusskillrevive']='97,95' +NTIPAliasStat['plusskillsacrifice']='97,96' +NTIPAliasStat['plusskillsmite']='97,97' +NTIPAliasStat['plusskillmight']='97,98' +NTIPAliasStat['plusskillprayer']='97,99' +NTIPAliasStat['plusskillresistfire']='97,100' +NTIPAliasStat['plusskillholybolt']='97,101' +NTIPAliasStat['plusskillholyfire']='97,102' +NTIPAliasStat['plusskillthorns']='97,103' +NTIPAliasStat['plusskilldefiance']='97,104' +NTIPAliasStat['plusskillresistcold']='97,105' +NTIPAliasStat['plusskillzeal']='97,106' +NTIPAliasStat['plusskillcharge']='97,107' +NTIPAliasStat['plusskillblessedaim']='97,108' +NTIPAliasStat['plusskillcleansing']='97,109' +NTIPAliasStat['plusskillresistlightning']='97,110' +NTIPAliasStat['plusskillvengeance']='97,111' +NTIPAliasStat['plusskillblessedhammer']='97,112' +NTIPAliasStat['plusskillconcentration']='97,113' +NTIPAliasStat['plusskillholyfreeze']='97,114' +NTIPAliasStat['plusskillvigor']='97,115' +NTIPAliasStat['plusskillconversion']='97,116' +NTIPAliasStat['plusskillholyshield']='97,117' +NTIPAliasStat['plusskillholyshock']='97,118' +NTIPAliasStat['plusskillsanctuary']='97,119' +NTIPAliasStat['plusskillmeditation']='97,120' +NTIPAliasStat['plusskillfistoftheheavens']='97,121' +NTIPAliasStat['plusskillfanaticism']='97,122' +NTIPAliasStat['plusskillconviction']='97,123' +NTIPAliasStat['plusskillredemption']='97,124' +NTIPAliasStat['plusskillsalvation']='97,125' +NTIPAliasStat['plusskillbash']='97,126' +NTIPAliasStat['plusskillblademastery']='97,127' +NTIPAliasStat['plusskillaxemastery']='97,128' +NTIPAliasStat['plusskillmacemastery']='97,129' +NTIPAliasStat['plusskillhowl']='97,130' +NTIPAliasStat['plusskillfindpotion']='97,131' +NTIPAliasStat['plusskillleap']='97,132' +NTIPAliasStat['plusskilldoubleswing']='97,133' +NTIPAliasStat['plusskillpolearmmastery']='97,134' +NTIPAliasStat['plusskillthrowingmastery']='97,135' +NTIPAliasStat['plusskillspearmastery']='97,136' +NTIPAliasStat['plusskilltaunt']='97,137' +NTIPAliasStat['plusskillshout']='97,138' +NTIPAliasStat['plusskillstun']='97,139' +NTIPAliasStat['plusskilldoublethrow']='97,140' +NTIPAliasStat['plusskillincreasedstamina']='97,141' +NTIPAliasStat['plusskillfinditem']='97,142' +NTIPAliasStat['plusskillleapattack']='97,143' +NTIPAliasStat['plusskillconcentrate']='97,144' +NTIPAliasStat['plusskillironskin']='97,145' +NTIPAliasStat['plusskillbattlecry']='97,146' +NTIPAliasStat['plusskillfrenzy']='97,147' +NTIPAliasStat['plusskillincreasedspeed']='97,148' +NTIPAliasStat['plusskillbattleorders']='97,149' +NTIPAliasStat['plusskillgrimward']='97,150' +NTIPAliasStat['plusskillwhirlwind']='97,151' +NTIPAliasStat['plusskillberserk']='97,152' +NTIPAliasStat['plusskillnaturalresistance']='97,153' +NTIPAliasStat['plusskillwarcry']='97,154' +NTIPAliasStat['plusskillbattlecommand']='97,155' +NTIPAliasStat['plusskillraven']='97,221' +NTIPAliasStat['plusskillpoisoncreeper']='97,222' +NTIPAliasStat['plusskillwerewolf']='97,223' +NTIPAliasStat['plusskilllycanthropy']='97,224' +NTIPAliasStat['plusskillfirestorm']='97,225' +NTIPAliasStat['plusskilloaksage']='97,226' +NTIPAliasStat['plusskillsummonspiritwolf']='97,227' +NTIPAliasStat['plusskillwerebear']='97,228' +NTIPAliasStat['plusskillmoltenboulder']='97,229' +NTIPAliasStat['plusskillarcticblast']='97,230' +NTIPAliasStat['plusskillcarrionvine']='97,231' +NTIPAliasStat['plusskillferalrage']='97,232' +NTIPAliasStat['plusskillmaul']='97,233' +NTIPAliasStat['plusskillfissure']='97,234' +NTIPAliasStat['plusskillcyclonearmor']='97,235' +NTIPAliasStat['plusskillheartofwolverine']='97,236' +NTIPAliasStat['plusskillsummondirewolf']='97,237' +NTIPAliasStat['plusskillrabies']='97,238' +NTIPAliasStat['plusskillfireclaws']='97,239' +NTIPAliasStat['plusskilltwister']='97,240' +NTIPAliasStat['plusskillsolarcreeper']='97,241' +NTIPAliasStat['plusskillhunger']='97,242' +NTIPAliasStat['plusskillshockwave']='97,243' +NTIPAliasStat['plusskillvolcano']='97,244' +NTIPAliasStat['plusskilltornado']='97,245' +NTIPAliasStat['plusskillspiritofbarbs']='97,246' +NTIPAliasStat['plusskillsummongrizzly']='97,247' +NTIPAliasStat['plusskillfury']='97,248' +NTIPAliasStat['plusskillarmageddon']='97,249' +NTIPAliasStat['plusskillhurricane']='97,250' +NTIPAliasStat['plusskillfireblast']='97,251' +NTIPAliasStat['plusskillclawmastery']='97,252' +NTIPAliasStat['plusskillpsychichammer']='97,253' +NTIPAliasStat['plusskilltigerstrike']='97,254' +NTIPAliasStat['plusskilldragontalon']='97,255' +NTIPAliasStat['plusskillshockweb']='97,256' +NTIPAliasStat['plusskillbladesentinel']='97,257' +NTIPAliasStat['plusskillburstofspeed']='97,258' +NTIPAliasStat['plusskillfistsoffire']='97,259' +NTIPAliasStat['plusskilldragonclaw']='97,260' +NTIPAliasStat['plusskillchargedboltsentry']='97,261' +NTIPAliasStat['plusskillwakeoffire']='97,262' +NTIPAliasStat['plusskillweaponblock']='97,263' +NTIPAliasStat['plusskillcloakofshadows']='97,264' +NTIPAliasStat['plusskillcobrastrike']='97,265' +NTIPAliasStat['plusskillbladefury']='97,266' +NTIPAliasStat['plusskillfade']='97,267' +NTIPAliasStat['plusskillshadowwarrior']='97,268' +NTIPAliasStat['plusskillclawsofthunder']='97,269' +NTIPAliasStat['plusskilldragontail']='97,270' +NTIPAliasStat['plusskilllightningsentry']='97,271' +NTIPAliasStat['plusskillwakeofinferno']='97,272' +NTIPAliasStat['plusskillmindblast']='97,273' +NTIPAliasStat['plusskillbladesofice']='97,274' +NTIPAliasStat['plusskilldragonflight']='97,275' +NTIPAliasStat['plusskilldeathsentry']='97,276' +NTIPAliasStat['plusskillbladeshield']='97,277' +NTIPAliasStat['plusskillvenom']='97,278' +NTIPAliasStat['plusskillshadowmaster']='97,279' +NTIPAliasStat['plusskillphoenixstrike']='97,280' +NTIPAliasStat['itemnonclassskill']='97' +NTIPAliasStat['state']='98' +NTIPAliasStat['itemfastergethitrate']='99' +NTIPAliasStat['fhr']='99' +NTIPAliasStat['monsterplayercount']='100' +NTIPAliasStat['itemfasterblockrate']='102' +NTIPAliasStat['fbr']='102' +NTIPAliasStat['itemfastercastrate']='105' +NTIPAliasStat['fcr']='105' +NTIPAliasStat['skillmagicarrow']='107,6' +NTIPAliasStat['skillfirearrow']='107,7' +NTIPAliasStat['skillinnersight']='107,8' +NTIPAliasStat['skillcriticalstrike']='107,9' +NTIPAliasStat['skilljab']='107,10' +NTIPAliasStat['skillcoldarrow']='107,11' +NTIPAliasStat['skillmultipleshot']='107,12' +NTIPAliasStat['skilldodge']='107,13' +NTIPAliasStat['skillpowerstrike']='107,14' +NTIPAliasStat['skillpoisonjavelin']='107,15' +NTIPAliasStat['skillexplodingarrow']='107,16' +NTIPAliasStat['skillslowmissiles']='107,17' +NTIPAliasStat['skillavoid']='107,18' +NTIPAliasStat['skillimpale']='107,19' +NTIPAliasStat['skilllightningbolt']='107,20' +NTIPAliasStat['skillicearrow']='107,21' +NTIPAliasStat['skillguidedarrow']='107,22' +NTIPAliasStat['skillpenetrate']='107,23' +NTIPAliasStat['skillchargedstrike']='107,24' +NTIPAliasStat['skillplaguejavelin']='107,25' +NTIPAliasStat['skillstrafe']='107,26' +NTIPAliasStat['skillimmolationarrow']='107,27' +NTIPAliasStat['skilldecoy']='107,28' +NTIPAliasStat['skillevade']='107,29' +NTIPAliasStat['skillfend']='107,30' +NTIPAliasStat['skillfreezingarrow']='107,31' +NTIPAliasStat['skillvalkyrie']='107,32' +NTIPAliasStat['skillpierce']='107,33' +NTIPAliasStat['skilllightningstrike']='107,34' +NTIPAliasStat['skilllightningfury']='107,35' +NTIPAliasStat['skillfirebolt']='107,36' +NTIPAliasStat['skillwarmth']='107,37' +NTIPAliasStat['skillchargedbolt']='107,38' +NTIPAliasStat['skillicebolt']='107,39' +NTIPAliasStat['skillfrozenarmor']='107,40' +NTIPAliasStat['skillinferno']='107,41' +NTIPAliasStat['skillstaticfield']='107,42' +NTIPAliasStat['skilltelekinesis']='107,43' +NTIPAliasStat['skillfrostnova']='107,44' +NTIPAliasStat['skilliceblast']='107,45' +NTIPAliasStat['skillblaze']='107,46' +NTIPAliasStat['skillfireball']='107,47' +NTIPAliasStat['skillnova']='107,48' +NTIPAliasStat['skilllightning']='107,49' +NTIPAliasStat['skillshiverarmor']='107,50' +NTIPAliasStat['skillfirewall']='107,51' +NTIPAliasStat['skillenchant']='107,52' +NTIPAliasStat['skillchainlightning']='107,53' +NTIPAliasStat['skillteleport']='107,54' +NTIPAliasStat['skillglacialspike']='107,55' +NTIPAliasStat['skillmeteor']='107,56' +NTIPAliasStat['skillthunderstorm']='107,57' +NTIPAliasStat['skillenergyshield']='107,58' +NTIPAliasStat['skillblizzard']='107,59' +NTIPAliasStat['skillchillingarmor']='107,60' +NTIPAliasStat['skillfiremastery']='107,61' +NTIPAliasStat['skillhydra']='107,62' +NTIPAliasStat['skilllightningmastery']='107,63' +NTIPAliasStat['skillfrozenorb']='107,64' +NTIPAliasStat['skillcoldmastery']='107,65' +NTIPAliasStat['skillamplifydamage']='107,66' +NTIPAliasStat['skillteeth']='107,67' +NTIPAliasStat['skillbonearmor']='107,68' +NTIPAliasStat['skillskeletonmastery']='107,69' +NTIPAliasStat['skillraiseskeleton']='107,70' +NTIPAliasStat['skilldimvision']='107,71' +NTIPAliasStat['skillweaken']='107,72' +NTIPAliasStat['skillpoisondagger']='107,73' +NTIPAliasStat['skillcorpseexplosion']='107,74' +NTIPAliasStat['skillclaygolem']='107,75' +NTIPAliasStat['skillironmaiden']='107,76' +NTIPAliasStat['skillterror']='107,77' +NTIPAliasStat['skillbonewall']='107,78' +NTIPAliasStat['skillgolemmastery']='107,79' +NTIPAliasStat['skillraiseskeletalmage']='107,80' +NTIPAliasStat['skillconfuse']='107,81' +NTIPAliasStat['skilllifetap']='107,82' +NTIPAliasStat['skillpoisonexplosion']='107,83' +NTIPAliasStat['skillbonespear']='107,84' +NTIPAliasStat['skillbloodgolem']='107,85' +NTIPAliasStat['skillattract']='107,86' +NTIPAliasStat['skilldecrepify']='107,87' +NTIPAliasStat['skillboneprison']='107,88' +NTIPAliasStat['skillsummonresist']='107,89' +NTIPAliasStat['skillirongolem']='107,90' +NTIPAliasStat['skilllowerresist']='107,91' +NTIPAliasStat['skillpoisonnova']='107,92' +NTIPAliasStat['skillbonespirit']='107,93' +NTIPAliasStat['skillfiregolem']='107,94' +NTIPAliasStat['skillrevive']='107,95' +NTIPAliasStat['skillsacrifice']='107,96' +NTIPAliasStat['skillsmite']='107,97' +NTIPAliasStat['skillmight']='107,98' +NTIPAliasStat['skillprayer']='107,99' +NTIPAliasStat['skillresistfire']='107,100' +NTIPAliasStat['skillholybolt']='107,101' +NTIPAliasStat['skillholyfire']='107,102' +NTIPAliasStat['skillthorns']='107,103' +NTIPAliasStat['skilldefiance']='107,104' +NTIPAliasStat['skillresistcold']='107,105' +NTIPAliasStat['skillzeal']='107,106' +NTIPAliasStat['skillcharge']='107,107' +NTIPAliasStat['skillblessedaim']='107,108' +NTIPAliasStat['skillcleansing']='107,109' +NTIPAliasStat['skillresistlightning']='107,110' +NTIPAliasStat['skillvengeance']='107,111' +NTIPAliasStat['skillblessedhammer']='107,112' +NTIPAliasStat['skillconcentration']='107,113' +NTIPAliasStat['skillholyfreeze']='107,114' +NTIPAliasStat['skillvigor']='107,115' +NTIPAliasStat['skillconversion']='107,116' +NTIPAliasStat['skillholyshield']='107,117' +NTIPAliasStat['skillholyshock']='107,118' +NTIPAliasStat['skillsanctuary']='107,119' +NTIPAliasStat['skillmeditation']='107,120' +NTIPAliasStat['skillfistoftheheavens']='107,121' +NTIPAliasStat['skillfanaticism']='107,122' +NTIPAliasStat['skillconviction']='107,123' +NTIPAliasStat['skillredemption']='107,124' +NTIPAliasStat['skillsalvation']='107,125' +NTIPAliasStat['skillbash']='107,126' +NTIPAliasStat['skillblademastery']='107,127' +NTIPAliasStat['skillaxemastery']='107,128' +NTIPAliasStat['skillmacemastery']='107,129' +NTIPAliasStat['skillhowl']='107,130' +NTIPAliasStat['skillfindpotion']='107,131' +NTIPAliasStat['skillleap']='107,132' +NTIPAliasStat['skilldoubleswing']='107,133' +NTIPAliasStat['skillpolearmmastery']='107,134' +NTIPAliasStat['skillthrowingmastery']='107,135' +NTIPAliasStat['skillspearmastery']='107,136' +NTIPAliasStat['skilltaunt']='107,137' +NTIPAliasStat['skillshout']='107,138' +NTIPAliasStat['skillstun']='107,139' +NTIPAliasStat['skilldoublethrow']='107,140' +NTIPAliasStat['skillincreasedstamina']='107,141' +NTIPAliasStat['skillfinditem']='107,142' +NTIPAliasStat['skillleapattack']='107,143' +NTIPAliasStat['skillconcentrate']='107,144' +NTIPAliasStat['skillironskin']='107,145' +NTIPAliasStat['skillbattlecry']='107,146' +NTIPAliasStat['skillfrenzy']='107,147' +NTIPAliasStat['skillincreasedspeed']='107,148' +NTIPAliasStat['skillbattleorders']='107,149' +NTIPAliasStat['skillgrimward']='107,150' +NTIPAliasStat['skillwhirlwind']='107,151' +NTIPAliasStat['skillberserk']='107,152' +NTIPAliasStat['skillnaturalresistance']='107,153' +NTIPAliasStat['skillwarcry']='107,154' +NTIPAliasStat['skillbattlecommand']='107,155' +NTIPAliasStat['skillraven']='107,221' +NTIPAliasStat['skillpoisoncreeper']='107,222' +NTIPAliasStat['skillwerewolf']='107,223' +NTIPAliasStat['skilllycanthropy']='107,224' +NTIPAliasStat['skillfirestorm']='107,225' +NTIPAliasStat['skilloaksage']='107,226' +NTIPAliasStat['skillsummonspiritwolf']='107,227' +NTIPAliasStat['skillwerebear']='107,228' +NTIPAliasStat['skillmoltenboulder']='107,229' +NTIPAliasStat['skillarcticblast']='107,230' +NTIPAliasStat['skillcarrionvine']='107,231' +NTIPAliasStat['skillferalrage']='107,232' +NTIPAliasStat['skillmaul']='107,233' +NTIPAliasStat['skillfissure']='107,234' +NTIPAliasStat['skillcyclonearmor']='107,235' +NTIPAliasStat['skillheartofwolverine']='107,236' +NTIPAliasStat['skillsummondirewolf']='107,237' +NTIPAliasStat['skillrabies']='107,238' +NTIPAliasStat['skillfireclaws']='107,239' +NTIPAliasStat['skilltwister']='107,240' +NTIPAliasStat['skillsolarcreeper']='107,241' +NTIPAliasStat['skillhunger']='107,242' +NTIPAliasStat['skillshockwave']='107,243' +NTIPAliasStat['skillvolcano']='107,244' +NTIPAliasStat['skilltornado']='107,245' +NTIPAliasStat['skillspiritofbarbs']='107,246' +NTIPAliasStat['skillsummongrizzly']='107,247' +NTIPAliasStat['skillfury']='107,248' +NTIPAliasStat['skillarmageddon']='107,249' +NTIPAliasStat['skillhurricane']='107,250' +NTIPAliasStat['skillfireblast']='107,251' +NTIPAliasStat['skillclawmastery']='107,252' +NTIPAliasStat['skillpsychichammer']='107,253' +NTIPAliasStat['skilltigerstrike']='107,254' +NTIPAliasStat['skilldragontalon']='107,255' +NTIPAliasStat['skillshockweb']='107,256' +NTIPAliasStat['skillbladesentinel']='107,257' +NTIPAliasStat['skillburstofspeed']='107,258' +NTIPAliasStat['skillfistsoffire']='107,259' +NTIPAliasStat['skilldragonclaw']='107,260' +NTIPAliasStat['skillchargedboltsentry']='107,261' +NTIPAliasStat['skillwakeoffire']='107,262' +NTIPAliasStat['skillweaponblock']='107,263' +NTIPAliasStat['skillcloakofshadows']='107,264' +NTIPAliasStat['skillcobrastrike']='107,265' +NTIPAliasStat['skillbladefury']='107,266' +NTIPAliasStat['skillfade']='107,267' +NTIPAliasStat['skillshadowwarrior']='107,268' +NTIPAliasStat['skillclawsofthunder']='107,269' +NTIPAliasStat['skilldragontail']='107,270' +NTIPAliasStat['skilllightningsentry']='107,271' +NTIPAliasStat['skillwakeofinferno']='107,272' +NTIPAliasStat['skillmindblast']='107,273' +NTIPAliasStat['skillbladesofice']='107,274' +NTIPAliasStat['skilldragonflight']='107,275' +NTIPAliasStat['skilldeathsentry']='107,276' +NTIPAliasStat['skillbladeshield']='107,277' +NTIPAliasStat['skillvenom']='107,278' +NTIPAliasStat['skillshadowmaster']='107,279' +NTIPAliasStat['skillphoenixstrike']='107,280' +NTIPAliasStat['itemsingleskill']='107' +NTIPAliasStat['itemrestinpeace']='108' +NTIPAliasStat['curseresistance']='109' +NTIPAliasStat['itempoisonlengthresist']='110' +NTIPAliasStat['itemnormaldamage']='111' +NTIPAliasStat['itemhowl']='112' +NTIPAliasStat['itemstupidity']='113' +NTIPAliasStat['itemdamagetomana']='114' +NTIPAliasStat['itemignoretargetac']='115' +NTIPAliasStat['itemfractionaltargetac']='116' +NTIPAliasStat['itempreventheal']='117' +NTIPAliasStat['itemhalffreezeduration']='118' +NTIPAliasStat['itemtohitpercent']='119' +NTIPAliasStat['itemdamagetargetac']='120' +NTIPAliasStat['itemdemondamagepercent']='121' +NTIPAliasStat['itemundeaddamagepercent']='122' +NTIPAliasStat['itemdemontohit']='123' +NTIPAliasStat['itemundeadtohit']='124' +NTIPAliasStat['itemthrowable']='125' +NTIPAliasStat['itemelemskill']='126' +NTIPAliasStat['itemallskills']='127' +NTIPAliasStat['itemattackertakeslightdamage']='128' +NTIPAliasStat['ironmaidenlevel']='129' +NTIPAliasStat['lifetaplevel']='130' +NTIPAliasStat['thornspercent']='131' +NTIPAliasStat['bonearmor']='132' +NTIPAliasStat['bonearmormax']='133' +NTIPAliasStat['itemfreeze']='134' +NTIPAliasStat['itemopenwounds']='135' +NTIPAliasStat['itemcrushingblow']='136' +NTIPAliasStat['itemkickdamage']='137' +NTIPAliasStat['itemmanaafterkill']='138' +NTIPAliasStat['itemhealafterdemonkill']='139' +NTIPAliasStat['itemextrablood']='140' +NTIPAliasStat['itemdeadlystrike']='141' +NTIPAliasStat['itemabsorbfirepercent']='142' +NTIPAliasStat['itemabsorbfire']='143' +NTIPAliasStat['itemabsorblightpercent']='144' +NTIPAliasStat['itemabsorblight']='145' +NTIPAliasStat['itemabsorbmagicpercent']='146' +NTIPAliasStat['itemabsorbmagic']='147' +NTIPAliasStat['itemabsorbcoldpercent']='148' +NTIPAliasStat['itemabsorbcold']='149' +NTIPAliasStat['itemslow']='150' +NTIPAliasStat['mightaura']='151,98' +NTIPAliasStat['thornsaura']='151,103' +NTIPAliasStat['defianceaura']='151,104' +NTIPAliasStat['concentrationaura']='151,113' +NTIPAliasStat['vigoraura']='151,115' +NTIPAliasStat['sanctuaryaura']='151,119' +NTIPAliasStat['meditationaura']='151,120' +NTIPAliasStat['fanaticismaura']='151,122' +NTIPAliasStat['convictionaura']='151,123' +NTIPAliasStat['redemptionaura']='151,124' +NTIPAliasStat['itemaura']='151' +NTIPAliasStat['itemindesctructible']='152' +NTIPAliasStat['itemcannotbefrozen']='153' +NTIPAliasStat['itemstaminadrainpct']='154' +NTIPAliasStat['itemreanimate']='155' +NTIPAliasStat['itempierce']='156' +NTIPAliasStat['itemmagicarrow']='157' +NTIPAliasStat['itemexplosivearrow']='158' +NTIPAliasStat['itemthrowmindamage']='159' +NTIPAliasStat['itemthrowmaxdamage']='160' +NTIPAliasStat['alignment']='172' +NTIPAliasStat['target0']='173' +NTIPAliasStat['target1']='174' +NTIPAliasStat['goldlost']='175' +NTIPAliasStat['conversionlevel']='176' +NTIPAliasStat['conversionmaxhp']='177' +NTIPAliasStat['unitdooverlay']='178' +NTIPAliasStat['attackvsmontype']='179' +NTIPAliasStat['damagevsmontype']='180' +NTIPAliasStat['fade']='181' +NTIPAliasStat['armoroverridepercent']='182' +NTIPAliasStat['unused183']='183' +NTIPAliasStat['unused184']='184' +NTIPAliasStat['bonusmindamage']='185' +NTIPAliasStat['bonusmaxdamage']='186' +NTIPAliasStat['unused187']='187' +NTIPAliasStat['itemaddbowandcrossbowskilltab']='188,0' +NTIPAliasStat['bowandcrossbowskilltab']='188,0' +NTIPAliasStat['itemaddamazonbowandcrossbowskilltab']='188,0' +NTIPAliasStat['amazonbowandcrossbowskilltab']='188,0' +NTIPAliasStat['itemaddamabowandcrossbowskilltab']='188,0' +NTIPAliasStat['amabowandcrossbowskilltab']='188,0' +NTIPAliasStat['itemaddzonbowandcrossbowskilltab']='188,0' +NTIPAliasStat['zonbowandcrossbowskilltab']='188,0' +NTIPAliasStat['itemaddpassiveandmagicskilltab']='188,1' +NTIPAliasStat['passiveandmagicskilltab']='188,1' +NTIPAliasStat['itemaddamazonpassiveandmagicskilltab']='188,1' +NTIPAliasStat['amazonpassiveandmagicskilltab']='188,1' +NTIPAliasStat['itemaddamapassiveandmagicskilltab']='188,1' +NTIPAliasStat['amapassiveandmagicskilltab']='188,1' +NTIPAliasStat['itemaddzonpassiveandmagicskilltab']='188,1' +NTIPAliasStat['zonpassiveandmagicskilltab']='188,1' +NTIPAliasStat['itemaddjavelinandspearskilltab']='188,2' +NTIPAliasStat['javelinandspearskilltab']='188,2' +NTIPAliasStat['itemaddamazonjavelinandspearskilltab']='188,2' +NTIPAliasStat['amazonjavelinandspearskilltab']='188,2' +NTIPAliasStat['itemaddamajavelinandspearskilltab']='188,2' +NTIPAliasStat['amajavelinandspearskilltab']='188,2' +NTIPAliasStat['itemaddzonjavelinandspearskilltab']='188,2' +NTIPAliasStat['zonjavelinandspearskilltab']='188,2' +NTIPAliasStat['itemaddfireskilltab']='188,3' +NTIPAliasStat['fireskilltab']='188,3' +NTIPAliasStat['itemaddsorceressfireskilltab']='188,3' +NTIPAliasStat['sorceressfireskilltab']='188,3' +NTIPAliasStat['itemaddsorfireskilltab']='188,3' +NTIPAliasStat['sorfireskilltab']='188,3' +NTIPAliasStat['itemaddsorcfireskilltab']='188,3' +NTIPAliasStat['sorcfireskilltab']='188,3' +NTIPAliasStat['itemaddlightningskilltab']='188,4' +NTIPAliasStat['lightningskilltab']='188,4' +NTIPAliasStat['itemaddsorceresslightningskilltab']='188,4' +NTIPAliasStat['sorceresslightningskilltab']='188,4' +NTIPAliasStat['itemaddsorlightningskilltab']='188,4' +NTIPAliasStat['sorlightningskilltab']='188,4' +NTIPAliasStat['itemaddsorclightningskilltab']='188,4' +NTIPAliasStat['sorclightningskilltab']='188,4' +NTIPAliasStat['itemaddcoldskilltab']='188,5' +NTIPAliasStat['coldskilltab']='188,5' +NTIPAliasStat['itemaddsorceresscoldskilltab']='188,5' +NTIPAliasStat['sorceresscoldskilltab']='188,5' +NTIPAliasStat['itemaddsorcoldskilltab']='188,5' +NTIPAliasStat['sorcoldskilltab']='188,5' +NTIPAliasStat['itemaddsorccoldskilltab']='188,5' +NTIPAliasStat['sorccoldskilltab']='188,5' +NTIPAliasStat['itemaddcursesskilltab']='188,6' +NTIPAliasStat['cursesskilltab']='188,6' +NTIPAliasStat['itemaddnecromancercursesskilltab']='188,6' +NTIPAliasStat['necromancercursesskilltab']='188,6' +NTIPAliasStat['itemaddneccursesskilltab']='188,6' +NTIPAliasStat['neccursesskilltab']='188,6' +NTIPAliasStat['itemaddnecrocursesskilltab']='188,6' +NTIPAliasStat['necrocursesskilltab']='188,6' +NTIPAliasStat['itemaddpoisonandboneskilltab']='188,7' +NTIPAliasStat['poisonandboneskilltab']='188,7' +NTIPAliasStat['itemaddnecromancerpoisonandboneskilltab']='188,7' +NTIPAliasStat['necromancerpoisonandboneskilltab']='188,7' +NTIPAliasStat['itemaddnecpoisonandboneskilltab']='188,7' +NTIPAliasStat['necpoisonandboneskilltab']='188,7' +NTIPAliasStat['itemaddnecropoisonandboneskilltab']='188,7' +NTIPAliasStat['necropoisonandboneskilltab']='188,7' +NTIPAliasStat['itemaddcombatskilltab']='188,12' +NTIPAliasStat['combatskilltab']='188,12' +NTIPAliasStat['itemaddnecromancercombatskilltab']='188,8' +NTIPAliasStat['necromancercombatskilltab']='188,8' +NTIPAliasStat['itemaddneccombatskilltab']='188,8' +NTIPAliasStat['neccombatskilltab']='188,8' +NTIPAliasStat['itemaddnecrocombatskilltab']='188,8' +NTIPAliasStat['necrocombatskilltab']='188,8' +NTIPAliasStat['itemaddpaladincombatskilltab']='188,9' +NTIPAliasStat['paladincombatskilltab']='188,9' +NTIPAliasStat['itemaddpalcombatskilltab']='188,9' +NTIPAliasStat['palcombatskilltab']='188,9' +NTIPAliasStat['itemaddpalicombatskilltab']='188,9' +NTIPAliasStat['palicombatskilltab']='188,9' +NTIPAliasStat['itemaddoffensiveaurasskilltab']='188,10' +NTIPAliasStat['offensiveaurasskilltab']='188,10' +NTIPAliasStat['itemaddpaladinoffensiveaurasskilltab']='188,10' +NTIPAliasStat['paladinoffensiveaurasskilltab']='188,10' +NTIPAliasStat['itemaddpaloffensiveaurasskilltab']='188,10' +NTIPAliasStat['paloffensiveaurasskilltab']='188,10' +NTIPAliasStat['itemaddpalioffensiveaurasskilltab']='188,10' +NTIPAliasStat['palioffensiveaurasskilltab']='188,10' +NTIPAliasStat['itemadddefensiveaurasskilltab']='188,11' +NTIPAliasStat['defensiveaurasskilltab']='188,11' +NTIPAliasStat['itemaddpaladindefensiveaurasskilltab']='188,11' +NTIPAliasStat['paladindefensiveaurasskilltab']='188,11' +NTIPAliasStat['itemaddpaldefensiveaurasskilltab']='188,11' +NTIPAliasStat['paldefensiveaurasskilltab']='188,11' +NTIPAliasStat['itemaddpalidefensiveaurasskilltab']='188,11' +NTIPAliasStat['palidefensiveaurasskilltab']='188,11' +NTIPAliasStat['itemaddbarbariancombatskilltab']='188,12' +NTIPAliasStat['barbariancombatskilltab']='188,12' +NTIPAliasStat['itemaddbarcombatskilltab']='188,12' +NTIPAliasStat['barcombatskilltab']='188,12' +NTIPAliasStat['itemaddbarbcombatskilltab']='188,12' +NTIPAliasStat['barbcombatskilltab']='188,12' +NTIPAliasStat['itemaddmasteriesskilltab']='188,13' +NTIPAliasStat['masteriesskilltab']='188,13' +NTIPAliasStat['itemaddbarbarianmasteriesskilltab']='188,13' +NTIPAliasStat['barbarianmasteriesskilltab']='188,13' +NTIPAliasStat['itemaddbarmasteriesskilltab']='188,13' +NTIPAliasStat['barmasteriesskilltab']='188,13' +NTIPAliasStat['itemaddbarbmasteriesskilltab']='188,13' +NTIPAliasStat['barbmasteriesskilltab']='188,13' +NTIPAliasStat['itemaddwarcriesskilltab']='188,14' +NTIPAliasStat['warcriesskilltab']='188,14' +NTIPAliasStat['itemaddbarbarianwarcriesskilltab']='188,14' +NTIPAliasStat['barbarianwarcriesskilltab']='188,14' +NTIPAliasStat['itemaddbarwarcriesskilltab']='188,14' +NTIPAliasStat['barwarcriesskilltab']='188,14' +NTIPAliasStat['itemaddbarbwarcriesskilltab']='188,14' +NTIPAliasStat['barbwarcriesskilltab']='188,14' +NTIPAliasStat['itemaddsummoningskilltab']='188,15' +NTIPAliasStat['summoningskilltab']='188,15' +NTIPAliasStat['itemadddruidsummoningskilltab']='188,15' +NTIPAliasStat['druidsummoningskilltab']='188,15' +NTIPAliasStat['itemadddrusummoningskilltab']='188,15' +NTIPAliasStat['drusummoningskilltab']='188,15' +NTIPAliasStat['itemaddshapeshiftingskilltab']='188,16' +NTIPAliasStat['shapeshiftingskilltab']='188,16' +NTIPAliasStat['itemadddruidshapeshiftingskilltab']='188,16' +NTIPAliasStat['druidshapeshiftingskilltab']='188,16' +NTIPAliasStat['itemadddrushapeshiftingskilltab']='188,16' +NTIPAliasStat['drushapeshiftingskilltab']='188,16' +NTIPAliasStat['itemaddelementalskilltab']='188,17' +NTIPAliasStat['elementalskilltab']='188,17' +NTIPAliasStat['itemadddruidelementalskilltab']='188,17' +NTIPAliasStat['druidelementalskilltab']='188,17' +NTIPAliasStat['itemadddruelementalskilltab']='188,17' +NTIPAliasStat['druelementalskilltab']='188,17' +NTIPAliasStat['itemaddtrapsskilltab']='188,18' +NTIPAliasStat['trapsskilltab']='188,18' +NTIPAliasStat['itemaddassassintrapsskilltab']='188,18' +NTIPAliasStat['assassintrapsskilltab']='188,18' +NTIPAliasStat['itemaddasstrapsskilltab']='188,18' +NTIPAliasStat['asstrapsskilltab']='188,18' +NTIPAliasStat['itemaddsintrapsskilltab']='188,18' +NTIPAliasStat['sintrapsskilltab']='188,18' +NTIPAliasStat['itemaddshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['shadowdisciplinesskilltab']='188,19' +NTIPAliasStat['itemaddassassinshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['assassinshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['itemaddassshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['assshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['itemaddsinshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['sinshadowdisciplinesskilltab']='188,19' +NTIPAliasStat['itemaddmartialartsskilltab']='188,20' +NTIPAliasStat['martialartsskilltab']='188,20' +NTIPAliasStat['itemaddassassinmartialartsskilltab']='188,20' +NTIPAliasStat['assassinmartialartsskilltab']='188,20' +NTIPAliasStat['itemaddassmartialartsskilltab']='188,20' +NTIPAliasStat['assmartialartsskilltab']='188,20' +NTIPAliasStat['itemaddsinmartialartsskilltab']='188,20' +NTIPAliasStat['sinmartialartsskilltab']='188,20' +NTIPAliasStat['itemaddskilltab']='188' +NTIPAliasStat['unused189']='189' +NTIPAliasStat['unused190']='190' +NTIPAliasStat['unused191']='191' +NTIPAliasStat['unused192']='192' +NTIPAliasStat['unused193']='193' +NTIPAliasStat['itemnumsockets']='194' +NTIPAliasStat['sockets']='194' +NTIPAliasStat['itemskillonattack']='195' +NTIPAliasStat['itemskillonkill']='196' +NTIPAliasStat['itemskillondeath']='197' +NTIPAliasStat['itemskillonhit']='198' +NTIPAliasStat['itemskillonlevelup']='199' +NTIPAliasStat['unused200']='200' +NTIPAliasStat['itemskillongethit']='201' +NTIPAliasStat['unused202']='202' +NTIPAliasStat['unused203']='203' +NTIPAliasStat['skillmagicarrowcharges']='204,6' +NTIPAliasStat['skillfirearrowcharges']='204,7' +NTIPAliasStat['skillinnersightcharges']='204,8' +NTIPAliasStat['skillcriticalstrikecharges']='204,9' +NTIPAliasStat['skilljabcharges']='204,10' +NTIPAliasStat['skillcoldarrowcharges']='204,11' +NTIPAliasStat['skillmultipleshotcharges']='204,12' +NTIPAliasStat['skilldodgecharges']='204,13' +NTIPAliasStat['skillpowerstrikecharges']='204,14' +NTIPAliasStat['skillpoisonjavelincharges']='204,15' +NTIPAliasStat['skillexplodingarrowcharges']='204,16' +NTIPAliasStat['skillslowmissilescharges']='204,17' +NTIPAliasStat['skillavoidcharges']='204,18' +NTIPAliasStat['skillimpalecharges']='204,19' +NTIPAliasStat['skilllightningboltcharges']='204,20' +NTIPAliasStat['skillicearrowcharges']='204,21' +NTIPAliasStat['skillguidedarrowcharges']='204,22' +NTIPAliasStat['skillpenetratecharges']='204,23' +NTIPAliasStat['skillchargedstrikecharges']='204,24' +NTIPAliasStat['skillplaguejavelincharges']='204,25' +NTIPAliasStat['skillstrafecharges']='204,26' +NTIPAliasStat['skillimmolationarrowcharges']='204,27' +NTIPAliasStat['skilldecoycharges']='204,28' +NTIPAliasStat['skillevadecharges']='204,29' +NTIPAliasStat['skillfendcharges']='204,30' +NTIPAliasStat['skillfreezingarrowcharges']='204,31' +NTIPAliasStat['skillvalkyriecharges']='204,32' +NTIPAliasStat['skillpiercecharges']='204,33' +NTIPAliasStat['skilllightningstrikecharges']='204,34' +NTIPAliasStat['skilllightningfurycharges']='204,35' +NTIPAliasStat['skillfireboltcharges']='204,36' +NTIPAliasStat['skillwarmthcharges']='204,37' +NTIPAliasStat['skillchargedboltcharges']='204,38' +NTIPAliasStat['skilliceboltcharges']='204,39' +NTIPAliasStat['skillfrozenarmorcharges']='204,40' +NTIPAliasStat['skillinfernocharges']='204,41' +NTIPAliasStat['skillstaticfieldcharges']='204,42' +NTIPAliasStat['skilltelekinesischarges']='204,43' +NTIPAliasStat['skillfrostnovacharges']='204,44' +NTIPAliasStat['skilliceblastcharges']='204,45' +NTIPAliasStat['skillblazecharges']='204,46' +NTIPAliasStat['skillfireballcharges']='204,47' +NTIPAliasStat['skillnovacharges']='204,48' +NTIPAliasStat['skilllightningcharges']='204,49' +NTIPAliasStat['skillshiverarmorcharges']='204,50' +NTIPAliasStat['skillfirewallcharges']='204,51' +NTIPAliasStat['skillenchantcharges']='204,52' +NTIPAliasStat['skillchainlightningcharges']='204,53' +NTIPAliasStat['skillteleportcharges']='204,54' +NTIPAliasStat['skillglacialspikecharges']='204,55' +NTIPAliasStat['skillmeteorcharges']='204,56' +NTIPAliasStat['skillthunderstormcharges']='204,57' +NTIPAliasStat['skillenergyshieldcharges']='204,58' +NTIPAliasStat['skillblizzardcharges']='204,59' +NTIPAliasStat['skillchillingarmorcharges']='204,60' +NTIPAliasStat['skillfiremasterycharges']='204,61' +NTIPAliasStat['skillhydracharges']='204,62' +NTIPAliasStat['skilllightningmasterycharges']='204,63' +NTIPAliasStat['skillfrozenorbcharges']='204,64' +NTIPAliasStat['skillcoldmasterycharges']='204,65' +NTIPAliasStat['skillamplifydamagecharges']='204,66' +NTIPAliasStat['skillteethcharges']='204,67' +NTIPAliasStat['skillbonearmorcharges']='204,68' +NTIPAliasStat['skillskeletonmasterycharges']='204,69' +NTIPAliasStat['skillraiseskeletoncharges']='204,70' +NTIPAliasStat['skilldimvisioncharges']='204,71' +NTIPAliasStat['skillweakencharges']='204,72' +NTIPAliasStat['skillpoisondaggercharges']='204,73' +NTIPAliasStat['skillcorpseexplosioncharges']='204,74' +NTIPAliasStat['skillclaygolemcharges']='204,75' +NTIPAliasStat['skillironmaidencharges']='204,76' +NTIPAliasStat['skillterrorcharges']='204,77' +NTIPAliasStat['skillbonewallcharges']='204,78' +NTIPAliasStat['skillgolemmasterycharges']='204,79' +NTIPAliasStat['skillraiseskeletalmagecharges']='204,80' +NTIPAliasStat['skillconfusecharges']='204,81' +NTIPAliasStat['skilllifetapcharges']='204,82' +NTIPAliasStat['skillpoisonexplosioncharges']='204,83' +NTIPAliasStat['skillbonespearcharges']='204,84' +NTIPAliasStat['skillbloodgolemcharges']='204,85' +NTIPAliasStat['skillattractcharges']='204,86' +NTIPAliasStat['skilldecrepifycharges']='204,87' +NTIPAliasStat['skillboneprisoncharges']='204,88' +NTIPAliasStat['skillsummonresistcharges']='204,89' +NTIPAliasStat['skillirongolemcharges']='204,90' +NTIPAliasStat['skilllowerresistcharges']='204,91' +NTIPAliasStat['skillpoisonnovacharges']='204,92' +NTIPAliasStat['skillbonespiritcharges']='204,93' +NTIPAliasStat['skillfiregolemcharges']='204,94' +NTIPAliasStat['skillrevivecharges']='204,95' +NTIPAliasStat['skillsacrificecharges']='204,96' +NTIPAliasStat['skillsmitecharges']='204,97' +NTIPAliasStat['skillmightcharges']='204,98' +NTIPAliasStat['skillprayercharges']='204,99' +NTIPAliasStat['skillresistfirecharges']='204,100' +NTIPAliasStat['skillholyboltcharges']='204,101' +NTIPAliasStat['skillholyfirecharges']='204,102' +NTIPAliasStat['skillthornscharges']='204,103' +NTIPAliasStat['skilldefiancecharges']='204,104' +NTIPAliasStat['skillresistcoldcharges']='204,105' +NTIPAliasStat['skillzealcharges']='204,106' +NTIPAliasStat['skillchargecharges']='204,107' +NTIPAliasStat['skillblessedaimcharges']='204,108' +NTIPAliasStat['skillcleansingcharges']='204,109' +NTIPAliasStat['skillresistlightningcharges']='204,110' +NTIPAliasStat['skillvengeancecharges']='204,111' +NTIPAliasStat['skillblessedhammercharges']='204,112' +NTIPAliasStat['skillconcentrationcharges']='204,113' +NTIPAliasStat['skillholyfreezecharges']='204,114' +NTIPAliasStat['skillvigorcharges']='204,115' +NTIPAliasStat['skillconversioncharges']='204,116' +NTIPAliasStat['skillholyshieldcharges']='204,117' +NTIPAliasStat['skillholyshockcharges']='204,118' +NTIPAliasStat['skillsanctuarycharges']='204,119' +NTIPAliasStat['skillmeditationcharges']='204,120' +NTIPAliasStat['skillfistoftheheavenscharges']='204,121' +NTIPAliasStat['skillfanaticismcharges']='204,122' +NTIPAliasStat['skillconvictioncharges']='204,123' +NTIPAliasStat['skillredemptioncharges']='204,124' +NTIPAliasStat['skillsalvationcharges']='204,125' +NTIPAliasStat['skillbashcharges']='204,126' +NTIPAliasStat['skillblademasterycharges']='204,127' +NTIPAliasStat['skillaxemasterycharges']='204,128' +NTIPAliasStat['skillmacemasterycharges']='204,129' +NTIPAliasStat['skillhowlcharges']='204,130' +NTIPAliasStat['skillfindpotioncharges']='204,131' +NTIPAliasStat['skillleapcharges']='204,132' +NTIPAliasStat['skilldoubleswingcharges']='204,133' +NTIPAliasStat['skillpolearmmasterycharges']='204,134' +NTIPAliasStat['skillthrowingmasterycharges']='204,135' +NTIPAliasStat['skillspearmasterycharges']='204,136' +NTIPAliasStat['skilltauntcharges']='204,137' +NTIPAliasStat['skillshoutcharges']='204,138' +NTIPAliasStat['skillstuncharges']='204,139' +NTIPAliasStat['skilldoublethrowcharges']='204,140' +NTIPAliasStat['skillincreasedstaminacharges']='204,141' +NTIPAliasStat['skillfinditemcharges']='204,142' +NTIPAliasStat['skillleapattackcharges']='204,143' +NTIPAliasStat['skillconcentratecharges']='204,144' +NTIPAliasStat['skillironskincharges']='204,145' +NTIPAliasStat['skillbattlecrycharges']='204,146' +NTIPAliasStat['skillfrenzycharges']='204,147' +NTIPAliasStat['skillincreasedspeedcharges']='204,148' +NTIPAliasStat['skillbattleorderscharges']='204,149' +NTIPAliasStat['skillgrimwardcharges']='204,150' +NTIPAliasStat['skillwhirlwindcharges']='204,151' +NTIPAliasStat['skillberserkcharges']='204,152' +NTIPAliasStat['skillnaturalresistancecharges']='204,153' +NTIPAliasStat['skillwarcrycharges']='204,154' +NTIPAliasStat['skillbattlecommandcharges']='204,155' +NTIPAliasStat['skillravencharges']='204,221' +NTIPAliasStat['skillpoisoncreepercharges']='204,222' +NTIPAliasStat['skillwerewolfcharges']='204,223' +NTIPAliasStat['skilllycanthropycharges']='204,224' +NTIPAliasStat['skillfirestormcharges']='204,225' +NTIPAliasStat['skilloaksagecharges']='204,226' +NTIPAliasStat['skillsummonspiritwolfcharges']='204,227' +NTIPAliasStat['skillwerebearcharges']='204,228' +NTIPAliasStat['skillmoltenbouldercharges']='204,229' +NTIPAliasStat['skillarcticblastcharges']='204,230' +NTIPAliasStat['skillcarrionvinecharges']='204,231' +NTIPAliasStat['skillferalragecharges']='204,232' +NTIPAliasStat['skillmaulcharges']='204,233' +NTIPAliasStat['skillfissurecharges']='204,234' +NTIPAliasStat['skillcyclonearmorcharges']='204,235' +NTIPAliasStat['skillheartofwolverinecharges']='204,236' +NTIPAliasStat['skillsummondirewolfcharges']='204,237' +NTIPAliasStat['skillrabiescharges']='204,238' +NTIPAliasStat['skillfireclawscharges']='204,239' +NTIPAliasStat['skilltwistercharges']='204,240' +NTIPAliasStat['skillsolarcreepercharges']='204,241' +NTIPAliasStat['skillhungercharges']='204,242' +NTIPAliasStat['skillshockwavecharges']='204,243' +NTIPAliasStat['skillvolcanocharges']='204,244' +NTIPAliasStat['skilltornadocharges']='204,245' +NTIPAliasStat['skillspiritofbarbscharges']='204,246' +NTIPAliasStat['skillsummongrizzlycharges']='204,247' +NTIPAliasStat['skillfurycharges']='204,248' +NTIPAliasStat['skillarmageddoncharges']='204,249' +NTIPAliasStat['skillhurricanecharges']='204,250' +NTIPAliasStat['skillfireblastcharges']='204,251' +NTIPAliasStat['skillclawmasterycharges']='204,252' +NTIPAliasStat['skillpsychichammercharges']='204,253' +NTIPAliasStat['skilltigerstrikecharges']='204,254' +NTIPAliasStat['skilldragontaloncharges']='204,255' +NTIPAliasStat['skillshockwebcharges']='204,256' +NTIPAliasStat['skillbladesentinelcharges']='204,257' +NTIPAliasStat['skillburstofspeedcharges']='204,258' +NTIPAliasStat['skillfistsoffirecharges']='204,259' +NTIPAliasStat['skilldragonclawcharges']='204,260' +NTIPAliasStat['skillchargedboltsentrycharges']='204,261' +NTIPAliasStat['skillwakeoffirecharges']='204,262' +NTIPAliasStat['skillweaponblockcharges']='204,263' +NTIPAliasStat['skillcloakofshadowscharges']='204,264' +NTIPAliasStat['skillcobrastrikecharges']='204,265' +NTIPAliasStat['skillbladefurycharges']='204,266' +NTIPAliasStat['skillfadecharges']='204,267' +NTIPAliasStat['skillshadowwarriorcharges']='204,268' +NTIPAliasStat['skillclawsofthundercharges']='204,269' +NTIPAliasStat['skilldragontailcharges']='204,270' +NTIPAliasStat['skilllightningsentrycharges']='204,271' +NTIPAliasStat['skillwakeofinfernocharges']='204,272' +NTIPAliasStat['skillmindblastcharges']='204,273' +NTIPAliasStat['skillbladesoficecharges']='204,274' +NTIPAliasStat['skilldragonflightcharges']='204,275' +NTIPAliasStat['skilldeathsentrycharges']='204,276' +NTIPAliasStat['skillbladeshieldcharges']='204,277' +NTIPAliasStat['skillvenomcharges']='204,278' +NTIPAliasStat['skillshadowmastercharges']='204,279' +NTIPAliasStat['skillphoenixstrikecharges']='204,280' +NTIPAliasStat['itemchargedskill']='204' +NTIPAliasStat['itemnoconsume']='205' +NTIPAliasStat['passivemasterynoconsume']='206' +NTIPAliasStat['passivemasteryreplenishoncrit']='206' +NTIPAliasStat['unused208']='208' +NTIPAliasStat['unused209']='209' +NTIPAliasStat['unused210']='210' +NTIPAliasStat['unused211']='211' +NTIPAliasStat['passivemasterygethitrate']='213' +NTIPAliasStat['passivemasteryattackspeed']='213' +NTIPAliasStat['itemarmorperlevel']='214' +NTIPAliasStat['itemarmorpercentperlevel']='215' +NTIPAliasStat['itemhpperlevel']='216' +NTIPAliasStat['itemmanaperlevel']='217' +NTIPAliasStat['itemmaxdamageperlevel']='218' +NTIPAliasStat['itemmaxdamagepercentperlevel']='219' +NTIPAliasStat['itemstrengthperlevel']='220' +NTIPAliasStat['itemdexterityperlevel']='221' +NTIPAliasStat['itemenergyperlevel']='222' +NTIPAliasStat['itemvitalityperlevel']='223' +NTIPAliasStat['itemtohitperlevel']='224' +NTIPAliasStat['itemtohitpercentperlevel']='225' +NTIPAliasStat['itemcolddamagemaxperlevel']='226' +NTIPAliasStat['itemfiredamagemaxperlevel']='227' +NTIPAliasStat['itemltngdamagemaxperlevel']='228' +NTIPAliasStat['itempoisdamagemaxperlevel']='229' +NTIPAliasStat['itemresistcoldperlevel']='230' +NTIPAliasStat['itemresistfireperlevel']='231' +NTIPAliasStat['itemresistltngperlevel']='232' +NTIPAliasStat['itemresistpoisperlevel']='233' +NTIPAliasStat['itemabsorbcoldperlevel']='234' +NTIPAliasStat['itemabsorbfireperlevel']='235' +NTIPAliasStat['itemabsorbltngperlevel']='236' +NTIPAliasStat['itemabsorbpoisperlevel']='237' +NTIPAliasStat['itemthornsperlevel']='238' +NTIPAliasStat['itemfindgoldperlevel']='239' +NTIPAliasStat['itemfindmagicperlevel']='240' +NTIPAliasStat['itemregenstaminaperlevel']='241' +NTIPAliasStat['itemstaminaperlevel']='242' +NTIPAliasStat['itemdamagedemonperlevel']='243' +NTIPAliasStat['itemdamageundeadperlevel']='244' +NTIPAliasStat['itemtohitdemonperlevel']='245' +NTIPAliasStat['itemtohitundeadperlevel']='246' +NTIPAliasStat['itemcrushingblowperlevel']='247' +NTIPAliasStat['itemopenwoundsperlevel']='248' +NTIPAliasStat['itemkickdamageperlevel']='249' +NTIPAliasStat['itemdeadlystrikeperlevel']='250' +NTIPAliasStat['itemfindgemsperlevel']='251' +NTIPAliasStat['itemreplenishdurability']='252' +NTIPAliasStat['itemreplenishquantity']='253' +NTIPAliasStat['itemextrastack']='254' +NTIPAliasStat['itemfinditem']='255' +NTIPAliasStat['itemslashdamage']='256' +NTIPAliasStat['itemslashdamagepercent']='257' +NTIPAliasStat['itemcrushdamage']='258' +NTIPAliasStat['itemcrushdamagepercent']='259' +NTIPAliasStat['itemthrustdamage']='260' +NTIPAliasStat['itemthrustdamagepercent']='261' +NTIPAliasStat['itemabsorbslash']='262' +NTIPAliasStat['itemabsorbcrush']='263' +NTIPAliasStat['itemabsorbthrust']='264' +NTIPAliasStat['itemabsorbslashpercent']='265' +NTIPAliasStat['itemabsorbcrushpercent']='266' +NTIPAliasStat['itemabsorbthrustpercent']='267' +NTIPAliasStat['itemarmorbytime']='268' +NTIPAliasStat['itemarmorpercentbytime']='269' +NTIPAliasStat['itemhpbytime']='270' +NTIPAliasStat['itemmanabytime']='271' +NTIPAliasStat['itemmaxdamagebytime']='272' +NTIPAliasStat['itemmaxdamagepercentbytime']='273' +NTIPAliasStat['itemstrengthbytime']='274' +NTIPAliasStat['itemdexteritybytime']='275' +NTIPAliasStat['itemenergybytime']='276' +NTIPAliasStat['itemvitalitybytime']='277' +NTIPAliasStat['itemtohitbytime']='278' +NTIPAliasStat['itemtohitpercentbytime']='279' +NTIPAliasStat['itemcolddamagemaxbytime']='280' +NTIPAliasStat['itemfiredamagemaxbytime']='281' +NTIPAliasStat['itemltngdamagemaxbytime']='282' +NTIPAliasStat['itempoisdamagemaxbytime']='283' +NTIPAliasStat['itemresistcoldbytime']='284' +NTIPAliasStat['itemresistfirebytime']='285' +NTIPAliasStat['itemresistltngbytime']='286' +NTIPAliasStat['itemresistpoisbytime']='287' +NTIPAliasStat['itemabsorbcoldbytime']='288' +NTIPAliasStat['itemabsorbfirebytime']='289' +NTIPAliasStat['itemabsorbltngbytime']='290' +NTIPAliasStat['itemabsorbpoisbytime']='291' +NTIPAliasStat['itemfindgoldbytime']='292' +NTIPAliasStat['itemfindmagicbytime']='293' +NTIPAliasStat['itemregenstaminabytime']='294' +NTIPAliasStat['itemstaminabytime']='295' +NTIPAliasStat['itemdamagedemonbytime']='296' +NTIPAliasStat['itemdamageundeadbytime']='297' +NTIPAliasStat['itemtohitdemonbytime']='298' +NTIPAliasStat['itemtohitundeadbytime']='299' +NTIPAliasStat['itemcrushingblowbytime']='300' +NTIPAliasStat['itemopenwoundsbytime']='301' +NTIPAliasStat['itemkickdamagebytime']='302' +NTIPAliasStat['itemdeadlystrikebytime']='303' +NTIPAliasStat['itemfindgemsbytime']='304' +NTIPAliasStat['itempiercecold']='305' +NTIPAliasStat['itempiercefire']='306' +NTIPAliasStat['itempierceltng']='307' +NTIPAliasStat['itempiercepois']='308' +NTIPAliasStat['itemdamagevsmonster']='309' +NTIPAliasStat['itemdamagepercentvsmonster']='310' +NTIPAliasStat['itemtohitvsmonster']='311' +NTIPAliasStat['itemtohitpercentvsmonster']='312' +NTIPAliasStat['itemacvsmonster']='313' +NTIPAliasStat['itemacpercentvsmonster']='314' +NTIPAliasStat['firelength']='315' +NTIPAliasStat['burningmin']='316' +NTIPAliasStat['burningmax']='317' +NTIPAliasStat['progressivedamage']='318' +NTIPAliasStat['progressivesteal']='319' +NTIPAliasStat['progressiveother']='320' +NTIPAliasStat['progressivefire']='321' +NTIPAliasStat['progressivecold']='322' +NTIPAliasStat['progressivelightning']='323' +NTIPAliasStat['itemextracharges']='324' +NTIPAliasStat['progressivetohit']='325' +NTIPAliasStat['poisoncount']='326' +NTIPAliasStat['damageframerate']='327' +NTIPAliasStat['pierceidx']='328' +NTIPAliasStat['passivefiremastery']='329' +NTIPAliasStat['passiveltngmastery']='330' +NTIPAliasStat['passivecoldmastery']='331' +NTIPAliasStat['passivepoismastery']='332' +NTIPAliasStat['passivefirepierce']='333' +NTIPAliasStat['passiveltngpierce']='334' +NTIPAliasStat['passivecoldpierce']='335' +NTIPAliasStat['passivepoispierce']='336' +NTIPAliasStat['passivecriticalstrike']='337' +NTIPAliasStat['passivedodge']='338' +NTIPAliasStat['passiveavoid']='339' +NTIPAliasStat['passiveevade']='340' +NTIPAliasStat['passivewarmth']='341' +NTIPAliasStat['passivemasterymeleeth']='342' +NTIPAliasStat['passivemasterymeleedmg']='343' +NTIPAliasStat['passivemasterymeleecrit']='344' +NTIPAliasStat['passivemasterythrowth']='345' +NTIPAliasStat['passivemasterythrowdmg']='346' +NTIPAliasStat['passivemasterythrowcrit']='347' +NTIPAliasStat['passiveweaponblock']='348' +NTIPAliasStat['passivesummonresist']='349' +NTIPAliasStat['modifierlistskill']='350' +NTIPAliasStat['modifierlistlevel']='351' +NTIPAliasStat['lastsenthppct']='352' +NTIPAliasStat['sourceunittype']='353' +NTIPAliasStat['sourceunitid']='354' +NTIPAliasStat['shortparam1']='355' +NTIPAliasStat['questitemdifficulty']='356' +NTIPAliasStat['passivemagmastery']='357' +NTIPAliasStat['passivemagpierce']='358' +NTIPAliasStat['allstats']='420' +NTIPAliasStat['allres']='6969' + +# The below stats were added manually +NTIPAliasStat['plusdefense']='5006' +NTIPAliasStat['weapmin']='5000' +NTIPAliasStat['weapmax']='5001' +NTIPAliasStat['itemaddnecromancersummoningskilltab']='188,21' +NTIPAliasStat['necromancersummoningskilltab']='188,21' +NTIPAliasStat['quantitymax']='5003' +NTIPAliasStat['enhanceddamage']='5007' +NTIPAliasStat['plusmindamage']='21' +NTIPAliasStat['plusmaxdamage']='22' +NTIPAliasStat['allresist']='6969' +NTIPAliasStat['resistall']='6969' diff --git a/src/bnip/NTIPAliasType.py b/src/bnip/NTIPAliasType.py new file mode 100644 index 000000000..3cb4f8737 --- /dev/null +++ b/src/bnip/NTIPAliasType.py @@ -0,0 +1,107 @@ +NTIPAliasType = {} +NTIPAliasType['any']='0' +NTIPAliasType['none']='1' +NTIPAliasType['shield']='2' +NTIPAliasType['armor']='3' +NTIPAliasType['gold']='4' +NTIPAliasType['bowquiver']='5' +NTIPAliasType['crossbowquiver']='6' +NTIPAliasType['playerbodypart']='7' +NTIPAliasType['herb']='8' +NTIPAliasType['potion']='9' +NTIPAliasType['ring']='10' +NTIPAliasType['elixir']='11' +NTIPAliasType['amulet']='12' +NTIPAliasType['charm']='13' +NTIPAliasType['notused']='14' +NTIPAliasType['boots']='15' +NTIPAliasType['gloves']='16' +NTIPAliasType['notused']='17' +NTIPAliasType['book']='18' +NTIPAliasType['belt']='19' +NTIPAliasType['gem']='20' +NTIPAliasType['torch']='21' +NTIPAliasType['scroll']='22' +NTIPAliasType['notused']='23' +NTIPAliasType['scepter']='24' +NTIPAliasType['wand']='25' +NTIPAliasType['staff']='26' +NTIPAliasType['bow']='27' +NTIPAliasType['axe']='28' +NTIPAliasType['club']='29' +NTIPAliasType['sword']='30' +NTIPAliasType['hammer']='31' +NTIPAliasType['knife']='32' +NTIPAliasType['spear']='33' +NTIPAliasType['polearm']='34' +NTIPAliasType['crossbow']='35' +NTIPAliasType['mace']='36' +NTIPAliasType['helm']='37' +NTIPAliasType['missilepotion']='38' +NTIPAliasType['quest']='39' +NTIPAliasType['bodypart']='40' +NTIPAliasType['key']='41' +NTIPAliasType['throwingknife']='42' +NTIPAliasType['throwingaxe']='43' +NTIPAliasType['javelin']='44' +NTIPAliasType['weapon']='45' +NTIPAliasType['meleeweapon']='46' +NTIPAliasType['missileweapon']='47' +NTIPAliasType['thrownweapon']='48' +NTIPAliasType['comboweapon']='49' +NTIPAliasType['anyarmor']='50' +NTIPAliasType['anyshield']='51' +NTIPAliasType['miscellaneous']='52' +NTIPAliasType['socketfiller']='53' +NTIPAliasType['secondhand']='54' +NTIPAliasType['stavesandrods']='55' +NTIPAliasType['missile']='56' +NTIPAliasType['blunt']='57' +NTIPAliasType['expansion']='58' +NTIPAliasType['jewel']='59' +NTIPAliasType['classspecific']='60' +NTIPAliasType['amazonitem']='61' +NTIPAliasType['barbarianitem']='62' +NTIPAliasType['necromanceritem']='63' +NTIPAliasType['paladinitem']='64' +NTIPAliasType['sorceressitem']='65' +NTIPAliasType['assassinitem']='66' +NTIPAliasType['druiditem']='67' +NTIPAliasType['handtohand']='68' +NTIPAliasType['orb']='69' +NTIPAliasType['voodooheads']='70' +NTIPAliasType['auricshields']='71' +NTIPAliasType['primalhelm']='72' +NTIPAliasType['pelt']='73' +NTIPAliasType['cloak']='74' +NTIPAliasType['rune']='75' +NTIPAliasType['circlet']='76' +NTIPAliasType['healingpotion']='77' +NTIPAliasType['manapotion']='78' +NTIPAliasType['rejuvpotion']='79' +NTIPAliasType['staminapotion']='80' +NTIPAliasType['antidotepotion']='81' +NTIPAliasType['thawingpotion']='82' +NTIPAliasType['smallcharm']='83' +NTIPAliasType['mediumcharm']='84' +NTIPAliasType['largecharm']='85' +NTIPAliasType['amazonbow']='86' +NTIPAliasType['amazonspear']='87' +NTIPAliasType['amazonjavelin']='88' +NTIPAliasType['assassinclaw']='89' +NTIPAliasType['magicbowquiv']='90' +NTIPAliasType['magicxbowquiv']='91' +NTIPAliasType['chippedgem']='92' +NTIPAliasType['flawedgem']='93' +NTIPAliasType['standardgem']='94' +NTIPAliasType['flawlessgem']='95' +NTIPAliasType['perfectgem']='96' +NTIPAliasType['amethyst']='97' +NTIPAliasType['diamond']='98' +NTIPAliasType['emerald']='99' +NTIPAliasType['ruby']='100' +NTIPAliasType['sapphire']='101' +NTIPAliasType['topaz']='102' +NTIPAliasType['skull']='103' +NTIPAliasType['swordsandknives']='104' +NTIPAliasType['spearsandpolearms']='105' diff --git a/src/bnip/NipSyntaxErrors.py b/src/bnip/NipSyntaxErrors.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/bnip/UniqueAndSetData.py b/src/bnip/UniqueAndSetData.py new file mode 100644 index 000000000..573d80b03 --- /dev/null +++ b/src/bnip/UniqueAndSetData.py @@ -0,0 +1,3118 @@ +UniqueAndSetData = { + "aegis": { + "uniques": [ + [ + "MEDUSASGAZE" + ] + ] + }, + "ancientarmor": { + "uniques": [ + [ + "SILKSOFTHEVICTOR" + ] + ], + "sets": [ + [ + "MILABREGASROBE" + ] + ] + }, + "ancientshield": { + "uniques": [ + [ + "RADAMENTSSPHERE" + ] + ] + }, + "armet": { + "uniques": [ + [ + "STEELSHADE", + "DARKFEAR" + ] + ] + }, + "avengerguard": { + "sets": [ + [ + "IMMORTALKINGSWILL" + ] + ] + }, + "balrogskin": { + "uniques": [ + [ + "ARKAINESVALOR" + ] + ], + "sets": [ + [ + "SAZABISGHOSTLIBERATOR" + ] + ] + }, + "barbedshield": { + "uniques": [ + [ + "LANCEGUARD" + ] + ] + }, + "basinet": { + "uniques": [ + [ + "DARKSIGHTHELM" + ] + ], + "sets": [ + [ + "SAZABISMENTALSHEATH" + ] + ] + }, + "battlebelt": { + "uniques": [ + [ + "SNOWCLASH" + ] + ], + "sets": [ + [ + "WILHELMSPRIDE" + ] + ] + }, + "battleboots": { + "uniques": [ + [ + "WARTRAVELER" + ] + ], + "sets": [ + [ + "ALDURSADVANCE" + ] + ] + }, + "battlegauntlets": { + "uniques": [ + [ + "LAVAGOUT" + ] + ], + "sets": [ + [ + "MAVINASICYCLUTCH" + ] + ] + }, + "belt": { + "uniques": [ + [ + "NIGHTSMOKE" + ] + ], + "sets": [ + [ + "HSARUSIRONSTAY", + "HWANINSBLESSING" + ] + ] + }, + "bladebarrier": { + "uniques": [ + [ + "SPIKETHORN" + ] + ] + }, + "bloodspirit": { + "uniques": [ + [ + "CEREBUSBITE" + ] + ] + }, + "bloodlordskull": { + "uniques": [ + [ + "DARKFORCESPAWN" + ] + ] + }, + "bonehelm": { + "uniques": [ + [ + "WORMSKULL" + ] + ], + "sets": [ + [ + "TANCREDSSKULL" + ] + ] + }, + "boneshield": { + "uniques": [ + [ + "WALLOFTHEEYELESS" + ] + ] + }, + "bonevisage": { + "uniques": [ + [ + "GIANTSKULL" + ] + ], + "sets": [ + [ + "TRANGOULSGUISE" + ] + ] + }, + "boneweaveboots": { + "uniques": [ + [ + "MARROWWALK" + ] + ] + }, + "boots": { + "uniques": [ + [ + "HOTSPUR" + ] + ], + "sets": [ + [ + "TANCREDSHOBNAILS" + ] + ] + }, + "bramblemitts": { + "sets": [ + [ + "LAYINGOFHANDS" + ] + ] + }, + "breastplate": { + "uniques": [ + [ + "VENOMWARD" + ] + ], + "sets": [ + [ + "ISENHARTSCASE" + ] + ] + }, + "buckler": { + "uniques": [ + [ + "PELTALUNATA" + ] + ], + "sets": [ + [ + "HSARUSIRONFIST" + ] + ] + }, + "cantortrophy": { + "sets": [ + [ + "TRANGOULSWING" + ] + ] + }, + "cap": { + "uniques": [ + [ + "BIGGINSBONNET" + ] + ], + "sets": [ + [ + "INFERNALCRANIUM", + "SANDERSPARAGON" + ] + ] + }, + "casque": { + "uniques": [ + [ + "STEALSKULL" + ] + ] + }, + "chainboots": { + "uniques": [ + [ + "TREADSOFCTHON" + ] + ], + "sets": [ + [ + "HSARUSIRONHEEL" + ] + ] + }, + "chaingloves": { + "uniques": [ + [ + "CHANCEGUARDS" + ] + ], + "sets": [ + [ + "CLEGLAWSPINCERS" + ] + ] + }, + "chainmail": { + "uniques": [ + [ + "SPARKINGMAIL" + ] + ], + "sets": [ + [ + "CATHANSMESH" + ] + ] + }, + "chaosarmor": { + "uniques": [ + [ + "BLACKHADES" + ] + ], + "sets": [ + [ + "TRANGOULSSCALES" + ] + ] + }, + "circlet": { + "sets": [ + [ + "NAJSCIRCLET" + ] + ] + }, + "conquerorcrown": { + "uniques": [ + [ + "HALABERDSREIGN" + ] + ] + }, + "corona": { + "uniques": [ + [ + "CROWNOFAGES" + ] + ], + "sets": [ + [ + "GRISWOLDSVALOR" + ] + ] + }, + "crown": { + "uniques": [ + [ + "UNDEADCROWN" + ] + ], + "sets": [ + [ + "IRATHASCOIL", + "MILABREGASDIADEM" + ] + ] + }, + "cuirass": { + "uniques": [ + [ + "DURIELSSHELL" + ] + ], + "sets": [ + [ + "HAEMOSUSADAMANT" + ] + ] + }, + "deathmask": { + "uniques": [ + [ + "BLACKHORNSFACE" + ] + ], + "sets": [ + [ + "TALRASHASHORADRICCREST" + ] + ] + }, + "defender": { + "uniques": [ + [ + "VISCERATUANT" + ] + ] + }, + "demonhead": { + "uniques": [ + [ + "ANDARIELSVISAGE" + ] + ] + }, + "demonhidearmor": { + "uniques": [ + [ + "SKINOFTHEFLAYEDONE" + ] + ] + }, + "demonhideboots": { + "uniques": [ + [ + "INFERNOSTRIDE" + ] + ], + "sets": [ + [ + "RITEOFPASSAGE" + ] + ] + }, + "demonhidegloves": { + "uniques": [ + [ + "VENOMGRIP" + ] + ] + }, + "demonhidesash": { + "uniques": [ + [ + "STRINGOFEARS" + ] + ] + }, + "destroyerhelm": { + "uniques": [ + [ + "DEMONHORNSEDGE" + ] + ] + }, + "diadem": { + "uniques": [ + [ + "GRIFFONSEYE" + ] + ], + "sets": [ + [ + "MAVINASTRUESIGHT" + ] + ] + }, + "dragonshield": { + "uniques": [ + [ + "TIAMATSREBUKE" + ] + ] + }, + "duskshroud": { + "uniques": [ + [ + "ORMUSROBES" + ] + ], + "sets": [ + [ + "DARKADHERENT" + ] + ] + }, + "earthspirit": { + "uniques": [ + [ + "SPIRITKEEPER" + ] + ] + }, + "embossedplate": { + "uniques": [ + [ + "ATMASWAIL" + ] + ] + }, + "fieldplate": { + "uniques": [ + [ + "ROCKFLEECE" + ] + ] + }, + "fullhelm": { + "uniques": [ + [ + "DUSKDEEP" + ] + ], + "sets": [ + [ + "ISENHARTSHORNS" + ] + ] + }, + "fullplatemail": { + "uniques": [ + [ + "GOLDSKIN" + ] + ], + "sets": [ + [ + "TANCREDSSPINE" + ] + ] + }, + "furyvisor": { + "uniques": [ + [ + "WOLFHOWL" + ] + ] + }, + "gauntlets": { + "uniques": [ + [ + "FROSTBURN" + ] + ], + "sets": [ + [ + "SIGONSGAGE" + ] + ] + }, + "ghostarmor": { + "uniques": [ + [ + "THESPIRITSHROUD" + ] + ] + }, + "gildedshield": { + "uniques": [ + [ + "HERALDOFZAKARUM" + ] + ] + }, + "gothicplate": { + "uniques": [ + [ + "RATTLECAGE" + ] + ], + "sets": [ + [ + "SIGONSSHELTER" + ] + ] + }, + "gothicshield": { + "uniques": [ + [ + "THEWARD" + ] + ], + "sets": [ + [ + "ISENHARTSPARRY" + ] + ] + }, + "grandcrown": { + "uniques": [ + [ + "CROWNOFTHIEVES" + ] + ], + "sets": [ + [ + "HWANINSSPLENDOR" + ] + ] + }, + "greathelm": { + "uniques": [ + [ + "HOWLTUSK" + ] + ], + "sets": [ + [ + "SIGONSVISOR" + ] + ] + }, + "greaves": { + "uniques": [ + [ + "TEARHAUNCH" + ] + ], + "sets": [ + [ + "SIGONSSABOT" + ] + ] + }, + "grimhelm": { + "uniques": [ + [ + "VAMPIREGAZE" + ] + ], + "sets": [ + [ + "NATALYASTOTEM" + ] + ] + }, + "grimshield": { + "uniques": [ + [ + "LIDLESSWALL" + ] + ] + }, + "hardleatherarmor": { + "uniques": [ + [ + "THECENTURION" + ] + ] + }, + "heavybelt": { + "uniques": [ + [ + "GOLDWRAP" + ] + ], + "sets": [ + [ + "INFERNALSIGN", + "IRATHASCORD" + ] + ] + }, + "heavyboots": { + "uniques": [ + [ + "GOREFOOT" + ] + ], + "sets": [ + [ + "COWKINGSHOOVES", + "SANDERSRIPRAP" + ] + ] + }, + "heavybracers": { + "uniques": [ + [ + "GHOULHIDE" + ] + ], + "sets": [ + [ + "TRANGOULSCLAWS" + ] + ] + }, + "heavygloves": { + "uniques": [ + [ + "BLOODFIST" + ] + ], + "sets": [ + [ + "SANDERSTABOO" + ] + ] + }, + "hellforgeplate": { + "sets": [ + [ + "NAJSLIGHTPLATE" + ] + ] + }, + "helm": { + "uniques": [ + [ + "COIFOFGLORY" + ] + ], + "sets": [ + [ + "BERSERKERSHEADGEAR" + ] + ] + }, + "hierophanttrophy": { + "uniques": [ + [ + "HOMUNCULUS" + ] + ] + }, + "huntersguise": { + "sets": [ + [ + "ALDURSSTONYGAZE" + ] + ] + }, + "kiteshield": { + "uniques": [ + [ + "STEELCLASH" + ] + ], + "sets": [ + [ + "MILABREGASORB" + ] + ] + }, + "krakenshell": { + "uniques": [ + [ + "LEVIATHAN" + ] + ], + "sets": [ + [ + "MAVINASEMBRACE" + ] + ] + }, + "lacqueredplate": { + "sets": [ + [ + "TALRASHASGUARDIANSHIP" + ] + ] + }, + "largeshield": { + "uniques": [ + [ + "STORMGUILD" + ] + ], + "sets": [ + [ + "CIVERBSWARD" + ] + ] + }, + "leatherarmor": { + "uniques": [ + [ + "BLINKBATSFORM" + ] + ], + "sets": [ + [ + "VIDALASAMBUSH" + ] + ] + }, + "leathergloves": { + "uniques": [ + [ + "THEHANDOFBROC" + ] + ], + "sets": [ + [ + "DEATHSHAND" + ] + ] + }, + "lightbelt": { + "uniques": [ + [ + "SNAKECORD" + ] + ], + "sets": [ + [ + "ARCTICBINDING" + ] + ] + }, + "lightgauntlets": { + "uniques": [ + [ + "MAGEFIST" + ] + ], + "sets": [ + [ + "ARCTICMITTS", + "IRATHASCUFF" + ] + ] + }, + "lightplate": { + "uniques": [ + [ + "HEAVENLYGARB" + ] + ], + "sets": [ + [ + "ARCANNASFLESH" + ] + ] + }, + "lightplatedboots": { + "uniques": [ + [ + "GOBLINTOE" + ] + ], + "sets": [ + [ + "VIDALASFETLOCK" + ] + ] + }, + "linkedmail": { + "uniques": [ + [ + "SPIRITFORGE" + ] + ] + }, + "loricatedmail": { + "sets": [ + [ + "NATALYASSHADOW" + ] + ] + }, + "luna": { + "uniques": [ + [ + "BLACKOAKSHIELD" + ] + ] + }, + "mageplate": { + "uniques": [ + [ + "QUEHEGANSWISDOM" + ] + ] + }, + "mask": { + "uniques": [ + [ + "THEFACEOFHORROR" + ] + ], + "sets": [ + [ + "CATHANSVISAGE" + ] + ] + }, + "mesharmor": { + "uniques": [ + [ + "SHAFTSTOP" + ] + ] + }, + "meshbelt": { + "uniques": [ + [ + "GLOOMSTRAP" + ] + ], + "sets": [ + [ + "TALRASHASFINESPUNCLOTH" + ] + ] + }, + "meshboots": { + "uniques": [ + [ + "SILKWEAVE" + ] + ], + "sets": [ + [ + "NATALYASSOUL" + ] + ] + }, + "mithrilcoil": { + "uniques": [ + [ + "VERDUNGOSHEARTYCORD" + ] + ], + "sets": [ + [ + "CREDENDUM" + ] + ] + }, + "monarch": { + "uniques": [ + [ + "STORMSHIELD" + ] + ] + }, + "myrmidongreaves": { + "uniques": [ + [ + "SHADOWDANCER" + ] + ] + }, + "ogregauntlets": { + "uniques": [ + [ + "STEELREND" + ] + ] + }, + "ornateplate": { + "uniques": [ + [ + "CORPSEMOURN" + ] + ], + "sets": [ + [ + "GRISWOLDSHEART" + ] + ] + }, + "pavise": { + "uniques": [ + [ + "GERKESSANCTUARY" + ] + ] + }, + "platemail": { + "uniques": [ + [ + "BONEFLESH" + ] + ] + }, + "platedbelt": { + "uniques": [ + [ + "BLADEBUCKLE" + ] + ], + "sets": [ + [ + "SIGONSWRAP" + ] + ] + }, + "quiltedarmor": { + "uniques": [ + [ + "GREYFORM" + ] + ], + "sets": [ + [ + "ARCTICFURS" + ] + ] + }, + "ringmail": { + "uniques": [ + [ + "DARKGLOW" + ] + ], + "sets": [ + [ + "ANGELICMANTLE" + ] + ] + }, + "roundshield": { + "uniques": [ + [ + "MOSERSBLESSEDCIRCLE" + ] + ], + "sets": [ + [ + "WHITSTANSGUARD" + ] + ] + }, + "russetarmor": { + "uniques": [ + [ + "SKULLDERSIRE" + ] + ] + }, + "sacredarmor": { + "uniques": [ + [ + "TYRAELSMIGHT", + "TEMPLARSMIGHT" + ] + ], + "sets": [ + [ + "IMMORTALKINGSSOULCAGE" + ] + ] + }, + "sacredrondache": { + "uniques": [ + [ + "ALMANEGRA" + ] + ] + }, + "sallet": { + "uniques": [ + [ + "ROCKSTOPPER" + ] + ] + }, + "sash": { + "uniques": [ + [ + "LENYMO" + ] + ], + "sets": [ + [ + "DEATHSGUARD" + ] + ] + }, + "scalemail": { + "uniques": [ + [ + "HAWKMAIL" + ] + ] + }, + "scarabshellboots": { + "uniques": [ + [ + "SANDSTORMTREK" + ] + ] + }, + "scutum": { + "uniques": [ + [ + "STORMCHASER" + ] + ] + }, + "serpentskinarmor": { + "uniques": [ + [ + "SKINOFTHEVIPERMAGI" + ] + ] + }, + "shadowplate": { + "uniques": [ + [ + "STEELCARAPACE" + ] + ], + "sets": [ + [ + "ALDURSDECEPTION" + ] + ] + }, + "shako": { + "uniques": [ + [ + "HARLEQUINCREST" + ] + ] + }, + "sharkskinbelt": { + "uniques": [ + [ + "RAZORTAIL" + ] + ], + "sets": [ + [ + "MAVINASTENET" + ] + ] + }, + "sharkskinboots": { + "uniques": [ + [ + "WATERWALK" + ] + ] + }, + "sharkskingloves": { + "uniques": [ + [ + "GRAVEPALM" + ] + ], + "sets": [ + [ + "MAGNUSSKIN" + ] + ] + }, + "sharktootharmor": { + "uniques": [ + [ + "TOOTHROW" + ] + ] + }, + "skullcap": { + "uniques": [ + [ + "TARNHELM" + ] + ], + "sets": [ + [ + "ARCANNASHEAD" + ] + ] + }, + "skyspirit": { + "uniques": [ + [ + "RAVENLORE" + ] + ] + }, + "slayerguard": { + "uniques": [ + [ + "ARREATSFACE" + ] + ] + }, + "smallshield": { + "uniques": [ + [ + "UMBRALDISK" + ] + ], + "sets": [ + [ + "CLEGLAWSCLAW" + ] + ] + }, + "spiderwebsash": { + "uniques": [ + [ + "ARACHNIDMESH" + ] + ] + }, + "spikedshield": { + "uniques": [ + [ + "SWORDBACKHOLD" + ] + ] + }, + "spiredhelm": { + "uniques": [ + [ + "VEILOFSTEEL", + "NIGHTWINGSVEIL" + ] + ], + "sets": [ + [ + "ONDALSALMIGHTY" + ] + ] + }, + "splintmail": { + "uniques": [ + [ + "ICEBLINK" + ] + ], + "sets": [ + [ + "BERSERKERSHAUBERK" + ] + ] + }, + "studdedleather": { + "uniques": [ + [ + "TWITCHTHROE" + ] + ], + "sets": [ + [ + "COWKINGSHIDE" + ] + ] + }, + "succubusskull": { + "uniques": [ + [ + "BONEFLAME" + ] + ] + }, + "templarcoat": { + "uniques": [ + [ + "GUARDIANANGEL" + ] + ] + }, + "tiara": { + "uniques": [ + [ + "KIRASGUARDIAN" + ] + ] + }, + "tigulatedmail": { + "uniques": [ + [ + "CROWCAW" + ] + ], + "sets": [ + [ + "HWANINSREFUGE" + ] + ] + }, + "totemicmask": { + "uniques": [ + [ + "JALALSMANE" + ] + ] + }, + "towershield": { + "uniques": [ + [ + "BVERRITKEEP" + ] + ], + "sets": [ + [ + "SIGONSGUARD" + ] + ] + }, + "trellisedarmor": { + "uniques": [ + [ + "IRONPELT" + ] + ] + }, + "trollbelt": { + "sets": [ + [ + "TRANGOULSGIRTH" + ] + ] + }, + "trollnest": { + "uniques": [ + [ + "HEADHUNTERSGLORY" + ] + ] + }, + "vambraces": { + "uniques": [ + [ + "SOULDRAINER" + ] + ] + }, + "vampirebonegloves": { + "uniques": [ + [ + "DRACULSGRASP" + ] + ] + }, + "vampirefangbelt": { + "uniques": [ + [ + "NOSFERATUSCOIL" + ] + ] + }, + "vortexshield": { + "sets": [ + [ + "GRISWOLDSHONOR" + ] + ] + }, + "warbelt": { + "uniques": [ + [ + "THUNDERGODSVIGOR" + ] + ], + "sets": [ + [ + "IMMORTALKINGSDETAIL" + ] + ] + }, + "warboots": { + "uniques": [ + [ + "GORERIDER" + ] + ], + "sets": [ + [ + "IMMORTALKINGSPILLAR" + ] + ] + }, + "wargauntlets": { + "uniques": [ + [ + "HELLMOUTH" + ] + ], + "sets": [ + [ + "IMMORTALKINGSFORGE" + ] + ] + }, + "warhat": { + "uniques": [ + [ + "PEASANTCROWN" + ] + ], + "sets": [ + [ + "COWKINGSHORNS" + ] + ] + }, + "ward": { + "uniques": [ + [ + "SPIRITWARD" + ] + ], + "sets": [ + [ + "TAEBAEKSGLORY" + ] + ] + }, + "wingedhelm": { + "uniques": [ + [ + "VALKYRIEWING" + ] + ], + "sets": [ + [ + "GUILLAUMESFACE" + ] + ] + }, + "wirefleece": { + "uniques": [ + [ + "THEGLADIATORSBANE" + ] + ] + }, + "zakarumshield": { + "uniques": [ + [ + "DRAGONSCALE" + ] + ] + }, + "amulet": { + "uniques": [ + [ + "NOKOZANRELIC", + "THEEYEOFETLICH", + "THEMAHIMOAKCURIO", + "THECATSEYE", + "THERISINGSUN", + "CRESCENTMOON", + "MARASKALEIDOSCOPE", + "ATMASSCARAB", + "HIGHLORDSWRATH", + "SARACENSCHANCE", + "SERAPHSHYMN", + "METALGRID" + ] + ], + "sets": [ + [ + "ANGELICWINGS", + "ARCANNASSIGN", + "CATHANSSIGIL", + "CIVERBSICON", + "IRATHASCOLLAR", + "TALRASHASADJUDICATION", + "TANCREDSWEIRD", + "TELLINGOFBEADS", + "VIDALASSNARE" + ] + ] + }, + "grandcharm": { + "uniques": [ + [ + "GHEEDSFORTUNE" + ] + ] + }, + "jewel": { + "uniques": [ + [ + "RAINBOWFACET" + ] + ] + }, + "largecharm": { + "uniques": [ + [ + "HELLFIRETORCH" + ] + ] + }, + "ring": { + "uniques": [ + [ + "NAGELRING", + "MANALDHEAL", + "THESTONEOFJORDAN", + "CONSTRICTINGRING", + "BULKATHOSWEDDINGBAND", + "DWARFSTAR", + "RAVENFROST", + "NATURESPEACE", + "WISPPROJECTOR", + "CARRIONWIND" + ] + ], + "sets": [ + [ + "ANGELICHALO", + "CATHANSSEAL" + ] + ] + }, + "smallcharm": { + "uniques": [ + [ + "ANNIHILUS" + ] + ] + }, + "topofthehoradricstaff": { + "uniques": [ + [ + "AMULETOFTHEVIPER" + ] + ] + }, + "ancientaxe": { + "uniques": [ + [ + "THEMINOTAUR" + ] + ] + }, + "ancientsword": { + "uniques": [ + [ + "THEATLANTEAN" + ] + ] + }, + "arbalest": { + "uniques": [ + [ + "LANGERBRISER" + ] + ] + }, + "archonstaff": { + "uniques": [ + [ + "MANGSONGSLESSON" + ] + ] + }, + "ataghan": { + "uniques": [ + [ + "DJINNSLAYER" + ] + ] + }, + "axe": { + "uniques": [ + [ + "DEATHSPADE" + ] + ] + }, + "ballista": { + "uniques": [ + [ + "BURIZADOKYANON" + ] + ] + }, + "balrogblade": { + "uniques": [ + [ + "FLAMEBELLOW" + ] + ] + }, + "balrogspear": { + "uniques": [ + [ + "DEMONSARCH" + ] + ] + }, + "barbedclub": { + "uniques": [ + [ + "FLESHRENDER" + ] + ] + }, + "bardiche": { + "uniques": [ + [ + "DIMOAKSHEW" + ] + ] + }, + "bastardsword": { + "uniques": [ + [ + "BLACKTONGUE" + ] + ] + }, + "battleaxe": { + "uniques": [ + [ + "THECHIEFTAIN" + ] + ] + }, + "battlecestus": { + "uniques": [ + [ + "SHADOWKILLER" + ] + ] + }, + "battledart": { + "uniques": [ + [ + "DEATHBIT" + ] + ] + }, + "battlehammer": { + "uniques": [ + [ + "EARTHSHAKER" + ] + ] + }, + "battlescythe": { + "uniques": [ + [ + "ATHENASWRATH" + ] + ] + }, + "battlestaff": { + "uniques": [ + [ + "THESALAMANDER" + ] + ], + "sets": [ + [ + "CATHANSRULE" + ] + ] + }, + "battlesword": { + "uniques": [ + [ + "HEADSTRIKER" + ] + ] + }, + "beardedaxe": { + "uniques": [ + [ + "SPELLSTEEL" + ] + ] + }, + "becdecorbin": { + "uniques": [ + [ + "HUSOLDALEVO" + ] + ] + }, + "berserkeraxe": { + "uniques": [ + [ + "DEATHCLEAVER" + ] + ] + }, + "bill": { + "uniques": [ + [ + "BLACKLEACHBLADE" + ] + ], + "sets": [ + [ + "HWANINSJUSTICE" + ] + ] + }, + "blade": { + "uniques": [ + [ + "SPECTRALSHARD" + ] + ] + }, + "boneknife": { + "uniques": [ + [ + "WIZARDSPIKE" + ] + ] + }, + "bonewand": { + "uniques": [ + [ + "GRAVENSPINE" + ] + ], + "sets": [ + [ + "SANDERSSUPERSTITION" + ] + ] + }, + "brandistock": { + "uniques": [ + [ + "BLOODTHIEF" + ] + ] + }, + "broadaxe": { + "uniques": [ + [ + "GORESHOVEL" + ] + ] + }, + "broadsword": { + "uniques": [ + [ + "GRISWOLDSEDGE" + ] + ], + "sets": [ + [ + "ISENHARTSLIGHTBRAND" + ] + ] + }, + "burntwand": { + "uniques": [ + [ + "SUICIDEBRANCH" + ] + ] + }, + "caduceus": { + "uniques": [ + [ + "ASTREONSIRONWARD" + ] + ], + "sets": [ + [ + "GRISWOLDSREDEMPTION" + ] + ] + }, + "cedarbow": { + "uniques": [ + [ + "KUKOSHAKAKU" + ] + ] + }, + "cedarstaff": { + "uniques": [ + [ + "CHROMATICIRE" + ] + ] + }, + "ceremonialbow": { + "uniques": [ + [ + "LYCANDERSAIM" + ] + ] + }, + "ceremonialjavelin": { + "uniques": [ + [ + "TITANSREVENGE" + ] + ] + }, + "ceremonialpike": { + "uniques": [ + [ + "LYCANDERSFLANK" + ] + ] + }, + "championaxe": { + "uniques": [ + [ + "MESSERSCHMIDTSREAVER" + ] + ] + }, + "championsword": { + "uniques": [ + [ + "DOOMBRINGER" + ] + ] + }, + "chukonu": { + "uniques": [ + [ + "DEMONMACHINE" + ] + ] + }, + "cinquedeas": { + "uniques": [ + [ + "BLACKBOGSSHARP" + ] + ] + }, + "claymore": { + "uniques": [ + [ + "SOULFLAY" + ] + ] + }, + "cleaver": { + "uniques": [ + [ + "BUTCHERSPUPIL" + ] + ] + }, + "club": { + "uniques": [ + [ + "FELLOAK" + ] + ] + }, + "colossusblade": { + "uniques": [ + [ + "THEGRANDFATHER" + ] + ], + "sets": [ + [ + "BULKATHOSSACREDCHARGE" + ] + ] + }, + "colossuscrossbow": { + "uniques": [ + [ + "HELLRACK" + ] + ] + }, + "compositebow": { + "uniques": [ + [ + "ROGUESBOW" + ] + ] + }, + "crossbow": { + "uniques": [ + [ + "ICHORSTING" + ] + ] + }, + "crowbill": { + "uniques": [ + [ + "POMPEIISWRATH" + ] + ] + }, + "crusaderbow": { + "uniques": [ + [ + "EAGLEHORN" + ] + ] + }, + "crypticaxe": { + "uniques": [ + [ + "TOMBREAVER" + ] + ] + }, + "crypticsword": { + "uniques": [ + [ + "FROSTWIND" + ] + ], + "sets": [ + [ + "SAZABISCOBALTREDEEMER" + ] + ] + }, + "crystalsword": { + "uniques": [ + [ + "AZUREWRATH" + ] + ] + }, + "cudgel": { + "uniques": [ + [ + "DARKCLANCRUSHER" + ] + ] + }, + "cutlass": { + "uniques": [ + [ + "COLDSTEELEYE" + ] + ] + }, + "dacianfalx": { + "uniques": [ + [ + "BINGSZWANG" + ] + ] + }, + "dagger": { + "uniques": [ + [ + "GULL" + ] + ] + }, + "decapitator": { + "uniques": [ + [ + "HELLSLAYER" + ] + ] + }, + "demoncrossbow": { + "uniques": [ + [ + "GUTSIPHON" + ] + ] + }, + "devilstar": { + "uniques": [ + [ + "BARANARSSTAR" + ] + ] + }, + "dimensionalblade": { + "uniques": [ + [ + "GINTHERSRIFT" + ] + ] + }, + "dimensionalshard": { + "uniques": [ + [ + "DEATHSFATHOM" + ] + ] + }, + "dirk": { + "uniques": [ + [ + "THEDIGGLER" + ] + ] + }, + "divinescepter": { + "uniques": [ + [ + "HANDOFBLESSEDLIGHT" + ] + ] + }, + "doubleaxe": { + "uniques": [ + [ + "BLADEBONE" + ] + ], + "sets": [ + [ + "BERSERKERSHATCHET" + ] + ] + }, + "doublebow": { + "uniques": [ + [ + "ENDLESSHAIL" + ] + ] + }, + "edgebow": { + "uniques": [ + [ + "SKYSTRIKE" + ] + ] + }, + "elderstaff": { + "uniques": [ + [ + "ONDALSWISDOM" + ] + ], + "sets": [ + [ + "NAJSPUZZLER" + ] + ] + }, + "eldritchorb": { + "uniques": [ + [ + "ESCHUTASTEMPER" + ] + ] + }, + "elegantblade": { + "uniques": [ + [ + "BLOODMOON" + ] + ] + }, + "espandon": { + "uniques": [ + [ + "CRAINTEVOMIR" + ] + ] + }, + "ettinaxe": { + "uniques": [ + [ + "RUNEMASTER" + ] + ] + }, + "executionersword": { + "uniques": [ + [ + "SWORDGUARD" + ] + ] + }, + "falchion": { + "uniques": [ + [ + "GLEAMSCYTHE" + ] + ] + }, + "fangedknife": { + "uniques": [ + [ + "FLESHRIPPER" + ] + ] + }, + "feralclaws": { + "uniques": [ + [ + "FIRELIZARDSTALONS" + ] + ] + }, + "flail": { + "uniques": [ + [ + "THEGENERALSTANDOLIGA" + ] + ] + }, + "flamberge": { + "uniques": [ + [ + "RIPSAW" + ] + ] + }, + "flangedmace": { + "uniques": [ + [ + "SURESHRILLFROST" + ] + ] + }, + "flyingaxe": { + "uniques": [ + [ + "GIMMERSHRED" + ] + ] + }, + "francisca": { + "uniques": [ + [ + "THESCALPER" + ] + ] + }, + "fuscina": { + "uniques": [ + [ + "KELPIESNARE" + ] + ] + }, + "ghostglaive": { + "uniques": [ + [ + "WRAITHFLIGHT" + ] + ] + }, + "giantaxe": { + "uniques": [ + [ + "HUMONGOUS" + ] + ] + }, + "giantsword": { + "uniques": [ + [ + "KINEMILSAWL" + ] + ] + }, + "giantthresher": { + "uniques": [ + [ + "STORMSPIRE" + ] + ] + }, + "gladius": { + "uniques": [ + [ + "BLOODLETTER" + ] + ] + }, + "gloriousaxe": { + "uniques": [ + [ + "EXECUTIONERSJUSTICE" + ] + ] + }, + "gnarledstaff": { + "uniques": [ + [ + "SPIREOFLAZARUS" + ] + ] + }, + "gothicaxe": { + "uniques": [ + [ + "BONESLAYERBLADE" + ] + ] + }, + "gothicbow": { + "uniques": [ + [ + "GOLDSTRIKEARCH" + ] + ] + }, + "gothicstaff": { + "uniques": [ + [ + "WARPSPEAR" + ] + ] + }, + "gothicsword": { + "uniques": [ + [ + "CLOUDCRACK" + ] + ] + }, + "grandmatronbow": { + "sets": [ + [ + "MAVINASCASTER" + ] + ] + }, + "grandscepter": { + "uniques": [ + [ + "RUSTHANDLE" + ] + ], + "sets": [ + [ + "CIVERBSCUDGEL" + ] + ] + }, + "gravewand": { + "uniques": [ + [ + "BLACKHANDKEY" + ] + ] + }, + "greataxe": { + "uniques": [ + [ + "BRAINHEW" + ] + ] + }, + "greatmaul": { + "uniques": [ + [ + "STEELDRIVER" + ] + ] + }, + "greatsword": { + "uniques": [ + [ + "THEPATRIARCH" + ] + ] + }, + "greatertalons": { + "uniques": [ + [ + "BARTUCSCUTTHROAT" + ] + ] + }, + "grimscythe": { + "uniques": [ + [ + "GRIMSBURNINGDEAD" + ] + ] + }, + "grimwand": { + "uniques": [ + [ + "UMESLAMENT" + ] + ], + "sets": [ + [ + "INFERNALTORCH" + ] + ] + }, + "halberd": { + "uniques": [ + [ + "WOESTAVE" + ] + ] + }, + "handaxe": { + "uniques": [ + [ + "THEGNASHER" + ] + ] + }, + "hatchet": { + "uniques": [ + [ + "COLDKILL" + ] + ] + }, + "heavycrossbow": { + "uniques": [ + [ + "HELLCAST" + ] + ] + }, + "hellforgehammer": { + "uniques": [ + [ + "HELLFORGEHAMMER" + ] + ] + }, + "holywatersprinkler": { + "uniques": [ + [ + "THEFETIDSPRINKLER" + ] + ] + }, + "horadricstaff": { + "uniques": [ + [ + "HORADRICSTAFF" + ] + ] + }, + "huntersbow": { + "uniques": [ + [ + "WITHERSTRING" + ] + ] + }, + "hydrabow": { + "uniques": [ + [ + "WINDFORCE" + ] + ] + }, + "hyperionspear": { + "uniques": [ + [ + "ARIOCSNEEDLE" + ] + ] + }, + "jaggedstar": { + "uniques": [ + [ + "MOONFALL" + ] + ], + "sets": [ + [ + "ALDURSRHYTHM" + ] + ] + }, + "jostaff": { + "uniques": [ + [ + "RAZORSWITCH" + ] + ] + }, + "khalimsflail": { + "uniques": [ + [ + "KHALIMSFLAIL" + ] + ] + }, + "khalimswill": { + "uniques": [ + [ + "KHALIMSWILL" + ] + ] + }, + "knout": { + "uniques": [ + [ + "BAEZILSVORTEX" + ] + ] + }, + "kris": { + "uniques": [ + [ + "THEJADETANDO" + ] + ] + }, + "lance": { + "uniques": [ + [ + "SPIREOFHONOR" + ] + ] + }, + "largeaxe": { + "uniques": [ + [ + "AXEOFFECHMAR" + ] + ] + }, + "largesiegebow": { + "uniques": [ + [ + "CLIFFKILLER" + ] + ] + }, + "legendspike": { + "uniques": [ + [ + "GHOSTFLAME" + ] + ] + }, + "legendarymallet": { + "uniques": [ + [ + "SCHAEFERSHAMMER", + "STONECRUSHER" + ] + ] + }, + "lichwand": { + "uniques": [ + [ + "BONESHADE" + ] + ] + }, + "lightcrossbow": { + "uniques": [ + [ + "LEADCROW" + ] + ] + }, + "lochaberaxe": { + "uniques": [ + [ + "THEMEATSCRAPER" + ] + ] + }, + "longbattlebow": { + "uniques": [ + [ + "WIZENDRAW" + ] + ], + "sets": [ + [ + "VIDALASBARB" + ] + ] + }, + "longbow": { + "uniques": [ + [ + "RAVENCLAW" + ] + ] + }, + "longstaff": { + "uniques": [ + [ + "SERPENTLORD" + ] + ] + }, + "longsword": { + "uniques": [ + [ + "HELLPLAGUE" + ] + ], + "sets": [ + [ + "CLEGLAWSTOOTH" + ] + ] + }, + "longwarbow": { + "uniques": [ + [ + "BLASTBARK" + ] + ] + }, + "mace": { + "uniques": [ + [ + "CRUSHFLANGE" + ] + ] + }, + "mancatcher": { + "uniques": [ + [ + "VIPERFORK" + ] + ] + }, + "marteldefer": { + "uniques": [ + [ + "THEGAVELOFPAIN" + ] + ] + }, + "matriarchalbow": { + "uniques": [ + [ + "BLOODRAVENSCHARGE" + ] + ] + }, + "matriarchaljavelin": { + "uniques": [ + [ + "THUNDERSTROKE" + ] + ] + }, + "matriarchalspear": { + "uniques": [ + [ + "STONERAVEN" + ] + ] + }, + "maul": { + "uniques": [ + [ + "BONESNAP" + ] + ] + }, + "mightyscepter": { + "uniques": [ + [ + "HEAVENSLIGHT", + "THEREDEEMER" + ] + ] + }, + "militaryaxe": { + "uniques": [ + [ + "WARLORDSTRUST" + ] + ] + }, + "militarypick": { + "uniques": [ + [ + "SKULLSPLITTER" + ] + ], + "sets": [ + [ + "TANCREDSCROWBILL" + ] + ] + }, + "morningstar": { + "uniques": [ + [ + "BLOODRISE" + ] + ] + }, + "mythicalsword": { + "sets": [ + [ + "BULKATHOSTRIBALGUARDIAN" + ] + ] + }, + "naga": { + "uniques": [ + [ + "GUARDIANNAGA" + ] + ] + }, + "ogreaxe": { + "uniques": [ + [ + "BONEHEW" + ] + ] + }, + "ogremaul": { + "uniques": [ + [ + "WINDHAMMER" + ] + ], + "sets": [ + [ + "IMMORTALKINGSSTONECRUSHER" + ] + ] + }, + "partizan": { + "uniques": [ + [ + "PIERRETOMBALECOUANT" + ] + ] + }, + "petrifiedwand": { + "uniques": [ + [ + "CARINSHARD" + ] + ] + }, + "phaseblade": { + "uniques": [ + [ + "LIGHTSABRE", + "AZUREWRATH" + ] + ] + }, + "pike": { + "uniques": [ + [ + "THETANNRGOREROD" + ] + ] + }, + "poignard": { + "uniques": [ + [ + "SPINERIPPER" + ] + ] + }, + "poleaxe": { + "uniques": [ + [ + "THEBATTLEBRANCH" + ] + ] + }, + "quarterstaff": { + "uniques": [ + [ + "RIBCRACKER" + ] + ] + }, + "razorbow": { + "uniques": [ + [ + "RIPHOOK" + ] + ] + }, + "reinforcedmace": { + "sets": [ + [ + "DANGOONSTEACHING" + ] + ] + }, + "repeatingcrossbow": { + "uniques": [ + [ + "DOOMSLINGER" + ] + ] + }, + "rondel": { + "uniques": [ + [ + "HEARTCARVER" + ] + ] + }, + "runebow": { + "uniques": [ + [ + "MAGEWRATH" + ] + ] + }, + "runescepter": { + "uniques": [ + [ + "ZAKARUMSHAND" + ] + ] + }, + "runestaff": { + "uniques": [ + [ + "SKULLCOLLECTOR" + ] + ] + }, + "runesword": { + "uniques": [ + [ + "PLAGUEBEARER" + ] + ] + }, + "sabre": { + "uniques": [ + [ + "SKEWEROFKRINTIZ" + ] + ], + "sets": [ + [ + "ANGELICSICKLE" + ] + ] + }, + "scepter": { + "uniques": [ + [ + "KNELLSTRIKER" + ] + ] + }, + "scimitar": { + "uniques": [ + [ + "BLOODCRESCENT" + ] + ] + }, + "scissorssuwayyah": { + "sets": [ + [ + "NATALYASMARK" + ] + ] + }, + "scourge": { + "uniques": [ + [ + "HORIZONSTORNADO", + "STORMLASH" + ] + ] + }, + "scythe": { + "uniques": [ + [ + "SOULHARVEST" + ] + ] + }, + "shaftofthehoradricstaff": { + "uniques": [ + [ + "STAFFOFKINGS" + ] + ] + }, + "shamshir": { + "uniques": [ + [ + "HEXFIRE" + ] + ] + }, + "shortbattlebow": { + "uniques": [ + [ + "STORMSTRIKE" + ] + ] + }, + "shortbow": { + "uniques": [ + [ + "PLUCKEYE" + ] + ] + }, + "shortsiegebow": { + "uniques": [ + [ + "WITCHWILDSTRING" + ] + ] + }, + "shortstaff": { + "uniques": [ + [ + "BANEASH" + ] + ] + }, + "shortsword": { + "uniques": [ + [ + "RIXOTSKEEN" + ] + ] + }, + "shortwarbow": { + "uniques": [ + [ + "HELLCLAP" + ] + ], + "sets": [ + [ + "ARCTICHORN" + ] + ] + }, + "siegecrossbow": { + "uniques": [ + [ + "PUSSPITTER" + ] + ] + }, + "silveredgedaxe": { + "uniques": [ + [ + "ETHEREALEDGE" + ] + ] + }, + "spear": { + "uniques": [ + [ + "THEDRAGONCHANG" + ] + ] + }, + "spetum": { + "uniques": [ + [ + "LANCEOFYAGGAI" + ] + ] + }, + "spikedclub": { + "uniques": [ + [ + "STOUTNAIL" + ] + ] + }, + "stiletto": { + "uniques": [ + [ + "STORMSPIKE" + ] + ] + }, + "swirlingcrystal": { + "uniques": [ + [ + "THEOCULUS" + ] + ], + "sets": [ + [ + "TALRASHASLIDLESSEYE" + ] + ] + }, + "tabar": { + "uniques": [ + [ + "STORMRIDER" + ] + ] + }, + "thresher": { + "uniques": [ + [ + "THEREAPERSTOLL" + ] + ] + }, + "thundermaul": { + "uniques": [ + [ + "THECRANIUMBASHER", + "EARTHSHIFTER" + ] + ] + }, + "tomahawk": { + "uniques": [ + [ + "RAZORSEDGE" + ] + ] + }, + "tombwand": { + "uniques": [ + [ + "ARMOFKINGLEORIC" + ] + ] + }, + "trident": { + "uniques": [ + [ + "RAZORTINE" + ] + ] + }, + "truncheon": { + "uniques": [ + [ + "NORDSTENDERIZER" + ] + ] + }, + "tulwar": { + "uniques": [ + [ + "BLADEOFALIBABA" + ] + ] + }, + "tusksword": { + "uniques": [ + [ + "THEVILEHUSK" + ] + ] + }, + "twinaxe": { + "uniques": [ + [ + "ISLESTRIKE" + ] + ] + }, + "twohandedsword": { + "uniques": [ + [ + "SHADOWFANG" + ] + ] + }, + "tyrantclub": { + "uniques": [ + [ + "DEMONLIMB" + ] + ] + }, + "unearthedwand": { + "uniques": [ + [ + "DEATHSWEB" + ] + ] + }, + "voulge": { + "uniques": [ + [ + "STEELGOAD" + ] + ] + }, + "wand": { + "uniques": [ + [ + "TORCHOFIRO" + ] + ] + }, + "waraxe": { + "uniques": [ + [ + "RAKESCAR" + ] + ] + }, + "warclub": { + "uniques": [ + [ + "BLOODTREESTUMP" + ] + ] + }, + "warfork": { + "uniques": [ + [ + "SOULFEASTTINE" + ] + ] + }, + "warhammer": { + "uniques": [ + [ + "IRONSTONE" + ] + ] + }, + "warpike": { + "uniques": [ + [ + "STEELPILLAR" + ] + ] + }, + "warscepter": { + "uniques": [ + [ + "STORMEYE" + ] + ], + "sets": [ + [ + "MILABREGASROD" + ] + ] + }, + "warscythe": { + "uniques": [ + [ + "THEGRIMREAPER" + ] + ] + }, + "warspear": { + "uniques": [ + [ + "THEIMPALER" + ] + ] + }, + "warspike": { + "uniques": [ + [ + "CRANEBEAK" + ] + ] + }, + "warstaff": { + "uniques": [ + [ + "THEIRONJANGBONG" + ] + ], + "sets": [ + [ + "ARCANNASDEATHWAND" + ] + ] + }, + "warsword": { + "uniques": [ + [ + "CULWENSPOINT" + ] + ], + "sets": [ + [ + "DEATHSTOUCH" + ] + ] + }, + "wardbow": { + "uniques": [ + [ + "WIDOWMAKER" + ] + ] + }, + "wingedaxe": { + "uniques": [ + [ + "LACERATOR" + ] + ] + }, + "wingedharpoon": { + "uniques": [ + [ + "GARGOYLESBITE" + ] + ] + }, + "wingedknife": { + "uniques": [ + [ + "WARSHRIKE" + ] + ] + }, + "wristsword": { + "uniques": [ + [ + "JADETALON" + ] + ] + }, + "yari": { + "uniques": [ + [ + "HONESUNDAN" + ] + ] + }, + "yewwand": { + "uniques": [ + [ + "MAELSTROM" + ] + ] + }, + "zweihander": { + "uniques": [ + [ + "TODESFAELLEFLAMME" + ] + ] + } +} + +# set_and_unique_names = [] + +# for k, v in UniqueAndSetData.items(): +# if "sets" in v: +# for set_name in v["sets"][0]: +# set_and_unique_names.append(set_name.lower()) +# if "uniques" in v: +# for unique_name in v["uniques"][0]: +# set_and_unique_names.append(unique_name.lower()) +# import json +# # print("goldwrap".lower() in set_and_unique_names) + +# print(json.dumps(set_and_unique_names, indent=4)) \ No newline at end of file diff --git a/src/bnip/actions.py b/src/bnip/actions.py new file mode 100644 index 000000000..19b829f1c --- /dev/null +++ b/src/bnip/actions.py @@ -0,0 +1,252 @@ +""" + Provides actions to perform tests on items in game. +""" + + +import os +import re +import glob +import traceback +from logger import Logger +from dataclasses import dataclass +from bnip.lexer import BNipSections +from bnip.tokens import TokenType +from bnip.transpile import ( + prepare_bnip_expression, + transpile_bnip_expression, + get_section_from_tokens, + BNIPExpression, + bnip_expressions, + load_bnip_expression, +) + +# ! The below imports are necessary, they are used within the eval statements. Your text editor probably is not showing them as not in use. +from bnip.NTIPAliasQuality import NTIPAliasQuality +from bnip.NTIPAliasClass import NTIPAliasClass +from bnip.NTIPAliasClassID import NTIPAliasClassID +from bnip.NTIPAliasFlag import NTIPAliasFlag +from bnip.NTIPAliasStat import NTIPAliasStat +from bnip.NTIPAliasType import NTIPAliasType +from bnip.utils import find_unique_or_set_base + + + +def should_keep(item_data) -> tuple[bool, str]: + """Decides whether or not to keep an item. + Args: + item_data (dict): The item data. + returns: + tuple[bool, str]: A tuple containing the following: + bool: Whether or not to keep the item. + str: The raw expression to use for the keep condition. + + """ + for expression in bnip_expressions: + if eval(expression.transpiled): + return True, expression.raw + return False, "" + +def _gold_pickup(item_data: dict, expression: BNIPExpression) -> bool | None: + res = None + for i, token in enumerate(expression.tokens): + if ( + token.type == TokenType.KeywordNTIPAliasStat + and token.value == str(NTIPAliasStat["gold"]) + and "Amount" in item_data + and item_data["Amount"] is not None + ): + try: + read_gold = int(item_data["Amount"]) + operator = expression.tokens[i + 1].value + desired_gold = int(expression.tokens[i + 2].value) + res = eval(f"{read_gold} {operator} {desired_gold}") + except Exception as e: + Logger.warning(f"Error evaluating gold pickup condition: {e}") + break + return res + + +def _handle_pick_eth_sockets(item_data: dict, expression: BNIPExpression) -> tuple[bool, str]: + """Handles the pick condition for eth and sockets. + Args: + item_data (dict): The item data. + expression (BNIPExpression): The expression to use. + Returns: + tuple[bool, str]: A tuple containing the following: + bool: Whether or not to keep the item. + BNIPExpression: The expression object that was used to evaluate the condition. + """ + expression_raw = prepare_bnip_expression(expression.raw) + all_tokens = expression.tokens + + tokens_by_section = get_section_from_tokens(all_tokens) + eth_keyword_present = "ethereal" in expression_raw.lower() + soc_keyword_present = expression_raw.lower().count("[sockets]") == 1 # currently ignoring if there's socket logic; i.e., [sockets] == 0 || [sockets] == 5 + + eth = 0 # * -1 = set to false, 0 = not set, 1 = set to true + soc = 0 + if eth_keyword_present: + for i, token in enumerate(tokens := tokens_by_section[BNipSections.PROP]): + if token.type == TokenType.ValueNTIPAliasFlag and str(token.value).lower() == "ethereal": + if tokens[i - 1].value == "==": + eth = 1 + else: + eth = -1 + break + + if len(tokens_by_section) > 1 and soc_keyword_present: + for i, token in enumerate(tokens := tokens_by_section[BNipSections.STAT]): + if token.type == TokenType.KeywordNTIPAliasStat and token.value == str(NTIPAliasStat["sockets"]): + desired_sockets = int(tokens[i + 2].value) + if (desired_sockets > 0 and not (desired_sockets == 1 and tokens[i + 1].value == "<")) or (desired_sockets == 0 and tokens[i + 1].value == ">"): + soc = 1 + else: + soc = -1 + break + + + # pickup table: + # * w = white, g = gray + # -1 eth 0 eth 1 eth + # -1 soc w w,g g + # 0 soc w,g w,g g + # 1 soc g g g + + ignore = 0 + if item_data["Color"] == "white": + ignore = eth == 1 or soc == 1 + elif item_data["Color"] == "gray": + ignore = eth == soc == -1 + + pick_eval_expr = expression.should_pickup + # print(f"color: {item_data['Color']}, eth: {eth}, soc: {soc}, ignore: {ignore}") + if not ignore and eth_keyword_present: + # remove ethereal from expression + raw = expression.raw.replace("&& [flag]", "[flag]").replace("|| [flag]", "[flag]") + raw = re.sub(r"\[flag\] (==|!=)\sethereal", "", raw) + # print(f"Modified raw expression: {raw}") + pick_eval_expr = transpile_bnip_expression(raw.split("#")[0], isPickUpPhase=True) + # print(f"Modified transpiled expression: {pick_eval_expr}") + + return ignore, pick_eval_expr + + +def should_pickup(item_data) -> tuple[bool, str]: + """Decides whether or not to keep an item. + Args: + item_data (dict): The item data. + returns: + tuple[bool, str]: A tuple containing the following: + bool: Whether or not to keep the item. + str: The raw expression to use for the keep condition. + """ + + pick_eval_expr = "" + item_is_gold = item_data["BaseItem"]["DisplayName"] == "Gold" + + for expression in bnip_expressions: + if expression.raw: + # check gold + if item_is_gold and "[gold]" in expression.raw.lower(): + if (res := _gold_pickup(item_data, expression)) is not None: + return res, expression.raw + # check eth / sockets + pick_eval_expr = expression.should_pickup + if any(substring == item_data["Color"] for substring in ["white", "gray"]): + ignore, pick_eval_expr = _handle_pick_eth_sockets(item_data, expression) + if ignore: + continue + + property_condition = eval(pick_eval_expr) # * This string in the eval uses the item_data that is being passed in + if property_condition: + return True, expression.raw + + + return False, "" + + +def should_id(item_data) -> bool: + """Checks if the item should be identified. + + Args: + item_data (dict): The item data. + + Returns: (bool): + True if the item should be identified, False otherwise. + + Raises: + None + + Examples: + [name] == ring && [quality] == rare -> True + [name] == ring && [quality] == rare # [strength] == 5 -> Falsep + """ + for expression in bnip_expressions: + if expression and expression.should_id_transpiled: + split_expression = expression.raw.split("#") + if "[idname]" in expression.raw.lower(): + return True + if len(split_expression) == 1: + if eval(expression.should_id_transpiled): + return False + return True + +def _load_bnip_expressions(filepath): + """ + Loads the BNIP expressions from the file. + Args: + filepath (str): The path to the file. + Returns: + None + """ + with open(filepath, "r", encoding="utf-8") as f: + for i, line in enumerate(f): + line = line.strip() + if line == "" or line.startswith("//"): # Empty or comment line + continue + try: + load_bnip_expression(line) + except Exception as e: + filepath = filepath.replace("\\", "/") + file = filepath.split('/config/')[1] + print(f"{file}:{e}:line {i + 1}") # TODO look at these errors + if False and traceback.print_exc(): # * Switch between True and False for debugging + break + + +default_bnip_file_path = f"{os.getcwd()}/config/default.bnip" +bnip_path = f"{os.getcwd()}/config/bnip" + +glob_bnip_path = os.path.join(bnip_path, '**', '*.bnip') +glob_nip_path = os.path.join(bnip_path, '**', '*.nip') + +bnip_file_paths = glob.glob(glob_bnip_path, recursive=True) + glob.glob(glob_nip_path, recursive=True) + +# * Remove all directories or files that are in the .nipignore file from bnip_file_paths. (accepts glob patterns) +if os.path.isfile(os.path.join(bnip_path, '.nipignore')): + with open(os.path.join(bnip_path, '.nipignore'), "r") as f: + for line in f: + line = line.strip() + line = line.replace("/", "\\") + remove_files = glob.glob(os.path.join(bnip_path, line), recursive=True) + for remove_file in remove_files: + if remove_file in bnip_file_paths: + bnip_file_paths.remove(remove_file) + +num_files = 0 +# load all nip expressions +if len(bnip_file_paths) > 0: + num_files = len(bnip_file_paths) + for bnip_file_path in bnip_file_paths: + _load_bnip_expressions(bnip_file_path) +# fallback to default nip file if no custom nip files specified or existing files are excluded +else: + num_files = 1 + _load_bnip_expressions(default_bnip_file_path) + Logger.warning("No .bnip files in config/nip/, fallback to default.bnip") +Logger.info(f"Loaded {num_files} nip files with {len(bnip_expressions)} total expressions.") + +bnip_expressions = sorted(bnip_expressions, key=lambda x: len(x.raw)) + +if __name__ == "__main__": + print(transpile_bnip_expression("[name] == ring && [quality] == rare # [strength] == 5")) diff --git a/src/bnip/lexer.py b/src/bnip/lexer.py new file mode 100644 index 000000000..5e7f63e43 --- /dev/null +++ b/src/bnip/lexer.py @@ -0,0 +1,371 @@ +""" + Lexer for BNIP expressions. +""" + +from dataclasses import dataclass +from logger import Logger +from bnip.NTIPAliasQuality import NTIPAliasQuality +from bnip.NTIPAliasClass import NTIPAliasClass +from bnip.NTIPAliasClassID import NTIPAliasClassID +from bnip.NTIPAliasFlag import NTIPAliasFlag +from bnip.NTIPAliasStat import NTIPAliasStat +from bnip.NTIPAliasType import NTIPAliasType +from bnip.tokens import Token, TokenType + +from bnip.BNipExceptions import BNipSyntaxError + +from enum import Enum +import re +from rapidfuzz.string_metric import levenshtein + +WHITESPACE = " \t\n\r\v\f" +DIGITS = "0123456789.-" # ! Put % back in here when ready to use percentages. +SYMBOLS = [">", "=> ", "<", "<=", "=", "!", "", "", ",", "&", "|", "#"] +MATH_SYMBOLS = ["(", ")", "^", "*", "/", "\\", "+", "-"] +CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'" + +class BNipSections(Enum): + PROP = 1 + STAT = 2 + MAXQUANTITY = 3 + +class Lexer: + def __init__(self): + self.current_section: BNipSections = BNipSections.PROP + self.current_token: str | None = "" + self.text_i: int = -1 + self.tokens: list[Token] = [] + + + def _increment_section(self): + if self.current_section == BNipSections.PROP: + self.current_section = BNipSections.STAT + elif self.current_section == BNipSections.STAT: + self.current_section = BNipSections.MAXQUANTITY + + + def _get_text(self): + return "".join(self.text) + + + def _get_current_iteration_of_text_raw(self): + """ + Returns the self.text in a string type, and at its current iteration. + """ + return self._get_text()[self.text_i:] + + def _advance(self): + try: + self.text_i += 1 + self.current_token = self.text[self.text_i] + except IndexError: + self.current_token = None + + + def create_tokens(self, bnip_expression: str, starting_section: BNipSections = BNipSections.PROP): + """Creates token from a bnip expression string + + Args: + bnip_expression (str): the bnip expression string + starting_section (BNipSections): the section to start parsing from + Returns: + A list of tokens + Raises: + BNipSyntaxError: If there is a syntax error in the bnip expression + """ + self.current_section = starting_section + self.text = list(bnip_expression) + self._advance() + self.tokens = [] + while self.current_token != None: + + if self.current_token == "-": # * Since - is a math symbol and a negative sign for numbers, we need to handle it differently. + NTIPAliasKeywords = [ + TokenType.KeywordNTIPAliasClass, + TokenType.KeywordNTIPAliasFlag, + TokenType.KeywordNTIPAliasIDName, + TokenType.KeywordNTIPAliasMaxQuantity, + TokenType.KeywordNTIPAliasName, + TokenType.KeywordNTIPAliasQuality, + TokenType.KeywordNTIPAliasStat, + TokenType.KeywordNTIPAliasType, + ] + if self.tokens[-1].type in NTIPAliasKeywords + [TokenType.NUMBER]: + self.tokens.append(self._create_math_operator()) + self._advance() + else: + self.tokens.append(self._create_digits()) + continue + + + if self.current_token in DIGITS: + self.tokens.append(self._create_digits()) + elif self.current_token in WHITESPACE: + self._advance() + elif self.current_token in SYMBOLS: + self.tokens.append(self._create_logical_operator()) + elif self.current_token in MATH_SYMBOLS: + self.tokens.append(self._create_math_operator()) + self._advance() + elif self.current_token == "[": + self.tokens.append(self._create_keyword_lookup()) + elif self.current_token in CHARS: + self.tokens.append(self._create_d2r_image_data_lookup()) + elif self.current_section == BNipSections.PROP and self.text_i == 0 and self.current_token == "@": + self.tokens.append(Token(TokenType.NOTIFICATION, '@')) + self._advance() + else: + raise BNipSyntaxError("BNIP_0x1", f"Unknown token: '{self.current_token}'", self._get_text()) + return self.tokens + + def detokenize(self, tokens: list[Token]) -> str: + """Detokenizes a list of tokens into a bnip expression string + + Args: + tokens (list[Token]): the list of tokens to detokenize + Returns: + A bnip expression string + Raises: + None + + """ + + token_to_value = { + TokenType.NUMBER: '{}', + TokenType.NUMBERPERCENT: '{}%', + TokenType.PLUS: '+', + TokenType.MINUS: '-', + TokenType.MULTIPLY: '*', + TokenType.DIVIDE: '/', + TokenType.MODULO: '%', + + TokenType.LPAREN: '(', + TokenType.RPAREN: ')', + + TokenType.GT: '>', + TokenType.LT: '<', + TokenType.LE: '<=', + TokenType.GE: '>=', + TokenType.EQ: '==', + TokenType.NE: '!=', + + TokenType.AND: '&&', + TokenType.OR: '||', + + TokenType.SECTIONAND: '#', + + TokenType.KeywordNTIPAliasClass: '[class]', + TokenType.KeywordNTIPAliasFlag: '[flag]', + TokenType.KeywordNTIPAliasIDName: '[idname]', + TokenType.KeywordNTIPAliasMaxQuantity: '[maxquantity]', + TokenType.KeywordNTIPAliasName: '[name]', + TokenType.KeywordNTIPAliasQuality: '[quality]', + TokenType.KeywordNTIPAliasType: '[type]', + + TokenType.ValueNTIPAliasClass: '{}', + TokenType.ValueNTIPAliasClassID: '{}', + TokenType.ValueNTIPAliasFlag: '{}', + TokenType.ValueNTIPAliasIDName: '{}', + TokenType.ValueNTIPAliasQuality: '{}', + TokenType.ValueNTIPAliasStat: '{}', + TokenType.ValueNTIPAliasType: '{}', + } + + expression = '' + + # * Find NTIPAliasStat key by value. + def find_stat_by_value(wanted_value): + for key, value in NTIPAliasStat.items(): + if value == wanted_value: + return key + return None + + for token in tokens: + if token.type in token_to_value: + if token.type == TokenType.ValueNTIPAliasStat: + expression += token_to_value[token.type].format(f'[{find_stat_by_value(token.value)}]') + else: + expression += token_to_value[token.type].format(token.value) + expression += ' ' + return expression.strip() + + + + def _create_custom_digit_token(self, found_number, append_text="", append_front=False): + """ + Creates a custom token for a number that allows for custom text to be appended to the front or back of the found number. + """ + for _ in range(len(found_number)): + self._advance() + if append_text: + if append_front: + found_number = append_text + found_number + else: + found_number += append_text + + return Token(TokenType.NUMBER, float(found_number)) + + def _create_digits(self) -> Token: + found_decimal_number = re.match(r"^-*[0-9]+\.[0-9]+", self._get_current_iteration_of_text_raw()) + if found_decimal_number: + return self._create_custom_digit_token(found_decimal_number.group(0)) + + shorthand_decimal_number = re.match(r"^-*\.[0-9]+", self._get_current_iteration_of_text_raw()) + if shorthand_decimal_number: + return self._create_custom_digit_token(shorthand_decimal_number.group(0), "0", append_front=True) + + found_whole_number = re.match(r"^-*[0-9]+", self._get_current_iteration_of_text_raw()) + if found_whole_number: + return self._create_custom_digit_token(found_whole_number.group(0)) + if self.current_token: + return Token(TokenType.UNKNOWN, self.current_token) + else: + return Token(TokenType.UNKNOWN, "") + + + def _create_math_operator(self) -> Token: + symbol_map = { + '+': TokenType.PLUS, + '-': TokenType.MINUS, + '*': TokenType.MULTIPLY, + '/': TokenType.DIVIDE, + '\\': TokenType.MODULO, + '^': TokenType.POW, + "(": TokenType.LPAREN, + ")": TokenType.RPAREN + } + + symbol = self.current_token + + if symbol: + if symbol in symbol_map: + return Token(symbol_map[symbol], symbol) + return Token(TokenType.UNKNOWN, symbol) + return Token(TokenType.UNKNOWN, "") + def _create_keyword_lookup(self) -> Token: + """ + item data lookup i.e [name] + """ + lookup_key = "" + if self.text: + found_match = re.match(r"\[\w+\]|\[d+\]", self._get_current_iteration_of_text_raw()) # Finds the first match of [word] or [21234223892] (numbers :P) + if found_match: + found = found_match.group(0) + for char in found: + if char.isalnum(): # is alpha numeric + lookup_key += char + self._advance() + else: + raise BNipSyntaxError("BNIP_0x2", "Missing ] after keyword", self._get_text()) + if lookup_key: + if self.current_section == BNipSections.PROP: + match lookup_key: + case "name": + return Token(TokenType.KeywordNTIPAliasName, lookup_key) + case "flag": + return Token(TokenType.KeywordNTIPAliasFlag, lookup_key) + case "class": + return Token(TokenType.KeywordNTIPAliasClass, lookup_key) + case "quality": + return Token(TokenType.KeywordNTIPAliasQuality, lookup_key) + case "type": + return Token(TokenType.KeywordNTIPAliasType, lookup_key) + case "idname": + return Token(TokenType.KeywordNTIPAliasIDName, lookup_key) + case _: # ? This is default.. + if lookup_key in NTIPAliasClass: + return Token(TokenType.ValueNTIPAliasClass, NTIPAliasClass[lookup_key]) + elif lookup_key in NTIPAliasQuality: + return Token(TokenType.ValueNTIPAliasQuality, NTIPAliasQuality[lookup_key]) + elif lookup_key in NTIPAliasClassID: + return Token(TokenType.ValueNTIPAliasClassID, NTIPAliasClassID[lookup_key]) + elif lookup_key in NTIPAliasFlag: + return Token(TokenType.ValueNTIPAliasFlag, NTIPAliasFlag[lookup_key]) + elif lookup_key in NTIPAliasType: + return Token(TokenType.ValueNTIPAliasType, NTIPAliasType[lookup_key]) + Logger.warning(f"Unknown property lookup: \"{lookup_key}\" {''.join(self.text)} {self.current_section}") + + return Token(TokenType.UNKNOWN, lookup_key) + elif self.current_section == BNipSections.STAT: + if lookup_key in NTIPAliasStat: + return Token(TokenType.KeywordNTIPAliasStat, NTIPAliasStat[lookup_key]) + else: + # spell_check = "" + # for key in NTIPAliasStat: + # if levenshtein(lookup_key, key) < 3: + # spell_check = f", did you mean {key}?" + # raise BNipSyntaxError("BNIP_0x3", f"Unknown NTIPStat lookup: {lookup_key}{spell_check}", self._get_text()) + return Token(TokenType.UNKNOWN, lookup_key) + elif self.current_section == BNipSections.MAXQUANTITY: + pass + + return Token(TokenType.UNKNOWN, lookup_key) + + def _create_d2r_image_data_lookup(self) -> Token: + lookup_key = "" + + found_lookup_key = re.match(r"^(\w+)\s*", self._get_current_iteration_of_text_raw()) + # print(found_lookup_key, self._get_current_iteration_of_text_raw()) + if found_lookup_key: + found = found_lookup_key.group(1).replace("'", "\\'") # Replace ' with escaped \' + for _ in range(len(found)): + self._advance() + lookup_key = found + + if self.current_section == BNipSections.PROP: + # TODO: The second checks (i.e NTIPAliasClass and self.tokens[-2].type == TokenType.CLASS:) seem a little misplaced, possibly put them inside the validation function that is inside transpiler.py and throw a warning accordingly. + if len(self.tokens) >= 2: + if lookup_key in NTIPAliasClass and self.tokens[-2].type == TokenType.KeywordNTIPAliasClass: + return Token(TokenType.ValueNTIPAliasClass, lookup_key) + elif lookup_key in NTIPAliasQuality and self.tokens[-2].type == TokenType.KeywordNTIPAliasQuality: + return Token(TokenType.ValueNTIPAliasQuality, lookup_key) + elif lookup_key in NTIPAliasClassID and self.tokens[-2].type == TokenType.KeywordNTIPAliasName: + return Token(TokenType.ValueNTIPAliasClassID, lookup_key) + elif lookup_key in NTIPAliasFlag and self.tokens[-2].type == TokenType.KeywordNTIPAliasFlag: + return Token(TokenType.ValueNTIPAliasFlag, lookup_key) + elif lookup_key in NTIPAliasType and self.tokens[-2].type == TokenType.KeywordNTIPAliasType: + return Token(TokenType.ValueNTIPAliasType, lookup_key) + elif self.tokens[-2].type == TokenType.KeywordNTIPAliasIDName: + return Token(TokenType.ValueNTIPAliasIDName, lookup_key) + else: + raise BNipSyntaxError("BNIP_0x20", f"Bad token sequence: {self._get_text()}", self._get_text()) + return Token(TokenType.UNKNOWN, lookup_key) + elif self.current_section == BNipSections.STAT: + if lookup_key in NTIPAliasStat: + return Token(TokenType.ValueNTIPAliasStat, lookup_key) + else: + return Token(TokenType.UNKNOWN, lookup_key) + return Token(TokenType.UNKNOWN, lookup_key) + + def _create_logical_operator(self) -> Token: + char = self.current_token + logical_operator_map = { + ">": TokenType.GT, + "<": TokenType.LT, + + ">=": TokenType.GE, + "<=": TokenType.LE, + + "==": TokenType.EQ, + "!=": TokenType.NE, + + "&&": TokenType.AND, + "||": TokenType.OR, + + "#": TokenType.SECTIONAND + } + + pattern = r"(>=|<=|==|!=|&&|\|\||>|<|\#)" + + found = re.match(pattern, self._get_current_iteration_of_text_raw()) + if found: + found_text = found.group(1) + if logical_operator_map[found_text] == TokenType.SECTIONAND: + self._increment_section() + for _ in range(len(found_text)): + self._advance() + + pythonic_operator = found_text.replace("#", "and").replace("||", "or").replace("&&", "and") + return Token(logical_operator_map[found_text], pythonic_operator) + else: + raise BNipSyntaxError("BNIP_0x5", f"Invalid logical operator: '{char}'", self._get_text()) \ No newline at end of file diff --git a/src/bnip/tokens.py b/src/bnip/tokens.py new file mode 100644 index 000000000..9f6d19eb5 --- /dev/null +++ b/src/bnip/tokens.py @@ -0,0 +1,65 @@ +from enum import Enum, auto +from dataclasses import dataclass +from typing import Any + +class TokenType(Enum): + NUMBER = auto() + NUMBERPERCENT = auto() + PLUS = auto() + MINUS = auto() + MULTIPLY = auto() + DIVIDE = auto() + MODULO = auto() + POW = auto() + + LPAREN = auto() + RPAREN = auto() + + GT = auto() + LT = auto() + LE = auto() + GE = auto() + EQ = auto() + NE = auto() + AND = auto() + OR = auto() + + KeywordNTIPAliasClass = auto() + KeywordNTIPAliasFlag = auto() + KeywordNTIPAliasIDName = auto() + KeywordNTIPAliasName = auto() + KeywordNTIPAliasQuality = auto() + KeywordNTIPAliasType = auto() + KeywordNTIPAliasStat = auto() + KeywordNTIPAliasMaxQuantity = auto() + + ValueNTIPAliasClass = auto() + ValueNTIPAliasClassID = auto() + ValueNTIPAliasFlag = auto() + ValueNTIPAliasIDName = auto() + ValueNTIPAliasQuality = auto() + ValueNTIPAliasStat = auto() + ValueNTIPAliasType = auto() + + WHITESPACE = auto() + COMMENT = auto() + + SECTIONAND = auto() + + NOTIFICATION = auto() + + UNKNOWN = auto() + +@dataclass +class Token: + type: TokenType + value: str | int | float + + def __repr__(self) -> str: + return f"{self.type} : {self.value}" + + def data(self) -> dict: + return { + "type": self.type.name, + "value": self.value + } \ No newline at end of file diff --git a/src/bnip/transpile.py b/src/bnip/transpile.py new file mode 100644 index 000000000..56a596b8c --- /dev/null +++ b/src/bnip/transpile.py @@ -0,0 +1,452 @@ +from bnip.NTIPAliasQuality import NTIPAliasQuality +from bnip.NTIPAliasClass import NTIPAliasClass +from bnip.NTIPAliasClassID import NTIPAliasClassID +from bnip.NTIPAliasFlag import NTIPAliasFlag +from bnip.NTIPAliasStat import NTIPAliasStat +from bnip.NTIPAliasType import NTIPAliasType + +# ! The above imports are necessary, they are used within the eval statements. Your text editor probably is not showing them as not in use. + +from dataclasses import dataclass +from bnip.lexer import Lexer, BNipSections +from bnip.BNipExceptions import BNipSyntaxError +from bnip.tokens import Token, TokenType +from bnip.utils import find_unique_or_set_base + +@dataclass +class BNIPExpression: + raw: str + should_id_transpiled: str | None + transpiled: str + should_pickup: str | None + tokens: list[Token] + + +bnip_expressions: list[BNIPExpression] = [] + + +token_transpile_map = { + + TokenType.NUMBER: "{}", + # TokenType.NUMBERPERCENT: "int({})", + + # TokenType.KeywordNTIPAliasIDName: "str(item_data['NTIPAliasIdName']).lower()", # * Special case + TokenType.KeywordNTIPAliasName: "int(item_data['NTIPAliasClassID'])", # * [name] (NTIPAliasName) is an alias for NTIPAliasClassID + TokenType.KeywordNTIPAliasClass: "int(item_data['NTIPAliasClass'])", # * This is not ClassID, but Class which refers to normal, expectational, elte + TokenType.KeywordNTIPAliasQuality: "int(item_data['NTIPAliasQuality'])", + # TokenType.KeywordNTIPAliasType: "int(item_data['NTIPAliasType'])", # * Special case + # TokenType.KeywordNTIPAliasFlag: "int(item_data['NTIPAliasFlag'])", # * Special case + + # TokenType.ValueNTIPAliasFlag: "NTIPAliasFlag['{}']", # * Special case + TokenType.ValueNTIPAliasType: "int(NTIPAliasType['{}'])", + TokenType.ValueNTIPAliasClass: "int(NTIPAliasClass['{}'])", + TokenType.ValueNTIPAliasQuality: "int(NTIPAliasQuality['{}'])", + TokenType.ValueNTIPAliasClassID: "int(NTIPAliasClassID['{}'])", + # TokenType.ValueNTIPAliasIDName : "str(NTIPAliasIDName['{}']).lower()", # * Special case +} + +def transpile(tokens: list[Token], isPickUpPhase: bool = False, transpiled_expressions: str = ""): + """ + Transpiles the tokens into python code, some of the code that gets transpiled is dependent if we are in the pickup phase or not + """ + + + expression = "" + section_start = True + section_open_paranthesis_count = 0 + + # print("tokens", tokens) + # print("detokenize", Lexer().detokenize(tokens)) + + for i, token in enumerate(tokens): + if token == None: continue + token_value = str(token.value) + if section_start: + expression += "(" + section_start = False + section_open_paranthesis_count += 1 + if token.type in token_transpile_map: + expression += f"({token_transpile_map[token.type].format(token_value)})" + continue + match token.type: + case TokenType.NE | TokenType.GT | TokenType.LT | TokenType.GE | TokenType.LE: + if tokens[i + 1].type != TokenType.ValueNTIPAliasFlag: + expression += token_value + case TokenType.EQ: + if tokens[i + 1].type == TokenType.ValueNTIPAliasFlag: + continue + if isPickUpPhase and tokens[i + 1].type == TokenType.ValueNTIPAliasIDName: + continue + expression += "==" + case TokenType.OR | TokenType.AND | TokenType.LPAREN | TokenType.RPAREN | TokenType.PLUS | TokenType.MINUS | TokenType.MULTIPLY | TokenType.DIVIDE: + expression += token_value + if token.type == TokenType.LPAREN: + section_open_paranthesis_count += 1 + elif token.type == TokenType.RPAREN: + section_open_paranthesis_count -= 1 + case TokenType.SECTIONAND: + expression += ")" + section_open_paranthesis_count -= 1 + expression += "and" + section_start = True + case TokenType.KeywordNTIPAliasStat: + expression += "(int(item_data.get('NTIPAliasStat', {})" + f".get('{token_value}', 0)))" + case TokenType.KeywordNTIPAliasIDName: + if not isPickUpPhase: + expression += "(str(item_data['NTIPAliasIdName']).lower())" + case TokenType.KeywordNTIPAliasFlag: + if tokens[i + 2].type == TokenType.ValueNTIPAliasFlag: # * Get the token after the operator + condition_type = tokens[i + 1] # * Get the operator + flag = NTIPAliasFlag[tokens[i + 2].value] # * I.E if the input is ethereal, flag would be equal to "0x400000" (which is a string) + match condition_type.type: + case TokenType.EQ: + expression += f"(item_data['NTIPAliasFlag']['{flag}'])" + case TokenType.NE: + expression += f"(not item_data['NTIPAliasFlag']['{flag}'])" + case TokenType.ValueNTIPAliasIDName: + if tokens[i - 2].type == TokenType.KeywordNTIPAliasIDName: + if isPickUpPhase: + base, quality = find_unique_or_set_base(token_value) + expression += f"(int(item_data['NTIPAliasClassID']))==(int(NTIPAliasClassID['{base}']))and(int(item_data['NTIPAliasQuality']))==(int(NTIPAliasQuality['{quality}']))" + else: + expression += f"(str('{token_value}').lower())" + else: + expression += "(0)" + case TokenType.KeywordNTIPAliasType: + token_after_operator = tokens[i + 2] + # * The below code uses short-circuit evaluation + expression += f"(int(NTIPAliasType['{token_after_operator.value}']) in item_data['NTIPAliasType'] and int(NTIPAliasType['{token_after_operator.value}']) or -1)" + case TokenType.UNKNOWN: # * _ is default.. + expression += "(0)" + + for _ in range(section_open_paranthesis_count): # * This is needed to close the last section + expression += ")" + return expression + + +def validate_correct_math_syntax(left_token=None, right_token=None): + """Makes sure that there are no invalid math operations going on inside the expression""" + allowed_left_and_right_tokens = [ + TokenType.KeywordNTIPAliasClass, + TokenType.KeywordNTIPAliasFlag, + TokenType.KeywordNTIPAliasMaxQuantity, + TokenType.KeywordNTIPAliasName, + TokenType.KeywordNTIPAliasQuality, + TokenType.KeywordNTIPAliasType, + TokenType.KeywordNTIPAliasStat, + + TokenType.ValueNTIPAliasClass, + TokenType.ValueNTIPAliasClassID, + TokenType.ValueNTIPAliasFlag, + TokenType.ValueNTIPAliasQuality, + TokenType.ValueNTIPAliasStat, + TokenType.ValueNTIPAliasType, + + TokenType.NUMBER, + + TokenType.LPAREN, + TokenType.RPAREN, + ] + if left_token and left_token.type not in allowed_left_and_right_tokens: + raise BNipSyntaxError2("BNIP_0x3", "unexpected token on left of math operator") + if right_token and right_token.type not in allowed_left_and_right_tokens: + raise BNipSyntaxError2("BNIP_0x4", "unexpected token on right of math operator") + +OPENING_PARENTHESIS_COUNT = 0 # * This needs to be reset every time an validation error occurs +CURRENT_EXPRESSION = "" +def BNipSyntaxError2(error_code, error_message): # * "hook" the error constructor so every time the error is raised / called, we reset the opening parenthesis count + global OPENING_PARENTHESIS_COUNT + OPENING_PARENTHESIS_COUNT = 0 + print(CURRENT_EXPRESSION) + return BNipSyntaxError(error_code, error_message, CURRENT_EXPRESSION) + + +def validate_correct_parenthesis_syntax(current_pos, all_tokens, left_token=None, right_token=None): + """Makes sure that every parenthesis is closed and that there are no unclosed parenthesis.""" + + + allowed_left_and_right_tokens = [ + TokenType.PLUS, + TokenType.MINUS, + TokenType.MULTIPLY, + TokenType.DIVIDE, + TokenType.EQ, + TokenType.NE, + TokenType.GT, + TokenType.LT, + TokenType.GE, + TokenType.LE, + TokenType.OR, + TokenType.AND, + TokenType.SECTIONAND, + TokenType.NOTIFICATION + ] + + global OPENING_PARENTHESIS_COUNT + token = all_tokens[current_pos] + if token.type == TokenType.LPAREN: + OPENING_PARENTHESIS_COUNT += 1 + if left_token and left_token.type not in allowed_left_and_right_tokens + [TokenType.LPAREN]: + raise BNipSyntaxError2("BNIP_0x18", "unexpected token on left of parenthesis") + elif token.type == TokenType.RPAREN: + if right_token and right_token.type not in allowed_left_and_right_tokens + [TokenType.RPAREN]: + raise BNipSyntaxError2("BNIP_0x19", "unexpected token on right of parenthesis") + OPENING_PARENTHESIS_COUNT -= 1 + + + + + # TODO Backtrace until the last opening to make sure it wasn't from the past section. + # for i in range(current_pos, -1, -1): + # # print(all_tokens[i].type) + # if all_tokens[i].type == TokenType.SECTIONAND: + # raise BNipSyntaxError2("BNIP_0x8", "parenthesis cannot cross the section and (#)") + + if current_pos == len(all_tokens) - 1: + if OPENING_PARENTHESIS_COUNT != 0: + if OPENING_PARENTHESIS_COUNT > 0: + OPENING_PARENTHESIS_COUNT = 0 + raise BNipSyntaxError2("BNIP_0x6", "unclosed parenthesis") + else: + OPENING_PARENTHESIS_COUNT = 0 + raise BNipSyntaxError2("BNIP_0x7", "unopened parenthesis") + OPENING_PARENTHESIS_COUNT = 0 + +def validate_digits_syntax(left=None, right=None): + """Makes sure that the left and right tokens are valid to be next to a digit.""" + allowed_left_and_right_tokens = [ + TokenType.PLUS, + TokenType.MINUS, + TokenType.MULTIPLY, + TokenType.DIVIDE, + TokenType.MODULO, + TokenType.POW, + + TokenType.AND, + TokenType.OR, + TokenType.EQ, + TokenType.NE, + TokenType.GT, + TokenType.LT, + TokenType.GE, + TokenType.LE, + + TokenType.SECTIONAND, + + TokenType.LPAREN, + TokenType.RPAREN, + + ] + + if left: + if left.type not in allowed_left_and_right_tokens: + raise BNipSyntaxError2("BNIP_0x8", "Expected operator on left of number") + if right: + if right.type not in allowed_left_and_right_tokens: + raise BNipSyntaxError2("BNIP_0x9", "Expected operator on right of number") + + +def validate_logical_operators(left=None, right=None): + """Makes sure that the logical operators are used correctly.""" + allowed_left_and_right_tokens = [ + TokenType.NUMBER, + + TokenType.ValueNTIPAliasClass, + TokenType.ValueNTIPAliasClassID, + TokenType.ValueNTIPAliasFlag, + TokenType.ValueNTIPAliasType, + TokenType.ValueNTIPAliasQuality, + TokenType.ValueNTIPAliasStat, + TokenType.ValueNTIPAliasIDName, + + TokenType.KeywordNTIPAliasClass, + TokenType.KeywordNTIPAliasFlag, + TokenType.KeywordNTIPAliasType, + TokenType.KeywordNTIPAliasQuality, + TokenType.KeywordNTIPAliasName, + TokenType.KeywordNTIPAliasIDName, + TokenType.KeywordNTIPAliasMaxQuantity, + TokenType.KeywordNTIPAliasStat + ] + + if left: + if left.type not in allowed_left_and_right_tokens + [TokenType.RPAREN]: + raise BNipSyntaxError2("BNIP_0x10", "Expected token on left of logical operator") + if right: + if right.type not in allowed_left_and_right_tokens + [TokenType.LPAREN]: + raise BNipSyntaxError2("BNIP_0x11", "Expected token on right of logical operator") + else: + raise BNipSyntaxError2("BNIP_0x12", "Expected token on right of logical operator") + + +def validate_bnip_expression_syntax(bnip_expression): # * enforces that {property} # {stats} # {maxquantity} + tokens = None + global CURRENT_EXPRESSION + if not bnip_expression: + return + + all_tokens = [] + CURRENT_EXPRESSION = bnip_expression + + split_bnip_expression = bnip_expression.split("#") + split_bnip_expression_len = len(split_bnip_expression) + if split_bnip_expression_len >= 1: # property + tokens = Lexer().create_tokens(split_bnip_expression[0], BNipSections.PROP) + all_tokens.extend(tokens) + for token in tokens: + if token.type == TokenType.ValueNTIPAliasStat or token.type == TokenType.UNKNOWN: + raise BNipSyntaxError2("BNIP_0x13", f"Invalid token '{token.value}' in property section") + if split_bnip_expression_len >= 2: # stats + all_tokens.append(Token(TokenType.SECTIONAND, "#")) + tokens = Lexer().create_tokens(split_bnip_expression[1], BNipSections.STAT) + all_tokens.extend(tokens) + for token in tokens: + is_invalid_stat_lookup = ( + token.type == TokenType.ValueNTIPAliasClass or + token.type == TokenType.ValueNTIPAliasClassID and token.value != '523' or # 523 refers to gold + token.type == TokenType.ValueNTIPAliasFlag or + token.type == TokenType.ValueNTIPAliasType or + token.type == TokenType.ValueNTIPAliasQuality or + token.type == TokenType.UNKNOWN + ) + + if is_invalid_stat_lookup: + raise BNipSyntaxError2("BNIP_0x14", f"Invalid token '{token.value}' in stats section") + + if split_bnip_expression_len >= 3: # maxquantity + # all_tokens.append(Token(TokenType.SECTIONAND, "#")) + tokens = Lexer().create_tokens(split_bnip_expression[2], BNipSections.MAXQUANTITY) + all_tokens.extend(tokens) + for token in tokens: + is_invalid_maxquantity_lookup = ( + token.type == TokenType.ValueNTIPAliasClass or + token.type == TokenType.ValueNTIPAliasQuality or + token.type == TokenType.ValueNTIPAliasClassID or + token.type == TokenType.ValueNTIPAliasFlag or + token.type == TokenType.ValueNTIPAliasType or + token.type == TokenType.ValueNTIPAliasStat or + token.type == TokenType.UNKNOWN + ) + + if is_invalid_maxquantity_lookup: + pass + raise BNipSyntaxError2("BNIP_0x15", "Invalid maxquantity lookup") + + # * Further syntax validation + # print(all_tokens) + if all_tokens[-1].type == TokenType.SECTIONAND: + raise BNipSyntaxError2("BNIP_0x16", "unexpected sectionand (#) at end of expression") + math_tokens = [TokenType.MULTIPLY, TokenType.PLUS, TokenType.MINUS, TokenType.DIVIDE, TokenType.MODULO, TokenType.POW] + logical_tokens = [TokenType.AND, TokenType.OR, TokenType.EQ, TokenType.NE, TokenType.GT, TokenType.LT, TokenType.GE, TokenType.LE, TokenType.SECTIONAND] + for i, token in enumerate(all_tokens): + # Get the left and right tokens for the current token + left = None + right = None + if i > 0: + left = all_tokens[i-1] + if i < len(all_tokens)-1: + right = all_tokens[i+1] + + if token.type == TokenType.EQ: + if i == len(all_tokens) - 1: # * Check to make sure the next token is a token. + # ! the logic only makes sense for the last token, what the f*ck + raise BNipSyntaxError2("BNIP_0x17", "No value after equal sign") + elif token.type in math_tokens: + validate_correct_math_syntax(left_token=left, right_token=right) + # * Make sure two numbers aren't next to each other. + elif token.type == TokenType.NUMBER or token.type == TokenType.UNKNOWN: + validate_digits_syntax(left=left, right=right) + + if token.type in logical_tokens: + validate_logical_operators(left=left, right=right) + + if token.type == TokenType.LPAREN or token.type == TokenType.RPAREN or i == len(all_tokens) - 1: # * Also check the last token no matter what so if there is an opening parenthesis without a closing parenthesis it will raise an error + validate_correct_parenthesis_syntax(i, all_tokens, left_token=left, right_token=right) + return True + + +def remove_quantity(expression): # ! This is a bit ghetto, but since we're not using the maxquantity, we can just remove it. # + # TODO FIX THIS SHIT + split_expression = expression.split("#") + if len(split_expression) == 3: + split_expression = (split_expression[0] + "#" + split_expression[1]).split("#") + if len(split_expression[1]) <= 1: + return split_expression[0] + else: + return "#".join(split_expression) + return expression + + +def get_section_from_tokens(all_tokens: list[Token], section: BNipSections | None = None) -> dict[BNipSections, list[Token]]: + tokens_split_by_section = [] + temp_section = [] + + for i, token in enumerate(all_tokens): + if token.type == TokenType.SECTIONAND: + tokens_split_by_section.append(temp_section) + temp_section = [] + elif i == len(all_tokens) - 1: + temp_section.append(token) + tokens_split_by_section.append(temp_section) + temp_section = [] + else: + temp_section.append(token) + section_tokens_len = len(tokens_split_by_section) + + bnip_map = { + BNipSections.PROP: tokens_split_by_section[0] if section_tokens_len >= 1 else [], + BNipSections.STAT: tokens_split_by_section[1] if section_tokens_len >= 2 else [], + BNipSections.MAXQUANTITY: tokens_split_by_section[2] if section_tokens_len >= 3 else [] + } + + return bnip_map + + +def prepare_bnip_expression(expression: str) -> str: + if not expression.startswith("//") and not expression.startswith("-"): + expression = expression.lower() + expression = expression.replace("'", "") + expression = expression.split("//")[0] # * Ignore the comments inside the nip expression + expression = remove_quantity(expression) + if validate_bnip_expression_syntax(expression): + return expression + return '' + + +def transpile_bnip_expression(expression: str | list[Token], isPickUpPhase=False): + if isinstance(expression, str): + expression = prepare_bnip_expression(expression) + if expression: + tokens = Lexer().create_tokens(expression) + transpiled_expression = transpile(tokens, isPickUpPhase=isPickUpPhase) + if transpiled_expression: + return transpiled_expression + elif isinstance(expression, list): + transpiled_expression = transpile(expression, isPickUpPhase=isPickUpPhase) + if transpiled_expression: + return transpiled_expression + +def generate_expression_object(bnip_expression: str) -> BNIPExpression | None: + bnip_expression = prepare_bnip_expression(bnip_expression) + + if bnip_expression: + tokens = Lexer().create_tokens(bnip_expression) + if transpiled_expression := transpile_bnip_expression(tokens): + split_tokens = get_section_from_tokens(tokens) + expression_obj = BNIPExpression( + raw=bnip_expression, + tokens=tokens, + transpiled=transpiled_expression, + should_id_transpiled=transpile_bnip_expression(split_tokens[BNipSections.PROP]), + should_pickup=transpile_bnip_expression(split_tokens[BNipSections.PROP], isPickUpPhase=True) # * Some stuff gets transpiled differently in the pickup phase + ) + return expression_obj + return None + + +def load_bnip_expression(bnip_expression: str): + if (expression_obj := generate_expression_object(bnip_expression)) is not None: + bnip_expressions.append(expression_obj) + + + \ No newline at end of file diff --git a/src/bnip/utils.py b/src/bnip/utils.py new file mode 100644 index 000000000..489376d67 --- /dev/null +++ b/src/bnip/utils.py @@ -0,0 +1,17 @@ +from bnip.UniqueAndSetData import UniqueAndSetData + + +def find_unique_or_set_base(unique_or_set_name) -> tuple[str, str]: + unique_or_set_name = unique_or_set_name.lower() + for key in UniqueAndSetData: + if UniqueAndSetData[key].get("uniques"): + for uniques in UniqueAndSetData[key]["uniques"]: + for unique in uniques: + if unique.lower() == unique_or_set_name: + return key, "unique" + if UniqueAndSetData[key].get("sets"): + for sets in UniqueAndSetData[key]["sets"]: + for set in sets: + if set.lower() == unique_or_set_name: + return key, "set" + return "","" \ No newline at end of file diff --git a/src/bot.py b/src/bot.py index 8b90823ca..01f8ee969 100644 --- a/src/bot.py +++ b/src/bot.py @@ -7,79 +7,79 @@ import cv2 import math from copy import copy -from typing import Union from collections import OrderedDict + from health_manager import set_pause_state from transmute import Transmute from utils.misc import wait, hms - +from utils.restart import safe_exit, restart_game from game_stats import GameStats from logger import Logger from config import Config from screen import grab -from template_finder import TemplateFinder +import template_finder from char import IChar -from item import ItemFinder from item.pickit import PickIt +from item import consumables from pather import Pather, Location from char.sorceress import LightSorc, BlizzSorc, NovaSorc,HydraSorc from char.trapsin import Trapsin -from char.hammerdin import Hammerdin +from char.paladin.hammerdin import Hammerdin +from char.paladin import FoHdin from char.barbarian import Barbarian from char.necro import Necro from char.poison_necro import Poison_Necro from char.bone_necro import Bone_Necro from char.basic import Basic from char.basic_ranged import Basic_Ranged -from ui_manager import wait_until_hidden, wait_until_visible, ScreenObjects, is_visible +from ui_manager import wait_until_hidden, wait_until_visible, ScreenObjects, is_visible, detect_screen_object from ui import meters, skills, view, character_select, main_menu -from inventory import personal, vendor, belt, common, consumables +from inventory import personal, vendor, belt, common from run import Pindle, ShenkEld, Trav, Nihlathak, Arcane, Diablo from town import TownManager, A1, A2, A3, A4, A5, town_manager -# Added for dclone ip hunt from messages import Messenger -from utils.dclone_ip import get_d2r_game_ip class Bot: - _MAIN_MENU_MARKERS = ["MAIN_MENU_TOP_LEFT","MAIN_MENU_TOP_LEFT_DARK"] def __init__(self, game_stats: GameStats): self._game_stats = game_stats self._messenger = Messenger() - self._item_finder = ItemFinder() self._pather = Pather() - self._pickit = PickIt(self._item_finder) + self._pickit = PickIt() # Create Character - if Config().char["type"] in ["sorceress", "light_sorc"]: - self._char: IChar = LightSorc(Config().light_sorc, self._pather) - elif Config().char["type"] == "blizz_sorc": - self._char: IChar = BlizzSorc(Config().blizz_sorc, self._pather) - elif Config().char["type"] == "nova_sorc": - self._char: IChar = NovaSorc(Config().nova_sorc, self._pather) - elif Config().char["type"] == "hydra_sorc": - self._char: IChar = HydraSorc(Config().hydra_sorc, self._pather) - elif Config().char["type"] == "hammerdin": - self._char: IChar = Hammerdin(Config().hammerdin, self._pather, self._pickit) #pickit added for diablo - elif Config().char["type"] == "trapsin": - self._char: IChar = Trapsin(Config().trapsin, self._pather) - elif Config().char["type"] == "barbarian": - self._char: IChar = Barbarian(Config().barbarian, self._pather) - elif Config().char["type"] == "poison_necro": - self._char: IChar = Poison_Necro(Config().poison_necro, self._pather) - elif Config().char["type"] == "bone_necro": - self._char: IChar = Bone_Necro(Config().bone_necro, self._pather) - elif Config().char["type"] == "necro": - self._char: IChar = Necro(Config().necro, self._pather) - elif Config().char["type"] == "basic": - self._char: IChar = Basic(Config().basic, self._pather) - elif Config().char["type"] == "basic_ranged": - self._char: IChar = Basic_Ranged(Config().basic_ranged, self._pather) - else: - Logger.error(f'{Config().char["type"]} is not supported! Closing down bot.') - os._exit(1) + match Config().char["type"]: + case "sorceress" | "light_sorc": + self._char: IChar = LightSorc(Config().light_sorc, self._pather) + case "blizz_sorc": + self._char: IChar = BlizzSorc(Config().blizz_sorc, self._pather) + case "nova_sorc": + self._char: IChar = NovaSorc(Config().nova_sorc, self._pather) + case "hydra_sorc": + self._char: IChar = HydraSorc(Config().hydra_sorc, self._pather) + case "hammerdin" | "paladin": + self._char: IChar = Hammerdin(Config().hammerdin, self._pather, self._pickit) #pickit added for diablo + case "fohdin": + self._char: IChar = FoHdin(Config().fohdin, self._pather, self._pickit) #pickit added for diablo + case "trapsin": + self._char: IChar = Trapsin(Config().trapsin, self._pather) + case "barbarian": + self._char: IChar = Barbarian(Config().barbarian, self._pather) + case "poison_necro": + self._char: IChar = Poison_Necro(Config().poison_necro, self._pather) + case "bone_necro": + self._char: IChar = Bone_Necro(Config().bone_necro, self._pather) + case "necro": + self._char: IChar = Necro(Config().necro, self._pather) + case "basic": + self._char: IChar = Basic(Config().basic, self._pather) + case "basic_ranged": + self._char: IChar = Basic_Ranged(Config().basic_ranged, self._pather) + case _: + Logger.error(f'{Config().char["type"]} is not supported! Closing down bot.') + os._exit(1) # Create Town Manager a5 = A5(self._pather, self._char) @@ -100,20 +100,22 @@ def __init__(self, game_stats: GameStats): } # Adapt order to the config self._do_runs = OrderedDict((k, self._do_runs[k]) for k in Config().routes_order if k in self._do_runs and self._do_runs[k]) + + runs = list(self._do_runs.keys()) self._do_runs_reset = copy(self._do_runs) Logger.info(f"Doing runs: {self._do_runs_reset.keys()}") if Config().general["randomize_runs"]: self.shuffle_runs() - self._pindle = Pindle(self._pather, self._town_manager, self._char, self._pickit) - self._shenk = ShenkEld(self._pather, self._town_manager, self._char, self._pickit) - self._trav = Trav(self._pather, self._town_manager, self._char, self._pickit) - self._nihlathak = Nihlathak(self._pather, self._town_manager, self._char, self._pickit) - self._arcane = Arcane(self._pather, self._town_manager, self._char, self._pickit) - self._diablo = Diablo(self._pather, self._town_manager, self._char, self._pickit) + self._pindle = Pindle(self._pather, self._town_manager, self._char, self._pickit, runs) + self._shenk = ShenkEld(self._pather, self._town_manager, self._char, self._pickit, runs) + self._trav = Trav(self._pather, self._town_manager, self._char, self._pickit, runs) + self._nihlathak = Nihlathak(self._pather, self._town_manager, self._char, self._pickit, runs) + self._arcane = Arcane(self._pather, self._town_manager, self._char, self._pickit, runs) + self._diablo = Diablo(self._pather, self._town_manager, self._char, self._pickit, runs) # Create member variables self._picked_up_items = False - self._curr_loc: Union[bool, Location] = None + self._curr_loc: bool | Location = None self._use_id_tome = True self._use_keys = True self._pre_buffed = False @@ -180,6 +182,17 @@ def trigger_or_stop(self, name: str, **kwargs): if not self._stopping: self.trigger(name, **kwargs) + def restart_or_exit(self, message: str =""): + if message: + Logger.error(message) + if Config().general["restart_d2r_when_stuck"]: + Logger.info("Restart botty") + restart_game(Config().general["d2r_path"], Config().advanced_options["launch_options"]) + self.stop() + else: + Logger.info("Shut down botty") + safe_exit() + def current_game_length(self): return self._game_stats.get_current_game_length() @@ -207,20 +220,28 @@ def on_init(self): self._game_stats.log_start_game() keyboard.release(Config().char["stand_still"]) transition_to_screens = Bot._rebuild_as_asset_to_trigger({ - "select_character": Bot._MAIN_MENU_MARKERS, + "select_character": main_menu.MAIN_MENU_MARKERS, "start_from_town": town_manager.TOWN_MARKERS, }) - match = TemplateFinder().search_and_wait(list(transition_to_screens.keys()), best_match=True) - self.trigger_or_stop(transition_to_screens[match.name]) + if (match := template_finder.search_and_wait(list(transition_to_screens.keys()), best_match=True)).valid: + self.trigger_or_stop(transition_to_screens[match.name]) + else: + self.restart_or_exit(f"Failed to detect {list(transition_to_screens.keys())}.") def on_select_character(self): - if Config().general['restart_d2r_when_stuck']: - # Make sure the correct char is selected - if character_select.has_char_template_saved(): - character_select.select_char() - else: - character_select.save_char_online_status() - character_select.save_char_template() + # Make sure the correct char is selected + if not character_select.has_char_template_saved(): + character_select.save_char_online_status() + character_select.save_char_template() + else: + if not character_select.select_char(): + if Config().general["info_screenshots"]: + timestamp = time.strftime("%Y%m%d_%H%M%S") + cv2.imwrite("./log/screenshots/info/info_failed_character_select_" + timestamp + ".png", grab()) + if character_select.has_char_template_saved(): + saved_char_img = character_select.get_saved_char_template() + cv2.imwrite("./log/screenshots/info/info_failed_character_select_saved_template_" + timestamp + ".png", saved_char_img) + self.restart_or_exit(f"Character select failed.") self.trigger_or_stop("create_game") def on_create_game(self): @@ -230,7 +251,8 @@ def on_create_game(self): keyboard.send("esc") main_menu.start_game() view.move_to_corpse() - else: return + else: + self.restart_or_exit() self.trigger_or_stop("start_from_town") def on_start_from_town(self): @@ -244,25 +266,12 @@ def on_start_from_town(self): belt.fill_up_belt_from_inventory(Config().char["num_loot_columns"]) self._char.discover_capabilities() if corpse_present and self._char.capabilities.can_teleport_with_charges and not self._char.select_tp(): - keybind = self._char._skill_hotkeys["teleport"] + keybind = Config().char["teleport"] Logger.info(f"Teleport keybind is lost upon death. Rebinding teleport to '{keybind}'") - self._char.remap_right_skill_hotkey("TELE_ACTIVE", self._char._skill_hotkeys["teleport"]) - - # Check for the current game ip and pause if we are able to obtain the hot ip - if Config().dclone["region_ips"] != "" and Config().dclone["dclone_hotip"] != "": - cur_game_ip = get_d2r_game_ip() - hot_ip = Config().dclone["dclone_hotip"] - Logger.debug(f"Current Game IP: {cur_game_ip} and HOTIP: {hot_ip}") - if hot_ip == cur_game_ip: - self._messenger.send_message(f"Dclone IP Found on IP: {cur_game_ip}") - print("Press Enter") - input() - os._exit(1) - else: - Logger.info(f"Please Enter the region ip and hot ip on config to use") + self._char.remap_right_skill_hotkey("TELE_ACTIVE", Config().char["teleport"]) # Run /nopickup command to avoid picking up stuff on accident - if not self._ran_no_pickup and not self._game_stats._nopickup_active: + if Config().char["enable_no_pickup"] and (not self._ran_no_pickup and not self._game_stats._nopickup_active): self._ran_no_pickup = True if view.enable_no_pickup(): self._game_stats._nopickup_active = True @@ -297,17 +306,17 @@ def on_maintenance(self): self._use_id_tome = common.tome_state(img, 'id')[0] is not None self._use_keys = is_visible(ScreenObjects.Key, img) if (self._game_stats._run_counter - 1) % 4 == 0 or self._previous_run_failed: - consumables.update_tome_key_needs(img, item_type = 'tp') + personal.update_tome_key_needs(img, item_type = 'tp') if self._use_id_tome: - consumables.update_tome_key_needs(img, item_type = 'id') + personal.update_tome_key_needs(img, item_type = 'id') if self._use_keys: # if keys run out then refilling will be unreliable :( - self._use_keys = consumables.update_tome_key_needs(img, item_type = 'key') + self._use_keys = personal.update_tome_key_needs(img, item_type = 'key') # Check inventory items if personal.inventory_has_items(img): Logger.debug("Inspecting inventory items") - items = personal.inspect_items(img, close_window=False, game_stats=self._game_stats) - common.close() + items = personal.inspect_items(img, game_stats=self._game_stats, close_window=False) + common.close() Logger.debug(f"Needs: {consumables.get_needs()}") if items: # if there are still items that need identifying, go to cain to identify them @@ -320,6 +329,7 @@ def on_maintenance(self): items = personal.inspect_items(game_stats=self._game_stats) keep_items = any([item.keep for item in items]) if items else None sell_items = any([item.sell for item in items]) if items else None + stash_gold = personal.get_inventory_gold_full() # Check if should need some healing img = grab() @@ -344,9 +354,10 @@ def on_maintenance(self): return self.trigger_or_stop("end_game", failed=True) # Stash stuff - if keep_items or personal.get_inventory_gold_full(): + if keep_items or stash_gold: Logger.info("Stashing items") self._curr_loc, result_items = self._town_manager.stash(self._curr_loc, items=items) + sell_items = any([item.sell for item in result_items]) if result_items else None Logger.info("Running transmutes") self._transmute.run_transmutes(force=False) common.close() @@ -405,7 +416,7 @@ def on_maintenance(self): def on_end_game(self, failed: bool = False): if Config().general["info_screenshots"] and failed: - cv2.imwrite("./info_screenshots/info_failed_game_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + cv2.imwrite("./log/screenshots/info/info_failed_game_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) self._curr_loc = False self._pre_buffed = False view.save_and_exit() @@ -419,7 +430,8 @@ def on_end_game(self, failed: bool = False): if elapsed_time > (Config().general["max_runtime_before_break_m"]*60): break_msg = f'Ran for {hms(elapsed_time)}, taking a break for {hms(Config().general["break_length_m"]*60)}.' Logger.info(break_msg) - self._messenger.send_message(break_msg) + if self._messenger.enabled: + self._messenger.send_message(break_msg) if not self._pausing: self.toggle_pause() @@ -427,7 +439,8 @@ def on_end_game(self, failed: bool = False): break_msg = f'Break over, will now run for {hms(Config().general["max_runtime_before_break_m"]*60)}.' Logger.info(break_msg) - self._messenger.send_message(break_msg) + if self._messenger.enabled: + self._messenger.send_message(break_msg) if self._pausing: self.toggle_pause() @@ -455,7 +468,7 @@ def on_end_run(self): # All the runs go here # ================================== - def _ending_run_helper(self, res: Union[bool, tuple[Location, bool]]): + def _ending_run_helper(self, res: bool | tuple[Location, bool]): self._game_stats._run_counter += 1 self._game_stats.log_exp() # either fill member variables with result data or mark run as failed @@ -528,4 +541,4 @@ def on_run_diablo(self): if self._curr_loc: set_pause_state(False) res = self._diablo.battle(not self._pre_buffed) - self._ending_run_helper(res) + self._ending_run_helper(res) \ No newline at end of file diff --git a/src/char/barbarian.py b/src/char/barbarian.py index 954d5b6d5..50f3f0332 100644 --- a/src/char/barbarian.py +++ b/src/char/barbarian.py @@ -2,7 +2,7 @@ from ui import skills from utils.custom_mouse import mouse from char import IChar, CharacterCapabilities -from template_finder import TemplateFinder +import template_finder from pather import Pather from logger import Logger from screen import convert_abs_to_monitor diff --git a/src/char/basic.py b/src/char/basic.py index 792d843c7..6703094f9 100644 --- a/src/char/basic.py +++ b/src/char/basic.py @@ -2,7 +2,7 @@ from ui import skills from utils.custom_mouse import mouse from char import IChar,CharacterCapabilities -from template_finder import TemplateFinder +import template_finder from pather import Pather from logger import Logger from screen import convert_abs_to_monitor diff --git a/src/char/basic_ranged.py b/src/char/basic_ranged.py index 2f7bfaee4..50215ad5f 100644 --- a/src/char/basic_ranged.py +++ b/src/char/basic_ranged.py @@ -2,7 +2,7 @@ from ui import skills from utils.custom_mouse import mouse from char import IChar -from template_finder import TemplateFinder +import template_finder from pather import Pather from logger import Logger from screen import convert_abs_to_monitor, convert_screen_to_abs, grab @@ -192,7 +192,7 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: if __name__ == "__main__": import os import keyboard - from template_finder import TemplateFinder + import template_finder from pather import Pather keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) keyboard.wait("f11") diff --git a/src/char/bone_necro.py b/src/char/bone_necro.py index 4586bc36d..b45f97b0e 100644 --- a/src/char/bone_necro.py +++ b/src/char/bone_necro.py @@ -1,20 +1,20 @@ import keyboard from utils.custom_mouse import mouse from char import IChar -from template_finder import TemplateFinder +import template_finder from pather import Pather from logger import Logger from screen import grab, convert_abs_to_monitor, convert_screen_to_abs from config import Config from utils.misc import wait, rotate_vec, unit_vector import random -from typing import Tuple from pather import Location, Pather import screen as screen import numpy as np import time import os from ui_manager import ScreenObjects +from ui_manager import get_closest_non_hud_pixel class Bone_Necro(IChar): def __init__(self, skill_hotkeys: dict, pather: Pather): @@ -23,13 +23,13 @@ def __init__(self, skill_hotkeys: dict, pather: Pather): self._pather = pather if "damage_scaling" in Config().bone_necro: self.damage_scaling = float(Config().bone_necro["damage_scaling"]) - + def move_to(self, x, y): pos_m = convert_abs_to_monitor((x, y)) self.pre_move() self.move(pos_m, force_move=True) - - def bone_wall(self, cast_pos_abs: Tuple[float, float], spray: int): + + def bone_wall(self, cast_pos_abs: tuple[float, float], spray: int): if not self._skill_hotkeys["bone_wall"]: raise ValueError("You did not set bone_wall hotkey!") keyboard.send(Config().char["stand_still"], do_release=False) @@ -42,7 +42,7 @@ def bone_wall(self, cast_pos_abs: Tuple[float, float], spray: int): mouse.press(button="right") wait(self._cast_duration+.04, self._cast_duration+.08) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(Config().char["stand_still"], do_press=False) def pre_buff(self): self.bone_armor() @@ -77,7 +77,7 @@ def _bone_armor(self): mouse.click(button="right") wait(self._cast_duration) - def _corpse_explosion(self, cast_pos_abs: Tuple[float, float], spray: int = 10,cast_count: int = 8): + def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8): keyboard.send(Config().char["stand_still"], do_release=False) Logger.debug(f'casting corpse explosion {cast_count} times with spray = {spray}') for _ in range(cast_count): @@ -92,16 +92,12 @@ def _corpse_explosion(self, cast_pos_abs: Tuple[float, float], spray: int = 10,c mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - - def _lerp(self,a: float,b: float, f:float): - return a + f * (b - a) - - def _cast_circle(self, cast_dir: Tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_spell: str='raise_skeleton',delay: float=1.0, radius=120, hold_duration: float = 3, hold=True): + def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_spell: str='raise_skeleton',delay: float=1.0, radius=120, hold_duration: float = 3, hold=True): if hold: Logger.info(f'Circle cast {cast_spell} from {cast_start_angle}º to {cast_end_angle}º over {hold_duration}s') else: Logger.info(f'Circle cast {cast_spell} from {cast_start_angle}º to {cast_end_angle}º over {cast_div} casts') - + keyboard.send(Config().char["stand_still"], do_release=False) keyboard.send(self._skill_hotkeys[cast_spell]) if hold: @@ -111,8 +107,8 @@ def _cast_circle(self, cast_dir: Tuple[float,float],cast_start_angle: float=0.0, angle = self._lerp(cast_start_angle,cast_end_angle,float(i)/cast_div) target = unit_vector(rotate_vec(cast_dir, angle)) Logger.debug(f"Circle cast - current angle: {angle}º") - circle_pos_screen = self._pather._adjust_abs_range_to_screen(target*radius) - circle_pos_monitor = convert_abs_to_monitor(circle_pos_screen) + circle_pos_abs = get_closest_non_hud_pixel(pos = target*radius, pos_type="abs") + circle_pos_monitor = convert_abs_to_monitor(circle_pos_abs) start = time.time() mouse.move(*circle_pos_monitor,delay_factor=[0.95*delay, 1.05*delay]) duration = time.time() - start @@ -169,18 +165,18 @@ def kill_council(self) -> bool: #move down adjacent to the right moat self.move_to(-150,150) self.move_to(-150,150) - + #moat on right side, encircle with bone walls on the other 3 sides for pos in [[100,-100], [-125,-25], [-50,100]]: self.bone_wall(pos, spray=10) self.cast_in_arc(ability='teeth', cast_pos_abs=[40,-100], spread_deg=180, time_in_s=5) self.cast_in_arc(ability='bone_spear', cast_pos_abs=[40,-100], spread_deg=120, time_in_s=8) - + self._corpse_explosion([40,-100], spray=200, cast_count=8) self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[20,-50], spread_deg=180, time_in_s=5) self._corpse_explosion([40,-100], spray=200, cast_count=8) self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[20,-50], spread_deg=360, time_in_s=4) - + return True @@ -189,7 +185,7 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: nihlathak_pos_abs = self._pather.find_abs_node_pos(end_nodes[-1], grab()) if nihlathak_pos_abs is None: return False - + cast_pos_abs = np.array(nihlathak_pos_abs)*.2 self._cast_circle(cast_dir=[1,1],cast_start_angle=0,cast_end_angle=360,cast_div=5,cast_spell='bone_wall',delay=.8,radius=100, hold=False) self._bone_armor() @@ -213,8 +209,8 @@ def kill_summoner(self) -> bool: self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[30,30], spread_deg=360, time_in_s=2) self._corpse_explosion([0,0], spray=200, cast_count=8) self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[30,30], spread_deg=360, time_in_s=2) - - return True + + return True if __name__ == "__main__": import os diff --git a/src/char/hammerdin.py b/src/char/hammerdin.py deleted file mode 100644 index c4199269b..000000000 --- a/src/char/hammerdin.py +++ /dev/null @@ -1,1285 +0,0 @@ -import keyboard -from ui import skills -from utils.custom_mouse import mouse -from char import IChar, CharacterCapabilities -from template_finder import TemplateFinder -from pather import Pather -from logger import Logger -from screen import convert_abs_to_monitor -from config import Config -from utils.misc import wait -import time -from pather import Pather, Location -import cv2 #for Diablo -from item.pickit import PickIt #for Diablo -import numpy as np -from target_detect import mob_check - - -class Hammerdin(IChar): - def __init__(self, skill_hotkeys: dict, pather: Pather, pickit: PickIt): - Logger.info("Setting up Hammerdin") - super().__init__(skill_hotkeys) - self._pather = pather - self._do_pre_move = True - self._pickit = pickit #for Diablo - self._picked_up_items = False #for Diablo - #hammerdin needs to be closer to shenk to reach it with hammers - self._pather.offset_node(149, (70, 10)) - - def _cast_hammers(self, time_in_s: float, aura: str = "concentration"): - if aura in self._skill_hotkeys and self._skill_hotkeys[aura]: - keyboard.send(self._skill_hotkeys[aura]) - wait(0.05, 0.1) - keyboard.send(Config().char["stand_still"], do_release=False) - wait(0.05, 0.1) - if self._skill_hotkeys["blessed_hammer"]: - keyboard.send(self._skill_hotkeys["blessed_hammer"]) - wait(0.05, 0.1) - start = time.time() - while (time.time() - start) < time_in_s: - wait(0.06, 0.08) - mouse.press(button="left") - wait(0.1, 0.2) - mouse.release(button="left") - wait(0.01, 0.05) - keyboard.send(Config().char["stand_still"], do_press=False) - - def pre_buff(self): - if Config().char["cta_available"]: - self._pre_buff_cta() - keyboard.send(self._skill_hotkeys["holy_shield"]) - wait(0.04, 0.1) - mouse.click(button="right") - wait(self._cast_duration, self._cast_duration + 0.06) - - def on_capabilities_discovered(self, capabilities: CharacterCapabilities): - # In case we have a running pala, we want to switch to concentration when moving to the boss - # ass most likely we will click on some mobs and already cast hammers - if capabilities.can_teleport_natively: - self._do_pre_move = False - - def pre_move(self): - # select teleport if available - super().pre_move() - # in case teleport hotkey is not set or teleport can not be used, use vigor if set - should_cast_vigor = self._skill_hotkeys["vigor"] and not skills.is_right_skill_selected(["VIGOR"]) - can_teleport = self.capabilities.can_teleport_natively and skills.is_right_skill_active() - if should_cast_vigor and not can_teleport: - keyboard.send(self._skill_hotkeys["vigor"]) - wait(0.15, 0.25) - - def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float): - pos_m = convert_abs_to_monitor(abs_move) - self.pre_move() - self.move(pos_m, force_move=True) - self._cast_hammers(atk_len) - - def kill_pindle(self) -> bool: - wait(0.1, 0.15) - if self.capabilities.can_teleport_natively: - self._pather.traverse_nodes_fixed("pindle_end", self) - else: - if not self._do_pre_move: - keyboard.send(self._skill_hotkeys["concentration"]) - wait(0.05, 0.15) - self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, timeout=1.0, do_pre_move=self._do_pre_move) - self._cast_hammers(Config().char["atk_len_pindle"]) - wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") - return True - - def kill_eldritch(self) -> bool: - if self.capabilities.can_teleport_natively: - # Custom eld position for teleport that brings us closer to eld - self._pather.traverse_nodes_fixed([(675, 30)], self) - else: - if not self._do_pre_move: - keyboard.send(self._skill_hotkeys["concentration"]) - wait(0.05, 0.15) - self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=1.0, do_pre_move=self._do_pre_move, force_tp=True, use_tp_charge=True) - wait(0.05, 0.1) - self._cast_hammers(Config().char["atk_len_eldritch"]) - wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") - return True - - def kill_shenk(self): - if not self._do_pre_move: - keyboard.send(self._skill_hotkeys["concentration"]) - wait(0.05, 0.15) - self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0, do_pre_move=self._do_pre_move, force_tp=True, use_tp_charge=True) - wait(0.05, 0.1) - self._cast_hammers(Config().char["atk_len_shenk"]) - wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") - return True - - def kill_council(self) -> bool: - if not self._do_pre_move: - keyboard.send(self._skill_hotkeys["concentration"]) - wait(0.05, 0.15) - # Check out the node screenshot in assets/templates/trav/nodes to see where each node is at - atk_len = Config().char["atk_len_trav"] - # Go inside and hammer a bit - self._pather.traverse_nodes([228, 229], self, timeout=2.5, force_tp=True, use_tp_charge=True) - self._cast_hammers(atk_len) - # Move a bit back and another round - self._move_and_attack((40, 20), atk_len) - # Here we have two different attack sequences depending if tele is available or not - if self.capabilities.can_teleport_natively or self.capabilities.can_teleport_with_charges: - # Back to center stairs and more hammers - self._pather.traverse_nodes([226], self, timeout=2.5, force_tp=True, use_tp_charge=True) - self._cast_hammers(atk_len) - # move a bit to the top - self._move_and_attack((65, -30), atk_len) - else: - # Stay inside and cast hammers again moving forward - self._move_and_attack((40, 10), atk_len) - self._move_and_attack((-40, -20), atk_len) - self._cast_hammers(1.6, "redemption") - return True - - def kill_nihlathak(self, end_nodes: list[int]) -> bool: - # Move close to nihlathak - self._pather.traverse_nodes(end_nodes, self, timeout=0.8, do_pre_move=False) - # move mouse to center, otherwise hammers sometimes dont fly, not sure why - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._cast_hammers(Config().char["atk_len_nihlathak"] * 0.4) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((30, 15), Config().char["atk_len_nihlathak"] * 0.3) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_nihlathak"] * 0.4) - wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") - return True - - def kill_summoner(self) -> bool: - # move mouse to below altar - pos_m = convert_abs_to_monitor((0, 20)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - # Attack - self._cast_hammers(Config().char["atk_len_arc"]) - wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") - # Move a bit back and another round - self._move_and_attack((0, 80), Config().char["atk_len_arc"] * 0.5) - wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") - return True - - ######################################################################################## - # Chaos Sanctuary, Trash, Seal Bosses (a = Vizier, b = De Seis, c = Infector) & Diablo # - ######################################################################################## - - def kill_cs_trash(self, location:str) -> bool: - - ########### - # SEALDANCE - ########### - - if location == "sealdance": #if seal opening fails & trash needs to be cleared -> used at ANY seal - ### APPROACH - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.5, 1.0) #clear seal from corpses - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - ################ - # CLEAR CS TRASH - ################ - - elif location == "rof_01": #node 603 - outside CS in ROF - ### APPROACH ### - if not self._pather.traverse_nodes([603], self, timeout=3): return False #calibrate after static path - pos_m = convert_abs_to_monitor((0, 0)) - ### ATTACK ### - wait(1)#give merc the chance to activate holy freeze - #print("mercwait") - if not Config().char['cs_mob_detect'] or mob_check(): - - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - ### LOOT ### - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([603], self): return False #calibrate after looting - - - elif location == "rof_02": #node 604 - inside ROF - ### APPROACH ### - if not self._pather.traverse_nodes([604], self, timeout=3): return False #threshold=0.8 (ex 601) - ### ATTACK ### - wait(1)#give merc the chance to activate holy freeze - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "entrance_hall_01": ##static_path "diablo_entrance_hall_1", node 677, CS Entrance Hall1 - ### APPROACH ### - self._pather.traverse_nodes_fixed("diablo_entrance_hall_1", self) # 604 -> 671 Hall1 - ### ATTACK ### - wait(1)#give merc the chance to activate holy freeze - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "entrance_hall_02": #node 670,671, CS Entrance Hall1, CS Entrance Hall1 - ### APPROACH ### - if not self._pather.traverse_nodes([670], self): return False # pull top mobs 672 to bottom 670 - self._pather.traverse_nodes_fixed("diablo_entrance_1_670_672", self) # 604 -> 671 Hall1 - if not self._pather.traverse_nodes([670], self): return False # pull top mobs 672 to bottom 670 - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - #Move to Layout Check - if not self._pather.traverse_nodes([671], self): return False # calibrate before static path - self._pather.traverse_nodes_fixed("diablo_entrance_hall_2", self) # 671 -> LC Hall2 - - - - # TRASH LAYOUT A - - elif location == "entrance1_01": #static_path "diablo_entrance_hall_2", Hall1 (before layout check) - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([673], self): return False # , timeout=3): # Re-adjust itself and continues to attack - - elif location == "entrance1_02": #node 673 - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - self._pather.traverse_nodes_fixed("diablo_entrance_1_1", self) # Moves char to postion close to node 674 continues to attack - if not self._pather.traverse_nodes([674], self): return False#, timeout=3) - - elif location == "entrance1_03": #node 674 - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([675], self): return False#, timeout=3) # Re-adjust itself - self._pather.traverse_nodes_fixed("diablo_entrance_1_1", self) #static path to get to be able to spot 676 - if not self._pather.traverse_nodes([676], self): return False#, timeout=3) - - elif location == "entrance1_04": #node 676- Hall3 - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-50, -150), Config().char["atk_len_cs_trashmobs"]) - self._move_and_attack((50, 150), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - # TRASH LAYOUT B - - elif location == "entrance2_01": #static_path "diablo_entrance_hall_2" - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "entrance2_02": #node 682 - ### APPROACH ### - #if not self._pather.traverse_nodes([682], self): return False # , timeout=3): - self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_right", self) #pull mobs from the right - wait (0.2, 0.5) - if not self._pather.traverse_nodes([605], self): return False#, timeout=3) - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "entrance2_03": #node 683 - ### APPROACH ### - #if not self._pather.traverse_nodes([682], self): return False # , timeout=3): - #self._pather.traverse_nodes_fixed("diablo_entrance2_1", self) - #if not self._pather.traverse_nodes([683], self): return False # , timeout=3): - self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_top1", self) #pull mobs from top - wait (0.2, 0.5) - self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_top2", self) #pull mobs from top - if not self._pather.traverse_nodes([605], self): return False#, timeout=3) - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "entrance2_04": #node 686 - Hall3 - ### APPROACH ### - if not self._pather.traverse_nodes([605], self): return False#, timeout=3) - #if not self._pather.traverse_nodes([683,684], self): return False#, timeout=3) - #self._pather.traverse_nodes_fixed("diablo_entrance2_2", self) - #if not self._pather.traverse_nodes([685,686], self): return False#, timeout=3) - self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_hall3", self) - if not self._pather.traverse_nodes([609], self): return False#, timeout=3) - self._pather.traverse_nodes_fixed("diablo_trash_b_hall3_pull_609", self) - if not self._pather.traverse_nodes([609], self): return False#, timeout=3) - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((0, 0), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-50, -150), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._move_and_attack((50, 150), Config().char["atk_len_cs_trashmobs"] * 0.2) - self._move_and_attack((250, -150), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._move_and_attack((-250, -150), Config().char["atk_len_cs_trashmobs"] * 0.2) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([609], self): return False#, timeout=3) - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([609], self): return False#, timeout=3) - - #################### - # PENT TRASH TO SEAL - #################### - - elif location == "dia_trash_a": #trash before between Pentagramm and Seal A Layoutcheck - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) - self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "dia_trash_b": #trash before between Pentagramm and Seal B Layoutcheck - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) - self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "dia_trash_c": ##trash before between Pentagramm and Seal C Layoutcheck - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) - self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - ############### - # LAYOUT CHECKS - ############### - - elif location == "layoutcheck_a": #layout check seal A, node 619 A1-L, node 620 A2-Y - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - #Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "layoutcheck_b": #layout check seal B, node 634 B1-S, node 649 B2-U - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "layoutcheck_c": #layout check seal C, node 656 C1-F, node 664 C2-G - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - ################## - # PENT BEFORE SEAL - ################## - - elif location == "pent_before_a": #node 602, pentagram, before CTA buff & depature to layout check - not needed when trash is skipped & seals run in right order - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "pent_before_b": #node 602, pentagram, before CTA buff & depature to layout check - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif location == "pent_before_c": #node 602, pentagram, before CTA buff & depature to layout check - ### APPROACH ### - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - ########### - # SEAL A1-L - ########### - - elif location == "A1-L_01": #node 611 seal layout A1-L: safe_dist - ### APPROACH ### - if not self._pather.traverse_nodes([611], self): return False # , timeout=3): - ### ATTACK ### - wait(1)#give merc the chance to activate holy freeze - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - # we loot at boss - - elif location == "A1-L_02": #node 612 seal layout A1-L: center - ### APPROACH ### - if not self._pather.traverse_nodes([612], self): return False # , timeout=3): - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._cast_hammers(0.5, "cleansing") - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - # we loot at boss - - elif location == "A1-L_03": #node 613 seal layout A1-L: fake_seal - ### APPROACH ### - if not self._pather.traverse_nodes([613], self): return False # , timeout=3): - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._cast_hammers(0.5, "cleansing") - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - - elif location == "A1-L_seal1": #node 613 seal layout A1-L: fake_seal - ### APPROACH ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([614], self): return False - ### ATTACK ### - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - # we loot at boss - - elif location == "A1-L_seal2": #node 614 seal layout A1-L: boss_seal - ### APPROACH ### - if not self._pather.traverse_nodes([613, 615], self): return False # , timeout=3): - ### ATTACK ### - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - # we loot at boss - - ########### - # SEAL A2-Y - ########### - - elif location == "A2-Y_01": #node 622 seal layout A2-Y: safe_dist - ### APPROACH ### - if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False - Logger.debug("A2-Y: Hop!") - #if not self._pather.traverse_nodes([622], self): return False # , timeout=3): - if not self._pather.traverse_nodes([622], self): return False - wait(1)#give merc the chance to activate holy freeze - if not Config().char['cs_mob_detect'] or mob_check(): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### ATTACK ### - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - # we loot at boss - - elif location == "A2-Y_02": #node 623 seal layout A2-Y: center - ### APPROACH ### - # if not self._pather.traverse_nodes([623,624], self): return False # - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - # we loot at boss - - elif location == "A2-Y_03": #skipped - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "A2-Y_seal1": #node 625 seal layout A2-Y: fake seal - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - if not self._pather.traverse_nodes([625], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - - elif location == "A2-Y_seal2": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - self._pather.traverse_nodes_fixed("dia_a2y_sealfake_sealboss", self) #instead of traversing node 626 which causes issues - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - - ########### - # SEAL B1-S - ########### - - elif location == "B1-S_01": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "B1-S_02": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "B1-S_03": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "B1-S_seal2": #B only has 1 seal, which is the boss seal = seal2 - ### APPROACH ### - if not self._pather.traverse_nodes([634], self): return False # , timeout=3): - ### ATTACK ### - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - - - ########### - # SEAL B2-U - ########### - - elif location == "B2-U_01": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "B2-U_02": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "B2-U_03": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "B2-U_seal2": #B only has 1 seal, which is the boss seal = seal2 - ### APPROACH ### - self._pather.traverse_nodes_fixed("dia_b2u_bold_seal", self) - if not self._pather.traverse_nodes([644], self): return False # , timeout=3): - ### ATTACK ### - ### LOOT ### - # we loot at boss - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - - - ########### - # SEAL C1-F - ########### - - elif location == "C1-F_01": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "C1-F_02": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "C1-F_03": - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "C1-F_seal1": - ### APPROACH ### - wait(0.1,0.3) - self._pather.traverse_nodes_fixed("dia_c1f_hop_fakeseal", self) - wait(0.1,0.3) - if not self._pather.traverse_nodes([655], self): return False # , timeout=3): - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([655], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - - elif location == "C1-F_seal2": - ### APPROACH ### - self._pather.traverse_nodes_fixed("dia_c1f_654_651", self) - if not self._pather.traverse_nodes([652], self): return False # , timeout=3): - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([652], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - - ########### - # SEAL C2-G - ########### - - elif location == "C2-G_01": #skipped - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "C2-G_02": #skipped - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "C2-G_03": #skipped - ### APPROACH ### - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - - elif location == "C2-G_seal1": - ### APPROACH ### - #if not self._pather.traverse_nodes([663, 662], self): return False # , timeout=3): #caused 7% failed runs, replaced by static path. - self._pather.traverse_nodes_fixed("dia_c2g_lc_661", self) - ### ATTACK ### - ### LOOT ### - # we loot at boss - Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") - """ - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - """ - - elif location == "C2-G_seal2": - ### APPROACH ### - # Killing infector here, because for C2G its the only seal where a bossfight occures BETWEEN opening seals - seal_layout="C2-G" - self._pather.traverse_nodes_fixed("dia_c2g_663", self) - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - Logger.debug(seal_layout + ": Attacking Infector at position 1/1") - self._cast_hammers(Config().char["atk_len_diablo_infector"]) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((30, 15), Config().char["atk_len_diablo_infector"]) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((30, -15), Config().char["atk_len_diablo_infector"]) - wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - if not self._pather.traverse_nodes([664, 665], self): return False # , timeout=3): - - else: - ### APPROACH ### - Logger.warning("I have no location argument given for kill_cs_trash(" + location + "), should not happen. Throwing some random hammers") - ### ATTACK ### - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - return True - - - - def kill_vizier(self, seal_layout:str) -> bool: - if seal_layout == "A1-L": - ### APPROACH ### - if not self._pather.traverse_nodes([612], self): return False # , timeout=3): - ### ATTACK ### - Logger.debug(seal_layout + ": Attacking Vizier at position 1/2") - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") - self._pather.traverse_nodes([611], self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses - self._cast_hammers(1, "redemption") - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) - wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - wait(0.3, 1.2) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([612], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([612], self): return False # , timeout=3): # recalibrate after loot - - elif seal_layout == "A2-Y": - ### APPROACH ### - if not self._pather.traverse_nodes([627, 622], self): return False # , timeout=3): - ### ATTACK ### - Logger.debug(seal_layout + ": Attacking Vizier at position 1/2") - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") - self._pather.traverse_nodes([623], self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking Vizier at position 3/3") - if not self._pather.traverse_nodes([624], self): return False - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"]) - wait(0.1, 0.15) - self._cast_hammers(2, "redemption") - self._cast_hammers(1, "cleansing") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([624], self): return False - if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False - Logger.debug(seal_layout + ": Hop!") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - if not self._pather.traverse_nodes([622], self): return False #, timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([622], self): return False # , timeout=3): #recalibrate after loot - - else: - Logger.warning(seal_layout + ": Invalid location for kill_deseis("+ seal_layout +"), should not happen.") - return False - return True - - - - def kill_deseis(self, seal_layout:str) -> bool: - if seal_layout == "B1-S": - ### APPROACH ### - self._pather.traverse_nodes_fixed("dia_b1s_seal_deseis", self) # quite aggressive path, but has high possibility of directly killing De Seis with first hammers, for 50% of his spawn locations - nodes1 = [632] - nodes2 = [631] - nodes3 = [632] - ### ATTACK ### - Logger.debug(seal_layout + ": Attacking De Seis at position 1/4") - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking De Seis at position 2/4") - self._pather.traverse_nodes(nodes1, self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking De Seis at position 3/4") - self._pather.traverse_nodes(nodes2, self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"] * 0.5) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking De Seis at position 4/4") - self._pather.traverse_nodes(nodes3, self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses - wait(0.1, 0.2) - self._cast_hammers(2, "redemption") - self._cast_hammers(1, "cleansing") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(2.5, 3.5) # to keep redemption on for a couple of seconds before the next teleport to have more corpses cleared & increase chance to find next template - Logger.debug(seal_layout + ": Waiting with Redemption active to clear more corpses.") - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif seal_layout == "B2-U": - ### APPROACH ### - self._pather.traverse_nodes_fixed("dia_b2u_644_646", self) # We try to breaking line of sight, sometimes makes De Seis walk into the hammercloud. A better attack sequence here could make sense. - #self._pather.traverse_nodes_fixed("dia_b2u_seal_deseis", self) # We try to breaking line of sight, sometimes makes De Seis walk into the hammercloud. A better attack sequence here could make sense. - nodes1 = [640] - nodes2 = [646] - nodes3 = [641] - ### ATTACK ### - Logger.debug(seal_layout + ": Attacking De Seis at position 1/4") - if not Config().char['cs_mob_detect'] or mob_check(): - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking De Seis at position 2/4") - self._pather.traverse_nodes(nodes1, self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking De Seis at position 3/4") - self._pather.traverse_nodes(nodes2, self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"] * 0.5) - self._cast_hammers(1, "redemption") - Logger.debug(seal_layout + ": Attacking De Seis at position 4/4") - self._pather.traverse_nodes(nodes3, self, timeout=3) - if not Config().char['cs_mob_detect'] or mob_check(): - self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses - wait(0.1, 0.2) - self._cast_hammers(2, "redemption") - self._cast_hammers(1, "cleansing") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) - wait(0.3, 0.6) - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([641], self): return False # , timeout=3): - if not self._pather.traverse_nodes([646], self): return False # , timeout=3): - self._picked_up_items |= self._pickit.pick_up_items(self) - if not self._pather.traverse_nodes([646], self): return False # , timeout=3): - if not self._pather.traverse_nodes([640], self): return False # , timeout=3): - self._picked_up_items |= self._pickit.pick_up_items(self) - - else: - Logger.warning(seal_layout + ": Invalid location for kill_deseis("+ seal_layout +"), should not happen.") - return False - return True - - - - def kill_infector(self, seal_layout:str) -> bool: - if seal_layout == "C1-F": - ### APPROACH ### - self._pather.traverse_nodes_fixed("dia_c1f_652", self) - ### ATTACK ### - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - Logger.debug(seal_layout + ": Attacking Infector at position 1/1") - self._cast_hammers(Config().char["atk_len_diablo_infector"] * 0.4) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((30, 15), Config().char["atk_len_diablo_infector"] * 0.3) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((30, -15), Config().char["atk_len_diablo_infector"] * 0.4) - wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - - elif seal_layout == "C2-G": - # NOT killing infector here, because for C2G its the only seal where a bossfight occures BETWEEN opening seals his attack sequence can be found in C2-G_seal2 - Logger.debug(seal_layout + ": No need for attacking Infector at position 1/1 - he was killed during clearing the seal") - - else: - Logger.warning(seal_layout + ": Invalid location for kill_infector("+ seal_layout +"), should not happen.") - return False - return True - - - def kill_diablo(self) -> bool: - ### APPROACH ### - ### ATTACK ### - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) - Logger.debug("Attacking Diablo at position 1/1") - self._cast_hammers(Config().char["atk_len_diablo"]) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((60, 30), Config().char["atk_len_diablo"]) - self._cast_hammers(0.8, "redemption") - self._move_and_attack((-60, -30), Config().char["atk_len_diablo"]) - wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") - ### LOOT ### - self._picked_up_items |= self._pickit.pick_up_items(self) - return True - - -if __name__ == "__main__": - import os - import keyboard - keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) - keyboard.wait("f11") - from config import Config - pather = Pather() - char = Hammerdin(Config().hammerdin, Config().char, pather) diff --git a/src/char/i_char.py b/src/char/i_char.py index 19c3e5596..4374b43ef 100644 --- a/src/char/i_char.py +++ b/src/char/i_char.py @@ -1,9 +1,9 @@ -from typing import Dict, Tuple, Union, List, Callable +from typing import Callable import random import time import cv2 import math -from inventory import consumables +from item import consumables import keyboard import numpy as np from char.capabilities import CharacterCapabilities @@ -14,26 +14,54 @@ from logger import Logger from config import Config from screen import grab, convert_monitor_to_screen, convert_screen_to_abs, convert_abs_to_monitor, convert_screen_to_monitor -from template_finder import TemplateFinder -from ocr import Ocr -from ui_manager import detect_screen_object, ScreenObjects +import template_finder +from ui_manager import detect_screen_object, ScreenObjects, get_closest_non_hud_pixel class IChar: - _CrossGameCapabilities: Union[None, CharacterCapabilities] = None + _CrossGameCapabilities: None | CharacterCapabilities = None - def __init__(self, skill_hotkeys: Dict): + def __init__(self, skill_hotkeys: dict): self._skill_hotkeys = skill_hotkeys self._last_tp = time.time() - self._ocr = Ocr() # Add a bit to be on the save side self._cast_duration = Config().char["casting_frames"] * 0.04 + 0.01 self.damage_scaling = float(Config().char.get("damage_scaling", 1.0)) self.capabilities = None + self._active_skill = { + "left": "", + "right": "" + } + self._use_safer_routines = Config().char["safer_routines"] + + def _set_active_skill(self, mouse_click_type: str = "left", skill: str =""): + self._active_skill[mouse_click_type] = skill + + def _select_skill(self, skill: str, mouse_click_type: str = "left", delay: float | list | tuple = None): + if not ( + skill in self._skill_hotkeys and (hotkey := self._skill_hotkeys[skill]) + or (skill in Config().char and (hotkey := Config().char[skill])) + ): + Logger.warning(f"No hotkey for skill: {skill}") + self._set_active_skill(mouse_click_type, "") + return False + + if self._active_skill[mouse_click_type] != skill: + keyboard.send(hotkey) + self._set_active_skill(mouse_click_type, skill) + if delay: + try: + wait(*delay) + except: + try: + wait(delay) + except Exception as e: + Logger.warning(f"_select_skill: Failed to delay with delay: {delay}. Exception: {e}") + return True def _discover_capabilities(self) -> CharacterCapabilities: override = Config().advanced_options["override_capabilities"] if override is None: - if self._skill_hotkeys["teleport"]: + if Config().char["teleport"]: if self.select_tp(): if self.skill_is_charged(): return CharacterCapabilities(can_teleport_natively=False, can_teleport_with_charges=True) @@ -59,16 +87,16 @@ def discover_capabilities(self, force = False): def on_capabilities_discovered(self, capabilities: CharacterCapabilities): pass - def pick_up_item(self, pos: Tuple[float, float], item_name: str = None, prev_cast_start: float = 0): + def pick_up_item(self, pos: tuple[float, float], item_name: str = None, prev_cast_start: float = 0): mouse.move(pos[0], pos[1]) time.sleep(0.1) mouse.click(button="left") - wait(0.45, 0.5) + wait(0.25, 0.3) return prev_cast_start def select_by_template( self, - template_type: Union[str, List[str]], + template_type: str | list[str], success_func: Callable = None, timeout: float = 8, threshold: float = 0.68, @@ -88,10 +116,10 @@ def select_by_template( keyboard.send("esc") start = time.time() while timeout is None or (time.time() - start) < timeout: - template_match = TemplateFinder().search(template_type, grab(), threshold=threshold, normalize_monitor=True) + template_match = template_finder.search(template_type, grab(), threshold=threshold) if template_match.valid: Logger.debug(f"Select {template_match.name} ({template_match.score*100:.1f}% confidence)") - mouse.move(*template_match.center) + mouse.move(*template_match.center_monitor) wait(0.2, 0.3) mouse.click(button="left") # check the successfunction for 2 sec, if not found, try again @@ -113,7 +141,7 @@ def skill_is_charged(self, img: np.ndarray = None) -> bool: def is_low_on_teleport_charges(self): img = grab() - charges_remaining = skills.get_skill_charges(self._ocr, img) + charges_remaining = skills.get_skill_charges(img) if charges_remaining: Logger.debug(f"{charges_remaining} teleport charges remain") return charges_remaining <= 3 @@ -129,10 +157,9 @@ def _remap_skill_hotkey(self, skill_asset, hotkey, skill_roi, expanded_skill_roi mouse.move(x + w/2, y + h / 2) mouse.click("left") wait(0.3) - match = TemplateFinder().search(skill_asset, grab(), threshold=0.84, roi=expanded_skill_roi) + match = template_finder.search(skill_asset, grab(), threshold=0.84, roi=expanded_skill_roi) if match.valid: - x, y = convert_screen_to_monitor(match.center) - mouse.move(x, y) + mouse.move(*match.center_monitor) wait(0.3) keyboard.send(hotkey) wait(0.3) @@ -143,18 +170,24 @@ def remap_right_skill_hotkey(self, skill_asset, hotkey): return self._remap_skill_hotkey(skill_asset, hotkey, Config().ui_roi["skill_right"], Config().ui_roi["skill_right_expanded"]) def select_tp(self): - return skills.select_tp(self._skill_hotkeys["teleport"]) + return skills.select_tp(Config().char["teleport"]) def pre_move(self): # if teleport hotkey is set and if teleport is not already selected if self.capabilities.can_teleport_natively: self.select_tp() + self._set_active_skill("right", "teleport") - def move(self, pos_monitor: Tuple[float, float], force_tp: bool = False, force_move: bool = False): + def move(self, pos_monitor: tuple[float, float], force_tp: bool = False, force_move: bool = False): factor = Config().advanced_options["pathing_delay_factor"] - if self._skill_hotkeys["teleport"] and \ - (force_tp or (skills.is_right_skill_selected(["TELE_ACTIVE"]) and \ - skills.is_right_skill_active())): + if "teleport" in Config().char and Config().char["teleport"] and ( + force_tp + or ( + skills.is_right_skill_selected(["TELE_ACTIVE"]) + and skills.is_right_skill_active() + ) + ): + self._set_active_skill("right", "teleport") mouse.move(pos_monitor[0], pos_monitor[1], randomize=3, delay_factor=[factor*0.1, factor*0.14]) wait(0.012, 0.02) mouse.click(button="right") @@ -175,8 +208,8 @@ def move(self, pos_monitor: Tuple[float, float], force_tp: bool = False, force_m keyboard.send(Config().char["force_move"]) else: mouse.click(button="left") - - def walk(self, pos_monitor: Tuple[float, float], force_tp: bool = False, force_move: bool = False): + + def walk(self, pos_monitor: tuple[float, float], force_tp: bool = False, force_move: bool = False): factor = Config().advanced_options["pathing_delay_factor"] # in case we want to walk we actually want to move a bit before the point cause d2r will always "overwalk" pos_screen = convert_monitor_to_screen(pos_monitor) @@ -192,7 +225,7 @@ def walk(self, pos_monitor: Tuple[float, float], force_tp: bool = False, force_m if force_move: keyboard.send(Config().char["force_move"]) else: - mouse.click(button="left") + mouse.click(button="left") def tp_town(self): # will check if tp is available and select the skill @@ -222,7 +255,7 @@ def tp_town(self): consumables.increment_need("tp", 1) wait(0.8, 1.3) # takes quite a while for tp to be visible if (template_match := detect_screen_object(ScreenObjects.TownPortal)).valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] + 30) # Note: Template is top of portal, thus move the y-position a bit to the bottom mouse.move(*pos, randomize=6, delay_factor=[0.9, 1.1]) @@ -245,8 +278,7 @@ def _pre_buff_cta(self): while time.time() - start < 4: keyboard.send(Config().char["weapon_switch"]) wait(0.3, 0.35) - keyboard.send(Config().char["battle_command"]) - wait(0.1, 0.19) + self._select_skill(skill = "battle_command", mouse_click_type="right", delay=(0.1, 0.2)) if skills.is_right_skill_selected(["BC", "BO"]): switch_sucess = True break @@ -258,8 +290,7 @@ def _pre_buff_cta(self): # We switched succesfully, let's pre buff mouse.click(button="right") wait(self._cast_duration + 0.16, self._cast_duration + 0.18) - keyboard.send(Config().char["battle_orders"]) - wait(0.1, 0.19) + self._select_skill(skill = "battle_orders", mouse_click_type="right", delay=(0.1, 0.2)) mouse.click(button="right") wait(self._cast_duration + 0.16, self._cast_duration + 0.18) @@ -275,21 +306,23 @@ def _pre_buff_cta(self): else: Logger.warning("Failed to switch weapon, try again") wait(0.5) - - + + def vec_to_monitor(self, target): - circle_pos_screen = self._pather._adjust_abs_range_to_screen(target) - return convert_abs_to_monitor(circle_pos_screen) - - def cast_in_arc(self, ability: str, cast_pos_abs: Tuple[float, float] = [0,-100], time_in_s: float = 3, spread_deg: float = 10, hold=True): + circle_pos_abs = get_closest_non_hud_pixel(pos = target, pos_type="abs") + return convert_abs_to_monitor(circle_pos_abs) + + def _lerp(self,a: float,b: float, f:float): + return a + f * (b - a) + + def cast_in_arc(self, ability: str, cast_pos_abs: tuple[float, float] = [0,-100], time_in_s: float = 3, spread_deg: float = 10, hold=True): #scale cast time by damage_scaling time_in_s *= self.damage_scaling Logger.debug(f'Casting {ability} for {time_in_s:.02f}s at {cast_pos_abs} with {spread_deg}°') if not self._skill_hotkeys[ability]: raise ValueError(f"You did not set {ability} hotkey!") keyboard.send(Config().char["stand_still"], do_release=False) - keyboard.send(self._skill_hotkeys[ability]) - wait(0.02, 0.08) + self._select_skill(skill = ability, mouse_click_type="right", delay=(0.02, 0.08)) target = self.vec_to_monitor(arc_spread(cast_pos_abs, spread_deg=spread_deg)) mouse.move(*target,delay_factor=[0.95, 1.05]) @@ -307,11 +340,11 @@ def cast_in_arc(self, ability: str, cast_pos_abs: Tuple[float, float] = [0,-100] wait(0.02, 0.06) mouse.release(button="right") wait(self._cast_duration, self._cast_duration) - + if hold: mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - + def pre_buff(self): pass @@ -357,12 +390,9 @@ def kill_cs_trash(self, location:str) -> bool: keyboard.wait("f11") from utils.misc import cut_roi from config import Config - from template_finder import TemplateFinder - from ocr import Ocr from ui import skills skill_hotkeys = {} - ocr = Ocr() i_char = IChar({}) diff --git a/src/char/necro.py b/src/char/necro.py index 7080f9450..02535d7fa 100644 --- a/src/char/necro.py +++ b/src/char/necro.py @@ -1,19 +1,19 @@ import keyboard from utils.custom_mouse import mouse from char import IChar -from template_finder import TemplateFinder +import template_finder +from template_finder import TemplateMatch from pather import Pather from logger import Logger from screen import grab, convert_abs_to_monitor, convert_screen_to_abs from config import Config from utils.misc import wait, rotate_vec, unit_vector import random -from typing import Tuple from pather import Location, Pather import numpy as np import time import os -from ui_manager import wait_until_visible, ScreenObjects +from ui_manager import wait_until_visible, ScreenObjects, get_closest_non_hud_pixel class Necro(IChar): def __init__(self, skill_hotkeys: dict, pather: Pather): @@ -53,7 +53,7 @@ def _check_shenk_death(self): roi = [640,0,640,720] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ['SHENK_DEATH_1','SHENK_DEATH_2','SHENK_DEATH_3','SHENK_DEATH_4'], img, threshold=0.6, @@ -71,7 +71,7 @@ def _count_revives(self): img = grab() max_rev = 13 - template_match = TemplateFinder().search( + template_match = template_finder.search( ['REV_BASE'], img, threshold=0.6, @@ -85,7 +85,7 @@ def _count_revives(self): for count in range(1,max_rev): rev_num = "REV_"+str(count) - template_match = TemplateFinder().search( + template_match = template_finder.search( [rev_num], img, threshold=0.66, @@ -100,7 +100,7 @@ def _count_skeletons(self): img = grab() max_skeles = 13 - template_match = TemplateFinder().search( + template_match = template_finder.search( ['SKELE_BASE'], img, threshold=0.6, @@ -114,7 +114,7 @@ def _count_skeletons(self): for count in range(1,max_skeles): skele_num = "SKELE_"+str(count) - template_match = TemplateFinder().search( + template_match = template_finder.search( [skele_num], img, threshold=0.66, @@ -128,7 +128,7 @@ def _count_gol(self): roi = [15,14,400,45] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ['CLAY'], img, threshold=0.6, @@ -150,7 +150,7 @@ def _summon_stat(self): ''' print counts for summons ''' Logger.info('\33[31m'+"Summon status | "+str(self._skeletons_count)+"skele | "+str(self._revive_count)+" rev | "+self._golem_count+" |"+'\033[0m') - def _revive(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=12): + def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=12): Logger.info('\033[94m'+"raise revive"+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) for _ in range(cast_count): @@ -179,7 +179,7 @@ def _revive(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - def _raise_skeleton(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=16): + def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise skeleton"+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) for _ in range(cast_count): @@ -208,7 +208,7 @@ def _raise_skeleton(self, cast_pos_abs: Tuple[float, float], spray: int = 10, ca mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - def _raise_mage(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=16): + def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise mage"+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) for _ in range(cast_count): @@ -284,7 +284,7 @@ def _bone_armor(self): - def _left_attack(self, cast_pos_abs: Tuple[float, float], spray: int = 10): + def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): keyboard.send(Config().char["stand_still"], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) @@ -299,7 +299,7 @@ def _left_attack(self, cast_pos_abs: Tuple[float, float], spray: int = 10): keyboard.send(Config().char["stand_still"], do_press=False) - def _left_attack_single(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=6): + def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=6): keyboard.send(Config().char["stand_still"], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) @@ -314,7 +314,7 @@ def _left_attack_single(self, cast_pos_abs: Tuple[float, float], spray: int = 10 keyboard.send(Config().char["stand_still"], do_press=False) - def _amp_dmg(self, cast_pos_abs: Tuple[float, float], spray: float = 10): + def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10): if self._skill_hotkeys["amp_dmg"]: keyboard.send(self._skill_hotkeys["amp_dmg"]) @@ -326,7 +326,7 @@ def _amp_dmg(self, cast_pos_abs: Tuple[float, float], spray: float = 10): wait(0.25, 0.35) mouse.release(button="right") - def _corpse_explosion(self, cast_pos_abs: Tuple[float, float], spray: int = 10,cast_count: int = 8): + def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8): keyboard.send(Config().char["stand_still"], do_release=False) Logger.info('\033[93m'+"corpse explosion~> random cast"+'\033[0m') for _ in range(cast_count): @@ -341,11 +341,7 @@ def _corpse_explosion(self, cast_pos_abs: Tuple[float, float], spray: int = 10,c mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - - def _lerp(self,a: float,b: float, f:float): - return a + f * (b - a) - - def _cast_circle(self, cast_dir: Tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0): + def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0): Logger.info('\033[93m'+"circle cast ~>"+cast_spell+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) keyboard.send(self._skill_hotkeys[cast_spell]) @@ -356,11 +352,10 @@ def _cast_circle(self, cast_dir: Tuple[float,float],cast_start_angle: float=0.0, target = unit_vector(rotate_vec(cast_dir, angle)) #Logger.info("current angle ~> "+str(angle)) for j in range(cast_v_div): - circle_pos_screen = self._pather._adjust_abs_range_to_screen((target*120.0*float(j+1.0))*offset) - circle_pos_monitor = convert_abs_to_monitor(circle_pos_screen) + circle_pos_abs = get_closest_non_hud_pixel(pos = (target*120.0*float(j+1.0))*offset, pos_type="abs") + circle_pos_monitor = convert_abs_to_monitor(circle_pos_abs) mouse.move(*circle_pos_monitor,delay_factor=[0.3*delay, .6*delay]) - #Logger.info("circle move") mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) @@ -583,15 +578,14 @@ def kill_shenk(self) -> bool: def stairs_S(self): roi = [0,0,1280,720] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ["TRAV_S","TRAV_S_1"], img, threshold=0.4, - roi=roi, - normalize_monitor=True + roi=roi ) if template_match.valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] ) Logger.debug("mid point >> "+str(pos)) @@ -607,15 +601,14 @@ def stairs_S(self): def stairs_F(self): roi = [0,0,1280,720] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ["TRAV_F"], img, threshold=0.4, - roi=roi, - normalize_monitor=True + roi=roi ) if template_match.valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] ) Logger.debug("mid point >> "+str(pos)) @@ -632,15 +625,14 @@ def stairs_F(self): def stairs_W(self): roi = [0,0,1280,720] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ["TRAV_W","TRAV_W_1"], img, threshold=0.4, - roi=roi, - normalize_monitor=True + roi=roi ) if template_match.valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] ) Logger.debug("mid point >> "+str(pos)) @@ -661,15 +653,14 @@ def to_durance(self): roi = [0,0,1280,720] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ["TRAV_18"], img, threshold=0.3, - roi=roi, - normalize_monitor=True + roi=roi ) if template_match.valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] ) Logger.debug("DURANCE ENTRANCE >> "+str(pos)) # Note: Template is top of portal, thus move the y-position a bit to the bottom @@ -699,15 +690,14 @@ def to_trav(self): mouse.move(*target, randomize=6, delay_factor=[0.9, 1.1]) img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ["TO_TRAV_0"], img, threshold=0.95, - roi=roi, - normalize_monitor=True + roi=roi ) if template_match.valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] ) Logger.debug("DURANCE EXIT >> "+str(pos)) # Note: Template is top of portal, thus move the y-position a bit to the bottom diff --git a/src/char/paladin/__init__.py b/src/char/paladin/__init__.py new file mode 100644 index 000000000..3ff911112 --- /dev/null +++ b/src/char/paladin/__init__.py @@ -0,0 +1,3 @@ +from .paladin import Paladin +from .fohdin import FoHdin +from .hammerdin import Hammerdin \ No newline at end of file diff --git a/src/char/paladin/fohdin.py b/src/char/paladin/fohdin.py new file mode 100644 index 000000000..b2fcc186e --- /dev/null +++ b/src/char/paladin/fohdin.py @@ -0,0 +1,763 @@ +import random +import keyboard +import time +import numpy as np + +from health_manager import get_panel_check_paused, set_panel_check_paused +from inventory.personal import inspect_items +from screen import convert_abs_to_monitor, convert_screen_to_abs, grab, convert_abs_to_screen +from utils.custom_mouse import mouse +from char.paladin import Paladin +from logger import Logger +from config import Config +from utils.misc import wait +from pather import Location +from target_detect import get_visible_targets, TargetInfo, log_targets + +class FoHdin(Paladin): + def __init__(self, *args, **kwargs): + Logger.info("Setting up FoHdin") + super().__init__(*args, **kwargs) + self._pather.adapt_path((Location.A3_TRAV_START, Location.A3_TRAV_CENTER_STAIRS), [220, 221, 222, 903, 904, 905, 906]) + + + def _cast_foh(self, cast_pos_abs: tuple[float, float], spray: int = 10, min_duration: float = 0, aura: str = "conviction"): + return self._cast_skill_with_aura(skill_name = "foh", cast_pos_abs = cast_pos_abs, spray = spray, min_duration = min_duration, aura = aura) + + def _cast_holy_bolt(self, cast_pos_abs: tuple[float, float], spray: int = 10, min_duration: float = 0, aura: str = "concentration"): + #if skill is bound : concentration, use concentration, otherwise move on with conviction. alternatively use redemption whilst holybolting. conviction does not help holy bolt (its magic damage) + return self._cast_skill_with_aura(skill_name = "holy_bolt", cast_pos_abs = cast_pos_abs, spray = spray, min_duration = min_duration, aura = aura) + + def _cast_hammers(self, min_duration: float = 0, aura: str = "concentration"): #for nihlathak + return self._cast_skill_with_aura(skill_name = "blessed_hammer", spray = 0, min_duration = min_duration, aura = aura) + + def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float, aura: str = "concentration"): #for nihalthak + pos_m = convert_abs_to_monitor(abs_move) + self.pre_move() + self.move(pos_m, force_move=True) + self._cast_hammers(atk_len, aura=aura) + + def _generic_foh_attack_sequence( + self, + default_target_abs: tuple[int, int] = (0, 0), + min_duration: float = 0, + max_duration: float = 15, + foh_to_holy_bolt_ratio: int = 3, + target_detect: bool = True, + default_spray: int = 50, + aura: str = "" + ) -> bool: + start = time.time() + target_check_count = 1 + foh_aura = aura if aura else "conviction" + holy_bolt_aura = aura if aura else "concentration" + while (elapsed := (time.time() - start)) <= max_duration: + cast_pos_abs = default_target_abs + spray = default_spray + # if targets are detected, switch to targeting with reduced spread rather than present default cast position and default spread + if target_detect and (targets := get_visible_targets()): + # log_targets(targets) + spray = 5 + cast_pos_abs = targets[0].center_abs + + # if time > minimum and either targets aren't set or targets don't exist, exit loop + if elapsed > min_duration and (not target_detect or not targets): + break + else: + + # TODO: add delay between FOH casts--doesn't properly cast each FOH in sequence + # cast foh to holy bolt with preset ratio (e.g. 3 foh followed by 1 holy bolt if foh_to_holy_bolt_ratio = 3) + if foh_to_holy_bolt_ratio > 0 and not target_check_count % (foh_to_holy_bolt_ratio + 1): + self._cast_holy_bolt(cast_pos_abs, spray=spray, aura=holy_bolt_aura) + else: + self._cast_foh(cast_pos_abs, spray=spray, aura=foh_aura) + + target_check_count += 1 + return True + + #FOHdin Attack Sequence Optimized for trash + def _cs_attack_sequence(self, min_duration: float = Config().char["atk_len_cs_trashmobs"], max_duration: float = Config().char["atk_len_cs_trashmobs"] * 3): + self._generic_foh_attack_sequence(default_target_abs=(20,20), min_duration = min_duration, max_duration = max_duration, default_spray=100, foh_to_holy_bolt_ratio=6) + self._activate_redemption_aura() + + def _cs_trash_mobs_attack_sequence(self, min_duration: float = 1.2, max_duration: float = Config().char["atk_len_cs_trashmobs"]): + self._cs_attack_sequence(min_duration = min_duration, max_duration = max_duration) + + def _cs_pickit(self, skip_inspect: bool = False): + new_items = self._pickit.pick_up_items(self) + self._picked_up_items |= new_items + if not skip_inspect and new_items: + set_panel_check_paused(True) + inspect_items(grab(), ignore_sell=True) + set_panel_check_paused(False) + + + def kill_pindle(self) -> bool: + atk_len_dur = float(Config().char["atk_len_pindle"]) + pindle_pos_abs = convert_screen_to_abs(Config().path["pindle_end"][0]) + + if (self.capabilities.can_teleport_natively or self.capabilities.can_teleport_with_charges) and self._use_safer_routines: + # Slightly retreating, so the Merc gets charged + if not self._pather.traverse_nodes([102], self, timeout=1.0, do_pre_move=False, force_move=True,force_tp=False, use_tp_charge=False): + return False + # Doing one Teleport to safe_dist to grab our Merc + Logger.debug("Teleporting backwards to let Pindle charge the MERC. Looks strange, but is intended!") #I would leave this message in, so users dont complain that there is a strange movement pattern. + if not self._pather.traverse_nodes([103], self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True): + return False + # Slightly retreating, so the Merc gets charged + if not self._pather.traverse_nodes([103], self, timeout=1.0, do_pre_move=False, force_move=True, force_tp=False, use_tp_charge=False): + return False + else: + keyboard.send(self._skill_hotkeys["conviction"]) + wait(0.15) + self._pather.traverse_nodes([103], self, timeout=1.0, do_pre_move=False) + + cast_pos_abs = [pindle_pos_abs[0] * 0.9, pindle_pos_abs[1] * 0.9] + self._generic_foh_attack_sequence(default_target_abs=cast_pos_abs, min_duration=atk_len_dur, max_duration=atk_len_dur*3, default_spray=11) + + if self.capabilities.can_teleport_natively: + self._pather.traverse_nodes_fixed("pindle_end", self) + else: + + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.15) + self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, timeout=1.0, do_pre_move=False) + + # Use target-based attack sequence one more time before pickit + self._generic_foh_attack_sequence(default_target_abs=cast_pos_abs, max_duration=atk_len_dur, default_spray=11) + self._activate_cleanse_redemption() + + return True + + + def kill_council(self) -> bool: + atk_len_dur = float(Config().char["atk_len_trav"]) + + keyboard.send(self._skill_hotkeys["conviction"]) + wait(.15) + # traverse to nodes and attack + nodes = [225, 226, 300] + for i, node in enumerate(nodes): + self._pather.traverse_nodes([node], self, timeout=2.2, do_pre_move = False, force_tp=(self.capabilities.can_teleport_natively or i > 0), use_tp_charge=(self.capabilities.can_teleport_natively or i > 0)) + default_target_abs = self._pather.find_abs_node_pos(node, img := grab()) or self._pather.find_abs_node_pos(906, img) or (-50, -50) + self._generic_foh_attack_sequence(default_target_abs=default_target_abs, min_duration=atk_len_dur, max_duration=atk_len_dur*3, default_spray=80) + + # return to 226 and prepare for pickit + self._pather.traverse_nodes([226], self, timeout=2.2, do_pre_move = False, force_tp=True, use_tp_charge=True) + default_target_abs = self._pather.find_abs_node_pos(226, img := grab()) or self._pather.find_abs_node_pos(906, img) or (-50, -50) + self._generic_foh_attack_sequence(default_target_abs=default_target_abs, max_duration=atk_len_dur*3, default_spray=80) + + self._activate_cleanse_redemption() + + return True + + def kill_eldritch(self) -> bool: + eld_pos_abs = convert_screen_to_abs(Config().path["eldritch_end"][0]) + atk_len_dur = float(Config().char["atk_len_eldritch"]) + + self._generic_foh_attack_sequence(default_target_abs=eld_pos_abs, min_duration=atk_len_dur, max_duration=atk_len_dur*3, default_spray=70) + + # move to end node + pos_m = convert_abs_to_monitor((70, -200)) + self.pre_move() + self.move(pos_m, force_move=True) + self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=0.1) + + # check mobs one more time before pickit + self._generic_foh_attack_sequence(default_target_abs=eld_pos_abs, max_duration=atk_len_dur, default_spray=70) + self._activate_cleanse_redemption() + + return True + + + def kill_shenk(self): + atk_len_dur = float(Config().char["atk_len_shenk"]) + + # traverse to shenk + keyboard.send(self._skill_hotkeys["conviction"]) + wait(0.15) + self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) + wait(0.05, 0.1) + + # bypass mob detect first + self._cast_foh((0, 0), spray=11, min_duration = 2, aura = "conviction") + # then do generic mob detect sequence + diff = atk_len_dur if atk_len_dur <= 2 else (atk_len_dur - 2) + self._generic_foh_attack_sequence(min_duration=atk_len_dur - diff, max_duration=atk_len_dur*3 - diff, default_spray=10, target_detect=False) + self._activate_cleanse_redemption() + + return True + + + def kill_nihlathak(self, end_nodes: list[int]) -> bool: + atk_len_dur = Config().char["atk_len_nihlathak"] + # Move close to nihlathak + self._pather.traverse_nodes(end_nodes, self, timeout=0.8, do_pre_move=False) + if self._select_skill("blessed_hammer"): + self._cast_hammers(atk_len_dur/4) + self._cast_hammers(2*atk_len_dur/4, "redemption") + self._move_and_attack((30, 15), atk_len_dur/4, "redemption") + else: + Logger.warning("FOHDin without blessed hammer is not very strong vs. Nihlathak!") + self._generic_foh_attack_sequence(min_duration=atk_len_dur/2, max_duration=atk_len_dur, default_spray=70, aura="redemption") + self._generic_foh_attack_sequence(min_duration=atk_len_dur/2, max_duration=atk_len_dur, default_spray=70, aura="redemption") + self._generic_foh_attack_sequence(max_duration=atk_len_dur*2, default_spray=70) + self._activate_cleanse_redemption() + return True + + def kill_summoner(self) -> bool: + # Attack + atk_len_dur = Config().char["atk_len_arc"] + self._generic_foh_attack_sequence(min_duration=atk_len_dur, max_duration=atk_len_dur*2, default_spray=80) + self._activate_cleanse_redemption() + return True + + + ######################################################################################## + # Chaos Sanctuary, Trash, Seal Bosses (a = Vizier, b = De Seis, c = Infector) & Diablo # + ######################################################################################## + + def kill_cs_trash(self, location:str) -> bool: + + ########### + # SEALDANCE + ########### + + #these locations have no traverses and are basically identical. + #if location in ("sealdance", "rof_01", "rof_02", "entrance_hall_01", "entrance_hall_02", "entrance1_01", "entrance1_02", "entrance1_03", "entrance1_04", "entrance2_01", "entrance2_03"): + + match location: + case "sealdance": #if seal opening fails & trash needs to be cleared -> used at ANY seal + ### APPROACH + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + + + ################ + # CLEAR CS TRASH + ################ + + case "rof_01": #node 603 - outside CS in ROF + ### APPROACH ### + if not self._pather.traverse_nodes([603], self, timeout=3): return False #calibrate after static path + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([603], self): return False #calibrate after looting + + + case "rof_02": #node 604 - inside ROF + ### APPROACH ### + if not self._pather.traverse_nodes([604], self, timeout=3): return False #threshold=0.8 (ex 601) + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + case "entrance_hall_01": ##static_path "diablo_entrance_hall_1", node 677, CS Entrance Hall1 + ### APPROACH ### + self._pather.traverse_nodes_fixed("diablo_entrance_hall_1", self) # 604 -> 671 Hall1 + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + case "entrance_hall_02": #node 670,671, CS Entrance Hall1, CS Entrance Hall1 + ### APPROACH ### + if not self._pather.traverse_nodes([670], self): return False # pull top mobs 672 to bottom 670 + self._pather.traverse_nodes_fixed("diablo_entrance_1_670_672", self) # 604 -> 671 Hall1 + if not self._pather.traverse_nodes([670], self): return False # pull top mobs 672 to bottom 670 + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([671], self): return False # calibrate before static path + self._pather.traverse_nodes_fixed("diablo_entrance_hall_2", self) # 671 -> LC Hall2 + + + + # TRASH LAYOUT A + + case "entrance1_01": #static_path "diablo_entrance_hall_2", Hall1 (before layout check) + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([673], self): return False # , timeout=3): # Re-adjust itself and continues to attack + + case "entrance1_02": #node 673 + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + self._pather.traverse_nodes_fixed("diablo_entrance_1_1", self) # Moves char to postion close to node 674 continues to attack + if not self._pather.traverse_nodes([674], self): return False#, timeout=3) + + case "entrance1_03": #node 674 + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([675], self): return False#, timeout=3) # Re-adjust itself + self._pather.traverse_nodes_fixed("diablo_entrance_1_1", self) #static path to get to be able to spot 676 + if not self._pather.traverse_nodes([676], self): return False#, timeout=3) + + case "entrance1_04": #node 676- Hall3 + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + # TRASH LAYOUT B + + case "entrance2_01": #static_path "diablo_entrance_hall_2" + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + case "entrance2_02": #node 682 + ### APPROACH ### + #if not self._pather.traverse_nodes([682], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + case "entrance2_03": #node 683 + ### APPROACH ### + #if not self._pather.traverse_nodes([682], self): return False # , timeout=3): + #self._pather.traverse_nodes_fixed("diablo_entrance2_1", self) + #if not self._pather.traverse_nodes([683], self): return False # , timeout=3): + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_top1", self) #pull mobs from top + wait (0.2, 0.5) + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_top2", self) #pull mobs from top + if not self._pather.traverse_nodes([605], self): return False#, timeout=3) + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + case "entrance2_04": #node 686 - Hall3 + ### APPROACH ### + if not self._pather.traverse_nodes([605], self): return False#, timeout=3) + #if not self._pather.traverse_nodes([683,684], self): return False#, timeout=3) + #self._pather.traverse_nodes_fixed("diablo_entrance2_2", self) + #if not self._pather.traverse_nodes([685,686], self): return False#, timeout=3) + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_hall3", self) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + self._pather.traverse_nodes_fixed("diablo_trash_b_hall3_pull_609", self) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit(skip_inspect=True) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + self._cs_pickit() + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + + #################### + # PENT TRASH TO SEAL + #################### + + case "dia_trash_a" | "dia_trash_b" | "dia_trash_c": #trash before between Pentagramm and Seal A Layoutcheck + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + ############### + # LAYOUT CHECKS + ############### + + case "layoutcheck_a" | "layoutcheck_b" | "layoutcheck_c": #layout check seal A, node 619 A1-L, node 620 A2-Y + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + ################## + # PENT BEFORE SEAL + ################## + + case "pent_before_a": #node 602, pentagram, before CTA buff & depature to layout check - not needed when trash is skipped & seals run in right order + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + Logger.debug("No attack choreography available in fohdin.py for this node " + location + " - skipping to shorten run.") + + case "pent_before_b" | "pent_before_c": #node 602, pentagram, before CTA buff & depature to layout check + ### APPROACH ### + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + ########### + # SEAL A1-L + ########### + + case "A1-L_01": #node 611 seal layout A1-L: safe_dist + ### APPROACH ### + if not self._pather.traverse_nodes([611], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + # we loot at boss + + case "A1-L_02": #node 612 seal layout A1-L: center + ### APPROACH ### + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + # we loot at boss + + case "A1-L_03": #node 613 seal layout A1-L: fake_seal + ### APPROACH ### + if not self._pather.traverse_nodes([613], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + + case "A1-L_seal1": #node 613 seal layout A1-L: fake_seal + ### APPROACH ### + self._cs_pickit() + if not self._pather.traverse_nodes([614], self): return False + ### ATTACK ### + self._activate_redemption_aura() + ### LOOT ### + # we loot at boss + + case "A1-L_seal2": #node 614 seal layout A1-L: boss_seal + ### APPROACH ### + if not self._pather.traverse_nodes([613, 615], self): return False # , timeout=3): + ### ATTACK ### + self._activate_redemption_aura() + ### LOOT ### + # we loot at boss + + ########### + # SEAL A2-Y + ########### + + case "A2-Y_01": #node 622 seal layout A2-Y: safe_dist + ### APPROACH ### + if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False + Logger.debug("A2-Y: Hop!") + #if not self._pather.traverse_nodes([622], self): return False # , timeout=3): + if not self._pather.traverse_nodes([622], self): return False + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + # we loot at boss + + case "A2-Y_02": #node 623 seal layout A2-Y: center + ### APPROACH ### + # if not self._pather.traverse_nodes([623,624], self): return False # + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + # we loot at boss + + case "A2-Y_03": #skipped + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in fohdin.py for this node " + location + " - skipping to shorten run.") + + case "A2-Y_seal1": #node 625 seal layout A2-Y: fake seal + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + if not self._pather.traverse_nodes([625], self): return False # , timeout=3): + self._activate_redemption_aura() + + case "A2-Y_seal2": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + self._pather.traverse_nodes_fixed("dia_a2y_sealfake_sealboss", self) #instead of traversing node 626 which causes issues + self._activate_redemption_aura() + + ########### + # SEAL B1-S + ########### + + case "B1-S_01" | "B1-S_02" | "B1-S_03": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in fohdin.py for this node " + location + " - skipping to shorten run.") + + case "B1-S_seal2": #B only has 1 seal, which is the boss seal = seal2 + ### APPROACH ### + if not self._pather.traverse_nodes([634], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + + + ########### + # SEAL B2-U + ########### + + case "B2-U_01" | "B2-U_02" | "B2-U_03": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in fohdin.py for this node " + location + " - skipping to shorten run.") + + case "B2-U_seal2": #B only has 1 seal, which is the boss seal = seal2 + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_b2u_bold_seal", self) + if not self._pather.traverse_nodes([644], self): return False # , timeout=3): + ### ATTACK ### + self._activate_redemption_aura() + ### LOOT ### + # we loot at boss + + + ########### + # SEAL C1-F + ########### + + case "C1-F_01" | "C1-F_02" | "C1-F_03": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in fohdin.py for this node " + location + " - skipping to shorten run.") + + case "C1-F_seal1": + ### APPROACH ### + wait(0.1,0.3) + self._pather.traverse_nodes_fixed("dia_c1f_hop_fakeseal", self) + wait(0.1,0.3) + if not self._pather.traverse_nodes([655], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([655], self): return False # , timeout=3): + self._activate_redemption_aura() + + case "C1-F_seal2": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_c1f_654_651", self) + if not self._pather.traverse_nodes([652], self): return False # , timeout=3): + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([652], self): return False # , timeout=3): + self._activate_redemption_aura() + + ########### + # SEAL C2-G + ########### + + case "C2-G_01" | "C2-G_02" | "C2-G_03": #skipped + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in fohdin.py for this node " + location + " - skipping to shorten run.") + + case "C2-G_seal1": + ### APPROACH ### + if not self._pather.traverse_nodes([663, 662], self) or not self._pather.traverse_nodes_fixed("dia_c2g_lc_661", self): + return False + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + if not self._pather.traverse_nodes([662], self): return False + self._activate_redemption_aura() + + + case "C2-G_seal2": + ### APPROACH ### + # Killing infector here, because for C2G its the only seal where a bossfight occures BETWEEN opening seals + seal_layout="C2-G" + if not self._pather.traverse_nodes([662], self) or not self._pather.traverse_nodes_fixed("dia_c2g_663", self): + return False + ### ATTACK ### + atk_dur_min = Config().char["atk_len_diablo_infector"] + atk_dur_max = atk_dur_min * 3 + Logger.debug(seal_layout + ": Attacking Infector at position 1/2") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + if not self._pather.traverse_nodes([663], self): return False # , timeout=3): + Logger.debug(seal_layout + ": Attacking Infector at position 2/2") + self._cs_attack_sequence(min_duration=2, max_duration=atk_dur_max) + ### LOOT ### + self._cs_pickit(skip_inspect=True) # inspect on other + if not self._pather.traverse_nodes([664, 665], self): return False # , timeout=3): + + case _: + ### APPROACH ### + Logger.error("No location argument given for kill_cs_trash(" + location + "), should not happen") + ### ATTACK ### + self._cs_trash_mobs_attack_sequence() + ### LOOT ### + self._cs_pickit() + return True + + + def kill_vizier(self, seal_layout:str) -> bool: + atk_dur_min = Config().char["atk_len_diablo_vizier"] + atk_dur_max = atk_dur_min * 3 + match seal_layout: + case "A1-L": + ### APPROACH ### + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking Vizier at position 1/2") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") + self._pather.traverse_nodes([611], self, timeout=3) + self._cs_attack_sequence(min_duration=2, max_duration=atk_dur_max) + ### LOOT ### + self._cs_pickit(skip_inspect=True) + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): + self._activate_cleanse_redemption() + self._cs_pickit() + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): # recalibrate after loot + + case "A2-Y": + ### APPROACH ### + if not self._pather.traverse_nodes([627, 622], self): return False # , timeout=3): + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking Vizier at position 1/3") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + Logger.debug(seal_layout + ": Attacking Vizier at position 2/3") + self._pather.traverse_nodes([623], self, timeout=3) + self._cs_attack_sequence(min_duration=1.5, max_duration=atk_dur_max) + Logger.debug(seal_layout + ": Attacking Vizier at position 3/3") + if not self._pather.traverse_nodes([624], self): return False + self._cs_attack_sequence(min_duration=1.5, max_duration=atk_dur_max) + ### LOOT ### + self._cs_pickit(skip_inspect=True) + if not self._pather.traverse_nodes([624], self): return False + if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False + Logger.debug(seal_layout + ": Hop!") + self._activate_cleanse_redemption() + if not self._pather.traverse_nodes([622], self): return False #, timeout=3): + self._activate_redemption_aura() + self._cs_pickit() + if not self._pather.traverse_nodes([622], self): return False # , timeout=3): #recalibrate after loot + + case _: + Logger.warning(seal_layout + ": Invalid location for kill_vizier("+ seal_layout +"), should not happen.") + return False + return True + + + def kill_deseis(self, seal_layout:str) -> bool: + atk_dur_min = Config().char["atk_len_diablo_deseis"] + atk_dur_max = atk_dur_min * 3 + match seal_layout: + case "B1-S": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_b1s_seal_deseis_foh", self) + nodes = [631] + ### ATTACK ### + Logger.debug(f"{seal_layout}: Attacking De Seis at position 1/{len(nodes)+1}") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + for i, node in enumerate(nodes): + Logger.debug(f"{seal_layout}: Attacking De Seis at position {i+2}/{len(nodes)+1}") + self._pather.traverse_nodes([node], self, timeout=3) + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + self._activate_redemption_aura(delay=[1, 2]) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + ### LOOT ### + self._cs_pickit() + + case "B2-U": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_b2u_644_646", self) # We try to breaking line of sight, sometimes makes De Seis walk into the hammercloud. A better attack sequence here could make sense. + #self._pather.traverse_nodes_fixed("dia_b2u_seal_deseis", self) # We try to breaking line of sight, sometimes makes De Seis walk into the hammercloud. A better attack sequence here could make sense. + nodes = [646, 641] + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking De Seis at position 1/{len(nodes)+1}") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + for i, node in enumerate(nodes): + Logger.debug(f"{seal_layout}: Attacking De Seis at position {i+2}/{len(nodes)+1}") + self._pather.traverse_nodes([node], self, timeout=3) + self._cs_attack_sequence(min_duration=2, max_duration=atk_dur_max) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + ### LOOT ### + self._cs_pickit(skip_inspect=True) + if not self._pather.traverse_nodes([641], self): return False # , timeout=3): + if not self._pather.traverse_nodes([646], self): return False # , timeout=3): + self._cs_pickit(skip_inspect=True) + if not self._pather.traverse_nodes([646], self): return False # , timeout=3): + if not self._pather.traverse_nodes([640], self): return False # , timeout=3): + self._cs_pickit() + + case _: + Logger.warning(seal_layout + ": Invalid location for kill_deseis("+ seal_layout +"), should not happen.") + return False + return True + + + def kill_infector(self, seal_layout:str) -> bool: + atk_dur_min = Config().char["atk_len_diablo_infector"] + atk_dur_max = atk_dur_min * 3 + match seal_layout: + case "C1-F": + ### APPROACH ### + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking Infector at position 1/1") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + self._pather.traverse_nodes_fixed("dia_c1f_652", self) + Logger.debug(seal_layout + ": Attacking Infector at position 2/2") + self._cs_attack_sequence(min_duration=2, max_duration=atk_dur_max) + ### LOOT ### + self._cs_pickit() + + case "C2-G": + ### APPROACH ### + if not self._pather.traverse_nodes([665], self): return False # , timeout=3): + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking Infector at position 1/2") + self._cs_attack_sequence(min_duration=atk_dur_min, max_duration=atk_dur_max) + if not self._pather.traverse_nodes([663], self): return False # , timeout=3): + Logger.debug(seal_layout + ": Attacking Infector at position 2/2") + self._cs_attack_sequence(min_duration=2, max_duration=atk_dur_max) + ### LOOT ### + self._cs_pickit() + + case _: + Logger.warning(seal_layout + ": Invalid location for kill_infector("+ seal_layout +"), should not happen.") + return False + return True + + + #no aura effect on dia. not good for mob detection + def kill_diablo(self) -> bool: + ### APPROACH ### + ### ATTACK ### + atk_len_dur = float(Config().char["atk_len_diablo"]) + Logger.debug("Attacking Diablo at position 1/1") + diablo_abs = [100,-100] #hardcoded dia pos. + self._generic_foh_attack_sequence(default_target_abs=diablo_abs, min_duration=atk_len_dur, max_duration=atk_len_dur*3, aura="concentration", foh_to_holy_bolt_ratio=2) + self._activate_cleanse_redemption() + ### LOOT ### + #self._cs_pickit() + return True \ No newline at end of file diff --git a/src/char/paladin/hammerdin.py b/src/char/paladin/hammerdin.py new file mode 100644 index 000000000..8fa88ed1b --- /dev/null +++ b/src/char/paladin/hammerdin.py @@ -0,0 +1,1274 @@ +import keyboard +import random +import time + +from char import CharacterCapabilities +from char.paladin import Paladin +from config import Config +from logger import Logger +from pather import Location +from pather import Pather +from pather import Pather, Location +from screen import convert_abs_to_monitor, convert_screen_to_abs, grab +from target_detect import get_visible_targets +from ui import skills +from utils.custom_mouse import mouse +from utils.misc import wait + +class Hammerdin(Paladin): + def __init__(self, *args, **kwargs): + Logger.info("Setting up Hammerdin") + super().__init__(*args, **kwargs) + #hammerdin needs to be closer to shenk to reach it with hammers + self._pather.offset_node(149, (70, 10)) + + def _cast_hammers(self, time_in_s: float, aura: str = "concentration"): + if aura in self._skill_hotkeys and self._skill_hotkeys[aura]: + keyboard.send(self._skill_hotkeys[aura]) + wait(0.05, 0.1) + keyboard.send(Config().char["stand_still"], do_release=False) + wait(0.05, 0.1) + if self._skill_hotkeys["blessed_hammer"]: + keyboard.send(self._skill_hotkeys["blessed_hammer"]) + wait(0.05, 0.1) + start = time.time() + while (time.time() - start) < time_in_s: + wait(0.06, 0.08) + mouse.press(button="left") + wait(0.1, 0.2) + mouse.release(button="left") + wait(0.01, 0.05) + keyboard.send(Config().char["stand_still"], do_press=False) + + def pre_buff(self): + if Config().char["cta_available"]: + self._pre_buff_cta() + keyboard.send(self._skill_hotkeys["holy_shield"]) + wait(0.04, 0.1) + mouse.click(button="right") + wait(self._cast_duration, self._cast_duration + 0.06) + + def pre_move(self): + # select teleport if available + super().pre_move() + # in case teleport hotkey is not set or teleport can not be used, use vigor if set + should_cast_vigor = self._skill_hotkeys["vigor"] and not skills.is_right_skill_selected(["VIGOR"]) + can_teleport = self.capabilities.can_teleport_natively and skills.is_right_skill_active() + if should_cast_vigor and not can_teleport: + keyboard.send(self._skill_hotkeys["vigor"]) + wait(0.15, 0.25) + + def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float): + pos_m = convert_abs_to_monitor(abs_move) + self.pre_move() + self.move(pos_m, force_move=True) + self._cast_hammers(atk_len) + + def kill_pindle(self) -> bool: + wait(0.1, 0.15) + if self.capabilities.can_teleport_with_charges: + if not self._pather.traverse_nodes([104], self, timeout=1.0, force_tp=True, use_tp_charge=True): + return False + elif self.capabilities.can_teleport_natively: + if not self._pather.traverse_nodes_fixed("pindle_end", self): + return False + else: + keyboard.send(self._skill_hotkeys["concentration"]) + wait(0.15) + self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) + self._cast_hammers(Config().char["atk_len_pindle"]) + wait(0.1, 0.15) + self._cast_hammers(1.6, "redemption") + return True + + def kill_eldritch(self) -> bool: + if self.capabilities.can_teleport_natively: + # Custom eld position for teleport that brings us closer to eld + self._pather.traverse_nodes_fixed([(675, 30)], self) + else: + keyboard.send(self._skill_hotkeys["concentration"]) + wait(0.15) + # Traverse without pre_move, because we don't want to activate vigor when walking! + self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) + wait(0.05, 0.1) + self._cast_hammers(Config().char["atk_len_eldritch"]) + wait(0.1, 0.15) + self._cast_hammers(1.6, "redemption") + return True + + def kill_shenk(self): + keyboard.send(self._skill_hotkeys["concentration"]) + wait(0.15) + self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) + wait(0.05, 0.1) + self._cast_hammers(Config().char["atk_len_shenk"]) + wait(0.1, 0.15) + self._cast_hammers(1.6, "redemption") + return True + + def kill_council(self) -> bool: + keyboard.send(self._skill_hotkeys["concentration"]) + wait(.15) + # Check out the node screenshot in assets/templates/trav/nodes to see where each node is at + atk_len = Config().char["atk_len_trav"] + # Go inside and hammer a bit + self._pather.traverse_nodes([228, 229], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True) + # Move a bit back and another round + self._move_and_attack((40, 20), atk_len) + # Here we have two different attack sequences depending if tele is available or not + if self.capabilities.can_teleport_natively or self.capabilities.can_teleport_with_charges: + # Back to center stairs and more hammers + self._pather.traverse_nodes([226], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True) + self._cast_hammers(atk_len) + # move a bit to the top + self._move_and_attack((65, -30), atk_len) + else: + # Stay inside and cast hammers again moving forward + self._move_and_attack((40, 10), atk_len) + self._move_and_attack((-40, -20), atk_len) + self._cast_hammers(1.6, "redemption") + return True + + def kill_nihlathak(self, end_nodes: list[int]) -> bool: + # Move close to nihlathak + self._pather.traverse_nodes(end_nodes, self, timeout=0.8, do_pre_move=False) + # move mouse to center, otherwise hammers sometimes dont fly, not sure why + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._cast_hammers(Config().char["atk_len_nihlathak"] * 0.4) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((30, 15), Config().char["atk_len_nihlathak"] * 0.3) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_nihlathak"] * 0.4) + wait(0.1, 0.15) + self._cast_hammers(1.2, "redemption") + return True + + def kill_summoner(self) -> bool: + # move mouse to below altar + pos_m = convert_abs_to_monitor((0, 20)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + # Attack + self._cast_hammers(Config().char["atk_len_arc"]) + wait(0.1, 0.15) + self._cast_hammers(1.6, "redemption") + # Move a bit back and another round + self._move_and_attack((0, 80), Config().char["atk_len_arc"] * 0.5) + wait(0.1, 0.15) + self._cast_hammers(1.6, "redemption") + return True + + ######################################################################################## + # Chaos Sanctuary, Trash, Seal Bosses (a = Vizier, b = De Seis, c = Infector) & Diablo # + ######################################################################################## + + def kill_cs_trash(self, location:str) -> bool: + + ########### + # SEALDANCE + ########### + match location: + case "sealdance": #if seal opening fails & trash needs to be cleared -> used at ANY seal + ### APPROACH + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.5, 1.0) #clear seal from corpses + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + ################ + # CLEAR CS TRASH + ################ + + case "rof_01": #node 603 - outside CS in ROF + ### APPROACH ### + if not self._pather.traverse_nodes([603], self, timeout=3): return False #calibrate after static path + pos_m = convert_abs_to_monitor((0, 0)) + ### ATTACK ### + wait(1)#give merc the chance to activate holy freeze + #print("mercwait") + if not Config().char['cs_mob_detect'] or get_visible_targets(): + + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + ### LOOT ### + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([603], self): return False #calibrate after looting + + + case "rof_02": #node 604 - inside ROF + ### APPROACH ### + if not self._pather.traverse_nodes([604], self, timeout=3): return False #threshold=0.8 (ex 601) + ### ATTACK ### + wait(1)#give merc the chance to activate holy freeze + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "entrance_hall_01": ##static_path "diablo_entrance_hall_1", node 677, CS Entrance Hall1 + ### APPROACH ### + self._pather.traverse_nodes_fixed("diablo_entrance_hall_1", self) # 604 -> 671 Hall1 + ### ATTACK ### + wait(1)#give merc the chance to activate holy freeze + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "entrance_hall_02": #node 670,671, CS Entrance Hall1, CS Entrance Hall1 + ### APPROACH ### + if not self._pather.traverse_nodes([670], self): return False # pull top mobs 672 to bottom 670 + self._pather.traverse_nodes_fixed("diablo_entrance_1_670_672", self) # 604 -> 671 Hall1 + if not self._pather.traverse_nodes([670], self): return False # pull top mobs 672 to bottom 670 + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + #Move to Layout Check + if not self._pather.traverse_nodes([671], self): return False # calibrate before static path + self._pather.traverse_nodes_fixed("diablo_entrance_hall_2", self) # 671 -> LC Hall2 + + + + # TRASH LAYOUT A + + case "entrance1_01": #static_path "diablo_entrance_hall_2", Hall1 (before layout check) + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([673], self): return False # , timeout=3): # Re-adjust itself and continues to attack + + case "entrance1_02": #node 673 + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + self._pather.traverse_nodes_fixed("diablo_entrance_1_1", self) # Moves char to postion close to node 674 continues to attack + if not self._pather.traverse_nodes([674], self): return False#, timeout=3) + + case "entrance1_03": #node 674 + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([675], self): return False#, timeout=3) # Re-adjust itself + self._pather.traverse_nodes_fixed("diablo_entrance_1_1", self) #static path to get to be able to spot 676 + if not self._pather.traverse_nodes([676], self): return False#, timeout=3) + + case "entrance1_04": #node 676- Hall3 + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-50, -150), Config().char["atk_len_cs_trashmobs"]) + self._move_and_attack((50, 150), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + # TRASH LAYOUT B + + case "entrance2_01": #static_path "diablo_entrance_hall_2" + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "entrance2_02": #node 682 + ### APPROACH ### + #if not self._pather.traverse_nodes([682], self): return False # , timeout=3): + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_right", self) #pull mobs from the right + wait (0.2, 0.5) + if not self._pather.traverse_nodes([605], self): return False#, timeout=3) + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "entrance2_03": #node 683 + ### APPROACH ### + #if not self._pather.traverse_nodes([682], self): return False # , timeout=3): + #self._pather.traverse_nodes_fixed("diablo_entrance2_1", self) + #if not self._pather.traverse_nodes([683], self): return False # , timeout=3): + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_top1", self) #pull mobs from top + wait (0.2, 0.5) + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_top2", self) #pull mobs from top + if not self._pather.traverse_nodes([605], self): return False#, timeout=3) + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "entrance2_04": #node 686 - Hall3 + ### APPROACH ### + if not self._pather.traverse_nodes([605], self): return False#, timeout=3) + #if not self._pather.traverse_nodes([683,684], self): return False#, timeout=3) + #self._pather.traverse_nodes_fixed("diablo_entrance2_2", self) + #if not self._pather.traverse_nodes([685,686], self): return False#, timeout=3) + self._pather.traverse_nodes_fixed("diablo_trash_b_hall2_605_hall3", self) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + self._pather.traverse_nodes_fixed("diablo_trash_b_hall3_pull_609", self) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((0, 0), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-50, -150), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._move_and_attack((50, 150), Config().char["atk_len_cs_trashmobs"] * 0.2) + self._move_and_attack((250, -150), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._move_and_attack((-250, -150), Config().char["atk_len_cs_trashmobs"] * 0.2) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([609], self): return False#, timeout=3) + + #################### + # PENT TRASH TO SEAL + #################### + + case "dia_trash_a": #trash before between Pentagramm and Seal A Layoutcheck + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) + self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "dia_trash_b": #trash before between Pentagramm and Seal B Layoutcheck + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) + self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "dia_trash_c": ##trash before between Pentagramm and Seal C Layoutcheck + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) + self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"]) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + ############### + # LAYOUT CHECKS + ############### + + case "layoutcheck_a": #layout check seal A, node 619 A1-L, node 620 A2-Y + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + #Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "layoutcheck_b": #layout check seal B, node 634 B1-S, node 649 B2-U + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "layoutcheck_c": #layout check seal C, node 656 C1-F, node 664 C2-G + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + ################## + # PENT BEFORE SEAL + ################## + + case "pent_before_a": #node 602, pentagram, before CTA buff & depature to layout check - not needed when trash is skipped & seals run in right order + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "pent_before_b": #node 602, pentagram, before CTA buff & depature to layout check + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + case "pent_before_c": #node 602, pentagram, before CTA buff & depature to layout check + ### APPROACH ### + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + ########### + # SEAL A1-L + ########### + + case "A1-L_01": #node 611 seal layout A1-L: safe_dist + ### APPROACH ### + if not self._pather.traverse_nodes([611], self): return False # , timeout=3): + ### ATTACK ### + wait(1)#give merc the chance to activate holy freeze + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + # we loot at boss + + case "A1-L_02": #node 612 seal layout A1-L: center + ### APPROACH ### + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.5, "cleansing") + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + # we loot at boss + + case "A1-L_03": #node 613 seal layout A1-L: fake_seal + ### APPROACH ### + if not self._pather.traverse_nodes([613], self): return False # , timeout=3): + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.5, "cleansing") + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + + case "A1-L_seal1": #node 613 seal layout A1-L: fake_seal + ### APPROACH ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([614], self): return False + ### ATTACK ### + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + # we loot at boss + + case "A1-L_seal2": #node 614 seal layout A1-L: boss_seal + ### APPROACH ### + if not self._pather.traverse_nodes([613, 615], self): return False # , timeout=3): + ### ATTACK ### + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + # we loot at boss + + ########### + # SEAL A2-Y + ########### + + case "A2-Y_01": #node 622 seal layout A2-Y: safe_dist + ### APPROACH ### + if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False + Logger.debug("A2-Y: Hop!") + #if not self._pather.traverse_nodes([622], self): return False # , timeout=3): + if not self._pather.traverse_nodes([622], self): return False + wait(1)#give merc the chance to activate holy freeze + if not Config().char['cs_mob_detect'] or get_visible_targets(): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### ATTACK ### + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + # we loot at boss + + case "A2-Y_02": #node 623 seal layout A2-Y: center + ### APPROACH ### + # if not self._pather.traverse_nodes([623,624], self): return False # + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + # we loot at boss + + case "A2-Y_03": #skipped + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "A2-Y_seal1": #node 625 seal layout A2-Y: fake seal + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + if not self._pather.traverse_nodes([625], self): return False # , timeout=3): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + + case "A2-Y_seal2": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + self._pather.traverse_nodes_fixed("dia_a2y_sealfake_sealboss", self) #instead of traversing node 626 which causes issues + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + + ########### + # SEAL B1-S + ########### + + case "B1-S_01": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "B1-S_02": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "B1-S_03": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "B1-S_seal2": #B only has 1 seal, which is the boss seal = seal2 + ### APPROACH ### + if not self._pather.traverse_nodes([634], self): return False # , timeout=3): + ### ATTACK ### + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + + + ########### + # SEAL B2-U + ########### + + case "B2-U_01": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "B2-U_02": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "B2-U_03": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "B2-U_seal2": #B only has 1 seal, which is the boss seal = seal2 + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_b2u_bold_seal", self) + if not self._pather.traverse_nodes([644], self): return False # , timeout=3): + ### ATTACK ### + ### LOOT ### + # we loot at boss + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + + + ########### + # SEAL C1-F + ########### + + case "C1-F_01": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "C1-F_02": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "C1-F_03": + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "C1-F_seal1": + ### APPROACH ### + wait(0.1,0.3) + self._pather.traverse_nodes_fixed("dia_c1f_hop_fakeseal", self) + wait(0.1,0.3) + if not self._pather.traverse_nodes([655], self): return False # , timeout=3): + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([655], self): return False # , timeout=3): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + + case "C1-F_seal2": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_c1f_654_651", self) + if not self._pather.traverse_nodes([652], self): return False # , timeout=3): + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([652], self): return False # , timeout=3): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + + ########### + # SEAL C2-G + ########### + + case "C2-G_01": #skipped + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "C2-G_02": #skipped + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "C2-G_03": #skipped + ### APPROACH ### + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + + case "C2-G_seal1": + ### APPROACH ### + #if not self._pather.traverse_nodes([663, 662], self): return False # , timeout=3): #caused 7% failed runs, replaced by static path. + self._pather.traverse_nodes_fixed("dia_c2g_lc_661", self) + ### ATTACK ### + ### LOOT ### + # we loot at boss + Logger.debug("No attack choreography available in hammerdin.py for this node " + location + " - skipping to shorten run.") + """ + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + """ + + case "C2-G_seal2": + ### APPROACH ### + # Killing infector here, because for C2G its the only seal where a bossfight occures BETWEEN opening seals + seal_layout="C2-G" + self._pather.traverse_nodes_fixed("dia_c2g_663", self) + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + Logger.debug(seal_layout + ": Attacking Infector at position 1/1") + self._cast_hammers(Config().char["atk_len_diablo_infector"]) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((30, 15), Config().char["atk_len_diablo_infector"]) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((30, -15), Config().char["atk_len_diablo_infector"]) + wait(0.1, 0.15) + self._cast_hammers(1.2, "redemption") + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + if not self._pather.traverse_nodes([664, 665], self): return False # , timeout=3): + + case _: + ### APPROACH ### + Logger.warning("I have no location argument given for kill_cs_trash(" + location + "), should not happen. Throwing some random hammers") + ### ATTACK ### + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) + self._cast_hammers(0.75, "redemption") + self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + return True + + + + def kill_vizier(self, seal_layout:str) -> bool: + if seal_layout == "A1-L": + ### APPROACH ### + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking Vizier at position 1/2") + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") + self._pather.traverse_nodes([611], self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses + self._cast_hammers(1, "redemption") + if self._skill_hotkeys["cleansing"]: + keyboard.send(self._skill_hotkeys["cleansing"]) + wait(0.1, 0.2) + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + wait(0.3, 1.2) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([612], self): return False # , timeout=3): # recalibrate after loot + + elif seal_layout == "A2-Y": + ### APPROACH ### + if not self._pather.traverse_nodes([627, 622], self): return False # , timeout=3): + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking Vizier at position 1/2") + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") + self._pather.traverse_nodes([623], self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking Vizier at position 3/3") + if not self._pather.traverse_nodes([624], self): return False + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"]) + wait(0.1, 0.15) + self._cast_hammers(2, "redemption") + self._cast_hammers(1, "cleansing") + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([624], self): return False + if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False + Logger.debug(seal_layout + ": Hop!") + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + if not self._pather.traverse_nodes([622], self): return False #, timeout=3): + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([622], self): return False # , timeout=3): #recalibrate after loot + + else: + Logger.warning(seal_layout + ": Invalid location for kill_deseis("+ seal_layout +"), should not happen.") + return False + return True + + + + def kill_deseis(self, seal_layout:str) -> bool: + if seal_layout == "B1-S": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_b1s_seal_deseis", self) # quite aggressive path, but has high possibility of directly killing De Seis with first hammers, for 50% of his spawn locations + nodes1 = [632] + nodes2 = [631] + nodes3 = [632] + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking De Seis at position 1/4") + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking De Seis at position 2/4") + self._pather.traverse_nodes(nodes1, self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking De Seis at position 3/4") + self._pather.traverse_nodes(nodes2, self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"] * 0.5) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking De Seis at position 4/4") + self._pather.traverse_nodes(nodes3, self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses + wait(0.1, 0.2) + self._cast_hammers(2, "redemption") + self._cast_hammers(1, "cleansing") + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(2.5, 3.5) # to keep redemption on for a couple of seconds before the next teleport to have more corpses cleared & increase chance to find next template + Logger.debug(seal_layout + ": Waiting with Redemption active to clear more corpses.") + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + elif seal_layout == "B2-U": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_b2u_644_646", self) # We try to breaking line of sight, sometimes makes De Seis walk into the hammercloud. A better attack sequence here could make sense. + #self._pather.traverse_nodes_fixed("dia_b2u_seal_deseis", self) # We try to breaking line of sight, sometimes makes De Seis walk into the hammercloud. A better attack sequence here could make sense. + nodes1 = [640] + nodes2 = [646] + nodes3 = [641] + ### ATTACK ### + Logger.debug(seal_layout + ": Attacking De Seis at position 1/4") + if not Config().char['cs_mob_detect'] or get_visible_targets(): + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking De Seis at position 2/4") + self._pather.traverse_nodes(nodes1, self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking De Seis at position 3/4") + self._pather.traverse_nodes(nodes2, self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"] * 0.5) + self._cast_hammers(1, "redemption") + Logger.debug(seal_layout + ": Attacking De Seis at position 4/4") + self._pather.traverse_nodes(nodes3, self, timeout=3) + if not Config().char['cs_mob_detect'] or get_visible_targets(): + self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses + wait(0.1, 0.2) + self._cast_hammers(2, "redemption") + self._cast_hammers(1, "cleansing") + if self._skill_hotkeys["redemption"]: + keyboard.send(self._skill_hotkeys["redemption"]) + wait(0.3, 0.6) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([641], self): return False # , timeout=3): + if not self._pather.traverse_nodes([646], self): return False # , timeout=3): + self._picked_up_items |= self._pickit.pick_up_items(self) + if not self._pather.traverse_nodes([646], self): return False # , timeout=3): + if not self._pather.traverse_nodes([640], self): return False # , timeout=3): + self._picked_up_items |= self._pickit.pick_up_items(self) + + else: + Logger.warning(seal_layout + ": Invalid location for kill_deseis("+ seal_layout +"), should not happen.") + return False + return True + + + + def kill_infector(self, seal_layout:str) -> bool: + if seal_layout == "C1-F": + ### APPROACH ### + self._pather.traverse_nodes_fixed("dia_c1f_652", self) + ### ATTACK ### + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + Logger.debug(seal_layout + ": Attacking Infector at position 1/1") + self._cast_hammers(Config().char["atk_len_diablo_infector"] * 0.4) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((30, 15), Config().char["atk_len_diablo_infector"] * 0.3) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((30, -15), Config().char["atk_len_diablo_infector"] * 0.4) + wait(0.1, 0.15) + self._cast_hammers(1.2, "redemption") + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + + elif seal_layout == "C2-G": + # NOT killing infector here, because for C2G its the only seal where a bossfight occures BETWEEN opening seals his attack sequence can be found in C2-G_seal2 + Logger.debug(seal_layout + ": No need for attacking Infector at position 1/1 - he was killed during clearing the seal") + + else: + Logger.warning(seal_layout + ": Invalid location for kill_infector("+ seal_layout +"), should not happen.") + return False + return True + + + def kill_diablo(self) -> bool: + ### APPROACH ### + ### ATTACK ### + pos_m = convert_abs_to_monitor((0, 0)) + mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) + Logger.debug("Attacking Diablo at position 1/1") + self._cast_hammers(Config().char["atk_len_diablo"]) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((60, 30), Config().char["atk_len_diablo"]) + self._cast_hammers(0.8, "redemption") + self._move_and_attack((-60, -30), Config().char["atk_len_diablo"]) + wait(0.1, 0.15) + self._cast_hammers(1.2, "redemption") + ### LOOT ### + self._picked_up_items |= self._pickit.pick_up_items(self) + return True + + +if __name__ == "__main__": + import os + import keyboard + keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) + keyboard.wait("f11") + from config import Config + pather = Pather() + char = Hammerdin(Config().hammerdin, Config().char, pather) \ No newline at end of file diff --git a/src/char/paladin/paladin.py b/src/char/paladin/paladin.py new file mode 100644 index 000000000..283cc9baa --- /dev/null +++ b/src/char/paladin/paladin.py @@ -0,0 +1,101 @@ +import keyboard +from ui import skills +import time +import random +from utils.custom_mouse import mouse +from char import IChar, CharacterCapabilities +from pather import Pather +from logger import Logger +from config import Config +from utils.misc import wait +from screen import convert_abs_to_screen, convert_abs_to_monitor +from pather import Pather +#import cv2 #for Diablo +from item.pickit import PickIt #for Diablo + +class Paladin(IChar): + def __init__(self, skill_hotkeys: dict, pather: Pather, pickit: PickIt): + Logger.info("Setting up Paladin") + super().__init__(skill_hotkeys) + self._pather = pather + self._pickit = pickit #for Diablo + self._picked_up_items = False #for Diablo + + def pre_buff(self): + if Config().char["cta_available"]: + self._pre_buff_cta() + keyboard.send(self._skill_hotkeys["holy_shield"]) + wait(0.04, 0.1) + mouse.click(button="right") + wait(self._cast_duration, self._cast_duration + 0.06) + + def pre_move(self): + # select teleport if available + super().pre_move() + # in case teleport hotkey is not set or teleport can not be used, use vigor if set + should_cast_vigor = self._skill_hotkeys["vigor"] and not skills.is_right_skill_selected(["VIGOR"]) + can_teleport = self.capabilities.can_teleport_natively and skills.is_right_skill_active() + if should_cast_vigor and not can_teleport: + keyboard.send(self._skill_hotkeys["vigor"]) + wait(0.15, 0.25) + + def _log_cast(self, skill_name: str, cast_pos_abs: tuple[float, float], spray: int, min_duration: float, aura: str): + msg = f"Casting skill {skill_name}" + if cast_pos_abs: + msg += f" at screen coordinate {convert_abs_to_screen(cast_pos_abs)}" + if spray: + msg += f" with spray of {spray}" + if min_duration: + msg += f" for {round(min_duration, 1)}s" + if aura: + msg += f" with {aura} active" + Logger.debug(msg) + + def _click_cast(self, cast_pos_abs: tuple[float, float], spray: int, mouse_click_type: str = "left"): + if cast_pos_abs: + x = cast_pos_abs[0] + y = cast_pos_abs[1] + if spray: + x += (random.random() * 2 * spray - spray) + y += (random.random() * 2 * spray - spray) + pos_m = convert_abs_to_monitor((x, y)) + mouse.move(*pos_m, delay_factor=[0.1, 0.2]) + wait(0.06, 0.08) + mouse.press(button = mouse_click_type) + wait(0.06, 0.08) + mouse.release(button = mouse_click_type) + + def _cast_skill_with_aura(self, skill_name: str, cast_pos_abs: tuple[float, float] = None, spray: int = 0, min_duration: float = 0, aura: str = ""): + #self._log_cast(skill_name, cast_pos_abs, spray, min_duration, aura) + + # set aura if needed + if aura: + self._select_skill(aura, mouse_click_type = "right") + + # ensure character stands still + keyboard.send(Config().char["stand_still"], do_release=False) + + # set left hand skill + self._select_skill(skill_name, mouse_click_type = "left") + wait(0.04) + + # cast left hand skill + start = time.time() + if min_duration: + while (time.time() - start) <= min_duration: + self._click_cast(cast_pos_abs, spray) + else: + self._click_cast(cast_pos_abs, spray) + + # release stand still key + keyboard.send(Config().char["stand_still"], do_press=False) + + def _activate_redemption_aura(self, delay = [0.6, 0.8]): + self._select_skill("redemption", delay=delay) + + def _activate_cleanse_aura(self, delay = [0.3, 0.4]): + self._select_skill("cleansing", delay=delay) + + def _activate_cleanse_redemption(self): + self._activate_cleanse_aura() + self._activate_redemption_aura() \ No newline at end of file diff --git a/src/char/poison_necro.py b/src/char/poison_necro.py index 841d6c7d4..72ae64cac 100644 --- a/src/char/poison_necro.py +++ b/src/char/poison_necro.py @@ -1,20 +1,19 @@ import keyboard from utils.custom_mouse import mouse from char import IChar -from template_finder import TemplateFinder +import template_finder from pather import Pather from logger import Logger -from screen import grab, convert_abs_to_monitor, convert_screen_to_abs +from screen import grab from config import Config from utils.misc import wait, rotate_vec, unit_vector import random -from typing import Tuple from pather import Location, Pather import screen as screen import numpy as np import time import os -from ui_manager import ScreenObjects +from ui_manager import get_closest_non_hud_pixel class Poison_Necro(IChar): def __init__(self, skill_hotkeys: dict, pather: Pather): @@ -29,7 +28,7 @@ def __init__(self, skill_hotkeys: dict, pather: Pather): self._pather.offset_node(102, [15, 0]) self._pather.offset_node(103, [15, 0]) self._pather.offset_node(101, [100,-5]) - + #Diablo self._pather.offset_node(644, [150, -70]) self._pather.offset_node(610620, [50, 50]) @@ -49,7 +48,7 @@ def _check_shenk_death(self): roi = [640,0,640,720] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ['SHENK_DEATH_1','SHENK_DEATH_2','SHENK_DEATH_3','SHENK_DEATH_4'], img, threshold=0.6, @@ -67,7 +66,7 @@ def _count_revives(self): img = grab() max_rev = 13 - template_match = TemplateFinder().search( + template_match = template_finder.search( ['REV_BASE'], img, threshold=0.6, @@ -81,7 +80,7 @@ def _count_revives(self): for count in range(1,max_rev): rev_num = "REV_"+str(count) - template_match = TemplateFinder().search( + template_match = template_finder.search( [rev_num], img, threshold=0.66, @@ -102,14 +101,14 @@ def poison_nova(self, time_in_s: float): wait(0.03, 0.04) mouse.press(button="right") wait(0.12, 0.2) - mouse.release(button="right") + mouse.release(button="right") def _count_skeletons(self): roi = [15,14,400,45] img = grab() max_skeles = 13 - template_match = TemplateFinder().search( + template_match = template_finder.search( ['SKELE_BASE'], img, threshold=0.6, @@ -123,7 +122,7 @@ def _count_skeletons(self): for count in range(1,max_skeles): skele_num = "SKELE_"+str(count) - template_match = TemplateFinder().search( + template_match = template_finder.search( [skele_num], img, threshold=0.66, @@ -137,7 +136,7 @@ def _count_gol(self): roi = [15,14,400,45] img = grab() - template_match = TemplateFinder().search( + template_match = template_finder.search( ['CLAY'], img, threshold=0.6, @@ -159,7 +158,7 @@ def _summon_stat(self): ''' print counts for summons ''' Logger.info('\33[31m'+"Summon status | "+str(self._skeletons_count)+"skele | "+str(self._revive_count)+" rev | "+self._golem_count+" |"+'\033[0m') - def _revive(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=12): + def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=12): Logger.info('\033[94m'+"raise revive"+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) for _ in range(cast_count): @@ -188,7 +187,7 @@ def _revive(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - def _raise_skeleton(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=16): + def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise skeleton"+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) for _ in range(cast_count): @@ -217,7 +216,7 @@ def _raise_skeleton(self, cast_pos_abs: Tuple[float, float], spray: int = 10, ca mouse.release(button="right") keyboard.send(Config().char["stand_still"], do_press=False) - def _raise_mage(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=16): + def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise mage"+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) for _ in range(cast_count): @@ -293,7 +292,7 @@ def _bone_armor(self): - def _left_attack(self, cast_pos_abs: Tuple[float, float], spray: int = 10): + def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): keyboard.send(Config().char["stand_still"], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) @@ -308,7 +307,7 @@ def _left_attack(self, cast_pos_abs: Tuple[float, float], spray: int = 10): keyboard.send(Config().char["stand_still"], do_press=False) - def _left_attack_single(self, cast_pos_abs: Tuple[float, float], spray: int = 10, cast_count: int=6): + def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=6): keyboard.send(Config().char["stand_still"], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) @@ -323,7 +322,7 @@ def _left_attack_single(self, cast_pos_abs: Tuple[float, float], spray: int = 10 keyboard.send(Config().char["stand_still"], do_press=False) - def _amp_dmg(self, cast_pos_abs: Tuple[float, float], spray: float = 10): + def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10): if self._skill_hotkeys["amp_dmg"]: keyboard.send(self._skill_hotkeys["amp_dmg"]) @@ -335,7 +334,7 @@ def _amp_dmg(self, cast_pos_abs: Tuple[float, float], spray: float = 10): wait(0.25, 0.35) mouse.release(button="right") - def _lower_res(self, cast_pos_abs: Tuple[float, float], spray: float = 10): + def _lower_res(self, cast_pos_abs: tuple[float, float], spray: float = 10): if self._skill_hotkeys["lower_res"]: keyboard.send(self._skill_hotkeys["lower_res"]) @@ -345,9 +344,9 @@ def _lower_res(self, cast_pos_abs: Tuple[float, float], spray: float = 10): mouse.move(*cast_pos_monitor) mouse.press(button="right") wait(0.25, 0.35) - mouse.release(button="right") + mouse.release(button="right") - def _corpse_explosion(self, cast_pos_abs: Tuple[float, float], spray: int = 10,cast_count: int = 8): + def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8): keyboard.send(Config().char["stand_still"], do_release=False) Logger.info('\033[93m'+"corpse explosion~> random cast"+'\033[0m') for _ in range(cast_count): @@ -363,10 +362,7 @@ def _corpse_explosion(self, cast_pos_abs: Tuple[float, float], spray: int = 10,c keyboard.send(Config().char["stand_still"], do_press=False) - def _lerp(self,a: float,b: float, f:float): - return a + f * (b - a) - - def _cast_circle(self, cast_dir: Tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0): + def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0): Logger.info('\033[93m'+"circle cast ~>"+cast_spell+'\033[0m') keyboard.send(Config().char["stand_still"], do_release=False) keyboard.send(self._skill_hotkeys[cast_spell]) @@ -377,8 +373,8 @@ def _cast_circle(self, cast_dir: Tuple[float,float],cast_start_angle: float=0.0, target = unit_vector(rotate_vec(cast_dir, angle)) #Logger.info("current angle ~> "+str(angle)) for j in range(cast_v_div): - circle_pos_screen = self._pather._adjust_abs_range_to_screen((target*120.0*float(j+1.0))*offset) - circle_pos_monitor = screen.convert_abs_to_monitor(circle_pos_screen) + circle_pos_abs = get_closest_non_hud_pixel(pos = ((target*120.0*float(j+1.0))*offset), pos_type="abs") + circle_pos_monitor = screen.convert_abs_to_monitor(circle_pos_abs) mouse.move(*circle_pos_monitor,delay_factor=[0.3*delay, .6*delay]) @@ -462,11 +458,11 @@ def kill_council(self) -> bool: pos_m = screen.convert_abs_to_monitor((0, -200)) self.pre_move() self.move(pos_m, force_move=True) - self._pather.traverse_nodes([229], self, timeout=2.5, force_tp=True, use_tp_charge=True) + self._pather.traverse_nodes([229], self, timeout=2.5, force_tp=True, use_tp_charge=True) pos_m = screen.convert_abs_to_monitor((50, 0)) self.walk(pos_m, force_move=True) #self._lower_res((-50, 0), spray=10) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) self.poison_nova(2.0) #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_skeleton',delay=1.2,offset=.8) pos_m = screen.convert_abs_to_monitor((200, 50)) @@ -529,7 +525,7 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=7200,cast_div=2,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8) wait(self._cast_duration, self._cast_duration +.2) self.poison_nova(3.0) - return True + return True def kill_summoner(self) -> bool: # Attack @@ -543,7 +539,7 @@ def kill_summoner(self) -> bool: self.move(pos_m, force_move=True) wait(self._cast_duration, self._cast_duration + 0.2) self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.2,offset=.8) - return True + return True if __name__ == "__main__": diff --git a/src/char/sorceress/blizz_sorc.py b/src/char/sorceress/blizz_sorc.py index f81e4ddde..39cc7bd5d 100644 --- a/src/char/sorceress/blizz_sorc.py +++ b/src/char/sorceress/blizz_sorc.py @@ -8,7 +8,7 @@ import numpy as np from screen import convert_abs_to_monitor, grab, convert_screen_to_abs from config import Config -from template_finder import TemplateFinder +import template_finder class BlizzSorc(Sorceress): def __init__(self, *args, **kwargs): @@ -73,7 +73,7 @@ def kill_eldritch(self) -> bool: self.move(pos_m, force_move=True) self._blizzard((-50, -50), spray=10) self._cast_static() - wait(0.75) + wait(0.75) #move down pos_m = convert_abs_to_monitor((0, 85)) self.pre_move() @@ -225,21 +225,20 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: nihlathak_pos_abs = self._pather.find_abs_node_pos(end_nodes[-1], grab()) if nihlathak_pos_abs is not None: cast_pos_abs = np.array([nihlathak_pos_abs[0] * 1.0, nihlathak_pos_abs[1] * 1.0]) - wait(0.8) + wait(0.5) self._blizzard(cast_pos_abs, spray=0) - wait(0.3) - is_nihl = TemplateFinder().search(["NIHL_BAR"], grab(), threshold=0.8, roi=Config().ui_roi["enemy_info"]).valid - nihl_immune = TemplateFinder().search(["COLD_IMMUNE","COLD_IMMUNES"], grab(), threshold=0.8, roi=Config().ui_roi["enemy_info"]).valid + wait(0.2) + is_nihl = template_finder.search(["NIHL_BAR"], grab(), threshold=0.8, roi=Config().ui_roi["enemy_info"]).valid + nihl_immune = template_finder.search(["COLD_IMMUNE","COLD_IMMUNES"], grab(), threshold=0.8, roi=Config().ui_roi["enemy_info"]).valid if is_nihl: Logger.info("Found him!") if nihl_immune: Logger.info("Cold Immune! - Exiting") return True - wait(0.8) + wait(0.5) self._cast_static() self._blizzard(cast_pos_abs, spray=15) # Move to items - wait(1.3) self._pather.traverse_nodes(end_nodes, self, timeout=0.8) return True @@ -258,7 +257,7 @@ def kill_summoner(self) -> bool: if __name__ == "__main__": import os import keyboard - from template_finder import TemplateFinder + import template_finder from pather import Pather keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) keyboard.wait("f11") diff --git a/src/char/sorceress/sorceress.py b/src/char/sorceress/sorceress.py index 7993e89d2..0737d7fe6 100644 --- a/src/char/sorceress/sorceress.py +++ b/src/char/sorceress/sorceress.py @@ -1,13 +1,12 @@ import keyboard -from typing import Tuple, Union, List, Callable +from typing import Callable from utils.custom_mouse import mouse from char import IChar -from template_finder import TemplateFinder +import template_finder from pather import Pather from screen import grab from utils.misc import wait import time -from typing import Tuple from pather import Pather from config import Config from ui_manager import ScreenObjects, is_visible @@ -17,7 +16,7 @@ def __init__(self, skill_hotkeys: dict, pather: Pather): super().__init__(skill_hotkeys) self._pather = pather - def pick_up_item(self, pos: Tuple[float, float], item_name: str = None, prev_cast_start: float = 0): + def pick_up_item(self, pos: tuple[float, float], item_name: str = None, prev_cast_start: float = 0): if self._skill_hotkeys["telekinesis"] and any(x in item_name for x in ['potion', 'misc_gold', 'tp_scroll']): keyboard.send(self._skill_hotkeys["telekinesis"]) wait(0.1, 0.2) @@ -36,7 +35,7 @@ def pick_up_item(self, pos: Tuple[float, float], item_name: str = None, prev_cas def select_by_template( self, - template_type: Union[str, List[str]], + template_type: str | list[str], success_func: Callable = None, timeout: float = 8, threshold: float = 0.68, @@ -51,11 +50,11 @@ def select_by_template( keyboard.send("esc") start = time.time() while timeout is None or (time.time() - start) < timeout: - template_match = TemplateFinder().search(template_type, grab(), threshold=threshold, normalize_monitor=True) + template_match = template_finder.search(template_type, grab(), threshold=threshold) if template_match.valid: keyboard.send(self._skill_hotkeys["telekinesis"]) wait(0.1, 0.2) - mouse.move(*template_match.center) + mouse.move(*template_match.center_monitor) wait(0.2, 0.3) mouse.click(button="right") # check the successfunction for 2 sec, if not found, try again diff --git a/src/char/trapsin.py b/src/char/trapsin.py index 2fa1fe488..f7117058f 100644 --- a/src/char/trapsin.py +++ b/src/char/trapsin.py @@ -1,14 +1,12 @@ import keyboard from utils.custom_mouse import mouse from char import IChar -from template_finder import TemplateFinder from pather import Pather from logger import Logger from screen import convert_abs_to_monitor, convert_screen_to_abs, grab from config import Config from utils.misc import wait, rotate_vec, unit_vector import random -from typing import Tuple from pather import Location, Pather import numpy as np @@ -38,7 +36,7 @@ def pre_buff(self): mouse.click(button="right") wait(self._cast_duration) - def _left_attack(self, cast_pos_abs: Tuple[float, float], spray: int = 10): + def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): keyboard.send(Config().char["stand_still"], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) @@ -53,7 +51,7 @@ def _left_attack(self, cast_pos_abs: Tuple[float, float], spray: int = 10): keyboard.send(Config().char["stand_still"], do_press=False) - def _right_attack(self, cast_pos_abs: Tuple[float, float], spray: float = 10): + def _right_attack(self, cast_pos_abs: tuple[float, float], spray: float = 10): keyboard.send(self._skill_hotkeys["lightning_sentry"]) x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) diff --git a/src/chest.py b/src/chest.py index c54cc69ad..8b1a23091 100644 --- a/src/chest.py +++ b/src/chest.py @@ -2,13 +2,13 @@ import os from logger import Logger -from template_finder import TemplateFinder +import template_finder from screen import grab from char import IChar from config import Config from utils.custom_mouse import mouse from utils.misc import wait -from inventory import consumables +from item import consumables class Chest: @@ -29,7 +29,7 @@ def open_up_chests(self, timeout: float = 8.0, threshold: float = 0.73) -> bool: found_chest = True start = time.time() while time.time() - start < timeout: - template_match = TemplateFinder().search(templates, grab(), roi=Config().ui_roi["reduce_to_center"], threshold=threshold, use_grayscale=True, best_match=True, normalize_monitor=True) + template_match = template_finder.search(templates, grab(), roi=Config().ui_roi["reduce_to_center"], threshold=threshold, use_grayscale=True, best_match=True) # search for at least 1.5 second, if no chest found, break if not template_match.valid: if time.time() - start > 1.5: @@ -37,19 +37,19 @@ def open_up_chests(self, timeout: float = 8.0, threshold: float = 0.73) -> bool: else: found_chest = True # move mouse and check for label - mouse.move(*template_match.center, delay_factor=[0.4, 0.6]) + mouse.move(*template_match.center_monitor, delay_factor=[0.4, 0.6]) wait(0.13, 0.16) chest_label_img = grab() - chest_label = TemplateFinder().search("CHEST_LABEL", chest_label_img, threshold=0.85) - is_locked = TemplateFinder().search("LOCKED", chest_label_img, threshold=0.85).valid + chest_label = template_finder.search("CHEST_LABEL", chest_label_img, threshold=0.85) + is_locked = template_finder.search("LOCKED", chest_label_img, threshold=0.85).valid if chest_label.valid: if is_locked: consumables.increment_need("key", 1) Logger.debug(f"Opening {template_match.name} ({template_match.score*100:.1f}% confidence)") # TODO: Act as picking up a potion to support telekinesis. This workaround needs a proper solution. - self._char.pick_up_item(template_match.center, 'potion') - wait(0.13, 0.16) - if TemplateFinder().search("LOCKED", grab(), threshold=0.85).valid: + self._char.pick_up_item(template_match.center_monitor, 'potion') + wait(0.33, 0.36) + if template_finder.search("LOCKED", grab(), threshold=0.85).valid: templates.remove(template_match.name) Logger.debug("No more keys, removing locked chest template") continue diff --git a/src/config.py b/src/config.py index e1185ef8c..daccc72c7 100644 --- a/src/config.py +++ b/src/config.py @@ -6,19 +6,11 @@ from dataclasses import dataclass from logger import Logger config_lock = threading.Lock() - +from utils.misc import wait, only_lowercase_letters def _default_iff(value, iff, default = None): return default if value == iff else value -@dataclass -class ItemProps: - pickit_type: int = 0 - include: list[str] = None - exclude: list[str] = None - include_type: str = "OR" - exclude_type: str = "OR" - class Config: data_loaded = False @@ -30,11 +22,9 @@ class Config: gamble = {} ui_roi = {} ui_pos = {} - dclone = {} routes = {} routes_order = [] char = {} - items = {} colors = {} shop = {} path = {} @@ -43,6 +33,7 @@ class Config: nova_sorc = {} hydra_sorc = {} hammerdin = {} + fohdin = {} trapsin = {} barbarian = {} poison_necro = {} @@ -70,127 +61,51 @@ def _select_optional(self, section: string, key: string, default = None): def _select_val(self, section: str, key: str = None): found_in = "" - if section in self.configs["custom"]["parser"] and key in self.configs["custom"]["parser"][section]: - found_val = self.configs["custom"]["parser"][section][key] - found_in = "custom" - elif section in self.configs["config"]["parser"]: - found_val = self.configs["config"]["parser"][section][key] - found_in = "config" - elif section in self.configs["pickit"]["parser"]: - found_val = self.configs["pickit"]["parser"][section][key] - found_in = "pickit" - elif section in self.configs["shop"]["parser"]: - found_val = self.configs["shop"]["parser"][section][key] - found_in = "shop" - else: - found_val = self.configs["game"]["parser"][section][key] - found_in = "game" - - for var_name in self.configs[found_in]["vars"]: # set variable. - if var_name in found_val: - var_val = self.configs[found_in]["vars"][var_name] - found_val = found_val.replace(var_name, var_val) - return found_val - - def parse_item_config_string(self, key: str = None) -> ItemProps: - string = self._select_val("items", key).upper() - return self.string_to_item_prop (string) - - def string_to_item_prop (self, string: str) -> ItemProps: - item_props = ItemProps() - brk_on = 0 - brk_off = 0 - section = 0 - counter = 0 - start_section = 0 - start_item = 0 - include_list = [] - exclude_list = [] - for char in string: - new_section = False - counter+=1 - if char == "(": - brk_on +=1 - elif char == ")": - brk_off += 1 - if ((char == "," and brk_on==brk_off)): - new_section = True - if (counter == len (string)): - string_section = string [start_section:counter] - else: - string_section = string [start_section:counter-1] - if section == 0: - item_props.pickit_type = int (string_section) - section +=1 - start_section = counter - if ((char == "," and (brk_on==brk_off+1)) or new_section or counter == len (string)): - if new_section: - section -=1 - if start_item ==0: - start_item = start_section - if (counter == len (string)): - item = string [start_item:counter] - else: - item = string [start_item:counter-1] - if section == 0 and counter == len (string): - item_props.pickit_type = int (item) - pass - if section ==1: - include_list.append (item) - start_item = counter +1 - elif section ==2: - exclude_list.append (item) - start_item = counter +1 - if new_section: - section +=1 - if (len (include_list)>0 and (len (include_list[0]) >=6)): - if ("AND" in include_list[0][0: 6] and not ")" in include_list[0]): - item_props.include_type = "AND" - else: - item_props.include_type = "OR" - if (len (exclude_list)>0 and (len (exclude_list[0]) >=6)): - if ("AND" in exclude_list[0][0:6] and not ")" in include_list[0]): - item_props.exclude_type = "AND" + try: + if section in self.configs["custom"]["parser"] and key in self.configs["custom"]["parser"][section]: + found_val = self.configs["custom"]["parser"][section][key] + found_in = "custom" + elif section in self.configs["config"]["parser"]: + found_val = self.configs["config"]["parser"][section][key] + found_in = "config" + elif section in self.configs["shop"]["parser"]: + found_val = self.configs["shop"]["parser"][section][key] + found_in = "shop" else: - item_props.exclude_type = "OR" - for i in range (len(include_list)): - include_list[i] = include_list[i].replace (" ","").replace ("OR(","").replace ("AND(", "").replace ("(", "").replace (")","") - include_list[i] = include_list[i].split (",") - for l in range (len (exclude_list)): - exclude_list[l] = exclude_list[l].replace (" ","").replace ("OR(","").replace ("AND(", "").replace ("(", "").replace (")","") - exclude_list[l] = exclude_list[l].split (",") - item_props.include = include_list - item_props.exclude = exclude_list - return item_props + found_val = self.configs["game"]["parser"][section][key] + found_in = "game" + + for var_name in self.configs[found_in]["vars"]: # set variable. + if var_name in found_val: + var_val = self.configs[found_in]["vars"][var_name] + found_val = found_val.replace(var_name, var_val) + return found_val + except KeyError: + Logger.error(f"Key '{key}' not found in section '{section}'") + Logger.error("Closing in 10 seconds..") + wait(10) + os._exit(1) def turn_off_goldpickup(self): Logger.info("All stash tabs and character are full of gold, turn off gold pickup") with config_lock: self.char["stash_gold"] = False - self.items["misc_gold"].pickit_type = 0 def turn_on_goldpickup(self): Logger.info("All stash tabs and character are no longer full of gold. Turn gold stashing back on.") self.char["stash_gold"] = True - # if gold pickup in pickit config was originally on but turned off, turn back on - if self.string_to_item_prop(self._select_val("items", "misc_gold")).pickit_type > 0: - Logger.info("Turn gold pickup back on") - with config_lock: - self.items["misc_gold"].pickit_type = 1 def load_data(self): Logger.debug("Loading config") self.configs = { "config": {"parser": configparser.ConfigParser(), "vars": {}}, "game": {"parser": configparser.ConfigParser(), "vars": {}}, - "pickit": {"parser": configparser.ConfigParser(), "vars": {}}, "shop": {"parser": configparser.ConfigParser(), "vars": {}}, "transmute": {"parser": configparser.ConfigParser(), "vars": {}}, "custom": {"parser": configparser.ConfigParser(), "vars": {}}, } self.configs["config"]["parser"].read('config/params.ini') self.configs["game"]["parser"].read('config/game.ini') - self.configs["pickit"]["parser"].read('config/pickit.ini') self.configs["shop"]["parser"].read('config/shop.ini') self.configs["transmute"]["parser"].read('config/transmute.ini') @@ -212,7 +127,7 @@ def load_data(self): self.general = { "saved_games_folder": self._select_val("general", "saved_games_folder"), - "name": self._select_val("general", "name"), + "name": _default_iff(self._select_val("general", "name"), "", "botty"), "max_game_length_s": float(self._select_val("general", "max_game_length_s")), "max_consecutive_fails": int(self._select_val("general", "max_consecutive_fails")), "max_runtime_before_break_m": float(_default_iff(self._select_val("general", "max_runtime_before_break_m"), '', 0)), @@ -221,20 +136,15 @@ def load_data(self): "difficulty": self._select_val("general", "difficulty"), "message_api_type": self._select_val("general", "message_api_type"), "custom_message_hook": self._select_val("general", "custom_message_hook"), + "custom_loot_message_hook": self._select_val("general", "custom_loot_message_hook"), "discord_status_count": False if not self._select_val("general", "discord_status_count") else int(self._select_val("general", "discord_status_count")), "discord_log_chicken": bool(int(self._select_val("general", "discord_log_chicken"))), "info_screenshots": bool(int(self._select_val("general", "info_screenshots"))), - "loot_screenshots": bool(int(self._select_val("general", "loot_screenshots"))), + "pickit_screenshots": bool(int(self._select_val("general", "pickit_screenshots"))), "d2r_path": _default_iff(self._select_val("general", "d2r_path"), "", "C:\Program Files (x86)\Diablo II Resurrected"), "restart_d2r_when_stuck": bool(int(self._select_val("general", "restart_d2r_when_stuck"))), } - # Added for dclone ip hunting - self.dclone = { - "region_ips": self._select_val("dclone", "region_ips"), - "dclone_hotip": self._select_val("dclone", "dclone_hotip"), - } - self.routes = {} order_str = self._select_val("routes", "order") self.routes_order = [x.strip() for x in order_str.split(",")] @@ -248,6 +158,7 @@ def load_data(self): "type": self._select_val("char", "type"), "show_items": self._select_val("char", "show_items"), "inventory_screen": self._select_val("char", "inventory_screen"), + "teleport": self._select_val("char", "teleport"), "stand_still": self._select_val("char", "stand_still"), "force_move": self._select_val("char", "force_move"), "num_loot_columns": int(self._select_val("char", "num_loot_columns")), @@ -259,7 +170,7 @@ def load_data(self): "heal_rejuv_merc": float(self._select_val("char", "heal_rejuv_merc")), "chicken": float(self._select_val("char", "chicken")), "merc_chicken": float(self._select_val("char", "merc_chicken")), - "tp": self._select_val("char", "tp"), + "town_portal": self._select_val("char", "town_portal"), "belt_rows": int(self._select_val("char", "belt_rows")), "show_belt": self._select_val("char", "show_belt"), "potion1": self._select_val("char", "potion1"), @@ -270,9 +181,7 @@ def load_data(self): "belt_hp_columns": int(self._select_val("char", "belt_hp_columns")), "belt_mp_columns": int(self._select_val("char", "belt_mp_columns")), "stash_gold": bool(int(self._select_val("char", "stash_gold"))), - "min_gold_to_pick": int(_default_iff(self._select_val("char", "min_gold_to_pick"), '', 0)), "use_merc": bool(int(self._select_val("char", "use_merc"))), - "id_items": bool(int(self._select_val("char", "id_items"))), "open_chests": bool(int(self._select_val("char", "open_chests"))), "fill_shared_stash_first": bool(int(self._select_val("char", "fill_shared_stash_first"))), "pre_buff_every_run": bool(int(self._select_val("char", "pre_buff_every_run"))), @@ -299,6 +208,8 @@ def load_data(self): "runs_per_repair": False if not self._select_val("char", "runs_per_repair") else int(self._select_val("char", "runs_per_repair")), "gamble_items": False if not self._select_val("char", "gamble_items") else self._select_val("char", "gamble_items").replace(" ","").split(","), "sell_junk": bool(int(self._select_val("char", "sell_junk"))), + "enable_no_pickup": bool(int(self._select_val("char", "enable_no_pickup"))), + "safer_routines": bool(int(self._select_val("char", "safer_routines"))), } # Sorc base config sorc_base_cfg = dict(self.configs["config"]["parser"]["sorceress"]) @@ -325,12 +236,22 @@ def load_data(self): self.hydra_sorc.update(dict(self.configs["custom"]["parser"]["hydra_sorc"])) self.hydra_sorc.update(sorc_base_cfg) - # Palandin config + # Paladin base config + paladin_base_cfg = dict(self.configs["config"]["parser"]["paladin"]) + if "paladin" in self.configs["custom"]["parser"]: + paladin_base_cfg.update(dict(self.configs["custom"]["parser"]["paladin"])) + # Hammerdin config self.hammerdin = self.configs["config"]["parser"]["hammerdin"] if "hammerdin" in self.configs["custom"]["parser"]: self.hammerdin.update(self.configs["custom"]["parser"]["hammerdin"]) - - # Assasin config + self.hammerdin.update(paladin_base_cfg) + # FoHdin config + self.fohdin = dict(self.configs["config"]["parser"]["fohdin"]) + if "fohdin" in self.configs["custom"]["parser"]: + self.fohdin.update(self.configs["custom"]["parser"]["fohdin"]) + self.fohdin.update(paladin_base_cfg) + + # Assassin config self.trapsin = self.configs["config"]["parser"]["trapsin"] if "trapsin" in self.configs["custom"]["parser"]: self.trapsin.update(self.configs["custom"]["parser"]["trapsin"]) @@ -360,7 +281,7 @@ def load_data(self): self.poison_necro = self.configs["config"]["parser"]["poison_necro"] if "poison_necro" in self.configs["custom"]["parser"]: self.poison_necro.update(self.configs["custom"]["parser"]["poison_necro"]) - + self.bone_necro = self.configs["config"]["parser"]["bone_necro"] if "bone_necro" in self.configs["custom"]["parser"]: self.bone_necro.update(self.configs["custom"]["parser"]["bone_necro"]) @@ -381,19 +302,10 @@ def load_data(self): "hwnd_window_process": _default_iff(Config()._select_val("advanced_options", "hwnd_window_process"), ''), "window_client_area_offset": tuple(map(int, Config()._select_val("advanced_options", "window_client_area_offset").split(","))), "ocr_during_pickit": bool(int(self._select_val("advanced_options", "ocr_during_pickit"))), - "launch_options": self._select_val("advanced_options", "launch_options"), + "launch_options": self._select_val("advanced_options", "launch_options").replace("", only_lowercase_letters(self.general["name"].lower())), "override_capabilities": _default_iff(Config()._select_optional("advanced_options", "override_capabilities"), ""), } - self.items = {} - for key in self.configs["pickit"]["parser"]["items"]: - try: - self.items[key] = self.parse_item_config_string(key) - if self.items[key].pickit_type and not os.path.exists(f"./assets/items/{key}.png"): - Logger.warning(f"You activated {key} in pickit, but there is no img available in assets/items") - except ValueError as e: - Logger.error(f"Error with pickit config: {key} ({e})") - self.colors = {} for key in self.configs["game"]["parser"]["colors"]: self.colors[key] = np.split(np.array([int(x) for x in self._select_val("colors", key).split(",")]), 2) @@ -430,25 +342,13 @@ def load_data(self): "apply_pather_adjustment": bool(int(self._select_val("scepters", "apply_pather_adjustment"))), } stash_destination_str = self._select_val("transmute","stash_destination") + transmute_str = self._select_val("transmute","transmute") self.configs["transmute"]["parser"] = { "stash_destination": [int(x.strip()) for x in stash_destination_str.split(",")], "transmute_every_x_game": self._select_val("transmute","transmute_every_x_game"), + "transmute": [x.strip() for x in transmute_str.split(",")], } if __name__ == "__main__": from copy import deepcopy config = Config() - - # Check if any added items miss templates - for k in config.items: - if not os.path.exists(f"./assets/items/{k}.png"): - Logger.warning(f"Template not found: {k}") - - # Check if any item templates miss a config - for filename in os.listdir(f'assets/items'): - filename = filename.lower() - if filename.endswith('.png'): - item_name = filename[:-4] - blacklist_item = item_name.startswith("bl__") - if item_name not in config.items and not blacklist_item: - Logger.warning(f"Config not found for: " + filename) diff --git a/src/d2r_image/__init__.py b/src/d2r_image/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/d2r_image/bnip_data.py b/src/d2r_image/bnip_data.py new file mode 100644 index 000000000..e495534ff --- /dev/null +++ b/src/d2r_image/bnip_data.py @@ -0,0 +1,9806 @@ +from d2r_image.data_models import ItemQuality, ItemQualityKeyword + + +NTIP_ALIAS_QUALITY_MAP = { + ItemQualityKeyword.LowQuality.value: 1, + ItemQualityKeyword.Crude.value: 1, + ItemQualityKeyword.Cracked.value: 1, + ItemQuality.LowQuality.value: 1, + ItemQuality.Crude.value: 1, + ItemQuality.Cracked.value: 1, + ItemQuality.Gray.value: 2, + ItemQuality.Normal.value: 2, + ItemQuality.Superior.value: 3, + ItemQualityKeyword.Superior.value: 3, + ItemQuality.Magic.value: 4, + ItemQuality.Set.value: 5, + ItemQuality.Rare.value: 6, + ItemQuality.Unique.value: 7, + ItemQuality.Crafted.value: 8, + ItemQuality.Runeword.value: 9, + ItemQuality.Rune.value: 10, +} + +""" +ITEM PROPERTIES THAT MAP TO STATS RATHER THAN A READ PROPERTY +['itemskillonattack']='195' +['itemskillonkill']='196' +['itemskillondeath']='197' +['itemskillonhit']='198' +['itemskillonlevelup']='199' +['itemskillongethit']='201' +['itemchargedskill']='204' +['itemnonclassskill']='97' (not sure how this is used) +['itemsingleskill']='107' doesn't map to skill +['itemaddskilltab']='188' doesn't map to skill +""" +PROPS_TO_SKILLID = {195, 196, 197, 198, 199, 201, 204} + +BNIP_ALIAS_STAT_PATTERNS = { + "{:d} Defense": [ + "5006" + ], + "{:d} Defense vs. Missile": [ + "32" + ], + "{:d} Defense vs. Melee": [ + "33" + ], + "Damage Reduced by {:d}": [ + "34" + ], + "Damage Reduced by {:d}%": [ + "36" + ], + "{:d}% Enhanced Defense": [ + "16" + ], + "Magic Damage Reduced by {:d}": [ + "35" + ], + "{:d} to Strength": [ + "0" + ], + "{:d} to Dexterity": [ + "2" + ], + "{:d} to Vitality": [ + "3" + ], + "{:d} to Energy": [ + "1" + ], + "{:d} to Mana": [ + [ + "8", + "9" + ] + ], + "Increase Maximum Mana {:d}%": [ + "77" + ], + "{:d} to Life": [ + [ + "6", + "7" + ] + ], + "Increase Maximum Life {:d}%": [ + "76" + ], + "{:d} to Attack Rating": [ + "19" + ], + "{:d}% Increased Chance of Blocking": [ + "20" + ], + "{:d} to Minimum Cold Damage": [ + "54" + ], + "{:d} to Maximum Cold Damage": [ + "55" + ], + "{:d} to Minimum Fire Damage": [ + "48" + ], + "{:d} to Maximum Fire Damage": [ + "49" + ], + "{:d} to Minimum Lightning Damage": [ + "50" + ], + "{:d} to Maximum Lightning Damage": [ + "51" + ], + "{:d} to Minimum Poison Damage": [ + "57" + ], + "{:d} to Maximum Poison Damage": [ + "58" + ], + "{:d} to Minimum Damage": [ + "21" + ], + "{:d} to Maximum Damage": [ + "22" + ], + "{:d}% Damage Taken Goes To Mana": [ + "114" + ], + "Fire Resist {:d}%": [ + "39" + ], + "{:d}% to Maximum Fire Resist": [ + "40" + ], + "Lightning Resist {:d}%": [ + "41" + ], + "{:d}% to Maximum Lightning Resist": [ + "42" + ], + "Cold Resist {:d}%": [ + "43" + ], + "{:d}% to Maximum Cold Resist": [ + "44" + ], + "Magic Resist {:d}%": [ + "37" + ], + "{:d}% to Maximum Magic Resist": [ + "38" + ], + "Poison Resist {:d}%": [ + "45" + ], + "{:d}% to Maximum Poison Resist": [ + "46" + ], + "All Resistances {:d}": [ + [ + "6969", + "39", + "41", + "43", + "45" + ] + ], + "{:d} Fire Absorb": [ + "143" + ], + "Fire Absorb {:d}%": [ + "142" + ], + "{:d} Lightning Absorb": [ + "145" + ], + "Lightning Absorb {:d}%": [ + "144" + ], + "{:d} Magic Absorb": [ + "147" + ], + "Magic Absorb {:d}%": [ + "146" + ], + "{:d} Cold Absorb": [ + "149" + ], + "Cold Absorb {:d}%": [ + "148" + ], + "Durability: {:d} of {:d}": [ + "72", + "73" + ], + "Increase Maximum Durability {:d}%": [ + "75" + ], + "Replenish Life {:d}": [ + "74" + ], + "Attacker Takes Damage of {:d}": [ + "78" + ], + "{:d}% Increased Attack Speed": [ + "93" + ], + "{:d}% Extra Gold from Monsters": [ + "79" + ], + "{:d}% Better Chance of Getting Magic Items": [ + "80" + ], + "Knockback": [ + "81" + ], + "Heal Stamina Plus {:d}%": [ + "28" + ], + "Regenerate Mana {:d}%": [ + "27" + ], + "{:d} Maximum Stamina": [ + [ + "10", + "11" + ] + ], + "{:d}% Mana stolen per hit": [ + "62" + ], + "{:d}% Life stolen per hit": [ + "60" + ], + "{:d} to Amazon Skill Levels": [ + "83,0" + ], + "{:d} to Paladin Skill Levels": [ + "83,3" + ], + "{:d} to Necromancer Skill Levels": [ + "83,2" + ], + "{:d} to Sorceress Skill Levels": [ + "83,1" + ], + "{:d} to Barbarian Skill Levels": [ + "83,4" + ], + "{:d} to Light Radius": [ + "89" + ], + "Requirements {:d}%": [ + "91" + ], + "{:d}% Faster Run/Walk": [ + "96" + ], + "{:d}% Faster Hit Recovery": [ + "99" + ], + "{:d}% Faster Block Rate": [ + "102" + ], + "{:d}% Faster Cast Rate": [ + "105" + ], + "Poison Length Reduced by {:d}%": [ + "110" + ], + "Damage {:d}": [ + "111" + ], + "Hit Causes Monster to Flee {:d}%": [ + "112" + ], + "Hit Blinds Target {:d}": [ + "113" + ], + "Ignore Target's Defense": [ + "115" + ], + "{:d}% Target Defense": [ + "116" + ], + "Prevent Monster Heal": [ + "117" + ], + "Half Freeze Duration": [ + "118" + ], + "{:d}% Bonus to Attack Rating": [ + "119" + ], + "{:d} to Monster Defense Per Hit": [ + "120" + ], + "{:d}% Damage to Demons": [ + "121" + ], + "{:d}% Damage to Undead": [ + "122" + ], + "{:d} to Attack Rating against Demons": [ + "123" + ], + "{:d} to Attack Rating against Undead": [ + "124" + ], + "{:d} to Fire Skills": [ + "126" + ], + "{:d} to All Skills": [ + "127" + ], + "Attacker Takes Lightning Damage of {:d}": [ + "128" + ], + "Freezes Target {:d}": [ + "134" + ], + "{:d}% Chance of Open Wounds": [ + "135" + ], + "{:d}% Chance of Crushing Blow": [ + "136" + ], + "{:d} Kick Damage": [ + "137" + ], + "{:d} to Mana after each Kill": [ + "138" + ], + "{:d} Life after each Demon Kill": [ + "139" + ], + "{:d}% Deadly Strike": [ + "141" + ], + "Slows Target by {:d}%": [ + "150" + ], + "Cannot Be Frozen": [ + "153" + ], + "{:d}% Slower Stamina Drain": [ + "154" + ], + "Reanimate As: [Returned]": [ + "155" + ], + "Piercing Attack": [ + "156" + ], + "Fires Magic Arrows": [ + "157" + ], + "Fires Explosive Arrows or Bolts": [ + "158" + ], + "{:d} to Druid Skill Levels": [ + "83,5" + ], + "{:d} to Assassin Skill Levels": [ + "83,6" + ], + "{:d} to Magic Arrow (Amazon only)": [ + "107,6" + ], + "{:d} to Fire Arrow (Amazon only)": [ + "107,7" + ], + "{:d} to Inner Sight (Amazon only)": [ + "107,8" + ], + "{:d} to Critical Strike (Amazon only)": [ + "107,9" + ], + "{:d} to Jab (Amazon only)": [ + "107,10" + ], + "{:d} to Cold Arrow (Amazon only)": [ + "107,11" + ], + "{:d} to Multiple Shot (Amazon only)": [ + "107,12" + ], + "{:d} to Dodge (Amazon only)": [ + "107,13" + ], + "{:d} to Power Strike (Amazon only)": [ + "107,14" + ], + "{:d} to Poison Javelin (Amazon only)": [ + "107,15" + ], + "{:d} to Exploding Arrow (Amazon only)": [ + "107,16" + ], + "{:d} to Slow Missiles (Amazon only)": [ + "107,17" + ], + "{:d} to Avoid (Amazon only)": [ + "107,18" + ], + "{:d} to Impale (Amazon only)": [ + "107,19" + ], + "{:d} to Lightning Bolt (Amazon only)": [ + "107,20" + ], + "{:d} to Ice Arrow (Amazon only)": [ + "107,21" + ], + "{:d} to Guided Arrow (Amazon only)": [ + "107,22" + ], + "{:d} to Penetrate (Amazon only)": [ + "107,23" + ], + "{:d} to Charged Strike (Amazon only)": [ + "107,24" + ], + "{:d} to Plague Javelin (Amazon only)": [ + "107,25" + ], + "{:d} to Strafe (Amazon only)": [ + "107,26" + ], + "{:d} to Immolation Arrow (Amazon only)": [ + "107,27" + ], + "{:d} to Decoy (Amazon only)": [ + "107,28" + ], + "{:d} to Evade (Amazon only)": [ + "107,29" + ], + "{:d} to Fend (Amazon only)": [ + "107,30" + ], + "{:d} to Freezing Arrow (Amazon only)": [ + "107,31" + ], + "{:d} to Valkyrie (Amazon only)": [ + "107,32" + ], + "{:d} to Pierce (Amazon only)": [ + "107,33" + ], + "{:d} to Lightning Strike (Amazon only)": [ + "107,34" + ], + "{:d} to Lightning Fury (Amazon only)": [ + "107,35" + ], + "{:d} to Fire Bolt (Sorceress only)": [ + "107,36" + ], + "{:d} to Warmth (Sorceress only)": [ + "107,37" + ], + "{:d} to Charged Bolt (Sorceress only)": [ + "107,38" + ], + "{:d} to Ice Bolt (Sorceress only)": [ + "107,39" + ], + "{:d} to Frozen Armor (Sorceress only)": [ + "107,40" + ], + "{:d} to Inferno (Sorceress only)": [ + "107,41" + ], + "{:d} to Static Field (Sorceress only)": [ + "107,42" + ], + "{:d} to Telekinesis (Sorceress only)": [ + "107,43" + ], + "{:d} to Frost Nova (Sorceress only)": [ + "107,44" + ], + "{:d} to Ice Blast (Sorceress only)": [ + "107,45" + ], + "{:d} to Blaze (Sorceress only)": [ + "107,46" + ], + "{:d} to Fire Ball (Sorceress only)": [ + "107,47" + ], + "{:d} to Nova (Sorceress only)": [ + "107,48" + ], + "{:d} to Lightning (Sorceress only)": [ + "107,49" + ], + "{:d} to Shiver Armor (Sorceress only)": [ + "107,50" + ], + "{:d} to Fire Wall (Sorceress only)": [ + "107,51" + ], + "{:d} to Enchant (Sorceress only)": [ + "107,52" + ], + "{:d} to Chain Lightning (Sorceress only)": [ + "107,53" + ], + "{:d} to Teleport (Sorceress only)": [ + "107,54" + ], + "{:d} to Glacial Spike (Sorceress only)": [ + "107,55" + ], + "{:d} to Meteor (Sorceress only)": [ + "107,56" + ], + "{:d} to Thunder Storm (Sorceress only)": [ + "107,57" + ], + "{:d} to Energy Shield (Sorceress only)": [ + "107,58" + ], + "{:d} to Blizzard (Sorceress only)": [ + "107,59" + ], + "{:d} to Chilling Armor (Sorceress only)": [ + "107,60" + ], + "{:d} to Fire Mastery (Sorceress only)": [ + "107,61" + ], + "{:d} to Hydra (Sorceress only)": [ + "107,62" + ], + "{:d} to Lightning Mastery (Sorceress only)": [ + "107,63" + ], + "{:d} to Frozen Orb (Sorceress only)": [ + "107,64" + ], + "{:d} to Cold Mastery (Sorceress only)": [ + "107,65" + ], + "{:d} to Amplify Damage (Necromancer only)": [ + "107,66" + ], + "{:d} to Teeth (Necromancer only)": [ + "107,67" + ], + "{:d} to Bone Armor (Necromancer only)": [ + "107,68" + ], + "{:d} to Skeleton Mastery (Necromancer only)": [ + "107,69" + ], + "{:d} to Raise Skeleton (Necromancer only)": [ + "107,70" + ], + "{:d} to Dim Vision (Necromancer only)": [ + "107,71" + ], + "{:d} to Weaken (Necromancer only)": [ + "107,72" + ], + "{:d} to Poison Dagger (Necromancer only)": [ + "107,73" + ], + "{:d} to Corpse Explosion (Necromancer only)": [ + "107,74" + ], + "{:d} to Clay Golem (Necromancer only)": [ + "107,75" + ], + "{:d} to Iron Maiden (Necromancer only)": [ + "107,76" + ], + "{:d} to Terror (Necromancer only)": [ + "107,77" + ], + "{:d} to Bone Wall (Necromancer only)": [ + "107,78" + ], + "{:d} to Golem Mastery (Necromancer only)": [ + "107,79" + ], + "{:d} to Raise Skeletal Mage (Necromancer only)": [ + "107,80" + ], + "{:d} to Confuse (Necromancer only)": [ + "107,81" + ], + "{:d} to Life Tap (Necromancer only)": [ + "107,82" + ], + "{:d} to Poison Explosion (Necromancer only)": [ + "107,83" + ], + "{:d} to Bone Spear (Necromancer only)": [ + "107,84" + ], + "{:d} to Blood Golem (Necromancer only)": [ + "107,85" + ], + "{:d} to Attract (Necromancer only)": [ + "107,86" + ], + "{:d} to Decrepify (Necromancer only)": [ + "107,87" + ], + "{:d} to Bone Prison (Necromancer only)": [ + "107,88" + ], + "{:d} to Summon Resist (Necromancer only)": [ + "107,89" + ], + "{:d} to Iron Golem (Necromancer only)": [ + "107,90" + ], + "{:d} to Lower Resist (Necromancer only)": [ + "107,91" + ], + "{:d} to Poison Nova (Necromancer only)": [ + "107,92" + ], + "{:d} to Bone Spirit (Necromancer only)": [ + "107,93" + ], + "{:d} to Fire Golem (Necromancer only)": [ + "107,94" + ], + "{:d} to Revive (Necromancer only)": [ + "107,95" + ], + "{:d} to Sacrifice (Paladin only)": [ + "107,96" + ], + "{:d} to Smite (Paladin only)": [ + "107,97" + ], + "{:d} to Might (Paladin only)": [ + "107,98" + ], + "{:d} to Prayer (Paladin only)": [ + "107,99" + ], + "{:d} to Resist Fire (Paladin only)": [ + "107,100" + ], + "{:d} to Holy Bolt (Paladin only)": [ + "107,101" + ], + "{:d} to Holy Fire (Paladin only)": [ + "107,102" + ], + "{:d} to Thorns (Paladin only)": [ + "107,103" + ], + "{:d} to Defiance (Paladin only)": [ + "107,104" + ], + "{:d} to Resist Cold (Paladin only)": [ + "107,105" + ], + "{:d} to Zeal (Paladin only)": [ + "107,106" + ], + "{:d} to Charge (Paladin only)": [ + "107,107" + ], + "{:d} to Blessed Aim (Paladin only)": [ + "107,108" + ], + "{:d} to Cleansing (Paladin only)": [ + "107,109" + ], + "{:d} to Resist Lightning (Paladin only)": [ + "107,110" + ], + "{:d} to Vengeance (Paladin only)": [ + "107,111" + ], + "{:d} to Blessed Hammer (Paladin only)": [ + "107,112" + ], + "{:d} to Concentration (Paladin only)": [ + "107,113" + ], + "{:d} to Holy Freeze (Paladin only)": [ + "107,114" + ], + "{:d} to Vigor (Paladin only)": [ + "107,115" + ], + "{:d} to Conversion (Paladin only)": [ + "107,116" + ], + "{:d} to Holy Shield (Paladin only)": [ + "107,117" + ], + "{:d} to Holy Shock (Paladin only)": [ + "107,118" + ], + "{:d} to Sanctuary (Paladin only)": [ + "107,119" + ], + "{:d} to Meditation (Paladin only)": [ + "107,120" + ], + "{:d} to Fist of the Heavens (Paladin only)": [ + "107,121" + ], + "{:d} to Fanaticism (Paladin only)": [ + "107,122" + ], + "{:d} to Conviction (Paladin only)": [ + "107,123" + ], + "{:d} to Redemption (Paladin only)": [ + "107,124" + ], + "{:d} to Salvation (Paladin only)": [ + "107,125" + ], + "{:d} to Bash (Barbarian only)": [ + "107,126" + ], + "{:d} to Blade Mastery (Barbarian only)": [ + "107,127" + ], + "{:d} to Axe Mastery (Barbarian only)": [ + "107,128" + ], + "{:d} to Mace Mastery (Barbarian only)": [ + "107,129" + ], + "{:d} to Howl (Barbarian only)": [ + "107,130" + ], + "{:d} to Find Potion (Barbarian only)": [ + "107,131" + ], + "{:d} to Leap (Barbarian only)": [ + "107,132" + ], + "{:d} to Double Swing (Barbarian only)": [ + "107,133" + ], + "{:d} to Polearm Mastery (Barbarian only)": [ + "107,134" + ], + "{:d} to Throwing Mastery (Barbarian only)": [ + "107,135" + ], + "{:d} to Spear Mastery (Barbarian only)": [ + "107,136" + ], + "{:d} to Taunt (Barbarian only)": [ + "107,137" + ], + "{:d} to Shout (Barbarian only)": [ + "107,138" + ], + "{:d} to Stun (Barbarian only)": [ + "107,139" + ], + "{:d} to Double Throw (Barbarian only)": [ + "107,140" + ], + "{:d} to Increased Stamina (Barbarian only)": [ + "107,141" + ], + "{:d} to Find Item (Barbarian only)": [ + "107,142" + ], + "{:d} to Leap Attack (Barbarian only)": [ + "107,143" + ], + "{:d} to Concentrate (Barbarian only)": [ + "107,144" + ], + "{:d} to Iron Skin (Barbarian only)": [ + "107,145" + ], + "{:d} to Battle Cry (Barbarian only)": [ + "107,146" + ], + "{:d} to Frenzy (Barbarian only)": [ + "107,147" + ], + "{:d} to Increased Speed (Barbarian only)": [ + "107,148" + ], + "{:d} to Battle Orders (Barbarian only)": [ + "107,149" + ], + "{:d} to Grim Ward (Barbarian only)": [ + "107,150" + ], + "{:d} to Whirlwind (Barbarian only)": [ + "107,151" + ], + "{:d} to Berserk (Barbarian only)": [ + "107,152" + ], + "{:d} to Natural Resistance (Barbarian only)": [ + "107,153" + ], + "{:d} to War Cry (Barbarian only)": [ + "107,154" + ], + "{:d} to Battle Command (Barbarian only)": [ + "107,155" + ], + "{:d} to Raven (Druid only)": [ + "107,221" + ], + "{:d} to Poison Creeper (Druid only)": [ + "107,222" + ], + "{:d} to Werewolf (Druid only)": [ + "107,223" + ], + "{:d} to Lycanthropy (Druid only)": [ + "107,224" + ], + "{:d} to Firestorm (Druid only)": [ + "107,225" + ], + "{:d} to Oak Sage (Druid only)": [ + "107,226" + ], + "{:d} to Summon Spirit Wolf (Druid only)": [ + "107,227" + ], + "{:d} to Werebear (Druid only)": [ + "107,228" + ], + "{:d} to Molten Boulder (Druid only)": [ + "107,229" + ], + "{:d} to Arctic Blast (Druid only)": [ + "107,230" + ], + "{:d} to Carrion Vine (Druid only)": [ + "107,231" + ], + "{:d} to Feral Rage (Druid only)": [ + "107,232" + ], + "{:d} to Maul (Druid only)": [ + "107,233" + ], + "{:d} to Fissure (Druid only)": [ + "107,234" + ], + "{:d} to Cyclone Armor (Druid only)": [ + "107,235" + ], + "{:d} to Heart of Wolverine (Druid only)": [ + "107,236" + ], + "{:d} to Summon Dire Wolf (Druid only)": [ + "107,237" + ], + "{:d} to Rabies (Druid only)": [ + "107,238" + ], + "{:d} to Fire Claws (Druid only)": [ + "107,239" + ], + "{:d} to Twister (Druid only)": [ + "107,240" + ], + "{:d} to Solar Creeper (Druid only)": [ + "107,241" + ], + "{:d} to Hunger (Druid only)": [ + "107,242" + ], + "{:d} to Shock Wave (Druid only)": [ + "107,243" + ], + "{:d} to Volcano (Druid only)": [ + "107,244" + ], + "{:d} to Tornado (Druid only)": [ + "107,245" + ], + "{:d} to Spirit of Barbs (Druid only)": [ + "107,246" + ], + "{:d} to Summon Grizzly (Druid only)": [ + "107,247" + ], + "{:d} to Fury (Druid only)": [ + "107,248" + ], + "{:d} to Armageddon (Druid only)": [ + "107,249" + ], + "{:d} to Hurricane (Druid only)": [ + "107,250" + ], + "{:d} to Fire Blast (Assassin only)": [ + "107,251" + ], + "{:d} to Claw Mastery (Assassin only)": [ + "107,252" + ], + "{:d} to Psychic Hammer (Assassin only)": [ + "107,253" + ], + "{:d} to Tiger Strike (Assassin only)": [ + "107,254" + ], + "{:d} to Dragon Talon (Assassin only)": [ + "107,255" + ], + "{:d} to Shock Web (Assassin only)": [ + "107,256" + ], + "{:d} to Blade Sentinel (Assassin only)": [ + "107,257" + ], + "{:d} to Burst of Speed (Assassin only)": [ + "107,258" + ], + "{:d} to Fists of Fire (Assassin only)": [ + "107,259" + ], + "{:d} to Dragon Claw (Assassin only)": [ + "107,260" + ], + "{:d} to Charged Bolt Sentry (Assassin only)": [ + "107,261" + ], + "{:d} to Wake of Fire (Assassin only)": [ + "107,262" + ], + "{:d} to Weapon Block (Assassin only)": [ + "107,263" + ], + "{:d} to Cloak of Shadows (Assassin only)": [ + "107,264" + ], + "{:d} to Cobra Strike (Assassin only)": [ + "107,265" + ], + "{:d} to Blade Fury (Assassin only)": [ + "107,266" + ], + "{:d} to Fade (Assassin only)": [ + "107,267" + ], + "{:d} to Shadow Warrior (Assassin only)": [ + "107,268" + ], + "{:d} to Claws of Thunder (Assassin only)": [ + "107,269" + ], + "{:d} to Dragon Tail (Assassin only)": [ + "107,270" + ], + "{:d} to Lightning Sentry (Assassin only)": [ + "107,271" + ], + "{:d} to Wake of Inferno (Assassin only)": [ + "107,272" + ], + "{:d} to Mind Blast (Assassin only)": [ + "107,273" + ], + "{:d} to Blades of Ice (Assassin only)": [ + "107,274" + ], + "{:d} to Dragon Flight (Assassin only)": [ + "107,275" + ], + "{:d} to Death Sentry (Assassin only)": [ + "107,276" + ], + "{:d} to Blade Shield (Assassin only)": [ + "107,277" + ], + "{:d} to Venom (Assassin only)": [ + "107,278" + ], + "{:d} to Shadow Master (Assassin only)": [ + "107,279" + ], + "{:d} to Phoenix Strike (Assassin only)": [ + "107,280" + ], + "{:d} to Bow and Crossbow Skills (Amazon Only)": [ + "188,0" + ], + "{:d} to Passive and Magic Skills (Amazon Only)": [ + "188,1" + ], + "{:d} to Javelin and Spear Skills (Amazon Only)": [ + "188,2" + ], + "{:d} to Fire Skills (Sorceress Only)": [ + "188,3" + ], + "{:d} to Lightning Skills (Sorceress Only)": [ + "188,4" + ], + "{:d} to Cold Skills (Sorceress Only)": [ + "188,5" + ], + "{:d} to Curses (Necromancer Only)": [ + "188,6" + ], + "{:d} to Poison and Bone Skills (Necromancer Only)": [ + "188,7" + ], + "{:d} to Combat Skills (Necromancer Only)": [ + "188,8" + ], + "{:d} to Combat Skills (Paladin Only)": [ + "188,9" + ], + "{:d} to Offensive Auras (Paladin Only)": [ + "188,10" + ], + "{:d} to Defensive Auras (Paladin Only)": [ + "188,11" + ], + "{:d} to Combat Skills (Barbarian Only)": [ + "188,12" + ], + "{:d} to Masteries (Barbarian Only)": [ + "188,13" + ], + "{:d} to Warcries (Barbarian Only)": [ + "188,14" + ], + "{:d} to Summoning Skills (Druid Only)": [ + "188,15" + ], + "{:d} to Shape Shifting Skills (Druid Only)": [ + "188,16" + ], + "{:d} to Elemental Skills (Druid Only)": [ + "188,17" + ], + "{:d} to Traps (Assassin Only)": [ + "188,18" + ], + "{:d} to Shadow Disciplines (Assassin Only)": [ + "188,19" + ], + "{:d} to Martial Arts (Assassin Only)": [ + "188,20" + ], + "Level {:d} Magic Arrow Aura When Equipped": [ + "151,6" + ], + "Level {:d} Fire Arrow Aura When Equipped": [ + "151,7" + ], + "Level {:d} Inner Sight Aura When Equipped": [ + "151,8" + ], + "Level {:d} Critical Strike Aura When Equipped": [ + "151,9" + ], + "Level {:d} Jab Aura When Equipped": [ + "151,10" + ], + "Level {:d} Cold Arrow Aura When Equipped": [ + "151,11" + ], + "Level {:d} Multiple Shot Aura When Equipped": [ + "151,12" + ], + "Level {:d} Dodge Aura When Equipped": [ + "151,13" + ], + "Level {:d} Power Strike Aura When Equipped": [ + "151,14" + ], + "Level {:d} Poison Javelin Aura When Equipped": [ + "151,15" + ], + "Level {:d} Exploding Arrow Aura When Equipped": [ + "151,16" + ], + "Level {:d} Slow Missiles Aura When Equipped": [ + "151,17" + ], + "Level {:d} Avoid Aura When Equipped": [ + "151,18" + ], + "Level {:d} Impale Aura When Equipped": [ + "151,19" + ], + "Level {:d} Lightning Bolt Aura When Equipped": [ + "151,20" + ], + "Level {:d} Ice Arrow Aura When Equipped": [ + "151,21" + ], + "Level {:d} Guided Arrow Aura When Equipped": [ + "151,22" + ], + "Level {:d} Penetrate Aura When Equipped": [ + "151,23" + ], + "Level {:d} Charged Strike Aura When Equipped": [ + "151,24" + ], + "Level {:d} Plague Javelin Aura When Equipped": [ + "151,25" + ], + "Level {:d} Strafe Aura When Equipped": [ + "151,26" + ], + "Level {:d} Immolation Arrow Aura When Equipped": [ + "151,27" + ], + "Level {:d} Decoy Aura When Equipped": [ + "151,28" + ], + "Level {:d} Evade Aura When Equipped": [ + "151,29" + ], + "Level {:d} Fend Aura When Equipped": [ + "151,30" + ], + "Level {:d} Freezing Arrow Aura When Equipped": [ + "151,31" + ], + "Level {:d} Valkyrie Aura When Equipped": [ + "151,32" + ], + "Level {:d} Pierce Aura When Equipped": [ + "151,33" + ], + "Level {:d} Lightning Strike Aura When Equipped": [ + "151,34" + ], + "Level {:d} Lightning Fury Aura When Equipped": [ + "151,35" + ], + "Level {:d} Fire Bolt Aura When Equipped": [ + "151,36" + ], + "Level {:d} Warmth Aura When Equipped": [ + "151,37" + ], + "Level {:d} Charged Bolt Aura When Equipped": [ + "151,38" + ], + "Level {:d} Ice Bolt Aura When Equipped": [ + "151,39" + ], + "Level {:d} Frozen Armor Aura When Equipped": [ + "151,40" + ], + "Level {:d} Inferno Aura When Equipped": [ + "151,41" + ], + "Level {:d} Static Field Aura When Equipped": [ + "151,42" + ], + "Level {:d} Telekinesis Aura When Equipped": [ + "151,43" + ], + "Level {:d} Frost Nova Aura When Equipped": [ + "151,44" + ], + "Level {:d} Ice Blast Aura When Equipped": [ + "151,45" + ], + "Level {:d} Blaze Aura When Equipped": [ + "151,46" + ], + "Level {:d} Fire Ball Aura When Equipped": [ + "151,47" + ], + "Level {:d} Nova Aura When Equipped": [ + "151,48" + ], + "Level {:d} Lightning Aura When Equipped": [ + "151,49" + ], + "Level {:d} Shiver Armor Aura When Equipped": [ + "151,50" + ], + "Level {:d} Fire Wall Aura When Equipped": [ + "151,51" + ], + "Level {:d} Enchant Aura When Equipped": [ + "151,52" + ], + "Level {:d} Chain Lightning Aura When Equipped": [ + "151,53" + ], + "Level {:d} Teleport Aura When Equipped": [ + "151,54" + ], + "Level {:d} Glacial Spike Aura When Equipped": [ + "151,55" + ], + "Level {:d} Meteor Aura When Equipped": [ + "151,56" + ], + "Level {:d} Thunder Storm Aura When Equipped": [ + "151,57" + ], + "Level {:d} Energy Shield Aura When Equipped": [ + "151,58" + ], + "Level {:d} Blizzard Aura When Equipped": [ + "151,59" + ], + "Level {:d} Chilling Armor Aura When Equipped": [ + "151,60" + ], + "Level {:d} Fire Mastery Aura When Equipped": [ + "151,61" + ], + "Level {:d} Hydra Aura When Equipped": [ + "151,62" + ], + "Level {:d} Lightning Mastery Aura When Equipped": [ + "151,63" + ], + "Level {:d} Frozen Orb Aura When Equipped": [ + "151,64" + ], + "Level {:d} Cold Mastery Aura When Equipped": [ + "151,65" + ], + "Level {:d} Amplify Damage Aura When Equipped": [ + "151,66" + ], + "Level {:d} Teeth Aura When Equipped": [ + "151,67" + ], + "Level {:d} Bone Armor Aura When Equipped": [ + "151,68" + ], + "Level {:d} Skeleton Mastery Aura When Equipped": [ + "151,69" + ], + "Level {:d} Raise Skeleton Aura When Equipped": [ + "151,70" + ], + "Level {:d} Dim Vision Aura When Equipped": [ + "151,71" + ], + "Level {:d} Weaken Aura When Equipped": [ + "151,72" + ], + "Level {:d} Poison Dagger Aura When Equipped": [ + "151,73" + ], + "Level {:d} Corpse Explosion Aura When Equipped": [ + "151,74" + ], + "Level {:d} Clay Golem Aura When Equipped": [ + "151,75" + ], + "Level {:d} Iron Maiden Aura When Equipped": [ + "151,76" + ], + "Level {:d} Terror Aura When Equipped": [ + "151,77" + ], + "Level {:d} Bone Wall Aura When Equipped": [ + "151,78" + ], + "Level {:d} Golem Mastery Aura When Equipped": [ + "151,79" + ], + "Level {:d} Raise Skeletal Mage Aura When Equipped": [ + "151,80" + ], + "Level {:d} Confuse Aura When Equipped": [ + "151,81" + ], + "Level {:d} Life Tap Aura When Equipped": [ + "151,82" + ], + "Level {:d} Poison Explosion Aura When Equipped": [ + "151,83" + ], + "Level {:d} Bone Spear Aura When Equipped": [ + "151,84" + ], + "Level {:d} Blood Golem Aura When Equipped": [ + "151,85" + ], + "Level {:d} Attract Aura When Equipped": [ + "151,86" + ], + "Level {:d} Decrepify Aura When Equipped": [ + "151,87" + ], + "Level {:d} Bone Prison Aura When Equipped": [ + "151,88" + ], + "Level {:d} Summon Resist Aura When Equipped": [ + "151,89" + ], + "Level {:d} Iron Golem Aura When Equipped": [ + "151,90" + ], + "Level {:d} Lower Resist Aura When Equipped": [ + "151,91" + ], + "Level {:d} Poison Nova Aura When Equipped": [ + "151,92" + ], + "Level {:d} Bone Spirit Aura When Equipped": [ + "151,93" + ], + "Level {:d} Fire Golem Aura When Equipped": [ + "151,94" + ], + "Level {:d} Revive Aura When Equipped": [ + "151,95" + ], + "Level {:d} Sacrifice Aura When Equipped": [ + "151,96" + ], + "Level {:d} Smite Aura When Equipped": [ + "151,97" + ], + "Level {:d} Might Aura When Equipped": [ + "151,98" + ], + "Level {:d} Prayer Aura When Equipped": [ + "151,99" + ], + "Level {:d} Resist Fire Aura When Equipped": [ + "151,100" + ], + "Level {:d} Holy Bolt Aura When Equipped": [ + "151,101" + ], + "Level {:d} Holy Fire Aura When Equipped": [ + "151,102" + ], + "Level {:d} Thorns Aura When Equipped": [ + "151,103" + ], + "Level {:d} Defiance Aura When Equipped": [ + "151,104" + ], + "Level {:d} Resist Cold Aura When Equipped": [ + "151,105" + ], + "Level {:d} Zeal Aura When Equipped": [ + "151,106" + ], + "Level {:d} Charge Aura When Equipped": [ + "151,107" + ], + "Level {:d} Blessed Aim Aura When Equipped": [ + "151,108" + ], + "Level {:d} Cleansing Aura When Equipped": [ + "151,109" + ], + "Level {:d} Resist Lightning Aura When Equipped": [ + "151,110" + ], + "Level {:d} Vengeance Aura When Equipped": [ + "151,111" + ], + "Level {:d} Blessed Hammer Aura When Equipped": [ + "151,112" + ], + "Level {:d} Concentration Aura When Equipped": [ + "151,113" + ], + "Level {:d} Holy Freeze Aura When Equipped": [ + "151,114" + ], + "Level {:d} Vigor Aura When Equipped": [ + "151,115" + ], + "Level {:d} Conversion Aura When Equipped": [ + "151,116" + ], + "Level {:d} Holy Shield Aura When Equipped": [ + "151,117" + ], + "Level {:d} Holy Shock Aura When Equipped": [ + "151,118" + ], + "Level {:d} Sanctuary Aura When Equipped": [ + "151,119" + ], + "Level {:d} Meditation Aura When Equipped": [ + "151,120" + ], + "Level {:d} Fist of the Heavens Aura When Equipped": [ + "151,121" + ], + "Level {:d} Fanaticism Aura When Equipped": [ + "151,122" + ], + "Level {:d} Conviction Aura When Equipped": [ + "151,123" + ], + "Level {:d} Redemption Aura When Equipped": [ + "151,124" + ], + "Level {:d} Salvation Aura When Equipped": [ + "151,125" + ], + "Level {:d} Bash Aura When Equipped": [ + "151,126" + ], + "Level {:d} Blade Mastery Aura When Equipped": [ + "151,127" + ], + "Level {:d} Axe Mastery Aura When Equipped": [ + "151,128" + ], + "Level {:d} Mace Mastery Aura When Equipped": [ + "151,129" + ], + "Level {:d} Howl Aura When Equipped": [ + "151,130" + ], + "Level {:d} Find Potion Aura When Equipped": [ + "151,131" + ], + "Level {:d} Leap Aura When Equipped": [ + "151,132" + ], + "Level {:d} Double Swing Aura When Equipped": [ + "151,133" + ], + "Level {:d} Polearm Mastery Aura When Equipped": [ + "151,134" + ], + "Level {:d} Throwing Mastery Aura When Equipped": [ + "151,135" + ], + "Level {:d} Spear Mastery Aura When Equipped": [ + "151,136" + ], + "Level {:d} Taunt Aura When Equipped": [ + "151,137" + ], + "Level {:d} Shout Aura When Equipped": [ + "151,138" + ], + "Level {:d} Stun Aura When Equipped": [ + "151,139" + ], + "Level {:d} Double Throw Aura When Equipped": [ + "151,140" + ], + "Level {:d} Increased Stamina Aura When Equipped": [ + "151,141" + ], + "Level {:d} Find Item Aura When Equipped": [ + "151,142" + ], + "Level {:d} Leap Attack Aura When Equipped": [ + "151,143" + ], + "Level {:d} Concentrate Aura When Equipped": [ + "151,144" + ], + "Level {:d} Iron Skin Aura When Equipped": [ + "151,145" + ], + "Level {:d} Battle Cry Aura When Equipped": [ + "151,146" + ], + "Level {:d} Frenzy Aura When Equipped": [ + "151,147" + ], + "Level {:d} Increased Speed Aura When Equipped": [ + "151,148" + ], + "Level {:d} Battle Orders Aura When Equipped": [ + "151,149" + ], + "Level {:d} Grim Ward Aura When Equipped": [ + "151,150" + ], + "Level {:d} Whirlwind Aura When Equipped": [ + "151,151" + ], + "Level {:d} Berserk Aura When Equipped": [ + "151,152" + ], + "Level {:d} Natural Resistance Aura When Equipped": [ + "151,153" + ], + "Level {:d} War Cry Aura When Equipped": [ + "151,154" + ], + "Level {:d} Battle Command Aura When Equipped": [ + "151,155" + ], + "Level {:d} Raven Aura When Equipped": [ + "151,221" + ], + "Level {:d} Poison Creeper Aura When Equipped": [ + "151,222" + ], + "Level {:d} Werewolf Aura When Equipped": [ + "151,223" + ], + "Level {:d} Lycanthropy Aura When Equipped": [ + "151,224" + ], + "Level {:d} Firestorm Aura When Equipped": [ + "151,225" + ], + "Level {:d} Oak Sage Aura When Equipped": [ + "151,226" + ], + "Level {:d} Summon Spirit Wolf Aura When Equipped": [ + "151,227" + ], + "Level {:d} Werebear Aura When Equipped": [ + "151,228" + ], + "Level {:d} Molten Boulder Aura When Equipped": [ + "151,229" + ], + "Level {:d} Arctic Blast Aura When Equipped": [ + "151,230" + ], + "Level {:d} Carrion Vine Aura When Equipped": [ + "151,231" + ], + "Level {:d} Feral Rage Aura When Equipped": [ + "151,232" + ], + "Level {:d} Maul Aura When Equipped": [ + "151,233" + ], + "Level {:d} Fissure Aura When Equipped": [ + "151,234" + ], + "Level {:d} Cyclone Armor Aura When Equipped": [ + "151,235" + ], + "Level {:d} Heart of Wolverine Aura When Equipped": [ + "151,236" + ], + "Level {:d} Summon Dire Wolf Aura When Equipped": [ + "151,237" + ], + "Level {:d} Rabies Aura When Equipped": [ + "151,238" + ], + "Level {:d} Fire Claws Aura When Equipped": [ + "151,239" + ], + "Level {:d} Twister Aura When Equipped": [ + "151,240" + ], + "Level {:d} Solar Creeper Aura When Equipped": [ + "151,241" + ], + "Level {:d} Hunger Aura When Equipped": [ + "151,242" + ], + "Level {:d} Shock Wave Aura When Equipped": [ + "151,243" + ], + "Level {:d} Volcano Aura When Equipped": [ + "151,244" + ], + "Level {:d} Tornado Aura When Equipped": [ + "151,245" + ], + "Level {:d} Spirit of Barbs Aura When Equipped": [ + "151,246" + ], + "Level {:d} Summon Grizzly Aura When Equipped": [ + "151,247" + ], + "Level {:d} Fury Aura When Equipped": [ + "151,248" + ], + "Level {:d} Armageddon Aura When Equipped": [ + "151,249" + ], + "Level {:d} Hurricane Aura When Equipped": [ + "151,250" + ], + "Level {:d} Fire Blast Aura When Equipped": [ + "151,251" + ], + "Level {:d} Claw Mastery Aura When Equipped": [ + "151,252" + ], + "Level {:d} Psychic Hammer Aura When Equipped": [ + "151,253" + ], + "Level {:d} Tiger Strike Aura When Equipped": [ + "151,254" + ], + "Level {:d} Dragon Talon Aura When Equipped": [ + "151,255" + ], + "Level {:d} Shock Web Aura When Equipped": [ + "151,256" + ], + "Level {:d} Blade Sentinel Aura When Equipped": [ + "151,257" + ], + "Level {:d} Burst of Speed Aura When Equipped": [ + "151,258" + ], + "Level {:d} Fists of Fire Aura When Equipped": [ + "151,259" + ], + "Level {:d} Dragon Claw Aura When Equipped": [ + "151,260" + ], + "Level {:d} Charged Bolt Sentry Aura When Equipped": [ + "151,261" + ], + "Level {:d} Wake of Fire Aura When Equipped": [ + "151,262" + ], + "Level {:d} Weapon Block Aura When Equipped": [ + "151,263" + ], + "Level {:d} Cloak of Shadows Aura When Equipped": [ + "151,264" + ], + "Level {:d} Cobra Strike Aura When Equipped": [ + "151,265" + ], + "Level {:d} Blade Fury Aura When Equipped": [ + "151,266" + ], + "Level {:d} Fade Aura When Equipped": [ + "151,267" + ], + "Level {:d} Shadow Warrior Aura When Equipped": [ + "151,268" + ], + "Level {:d} Claws of Thunder Aura When Equipped": [ + "151,269" + ], + "Level {:d} Dragon Tail Aura When Equipped": [ + "151,270" + ], + "Level {:d} Lightning Sentry Aura When Equipped": [ + "151,271" + ], + "Level {:d} Wake of Inferno Aura When Equipped": [ + "151,272" + ], + "Level {:d} Mind Blast Aura When Equipped": [ + "151,273" + ], + "Level {:d} Blades of Ice Aura When Equipped": [ + "151,274" + ], + "Level {:d} Dragon Flight Aura When Equipped": [ + "151,275" + ], + "Level {:d} Death Sentry Aura When Equipped": [ + "151,276" + ], + "Level {:d} Blade Shield Aura When Equipped": [ + "151,277" + ], + "Level {:d} Venom Aura When Equipped": [ + "151,278" + ], + "Level {:d} Shadow Master Aura When Equipped": [ + "151,279" + ], + "Level {:d} Phoenix Strike Aura When Equipped": [ + "151,280" + ], + "{:d}% Chance to cast level {:d} Magic Arrow on attack": [ + "195,6" + ], + "{:d}% Chance to cast level {:d} Fire Arrow on attack": [ + "195,7" + ], + "{:d}% Chance to cast level {:d} Inner Sight on attack": [ + "195,8" + ], + "{:d}% Chance to cast level {:d} Critical Strike on attack": [ + "195,9" + ], + "{:d}% Chance to cast level {:d} Jab on attack": [ + "195,10" + ], + "{:d}% Chance to cast level {:d} Cold Arrow on attack": [ + "195,11" + ], + "{:d}% Chance to cast level {:d} Multiple Shot on attack": [ + "195,12" + ], + "{:d}% Chance to cast level {:d} Dodge on attack": [ + "195,13" + ], + "{:d}% Chance to cast level {:d} Power Strike on attack": [ + "195,14" + ], + "{:d}% Chance to cast level {:d} Poison Javelin on attack": [ + "195,15" + ], + "{:d}% Chance to cast level {:d} Exploding Arrow on attack": [ + "195,16" + ], + "{:d}% Chance to cast level {:d} Slow Missiles on attack": [ + "195,17" + ], + "{:d}% Chance to cast level {:d} Avoid on attack": [ + "195,18" + ], + "{:d}% Chance to cast level {:d} Impale on attack": [ + "195,19" + ], + "{:d}% Chance to cast level {:d} Lightning Bolt on attack": [ + "195,20" + ], + "{:d}% Chance to cast level {:d} Ice Arrow on attack": [ + "195,21" + ], + "{:d}% Chance to cast level {:d} Guided Arrow on attack": [ + "195,22" + ], + "{:d}% Chance to cast level {:d} Penetrate on attack": [ + "195,23" + ], + "{:d}% Chance to cast level {:d} Charged Strike on attack": [ + "195,24" + ], + "{:d}% Chance to cast level {:d} Plague Javelin on attack": [ + "195,25" + ], + "{:d}% Chance to cast level {:d} Strafe on attack": [ + "195,26" + ], + "{:d}% Chance to cast level {:d} Immolation Arrow on attack": [ + "195,27" + ], + "{:d}% Chance to cast level {:d} Decoy on attack": [ + "195,28" + ], + "{:d}% Chance to cast level {:d} Evade on attack": [ + "195,29" + ], + "{:d}% Chance to cast level {:d} Fend on attack": [ + "195,30" + ], + "{:d}% Chance to cast level {:d} Freezing Arrow on attack": [ + "195,31" + ], + "{:d}% Chance to cast level {:d} Valkyrie on attack": [ + "195,32" + ], + "{:d}% Chance to cast level {:d} Pierce on attack": [ + "195,33" + ], + "{:d}% Chance to cast level {:d} Lightning Strike on attack": [ + "195,34" + ], + "{:d}% Chance to cast level {:d} Lightning Fury on attack": [ + "195,35" + ], + "{:d}% Chance to cast level {:d} Fire Bolt on attack": [ + "195,36" + ], + "{:d}% Chance to cast level {:d} Warmth on attack": [ + "195,37" + ], + "{:d}% Chance to cast level {:d} Charged Bolt on attack": [ + "195,38" + ], + "{:d}% Chance to cast level {:d} Ice Bolt on attack": [ + "195,39" + ], + "{:d}% Chance to cast level {:d} Frozen Armor on attack": [ + "195,40" + ], + "{:d}% Chance to cast level {:d} Inferno on attack": [ + "195,41" + ], + "{:d}% Chance to cast level {:d} Static Field on attack": [ + "195,42" + ], + "{:d}% Chance to cast level {:d} Telekinesis on attack": [ + "195,43" + ], + "{:d}% Chance to cast level {:d} Frost Nova on attack": [ + "195,44" + ], + "{:d}% Chance to cast level {:d} Ice Blast on attack": [ + "195,45" + ], + "{:d}% Chance to cast level {:d} Blaze on attack": [ + "195,46" + ], + "{:d}% Chance to cast level {:d} Fire Ball on attack": [ + "195,47" + ], + "{:d}% Chance to cast level {:d} Nova on attack": [ + "195,48" + ], + "{:d}% Chance to cast level {:d} Lightning on attack": [ + "195,49" + ], + "{:d}% Chance to cast level {:d} Shiver Armor on attack": [ + "195,50" + ], + "{:d}% Chance to cast level {:d} Fire Wall on attack": [ + "195,51" + ], + "{:d}% Chance to cast level {:d} Enchant on attack": [ + "195,52" + ], + "{:d}% Chance to cast level {:d} Chain Lightning on attack": [ + "195,53" + ], + "{:d}% Chance to cast level {:d} Teleport on attack": [ + "195,54" + ], + "{:d}% Chance to cast level {:d} Glacial Spike on attack": [ + "195,55" + ], + "{:d}% Chance to cast level {:d} Meteor on attack": [ + "195,56" + ], + "{:d}% Chance to cast level {:d} Thunder Storm on attack": [ + "195,57" + ], + "{:d}% Chance to cast level {:d} Energy Shield on attack": [ + "195,58" + ], + "{:d}% Chance to cast level {:d} Blizzard on attack": [ + "195,59" + ], + "{:d}% Chance to cast level {:d} Chilling Armor on attack": [ + "195,60" + ], + "{:d}% Chance to cast level {:d} Fire Mastery on attack": [ + "195,61" + ], + "{:d}% Chance to cast level {:d} Hydra on attack": [ + "195,62" + ], + "{:d}% Chance to cast level {:d} Lightning Mastery on attack": [ + "195,63" + ], + "{:d}% Chance to cast level {:d} Frozen Orb on attack": [ + "195,64" + ], + "{:d}% Chance to cast level {:d} Cold Mastery on attack": [ + "195,65" + ], + "{:d}% Chance to cast level {:d} Amplify Damage on attack": [ + "195,66" + ], + "{:d}% Chance to cast level {:d} Teeth on attack": [ + "195,67" + ], + "{:d}% Chance to cast level {:d} Bone Armor on attack": [ + "195,68" + ], + "{:d}% Chance to cast level {:d} Skeleton Mastery on attack": [ + "195,69" + ], + "{:d}% Chance to cast level {:d} Raise Skeleton on attack": [ + "195,70" + ], + "{:d}% Chance to cast level {:d} Dim Vision on attack": [ + "195,71" + ], + "{:d}% Chance to cast level {:d} Weaken on attack": [ + "195,72" + ], + "{:d}% Chance to cast level {:d} Poison Dagger on attack": [ + "195,73" + ], + "{:d}% Chance to cast level {:d} Corpse Explosion on attack": [ + "195,74" + ], + "{:d}% Chance to cast level {:d} Clay Golem on attack": [ + "195,75" + ], + "{:d}% Chance to cast level {:d} Iron Maiden on attack": [ + "195,76" + ], + "{:d}% Chance to cast level {:d} Terror on attack": [ + "195,77" + ], + "{:d}% Chance to cast level {:d} Bone Wall on attack": [ + "195,78" + ], + "{:d}% Chance to cast level {:d} Golem Mastery on attack": [ + "195,79" + ], + "{:d}% Chance to cast level {:d} Raise Skeletal Mage on attack": [ + "195,80" + ], + "{:d}% Chance to cast level {:d} Confuse on attack": [ + "195,81" + ], + "{:d}% Chance to cast level {:d} Life Tap on attack": [ + "195,82" + ], + "{:d}% Chance to cast level {:d} Poison Explosion on attack": [ + "195,83" + ], + "{:d}% Chance to cast level {:d} Bone Spear on attack": [ + "195,84" + ], + "{:d}% Chance to cast level {:d} Blood Golem on attack": [ + "195,85" + ], + "{:d}% Chance to cast level {:d} Attract on attack": [ + "195,86" + ], + "{:d}% Chance to cast level {:d} Decrepify on attack": [ + "195,87" + ], + "{:d}% Chance to cast level {:d} Bone Prison on attack": [ + "195,88" + ], + "{:d}% Chance to cast level {:d} Summon Resist on attack": [ + "195,89" + ], + "{:d}% Chance to cast level {:d} Iron Golem on attack": [ + "195,90" + ], + "{:d}% Chance to cast level {:d} Lower Resist on attack": [ + "195,91" + ], + "{:d}% Chance to cast level {:d} Poison Nova on attack": [ + "195,92" + ], + "{:d}% Chance to cast level {:d} Bone Spirit on attack": [ + "195,93" + ], + "{:d}% Chance to cast level {:d} Fire Golem on attack": [ + "195,94" + ], + "{:d}% Chance to cast level {:d} Revive on attack": [ + "195,95" + ], + "{:d}% Chance to cast level {:d} Sacrifice on attack": [ + "195,96" + ], + "{:d}% Chance to cast level {:d} Smite on attack": [ + "195,97" + ], + "{:d}% Chance to cast level {:d} Might on attack": [ + "195,98" + ], + "{:d}% Chance to cast level {:d} Prayer on attack": [ + "195,99" + ], + "{:d}% Chance to cast level {:d} Resist Fire on attack": [ + "195,100" + ], + "{:d}% Chance to cast level {:d} Holy Bolt on attack": [ + "195,101" + ], + "{:d}% Chance to cast level {:d} Holy Fire on attack": [ + "195,102" + ], + "{:d}% Chance to cast level {:d} Thorns on attack": [ + "195,103" + ], + "{:d}% Chance to cast level {:d} Defiance on attack": [ + "195,104" + ], + "{:d}% Chance to cast level {:d} Resist Cold on attack": [ + "195,105" + ], + "{:d}% Chance to cast level {:d} Zeal on attack": [ + "195,106" + ], + "{:d}% Chance to cast level {:d} Charge on attack": [ + "195,107" + ], + "{:d}% Chance to cast level {:d} Blessed Aim on attack": [ + "195,108" + ], + "{:d}% Chance to cast level {:d} Cleansing on attack": [ + "195,109" + ], + "{:d}% Chance to cast level {:d} Resist Lightning on attack": [ + "195,110" + ], + "{:d}% Chance to cast level {:d} Vengeance on attack": [ + "195,111" + ], + "{:d}% Chance to cast level {:d} Blessed Hammer on attack": [ + "195,112" + ], + "{:d}% Chance to cast level {:d} Concentration on attack": [ + "195,113" + ], + "{:d}% Chance to cast level {:d} Holy Freeze on attack": [ + "195,114" + ], + "{:d}% Chance to cast level {:d} Vigor on attack": [ + "195,115" + ], + "{:d}% Chance to cast level {:d} Conversion on attack": [ + "195,116" + ], + "{:d}% Chance to cast level {:d} Holy Shield on attack": [ + "195,117" + ], + "{:d}% Chance to cast level {:d} Holy Shock on attack": [ + "195,118" + ], + "{:d}% Chance to cast level {:d} Sanctuary on attack": [ + "195,119" + ], + "{:d}% Chance to cast level {:d} Meditation on attack": [ + "195,120" + ], + "{:d}% Chance to cast level {:d} Fist of the Heavens on attack": [ + "195,121" + ], + "{:d}% Chance to cast level {:d} Fanaticism on attack": [ + "195,122" + ], + "{:d}% Chance to cast level {:d} Conviction on attack": [ + "195,123" + ], + "{:d}% Chance to cast level {:d} Redemption on attack": [ + "195,124" + ], + "{:d}% Chance to cast level {:d} Salvation on attack": [ + "195,125" + ], + "{:d}% Chance to cast level {:d} Bash on attack": [ + "195,126" + ], + "{:d}% Chance to cast level {:d} Blade Mastery on attack": [ + "195,127" + ], + "{:d}% Chance to cast level {:d} Axe Mastery on attack": [ + "195,128" + ], + "{:d}% Chance to cast level {:d} Mace Mastery on attack": [ + "195,129" + ], + "{:d}% Chance to cast level {:d} Howl on attack": [ + "195,130" + ], + "{:d}% Chance to cast level {:d} Find Potion on attack": [ + "195,131" + ], + "{:d}% Chance to cast level {:d} Leap on attack": [ + "195,132" + ], + "{:d}% Chance to cast level {:d} Double Swing on attack": [ + "195,133" + ], + "{:d}% Chance to cast level {:d} Polearm Mastery on attack": [ + "195,134" + ], + "{:d}% Chance to cast level {:d} Throwing Mastery on attack": [ + "195,135" + ], + "{:d}% Chance to cast level {:d} Spear Mastery on attack": [ + "195,136" + ], + "{:d}% Chance to cast level {:d} Taunt on attack": [ + "195,137" + ], + "{:d}% Chance to cast level {:d} Shout on attack": [ + "195,138" + ], + "{:d}% Chance to cast level {:d} Stun on attack": [ + "195,139" + ], + "{:d}% Chance to cast level {:d} Double Throw on attack": [ + "195,140" + ], + "{:d}% Chance to cast level {:d} Increased Stamina on attack": [ + "195,141" + ], + "{:d}% Chance to cast level {:d} Find Item on attack": [ + "195,142" + ], + "{:d}% Chance to cast level {:d} Leap Attack on attack": [ + "195,143" + ], + "{:d}% Chance to cast level {:d} Concentrate on attack": [ + "195,144" + ], + "{:d}% Chance to cast level {:d} Iron Skin on attack": [ + "195,145" + ], + "{:d}% Chance to cast level {:d} Battle Cry on attack": [ + "195,146" + ], + "{:d}% Chance to cast level {:d} Frenzy on attack": [ + "195,147" + ], + "{:d}% Chance to cast level {:d} Increased Speed on attack": [ + "195,148" + ], + "{:d}% Chance to cast level {:d} Battle Orders on attack": [ + "195,149" + ], + "{:d}% Chance to cast level {:d} Grim Ward on attack": [ + "195,150" + ], + "{:d}% Chance to cast level {:d} Whirlwind on attack": [ + "195,151" + ], + "{:d}% Chance to cast level {:d} Berserk on attack": [ + "195,152" + ], + "{:d}% Chance to cast level {:d} Natural Resistance on attack": [ + "195,153" + ], + "{:d}% Chance to cast level {:d} War Cry on attack": [ + "195,154" + ], + "{:d}% Chance to cast level {:d} Battle Command on attack": [ + "195,155" + ], + "{:d}% Chance to cast level {:d} Raven on attack": [ + "195,221" + ], + "{:d}% Chance to cast level {:d} Poison Creeper on attack": [ + "195,222" + ], + "{:d}% Chance to cast level {:d} Werewolf on attack": [ + "195,223" + ], + "{:d}% Chance to cast level {:d} Lycanthropy on attack": [ + "195,224" + ], + "{:d}% Chance to cast level {:d} Firestorm on attack": [ + "195,225" + ], + "{:d}% Chance to cast level {:d} Oak Sage on attack": [ + "195,226" + ], + "{:d}% Chance to cast level {:d} Summon Spirit Wolf on attack": [ + "195,227" + ], + "{:d}% Chance to cast level {:d} Werebear on attack": [ + "195,228" + ], + "{:d}% Chance to cast level {:d} Molten Boulder on attack": [ + "195,229" + ], + "{:d}% Chance to cast level {:d} Arctic Blast on attack": [ + "195,230" + ], + "{:d}% Chance to cast level {:d} Carrion Vine on attack": [ + "195,231" + ], + "{:d}% Chance to cast level {:d} Feral Rage on attack": [ + "195,232" + ], + "{:d}% Chance to cast level {:d} Maul on attack": [ + "195,233" + ], + "{:d}% Chance to cast level {:d} Fissure on attack": [ + "195,234" + ], + "{:d}% Chance to cast level {:d} Cyclone Armor on attack": [ + "195,235" + ], + "{:d}% Chance to cast level {:d} Heart of Wolverine on attack": [ + "195,236" + ], + "{:d}% Chance to cast level {:d} Summon Dire Wolf on attack": [ + "195,237" + ], + "{:d}% Chance to cast level {:d} Rabies on attack": [ + "195,238" + ], + "{:d}% Chance to cast level {:d} Fire Claws on attack": [ + "195,239" + ], + "{:d}% Chance to cast level {:d} Twister on attack": [ + "195,240" + ], + "{:d}% Chance to cast level {:d} Solar Creeper on attack": [ + "195,241" + ], + "{:d}% Chance to cast level {:d} Hunger on attack": [ + "195,242" + ], + "{:d}% Chance to cast level {:d} Shock Wave on attack": [ + "195,243" + ], + "{:d}% Chance to cast level {:d} Volcano on attack": [ + "195,244" + ], + "{:d}% Chance to cast level {:d} Tornado on attack": [ + "195,245" + ], + "{:d}% Chance to cast level {:d} Spirit of Barbs on attack": [ + "195,246" + ], + "{:d}% Chance to cast level {:d} Summon Grizzly on attack": [ + "195,247" + ], + "{:d}% Chance to cast level {:d} Fury on attack": [ + "195,248" + ], + "{:d}% Chance to cast level {:d} Armageddon on attack": [ + "195,249" + ], + "{:d}% Chance to cast level {:d} Hurricane on attack": [ + "195,250" + ], + "{:d}% Chance to cast level {:d} Fire Blast on attack": [ + "195,251" + ], + "{:d}% Chance to cast level {:d} Claw Mastery on attack": [ + "195,252" + ], + "{:d}% Chance to cast level {:d} Psychic Hammer on attack": [ + "195,253" + ], + "{:d}% Chance to cast level {:d} Tiger Strike on attack": [ + "195,254" + ], + "{:d}% Chance to cast level {:d} Dragon Talon on attack": [ + "195,255" + ], + "{:d}% Chance to cast level {:d} Shock Web on attack": [ + "195,256" + ], + "{:d}% Chance to cast level {:d} Blade Sentinel on attack": [ + "195,257" + ], + "{:d}% Chance to cast level {:d} Burst of Speed on attack": [ + "195,258" + ], + "{:d}% Chance to cast level {:d} Fists of Fire on attack": [ + "195,259" + ], + "{:d}% Chance to cast level {:d} Dragon Claw on attack": [ + "195,260" + ], + "{:d}% Chance to cast level {:d} Charged Bolt Sentry on attack": [ + "195,261" + ], + "{:d}% Chance to cast level {:d} Wake of Fire on attack": [ + "195,262" + ], + "{:d}% Chance to cast level {:d} Weapon Block on attack": [ + "195,263" + ], + "{:d}% Chance to cast level {:d} Cloak of Shadows on attack": [ + "195,264" + ], + "{:d}% Chance to cast level {:d} Cobra Strike on attack": [ + "195,265" + ], + "{:d}% Chance to cast level {:d} Blade Fury on attack": [ + "195,266" + ], + "{:d}% Chance to cast level {:d} Fade on attack": [ + "195,267" + ], + "{:d}% Chance to cast level {:d} Shadow Warrior on attack": [ + "195,268" + ], + "{:d}% Chance to cast level {:d} Claws of Thunder on attack": [ + "195,269" + ], + "{:d}% Chance to cast level {:d} Dragon Tail on attack": [ + "195,270" + ], + "{:d}% Chance to cast level {:d} Lightning Sentry on attack": [ + "195,271" + ], + "{:d}% Chance to cast level {:d} Wake of Inferno on attack": [ + "195,272" + ], + "{:d}% Chance to cast level {:d} Mind Blast on attack": [ + "195,273" + ], + "{:d}% Chance to cast level {:d} Blades of Ice on attack": [ + "195,274" + ], + "{:d}% Chance to cast level {:d} Dragon Flight on attack": [ + "195,275" + ], + "{:d}% Chance to cast level {:d} Death Sentry on attack": [ + "195,276" + ], + "{:d}% Chance to cast level {:d} Blade Shield on attack": [ + "195,277" + ], + "{:d}% Chance to cast level {:d} Venom on attack": [ + "195,278" + ], + "{:d}% Chance to cast level {:d} Shadow Master on attack": [ + "195,279" + ], + "{:d}% Chance to cast level {:d} Phoenix Strike on attack": [ + "195,280" + ], + "{:d}% Chance to cast level {:d} Magic Arrow on striking": [ + "198,6" + ], + "{:d}% Chance to cast level {:d} Fire Arrow on striking": [ + "198,7" + ], + "{:d}% Chance to cast level {:d} Inner Sight on striking": [ + "198,8" + ], + "{:d}% Chance to cast level {:d} Critical Strike on striking": [ + "198,9" + ], + "{:d}% Chance to cast level {:d} Jab on striking": [ + "198,10" + ], + "{:d}% Chance to cast level {:d} Cold Arrow on striking": [ + "198,11" + ], + "{:d}% Chance to cast level {:d} Multiple Shot on striking": [ + "198,12" + ], + "{:d}% Chance to cast level {:d} Dodge on striking": [ + "198,13" + ], + "{:d}% Chance to cast level {:d} Power Strike on striking": [ + "198,14" + ], + "{:d}% Chance to cast level {:d} Poison Javelin on striking": [ + "198,15" + ], + "{:d}% Chance to cast level {:d} Exploding Arrow on striking": [ + "198,16" + ], + "{:d}% Chance to cast level {:d} Slow Missiles on striking": [ + "198,17" + ], + "{:d}% Chance to cast level {:d} Avoid on striking": [ + "198,18" + ], + "{:d}% Chance to cast level {:d} Impale on striking": [ + "198,19" + ], + "{:d}% Chance to cast level {:d} Lightning Bolt on striking": [ + "198,20" + ], + "{:d}% Chance to cast level {:d} Ice Arrow on striking": [ + "198,21" + ], + "{:d}% Chance to cast level {:d} Guided Arrow on striking": [ + "198,22" + ], + "{:d}% Chance to cast level {:d} Penetrate on striking": [ + "198,23" + ], + "{:d}% Chance to cast level {:d} Charged Strike on striking": [ + "198,24" + ], + "{:d}% Chance to cast level {:d} Plague Javelin on striking": [ + "198,25" + ], + "{:d}% Chance to cast level {:d} Strafe on striking": [ + "198,26" + ], + "{:d}% Chance to cast level {:d} Immolation Arrow on striking": [ + "198,27" + ], + "{:d}% Chance to cast level {:d} Decoy on striking": [ + "198,28" + ], + "{:d}% Chance to cast level {:d} Evade on striking": [ + "198,29" + ], + "{:d}% Chance to cast level {:d} Fend on striking": [ + "198,30" + ], + "{:d}% Chance to cast level {:d} Freezing Arrow on striking": [ + "198,31" + ], + "{:d}% Chance to cast level {:d} Valkyrie on striking": [ + "198,32" + ], + "{:d}% Chance to cast level {:d} Pierce on striking": [ + "198,33" + ], + "{:d}% Chance to cast level {:d} Lightning Strike on striking": [ + "198,34" + ], + "{:d}% Chance to cast level {:d} Lightning Fury on striking": [ + "198,35" + ], + "{:d}% Chance to cast level {:d} Fire Bolt on striking": [ + "198,36" + ], + "{:d}% Chance to cast level {:d} Warmth on striking": [ + "198,37" + ], + "{:d}% Chance to cast level {:d} Charged Bolt on striking": [ + "198,38" + ], + "{:d}% Chance to cast level {:d} Ice Bolt on striking": [ + "198,39" + ], + "{:d}% Chance to cast level {:d} Frozen Armor on striking": [ + "198,40" + ], + "{:d}% Chance to cast level {:d} Inferno on striking": [ + "198,41" + ], + "{:d}% Chance to cast level {:d} Static Field on striking": [ + "198,42" + ], + "{:d}% Chance to cast level {:d} Telekinesis on striking": [ + "198,43" + ], + "{:d}% Chance to cast level {:d} Frost Nova on striking": [ + "198,44" + ], + "{:d}% Chance to cast level {:d} Ice Blast on striking": [ + "198,45" + ], + "{:d}% Chance to cast level {:d} Blaze on striking": [ + "198,46" + ], + "{:d}% Chance to cast level {:d} Fire Ball on striking": [ + "198,47" + ], + "{:d}% Chance to cast level {:d} Nova on striking": [ + "198,48" + ], + "{:d}% Chance to cast level {:d} Lightning on striking": [ + "198,49" + ], + "{:d}% Chance to cast level {:d} Shiver Armor on striking": [ + "198,50" + ], + "{:d}% Chance to cast level {:d} Fire Wall on striking": [ + "198,51" + ], + "{:d}% Chance to cast level {:d} Enchant on striking": [ + "198,52" + ], + "{:d}% Chance to cast level {:d} Chain Lightning on striking": [ + "198,53" + ], + "{:d}% Chance to cast level {:d} Teleport on striking": [ + "198,54" + ], + "{:d}% Chance to cast level {:d} Glacial Spike on striking": [ + "198,55" + ], + "{:d}% Chance to cast level {:d} Meteor on striking": [ + "198,56" + ], + "{:d}% Chance to cast level {:d} Thunder Storm on striking": [ + "198,57" + ], + "{:d}% Chance to cast level {:d} Energy Shield on striking": [ + "198,58" + ], + "{:d}% Chance to cast level {:d} Blizzard on striking": [ + "198,59" + ], + "{:d}% Chance to cast level {:d} Chilling Armor on striking": [ + "198,60" + ], + "{:d}% Chance to cast level {:d} Fire Mastery on striking": [ + "198,61" + ], + "{:d}% Chance to cast level {:d} Hydra on striking": [ + "198,62" + ], + "{:d}% Chance to cast level {:d} Lightning Mastery on striking": [ + "198,63" + ], + "{:d}% Chance to cast level {:d} Frozen Orb on striking": [ + "198,64" + ], + "{:d}% Chance to cast level {:d} Cold Mastery on striking": [ + "198,65" + ], + "{:d}% Chance to cast level {:d} Amplify Damage on striking": [ + "198,66" + ], + "{:d}% Chance to cast level {:d} Teeth on striking": [ + "198,67" + ], + "{:d}% Chance to cast level {:d} Bone Armor on striking": [ + "198,68" + ], + "{:d}% Chance to cast level {:d} Skeleton Mastery on striking": [ + "198,69" + ], + "{:d}% Chance to cast level {:d} Raise Skeleton on striking": [ + "198,70" + ], + "{:d}% Chance to cast level {:d} Dim Vision on striking": [ + "198,71" + ], + "{:d}% Chance to cast level {:d} Weaken on striking": [ + "198,72" + ], + "{:d}% Chance to cast level {:d} Poison Dagger on striking": [ + "198,73" + ], + "{:d}% Chance to cast level {:d} Corpse Explosion on striking": [ + "198,74" + ], + "{:d}% Chance to cast level {:d} Clay Golem on striking": [ + "198,75" + ], + "{:d}% Chance to cast level {:d} Iron Maiden on striking": [ + "198,76" + ], + "{:d}% Chance to cast level {:d} Terror on striking": [ + "198,77" + ], + "{:d}% Chance to cast level {:d} Bone Wall on striking": [ + "198,78" + ], + "{:d}% Chance to cast level {:d} Golem Mastery on striking": [ + "198,79" + ], + "{:d}% Chance to cast level {:d} Raise Skeletal Mage on striking": [ + "198,80" + ], + "{:d}% Chance to cast level {:d} Confuse on striking": [ + "198,81" + ], + "{:d}% Chance to cast level {:d} Life Tap on striking": [ + "198,82" + ], + "{:d}% Chance to cast level {:d} Poison Explosion on striking": [ + "198,83" + ], + "{:d}% Chance to cast level {:d} Bone Spear on striking": [ + "198,84" + ], + "{:d}% Chance to cast level {:d} Blood Golem on striking": [ + "198,85" + ], + "{:d}% Chance to cast level {:d} Attract on striking": [ + "198,86" + ], + "{:d}% Chance to cast level {:d} Decrepify on striking": [ + "198,87" + ], + "{:d}% Chance to cast level {:d} Bone Prison on striking": [ + "198,88" + ], + "{:d}% Chance to cast level {:d} Summon Resist on striking": [ + "198,89" + ], + "{:d}% Chance to cast level {:d} Iron Golem on striking": [ + "198,90" + ], + "{:d}% Chance to cast level {:d} Lower Resist on striking": [ + "198,91" + ], + "{:d}% Chance to cast level {:d} Poison Nova on striking": [ + "198,92" + ], + "{:d}% Chance to cast level {:d} Bone Spirit on striking": [ + "198,93" + ], + "{:d}% Chance to cast level {:d} Fire Golem on striking": [ + "198,94" + ], + "{:d}% Chance to cast level {:d} Revive on striking": [ + "198,95" + ], + "{:d}% Chance to cast level {:d} Sacrifice on striking": [ + "198,96" + ], + "{:d}% Chance to cast level {:d} Smite on striking": [ + "198,97" + ], + "{:d}% Chance to cast level {:d} Might on striking": [ + "198,98" + ], + "{:d}% Chance to cast level {:d} Prayer on striking": [ + "198,99" + ], + "{:d}% Chance to cast level {:d} Resist Fire on striking": [ + "198,100" + ], + "{:d}% Chance to cast level {:d} Holy Bolt on striking": [ + "198,101" + ], + "{:d}% Chance to cast level {:d} Holy Fire on striking": [ + "198,102" + ], + "{:d}% Chance to cast level {:d} Thorns on striking": [ + "198,103" + ], + "{:d}% Chance to cast level {:d} Defiance on striking": [ + "198,104" + ], + "{:d}% Chance to cast level {:d} Resist Cold on striking": [ + "198,105" + ], + "{:d}% Chance to cast level {:d} Zeal on striking": [ + "198,106" + ], + "{:d}% Chance to cast level {:d} Charge on striking": [ + "198,107" + ], + "{:d}% Chance to cast level {:d} Blessed Aim on striking": [ + "198,108" + ], + "{:d}% Chance to cast level {:d} Cleansing on striking": [ + "198,109" + ], + "{:d}% Chance to cast level {:d} Resist Lightning on striking": [ + "198,110" + ], + "{:d}% Chance to cast level {:d} Vengeance on striking": [ + "198,111" + ], + "{:d}% Chance to cast level {:d} Blessed Hammer on striking": [ + "198,112" + ], + "{:d}% Chance to cast level {:d} Concentration on striking": [ + "198,113" + ], + "{:d}% Chance to cast level {:d} Holy Freeze on striking": [ + "198,114" + ], + "{:d}% Chance to cast level {:d} Vigor on striking": [ + "198,115" + ], + "{:d}% Chance to cast level {:d} Conversion on striking": [ + "198,116" + ], + "{:d}% Chance to cast level {:d} Holy Shield on striking": [ + "198,117" + ], + "{:d}% Chance to cast level {:d} Holy Shock on striking": [ + "198,118" + ], + "{:d}% Chance to cast level {:d} Sanctuary on striking": [ + "198,119" + ], + "{:d}% Chance to cast level {:d} Meditation on striking": [ + "198,120" + ], + "{:d}% Chance to cast level {:d} Fist of the Heavens on striking": [ + "198,121" + ], + "{:d}% Chance to cast level {:d} Fanaticism on striking": [ + "198,122" + ], + "{:d}% Chance to cast level {:d} Conviction on striking": [ + "198,123" + ], + "{:d}% Chance to cast level {:d} Redemption on striking": [ + "198,124" + ], + "{:d}% Chance to cast level {:d} Salvation on striking": [ + "198,125" + ], + "{:d}% Chance to cast level {:d} Bash on striking": [ + "198,126" + ], + "{:d}% Chance to cast level {:d} Blade Mastery on striking": [ + "198,127" + ], + "{:d}% Chance to cast level {:d} Axe Mastery on striking": [ + "198,128" + ], + "{:d}% Chance to cast level {:d} Mace Mastery on striking": [ + "198,129" + ], + "{:d}% Chance to cast level {:d} Howl on striking": [ + "198,130" + ], + "{:d}% Chance to cast level {:d} Find Potion on striking": [ + "198,131" + ], + "{:d}% Chance to cast level {:d} Leap on striking": [ + "198,132" + ], + "{:d}% Chance to cast level {:d} Double Swing on striking": [ + "198,133" + ], + "{:d}% Chance to cast level {:d} Polearm Mastery on striking": [ + "198,134" + ], + "{:d}% Chance to cast level {:d} Throwing Mastery on striking": [ + "198,135" + ], + "{:d}% Chance to cast level {:d} Spear Mastery on striking": [ + "198,136" + ], + "{:d}% Chance to cast level {:d} Taunt on striking": [ + "198,137" + ], + "{:d}% Chance to cast level {:d} Shout on striking": [ + "198,138" + ], + "{:d}% Chance to cast level {:d} Stun on striking": [ + "198,139" + ], + "{:d}% Chance to cast level {:d} Double Throw on striking": [ + "198,140" + ], + "{:d}% Chance to cast level {:d} Increased Stamina on striking": [ + "198,141" + ], + "{:d}% Chance to cast level {:d} Find Item on striking": [ + "198,142" + ], + "{:d}% Chance to cast level {:d} Leap Attack on striking": [ + "198,143" + ], + "{:d}% Chance to cast level {:d} Concentrate on striking": [ + "198,144" + ], + "{:d}% Chance to cast level {:d} Iron Skin on striking": [ + "198,145" + ], + "{:d}% Chance to cast level {:d} Battle Cry on striking": [ + "198,146" + ], + "{:d}% Chance to cast level {:d} Frenzy on striking": [ + "198,147" + ], + "{:d}% Chance to cast level {:d} Increased Speed on striking": [ + "198,148" + ], + "{:d}% Chance to cast level {:d} Battle Orders on striking": [ + "198,149" + ], + "{:d}% Chance to cast level {:d} Grim Ward on striking": [ + "198,150" + ], + "{:d}% Chance to cast level {:d} Whirlwind on striking": [ + "198,151" + ], + "{:d}% Chance to cast level {:d} Berserk on striking": [ + "198,152" + ], + "{:d}% Chance to cast level {:d} Natural Resistance on striking": [ + "198,153" + ], + "{:d}% Chance to cast level {:d} War Cry on striking": [ + "198,154" + ], + "{:d}% Chance to cast level {:d} Battle Command on striking": [ + "198,155" + ], + "{:d}% Chance to cast level {:d} Raven on striking": [ + "198,221" + ], + "{:d}% Chance to cast level {:d} Poison Creeper on striking": [ + "198,222" + ], + "{:d}% Chance to cast level {:d} Werewolf on striking": [ + "198,223" + ], + "{:d}% Chance to cast level {:d} Lycanthropy on striking": [ + "198,224" + ], + "{:d}% Chance to cast level {:d} Firestorm on striking": [ + "198,225" + ], + "{:d}% Chance to cast level {:d} Oak Sage on striking": [ + "198,226" + ], + "{:d}% Chance to cast level {:d} Summon Spirit Wolf on striking": [ + "198,227" + ], + "{:d}% Chance to cast level {:d} Werebear on striking": [ + "198,228" + ], + "{:d}% Chance to cast level {:d} Molten Boulder on striking": [ + "198,229" + ], + "{:d}% Chance to cast level {:d} Arctic Blast on striking": [ + "198,230" + ], + "{:d}% Chance to cast level {:d} Carrion Vine on striking": [ + "198,231" + ], + "{:d}% Chance to cast level {:d} Feral Rage on striking": [ + "198,232" + ], + "{:d}% Chance to cast level {:d} Maul on striking": [ + "198,233" + ], + "{:d}% Chance to cast level {:d} Fissure on striking": [ + "198,234" + ], + "{:d}% Chance to cast level {:d} Cyclone Armor on striking": [ + "198,235" + ], + "{:d}% Chance to cast level {:d} Heart of Wolverine on striking": [ + "198,236" + ], + "{:d}% Chance to cast level {:d} Summon Dire Wolf on striking": [ + "198,237" + ], + "{:d}% Chance to cast level {:d} Rabies on striking": [ + "198,238" + ], + "{:d}% Chance to cast level {:d} Fire Claws on striking": [ + "198,239" + ], + "{:d}% Chance to cast level {:d} Twister on striking": [ + "198,240" + ], + "{:d}% Chance to cast level {:d} Solar Creeper on striking": [ + "198,241" + ], + "{:d}% Chance to cast level {:d} Hunger on striking": [ + "198,242" + ], + "{:d}% Chance to cast level {:d} Shock Wave on striking": [ + "198,243" + ], + "{:d}% Chance to cast level {:d} Volcano on striking": [ + "198,244" + ], + "{:d}% Chance to cast level {:d} Tornado on striking": [ + "198,245" + ], + "{:d}% Chance to cast level {:d} Spirit of Barbs on striking": [ + "198,246" + ], + "{:d}% Chance to cast level {:d} Summon Grizzly on striking": [ + "198,247" + ], + "{:d}% Chance to cast level {:d} Fury on striking": [ + "198,248" + ], + "{:d}% Chance to cast level {:d} Armageddon on striking": [ + "198,249" + ], + "{:d}% Chance to cast level {:d} Hurricane on striking": [ + "198,250" + ], + "{:d}% Chance to cast level {:d} Fire Blast on striking": [ + "198,251" + ], + "{:d}% Chance to cast level {:d} Claw Mastery on striking": [ + "198,252" + ], + "{:d}% Chance to cast level {:d} Psychic Hammer on striking": [ + "198,253" + ], + "{:d}% Chance to cast level {:d} Tiger Strike on striking": [ + "198,254" + ], + "{:d}% Chance to cast level {:d} Dragon Talon on striking": [ + "198,255" + ], + "{:d}% Chance to cast level {:d} Shock Web on striking": [ + "198,256" + ], + "{:d}% Chance to cast level {:d} Blade Sentinel on striking": [ + "198,257" + ], + "{:d}% Chance to cast level {:d} Burst of Speed on striking": [ + "198,258" + ], + "{:d}% Chance to cast level {:d} Fists of Fire on striking": [ + "198,259" + ], + "{:d}% Chance to cast level {:d} Dragon Claw on striking": [ + "198,260" + ], + "{:d}% Chance to cast level {:d} Charged Bolt Sentry on striking": [ + "198,261" + ], + "{:d}% Chance to cast level {:d} Wake of Fire on striking": [ + "198,262" + ], + "{:d}% Chance to cast level {:d} Weapon Block on striking": [ + "198,263" + ], + "{:d}% Chance to cast level {:d} Cloak of Shadows on striking": [ + "198,264" + ], + "{:d}% Chance to cast level {:d} Cobra Strike on striking": [ + "198,265" + ], + "{:d}% Chance to cast level {:d} Blade Fury on striking": [ + "198,266" + ], + "{:d}% Chance to cast level {:d} Fade on striking": [ + "198,267" + ], + "{:d}% Chance to cast level {:d} Shadow Warrior on striking": [ + "198,268" + ], + "{:d}% Chance to cast level {:d} Claws of Thunder on striking": [ + "198,269" + ], + "{:d}% Chance to cast level {:d} Dragon Tail on striking": [ + "198,270" + ], + "{:d}% Chance to cast level {:d} Lightning Sentry on striking": [ + "198,271" + ], + "{:d}% Chance to cast level {:d} Wake of Inferno on striking": [ + "198,272" + ], + "{:d}% Chance to cast level {:d} Mind Blast on striking": [ + "198,273" + ], + "{:d}% Chance to cast level {:d} Blades of Ice on striking": [ + "198,274" + ], + "{:d}% Chance to cast level {:d} Dragon Flight on striking": [ + "198,275" + ], + "{:d}% Chance to cast level {:d} Death Sentry on striking": [ + "198,276" + ], + "{:d}% Chance to cast level {:d} Blade Shield on striking": [ + "198,277" + ], + "{:d}% Chance to cast level {:d} Venom on striking": [ + "198,278" + ], + "{:d}% Chance to cast level {:d} Shadow Master on striking": [ + "198,279" + ], + "{:d}% Chance to cast level {:d} Phoenix Strike on striking": [ + "198,280" + ], + "{:d}% Chance to cast level {:d} Magic Arrow when struck": [ + "201,6" + ], + "{:d}% Chance to cast level {:d} Fire Arrow when struck": [ + "201,7" + ], + "{:d}% Chance to cast level {:d} Inner Sight when struck": [ + "201,8" + ], + "{:d}% Chance to cast level {:d} Critical Strike when struck": [ + "201,9" + ], + "{:d}% Chance to cast level {:d} Jab when struck": [ + "201,10" + ], + "{:d}% Chance to cast level {:d} Cold Arrow when struck": [ + "201,11" + ], + "{:d}% Chance to cast level {:d} Multiple Shot when struck": [ + "201,12" + ], + "{:d}% Chance to cast level {:d} Dodge when struck": [ + "201,13" + ], + "{:d}% Chance to cast level {:d} Power Strike when struck": [ + "201,14" + ], + "{:d}% Chance to cast level {:d} Poison Javelin when struck": [ + "201,15" + ], + "{:d}% Chance to cast level {:d} Exploding Arrow when struck": [ + "201,16" + ], + "{:d}% Chance to cast level {:d} Slow Missiles when struck": [ + "201,17" + ], + "{:d}% Chance to cast level {:d} Avoid when struck": [ + "201,18" + ], + "{:d}% Chance to cast level {:d} Impale when struck": [ + "201,19" + ], + "{:d}% Chance to cast level {:d} Lightning Bolt when struck": [ + "201,20" + ], + "{:d}% Chance to cast level {:d} Ice Arrow when struck": [ + "201,21" + ], + "{:d}% Chance to cast level {:d} Guided Arrow when struck": [ + "201,22" + ], + "{:d}% Chance to cast level {:d} Penetrate when struck": [ + "201,23" + ], + "{:d}% Chance to cast level {:d} Charged Strike when struck": [ + "201,24" + ], + "{:d}% Chance to cast level {:d} Plague Javelin when struck": [ + "201,25" + ], + "{:d}% Chance to cast level {:d} Strafe when struck": [ + "201,26" + ], + "{:d}% Chance to cast level {:d} Immolation Arrow when struck": [ + "201,27" + ], + "{:d}% Chance to cast level {:d} Decoy when struck": [ + "201,28" + ], + "{:d}% Chance to cast level {:d} Evade when struck": [ + "201,29" + ], + "{:d}% Chance to cast level {:d} Fend when struck": [ + "201,30" + ], + "{:d}% Chance to cast level {:d} Freezing Arrow when struck": [ + "201,31" + ], + "{:d}% Chance to cast level {:d} Valkyrie when struck": [ + "201,32" + ], + "{:d}% Chance to cast level {:d} Pierce when struck": [ + "201,33" + ], + "{:d}% Chance to cast level {:d} Lightning Strike when struck": [ + "201,34" + ], + "{:d}% Chance to cast level {:d} Lightning Fury when struck": [ + "201,35" + ], + "{:d}% Chance to cast level {:d} Fire Bolt when struck": [ + "201,36" + ], + "{:d}% Chance to cast level {:d} Warmth when struck": [ + "201,37" + ], + "{:d}% Chance to cast level {:d} Charged Bolt when struck": [ + "201,38" + ], + "{:d}% Chance to cast level {:d} Ice Bolt when struck": [ + "201,39" + ], + "{:d}% Chance to cast level {:d} Frozen Armor when struck": [ + "201,40" + ], + "{:d}% Chance to cast level {:d} Inferno when struck": [ + "201,41" + ], + "{:d}% Chance to cast level {:d} Static Field when struck": [ + "201,42" + ], + "{:d}% Chance to cast level {:d} Telekinesis when struck": [ + "201,43" + ], + "{:d}% Chance to cast level {:d} Frost Nova when struck": [ + "201,44" + ], + "{:d}% Chance to cast level {:d} Ice Blast when struck": [ + "201,45" + ], + "{:d}% Chance to cast level {:d} Blaze when struck": [ + "201,46" + ], + "{:d}% Chance to cast level {:d} Fire Ball when struck": [ + "201,47" + ], + "{:d}% Chance to cast level {:d} Nova when struck": [ + "201,48" + ], + "{:d}% Chance to cast level {:d} Lightning when struck": [ + "201,49" + ], + "{:d}% Chance to cast level {:d} Shiver Armor when struck": [ + "201,50" + ], + "{:d}% Chance to cast level {:d} Fire Wall when struck": [ + "201,51" + ], + "{:d}% Chance to cast level {:d} Enchant when struck": [ + "201,52" + ], + "{:d}% Chance to cast level {:d} Chain Lightning when struck": [ + "201,53" + ], + "{:d}% Chance to cast level {:d} Teleport when struck": [ + "201,54" + ], + "{:d}% Chance to cast level {:d} Glacial Spike when struck": [ + "201,55" + ], + "{:d}% Chance to cast level {:d} Meteor when struck": [ + "201,56" + ], + "{:d}% Chance to cast level {:d} Thunder Storm when struck": [ + "201,57" + ], + "{:d}% Chance to cast level {:d} Energy Shield when struck": [ + "201,58" + ], + "{:d}% Chance to cast level {:d} Blizzard when struck": [ + "201,59" + ], + "{:d}% Chance to cast level {:d} Chilling Armor when struck": [ + "201,60" + ], + "{:d}% Chance to cast level {:d} Fire Mastery when struck": [ + "201,61" + ], + "{:d}% Chance to cast level {:d} Hydra when struck": [ + "201,62" + ], + "{:d}% Chance to cast level {:d} Lightning Mastery when struck": [ + "201,63" + ], + "{:d}% Chance to cast level {:d} Frozen Orb when struck": [ + "201,64" + ], + "{:d}% Chance to cast level {:d} Cold Mastery when struck": [ + "201,65" + ], + "{:d}% Chance to cast level {:d} Amplify Damage when struck": [ + "201,66" + ], + "{:d}% Chance to cast level {:d} Teeth when struck": [ + "201,67" + ], + "{:d}% Chance to cast level {:d} Bone Armor when struck": [ + "201,68" + ], + "{:d}% Chance to cast level {:d} Skeleton Mastery when struck": [ + "201,69" + ], + "{:d}% Chance to cast level {:d} Raise Skeleton when struck": [ + "201,70" + ], + "{:d}% Chance to cast level {:d} Dim Vision when struck": [ + "201,71" + ], + "{:d}% Chance to cast level {:d} Weaken when struck": [ + "201,72" + ], + "{:d}% Chance to cast level {:d} Poison Dagger when struck": [ + "201,73" + ], + "{:d}% Chance to cast level {:d} Corpse Explosion when struck": [ + "201,74" + ], + "{:d}% Chance to cast level {:d} Clay Golem when struck": [ + "201,75" + ], + "{:d}% Chance to cast level {:d} Iron Maiden when struck": [ + "201,76" + ], + "{:d}% Chance to cast level {:d} Terror when struck": [ + "201,77" + ], + "{:d}% Chance to cast level {:d} Bone Wall when struck": [ + "201,78" + ], + "{:d}% Chance to cast level {:d} Golem Mastery when struck": [ + "201,79" + ], + "{:d}% Chance to cast level {:d} Raise Skeletal Mage when struck": [ + "201,80" + ], + "{:d}% Chance to cast level {:d} Confuse when struck": [ + "201,81" + ], + "{:d}% Chance to cast level {:d} Life Tap when struck": [ + "201,82" + ], + "{:d}% Chance to cast level {:d} Poison Explosion when struck": [ + "201,83" + ], + "{:d}% Chance to cast level {:d} Bone Spear when struck": [ + "201,84" + ], + "{:d}% Chance to cast level {:d} Blood Golem when struck": [ + "201,85" + ], + "{:d}% Chance to cast level {:d} Attract when struck": [ + "201,86" + ], + "{:d}% Chance to cast level {:d} Decrepify when struck": [ + "201,87" + ], + "{:d}% Chance to cast level {:d} Bone Prison when struck": [ + "201,88" + ], + "{:d}% Chance to cast level {:d} Summon Resist when struck": [ + "201,89" + ], + "{:d}% Chance to cast level {:d} Iron Golem when struck": [ + "201,90" + ], + "{:d}% Chance to cast level {:d} Lower Resist when struck": [ + "201,91" + ], + "{:d}% Chance to cast level {:d} Poison Nova when struck": [ + "201,92" + ], + "{:d}% Chance to cast level {:d} Bone Spirit when struck": [ + "201,93" + ], + "{:d}% Chance to cast level {:d} Fire Golem when struck": [ + "201,94" + ], + "{:d}% Chance to cast level {:d} Revive when struck": [ + "201,95" + ], + "{:d}% Chance to cast level {:d} Sacrifice when struck": [ + "201,96" + ], + "{:d}% Chance to cast level {:d} Smite when struck": [ + "201,97" + ], + "{:d}% Chance to cast level {:d} Might when struck": [ + "201,98" + ], + "{:d}% Chance to cast level {:d} Prayer when struck": [ + "201,99" + ], + "{:d}% Chance to cast level {:d} Resist Fire when struck": [ + "201,100" + ], + "{:d}% Chance to cast level {:d} Holy Bolt when struck": [ + "201,101" + ], + "{:d}% Chance to cast level {:d} Holy Fire when struck": [ + "201,102" + ], + "{:d}% Chance to cast level {:d} Thorns when struck": [ + "201,103" + ], + "{:d}% Chance to cast level {:d} Defiance when struck": [ + "201,104" + ], + "{:d}% Chance to cast level {:d} Resist Cold when struck": [ + "201,105" + ], + "{:d}% Chance to cast level {:d} Zeal when struck": [ + "201,106" + ], + "{:d}% Chance to cast level {:d} Charge when struck": [ + "201,107" + ], + "{:d}% Chance to cast level {:d} Blessed Aim when struck": [ + "201,108" + ], + "{:d}% Chance to cast level {:d} Cleansing when struck": [ + "201,109" + ], + "{:d}% Chance to cast level {:d} Resist Lightning when struck": [ + "201,110" + ], + "{:d}% Chance to cast level {:d} Vengeance when struck": [ + "201,111" + ], + "{:d}% Chance to cast level {:d} Blessed Hammer when struck": [ + "201,112" + ], + "{:d}% Chance to cast level {:d} Concentration when struck": [ + "201,113" + ], + "{:d}% Chance to cast level {:d} Holy Freeze when struck": [ + "201,114" + ], + "{:d}% Chance to cast level {:d} Vigor when struck": [ + "201,115" + ], + "{:d}% Chance to cast level {:d} Conversion when struck": [ + "201,116" + ], + "{:d}% Chance to cast level {:d} Holy Shield when struck": [ + "201,117" + ], + "{:d}% Chance to cast level {:d} Holy Shock when struck": [ + "201,118" + ], + "{:d}% Chance to cast level {:d} Sanctuary when struck": [ + "201,119" + ], + "{:d}% Chance to cast level {:d} Meditation when struck": [ + "201,120" + ], + "{:d}% Chance to cast level {:d} Fist of the Heavens when struck": [ + "201,121" + ], + "{:d}% Chance to cast level {:d} Fanaticism when struck": [ + "201,122" + ], + "{:d}% Chance to cast level {:d} Conviction when struck": [ + "201,123" + ], + "{:d}% Chance to cast level {:d} Redemption when struck": [ + "201,124" + ], + "{:d}% Chance to cast level {:d} Salvation when struck": [ + "201,125" + ], + "{:d}% Chance to cast level {:d} Bash when struck": [ + "201,126" + ], + "{:d}% Chance to cast level {:d} Blade Mastery when struck": [ + "201,127" + ], + "{:d}% Chance to cast level {:d} Axe Mastery when struck": [ + "201,128" + ], + "{:d}% Chance to cast level {:d} Mace Mastery when struck": [ + "201,129" + ], + "{:d}% Chance to cast level {:d} Howl when struck": [ + "201,130" + ], + "{:d}% Chance to cast level {:d} Find Potion when struck": [ + "201,131" + ], + "{:d}% Chance to cast level {:d} Leap when struck": [ + "201,132" + ], + "{:d}% Chance to cast level {:d} Double Swing when struck": [ + "201,133" + ], + "{:d}% Chance to cast level {:d} Polearm Mastery when struck": [ + "201,134" + ], + "{:d}% Chance to cast level {:d} Throwing Mastery when struck": [ + "201,135" + ], + "{:d}% Chance to cast level {:d} Spear Mastery when struck": [ + "201,136" + ], + "{:d}% Chance to cast level {:d} Taunt when struck": [ + "201,137" + ], + "{:d}% Chance to cast level {:d} Shout when struck": [ + "201,138" + ], + "{:d}% Chance to cast level {:d} Stun when struck": [ + "201,139" + ], + "{:d}% Chance to cast level {:d} Double Throw when struck": [ + "201,140" + ], + "{:d}% Chance to cast level {:d} Increased Stamina when struck": [ + "201,141" + ], + "{:d}% Chance to cast level {:d} Find Item when struck": [ + "201,142" + ], + "{:d}% Chance to cast level {:d} Leap Attack when struck": [ + "201,143" + ], + "{:d}% Chance to cast level {:d} Concentrate when struck": [ + "201,144" + ], + "{:d}% Chance to cast level {:d} Iron Skin when struck": [ + "201,145" + ], + "{:d}% Chance to cast level {:d} Battle Cry when struck": [ + "201,146" + ], + "{:d}% Chance to cast level {:d} Frenzy when struck": [ + "201,147" + ], + "{:d}% Chance to cast level {:d} Increased Speed when struck": [ + "201,148" + ], + "{:d}% Chance to cast level {:d} Battle Orders when struck": [ + "201,149" + ], + "{:d}% Chance to cast level {:d} Grim Ward when struck": [ + "201,150" + ], + "{:d}% Chance to cast level {:d} Whirlwind when struck": [ + "201,151" + ], + "{:d}% Chance to cast level {:d} Berserk when struck": [ + "201,152" + ], + "{:d}% Chance to cast level {:d} Natural Resistance when struck": [ + "201,153" + ], + "{:d}% Chance to cast level {:d} War Cry when struck": [ + "201,154" + ], + "{:d}% Chance to cast level {:d} Battle Command when struck": [ + "201,155" + ], + "{:d}% Chance to cast level {:d} Raven when struck": [ + "201,221" + ], + "{:d}% Chance to cast level {:d} Poison Creeper when struck": [ + "201,222" + ], + "{:d}% Chance to cast level {:d} Werewolf when struck": [ + "201,223" + ], + "{:d}% Chance to cast level {:d} Lycanthropy when struck": [ + "201,224" + ], + "{:d}% Chance to cast level {:d} Firestorm when struck": [ + "201,225" + ], + "{:d}% Chance to cast level {:d} Oak Sage when struck": [ + "201,226" + ], + "{:d}% Chance to cast level {:d} Summon Spirit Wolf when struck": [ + "201,227" + ], + "{:d}% Chance to cast level {:d} Werebear when struck": [ + "201,228" + ], + "{:d}% Chance to cast level {:d} Molten Boulder when struck": [ + "201,229" + ], + "{:d}% Chance to cast level {:d} Arctic Blast when struck": [ + "201,230" + ], + "{:d}% Chance to cast level {:d} Carrion Vine when struck": [ + "201,231" + ], + "{:d}% Chance to cast level {:d} Feral Rage when struck": [ + "201,232" + ], + "{:d}% Chance to cast level {:d} Maul when struck": [ + "201,233" + ], + "{:d}% Chance to cast level {:d} Fissure when struck": [ + "201,234" + ], + "{:d}% Chance to cast level {:d} Cyclone Armor when struck": [ + "201,235" + ], + "{:d}% Chance to cast level {:d} Heart of Wolverine when struck": [ + "201,236" + ], + "{:d}% Chance to cast level {:d} Summon Dire Wolf when struck": [ + "201,237" + ], + "{:d}% Chance to cast level {:d} Rabies when struck": [ + "201,238" + ], + "{:d}% Chance to cast level {:d} Fire Claws when struck": [ + "201,239" + ], + "{:d}% Chance to cast level {:d} Twister when struck": [ + "201,240" + ], + "{:d}% Chance to cast level {:d} Solar Creeper when struck": [ + "201,241" + ], + "{:d}% Chance to cast level {:d} Hunger when struck": [ + "201,242" + ], + "{:d}% Chance to cast level {:d} Shock Wave when struck": [ + "201,243" + ], + "{:d}% Chance to cast level {:d} Volcano when struck": [ + "201,244" + ], + "{:d}% Chance to cast level {:d} Tornado when struck": [ + "201,245" + ], + "{:d}% Chance to cast level {:d} Spirit of Barbs when struck": [ + "201,246" + ], + "{:d}% Chance to cast level {:d} Summon Grizzly when struck": [ + "201,247" + ], + "{:d}% Chance to cast level {:d} Fury when struck": [ + "201,248" + ], + "{:d}% Chance to cast level {:d} Armageddon when struck": [ + "201,249" + ], + "{:d}% Chance to cast level {:d} Hurricane when struck": [ + "201,250" + ], + "{:d}% Chance to cast level {:d} Fire Blast when struck": [ + "201,251" + ], + "{:d}% Chance to cast level {:d} Claw Mastery when struck": [ + "201,252" + ], + "{:d}% Chance to cast level {:d} Psychic Hammer when struck": [ + "201,253" + ], + "{:d}% Chance to cast level {:d} Tiger Strike when struck": [ + "201,254" + ], + "{:d}% Chance to cast level {:d} Dragon Talon when struck": [ + "201,255" + ], + "{:d}% Chance to cast level {:d} Shock Web when struck": [ + "201,256" + ], + "{:d}% Chance to cast level {:d} Blade Sentinel when struck": [ + "201,257" + ], + "{:d}% Chance to cast level {:d} Burst of Speed when struck": [ + "201,258" + ], + "{:d}% Chance to cast level {:d} Fists of Fire when struck": [ + "201,259" + ], + "{:d}% Chance to cast level {:d} Dragon Claw when struck": [ + "201,260" + ], + "{:d}% Chance to cast level {:d} Charged Bolt Sentry when struck": [ + "201,261" + ], + "{:d}% Chance to cast level {:d} Wake of Fire when struck": [ + "201,262" + ], + "{:d}% Chance to cast level {:d} Weapon Block when struck": [ + "201,263" + ], + "{:d}% Chance to cast level {:d} Cloak of Shadows when struck": [ + "201,264" + ], + "{:d}% Chance to cast level {:d} Cobra Strike when struck": [ + "201,265" + ], + "{:d}% Chance to cast level {:d} Blade Fury when struck": [ + "201,266" + ], + "{:d}% Chance to cast level {:d} Fade when struck": [ + "201,267" + ], + "{:d}% Chance to cast level {:d} Shadow Warrior when struck": [ + "201,268" + ], + "{:d}% Chance to cast level {:d} Claws of Thunder when struck": [ + "201,269" + ], + "{:d}% Chance to cast level {:d} Dragon Tail when struck": [ + "201,270" + ], + "{:d}% Chance to cast level {:d} Lightning Sentry when struck": [ + "201,271" + ], + "{:d}% Chance to cast level {:d} Wake of Inferno when struck": [ + "201,272" + ], + "{:d}% Chance to cast level {:d} Mind Blast when struck": [ + "201,273" + ], + "{:d}% Chance to cast level {:d} Blades of Ice when struck": [ + "201,274" + ], + "{:d}% Chance to cast level {:d} Dragon Flight when struck": [ + "201,275" + ], + "{:d}% Chance to cast level {:d} Death Sentry when struck": [ + "201,276" + ], + "{:d}% Chance to cast level {:d} Blade Shield when struck": [ + "201,277" + ], + "{:d}% Chance to cast level {:d} Venom when struck": [ + "201,278" + ], + "{:d}% Chance to cast level {:d} Shadow Master when struck": [ + "201,279" + ], + "{:d}% Chance to cast level {:d} Phoenix Strike when struck": [ + "201,280" + ], + "Socketed ({:d})": [ + "194" + ], + "Adds {:d}-{:d} Fire Damage": [ + "48", + "49" + ], + "Adds {:d}-{:d} Lightning Damage": [ + "50", + "51" + ], + "Adds {:d}-{:d} Magic Damage": [ + "52", + "53" + ], + "Adds {:d}-{:d} Cold Damage": [ + "54", + "55" + ], + "Adds {:d}-{:d} Poison Damage Over {:d} Seconds": [ + "57", + "58", + "59" + ], + "Adds {:d}-{:d} Damage": [ + "21", + "22" + ], + "{:d} Defense (Based on Character Level)": [ + "214" + ], + "{:d}% Enhanced Defense (Based on Character Level)": [ + "215" + ], + "{:d} to Life (Based on Character Level)": [ + "216" + ], + "{:d} to Mana (Based on Character Level)": [ + "217" + ], + "{:d} to Maximum Damage (Based on Character Level)": [ + "218" + ], + "{:d}% Enhanced Maximum Damage (Based on Character Level)": [ + "219" + ], + "{:d} to Strength (Based on Character Level)": [ + "220" + ], + "{:d} to Dexterity (Based on Character Level)": [ + "221" + ], + "{:d} to Vitality (Based on Character Level)": [ + "223" + ], + "{:d} to Attack Rating (Based on Character Level)": [ + "224" + ], + "{:d}% Bonus to Attack Rating (Based on Character Level)": [ + "225" + ], + "Cold Resist {:d}% (Based on Character Level)": [ + "230" + ], + "Fire Resist {:d}% (Based on Character Level)": [ + "231" + ], + "Lightning Resist {:d}% (Based on Character Level)": [ + "232" + ], + "Poison Resist {:d}% (Based on Character Level)": [ + "233" + ], + "Absorbs Cold Damage (Based on Character Level)": [ + "234" + ], + "Absorbs Fire Damage (Based on Character Level)": [ + "235" + ], + "Attacker Takes Damage of {:d} (Based on Character Level)": [ + "238" + ], + "{:d}% Extra Gold from Monsters (Based on Character Level)": [ + "239" + ], + "{:d}% Better Chance of Getting Magic Items (Based on Character Level)": [ + "240" + ], + "Heal Stamina Plus {:d}% (Based on Character Level)": [ + "241" + ], + "{:d} Maximum Stamina (Based on Character Level)": [ + "242" + ], + "{:d}% Damage to Demons (Based on Character Level)": [ + "243" + ], + "{:d}% Damage to Undead (Based on Character Level)": [ + "244" + ], + "{:d} to Attack Rating against Demons (Based on Character Level)": [ + "245" + ], + "{:d} to Attack Rating against Undead (Based on Character Level)": [ + "246" + ], + "{:d}% Deadly Strike (Based on Character Level)": [ + "250" + ], + "Repairs 1 durability in {:d} seconds": [ + "252" + ], + "Replenishes quantity": [ + "253" + ], + "Increased Stack Size": [ + "254" + ], + "{:d} Defense (Increases near [Day/Dusk/Night/Dawn])": [ + "268" + ], + "{:d}% Enhanced Defense (Increases near [Day/Dusk/Night/Dawn])": [ + "269" + ], + "{:d} to Life (Increases near [Day/Dusk/Night/Dawn])": [ + "270" + ], + "{:d} to Mana (Increases near [Day/Dusk/Night/Dawn])": [ + "271" + ], + "{:d} to Maximum Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "272" + ], + "{:d}% Enhanced Maximum Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "273" + ], + "{:d} to Strength (Increases near [Day/Dusk/Night/Dawn])": [ + "274" + ], + "{:d} to Dexterity (Increases near [Day/Dusk/Night/Dawn])": [ + "275" + ], + "{:d} to Energy (Increases near [Day/Dusk/Night/Dawn])": [ + "276" + ], + "{:d} to Vitality (Increases near [Day/Dusk/Night/Dawn])": [ + "277" + ], + "{:d} to Attack Rating (Increases near [Day/Dusk/Night/Dawn])": [ + "278" + ], + "{:d}% Bonus to Attack Rating (Increases near [Day/Dusk/Night/Dawn])": [ + "279" + ], + "{:d} to Maximum Cold Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "280" + ], + "{:d} to Maximum Fire Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "281" + ], + "{:d} to Maximum Lightning Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "282" + ], + "{:d} to Maximum Poison Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "283" + ], + "Cold Resist {:d}% (Increases near [Day/Dusk/Night/Dawn])": [ + "284" + ], + "Fire Resist {:d}% (Increases near [Day/Dusk/Night/Dawn])": [ + "285" + ], + "Lightning Resist {:d}% (Increases near [Day/Dusk/Night/Dawn])": [ + "286" + ], + "Poison Resist {:d}% (Increases near [Day/Dusk/Night/Dawn])": [ + "287" + ], + "Absorbs Cold Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "288" + ], + "Absorbs Fire Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "289" + ], + "Absorbs Lightning Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "290" + ], + "Absorbs Poison Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "291" + ], + "{:d}% Extra Gold from Monsters (Increases near [Day/Dusk/Night/Dawn])": [ + "292" + ], + "{:d}% Better Chance of Getting Magic Items (Increases near [Day/Dusk/Night/Dawn])": [ + "293" + ], + "Heal Stamina Plus {:d}% (Increases near [Day/Dusk/Night/Dawn])": [ + "294" + ], + "{:d} Maximum Stamina (Increases near [Day/Dusk/Night/Dawn])": [ + "295" + ], + "{:d}% Damage to Demons (Increases near [Day/Dusk/Night/Dawn])": [ + "296" + ], + "{:d}% Damage to Undead (Increases near [Day/Dusk/Night/Dawn])": [ + "297" + ], + "{:d} to Attack Rating against Demons (Increases near [Day/Dusk/Night/Dawn])": [ + "298" + ], + "{:d} to Attack Rating against Undead (Increases near [Day/Dusk/Night/Dawn])": [ + "299" + ], + "{:d}% Chance of Crushing Blow (Increases near [Day/Dusk/Night/Dawn])": [ + "300" + ], + "{:d}% Chance of Open Wounds (Increases near [Day/Dusk/Night/Dawn])": [ + "301" + ], + "{:d} Kick Damage (Increases near [Day/Dusk/Night/Dawn])": [ + "302" + ], + "{:d}% Deadly Strike (Increases near [Day/Dusk/Night/Dawn])": [ + "303" + ], + "{:d}% to Enemy Fire Resistance": [ + "333" + ], + "{:d}% to Enemy Lightning Resistance": [ + "334" + ], + "{:d}% to Enemy Cold Resistance": [ + "335" + ], + "{:d}% to Enemy Poison Resistance": [ + "336" + ], + "Level {:d} Magic Arrow ({:d}/{:d} Charges)": [ + "204,6" + ], + "Level {:d} Fire Arrow ({:d}/{:d} Charges)": [ + "204,7" + ], + "Level {:d} Inner Sight ({:d}/{:d} Charges)": [ + "204,8" + ], + "Level {:d} Critical Strike ({:d}/{:d} Charges)": [ + "204,9" + ], + "Level {:d} Jab ({:d}/{:d} Charges)": [ + "204,10" + ], + "Level {:d} Cold Arrow ({:d}/{:d} Charges)": [ + "204,11" + ], + "Level {:d} Multiple Shot ({:d}/{:d} Charges)": [ + "204,12" + ], + "Level {:d} Dodge ({:d}/{:d} Charges)": [ + "204,13" + ], + "Level {:d} Power Strike ({:d}/{:d} Charges)": [ + "204,14" + ], + "Level {:d} Poison Javelin ({:d}/{:d} Charges)": [ + "204,15" + ], + "Level {:d} Exploding Arrow ({:d}/{:d} Charges)": [ + "204,16" + ], + "Level {:d} Slow Missiles ({:d}/{:d} Charges)": [ + "204,17" + ], + "Level {:d} Avoid ({:d}/{:d} Charges)": [ + "204,18" + ], + "Level {:d} Impale ({:d}/{:d} Charges)": [ + "204,19" + ], + "Level {:d} Lightning Bolt ({:d}/{:d} Charges)": [ + "204,20" + ], + "Level {:d} Ice Arrow ({:d}/{:d} Charges)": [ + "204,21" + ], + "Level {:d} Guided Arrow ({:d}/{:d} Charges)": [ + "204,22" + ], + "Level {:d} Penetrate ({:d}/{:d} Charges)": [ + "204,23" + ], + "Level {:d} Charged Strike ({:d}/{:d} Charges)": [ + "204,24" + ], + "Level {:d} Plague Javelin ({:d}/{:d} Charges)": [ + "204,25" + ], + "Level {:d} Strafe ({:d}/{:d} Charges)": [ + "204,26" + ], + "Level {:d} Immolation Arrow ({:d}/{:d} Charges)": [ + "204,27" + ], + "Level {:d} Decoy ({:d}/{:d} Charges)": [ + "204,28" + ], + "Level {:d} Evade ({:d}/{:d} Charges)": [ + "204,29" + ], + "Level {:d} Fend ({:d}/{:d} Charges)": [ + "204,30" + ], + "Level {:d} Freezing Arrow ({:d}/{:d} Charges)": [ + "204,31" + ], + "Level {:d} Valkyrie ({:d}/{:d} Charges)": [ + "204,32" + ], + "Level {:d} Pierce ({:d}/{:d} Charges)": [ + "204,33" + ], + "Level {:d} Lightning Strike ({:d}/{:d} Charges)": [ + "204,34" + ], + "Level {:d} Lightning Fury ({:d}/{:d} Charges)": [ + "204,35" + ], + "Level {:d} Fire Bolt ({:d}/{:d} Charges)": [ + "204,36" + ], + "Level {:d} Warmth ({:d}/{:d} Charges)": [ + "204,37" + ], + "Level {:d} Charged Bolt ({:d}/{:d} Charges)": [ + "204,38" + ], + "Level {:d} Ice Bolt ({:d}/{:d} Charges)": [ + "204,39" + ], + "Level {:d} Frozen Armor ({:d}/{:d} Charges)": [ + "204,40" + ], + "Level {:d} Inferno ({:d}/{:d} Charges)": [ + "204,41" + ], + "Level {:d} Static Field ({:d}/{:d} Charges)": [ + "204,42" + ], + "Level {:d} Telekinesis ({:d}/{:d} Charges)": [ + "204,43" + ], + "Level {:d} Frost Nova ({:d}/{:d} Charges)": [ + "204,44" + ], + "Level {:d} Ice Blast ({:d}/{:d} Charges)": [ + "204,45" + ], + "Level {:d} Blaze ({:d}/{:d} Charges)": [ + "204,46" + ], + "Level {:d} Fire Ball ({:d}/{:d} Charges)": [ + "204,47" + ], + "Level {:d} Nova ({:d}/{:d} Charges)": [ + "204,48" + ], + "Level {:d} Lightning ({:d}/{:d} Charges)": [ + "204,49" + ], + "Level {:d} Shiver Armor ({:d}/{:d} Charges)": [ + "204,50" + ], + "Level {:d} Fire Wall ({:d}/{:d} Charges)": [ + "204,51" + ], + "Level {:d} Enchant ({:d}/{:d} Charges)": [ + "204,52" + ], + "Level {:d} Chain Lightning ({:d}/{:d} Charges)": [ + "204,53" + ], + "Level {:d} Teleport ({:d}/{:d} Charges)": [ + "204,54" + ], + "Level {:d} Glacial Spike ({:d}/{:d} Charges)": [ + "204,55" + ], + "Level {:d} Meteor ({:d}/{:d} Charges)": [ + "204,56" + ], + "Level {:d} Thunder Storm ({:d}/{:d} Charges)": [ + "204,57" + ], + "Level {:d} Energy Shield ({:d}/{:d} Charges)": [ + "204,58" + ], + "Level {:d} Blizzard ({:d}/{:d} Charges)": [ + "204,59" + ], + "Level {:d} Chilling Armor ({:d}/{:d} Charges)": [ + "204,60" + ], + "Level {:d} Fire Mastery ({:d}/{:d} Charges)": [ + "204,61" + ], + "Level {:d} Hydra ({:d}/{:d} Charges)": [ + "204,62" + ], + "Level {:d} Lightning Mastery ({:d}/{:d} Charges)": [ + "204,63" + ], + "Level {:d} Frozen Orb ({:d}/{:d} Charges)": [ + "204,64" + ], + "Level {:d} Cold Mastery ({:d}/{:d} Charges)": [ + "204,65" + ], + "Level {:d} Amplify Damage ({:d}/{:d} Charges)": [ + "204,66" + ], + "Level {:d} Teeth ({:d}/{:d} Charges)": [ + "204,67" + ], + "Level {:d} Bone Armor ({:d}/{:d} Charges)": [ + "204,68" + ], + "Level {:d} Skeleton Mastery ({:d}/{:d} Charges)": [ + "204,69" + ], + "Level {:d} Raise Skeleton ({:d}/{:d} Charges)": [ + "204,70" + ], + "Level {:d} Dim Vision ({:d}/{:d} Charges)": [ + "204,71" + ], + "Level {:d} Weaken ({:d}/{:d} Charges)": [ + "204,72" + ], + "Level {:d} Poison Dagger ({:d}/{:d} Charges)": [ + "204,73" + ], + "Level {:d} Corpse Explosion ({:d}/{:d} Charges)": [ + "204,74" + ], + "Level {:d} Clay Golem ({:d}/{:d} Charges)": [ + "204,75" + ], + "Level {:d} Iron Maiden ({:d}/{:d} Charges)": [ + "204,76" + ], + "Level {:d} Terror ({:d}/{:d} Charges)": [ + "204,77" + ], + "Level {:d} Bone Wall ({:d}/{:d} Charges)": [ + "204,78" + ], + "Level {:d} Golem Mastery ({:d}/{:d} Charges)": [ + "204,79" + ], + "Level {:d} Raise Skeletal Mage ({:d}/{:d} Charges)": [ + "204,80" + ], + "Level {:d} Confuse ({:d}/{:d} Charges)": [ + "204,81" + ], + "Level {:d} Life Tap ({:d}/{:d} Charges)": [ + "204,82" + ], + "Level {:d} Poison Explosion ({:d}/{:d} Charges)": [ + "204,83" + ], + "Level {:d} Bone Spear ({:d}/{:d} Charges)": [ + "204,84" + ], + "Level {:d} Blood Golem ({:d}/{:d} Charges)": [ + "204,85" + ], + "Level {:d} Attract ({:d}/{:d} Charges)": [ + "204,86" + ], + "Level {:d} Decrepify ({:d}/{:d} Charges)": [ + "204,87" + ], + "Level {:d} Bone Prison ({:d}/{:d} Charges)": [ + "204,88" + ], + "Level {:d} Summon Resist ({:d}/{:d} Charges)": [ + "204,89" + ], + "Level {:d} Iron Golem ({:d}/{:d} Charges)": [ + "204,90" + ], + "Level {:d} Lower Resist ({:d}/{:d} Charges)": [ + "204,91" + ], + "Level {:d} Poison Nova ({:d}/{:d} Charges)": [ + "204,92" + ], + "Level {:d} Bone Spirit ({:d}/{:d} Charges)": [ + "204,93" + ], + "Level {:d} Fire Golem ({:d}/{:d} Charges)": [ + "204,94" + ], + "Level {:d} Revive ({:d}/{:d} Charges)": [ + "204,95" + ], + "Level {:d} Sacrifice ({:d}/{:d} Charges)": [ + "204,96" + ], + "Level {:d} Smite ({:d}/{:d} Charges)": [ + "204,97" + ], + "Level {:d} Might ({:d}/{:d} Charges)": [ + "204,98" + ], + "Level {:d} Prayer ({:d}/{:d} Charges)": [ + "204,99" + ], + "Level {:d} Resist Fire ({:d}/{:d} Charges)": [ + "204,100" + ], + "Level {:d} Holy Bolt ({:d}/{:d} Charges)": [ + "204,101" + ], + "Level {:d} Holy Fire ({:d}/{:d} Charges)": [ + "204,102" + ], + "Level {:d} Thorns ({:d}/{:d} Charges)": [ + "204,103" + ], + "Level {:d} Defiance ({:d}/{:d} Charges)": [ + "204,104" + ], + "Level {:d} Resist Cold ({:d}/{:d} Charges)": [ + "204,105" + ], + "Level {:d} Zeal ({:d}/{:d} Charges)": [ + "204,106" + ], + "Level {:d} Charge ({:d}/{:d} Charges)": [ + "204,107" + ], + "Level {:d} Blessed Aim ({:d}/{:d} Charges)": [ + "204,108" + ], + "Level {:d} Cleansing ({:d}/{:d} Charges)": [ + "204,109" + ], + "Level {:d} Resist Lightning ({:d}/{:d} Charges)": [ + "204,110" + ], + "Level {:d} Vengeance ({:d}/{:d} Charges)": [ + "204,111" + ], + "Level {:d} Blessed Hammer ({:d}/{:d} Charges)": [ + "204,112" + ], + "Level {:d} Concentration ({:d}/{:d} Charges)": [ + "204,113" + ], + "Level {:d} Holy Freeze ({:d}/{:d} Charges)": [ + "204,114" + ], + "Level {:d} Vigor ({:d}/{:d} Charges)": [ + "204,115" + ], + "Level {:d} Conversion ({:d}/{:d} Charges)": [ + "204,116" + ], + "Level {:d} Holy Shield ({:d}/{:d} Charges)": [ + "204,117" + ], + "Level {:d} Holy Shock ({:d}/{:d} Charges)": [ + "204,118" + ], + "Level {:d} Sanctuary ({:d}/{:d} Charges)": [ + "204,119" + ], + "Level {:d} Meditation ({:d}/{:d} Charges)": [ + "204,120" + ], + "Level {:d} Fist of the Heavens ({:d}/{:d} Charges)": [ + "204,121" + ], + "Level {:d} Fanaticism ({:d}/{:d} Charges)": [ + "204,122" + ], + "Level {:d} Conviction ({:d}/{:d} Charges)": [ + "204,123" + ], + "Level {:d} Redemption ({:d}/{:d} Charges)": [ + "204,124" + ], + "Level {:d} Salvation ({:d}/{:d} Charges)": [ + "204,125" + ], + "Level {:d} Bash ({:d}/{:d} Charges)": [ + "204,126" + ], + "Level {:d} Blade Mastery ({:d}/{:d} Charges)": [ + "204,127" + ], + "Level {:d} Axe Mastery ({:d}/{:d} Charges)": [ + "204,128" + ], + "Level {:d} Mace Mastery ({:d}/{:d} Charges)": [ + "204,129" + ], + "Level {:d} Howl ({:d}/{:d} Charges)": [ + "204,130" + ], + "Level {:d} Find Potion ({:d}/{:d} Charges)": [ + "204,131" + ], + "Level {:d} Leap ({:d}/{:d} Charges)": [ + "204,132" + ], + "Level {:d} Double Swing ({:d}/{:d} Charges)": [ + "204,133" + ], + "Level {:d} Polearm Mastery ({:d}/{:d} Charges)": [ + "204,134" + ], + "Level {:d} Throwing Mastery ({:d}/{:d} Charges)": [ + "204,135" + ], + "Level {:d} Spear Mastery ({:d}/{:d} Charges)": [ + "204,136" + ], + "Level {:d} Taunt ({:d}/{:d} Charges)": [ + "204,137" + ], + "Level {:d} Shout ({:d}/{:d} Charges)": [ + "204,138" + ], + "Level {:d} Stun ({:d}/{:d} Charges)": [ + "204,139" + ], + "Level {:d} Double Throw ({:d}/{:d} Charges)": [ + "204,140" + ], + "Level {:d} Increased Stamina ({:d}/{:d} Charges)": [ + "204,141" + ], + "Level {:d} Find Item ({:d}/{:d} Charges)": [ + "204,142" + ], + "Level {:d} Leap Attack ({:d}/{:d} Charges)": [ + "204,143" + ], + "Level {:d} Concentrate ({:d}/{:d} Charges)": [ + "204,144" + ], + "Level {:d} Iron Skin ({:d}/{:d} Charges)": [ + "204,145" + ], + "Level {:d} Battle Cry ({:d}/{:d} Charges)": [ + "204,146" + ], + "Level {:d} Frenzy ({:d}/{:d} Charges)": [ + "204,147" + ], + "Level {:d} Increased Speed ({:d}/{:d} Charges)": [ + "204,148" + ], + "Level {:d} Battle Orders ({:d}/{:d} Charges)": [ + "204,149" + ], + "Level {:d} Grim Ward ({:d}/{:d} Charges)": [ + "204,150" + ], + "Level {:d} Whirlwind ({:d}/{:d} Charges)": [ + "204,151" + ], + "Level {:d} Berserk ({:d}/{:d} Charges)": [ + "204,152" + ], + "Level {:d} Natural Resistance ({:d}/{:d} Charges)": [ + "204,153" + ], + "Level {:d} War Cry ({:d}/{:d} Charges)": [ + "204,154" + ], + "Level {:d} Battle Command ({:d}/{:d} Charges)": [ + "204,155" + ], + "Level {:d} Raven ({:d}/{:d} Charges)": [ + "204,221" + ], + "Level {:d} Poison Creeper ({:d}/{:d} Charges)": [ + "204,222" + ], + "Level {:d} Werewolf ({:d}/{:d} Charges)": [ + "204,223" + ], + "Level {:d} Lycanthropy ({:d}/{:d} Charges)": [ + "204,224" + ], + "Level {:d} Firestorm ({:d}/{:d} Charges)": [ + "204,225" + ], + "Level {:d} Oak Sage ({:d}/{:d} Charges)": [ + "204,226" + ], + "Level {:d} Summon Spirit Wolf ({:d}/{:d} Charges)": [ + "204,227" + ], + "Level {:d} Werebear ({:d}/{:d} Charges)": [ + "204,228" + ], + "Level {:d} Molten Boulder ({:d}/{:d} Charges)": [ + "204,229" + ], + "Level {:d} Arctic Blast ({:d}/{:d} Charges)": [ + "204,230" + ], + "Level {:d} Carrion Vine ({:d}/{:d} Charges)": [ + "204,231" + ], + "Level {:d} Feral Rage ({:d}/{:d} Charges)": [ + "204,232" + ], + "Level {:d} Maul ({:d}/{:d} Charges)": [ + "204,233" + ], + "Level {:d} Fissure ({:d}/{:d} Charges)": [ + "204,234" + ], + "Level {:d} Cyclone Armor ({:d}/{:d} Charges)": [ + "204,235" + ], + "Level {:d} Heart of Wolverine ({:d}/{:d} Charges)": [ + "204,236" + ], + "Level {:d} Summon Dire Wolf ({:d}/{:d} Charges)": [ + "204,237" + ], + "Level {:d} Rabies ({:d}/{:d} Charges)": [ + "204,238" + ], + "Level {:d} Fire Claws ({:d}/{:d} Charges)": [ + "204,239" + ], + "Level {:d} Twister ({:d}/{:d} Charges)": [ + "204,240" + ], + "Level {:d} Solar Creeper ({:d}/{:d} Charges)": [ + "204,241" + ], + "Level {:d} Hunger ({:d}/{:d} Charges)": [ + "204,242" + ], + "Level {:d} Shock Wave ({:d}/{:d} Charges)": [ + "204,243" + ], + "Level {:d} Volcano ({:d}/{:d} Charges)": [ + "204,244" + ], + "Level {:d} Tornado ({:d}/{:d} Charges)": [ + "204,245" + ], + "Level {:d} Spirit of Barbs ({:d}/{:d} Charges)": [ + "204,246" + ], + "Level {:d} Summon Grizzly ({:d}/{:d} Charges)": [ + "204,247" + ], + "Level {:d} Fury ({:d}/{:d} Charges)": [ + "204,248" + ], + "Level {:d} Armageddon ({:d}/{:d} Charges)": [ + "204,249" + ], + "Level {:d} Hurricane ({:d}/{:d} Charges)": [ + "204,250" + ], + "Level {:d} Fire Blast ({:d}/{:d} Charges)": [ + "204,251" + ], + "Level {:d} Claw Mastery ({:d}/{:d} Charges)": [ + "204,252" + ], + "Level {:d} Psychic Hammer ({:d}/{:d} Charges)": [ + "204,253" + ], + "Level {:d} Tiger Strike ({:d}/{:d} Charges)": [ + "204,254" + ], + "Level {:d} Dragon Talon ({:d}/{:d} Charges)": [ + "204,255" + ], + "Level {:d} Shock Web ({:d}/{:d} Charges)": [ + "204,256" + ], + "Level {:d} Blade Sentinel ({:d}/{:d} Charges)": [ + "204,257" + ], + "Level {:d} Burst of Speed ({:d}/{:d} Charges)": [ + "204,258" + ], + "Level {:d} Fists of Fire ({:d}/{:d} Charges)": [ + "204,259" + ], + "Level {:d} Dragon Claw ({:d}/{:d} Charges)": [ + "204,260" + ], + "Level {:d} Charged Bolt Sentry ({:d}/{:d} Charges)": [ + "204,261" + ], + "Level {:d} Wake of Fire ({:d}/{:d} Charges)": [ + "204,262" + ], + "Level {:d} Weapon Block ({:d}/{:d} Charges)": [ + "204,263" + ], + "Level {:d} Cloak of Shadows ({:d}/{:d} Charges)": [ + "204,264" + ], + "Level {:d} Cobra Strike ({:d}/{:d} Charges)": [ + "204,265" + ], + "Level {:d} Blade Fury ({:d}/{:d} Charges)": [ + "204,266" + ], + "Level {:d} Fade ({:d}/{:d} Charges)": [ + "204,267" + ], + "Level {:d} Shadow Warrior ({:d}/{:d} Charges)": [ + "204,268" + ], + "Level {:d} Claws of Thunder ({:d}/{:d} Charges)": [ + "204,269" + ], + "Level {:d} Dragon Tail ({:d}/{:d} Charges)": [ + "204,270" + ], + "Level {:d} Lightning Sentry ({:d}/{:d} Charges)": [ + "204,271" + ], + "Level {:d} Wake of Inferno ({:d}/{:d} Charges)": [ + "204,272" + ], + "Level {:d} Mind Blast ({:d}/{:d} Charges)": [ + "204,273" + ], + "Level {:d} Blades of Ice ({:d}/{:d} Charges)": [ + "204,274" + ], + "Level {:d} Dragon Flight ({:d}/{:d} Charges)": [ + "204,275" + ], + "Level {:d} Death Sentry ({:d}/{:d} Charges)": [ + "204,276" + ], + "Level {:d} Blade Shield ({:d}/{:d} Charges)": [ + "204,277" + ], + "Level {:d} Venom ({:d}/{:d} Charges)": [ + "204,278" + ], + "Level {:d} Shadow Master ({:d}/{:d} Charges)": [ + "204,279" + ], + "Level {:d} Phoenix Strike ({:d}/{:d} Charges)": [ + "204,280" + ], + "{:d}% to Fire Skill Damage": [ + "329" + ], + "{:d}% to Lightning Skill Damage": [ + "330" + ], + "{:d}% to Cold Skill Damage": [ + "331" + ], + "{:d}% to Poison Skill Damage": [ + "332" + ], + "Adds {:d}-{:d} Fire/Lightning/Cold Damage": [ + "48", + "49" + ], + "{:d} to all Attributes": [ + [ + "420", + "0", + "2", + "3", + "1" + ] + ], + "{:d}% to Experience Gained": [ + "85" + ], + "{:d} Life after each Kill": [ + "86" + ], + "Reduces all Vendor Prices {:d}%": [ + "87" + ], + "Slain Monsters Rest in Peace": [ + "108" + ], + "{:d}% Chance to cast level {:d} Magic Arrow when you Kill an Enemy": [ + "196,6" + ], + "{:d}% Chance to cast level {:d} Fire Arrow when you Kill an Enemy": [ + "196,7" + ], + "{:d}% Chance to cast level {:d} Inner Sight when you Kill an Enemy": [ + "196,8" + ], + "{:d}% Chance to cast level {:d} Critical Strike when you Kill an Enemy": [ + "196,9" + ], + "{:d}% Chance to cast level {:d} Jab when you Kill an Enemy": [ + "196,10" + ], + "{:d}% Chance to cast level {:d} Cold Arrow when you Kill an Enemy": [ + "196,11" + ], + "{:d}% Chance to cast level {:d} Multiple Shot when you Kill an Enemy": [ + "196,12" + ], + "{:d}% Chance to cast level {:d} Dodge when you Kill an Enemy": [ + "196,13" + ], + "{:d}% Chance to cast level {:d} Power Strike when you Kill an Enemy": [ + "196,14" + ], + "{:d}% Chance to cast level {:d} Poison Javelin when you Kill an Enemy": [ + "196,15" + ], + "{:d}% Chance to cast level {:d} Exploding Arrow when you Kill an Enemy": [ + "196,16" + ], + "{:d}% Chance to cast level {:d} Slow Missiles when you Kill an Enemy": [ + "196,17" + ], + "{:d}% Chance to cast level {:d} Avoid when you Kill an Enemy": [ + "196,18" + ], + "{:d}% Chance to cast level {:d} Impale when you Kill an Enemy": [ + "196,19" + ], + "{:d}% Chance to cast level {:d} Lightning Bolt when you Kill an Enemy": [ + "196,20" + ], + "{:d}% Chance to cast level {:d} Ice Arrow when you Kill an Enemy": [ + "196,21" + ], + "{:d}% Chance to cast level {:d} Guided Arrow when you Kill an Enemy": [ + "196,22" + ], + "{:d}% Chance to cast level {:d} Penetrate when you Kill an Enemy": [ + "196,23" + ], + "{:d}% Chance to cast level {:d} Charged Strike when you Kill an Enemy": [ + "196,24" + ], + "{:d}% Chance to cast level {:d} Plague Javelin when you Kill an Enemy": [ + "196,25" + ], + "{:d}% Chance to cast level {:d} Strafe when you Kill an Enemy": [ + "196,26" + ], + "{:d}% Chance to cast level {:d} Immolation Arrow when you Kill an Enemy": [ + "196,27" + ], + "{:d}% Chance to cast level {:d} Decoy when you Kill an Enemy": [ + "196,28" + ], + "{:d}% Chance to cast level {:d} Evade when you Kill an Enemy": [ + "196,29" + ], + "{:d}% Chance to cast level {:d} Fend when you Kill an Enemy": [ + "196,30" + ], + "{:d}% Chance to cast level {:d} Freezing Arrow when you Kill an Enemy": [ + "196,31" + ], + "{:d}% Chance to cast level {:d} Valkyrie when you Kill an Enemy": [ + "196,32" + ], + "{:d}% Chance to cast level {:d} Pierce when you Kill an Enemy": [ + "196,33" + ], + "{:d}% Chance to cast level {:d} Lightning Strike when you Kill an Enemy": [ + "196,34" + ], + "{:d}% Chance to cast level {:d} Lightning Fury when you Kill an Enemy": [ + "196,35" + ], + "{:d}% Chance to cast level {:d} Fire Bolt when you Kill an Enemy": [ + "196,36" + ], + "{:d}% Chance to cast level {:d} Warmth when you Kill an Enemy": [ + "196,37" + ], + "{:d}% Chance to cast level {:d} Charged Bolt when you Kill an Enemy": [ + "196,38" + ], + "{:d}% Chance to cast level {:d} Ice Bolt when you Kill an Enemy": [ + "196,39" + ], + "{:d}% Chance to cast level {:d} Frozen Armor when you Kill an Enemy": [ + "196,40" + ], + "{:d}% Chance to cast level {:d} Inferno when you Kill an Enemy": [ + "196,41" + ], + "{:d}% Chance to cast level {:d} Static Field when you Kill an Enemy": [ + "196,42" + ], + "{:d}% Chance to cast level {:d} Telekinesis when you Kill an Enemy": [ + "196,43" + ], + "{:d}% Chance to cast level {:d} Frost Nova when you Kill an Enemy": [ + "196,44" + ], + "{:d}% Chance to cast level {:d} Ice Blast when you Kill an Enemy": [ + "196,45" + ], + "{:d}% Chance to cast level {:d} Blaze when you Kill an Enemy": [ + "196,46" + ], + "{:d}% Chance to cast level {:d} Fire Ball when you Kill an Enemy": [ + "196,47" + ], + "{:d}% Chance to cast level {:d} Nova when you Kill an Enemy": [ + "196,48" + ], + "{:d}% Chance to cast level {:d} Lightning when you Kill an Enemy": [ + "196,49" + ], + "{:d}% Chance to cast level {:d} Shiver Armor when you Kill an Enemy": [ + "196,50" + ], + "{:d}% Chance to cast level {:d} Fire Wall when you Kill an Enemy": [ + "196,51" + ], + "{:d}% Chance to cast level {:d} Enchant when you Kill an Enemy": [ + "196,52" + ], + "{:d}% Chance to cast level {:d} Chain Lightning when you Kill an Enemy": [ + "196,53" + ], + "{:d}% Chance to cast level {:d} Teleport when you Kill an Enemy": [ + "196,54" + ], + "{:d}% Chance to cast level {:d} Glacial Spike when you Kill an Enemy": [ + "196,55" + ], + "{:d}% Chance to cast level {:d} Meteor when you Kill an Enemy": [ + "196,56" + ], + "{:d}% Chance to cast level {:d} Thunder Storm when you Kill an Enemy": [ + "196,57" + ], + "{:d}% Chance to cast level {:d} Energy Shield when you Kill an Enemy": [ + "196,58" + ], + "{:d}% Chance to cast level {:d} Blizzard when you Kill an Enemy": [ + "196,59" + ], + "{:d}% Chance to cast level {:d} Chilling Armor when you Kill an Enemy": [ + "196,60" + ], + "{:d}% Chance to cast level {:d} Fire Mastery when you Kill an Enemy": [ + "196,61" + ], + "{:d}% Chance to cast level {:d} Hydra when you Kill an Enemy": [ + "196,62" + ], + "{:d}% Chance to cast level {:d} Lightning Mastery when you Kill an Enemy": [ + "196,63" + ], + "{:d}% Chance to cast level {:d} Frozen Orb when you Kill an Enemy": [ + "196,64" + ], + "{:d}% Chance to cast level {:d} Cold Mastery when you Kill an Enemy": [ + "196,65" + ], + "{:d}% Chance to cast level {:d} Amplify Damage when you Kill an Enemy": [ + "196,66" + ], + "{:d}% Chance to cast level {:d} Teeth when you Kill an Enemy": [ + "196,67" + ], + "{:d}% Chance to cast level {:d} Bone Armor when you Kill an Enemy": [ + "196,68" + ], + "{:d}% Chance to cast level {:d} Skeleton Mastery when you Kill an Enemy": [ + "196,69" + ], + "{:d}% Chance to cast level {:d} Raise Skeleton when you Kill an Enemy": [ + "196,70" + ], + "{:d}% Chance to cast level {:d} Dim Vision when you Kill an Enemy": [ + "196,71" + ], + "{:d}% Chance to cast level {:d} Weaken when you Kill an Enemy": [ + "196,72" + ], + "{:d}% Chance to cast level {:d} Poison Dagger when you Kill an Enemy": [ + "196,73" + ], + "{:d}% Chance to cast level {:d} Corpse Explosion when you Kill an Enemy": [ + "196,74" + ], + "{:d}% Chance to cast level {:d} Clay Golem when you Kill an Enemy": [ + "196,75" + ], + "{:d}% Chance to cast level {:d} Iron Maiden when you Kill an Enemy": [ + "196,76" + ], + "{:d}% Chance to cast level {:d} Terror when you Kill an Enemy": [ + "196,77" + ], + "{:d}% Chance to cast level {:d} Bone Wall when you Kill an Enemy": [ + "196,78" + ], + "{:d}% Chance to cast level {:d} Golem Mastery when you Kill an Enemy": [ + "196,79" + ], + "{:d}% Chance to cast level {:d} Raise Skeletal Mage when you Kill an Enemy": [ + "196,80" + ], + "{:d}% Chance to cast level {:d} Confuse when you Kill an Enemy": [ + "196,81" + ], + "{:d}% Chance to cast level {:d} Life Tap when you Kill an Enemy": [ + "196,82" + ], + "{:d}% Chance to cast level {:d} Poison Explosion when you Kill an Enemy": [ + "196,83" + ], + "{:d}% Chance to cast level {:d} Bone Spear when you Kill an Enemy": [ + "196,84" + ], + "{:d}% Chance to cast level {:d} Blood Golem when you Kill an Enemy": [ + "196,85" + ], + "{:d}% Chance to cast level {:d} Attract when you Kill an Enemy": [ + "196,86" + ], + "{:d}% Chance to cast level {:d} Decrepify when you Kill an Enemy": [ + "196,87" + ], + "{:d}% Chance to cast level {:d} Bone Prison when you Kill an Enemy": [ + "196,88" + ], + "{:d}% Chance to cast level {:d} Summon Resist when you Kill an Enemy": [ + "196,89" + ], + "{:d}% Chance to cast level {:d} Iron Golem when you Kill an Enemy": [ + "196,90" + ], + "{:d}% Chance to cast level {:d} Lower Resist when you Kill an Enemy": [ + "196,91" + ], + "{:d}% Chance to cast level {:d} Poison Nova when you Kill an Enemy": [ + "196,92" + ], + "{:d}% Chance to cast level {:d} Bone Spirit when you Kill an Enemy": [ + "196,93" + ], + "{:d}% Chance to cast level {:d} Fire Golem when you Kill an Enemy": [ + "196,94" + ], + "{:d}% Chance to cast level {:d} Revive when you Kill an Enemy": [ + "196,95" + ], + "{:d}% Chance to cast level {:d} Sacrifice when you Kill an Enemy": [ + "196,96" + ], + "{:d}% Chance to cast level {:d} Smite when you Kill an Enemy": [ + "196,97" + ], + "{:d}% Chance to cast level {:d} Might when you Kill an Enemy": [ + "196,98" + ], + "{:d}% Chance to cast level {:d} Prayer when you Kill an Enemy": [ + "196,99" + ], + "{:d}% Chance to cast level {:d} Resist Fire when you Kill an Enemy": [ + "196,100" + ], + "{:d}% Chance to cast level {:d} Holy Bolt when you Kill an Enemy": [ + "196,101" + ], + "{:d}% Chance to cast level {:d} Holy Fire when you Kill an Enemy": [ + "196,102" + ], + "{:d}% Chance to cast level {:d} Thorns when you Kill an Enemy": [ + "196,103" + ], + "{:d}% Chance to cast level {:d} Defiance when you Kill an Enemy": [ + "196,104" + ], + "{:d}% Chance to cast level {:d} Resist Cold when you Kill an Enemy": [ + "196,105" + ], + "{:d}% Chance to cast level {:d} Zeal when you Kill an Enemy": [ + "196,106" + ], + "{:d}% Chance to cast level {:d} Charge when you Kill an Enemy": [ + "196,107" + ], + "{:d}% Chance to cast level {:d} Blessed Aim when you Kill an Enemy": [ + "196,108" + ], + "{:d}% Chance to cast level {:d} Cleansing when you Kill an Enemy": [ + "196,109" + ], + "{:d}% Chance to cast level {:d} Resist Lightning when you Kill an Enemy": [ + "196,110" + ], + "{:d}% Chance to cast level {:d} Vengeance when you Kill an Enemy": [ + "196,111" + ], + "{:d}% Chance to cast level {:d} Blessed Hammer when you Kill an Enemy": [ + "196,112" + ], + "{:d}% Chance to cast level {:d} Concentration when you Kill an Enemy": [ + "196,113" + ], + "{:d}% Chance to cast level {:d} Holy Freeze when you Kill an Enemy": [ + "196,114" + ], + "{:d}% Chance to cast level {:d} Vigor when you Kill an Enemy": [ + "196,115" + ], + "{:d}% Chance to cast level {:d} Conversion when you Kill an Enemy": [ + "196,116" + ], + "{:d}% Chance to cast level {:d} Holy Shield when you Kill an Enemy": [ + "196,117" + ], + "{:d}% Chance to cast level {:d} Holy Shock when you Kill an Enemy": [ + "196,118" + ], + "{:d}% Chance to cast level {:d} Sanctuary when you Kill an Enemy": [ + "196,119" + ], + "{:d}% Chance to cast level {:d} Meditation when you Kill an Enemy": [ + "196,120" + ], + "{:d}% Chance to cast level {:d} Fist of the Heavens when you Kill an Enemy": [ + "196,121" + ], + "{:d}% Chance to cast level {:d} Fanaticism when you Kill an Enemy": [ + "196,122" + ], + "{:d}% Chance to cast level {:d} Conviction when you Kill an Enemy": [ + "196,123" + ], + "{:d}% Chance to cast level {:d} Redemption when you Kill an Enemy": [ + "196,124" + ], + "{:d}% Chance to cast level {:d} Salvation when you Kill an Enemy": [ + "196,125" + ], + "{:d}% Chance to cast level {:d} Bash when you Kill an Enemy": [ + "196,126" + ], + "{:d}% Chance to cast level {:d} Blade Mastery when you Kill an Enemy": [ + "196,127" + ], + "{:d}% Chance to cast level {:d} Axe Mastery when you Kill an Enemy": [ + "196,128" + ], + "{:d}% Chance to cast level {:d} Mace Mastery when you Kill an Enemy": [ + "196,129" + ], + "{:d}% Chance to cast level {:d} Howl when you Kill an Enemy": [ + "196,130" + ], + "{:d}% Chance to cast level {:d} Find Potion when you Kill an Enemy": [ + "196,131" + ], + "{:d}% Chance to cast level {:d} Leap when you Kill an Enemy": [ + "196,132" + ], + "{:d}% Chance to cast level {:d} Double Swing when you Kill an Enemy": [ + "196,133" + ], + "{:d}% Chance to cast level {:d} Polearm Mastery when you Kill an Enemy": [ + "196,134" + ], + "{:d}% Chance to cast level {:d} Throwing Mastery when you Kill an Enemy": [ + "196,135" + ], + "{:d}% Chance to cast level {:d} Spear Mastery when you Kill an Enemy": [ + "196,136" + ], + "{:d}% Chance to cast level {:d} Taunt when you Kill an Enemy": [ + "196,137" + ], + "{:d}% Chance to cast level {:d} Shout when you Kill an Enemy": [ + "196,138" + ], + "{:d}% Chance to cast level {:d} Stun when you Kill an Enemy": [ + "196,139" + ], + "{:d}% Chance to cast level {:d} Double Throw when you Kill an Enemy": [ + "196,140" + ], + "{:d}% Chance to cast level {:d} Increased Stamina when you Kill an Enemy": [ + "196,141" + ], + "{:d}% Chance to cast level {:d} Find Item when you Kill an Enemy": [ + "196,142" + ], + "{:d}% Chance to cast level {:d} Leap Attack when you Kill an Enemy": [ + "196,143" + ], + "{:d}% Chance to cast level {:d} Concentrate when you Kill an Enemy": [ + "196,144" + ], + "{:d}% Chance to cast level {:d} Iron Skin when you Kill an Enemy": [ + "196,145" + ], + "{:d}% Chance to cast level {:d} Battle Cry when you Kill an Enemy": [ + "196,146" + ], + "{:d}% Chance to cast level {:d} Frenzy when you Kill an Enemy": [ + "196,147" + ], + "{:d}% Chance to cast level {:d} Increased Speed when you Kill an Enemy": [ + "196,148" + ], + "{:d}% Chance to cast level {:d} Battle Orders when you Kill an Enemy": [ + "196,149" + ], + "{:d}% Chance to cast level {:d} Grim Ward when you Kill an Enemy": [ + "196,150" + ], + "{:d}% Chance to cast level {:d} Whirlwind when you Kill an Enemy": [ + "196,151" + ], + "{:d}% Chance to cast level {:d} Berserk when you Kill an Enemy": [ + "196,152" + ], + "{:d}% Chance to cast level {:d} Natural Resistance when you Kill an Enemy": [ + "196,153" + ], + "{:d}% Chance to cast level {:d} War Cry when you Kill an Enemy": [ + "196,154" + ], + "{:d}% Chance to cast level {:d} Battle Command when you Kill an Enemy": [ + "196,155" + ], + "{:d}% Chance to cast level {:d} Raven when you Kill an Enemy": [ + "196,221" + ], + "{:d}% Chance to cast level {:d} Poison Creeper when you Kill an Enemy": [ + "196,222" + ], + "{:d}% Chance to cast level {:d} Werewolf when you Kill an Enemy": [ + "196,223" + ], + "{:d}% Chance to cast level {:d} Lycanthropy when you Kill an Enemy": [ + "196,224" + ], + "{:d}% Chance to cast level {:d} Firestorm when you Kill an Enemy": [ + "196,225" + ], + "{:d}% Chance to cast level {:d} Oak Sage when you Kill an Enemy": [ + "196,226" + ], + "{:d}% Chance to cast level {:d} Summon Spirit Wolf when you Kill an Enemy": [ + "196,227" + ], + "{:d}% Chance to cast level {:d} Werebear when you Kill an Enemy": [ + "196,228" + ], + "{:d}% Chance to cast level {:d} Molten Boulder when you Kill an Enemy": [ + "196,229" + ], + "{:d}% Chance to cast level {:d} Arctic Blast when you Kill an Enemy": [ + "196,230" + ], + "{:d}% Chance to cast level {:d} Carrion Vine when you Kill an Enemy": [ + "196,231" + ], + "{:d}% Chance to cast level {:d} Feral Rage when you Kill an Enemy": [ + "196,232" + ], + "{:d}% Chance to cast level {:d} Maul when you Kill an Enemy": [ + "196,233" + ], + "{:d}% Chance to cast level {:d} Fissure when you Kill an Enemy": [ + "196,234" + ], + "{:d}% Chance to cast level {:d} Cyclone Armor when you Kill an Enemy": [ + "196,235" + ], + "{:d}% Chance to cast level {:d} Heart of Wolverine when you Kill an Enemy": [ + "196,236" + ], + "{:d}% Chance to cast level {:d} Summon Dire Wolf when you Kill an Enemy": [ + "196,237" + ], + "{:d}% Chance to cast level {:d} Rabies when you Kill an Enemy": [ + "196,238" + ], + "{:d}% Chance to cast level {:d} Fire Claws when you Kill an Enemy": [ + "196,239" + ], + "{:d}% Chance to cast level {:d} Twister when you Kill an Enemy": [ + "196,240" + ], + "{:d}% Chance to cast level {:d} Solar Creeper when you Kill an Enemy": [ + "196,241" + ], + "{:d}% Chance to cast level {:d} Hunger when you Kill an Enemy": [ + "196,242" + ], + "{:d}% Chance to cast level {:d} Shock Wave when you Kill an Enemy": [ + "196,243" + ], + "{:d}% Chance to cast level {:d} Volcano when you Kill an Enemy": [ + "196,244" + ], + "{:d}% Chance to cast level {:d} Tornado when you Kill an Enemy": [ + "196,245" + ], + "{:d}% Chance to cast level {:d} Spirit of Barbs when you Kill an Enemy": [ + "196,246" + ], + "{:d}% Chance to cast level {:d} Summon Grizzly when you Kill an Enemy": [ + "196,247" + ], + "{:d}% Chance to cast level {:d} Fury when you Kill an Enemy": [ + "196,248" + ], + "{:d}% Chance to cast level {:d} Armageddon when you Kill an Enemy": [ + "196,249" + ], + "{:d}% Chance to cast level {:d} Hurricane when you Kill an Enemy": [ + "196,250" + ], + "{:d}% Chance to cast level {:d} Fire Blast when you Kill an Enemy": [ + "196,251" + ], + "{:d}% Chance to cast level {:d} Claw Mastery when you Kill an Enemy": [ + "196,252" + ], + "{:d}% Chance to cast level {:d} Psychic Hammer when you Kill an Enemy": [ + "196,253" + ], + "{:d}% Chance to cast level {:d} Tiger Strike when you Kill an Enemy": [ + "196,254" + ], + "{:d}% Chance to cast level {:d} Dragon Talon when you Kill an Enemy": [ + "196,255" + ], + "{:d}% Chance to cast level {:d} Shock Web when you Kill an Enemy": [ + "196,256" + ], + "{:d}% Chance to cast level {:d} Blade Sentinel when you Kill an Enemy": [ + "196,257" + ], + "{:d}% Chance to cast level {:d} Burst of Speed when you Kill an Enemy": [ + "196,258" + ], + "{:d}% Chance to cast level {:d} Fists of Fire when you Kill an Enemy": [ + "196,259" + ], + "{:d}% Chance to cast level {:d} Dragon Claw when you Kill an Enemy": [ + "196,260" + ], + "{:d}% Chance to cast level {:d} Charged Bolt Sentry when you Kill an Enemy": [ + "196,261" + ], + "{:d}% Chance to cast level {:d} Wake of Fire when you Kill an Enemy": [ + "196,262" + ], + "{:d}% Chance to cast level {:d} Weapon Block when you Kill an Enemy": [ + "196,263" + ], + "{:d}% Chance to cast level {:d} Cloak of Shadows when you Kill an Enemy": [ + "196,264" + ], + "{:d}% Chance to cast level {:d} Cobra Strike when you Kill an Enemy": [ + "196,265" + ], + "{:d}% Chance to cast level {:d} Blade Fury when you Kill an Enemy": [ + "196,266" + ], + "{:d}% Chance to cast level {:d} Fade when you Kill an Enemy": [ + "196,267" + ], + "{:d}% Chance to cast level {:d} Shadow Warrior when you Kill an Enemy": [ + "196,268" + ], + "{:d}% Chance to cast level {:d} Claws of Thunder when you Kill an Enemy": [ + "196,269" + ], + "{:d}% Chance to cast level {:d} Dragon Tail when you Kill an Enemy": [ + "196,270" + ], + "{:d}% Chance to cast level {:d} Lightning Sentry when you Kill an Enemy": [ + "196,271" + ], + "{:d}% Chance to cast level {:d} Wake of Inferno when you Kill an Enemy": [ + "196,272" + ], + "{:d}% Chance to cast level {:d} Mind Blast when you Kill an Enemy": [ + "196,273" + ], + "{:d}% Chance to cast level {:d} Blades of Ice when you Kill an Enemy": [ + "196,274" + ], + "{:d}% Chance to cast level {:d} Dragon Flight when you Kill an Enemy": [ + "196,275" + ], + "{:d}% Chance to cast level {:d} Death Sentry when you Kill an Enemy": [ + "196,276" + ], + "{:d}% Chance to cast level {:d} Blade Shield when you Kill an Enemy": [ + "196,277" + ], + "{:d}% Chance to cast level {:d} Venom when you Kill an Enemy": [ + "196,278" + ], + "{:d}% Chance to cast level {:d} Shadow Master when you Kill an Enemy": [ + "196,279" + ], + "{:d}% Chance to cast level {:d} Phoenix Strike when you Kill an Enemy": [ + "196,280" + ], + "{:d}% Chance to cast level {:d} Magic Arrow when you Die": [ + "197,6" + ], + "{:d}% Chance to cast level {:d} Fire Arrow when you Die": [ + "197,7" + ], + "{:d}% Chance to cast level {:d} Inner Sight when you Die": [ + "197,8" + ], + "{:d}% Chance to cast level {:d} Critical Strike when you Die": [ + "197,9" + ], + "{:d}% Chance to cast level {:d} Jab when you Die": [ + "197,10" + ], + "{:d}% Chance to cast level {:d} Cold Arrow when you Die": [ + "197,11" + ], + "{:d}% Chance to cast level {:d} Multiple Shot when you Die": [ + "197,12" + ], + "{:d}% Chance to cast level {:d} Dodge when you Die": [ + "197,13" + ], + "{:d}% Chance to cast level {:d} Power Strike when you Die": [ + "197,14" + ], + "{:d}% Chance to cast level {:d} Poison Javelin when you Die": [ + "197,15" + ], + "{:d}% Chance to cast level {:d} Exploding Arrow when you Die": [ + "197,16" + ], + "{:d}% Chance to cast level {:d} Slow Missiles when you Die": [ + "197,17" + ], + "{:d}% Chance to cast level {:d} Avoid when you Die": [ + "197,18" + ], + "{:d}% Chance to cast level {:d} Impale when you Die": [ + "197,19" + ], + "{:d}% Chance to cast level {:d} Lightning Bolt when you Die": [ + "197,20" + ], + "{:d}% Chance to cast level {:d} Ice Arrow when you Die": [ + "197,21" + ], + "{:d}% Chance to cast level {:d} Guided Arrow when you Die": [ + "197,22" + ], + "{:d}% Chance to cast level {:d} Penetrate when you Die": [ + "197,23" + ], + "{:d}% Chance to cast level {:d} Charged Strike when you Die": [ + "197,24" + ], + "{:d}% Chance to cast level {:d} Plague Javelin when you Die": [ + "197,25" + ], + "{:d}% Chance to cast level {:d} Strafe when you Die": [ + "197,26" + ], + "{:d}% Chance to cast level {:d} Immolation Arrow when you Die": [ + "197,27" + ], + "{:d}% Chance to cast level {:d} Decoy when you Die": [ + "197,28" + ], + "{:d}% Chance to cast level {:d} Evade when you Die": [ + "197,29" + ], + "{:d}% Chance to cast level {:d} Fend when you Die": [ + "197,30" + ], + "{:d}% Chance to cast level {:d} Freezing Arrow when you Die": [ + "197,31" + ], + "{:d}% Chance to cast level {:d} Valkyrie when you Die": [ + "197,32" + ], + "{:d}% Chance to cast level {:d} Pierce when you Die": [ + "197,33" + ], + "{:d}% Chance to cast level {:d} Lightning Strike when you Die": [ + "197,34" + ], + "{:d}% Chance to cast level {:d} Lightning Fury when you Die": [ + "197,35" + ], + "{:d}% Chance to cast level {:d} Fire Bolt when you Die": [ + "197,36" + ], + "{:d}% Chance to cast level {:d} Warmth when you Die": [ + "197,37" + ], + "{:d}% Chance to cast level {:d} Charged Bolt when you Die": [ + "197,38" + ], + "{:d}% Chance to cast level {:d} Ice Bolt when you Die": [ + "197,39" + ], + "{:d}% Chance to cast level {:d} Frozen Armor when you Die": [ + "197,40" + ], + "{:d}% Chance to cast level {:d} Inferno when you Die": [ + "197,41" + ], + "{:d}% Chance to cast level {:d} Static Field when you Die": [ + "197,42" + ], + "{:d}% Chance to cast level {:d} Telekinesis when you Die": [ + "197,43" + ], + "{:d}% Chance to cast level {:d} Frost Nova when you Die": [ + "197,44" + ], + "{:d}% Chance to cast level {:d} Ice Blast when you Die": [ + "197,45" + ], + "{:d}% Chance to cast level {:d} Blaze when you Die": [ + "197,46" + ], + "{:d}% Chance to cast level {:d} Fire Ball when you Die": [ + "197,47" + ], + "{:d}% Chance to cast level {:d} Nova when you Die": [ + "197,48" + ], + "{:d}% Chance to cast level {:d} Lightning when you Die": [ + "197,49" + ], + "{:d}% Chance to cast level {:d} Shiver Armor when you Die": [ + "197,50" + ], + "{:d}% Chance to cast level {:d} Fire Wall when you Die": [ + "197,51" + ], + "{:d}% Chance to cast level {:d} Enchant when you Die": [ + "197,52" + ], + "{:d}% Chance to cast level {:d} Chain Lightning when you Die": [ + "197,53" + ], + "{:d}% Chance to cast level {:d} Teleport when you Die": [ + "197,54" + ], + "{:d}% Chance to cast level {:d} Glacial Spike when you Die": [ + "197,55" + ], + "{:d}% Chance to cast level {:d} Meteor when you Die": [ + "197,56" + ], + "{:d}% Chance to cast level {:d} Thunder Storm when you Die": [ + "197,57" + ], + "{:d}% Chance to cast level {:d} Energy Shield when you Die": [ + "197,58" + ], + "{:d}% Chance to cast level {:d} Blizzard when you Die": [ + "197,59" + ], + "{:d}% Chance to cast level {:d} Chilling Armor when you Die": [ + "197,60" + ], + "{:d}% Chance to cast level {:d} Fire Mastery when you Die": [ + "197,61" + ], + "{:d}% Chance to cast level {:d} Hydra when you Die": [ + "197,62" + ], + "{:d}% Chance to cast level {:d} Lightning Mastery when you Die": [ + "197,63" + ], + "{:d}% Chance to cast level {:d} Frozen Orb when you Die": [ + "197,64" + ], + "{:d}% Chance to cast level {:d} Cold Mastery when you Die": [ + "197,65" + ], + "{:d}% Chance to cast level {:d} Amplify Damage when you Die": [ + "197,66" + ], + "{:d}% Chance to cast level {:d} Teeth when you Die": [ + "197,67" + ], + "{:d}% Chance to cast level {:d} Bone Armor when you Die": [ + "197,68" + ], + "{:d}% Chance to cast level {:d} Skeleton Mastery when you Die": [ + "197,69" + ], + "{:d}% Chance to cast level {:d} Raise Skeleton when you Die": [ + "197,70" + ], + "{:d}% Chance to cast level {:d} Dim Vision when you Die": [ + "197,71" + ], + "{:d}% Chance to cast level {:d} Weaken when you Die": [ + "197,72" + ], + "{:d}% Chance to cast level {:d} Poison Dagger when you Die": [ + "197,73" + ], + "{:d}% Chance to cast level {:d} Corpse Explosion when you Die": [ + "197,74" + ], + "{:d}% Chance to cast level {:d} Clay Golem when you Die": [ + "197,75" + ], + "{:d}% Chance to cast level {:d} Iron Maiden when you Die": [ + "197,76" + ], + "{:d}% Chance to cast level {:d} Terror when you Die": [ + "197,77" + ], + "{:d}% Chance to cast level {:d} Bone Wall when you Die": [ + "197,78" + ], + "{:d}% Chance to cast level {:d} Golem Mastery when you Die": [ + "197,79" + ], + "{:d}% Chance to cast level {:d} Raise Skeletal Mage when you Die": [ + "197,80" + ], + "{:d}% Chance to cast level {:d} Confuse when you Die": [ + "197,81" + ], + "{:d}% Chance to cast level {:d} Life Tap when you Die": [ + "197,82" + ], + "{:d}% Chance to cast level {:d} Poison Explosion when you Die": [ + "197,83" + ], + "{:d}% Chance to cast level {:d} Bone Spear when you Die": [ + "197,84" + ], + "{:d}% Chance to cast level {:d} Blood Golem when you Die": [ + "197,85" + ], + "{:d}% Chance to cast level {:d} Attract when you Die": [ + "197,86" + ], + "{:d}% Chance to cast level {:d} Decrepify when you Die": [ + "197,87" + ], + "{:d}% Chance to cast level {:d} Bone Prison when you Die": [ + "197,88" + ], + "{:d}% Chance to cast level {:d} Summon Resist when you Die": [ + "197,89" + ], + "{:d}% Chance to cast level {:d} Iron Golem when you Die": [ + "197,90" + ], + "{:d}% Chance to cast level {:d} Lower Resist when you Die": [ + "197,91" + ], + "{:d}% Chance to cast level {:d} Poison Nova when you Die": [ + "197,92" + ], + "{:d}% Chance to cast level {:d} Bone Spirit when you Die": [ + "197,93" + ], + "{:d}% Chance to cast level {:d} Fire Golem when you Die": [ + "197,94" + ], + "{:d}% Chance to cast level {:d} Revive when you Die": [ + "197,95" + ], + "{:d}% Chance to cast level {:d} Sacrifice when you Die": [ + "197,96" + ], + "{:d}% Chance to cast level {:d} Smite when you Die": [ + "197,97" + ], + "{:d}% Chance to cast level {:d} Might when you Die": [ + "197,98" + ], + "{:d}% Chance to cast level {:d} Prayer when you Die": [ + "197,99" + ], + "{:d}% Chance to cast level {:d} Resist Fire when you Die": [ + "197,100" + ], + "{:d}% Chance to cast level {:d} Holy Bolt when you Die": [ + "197,101" + ], + "{:d}% Chance to cast level {:d} Holy Fire when you Die": [ + "197,102" + ], + "{:d}% Chance to cast level {:d} Thorns when you Die": [ + "197,103" + ], + "{:d}% Chance to cast level {:d} Defiance when you Die": [ + "197,104" + ], + "{:d}% Chance to cast level {:d} Resist Cold when you Die": [ + "197,105" + ], + "{:d}% Chance to cast level {:d} Zeal when you Die": [ + "197,106" + ], + "{:d}% Chance to cast level {:d} Charge when you Die": [ + "197,107" + ], + "{:d}% Chance to cast level {:d} Blessed Aim when you Die": [ + "197,108" + ], + "{:d}% Chance to cast level {:d} Cleansing when you Die": [ + "197,109" + ], + "{:d}% Chance to cast level {:d} Resist Lightning when you Die": [ + "197,110" + ], + "{:d}% Chance to cast level {:d} Vengeance when you Die": [ + "197,111" + ], + "{:d}% Chance to cast level {:d} Blessed Hammer when you Die": [ + "197,112" + ], + "{:d}% Chance to cast level {:d} Concentration when you Die": [ + "197,113" + ], + "{:d}% Chance to cast level {:d} Holy Freeze when you Die": [ + "197,114" + ], + "{:d}% Chance to cast level {:d} Vigor when you Die": [ + "197,115" + ], + "{:d}% Chance to cast level {:d} Conversion when you Die": [ + "197,116" + ], + "{:d}% Chance to cast level {:d} Holy Shield when you Die": [ + "197,117" + ], + "{:d}% Chance to cast level {:d} Holy Shock when you Die": [ + "197,118" + ], + "{:d}% Chance to cast level {:d} Sanctuary when you Die": [ + "197,119" + ], + "{:d}% Chance to cast level {:d} Meditation when you Die": [ + "197,120" + ], + "{:d}% Chance to cast level {:d} Fist of the Heavens when you Die": [ + "197,121" + ], + "{:d}% Chance to cast level {:d} Fanaticism when you Die": [ + "197,122" + ], + "{:d}% Chance to cast level {:d} Conviction when you Die": [ + "197,123" + ], + "{:d}% Chance to cast level {:d} Redemption when you Die": [ + "197,124" + ], + "{:d}% Chance to cast level {:d} Salvation when you Die": [ + "197,125" + ], + "{:d}% Chance to cast level {:d} Bash when you Die": [ + "197,126" + ], + "{:d}% Chance to cast level {:d} Blade Mastery when you Die": [ + "197,127" + ], + "{:d}% Chance to cast level {:d} Axe Mastery when you Die": [ + "197,128" + ], + "{:d}% Chance to cast level {:d} Mace Mastery when you Die": [ + "197,129" + ], + "{:d}% Chance to cast level {:d} Howl when you Die": [ + "197,130" + ], + "{:d}% Chance to cast level {:d} Find Potion when you Die": [ + "197,131" + ], + "{:d}% Chance to cast level {:d} Leap when you Die": [ + "197,132" + ], + "{:d}% Chance to cast level {:d} Double Swing when you Die": [ + "197,133" + ], + "{:d}% Chance to cast level {:d} Polearm Mastery when you Die": [ + "197,134" + ], + "{:d}% Chance to cast level {:d} Throwing Mastery when you Die": [ + "197,135" + ], + "{:d}% Chance to cast level {:d} Spear Mastery when you Die": [ + "197,136" + ], + "{:d}% Chance to cast level {:d} Taunt when you Die": [ + "197,137" + ], + "{:d}% Chance to cast level {:d} Shout when you Die": [ + "197,138" + ], + "{:d}% Chance to cast level {:d} Stun when you Die": [ + "197,139" + ], + "{:d}% Chance to cast level {:d} Double Throw when you Die": [ + "197,140" + ], + "{:d}% Chance to cast level {:d} Increased Stamina when you Die": [ + "197,141" + ], + "{:d}% Chance to cast level {:d} Find Item when you Die": [ + "197,142" + ], + "{:d}% Chance to cast level {:d} Leap Attack when you Die": [ + "197,143" + ], + "{:d}% Chance to cast level {:d} Concentrate when you Die": [ + "197,144" + ], + "{:d}% Chance to cast level {:d} Iron Skin when you Die": [ + "197,145" + ], + "{:d}% Chance to cast level {:d} Battle Cry when you Die": [ + "197,146" + ], + "{:d}% Chance to cast level {:d} Frenzy when you Die": [ + "197,147" + ], + "{:d}% Chance to cast level {:d} Increased Speed when you Die": [ + "197,148" + ], + "{:d}% Chance to cast level {:d} Battle Orders when you Die": [ + "197,149" + ], + "{:d}% Chance to cast level {:d} Grim Ward when you Die": [ + "197,150" + ], + "{:d}% Chance to cast level {:d} Whirlwind when you Die": [ + "197,151" + ], + "{:d}% Chance to cast level {:d} Berserk when you Die": [ + "197,152" + ], + "{:d}% Chance to cast level {:d} Natural Resistance when you Die": [ + "197,153" + ], + "{:d}% Chance to cast level {:d} War Cry when you Die": [ + "197,154" + ], + "{:d}% Chance to cast level {:d} Battle Command when you Die": [ + "197,155" + ], + "{:d}% Chance to cast level {:d} Raven when you Die": [ + "197,221" + ], + "{:d}% Chance to cast level {:d} Poison Creeper when you Die": [ + "197,222" + ], + "{:d}% Chance to cast level {:d} Werewolf when you Die": [ + "197,223" + ], + "{:d}% Chance to cast level {:d} Lycanthropy when you Die": [ + "197,224" + ], + "{:d}% Chance to cast level {:d} Firestorm when you Die": [ + "197,225" + ], + "{:d}% Chance to cast level {:d} Oak Sage when you Die": [ + "197,226" + ], + "{:d}% Chance to cast level {:d} Summon Spirit Wolf when you Die": [ + "197,227" + ], + "{:d}% Chance to cast level {:d} Werebear when you Die": [ + "197,228" + ], + "{:d}% Chance to cast level {:d} Molten Boulder when you Die": [ + "197,229" + ], + "{:d}% Chance to cast level {:d} Arctic Blast when you Die": [ + "197,230" + ], + "{:d}% Chance to cast level {:d} Carrion Vine when you Die": [ + "197,231" + ], + "{:d}% Chance to cast level {:d} Feral Rage when you Die": [ + "197,232" + ], + "{:d}% Chance to cast level {:d} Maul when you Die": [ + "197,233" + ], + "{:d}% Chance to cast level {:d} Fissure when you Die": [ + "197,234" + ], + "{:d}% Chance to cast level {:d} Cyclone Armor when you Die": [ + "197,235" + ], + "{:d}% Chance to cast level {:d} Heart of Wolverine when you Die": [ + "197,236" + ], + "{:d}% Chance to cast level {:d} Summon Dire Wolf when you Die": [ + "197,237" + ], + "{:d}% Chance to cast level {:d} Rabies when you Die": [ + "197,238" + ], + "{:d}% Chance to cast level {:d} Fire Claws when you Die": [ + "197,239" + ], + "{:d}% Chance to cast level {:d} Twister when you Die": [ + "197,240" + ], + "{:d}% Chance to cast level {:d} Solar Creeper when you Die": [ + "197,241" + ], + "{:d}% Chance to cast level {:d} Hunger when you Die": [ + "197,242" + ], + "{:d}% Chance to cast level {:d} Shock Wave when you Die": [ + "197,243" + ], + "{:d}% Chance to cast level {:d} Volcano when you Die": [ + "197,244" + ], + "{:d}% Chance to cast level {:d} Tornado when you Die": [ + "197,245" + ], + "{:d}% Chance to cast level {:d} Spirit of Barbs when you Die": [ + "197,246" + ], + "{:d}% Chance to cast level {:d} Summon Grizzly when you Die": [ + "197,247" + ], + "{:d}% Chance to cast level {:d} Fury when you Die": [ + "197,248" + ], + "{:d}% Chance to cast level {:d} Armageddon when you Die": [ + "197,249" + ], + "{:d}% Chance to cast level {:d} Hurricane when you Die": [ + "197,250" + ], + "{:d}% Chance to cast level {:d} Fire Blast when you Die": [ + "197,251" + ], + "{:d}% Chance to cast level {:d} Claw Mastery when you Die": [ + "197,252" + ], + "{:d}% Chance to cast level {:d} Psychic Hammer when you Die": [ + "197,253" + ], + "{:d}% Chance to cast level {:d} Tiger Strike when you Die": [ + "197,254" + ], + "{:d}% Chance to cast level {:d} Dragon Talon when you Die": [ + "197,255" + ], + "{:d}% Chance to cast level {:d} Shock Web when you Die": [ + "197,256" + ], + "{:d}% Chance to cast level {:d} Blade Sentinel when you Die": [ + "197,257" + ], + "{:d}% Chance to cast level {:d} Burst of Speed when you Die": [ + "197,258" + ], + "{:d}% Chance to cast level {:d} Fists of Fire when you Die": [ + "197,259" + ], + "{:d}% Chance to cast level {:d} Dragon Claw when you Die": [ + "197,260" + ], + "{:d}% Chance to cast level {:d} Charged Bolt Sentry when you Die": [ + "197,261" + ], + "{:d}% Chance to cast level {:d} Wake of Fire when you Die": [ + "197,262" + ], + "{:d}% Chance to cast level {:d} Weapon Block when you Die": [ + "197,263" + ], + "{:d}% Chance to cast level {:d} Cloak of Shadows when you Die": [ + "197,264" + ], + "{:d}% Chance to cast level {:d} Cobra Strike when you Die": [ + "197,265" + ], + "{:d}% Chance to cast level {:d} Blade Fury when you Die": [ + "197,266" + ], + "{:d}% Chance to cast level {:d} Fade when you Die": [ + "197,267" + ], + "{:d}% Chance to cast level {:d} Shadow Warrior when you Die": [ + "197,268" + ], + "{:d}% Chance to cast level {:d} Claws of Thunder when you Die": [ + "197,269" + ], + "{:d}% Chance to cast level {:d} Dragon Tail when you Die": [ + "197,270" + ], + "{:d}% Chance to cast level {:d} Lightning Sentry when you Die": [ + "197,271" + ], + "{:d}% Chance to cast level {:d} Wake of Inferno when you Die": [ + "197,272" + ], + "{:d}% Chance to cast level {:d} Mind Blast when you Die": [ + "197,273" + ], + "{:d}% Chance to cast level {:d} Blades of Ice when you Die": [ + "197,274" + ], + "{:d}% Chance to cast level {:d} Dragon Flight when you Die": [ + "197,275" + ], + "{:d}% Chance to cast level {:d} Death Sentry when you Die": [ + "197,276" + ], + "{:d}% Chance to cast level {:d} Blade Shield when you Die": [ + "197,277" + ], + "{:d}% Chance to cast level {:d} Venom when you Die": [ + "197,278" + ], + "{:d}% Chance to cast level {:d} Shadow Master when you Die": [ + "197,279" + ], + "{:d}% Chance to cast level {:d} Phoenix Strike when you Die": [ + "197,280" + ], + "{:d}% Chance to cast level {:d} Magic Arrow when you Level-Up": [ + "199,6" + ], + "{:d}% Chance to cast level {:d} Fire Arrow when you Level-Up": [ + "199,7" + ], + "{:d}% Chance to cast level {:d} Inner Sight when you Level-Up": [ + "199,8" + ], + "{:d}% Chance to cast level {:d} Critical Strike when you Level-Up": [ + "199,9" + ], + "{:d}% Chance to cast level {:d} Jab when you Level-Up": [ + "199,10" + ], + "{:d}% Chance to cast level {:d} Cold Arrow when you Level-Up": [ + "199,11" + ], + "{:d}% Chance to cast level {:d} Multiple Shot when you Level-Up": [ + "199,12" + ], + "{:d}% Chance to cast level {:d} Dodge when you Level-Up": [ + "199,13" + ], + "{:d}% Chance to cast level {:d} Power Strike when you Level-Up": [ + "199,14" + ], + "{:d}% Chance to cast level {:d} Poison Javelin when you Level-Up": [ + "199,15" + ], + "{:d}% Chance to cast level {:d} Exploding Arrow when you Level-Up": [ + "199,16" + ], + "{:d}% Chance to cast level {:d} Slow Missiles when you Level-Up": [ + "199,17" + ], + "{:d}% Chance to cast level {:d} Avoid when you Level-Up": [ + "199,18" + ], + "{:d}% Chance to cast level {:d} Impale when you Level-Up": [ + "199,19" + ], + "{:d}% Chance to cast level {:d} Lightning Bolt when you Level-Up": [ + "199,20" + ], + "{:d}% Chance to cast level {:d} Ice Arrow when you Level-Up": [ + "199,21" + ], + "{:d}% Chance to cast level {:d} Guided Arrow when you Level-Up": [ + "199,22" + ], + "{:d}% Chance to cast level {:d} Penetrate when you Level-Up": [ + "199,23" + ], + "{:d}% Chance to cast level {:d} Charged Strike when you Level-Up": [ + "199,24" + ], + "{:d}% Chance to cast level {:d} Plague Javelin when you Level-Up": [ + "199,25" + ], + "{:d}% Chance to cast level {:d} Strafe when you Level-Up": [ + "199,26" + ], + "{:d}% Chance to cast level {:d} Immolation Arrow when you Level-Up": [ + "199,27" + ], + "{:d}% Chance to cast level {:d} Decoy when you Level-Up": [ + "199,28" + ], + "{:d}% Chance to cast level {:d} Evade when you Level-Up": [ + "199,29" + ], + "{:d}% Chance to cast level {:d} Fend when you Level-Up": [ + "199,30" + ], + "{:d}% Chance to cast level {:d} Freezing Arrow when you Level-Up": [ + "199,31" + ], + "{:d}% Chance to cast level {:d} Valkyrie when you Level-Up": [ + "199,32" + ], + "{:d}% Chance to cast level {:d} Pierce when you Level-Up": [ + "199,33" + ], + "{:d}% Chance to cast level {:d} Lightning Strike when you Level-Up": [ + "199,34" + ], + "{:d}% Chance to cast level {:d} Lightning Fury when you Level-Up": [ + "199,35" + ], + "{:d}% Chance to cast level {:d} Fire Bolt when you Level-Up": [ + "199,36" + ], + "{:d}% Chance to cast level {:d} Warmth when you Level-Up": [ + "199,37" + ], + "{:d}% Chance to cast level {:d} Charged Bolt when you Level-Up": [ + "199,38" + ], + "{:d}% Chance to cast level {:d} Ice Bolt when you Level-Up": [ + "199,39" + ], + "{:d}% Chance to cast level {:d} Frozen Armor when you Level-Up": [ + "199,40" + ], + "{:d}% Chance to cast level {:d} Inferno when you Level-Up": [ + "199,41" + ], + "{:d}% Chance to cast level {:d} Static Field when you Level-Up": [ + "199,42" + ], + "{:d}% Chance to cast level {:d} Telekinesis when you Level-Up": [ + "199,43" + ], + "{:d}% Chance to cast level {:d} Frost Nova when you Level-Up": [ + "199,44" + ], + "{:d}% Chance to cast level {:d} Ice Blast when you Level-Up": [ + "199,45" + ], + "{:d}% Chance to cast level {:d} Blaze when you Level-Up": [ + "199,46" + ], + "{:d}% Chance to cast level {:d} Fire Ball when you Level-Up": [ + "199,47" + ], + "{:d}% Chance to cast level {:d} Nova when you Level-Up": [ + "199,48" + ], + "{:d}% Chance to cast level {:d} Lightning when you Level-Up": [ + "199,49" + ], + "{:d}% Chance to cast level {:d} Shiver Armor when you Level-Up": [ + "199,50" + ], + "{:d}% Chance to cast level {:d} Fire Wall when you Level-Up": [ + "199,51" + ], + "{:d}% Chance to cast level {:d} Enchant when you Level-Up": [ + "199,52" + ], + "{:d}% Chance to cast level {:d} Chain Lightning when you Level-Up": [ + "199,53" + ], + "{:d}% Chance to cast level {:d} Teleport when you Level-Up": [ + "199,54" + ], + "{:d}% Chance to cast level {:d} Glacial Spike when you Level-Up": [ + "199,55" + ], + "{:d}% Chance to cast level {:d} Meteor when you Level-Up": [ + "199,56" + ], + "{:d}% Chance to cast level {:d} Thunder Storm when you Level-Up": [ + "199,57" + ], + "{:d}% Chance to cast level {:d} Energy Shield when you Level-Up": [ + "199,58" + ], + "{:d}% Chance to cast level {:d} Blizzard when you Level-Up": [ + "199,59" + ], + "{:d}% Chance to cast level {:d} Chilling Armor when you Level-Up": [ + "199,60" + ], + "{:d}% Chance to cast level {:d} Fire Mastery when you Level-Up": [ + "199,61" + ], + "{:d}% Chance to cast level {:d} Hydra when you Level-Up": [ + "199,62" + ], + "{:d}% Chance to cast level {:d} Lightning Mastery when you Level-Up": [ + "199,63" + ], + "{:d}% Chance to cast level {:d} Frozen Orb when you Level-Up": [ + "199,64" + ], + "{:d}% Chance to cast level {:d} Cold Mastery when you Level-Up": [ + "199,65" + ], + "{:d}% Chance to cast level {:d} Amplify Damage when you Level-Up": [ + "199,66" + ], + "{:d}% Chance to cast level {:d} Teeth when you Level-Up": [ + "199,67" + ], + "{:d}% Chance to cast level {:d} Bone Armor when you Level-Up": [ + "199,68" + ], + "{:d}% Chance to cast level {:d} Skeleton Mastery when you Level-Up": [ + "199,69" + ], + "{:d}% Chance to cast level {:d} Raise Skeleton when you Level-Up": [ + "199,70" + ], + "{:d}% Chance to cast level {:d} Dim Vision when you Level-Up": [ + "199,71" + ], + "{:d}% Chance to cast level {:d} Weaken when you Level-Up": [ + "199,72" + ], + "{:d}% Chance to cast level {:d} Poison Dagger when you Level-Up": [ + "199,73" + ], + "{:d}% Chance to cast level {:d} Corpse Explosion when you Level-Up": [ + "199,74" + ], + "{:d}% Chance to cast level {:d} Clay Golem when you Level-Up": [ + "199,75" + ], + "{:d}% Chance to cast level {:d} Iron Maiden when you Level-Up": [ + "199,76" + ], + "{:d}% Chance to cast level {:d} Terror when you Level-Up": [ + "199,77" + ], + "{:d}% Chance to cast level {:d} Bone Wall when you Level-Up": [ + "199,78" + ], + "{:d}% Chance to cast level {:d} Golem Mastery when you Level-Up": [ + "199,79" + ], + "{:d}% Chance to cast level {:d} Raise Skeletal Mage when you Level-Up": [ + "199,80" + ], + "{:d}% Chance to cast level {:d} Confuse when you Level-Up": [ + "199,81" + ], + "{:d}% Chance to cast level {:d} Life Tap when you Level-Up": [ + "199,82" + ], + "{:d}% Chance to cast level {:d} Poison Explosion when you Level-Up": [ + "199,83" + ], + "{:d}% Chance to cast level {:d} Bone Spear when you Level-Up": [ + "199,84" + ], + "{:d}% Chance to cast level {:d} Blood Golem when you Level-Up": [ + "199,85" + ], + "{:d}% Chance to cast level {:d} Attract when you Level-Up": [ + "199,86" + ], + "{:d}% Chance to cast level {:d} Decrepify when you Level-Up": [ + "199,87" + ], + "{:d}% Chance to cast level {:d} Bone Prison when you Level-Up": [ + "199,88" + ], + "{:d}% Chance to cast level {:d} Summon Resist when you Level-Up": [ + "199,89" + ], + "{:d}% Chance to cast level {:d} Iron Golem when you Level-Up": [ + "199,90" + ], + "{:d}% Chance to cast level {:d} Lower Resist when you Level-Up": [ + "199,91" + ], + "{:d}% Chance to cast level {:d} Poison Nova when you Level-Up": [ + "199,92" + ], + "{:d}% Chance to cast level {:d} Bone Spirit when you Level-Up": [ + "199,93" + ], + "{:d}% Chance to cast level {:d} Fire Golem when you Level-Up": [ + "199,94" + ], + "{:d}% Chance to cast level {:d} Revive when you Level-Up": [ + "199,95" + ], + "{:d}% Chance to cast level {:d} Sacrifice when you Level-Up": [ + "199,96" + ], + "{:d}% Chance to cast level {:d} Smite when you Level-Up": [ + "199,97" + ], + "{:d}% Chance to cast level {:d} Might when you Level-Up": [ + "199,98" + ], + "{:d}% Chance to cast level {:d} Prayer when you Level-Up": [ + "199,99" + ], + "{:d}% Chance to cast level {:d} Resist Fire when you Level-Up": [ + "199,100" + ], + "{:d}% Chance to cast level {:d} Holy Bolt when you Level-Up": [ + "199,101" + ], + "{:d}% Chance to cast level {:d} Holy Fire when you Level-Up": [ + "199,102" + ], + "{:d}% Chance to cast level {:d} Thorns when you Level-Up": [ + "199,103" + ], + "{:d}% Chance to cast level {:d} Defiance when you Level-Up": [ + "199,104" + ], + "{:d}% Chance to cast level {:d} Resist Cold when you Level-Up": [ + "199,105" + ], + "{:d}% Chance to cast level {:d} Zeal when you Level-Up": [ + "199,106" + ], + "{:d}% Chance to cast level {:d} Charge when you Level-Up": [ + "199,107" + ], + "{:d}% Chance to cast level {:d} Blessed Aim when you Level-Up": [ + "199,108" + ], + "{:d}% Chance to cast level {:d} Cleansing when you Level-Up": [ + "199,109" + ], + "{:d}% Chance to cast level {:d} Resist Lightning when you Level-Up": [ + "199,110" + ], + "{:d}% Chance to cast level {:d} Vengeance when you Level-Up": [ + "199,111" + ], + "{:d}% Chance to cast level {:d} Blessed Hammer when you Level-Up": [ + "199,112" + ], + "{:d}% Chance to cast level {:d} Concentration when you Level-Up": [ + "199,113" + ], + "{:d}% Chance to cast level {:d} Holy Freeze when you Level-Up": [ + "199,114" + ], + "{:d}% Chance to cast level {:d} Vigor when you Level-Up": [ + "199,115" + ], + "{:d}% Chance to cast level {:d} Conversion when you Level-Up": [ + "199,116" + ], + "{:d}% Chance to cast level {:d} Holy Shield when you Level-Up": [ + "199,117" + ], + "{:d}% Chance to cast level {:d} Holy Shock when you Level-Up": [ + "199,118" + ], + "{:d}% Chance to cast level {:d} Sanctuary when you Level-Up": [ + "199,119" + ], + "{:d}% Chance to cast level {:d} Meditation when you Level-Up": [ + "199,120" + ], + "{:d}% Chance to cast level {:d} Fist of the Heavens when you Level-Up": [ + "199,121" + ], + "{:d}% Chance to cast level {:d} Fanaticism when you Level-Up": [ + "199,122" + ], + "{:d}% Chance to cast level {:d} Conviction when you Level-Up": [ + "199,123" + ], + "{:d}% Chance to cast level {:d} Redemption when you Level-Up": [ + "199,124" + ], + "{:d}% Chance to cast level {:d} Salvation when you Level-Up": [ + "199,125" + ], + "{:d}% Chance to cast level {:d} Bash when you Level-Up": [ + "199,126" + ], + "{:d}% Chance to cast level {:d} Blade Mastery when you Level-Up": [ + "199,127" + ], + "{:d}% Chance to cast level {:d} Axe Mastery when you Level-Up": [ + "199,128" + ], + "{:d}% Chance to cast level {:d} Mace Mastery when you Level-Up": [ + "199,129" + ], + "{:d}% Chance to cast level {:d} Howl when you Level-Up": [ + "199,130" + ], + "{:d}% Chance to cast level {:d} Find Potion when you Level-Up": [ + "199,131" + ], + "{:d}% Chance to cast level {:d} Leap when you Level-Up": [ + "199,132" + ], + "{:d}% Chance to cast level {:d} Double Swing when you Level-Up": [ + "199,133" + ], + "{:d}% Chance to cast level {:d} Polearm Mastery when you Level-Up": [ + "199,134" + ], + "{:d}% Chance to cast level {:d} Throwing Mastery when you Level-Up": [ + "199,135" + ], + "{:d}% Chance to cast level {:d} Spear Mastery when you Level-Up": [ + "199,136" + ], + "{:d}% Chance to cast level {:d} Taunt when you Level-Up": [ + "199,137" + ], + "{:d}% Chance to cast level {:d} Shout when you Level-Up": [ + "199,138" + ], + "{:d}% Chance to cast level {:d} Stun when you Level-Up": [ + "199,139" + ], + "{:d}% Chance to cast level {:d} Double Throw when you Level-Up": [ + "199,140" + ], + "{:d}% Chance to cast level {:d} Increased Stamina when you Level-Up": [ + "199,141" + ], + "{:d}% Chance to cast level {:d} Find Item when you Level-Up": [ + "199,142" + ], + "{:d}% Chance to cast level {:d} Leap Attack when you Level-Up": [ + "199,143" + ], + "{:d}% Chance to cast level {:d} Concentrate when you Level-Up": [ + "199,144" + ], + "{:d}% Chance to cast level {:d} Iron Skin when you Level-Up": [ + "199,145" + ], + "{:d}% Chance to cast level {:d} Battle Cry when you Level-Up": [ + "199,146" + ], + "{:d}% Chance to cast level {:d} Frenzy when you Level-Up": [ + "199,147" + ], + "{:d}% Chance to cast level {:d} Increased Speed when you Level-Up": [ + "199,148" + ], + "{:d}% Chance to cast level {:d} Battle Orders when you Level-Up": [ + "199,149" + ], + "{:d}% Chance to cast level {:d} Grim Ward when you Level-Up": [ + "199,150" + ], + "{:d}% Chance to cast level {:d} Whirlwind when you Level-Up": [ + "199,151" + ], + "{:d}% Chance to cast level {:d} Berserk when you Level-Up": [ + "199,152" + ], + "{:d}% Chance to cast level {:d} Natural Resistance when you Level-Up": [ + "199,153" + ], + "{:d}% Chance to cast level {:d} War Cry when you Level-Up": [ + "199,154" + ], + "{:d}% Chance to cast level {:d} Battle Command when you Level-Up": [ + "199,155" + ], + "{:d}% Chance to cast level {:d} Raven when you Level-Up": [ + "199,221" + ], + "{:d}% Chance to cast level {:d} Poison Creeper when you Level-Up": [ + "199,222" + ], + "{:d}% Chance to cast level {:d} Werewolf when you Level-Up": [ + "199,223" + ], + "{:d}% Chance to cast level {:d} Lycanthropy when you Level-Up": [ + "199,224" + ], + "{:d}% Chance to cast level {:d} Firestorm when you Level-Up": [ + "199,225" + ], + "{:d}% Chance to cast level {:d} Oak Sage when you Level-Up": [ + "199,226" + ], + "{:d}% Chance to cast level {:d} Summon Spirit Wolf when you Level-Up": [ + "199,227" + ], + "{:d}% Chance to cast level {:d} Werebear when you Level-Up": [ + "199,228" + ], + "{:d}% Chance to cast level {:d} Molten Boulder when you Level-Up": [ + "199,229" + ], + "{:d}% Chance to cast level {:d} Arctic Blast when you Level-Up": [ + "199,230" + ], + "{:d}% Chance to cast level {:d} Carrion Vine when you Level-Up": [ + "199,231" + ], + "{:d}% Chance to cast level {:d} Feral Rage when you Level-Up": [ + "199,232" + ], + "{:d}% Chance to cast level {:d} Maul when you Level-Up": [ + "199,233" + ], + "{:d}% Chance to cast level {:d} Fissure when you Level-Up": [ + "199,234" + ], + "{:d}% Chance to cast level {:d} Cyclone Armor when you Level-Up": [ + "199,235" + ], + "{:d}% Chance to cast level {:d} Heart of Wolverine when you Level-Up": [ + "199,236" + ], + "{:d}% Chance to cast level {:d} Summon Dire Wolf when you Level-Up": [ + "199,237" + ], + "{:d}% Chance to cast level {:d} Rabies when you Level-Up": [ + "199,238" + ], + "{:d}% Chance to cast level {:d} Fire Claws when you Level-Up": [ + "199,239" + ], + "{:d}% Chance to cast level {:d} Twister when you Level-Up": [ + "199,240" + ], + "{:d}% Chance to cast level {:d} Solar Creeper when you Level-Up": [ + "199,241" + ], + "{:d}% Chance to cast level {:d} Hunger when you Level-Up": [ + "199,242" + ], + "{:d}% Chance to cast level {:d} Shock Wave when you Level-Up": [ + "199,243" + ], + "{:d}% Chance to cast level {:d} Volcano when you Level-Up": [ + "199,244" + ], + "{:d}% Chance to cast level {:d} Tornado when you Level-Up": [ + "199,245" + ], + "{:d}% Chance to cast level {:d} Spirit of Barbs when you Level-Up": [ + "199,246" + ], + "{:d}% Chance to cast level {:d} Summon Grizzly when you Level-Up": [ + "199,247" + ], + "{:d}% Chance to cast level {:d} Fury when you Level-Up": [ + "199,248" + ], + "{:d}% Chance to cast level {:d} Armageddon when you Level-Up": [ + "199,249" + ], + "{:d}% Chance to cast level {:d} Hurricane when you Level-Up": [ + "199,250" + ], + "{:d}% Chance to cast level {:d} Fire Blast when you Level-Up": [ + "199,251" + ], + "{:d}% Chance to cast level {:d} Claw Mastery when you Level-Up": [ + "199,252" + ], + "{:d}% Chance to cast level {:d} Psychic Hammer when you Level-Up": [ + "199,253" + ], + "{:d}% Chance to cast level {:d} Tiger Strike when you Level-Up": [ + "199,254" + ], + "{:d}% Chance to cast level {:d} Dragon Talon when you Level-Up": [ + "199,255" + ], + "{:d}% Chance to cast level {:d} Shock Web when you Level-Up": [ + "199,256" + ], + "{:d}% Chance to cast level {:d} Blade Sentinel when you Level-Up": [ + "199,257" + ], + "{:d}% Chance to cast level {:d} Burst of Speed when you Level-Up": [ + "199,258" + ], + "{:d}% Chance to cast level {:d} Fists of Fire when you Level-Up": [ + "199,259" + ], + "{:d}% Chance to cast level {:d} Dragon Claw when you Level-Up": [ + "199,260" + ], + "{:d}% Chance to cast level {:d} Charged Bolt Sentry when you Level-Up": [ + "199,261" + ], + "{:d}% Chance to cast level {:d} Wake of Fire when you Level-Up": [ + "199,262" + ], + "{:d}% Chance to cast level {:d} Weapon Block when you Level-Up": [ + "199,263" + ], + "{:d}% Chance to cast level {:d} Cloak of Shadows when you Level-Up": [ + "199,264" + ], + "{:d}% Chance to cast level {:d} Cobra Strike when you Level-Up": [ + "199,265" + ], + "{:d}% Chance to cast level {:d} Blade Fury when you Level-Up": [ + "199,266" + ], + "{:d}% Chance to cast level {:d} Fade when you Level-Up": [ + "199,267" + ], + "{:d}% Chance to cast level {:d} Shadow Warrior when you Level-Up": [ + "199,268" + ], + "{:d}% Chance to cast level {:d} Claws of Thunder when you Level-Up": [ + "199,269" + ], + "{:d}% Chance to cast level {:d} Dragon Tail when you Level-Up": [ + "199,270" + ], + "{:d}% Chance to cast level {:d} Lightning Sentry when you Level-Up": [ + "199,271" + ], + "{:d}% Chance to cast level {:d} Wake of Inferno when you Level-Up": [ + "199,272" + ], + "{:d}% Chance to cast level {:d} Mind Blast when you Level-Up": [ + "199,273" + ], + "{:d}% Chance to cast level {:d} Blades of Ice when you Level-Up": [ + "199,274" + ], + "{:d}% Chance to cast level {:d} Dragon Flight when you Level-Up": [ + "199,275" + ], + "{:d}% Chance to cast level {:d} Death Sentry when you Level-Up": [ + "199,276" + ], + "{:d}% Chance to cast level {:d} Blade Shield when you Level-Up": [ + "199,277" + ], + "{:d}% Chance to cast level {:d} Venom when you Level-Up": [ + "199,278" + ], + "{:d}% Chance to cast level {:d} Shadow Master when you Level-Up": [ + "199,279" + ], + "{:d}% Chance to cast level {:d} Phoenix Strike when you Level-Up": [ + "199,280" + ], + "Required Level: {:d}": [ + "92" + ], + "{:d} to Magic Arrow": [ + "97,6" + ], + "{:d} to Fire Arrow": [ + "97,7" + ], + "{:d} to Inner Sight": [ + "97,8" + ], + "{:d} to Critical Strike": [ + "97,9" + ], + "{:d} to Jab": [ + "97,10" + ], + "{:d} to Cold Arrow": [ + "97,11" + ], + "{:d} to Multiple Shot": [ + "97,12" + ], + "{:d} to Dodge": [ + "97,13" + ], + "{:d} to Power Strike": [ + "97,14" + ], + "{:d} to Poison Javelin": [ + "97,15" + ], + "{:d} to Exploding Arrow": [ + "97,16" + ], + "{:d} to Slow Missiles": [ + "97,17" + ], + "{:d} to Avoid": [ + "97,18" + ], + "{:d} to Impale": [ + "97,19" + ], + "{:d} to Lightning Bolt": [ + "97,20" + ], + "{:d} to Ice Arrow": [ + "97,21" + ], + "{:d} to Guided Arrow": [ + "97,22" + ], + "{:d} to Penetrate": [ + "97,23" + ], + "{:d} to Charged Strike": [ + "97,24" + ], + "{:d} to Plague Javelin": [ + "97,25" + ], + "{:d} to Strafe": [ + "97,26" + ], + "{:d} to Immolation Arrow": [ + "97,27" + ], + "{:d} to Decoy": [ + "97,28" + ], + "{:d} to Evade": [ + "97,29" + ], + "{:d} to Fend": [ + "97,30" + ], + "{:d} to Freezing Arrow": [ + "97,31" + ], + "{:d} to Valkyrie": [ + "97,32" + ], + "{:d} to Pierce": [ + "97,33" + ], + "{:d} to Lightning Strike": [ + "97,34" + ], + "{:d} to Lightning Fury": [ + "97,35" + ], + "{:d} to Fire Bolt": [ + "97,36" + ], + "{:d} to Warmth": [ + "97,37" + ], + "{:d} to Charged Bolt": [ + "97,38" + ], + "{:d} to Ice Bolt": [ + "97,39" + ], + "{:d} to Frozen Armor": [ + "97,40" + ], + "{:d} to Inferno": [ + "97,41" + ], + "{:d} to Static Field": [ + "97,42" + ], + "{:d} to Telekinesis": [ + "97,43" + ], + "{:d} to Frost Nova": [ + "97,44" + ], + "{:d} to Ice Blast": [ + "97,45" + ], + "{:d} to Blaze": [ + "97,46" + ], + "{:d} to Fire Ball": [ + "97,47" + ], + "{:d} to Nova": [ + "97,48" + ], + "{:d} to Lightning": [ + "97,49" + ], + "{:d} to Shiver Armor": [ + "97,50" + ], + "{:d} to Fire Wall": [ + "97,51" + ], + "{:d} to Enchant": [ + "97,52" + ], + "{:d} to Chain Lightning": [ + "97,53" + ], + "{:d} to Teleport": [ + "97,54" + ], + "{:d} to Glacial Spike": [ + "97,55" + ], + "{:d} to Meteor": [ + "97,56" + ], + "{:d} to Thunder Storm": [ + "97,57" + ], + "{:d} to Energy Shield": [ + "97,58" + ], + "{:d} to Blizzard": [ + "97,59" + ], + "{:d} to Chilling Armor": [ + "97,60" + ], + "{:d} to Fire Mastery": [ + "97,61" + ], + "{:d} to Hydra": [ + "97,62" + ], + "{:d} to Lightning Mastery": [ + "97,63" + ], + "{:d} to Frozen Orb": [ + "97,64" + ], + "{:d} to Cold Mastery": [ + "97,65" + ], + "{:d} to Amplify Damage": [ + "97,66" + ], + "{:d} to Teeth": [ + "97,67" + ], + "{:d} to Bone Armor": [ + "97,68" + ], + "{:d} to Skeleton Mastery": [ + "97,69" + ], + "{:d} to Raise Skeleton": [ + "97,70" + ], + "{:d} to Dim Vision": [ + "97,71" + ], + "{:d} to Weaken": [ + "97,72" + ], + "{:d} to Poison Dagger": [ + "97,73" + ], + "{:d} to Corpse Explosion": [ + "97,74" + ], + "{:d} to Clay Golem": [ + "97,75" + ], + "{:d} to Iron Maiden": [ + "97,76" + ], + "{:d} to Terror": [ + "97,77" + ], + "{:d} to Bone Wall": [ + "97,78" + ], + "{:d} to Golem Mastery": [ + "97,79" + ], + "{:d} to Raise Skeletal Mage": [ + "97,80" + ], + "{:d} to Confuse": [ + "97,81" + ], + "{:d} to Life Tap": [ + "97,82" + ], + "{:d} to Poison Explosion": [ + "97,83" + ], + "{:d} to Bone Spear": [ + "97,84" + ], + "{:d} to Blood Golem": [ + "97,85" + ], + "{:d} to Attract": [ + "97,86" + ], + "{:d} to Decrepify": [ + "97,87" + ], + "{:d} to Bone Prison": [ + "97,88" + ], + "{:d} to Summon Resist": [ + "97,89" + ], + "{:d} to Iron Golem": [ + "97,90" + ], + "{:d} to Lower Resist": [ + "97,91" + ], + "{:d} to Poison Nova": [ + "97,92" + ], + "{:d} to Bone Spirit": [ + "97,93" + ], + "{:d} to Fire Golem": [ + "97,94" + ], + "{:d} to Revive": [ + "97,95" + ], + "{:d} to Sacrifice": [ + "97,96" + ], + "{:d} to Smite": [ + "97,97" + ], + "{:d} to Might": [ + "97,98" + ], + "{:d} to Prayer": [ + "97,99" + ], + "{:d} to Resist Fire": [ + "97,100" + ], + "{:d} to Holy Bolt": [ + "97,101" + ], + "{:d} to Holy Fire": [ + "97,102" + ], + "{:d} to Thorns": [ + "97,103" + ], + "{:d} to Defiance": [ + "97,104" + ], + "{:d} to Resist Cold": [ + "97,105" + ], + "{:d} to Zeal": [ + "97,106" + ], + "{:d} to Charge": [ + "97,107" + ], + "{:d} to Blessed Aim": [ + "97,108" + ], + "{:d} to Cleansing": [ + "97,109" + ], + "{:d} to Resist Lightning": [ + "97,110" + ], + "{:d} to Vengeance": [ + "97,111" + ], + "{:d} to Blessed Hammer": [ + "97,112" + ], + "{:d} to Concentration": [ + "97,113" + ], + "{:d} to Holy Freeze": [ + "97,114" + ], + "{:d} to Vigor": [ + "97,115" + ], + "{:d} to Conversion": [ + "97,116" + ], + "{:d} to Holy Shield": [ + "97,117" + ], + "{:d} to Holy Shock": [ + "97,118" + ], + "{:d} to Sanctuary": [ + "97,119" + ], + "{:d} to Meditation": [ + "97,120" + ], + "{:d} to Fist of the Heavens": [ + "97,121" + ], + "{:d} to Fanaticism": [ + "97,122" + ], + "{:d} to Conviction": [ + "97,123" + ], + "{:d} to Redemption": [ + "97,124" + ], + "{:d} to Salvation": [ + "97,125" + ], + "{:d} to Bash": [ + "97,126" + ], + "{:d} to Blade Mastery": [ + "97,127" + ], + "{:d} to Axe Mastery": [ + "97,128" + ], + "{:d} to Mace Mastery": [ + "97,129" + ], + "{:d} to Howl": [ + "97,130" + ], + "{:d} to Find Potion": [ + "97,131" + ], + "{:d} to Leap": [ + "97,132" + ], + "{:d} to Double Swing": [ + "97,133" + ], + "{:d} to Polearm Mastery": [ + "97,134" + ], + "{:d} to Throwing Mastery": [ + "97,135" + ], + "{:d} to Spear Mastery": [ + "97,136" + ], + "{:d} to Taunt": [ + "97,137" + ], + "{:d} to Shout": [ + "97,138" + ], + "{:d} to Stun": [ + "97,139" + ], + "{:d} to Double Throw": [ + "97,140" + ], + "{:d} to Increased Stamina": [ + "97,141" + ], + "{:d} to Find Item": [ + "97,142" + ], + "{:d} to Leap Attack": [ + "97,143" + ], + "{:d} to Concentrate": [ + "97,144" + ], + "{:d} to Iron Skin": [ + "97,145" + ], + "{:d} to Battle Cry": [ + "97,146" + ], + "{:d} to Frenzy": [ + "97,147" + ], + "{:d} to Increased Speed": [ + "97,148" + ], + "{:d} to Battle Orders": [ + "97,149" + ], + "{:d} to Grim Ward": [ + "97,150" + ], + "{:d} to Whirlwind": [ + "97,151" + ], + "{:d} to Berserk": [ + "97,152" + ], + "{:d} to Natural Resistance": [ + "97,153" + ], + "{:d} to War Cry": [ + "97,154" + ], + "{:d} to Battle Command": [ + "97,155" + ], + "{:d} to Raven": [ + "97,221" + ], + "{:d} to Poison Creeper": [ + "97,222" + ], + "{:d} to Werewolf": [ + "97,223" + ], + "{:d} to Lycanthropy": [ + "97,224" + ], + "{:d} to Firestorm": [ + "97,225" + ], + "{:d} to Oak Sage": [ + "97,226" + ], + "{:d} to Summon Spirit Wolf": [ + "97,227" + ], + "{:d} to Werebear": [ + "97,228" + ], + "{:d} to Molten Boulder": [ + "97,229" + ], + "{:d} to Arctic Blast": [ + "97,230" + ], + "{:d} to Carrion Vine": [ + "97,231" + ], + "{:d} to Feral Rage": [ + "97,232" + ], + "{:d} to Maul": [ + "97,233" + ], + "{:d} to Fissure": [ + "97,234" + ], + "{:d} to Cyclone Armor": [ + "97,235" + ], + "{:d} to Heart of Wolverine": [ + "97,236" + ], + "{:d} to Summon Dire Wolf": [ + "97,237" + ], + "{:d} to Rabies": [ + "97,238" + ], + "{:d} to Fire Claws": [ + "97,239" + ], + "{:d} to Twister": [ + "97,240" + ], + "{:d} to Solar Creeper": [ + "97,241" + ], + "{:d} to Hunger": [ + "97,242" + ], + "{:d} to Shock Wave": [ + "97,243" + ], + "{:d} to Volcano": [ + "97,244" + ], + "{:d} to Tornado": [ + "97,245" + ], + "{:d} to Spirit of Barbs": [ + "97,246" + ], + "{:d} to Summon Grizzly": [ + "97,247" + ], + "{:d} to Fury": [ + "97,248" + ], + "{:d} to Armageddon": [ + "97,249" + ], + "{:d} to Hurricane": [ + "97,250" + ], + "{:d} to Fire Blast": [ + "97,251" + ], + "{:d} to Claw Mastery": [ + "97,252" + ], + "{:d} to Psychic Hammer": [ + "97,253" + ], + "{:d} to Tiger Strike": [ + "97,254" + ], + "{:d} to Dragon Talon": [ + "97,255" + ], + "{:d} to Shock Web": [ + "97,256" + ], + "{:d} to Blade Sentinel": [ + "97,257" + ], + "{:d} to Burst of Speed": [ + "97,258" + ], + "{:d} to Fists of Fire": [ + "97,259" + ], + "{:d} to Dragon Claw": [ + "97,260" + ], + "{:d} to Charged Bolt Sentry": [ + "97,261" + ], + "{:d} to Wake of Fire": [ + "97,262" + ], + "{:d} to Weapon Block": [ + "97,263" + ], + "{:d} to Cloak of Shadows": [ + "97,264" + ], + "{:d} to Cobra Strike": [ + "97,265" + ], + "{:d} to Blade Fury": [ + "97,266" + ], + "{:d} to Fade": [ + "97,267" + ], + "{:d} to Shadow Warrior": [ + "97,268" + ], + "{:d} to Claws of Thunder": [ + "97,269" + ], + "{:d} to Dragon Tail": [ + "97,270" + ], + "{:d} to Lightning Sentry": [ + "97,271" + ], + "{:d} to Wake of Inferno": [ + "97,272" + ], + "{:d} to Mind Blast": [ + "97,273" + ], + "{:d} to Blades of Ice": [ + "97,274" + ], + "{:d} to Dragon Flight": [ + "97,275" + ], + "{:d} to Death Sentry": [ + "97,276" + ], + "{:d} to Blade Shield": [ + "97,277" + ], + "{:d} to Venom": [ + "97,278" + ], + "{:d} to Shadow Master": [ + "97,279" + ], + "{:d} to Phoenix Strike": [ + "97,280" + ], + "{:d} to not Consume Quantity": [ + "205" + ], + "ETHEREAL (CANNOT BE REPAIRED), SOCKETED ({:d})": [ + "194" + ], + "{:d} Poison Damage over {:d} Seconds": [ + [ + "57", + "58" + ], + "59" + ], + "One-Hand Damage: {:d} to {:d}": [ + "5000", + "5001" + ], + "Two-Hand Damage: {:d} to {:d}": [ + "5000", + "5001" + ], + "Throw Damage: {:d} to {:d}": [ + "5000", + "5001" + ], + "Smite Damage: {:d} to {:d}": [ + "5000", + "5001" + ], + "Quantity: {:d}": [ + "70" + ], + "Quantity: {:d} of {:d}": [ + "70", + "5003" + ], + "Indestructible": [ + "5004" + ], + "Defense: {:d}": [ + "31" + ], + "{:d}% Enhanced Damage": [ + "5007" + ], + "{:d} to Summoning Skills (Necromancer Only)": [ + "188,21" + ] +} + +BNIP_ALIAS_STAT_PATTERNS_NO_INTS = dict( + zip( + list( + map( + lambda mystr: ''.join(filter(lambda x: not x.isdigit(), mystr)).replace('+','').replace('-','').replace('{:d}','').upper(), + BNIP_ALIAS_STAT_PATTERNS.keys() + ) + ), + BNIP_ALIAS_STAT_PATTERNS.keys() + ) +) + + +BNIP_ITEM_TYPE_DATA = { + "Cap": [ + "helm", + "anyarmor" + ], + "Skull Cap": [ + "helm", + "anyarmor" + ], + "Helm": [ + "helm", + "anyarmor" + ], + "Full Helm": [ + "helm", + "anyarmor" + ], + "Great Helm": [ + "helm", + "anyarmor" + ], + "Crown": [ + "helm", + "anyarmor" + ], + "Mask": [ + "helm", + "anyarmor" + ], + "Quilted Armor": [ + "armor", + "anyarmor" + ], + "Leather Armor": [ + "armor", + "anyarmor" + ], + "Hard Leather Armor": [ + "armor", + "anyarmor" + ], + "Studded Leather": [ + "armor", + "anyarmor" + ], + "Ring Mail": [ + "armor", + "anyarmor" + ], + "Scale Mail": [ + "armor", + "anyarmor" + ], + "Chain Mail": [ + "armor", + "anyarmor" + ], + "Breast Plate": [ + "armor", + "anyarmor" + ], + "Splint Mail": [ + "armor", + "anyarmor" + ], + "Plate Mail": [ + "armor", + "anyarmor" + ], + "Field Plate": [ + "armor", + "anyarmor" + ], + "Gothic Plate": [ + "armor", + "anyarmor" + ], + "Full Plate Mail": [ + "armor", + "anyarmor" + ], + "Ancient Armor": [ + "armor", + "anyarmor" + ], + "Light Plate": [ + "armor", + "anyarmor" + ], + "Buckler": [ + "shield", + "anyshield" + ], + "Small Shield": [ + "shield", + "anyshield" + ], + "Large Shield": [ + "shield", + "anyshield" + ], + "Kite Shield": [ + "shield", + "anyshield" + ], + "Tower Shield": [ + "shield", + "anyshield" + ], + "Gothic Shield": [ + "shield", + "anyshield" + ], + "Leather Gloves": [ + "gloves", + "anyarmor" + ], + "Heavy Gloves": [ + "gloves", + "anyarmor" + ], + "Chain Gloves": [ + "gloves", + "anyarmor" + ], + "Light Gauntlets": [ + "gloves", + "anyarmor" + ], + "Gauntlets": [ + "gloves", + "anyarmor" + ], + "Boots": [ + "boots", + "anyarmor" + ], + "Heavy Boots": [ + "boots", + "anyarmor" + ], + "Chain Boots": [ + "boots", + "anyarmor" + ], + "Light Plated Boots": [ + "boots", + "anyarmor" + ], + "Greaves": [ + "boots", + "anyarmor" + ], + "Sash": [ + "belt", + "anyarmor" + ], + "Light Belt": [ + "belt", + "anyarmor" + ], + "Belt": [ + "belt", + "anyarmor" + ], + "Heavy Belt": [ + "belt", + "anyarmor" + ], + "Plated Belt": [ + "belt", + "anyarmor" + ], + "Bone Helm": [ + "helm", + "anyarmor" + ], + "Bone Shield": [ + "shield", + "anyshield" + ], + "Spiked Shield": [ + "shield", + "anyshield" + ], + "War Hat": [ + "helm", + "anyarmor" + ], + "Sallet": [ + "helm", + "anyarmor" + ], + "Casque": [ + "helm", + "anyarmor" + ], + "Basinet": [ + "helm", + "anyarmor" + ], + "Winged Helm": [ + "helm", + "anyarmor" + ], + "Grand Crown": [ + "helm", + "anyarmor" + ], + "Death Mask": [ + "helm", + "anyarmor" + ], + "Ghost Armor": [ + "armor", + "anyarmor" + ], + "Serpentskin Armor": [ + "armor", + "anyarmor" + ], + "Demonhide Armor": [ + "armor", + "anyarmor" + ], + "Trellised Armor": [ + "armor", + "anyarmor" + ], + "Linked Mail": [ + "armor", + "anyarmor" + ], + "Tigulated Mail": [ + "armor", + "anyarmor" + ], + "Mesh Armor": [ + "armor", + "anyarmor" + ], + "Cuirass": [ + "armor", + "anyarmor" + ], + "Russet Armor": [ + "armor", + "anyarmor" + ], + "Templar Coat": [ + "armor", + "anyarmor" + ], + "Sharktooth Armor": [ + "armor", + "anyarmor" + ], + "Embossed Plate": [ + "armor", + "anyarmor" + ], + "Chaos Armor": [ + "armor", + "anyarmor" + ], + "Ornate Plate": [ + "armor", + "anyarmor" + ], + "Mage Plate": [ + "armor", + "anyarmor" + ], + "Defender": [ + "shield", + "anyshield" + ], + "Round Shield": [ + "shield", + "anyshield" + ], + "Scutum": [ + "shield", + "anyshield" + ], + "Dragon Shield": [ + "shield", + "anyshield" + ], + "Pavise": [ + "shield", + "anyshield" + ], + "Ancient Shield": [ + "shield", + "anyshield" + ], + "Demonhide Gloves": [ + "gloves", + "anyarmor" + ], + "Sharkskin Gloves": [ + "gloves", + "anyarmor" + ], + "Heavy Bracers": [ + "gloves", + "anyarmor" + ], + "Battle Gauntlets": [ + "gloves", + "anyarmor" + ], + "War Gauntlets": [ + "gloves", + "anyarmor" + ], + "Demonhide Boots": [ + "boots", + "anyarmor" + ], + "Sharkskin Boots": [ + "boots", + "anyarmor" + ], + "Mesh Boots": [ + "boots", + "anyarmor" + ], + "Battle Boots": [ + "boots", + "anyarmor" + ], + "War Boots": [ + "boots", + "anyarmor" + ], + "Demonhide Sash": [ + "belt", + "anyarmor" + ], + "Sharkskin Belt": [ + "belt", + "anyarmor" + ], + "Mesh Belt": [ + "belt", + "anyarmor" + ], + "Battle Belt": [ + "belt", + "anyarmor" + ], + "War Belt": [ + "belt", + "anyarmor" + ], + "Grim Helm": [ + "helm", + "anyarmor" + ], + "Grim Shield": [ + "shield", + "anyshield" + ], + "Barbed Shield": [ + "shield", + "anyshield" + ], + "Wolf Head": [ + "pelt", + "helm", + "druiditem" + ], + "Hawk Helm": [ + "pelt", + "helm", + "druiditem" + ], + "Antlers": [ + "pelt", + "helm", + "druiditem" + ], + "Falcon Mask": [ + "pelt", + "helm", + "druiditem" + ], + "Spirit Mask": [ + "pelt", + "helm", + "druiditem" + ], + "Jawbone Cap": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Fanged Helm": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Horned Helm": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Assault Helmet": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Avenger Guard": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Targe": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Rondache": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Heraldic Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Aerin Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Crown Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Preserved Head": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Zombie Head": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Unraveller Head": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Gargoyle Head": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Demon Head": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Circlet": [ + "circlet", + "helm" + ], + "Coronet": [ + "circlet", + "helm" + ], + "Tiara": [ + "circlet", + "helm" + ], + "Diadem": [ + "circlet", + "helm" + ], + "Shako": [ + "helm", + "anyarmor" + ], + "Hydraskull": [ + "helm", + "anyarmor" + ], + "Armet": [ + "helm", + "anyarmor" + ], + "Giant Conch": [ + "helm", + "anyarmor" + ], + "Spired Helm": [ + "helm", + "anyarmor" + ], + "Corona": [ + "helm", + "anyarmor" + ], + "Demonhead": [ + "helm", + "anyarmor" + ], + "Dusk Shroud": [ + "armor", + "anyarmor" + ], + "Wyrmhide": [ + "armor", + "anyarmor" + ], + "Scarab Husk": [ + "armor", + "anyarmor" + ], + "Wire Fleece": [ + "armor", + "anyarmor" + ], + "Diamond Mail": [ + "armor", + "anyarmor" + ], + "Loricated Mail": [ + "armor", + "anyarmor" + ], + "Boneweave": [ + "armor", + "anyarmor" + ], + "Great Hauberk": [ + "armor", + "anyarmor" + ], + "Balrog Skin": [ + "armor", + "anyarmor" + ], + "Hellforge Plate": [ + "armor", + "anyarmor" + ], + "Kraken Shell": [ + "armor", + "anyarmor" + ], + "Lacquered Plate": [ + "armor", + "anyarmor" + ], + "Shadow Plate": [ + "armor", + "anyarmor" + ], + "Sacred Armor": [ + "armor", + "anyarmor" + ], + "Archon Plate": [ + "armor", + "anyarmor" + ], + "Heater": [ + "shield", + "anyshield" + ], + "Luna": [ + "shield", + "anyshield" + ], + "Hyperion": [ + "shield", + "anyshield" + ], + "Monarch": [ + "shield", + "anyshield" + ], + "Aegis": [ + "shield", + "anyshield" + ], + "Ward": [ + "shield", + "anyshield" + ], + "Bramble Mitts": [ + "gloves", + "anyarmor" + ], + "Vampirebone Gloves": [ + "gloves", + "anyarmor" + ], + "Vambraces": [ + "gloves", + "anyarmor" + ], + "Crusader Gauntlets": [ + "gloves", + "anyarmor" + ], + "Ogre Gauntlets": [ + "gloves", + "anyarmor" + ], + "Wyrmhide Boots": [ + "boots", + "anyarmor" + ], + "Scarabshell Boots": [ + "boots", + "anyarmor" + ], + "Boneweave Boots": [ + "boots", + "anyarmor" + ], + "Mirrored Boots": [ + "boots", + "anyarmor" + ], + "Myrmidon Greaves": [ + "boots", + "anyarmor" + ], + "Spiderweb Sash": [ + "belt", + "anyarmor" + ], + "Vampirefang Belt": [ + "belt", + "anyarmor" + ], + "Mithril Coil": [ + "belt", + "anyarmor" + ], + "Troll Belt": [ + "belt", + "anyarmor" + ], + "Colossus Girdle": [ + "belt", + "anyarmor" + ], + "Bone Visage": [ + "helm", + "anyarmor" + ], + "Troll Nest": [ + "shield", + "anyshield" + ], + "Blade Barrier": [ + "shield", + "anyshield" + ], + "Alpha Helm": [ + "pelt", + "helm", + "druiditem" + ], + "Griffon Headdress": [ + "pelt", + "helm", + "druiditem" + ], + "Hunter's Guise": [ + "pelt", + "helm", + "druiditem" + ], + "Sacred Feathers": [ + "pelt", + "helm", + "druiditem" + ], + "Totemic Mask": [ + "pelt", + "helm", + "druiditem" + ], + "Jawbone Visor": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Lion Helm": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Rage Mask": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Savage Helmet": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Slayer Guard": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Akaran Targe": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Akaran Rondache": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Protector Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Gilded Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Royal Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Mummified Trophy": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Fetish Trophy": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Sexton Trophy": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Cantor Trophy": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Hierophant Trophy": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Blood Spirit": [ + "pelt", + "helm", + "druiditem" + ], + "Sun Spirit": [ + "pelt", + "helm", + "druiditem" + ], + "Earth Spirit": [ + "pelt", + "helm", + "druiditem" + ], + "Sky Spirit": [ + "pelt", + "helm", + "druiditem" + ], + "Dream Spirit": [ + "pelt", + "helm", + "druiditem" + ], + "Carnage Helm": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Fury Visor": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Destroyer Helm": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Conqueror Crown": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Guardian Crown": [ + "primalhelm", + "helm", + "barbarianitem" + ], + "Sacred Targe": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Sacred Rondache": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Kurast Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Zakarum Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Vortex Shield": [ + "auricshields", + "anyshield", + "paladinitem" + ], + "Minion Skull": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Hellspawn Skull": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Overseer Skull": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Succubus Skull": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Bloodlord Skull": [ + "voodooheads", + "anyshield", + "necromanceritem" + ], + "Hand Axe": [ + "axe", + "meleeweapon" + ], + "Axe": [ + "axe", + "meleeweapon" + ], + "Double Axe": [ + "axe", + "meleeweapon" + ], + "Military Pick": [ + "axe", + "meleeweapon" + ], + "War Axe": [ + "axe", + "meleeweapon" + ], + "Large Axe": [ + "axe", + "meleeweapon" + ], + "Broad Axe": [ + "axe", + "meleeweapon" + ], + "Battle Axe": [ + "axe", + "meleeweapon" + ], + "Great Axe": [ + "axe", + "meleeweapon" + ], + "Giant Axe": [ + "axe", + "meleeweapon" + ], + "Wand": [ + "wand", + "stavesandrods" + ], + "Yew Wand": [ + "wand", + "stavesandrods" + ], + "Bone Wand": [ + "wand", + "stavesandrods" + ], + "Grim Wand": [ + "wand", + "stavesandrods" + ], + "Club": [ + "club", + "blunt" + ], + "Scepter": [ + "scepter", + "stavesandrods" + ], + "Grand Scepter": [ + "scepter", + "stavesandrods" + ], + "War Scepter": [ + "scepter", + "stavesandrods" + ], + "Spiked Club": [ + "club", + "blunt" + ], + "Mace": [ + "mace", + "blunt" + ], + "Morning Star": [ + "mace", + "blunt" + ], + "Flail": [ + "mace", + "blunt" + ], + "War Hammer": [ + "hammer", + "blunt" + ], + "Maul": [ + "hammer", + "blunt" + ], + "Great Maul": [ + "hammer", + "blunt" + ], + "Short Sword": [ + "sword", + "swordsandknives" + ], + "Scimitar": [ + "sword", + "swordsandknives" + ], + "Sabre": [ + "sword", + "swordsandknives" + ], + "Falchion": [ + "sword", + "swordsandknives" + ], + "Crystal Sword": [ + "sword", + "swordsandknives" + ], + "Broad Sword": [ + "sword", + "swordsandknives" + ], + "Long Sword": [ + "sword", + "swordsandknives" + ], + "War Sword": [ + "sword", + "swordsandknives" + ], + "Two-Handed Sword": [ + "sword", + "swordsandknives" + ], + "Claymore": [ + "sword", + "swordsandknives" + ], + "Giant Sword": [ + "sword", + "swordsandknives" + ], + "Bastard Sword": [ + "sword", + "swordsandknives" + ], + "Flamberge": [ + "sword", + "swordsandknives" + ], + "Great Sword": [ + "sword", + "swordsandknives" + ], + "Dagger": [ + "knife", + "swordsandknives" + ], + "Dirk": [ + "knife", + "swordsandknives" + ], + "Kris": [ + "knife", + "swordsandknives" + ], + "Blade": [ + "knife", + "swordsandknives" + ], + "Throwing Knife": [ + "throwingknife", + "comboweapon", + "knife" + ], + "Throwing Axe": [ + "throwingaxe", + "comboweapon", + "axe" + ], + "Balanced Knife": [ + "throwingknife", + "comboweapon", + "knife" + ], + "Balanced Axe": [ + "throwingaxe", + "comboweapon", + "axe" + ], + "Javelin": [ + "javelin", + "comboweapon", + "spear" + ], + "Pilum": [ + "javelin", + "comboweapon", + "spear" + ], + "Short Spear": [ + "javelin", + "comboweapon", + "spear" + ], + "Glaive": [ + "javelin", + "comboweapon", + "spear" + ], + "Throwing Spear": [ + "javelin", + "comboweapon", + "spear" + ], + "Spear": [ + "spear", + "spearsandpolearms" + ], + "Trident": [ + "spear", + "spearsandpolearms" + ], + "Brandistock": [ + "spear", + "spearsandpolearms" + ], + "Spetum": [ + "spear", + "spearsandpolearms" + ], + "Pike": [ + "spear", + "spearsandpolearms" + ], + "Bardiche": [ + "polearm", + "spearsandpolearms" + ], + "Voulge": [ + "polearm", + "spearsandpolearms" + ], + "Scythe": [ + "polearm", + "spearsandpolearms" + ], + "Poleaxe": [ + "polearm", + "spearsandpolearms" + ], + "Halberd": [ + "polearm", + "spearsandpolearms" + ], + "War Scythe": [ + "polearm", + "spearsandpolearms" + ], + "Short Staff": [ + "staff", + "stavesandrods" + ], + "Long Staff": [ + "staff", + "stavesandrods" + ], + "Gnarled Staff": [ + "staff", + "stavesandrods" + ], + "Battle Staff": [ + "staff", + "stavesandrods" + ], + "War Staff": [ + "staff", + "stavesandrods" + ], + "Short Bow": [ + "bow", + "missileweapon" + ], + "Hunter's Bow": [ + "bow", + "missileweapon" + ], + "Long Bow": [ + "bow", + "missileweapon" + ], + "Composite Bow": [ + "bow", + "missileweapon" + ], + "Short Battle Bow": [ + "bow", + "missileweapon" + ], + "Long Battle Bow": [ + "bow", + "missileweapon" + ], + "Short War Bow": [ + "bow", + "missileweapon" + ], + "Long War Bow": [ + "bow", + "missileweapon" + ], + "Light Crossbow": [ + "crossbow", + "missileweapon" + ], + "Crossbow": [ + "crossbow", + "missileweapon" + ], + "Heavy Crossbow": [ + "crossbow", + "missileweapon" + ], + "Repeating Crossbow": [ + "crossbow", + "missileweapon" + ], + "Rancid Gas Potion": [ + "missilepotion", + "thrownweapon" + ], + "Oil Potion": [ + "missilepotion", + "thrownweapon" + ], + "Choking Gas Potion": [ + "missilepotion", + "thrownweapon" + ], + "Exploding Potion": [ + "missilepotion", + "thrownweapon" + ], + "Strangling Gas Potion": [ + "missilepotion", + "thrownweapon" + ], + "Fulminating Potion": [ + "missilepotion", + "thrownweapon" + ], + "Decoy Gidbinn": [ + "knife", + "swordsandknives" + ], + "The Gidbinn": [ + "knife", + "swordsandknives" + ], + "Wirt's Leg": [ + "club", + "blunt" + ], + "Horadric Malus": [ + "hammer", + "blunt" + ], + "Hell Forge Hammer": [ + "hammer", + "blunt" + ], + "Horadric Staff": [ + "staff", + "stavesandrods" + ], + "Shaft of the Horadric Staff": [ + "staff", + "stavesandrods" + ], + "Hatchet": [ + "axe", + "meleeweapon" + ], + "Cleaver": [ + "axe", + "meleeweapon" + ], + "Twin Axe": [ + "axe", + "meleeweapon" + ], + "Crowbill": [ + "axe", + "meleeweapon" + ], + "Naga": [ + "axe", + "meleeweapon" + ], + "Military Axe": [ + "axe", + "meleeweapon" + ], + "Bearded Axe": [ + "axe", + "meleeweapon" + ], + "Tabar": [ + "axe", + "meleeweapon" + ], + "Gothic Axe": [ + "axe", + "meleeweapon" + ], + "Ancient Axe": [ + "axe", + "meleeweapon" + ], + "Burnt Wand": [ + "wand", + "stavesandrods" + ], + "Petrified Wand": [ + "wand", + "stavesandrods" + ], + "Tomb Wand": [ + "wand", + "stavesandrods" + ], + "Grave Wand": [ + "wand", + "stavesandrods" + ], + "Cudgel": [ + "club", + "blunt" + ], + "Rune Scepter": [ + "scepter", + "stavesandrods" + ], + "Holy Water Sprinkler": [ + "scepter", + "stavesandrods" + ], + "Divine Scepter": [ + "scepter", + "stavesandrods" + ], + "Barbed Club": [ + "club", + "blunt" + ], + "Flanged Mace": [ + "mace", + "blunt" + ], + "Jagged Star": [ + "mace", + "blunt" + ], + "Knout": [ + "mace", + "blunt" + ], + "Battle Hammer": [ + "hammer", + "blunt" + ], + "War Club": [ + "hammer", + "blunt" + ], + "Martel de Fer": [ + "hammer", + "blunt" + ], + "Gladius": [ + "sword", + "swordsandknives" + ], + "Cutlass": [ + "sword", + "swordsandknives" + ], + "Shamshir": [ + "sword", + "swordsandknives" + ], + "Tulwar": [ + "sword", + "swordsandknives" + ], + "Dimensional Blade": [ + "sword", + "swordsandknives" + ], + "Battle Sword": [ + "sword", + "swordsandknives" + ], + "Rune Sword": [ + "sword", + "swordsandknives" + ], + "Ancient Sword": [ + "sword", + "swordsandknives" + ], + "Espandon": [ + "sword", + "swordsandknives" + ], + "Dacian Falx": [ + "sword", + "swordsandknives" + ], + "Tusk Sword": [ + "sword", + "swordsandknives" + ], + "Gothic Sword": [ + "sword", + "swordsandknives" + ], + "Zweihander": [ + "sword", + "swordsandknives" + ], + "Executioner Sword": [ + "sword", + "swordsandknives" + ], + "Poignard": [ + "knife", + "swordsandknives" + ], + "Rondel": [ + "knife", + "swordsandknives" + ], + "Cinquedeas": [ + "knife", + "swordsandknives" + ], + "Stiletto": [ + "knife", + "swordsandknives" + ], + "Battle Dart": [ + "throwingknife", + "comboweapon", + "knife" + ], + "Francisca": [ + "throwingaxe", + "comboweapon", + "axe" + ], + "War Dart": [ + "throwingknife", + "comboweapon", + "knife" + ], + "Hurlbat": [ + "throwingaxe", + "comboweapon", + "axe" + ], + "War Javelin": [ + "javelin", + "comboweapon", + "spear" + ], + "Great Pilum": [ + "javelin", + "comboweapon", + "spear" + ], + "Simbilan": [ + "javelin", + "comboweapon", + "spear" + ], + "Spiculum": [ + "javelin", + "comboweapon", + "spear" + ], + "Harpoon": [ + "javelin", + "comboweapon", + "spear" + ], + "War Spear": [ + "spear", + "spearsandpolearms" + ], + "Fuscina": [ + "spear", + "spearsandpolearms" + ], + "War Fork": [ + "spear", + "spearsandpolearms" + ], + "Yari": [ + "spear", + "spearsandpolearms" + ], + "Lance": [ + "spear", + "spearsandpolearms" + ], + "Lochaber Axe": [ + "polearm", + "spearsandpolearms" + ], + "Bill": [ + "polearm", + "spearsandpolearms" + ], + "Battle Scythe": [ + "polearm", + "spearsandpolearms" + ], + "Partizan": [ + "polearm", + "spearsandpolearms" + ], + "Bec-de-Corbin": [ + "polearm", + "spearsandpolearms" + ], + "Grim Scythe": [ + "polearm", + "spearsandpolearms" + ], + "Jo Staff": [ + "staff", + "stavesandrods" + ], + "Quarterstaff": [ + "staff", + "stavesandrods" + ], + "Cedar Staff": [ + "staff", + "stavesandrods" + ], + "Gothic Staff": [ + "staff", + "stavesandrods" + ], + "Rune Staff": [ + "staff", + "stavesandrods" + ], + "Edge Bow": [ + "bow", + "missileweapon" + ], + "Razor Bow": [ + "bow", + "missileweapon" + ], + "Cedar Bow": [ + "bow", + "missileweapon" + ], + "Double Bow": [ + "bow", + "missileweapon" + ], + "Short Siege Bow": [ + "bow", + "missileweapon" + ], + "Large Siege Bow": [ + "bow", + "missileweapon" + ], + "Rune Bow": [ + "bow", + "missileweapon" + ], + "Gothic Bow": [ + "bow", + "missileweapon" + ], + "Arbalest": [ + "crossbow", + "missileweapon" + ], + "Siege Crossbow": [ + "crossbow", + "missileweapon" + ], + "Ballista": [ + "crossbow", + "missileweapon" + ], + "Chu-Ko-Nu": [ + "crossbow", + "missileweapon" + ], + "Khalim's Flail": [ + "mace", + "blunt" + ], + "Khalim's Will": [ + "mace", + "blunt" + ], + "Katar": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Wrist Blade": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Hatchet Hands": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Cestus": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Claws": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Blade Talons": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Scissors Katar": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Quhab": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Wrist Spike": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Fascia": [ + "handtohand", + "meleeweapon", + "assassinitem", + "assassinclaw" + ], + "Hand Scythe": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Greater Claws": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Greater Talons": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Scissors Quhab": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Suwayyah": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Wrist Sword": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "War Fist": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Battle Cestus": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Feral Claws": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Runic Talons": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Scissors Suwayyah": [ + "assassinclaw", + "handtohand", + "assassinitem" + ], + "Tomahawk": [ + "axe", + "meleeweapon" + ], + "Small Crescent": [ + "axe", + "meleeweapon" + ], + "Ettin Axe": [ + "axe", + "meleeweapon" + ], + "War Spike": [ + "axe", + "meleeweapon" + ], + "Berserker Axe": [ + "axe", + "meleeweapon" + ], + "Feral Axe": [ + "axe", + "meleeweapon" + ], + "Silver-edged Axe": [ + "axe", + "meleeweapon" + ], + "Decapitator": [ + "axe", + "meleeweapon" + ], + "Champion Axe": [ + "axe", + "meleeweapon" + ], + "Glorious Axe": [ + "axe", + "meleeweapon" + ], + "Polished Wand": [ + "wand", + "stavesandrods" + ], + "Ghost Wand": [ + "wand", + "stavesandrods" + ], + "Lich Wand": [ + "wand", + "stavesandrods" + ], + "Unearthed Wand": [ + "wand", + "stavesandrods" + ], + "Truncheon": [ + "club", + "blunt" + ], + "Mighty Scepter": [ + "scepter", + "stavesandrods" + ], + "Seraph Rod": [ + "scepter", + "stavesandrods" + ], + "Caduceus": [ + "scepter", + "stavesandrods" + ], + "Tyrant Club": [ + "club", + "blunt" + ], + "Reinforced Mace": [ + "mace", + "blunt" + ], + "Devil Star": [ + "mace", + "blunt" + ], + "Scourge": [ + "mace", + "blunt" + ], + "Legendary Mallet": [ + "hammer", + "blunt" + ], + "Ogre Maul": [ + "hammer", + "blunt" + ], + "Thunder Maul": [ + "hammer", + "blunt" + ], + "Falcata": [ + "sword", + "swordsandknives" + ], + "Ataghan": [ + "sword", + "swordsandknives" + ], + "Elegant Blade": [ + "sword", + "swordsandknives" + ], + "Hydra Edge": [ + "sword", + "swordsandknives" + ], + "Phase Blade": [ + "sword", + "swordsandknives" + ], + "Conquest Sword": [ + "sword", + "swordsandknives" + ], + "Cryptic Sword": [ + "sword", + "swordsandknives" + ], + "Mythical Sword": [ + "sword", + "swordsandknives" + ], + "Legend Sword": [ + "sword", + "swordsandknives" + ], + "Highland Blade": [ + "sword", + "swordsandknives" + ], + "Balrog Blade": [ + "sword", + "swordsandknives" + ], + "Champion Sword": [ + "sword", + "swordsandknives" + ], + "Colossus Sword": [ + "sword", + "swordsandknives" + ], + "Colossus Blade": [ + "sword", + "swordsandknives" + ], + "Bone Knife": [ + "knife", + "swordsandknives" + ], + "Mithril Point": [ + "knife", + "swordsandknives" + ], + "Fanged Knife": [ + "knife", + "swordsandknives" + ], + "Legend Spike": [ + "knife", + "swordsandknives" + ], + "Flying Knife": [ + "throwingknife", + "comboweapon", + "knife" + ], + "Flying Axe": [ + "throwingaxe", + "comboweapon", + "axe" + ], + "Winged Knife": [ + "throwingknife", + "comboweapon", + "knife" + ], + "Winged Axe": [ + "throwingaxe", + "comboweapon", + "axe" + ], + "Hyperion Javelin": [ + "javelin", + "comboweapon", + "spear" + ], + "Stygian Pilum": [ + "javelin", + "comboweapon", + "spear" + ], + "Balrog Spear": [ + "javelin", + "comboweapon", + "spear" + ], + "Ghost Glaive": [ + "javelin", + "comboweapon", + "spear" + ], + "Winged Harpoon": [ + "javelin", + "comboweapon", + "spear" + ], + "Hyperion Spear": [ + "spear", + "spearsandpolearms" + ], + "Stygian Pike": [ + "spear", + "spearsandpolearms" + ], + "Mancatcher": [ + "spear", + "spearsandpolearms" + ], + "Ghost Spear": [ + "spear", + "spearsandpolearms" + ], + "War Pike": [ + "spear", + "spearsandpolearms" + ], + "Ogre Axe": [ + "polearm", + "spearsandpolearms" + ], + "Colossus Voulge": [ + "polearm", + "spearsandpolearms" + ], + "Thresher": [ + "polearm", + "spearsandpolearms" + ], + "Cryptic Axe": [ + "polearm", + "spearsandpolearms" + ], + "Great Poleaxe": [ + "polearm", + "spearsandpolearms" + ], + "Giant Thresher": [ + "polearm", + "spearsandpolearms" + ], + "Walking Stick": [ + "staff", + "stavesandrods" + ], + "Stalagmite": [ + "staff", + "stavesandrods" + ], + "Elder Staff": [ + "staff", + "stavesandrods" + ], + "Shillelagh": [ + "staff", + "stavesandrods" + ], + "Archon Staff": [ + "staff", + "stavesandrods" + ], + "Spider Bow": [ + "bow", + "missileweapon" + ], + "Blade Bow": [ + "bow", + "missileweapon" + ], + "Shadow Bow": [ + "bow", + "missileweapon" + ], + "Great Bow": [ + "bow", + "missileweapon" + ], + "Diamond Bow": [ + "bow", + "missileweapon" + ], + "Crusader Bow": [ + "bow", + "missileweapon" + ], + "Ward Bow": [ + "bow", + "missileweapon" + ], + "Hydra Bow": [ + "bow", + "missileweapon" + ], + "Pellet Bow": [ + "crossbow", + "missileweapon" + ], + "Gorgon Crossbow": [ + "crossbow", + "missileweapon" + ], + "Colossus Crossbow": [ + "crossbow", + "missileweapon" + ], + "Demon Crossbow": [ + "crossbow", + "missileweapon" + ], + "Eagle Orb": [ + "orb", + "weapon", + "sorceressitem" + ], + "Sacred Globe": [ + "orb", + "weapon", + "sorceressitem" + ], + "Smoked Sphere": [ + "orb", + "weapon", + "sorceressitem" + ], + "Clasped Orb": [ + "orb", + "weapon", + "sorceressitem" + ], + "Jared's Stone": [ + "orb", + "weapon", + "sorceressitem" + ], + "Stag Bow": [ + "amazonbow", + "bow", + "amazonitem" + ], + "Reflex Bow": [ + "amazonbow", + "bow", + "amazonitem" + ], + "Maiden Spear": [ + "amazonspear", + "spear", + "amazonitem" + ], + "Maiden Pike": [ + "amazonspear", + "spear", + "amazonitem" + ], + "Maiden Javelin": [ + "amazonjavelin", + "javelin", + "amazonitem" + ], + "Glowing Orb": [ + "orb", + "weapon", + "sorceressitem" + ], + "Crystalline Globe": [ + "orb", + "weapon", + "sorceressitem" + ], + "Cloudy Sphere": [ + "orb", + "weapon", + "sorceressitem" + ], + "Sparkling Ball": [ + "orb", + "weapon", + "sorceressitem" + ], + "Swirling Crystal": [ + "orb", + "weapon", + "sorceressitem" + ], + "Ashwood Bow": [ + "amazonbow", + "bow", + "amazonitem" + ], + "Ceremonial Bow": [ + "amazonbow", + "bow", + "amazonitem" + ], + "Ceremonial Spear": [ + "amazonspear", + "spear", + "amazonitem" + ], + "Ceremonial Pike": [ + "amazonspear", + "spear", + "amazonitem" + ], + "Ceremonial Javelin": [ + "amazonjavelin", + "javelin", + "amazonitem" + ], + "Heavenly Stone": [ + "orb", + "weapon", + "sorceressitem" + ], + "Eldritch Orb": [ + "orb", + "weapon", + "sorceressitem" + ], + "Demon Heart": [ + "orb", + "weapon", + "sorceressitem" + ], + "Vortex Orb": [ + "orb", + "weapon", + "sorceressitem" + ], + "Dimensional Shard": [ + "orb", + "weapon", + "sorceressitem" + ], + "Matriarchal Bow": [ + "amazonbow", + "bow", + "amazonitem" + ], + "Grand Matron Bow": [ + "amazonbow", + "bow", + "amazonitem" + ], + "Matriarchal Spear": [ + "amazonspear", + "spear", + "amazonitem" + ], + "Matriarchal Pike": [ + "amazonspear", + "spear", + "amazonitem" + ], + "Matriarchal Javelin": [ + "amazonjavelin", + "javelin", + "amazonitem" + ], + "Elixir": [ + "elixir", + "miscellaneous" + ], + "null": [ + "manapotion", + "potion" + ], + "Stamina Potion": [ + "staminapotion", + "potion" + ], + "Antidote Potion": [ + "antidotepotion", + "potion" + ], + "Rejuvenation Potion": [ + "rejuvpotion", + "healingpotion", + "manapotion" + ], + "Full Rejuvenation Potion": [ + "rejuvpotion", + "healingpotion", + "manapotion" + ], + "Thawing Potion": [ + "thawingpotion", + "potion" + ], + "Tome of Town Portal": [ + "book", + "miscellaneous" + ], + "Tome of Identify": [ + "book", + "miscellaneous" + ], + "Amulet": [ + "amulet", + "miscellaneous" + ], + "Top of the Horadric Staff": [ + "amulet", + "miscellaneous" + ], + "Ring": [ + "ring", + "miscellaneous" + ], + "Gold": [ + "gold", + "miscellaneous" + ], + "Scroll of Inifuss": [ + "quest" + ], + "Key to the Cairn Stones": [ + "quest" + ], + "Arrows": [ + "bowquiver", + "missile", + "secondhand" + ], + "Torch": [ + "torch", + "miscellaneous" + ], + "Bolts": [ + "crossbowquiver", + "missile", + "secondhand" + ], + "Scroll of Town Portal": [ + "scroll", + "miscellaneous" + ], + "Scroll of Identify": [ + "scroll", + "miscellaneous" + ], + "Heart": [ + "bodypart", + "miscellaneous" + ], + "Brain": [ + "bodypart", + "miscellaneous" + ], + "Jawbone": [ + "bodypart", + "miscellaneous" + ], + "Eye": [ + "bodypart", + "miscellaneous" + ], + "Horn": [ + "bodypart", + "miscellaneous" + ], + "Tail": [ + "bodypart", + "miscellaneous" + ], + "Flag": [ + "bodypart", + "miscellaneous" + ], + "Fang": [ + "bodypart", + "miscellaneous" + ], + "Quill": [ + "bodypart", + "miscellaneous" + ], + "Soul": [ + "bodypart", + "miscellaneous" + ], + "Scalp": [ + "bodypart", + "miscellaneous" + ], + "Spleen": [ + "bodypart", + "miscellaneous" + ], + "Key": [ + "key", + "miscellaneous" + ], + "The Black Tower Key": [ + "key", + "miscellaneous" + ], + "Potion of Life": [ + "quest" + ], + "A Jade Figurine": [ + "quest" + ], + "The Golden Bird": [ + "quest" + ], + "Lam Esen's Tome": [ + "quest" + ], + "Horadric Cube": [ + "quest" + ], + "Horadric Scroll": [ + "quest" + ], + "Mephisto's Soulstone": [ + "quest" + ], + "Book of Skill": [ + "quest" + ], + "Khalim's Eye": [ + "quest" + ], + "Khalim's Heart": [ + "quest" + ], + "Khalim's Brain": [ + "quest" + ], + "Ear": [ + "playerbodypart", + "miscellaneous" + ], + "Chipped Amethyst": [ + "amethyst", + "gem" + ], + "Flawed Amethyst": [ + "amethyst", + "gem" + ], + "Amethyst": [ + "amethyst", + "gem" + ], + "Flawless Amethyst": [ + "amethyst", + "gem" + ], + "Perfect Amethyst": [ + "amethyst", + "gem" + ], + "Chipped Topaz": [ + "topaz", + "gem" + ], + "Flawed Topaz": [ + "topaz", + "gem" + ], + "Topaz": [ + "topaz", + "gem" + ], + "Flawless Topaz": [ + "topaz", + "gem" + ], + "Perfect Topaz": [ + "topaz", + "gem" + ], + "Chipped Sapphire": [ + "sapphire", + "gem" + ], + "Flawed Sapphire": [ + "sapphire", + "gem" + ], + "Sapphire": [ + "sapphire", + "gem" + ], + "Flawless Sapphire": [ + "sapphire", + "gem" + ], + "Perfect Sapphire": [ + "sapphire", + "gem" + ], + "Chipped Emerald": [ + "emerald", + "gem" + ], + "Flawed Emerald": [ + "emerald", + "gem" + ], + "Emerald": [ + "emerald", + "gem" + ], + "Flawless Emerald": [ + "emerald", + "gem" + ], + "Perfect Emerald": [ + "emerald", + "gem" + ], + "Chipped Ruby": [ + "ruby", + "gem" + ], + "Flawed Ruby": [ + "ruby", + "gem" + ], + "Ruby": [ + "ruby", + "gem" + ], + "Flawless Ruby": [ + "ruby", + "gem" + ], + "Perfect Ruby": [ + "ruby", + "gem" + ], + "Chipped Diamond": [ + "diamond", + "gem" + ], + "Flawed Diamond": [ + "diamond", + "gem" + ], + "Diamond": [ + "diamond", + "gem" + ], + "Flawless Diamond": [ + "diamond", + "gem" + ], + "Perfect Diamond": [ + "diamond", + "gem" + ], + "Minor Healing Potion": [ + "healingpotion", + "potion" + ], + "Light Healing Potion": [ + "healingpotion", + "potion" + ], + "Healing Potion": [ + "healingpotion", + "potion" + ], + "Greater Healing Potion": [ + "healingpotion", + "potion" + ], + "Super Healing Potion": [ + "healingpotion", + "potion" + ], + "Minor Mana Potion": [ + "manapotion", + "potion" + ], + "Light Mana Potion": [ + "manapotion", + "potion" + ], + "Mana Potion": [ + "manapotion", + "potion" + ], + "Greater Mana Potion": [ + "manapotion", + "potion" + ], + "Super Mana Potion": [ + "manapotion", + "potion" + ], + "Chipped Skull": [ + "skull", + "gem" + ], + "Flawed Skull": [ + "skull", + "gem" + ], + "Skull": [ + "skull", + "gem" + ], + "Flawless Skull": [ + "skull", + "gem" + ], + "Perfect Skull": [ + "skull", + "gem" + ], + "Herb": [ + "herb", + "miscellaneous" + ], + "Small Charm": [ + "smallcharm", + "charm" + ], + "Large Charm": [ + "mediumcharm", + "charm" + ], + "Grand Charm": [ + "largecharm", + "charm" + ], + "El Rune": [ + "rune", + "socketfiller" + ], + "Eld Rune": [ + "rune", + "socketfiller" + ], + "Tir Rune": [ + "rune", + "socketfiller" + ], + "Nef Rune": [ + "rune", + "socketfiller" + ], + "Eth Rune": [ + "rune", + "socketfiller" + ], + "Ith Rune": [ + "rune", + "socketfiller" + ], + "Tal Rune": [ + "rune", + "socketfiller" + ], + "Ral Rune": [ + "rune", + "socketfiller" + ], + "Ort Rune": [ + "rune", + "socketfiller" + ], + "Thul Rune": [ + "rune", + "socketfiller" + ], + "Amn Rune": [ + "rune", + "socketfiller" + ], + "Sol Rune": [ + "rune", + "socketfiller" + ], + "Shael Rune": [ + "rune", + "socketfiller" + ], + "Dol Rune": [ + "rune", + "socketfiller" + ], + "Hel Rune": [ + "rune", + "socketfiller" + ], + "Io Rune": [ + "rune", + "socketfiller" + ], + "Lum Rune": [ + "rune", + "socketfiller" + ], + "Ko Rune": [ + "rune", + "socketfiller" + ], + "Fal Rune": [ + "rune", + "socketfiller" + ], + "Lem Rune": [ + "rune", + "socketfiller" + ], + "Pul Rune": [ + "rune", + "socketfiller" + ], + "Um Rune": [ + "rune", + "socketfiller" + ], + "Mal Rune": [ + "rune", + "socketfiller" + ], + "Ist Rune": [ + "rune", + "socketfiller" + ], + "Gul Rune": [ + "rune", + "socketfiller" + ], + "Vex Rune": [ + "rune", + "socketfiller" + ], + "Ohm Rune": [ + "rune", + "socketfiller" + ], + "Lo Rune": [ + "rune", + "socketfiller" + ], + "Sur Rune": [ + "rune", + "socketfiller" + ], + "Ber Rune": [ + "rune", + "socketfiller" + ], + "Jah Rune": [ + "rune", + "socketfiller" + ], + "Cham Rune": [ + "rune", + "socketfiller" + ], + "Zod Rune": [ + "rune", + "socketfiller" + ], + "Jewel": [ + "jewel", + "socketfiller" + ], + "Malah's Potion": [ + "quest" + ], + "Scroll of Knowledge": [ + "scroll", + "miscellaneous" + ], + "Scroll of Resistance": [ + "quest" + ], + "Key of Terror": [ + "quest" + ], + "Key of Hate": [ + "quest" + ], + "Key of Destruction": [ + "quest" + ], + "Diablo's Horn": [ + "quest" + ], + "Baal's Eye": [ + "quest" + ], + "Mephisto's Brain": [ + "quest" + ], + "Token of Absolution": [ + "quest" + ], + "Twisted Essence of Suffering": [ + "quest" + ], + "Charged Essence of Hatred": [ + "quest" + ], + "Burning Essence of Terror": [ + "quest" + ], + "Festering Essence of Destruction": [ + "quest" + ], + "Standard of Heroes": [ + "quest" + ] +} \ No newline at end of file diff --git a/src/d2r_image/bnip_helpers.py b/src/d2r_image/bnip_helpers.py new file mode 100644 index 000000000..019a6d5d6 --- /dev/null +++ b/src/d2r_image/bnip_helpers.py @@ -0,0 +1,226 @@ +from d2r_image.d2data_lookup import find_base_item_from_magic_item_text, find_pattern_match, find_set_item_by_name, find_unique_item_by_name, get_base, get_rune, is_base, is_rune, is_consumable, get_consumable, get_by_name +from d2r_image.data_models import HoveredItem, ItemQuality +from d2r_image.bnip_data import BNIP_ALIAS_STAT_PATTERNS, NTIP_ALIAS_QUALITY_MAP, PROPS_TO_SKILLID, BNIP_ALIAS_STAT_PATTERNS_NO_INTS, BNIP_ITEM_TYPE_DATA +from d2r_image.processing_data import Runeword +from rapidfuzz.string_metric import levenshtein +from bnip.NTIPAliasType import NTIPAliasType as NTIP_TYPES +from bnip.NTIPAliasStat import NTIPAliasStat as NTIP_STATS +from logger import Logger + +from parse import compile +from functools import cache + +@cache +def compiled_bnip_patterns(): + bnip_patterns = {} + for pattern in BNIP_ALIAS_STAT_PATTERNS.keys(): + bnip_patterns[pattern] = compile(pattern) + return bnip_patterns + + +def basename_to_types(basename: str) -> list[int]: + types=[] + if basename in BNIP_ITEM_TYPE_DATA: + for x in BNIP_ITEM_TYPE_DATA[basename]: + if x in NTIP_TYPES: + types.append(int(NTIP_TYPES[x])) + else: + Logger.error(f"type: {x} does not exist in bnip.NTIPAliasType") + else: + Logger.error(f"basename: {basename} does not exist in BNIP_ITEM_TYPE_DATA") + return types + + +def parse_item(quality, item, _call_count=1): + item_is_identified = True + item_is_ethereal = False + item_modifiers = {} + lines = item.splitlines() + cleaned_lines = [] + + + for line in lines: + if line and 'SELL VALUE' not in line and 'COST' not in line: + cleaned_lines.append(line) + lines = cleaned_lines + for line in lines: + if levenshtein(line, 'UNIDENTIFIED') < 3: + item_is_identified = False + if 'ETHEREAL' in line: + item_is_ethereal = True + if item_is_ethereal and not item_is_identified: + break + if item_is_identified: + for line in lines: + match = find_pattern_match(line) + if match: + # Store the property values + # if match["property_id"] not in parsed_item: + # parsed_item[match["property_id"]] = [] + # parsed_item[match["property_id"]].append(match["property_values"]) + if match["property_id"] not in item_modifiers: + item_modifiers[match["property_id"]] = [] + item_modifiers[match["property_id"]].append(match["property_values"]) + # The first line is usually the item name + # parsed_item["display_name"] = item[0] + # The second line is usually the type. Map it to be sure, (for now just setting to base_type) + # parsed_item["base_item"] = item[1] + # print(lines, item_is_identified) + base_name = lines[1] if item_is_identified and quality not in [ItemQuality.Superior.value, ItemQuality.Gray.value, ItemQuality.Normal.value, ItemQuality.Magic.value, ItemQuality.Crafted.value] else lines[0] + base_name = base_name.upper().replace(' ', '') + base_item = None + if quality == ItemQuality.Magic.value: + base_item = find_base_item_from_magic_item_text(cleaned_lines[0], item_is_identified) + else: + if quality == ItemQuality.Crafted.value and is_rune(base_name): + base_item = get_rune(base_name) + quality = ItemQuality.Rune.value + else: + normalized_base_name = base_name[:8] == "SUPERIOR" and base_name[8:] or base_name # * if superior is prefix, remove it + found_base = get_by_name(normalized_base_name) + if found_base: + base_item = found_base + else: + raise Exception('Unable to find item base for: ' + base_name) + + # Add matches from item data + found_item = None + ntip_alias_stat = None + if item_is_identified: + if quality == ItemQuality.Unique.value: + found_item = find_unique_item_by_name(lines[0].replace(' ', '')) + elif quality == ItemQuality.Set.value: + found_item = find_set_item_by_name(lines[0].replace(' ', '')) + elif quality in [ItemQuality.Superior.value, ItemQuality.Gray.value, ItemQuality.Normal.value, ItemQuality.Rune.value, ItemQuality.Crafted.value]: + found_item = base_item + if not found_item and quality not in [ItemQuality.Magic.value, ItemQuality.Rare.value]: + if quality == ItemQuality.Unique.value: + if not Runeword(lines[0].replace(' ', '')): + raise Exception('0x1 Unable to find item for: ' + lines[0].replace(' ', '')) + quality = ItemQuality.Runeword.value + found_item = { + 'DisplayName': lines[0].replace(' ', '') + } + else: + raise Exception('0x2 Unable to find item for: ' + lines[0].replace(' ', '')) + # parsed_item["item_data_matches"] = find_unique_item_by_name(parsed_item["display_name"]) | find_set_item_by_name(parsed_item["display_name"]) | get_base(parsed_item["base_item"]) + # The next few lines help us determine + ntip_alias_stat = find_bnip_pattern_match(lines) + else: + if quality == ItemQuality.Set.value and len(base_item['sets']) == 1: + found_item = find_set_item_by_name(base_item['sets'][0].replace('_', ' ').upper(), True) + elif quality == ItemQuality.Unique.value and len(base_item['uniques']) == 1: + found_item = find_unique_item_by_name(base_item['uniques'][0].replace('_', ' ').upper(), True) + # print("base_item", base_item) + + # bnip_item = Nip( + # NTIPAliasType=base_item['NTIPAliasType'], + # NTIPAliasClassID = base_item['NTIPAliasClassID'], + # NTIPAliasClass = None if 'item_class' not in base_item else 2 if base_item['item_class'] == 'elite' else 1 if base_item['item_class'] == 'exceptional' else 0, + # NTIPAliasQuality=NTIP_ALIAS_QUALITY_MAP[quality], + # NTIPAliasStat=ntip_alias_stat, + # NTIPAliasFlag={ + # '0x10': item_is_identified, + # '0x4000000': item_is_ethereal + # } + # ) + # d2_data = D2Data( + # BaseItem=base_item, + # Item=found_item, + # ItemModifiers=item_modifiers if item_modifiers else None + # ) + # return { + # 'name': lines[0], + # 'quality': quality, + # 'text': '|'.join(lines), + # 'baseItem': base_item, + # 'item': found_item, + # 'itemModifiers': ntip_alias_stat + # } + # print(found_item, base_item) + name = (found_item and found_item['DisplayName']) or (base_item and base_item['DisplayName']) + if quality in [ItemQuality.Magic.value, ItemQuality.Rare.value]: + if item_is_identified: + name = lines[0] + else: + name = base_item['DisplayName'] + return HoveredItem( + Name=name, + NTIPAliasIdName=lines[0].replace(" ", "").replace("\"", "").replace("'", ""), + Quality=quality, + Text='|'.join(lines), + BaseItem=base_item, + Item=found_item, + NTIPAliasType=basename_to_types(base_item['DisplayName']), + NTIPAliasClassID=base_item['NTIPAliasClassID'], + NTIPAliasClass = 0 if (base_item is None or not 'NTIPAliasClass' in base_item) else base_item['NTIPAliasClass'], + NTIPAliasQuality=NTIP_ALIAS_QUALITY_MAP[quality], + NTIPAliasStat=ntip_alias_stat or {}, + NTIPAliasFlag={ + '0x10': item_is_identified, + '0x400000': item_is_ethereal, + '0x4000000': quality == ItemQuality.Runeword.value + } + ) + +def find_bnip_pattern_match(item_lines): + bnip_alias_stat = {} + + for line in item_lines: + # print(f" line: {line}") # ex: line: LEVEL 6 BASH (35/35 CHARGES) + line_no_ints = ''.join(filter(lambda x: not x.isdigit(), line)).replace('+','').replace('-','') + try: + # check if line exists in pattern dict + pattern = BNIP_ALIAS_STAT_PATTERNS_NO_INTS[line_no_ints] + #Logger.debug(f"{line_no_ints} found in BNIP_ALIAS_STAT_PATTERNS_NO_INTS") + except: + #Logger.error(f"'{line_no_ints}' not found in BNIP_ALIAS_STAT_PATTERNS_NO_INTS, skip") + continue + ntip_alias_keys = BNIP_ALIAS_STAT_PATTERNS[pattern] + if (result := compiled_bnip_patterns()[pattern].parse(line)): + # print(f" result: {result}") # ex: result: + # print(f" ntip_alias_keys: {ntip_alias_keys}") # ex: ntip_alias_keys: ['204,126'] + if len(result.fixed) == 0: # if result exists but there are no parsed items, then the match was likely a plain string; i.e., "HALF FREEZE DURATION" + for ntip_alias_key in ntip_alias_keys: + bnip_alias_stat[ntip_alias_key] = 1 + else: + for item_prop_cnt, item_prop in enumerate(result.fixed): + # print(f" item_prop: {item_prop}, item_prop_cnt: {item_prop_cnt}") # ex: item_prop: 6, item_prop_cnt: 0 # ex: item_prop: 35, item_prop_cnt: 1 + try: + if isinstance(ntip_alias_keys[item_prop_cnt], list): + for sub_alias_key in ntip_alias_keys[item_prop_cnt]: + bnip_alias_stat[sub_alias_key] = item_prop + else: + # passivepierce (-x% to enemy y resist) is the only property treated as an opposite to the sign + if "% to enemy" in line.lower() and any([ + NTIP_STATS[x] == ntip_alias_keys[item_prop_cnt] + for x in [ + "passivefirepierce", + "passiveltngpierce", + "passivecoldpierce", + "passivepoispierce", + ] + ]): + item_prop = -1 * item_prop + + # ex: bnip_alias_stat['204,126'] = 6 + bnip_alias_stat[ntip_alias_keys[item_prop_cnt]] = item_prop + + except IndexError: + # more item properties than read fields, skip + pass + # Logger.warning(f"IndexError on line: {line}, ntip_alias_keys: {ntip_alias_keys}, result: {result}, item_prop: {item_prop}, item_prop_cnt: {item_prop_cnt}") + except Exception as e: + Logger.error(f"error {e} on line: {line}, ntip_alias_keys: {ntip_alias_keys}, result: {result}, item_prop: {item_prop}, item_prop_cnt: {item_prop_cnt}") + for key in bnip_alias_stat.copy(): + prop_list = key.split(',') + if len(prop_list) > 1: + # ex: '204,126' = skillbashcharges, '204' = itemchargedskill + # set group stat value (index 0) to skill ID (index 1) + if int(prop_list[0]) in PROPS_TO_SKILLID: + bnip_alias_stat[prop_list[0]] = int(prop_list[1]) + # ex: '83,3' = paladinskills, '83' = itemaddclassskills + # set group stat value (index 0) to value of the parsed property (*+3* to paladin skills) + else: + bnip_alias_stat[prop_list[0]] = bnip_alias_stat[key] + return bnip_alias_stat diff --git a/src/d2r_image/d2data_data.py b/src/d2r_image/d2data_data.py new file mode 100644 index 000000000..b3fe05de5 --- /dev/null +++ b/src/d2r_image/d2data_data.py @@ -0,0 +1,35707 @@ +ITEM_ARMOR = { + "aegis": + { + "DisplayName": "Aegis", + "NTIPAliasClassID": 448, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 92, + "73": 92, + "31": + { + "min": 145, + "max": 161 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["MEDUSASGAZE"], + "NTIPAliasClass": 2 + }, + "aerinshield": + { + "DisplayName": "Aerin Shield", + "NTIPAliasClassID": 411, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "31": + { + "min": 26, + "max": 36 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 0 + }, + "akaranrondache": + { + "DisplayName": "Akaran Rondache", + "NTIPAliasClassID": 479, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "31": + { + "min": 113, + "max": 137 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "akarantarge": + { + "DisplayName": "Akaran Targe", + "NTIPAliasClassID": 478, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 20, + "73": 20, + "31": + { + "min": 101, + "max": 125 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "alphahelm": + { + "DisplayName": "Alpha Helm", + "NTIPAliasClassID": 468, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 52, + "max": 62 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "ancientarmor": + { + "DisplayName": "Ancient Armor", + "NTIPAliasClassID": 326, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 218, + "max": 233 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["MILABREGASROBE"], + "uniques": ["SILKSOFTHEVICTOR"], + "NTIPAliasClass": 0 + }, + "ancientshield": + { + "DisplayName": "Ancient Shield", + "NTIPAliasClassID": 379, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 80, + "73": 80, + "31": + { + "min": 80, + "max": 93 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["RADAMENTSSPHERE"], + "NTIPAliasClass": 1 + }, + "antlers": + { + "DisplayName": "Antlers", + "NTIPAliasClassID": 400, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 18, + "max": 24 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "archonplate": + { + "DisplayName": "Archon Plate", + "NTIPAliasClassID": 443, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 410, + "max": 524 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "armet": + { + "DisplayName": "Armet", + "NTIPAliasClassID": 424, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "31": + { + "min": 105, + "max": 149 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["STEELSHADE", "DARKFEAR"], + "NTIPAliasClass": 2 + }, + "assaulthelmet": + { + "DisplayName": "Assault Helmet", + "NTIPAliasClassID": 406, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 30, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "avengerguard": + { + "DisplayName": "Avenger Guard", + "NTIPAliasClassID": 407, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 55, + "73": 55, + "31": + { + "min": 35, + "max": 50 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["IMMORTALKINGSWILL"], + "NTIPAliasClass": 0 + }, + "balrogskin": + { + "DisplayName": "Balrog Skin", + "NTIPAliasClassID": 437, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "31": + { + "min": 410, + "max": 517 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["SAZABISGHOSTLIBERATOR"], + "uniques": ["ARKAINESVALOR"], + "NTIPAliasClass": 2 + }, + "barbedshield": + { + "DisplayName": "Barbed Shield", + "NTIPAliasClassID": 397, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 55, + "73": 55, + "31": + { + "min": 58, + "max": 78 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["LANCEGUARD"], + "NTIPAliasClass": 1 + }, + "basinet": + { + "DisplayName": "Basinet", + "NTIPAliasClassID": 355, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 30, + "73": 30, + "31": + { + "min": 75, + "max": 84 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["SAZABISMENTALSHEATH"], + "uniques": ["DARKSIGHTHELM"], + "NTIPAliasClass": 1 + }, + "battlebelt": + { + "DisplayName": "Battle Belt", + "NTIPAliasClassID": 393, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 37, + "max": 42 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["WILHELMSPRIDE"], + "uniques": ["SNOWCLASH"], + "NTIPAliasClass": 1 + }, + "battleboots": + { + "DisplayName": "Battle Boots", + "NTIPAliasClassID": 388, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 39, + "max": 47 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["ALDURSADVANCE"], + "uniques": ["WARTRAVELER"], + "NTIPAliasClass": 1 + }, + "battlegauntlets": + { + "DisplayName": "Battle Gauntlets", + "NTIPAliasClassID": 383, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 39, + "max": 47 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["MAVINASICYCLUTCH"], + "uniques": ["LAVAGOUT"], + "NTIPAliasClass": 1 + }, + "belt": + { + "DisplayName": "Belt", + "NTIPAliasClassID": 346, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 5, + "max": 5 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["HSARUSIRONSTAY", "HWANINSBLESSING"], + "uniques": ["NIGHTSMOKE"], + "NTIPAliasClass": 0 + }, + "bladebarrier": + { + "DisplayName": "Blade Barrier", + "NTIPAliasClassID": 467, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 83, + "73": 83, + "31": + { + "min": 147, + "max": 163 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SPIKETHORN"], + "NTIPAliasClass": 2 + }, + "bloodspirit": + { + "DisplayName": "Blood Spirit", + "NTIPAliasClassID": 488, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 101, + "max": 145 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["CEREBUSBITE"], + "NTIPAliasClass": 2 + }, + "bloodlordskull": + { + "DisplayName": "Bloodlord Skull", + "NTIPAliasClassID": 507, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 103, + "max": 148 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["DARKFORCESPAWN"], + "NTIPAliasClass": 2 + }, + "bonehelm": + { + "DisplayName": "Bone Helm", + "NTIPAliasClassID": 349, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 40, + "73": 40, + "31": + { + "min": 33, + "max": 36 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["TANCREDSSKULL"], + "uniques": ["WORMSKULL"], + "NTIPAliasClass": 0 + }, + "boneshield": + { + "DisplayName": "Bone Shield", + "NTIPAliasClassID": 350, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 40, + "73": 40, + "31": + { + "min": 10, + "max": 30 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["WALLOFTHEEYELESS"], + "NTIPAliasClass": 0 + }, + "bonevisage": + { + "DisplayName": "Bone Visage", + "NTIPAliasClassID": 465, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 40, + "73": 40, + "31": + { + "min": 100, + "max": 157 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["TRANGOULSGUISE"], + "uniques": ["GIANTSKULL"], + "NTIPAliasClass": 2 + }, + "boneweave": + { + "DisplayName": "Boneweave", + "NTIPAliasClassID": 435, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 45, + "73": 45, + "31": + { + "min": 399, + "max": 505 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "boneweaveboots": + { + "DisplayName": "Boneweave Boots", + "NTIPAliasClassID": 457, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 59, + "max": 67 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["MARROWWALK"], + "NTIPAliasClass": 2 + }, + "boots": + { + "DisplayName": "Boots", + "NTIPAliasClassID": 339, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 2, + "max": 3 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["TANCREDSHOBNAILS"], + "uniques": ["HOTSPUR"], + "NTIPAliasClass": 0 + }, + "bramblemitts": + { + "DisplayName": "Bramble Mitts", + "NTIPAliasClassID": 450, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 54, + "max": 62 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["LAYINGOFHANDS"], + "NTIPAliasClass": 2 + }, + "breastplate": + { + "DisplayName": "Breast Plate", + "NTIPAliasClassID": 320, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 65, + "max": 68 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["ISENHARTSCASE"], + "uniques": ["VENOMWARD"], + "NTIPAliasClass": 0 + }, + "buckler": + { + "DisplayName": "Buckler", + "NTIPAliasClassID": 328, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 12, + "73": 12, + "31": + { + "min": 4, + "max": 6 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["HSARUSIRONFIST"], + "uniques": ["PELTALUNATA"], + "NTIPAliasClass": 0 + }, + "cantortrophy": + { + "DisplayName": "Cantor Trophy", + "NTIPAliasClassID": 486, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 50, + "max": 64 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["TRANGOULSWING"], + "NTIPAliasClass": 1 + }, + "cap": + { + "DisplayName": "Cap", + "NTIPAliasClassID": 306, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 12, + "73": 12, + "31": + { + "min": 3, + "max": 5 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["INFERNALCRANIUM", "SANDERSPARAGON"], + "uniques": ["BIGGINSBONNET"], + "NTIPAliasClass": 0 + }, + "carnagehelm": + { + "DisplayName": "Carnage Helm", + "NTIPAliasClassID": 493, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 25, + "73": 25, + "31": + { + "min": 102, + "max": 147 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "casque": + { + "DisplayName": "Casque", + "NTIPAliasClassID": 354, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "31": + { + "min": 63, + "max": 72 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["STEALSKULL"], + "NTIPAliasClass": 1 + }, + "chainboots": + { + "DisplayName": "Chain Boots", + "NTIPAliasClassID": 341, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 8, + "max": 9 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["HSARUSIRONHEEL"], + "uniques": ["TREADSOFCTHON"], + "NTIPAliasClass": 0 + }, + "chaingloves": + { + "DisplayName": "Chain Gloves", + "NTIPAliasClassID": 336, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 8, + "max": 9 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["CLEGLAWSPINCERS"], + "uniques": ["CHANCEGUARDS"], + "NTIPAliasClass": 0 + }, + "chainmail": + { + "DisplayName": "Chain Mail", + "NTIPAliasClassID": 319, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 45, + "73": 45, + "31": + { + "min": 72, + "max": 75 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["CATHANSMESH"], + "uniques": ["SPARKINGMAIL"], + "NTIPAliasClass": 0 + }, + "chaosarmor": + { + "DisplayName": "Chaos Armor", + "NTIPAliasClassID": 371, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 70, + "73": 70, + "31": + { + "min": 315, + "max": 342 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["TRANGOULSSCALES"], + "uniques": ["BLACKHADES"], + "NTIPAliasClass": 1 + }, + "circlet": + { + "DisplayName": "Circlet", + "NTIPAliasClassID": 418, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 35, + "73": 35, + "31": + { + "min": 20, + "max": 30 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["NAJSCIRCLET"], + "NTIPAliasClass": 0 + }, + "colossusgirdle": + { + "DisplayName": "Colossus Girdle", + "NTIPAliasClassID": 464, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 61, + "max": 71 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "NTIPAliasClass": 2 + }, + "conquerorcrown": + { + "DisplayName": "Conqueror Crown", + "NTIPAliasClassID": 496, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 114, + "max": 159 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["HALABERDSREIGN"], + "NTIPAliasClass": 2 + }, + "corona": + { + "DisplayName": "Corona", + "NTIPAliasClassID": 427, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 111, + "max": 165 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["GRISWOLDSVALOR"], + "uniques": ["CROWNOFAGES"], + "NTIPAliasClass": 2 + }, + "coronet": + { + "DisplayName": "Coronet", + "NTIPAliasClassID": 419, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 30, + "73": 30, + "31": + { + "min": 30, + "max": 40 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "crown": + { + "DisplayName": "Crown", + "NTIPAliasClassID": 311, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 25, + "max": 45 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["IRATHASCOIL", "MILABREGASDIADEM"], + "uniques": ["UNDEADCROWN"], + "NTIPAliasClass": 0 + }, + "crownshield": + { + "DisplayName": "Crown Shield", + "NTIPAliasClassID": 412, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 30, + "max": 40 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "crusadergauntlets": + { + "DisplayName": "Crusader Gauntlets", + "NTIPAliasClassID": 453, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 59, + "max": 68 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "cuirass": + { + "DisplayName": "Cuirass", + "NTIPAliasClassID": 366, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 188, + "max": 202 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["HAEMOSUSADAMANT"], + "uniques": ["DURIELSSHELL"], + "NTIPAliasClass": 1 + }, + "deathmask": + { + "DisplayName": "Death Mask", + "NTIPAliasClassID": 358, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 54, + "max": 86 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["TALRASHASHORADRICCREST"], + "uniques": ["BLACKHORNSFACE"], + "NTIPAliasClass": 1 + }, + "defender": + { + "DisplayName": "Defender", + "NTIPAliasClassID": 374, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 68, + "73": 68, + "31": + { + "min": 41, + "max": 49 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["VISCERATUANT"], + "NTIPAliasClass": 1 + }, + "demonhead": + { + "DisplayName": "Demonhead", + "NTIPAliasClassID": 428, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 101, + "max": 154 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["ANDARIELSVISAGE"], + "NTIPAliasClass": 2 + }, + "demonhidearmor": + { + "DisplayName": "Demonhide Armor", + "NTIPAliasClassID": 361, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 28, + "73": 28, + "31": + { + "min": 122, + "max": 136 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SKINOFTHEFLAYEDONE"], + "NTIPAliasClass": 1 + }, + "demonhideboots": + { + "DisplayName": "Demonhide Boots", + "NTIPAliasClassID": 385, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 28, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["RITEOFPASSAGE"], + "uniques": ["INFERNOSTRIDE"], + "NTIPAliasClass": 1 + }, + "demonhidegloves": + { + "DisplayName": "Demonhide Gloves", + "NTIPAliasClassID": 380, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 28, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["VENOMGRIP"], + "NTIPAliasClass": 1 + }, + "demonhidesash": + { + "DisplayName": "Demonhide Sash", + "NTIPAliasClassID": 390, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 29, + "max": 34 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "uniques": ["STRINGOFEARS"], + "NTIPAliasClass": 1 + }, + "destroyerhelm": + { + "DisplayName": "Destroyer Helm", + "NTIPAliasClassID": 495, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 45, + "73": 45, + "31": + { + "min": 111, + "max": 156 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["DEMONHORNSEDGE"], + "NTIPAliasClass": 2 + }, + "diadem": + { + "DisplayName": "Diadem", + "NTIPAliasClassID": 421, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 50, + "max": 60 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["MAVINASTRUESIGHT"], + "uniques": ["GRIFFONSEYE"], + "NTIPAliasClass": 2 + }, + "diamondmail": + { + "DisplayName": "Diamond Mail", + "NTIPAliasClassID": 433, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 26, + "73": 26, + "31": + { + "min": 383, + "max": 489 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "dragonshield": + { + "DisplayName": "Dragon Shield", + "NTIPAliasClassID": 377, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 76, + "73": 76, + "31": + { + "min": 59, + "max": 67 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["TIAMATSREBUKE"], + "NTIPAliasClass": 1 + }, + "dreamspirit": + { + "DisplayName": "Dream Spirit", + "NTIPAliasClassID": 492, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 109, + "max": 159 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "duskshroud": + { + "DisplayName": "Dusk Shroud", + "NTIPAliasClassID": 429, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 20, + "73": 20, + "31": + { + "min": 361, + "max": 467 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["DARKADHERENT"], + "uniques": ["ORMUSROBES"], + "NTIPAliasClass": 2 + }, + "earthspirit": + { + "DisplayName": "Earth Spirit", + "NTIPAliasClassID": 490, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 107, + "max": 152 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["SPIRITKEEPER"], + "NTIPAliasClass": 2 + }, + "embossedplate": + { + "DisplayName": "Embossed Plate", + "NTIPAliasClassID": 370, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 55, + "73": 55, + "31": + { + "min": 282, + "max": 303 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["ATMASWAIL"], + "NTIPAliasClass": 1 + }, + "falconmask": + { + "DisplayName": "Falcon Mask", + "NTIPAliasClassID": 401, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 12, + "max": 28 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "fangedhelm": + { + "DisplayName": "Fanged Helm", + "NTIPAliasClassID": 404, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 35, + "73": 35, + "31": + { + "min": 15, + "max": 20 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "fetishtrophy": + { + "DisplayName": "Fetish Trophy", + "NTIPAliasClassID": 484, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 41, + "max": 52 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "fieldplate": + { + "DisplayName": "Field Plate", + "NTIPAliasClassID": 323, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 48, + "73": 48, + "31": + { + "min": 101, + "max": 105 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["ROCKFLEECE"], + "NTIPAliasClass": 0 + }, + "fullhelm": + { + "DisplayName": "Full Helm", + "NTIPAliasClassID": 309, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 30, + "73": 30, + "31": + { + "min": 23, + "max": 26 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["ISENHARTSHORNS"], + "uniques": ["DUSKDEEP"], + "NTIPAliasClass": 0 + }, + "fullplatemail": + { + "DisplayName": "Full Plate Mail", + "NTIPAliasClassID": 325, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 70, + "73": 70, + "31": + { + "min": 150, + "max": 161 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["TANCREDSSPINE"], + "uniques": ["GOLDSKIN"], + "NTIPAliasClass": 0 + }, + "furyvisor": + { + "DisplayName": "Fury Visor", + "NTIPAliasClassID": 494, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 35, + "73": 35, + "31": + { + "min": 105, + "max": 150 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["WOLFHOWL"], + "NTIPAliasClass": 2 + }, + "gargoylehead": + { + "DisplayName": "Gargoyle Head", + "NTIPAliasClassID": 416, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 10, + "max": 16 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "gauntlets": + { + "DisplayName": "Gauntlets", + "NTIPAliasClassID": 338, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 12, + "max": 15 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["SIGONSGAGE"], + "uniques": ["FROSTBURN"], + "NTIPAliasClass": 0 + }, + "ghostarmor": + { + "DisplayName": "Ghost Armor", + "NTIPAliasClassID": 359, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 102, + "max": 117 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THESPIRITSHROUD"], + "NTIPAliasClass": 1 + }, + "giantconch": + { + "DisplayName": "Giant Conch", + "NTIPAliasClassID": 425, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 30, + "73": 30, + "31": + { + "min": 110, + "max": 154 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "gildedshield": + { + "DisplayName": "Gilded Shield", + "NTIPAliasClassID": 481, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "31": + { + "min": 144, + "max": 168 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["HERALDOFZAKARUM"], + "NTIPAliasClass": 1 + }, + "gothicplate": + { + "DisplayName": "Gothic Plate", + "NTIPAliasClassID": 324, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 55, + "73": 55, + "31": + { + "min": 128, + "max": 135 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["SIGONSSHELTER"], + "uniques": ["RATTLECAGE"], + "NTIPAliasClass": 0 + }, + "gothicshield": + { + "DisplayName": "Gothic Shield", + "NTIPAliasClassID": 333, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 40, + "73": 40, + "31": + { + "min": 30, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "sets": ["ISENHARTSPARRY"], + "uniques": ["THEWARD"], + "NTIPAliasClass": 0 + }, + "grandcrown": + { + "DisplayName": "Grand Crown", + "NTIPAliasClassID": 357, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 78, + "max": 113 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["HWANINSSPLENDOR"], + "uniques": ["CROWNOFTHIEVES"], + "NTIPAliasClass": 1 + }, + "greathauberk": + { + "DisplayName": "Great Hauberk", + "NTIPAliasClassID": 436, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "31": + { + "min": 395, + "max": 501 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "greathelm": + { + "DisplayName": "Great Helm", + "NTIPAliasClassID": 310, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 40, + "73": 40, + "31": + { + "min": 30, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["SIGONSVISOR"], + "uniques": ["HOWLTUSK"], + "NTIPAliasClass": 0 + }, + "greaves": + { + "DisplayName": "Greaves", + "NTIPAliasClassID": 343, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 12, + "max": 15 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["SIGONSSABOT"], + "uniques": ["TEARHAUNCH"], + "NTIPAliasClass": 0 + }, + "griffonheaddress": + { + "DisplayName": "Griffon Headdress", + "NTIPAliasClassID": 469, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 46, + "max": 68 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "grimhelm": + { + "DisplayName": "Grim Helm", + "NTIPAliasClassID": 395, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 40, + "73": 40, + "31": + { + "min": 60, + "max": 125 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["NATALYASTOTEM"], + "uniques": ["VAMPIREGAZE"], + "NTIPAliasClass": 1 + }, + "grimshield": + { + "DisplayName": "Grim Shield", + "NTIPAliasClassID": 396, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 70, + "73": 70, + "31": + { + "min": 50, + "max": 150 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["LIDLESSWALL"], + "NTIPAliasClass": 1 + }, + "guardiancrown": + { + "DisplayName": "Guardian Crown", + "NTIPAliasClassID": 497, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 55, + "73": 55, + "31": + { + "min": 117, + "max": 168 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "hardleatherarmor": + { + "DisplayName": "Hard Leather Armor", + "NTIPAliasClassID": 315, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 28, + "73": 28, + "31": + { + "min": 21, + "max": 24 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THECENTURION"], + "NTIPAliasClass": 0 + }, + "hawkhelm": + { + "DisplayName": "Hawk Helm", + "NTIPAliasClassID": 399, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 4, + "max": 15 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "heater": + { + "DisplayName": "Heater", + "NTIPAliasClassID": 444, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 88, + "73": 88, + "31": + { + "min": 95, + "max": 110 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "heavybelt": + { + "DisplayName": "Heavy Belt", + "NTIPAliasClassID": 347, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 6, + "max": 6 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["INFERNALSIGN", "IRATHASCORD"], + "uniques": ["GOLDWRAP"], + "NTIPAliasClass": 0 + }, + "heavyboots": + { + "DisplayName": "Heavy Boots", + "NTIPAliasClassID": 340, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 5, + "max": 6 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["COWKINGSHOOVES", "SANDERSRIPRAP"], + "uniques": ["GOREFOOT"], + "NTIPAliasClass": 0 + }, + "heavybracers": + { + "DisplayName": "Heavy Bracers", + "NTIPAliasClassID": 382, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 37, + "max": 44 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["TRANGOULSCLAWS"], + "uniques": ["GHOULHIDE"], + "NTIPAliasClass": 1 + }, + "heavygloves": + { + "DisplayName": "Heavy Gloves", + "NTIPAliasClassID": 335, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 5, + "max": 6 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["SANDERSTABOO"], + "uniques": ["BLOODFIST"], + "NTIPAliasClass": 0 + }, + "hellforgeplate": + { + "DisplayName": "Hellforge Plate", + "NTIPAliasClassID": 438, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 421, + "max": 530 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["NAJSLIGHTPLATE"], + "NTIPAliasClass": 2 + }, + "hellspawnskull": + { + "DisplayName": "Hellspawn Skull", + "NTIPAliasClassID": 504, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 96, + "max": 141 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "helm": + { + "DisplayName": "Helm", + "NTIPAliasClassID": 308, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "31": + { + "min": 15, + "max": 18 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["BERSERKERSHEADGEAR"], + "uniques": ["COIFOFGLORY"], + "NTIPAliasClass": 0 + }, + "heraldicshield": + { + "DisplayName": "Heraldic Shield", + "NTIPAliasClassID": 410, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "31": + { + "min": 16, + "max": 26 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 0 + }, + "hierophanttrophy": + { + "DisplayName": "Hierophant Trophy", + "NTIPAliasClassID": 487, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 58, + "max": 70 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["HOMUNCULUS"], + "NTIPAliasClass": 1 + }, + "hornedhelm": + { + "DisplayName": "Horned Helm", + "NTIPAliasClassID": 405, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 45, + "73": 45, + "31": + { + "min": 25, + "max": 30 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "huntersguise": + { + "DisplayName": "Hunter's Guise", + "NTIPAliasClassID": 470, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 67, + "max": 81 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["ALDURSSTONYGAZE"], + "NTIPAliasClass": 1 + }, + "hydraskull": + { + "DisplayName": "Hydraskull", + "NTIPAliasClassID": 423, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 18, + "73": 18, + "31": + { + "min": 101, + "max": 145 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "hyperion": + { + "DisplayName": "Hyperion", + "NTIPAliasClassID": 446, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 82, + "73": 82, + "31": + { + "min": 119, + "max": 135 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "jawbonecap": + { + "DisplayName": "Jawbone Cap", + "NTIPAliasClassID": 403, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 25, + "73": 25, + "31": + { + "min": 10, + "max": 15 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "jawbonevisor": + { + "DisplayName": "Jawbone Visor", + "NTIPAliasClassID": 473, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 25, + "73": 25, + "31": + { + "min": 55, + "max": 68 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "kiteshield": + { + "DisplayName": "Kite Shield", + "NTIPAliasClassID": 331, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "31": + { + "min": 16, + "max": 18 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["MILABREGASORB"], + "uniques": ["STEELCLASH"], + "NTIPAliasClass": 0 + }, + "krakenshell": + { + "DisplayName": "Kraken Shell", + "NTIPAliasClassID": 439, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 48, + "73": 48, + "31": + { + "min": 417, + "max": 523 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["MAVINASEMBRACE"], + "uniques": ["LEVIATHAN"], + "NTIPAliasClass": 2 + }, + "kurastshield": + { + "DisplayName": "Kurast Shield", + "NTIPAliasClassID": 500, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 55, + "73": 55, + "31": + { + "min": 154, + "max": 172 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "lacqueredplate": + { + "DisplayName": "Lacquered Plate", + "NTIPAliasClassID": 440, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 55, + "73": 55, + "31": + { + "min": 433, + "max": 541 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["TALRASHASGUARDIANSHIP"], + "NTIPAliasClass": 2 + }, + "largeshield": + { + "DisplayName": "Large Shield", + "NTIPAliasClassID": 330, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 24, + "73": 24, + "31": + { + "min": 12, + "max": 14 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["CIVERBSWARD"], + "uniques": ["STORMGUILD"], + "NTIPAliasClass": 0 + }, + "leatherarmor": + { + "DisplayName": "Leather Armor", + "NTIPAliasClassID": 314, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "31": + { + "min": 14, + "max": 17 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["VIDALASAMBUSH"], + "uniques": ["BLINKBATSFORM"], + "NTIPAliasClass": 0 + }, + "leathergloves": + { + "DisplayName": "Leather Gloves", + "NTIPAliasClassID": 334, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 2, + "max": 3 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["DEATHSHAND"], + "uniques": ["THEHANDOFBROC"], + "NTIPAliasClass": 0 + }, + "lightbelt": + { + "DisplayName": "Light Belt", + "NTIPAliasClassID": 345, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 3, + "max": 3 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["ARCTICBINDING"], + "uniques": ["SNAKECORD"], + "NTIPAliasClass": 0 + }, + "lightgauntlets": + { + "DisplayName": "Light Gauntlets", + "NTIPAliasClassID": 337, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 9, + "max": 11 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["ARCTICMITTS", "IRATHASCUFF"], + "uniques": ["MAGEFIST"], + "NTIPAliasClass": 0 + }, + "lightplate": + { + "DisplayName": "Light Plate", + "NTIPAliasClassID": 327, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "31": + { + "min": 90, + "max": 107 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["ARCANNASFLESH"], + "uniques": ["HEAVENLYGARB"], + "NTIPAliasClass": 0 + }, + "lightplatedboots": + { + "DisplayName": "Light Plated Boots", + "NTIPAliasClassID": 342, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 9, + "max": 11 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["VIDALASFETLOCK"], + "uniques": ["GOBLINTOE"], + "NTIPAliasClass": 0 + }, + "linkedmail": + { + "DisplayName": "Linked Mail", + "NTIPAliasClassID": 363, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 26, + "73": 26, + "31": + { + "min": 158, + "max": 172 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SPIRITFORGE"], + "NTIPAliasClass": 1 + }, + "lionhelm": + { + "DisplayName": "Lion Helm", + "NTIPAliasClassID": 474, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 35, + "73": 35, + "31": + { + "min": 63, + "max": 75 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "loricatedmail": + { + "DisplayName": "Loricated Mail", + "NTIPAliasClassID": 434, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 36, + "73": 36, + "31": + { + "min": 390, + "max": 496 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["NATALYASSHADOW"], + "NTIPAliasClass": 2 + }, + "luna": + { + "DisplayName": "Luna", + "NTIPAliasClassID": 445, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 84, + "73": 84, + "31": + { + "min": 108, + "max": 123 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["BLACKOAKSHIELD"], + "NTIPAliasClass": 2 + }, + "mageplate": + { + "DisplayName": "Mage Plate", + "NTIPAliasClassID": 373, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "31": + { + "min": 225, + "max": 261 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["QUEHEGANSWISDOM"], + "NTIPAliasClass": 1 + }, + "mask": + { + "DisplayName": "Mask", + "NTIPAliasClassID": 312, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 9, + "max": 27 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["CATHANSVISAGE"], + "uniques": ["THEFACEOFHORROR"], + "NTIPAliasClass": 0 + }, + "mesharmor": + { + "DisplayName": "Mesh Armor", + "NTIPAliasClassID": 365, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 45, + "73": 45, + "31": + { + "min": 198, + "max": 213 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SHAFTSTOP"], + "NTIPAliasClass": 1 + }, + "meshbelt": + { + "DisplayName": "Mesh Belt", + "NTIPAliasClassID": 392, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 35, + "max": 40 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["TALRASHASFINESPUNCLOTH"], + "uniques": ["GLOOMSTRAP"], + "NTIPAliasClass": 1 + }, + "meshboots": + { + "DisplayName": "Mesh Boots", + "NTIPAliasClassID": 387, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 37, + "max": 44 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["NATALYASSOUL"], + "uniques": ["SILKWEAVE"], + "NTIPAliasClass": 1 + }, + "minionskull": + { + "DisplayName": "Minion Skull", + "NTIPAliasClassID": 503, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 95, + "max": 139 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "mirroredboots": + { + "DisplayName": "Mirrored Boots", + "NTIPAliasClassID": 458, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 59, + "max": 68 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "mithrilcoil": + { + "DisplayName": "Mithril Coil", + "NTIPAliasClassID": 462, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 58, + "max": 65 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["CREDENDUM"], + "uniques": ["VERDUNGOSHEARTYCORD"], + "NTIPAliasClass": 2 + }, + "monarch": + { + "DisplayName": "Monarch", + "NTIPAliasClassID": 447, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 86, + "73": 86, + "31": + { + "min": 133, + "max": 148 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["STORMSHIELD"], + "NTIPAliasClass": 2 + }, + "mummifiedtrophy": + { + "DisplayName": "Mummified Trophy", + "NTIPAliasClassID": 483, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 38, + "max": 48 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "myrmidongreaves": + { + "DisplayName": "Myrmidon Greaves", + "NTIPAliasClassID": 459, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 62, + "max": 71 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["SHADOWDANCER"], + "NTIPAliasClass": 2 + }, + "ogregauntlets": + { + "DisplayName": "Ogre Gauntlets", + "NTIPAliasClassID": 454, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 62, + "max": 71 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["STEELREND"], + "NTIPAliasClass": 2 + }, + "ornateplate": + { + "DisplayName": "Ornate Plate", + "NTIPAliasClassID": 372, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 417, + "max": 450 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["GRISWOLDSHEART"], + "uniques": ["CORPSEMOURN"], + "NTIPAliasClass": 1 + }, + "overseerskull": + { + "DisplayName": "Overseer Skull", + "NTIPAliasClassID": 505, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 98, + "max": 142 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "pavise": + { + "DisplayName": "Pavise", + "NTIPAliasClassID": 378, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 72, + "73": 72, + "31": + { + "min": 68, + "max": 78 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["GERKESSANCTUARY"], + "NTIPAliasClass": 1 + }, + "platemail": + { + "DisplayName": "Plate Mail", + "NTIPAliasClassID": 322, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 60, + "73": 60, + "31": + { + "min": 108, + "max": 116 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["BONEFLESH"], + "NTIPAliasClass": 0 + }, + "platedbelt": + { + "DisplayName": "Plated Belt", + "NTIPAliasClassID": 348, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 8, + "max": 11 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["SIGONSWRAP"], + "uniques": ["BLADEBUCKLE"], + "NTIPAliasClass": 0 + }, + "preservedhead": + { + "DisplayName": "Preserved Head", + "NTIPAliasClassID": 413, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 2, + "max": 5 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "protectorshield": + { + "DisplayName": "Protector Shield", + "NTIPAliasClassID": 480, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "31": + { + "min": 129, + "max": 153 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 1 + }, + "quiltedarmor": + { + "DisplayName": "Quilted Armor", + "NTIPAliasClassID": 313, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 8, + "max": 11 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["ARCTICFURS"], + "uniques": ["GREYFORM"], + "NTIPAliasClass": 0 + }, + "ragemask": + { + "DisplayName": "Rage Mask", + "NTIPAliasClassID": 475, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 45, + "73": 45, + "31": + { + "min": 78, + "max": 90 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "ringmail": + { + "DisplayName": "Ring Mail", + "NTIPAliasClassID": 317, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 26, + "73": 26, + "31": + { + "min": 45, + "max": 48 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["ANGELICMANTLE"], + "uniques": ["DARKGLOW"], + "NTIPAliasClass": 0 + }, + "rondache": + { + "DisplayName": "Rondache", + "NTIPAliasClassID": 409, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "31": + { + "min": 10, + "max": 18 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "roundshield": + { + "DisplayName": "Round Shield", + "NTIPAliasClassID": 375, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 64, + "73": 64, + "31": + { + "min": 47, + "max": 55 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["WHITSTANSGUARD"], + "uniques": ["MOSERSBLESSEDCIRCLE"], + "NTIPAliasClass": 1 + }, + "royalshield": + { + "DisplayName": "Royal Shield", + "NTIPAliasClassID": 482, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 156, + "max": 181 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "russetarmor": + { + "DisplayName": "Russet Armor", + "NTIPAliasClassID": 367, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "31": + { + "min": 225, + "max": 243 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SKULLDERSIRE"], + "NTIPAliasClass": 1 + }, + "sacredarmor": + { + "DisplayName": "Sacred Armor", + "NTIPAliasClassID": 442, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 60, + "73": 60, + "31": + { + "min": 487, + "max": 600 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["IMMORTALKINGSSOULCAGE"], + "uniques": ["TYRAELSMIGHT", "TEMPLARSMIGHT"], + "NTIPAliasClass": 2 + }, + "sacredfeathers": + { + "DisplayName": "Sacred Feathers", + "NTIPAliasClassID": 471, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 58, + "max": 87 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "sacredrondache": + { + "DisplayName": "Sacred Rondache", + "NTIPAliasClassID": 499, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 68, + "73": 68, + "31": + { + "min": 138, + "max": 164 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["ALMANEGRA"], + "NTIPAliasClass": 2 + }, + "sacredtarge": + { + "DisplayName": "Sacred Targe", + "NTIPAliasClassID": 498, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 45, + "73": 45, + "31": + { + "min": 126, + "max": 158 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "sallet": + { + "DisplayName": "Sallet", + "NTIPAliasClassID": 353, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 18, + "73": 18, + "31": + { + "min": 52, + "max": 62 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["ROCKSTOPPER"], + "NTIPAliasClass": 1 + }, + "sash": + { + "DisplayName": "Sash", + "NTIPAliasClassID": 344, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 2, + "max": 2 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["DEATHSGUARD"], + "uniques": ["LENYMO"], + "NTIPAliasClass": 0 + }, + "savagehelmet": + { + "DisplayName": "Savage Helmet", + "NTIPAliasClassID": 476, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "31": + { + "min": 85, + "max": 98 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "scalemail": + { + "DisplayName": "Scale Mail", + "NTIPAliasClassID": 318, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 36, + "73": 36, + "31": + { + "min": 57, + "max": 60 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HAWKMAIL"], + "NTIPAliasClass": 0 + }, + "scarabhusk": + { + "DisplayName": "Scarab Husk", + "NTIPAliasClassID": 431, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 28, + "73": 28, + "31": + { + "min": 369, + "max": 474 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "scarabshellboots": + { + "DisplayName": "Scarabshell Boots", + "NTIPAliasClassID": 456, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 56, + "max": 65 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["SANDSTORMTREK"], + "NTIPAliasClass": 2 + }, + "scutum": + { + "DisplayName": "Scutum", + "NTIPAliasClassID": 376, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 62, + "73": 62, + "31": + { + "min": 53, + "max": 61 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["STORMCHASER"], + "NTIPAliasClass": 1 + }, + "serpentskinarmor": + { + "DisplayName": "Serpentskin Armor", + "NTIPAliasClassID": 360, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "31": + { + "min": 111, + "max": 126 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SKINOFTHEVIPERMAGI"], + "NTIPAliasClass": 1 + }, + "sextontrophy": + { + "DisplayName": "Sexton Trophy", + "NTIPAliasClassID": 485, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 44, + "max": 55 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 1 + }, + "shadowplate": + { + "DisplayName": "Shadow Plate", + "NTIPAliasClassID": 441, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 70, + "73": 70, + "31": + { + "min": 446, + "max": 557 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["ALDURSDECEPTION"], + "uniques": ["STEELCARAPACE"], + "NTIPAliasClass": 2 + }, + "shako": + { + "DisplayName": "Shako", + "NTIPAliasClassID": 422, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 12, + "73": 12, + "31": + { + "min": 98, + "max": 141 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["HARLEQUINCREST"], + "NTIPAliasClass": 2 + }, + "sharkskinbelt": + { + "DisplayName": "Sharkskin Belt", + "NTIPAliasClassID": 391, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 31, + "max": 36 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["MAVINASTENET"], + "uniques": ["RAZORTAIL"], + "NTIPAliasClass": 1 + }, + "sharkskinboots": + { + "DisplayName": "Sharkskin Boots", + "NTIPAliasClassID": 386, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 33, + "max": 39 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["WATERWALK"], + "NTIPAliasClass": 1 + }, + "sharkskingloves": + { + "DisplayName": "Sharkskin Gloves", + "NTIPAliasClassID": 381, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 33, + "max": 39 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["MAGNUSSKIN"], + "uniques": ["GRAVEPALM"], + "NTIPAliasClass": 1 + }, + "sharktootharmor": + { + "DisplayName": "Sharktooth Armor", + "NTIPAliasClassID": 369, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 48, + "73": 48, + "31": + { + "min": 242, + "max": 258 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["TOOTHROW"], + "NTIPAliasClass": 1 + }, + "skullcap": + { + "DisplayName": "Skull Cap", + "NTIPAliasClassID": 307, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 18, + "73": 18, + "31": + { + "min": 8, + "max": 11 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["ARCANNASHEAD"], + "uniques": ["TARNHELM"], + "NTIPAliasClass": 0 + }, + "skyspirit": + { + "DisplayName": "Sky Spirit", + "NTIPAliasClassID": 491, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 103, + "max": 155 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["RAVENLORE"], + "NTIPAliasClass": 2 + }, + "slayerguard": + { + "DisplayName": "Slayer Guard", + "NTIPAliasClassID": 477, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 55, + "73": 55, + "31": + { + "min": 93, + "max": 120 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["ARREATSFACE"], + "NTIPAliasClass": 1 + }, + "smallshield": + { + "DisplayName": "Small Shield", + "NTIPAliasClassID": 329, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 16, + "73": 16, + "31": + { + "min": 8, + "max": 10 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["CLEGLAWSCLAW"], + "uniques": ["UMBRALDISK"], + "NTIPAliasClass": 0 + }, + "spiderwebsash": + { + "DisplayName": "Spiderweb Sash", + "NTIPAliasClassID": 460, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 55, + "max": 62 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "uniques": ["ARACHNIDMESH"], + "NTIPAliasClass": 2 + }, + "spikedshield": + { + "DisplayName": "Spiked Shield", + "NTIPAliasClassID": 351, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 40, + "73": 40, + "31": + { + "min": 15, + "max": 25 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SWORDBACKHOLD"], + "NTIPAliasClass": 0 + }, + "spiredhelm": + { + "DisplayName": "Spired Helm", + "NTIPAliasClassID": 426, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 40, + "73": 40, + "31": + { + "min": 114, + "max": 159 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["ONDALSALMIGHTY"], + "uniques": ["VEILOFSTEEL", "NIGHTWINGSVEIL"], + "NTIPAliasClass": 2 + }, + "spiritmask": + { + "DisplayName": "Spirit Mask", + "NTIPAliasClassID": 402, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 22, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "splintmail": + { + "DisplayName": "Splint Mail", + "NTIPAliasClassID": 321, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 30, + "73": 30, + "31": + { + "min": 90, + "max": 95 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["BERSERKERSHAUBERK"], + "uniques": ["ICEBLINK"], + "NTIPAliasClass": 0 + }, + "studdedleather": + { + "DisplayName": "Studded Leather", + "NTIPAliasClassID": 316, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "31": + { + "min": 32, + "max": 35 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["COWKINGSHIDE"], + "uniques": ["TWITCHTHROE"], + "NTIPAliasClass": 0 + }, + "succubusskull": + { + "DisplayName": "Succubus Skull", + "NTIPAliasClassID": 506, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 100, + "max": 146 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["BONEFLAME"], + "NTIPAliasClass": 2 + }, + "sunspirit": + { + "DisplayName": "Sun Spirit", + "NTIPAliasClassID": 489, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 98, + "max": 147 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "targe": + { + "DisplayName": "Targe", + "NTIPAliasClassID": 408, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 20, + "73": 20, + "31": + { + "min": 8, + "max": 12 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "templarcoat": + { + "DisplayName": "Templar Coat", + "NTIPAliasClassID": 368, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "31": + { + "min": 252, + "max": 274 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["GUARDIANANGEL"], + "NTIPAliasClass": 1 + }, + "tiara": + { + "DisplayName": "Tiara", + "NTIPAliasClassID": 420, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 25, + "73": 25, + "31": + { + "min": 40, + "max": 50 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["KIRASGUARDIAN"], + "NTIPAliasClass": 1 + }, + "tigulatedmail": + { + "DisplayName": "Tigulated Mail", + "NTIPAliasClassID": 364, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 36, + "73": 36, + "31": + { + "min": 176, + "max": 190 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["HWANINSREFUGE"], + "uniques": ["CROWCAW"], + "NTIPAliasClass": 1 + }, + "totemicmask": + { + "DisplayName": "Totemic Mask", + "NTIPAliasClassID": 472, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 73, + "max": 98 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["JALALSMANE"], + "NTIPAliasClass": 1 + }, + "towershield": + { + "DisplayName": "Tower Shield", + "NTIPAliasClassID": 332, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "31": + { + "min": 22, + "max": 25 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["SIGONSGUARD"], + "uniques": ["BVERRITKEEP"], + "NTIPAliasClass": 0 + }, + "trellisedarmor": + { + "DisplayName": "Trellised Armor", + "NTIPAliasClassID": 362, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "31": + { + "min": 138, + "max": 153 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["IRONPELT"], + "NTIPAliasClass": 1 + }, + "trollbelt": + { + "DisplayName": "Troll Belt", + "NTIPAliasClassID": 463, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "31": + { + "min": 59, + "max": 66 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["TRANGOULSGIRTH"], + "NTIPAliasClass": 2 + }, + "trollnest": + { + "DisplayName": "Troll Nest", + "NTIPAliasClassID": 466, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 74, + "73": 74, + "31": + { + "min": 158, + "max": 173 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HEADHUNTERSGLORY"], + "NTIPAliasClass": 2 + }, + "unravellerhead": + { + "DisplayName": "Unraveller Head", + "NTIPAliasClassID": 415, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 6, + "max": 10 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "vambraces": + { + "DisplayName": "Vambraces", + "NTIPAliasClassID": 452, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "31": + { + "min": 59, + "max": 67 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["SOULDRAINER"], + "NTIPAliasClass": 2 + }, + "vampirebonegloves": + { + "DisplayName": "Vampirebone Gloves", + "NTIPAliasClassID": 451, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 56, + "max": 65 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "uniques": ["DRACULSGRASP"], + "NTIPAliasClass": 2 + }, + "vampirefangbelt": + { + "DisplayName": "Vampirefang Belt", + "NTIPAliasClassID": 461, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "31": + { + "min": 56, + "max": 63 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "uniques": ["NOSFERATUSCOIL"], + "NTIPAliasClass": 2 + }, + "vortexshield": + { + "DisplayName": "Vortex Shield", + "NTIPAliasClassID": 502, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 90, + "73": 90, + "31": + { + "min": 182, + "max": 225 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["GRISWOLDSHONOR"], + "NTIPAliasClass": 2 + }, + "warbelt": + { + "DisplayName": "War Belt", + "NTIPAliasClassID": 394, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 41, + "max": 52 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 1], + "sets": ["IMMORTALKINGSDETAIL"], + "uniques": ["THUNDERGODSVIGOR"], + "NTIPAliasClass": 1 + }, + "warboots": + { + "DisplayName": "War Boots", + "NTIPAliasClassID": 389, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 43, + "max": 53 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["IMMORTALKINGSPILLAR"], + "uniques": ["GORERIDER"], + "NTIPAliasClass": 1 + }, + "wargauntlets": + { + "DisplayName": "War Gauntlets", + "NTIPAliasClassID": 384, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "72": 24, + "73": 24, + "31": + { + "min": 43, + "max": 53 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["IMMORTALKINGSFORGE"], + "uniques": ["HELLMOUTH"], + "NTIPAliasClass": 1 + }, + "warhat": + { + "DisplayName": "War Hat", + "NTIPAliasClassID": 352, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 12, + "73": 12, + "31": + { + "min": 45, + "max": 53 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["COWKINGSHORNS"], + "uniques": ["PEASANTCROWN"], + "NTIPAliasClass": 1 + }, + "ward": + { + "DisplayName": "Ward", + "NTIPAliasClassID": 449, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 100, + "73": 100, + "31": + { + "min": 153, + "max": 170 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "sets": ["TAEBAEKSGLORY"], + "uniques": ["SPIRITWARD"], + "NTIPAliasClass": 2 + }, + "wingedhelm": + { + "DisplayName": "Winged Helm", + "NTIPAliasClassID": 356, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 40, + "73": 40, + "31": + { + "min": 85, + "max": 98 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "sets": ["GUILLAUMESFACE"], + "uniques": ["VALKYRIEWING"], + "NTIPAliasClass": 1 + }, + "wirefleece": + { + "DisplayName": "Wire Fleece", + "NTIPAliasClassID": 432, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "31": + { + "min": 375, + "max": 481 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THEGLADIATORSBANE"], + "NTIPAliasClass": 2 + }, + "wolfhead": + { + "DisplayName": "Wolf Head", + "NTIPAliasClassID": 398, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "31": + { + "min": 8, + "max": 11 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + }, + "wyrmhide": + { + "DisplayName": "Wyrmhide", + "NTIPAliasClassID": 430, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 24, + "73": 24, + "31": + { + "min": 364, + "max": 470 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "wyrmhideboots": + { + "DisplayName": "Wyrmhide Boots", + "NTIPAliasClassID": 455, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "31": + { + "min": 54, + "max": 62 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 2 + }, + "zakarumshield": + { + "DisplayName": "Zakarum Shield", + "NTIPAliasClassID": 501, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 65, + "73": 65, + "31": + { + "min": 169, + "max": 193 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["DRAGONSCALE"], + "NTIPAliasClass": 2 + }, + "zombiehead": + { + "DisplayName": "Zombie Head", + "NTIPAliasClassID": 414, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "31": + { + "min": 4, + "max": 8 + }, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 2], + "NTIPAliasClass": 0 + } +} + +ITEM_MISC = { + "ajadefigurine": + { + "DisplayName": "A Jade Figurine", + "NTIPAliasClassID": 546, + "NTIPAliasType": 39, + "dimensions": [1, 2] + }, + "amethyst": + { + "DisplayName": "Amethyst", + "NTIPAliasClassID": 559, + "NTIPAliasType": 96, + "dimensions": [1, 1] + }, + "amnrune": + { + "DisplayName": "Amn Rune", + "NTIPAliasClassID": 620, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "amulet": + { + "DisplayName": "Amulet", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "dimensions": [1, 1], + "sets": ["ANGELICWINGS", "ARCANNASSIGN", "CATHANSSIGIL", "CIVERBSICON", "IRATHASCOLLAR", "TALRASHASADJUDICATION", "TANCREDSWEIRD", "TELLINGOFBEADS", "VIDALASSNARE"], + "uniques": ["NOKOZANRELIC", "THEEYEOFETLICH", "THEMAHIMOAKCURIO", "THECATSEYE", "THERISINGSUN", "CRESCENTMOON", "MARASKALEIDOSCOPE", "ATMASSCARAB", "HIGHLORDSWRATH", "SARACENSCHANCE", "SERAPHSHYMN", "METALGRID"] + }, + "antidotepotion": + { + "DisplayName": "Antidote Potion", + "NTIPAliasClassID": 514, + "NTIPAliasType": 80, + "dimensions": [1, 1] + }, + "arrows": + { + "DisplayName": "Arrows", + "NTIPAliasClassID": 526, + "NTIPAliasType": 5, + "dimensions": [1, 3] + }, + "baalseye": + { + "DisplayName": "Baal's Eye", + "NTIPAliasClassID": 651, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "berrune": + { + "DisplayName": "Ber Rune", + "NTIPAliasClassID": 639, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "bolts": + { + "DisplayName": "Bolts", + "NTIPAliasClassID": 528, + "NTIPAliasType": 6, + "dimensions": [1, 3] + }, + "brain": + { + "DisplayName": "Brain", + "NTIPAliasClassID": 532, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "burningessenceofterror": + { + "DisplayName": "Burning Essence of Terror", + "NTIPAliasClassID": 656, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "chamrune": + { + "DisplayName": "Cham Rune", + "NTIPAliasClassID": 641, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "chargedessenceofhatred": + { + "DisplayName": "Charged Essence of Hatred", + "NTIPAliasClassID": 655, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "chippedamethyst": + { + "DisplayName": "Chipped Amethyst", + "NTIPAliasClassID": 557, + "NTIPAliasType": 96, + "dimensions": [1, 1] + }, + "chippeddiamond": + { + "DisplayName": "Chipped Diamond", + "NTIPAliasClassID": 582, + "NTIPAliasType": 97, + "dimensions": [1, 1] + }, + "chippedemerald": + { + "DisplayName": "Chipped Emerald", + "NTIPAliasClassID": 572, + "NTIPAliasType": 98, + "dimensions": [1, 1] + }, + "chippedruby": + { + "DisplayName": "Chipped Ruby", + "NTIPAliasClassID": 577, + "NTIPAliasType": 99, + "dimensions": [1, 1] + }, + "chippedsapphire": + { + "DisplayName": "Chipped Sapphire", + "NTIPAliasClassID": 567, + "NTIPAliasType": 100, + "dimensions": [1, 1] + }, + "chippedskull": + { + "DisplayName": "Chipped Skull", + "NTIPAliasClassID": 597, + "NTIPAliasType": 102, + "dimensions": [1, 1] + }, + "chippedtopaz": + { + "DisplayName": "Chipped Topaz", + "NTIPAliasClassID": 562, + "NTIPAliasType": 101, + "dimensions": [1, 1] + }, + "diabloshorn": + { + "DisplayName": "Diablo's Horn", + "NTIPAliasClassID": 650, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "diamond": + { + "DisplayName": "Diamond", + "NTIPAliasClassID": 584, + "NTIPAliasType": 97, + "dimensions": [1, 1] + }, + "dolrune": + { + "DisplayName": "Dol Rune", + "NTIPAliasClassID": 623, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "ear": + { + "DisplayName": "Ear", + "NTIPAliasClassID": 556, + "NTIPAliasType": 7, + "dimensions": [1, 1] + }, + "elrune": + { + "DisplayName": "El Rune", + "NTIPAliasClassID": 610, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "eldrune": + { + "DisplayName": "Eld Rune", + "NTIPAliasClassID": 611, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "elixir": + { + "DisplayName": "Elixir", + "NTIPAliasClassID": 508, + "NTIPAliasType": 11, + "dimensions": [1, 1] + }, + "emerald": + { + "DisplayName": "Emerald", + "NTIPAliasClassID": 574, + "NTIPAliasType": 98, + "dimensions": [1, 1] + }, + "ethrune": + { + "DisplayName": "Eth Rune", + "NTIPAliasClassID": 614, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "eye": + { + "DisplayName": "Eye", + "NTIPAliasClassID": 534, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "falrune": + { + "DisplayName": "Fal Rune", + "NTIPAliasClassID": 628, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "fang": + { + "DisplayName": "Fang", + "NTIPAliasClassID": 538, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "festeringessenceofdestruction": + { + "DisplayName": "Festering Essence of Destruction", + "NTIPAliasClassID": 657, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "flag": + { + "DisplayName": "Flag", + "NTIPAliasClassID": 537, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "flawedamethyst": + { + "DisplayName": "Flawed Amethyst", + "NTIPAliasClassID": 558, + "NTIPAliasType": 96, + "dimensions": [1, 1] + }, + "flaweddiamond": + { + "DisplayName": "Flawed Diamond", + "NTIPAliasClassID": 583, + "NTIPAliasType": 97, + "dimensions": [1, 1] + }, + "flawedemerald": + { + "DisplayName": "Flawed Emerald", + "NTIPAliasClassID": 573, + "NTIPAliasType": 98, + "dimensions": [1, 1] + }, + "flawedruby": + { + "DisplayName": "Flawed Ruby", + "NTIPAliasClassID": 578, + "NTIPAliasType": 99, + "dimensions": [1, 1] + }, + "flawedsapphire": + { + "DisplayName": "Flawed Sapphire", + "NTIPAliasClassID": 568, + "NTIPAliasType": 100, + "dimensions": [1, 1] + }, + "flawedskull": + { + "DisplayName": "Flawed Skull", + "NTIPAliasClassID": 598, + "NTIPAliasType": 102, + "dimensions": [1, 1] + }, + "flawedtopaz": + { + "DisplayName": "Flawed Topaz", + "NTIPAliasClassID": 563, + "NTIPAliasType": 101, + "dimensions": [1, 1] + }, + "flawlessamethyst": + { + "DisplayName": "Flawless Amethyst", + "NTIPAliasClassID": 560, + "NTIPAliasType": 96, + "dimensions": [1, 1] + }, + "flawlessdiamond": + { + "DisplayName": "Flawless Diamond", + "NTIPAliasClassID": 585, + "NTIPAliasType": 97, + "dimensions": [1, 1] + }, + "flawlessemerald": + { + "DisplayName": "Flawless Emerald", + "NTIPAliasClassID": 575, + "NTIPAliasType": 98, + "dimensions": [1, 1] + }, + "flawlessruby": + { + "DisplayName": "Flawless Ruby", + "NTIPAliasClassID": 580, + "NTIPAliasType": 99, + "dimensions": [1, 1] + }, + "flawlesssapphire": + { + "DisplayName": "Flawless Sapphire", + "NTIPAliasClassID": 570, + "NTIPAliasType": 100, + "dimensions": [1, 1] + }, + "flawlessskull": + { + "DisplayName": "Flawless Skull", + "NTIPAliasClassID": 600, + "NTIPAliasType": 102, + "dimensions": [1, 1] + }, + "flawlesstopaz": + { + "DisplayName": "Flawless Topaz", + "NTIPAliasClassID": 565, + "NTIPAliasType": 101, + "dimensions": [1, 1] + }, + "fullrejuvenationpotion": + { + "DisplayName": "Full Rejuvenation Potion", + "NTIPAliasClassID": 516, + "NTIPAliasType": 78, + "dimensions": [1, 1] + }, + "gold": + { + "DisplayName": "Gold", + "NTIPAliasClassID": 523, + "NTIPAliasType": 4, + "dimensions": [1, 1] + }, + "grandcharm": + { + "DisplayName": "Grand Charm", + "NTIPAliasClassID": 605, + "NTIPAliasType": 84, + "dimensions": [1, 3], + "uniques": ["GHEEDSFORTUNE"] + }, + "greaterhealingpotion": + { + "DisplayName": "Greater Healing Potion", + "NTIPAliasClassID": 590, + "NTIPAliasType": 76, + "dimensions": [1, 1] + }, + "greatermanapotion": + { + "DisplayName": "Greater Mana Potion", + "NTIPAliasClassID": 595, + "NTIPAliasType": 77, + "dimensions": [1, 1] + }, + "gulrune": + { + "DisplayName": "Gul Rune", + "NTIPAliasClassID": 634, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "healingpotion": + { + "DisplayName": "Healing Potion", + "NTIPAliasClassID": 589, + "NTIPAliasType": 76, + "dimensions": [1, 1] + }, + "heart": + { + "DisplayName": "Heart", + "NTIPAliasClassID": 531, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "helrune": + { + "DisplayName": "Hel Rune", + "NTIPAliasClassID": 624, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "herb": + { + "DisplayName": "Herb", + "NTIPAliasClassID": 602, + "NTIPAliasType": 8, + "dimensions": [1, 1] + }, + "horadriccube": + { + "DisplayName": "Horadric Cube", + "NTIPAliasClassID": 549, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "horadricscroll": + { + "DisplayName": "Horadric Scroll", + "NTIPAliasClassID": 550, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "horn": + { + "DisplayName": "Horn", + "NTIPAliasClassID": 535, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "iorune": + { + "DisplayName": "Io Rune", + "NTIPAliasClassID": 625, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "istrune": + { + "DisplayName": "Ist Rune", + "NTIPAliasClassID": 633, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "ithrune": + { + "DisplayName": "Ith Rune", + "NTIPAliasClassID": 615, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "jahrune": + { + "DisplayName": "Jah Rune", + "NTIPAliasClassID": 640, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "jawbone": + { + "DisplayName": "Jawbone", + "NTIPAliasClassID": 533, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "jewel": + { + "DisplayName": "Jewel", + "NTIPAliasClassID": 643, + "NTIPAliasType": 58, + "dimensions": [1, 1], + "uniques": ["RAINBOWFACET"] + }, + "malahspotion": + { + "DisplayName": "Keep it to thaw Anya\\nMalah's Potion", + "NTIPAliasClassID": 644, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "key": + { + "DisplayName": "Key", + "NTIPAliasClassID": 543, + "NTIPAliasType": 41, + "dimensions": [1, 1] + }, + "keyofdestruction": + { + "DisplayName": "Key of Destruction", + "NTIPAliasClassID": 649, + "NTIPAliasType": 39, + "dimensions": [1, 2] + }, + "keyofhate": + { + "DisplayName": "Key of Hate", + "NTIPAliasClassID": 648, + "NTIPAliasType": 39, + "dimensions": [1, 2] + }, + "keyofterror": + { + "DisplayName": "Key of Terror", + "NTIPAliasClassID": 647, + "NTIPAliasType": 39, + "dimensions": [1, 2] + }, + "keytothecairnstones": + { + "DisplayName": "Key to the Cairn Stones", + "NTIPAliasClassID": 525, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "khalimsbrain": + { + "DisplayName": "Khalim's Brain", + "NTIPAliasClassID": 555, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "khalimseye": + { + "DisplayName": "Khalim's Eye", + "NTIPAliasClassID": 553, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "khalimsheart": + { + "DisplayName": "Khalim's Heart", + "NTIPAliasClassID": 554, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "korune": + { + "DisplayName": "Ko Rune", + "NTIPAliasClassID": 627, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "lamesenstome": + { + "DisplayName": "Lam Esen's Tome", + "NTIPAliasClassID": 548, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "largecharm": + { + "DisplayName": "Large Charm", + "NTIPAliasClassID": 604, + "NTIPAliasType": 83, + "dimensions": [1, 2], + "uniques": ["HELLFIRETORCH"] + }, + "lemrune": + { + "DisplayName": "Lem Rune", + "NTIPAliasClassID": 629, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "lighthealingpotion": + { + "DisplayName": "Light Healing Potion", + "NTIPAliasClassID": 588, + "NTIPAliasType": 76, + "dimensions": [1, 1] + }, + "lightmanapotion": + { + "DisplayName": "Light Mana Potion", + "NTIPAliasClassID": 593, + "NTIPAliasType": 77, + "dimensions": [1, 1] + }, + "lorune": + { + "DisplayName": "Lo Rune", + "NTIPAliasClassID": 637, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "lumrune": + { + "DisplayName": "Lum Rune", + "NTIPAliasClassID": 626, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "malrune": + { + "DisplayName": "Mal Rune", + "NTIPAliasClassID": 632, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "manapotion": + { + "DisplayName": "Mana Potion", + "NTIPAliasClassID": 594, + "NTIPAliasType": 77, + "dimensions": [1, 1] + }, + "mephistosbrain": + { + "DisplayName": "Mephisto's Brain", + "NTIPAliasClassID": 652, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "mephistossoulstone": + { + "DisplayName": "Mephisto's Soulstone", + "NTIPAliasClassID": 551, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "minorhealingpotion": + { + "DisplayName": "Minor Healing Potion", + "NTIPAliasClassID": 587, + "NTIPAliasType": 76, + "dimensions": [1, 1] + }, + "minormanapotion": + { + "DisplayName": "Minor Mana Potion", + "NTIPAliasClassID": 592, + "NTIPAliasType": 77, + "dimensions": [1, 1] + }, + "nefrune": + { + "DisplayName": "Nef Rune", + "NTIPAliasClassID": 613, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "ohmrune": + { + "DisplayName": "Ohm Rune", + "NTIPAliasClassID": 636, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "ortrune": + { + "DisplayName": "Ort Rune", + "NTIPAliasClassID": 618, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "perfectamethyst": + { + "DisplayName": "Perfect Amethyst", + "NTIPAliasClassID": 561, + "NTIPAliasType": 96, + "dimensions": [1, 1] + }, + "perfectdiamond": + { + "DisplayName": "Perfect Diamond", + "NTIPAliasClassID": 586, + "NTIPAliasType": 97, + "dimensions": [1, 1] + }, + "perfectemerald": + { + "DisplayName": "Perfect Emerald", + "NTIPAliasClassID": 576, + "NTIPAliasType": 98, + "dimensions": [1, 1] + }, + "perfectruby": + { + "DisplayName": "Perfect Ruby", + "NTIPAliasClassID": 581, + "NTIPAliasType": 99, + "dimensions": [1, 1] + }, + "perfectsapphire": + { + "DisplayName": "Perfect Sapphire", + "NTIPAliasClassID": 571, + "NTIPAliasType": 100, + "dimensions": [1, 1] + }, + "perfectskull": + { + "DisplayName": "Perfect Skull", + "NTIPAliasClassID": 601, + "NTIPAliasType": 102, + "dimensions": [1, 1] + }, + "perfecttopaz": + { + "DisplayName": "Perfect Topaz", + "NTIPAliasClassID": 566, + "NTIPAliasType": 101, + "dimensions": [1, 1] + }, + "pulrune": + { + "DisplayName": "Pul Rune", + "NTIPAliasClassID": 630, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "quill": + { + "DisplayName": "Quill", + "NTIPAliasClassID": 539, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "ralrune": + { + "DisplayName": "Ral Rune", + "NTIPAliasClassID": 617, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "rejuvenationpotion": + { + "DisplayName": "Rejuvenation Potion", + "NTIPAliasClassID": 515, + "NTIPAliasType": 78, + "dimensions": [1, 1] + }, + "scrollofresistance": + { + "DisplayName": "Right Click to Cast\\nScroll of Resistance", + "NTIPAliasClassID": 646, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "bookofskill": + { + "DisplayName": "Right Click to learn skill of your choice\\nBook of Skill", + "NTIPAliasClassID": 552, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "potionoflife": + { + "DisplayName": "Right Click to permanently add 20 to Life\\nPotion of Life", + "NTIPAliasClassID": 545, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "tokenofabsolution": + { + "DisplayName": "Right-click to reset Stat/Skill Points\\nToken of Absolution", + "NTIPAliasClassID": 653, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "ring": + { + "DisplayName": "Ring", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "dimensions": [1, 1], + "sets": ["ANGELICHALO", "CATHANSSEAL"], + "uniques": ["NAGELRING", "MANALDHEAL", "THESTONEOFJORDAN", "CONSTRICTINGRING", "BULKATHOSWEDDINGBAND", "DWARFSTAR", "RAVENFROST", "NATURESPEACE", "WISPPROJECTOR", "CARRIONWIND"] + }, + "ruby": + { + "DisplayName": "Ruby", + "NTIPAliasClassID": 579, + "NTIPAliasType": 99, + "dimensions": [1, 1] + }, + "sapphire": + { + "DisplayName": "Sapphire", + "NTIPAliasClassID": 569, + "NTIPAliasType": 100, + "dimensions": [1, 1] + }, + "scalp": + { + "DisplayName": "Scalp", + "NTIPAliasClassID": 541, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "scrollofidentify": + { + "DisplayName": "Scroll of Identify", + "NTIPAliasClassID": 530, + "NTIPAliasType": 22, + "dimensions": [1, 1] + }, + "scrollofinifuss": + { + "DisplayName": "Scroll of Inifuss", + "NTIPAliasClassID": 524, + "NTIPAliasType": 39, + "dimensions": [2, 2] + }, + "scrollofknowledge": + { + "DisplayName": "Scroll of Knowledge", + "NTIPAliasClassID": 645, + "NTIPAliasType": 22, + "dimensions": [1, 1] + }, + "scrolloftownportal": + { + "DisplayName": "Scroll of Town Portal", + "NTIPAliasClassID": 529, + "NTIPAliasType": 22, + "dimensions": [1, 1] + }, + "shaelrune": + { + "DisplayName": "Shael Rune", + "NTIPAliasClassID": 622, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "skull": + { + "DisplayName": "Skull", + "NTIPAliasClassID": 599, + "NTIPAliasType": 102, + "dimensions": [1, 1] + }, + "smallcharm": + { + "DisplayName": "Small Charm", + "NTIPAliasClassID": 603, + "NTIPAliasType": 82, + "dimensions": [1, 1], + "uniques": ["ANNIHILUS"] + }, + + + "solrune": + { + "DisplayName": "Sol Rune", + "NTIPAliasClassID": 621, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "soul": + { + "DisplayName": "Soul", + "NTIPAliasClassID": 540, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "spleen": + { + "DisplayName": "Spleen", + "NTIPAliasClassID": 542, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "staminapotion": + { + "DisplayName": "Stamina Potion", + "NTIPAliasClassID": 513, + "NTIPAliasType": 79, + "dimensions": [1, 1] + }, + "standardofheroes": + { + "DisplayName": "Standard of Heroes", + "NTIPAliasClassID": 658, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "superhealingpotion": + { + "DisplayName": "Super Healing Potion", + "NTIPAliasClassID": 591, + "NTIPAliasType": 76, + "dimensions": [1, 1] + }, + "supermanapotion": + { + "DisplayName": "Super Mana Potion", + "NTIPAliasClassID": 596, + "NTIPAliasType": 77, + "dimensions": [1, 1] + }, + "surrune": + { + "DisplayName": "Sur Rune", + "NTIPAliasClassID": 638, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "tail": + { + "DisplayName": "Tail", + "NTIPAliasClassID": 536, + "NTIPAliasType": 40, + "dimensions": [1, 1] + }, + "talrune": + { + "DisplayName": "Tal Rune", + "NTIPAliasClassID": 616, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "thawingpotion": + { + "DisplayName": "Thawing Potion", + "NTIPAliasClassID": 517, + "NTIPAliasType": 81, + "dimensions": [1, 1] + }, + "theblacktowerkey": + { + "DisplayName": "The Black Tower Key", + "NTIPAliasClassID": 544, + "NTIPAliasType": 41, + "dimensions": [1, 2] + }, + "thegoldenbird": + { + "DisplayName": "The Golden Bird", + "NTIPAliasClassID": 547, + "NTIPAliasType": 39, + "dimensions": [1, 2] + }, + "thulrune": + { + "DisplayName": "Thul Rune", + "NTIPAliasClassID": 619, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "tirrune": + { + "DisplayName": "Tir Rune", + "NTIPAliasClassID": 612, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "tomeofidentify": + { + "DisplayName": "Tome of Identify", + "NTIPAliasClassID": 519, + "NTIPAliasType": 18, + "dimensions": [1, 2] + }, + "tomeoftownportal": + { + "DisplayName": "Tome of Town Portal", + "NTIPAliasClassID": 518, + "NTIPAliasType": 18, + "dimensions": [1, 2] + }, + "topofthehoradricstaff": + { + "DisplayName": "Top of the Horadric Staff", + "NTIPAliasClassID": 521, + "NTIPAliasType": 12, + "dimensions": [1, 1], + "uniques": ["AMULETOFTHEVIPER"] + }, + "topaz": + { + "DisplayName": "Topaz", + "NTIPAliasClassID": 564, + "NTIPAliasType": 101, + "dimensions": [1, 1] + }, + "torch": + { + "DisplayName": "Torch", + "NTIPAliasClassID": 527, + "NTIPAliasType": 21, + "dimensions": [1, 2] + }, + "twistedessenceofsuffering": + { + "DisplayName": "Twisted Essence of Suffering", + "NTIPAliasClassID": 654, + "NTIPAliasType": 39, + "dimensions": [1, 1] + }, + "umrune": + { + "DisplayName": "Um Rune", + "NTIPAliasClassID": 631, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "vexrune": + { + "DisplayName": "Vex Rune", + "NTIPAliasClassID": 635, + "NTIPAliasType": 74, + "dimensions": [1, 1] + }, + "zodrune": + { + "DisplayName": "Zod Rune", + "NTIPAliasClassID": 642, + "NTIPAliasType": 74, + "dimensions": [1, 1] + } +} + +ITEM_SET_ITEMS = { + "aldursadvance": + { + "DisplayName": "Aldur's Advance", + "NTIPAliasClassID": 388, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "152": + { + "min": 1, + "max": 1 + }, + "28": + { + "min": 32, + "max": 32 + }, + "6": + { + "min": 50, + "max": 50 + }, + "114": + { + "min": 10, + "max": 10 + }, + "96": + { + "min": 40, + "max": 40 + }, + "10": + { + "min": 180, + "max": 180 + }, + "39": + { + "min": 40, + "max": 50 + } + } + }, + "aldursdeception": + { + "DisplayName": "Aldur's Deception", + "NTIPAliasClassID": 441, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 300, + "max": 300 + }, + "188,41": + { + "min": 1, + "max": 1, + "par": "Shape Shifting Skills" + }, + "0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 15, + "max": 15 + }, + "41": + { + "min": 40, + "max": 50 + }, + "91": + { + "min": -50, + "max": -50 + }, + "188,42": + { + "min": 1, + "max": 1, + "par": "Elemental Skills" + } + } + }, + "aldursrhythm": + { + "DisplayName": "Aldur's Rhythm", + "NTIPAliasClassID": 113, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "21": 40, + "22": 62, + "50": 50, + "51": 75, + "60": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 30, + "max": 30 + }, + "121": + { + "min": 200, + "max": 200 + }, + "62": + { + "min": 5, + "max": 5 + }, + "194": + { + "min": 2, + "max": 5 + } + } + }, + "aldursstonygaze": + { + "DisplayName": "Aldur's Stony Gaze", + "NTIPAliasClassID": 470, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "31": + { + "min": 90, + "max": 90 + }, + "27": + { + "min": 17, + "max": 17 + }, + "89": + { + "min": 5, + "max": 5 + }, + "99": + { + "min": 25, + "max": 25 + }, + "43": + { + "min": 40, + "max": 50 + }, + "194": + { + "min": 2, + "max": 2 + } + } + }, + "angelichalo": + { + "DisplayName": "Angelic Halo", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "74": + { + "min": 6, + "max": 6 + }, + "6": + { + "min": 20, + "max": 20 + } + } + }, + "angelicmantle": + { + "DisplayName": "Angelic Mantle", + "NTIPAliasClassID": 317, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "34": + { + "min": 3, + "max": 3 + }, + "16,0": + { + "min": 40, + "max": 40 + } + } + }, + "angelicsickle": + { + "DisplayName": "Angelic Sickle", + "NTIPAliasClassID": 27, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "19": + { + "min": 75, + "max": 75 + }, + "122": + { + "min": 250, + "max": 250 + } + } + }, + "angelicwings": + { + "DisplayName": "Angelic Wings", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "89": + { + "min": 3, + "max": 3 + }, + "114": + { + "min": 20, + "max": 20 + } + } + }, + "arcannasdeathwand": + { + "DisplayName": "Arcanna's Deathwand", + "NTIPAliasClassID": 67, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 1, + "max": 1 + }, + "141": + { + "min": 25, + "max": 25 + } + } + }, + "arcannasflesh": + { + "DisplayName": "Arcanna's Flesh", + "NTIPAliasClassID": 327, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "89": + { + "min": 2, + "max": 2 + }, + "34": + { + "min": 3, + "max": 3 + } + } + }, + "arcannashead": + { + "DisplayName": "Arcanna's Head", + "NTIPAliasClassID": 307, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "74": + { + "min": 4, + "max": 4 + }, + "78": + { + "min": 2, + "max": 2 + } + } + }, + "arcannassign": + { + "DisplayName": "Arcanna's Sign", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "8": + { + "min": 15, + "max": 15 + }, + "27": + { + "min": 20, + "max": 20 + } + } + }, + "arcticbinding": + { + "DisplayName": "Arctic Binding", + "NTIPAliasClassID": 345, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "43": + { + "min": 40, + "max": 40 + }, + "31": + { + "min": 30, + "max": 30 + } + } + }, + "arcticfurs": + { + "DisplayName": "Arctic Furs", + "NTIPAliasClassID": 313, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 275, + "max": 325 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10 + } + }, + "arctichorn": + { + "DisplayName": "Arctic Horn", + "NTIPAliasClassID": 74, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "119": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 50, + "max": 50 + } + } + }, + "arcticmitts": + { + "DisplayName": "Arctic Mitts", + "NTIPAliasClassID": 337, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "6": + { + "min": 20, + "max": 20 + }, + "93": + { + "min": 10, + "max": 10 + } + } + }, + "berserkershatchet": + { + "DisplayName": "Berserker's Hatchet", + "NTIPAliasClassID": 2, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "119": + { + "min": 30, + "max": 30 + }, + "62": + { + "min": 5, + "max": 5 + } + } + }, + "berserkershauberk": + { + "DisplayName": "Berserker's Hauberk", + "NTIPAliasClassID": 321, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "35": + { + "min": 2, + "max": 2 + }, + "83,4": + { + "min": 1, + "max": 1 + } + } + }, + "berserkersheadgear": + { + "DisplayName": "Berserker's Headgear", + "NTIPAliasClassID": 308, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 15, + "max": 15 + }, + "39": + { + "min": 25, + "max": 25 + } + } + }, + "bulkathossacredcharge": + { + "DisplayName": "Bul-Kathos' Sacred Charge", + "NTIPAliasClassID": 234, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "136": + { + "min": 35, + "max": 35 + }, + "39": 20, + "43": 20, + "41": 20, + "45": 20, + "93": + { + "min": 20, + "max": 20 + }, + "81": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 200, + "max": 200 + } + } + }, + "bulkathostribalguardian": + { + "DisplayName": "Bul-Kathos' Tribal Guardian", + "NTIPAliasClassID": 228, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "39": + { + "min": 50, + "max": 50 + }, + "57": 50, + "58": 50, + "93": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 200, + "max": 200 + } + } + }, + "cathansmesh": + { + "DisplayName": "Cathan's Mesh", + "NTIPAliasClassID": 319, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 15, + "max": 15 + }, + "91": + { + "min": -50, + "max": -50 + } + } + }, + "cathansrule": + { + "DisplayName": "Cathan's Rule", + "NTIPAliasClassID": 66, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "188,8": + { + "min": 1, + "max": 1 + }, + "49": + { + "min": 10, + "max": 10 + } + } + }, + "cathansseal": + { + "DisplayName": "Cathan's Seal", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "60": + { + "min": 6, + "max": 6 + }, + "34": + { + "min": 2, + "max": 2 + } + } + }, + "cathanssigil": + { + "DisplayName": "Cathan's Sigil", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "99": + { + "min": 10, + "max": 10 + }, + "128": + { + "min": 5, + "max": 5 + } + } + }, + "cathansvisage": + { + "DisplayName": "Cathan's Visage", + "NTIPAliasClassID": 312, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "8": + { + "min": 20, + "max": 20 + }, + "43": + { + "min": 25, + "max": 25 + } + } + }, + "civerbscudgel": + { + "DisplayName": "Civerb's Cudgel", + "NTIPAliasClassID": 16, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "19": + { + "min": 75, + "max": 75 + }, + "22": + { + "min": 17, + "max": 23 + } + } + }, + "civerbsicon": + { + "DisplayName": "Civerb's Icon", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "27": + { + "min": 40, + "max": 40 + }, + "74": + { + "min": 4, + "max": 4 + } + } + }, + "civerbsward": + { + "DisplayName": "Civerb's Ward", + "NTIPAliasClassID": 330, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 15, + "max": 15 + }, + "20": + { + "min": 15, + "max": 15 + } + } + }, + "cleglawsclaw": + { + "DisplayName": "Cleglaw's Claw", + "NTIPAliasClassID": 329, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 17, + "max": 17 + }, + "110": + { + "min": 75, + "max": 75 + } + } + }, + "cleglawspincers": + { + "DisplayName": "Cleglaw's Pincers", + "NTIPAliasClassID": 336, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "81": + { + "min": 1, + "max": 1 + }, + "150": + { + "min": 25, + "max": 25 + } + } + }, + "cleglawstooth": + { + "DisplayName": "Cleglaw's Tooth", + "NTIPAliasClassID": 31, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "119": + { + "min": 30, + "max": 30 + }, + "141": + { + "min": 50, + "max": 50 + } + } + }, + "cowkingshide": + { + "DisplayName": "Cow King's Hide", + "NTIPAliasClassID": 316, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "39": 18, + "43": 18, + "41": 18, + "45": 18, + "16,0": + { + "min": 60, + "max": 60 + }, + "6": + { + "min": 30, + "max": 30 + }, + "201": + { + "chance": 18, + "level": 5, + "skill": "Chain Lightning" + } + } + }, + "cowkingshooves": + { + "DisplayName": "Cow King's Hooves", + "NTIPAliasClassID": 340, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "31": + { + "min": 25, + "max": 35 + }, + "96": + { + "min": 30, + "max": 30 + }, + "80": + { + "min": 25, + "max": 25 + }, + "2": + { + "min": 20, + "max": 20 + }, + "48": 25, + "49": 35 + } + }, + "cowkingshorns": + { + "DisplayName": "Cow King's Horns", + "NTIPAliasClassID": 352, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 75, + "max": 75 + }, + "118": + { + "min": 1, + "max": 1 + }, + "114": + { + "min": 35, + "max": 35 + }, + "78": + { + "min": 10, + "max": 10 + } + } + }, + "credendum": + { + "DisplayName": "Credendum", + "NTIPAliasClassID": 462, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 50, + "max": 50 + }, + "0": + { + "min": 10, + "max": 10 + }, + "2": + { + "min": 10, + "max": 10 + }, + "39": 15, + "43": 15, + "41": 15, + "45": 15 + } + }, + "dangoonsteaching": + { + "DisplayName": "Dangoon's Teaching", + "NTIPAliasClassID": 215, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "218": + { + "min": None, + "max": None, + "par": 12 + }, + "93": + { + "min": 40, + "max": 40 + }, + "198": + { + "chance": 10, + "level": 3, + "skill": "Frost Nova" + }, + "48": 20, + "49": 30 + } + }, + "darkadherent": + { + "DisplayName": "Dark Adherent", + "NTIPAliasClassID": 429, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 305, + "max": 415 + }, + "39": + { + "min": 24, + "max": 24 + }, + "201": + { + "chance": 25, + "level": 3, + "skill": "Nova" + }, + "57": 24, + "58": 34 + } + }, + "deathsguard": + { + "DisplayName": "Death's Guard", + "NTIPAliasClassID": 344, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 20, + "max": 20 + }, + "153": + { + "min": 1, + "max": 1 + } + } + }, + "deathshand": + { + "DisplayName": "Death's Hand", + "NTIPAliasClassID": 334, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "45": + { + "min": 50, + "max": 50 + }, + "110": + { + "min": 75, + "max": 75 + } + } + }, + "deathstouch": + { + "DisplayName": "Death's Touch", + "NTIPAliasClassID": 32, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "25": + { + "min": 25, + "max": 25 + }, + "60": + { + "min": 4, + "max": 4 + } + } + }, + "griswoldsheart": + { + "DisplayName": "Griswold's Heart", + "NTIPAliasClassID": 372, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 500, + "max": 500 + }, + "188,26": + { + "min": 2, + "max": 2, + "par": "Defensive Auras" + }, + "194": + { + "min": 3, + "max": 3 + }, + "0": + { + "min": 20, + "max": 20 + }, + "91": + { + "min": -40, + "max": -40 + } + } + }, + "griswoldshonor": + { + "DisplayName": "Griswold's Honor", + "NTIPAliasClassID": 502, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "31": + { + "min": 108, + "max": 108 + }, + "194": + { + "min": 3, + "max": 3 + }, + "102": + { + "min": 65, + "max": 65 + }, + "20": + { + "min": 20, + "max": 20 + }, + "39": 45, + "43": 45, + "41": 45, + "45": 45 + } + }, + "griswoldsredemption": + { + "DisplayName": "Griswold's Redemption", + "NTIPAliasClassID": 213, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "25": + { + "min": 200, + "max": 240 + }, + "93": + { + "min": 40, + "max": 40 + }, + "122": + { + "min": 200, + "max": 200 + }, + "91": + { + "min": -20, + "max": -20 + }, + "194": + { + "min": 3, + "max": 4 + } + } + }, + "griswoldsvalor": + { + "DisplayName": "Griswold's Valor", + "NTIPAliasClassID": 427, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 50, + "max": 75 + }, + "234": + { + "min": 2, + "max": 2 + }, + "194": + { + "min": 2, + "max": 2 + }, + "91": + { + "min": -40, + "max": -40 + }, + "80": + { + "min": 20, + "max": 30 + }, + "39": 5, + "43": 5, + "41": 5, + "45": 5 + } + }, + "guillaumesface": + { + "DisplayName": "Guillaume's Face", + "NTIPAliasClassID": 356, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 120 + }, + "99": + { + "min": 30, + "max": 30 + }, + "136": + { + "min": 35, + "max": 35 + }, + "141": + { + "min": 15, + "max": 15 + }, + "0": + { + "min": 15, + "max": 15 + } + } + }, + "haemosusadamant": + { + "DisplayName": "Haemosu's Adamant", + "NTIPAliasClassID": 366, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 500, + "max": 500 + }, + "32": + { + "min": 35, + "max": 35 + }, + "6": + { + "min": 75, + "max": 75 + }, + "33": + { + "min": 40, + "max": 40 + }, + "91": + { + "min": -20, + "max": -20 + } + } + }, + "hsarusironfist": + { + "DisplayName": "Hsarus' Iron Fist", + "NTIPAliasClassID": 328, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "34": + { + "min": 2, + "max": 2 + }, + "0": + { + "min": 10, + "max": 10 + } + } + }, + "hsarusironheel": + { + "DisplayName": "Hsarus' Iron Heel", + "NTIPAliasClassID": 341, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "39": + { + "min": 25, + "max": 25 + }, + "96": + { + "min": 20, + "max": 20 + } + } + }, + "hsarusironstay": + { + "DisplayName": "Hsarus' Iron Stay", + "NTIPAliasClassID": 346, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "43": + { + "min": 20, + "max": 20 + }, + "6": + { + "min": 20, + "max": 20 + } + } + }, + "hwaninsblessing": + { + "DisplayName": "Hwanin's Blessing", + "NTIPAliasClassID": 346, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "50": 3, + "51": 33, + "117": + { + "min": 1, + "max": 1 + }, + "214": + { + "min": None, + "max": None, + "par": 12 + }, + "114": + { + "min": 12, + "max": 12 + } + } + }, + "hwaninsjustice": + { + "DisplayName": "Hwanin's Justice", + "NTIPAliasClassID": 151, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "19": + { + "min": 330, + "max": 330 + }, + "152": + { + "min": 1, + "max": 1 + }, + "198": + { + "chance": 10, + "level": 3, + "skill": "Ice Blast" + }, + "93": + { + "min": 40, + "max": 40 + }, + "25": + { + "min": 200, + "max": 200 + }, + "50": 5, + "51": 25 + } + }, + "hwaninsrefuge": + { + "DisplayName": "Hwanin's Refuge", + "NTIPAliasClassID": 364, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 200, + "max": 200 + }, + "45": + { + "min": 27, + "max": 27 + }, + "6": + { + "min": 100, + "max": 100 + }, + "201": + { + "chance": 10, + "level": 3, + "skill": "Static Field" + } + } + }, + "hwaninssplendor": + { + "DisplayName": "Hwanin's Splendor", + "NTIPAliasClassID": 357, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "74": + { + "min": 20, + "max": 20 + }, + "35": + { + "min": 10, + "max": 10 + }, + "43": + { + "min": 37, + "max": 37 + }, + "16,0": + { + "min": 100, + "max": 100 + } + } + }, + "immortalkingsdetail": + { + "DisplayName": "Immortal King's Detail", + "NTIPAliasClassID": 394, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 36, + "max": 36 + }, + "39": + { + "min": 28, + "max": 28 + }, + "41": + { + "min": 31, + "max": 31 + }, + "0": + { + "min": 25, + "max": 25 + } + } + }, + "immortalkingsforge": + { + "DisplayName": "Immortal King's Forge", + "NTIPAliasClassID": 384, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 65, + "max": 65 + }, + "0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 20, + "max": 20 + }, + "201": + { + "chance": 12, + "level": 4, + "skill": "Charged Bolt" + } + } + }, + "immortalkingspillar": + { + "DisplayName": "Immortal King's Pillar", + "NTIPAliasClassID": 389, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "31": + { + "min": 75, + "max": 75 + }, + "96": + { + "min": 40, + "max": 40 + }, + "19": + { + "min": 110, + "max": 110 + }, + "6": + { + "min": 44, + "max": 44 + } + } + }, + "immortalkingssoulcage": + { + "DisplayName": "Immortal King's Soul Cage", + "NTIPAliasClassID": 442, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 400, + "max": 400 + }, + "201": + { + "chance": 5, + "level": 5, + "skill": "Enchant" + }, + "188,32": + { + "min": 2, + "max": 2, + "par": "Combat Skills" + }, + "45": + { + "min": 50, + "max": 50 + } + } + }, + "immortalkingsstonecrusher": + { + "DisplayName": "Immortal King's Stone Crusher", + "NTIPAliasClassID": 219, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "152": + { + "min": 1, + "max": 1 + }, + "93": + { + "min": 40, + "max": 40 + }, + "121": + { + "min": 200, + "max": 200 + }, + "122": + { + "min": 200, + "max": 200 + }, + "136": + { + "min": 35, + "max": 40 + }, + "25": + { + "min": 200, + "max": 200 + }, + "194": + { + "min": 2, + "max": 2 + } + } + }, + "immortalkingswill": + { + "DisplayName": "Immortal King's Will", + "NTIPAliasClassID": 407, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "31": + { + "min": 125, + "max": 125 + }, + "79": + { + "min": 37, + "max": 37 + }, + "188,34": + { + "min": 2, + "max": 2, + "par": "Warcries" + }, + "89": + { + "min": 4, + "max": 4 + }, + "80": + { + "min": 25, + "max": 40 + }, + "194": + { + "min": 2, + "max": 2 + } + } + }, + "infernalcranium": + { + "DisplayName": "Infernal Cranium", + "NTIPAliasClassID": 306, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "114": + { + "min": 20, + "max": 20 + } + } + }, + "infernalsign": + { + "DisplayName": "Infernal Sign", + "NTIPAliasClassID": 347, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 25, + "max": 25 + }, + "6": + { + "min": 20, + "max": 20 + } + } + }, + "infernaltorch": + { + "DisplayName": "Infernal Torch", + "NTIPAliasClassID": 13, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "21": + { + "min": 8, + "max": 8 + }, + "83,2": + { + "min": 1, + "max": 1 + } + } + }, + "irathascoil": + { + "DisplayName": "Iratha's Coil", + "NTIPAliasClassID": 311, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "39": + { + "min": 30, + "max": 30 + }, + "41": + { + "min": 30, + "max": 30 + } + } + }, + "irathascollar": + { + "DisplayName": "Iratha's Collar", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "45": + { + "min": 30, + "max": 30 + }, + "110": + { + "min": 75, + "max": 75 + } + } + }, + "irathascord": + { + "DisplayName": "Iratha's Cord", + "NTIPAliasClassID": 347, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 25, + "max": 25 + }, + "21": + { + "min": 5, + "max": 5 + } + } + }, + "irathascuff": + { + "DisplayName": "Iratha's Cuff", + "NTIPAliasClassID": 337, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "43": + { + "min": 30, + "max": 30 + }, + "118": + { + "min": 1, + "max": 1 + } + } + }, + "isenhartscase": + { + "DisplayName": "Isenhart's Case", + "NTIPAliasClassID": 320, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 40, + "max": 40 + }, + "35": + { + "min": 2, + "max": 2 + } + } + }, + "isenhartshorns": + { + "DisplayName": "Isenhart's Horns", + "NTIPAliasClassID": 309, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "2": + { + "min": 6, + "max": 6 + }, + "34": + { + "min": 2, + "max": 2 + } + } + }, + "isenhartslightbrand": + { + "DisplayName": "Isenhart's Lightbrand", + "NTIPAliasClassID": 30, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "21": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 20, + "max": 20 + } + } + }, + "isenhartsparry": + { + "DisplayName": "Isenhart's Parry", + "NTIPAliasClassID": 333, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 40, + "max": 40 + }, + "128": + { + "min": 4, + "max": 4 + } + } + }, + "layingofhands": + { + "DisplayName": "Laying of Hands", + "NTIPAliasClassID": 450, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 25, + "max": 25 + }, + "93": + { + "min": 20, + "max": 20 + }, + "39": + { + "min": 50, + "max": 50 + }, + "121": + { + "min": 350, + "max": 350 + }, + "198": + { + "chance": 10, + "level": 3, + "skill": "Holy Bolt" + } + } + }, + "magnusskin": + { + "DisplayName": "Magnus' Skin", + "NTIPAliasClassID": 381, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 50, + "max": 50 + }, + "39": + { + "min": 15, + "max": 15 + }, + "93": + { + "min": 20, + "max": 20 + }, + "89": + { + "min": 3, + "max": 3 + }, + "19": + { + "min": 100, + "max": 100 + } + } + }, + "mavinascaster": + { + "DisplayName": "M'avina's Caster", + "NTIPAliasClassID": 302, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "25": + { + "min": 188, + "max": 188 + }, + "93": + { + "min": 40, + "max": 40 + }, + "157": + { + "min": 1, + "max": 1 + }, + "19": + { + "min": 50, + "max": 50 + } + } + }, + "mavinasembrace": + { + "DisplayName": "M'avina's Embrace", + "NTIPAliasClassID": 439, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "201": + { + "chance": 10, + "level": 3, + "skill": "Glacial Spike" + }, + "91": + { + "min": -30, + "max": -30 + }, + "35": + { + "min": 5, + "max": 12 + }, + "188,1": + { + "min": 2, + "max": 2, + "par": "Passive and Magic Skills" + }, + "214": + { + "min": None, + "max": None, + "par": 32 + }, + "31": + { + "min": 350, + "max": 350 + } + } + }, + "mavinasicyclutch": + { + "DisplayName": "M'avina's Icy Clutch", + "NTIPAliasClassID": 383, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 45, + "max": 50 + }, + "54": 6, + "55": 18, + "118": + { + "min": 1, + "max": 1 + }, + "79": + { + "min": 56, + "max": 56 + }, + "0": + { + "min": 10, + "max": 10 + }, + "2": + { + "min": 15, + "max": 15 + } + } + }, + "mavinastenet": + { + "DisplayName": "M'avina's Tenet", + "NTIPAliasClassID": 391, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 50, + "max": 50 + }, + "96": + { + "min": 20, + "max": 20 + }, + "62": + { + "min": 5, + "max": 5 + }, + "89": + { + "min": 5, + "max": 5 + } + } + }, + "mavinastruesight": + { + "DisplayName": "M'avina's True Sight", + "NTIPAliasClassID": 421, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "31": + { + "min": 150, + "max": 150 + }, + "74": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 30, + "max": 30 + }, + "8": + { + "min": 25, + "max": 25 + } + } + }, + "milabregasdiadem": + { + "DisplayName": "Milabrega's Diadem", + "NTIPAliasClassID": 311, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "6": + { + "min": 15, + "max": 15 + }, + "8": + { + "min": 15, + "max": 15 + } + } + }, + "milabregasorb": + { + "DisplayName": "Milabrega's Orb", + "NTIPAliasClassID": 331, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "80": + { + "min": 20, + "max": 20 + }, + "31": + { + "min": 25, + "max": 25 + } + } + }, + "milabregasrobe": + { + "DisplayName": "Milabrega's Robe", + "NTIPAliasClassID": 326, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "78": + { + "min": 3, + "max": 3 + }, + "34": + { + "min": 2, + "max": 2 + } + } + }, + "milabregasrod": + { + "DisplayName": "Milabrega's Rod", + "NTIPAliasClassID": 17, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "83,3": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 50, + "max": 50 + }, + "89": + { + "min": 2, + "max": 2 + } + } + }, + "najscirclet": + { + "DisplayName": "Naj's Circlet", + "NTIPAliasClassID": 418, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "31": + { + "min": 75, + "max": 75 + }, + "48": 25, + "49": 35, + "89": + { + "min": 5, + "max": 5 + }, + "0": + { + "min": 15, + "max": 15 + }, + "201": + { + "chance": 12, + "level": 5, + "skill": "Chain Lightning" + } + } + }, + "najslightplate": + { + "DisplayName": "Naj's Light Plate", + "NTIPAliasClassID": 438, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "91": + { + "min": -60, + "max": -60 + }, + "6": + { + "min": 65, + "max": 65 + }, + "39": 25, + "43": 25, + "41": 25, + "45": 25, + "114": + { + "min": 45, + "max": 45 + }, + "127": + { + "min": 1, + "max": 1 + }, + "31": + { + "min": 300, + "max": 300 + } + } + }, + "najspuzzler": + { + "DisplayName": "Naj's Puzzler", + "NTIPAliasClassID": 261, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "1": + { + "min": 35, + "max": 35 + }, + "25": + { + "min": 150, + "max": 150 + }, + "204": + { + "charges": 69, + "level": 11, + "skill": "Teleport" + }, + "105": + { + "min": 30, + "max": 30 + }, + "50": 6, + "51": 45, + "8": + { + "min": 70, + "max": 70 + }, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "natalyasmark": + { + "DisplayName": "Natalya's Mark", + "NTIPAliasClassID": 195, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "93": + { + "min": 40, + "max": 40 + }, + "25": + { + "min": 200, + "max": 200 + }, + "115": + { + "min": 1, + "max": 1 + }, + "54": 50, + "55": 50, + "48": 12, + "49": 17, + "122": + { + "min": 200, + "max": 200 + }, + "121": + { + "min": 200, + "max": 200 + } + } + }, + "natalyasshadow": + { + "DisplayName": "Natalya's Shadow", + "NTIPAliasClassID": 434, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 150, + "max": 225 + }, + "216": + { + "min": None, + "max": None, + "par": 8 + }, + "188,49": + { + "min": 2, + "max": 2, + "par": "Shadow Disciplines" + }, + "110": + { + "min": 75, + "max": 75 + }, + "45": + { + "min": 25, + "max": 25 + }, + "194": + { + "min": 1, + "max": 3 + } + } + }, + "natalyassoul": + { + "DisplayName": "Natalya's Soul", + "NTIPAliasClassID": 387, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "31": + { + "min": 75, + "max": 125 + }, + "96": + { + "min": 40, + "max": 40 + }, + "241": + { + "min": None, + "max": None, + "par": 2 + }, + "72": 50, + "73": 50, + "43": + { + "min": 15, + "max": 25 + }, + "41": + { + "min": 15, + "max": 25 + } + } + }, + "natalyastotem": + { + "DisplayName": "Natalya's Totem", + "NTIPAliasClassID": 395, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 135, + "max": 175 + }, + "2": + { + "min": 20, + "max": 30 + }, + "0": + { + "min": 10, + "max": 20 + }, + "39": + { + "min": 10, + "max": 20 + }, + "43": + { + "min": 10, + "max": 20 + }, + "41": + { + "min": 10, + "max": 20 + }, + "45": + { + "min": 10, + "max": 20 + }, + "35": + { + "min": 3, + "max": 3 + } + } + }, + "ondalsalmighty": + { + "DisplayName": "Ondal's Almighty", + "NTIPAliasClassID": 426, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 50, + "max": 50 + }, + "91": + { + "min": -40, + "max": -40 + }, + "198": + { + "chance": 10, + "level": 3, + "skill": "Weaken" + }, + "0": + { + "min": 10, + "max": 10 + }, + "2": + { + "min": 15, + "max": 15 + }, + "99": + { + "min": 24, + "max": 24 + } + } + }, + "riteofpassage": + { + "DisplayName": "Rite of Passage", + "NTIPAliasClassID": 385, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "31": + { + "min": 25, + "max": 25 + }, + "96": + { + "min": 30, + "max": 30 + }, + "118": + { + "min": 1, + "max": 1 + }, + "10": + { + "min": 15, + "max": 25 + } + } + }, + "sandersparagon": + { + "DisplayName": "Sander's Paragon", + "NTIPAliasClassID": 306, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "80": + { + "min": 35, + "max": 35 + }, + "78": + { + "min": 8, + "max": 8 + }, + "214": + { + "min": None, + "max": None, + "par": 8 + } + } + }, + "sandersriprap": + { + "DisplayName": "Sander's Riprap", + "NTIPAliasClassID": 340, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "96": + { + "min": 40, + "max": 40 + }, + "19": + { + "min": 100, + "max": 100 + }, + "0": + { + "min": 5, + "max": 5 + }, + "2": + { + "min": 10, + "max": 10 + } + } + }, + "sanderssuperstition": + { + "DisplayName": "Sander's Superstition", + "NTIPAliasClassID": 12, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "25": + { + "min": 75, + "max": 75, + "par": 2 + }, + "8": + { + "min": 25, + "max": 25 + }, + "62": + { + "min": 8, + "max": 8 + }, + "105": + { + "min": 20, + "max": 20 + }, + "54": 25, + "55": 75 + } + }, + "sanderstaboo": + { + "DisplayName": "Sander's Taboo", + "NTIPAliasClassID": 335, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 20, + "max": 25 + }, + "93": + { + "min": 20, + "max": 20 + }, + "6": + { + "min": 40, + "max": 40 + }, + "57": 9, + "58": 11 + } + }, + "sazabiscobaltredeemer": + { + "DisplayName": "Sazabi's Cobalt Redeemer", + "NTIPAliasClassID": 227, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 150 + }, + "54": 25, + "55": 35, + "93": + { + "min": 40, + "max": 40 + }, + "121": + { + "min": 318, + "max": 318 + }, + "152": + { + "min": 1, + "max": 1 + }, + "2": + { + "min": 15, + "max": 15 + }, + "0": + { + "min": 5, + "max": 5 + } + } + }, + "sazabisghostliberator": + { + "DisplayName": "Sazabi's Ghost Liberator", + "NTIPAliasClassID": 437, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 400, + "max": 400 + }, + "99": + { + "min": 30, + "max": 30 + }, + "0": + { + "min": 25, + "max": 25 + }, + "123": + { + "min": 300, + "max": 300 + }, + "6": + { + "min": 50, + "max": 75 + } + } + }, + "sazabismentalsheath": + { + "DisplayName": "Sazabi's Mental Sheath", + "NTIPAliasClassID": 355, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 100, + "max": 100 + }, + "127": + { + "min": 1, + "max": 1 + }, + "39": + { + "min": 15, + "max": 20 + }, + "41": + { + "min": 15, + "max": 20 + } + } + }, + "sigonsgage": + { + "DisplayName": "Sigon's Gage", + "NTIPAliasClassID": 338, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "0": + { + "min": 10, + "max": 10 + }, + "19": + { + "min": 20, + "max": 20 + } + } + }, + "sigonsguard": + { + "DisplayName": "Sigon's Guard", + "NTIPAliasClassID": 332, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "127": + { + "min": 1, + "max": 1 + }, + "20": + { + "min": 20, + "max": 20 + } + } + }, + "sigonssabot": + { + "DisplayName": "Sigon's Sabot", + "NTIPAliasClassID": 343, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "96": + { + "min": 20, + "max": 20 + }, + "43": + { + "min": 40, + "max": 40 + } + } + }, + "sigonsshelter": + { + "DisplayName": "Sigon's Shelter", + "NTIPAliasClassID": 324, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 25, + "max": 25 + }, + "41": + { + "min": 30, + "max": 30 + } + } + }, + "sigonsvisor": + { + "DisplayName": "Sigon's Visor", + "NTIPAliasClassID": 310, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "8": + { + "min": 30, + "max": 30 + }, + "31": + { + "min": 25, + "max": 25 + } + } + }, + "sigonswrap": + { + "DisplayName": "Sigon's Wrap", + "NTIPAliasClassID": 348, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "39": + { + "min": 20, + "max": 20 + }, + "6": + { + "min": 20, + "max": 20 + } + } + }, + "taebaeksglory": + { + "DisplayName": "Taebaek's Glory", + "NTIPAliasClassID": 449, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 50, + "max": 50 + }, + "8": + { + "min": 100, + "max": 100 + }, + "41": + { + "min": 30, + "max": 30 + }, + "78": + { + "min": 30, + "max": 30 + }, + "152": + { + "min": 1, + "max": 1 + }, + "20": + { + "min": 25, + "max": 25 + }, + "102": + { + "min": 30, + "max": 30 + } + } + }, + "talrashasadjudication": + { + "DisplayName": "Tal Rasha's Adjudication", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "41": + { + "min": 33, + "max": 33 + }, + "83,1": + { + "min": 2, + "max": 2 + }, + "6": + { + "min": 50, + "max": 50 + }, + "50": 3, + "51": 32, + "8": + { + "min": 42, + "max": 42 + } + } + }, + "talrashasfinespuncloth": + { + "DisplayName": "Tal Rasha's Fine-Spun Cloth", + "NTIPAliasClassID": 392, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "91": + { + "min": -20, + "max": -20 + }, + "8": + { + "min": 30, + "max": 30 + }, + "2": + { + "min": 20, + "max": 20 + }, + "114": + { + "min": 37, + "max": 37 + }, + "80": + { + "min": 10, + "max": 15 + } + } + }, + "talrashasguardianship": + { + "DisplayName": "Tal Rasha's Guardianship", + "NTIPAliasClassID": 440, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "91": + { + "min": -60, + "max": -60 + }, + "35": + { + "min": 15, + "max": 15 + }, + "80": + { + "min": 88, + "max": 88 + }, + "43": + { + "min": 40, + "max": 40 + }, + "39": + { + "min": 40, + "max": 40 + }, + "41": + { + "min": 40, + "max": 40 + }, + "31": + { + "min": 400, + "max": 400 + } + } + }, + "talrashashoradriccrest": + { + "DisplayName": "Tal Rasha's Horadric Crest", + "NTIPAliasClassID": 358, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "8": + { + "min": 30, + "max": 30 + }, + "6": + { + "min": 60, + "max": 60 + }, + "31": + { + "min": 45, + "max": 45 + }, + "39": 15, + "43": 15, + "41": 15, + "45": 15, + "60": + { + "min": 10, + "max": 10 + }, + "62": + { + "min": 10, + "max": 10 + } + } + }, + "talrashaslidlesseye": + { + "DisplayName": "Tal Rasha's Lidless Eye", + "NTIPAliasClassID": 290, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "6": + { + "min": 57, + "max": 57 + }, + "8": + { + "min": 77, + "max": 77 + }, + "1": + { + "min": 10, + "max": 10 + }, + "105": + { + "min": 20, + "max": 20 + }, + "107,61": + { + "min": 1, + "max": 2 + }, + "107,63": + { + "min": 1, + "max": 2 + }, + "107,65": + { + "min": 1, + "max": 2 + } + } + }, + "tancredscrowbill": + { + "DisplayName": "Tancred's Crowbill", + "NTIPAliasClassID": 3, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "19": + { + "min": 75, + "max": 75 + }, + "25": + { + "min": 80, + "max": 80 + } + } + }, + "tancredshobnails": + { + "DisplayName": "Tancred's Hobnails", + "NTIPAliasClassID": 339, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "28": + { + "min": 25, + "max": 25 + }, + "2": + { + "min": 10, + "max": 10 + } + } + }, + "tancredsskull": + { + "DisplayName": "Tancred's Skull", + "NTIPAliasClassID": 349, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "25": + { + "min": 10, + "max": 10 + }, + "19": + { + "min": 40, + "max": 40 + } + } + }, + "tancredsspine": + { + "DisplayName": "Tancred's Spine", + "NTIPAliasClassID": 325, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "6": + { + "min": 40, + "max": 40 + }, + "0": + { + "min": 15, + "max": 15 + } + } + }, + "tancredsweird": + { + "DisplayName": "Tancred's Weird", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "34": + { + "min": 2, + "max": 2 + }, + "35": + { + "min": 1, + "max": 1 + } + } + }, + "tellingofbeads": + { + "DisplayName": "Telling of Beads", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "45": + { + "min": 35, + "max": 50 + }, + "127": + { + "min": 1, + "max": 1 + }, + "43": + { + "min": 18, + "max": 18 + }, + "78": + { + "min": 8, + "max": 10 + } + } + }, + "trangoulsclaws": + { + "DisplayName": "Trang-Oul's Claws", + "NTIPAliasClassID": 382, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 30, + "max": 30 + }, + "105": + { + "min": 20, + "max": 20 + }, + "43": + { + "min": 30, + "max": 30 + }, + "188,16": + { + "min": 2, + "max": 2, + "par": "Curses" + } + } + }, + "trangoulsgirth": + { + "DisplayName": "Trang-Oul's Girth", + "NTIPAliasClassID": 463, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "31": + { + "min": 75, + "max": 100 + }, + "10": + { + "min": 30, + "max": 30 + }, + "74": + { + "min": 5, + "max": 5 + }, + "6": + { + "min": 66, + "max": 66 + }, + "153": + { + "min": 1, + "max": 1 + }, + "91": + { + "min": -40, + "max": -40 + }, + "8": + { + "min": 25, + "max": 50 + } + } + }, + "trangoulsguise": + { + "DisplayName": "Trang-Oul's Guise", + "NTIPAliasClassID": 465, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 80, + "max": 100 + }, + "99": + { + "min": 25, + "max": 25 + }, + "78": + { + "min": 20, + "max": 20 + }, + "8": + { + "min": 150, + "max": 150 + }, + "74": + { + "min": 5, + "max": 5 + } + } + }, + "trangoulsscales": + { + "DisplayName": "Trang-Oul's Scales", + "NTIPAliasClassID": 371, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "91": + { + "min": -40, + "max": -40 + }, + "32": + { + "min": 100, + "max": 100 + }, + "45": + { + "min": 40, + "max": 40 + }, + "188,18": + { + "min": 2, + "max": 2, + "par": "Summoning Skills" + }, + "96": + { + "min": 40, + "max": 40 + }, + "16,0": + { + "min": 150, + "max": 150 + } + } + }, + "trangoulswing": + { + "DisplayName": "Trang-Oul's Wing", + "NTIPAliasClassID": 486, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "31": + { + "min": 125, + "max": 125 + }, + "0": + { + "min": 25, + "max": 25 + }, + "2": + { + "min": 15, + "max": 15 + }, + "39": + { + "min": 38, + "max": 45 + }, + "20": + { + "min": 30, + "max": 30 + }, + "45": + { + "min": 40, + "max": 40 + }, + "188,17": + { + "min": 2, + "max": 2, + "par": "Poison and Bone Skills" + } + } + }, + "vidalasambush": + { + "DisplayName": "Vidala's Ambush", + "NTIPAliasClassID": 314, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 50, + "max": 50 + }, + "2": + { + "min": 11, + "max": 11 + } + } + }, + "vidalasbarb": + { + "DisplayName": "Vidala's Barb", + "NTIPAliasClassID": 73, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 20, + "max": 20 + } + } + }, + "vidalasfetlock": + { + "DisplayName": "Vidala's Fetlock", + "NTIPAliasClassID": 342, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "10": + { + "min": 150, + "max": 150 + }, + "96": + { + "min": 30, + "max": 30 + } + } + }, + "vidalassnare": + { + "DisplayName": "Vidala's Snare", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "6": + { + "min": 15, + "max": 15 + }, + "43": + { + "min": 20, + "max": 20 + } + } + }, + "whitstansguard": + { + "DisplayName": "Whitstan's Guard", + "NTIPAliasClassID": 375, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 175, + "max": 175 + }, + "102": + { + "min": 40, + "max": 40 + }, + "20": + { + "min": 55, + "max": 55 + }, + "118": + { + "min": 1, + "max": 1 + }, + "89": + { + "min": 5, + "max": 5 + } + } + }, + "wilhelmspride": + { + "DisplayName": "Wilhelm's Pride", + "NTIPAliasClassID": 393, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 75, + "max": 75 + }, + "62": + { + "min": 5, + "max": 5 + }, + "43": + { + "min": 10, + "max": 10 + }, + "60": + { + "min": 5, + "max": 5 + } + } + } +} + +ITEM_TYPES = { + "amazon_bow": { + "display_name": "Amazon Bow", + "items": [ + "stag_bow", + "reflex_bow", + "ashwood_bow", + "ceremonial_bow", + "matriarchal_bow", + "grand_matron_bow" + ] + }, + "amazon_item": { + "display_name": "Amazon Item", + "items": [] + }, + "amazon_javelin": { + "display_name": "Amazon Javelin", + "items": [ + "maiden_javelin", + "ceremonial_javelin", + "matriarchal_javelin" + ] + }, + "amazon_spear": { + "display_name": "Amazon Spear", + "items": [ + "maiden_spear", + "maiden_pike", + "ceremonial_spear", + "ceremonial_pike", + "matriarchal_spear", + "matriarchal_pike" + ] + }, + "amethyst": { + "display_name": "Amethyst", + "items": [ + "chipped_amethyst", + "flawed_amethyst", + "perfect_amethyst", + "amethyst", + "flawless_amethyst" + ] + }, + "amulet": { + "display_name": "Amulet", + "items": [ + "amulet", + "top_of_the_horadric_staff" + ] + }, + "antidote_potion": { + "display_name": "Antidote Potion", + "items": [ + "antidote_potion" + ] + }, + "any_armor": { + "display_name": "Any Armor", + "items": [] + }, + "any_shield": { + "display_name": "Any Shield", + "items": [] + }, + "armor": { + "display_name": "Armor", + "items": [ + "ancient_armor", + "breast_plate", + "chain_mail", + "field_plate", + "full_plate_mail", + "gothic_plate", + "hard_leather_armor", + "leather_armor", + "light_plate", + "plate_mail", + "quilted_armor", + "ring_mail", + "scale_mail", + "splint_mail", + "studded_leather", + "sacred_armor", + "loricated_mail", + "wyrmhide", + "boneweave", + "scarab_husk", + "kraken_shell", + "hellforge_plate", + "diamond_mail", + "balrog_skin", + "great_hauberk", + "lacquered_plate", + "archon_plate", + "wire_fleece", + "dusk_shroud", + "shadow_plate", + "ornate_plate", + "tigulated_mail", + "serpentskin_armor", + "mesh_armor", + "demonhide_armor", + "sharktooth_armor", + "templar_coat", + "linked_mail", + "russet_armor", + "cuirass", + "embossed_plate", + "mage_plate", + "trellised_armor", + "ghost_armor", + "chaos_armor" + ] + }, + "assassin_item": { + "display_name": "Assassin Item", + "items": [] + }, + "auric_shields": { + "display_name": "Auric Shields", + "items": [ + "targe", + "rondache", + "heraldic_shield", + "aerin_shield", + "crown_shield", + "akaran_targe", + "akaran_rondache", + "protector_shield", + "gilded_shield", + "royal_shield", + "sacred_targe", + "sacred_rondache", + "kurast_shield", + "zakarum_shield", + "vortex_shield" + ] + }, + "axe": { + "display_name": "Axe", + "items": [ + "double_axe", + "ettin_axe", + "small_crescent", + "silveredged_axe", + "decapitator", + "champion_axe", + "glorious_axe", + "tomahawk", + "feral_axe", + "war_spike", + "berserker_axe", + "twin_axe", + "cleaver", + "bearded_axe", + "tabar", + "gothic_axe", + "ancient_axe", + "hatchet", + "military_axe", + "crowbill", + "naga", + "axe", + "broad_axe", + "battle_axe", + "great_axe", + "giant_axe", + "hand_axe", + "large_axe", + "military_pick", + "war_axe" + ] + }, + "barbarian_item": { + "display_name": "Barbarian Item", + "items": [] + }, + "belt": { + "display_name": "Belt", + "items": [ + "plated_belt", + "sash", + "belt", + "heavy_belt", + "colossus_girdle", + "spiderweb_sash", + "mithril_coil", + "troll_belt", + "vampirefang_belt", + "light_belt", + "war_belt", + "demonhide_sash", + "mesh_belt", + "battle_belt", + "sharkskin_belt" + ] + }, + "blunt": { + "display_name": "Blunt", + "items": [] + }, + "body_part": { + "display_name": "Body Part", + "items": [ + "brain", + "eye", + "flag", + "fang", + "horn", + "heart", + "jawbone", + "quill", + "scalp", + "soul", + "spleen", + "tail" + ] + }, + "book": { + "display_name": "Book", + "items": [ + "tome_of_identify", + "tome_of_town_portal" + ] + }, + "boots": { + "display_name": "Boots", + "items": [ + "greaves", + "boots", + "chain_boots", + "light_plated_boots", + "myrmidon_greaves", + "wyrmhide_boots", + "boneweave_boots", + "mirrored_boots", + "scarabshell_boots", + "heavy_boots", + "war_boots", + "demonhide_boots", + "mesh_boots", + "battle_boots", + "sharkskin_boots" + ] + }, + "bow": { + "display_name": "Bow", + "items": [ + "great_bow", + "blade_bow", + "crusader_bow", + "shadow_bow", + "hydra_bow", + "diamond_bow", + "spider_bow", + "ward_bow", + "double_bow", + "razor_bow", + "large_siege_bow", + "cedar_bow", + "gothic_bow", + "short_siege_bow", + "edge_bow", + "rune_bow", + "composite_bow", + "hunters_bow", + "long_battle_bow", + "long_bow", + "long_war_bow", + "short_battle_bow", + "short_bow", + "short_war_bow" + ] + }, + "bow_quiver": { + "display_name": "Bow Quiver", + "items": [ + "arrows" + ] + }, + "charm": { + "display_name": "Charm", + "items": [] + }, + "chipped_gem": { + "display_name": "Chipped Gem", + "items": [ + "chipped_sapphire", + "chipped_emerald", + "chipped_ruby", + "chipped_amethyst", + "chipped_diamond", + "chipped_topaz", + "chipped_skull" + ] + }, + "circlet": { + "display_name": "Circlet", + "items": [ + "circlet", + "coronet", + "tiara", + "diadem" + ] + }, + "class_specific": { + "display_name": "Class Specific", + "items": [] + }, + "cloak": { + "display_name": "Cloak", + "items": [] + }, + "club": { + "display_name": "Club", + "items": [ + "truncheon", + "tyrant_club", + "cudgel", + "barbed_club", + "club", + "wirts_leg", + "spiked_club" + ] + }, + "combo_weapon": { + "display_name": "Combo Weapon", + "items": [] + }, + "crossbow": { + "display_name": "Crossbow", + "items": [ + "colossus_crossbow", + "pellet_bow", + "gorgon_crossbow", + "demon_crossbow", + "ballista", + "arbalest", + "siege_crossbow", + "chukonu", + "heavy_crossbow", + "light_crossbow", + "crossbow", + "repeating_crossbow" + ] + }, + "crossbow_quiver": { + "display_name": "Crossbow Quiver", + "items": [ + "bolts" + ] + }, + "diamond": { + "display_name": "Diamond", + "items": [ + "chipped_diamond", + "flawed_diamond", + "flawless_diamond", + "perfect_diamond", + "diamond" + ] + }, + "druid_item": { + "display_name": "Druid Item", + "items": [] + }, + "elixir": { + "display_name": "Elixir", + "items": [ + "elixir" + ] + }, + "emerald": { + "display_name": "Emerald", + "items": [ + "chipped_emerald", + "flawed_emerald", + "flawless_emerald", + "perfect_emerald", + "emerald" + ] + }, + "flawed_gem": { + "display_name": "Flawed Gem", + "items": [ + "flawed_sapphire", + "flawed_emerald", + "flawed_ruby", + "flawed_amethyst", + "flawed_diamond", + "flawed_topaz", + "flawed_skull" + ] + }, + "flawless_gem": { + "display_name": "Flawless Gem", + "items": [ + "flawless_sapphire", + "flawless_emerald", + "flawless_ruby", + "flawless_diamond", + "flawless_topaz", + "flawless_amethyst", + "flawless_skull" + ] + }, + "gem": { + "display_name": "Gem", + "items": [] + }, + "gloves": { + "display_name": "Gloves", + "items": [ + "gauntlets", + "leather_gloves", + "chain_gloves", + "light_gauntlets", + "ogre_gauntlets", + "bramble_mitts", + "vambraces", + "crusader_gauntlets", + "vampirebone_gloves", + "heavy_gloves", + "war_gauntlets", + "demonhide_gloves", + "heavy_bracers", + "battle_gauntlets", + "sharkskin_gloves" + ] + }, + "gold": { + "display_name": "Gold", + "items": [ + "gold" + ] + }, + "hammer": { + "display_name": "Hammer", + "items": [ + "thunder_maul", + "ogre_maul", + "legendary_mallet", + "martel_de_fer", + "war_club", + "battle_hammer", + "great_maul", + "horadric_malus", + "hell_forge_hammer", + "maul", + "war_hammer" + ] + }, + "hand_to_hand": { + "display_name": "Hand to Hand", + "items": [ + "quhab", + "wrist_spike", + "fascia", + "hatchet_hands", + "blade_talons", + "cestus", + "claws", + "katar", + "scissors_katar", + "wrist_blade" + ] + }, + "hand_to_hand_2": { + "display_name": "Hand to Hand 2", + "items": [ + "suwayyah", + "battle_cestus", + "feral_claws", + "scissors_suwayyah", + "runic_talons", + "wrist_sword", + "war_fist", + "hand_scythe", + "greater_claws", + "scissors_quhab", + "greater_talons" + ] + }, + "healing_potion": { + "display_name": "Healing Potion", + "items": [ + "minor_healing_potion", + "light_healing_potion", + "healing_potion", + "greater_healing_potion", + "super_healing_potion" + ] + }, + "helm": { + "display_name": "Helm", + "items": [ + "bone_helm", + "cap", + "crown", + "full_helm", + "great_helm", + "helm", + "mask", + "skull_cap", + "shako", + "bone_visage", + "giant_conch", + "spired_helm", + "hydraskull", + "armet", + "corona", + "demonhead", + "war_hat", + "grim_helm", + "basinet", + "winged_helm", + "sallet", + "casque", + "grand_crown", + "death_mask" + ] + }, + "herb": { + "display_name": "Herb", + "items": [ + "herb" + ] + }, + "javelin": { + "display_name": "Javelin", + "items": [ + "ghost_glaive", + "hyperion_javelin", + "stygian_pilum", + "balrog_spear", + "winged_harpoon", + "spiculum", + "war_javelin", + "great_pilum", + "simbilan", + "harpoon", + "glaive", + "javelin", + "pilum", + "short_spear", + "throwing_spear" + ] + }, + "jewel": { + "display_name": "Jewel", + "items": [ + "jewel" + ] + }, + "key": { + "display_name": "Key", + "items": [ + "key", + "the_black_tower_key" + ] + }, + "knife": { + "display_name": "Knife", + "items": [ + "legend_spike", + "bone_knife", + "mithril_point", + "fanged_knife", + "stiletto", + "poignard", + "rondel", + "cinquedeas", + "blade", + "decoy_gidbinn", + "dagger", + "dirk", + "the_gidbinn", + "kris" + ] + }, + "large_charm": { + "display_name": "Large Charm", + "items": [ + "grand_charm" + ] + }, + "mace": { + "display_name": "Mace", + "items": [ + "scourge", + "reinforced_mace", + "devil_star", + "knout", + "flanged_mace", + "jagged_star", + "flail", + "mace", + "morning_star", + "khalims_flail", + "khalims_will" + ] + }, + "magic_bow_quiv": { + "display_name": "Magic Bow Quiv", + "items": [] + }, + "magic_xbow_quiv": { + "display_name": "Magic Xbow Quiv", + "items": [] + }, + "mana_potion": { + "display_name": "Mana Potion", + "items": [ + "minor_mana_potion", + "light_mana_potion", + "mana_potion", + "greater_mana_potion", + "super_mana_potion" + ] + }, + "medium_charm": { + "display_name": "Medium Charm", + "items": [ + "large_charm" + ] + }, + "melee_weapon": { + "display_name": "Melee Weapon", + "items": [] + }, + "miscellaneous": { + "display_name": "Miscellaneous", + "items": [] + }, + "missile": { + "display_name": "Missile", + "items": [] + }, + "missile_potion": { + "display_name": "Missile Potion", + "items": [ + "strangling_gas_potion", + "choking_gas_potion", + "rancid_gas_potion", + "fulminating_potion", + "exploding_potion", + "oil_potion" + ] + }, + "missile_weapon": { + "display_name": "Missile Weapon", + "items": [] + }, + "necromancer_item": { + "display_name": "Necromancer Item", + "items": [] + }, + "orb": { + "display_name": "Orb", + "items": [ + "eagle_orb", + "sacred_globe", + "smoked_sphere", + "clasped_orb", + "jareds_stone", + "glowing_orb", + "crystalline_globe", + "cloudy_sphere", + "sparkling_ball", + "swirling_crystal", + "heavenly_stone", + "eldritch_orb", + "demon_heart", + "vortex_orb", + "dimensional_shard" + ] + }, + "paladin_item": { + "display_name": "Paladin Item", + "items": [] + }, + "pelt": { + "display_name": "Pelt", + "items": [ + "wolf_head", + "hawk_helm", + "antlers", + "falcon_mask", + "spirit_mask", + "alpha_helm", + "griffon_headdress", + "hunters_guise", + "sacred_feathers", + "totemic_mask", + "blood_spirit", + "sun_spirit", + "earth_spirit", + "sky_spirit", + "dream_spirit" + ] + }, + "perfect_gem": { + "display_name": "Perfect Gem", + "items": [ + "perfect_sapphire", + "perfect_emerald", + "perfect_ruby", + "perfect_amethyst", + "perfect_diamond", + "perfect_topaz", + "perfect_skull" + ] + }, + "player_body_part": { + "display_name": "Player Body Part", + "items": [ + "ear" + ] + }, + "polearm": { + "display_name": "Polearm", + "items": [ + "great_poleaxe", + "ogre_axe", + "cryptic_axe", + "thresher", + "colossus_voulge", + "giant_thresher", + "lochaber_axe", + "becdecorbin", + "partizan", + "battle_scythe", + "bill", + "grim_scythe", + "bardiche", + "halberd", + "poleaxe", + "scythe", + "voulge", + "war_scythe" + ] + }, + "potion": { + "display_name": "Potion", + "items": [] + }, + "primal_helm": { + "display_name": "Primal Helm", + "items": [ + "jawbone_cap", + "fanged_helm", + "horned_helm", + "assault_helmet", + "avenger_guard", + "jawbone_visor", + "lion_helm", + "rage_mask", + "savage_helmet", + "slayer_guard", + "carnage_helm", + "fury_visor", + "destroyer_helm", + "conqueror_crown", + "guardian_crown" + ] + }, + "quest": { + "display_name": "Quest", + "items": [ + "right_click_to_learn_skill_of_your_choicebook_of_skill", + "lam_esens_tome", + "burning_essence_of_terror", + "baals_eye", + "key_to_the_cairn_stones", + "scroll_of_inifuss", + "horadric_cube", + "charged_essence_of_hatred", + "diablos_horn", + "festering_essence_of_destruction", + "the_golden_bird", + "keep_it_to_thaw_anyamalahs_potion", + "a_jade_figurine", + "mephistos_brain", + "mephistos_soulstone", + "key_of_terror", + "key_of_hate", + "key_of_destruction", + "khalims_brain", + "khalims_eye", + "khalims_heart", + "standard_of_heroes", + "twisted_essence_of_suffering", + "rightclick_to_reset_statskill_pointstoken_of_absolution", + "horadric_scroll", + "right_click_to_castscroll_of_resistance", + "right_click_to_permanently_add_20_to_lifepotion_of_life" + ] + }, + "rejuv_potion": { + "display_name": "Rejuv Potion", + "items": [ + "full_rejuvenation_potion", + "rejuvenation_potion" + ] + }, + "ring": { + "display_name": "Ring", + "items": [ + "ring" + ] + }, + "ruby": { + "display_name": "Ruby", + "items": [ + "chipped_ruby", + "flawed_ruby", + "flawless_ruby", + "perfect_ruby", + "ruby" + ] + }, + "rune": { + "display_name": "Rune", + "items": [ + "el_rune", + "eld_rune", + "tir_rune", + "nef_rune", + "eth_rune", + "ith_rune", + "tal_rune", + "ral_rune", + "ort_rune", + "thul_rune", + "amn_rune", + "sol_rune", + "shael_rune", + "dol_rune", + "hel_rune", + "io_rune", + "lum_rune", + "ko_rune", + "fal_rune", + "lem_rune", + "pul_rune", + "um_rune", + "mal_rune", + "ist_rune", + "gul_rune", + "vex_rune", + "ohm_rune", + "lo_rune", + "sur_rune", + "ber_rune", + "jah_rune", + "cham_rune", + "zod_rune" + ] + }, + "sapphire": { + "display_name": "Sapphire", + "items": [ + "chipped_sapphire", + "flawed_sapphire", + "flawless_sapphire", + "perfect_sapphire", + "sapphire" + ] + }, + "scepter": { + "display_name": "Scepter", + "items": [ + "seraph_rod", + "mighty_scepter", + "caduceus", + "holy_water_sprinkler", + "rune_scepter", + "divine_scepter", + "grand_scepter", + "scepter", + "war_scepter" + ] + }, + "scroll": { + "display_name": "Scroll", + "items": [ + "scroll_of_knowledge", + "scroll_of_identify", + "scroll_of_town_portal" + ] + }, + "second_hand": { + "display_name": "Second Hand", + "items": [] + }, + "shield": { + "display_name": "Shield", + "items": [ + "bone_shield", + "buckler", + "gothic_shield", + "kite_shield", + "large_shield", + "small_shield", + "spiked_shield", + "tower_shield", + "monarch", + "luna", + "aegis", + "blade_barrier", + "hyperion", + "troll_nest", + "ward", + "heater", + "dragon_shield", + "round_shield", + "pavise", + "barbed_shield", + "scutum", + "grim_shield", + "ancient_shield", + "defender" + ] + }, + "skull": { + "display_name": "Skull", + "items": [ + "chipped_skull", + "flawed_skull", + "flawless_skull", + "skull", + "perfect_skull" + ] + }, + "small_charm": { + "display_name": "Small Charm", + "items": [ + "small_charm" + ] + }, + "socket_filler": { + "display_name": "Socket Filler", + "items": [] + }, + "sorceress_item": { + "display_name": "Sorceress Item", + "items": [] + }, + "spear": { + "display_name": "Spear", + "items": [ + "mancatcher", + "war_pike", + "hyperion_spear", + "ghost_spear", + "stygian_pike", + "war_fork", + "lance", + "war_spear", + "yari", + "fuscina", + "brandistock", + "pike", + "spear", + "spetum", + "trident" + ] + }, + "staff": { + "display_name": "Staff", + "items": [ + "shillelagh", + "elder_staff", + "stalagmite", + "walking_stick", + "archon_staff", + "gothic_staff", + "cedar_staff", + "quarterstaff", + "jo_staff", + "rune_staff", + "battle_staff", + "gnarled_staff", + "horadric_staff", + "long_staff", + "shaft_of_the_horadric_staff", + "short_staff", + "war_staff" + ] + }, + "stamina_potion": { + "display_name": "Stamina Potion", + "items": [ + "stamina_potion" + ] + }, + "standard_gem": { + "display_name": "Standard Gem", + "items": [ + "sapphire", + "emerald", + "ruby", + "amethyst", + "diamond", + "topaz", + "skull" + ] + }, + "staves_and_rods": { + "display_name": "Staves And Rods", + "items": [] + }, + "sword": { + "display_name": "Sword", + "items": [ + "twohanded_sword", + "legend_sword", + "champion_sword", + "conquest_sword", + "highland_blade", + "phase_blade", + "colossus_sword", + "hydra_edge", + "colossus_blade", + "balrog_blade", + "cryptic_sword", + "elegant_blade", + "ataghan", + "falcata", + "mythical_sword", + "espandon", + "gothic_sword", + "battle_sword", + "dacian_falx", + "dimensional_blade", + "zweihander", + "tulwar", + "executioner_sword", + "tusk_sword", + "rune_sword", + "shamshir", + "cutlass", + "gladius", + "ancient_sword", + "broad_sword", + "bastard_sword", + "claymore", + "crystal_sword", + "flamberge", + "falchion", + "giant_sword", + "great_sword", + "long_sword", + "sabre", + "scimitar", + "short_sword", + "war_sword" + ] + }, + "thawing_potion": { + "display_name": "Thawing Potion", + "items": [ + "thawing_potion" + ] + }, + "throwing_axe": { + "display_name": "Throwing Axe", + "items": [ + "winged_axe", + "flying_axe", + "hurlbat", + "francisca", + "balanced_axe", + "throwing_axe" + ] + }, + "throwing_knife": { + "display_name": "Throwing Knife", + "items": [ + "winged_knife", + "flying_knife", + "war_dart", + "battle_dart", + "balanced_knife", + "throwing_knife" + ] + }, + "thrown_weapon": { + "display_name": "Thrown Weapon", + "items": [] + }, + "topaz": { + "display_name": "Topaz", + "items": [ + "chipped_topaz", + "flawed_topaz", + "flawless_topaz", + "perfect_topaz", + "topaz" + ] + }, + "torch": { + "display_name": "Torch", + "items": [ + "torch" + ] + }, + "voodoo_heads": { + "display_name": "Voodoo Heads", + "items": [ + "preserved_head", + "zombie_head", + "unraveller_head", + "gargoyle_head", + "demon_head", + "mummified_trophy", + "fetish_trophy", + "sexton_trophy", + "cantor_trophy", + "hierophant_trophy", + "minion_skull", + "overseer_skull", + "succubus_skull", + "bloodlord_skull", + "hellspawn_skull" + ] + }, + "wand": { + "display_name": "Wand", + "items": [ + "lich_wand", + "unearthed_wand", + "polished_wand", + "ghost_wand", + "tomb_wand", + "grave_wand", + "burnt_wand", + "petrified_wand", + "bone_wand", + "grim_wand", + "wand", + "yew_wand" + ] + }, + "weapon": { + "display_name": "Weapon", + "items": [] + } +} + +ITEM_UNIQUE_ITEMS = { + "almanegra": + { + "DisplayName": "Alma Negra", + "NTIPAliasClassID": 499, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 180, + "max": 210 + }, + "102": + { + "min": 30, + "max": 30 + }, + "83,3": + { + "min": 1, + "max": 2 + }, + "20": + { + "min": 20, + "max": 20 + }, + "35": + { + "min": 5, + "max": 9 + }, + "119": + { + "min": 40, + "max": 75 + }, + "25": + { + "min": 40, + "max": 75 + } + } + }, + "amuletoftheviper": + { + "DisplayName": "Amulet of the Viper", + "NTIPAliasClassID": 521, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "8": + { + "min": 10, + "max": 10 + }, + "45": + { + "min": 25, + "max": 25 + }, + "6": + { + "min": 10, + "max": 10 + } + } + }, + "andarielsvisage": + { + "DisplayName": "Andariel's Visage", + "NTIPAliasClassID": 428, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 100, + "max": 150 + }, + "45": + { + "min": 70, + "max": 70 + }, + "127": + { + "min": 2, + "max": 2 + }, + "46": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 25, + "max": 30 + }, + "201": + { + "chance": 15, + "level": 15, + "skill": "Poison Nova" + }, + "204": + { + "charges": 20, + "level": 3, + "skill": "Venom" + }, + "60": + { + "min": 8, + "max": 10 + }, + "39": + { + "min": -30, + "max": -30 + } + } + }, + "annihilus": + { + "DisplayName": "Annihilus", + "NTIPAliasClassID": 603, + "NTIPAliasType": 82, + "NTIPAliasStatProps": + { + "127": + { + "min": 1, + "max": 1 + }, + "0": + { + "min": 10, + "max": 20 + }, + "1": + { + "min": 10, + "max": 20 + }, + "2": + { + "min": 10, + "max": 20 + }, + "3": + { + "min": 10, + "max": 20 + }, + "39": + { + "min": 10, + "max": 20 + }, + "43": + { + "min": 10, + "max": 20 + }, + "41": + { + "min": 10, + "max": 20 + }, + "45": + { + "min": 10, + "max": 20 + }, + "85": + { + "min": 5, + "max": 10 + } + } + }, + "arachnidmesh": + { + "DisplayName": "Arachnid Mesh", + "NTIPAliasClassID": 460, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 90, + "max": 120 + }, + "105": + { + "min": 20, + "max": 20 + }, + "204": + { + "charges": 11, + "level": 3, + "skill": "Venom" + }, + "127": + { + "min": 1, + "max": 1 + }, + "150": + { + "min": 10, + "max": 10 + }, + "77": + { + "min": 5, + "max": 5 + } + } + }, + "ariocsneedle": + { + "DisplayName": "Arioc's Needle", + "NTIPAliasClassID": 248, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "57": 394, + "58": 394, + "141": + { + "min": 50, + "max": 50 + }, + "115": + { + "min": 1, + "max": 1 + }, + "127": + { + "min": 2, + "max": 4 + }, + "93": + { + "min": 30, + "max": 30 + } + } + }, + "arkainesvalor": + { + "DisplayName": "Arkaine's Valor", + "NTIPAliasClassID": 437, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 150, + "max": 180 + }, + "99": + { + "min": 30, + "max": 30 + }, + "127": + { + "min": 1, + "max": 2 + }, + "34": + { + "min": 10, + "max": 15 + }, + "223": + { + "min": None, + "max": None, + "par": 4 + } + } + }, + "armofkingleoric": + { + "DisplayName": "Arm of King Leoric", + "NTIPAliasClassID": 105, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "188,18": + { + "min": 2, + "max": 2, + "par": "Summoning Skills" + }, + "201": + { + "chance": 10, + "level": 2, + "skill": "Bone Prison" + }, + "217": + { + "min": None, + "max": None, + "par": 10 + }, + "105": + { + "min": 10, + "max": 10 + }, + "188,17": + { + "min": 2, + "max": 2, + "par": "Poison and Bone Skills" + }, + "107,77": + { + "min": 2, + "max": 2 + }, + "107,80": + { + "min": 2, + "max": 2 + }, + "107,69": + { + "min": 3, + "max": 3 + }, + "107,70": + { + "min": 3, + "max": 3 + } + } + }, + "arreatsface": + { + "DisplayName": "Arreat's Face", + "NTIPAliasClassID": 477, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "83,4": + { + "min": 2, + "max": 2 + }, + "188,32": + { + "min": 2, + "max": 2, + "par": "Combat Skills" + }, + "16,0": + { + "min": 150, + "max": 200 + }, + "99": + { + "min": 30, + "max": 30 + }, + "119": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 20, + "max": 20 + }, + "60": + { + "min": 3, + "max": 6 + }, + "39": 30, + "43": 30, + "41": 30, + "45": 30 + } + }, + "astreonsironward": + { + "DisplayName": "Astreon's Iron Ward", + "NTIPAliasClassID": 213, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "25": + { + "min": 240, + "max": 290 + }, + "150": + { + "min": 25, + "max": 25 + }, + "119": + { + "min": 150, + "max": 200 + }, + "93": + { + "min": 10, + "max": 10 + }, + "52": 80, + "53": 240, + "34": + { + "min": 4, + "max": 7 + }, + "21": 40, + "22": 85, + "188,24": + { + "min": 2, + "max": 4, + "par": "Combat Skills" + }, + "136": + { + "min": 33, + "max": 33 + } + } + }, + "athenaswrath": + { + "DisplayName": "Athena's Wrath", + "NTIPAliasClassID": 152, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "83,5": + { + "min": 1, + "max": 3 + }, + "2": + { + "min": 15, + "max": 15 + }, + "93": + { + "min": 30, + "max": 30 + }, + "216": + { + "min": None, + "max": None, + "par": 8 + }, + "218": + { + "min": None, + "max": None, + "par": 8 + }, + "25": + { + "min": 150, + "max": 180 + } + } + }, + "atmasscarab": + { + "DisplayName": "Atma's Scarab", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "57": 40, + "58": 40, + "45": + { + "min": 75, + "max": 75 + }, + "89": + { + "min": 3, + "max": 3 + }, + "78": + { + "min": 5, + "max": 5 + }, + "198": + { + "chance": 5, + "level": 2, + "skill": "Amplify Damage" + }, + "119": + { + "min": 20, + "max": 20 + } + } + }, + "atmaswail": + { + "DisplayName": "Atma's Wail", + "NTIPAliasClassID": 370, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "2": + { + "min": 15, + "max": 15 + }, + "74": + { + "min": 10, + "max": 10 + }, + "77": + { + "min": 15, + "max": 15 + }, + "99": + { + "min": 30, + "max": 30 + }, + "214": + { + "min": None, + "max": None, + "par": 16 + }, + "72": 50, + "73": 50, + "16,0": + { + "min": 120, + "max": 160 + }, + "80": + { + "min": 20, + "max": 20 + } + } + }, + "axeoffechmar": + { + "DisplayName": "Axe of Fechmar", + "NTIPAliasClassID": 5, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 70, + "max": 90 + }, + "134": + { + "min": 3, + "max": 3 + }, + "43": + { + "min": 50, + "max": 50 + }, + "89": + { + "min": 2, + "max": 2 + } + } + }, + "azurewrath": + { + "DisplayName": "Azurewrath", + "NTIPAliasClassID": 225, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "52": 250, + "53": 500, + "25": + { + "min": 230, + "max": 270 + }, + "151": + { + "min": 10, + "max": 13, + "par": "Sanctuary" + }, + "54": 250, + "55": 500, + "93": + { + "min": 30, + "max": 30 + }, + "0": + { + "min": 10, + "max": 20 + }, + "1": + { + "min": 10, + "max": 20 + }, + "2": + { + "min": 10, + "max": 20 + }, + "3": + { + "min": 10, + "max": 20 + }, + "89": + { + "min": 3, + "max": 3 + }, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "baezilsvortex": + { + "DisplayName": "Baezil's Vortex", + "NTIPAliasClassID": 114, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "198": + { + "chance": 5, + "level": 8, + "skill": "Nova" + }, + "50": 1, + "51": 150, + "8": + { + "min": 100, + "max": 100 + }, + "41": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 160, + "max": 200 + }, + "93": + { + "min": 20, + "max": 20 + }, + "204": + { + "charges": 80, + "level": 15, + "skill": "Nova" + } + } + }, + "baneash": + { + "DisplayName": "Bane Ash", + "NTIPAliasClassID": 63, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "48": + { + "min": 4, + "max": 4 + }, + "49": + { + "min": 6, + "max": 6 + }, + "39": + { + "min": 50, + "max": 50 + }, + "8": + { + "min": 30, + "max": 30 + }, + "93": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 50, + "max": 60 + }, + "107,36": + { + "min": 5, + "max": 5 + }, + "107,37": + { + "min": 2, + "max": 2 + } + } + }, + "baranarsstar": + { + "DisplayName": "Baranar's Star", + "NTIPAliasClassID": 216, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "119": + { + "min": 200, + "max": 200 + }, + "25": + { + "min": 200, + "max": 200 + }, + "2": + { + "min": 15, + "max": 15 + }, + "0": + { + "min": 15, + "max": 15 + }, + "93": + { + "min": 50, + "max": 50 + }, + "72": 100, + "73": 100, + "50": 1, + "51": 200, + "48": 1, + "49": 200, + "54": 1, + "55": 200 + } + }, + "bartucscutthroat": + { + "DisplayName": "Bartuc's Cut-Throat", + "NTIPAliasClassID": 187, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "83,6": + { + "min": 2, + "max": 2 + }, + "188,50": + { + "min": 1, + "max": 1, + "par": "Martial Arts" + }, + "25": + { + "min": 150, + "max": 200 + }, + "99": + { + "min": 30, + "max": 30 + }, + "119": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 20, + "max": 20 + }, + "60": + { + "min": 5, + "max": 9 + }, + "21": 25, + "22": 50 + } + }, + "bigginsbonnet": + { + "DisplayName": "Biggin's Bonnet", + "NTIPAliasClassID": 306, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "6": + { + "min": 15, + "max": 15 + }, + "19": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 30, + "max": 30 + }, + "8": + { + "min": 15, + "max": 15 + }, + "31": + { + "min": 14, + "max": 14 + } + } + }, + "bingszwang": + { + "DisplayName": "Bing Sz Wang", + "NTIPAliasClassID": 127, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "91": + { + "min": -30, + "max": -30 + }, + "54": 50, + "55": 140, + "0": + { + "min": 20, + "max": 20 + }, + "134": + { + "min": 2, + "max": 2 + }, + "198": + { + "chance": 5, + "level": 3, + "skill": "Frozen Orb" + }, + "25": + { + "min": 130, + "max": 160 + } + } + }, + "blackhades": + { + "DisplayName": "Black Hades", + "NTIPAliasClassID": 371, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "89": + { + "min": -2, + "max": -2 + }, + "123": + { + "min": 200, + "max": 250 + }, + "118": + { + "min": 1, + "max": 1 + }, + "194": + { + "min": 3, + "max": 3 + }, + "16,0": + { + "min": 140, + "max": 200 + }, + "121": + { + "min": 30, + "max": 60 + } + } + }, + "blackbogssharp": + { + "DisplayName": "Blackbog's Sharp", + "NTIPAliasClassID": 134, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "150": + { + "min": 50, + "max": 50 + }, + "31": + { + "min": 50, + "max": 50 + }, + "21": 15, + "22": 45, + "93": + { + "min": 30, + "max": 30 + }, + "57": 488, + "58": 488, + "107,73": + { + "min": 5, + "max": 5 + }, + "107,83": + { + "min": 4, + "max": 4 + }, + "107,92": + { + "min": 4, + "max": 4 + } + } + }, + "blackhandkey": + { + "DisplayName": "Blackhand Key", + "NTIPAliasClassID": 106, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "188,16": + { + "min": 1, + "max": 1, + "par": "Curses" + }, + "114": + { + "min": 20, + "max": 20 + }, + "6": + { + "min": 50, + "max": 50 + }, + "89": + { + "min": -2, + "max": -2 + }, + "105": + { + "min": 30, + "max": 30 + }, + "39": + { + "min": 37, + "max": 37 + }, + "83,2": + { + "min": 2, + "max": 2 + }, + "204": + { + "charges": 30, + "level": 13, + "skill": "Grim Ward" + } + } + }, + "blackhornsface": + { + "DisplayName": "Blackhorn's Face", + "NTIPAliasClassID": 358, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "128": + { + "min": 25, + "max": 25 + }, + "150": + { + "min": 20, + "max": 20 + }, + "117": + { + "min": 1, + "max": 1 + }, + "145": + { + "min": 20, + "max": 20 + }, + "41": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 180, + "max": 220 + } + } + }, + "blackleachblade": + { + "DisplayName": "Blackleach Blade", + "NTIPAliasClassID": 151, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "91": + { + "min": -25, + "max": -25 + }, + "198": + { + "chance": 5, + "level": 5, + "skill": "Weaken" + }, + "89": + { + "min": -2, + "max": -2 + }, + "60": + { + "min": 8, + "max": 8 + }, + "218": + { + "min": None, + "max": None, + "par": 10 + }, + "25": + { + "min": 100, + "max": 140 + } + } + }, + "blackoakshield": + { + "DisplayName": "Blackoak Shield", + "NTIPAliasClassID": 445, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "221": + { + "min": None, + "max": None, + "par": 4 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "234": + { + "min": None, + "max": None + }, + "201": + { + "chance": 4, + "level": 5, + "skill": "Weaken" + }, + "72": 45, + "73": 45, + "216": + { + "min": None, + "max": None, + "par": 10 + }, + "102": + { + "min": 50, + "max": 50 + }, + "118": + { + "min": 1, + "max": 1 + } + } + }, + "blacktongue": + { + "DisplayName": "Blacktongue", + "NTIPAliasClassID": 36, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "57": 112, + "58": 112, + "117": + { + "min": 1, + "max": 1 + }, + "19": + { + "min": 50, + "max": 50 + }, + "45": + { + "min": 50, + "max": 50 + }, + "25": + { + "min": 50, + "max": 60 + } + } + }, + "bladeofalibaba": + { + "DisplayName": "Blade of Ali Baba", + "NTIPAliasClassID": 121, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 3, + "max": 3 + }, + "239": + { + "min": None, + "max": None, + "par": 20 + }, + "240": + { + "min": None, + "max": None, + "par": 8 + }, + "8": + { + "min": 15, + "max": 15 + }, + "25": + { + "min": 60, + "max": 120 + }, + "2": + { + "min": 5, + "max": 15 + } + } + }, + "bladebone": + { + "DisplayName": "Bladebone", + "NTIPAliasClassID": 2, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "122": + { + "min": 100, + "max": 100 + }, + "124": + { + "min": 40, + "max": 40 + }, + "93": + { + "min": 20, + "max": 20 + }, + "31": + { + "min": 20, + "max": 20 + }, + "48": + { + "min": 8, + "max": 8 + }, + "49": + { + "min": 12, + "max": 12 + }, + "25": + { + "min": 30, + "max": 50 + } + } + }, + "bladebuckle": + { + "DisplayName": "Bladebuckle", + "NTIPAliasClassID": 348, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "78": + { + "min": 8, + "max": 8 + }, + "31": + { + "min": 30, + "max": 30 + }, + "34": + { + "min": 3, + "max": 3 + }, + "0": + { + "min": 5, + "max": 5 + }, + "2": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 80, + "max": 100 + }, + "99": + { + "min": 30, + "max": 30 + } + } + }, + "blastbark": + { + "DisplayName": "Blastbark", + "NTIPAliasClassID": 75, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "25": + { + "min": 70, + "max": 130 + }, + "0": + { + "min": 5, + "max": 5 + }, + "83,0": + { + "min": 1, + "max": 1 + }, + "62": + { + "min": 3, + "max": 3 + }, + "107,16": + { + "min": 2, + "max": 2 + } + } + }, + "blinkbatsform": + { + "DisplayName": "Blinkbat's Form", + "NTIPAliasClassID": 314, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "32": + { + "min": 50, + "max": 50 + }, + "96": + { + "min": 10, + "max": 10 + }, + "31": + { + "min": 25, + "max": 25 + }, + "48": + { + "min": 3, + "max": 3 + }, + "49": + { + "min": 6, + "max": 6 + }, + "99": + { + "min": 40, + "max": 40 + } + } + }, + "bloodcrescent": + { + "DisplayName": "Blood Crescent", + "NTIPAliasClassID": 26, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "39": 15, + "43": 15, + "41": 15, + "45": 15, + "25": + { + "min": 60, + "max": 80 + }, + "6": + { + "min": 15, + "max": 15 + }, + "89": + { + "min": 4, + "max": 4 + }, + "135": + { + "min": 33, + "max": 33 + }, + "93": + { + "min": 15, + "max": 15 + }, + "60": + { + "min": 15, + "max": 15 + } + } + }, + "bloodravenscharge": + { + "DisplayName": "Blood Raven's Charge", + "NTIPAliasClassID": 301, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "119": + { + "min": 200, + "max": 300 + }, + "158": + { + "min": 13, + "max": 13 + }, + "188,0": + { + "min": 2, + "max": 4, + "par": "Bow and Crossbow Skills" + }, + "204": + { + "charges": 30, + "level": 5, + "skill": "Revive" + } + } + }, + "bloodfist": + { + "DisplayName": "Bloodfist", + "NTIPAliasClassID": 335, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "21": + { + "min": 5, + "max": 5 + }, + "6": + { + "min": 40, + "max": 40 + }, + "99": + { + "min": 30, + "max": 30 + }, + "31": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 10, + "max": 20 + }, + "93": + { + "min": 10, + "max": 10 + } + } + }, + "bloodletter": + { + "DisplayName": "Bloodletter", + "NTIPAliasClassID": 118, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "21": 12, + "22": 45, + "19": + { + "min": 90, + "max": 90 + }, + "60": + { + "min": 8, + "max": 8 + }, + "154": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 140, + "max": 140 + }, + "107,127": + { + "min": 2, + "max": 4 + }, + "107,151": + { + "min": 1, + "max": 3 + }, + "72": 30, + "73": 30 + } + }, + "bloodmoon": + { + "DisplayName": "Bloodmoon", + "NTIPAliasClassID": 223, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "25": + { + "min": 210, + "max": 260 + }, + "60": + { + "min": 10, + "max": 15 + }, + "204": + { + "charges": 9, + "level": 15, + "skill": "BloodGolem" + }, + "86": + { + "min": 7, + "max": 13 + }, + "135": + { + "min": 50, + "max": 50 + } + } + }, + "bloodrise": + { + "DisplayName": "Bloodrise", + "NTIPAliasClassID": 20, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "25": + { + "min": 120, + "max": 120 + }, + "119": + { + "min": 50, + "max": 50 + }, + "135": + { + "min": 25, + "max": 25 + }, + "89": + { + "min": 2, + "max": 2 + }, + "93": + { + "min": 10, + "max": 10 + }, + "107,96": + { + "min": 3, + "max": 3 + }, + "60": + { + "min": 5, + "max": 5 + } + } + }, + "bloodthief": + { + "DisplayName": "Bloodthief", + "NTIPAliasClassID": 54, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "135": + { + "min": 35, + "max": 35 + }, + "0": + { + "min": 10, + "max": 10 + }, + "60": + { + "min": 8, + "max": 12 + }, + "6": + { + "min": 26, + "max": 26 + }, + "25": + { + "min": 50, + "max": 70 + } + } + }, + "bloodtreestump": + { + "DisplayName": "Bloodtree Stump", + "NTIPAliasClassID": 116, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "136": + { + "min": 50, + "max": 50 + }, + "25": + { + "min": 180, + "max": 220 + }, + "39": 20, + "43": 20, + "41": 20, + "45": 20, + "0": + { + "min": 25, + "max": 25 + }, + "188,33": + { + "min": 2, + "max": 2, + "par": "Masteries" + }, + "107,129": + { + "min": 3, + "max": 3 + }, + "72": 40, + "73": 40 + } + }, + "boneflame": + { + "DisplayName": "Boneflame", + "NTIPAliasClassID": 506, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 150 + }, + "96": + { + "min": 20, + "max": 20 + }, + "201": + { + "chance": 15, + "level": 3, + "skill": "Terror" + }, + "83,2": + { + "min": 2, + "max": 3 + }, + "39": + { + "min": 20, + "max": 30 + }, + "43": + { + "min": 20, + "max": 30 + }, + "41": + { + "min": 20, + "max": 30 + }, + "45": + { + "min": 20, + "max": 30 + } + } + }, + "boneflesh": + { + "DisplayName": "Boneflesh", + "NTIPAliasClassID": 322, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "60": + { + "min": 5, + "max": 5 + }, + "16,0": + { + "min": 100, + "max": 120 + }, + "19": + { + "min": 35, + "max": 35 + }, + "135": + { + "min": 25, + "max": 25 + } + } + }, + "bonehew": + { + "DisplayName": "Bonehew", + "NTIPAliasClassID": 253, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "25": + { + "min": 270, + "max": 320 + }, + "93": + { + "min": 30, + "max": 30 + }, + "204": + { + "charges": 30, + "level": 14, + "skill": "Corpse Explosion" + }, + "198": + { + "chance": 50, + "level": 16, + "skill": "Bone Spear" + }, + "117": + { + "min": 1, + "max": 1 + }, + "194": + { + "min": 2, + "max": 2 + } + } + }, + "boneshade": + { + "DisplayName": "Boneshade", + "NTIPAliasClassID": 208, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "83,2": + { + "min": 2, + "max": 2 + }, + "105": + { + "min": 25, + "max": 25 + }, + "107,67": + { + "min": 4, + "max": 5 + }, + "107,68": + { + "min": 4, + "max": 5 + }, + "107,84": + { + "min": 2, + "max": 3 + }, + "107,93": + { + "min": 1, + "max": 2 + }, + "107,78": + { + "min": 2, + "max": 3 + } + } + }, + "boneslayerblade": + { + "DisplayName": "Boneslayer Blade", + "NTIPAliasClassID": 101, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "244": + { + "min": None, + "max": None, + "par": 20 + }, + "0": + { + "min": 8, + "max": 8 + }, + "93": + { + "min": 20, + "max": 20 + }, + "119": + { + "min": 35, + "max": 35 + }, + "25": + { + "min": 180, + "max": 220 + }, + "204": + { + "charges": 200, + "level": 20, + "skill": "Holy Bolt" + }, + "201": + { + "chance": 50, + "level": None, + "skill": "Holy Bolt" + } + } + }, + "bonesnap": + { + "DisplayName": "Bonesnap", + "NTIPAliasClassID": 23, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "25": + { + "min": 200, + "max": 300 + }, + "136": + { + "min": 40, + "max": 40 + }, + "39": + { + "min": 30, + "max": 30 + }, + "43": + { + "min": 30, + "max": 30 + }, + "122": + { + "min": 50, + "max": 50 + } + } + }, + "brainhew": + { + "DisplayName": "Brainhew", + "NTIPAliasClassID": 8, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "21": + { + "min": 14, + "max": 14 + }, + "8": + { + "min": 25, + "max": 25 + }, + "89": + { + "min": 4, + "max": 4 + }, + "62": + { + "min": 10, + "max": 13 + }, + "25": + { + "min": 50, + "max": 80 + }, + "48": 15, + "49": 35 + } + }, + "bulkathosweddingband": + { + "DisplayName": "Bul-Kathos' Wedding Band", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "216": + { + "min": None, + "max": None, + "par": 4 + }, + "127": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 3, + "max": 5 + }, + "10": + { + "min": 50, + "max": 50 + } + } + }, + "burizadokyanon": + { + "DisplayName": "Buriza-Do Kyanon", + "NTIPAliasClassID": 171, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "156": + { + "min": 100, + "max": 100 + }, + "2": + { + "min": 35, + "max": 35 + }, + "31": + { + "min": 75, + "max": 150 + }, + "218": + { + "min": None, + "max": None, + "par": 20 + }, + "93": + { + "min": 80, + "max": 80 + }, + "25": + { + "min": 150, + "max": 200 + }, + "134": + { + "min": 3, + "max": 3 + }, + "54": 32, + "55": 196 + } + }, + "butcherspupil": + { + "DisplayName": "Butcher's Pupil", + "NTIPAliasClassID": 94, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "141": + { + "min": 35, + "max": 35 + }, + "135": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 150, + "max": 200 + }, + "152": + { + "min": 1, + "max": 1 + }, + "93": + { + "min": 30, + "max": 30 + }, + "21": 30, + "22": 50 + } + }, + "bverritkeep": + { + "DisplayName": "Bverrit Keep", + "NTIPAliasClassID": 332, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 30, + "max": 30 + }, + "39": + { + "min": 75, + "max": 75 + }, + "0": + { + "min": 5, + "max": 5 + }, + "35": + { + "min": 5, + "max": 5 + }, + "16,0": + { + "min": 80, + "max": 120 + }, + "20": + { + "min": 10, + "max": 10 + }, + "72": 80, + "73": 100 + } + }, + "carinshard": + { + "DisplayName": "Carin Shard", + "NTIPAliasClassID": 104, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "216": + { + "min": None, + "max": None, + "par": 10 + }, + "105": + { + "min": 10, + "max": 10 + }, + "217": + { + "min": None, + "max": None, + "par": 10 + }, + "99": + { + "min": 30, + "max": 30 + }, + "74": + { + "min": 5, + "max": 5 + }, + "83,2": + { + "min": 1, + "max": 1 + }, + "188,18": + { + "min": 2, + "max": 2, + "par": "Summoning Skills" + } + } + }, + "carrionwind": + { + "DisplayName": "Carrion Wind", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "32": + { + "min": 100, + "max": 160 + }, + "60": + { + "min": 6, + "max": 9 + }, + "45": + { + "min": 55, + "max": 55 + }, + "201": + { + "chance": 10, + "level": 10, + "skill": "Poison Nova" + }, + "204": + { + "charges": 15, + "level": 21, + "skill": "Plague Poppy" + }, + "198": + { + "chance": 8, + "level": 13, + "skill": "Twister" + }, + "114": + { + "min": 10, + "max": 10 + } + } + }, + "cerebusbite": + { + "DisplayName": "Cerebus' Bite", + "NTIPAliasClassID": 488, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 130, + "max": 140 + }, + "188,41": + { + "min": 2, + "max": 4, + "par": "Shape Shifting Skills" + }, + "60": + { + "min": 7, + "max": 10 + }, + "119": + { + "min": 60, + "max": 120 + }, + "135": + { + "min": 33, + "max": 33 + }, + "107,232": + { + "min": 1, + "max": 2 + } + } + }, + "chanceguards": + { + "DisplayName": "Chance Guards", + "NTIPAliasClassID": 336, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "79": + { + "min": 200, + "max": 200 + }, + "80": + { + "min": 25, + "max": 40 + }, + "19": + { + "min": 25, + "max": 25 + }, + "31": + { + "min": 15, + "max": 15 + }, + "89": + { + "min": 2, + "max": 2 + }, + "16,0": + { + "min": 20, + "max": 30 + } + } + }, + "chromaticire": + { + "DisplayName": "Chromatic Ire", + "NTIPAliasClassID": 158, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 3, + "max": 3 + }, + "39": + { + "min": 20, + "max": 40 + }, + "43": + { + "min": 20, + "max": 40 + }, + "41": + { + "min": 20, + "max": 40 + }, + "45": + { + "min": 20, + "max": 40 + }, + "105": + { + "min": 20, + "max": 20 + }, + "128": + { + "min": 20, + "max": 20 + }, + "76": + { + "min": 20, + "max": 25 + }, + "107,61": + { + "min": 1, + "max": 1 + }, + "107,63": + { + "min": 1, + "max": 1 + }, + "107,65": + { + "min": 1, + "max": 1 + } + } + }, + "cliffkiller": + { + "DisplayName": "Cliffkiller", + "NTIPAliasClassID": 166, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "83,0": + { + "min": 2, + "max": 2 + }, + "25": + { + "min": 190, + "max": 230 + }, + "32": + { + "min": 80, + "max": 80 + }, + "81": + { + "min": 1, + "max": 1 + }, + "6": + { + "min": 50, + "max": 50 + }, + "21": + { + "min": 5, + "max": 10 + }, + "22": + { + "min": 20, + "max": 30 + } + } + }, + "cloudcrack": + { + "DisplayName": "Cloudcrack", + "NTIPAliasClassID": 129, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "198": + { + "chance": 6, + "level": 7, + "skill": "Fist of the Heavens" + }, + "50": 1, + "51": 240, + "31": + { + "min": 30, + "max": 30 + }, + "89": + { + "min": 2, + "max": 2 + }, + "42": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 150, + "max": 200 + }, + "128": + { + "min": 15, + "max": 15 + }, + "188,25": + { + "min": 2, + "max": 2, + "par": "Offensive Auras" + }, + "188,26": + { + "min": 2, + "max": 2, + "par": "Defensive Auras" + } + } + }, + "coifofglory": + { + "DisplayName": "Coif of Glory", + "NTIPAliasClassID": 308, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "128": + { + "min": 7, + "max": 7 + }, + "113": + { + "min": 1, + "max": 1 + }, + "41": + { + "min": 15, + "max": 15 + }, + "32": + { + "min": 100, + "max": 100 + }, + "31": + { + "min": 10, + "max": 10 + } + } + }, + "coldkill": + { + "DisplayName": "Coldkill", + "NTIPAliasClassID": 93, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "54": 40, + "55": 40, + "43": + { + "min": 15, + "max": 15 + }, + "44": + { + "min": 15, + "max": 15 + }, + "93": + { + "min": 30, + "max": 30 + }, + "198": + { + "chance": 10, + "level": 10, + "skill": "Ice Blast" + }, + "201": + { + "chance": 10, + "level": 5, + "skill": "Frost Nova" + }, + "25": + { + "min": 150, + "max": 190 + } + } + }, + "coldsteeleye": + { + "DisplayName": "Coldsteel Eye", + "NTIPAliasClassID": 119, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "113": + { + "min": 1, + "max": 1 + }, + "150": + { + "min": 30, + "max": 30 + }, + "141": + { + "min": 50, + "max": 50 + }, + "72": 50, + "73": 50, + "25": + { + "min": 200, + "max": 250 + }, + "93": + { + "min": 20, + "max": 20 + }, + "62": + { + "min": 6, + "max": 6 + } + } + }, + "constrictingring": + { + "DisplayName": "Constricting Ring", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "39": 100, + "43": 100, + "41": 100, + "45": 100, + "74": + { + "min": -30, + "max": -30 + }, + "80": + { + "min": 100, + "max": 100 + }, + "40": 15, + "44": 15, + "42": 15, + "46": 15 + } + }, + "corpsemourn": + { + "DisplayName": "Corpsemourn", + "NTIPAliasClassID": 372, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "0": + { + "min": 8, + "max": 8 + }, + "3": + { + "min": 10, + "max": 10 + }, + "43": + { + "min": 35, + "max": 35 + }, + "201": + { + "chance": 6, + "level": 2, + "skill": "Iron Maiden" + }, + "16,0": + { + "min": 150, + "max": 180 + }, + "48": 12, + "49": 36, + "204": + { + "charges": 40, + "level": 5, + "skill": "Corpse Explosion" + } + } + }, + "craintevomir": + { + "DisplayName": "Crainte Vomir", + "NTIPAliasClassID": 126, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "150": + { + "min": 35, + "max": 35 + }, + "120": + { + "min": -70, + "max": -70 + }, + "96": + { + "min": 20, + "max": 20 + }, + "36": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 160, + "max": 200 + }, + "93": + { + "min": 50, + "max": 50 + } + } + }, + "cranebeak": + { + "DisplayName": "Cranebeak", + "NTIPAliasClassID": 199, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 240, + "max": 300 + }, + "50": 1, + "51": 305, + "93": + { + "min": 40, + "max": 40 + }, + "116": + { + "min": 25, + "max": 25 + }, + "80": + { + "min": 20, + "max": 50 + }, + "204": + { + "charges": 15, + "level": 8, + "skill": "Raven" + } + } + }, + "crescentmoon": + { + "DisplayName": "Crescent Moon", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "62": + { + "min": 11, + "max": 15 + }, + "35": + { + "min": 10, + "max": 10 + }, + "114": + { + "min": 10, + "max": 10 + }, + "89": + { + "min": -2, + "max": -2 + }, + "8": + { + "min": 45, + "max": 45 + }, + "60": + { + "min": 3, + "max": 6 + } + } + }, + "crowcaw": + { + "DisplayName": "Crow Caw", + "NTIPAliasClassID": 364, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "135": + { + "min": 35, + "max": 35 + }, + "16,0": + { + "min": 150, + "max": 180 + }, + "2": + { + "min": 15, + "max": 15 + }, + "99": + { + "min": 15, + "max": 15 + }, + "93": + { + "min": 15, + "max": 15 + } + } + }, + "crownofages": + { + "DisplayName": "Crown of Ages", + "NTIPAliasClassID": 427, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "99": + { + "min": 30, + "max": 30 + }, + "39": + { + "min": 20, + "max": 30 + }, + "43": + { + "min": 20, + "max": 30 + }, + "41": + { + "min": 20, + "max": 30 + }, + "45": + { + "min": 20, + "max": 30 + }, + "127": + { + "min": 1, + "max": 1 + }, + "31": + { + "min": 100, + "max": 150 + }, + "152": + { + "min": 1, + "max": 1 + }, + "36": + { + "min": 10, + "max": 15 + }, + "16,0": + { + "min": 50, + "max": 50 + }, + "194": + { + "min": 1, + "max": 2 + } + } + }, + "crownofthieves": + { + "DisplayName": "Crown of Thieves", + "NTIPAliasClassID": 357, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "2": + { + "min": 25, + "max": 25 + }, + "60": + { + "min": 9, + "max": 12 + }, + "6": + { + "min": 50, + "max": 50 + }, + "8": + { + "min": 35, + "max": 35 + }, + "39": + { + "min": 33, + "max": 33 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "79": + { + "min": 80, + "max": 100 + } + } + }, + "crushflange": + { + "DisplayName": "Crushflange", + "NTIPAliasClassID": 19, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "0": + { + "min": 15, + "max": 15 + }, + "81": + { + "min": 1, + "max": 1 + }, + "89": + { + "min": 2, + "max": 2 + }, + "39": + { + "min": 50, + "max": 50 + }, + "25": + { + "min": 50, + "max": 60 + }, + "136": + { + "min": 33, + "max": 33 + } + } + }, + "culwenspoint": + { + "DisplayName": "Culwen's Point", + "NTIPAliasClassID": 32, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "127": + { + "min": 1, + "max": 1 + }, + "110": + { + "min": 50, + "max": 50 + }, + "99": + { + "min": 20, + "max": 20 + }, + "93": + { + "min": 20, + "max": 20 + }, + "19": + { + "min": 60, + "max": 60 + }, + "25": + { + "min": 70, + "max": 80 + } + } + }, + "darkclancrusher": + { + "DisplayName": "Dark Clan Crusher", + "NTIPAliasClassID": 107, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "83,5": + { + "min": 2, + "max": 2 + }, + "121": + { + "min": 200, + "max": 200 + }, + "123": + { + "min": 200, + "max": 200 + }, + "25": + { + "min": 195, + "max": 195 + }, + "119": + { + "min": 20, + "max": 25 + }, + "139": + { + "min": 15, + "max": 15 + } + } + }, + "darkforcespawn": + { + "DisplayName": "Darkforce Spawn", + "NTIPAliasClassID": 507, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 140, + "max": 180 + }, + "105": + { + "min": 30, + "max": 30 + }, + "77": + { + "min": 10, + "max": 10 + }, + "188,16": + { + "min": 1, + "max": 3, + "par": "Curses" + }, + "188,17": + { + "min": 1, + "max": 3, + "par": "Poison and Bone Skills" + }, + "188,18": + { + "min": 1, + "max": 3, + "par": "Summoning Skills" + } + } + }, + "darkglow": + { + "DisplayName": "Darkglow", + "NTIPAliasClassID": 317, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "19": + { + "min": 20, + "max": 20 + }, + "40": 5, + "44": 5, + "42": 5, + "46": 5, + "89": + { + "min": 3, + "max": 3 + }, + "33": + { + "min": 50, + "max": 50 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "16,0": + { + "min": 70, + "max": 100 + } + } + }, + "darksighthelm": + { + "DisplayName": "Darksight Helm", + "NTIPAliasClassID": 355, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "89": + { + "min": -4, + "max": -4 + }, + "214": + { + "min": None, + "max": None, + "par": 16 + }, + "153": + { + "min": 1, + "max": 1 + }, + "62": + { + "min": 5, + "max": 5 + }, + "201": + { + "chance": 6, + "level": 3, + "skill": "Dim Vision" + }, + "204": + { + "charges": 30, + "level": 5, + "skill": "Cloak of Shadows" + }, + "39": + { + "min": 20, + "max": 40 + } + } + }, + "deathcleaver": + { + "DisplayName": "Death Cleaver", + "NTIPAliasClassID": 200, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 230, + "max": 280 + }, + "141": + { + "min": 66, + "max": 66 + }, + "116": + { + "min": 33, + "max": 33 + }, + "93": + { + "min": 40, + "max": 40 + }, + "86": + { + "min": 6, + "max": 9 + } + } + }, + "deathbit": + { + "DisplayName": "Deathbit", + "NTIPAliasClassID": 136, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "141": + { + "min": 40, + "max": 40 + }, + "25": + { + "min": 130, + "max": 180 + }, + "19": + { + "min": 200, + "max": 450 + }, + "60": + { + "min": 7, + "max": 9 + }, + "62": + { + "min": 4, + "max": 6 + }, + "253": + { + "min": None, + "max": None, + "par": 25 + } + } + }, + "deathsfathom": + { + "DisplayName": "Death's Fathom", + "NTIPAliasClassID": 300, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 3, + "max": 3 + }, + "331": + { + "min": 15, + "max": 30 + }, + "105": + { + "min": 20, + "max": 20 + }, + "39": + { + "min": 25, + "max": 40 + }, + "41": + { + "min": 25, + "max": 40 + } + } + }, + "deathsweb": + { + "DisplayName": "Death's Web", + "NTIPAliasClassID": 209, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "127": + { + "min": 2, + "max": 2 + }, + "336": + { + "min": 40, + "max": 50 + }, + "86": + { + "min": 7, + "max": 12 + }, + "138": + { + "min": 7, + "max": 12 + }, + "188,17": + { + "min": 1, + "max": 2, + "par": "Poison and Bone Skills" + } + } + }, + "deathspade": + { + "DisplayName": "Deathspade", + "NTIPAliasClassID": 1, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "113": + { + "min": 1, + "max": 1 + }, + "21": + { + "min": 8, + "max": 8 + }, + "119": + { + "min": 15, + "max": 15 + }, + "138": + { + "min": 4, + "max": 4 + }, + "25": + { + "min": 60, + "max": 70 + } + } + }, + "demonlimb": + { + "DisplayName": "Demon Limb", + "NTIPAliasClassID": 214, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "48": 222, + "49": 333, + "60": + { + "min": 7, + "max": 13 + }, + "204": + { + "charges": 20, + "level": 23, + "skill": "Enchant" + }, + "252": + { + "min": None, + "max": None, + "par": 5 + }, + "121": + { + "min": 123, + "max": 123 + }, + "39": + { + "min": 15, + "max": 20 + } + } + }, + "demonmachine": + { + "DisplayName": "Demon Machine", + "NTIPAliasClassID": 172, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "31": + { + "min": 321, + "max": 321 + }, + "8": + { + "min": 36, + "max": 36 + }, + "156": + { + "min": 66, + "max": 66 + }, + "158": + { + "min": 6, + "max": 6 + }, + "22": + { + "min": 66, + "max": 66 + }, + "25": + { + "min": 123, + "max": 123 + }, + "19": + { + "min": 632, + "max": 632 + } + } + }, + "demonhornsedge": + { + "DisplayName": "Demonhorn's Edge", + "NTIPAliasClassID": 495, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 160 + }, + "93": + { + "min": 10, + "max": 10 + }, + "60": + { + "min": 3, + "max": 6 + }, + "78": + { + "min": 55, + "max": 77 + }, + "188,32": + { + "min": 1, + "max": 3, + "par": "Combat Skills" + }, + "188,33": + { + "min": 1, + "max": 3, + "par": "Masteries" + }, + "188,34": + { + "min": 1, + "max": 3, + "par": "Warcries" + } + } + }, + "demonsarch": + { + "DisplayName": "Demon's Arch", + "NTIPAliasClassID": 245, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "25": + { + "min": 160, + "max": 210 + }, + "48": 232, + "49": 323, + "60": + { + "min": 6, + "max": 12 + }, + "253": + { + "min": None, + "max": None, + "par": 30 + }, + "93": + { + "min": 30, + "max": 30 + }, + "50": 23, + "51": 333 + } + }, + "dimoakshew": + { + "DisplayName": "Dimoak's Hew", + "NTIPAliasClassID": 57, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "2": + { + "min": 15, + "max": 15 + }, + "25": + { + "min": 100, + "max": 100 + }, + "93": + { + "min": 20, + "max": 20 + }, + "31": + { + "min": -8, + "max": -8 + } + } + }, + "djinnslayer": + { + "DisplayName": "Djinn Slayer", + "NTIPAliasClassID": 222, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "25": + { + "min": 190, + "max": 240 + }, + "48": 250, + "49": 500, + "121": + { + "min": 100, + "max": 150 + }, + "123": + { + "min": 200, + "max": 300 + }, + "145": + { + "min": 3, + "max": 7 + }, + "62": + { + "min": 3, + "max": 6 + }, + "194": + { + "min": 1, + "max": 2 + } + } + }, + "doombringer": + { + "DisplayName": "Doombringer", + "NTIPAliasClassID": 232, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "76": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 180, + "max": 250 + }, + "119": + { + "min": 40, + "max": 40 + }, + "152": + { + "min": 1, + "max": 1 + }, + "21": 30, + "22": 100, + "198": + { + "chance": 8, + "level": 3, + "skill": "Weaken" + }, + "60": + { + "min": 5, + "max": 7 + } + } + }, + "doomslinger": + { + "DisplayName": "Doomslinger", + "NTIPAliasClassID": 79, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "83,0": + { + "min": 1, + "max": 1 + }, + "156": + { + "min": 35, + "max": 35 + }, + "93": + { + "min": 30, + "max": 30 + }, + "6": + { + "min": 15, + "max": 15 + }, + "25": + { + "min": 60, + "max": 100 + } + } + }, + "draculsgrasp": + { + "DisplayName": "Dracul's Grasp", + "NTIPAliasClassID": 451, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 90, + "max": 120 + }, + "60": + { + "min": 7, + "max": 10 + }, + "135": + { + "min": 25, + "max": 25 + }, + "198": + { + "chance": 5, + "level": 10, + "skill": "Life Tap" + }, + "86": + { + "min": 5, + "max": 10 + }, + "0": + { + "min": 10, + "max": 15 + } + } + }, + "dragonscale": + { + "DisplayName": "Dragonscale", + "NTIPAliasClassID": 501, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 170, + "max": 200 + }, + "142": + { + "min": 10, + "max": 20 + }, + "40": + { + "min": 5, + "max": 5 + }, + "0": + { + "min": 15, + "max": 25 + }, + "48": 211, + "49": 371, + "107,62": + { + "min": 10, + "max": 10, + "par": "Hydra" + }, + "329": + { + "min": 15, + "max": 15 + } + } + }, + "durielsshell": + { + "DisplayName": "Duriel's Shell", + "NTIPAliasClassID": 366, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "0": + { + "min": 15, + "max": 15 + }, + "214": + { + "min": None, + "max": None, + "par": 10 + }, + "216": + { + "min": None, + "max": None, + "par": 8 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "39": + { + "min": 20, + "max": 20 + }, + "41": + { + "min": 20, + "max": 20 + }, + "45": + { + "min": 20, + "max": 20 + }, + "43": + { + "min": 50, + "max": 50 + }, + "153": + { + "min": 1, + "max": 1 + }, + "72": 100, + "73": 100 + } + }, + "duskdeep": + { + "DisplayName": "Duskdeep", + "NTIPAliasClassID": 309, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "89": + { + "min": -2, + "max": -2 + }, + "39": 15, + "43": 15, + "41": 15, + "45": 15, + "34": + { + "min": 7, + "max": 7 + }, + "22": + { + "min": 8, + "max": 8 + }, + "31": + { + "min": 10, + "max": 20 + }, + "16,0": + { + "min": 30, + "max": 50 + } + } + }, + "dwarfstar": + { + "DisplayName": "Dwarf Star", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "79": + { + "min": 100, + "max": 100 + }, + "10": + { + "min": 40, + "max": 40 + }, + "28": + { + "min": 15, + "max": 15 + }, + "6": + { + "min": 40, + "max": 40 + }, + "35": + { + "min": 12, + "max": 15 + }, + "142": + { + "min": 15, + "max": 15 + } + } + }, + "eaglehorn": + { + "DisplayName": "Eaglehorn", + "NTIPAliasClassID": 269, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "115": + { + "min": 1, + "max": 1 + }, + "224": + { + "min": None, + "max": None, + "par": 12 + }, + "219": + { + "min": None, + "max": None, + "par": 16 + }, + "25": + { + "min": 200, + "max": 200 + }, + "83,0": + { + "min": 1, + "max": 1 + }, + "2": + { + "min": 25, + "max": 25 + } + } + }, + "earthshifter": + { + "DisplayName": "Earth Shifter", + "NTIPAliasClassID": 220, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "25": + { + "min": 250, + "max": 300 + }, + "198": + { + "chance": 25, + "level": 14, + "skill": "Eruption" + }, + "136": + { + "min": 33, + "max": 33 + }, + "93": + { + "min": 10, + "max": 10 + }, + "204": + { + "charges": 30, + "level": 14, + "skill": "Volcano" + }, + "188,42": + { + "min": 7, + "max": 7, + "par": "Elemental Skills" + }, + "105": + { + "min": 10, + "max": 10 + } + } + }, + "earthshaker": + { + "DisplayName": "Earthshaker", + "NTIPAliasClassID": 115, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "198": + { + "chance": 5, + "level": 7, + "skill": "Eruption" + }, + "81": + { + "min": 1, + "max": 1 + }, + "93": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 180, + "max": 180 + }, + "113": + { + "min": 1, + "max": 1 + }, + "188,42": + { + "min": 3, + "max": 3, + "par": "Elemental Skills" + }, + "72": 50, + "73": 50 + } + }, + "endlesshail": + { + "DisplayName": "Endlesshail", + "NTIPAliasClassID": 164, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "43": + { + "min": 35, + "max": 35 + }, + "8": + { + "min": 40, + "max": 40 + }, + "32": + { + "min": 50, + "max": 50 + }, + "107,26": + { + "min": 3, + "max": 5 + }, + "25": + { + "min": 180, + "max": 220 + }, + "54": 15, + "55": 30 + } + }, + "eschutastemper": + { + "DisplayName": "Eschuta's Temper", + "NTIPAliasClassID": 297, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 1, + "max": 3 + }, + "105": + { + "min": 40, + "max": 40 + }, + "329": + { + "min": 10, + "max": 20 + }, + "330": + { + "min": 10, + "max": 20 + }, + "1": + { + "min": 20, + "max": 30 + } + } + }, + "etherealedge": + { + "DisplayName": "Ethereal Edge", + "NTIPAliasClassID": 202, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 180 + }, + "93": + { + "min": 25, + "max": 25 + }, + "143": + { + "min": 10, + "max": 12 + }, + "121": + { + "min": 150, + "max": 200 + }, + "139": + { + "min": 5, + "max": 10 + }, + "19": + { + "min": 270, + "max": 350 + }, + "0x400000": + { + "min": 1, + "max": 1 + }, + "152": + { + "min": 1, + "max": 1 + } + } + }, + "executionersjustice": + { + "DisplayName": "Executioner's Justice", + "NTIPAliasClassID": 205, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 240, + "max": 290 + }, + "136": + { + "min": 25, + "max": 25 + }, + "116": + { + "min": 33, + "max": 33 + }, + "196": + { + "chance": 50, + "level": 6, + "skill": "Decrepify" + }, + "93": + { + "min": 30, + "max": 30 + } + } + }, + "felloak": + { + "DisplayName": "Felloak", + "NTIPAliasClassID": 14, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "41": + { + "min": 60, + "max": 60 + }, + "39": + { + "min": 20, + "max": 20 + }, + "81": + { + "min": 1, + "max": 1 + }, + "48": + { + "min": 6, + "max": 6 + }, + "49": + { + "min": 8, + "max": 8 + }, + "25": + { + "min": 70, + "max": 80 + } + } + }, + "firelizardstalons": + { + "DisplayName": "Firelizard's Talons", + "NTIPAliasClassID": 193, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "25": + { + "min": 200, + "max": 270 + }, + "93": + { + "min": 15, + "max": 15 + }, + "188,50": + { + "min": 1, + "max": 3, + "par": "Martial Arts" + }, + "48": 236, + "49": 480, + "39": + { + "min": 40, + "max": 70 + }, + "107,262": + { + "min": 1, + "max": 2 + }, + "107,272": + { + "min": 1, + "max": 2 + } + } + }, + "flamebellow": + { + "DisplayName": "Flamebellow", + "NTIPAliasClassID": 231, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "25": + { + "min": 170, + "max": 240 + }, + "48": 233, + "49": 482, + "188,8": + { + "min": 3, + "max": 3 + }, + "142": + { + "min": 20, + "max": 30 + }, + "198": + { + "chance": 12, + "level": 16, + "skill": "Firestorm" + }, + "0": + { + "min": 10, + "max": 20 + }, + "3": + { + "min": 5, + "max": 10 + }, + "107,41": + { + "min": 12, + "max": 18, + "par": "Inferno" + } + } + }, + "fleshrender": + { + "DisplayName": "Fleshrender", + "NTIPAliasClassID": 111, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "135": + { + "min": 25, + "max": 25 + }, + "117": + { + "min": 1, + "max": 1 + }, + "136": + { + "min": 20, + "max": 20 + }, + "141": + { + "min": 20, + "max": 20 + }, + "21": 35, + "22": 50, + "25": + { + "min": 130, + "max": 200 + }, + "83,5": + { + "min": 1, + "max": 1 + }, + "188,41": + { + "min": 2, + "max": 2, + "par": "Shape Shifting Skills" + }, + "72": 20, + "73": 20 + } + }, + "fleshripper": + { + "DisplayName": "Fleshripper", + "NTIPAliasClassID": 237, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "25": + { + "min": 200, + "max": 300 + }, + "116": + { + "min": 50, + "max": 50 + }, + "117": + { + "min": 1, + "max": 1 + }, + "136": + { + "min": 25, + "max": 25 + }, + "135": + { + "min": 50, + "max": 50 + }, + "141": + { + "min": 33, + "max": 33 + }, + "150": + { + "min": 20, + "max": 20 + } + } + }, + "frostburn": + { + "DisplayName": "Frostburn", + "NTIPAliasClassID": 338, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 5, + "max": 5 + }, + "77": + { + "min": 40, + "max": 40 + }, + "54": 1, + "55": 6, + "16,0": + { + "min": 10, + "max": 20 + } + } + }, + "frostwind": + { + "DisplayName": "Frostwind", + "NTIPAliasClassID": 227, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "134": + { + "min": 4, + "max": 4 + }, + "118": + { + "min": 1, + "max": 1 + }, + "54": 237, + "55": 486, + "93": + { + "min": 25, + "max": 25 + }, + "148": + { + "min": 7, + "max": 15 + }, + "107,230": + { + "min": 7, + "max": 14, + "par": "Arctic Blast" + } + } + }, + "gargoylesbite": + { + "DisplayName": "Gargoyle's Bite", + "NTIPAliasClassID": 247, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "253": + { + "min": None, + "max": None, + "par": 30 + }, + "57": 293, + "58": 293, + "60": + { + "min": 9, + "max": 15 + }, + "204": + { + "charges": 60, + "level": 11, + "skill": "Plague Javelin" + } + } + }, + "gerkessanctuary": + { + "DisplayName": "Gerke's Sanctuary", + "NTIPAliasClassID": 378, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "34": + { + "min": 11, + "max": 16 + }, + "35": + { + "min": 14, + "max": 18 + }, + "74": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 180, + "max": 240 + }, + "72": 100, + "73": 100, + "20": + { + "min": 30, + "max": 30 + }, + "39": + { + "min": 20, + "max": 30 + }, + "43": + { + "min": 20, + "max": 30 + }, + "41": + { + "min": 20, + "max": 30 + }, + "45": + { + "min": 20, + "max": 30 + } + } + }, + "gheedsfortune": + { + "DisplayName": "Gheed's Fortune", + "NTIPAliasClassID": 605, + "NTIPAliasType": 84, + "NTIPAliasStatProps": + { + "80": + { + "min": 20, + "max": 40 + }, + "79": + { + "min": 80, + "max": 160 + }, + "87": + { + "min": 10, + "max": 15 + } + } + }, + "ghostflame": + { + "DisplayName": "Ghostflame", + "NTIPAliasClassID": 238, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "25": + { + "min": 190, + "max": 240 + }, + "115": + { + "min": 1, + "max": 1 + }, + "52": 108, + "53": 108, + "62": + { + "min": 10, + "max": 15 + }, + "0x400000": + { + "min": 1, + "max": 1 + }, + "152": + { + "min": 1, + "max": 1 + }, + "89": + { + "min": 2, + "max": 2 + } + } + }, + "ghoulhide": + { + "DisplayName": "Ghoulhide", + "NTIPAliasClassID": 382, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "244": + { + "min": None, + "max": None, + "par": 16 + }, + "62": + { + "min": 4, + "max": 5 + }, + "6": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 150, + "max": 190 + } + } + }, + "giantskull": + { + "DisplayName": "Giant Skull", + "NTIPAliasClassID": 465, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "31": + { + "min": 250, + "max": 320 + }, + "0": + { + "min": 25, + "max": 35 + }, + "136": + { + "min": 10, + "max": 10 + }, + "194": + { + "min": 1, + "max": 2 + }, + "81": + { + "min": 1, + "max": 1 + } + } + }, + "gimmershred": + { + "DisplayName": "Gimmershred", + "NTIPAliasClassID": 240, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "25": + { + "min": 160, + "max": 210 + }, + "48": 218, + "49": 483, + "54": 176, + "55": 397, + "50": 29, + "51": 501, + "254": + { + "min": 60, + "max": 60 + }, + "93": + { + "min": 30, + "max": 30 + } + } + }, + "ginthersrift": + { + "DisplayName": "Ginther's Rift", + "NTIPAliasClassID": 122, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "35": + { + "min": 7, + "max": 12 + }, + "93": + { + "min": 30, + "max": 30 + }, + "252": + { + "min": None, + "max": None, + "par": 20 + }, + "72": 40, + "73": 40, + "52": 50, + "53": 120, + "25": + { + "min": 100, + "max": 150 + } + } + }, + "gleamscythe": + { + "DisplayName": "Gleamscythe", + "NTIPAliasClassID": 28, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "89": + { + "min": 3, + "max": 3 + }, + "8": + { + "min": 30, + "max": 30 + }, + "31": + { + "min": 20, + "max": 20 + }, + "93": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 60, + "max": 100 + }, + "54": 3, + "55": 5 + } + }, + "gloomstrap": + { + "DisplayName": "Gloom's Trap", + "NTIPAliasClassID": 392, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "89": + { + "min": -3, + "max": -3 + }, + "77": + { + "min": 15, + "max": 15 + }, + "62": + { + "min": 5, + "max": 5 + }, + "16,0": + { + "min": 120, + "max": 150 + }, + "3": + { + "min": 15, + "max": 15 + }, + "27": + { + "min": 15, + "max": 15 + } + } + }, + "goblintoe": + { + "DisplayName": "Goblin Toe", + "NTIPAliasClassID": 342, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "136": + { + "min": 25, + "max": 25 + }, + "34": + { + "min": 1, + "max": 1 + }, + "35": + { + "min": 1, + "max": 1 + }, + "31": + { + "min": 15, + "max": 15 + }, + "89": + { + "min": -1, + "max": -1 + }, + "16,0": + { + "min": 50, + "max": 60 + } + } + }, + "goldskin": + { + "DisplayName": "Goldskin", + "NTIPAliasClassID": 325, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 150 + }, + "39": 35, + "43": 35, + "41": 35, + "45": 35, + "78": + { + "min": 10, + "max": 10 + }, + "89": + { + "min": 2, + "max": 2 + }, + "79": + { + "min": 100, + "max": 100 + } + } + }, + "goldstrikearch": + { + "DisplayName": "Goldstrike Arch", + "NTIPAliasClassID": 168, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "25": + { + "min": 200, + "max": 250 + }, + "119": + { + "min": 100, + "max": 150 + }, + "122": + { + "min": 100, + "max": 200 + }, + "121": + { + "min": 100, + "max": 200 + }, + "198": + { + "chance": 5, + "level": 7, + "skill": "Fist of the Heavens" + }, + "93": + { + "min": 50, + "max": 50 + }, + "74": + { + "min": 12, + "max": 12 + } + } + }, + "goldwrap": + { + "DisplayName": "Goldwrap", + "NTIPAliasClassID": 347, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "80": + { + "min": 30, + "max": 30 + }, + "89": + { + "min": 2, + "max": 2 + }, + "31": + { + "min": 25, + "max": 25 + }, + "93": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 40, + "max": 60 + }, + "79": + { + "min": 50, + "max": 80 + } + } + }, + "gorerider": + { + "DisplayName": "Gore Rider", + "NTIPAliasClassID": 389, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "91": + { + "min": -25, + "max": -25 + }, + "141": + { + "min": 15, + "max": 15 + }, + "96": + { + "min": 30, + "max": 30 + }, + "136": + { + "min": 15, + "max": 15 + }, + "135": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "72": 10, + "73": 10, + "10": + { + "min": 20, + "max": 20 + } + } + }, + "gorefoot": + { + "DisplayName": "Gorefoot", + "NTIPAliasClassID": 340, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "96": + { + "min": 20, + "max": 20 + }, + "62": + { + "min": 2, + "max": 2 + }, + "78": + { + "min": 2, + "max": 2 + }, + "31": + { + "min": 12, + "max": 12 + }, + "16,0": + { + "min": 20, + "max": 30 + }, + "107,132": + { + "min": 2, + "max": 2 + } + } + }, + "goreshovel": + { + "DisplayName": "Goreshovel", + "NTIPAliasClassID": 6, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "93": + { + "min": 30, + "max": 30 + }, + "0": + { + "min": 25, + "max": 25 + }, + "135": + { + "min": 60, + "max": 60 + }, + "25": + { + "min": 40, + "max": 50 + }, + "22": + { + "min": 9, + "max": 9 + } + } + }, + "gravenspine": + { + "DisplayName": "Gravenspine", + "NTIPAliasClassID": 12, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "0": + { + "min": 10, + "max": 10 + }, + "2": + { + "min": 10, + "max": 10 + }, + "54": + { + "min": 4, + "max": 4 + }, + "55": + { + "min": 8, + "max": 8 + }, + "56": + { + "min": 75, + "max": 75 + }, + "62": + { + "min": 5, + "max": 5 + }, + "83,2": + { + "min": 2, + "max": 2 + }, + "8": + { + "min": 25, + "max": 50 + } + } + }, + "gravepalm": + { + "DisplayName": "Gravepalm", + "NTIPAliasClassID": 381, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "1": + { + "min": 10, + "max": 10 + }, + "0": + { + "min": 10, + "max": 10 + }, + "122": + { + "min": 100, + "max": 200 + }, + "124": + { + "min": 100, + "max": 200 + }, + "16,0": + { + "min": 140, + "max": 180 + } + } + }, + "greyform": + { + "DisplayName": "Greyform", + "NTIPAliasClassID": 313, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "35": + { + "min": 3, + "max": 3 + }, + "43": + { + "min": 20, + "max": 20 + }, + "39": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 10, + "max": 10 + }, + "60": + { + "min": 5, + "max": 5 + }, + "31": + { + "min": 20, + "max": 20 + } + } + }, + "griffonseye": + { + "DisplayName": "Griffon's Eye", + "NTIPAliasClassID": 421, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "31": + { + "min": 100, + "max": 200 + }, + "105": + { + "min": 25, + "max": 25 + }, + "127": + { + "min": 1, + "max": 1 + }, + "330": + { + "min": 10, + "max": 15 + }, + "334": + { + "min": 15, + "max": 20 + } + } + }, + "grimsburningdead": + { + "DisplayName": "Grim's Burning Dead", + "NTIPAliasClassID": 155, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "48": 131, + "49": 232, + "39": + { + "min": 45, + "max": 45 + }, + "25": + { + "min": 140, + "max": 180 + }, + "78": + { + "min": 8, + "max": 8 + }, + "91": + { + "min": -50, + "max": -50 + }, + "83,2": + { + "min": 3, + "max": 3 + }, + "116": + { + "min": 50, + "max": 50 + }, + "16,0": + { + "min": 20, + "max": 20 + }, + "19": + { + "min": 200, + "max": 250 + } + } + }, + "griswoldsedge": + { + "DisplayName": "Griswold's Edge", + "NTIPAliasClassID": 30, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "48": + { + "min": 10, + "max": 12 + }, + "49": + { + "min": 15, + "max": 25 + }, + "19": + { + "min": 100, + "max": 100 + }, + "93": + { + "min": 10, + "max": 10 + }, + "81": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 80, + "max": 120 + }, + "0": + { + "min": 12, + "max": 12 + } + } + }, + "guardianangel": + { + "DisplayName": "Guardian Angel", + "NTIPAliasClassID": 368, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "89": + { + "min": 4, + "max": 4 + }, + "83,3": + { + "min": 1, + "max": 1 + }, + "16,0": + { + "min": 180, + "max": 200 + }, + "102": + { + "min": 30, + "max": 30 + }, + "40": 15, + "44": 15, + "42": 15, + "46": 15, + "245": + { + "min": None, + "max": None, + "par": 5 + }, + "20": + { + "min": 20, + "max": 20 + } + } + }, + "guardiannaga": + { + "DisplayName": "Guardian Naga", + "NTIPAliasClassID": 97, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "198": + { + "chance": 5, + "level": 8, + "skill": "Poison Nova" + }, + "78": + { + "min": 15, + "max": 15 + }, + "45": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 150, + "max": 180 + }, + "57": 250, + "58": 250, + "22": + { + "min": 20, + "max": 20 + } + } + }, + "gull": + { + "DisplayName": "Gull", + "NTIPAliasClassID": 39, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "21": + { + "min": 1, + "max": 1 + }, + "22": + { + "min": 15, + "max": 15 + }, + "80": + { + "min": 100, + "max": 100 + }, + "8": + { + "min": -5, + "max": -5 + } + } + }, + "gutsiphon": + { + "DisplayName": "Gut Siphon", + "NTIPAliasClassID": 275, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "25": + { + "min": 160, + "max": 220 + }, + "156": + { + "min": 33, + "max": 33 + }, + "60": + { + "min": 12, + "max": 18 + }, + "150": + { + "min": 25, + "max": 25 + }, + "135": + { + "min": 33, + "max": 33 + } + } + }, + "halaberdsreign": + { + "DisplayName": "Halaberd's Reign", + "NTIPAliasClassID": 496, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 140, + "max": 170 + }, + "188,33": + { + "min": 1, + "max": 1, + "par": "Masteries" + }, + "83,4": + { + "min": 2, + "max": 2 + }, + "99": + { + "min": 20, + "max": 20 + }, + "74": + { + "min": 15, + "max": 23 + }, + "107,149": + { + "min": 1, + "max": 2 + }, + "107,155": + { + "min": 1, + "max": 2 + } + } + }, + "handofblessedlight": + { + "DisplayName": "Hand of Blessed Light", + "NTIPAliasClassID": 110, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "83,3": + { + "min": 2, + "max": 2 + }, + "25": + { + "min": 130, + "max": 160 + }, + "119": + { + "min": 100, + "max": 100 + }, + "31": + { + "min": 50, + "max": 50 + }, + "27": + { + "min": 15, + "max": 15 + }, + "89": + { + "min": 4, + "max": 4 + }, + "21": 20, + "22": 45, + "107,101": + { + "min": 4, + "max": 4 + }, + "107,121": + { + "min": 2, + "max": 2 + }, + "198": + { + "chance": 5, + "level": 4, + "skill": "Fist of the Heavens" + } + } + }, + "harlequincrest": + { + "DisplayName": "Harlequin Crest", + "NTIPAliasClassID": 422, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "127": + { + "min": 2, + "max": 2 + }, + "216": + { + "min": None, + "max": None, + "par": 12 + }, + "217": + { + "min": None, + "max": None, + "par": 12 + }, + "80": + { + "min": 50, + "max": 50 + }, + "36": + { + "min": 10, + "max": 10 + }, + "0": + { + "min": 2, + "max": 2 + }, + "2": + { + "min": 2, + "max": 2 + }, + "3": + { + "min": 2, + "max": 2 + }, + "1": + { + "min": 2, + "max": 2 + } + } + }, + "hawkmail": + { + "DisplayName": "Hawkmail", + "NTIPAliasClassID": 318, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 80, + "max": 100 + }, + "44": + { + "min": 15, + "max": 15 + }, + "43": + { + "min": 15, + "max": 15 + }, + "153": + { + "min": 1, + "max": 1 + }, + "96": + { + "min": 10, + "max": 10 + } + } + }, + "headhuntersglory": + { + "DisplayName": "Head Hunter's Glory", + "NTIPAliasClassID": 466, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 320, + "max": 420 + }, + "32": + { + "min": 300, + "max": 350 + }, + "45": + { + "min": 30, + "max": 40 + }, + "194": + { + "min": 1, + "max": 3 + }, + "39": + { + "min": 20, + "max": 30 + }, + "86": + { + "min": 5, + "max": 7 + } + } + }, + "headstriker": + { + "DisplayName": "Headstriker", + "NTIPAliasClassID": 123, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "117": + { + "min": 1, + "max": 1 + }, + "0": + { + "min": 15, + "max": 15 + }, + "250": + { + "min": None, + "max": None, + "par": 12 + }, + "218": + { + "min": None, + "max": None, + "par": 8 + }, + "25": + { + "min": 150, + "max": 150 + } + } + }, + "heartcarver": + { + "DisplayName": "Heart Carver", + "NTIPAliasClassID": 133, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "141": + { + "min": 35, + "max": 35 + }, + "115": + { + "min": 1, + "max": 1 + }, + "21": 15, + "22": 35, + "25": + { + "min": 190, + "max": 240 + }, + "107,131": + { + "min": 4, + "max": 4 + }, + "107,142": + { + "min": 4, + "max": 4 + }, + "107,150": + { + "min": 4, + "max": 4 + } + } + }, + "heavenlygarb": + { + "DisplayName": "Heavenly Garb", + "NTIPAliasClassID": 327, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 100, + "max": 100 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "27": + { + "min": 25, + "max": 25 + }, + "1": + { + "min": 15, + "max": 15 + }, + "122": + { + "min": 50, + "max": 50 + }, + "124": + { + "min": 100, + "max": 100 + } + } + }, + "heavenslight": + { + "DisplayName": "Heaven's Light", + "NTIPAliasClassID": 211, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "25": + { + "min": 250, + "max": 300 + }, + "93": + { + "min": 20, + "max": 20 + }, + "116": + { + "min": 33, + "max": 33 + }, + "89": + { + "min": 3, + "max": 3 + }, + "139": + { + "min": 15, + "max": 20 + }, + "136": + { + "min": 33, + "max": 33 + }, + "194": + { + "min": 1, + "max": 3 + }, + "83,3": + { + "min": 2, + "max": 3 + } + } + }, + "hellforgehammer": + { + "DisplayName": "Hell Forge Hammer", + "NTIPAliasClassID": 90, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "48": + { + "min": 5, + "max": 5 + }, + "49": + { + "min": 20, + "max": 20 + }, + "39": + { + "min": 40, + "max": 40 + }, + "31": + { + "min": 35, + "max": 35 + } + } + }, + "hellcast": + { + "DisplayName": "Hellcast", + "NTIPAliasClassID": 78, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "158": + { + "min": 5, + "max": 5 + }, + "40": + { + "min": 15, + "max": 15 + }, + "39": + { + "min": 15, + "max": 15 + }, + "19": + { + "min": 70, + "max": 70 + }, + "93": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 70, + "max": 80 + }, + "48": 15, + "49": 35 + } + }, + "hellclap": + { + "DisplayName": "Hellclap", + "NTIPAliasClassID": 74, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "93": + { + "min": 10, + "max": 10 + }, + "48": + { + "min": 15, + "max": 15 + }, + "49": + { + "min": 30, + "max": 50 + }, + "19": + { + "min": 50, + "max": 75 + }, + "39": + { + "min": 40, + "max": 40 + }, + "2": + { + "min": 12, + "max": 12 + }, + "25": + { + "min": 70, + "max": 90 + }, + "188,8": + { + "min": 1, + "max": 1 + } + } + }, + "hellfiretorch": + { + "DisplayName": "Hellfire Torch", + "NTIPAliasClassID": 604, + "NTIPAliasType": 83, + "NTIPAliasStatProps": + { + "83": + { + "min": 3, + "max": 3 + }, + "0": + { + "min": 10, + "max": 20 + }, + "1": + { + "min": 10, + "max": 20 + }, + "2": + { + "min": 10, + "max": 20 + }, + "3": + { + "min": 10, + "max": 20 + }, + "39": + { + "min": 10, + "max": 20 + }, + "43": + { + "min": 10, + "max": 20 + }, + "41": + { + "min": 10, + "max": 20 + }, + "45": + { + "min": 10, + "max": 20 + }, + "89": + { + "min": 8, + "max": 8 + }, + "198": + { + "chance": 25, + "level": 10, + "skill": "Firestorm" + }, + "204": + { + "charges": 10, + "level": 30, + "skill": "Hydra" + } + } + }, + "hellmouth": + { + "DisplayName": "Hellmouth", + "NTIPAliasClassID": 384, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "48": 15, + "49": 72, + "143": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 150, + "max": 200 + }, + "72": 15, + "73": 15, + "198": + { + "chance": 4, + "level": 12, + "skill": "Firestorm" + } + } + }, + "hellplague": + { + "DisplayName": "Hellplague", + "NTIPAliasClassID": 31, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "62": + { + "min": 5, + "max": 5 + }, + "60": + { + "min": 5, + "max": 5 + }, + "57": + { + "min": 48, + "max": 48 + }, + "58": + { + "min": 96, + "max": 96 + }, + "59": + { + "min": 150, + "max": 150 + }, + "25": + { + "min": 70, + "max": 80 + }, + "48": 25, + "49": 75, + "188,8": + { + "min": 2, + "max": 2 + } + } + }, + "hellrack": + { + "DisplayName": "Hellrack", + "NTIPAliasClassID": 274, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "48": 63, + "49": 324, + "50": 63, + "51": 324, + "54": 63, + "55": 324, + "93": + { + "min": 20, + "max": 20 + }, + "119": + { + "min": 100, + "max": 150 + }, + "194": + { + "min": 2, + "max": 2 + }, + "204": + { + "charges": 150, + "level": 18, + "skill": "Immolation Arrow" + } + } + }, + "hellslayer": + { + "DisplayName": "Hellslayer", + "NTIPAliasClassID": 203, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "220": + { + "min": None, + "max": None, + "par": 4 + }, + "223": + { + "min": None, + "max": None, + "par": 4 + }, + "219": + { + "min": None, + "max": None, + "par": 24 + }, + "48": 150, + "49": 250, + "6": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 100, + "max": 100 + }, + "195": + { + "min": 10, + "max": None, + "par": "Fire Ball" + } + } + }, + "heraldofzakarum": + { + "DisplayName": "Herald of Zakarum", + "NTIPAliasClassID": 481, + "NTIPAliasType": 70, + "NTIPAliasStatProps": + { + "83,3": + { + "min": 2, + "max": 2 + }, + "188,24": + { + "min": 2, + "max": 2, + "par": "Combat Skills" + }, + "16,0": + { + "min": 150, + "max": 200 + }, + "102": + { + "min": 30, + "max": 30 + }, + "20": + { + "min": 30, + "max": 30 + }, + "0": + { + "min": 20, + "max": 20 + }, + "3": + { + "min": 20, + "max": 20 + }, + "119": + { + "min": 20, + "max": 20 + }, + "39": 50, + "43": 50, + "41": 50, + "45": 50 + } + }, + "hexfire": + { + "DisplayName": "Hexfire", + "NTIPAliasClassID": 120, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "204": + { + "charges": 36, + "level": 6, + "skill": "Hydra" + }, + "115": + { + "min": 1, + "max": 1 + }, + "39": + { + "min": 25, + "max": 25 + }, + "40": + { + "min": 10, + "max": 10 + }, + "21": 35, + "22": 40, + "25": + { + "min": 140, + "max": 160 + }, + "188,8": + { + "min": 3, + "max": 3 + } + } + }, + "highlordswrath": + { + "DisplayName": "Highlord's Wrath", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "41": + { + "min": 35, + "max": 35 + }, + "50": 1, + "51": 30, + "93": + { + "min": 20, + "max": 20 + }, + "127": + { + "min": 1, + "max": 1 + }, + "250": + { + "min": None, + "max": None, + "par": 3 + }, + "128": + { + "min": 15, + "max": 15 + } + } + }, + "homunculus": + { + "DisplayName": "Homunculus", + "NTIPAliasClassID": 487, + "NTIPAliasType": 69, + "NTIPAliasStatProps": + { + "83,2": + { + "min": 2, + "max": 2 + }, + "188,16": + { + "min": 2, + "max": 2, + "par": "Curses" + }, + "16,0": + { + "min": 150, + "max": 200 + }, + "102": + { + "min": 30, + "max": 30 + }, + "20": + { + "min": 40, + "max": 40 + }, + "1": + { + "min": 20, + "max": 20 + }, + "27": + { + "min": 33, + "max": 33 + }, + "138": + { + "min": 5, + "max": 5 + }, + "39": 40, + "43": 40, + "41": 40, + "45": 40 + } + }, + "honesundan": + { + "DisplayName": "Hone Sundan", + "NTIPAliasClassID": 148, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 3, + "max": 3 + }, + "21": 20, + "22": 40, + "136": + { + "min": 45, + "max": 45 + }, + "252": + { + "min": None, + "max": None, + "par": 10 + }, + "25": + { + "min": 160, + "max": 200 + } + } + }, + "horadricstaff": + { + "DisplayName": "Horadric Staff", + "NTIPAliasClassID": 91, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "8": + { + "min": 10, + "max": 10 + }, + "45": 10, + "6": + { + "min": 10, + "max": 10 + }, + "39": 10, + "43": 10, + "41": 10, + "93": + { + "min": 50, + "max": 50 + } + } + }, + "horizonstornado": + { + "DisplayName": "Horizon's Tornado", + "NTIPAliasClassID": 217, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "25": + { + "min": 230, + "max": 280 + }, + "93": + { + "min": 50, + "max": 50 + }, + "150": + { + "min": 20, + "max": 20 + }, + "198": + { + "chance": 20, + "level": 15, + "skill": "Tornado" + }, + "91": + { + "min": -20, + "max": -20 + } + } + }, + "hotspur": + { + "DisplayName": "Hotspur", + "NTIPAliasClassID": 339, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "40": + { + "min": 15, + "max": 15 + }, + "6": + { + "min": 15, + "max": 15 + }, + "48": 3, + "49": 6, + "31": + { + "min": 6, + "max": 6 + }, + "39": + { + "min": 45, + "max": 45 + }, + "16,0": + { + "min": 10, + "max": 20 + } + } + }, + "howltusk": + { + "DisplayName": "Howltusk", + "NTIPAliasClassID": 310, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "35": + { + "min": 2, + "max": 2 + }, + "78": + { + "min": 3, + "max": 3 + }, + "16,0": + { + "min": 80, + "max": 80 + }, + "114": + { + "min": 35, + "max": 35 + }, + "81": + { + "min": 1, + "max": 1 + }, + "112": + { + "min": 33, + "max": 33 + } + } + }, + "humongous": + { + "DisplayName": "Humongous", + "NTIPAliasClassID": 9, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "0": + { + "min": 20, + "max": 30 + }, + "21": + { + "min": 8, + "max": 8 + }, + "22": + { + "min": 15, + "max": 25 + }, + "136": + { + "min": 33, + "max": 33 + }, + "91": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 80, + "max": 120 + } + } + }, + "husoldalevo": + { + "DisplayName": "Husoldal Evo", + "NTIPAliasClassID": 154, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "74": + { + "min": 20, + "max": 20 + }, + "19": + { + "min": 200, + "max": 250 + }, + "117": + { + "min": 1, + "max": 1 + }, + "21": 20, + "22": 32, + "25": + { + "min": 160, + "max": 200 + }, + "93": + { + "min": 20, + "max": 20 + } + } + }, + "iceblink": + { + "DisplayName": "Iceblink", + "NTIPAliasClassID": 321, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "134": + { + "min": 1, + "max": 1 + }, + "43": + { + "min": 30, + "max": 30 + }, + "89": + { + "min": 4, + "max": 4 + }, + "35": + { + "min": 1, + "max": 1 + }, + "16,0": + { + "min": 70, + "max": 80 + } + } + }, + "ichorsting": + { + "DisplayName": "Ichorsting", + "NTIPAliasClassID": 77, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "57": 30, + "58": 30, + "2": + { + "min": 20, + "max": 20 + }, + "156": + { + "min": 50, + "max": 50 + }, + "19": + { + "min": 50, + "max": 50 + }, + "25": + { + "min": 50, + "max": 50 + }, + "93": + { + "min": 20, + "max": 20 + } + } + }, + "infernostride": + { + "DisplayName": "Infernostride", + "NTIPAliasClassID": 385, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "48": 12, + "49": 33, + "96": + { + "min": 20, + "max": 20 + }, + "40": + { + "min": 10, + "max": 10 + }, + "39": + { + "min": 30, + "max": 30 + }, + "89": + { + "min": 2, + "max": 2 + }, + "16,0": + { + "min": 120, + "max": 150 + }, + "79": + { + "min": 40, + "max": 70 + }, + "31": + { + "min": 15, + "max": 15 + }, + "201": + { + "chance": 5, + "level": 8, + "skill": "Blaze" + } + } + }, + "ironpelt": + { + "DisplayName": "Iron Pelt", + "NTIPAliasClassID": 362, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "72": 125, + "73": 125, + "6": + { + "min": 25, + "max": 25 + }, + "35": + { + "min": 10, + "max": 16 + }, + "34": + { + "min": 15, + "max": 20 + }, + "214": + { + "min": None, + "max": None, + "par": 24 + }, + "16,0": + { + "min": 50, + "max": 100 + } + } + }, + "ironstone": + { + "DisplayName": "Ironstone", + "NTIPAliasClassID": 22, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "19": + { + "min": 100, + "max": 150 + }, + "25": + { + "min": 100, + "max": 150 + }, + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 10, + "max": 10 + }, + "0": + { + "min": 10, + "max": 10 + } + } + }, + "islestrike": + { + "DisplayName": "Islestrike", + "NTIPAliasClassID": 95, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "83,5": + { + "min": 2, + "max": 2 + }, + "0": + { + "min": 10, + "max": 10 + }, + "2": + { + "min": 10, + "max": 10 + }, + "3": + { + "min": 10, + "max": 10 + }, + "1": + { + "min": 10, + "max": 10 + }, + "32": + { + "min": 50, + "max": 50 + }, + "136": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 170, + "max": 190 + }, + "107,233": + { + "min": 1, + "max": 1 + }, + "107,248": + { + "min": 1, + "max": 1 + } + } + }, + "jadetalon": + { + "DisplayName": "Jade Talon", + "NTIPAliasClassID": 190, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "25": + { + "min": 190, + "max": 240 + }, + "62": + { + "min": 10, + "max": 15 + }, + "39": + { + "min": 40, + "max": 50 + }, + "43": + { + "min": 40, + "max": 50 + }, + "41": + { + "min": 40, + "max": 50 + }, + "45": + { + "min": 40, + "max": 50 + }, + "99": + { + "min": 30, + "max": 30 + }, + "188,49": + { + "min": 1, + "max": 2, + "par": "Shadow Disciplines" + }, + "188,50": + { + "min": 1, + "max": 2, + "par": "Martial Arts" + } + } + }, + "jalalsmane": + { + "DisplayName": "Jalal's Mane", + "NTIPAliasClassID": 472, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "83,5": + { + "min": 2, + "max": 2 + }, + "188,41": + { + "min": 2, + "max": 2, + "par": "Shape Shifting Skills" + }, + "16,0": + { + "min": 150, + "max": 200 + }, + "99": + { + "min": 30, + "max": 30 + }, + "119": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 20, + "max": 20 + }, + "1": + { + "min": 20, + "max": 20 + }, + "138": + { + "min": 5, + "max": 5 + }, + "39": 30, + "43": 30, + "41": 30, + "45": 30 + } + }, + "kelpiesnare": + { + "DisplayName": "Kelpie Snare", + "NTIPAliasClassID": 146, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "150": + { + "min": 75, + "max": 75 + }, + "39": + { + "min": 50, + "max": 50 + }, + "216": + { + "min": None, + "max": None, + "par": 10 + }, + "21": 30, + "22": 50, + "0": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 140, + "max": 180 + } + } + }, + "khalimsflail": + { + "DisplayName": "Khalim's Flail", + "NTIPAliasClassID": 173, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 20, + "max": 20 + }, + "93": + { + "min": 50, + "max": 50 + }, + "19": + { + "min": 40, + "max": 40 + } + } + }, + "khalimswill": + { + "DisplayName": "Khalim's Will", + "NTIPAliasClassID": 174, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 40, + "max": 40 + }, + "93": + { + "min": 50, + "max": 50 + }, + "19": + { + "min": 40, + "max": 40 + }, + "62": + { + "min": 6, + "max": 6 + }, + "60": + { + "min": 6, + "max": 6 + } + } + }, + "kinemilsawl": + { + "DisplayName": "Kinemil's Awl", + "NTIPAliasClassID": 35, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "19": + { + "min": 100, + "max": 150 + }, + "8": + { + "min": 20, + "max": 20 + }, + "48": + { + "min": 6, + "max": 6 + }, + "49": + { + "min": 20, + "max": 40 + }, + "25": + { + "min": 80, + "max": 100 + }, + "107,102": + { + "min": 6, + "max": 6 + } + } + }, + "kirasguardian": + { + "DisplayName": "Kira's Guardian", + "NTIPAliasClassID": 420, + "NTIPAliasType": 75, + "NTIPAliasStatProps": + { + "31": + { + "min": 50, + "max": 120 + }, + "39": + { + "min": 50, + "max": 70 + }, + "43": + { + "min": 50, + "max": 70 + }, + "41": + { + "min": 50, + "max": 70 + }, + "45": + { + "min": 50, + "max": 70 + }, + "153": + { + "min": 1, + "max": 1 + }, + "99": + { + "min": 20, + "max": 20 + } + } + }, + "knellstriker": + { + "DisplayName": "Knell Striker", + "NTIPAliasClassID": 15, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "136": + { + "min": 25, + "max": 25 + }, + "39": + { + "min": 20, + "max": 20 + }, + "45": + { + "min": 20, + "max": 20 + }, + "8": + { + "min": 15, + "max": 15 + }, + "19": + { + "min": 35, + "max": 35 + }, + "25": + { + "min": 70, + "max": 80 + } + } + }, + "kukoshakaku": + { + "DisplayName": "Kuko Shakaku", + "NTIPAliasClassID": 163, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "107,27": + { + "min": 3, + "max": 3 + }, + "158": + { + "min": 7, + "max": 7 + }, + "25": + { + "min": 150, + "max": 180 + }, + "156": + { + "min": 50, + "max": 50 + }, + "48": 40, + "49": 180, + "188,0": + { + "min": 3, + "max": 3, + "par": "Bow and Crossbow Skills" + } + } + }, + "lacerator": + { + "DisplayName": "Lacerator", + "NTIPAliasClassID": 242, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 210 + }, + "253": + { + "min": None, + "max": None, + "par": 25 + }, + "93": + { + "min": 30, + "max": 30 + }, + "117": + { + "min": 1, + "max": 1 + }, + "135": + { + "min": 33, + "max": 33 + }, + "112": + { + "min": 64, + "max": 64 + }, + "198": + { + "chance": 33, + "level": 3, + "skill": "Amplify Damage" + } + } + }, + "lanceguard": + { + "DisplayName": "Lance Guard", + "NTIPAliasClassID": 397, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "6": + { + "min": 50, + "max": 50 + }, + "99": + { + "min": 30, + "max": 30 + }, + "114": + { + "min": 15, + "max": 15 + }, + "78": + { + "min": 47, + "max": 47 + }, + "16,0": + { + "min": 70, + "max": 120 + }, + "141": + { + "min": 20, + "max": 20 + } + } + }, + "lanceofyaggai": + { + "DisplayName": "Lance of Yaggai", + "NTIPAliasClassID": 55, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "78": + { + "min": 8, + "max": 8 + }, + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 60, + "max": 60 + }, + "39": 15, + "43": 15, + "41": 15, + "45": 15, + "93": + { + "min": 40, + "max": 40 + } + } + }, + "langerbriser": + { + "DisplayName": "Langer Briser", + "NTIPAliasClassID": 169, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "81": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 170, + "max": 200 + }, + "80": + { + "min": 30, + "max": 60 + }, + "6": + { + "min": 30, + "max": 30 + }, + "22": + { + "min": 10, + "max": 30 + }, + "135": + { + "min": 33, + "max": 33 + }, + "50": 1, + "51": 212 + } + }, + "lavagout": + { + "DisplayName": "Lava Gout", + "NTIPAliasClassID": 383, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "39": + { + "min": 24, + "max": 24 + }, + "118": + { + "min": 1, + "max": 1 + }, + "198": + { + "chance": 2, + "level": 10, + "skill": "Enchant" + }, + "93": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 150, + "max": 200 + }, + "48": 13, + "49": 46, + "72": 20, + "73": 20 + } + }, + "leadcrow": + { + "DisplayName": "Leadcrow", + "NTIPAliasClassID": 76, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "2": + { + "min": 10, + "max": 10 + }, + "6": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 70, + "max": 70 + }, + "45": + { + "min": 30, + "max": 30 + }, + "141": + { + "min": 25, + "max": 25 + }, + "19": + { + "min": 40, + "max": 40 + } + } + }, + "lenymo": + { + "DisplayName": "Lenymo", + "NTIPAliasClassID": 344, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "8": + { + "min": 15, + "max": 15 + }, + "27": + { + "min": 30, + "max": 30 + }, + "39": 5, + "43": 5, + "41": 5, + "45": 5, + "89": + { + "min": 1, + "max": 1 + } + } + }, + "leviathan": + { + "DisplayName": "Leviathan", + "NTIPAliasClassID": 439, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 170, + "max": 200 + }, + "31": + { + "min": 100, + "max": 150 + }, + "36": + { + "min": 15, + "max": 25 + }, + "0": + { + "min": 40, + "max": 50 + }, + "152": + { + "min": 1, + "max": 1 + } + } + }, + "lidlesswall": + { + "DisplayName": "Lidless Wall", + "NTIPAliasClassID": 396, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "89": + { + "min": 1, + "max": 1 + }, + "127": + { + "min": 1, + "max": 1 + }, + "105": + { + "min": 20, + "max": 20 + }, + "138": + { + "min": 3, + "max": 5 + }, + "16,0": + { + "min": 80, + "max": 130 + }, + "1": + { + "min": 10, + "max": 10 + }, + "77": + { + "min": 10, + "max": 10 + } + } + }, + "lightsabre": + { + "DisplayName": "Lightsabre", + "NTIPAliasClassID": 225, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "89": + { + "min": 7, + "max": 7 + }, + "195": + { + "min": 5, + "max": None, + "par": "Chain Lightning" + }, + "115": + { + "min": 1, + "max": 1, + "par": 1 + }, + "144": + { + "min": 25, + "max": 25 + }, + "93": + { + "min": 20, + "max": 20 + }, + "52": 60, + "53": 120, + "50": 1, + "51": 200, + "62": + { + "min": 5, + "max": 7 + }, + "25": + { + "min": 150, + "max": 200 + }, + "21": 10, + "22": 30 + } + }, + "lycandersaim": + { + "DisplayName": "Lycander's Aim", + "NTIPAliasClassID": 292, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "83,0": + { + "min": 2, + "max": 2 + }, + "188,0": + { + "min": 2, + "max": 2, + "par": "Bow and Crossbow Skills" + }, + "25": + { + "min": 150, + "max": 200 + }, + "93": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 20, + "max": 20 + }, + "1": + { + "min": 20, + "max": 20 + }, + "62": + { + "min": 5, + "max": 8 + }, + "21": 25, + "22": 50 + } + }, + "lycandersflank": + { + "DisplayName": "Lycander's Flank", + "NTIPAliasClassID": 294, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "83,0": + { + "min": 2, + "max": 2 + }, + "188,2": + { + "min": 2, + "max": 2, + "par": "Javelin and Spear Skills" + }, + "25": + { + "min": 150, + "max": 200 + }, + "93": + { + "min": 30, + "max": 30 + }, + "16,0": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 20, + "max": 20 + }, + "3": + { + "min": 20, + "max": 20 + }, + "60": + { + "min": 5, + "max": 9 + }, + "21": 25, + "22": 50 + } + }, + "maelstrom": + { + "DisplayName": "Maelstrom", + "NTIPAliasClassID": 11, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 9, + "max": 9 + }, + "41": + { + "min": 40, + "max": 40 + }, + "8": + { + "min": 13, + "max": 13 + }, + "105": + { + "min": 30, + "max": 30 + }, + "107,74": + { + "min": 1, + "max": 3 + }, + "107,77": + { + "min": 1, + "max": 3 + }, + "107,66": + { + "min": 1, + "max": 3 + }, + "107,76": + { + "min": 1, + "max": 3 + } + } + }, + "magefist": + { + "DisplayName": "Magefist", + "NTIPAliasClassID": 337, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "105": + { + "min": 20, + "max": 20 + }, + "27": + { + "min": 25, + "max": 25 + }, + "188,8": + { + "min": 1, + "max": 1 + }, + "48": 1, + "49": 6, + "31": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 20, + "max": 30 + } + } + }, + "magewrath": + { + "DisplayName": "Magewrath", + "NTIPAliasClassID": 167, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "62": + { + "min": 15, + "max": 15 + }, + "35": + { + "min": 9, + "max": 13 + }, + "107,22": + { + "min": 3, + "max": 3 + }, + "19": + { + "min": 200, + "max": 250 + }, + "2": + { + "min": 10, + "max": 10 + }, + "113": + { + "min": 1, + "max": 1 + }, + "21": 25, + "22": 50, + "25": + { + "min": 120, + "max": 150 + }, + "83,0": + { + "min": 1, + "max": 1 + } + } + }, + "manaldheal": + { + "DisplayName": "Manald Heal", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "62": + { + "min": 4, + "max": 7 + }, + "74": + { + "min": 5, + "max": 8 + }, + "6": + { + "min": 20, + "max": 20 + }, + "27": + { + "min": 20, + "max": 20 + } + } + }, + "mangsongslesson": + { + "DisplayName": "Mang Song's Lesson", + "NTIPAliasClassID": 263, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "127": + { + "min": 5, + "max": 5 + }, + "333": + { + "min": 7, + "max": 15 + }, + "334": + { + "min": 7, + "max": 15 + }, + "335": + { + "min": 7, + "max": 15 + }, + "27": + { + "min": 10, + "max": 10 + }, + "105": + { + "min": 30, + "max": 30 + } + } + }, + "maraskaleidoscope": + { + "DisplayName": "Mara's Kaleidoscope", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "127": + { + "min": 2, + "max": 2 + }, + "39": + { + "min": 20, + "max": 30 + }, + "43": + { + "min": 20, + "max": 30 + }, + "41": + { + "min": 20, + "max": 30 + }, + "45": + { + "min": 20, + "max": 30 + }, + "0": + { + "min": 5, + "max": 5 + }, + "2": + { + "min": 5, + "max": 5 + }, + "3": + { + "min": 5, + "max": 5 + }, + "1": + { + "min": 5, + "max": 5 + } + } + }, + "marrowwalk": + { + "DisplayName": "Marrowwalk", + "NTIPAliasClassID": 457, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 170, + "max": 200 + }, + "96": + { + "min": 20, + "max": 20 + }, + "204": + { + "charges": 10, + "level": 12, + "skill": "Life Tap" + }, + "28": + { + "min": 10, + "max": 10 + }, + "27": + { + "min": 10, + "max": 10 + }, + "118": + { + "min": 1, + "max": 1 + }, + "0": + { + "min": 10, + "max": 20 + }, + "2": + { + "min": 17, + "max": 17 + }, + "107,69": + { + "min": 1, + "max": 2 + } + } + }, + "medusasgaze": + { + "DisplayName": "Medusa's Gaze", + "NTIPAliasClassID": 448, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 150, + "max": 180 + }, + "150": + { + "min": 20, + "max": 20 + }, + "201": + { + "chance": 10, + "level": 7, + "skill": "Lower Resist" + }, + "60": + { + "min": 5, + "max": 9 + }, + "197": + { + "min": 100, + "max": 44, + "par": "Nova" + }, + "43": + { + "min": 40, + "max": 80 + } + } + }, + "messerschmidtsreaver": + { + "DisplayName": "Messerschmidt's Reaver", + "NTIPAliasClassID": 204, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "219": + { + "min": None, + "max": None, + "par": 20 + }, + "25": + { + "min": 200, + "max": 200 + }, + "0": + { + "min": 15, + "max": 15 + }, + "2": + { + "min": 15, + "max": 15 + }, + "3": + { + "min": 15, + "max": 15 + }, + "1": + { + "min": 15, + "max": 15 + }, + "48": 20, + "49": 240, + "72": 25, + "73": 25, + "119": + { + "min": 100, + "max": 100 + } + } + }, + "metalgrid": + { + "DisplayName": "Metalgrid", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "31": + { + "min": 300, + "max": 350 + }, + "39": + { + "min": 25, + "max": 35 + }, + "43": + { + "min": 25, + "max": 35 + }, + "41": + { + "min": 25, + "max": 35 + }, + "45": + { + "min": 25, + "max": 35 + }, + "19": + { + "min": 400, + "max": 450 + }, + "204": + { + "charges": 20, + "level": 12, + "skill": "Iron Maiden" + } + } + }, + "moonfall": + { + "DisplayName": "Moonfall", + "NTIPAliasClassID": 113, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "198": + { + "chance": 5, + "level": 6, + "skill": "Meteor" + }, + "48": 55, + "49": 115, + "35": + { + "min": 9, + "max": 12 + }, + "25": + { + "min": 120, + "max": 150 + }, + "89": + { + "min": 2, + "max": 2 + }, + "204": + { + "charges": 60, + "level": 11, + "skill": "Meteor" + }, + "21": 10, + "22": 15 + } + }, + "mosersblessedcircle": + { + "DisplayName": "Moser's Blessed Circle", + "NTIPAliasClassID": 375, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "39": 25, + "43": 25, + "41": 25, + "45": 25, + "20": + { + "min": 25, + "max": 25 + }, + "194": + { + "min": 2, + "max": 2 + }, + "16,0": + { + "min": 180, + "max": 220 + }, + "102": + { + "min": 30, + "max": 30 + } + } + }, + "nagelring": + { + "DisplayName": "Nagelring", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "35": + { + "min": 3, + "max": 3 + }, + "78": + { + "min": 3, + "max": 3 + }, + "19": + { + "min": 50, + "max": 75 + }, + "80": + { + "min": 15, + "max": 30 + } + } + }, + "naturespeace": + { + "DisplayName": "Nature's Peace", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "117": + { + "min": 1, + "max": 1 + }, + "108": + { + "min": 1, + "max": 1 + }, + "34": + { + "min": 7, + "max": 11 + }, + "45": + { + "min": 20, + "max": 30 + }, + "204": + { + "charges": 27, + "level": 5, + "skill": "Oak Sage" + } + } + }, + "nightsmoke": + { + "DisplayName": "Nightsmoke", + "NTIPAliasClassID": 346, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "114": + { + "min": 50, + "max": 50 + }, + "8": + { + "min": 20, + "max": 20 + }, + "34": + { + "min": 2, + "max": 2 + }, + "31": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 30, + "max": 50 + } + } + }, + "nightwingsveil": + { + "DisplayName": "Nightwing's Veil", + "NTIPAliasClassID": 426, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 90, + "max": 120 + }, + "127": + { + "min": 2, + "max": 2 + }, + "2": + { + "min": 10, + "max": 20 + }, + "149": + { + "min": 5, + "max": 9 + }, + "118": + { + "min": 1, + "max": 1 + }, + "331": + { + "min": 8, + "max": 15 + }, + "91": + { + "min": -50, + "max": -50 + } + } + }, + "nokozanrelic": + { + "DisplayName": "Nokozan Relic", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "48": 3, + "49": 6, + "40": + { + "min": 10, + "max": 10 + }, + "39": + { + "min": 50, + "max": 50 + }, + "89": + { + "min": 3, + "max": 3 + }, + "99": + { + "min": 20, + "max": 20 + } + } + }, + "nordstenderizer": + { + "DisplayName": "Nord's Tenderizer", + "NTIPAliasClassID": 210, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "25": + { + "min": 270, + "max": 330 + }, + "134": + { + "min": 2, + "max": 4 + }, + "93": + { + "min": 25, + "max": 25 + }, + "204": + { + "charges": 12, + "level": 16, + "skill": "Blizzard" + }, + "119": + { + "min": 150, + "max": 180 + }, + "148": + { + "min": 5, + "max": 15 + }, + "54": 205, + "55": 455 + } + }, + "nosferatuscoil": + { + "DisplayName": "Nosferatu's Coil", + "NTIPAliasClassID": 461, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "0": + { + "min": 15, + "max": 15 + }, + "138": + { + "min": 2, + "max": 2 + }, + "150": + { + "min": 10, + "max": 10 + }, + "60": + { + "min": 5, + "max": 7 + }, + "93": + { + "min": 10, + "max": 10 + }, + "89": + { + "min": -3, + "max": -3 + } + } + }, + "ondalswisdom": + { + "DisplayName": "Ondal's Wisdom", + "NTIPAliasClassID": 261, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "105": + { + "min": 45, + "max": 45 + }, + "1": + { + "min": 40, + "max": 50 + }, + "127": + { + "min": 2, + "max": 4 + }, + "31": + { + "min": 450, + "max": 550 + }, + "85": + { + "min": 5, + "max": 5 + }, + "35": + { + "min": 5, + "max": 8 + } + } + }, + "ormusrobes": + { + "DisplayName": "Ormus' Robes", + "NTIPAliasClassID": 429, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 10, + "max": 20 + }, + "105": + { + "min": 20, + "max": 20 + }, + "329": + { + "min": 10, + "max": 15 + }, + "331": + { + "min": 10, + "max": 15 + }, + "330": + { + "min": 10, + "max": 15 + }, + "27": + { + "min": 10, + "max": 15 + }, + "107,36": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,37": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,38": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,39": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,40": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,41": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,42": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,43": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,44": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,45": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,46": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,47": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,48": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,49": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,50": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,51": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,52": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,53": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,54": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,55": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,56": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,57": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,58": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,59": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,60": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,61": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,62": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,63": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,64": + { + "min": 36, + "max": 60, + "par": "Unsummon" + }, + "107,65": + { + "min": 36, + "max": 60, + "par": "Unsummon" + } + } + }, + "peasantcrown": + { + "DisplayName": "Peasant Crown", + "NTIPAliasClassID": 352, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "1": + { + "min": 20, + "max": 20 + }, + "3": + { + "min": 20, + "max": 20 + }, + "127": + { + "min": 1, + "max": 1 + }, + "96": + { + "min": 15, + "max": 15 + }, + "74": + { + "min": 6, + "max": 12 + }, + "16,0": + { + "min": 100, + "max": 100 + } + } + }, + "peltalunata": + { + "DisplayName": "Pelta Lunata", + "NTIPAliasClassID": 328, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 30, + "max": 30 + }, + "3": + { + "min": 10, + "max": 10 + }, + "0": + { + "min": 2, + "max": 2 + }, + "1": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 30, + "max": 40 + }, + "20": + { + "min": 20, + "max": 20 + }, + "102": + { + "min": 40, + "max": 40 + }, + "72": 8, + "73": 12 + } + }, + "pierretombalecouant": + { + "DisplayName": "Pierre Tombale Couant", + "NTIPAliasClassID": 153, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "141": + { + "min": 55, + "max": 55 + }, + "83,4": + { + "min": 3, + "max": 3 + }, + "99": + { + "min": 30, + "max": 30 + }, + "62": + { + "min": 6, + "max": 6 + }, + "21": 12, + "22": 20, + "25": + { + "min": 160, + "max": 220 + }, + "19": + { + "min": 100, + "max": 200 + } + } + }, + "plaguebearer": + { + "DisplayName": "Plague Bearer", + "NTIPAliasClassID": 124, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "198": + { + "chance": 5, + "level": 4, + "skill": "Poison Nova" + }, + "57": 300, + "58": 300, + "21": 10, + "22": 45, + "25": + { + "min": 150, + "max": 150 + }, + "45": + { + "min": 45, + "max": 45 + }, + "107,238": + { + "min": 5, + "max": 5 + } + } + }, + "pluckeye": + { + "DisplayName": "Pluckeye", + "NTIPAliasClassID": 68, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "19": + { + "min": 28, + "max": 28 + }, + "25": + { + "min": 100, + "max": 100 + }, + "6": + { + "min": 10, + "max": 10 + }, + "89": + { + "min": 2, + "max": 2 + }, + "62": + { + "min": 3, + "max": 3 + }, + "138": + { + "min": 2, + "max": 2 + } + } + }, + "pompeiiswrath": + { + "DisplayName": "Pompeii's Wrath", + "NTIPAliasClassID": 96, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "198": + { + "chance": 4, + "level": 8, + "skill": "Volcano" + }, + "150": + { + "min": 50, + "max": 50 + }, + "48": 35, + "49": 150, + "81": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 140, + "max": 170 + } + } + }, + "pusspitter": + { + "DisplayName": "Pus Spitter", + "NTIPAliasClassID": 170, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "57": 150, + "58": 150, + "198": + { + "chance": 4, + "level": 1, + "skill": "Lower Resist" + }, + "83,2": + { + "min": 2, + "max": 2 + }, + "91": + { + "min": -60, + "max": -60 + }, + "201": + { + "chance": 9, + "level": 6, + "skill": "Poison Nova" + }, + "93": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 150, + "max": 220 + }, + "224": + { + "min": None, + "max": None, + "par": 10 + } + } + }, + "queheganswisdom": + { + "DisplayName": "Que-Hegan's Wisdom", + "NTIPAliasClassID": 373, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "105": + { + "min": 20, + "max": 20 + }, + "138": + { + "min": 3, + "max": 3 + }, + "35": + { + "min": 6, + "max": 10 + }, + "1": + { + "min": 15, + "max": 15 + }, + "99": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 140, + "max": 160 + }, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "radamentssphere": + { + "DisplayName": "Radament's Sphere", + "NTIPAliasClassID": 379, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "57": 80, + "58": 80, + "201": + { + "chance": 5, + "level": 5, + "skill": "Poison Nova" + }, + "45": + { + "min": 75, + "max": 75 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "20": + { + "min": 20, + "max": 20 + }, + "102": + { + "min": 20, + "max": 20 + }, + "204": + { + "charges": 40, + "level": 6, + "skill": "Poison Explosion" + }, + "72": 20, + "73": 20 + } + }, + "rainbowfacet": + { + "DisplayName": "Rainbow Facet", + "NTIPAliasClassID": 643, + "NTIPAliasType": 58, + "NTIPAliasStatProps": + { + "57": 37, + "58": 37, + "336": + { + "min": 3, + "max": 5 + }, + "332": + { + "min": 3, + "max": 5 + }, + "199":[ + { + "chance": 100, + "level": 43, + "skill": "Frost Nova" + }, + { + "chance": 100, + "level": 29, + "skill": "Blaze" + }, + { + "chance": 100, + "level": 41, + "skill": "Nova" + }, + { + "chance": 100, + "level": 23, + "skill": "Venom" + }, + ], + "197":[ + { + "min": 100, + "max": 37, + "par": "Blizzard" + }, + { + "min": 100, + "max": 31, + "par": "Meteor" + }, + { + "min": 100, + "max": 47, + "par": "Chain Lightning" + }, + { + "min": 100, + "max": 51, + "par": "Poison Nova" + }, + ], + "50": 1, + "51": 74, + "334": + { + "min": 3, + "max": 5 + }, + "330": + { + "min": 3, + "max": 5 + }, + "54": 24, + "55": 38, + "335": + { + "min": 3, + "max": 5 + }, + "331": + { + "min": 3, + "max": 5 + }, + "48": 17, + "49": 45, + "333": + { + "min": 3, + "max": 5 + }, + "329": + { + "min": 3, + "max": 5 + } + } + }, + "rakescar": + { + "DisplayName": "Rakescar", + "NTIPAliasClassID": 4, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "57": + { + "min": 128, + "max": 128 + }, + "58": + { + "min": 128, + "max": 128 + }, + "59": + { + "min": 75, + "max": 75 + }, + "19": + { + "min": 50, + "max": 50 + }, + "45": + { + "min": 50, + "max": 50 + }, + "25": + { + "min": 75, + "max": 150 + }, + "93": + { + "min": 30, + "max": 30 + } + } + }, + "rattlecage": + { + "DisplayName": "Rattlecage", + "NTIPAliasClassID": 324, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "112": + { + "min": 52, + "max": 52 + }, + "19": + { + "min": 45, + "max": 45 + }, + "136": + { + "min": 25, + "max": 25 + }, + "31": + { + "min": 200, + "max": 200 + } + } + }, + "ravenclaw": + { + "DisplayName": "Raven Claw", + "NTIPAliasClassID": 70, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "119": + { + "min": 50, + "max": 50 + }, + "2": + { + "min": 3, + "max": 3 + }, + "158": + { + "min": 3, + "max": 3 + }, + "0": + { + "min": 3, + "max": 3 + }, + "25": + { + "min": 60, + "max": 70 + } + } + }, + "ravenfrost": + { + "DisplayName": "Raven Frost", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "153": + { + "min": 1, + "max": 1 + }, + "54": 15, + "55": 45, + "148": + { + "min": 20, + "max": 20 + }, + "8": + { + "min": 40, + "max": 40 + }, + "2": + { + "min": 15, + "max": 20 + }, + "19": + { + "min": 150, + "max": 250 + } + } + }, + "ravenlore": + { + "DisplayName": "Ravenlore", + "NTIPAliasClassID": 491, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 150 + }, + "39": + { + "min": 15, + "max": 25 + }, + "43": + { + "min": 15, + "max": 25 + }, + "41": + { + "min": 15, + "max": 25 + }, + "45": + { + "min": 15, + "max": 25 + }, + "188,42": + { + "min": 3, + "max": 3, + "par": "Elemental Skills" + }, + "1": + { + "min": 20, + "max": 30 + }, + "333": + { + "min": 10, + "max": 20 + }, + "107,221": + { + "min": 7, + "max": 7 + } + } + }, + "razorsedge": + { + "DisplayName": "Razor's Edge", + "NTIPAliasClassID": 196, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 175, + "max": 225 + }, + "93": + { + "min": 40, + "max": 40 + }, + "116": + { + "min": 33, + "max": 33 + }, + "141": + { + "min": 50, + "max": 50 + }, + "135": + { + "min": 50, + "max": 50 + } + } + }, + "razorswitch": + { + "DisplayName": "Razorswitch", + "NTIPAliasClassID": 156, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "105": + { + "min": 30, + "max": 30 + }, + "78": + { + "min": 15, + "max": 15 + }, + "8": + { + "min": 175, + "max": 175 + }, + "6": + { + "min": 80, + "max": 80 + }, + "35": + { + "min": 15, + "max": 15 + }, + "39": 50, + "43": 50, + "41": 50, + "45": 50, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "razortail": + { + "DisplayName": "Razortail", + "NTIPAliasClassID": 391, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "238": + { + "min": None, + "max": None, + "par": 8 + }, + "2": + { + "min": 15, + "max": 15 + }, + "156": + { + "min": 33, + "max": 33 + }, + "31": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 120, + "max": 150 + }, + "22": + { + "min": 10, + "max": 10 + } + } + }, + "razortine": + { + "DisplayName": "Razortine", + "NTIPAliasClassID": 53, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "150": + { + "min": 25, + "max": 25 + }, + "116": + { + "min": 50, + "max": 50 + }, + "0": + { + "min": 15, + "max": 15 + }, + "2": + { + "min": 8, + "max": 8 + }, + "93": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 30, + "max": 50 + } + } + }, + "ribcracker": + { + "DisplayName": "Ribcracker", + "NTIPAliasClassID": 157, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "21": 30, + "22": 65, + "25": + { + "min": 200, + "max": 300 + }, + "136": + { + "min": 50, + "max": 50 + }, + "2": + { + "min": 15, + "max": 15 + }, + "31": + { + "min": 100, + "max": 100 + }, + "16,0": + { + "min": 100, + "max": 100 + }, + "99": + { + "min": 50, + "max": 50 + }, + "93": + { + "min": 50, + "max": 50 + }, + "72": 100, + "73": 100 + } + }, + "riphook": + { + "DisplayName": "Riphook", + "NTIPAliasClassID": 162, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "135": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 180, + "max": 220 + }, + "150": + { + "min": 30, + "max": 30 + }, + "8": + { + "min": 35, + "max": 35 + }, + "93": + { + "min": 30, + "max": 30 + }, + "60": + { + "min": 7, + "max": 10 + } + } + }, + "ripsaw": + { + "DisplayName": "Ripsaw", + "NTIPAliasClassID": 37, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "135": + { + "min": 80, + "max": 80 + }, + "22": + { + "min": 15, + "max": 15 + }, + "62": + { + "min": 6, + "max": 6 + }, + "25": + { + "min": 80, + "max": 100 + } + } + }, + "rixotskeen": + { + "DisplayName": "Rixot's Keen", + "NTIPAliasClassID": 25, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "21": + { + "min": 5, + "max": 5 + }, + "119": + { + "min": 20, + "max": 20 + }, + "89": + { + "min": 2, + "max": 2 + }, + "136": + { + "min": 25, + "max": 25 + }, + "31": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 100, + "max": 100 + } + } + }, + "rockfleece": + { + "DisplayName": "Rockfleece", + "NTIPAliasClassID": 323, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "91": + { + "min": -10, + "max": -10 + }, + "16,0": + { + "min": 100, + "max": 130 + }, + "36": + { + "min": 10, + "max": 10 + }, + "34": + { + "min": 5, + "max": 5 + }, + "0": + { + "min": 5, + "max": 5 + } + } + }, + "rockstopper": + { + "DisplayName": "Rockstopper", + "NTIPAliasClassID": 353, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "41": + { + "min": 20, + "max": 40 + }, + "36": + { + "min": 10, + "max": 10 + }, + "99": + { + "min": 30, + "max": 30 + }, + "16,0": + { + "min": 160, + "max": 220 + }, + "39": + { + "min": 20, + "max": 50 + }, + "43": + { + "min": 20, + "max": 40 + }, + "3": + { + "min": 15, + "max": 15 + } + } + }, + "roguesbow": + { + "DisplayName": "Rogue's Bow", + "NTIPAliasClassID": 71, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "141": + { + "min": 30, + "max": 30 + }, + "19": + { + "min": 60, + "max": 60 + }, + "122": + { + "min": 100, + "max": 100 + }, + "25": + { + "min": 40, + "max": 60 + }, + "93": + { + "min": 50, + "max": 50 + } + } + }, + "runemaster": + { + "DisplayName": "Rune Master", + "NTIPAliasClassID": 198, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 220, + "max": 270 + }, + "194": + { + "min": 3, + "max": 5 + }, + "44": + { + "min": 5, + "max": 5 + }, + "153": + { + "min": 1, + "max": 1 + } + } + }, + "rusthandle": + { + "DisplayName": "Rusthandle", + "NTIPAliasClassID": 16, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "83,3": + { + "min": 1, + "max": 1 + }, + "21": 3, + "22": 7, + "35": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 8, + "max": 8 + }, + "25": + { + "min": 50, + "max": 60 + }, + "122": + { + "min": 50, + "max": 60 + }, + "107,111": + { + "min": 1, + "max": 3 + }, + "107,103": + { + "min": 3, + "max": 3 + } + } + }, + "sandstormtrek": + { + "DisplayName": "Sandstorm Trek", + "NTIPAliasClassID": 456, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 140, + "max": 170 + }, + "96": + { + "min": 20, + "max": 20 + }, + "99": + { + "min": 20, + "max": 20 + }, + "242": + { + "min": None, + "max": None, + "par": 8 + }, + "154": + { + "min": 50, + "max": 50 + }, + "45": + { + "min": 40, + "max": 70 + }, + "252": + { + "min": None, + "max": None, + "par": 5 + }, + "0": + { + "min": 10, + "max": 15 + }, + "3": + { + "min": 10, + "max": 15 + } + } + }, + "saracenschance": + { + "DisplayName": "Saracen's Chance", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "39": + { + "min": 15, + "max": 25 + }, + "43": + { + "min": 15, + "max": 25 + }, + "41": + { + "min": 15, + "max": 25 + }, + "45": + { + "min": 15, + "max": 25 + }, + "201": + { + "chance": 10, + "level": 2, + "skill": "Iron Maiden" + }, + "0": + { + "min": 12, + "max": 12 + }, + "2": + { + "min": 12, + "max": 12 + }, + "1": + { + "min": 12, + "max": 12 + }, + "3": + { + "min": 12, + "max": 12 + } + } + }, + "schaefershammer": + { + "DisplayName": "Schaefer's Hammer", + "NTIPAliasClassID": 218, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "198": + { + "chance": 20, + "level": 10, + "skill": "Static Field" + }, + "6": + { + "min": 50, + "max": 50 + }, + "224": + { + "min": None, + "max": None, + "par": 16 + }, + "41": + { + "min": 75, + "max": 75 + }, + "93": + { + "min": 20, + "max": 20 + }, + "218": + { + "min": None, + "max": None, + "par": 16 + }, + "152": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 100, + "max": 130 + }, + "89": + { + "min": 1, + "max": 1 + }, + "50": 50, + "51": 200 + } + }, + "seraphshymn": + { + "DisplayName": "Seraph's Hymn", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "127": + { + "min": 2, + "max": 2 + }, + "188,26": + { + "min": 1, + "max": 2, + "par": "Defensive Auras" + }, + "121": + { + "min": 25, + "max": 50 + }, + "122": + { + "min": 25, + "max": 50 + }, + "123": + { + "min": 150, + "max": 250 + }, + "124": + { + "min": 150, + "max": 250 + }, + "89": + { + "min": 2, + "max": 2 + } + } + }, + "serpentlord": + { + "DisplayName": "Serpent Lord", + "NTIPAliasClassID": 64, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "57": 12, + "58": 12, + "45": + { + "min": 50, + "max": 50 + }, + "89": + { + "min": -1, + "max": -1 + }, + "8": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 30, + "max": 40 + }, + "62": + { + "min": 100, + "max": 100 + }, + "116": + { + "min": 50, + "max": 50 + } + } + }, + "shadowdancer": + { + "DisplayName": "Shadow Dancer", + "NTIPAliasClassID": 459, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 70, + "max": 100 + }, + "96": + { + "min": 30, + "max": 30 + }, + "99": + { + "min": 30, + "max": 30 + }, + "2": + { + "min": 15, + "max": 25 + }, + "188,49": + { + "min": 1, + "max": 2, + "par": "Shadow Disciplines" + }, + "91": + { + "min": -20, + "max": -20 + } + } + }, + "shadowkiller": + { + "DisplayName": "Shadow Killer", + "NTIPAliasClassID": 192, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "25": + { + "min": 170, + "max": 220 + }, + "116": + { + "min": 25, + "max": 25 + }, + "134": + { + "min": 2, + "max": 2 + }, + "138": + { + "min": 10, + "max": 15 + }, + "198": + { + "chance": 33, + "level": 8, + "skill": "Frost Nova" + }, + "0x400000": + { + "min": 1, + "max": 1 + }, + "152": + { + "min": 1, + "max": 1 + } + } + }, + "shadowfang": + { + "DisplayName": "Shadowfang", + "NTIPAliasClassID": 33, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "62": + { + "min": 9, + "max": 9 + }, + "43": + { + "min": 20, + "max": 20 + }, + "89": + { + "min": -2, + "max": -2 + }, + "54": 10, + "55": 30, + "25": + { + "min": 100, + "max": 100 + }, + "60": + { + "min": 9, + "max": 9 + } + } + }, + "shaftstop": + { + "DisplayName": "Shaftstop", + "NTIPAliasClassID": 365, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "32": + { + "min": 250, + "max": 250 + }, + "36": + { + "min": 30, + "max": 30 + }, + "6": + { + "min": 60, + "max": 60 + }, + "16,0": + { + "min": 180, + "max": 220 + } + } + }, + "silksofthevictor": + { + "DisplayName": "Silks of the Victor", + "NTIPAliasClassID": 326, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "62": + { + "min": 5, + "max": 5 + }, + "127": + { + "min": 1, + "max": 1 + }, + "89": + { + "min": 2, + "max": 2 + }, + "16,0": + { + "min": 100, + "max": 120 + } + } + }, + "silkweave": + { + "DisplayName": "Silkweave", + "NTIPAliasClassID": 387, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 150, + "max": 190 + }, + "138": + { + "min": 5, + "max": 5 + }, + "32": + { + "min": 200, + "max": 200 + }, + "77": + { + "min": 10, + "max": 10 + }, + "96": + { + "min": 30, + "max": 30 + } + } + }, + "skewerofkrintiz": + { + "DisplayName": "Skewer of Krintiz", + "NTIPAliasClassID": 27, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "115": + { + "min": 1, + "max": 1 + }, + "0": + { + "min": 10, + "max": 10 + }, + "2": + { + "min": 10, + "max": 10 + }, + "62": + { + "min": 7, + "max": 7 + }, + "25": + { + "min": 50, + "max": 50 + }, + "21": 3, + "22": 7 + } + }, + "skinoftheflayedone": + { + "DisplayName": "Skin of the Flayed One", + "NTIPAliasClassID": 361, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "252": + { + "min": None, + "max": None, + "par": 10 + }, + "74": + { + "min": 15, + "max": 25 + }, + "72": 30, + "73": 30, + "60": + { + "min": 5, + "max": 7 + }, + "16,0": + { + "min": 150, + "max": 190 + }, + "78": + { + "min": 15, + "max": 15 + } + } + }, + "skinofthevipermagi": + { + "DisplayName": "Skin of the Vipermagi", + "NTIPAliasClassID": 360, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 120 + }, + "39": + { + "min": 20, + "max": 35 + }, + "43": + { + "min": 20, + "max": 35 + }, + "41": + { + "min": 20, + "max": 35 + }, + "45": + { + "min": 20, + "max": 35 + }, + "105": + { + "min": 30, + "max": 30 + }, + "35": + { + "min": 9, + "max": 13 + }, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "skullcollector": + { + "DisplayName": "Skull Collector", + "NTIPAliasClassID": 160, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "77": + { + "min": 20, + "max": 20 + }, + "138": + { + "min": 20, + "max": 20 + }, + "127": + { + "min": 2, + "max": 2 + }, + "240": + { + "min": None, + "max": None, + "par": 8 + } + } + }, + "skullsplitter": + { + "DisplayName": "Skull Splitter", + "NTIPAliasClassID": 3, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "113": + { + "min": 2, + "max": 2 + }, + "27": + { + "min": 20, + "max": 20 + }, + "50": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 12, + "max": 15 + }, + "19": + { + "min": 50, + "max": 100 + }, + "25": + { + "min": 60, + "max": 100 + }, + "135": + { + "min": 15, + "max": 15 + } + } + }, + "skulldersire": + { + "DisplayName": "Skullder's Ire", + "NTIPAliasClassID": 367, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "127": + { + "min": 1, + "max": 1 + }, + "240": + { + "min": None, + "max": None, + "par": 10 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "72": 60, + "73": 60, + "35": + { + "min": 10, + "max": 10 + }, + "252": + { + "min": None, + "max": None, + "par": 20 + } + } + }, + "skystrike": + { + "DisplayName": "Skystrike", + "NTIPAliasClassID": 161, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "50": 1, + "51": 250, + "19": + { + "min": 100, + "max": 100 + }, + "1": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 150, + "max": 200 + }, + "198": + { + "chance": 2, + "level": 6, + "skill": "Meteor" + }, + "83,0": + { + "min": 1, + "max": 1 + } + } + }, + "snakecord": + { + "DisplayName": "Snakecord", + "NTIPAliasClassID": 345, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "57": 12, + "58": 12, + "45": + { + "min": 25, + "max": 25 + }, + "31": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 20, + "max": 30 + }, + "74": + { + "min": 5, + "max": 5 + }, + "110": + { + "min": 50, + "max": 50 + } + } + }, + "snowclash": + { + "DisplayName": "Snowclash", + "NTIPAliasClassID": 393, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "201": + { + "chance": 5, + "level": None, + "skill": "Blizzard" + }, + "149": + { + "min": 15, + "max": 15 + }, + "44": + { + "min": 15, + "max": 15 + }, + "54": 13, + "55": 21, + "16,0": + { + "min": 130, + "max": 170 + }, + "107,59": + { + "min": 2, + "max": 2 + }, + "107,55": + { + "min": 3, + "max": 3 + }, + "107,60": + { + "min": 2, + "max": 2 + } + } + }, + "souldrainer": + { + "DisplayName": "Soul Drainer", + "NTIPAliasClassID": 452, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 90, + "max": 120 + }, + "62": + { + "min": 4, + "max": 7 + }, + "60": + { + "min": 4, + "max": 7 + }, + "198": + { + "chance": 8, + "level": 3, + "skill": "Weaken" + }, + "120": + { + "min": -50, + "max": -50 + } + } + }, + "soulharvest": + { + "DisplayName": "Soul Harvest", + "NTIPAliasClassID": 59, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "135": + { + "min": 30, + "max": 30 + }, + "19": + { + "min": 45, + "max": 45 + }, + "39": 20, + "43": 20, + "41": 20, + "45": 20, + "25": + { + "min": 50, + "max": 90 + }, + "62": + { + "min": 10, + "max": 10 + }, + "1": + { + "min": 5, + "max": 5 + } + } + }, + "soulfeasttine": + { + "DisplayName": "Soulfeast Tine", + "NTIPAliasClassID": 147, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "91": + { + "min": -20, + "max": -20 + }, + "60": + { + "min": 7, + "max": 7 + }, + "62": + { + "min": 7, + "max": 7 + }, + "154": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 150, + "max": 190 + }, + "19": + { + "min": 150, + "max": 250 + }, + "72": 15, + "73": 15 + } + }, + "soulflay": + { + "DisplayName": "Soulflay", + "NTIPAliasClassID": 34, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "62": + { + "min": 4, + "max": 10 + }, + "60": + { + "min": 4, + "max": 4 + }, + "25": + { + "min": 70, + "max": 100 + }, + "39": 5, + "43": 5, + "41": 5, + "45": 5, + "93": + { + "min": 10, + "max": 10 + } + } + }, + "sparkingmail": + { + "DisplayName": "Sparking Mail", + "NTIPAliasClassID": 319, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 75, + "max": 85 + }, + "50": 1, + "51": 20, + "128": + { + "min": 10, + "max": 14 + }, + "41": + { + "min": 30, + "max": 30 + } + } + }, + "spectralshard": + { + "DisplayName": "Spectral Shard", + "NTIPAliasClassID": 42, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "105": + { + "min": 50, + "max": 50 + }, + "8": + { + "min": 50, + "max": 50 + }, + "19": + { + "min": 55, + "max": 55 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10 + } + }, + "spellsteel": + { + "DisplayName": "Spellsteel", + "NTIPAliasClassID": 99, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "91": + { + "min": -60, + "max": -60 + }, + "8": + { + "min": 100, + "max": 100 + }, + "35": + { + "min": 12, + "max": 15 + }, + "105": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 165, + "max": 165 + }, + "27": + { + "min": 25, + "max": 25 + }, + "204": + { + "charges": 60, + "level": 12, + "skill": "Firestorm" + } + } + }, + "spikethorn": + { + "DisplayName": "Spike Thorn", + "NTIPAliasClassID": 467, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 150 + }, + "238": + { + "min": None, + "max": None, + "par": 11 + }, + "72": 250, + "73": 250, + "99": + { + "min": 30, + "max": 30 + }, + "36": + { + "min": 15, + "max": 20 + }, + "194": + { + "min": 1, + "max": 1 + } + } + }, + "spineripper": + { + "DisplayName": "Spineripper", + "NTIPAliasClassID": 132, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "115": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 8, + "max": 8 + }, + "117": + { + "min": 1, + "max": 1 + }, + "93": + { + "min": 15, + "max": 15 + }, + "2": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 200, + "max": 240 + }, + "21": 15, + "22": 27, + "83,2": + { + "min": 1, + "max": 1 + } + } + }, + "spireofhonor": + { + "DisplayName": "Spire of Honor", + "NTIPAliasClassID": 149, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "119": + { + "min": 25, + "max": 25 + }, + "89": + { + "min": 3, + "max": 3 + }, + "74": + { + "min": 20, + "max": 20 + }, + "99": + { + "min": 20, + "max": 20 + }, + "21": 20, + "22": 40, + "243": + { + "min": None, + "max": None, + "par": 12 + }, + "25": + { + "min": 150, + "max": 200 + }, + "188,24": + { + "min": 3, + "max": 3, + "par": "Combat Skills" + }, + "16,0": + { + "min": 25, + "max": 25 + } + } + }, + "spireoflazarus": + { + "DisplayName": "Spire of Lazarus", + "NTIPAliasClassID": 65, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "41": + { + "min": 75, + "max": 75 + }, + "34": + { + "min": 5, + "max": 5 + }, + "1": + { + "min": 15, + "max": 15 + }, + "107,53": + { + "min": 1, + "max": 1 + }, + "107,49": + { + "min": 2, + "max": 2 + }, + "107,42": + { + "min": 3, + "max": 3 + }, + "27": + { + "min": 43, + "max": 43 + }, + "50": 1, + "51": 28, + "83,1": + { + "min": 1, + "max": 1 + } + } + }, + "spiritforge": + { + "DisplayName": "Spirit Forge", + "NTIPAliasClassID": 363, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "89": + { + "min": 4, + "max": 4 + }, + "216": + { + "min": None, + "max": None, + "par": 10 + }, + "48": 20, + "49": 65, + "39": + { + "min": 5, + "max": 5 + }, + "16,0": + { + "min": 120, + "max": 160 + }, + "0": + { + "min": 15, + "max": 15 + }, + "194": + { + "min": 2, + "max": 2 + } + } + }, + "spiritkeeper": + { + "DisplayName": "Spirit Keeper", + "NTIPAliasClassID": 490, + "NTIPAliasType": 72, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 170, + "max": 190 + }, + "99": + { + "min": 20, + "max": 20 + }, + "145": + { + "min": 9, + "max": 14 + }, + "39": + { + "min": 30, + "max": 40 + }, + "148": + { + "min": 15, + "max": 25 + }, + "46": + { + "min": 10, + "max": 10 + }, + "83,5": + { + "min": 1, + "max": 2 + } + } + }, + "spiritward": + { + "DisplayName": "Spirit Ward", + "NTIPAliasClassID": 449, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 130, + "max": 180 + }, + "149": + { + "min": 6, + "max": 11 + }, + "39": + { + "min": 30, + "max": 40 + }, + "43": + { + "min": 30, + "max": 40 + }, + "41": + { + "min": 30, + "max": 40 + }, + "45": + { + "min": 30, + "max": 40 + }, + "20": + { + "min": 20, + "max": 30 + }, + "102": + { + "min": 25, + "max": 25 + }, + "201": + { + "chance": 5, + "level": 8, + "skill": "Fade" + } + } + }, + "staffofkings": + { + "DisplayName": "Staff of Kings", + "NTIPAliasClassID": 92, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "93": + { + "min": 50, + "max": 50 + } + } + }, + "stealskull": + { + "DisplayName": "Stealskull", + "NTIPAliasClassID": 354, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "62": + { + "min": 5, + "max": 5 + }, + "60": + { + "min": 5, + "max": 5 + }, + "99": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 200, + "max": 240 + }, + "80": + { + "min": 30, + "max": 50 + } + } + }, + "steelcarapace": + { + "DisplayName": "Steel Carapace", + "NTIPAliasClassID": 441, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 190, + "max": 220 + }, + "99": + { + "min": 20, + "max": 20 + }, + "34": + { + "min": 9, + "max": 14 + }, + "43": + { + "min": 40, + "max": 60 + }, + "27": + { + "min": 10, + "max": 15 + }, + "252": + { + "min": None, + "max": None, + "par": 5 + }, + "201": + { + "chance": 8, + "level": 6, + "skill": "Iron Maiden" + } + } + }, + "steelpillar": + { + "DisplayName": "Steel Pillar", + "NTIPAliasClassID": 252, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "25": + { + "min": 210, + "max": 260 + }, + "93": + { + "min": 25, + "max": 25 + }, + "116": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 50, + "max": 80 + }, + "152": + { + "min": 1, + "max": 1 + }, + "136": + { + "min": 25, + "max": 25 + } + } + }, + "steelshade": + { + "DisplayName": "Steel Shade", + "NTIPAliasClassID": 424, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 100, + "max": 130 + }, + "143": + { + "min": 5, + "max": 11 + }, + "62": + { + "min": 4, + "max": 8 + }, + "74": + { + "min": 10, + "max": 18 + } + } + }, + "steelclash": + { + "DisplayName": "Steelclash", + "NTIPAliasClassID": 331, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "20": + { + "min": 25, + "max": 25 + }, + "83,3": + { + "min": 1, + "max": 1 + }, + "34": + { + "min": 3, + "max": 3 + }, + "89": + { + "min": 3, + "max": 3 + }, + "16,0": + { + "min": 60, + "max": 100 + }, + "102": + { + "min": 20, + "max": 20 + }, + "39": 15, + "43": 15, + "41": 15, + "45": 15, + "31": + { + "min": 20, + "max": 20 + }, + "72": 15, + "73": 20 + } + }, + "steeldriver": + { + "DisplayName": "Steeldriver", + "NTIPAliasClassID": 24, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "91": + { + "min": -50, + "max": -50 + }, + "93": + { + "min": 40, + "max": 40 + }, + "28": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 150, + "max": 250 + } + } + }, + "steelgoad": + { + "DisplayName": "Steelgoad", + "NTIPAliasClassID": 58, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "112": + { + "min": 96, + "max": 96 + }, + "141": + { + "min": 30, + "max": 30 + }, + "19": + { + "min": 30, + "max": 30 + }, + "39": 5, + "43": 5, + "41": 5, + "45": 5, + "25": + { + "min": 60, + "max": 80 + }, + "72": 20, + "73": 40 + } + }, + "steelrend": + { + "DisplayName": "Steelrend", + "NTIPAliasClassID": 454, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "31": + { + "min": 170, + "max": 210 + }, + "0": + { + "min": 15, + "max": 20 + }, + "25": + { + "min": 30, + "max": 60 + }, + "136": + { + "min": 10, + "max": 10 + } + } + }, + "stonecrusher": + { + "DisplayName": "Stone Crusher", + "NTIPAliasClassID": 218, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "25": + { + "min": 280, + "max": 320 + }, + "0": + { + "min": 20, + "max": 30 + }, + "136": + { + "min": 40, + "max": 40 + }, + "116": + { + "min": 25, + "max": 25 + }, + "120": + { + "min": -100, + "max": -100 + }, + "21": 10, + "22": 30 + } + }, + "stoneraven": + { + "DisplayName": "Stoneraven", + "NTIPAliasClassID": 303, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "25": + { + "min": 230, + "max": 280 + }, + "52": 101, + "53": 187, + "39": + { + "min": 30, + "max": 50 + }, + "43": + { + "min": 30, + "max": 50 + }, + "41": + { + "min": 30, + "max": 50 + }, + "45": + { + "min": 30, + "max": 50 + }, + "31": + { + "min": 400, + "max": 600 + }, + "188,2": + { + "min": 1, + "max": 3, + "par": "Javelin and Spear Skills" + } + } + }, + "stormchaser": + { + "DisplayName": "Stormchaser", + "NTIPAliasClassID": 376, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "50": 1, + "51": 60, + "20": + { + "min": 20, + "max": 20 + }, + "118": + { + "min": 1, + "max": 1 + }, + "41": + { + "min": 50, + "max": 50 + }, + "19": + { + "min": 150, + "max": 150 + }, + "16,0": + { + "min": 160, + "max": 220 + }, + "102": + { + "min": 10, + "max": 10 + }, + "201": + { + "chance": 4, + "level": 5, + "skill": "Tornado" + } + } + }, + "stormeye": + { + "DisplayName": "Stormeye", + "NTIPAliasClassID": 17, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "50": 1, + "51": 6, + "54": 3, + "55": 5, + "74": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 80, + "max": 120 + }, + "107,110": + { + "min": 3, + "max": 5 + }, + "107,118": + { + "min": 3, + "max": 3 + }, + "107,121": + { + "min": 1, + "max": 1 + } + } + }, + "stormguild": + { + "DisplayName": "Stormguild", + "NTIPAliasClassID": 330, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "35": + { + "min": 1, + "max": 1 + }, + "41": + { + "min": 25, + "max": 25 + }, + "31": + { + "min": 30, + "max": 30 + }, + "50": 1, + "51": 6, + "16,0": + { + "min": 50, + "max": 60 + }, + "20": + { + "min": 30, + "max": 30 + }, + "128": + { + "min": 3, + "max": 3 + }, + "72": 10, + "73": 15 + } + }, + "stormlash": + { + "DisplayName": "Stormlash", + "NTIPAliasClassID": 217, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "25": + { + "min": 240, + "max": 300 + }, + "93": + { + "min": 30, + "max": 30 + }, + "198": + { + "chance": 20, + "level": 18, + "skill": "Tornado" + }, + "50": 1, + "51": 473, + "128": + { + "min": 30, + "max": 30 + }, + "136": + { + "min": 33, + "max": 33 + }, + "145": + { + "min": 3, + "max": 9 + } + } + }, + "stormrider": + { + "DisplayName": "Stormrider", + "NTIPAliasClassID": 100, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "198": + { + "chance": 10, + "level": None, + "skill": "Charged Bolt" + }, + "50": 1, + "51": 200, + "21": 35, + "22": 75, + "25": + { + "min": 100, + "max": 100 + }, + "72": 50, + "73": 50, + "128": + { + "min": 15, + "max": 15 + }, + "201": + { + "chance": 15, + "level": 5, + "skill": "Charged Bolt" + } + } + }, + "stormshield": + { + "DisplayName": "Stormshield", + "NTIPAliasClassID": 447, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "214": + { + "min": None, + "max": None, + "par": 30 + }, + "36": + { + "min": 35, + "max": 35 + }, + "0": + { + "min": 30, + "max": 30 + }, + "152": + { + "min": 1, + "max": 1 + }, + "102": + { + "min": 35, + "max": 35 + }, + "41": + { + "min": 25, + "max": 25 + }, + "20": + { + "min": 25, + "max": 25 + }, + "43": + { + "min": 60, + "max": 60 + }, + "128": + { + "min": 10, + "max": 10 + } + } + }, + "stormspike": + { + "DisplayName": "Stormspike", + "NTIPAliasClassID": 135, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "50": 1, + "51": 120, + "128": + { + "min": 20, + "max": 20 + }, + "201": + { + "chance": 25, + "level": 3, + "skill": "Charged Bolt" + }, + "25": + { + "min": 150, + "max": 150 + }, + "232": + { + "min": None, + "max": None, + "par": 8 + } + } + }, + "stormspire": + { + "DisplayName": "Stormspire", + "NTIPAliasClassID": 258, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "41": + { + "min": 50, + "max": 50 + }, + "201": + { + "chance": 2, + "level": None, + "skill": "Charged Bolt" + }, + "25": + { + "min": 150, + "max": 250 + }, + "0": + { + "min": 10, + "max": 10 + }, + "93": + { + "min": 30, + "max": 30 + }, + "152": + { + "min": 1, + "max": 1 + }, + "50": 1, + "51": 237, + "128": + { + "min": 27, + "max": 27 + } + } + }, + "stormstrike": + { + "DisplayName": "Stormstrike", + "NTIPAliasClassID": 72, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "50": 1, + "51": 30, + "0": + { + "min": 8, + "max": 8 + }, + "19": + { + "min": 28, + "max": 28 + }, + "156": + { + "min": 25, + "max": 25 + }, + "41": + { + "min": 25, + "max": 25 + }, + "25": + { + "min": 70, + "max": 90 + } + } + }, + "stoutnail": + { + "DisplayName": "Stoutnail", + "NTIPAliasClassID": 18, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "78": + { + "min": 3, + "max": 10 + }, + "25": + { + "min": 100, + "max": 100 + }, + "3": + { + "min": 7, + "max": 7 + }, + "35": + { + "min": 2, + "max": 2 + } + } + }, + "stringofears": + { + "DisplayName": "String of Ears", + "NTIPAliasClassID": 390, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "35": + { + "min": 10, + "max": 15 + }, + "36": + { + "min": 10, + "max": 15 + }, + "60": + { + "min": 6, + "max": 8 + }, + "16,0": + { + "min": 150, + "max": 180 + }, + "31": + { + "min": 15, + "max": 15 + }, + "72": 10, + "73": 10 + } + }, + "suicidebranch": + { + "DisplayName": "Suicide Branch", + "NTIPAliasClassID": 103, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "78": + { + "min": 25, + "max": 25 + }, + "105": + { + "min": 50, + "max": 50 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "77": + { + "min": 10, + "max": 10 + }, + "6": + { + "min": 40, + "max": 40 + }, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "sureshrillfrost": + { + "DisplayName": "Sureshrill Frost", + "NTIPAliasClassID": 112, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "54": 63, + "55": 112, + "153": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 150, + "max": 180 + }, + "21": 5, + "22": 10, + "134": + { + "min": 3, + "max": 3 + }, + "204": + { + "charges": 50, + "level": 9, + "skill": "Frozen Orb" + } + } + }, + "swordbackhold": + { + "DisplayName": "Swordback Hold", + "NTIPAliasClassID": 351, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "78": + { + "min": 5, + "max": 5 + }, + "20": + { + "min": 20, + "max": 20 + }, + "135": + { + "min": 50, + "max": 50 + }, + "16,0": + { + "min": 30, + "max": 60 + }, + "31": + { + "min": 10, + "max": 10 + } + } + }, + "swordguard": + { + "DisplayName": "Swordguard", + "NTIPAliasClassID": 131, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "91": + { + "min": -50, + "max": -50 + }, + "214": + { + "min": None, + "max": None, + "par": 40 + }, + "39": + { + "min": 10, + "max": 20 + }, + "43": + { + "min": 10, + "max": 20 + }, + "41": + { + "min": 10, + "max": 20 + }, + "45": + { + "min": 10, + "max": 20 + }, + "32": + { + "min": 100, + "max": 100 + }, + "114": + { + "min": 30, + "max": 30 + }, + "25": + { + "min": 170, + "max": 180 + }, + "33": + { + "min": 200, + "max": 200 + }, + "99": + { + "min": 20, + "max": 20 + }, + "20": + { + "min": 20, + "max": 20 + } + } + }, + "tarnhelm": + { + "DisplayName": "Tarnhelm", + "NTIPAliasClassID": 307, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "79": + { + "min": 75, + "max": 75 + }, + "80": + { + "min": 25, + "max": 50 + }, + "127": + { + "min": 1, + "max": 1 + } + } + }, + "tearhaunch": + { + "DisplayName": "Tearhaunch", + "NTIPAliasClassID": 343, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "31": + { + "min": 35, + "max": 35 + }, + "0": + { + "min": 5, + "max": 5 + }, + "2": + { + "min": 5, + "max": 5 + }, + "96": + { + "min": 20, + "max": 20 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "16,0": + { + "min": 60, + "max": 80 + }, + "107,115": + { + "min": 2, + "max": 2 + } + } + }, + "templarsmight": + { + "DisplayName": "Templar's Might", + "NTIPAliasClassID": 442, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 170, + "max": 220 + }, + "99": + { + "min": 20, + "max": 20 + }, + "32": + { + "min": 250, + "max": 300 + }, + "10": + { + "min": 40, + "max": 50 + }, + "0": + { + "min": 10, + "max": 15 + }, + "3": + { + "min": 10, + "max": 15 + }, + "188,25": + { + "min": 1, + "max": 2, + "par": "Offensive Auras" + } + } + }, + "theatlantean": + { + "DisplayName": "The Atlantean", + "NTIPAliasClassID": 125, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "72": 100, + "73": 100, + "31": + { + "min": 75, + "max": 75 + }, + "0": + { + "min": 16, + "max": 16 + }, + "2": + { + "min": 12, + "max": 12 + }, + "3": + { + "min": 8, + "max": 8 + }, + "25": + { + "min": 200, + "max": 250 + }, + "83,3": + { + "min": 2, + "max": 2 + }, + "119": + { + "min": 50, + "max": 50 + } + } + }, + "thebattlebranch": + { + "DisplayName": "The Battlebranch", + "NTIPAliasClassID": 60, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "93": + { + "min": 30, + "max": 30 + }, + "2": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 50, + "max": 70 + }, + "19": + { + "min": 50, + "max": 100 + }, + "60": + { + "min": 7, + "max": 7 + } + } + }, + "thecatseye": + { + "DisplayName": "The Cat's Eye", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "96": + { + "min": 30, + "max": 30 + }, + "93": + { + "min": 20, + "max": 20 + }, + "31": + { + "min": 100, + "max": 100 + }, + "32": + { + "min": 100, + "max": 100 + }, + "2": + { + "min": 25, + "max": 25 + } + } + }, + "thecenturion": + { + "DisplayName": "The Centurion", + "NTIPAliasClassID": 315, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "31": + { + "min": 30, + "max": 30 + }, + "19": + { + "min": 50, + "max": 50 + }, + "34": + { + "min": 2, + "max": 2 + }, + "6": + { + "min": 15, + "max": 15 + }, + "8": + { + "min": 15, + "max": 15 + }, + "10": + { + "min": 15, + "max": 15 + }, + "74": + { + "min": 5, + "max": 5 + }, + "154": + { + "min": 25, + "max": 25 + } + } + }, + "thechieftain": + { + "DisplayName": "The Chieftain", + "NTIPAliasClassID": 7, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "25": + { + "min": 100, + "max": 100 + }, + "39": + { + "min": 10, + "max": 20 + }, + "43": + { + "min": 10, + "max": 20 + }, + "41": + { + "min": 10, + "max": 20 + }, + "45": + { + "min": 10, + "max": 20 + }, + "138": + { + "min": 6, + "max": 6 + }, + "93": + { + "min": 20, + "max": 20 + }, + "50": 1, + "51": 40 + } + }, + "thecraniumbasher": + { + "DisplayName": "The Cranium Basher", + "NTIPAliasClassID": 220, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "93": + { + "min": 20, + "max": 20 + }, + "152": + { + "min": 1, + "max": 1 + }, + "0": + { + "min": 25, + "max": 25 + }, + "39": 25, + "43": 25, + "41": 25, + "45": 25, + "136": + { + "min": 75, + "max": 75 + }, + "21": 20, + "22": 20, + "25": + { + "min": 200, + "max": 240 + }, + "198": + { + "chance": 4, + "level": 1, + "skill": "Amplify Damage" + } + } + }, + "thediggler": + { + "DisplayName": "The Diggler", + "NTIPAliasClassID": 40, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "2": + { + "min": 10, + "max": 10 + }, + "25": + { + "min": 50, + "max": 50 + }, + "93": + { + "min": 30, + "max": 30 + }, + "43": + { + "min": 25, + "max": 25 + }, + "39": + { + "min": 25, + "max": 25 + }, + "115": + { + "min": 1, + "max": 1 + } + } + }, + "thedragonchang": + { + "DisplayName": "The Dragon Chang", + "NTIPAliasClassID": 52, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "19": + { + "min": 35, + "max": 35 + }, + "21": + { + "min": 10, + "max": 10 + }, + "89": + { + "min": 2, + "max": 2 + }, + "122": + { + "min": 100, + "max": 100 + }, + "48": 3, + "49": 6 + } + }, + "theeyeofetlich": + { + "DisplayName": "The Eye of Etlich", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "32": + { + "min": 10, + "max": 40 + }, + "89": + { + "min": 1, + "max": 5 + }, + "127": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 3, + "max": 7 + }, + "54": + { + "min": 1, + "max": 2 + }, + "55": + { + "min": 3, + "max": 5 + }, + "56": + { + "min": 50, + "max": 250 + } + } + }, + "thefaceofhorror": + { + "DisplayName": "The Face of Horror", + "NTIPAliasClassID": 312, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "112": + { + "min": 64, + "max": 64 + }, + "0": + { + "min": 20, + "max": 20 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "122": + { + "min": 50, + "max": 50 + }, + "31": + { + "min": 25, + "max": 25 + } + } + }, + "thefetidsprinkler": + { + "DisplayName": "The Fetid Sprinkler", + "NTIPAliasClassID": 109, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "83,3": + { + "min": 2, + "max": 2 + }, + "198": + { + "chance": 10, + "level": 1, + "skill": "Confuse" + }, + "57": 160, + "58": 160, + "25": + { + "min": 160, + "max": 190 + }, + "19": + { + "min": 150, + "max": 200 + }, + "21": 15, + "22": 25 + } + }, + "thegavelofpain": + { + "DisplayName": "The Gavel of Pain", + "NTIPAliasClassID": 117, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "198": + { + "chance": 5, + "level": 1, + "skill": "Amplify Damage" + }, + "201": + { + "chance": 5, + "level": 1, + "skill": "Iron Maiden" + }, + "78": + { + "min": 26, + "max": 26 + }, + "152": + { + "min": 1, + "max": 1 + }, + "21": 12, + "22": 30, + "25": + { + "min": 130, + "max": 160 + }, + "204": + { + "charges": 3, + "level": 8, + "skill": "Amplify Damage" + } + } + }, + "thegeneralstandoliga": + { + "DisplayName": "The General's Tan Do Li Ga", + "NTIPAliasClassID": 21, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "21": + { + "min": 1, + "max": 1 + }, + "22": + { + "min": 20, + "max": 20 + }, + "150": + { + "min": 50, + "max": 50 + }, + "31": + { + "min": 25, + "max": 25 + }, + "62": + { + "min": 5, + "max": 5 + }, + "25": + { + "min": 50, + "max": 60 + }, + "93": + { + "min": 20, + "max": 20 + } + } + }, + "thegladiatorsbane": + { + "DisplayName": "The Gladiator's Bane", + "NTIPAliasClassID": 432, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 150, + "max": 200 + }, + "35": + { + "min": 15, + "max": 20 + }, + "34": + { + "min": 15, + "max": 20 + }, + "78": + { + "min": 20, + "max": 20 + }, + "110": + { + "min": 50, + "max": 50 + }, + "72": 103, + "73": 103, + "99": + { + "min": 30, + "max": 30 + }, + "31": + { + "min": 50, + "max": 50 + }, + "153": + { + "min": 1, + "max": 1 + } + } + }, + "thegnasher": + { + "DisplayName": "The Gnasher", + "NTIPAliasClassID": 0, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "0": + { + "min": 8, + "max": 8 + }, + "135": + { + "min": 50, + "max": 50 + }, + "136": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 60, + "max": 70 + } + } + }, + "thegrandfather": + { + "DisplayName": "The Grandfather", + "NTIPAliasClassID": 234, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 20, + "max": 20 + }, + "3": + { + "min": 20, + "max": 20 + }, + "1": + { + "min": 20, + "max": 20 + }, + "119": + { + "min": 50, + "max": 50 + }, + "6": + { + "min": 80, + "max": 80 + }, + "218": + { + "min": None, + "max": None, + "par": 20 + }, + "152": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 150, + "max": 250 + } + } + }, + "thegrimreaper": + { + "DisplayName": "The Grim Reaper", + "NTIPAliasClassID": 62, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "141": + { + "min": 100, + "max": 100 + }, + "117": + { + "min": 1, + "max": 1 + }, + "62": + { + "min": 5, + "max": 5 + }, + "25": + { + "min": 20, + "max": 20 + }, + "21": + { + "min": 15, + "max": 15 + } + } + }, + "thehandofbroc": + { + "DisplayName": "The Hand of Broc", + "NTIPAliasClassID": 334, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "62": + { + "min": 3, + "max": 3 + }, + "60": + { + "min": 3, + "max": 3 + }, + "45": + { + "min": 10, + "max": 10 + }, + "8": + { + "min": 20, + "max": 20 + }, + "31": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 10, + "max": 20 + } + } + }, + "theimpaler": + { + "DisplayName": "The Impaler", + "NTIPAliasClassID": 145, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "115": + { + "min": 1, + "max": 1 + }, + "19": + { + "min": 150, + "max": 150 + }, + "93": + { + "min": 20, + "max": 20 + }, + "135": + { + "min": 40, + "max": 40 + }, + "117": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 140, + "max": 170 + }, + "107,19": + { + "min": 5, + "max": 5 + }, + "107,14": + { + "min": 3, + "max": 3 + } + } + }, + "theironjangbong": + { + "DisplayName": "The Iron Jang Bong", + "NTIPAliasClassID": 67, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "31": + { + "min": 30, + "max": 30 + }, + "105": + { + "min": 20, + "max": 20 + }, + "25": + { + "min": 100, + "max": 100 + }, + "119": + { + "min": 50, + "max": 50 + }, + "107,48": + { + "min": 2, + "max": 2 + }, + "107,46": + { + "min": 2, + "max": 2 + }, + "107,44": + { + "min": 3, + "max": 3 + }, + "83,1": + { + "min": 2, + "max": 2 + } + } + }, + "thejadetando": + { + "DisplayName": "The Jade Tan Do", + "NTIPAliasClassID": 41, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "19": + { + "min": 100, + "max": 150 + }, + "153": + { + "min": 1, + "max": 1 + }, + "57": 180, + "58": 180, + "45": + { + "min": 95, + "max": 95 + }, + "46": + { + "min": 20, + "max": 20 + } + } + }, + "themahimoakcurio": + { + "DisplayName": "The Mahim-Oak Curio", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "2": + { + "min": 10, + "max": 10 + }, + "0": + { + "min": 10, + "max": 10 + }, + "1": + { + "min": 10, + "max": 10 + }, + "3": + { + "min": 10, + "max": 10 + }, + "31": + { + "min": 10, + "max": 10 + }, + "119": + { + "min": 10, + "max": 10 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "16,0": + { + "min": 10, + "max": 10 + } + } + }, + "themeatscraper": + { + "DisplayName": "The Meat Scraper", + "NTIPAliasClassID": 150, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 200 + }, + "93": + { + "min": 30, + "max": 30 + }, + "60": + { + "min": 10, + "max": 10 + }, + "135": + { + "min": 50, + "max": 50 + }, + "80": + { + "min": 25, + "max": 25 + }, + "188,33": + { + "min": 3, + "max": 3, + "par": "Masteries" + } + } + }, + "theminotaur": + { + "DisplayName": "The Minotaur", + "NTIPAliasClassID": 102, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "113": + { + "min": 2, + "max": 2 + }, + "118": + { + "min": 1, + "max": 1 + }, + "0": + { + "min": 15, + "max": 20 + }, + "150": + { + "min": 50, + "max": 50 + }, + "136": + { + "min": 30, + "max": 30 + }, + "21": 20, + "22": 30, + "25": + { + "min": 140, + "max": 200 + } + } + }, + "theoculus": + { + "DisplayName": "The Oculus", + "NTIPAliasClassID": 290, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 3, + "max": 3 + }, + "201": + { + "chance": 25, + "level": 1, + "skill": "Teleport" + }, + "39": 20, + "43": 20, + "41": 20, + "45": 20, + "105": + { + "min": 30, + "max": 30 + }, + "16,0": + { + "min": 20, + "max": 20 + }, + "3": + { + "min": 20, + "max": 20 + }, + "1": + { + "min": 20, + "max": 20 + }, + "138": + { + "min": 5, + "max": 5 + }, + "80": + { + "min": 50, + "max": 50 + } + } + }, + "thepatriarch": + { + "DisplayName": "The Patriarch", + "NTIPAliasClassID": 38, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "34": + { + "min": 3, + "max": 3 + }, + "35": + { + "min": 3, + "max": 3 + }, + "113": + { + "min": 1, + "max": 1 + }, + "79": + { + "min": 100, + "max": 100 + }, + "25": + { + "min": 100, + "max": 120 + }, + "0": + { + "min": 10, + "max": 10 + } + } + }, + "thereaperstoll": + { + "DisplayName": "The Reaper's Toll", + "NTIPAliasClassID": 255, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "25": + { + "min": 190, + "max": 240 + }, + "198": + { + "chance": 33, + "level": 1, + "skill": "Decrepify" + }, + "115": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 11, + "max": 15 + }, + "91": + { + "min": -25, + "max": -25 + }, + "141": + { + "min": 33, + "max": 33 + }, + "54": 4, + "55": 44 + } + }, + "theredeemer": + { + "DisplayName": "The Redeemer", + "NTIPAliasClassID": 211, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "25": + { + "min": 250, + "max": 300 + }, + "121": + { + "min": 200, + "max": 250 + }, + "83,3": + { + "min": 2, + "max": 2 + }, + "91": + { + "min": -60, + "max": -60 + }, + "107,124": + { + "min": 2, + "max": 4 + }, + "107,101": + { + "min": 2, + "max": 4 + }, + "89": + { + "min": 3, + "max": 3 + }, + "116": + { + "min": 33, + "max": 33 + }, + "21": 60, + "22": 120 + } + }, + "therisingsun": + { + "DisplayName": "The Rising Sun", + "NTIPAliasClassID": 520, + "NTIPAliasType": 12, + "NTIPAliasStatProps": + { + "235": + { + "min": None, + "max": None, + "par": 6 + }, + "89": + { + "min": 4, + "max": 4 + }, + "201": + { + "chance": 2, + "level": None, + "skill": "Meteor" + }, + "48": 24, + "49": 48, + "188,8": + { + "min": 2, + "max": 2 + }, + "74": + { + "min": 10, + "max": 10 + } + } + }, + "thesalamander": + { + "DisplayName": "The Salamander", + "NTIPAliasClassID": 66, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "48": 15, + "49": 32, + "39": + { + "min": 30, + "max": 30 + }, + "107,51": + { + "min": 1, + "max": 1 + }, + "107,47": + { + "min": 2, + "max": 2 + }, + "107,37": + { + "min": 3, + "max": 3 + }, + "188,8": + { + "min": 2, + "max": 2 + } + } + }, + "thescalper": + { + "DisplayName": "The Scalper", + "NTIPAliasClassID": 137, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "253": + { + "min": None, + "max": None, + "par": 30 + }, + "25": + { + "min": 150, + "max": 200 + }, + "119": + { + "min": 25, + "max": 25 + }, + "93": + { + "min": 20, + "max": 20 + }, + "135": + { + "min": 33, + "max": 33 + }, + "60": + { + "min": 4, + "max": 6 + }, + "138": + { + "min": 4, + "max": 4 + } + } + }, + "thespiritshroud": + { + "DisplayName": "The Spirit Shroud", + "NTIPAliasClassID": 359, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "153": + { + "min": 1, + "max": 1 + }, + "127": + { + "min": 1, + "max": 1 + }, + "35": + { + "min": 7, + "max": 11 + }, + "74": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 150, + "max": 150 + } + } + }, + "thestoneofjordan": + { + "DisplayName": "The Stone of Jordan", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "8": + { + "min": 20, + "max": 20 + }, + "77": + { + "min": 25, + "max": 25 + }, + "50": + { + "min": 1, + "max": 1 + }, + "127": + { + "min": 1, + "max": 1 + }, + "51": + { + "min": 12, + "max": 12 + } + } + }, + "thetannrgorerod": + { + "DisplayName": "The Tannr Gorerod", + "NTIPAliasClassID": 56, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "48": + { + "min": 23, + "max": 23 + }, + "49": + { + "min": 54, + "max": 54 + }, + "40": + { + "min": 15, + "max": 15 + }, + "6": + { + "min": 30, + "max": 30 + }, + "19": + { + "min": 60, + "max": 60 + }, + "89": + { + "min": 3, + "max": 3 + }, + "39": + { + "min": 15, + "max": 15 + }, + "25": + { + "min": 80, + "max": 100 + } + } + }, + "thevilehusk": + { + "DisplayName": "The Vile Husk", + "NTIPAliasClassID": 128, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "198": + { + "chance": 6, + "level": 1, + "skill": "Amplify Damage" + }, + "244": + { + "min": None, + "max": None, + "par": 20 + }, + "45": + { + "min": 50, + "max": 50 + }, + "57": 250, + "58": 250, + "25": + { + "min": 150, + "max": 200 + } + } + }, + "theward": + { + "DisplayName": "The Ward", + "NTIPAliasClassID": 333, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "31": + { + "min": 40, + "max": 40 + }, + "35": + { + "min": 2, + "max": 2 + }, + "0": + { + "min": 10, + "max": 10 + }, + "20": + { + "min": 10, + "max": 10 + }, + "16,0": + { + "min": 100, + "max": 100 + }, + "39": + { + "min": 30, + "max": 50 + }, + "43": + { + "min": 30, + "max": 50 + }, + "41": + { + "min": 30, + "max": 50 + }, + "45": + { + "min": 30, + "max": 50 + } + } + }, + "thundergodsvigor": + { + "DisplayName": "Thundergod's Vigor", + "NTIPAliasClassID": 394, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "201": + { + "chance": 5, + "level": 7, + "skill": "Fist of the Heavens" + }, + "50": 1, + "51": 50, + "42": + { + "min": 10, + "max": 10 + }, + "145": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 160, + "max": 200 + }, + "3": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 20, + "max": 20 + }, + "107,34": + { + "min": 3, + "max": 3 + }, + "107,35": + { + "min": 3, + "max": 3 + } + } + }, + "thunderstroke": + { + "DisplayName": "Thunderstroke", + "NTIPAliasClassID": 305, + "NTIPAliasType": 87, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 200 + }, + "50": 1, + "51": 511, + "198": + { + "chance": 20, + "level": 14, + "skill": "Lightning" + }, + "93": + { + "min": 15, + "max": 15 + }, + "334": + { + "min": 15, + "max": 15 + }, + "107,20": + { + "min": 3, + "max": 3 + }, + "188,2": + { + "min": 2, + "max": 4, + "par": "Javelin and Spear Skills" + } + } + }, + "tiamatsrebuke": + { + "DisplayName": "Tiamat's Rebuke", + "NTIPAliasClassID": 377, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "54": 27, + "55": 53, + "48": 35, + "49": 95, + "50": 1, + "51": 120, + "39": + { + "min": 25, + "max": 35 + }, + "43": + { + "min": 25, + "max": 35 + }, + "41": + { + "min": 25, + "max": 35 + }, + "45": + { + "min": 25, + "max": 35 + }, + "16,0": + { + "min": 140, + "max": 200 + }, + "201": + { + "chance": 3, + "level": 6, + "skill": "Hydra" + }, + "72": 40, + "73": 40 + } + }, + "titansrevenge": + { + "DisplayName": "Titan's Revenge", + "NTIPAliasClassID": 295, + "NTIPAliasType": 87, + "NTIPAliasStatProps": + { + "83,0": + { + "min": 2, + "max": 2 + }, + "188,2": + { + "min": 2, + "max": 2, + "par": "Javelin and Spear Skills" + }, + "25": + { + "min": 150, + "max": 200 + }, + "96": + { + "min": 30, + "max": 30 + }, + "253": + { + "min": None, + "max": None, + "par": 30 + }, + "0": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 20, + "max": 20 + }, + "60": + { + "min": 5, + "max": 9 + }, + "21": 25, + "22": 50, + "254": + { + "min": 60, + "max": 60 + } + } + }, + "todesfaelleflamme": + { + "DisplayName": "Todesfaelle Flamme", + "NTIPAliasClassID": 130, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "48": 50, + "49": 200, + "39": + { + "min": 40, + "max": 40 + }, + "143": + { + "min": 10, + "max": 10 + }, + "195": + { + "min": 10, + "max": 6, + "par": "Fire Ball" + }, + "25": + { + "min": 120, + "max": 160 + }, + "204": + { + "charges": 20, + "level": 10, + "skill": "Fire Wall" + } + } + }, + "tombreaver": + { + "DisplayName": "Tomb Reaver", + "NTIPAliasClassID": 256, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "93": + { + "min": 60, + "max": 60 + }, + "89": + { + "min": 4, + "max": 4 + }, + "25": + { + "min": 200, + "max": 280 + }, + "122": + { + "min": 150, + "max": 230 + }, + "80": + { + "min": 50, + "max": 80 + }, + "39": + { + "min": 30, + "max": 50 + }, + "43": + { + "min": 30, + "max": 50 + }, + "41": + { + "min": 30, + "max": 50 + }, + "45": + { + "min": 30, + "max": 50 + }, + "124": + { + "min": 250, + "max": 350 + }, + "155": + { + "min": 10, + "max": 10, + "par": "Returned" + }, + "86": + { + "min": 10, + "max": 14 + }, + "194": + { + "min": 1, + "max": 3 + } + } + }, + "toothrow": + { + "DisplayName": "Toothrow", + "NTIPAliasClassID": 369, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "78": + { + "min": 20, + "max": 40 + }, + "31": + { + "min": 40, + "max": 60 + }, + "0": + { + "min": 10, + "max": 10 + }, + "135": + { + "min": 40, + "max": 40 + }, + "39": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 160, + "max": 220 + }, + "72": 15, + "73": 15 + } + }, + "torchofiro": + { + "DisplayName": "Torch of Iro", + "NTIPAliasClassID": 10, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "83,2": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 6, + "max": 6 + }, + "48": 5, + "49": 9, + "89": + { + "min": 3, + "max": 3 + }, + "1": + { + "min": 10, + "max": 10 + }, + "27": + { + "min": 5, + "max": 5 + } + } + }, + "treadsofcthon": + { + "DisplayName": "Treads of Cthon", + "NTIPAliasClassID": 341, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "96": + { + "min": 30, + "max": 30 + }, + "32": + { + "min": 50, + "max": 50 + }, + "154": + { + "min": 50, + "max": 50 + }, + "6": + { + "min": 10, + "max": 10 + }, + "31": + { + "min": 12, + "max": 12 + }, + "16,0": + { + "min": 30, + "max": 40 + } + } + }, + "twitchthroe": + { + "DisplayName": "Twitchthroe", + "NTIPAliasClassID": 316, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "93": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 10, + "max": 10 + }, + "20": + { + "min": 25, + "max": 25 + }, + "31": + { + "min": 25, + "max": 25 + }, + "0": + { + "min": 10, + "max": 10 + }, + "99": + { + "min": 20, + "max": 20 + } + } + }, + "tyraelsmight": + { + "DisplayName": "Tyrael's Might", + "NTIPAliasClassID": 442, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "91": + { + "min": -100, + "max": -100 + }, + "152": + { + "min": 1, + "max": 1 + }, + "16,0": + { + "min": 120, + "max": 150 + }, + "108": + { + "min": 1, + "max": 1 + }, + "121": + { + "min": 50, + "max": 100 + }, + "153": + { + "min": 1, + "max": 1 + }, + "96": + { + "min": 20, + "max": 20 + }, + "39": + { + "min": 20, + "max": 30 + }, + "43": + { + "min": 20, + "max": 30 + }, + "41": + { + "min": 20, + "max": 30 + }, + "45": + { + "min": 20, + "max": 30 + }, + "0": + { + "min": 20, + "max": 30 + } + } + }, + "umbraldisk": + { + "DisplayName": "Umbral Disk", + "NTIPAliasClassID": 329, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "113": + { + "min": 1, + "max": 1 + }, + "2": + { + "min": 10, + "max": 10 + }, + "31": + { + "min": 30, + "max": 30 + }, + "6": + { + "min": 20, + "max": 20 + }, + "89": + { + "min": -2, + "max": -2 + }, + "16,0": + { + "min": 40, + "max": 50 + }, + "20": + { + "min": 30, + "max": 30 + }, + "72": 10, + "73": 15 + } + }, + "umeslament": + { + "DisplayName": "Ume's Lament", + "NTIPAliasClassID": 13, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "83,2": + { + "min": 2, + "max": 2 + }, + "8": + { + "min": 40, + "max": 40 + }, + "105": + { + "min": 20, + "max": 20 + }, + "112": + { + "min": 64, + "max": 64 + }, + "107,77": + { + "min": 3, + "max": 3 + }, + "107,87": + { + "min": 2, + "max": 2 + } + } + }, + "undeadcrown": + { + "DisplayName": "Undead Crown", + "NTIPAliasClassID": 311, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "60": + { + "min": 5, + "max": 5 + }, + "31": + { + "min": 40, + "max": 40 + }, + "45": + { + "min": 50, + "max": 50 + }, + "118": + { + "min": 1, + "max": 1 + }, + "16,0": + { + "min": 30, + "max": 60 + }, + "122": + { + "min": 50, + "max": 50 + }, + "124": + { + "min": 50, + "max": 100 + }, + "107,69": + { + "min": 3, + "max": 3 + } + } + }, + "valkyriewing": + { + "DisplayName": "Valkyrie Wing", + "NTIPAliasClassID": 356, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 150, + "max": 200 + }, + "96": + { + "min": 20, + "max": 20 + }, + "99": + { + "min": 20, + "max": 20 + }, + "83,0": + { + "min": 1, + "max": 2 + }, + "138": + { + "min": 2, + "max": 4 + } + } + }, + "vampiregaze": + { + "DisplayName": "Vampire Gaze", + "NTIPAliasClassID": 395, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "62": + { + "min": 6, + "max": 8 + }, + "60": + { + "min": 6, + "max": 8 + }, + "154": + { + "min": 15, + "max": 15 + }, + "36": + { + "min": 15, + "max": 20 + }, + "35": + { + "min": 10, + "max": 15 + }, + "16,0": + { + "min": 100, + "max": 100 + }, + "54": 6, + "55": 22 + } + }, + "veilofsteel": + { + "DisplayName": "Veil of Steel", + "NTIPAliasClassID": 426, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "39": 50, + "43": 50, + "41": 50, + "45": 50, + "16,0": + { + "min": 60, + "max": 60 + }, + "0": + { + "min": 15, + "max": 15 + }, + "3": + { + "min": 15, + "max": 15 + }, + "89": + { + "min": -4, + "max": -4 + }, + "72": 20, + "73": 20, + "31": + { + "min": 140, + "max": 140 + } + } + }, + "venomgrip": + { + "DisplayName": "Venom Grip", + "NTIPAliasClassID": 380, + "NTIPAliasType": 16, + "NTIPAliasStatProps": + { + "45": + { + "min": 30, + "max": 30 + }, + "46": + { + "min": 5, + "max": 5 + }, + "57": 60, + "58": 60, + "136": + { + "min": 5, + "max": 5 + }, + "60": + { + "min": 5, + "max": 5 + }, + "31": + { + "min": 15, + "max": 25 + }, + "16,0": + { + "min": 130, + "max": 160 + } + } + }, + "venomward": + { + "DisplayName": "Venom Ward", + "NTIPAliasClassID": 320, + "NTIPAliasType": 3, + "NTIPAliasStatProps": + { + "46": + { + "min": 15, + "max": 15 + }, + "110": + { + "min": 50, + "max": 50 + }, + "45": + { + "min": 90, + "max": 90 + }, + "89": + { + "min": 2, + "max": 2 + }, + "16,0": + { + "min": 60, + "max": 100 + } + } + }, + "verdungosheartycord": + { + "DisplayName": "Verdungo's Hearty Cord", + "NTIPAliasClassID": 462, + "NTIPAliasType": 19, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 90, + "max": 140 + }, + "3": + { + "min": 30, + "max": 40 + }, + "10": + { + "min": 100, + "max": 120 + }, + "99": + { + "min": 10, + "max": 10 + }, + "36": + { + "min": 10, + "max": 15 + }, + "74": + { + "min": 10, + "max": 13 + } + } + }, + "viperfork": + { + "DisplayName": "Viperfork", + "NTIPAliasClassID": 250, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "25": + { + "min": 190, + "max": 240 + }, + "57": 325, + "58": 325, + "93": + { + "min": 50, + "max": 50 + }, + "19": + { + "min": 200, + "max": 250 + }, + "198": + { + "chance": 15, + "level": 9, + "skill": "Poison Explosion" + }, + "45": + { + "min": 30, + "max": 50 + } + } + }, + "visceratuant": + { + "DisplayName": "Visceratuant", + "NTIPAliasClassID": 374, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 1, + "max": 1 + }, + "102": + { + "min": 30, + "max": 30 + }, + "20": + { + "min": 30, + "max": 30 + }, + "16,0": + { + "min": 100, + "max": 150 + }, + "128": + { + "min": 10, + "max": 10 + } + } + }, + "walloftheeyeless": + { + "DisplayName": "Wall of the Eyeless", + "NTIPAliasClassID": 350, + "NTIPAliasType": 2, + "NTIPAliasStatProps": + { + "138": + { + "min": 5, + "max": 5 + }, + "62": + { + "min": 3, + "max": 3 + }, + "105": + { + "min": 20, + "max": 20 + }, + "45": + { + "min": 20, + "max": 20 + }, + "16,0": + { + "min": 30, + "max": 40 + }, + "31": + { + "min": 10, + "max": 10 + } + } + }, + "wartraveler": + { + "DisplayName": "War Traveler", + "NTIPAliasClassID": 388, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "3": + { + "min": 10, + "max": 10 + }, + "0": + { + "min": 10, + "max": 10 + }, + "80": + { + "min": 30, + "max": 50 + }, + "72": 30, + "73": 30, + "96": + { + "min": 25, + "max": 25 + }, + "16,0": + { + "min": 150, + "max": 190 + }, + "21": 15, + "22": 25, + "78": + { + "min": 5, + "max": 10 + }, + "154": + { + "min": 40, + "max": 40 + } + } + }, + "warlordstrust": + { + "DisplayName": "Warlord's Trust", + "NTIPAliasClassID": 98, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "31": + { + "min": 75, + "max": 75 + }, + "74": + { + "min": 20, + "max": 20 + }, + "223": + { + "min": None, + "max": None, + "par": 4 + }, + "39": 10, + "43": 10, + "41": 10, + "45": 10, + "252": + { + "min": None, + "max": None, + "par": 25 + }, + "25": + { + "min": 175, + "max": 175 + } + } + }, + "warpspear": + { + "DisplayName": "Warpspear", + "NTIPAliasClassID": 159, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "83,1": + { + "min": 3, + "max": 3 + }, + "115": + { + "min": 1, + "max": 1 + }, + "107,54": + { + "min": 3, + "max": 3 + }, + "107,43": + { + "min": 3, + "max": 3 + }, + "107,58": + { + "min": 3, + "max": 3 + }, + "32": + { + "min": 250, + "max": 250 + } + } + }, + "warshrike": + { + "DisplayName": "Warshrike", + "NTIPAliasClassID": 241, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "25": + { + "min": 200, + "max": 250 + }, + "156": + { + "min": 50, + "max": 50 + }, + "93": + { + "min": 30, + "max": 30 + }, + "141": + { + "min": 50, + "max": 50 + }, + "253": + { + "min": None, + "max": None, + "par": 30 + }, + "198": + { + "chance": 25, + "level": 9, + "skill": "Nova" + } + } + }, + "waterwalk": + { + "DisplayName": "Waterwalk", + "NTIPAliasClassID": 386, + "NTIPAliasType": 15, + "NTIPAliasStatProps": + { + "32": + { + "min": 100, + "max": 100 + }, + "96": + { + "min": 20, + "max": 20 + }, + "2": + { + "min": 15, + "max": 15 + }, + "16,0": + { + "min": 180, + "max": 210 + }, + "6": + { + "min": 45, + "max": 65 + }, + "10": + { + "min": 40, + "max": 40 + }, + "40": + { + "min": 5, + "max": 5 + }, + "28": + { + "min": 50, + "max": 50 + } + } + }, + "widowmaker": + { + "DisplayName": "Widowmaker", + "NTIPAliasClassID": 270, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 200 + }, + "141": + { + "min": 33, + "max": 33 + }, + "115": + { + "min": 1, + "max": 1 + }, + "157": + { + "min": 11, + "max": 11 + }, + "107,22": + { + "min": 3, + "max": 5, + "par": "Guided Arrow" + } + } + }, + "windforce": + { + "DisplayName": "Windforce", + "NTIPAliasClassID": 271, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "2": + { + "min": 5, + "max": 5 + }, + "218": + { + "min": None, + "max": None, + "par": 25 + }, + "28": + { + "min": 30, + "max": 30 + }, + "62": + { + "min": 6, + "max": 8 + }, + "81": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 250, + "max": 250 + }, + "93": + { + "min": 20, + "max": 20 + }, + "0": + { + "min": 10, + "max": 10 + } + } + }, + "windhammer": + { + "DisplayName": "Windhammer", + "NTIPAliasClassID": 219, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "25": + { + "min": 180, + "max": 230 + }, + "136": + { + "min": 50, + "max": 50 + }, + "93": + { + "min": 60, + "max": 60 + }, + "198": + { + "chance": 33, + "level": 22, + "skill": "Twister" + } + } + }, + "wispprojector": + { + "DisplayName": "Wisp Projector", + "NTIPAliasClassID": 522, + "NTIPAliasType": 10, + "NTIPAliasStatProps": + { + "144": + { + "min": 10, + "max": 20 + }, + "198": + { + "chance": 10, + "level": 16, + "skill": "Lightning" + }, + "80": + { + "min": 10, + "max": 20 + }, + "204": + { + "charges": 11, + "level": 7, + "skill": "Spirit of Barbs" + } + } + }, + "witchwildstring": + { + "DisplayName": "Witchwild String", + "NTIPAliasClassID": 165, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "198": + { + "chance": 2, + "level": 5, + "skill": "Amplify Damage" + }, + "39": 40, + "43": 40, + "41": 40, + "45": 40, + "250": + { + "min": None, + "max": None, + "par": 8 + }, + "25": + { + "min": 150, + "max": 170 + }, + "157": + { + "min": 20, + "max": 20 + }, + "194": + { + "min": 2, + "max": 2 + } + } + }, + "witherstring": + { + "DisplayName": "Witherstring", + "NTIPAliasClassID": 69, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "93": + { + "min": 30, + "max": 30 + }, + "21": + { + "min": 1, + "max": 1 + }, + "22": + { + "min": 3, + "max": 3 + }, + "19": + { + "min": 50, + "max": 50 + }, + "157": + { + "min": 3, + "max": 3 + }, + "25": + { + "min": 40, + "max": 50 + } + } + }, + "wizardspike": + { + "DisplayName": "Wizardspike", + "NTIPAliasClassID": 235, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "217": + { + "min": None, + "max": None, + "par": 16 + }, + "27": + { + "min": 15, + "max": 15 + }, + "77": + { + "min": 15, + "max": 15 + }, + "39": 75, + "43": 75, + "41": 75, + "45": 75, + "152": + { + "min": 1, + "max": 1 + }, + "105": + { + "min": 50, + "max": 50 + } + } + }, + "wizendraw": + { + "DisplayName": "Wizendraw", + "NTIPAliasClassID": 73, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "157": + { + "min": 5, + "max": 5 + }, + "8": + { + "min": 30, + "max": 30 + }, + "93": + { + "min": 20, + "max": 20 + }, + "43": + { + "min": 26, + "max": 26 + }, + "19": + { + "min": 50, + "max": 100 + }, + "25": + { + "min": 70, + "max": 80 + }, + "1": + { + "min": 15, + "max": 15 + }, + "335": + { + "min": 20, + "max": 35 + } + } + }, + "woestave": + { + "DisplayName": "Woestave", + "NTIPAliasClassID": 61, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "150": + { + "min": 50, + "max": 50 + }, + "135": + { + "min": 50, + "max": 50 + }, + "113": + { + "min": 3, + "max": 3 + }, + "120": + { + "min": -50, + "max": -50 + }, + "134": + { + "min": 1, + "max": 1 + }, + "89": + { + "min": -3, + "max": -3 + }, + "117": + { + "min": 1, + "max": 1 + }, + "25": + { + "min": 20, + "max": 40 + } + } + }, + "wolfhowl": + { + "DisplayName": "Wolfhowl", + "NTIPAliasClassID": 494, + "NTIPAliasType": 71, + "NTIPAliasStatProps": + { + "16,0": + { + "min": 120, + "max": 150 + }, + "188,34": + { + "min": 2, + "max": 3, + "par": "Warcries" + }, + "0": + { + "min": 8, + "max": 15 + }, + "2": + { + "min": 8, + "max": 15 + }, + "3": + { + "min": 8, + "max": 15 + }, + "107,223": + { + "min": 3, + "max": 6, + "par": "Werewolf" + }, + "204": + { + "charges": 18, + "level": 15, + "skill": "Summon Fenris" + }, + "188,41": + { + "min": 3, + "max": 6, + "par": "Shape Shifting" + }, + "107,232": + { + "min": 3, + "max": 6, + "par": "Feral Rage" + } + } + }, + "wormskull": + { + "DisplayName": "Wormskull", + "NTIPAliasClassID": 349, + "NTIPAliasType": 37, + "NTIPAliasStatProps": + { + "83,2": + { + "min": 1, + "max": 1 + }, + "60": + { + "min": 5, + "max": 5 + }, + "8": + { + "min": 10, + "max": 10 + }, + "45": + { + "min": 25, + "max": 25 + }, + "57": 80, + "58": 80 + } + }, + "wraithflight": + { + "DisplayName": "Wraith Flight", + "NTIPAliasClassID": 246, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "25": + { + "min": 150, + "max": 190 + }, + "253": + { + "min": None, + "max": None, + "par": 40 + }, + "60": + { + "min": 9, + "max": 13 + }, + "138": + { + "min": 15, + "max": 15 + }, + "0x400000": + { + "min": 1, + "max": 1 + } + } + }, + "zakarumshand": + { + "DisplayName": "Zakarum's Hand", + "NTIPAliasClassID": 108, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "62": + { + "min": 8, + "max": 8 + }, + "115": + { + "min": 1, + "max": 1 + }, + "27": + { + "min": 10, + "max": 10 + }, + "28": + { + "min": 15, + "max": 15 + }, + "198": + { + "chance": 6, + "level": 5, + "skill": "Blizzard" + }, + "25": + { + "min": 180, + "max": 220 + }, + "93": + { + "min": 30, + "max": 30 + }, + "107,114": + { + "min": 2, + "max": 2 + }, + "107,118": + { + "min": 2, + "max": 2 + } + } + } +} + +ITEM_WEAPONS = { + "ancientaxe": + { + "DisplayName": "Ancient Axe", + "NTIPAliasClassID": 102, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 43, + "24": 85, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THEMINOTAUR"], + "NTIPAliasClass": 1 + }, + "ancientsword": + { + "DisplayName": "Ancient Sword", + "NTIPAliasClassID": 125, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 44, + "73": 44, + "21": 18, + "22": 43, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["THEATLANTEAN"], + "NTIPAliasClass": 1 + }, + "arbalest": + { + "DisplayName": "Arbalest", + "NTIPAliasClassID": 169, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 14, + "24": 27 + }, + "dimensions": [2, 3], + "uniques": ["LANGERBRISER"], + "NTIPAliasClass": 1 + }, + "archonstaff": + { + "DisplayName": "Archon Staff", + "NTIPAliasClassID": 263, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "23": 83, + "24": 99, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["MANGSONGSLESSON"], + "NTIPAliasClass": 2 + }, + "ashwoodbow": + { + "DisplayName": "Ashwood Bow", + "NTIPAliasClassID": 291, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 48, + "73": 48, + "23": 16, + "24": 29 + }, + "dimensions": [2, 4], + "NTIPAliasClass": 1 + }, + "ataghan": + { + "DisplayName": "Ataghan", + "NTIPAliasClassID": 222, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 22, + "73": 22, + "21": 26, + "22": 46, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["DJINNSLAYER"], + "NTIPAliasClass": 2 + }, + "axe": + { + "DisplayName": "Axe", + "NTIPAliasClassID": 1, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 24, + "73": 24, + "21": 4, + "22": 11, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["DEATHSPADE"], + "NTIPAliasClass": 0 + }, + "balancedaxe": + { + "DisplayName": "Balanced Axe", + "NTIPAliasClassID": 46, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "72": 10, + "73": 10, + "21": 5, + "22": 10, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 0 + }, + "balancedknife": + { + "DisplayName": "Balanced Knife", + "NTIPAliasClassID": 45, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "72": 8, + "73": 8, + "21": 1, + "22": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "ballista": + { + "DisplayName": "Ballista", + "NTIPAliasClassID": 171, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 33, + "24": 55 + }, + "dimensions": [2, 4], + "uniques": ["BURIZADOKYANON"], + "NTIPAliasClass": 1 + }, + "balrogblade": + { + "DisplayName": "Balrog Blade", + "NTIPAliasClassID": 231, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 15, + "22": 75, + "23": 55, + "24": 118, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["FLAMEBELLOW"], + "NTIPAliasClass": 2 + }, + "balrogspear": + { + "DisplayName": "Balrog Spear", + "NTIPAliasClassID": 245, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "21": 33, + "22": 63, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["DEMONSARCH"], + "NTIPAliasClass": 2 + }, + "barbedclub": + { + "DisplayName": "Barbed Club", + "NTIPAliasClassID": 111, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 36, + "73": 36, + "21": 13, + "22": 25, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["FLESHRENDER"], + "NTIPAliasClass": 1 + }, + "bardiche": + { + "DisplayName": "Bardiche", + "NTIPAliasClassID": 57, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "23": 1, + "24": 27, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["DIMOAKSHEW"], + "NTIPAliasClass": 0 + }, + "bastardsword": + { + "DisplayName": "Bastard Sword", + "NTIPAliasClassID": 36, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "21": 7, + "22": 19, + "23": 20, + "24": 28, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["BLACKTONGUE"], + "NTIPAliasClass": 0 + }, + "battleaxe": + { + "DisplayName": "Battle Axe", + "NTIPAliasClassID": 7, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 12, + "24": 32, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THECHIEFTAIN"], + "NTIPAliasClass": 0 + }, + "battlecestus": + { + "DisplayName": "Battle Cestus", + "NTIPAliasClassID": 192, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 72, + "73": 72, + "21": 36, + "22": 42, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["SHADOWKILLER"], + "NTIPAliasClass": 2 + }, + "battledart": + { + "DisplayName": "Battle Dart", + "NTIPAliasClassID": 136, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 8, + "22": 16, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["DEATHBIT"], + "NTIPAliasClass": 1 + }, + "battlehammer": + { + "DisplayName": "Battle Hammer", + "NTIPAliasClassID": 115, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 55, + "73": 55, + "21": 35, + "22": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["EARTHSHAKER"], + "NTIPAliasClass": 1 + }, + "battlescythe": + { + "DisplayName": "Battle Scythe", + "NTIPAliasClassID": 152, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "23": 18, + "24": 45, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["ATHENASWRATH"], + "NTIPAliasClass": 1 + }, + "battlestaff": + { + "DisplayName": "Battle Staff", + "NTIPAliasClassID": 66, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "23": 6, + "24": 13, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "sets": ["CATHANSRULE"], + "uniques": ["THESALAMANDER"], + "NTIPAliasClass": 0 + }, + "battlesword": + { + "DisplayName": "Battle Sword", + "NTIPAliasClassID": 123, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "21": 16, + "22": 34, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HEADSTRIKER"], + "NTIPAliasClass": 1 + }, + "beardedaxe": + { + "DisplayName": "Bearded Axe", + "NTIPAliasClassID": 99, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 35, + "73": 35, + "23": 21, + "24": 49, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SPELLSTEEL"], + "NTIPAliasClass": 1 + }, + "becdecorbin": + { + "DisplayName": "Bec-de-Corbin", + "NTIPAliasClassID": 154, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 13, + "24": 85, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["HUSOLDALEVO"], + "NTIPAliasClass": 1 + }, + "berserkeraxe": + { + "DisplayName": "Berserker Axe", + "NTIPAliasClassID": 200, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "21": 24, + "22": 71, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["DEATHCLEAVER"], + "NTIPAliasClass": 2 + }, + "bill": + { + "DisplayName": "Bill", + "NTIPAliasClassID": 151, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "23": 14, + "24": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "sets": ["HWANINSJUSTICE"], + "uniques": ["BLACKLEACHBLADE"], + "NTIPAliasClass": 1 + }, + "blade": + { + "DisplayName": "Blade", + "NTIPAliasClassID": 42, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 4, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["SPECTRALSHARD"], + "NTIPAliasClass": 0 + }, + "bladebow": + { + "DisplayName": "Blade Bow", + "NTIPAliasClassID": 265, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "23": 21, + "24": 41 + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "bladetalons": + { + "DisplayName": "Blade Talons", + "NTIPAliasClassID": 180, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 69, + "73": 69, + "21": 10, + "22": 14, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "boneknife": + { + "DisplayName": "Bone Knife", + "NTIPAliasClassID": 235, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 26, + "73": 26, + "21": 23, + "22": 49, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["WIZARDSPIKE"], + "NTIPAliasClass": 2 + }, + "bonewand": + { + "DisplayName": "Bone Wand", + "NTIPAliasClassID": 12, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 15, + "73": 15, + "21": 3, + "22": 7, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "sets": ["SANDERSSUPERSTITION"], + "uniques": ["GRAVENSPINE"], + "NTIPAliasClass": 0 + }, + "brandistock": + { + "DisplayName": "Brandistock", + "NTIPAliasClassID": 54, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 28, + "73": 28, + "23": 7, + "24": 17, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["BLOODTHIEF"], + "NTIPAliasClass": 0 + }, + "broadaxe": + { + "DisplayName": "Broad Axe", + "NTIPAliasClassID": 6, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 35, + "73": 35, + "23": 10, + "24": 18, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["GORESHOVEL"], + "NTIPAliasClass": 0 + }, + "broadsword": + { + "DisplayName": "Broad Sword", + "NTIPAliasClassID": 30, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "21": 7, + "22": 14, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["ISENHARTSLIGHTBRAND"], + "uniques": ["GRISWOLDSEDGE"], + "NTIPAliasClass": 0 + }, + "burntwand": + { + "DisplayName": "Burnt Wand", + "NTIPAliasClassID": 103, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 15, + "73": 15, + "21": 8, + "22": 18, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["SUICIDEBRANCH"], + "NTIPAliasClass": 1 + }, + "caduceus": + { + "DisplayName": "Caduceus", + "NTIPAliasClassID": 213, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 70, + "73": 70, + "21": 37, + "22": 43, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["GRISWOLDSREDEMPTION"], + "uniques": ["ASTREONSIRONWARD"], + "NTIPAliasClass": 2 + }, + "cedarbow": + { + "DisplayName": "Cedar Bow", + "NTIPAliasClassID": 163, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 28, + "73": 28, + "23": 10, + "24": 29 + }, + "dimensions": [2, 4], + "uniques": ["KUKOSHAKAKU"], + "NTIPAliasClass": 1 + }, + "cedarstaff": + { + "DisplayName": "Cedar Staff", + "NTIPAliasClassID": 158, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "23": 11, + "24": 32, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["CHROMATICIRE"], + "NTIPAliasClass": 1 + }, + "ceremonialbow": + { + "DisplayName": "Ceremonial Bow", + "NTIPAliasClassID": 292, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 55, + "73": 55, + "23": 19, + "24": 41 + }, + "dimensions": [2, 4], + "uniques": ["LYCANDERSAIM"], + "NTIPAliasClass": 1 + }, + "ceremonialjavelin": + { + "DisplayName": "Ceremonial Javelin", + "NTIPAliasClassID": 295, + "NTIPAliasType": 87, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 18, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["TITANSREVENGE"], + "NTIPAliasClass": 1 + }, + "ceremonialpike": + { + "DisplayName": "Ceremonial Pike", + "NTIPAliasClassID": 294, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 25, + "73": 25, + "23": 42, + "24": 101, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["LYCANDERSFLANK"], + "NTIPAliasClass": 1 + }, + "ceremonialspear": + { + "DisplayName": "Ceremonial Spear", + "NTIPAliasClassID": 293, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 28, + "73": 28, + "23": 34, + "24": 51, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 1 + }, + "cestus": + { + "DisplayName": "Cestus", + "NTIPAliasClassID": 178, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 72, + "73": 72, + "21": 7, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "championaxe": + { + "DisplayName": "Champion Axe", + "NTIPAliasClassID": 204, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 59, + "24": 94, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["MESSERSCHMIDTSREAVER"], + "NTIPAliasClass": 2 + }, + "championsword": + { + "DisplayName": "Champion Sword", + "NTIPAliasClassID": 232, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "21": 24, + "22": 54, + "23": 71, + "24": 83, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["DOOMBRINGER"], + "NTIPAliasClass": 2 + }, + "chokinggaspotion": + { + "DisplayName": "Choking Gas Potion", + "NTIPAliasClassID": 82, + "NTIPAliasType": 38, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 1], + "NTIPAliasClass": 0 + }, + "chukonu": + { + "DisplayName": "Chu-Ko-Nu", + "NTIPAliasClassID": 172, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 14, + "24": 32 + }, + "dimensions": [2, 3], + "uniques": ["DEMONMACHINE"], + "NTIPAliasClass": 1 + }, + "cinquedeas": + { + "DisplayName": "Cinquedeas", + "NTIPAliasClassID": 134, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 24, + "73": 24, + "21": 15, + "22": 31, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BLACKBOGSSHARP"], + "NTIPAliasClass": 1 + }, + "claspedorb": + { + "DisplayName": "Clasped Orb", + "NTIPAliasClassID": 279, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "21": 5, + "22": 12, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "claws": + { + "DisplayName": "Claws", + "NTIPAliasClassID": 179, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 64, + "73": 64, + "21": 8, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "claymore": + { + "DisplayName": "Claymore", + "NTIPAliasClassID": 34, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 5, + "22": 12, + "23": 13, + "24": 30, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["SOULFLAY"], + "NTIPAliasClass": 0 + }, + "cleaver": + { + "DisplayName": "Cleaver", + "NTIPAliasClassID": 94, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 24, + "73": 24, + "21": 10, + "22": 33, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["BUTCHERSPUPIL"], + "NTIPAliasClass": 1 + }, + "cloudysphere": + { + "DisplayName": "Cloudy Sphere", + "NTIPAliasClassID": 288, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "21": 11, + "22": 29, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 1 + }, + "club": + { + "DisplayName": "Club", + "NTIPAliasClassID": 14, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 1, + "22": 6, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["FELLOAK"], + "NTIPAliasClass": 0 + }, + "colossusblade": + { + "DisplayName": "Colossus Blade", + "NTIPAliasClassID": 234, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "21": 25, + "22": 65, + "23": 58, + "24": 115, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "sets": ["BULKATHOSSACREDCHARGE"], + "uniques": ["THEGRANDFATHER"], + "NTIPAliasClass": 2 + }, + "colossuscrossbow": + { + "DisplayName": "Colossus Crossbow", + "NTIPAliasClassID": 274, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 32, + "24": 91 + }, + "dimensions": [2, 4], + "uniques": ["HELLRACK"], + "NTIPAliasClass": 2 + }, + "colossussword": + { + "DisplayName": "Colossus Sword", + "NTIPAliasClassID": 233, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 50, + "73": 50, + "21": 26, + "22": 70, + "23": 61, + "24": 121, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "colossusvoulge": + { + "DisplayName": "Colossus Voulge", + "NTIPAliasClassID": 254, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "23": 17, + "24": 165, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "compositebow": + { + "DisplayName": "Composite Bow", + "NTIPAliasClassID": 71, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 36, + "73": 36, + "23": 4, + "24": 8 + }, + "dimensions": [2, 3], + "uniques": ["ROGUESBOW"], + "NTIPAliasClass": 0 + }, + "conquestsword": + { + "DisplayName": "Conquest Sword", + "NTIPAliasClassID": 226, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "21": 37, + "22": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "crossbow": + { + "DisplayName": "Crossbow", + "NTIPAliasClassID": 77, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "23": 9, + "24": 16 + }, + "dimensions": [2, 3], + "uniques": ["ICHORSTING"], + "NTIPAliasClass": 0 + }, + "crowbill": + { + "DisplayName": "Crowbill", + "NTIPAliasClassID": 96, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "21": 14, + "22": 34, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["POMPEIISWRATH"], + "NTIPAliasClass": 1 + }, + "crusaderbow": + { + "DisplayName": "Crusader Bow", + "NTIPAliasClassID": 269, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 44, + "73": 44, + "23": 15, + "24": 63 + }, + "dimensions": [2, 4], + "uniques": ["EAGLEHORN"], + "NTIPAliasClass": 2 + }, + "crypticaxe": + { + "DisplayName": "Cryptic Axe", + "NTIPAliasClassID": 256, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "23": 33, + "24": 150, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["TOMBREAVER"], + "NTIPAliasClass": 2 + }, + "crypticsword": + { + "DisplayName": "Cryptic Sword", + "NTIPAliasClassID": 227, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 44, + "73": 44, + "21": 5, + "22": 77, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["SAZABISCOBALTREDEEMER"], + "uniques": ["FROSTWIND"], + "NTIPAliasClass": 2 + }, + "crystalsword": + { + "DisplayName": "Crystal Sword", + "NTIPAliasClassID": 29, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 20, + "73": 20, + "21": 5, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["AZUREWRATH"], + "NTIPAliasClass": 0 + }, + "crystallineglobe": + { + "DisplayName": "Crystalline Globe", + "NTIPAliasClassID": 287, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "21": 10, + "22": 26, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 1 + }, + "cudgel": + { + "DisplayName": "Cudgel", + "NTIPAliasClassID": 107, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 6, + "22": 21, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["DARKCLANCRUSHER"], + "NTIPAliasClass": 1 + }, + "cutlass": + { + "DisplayName": "Cutlass", + "NTIPAliasClassID": 119, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 22, + "73": 22, + "21": 8, + "22": 21, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["COLDSTEELEYE"], + "NTIPAliasClass": 1 + }, + "dacianfalx": + { + "DisplayName": "Dacian Falx", + "NTIPAliasClassID": 127, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 13, + "22": 30, + "23": 26, + "24": 61, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["BINGSZWANG"], + "NTIPAliasClass": 1 + }, + "dagger": + { + "DisplayName": "Dagger", + "NTIPAliasClassID": 39, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 16, + "73": 16, + "21": 1, + "22": 4, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["GULL"], + "NTIPAliasClass": 0 + }, + "decapitator": + { + "DisplayName": "Decapitator", + "NTIPAliasClassID": 203, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 49, + "24": 137, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HELLSLAYER"], + "NTIPAliasClass": 2 + }, + "decoygidbinn": + { + "DisplayName": "Decoy Gidbinn", + "NTIPAliasClassID": 86, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "72": 10, + "73": 10, + "21": 1, + "22": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "demoncrossbow": + { + "DisplayName": "Demon Crossbow", + "NTIPAliasClassID": 275, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 26, + "24": 40 + }, + "dimensions": [2, 3], + "uniques": ["GUTSIPHON"], + "NTIPAliasClass": 2 + }, + "demonheart": + { + "DisplayName": "Demon Heart", + "NTIPAliasClassID": 298, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "21": 23, + "22": 55, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "devilstar": + { + "DisplayName": "Devil Star", + "NTIPAliasClassID": 216, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 72, + "73": 72, + "21": 43, + "22": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BARANARSSTAR"], + "NTIPAliasClass": 2 + }, + "diamondbow": + { + "DisplayName": "Diamond Bow", + "NTIPAliasClassID": 268, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 33, + "24": 40 + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "dimensionalblade": + { + "DisplayName": "Dimensional Blade", + "NTIPAliasClassID": 122, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 20, + "73": 20, + "21": 13, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["GINTHERSRIFT"], + "NTIPAliasClass": 1 + }, + "dimensionalshard": + { + "DisplayName": "Dimensional Shard", + "NTIPAliasClassID": 300, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 30, + "22": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["DEATHSFATHOM"], + "NTIPAliasClass": 2 + }, + "dirk": + { + "DisplayName": "Dirk", + "NTIPAliasClassID": 40, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 20, + "73": 20, + "21": 3, + "22": 9, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["THEDIGGLER"], + "NTIPAliasClass": 0 + }, + "divinescepter": + { + "DisplayName": "Divine Scepter", + "NTIPAliasClassID": 110, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 70, + "73": 70, + "21": 16, + "22": 38, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HANDOFBLESSEDLIGHT"], + "NTIPAliasClass": 1 + }, + "doubleaxe": + { + "DisplayName": "Double Axe", + "NTIPAliasClassID": 2, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 24, + "73": 24, + "21": 5, + "22": 13, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["BERSERKERSHATCHET"], + "uniques": ["BLADEBONE"], + "NTIPAliasClass": 0 + }, + "doublebow": + { + "DisplayName": "Double Bow", + "NTIPAliasClassID": 164, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 36, + "73": 36, + "23": 11, + "24": 26 + }, + "dimensions": [2, 3], + "uniques": ["ENDLESSHAIL"], + "NTIPAliasClass": 1 + }, + "eagleorb": + { + "DisplayName": "Eagle Orb", + "NTIPAliasClassID": 276, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 20, + "73": 20, + "21": 2, + "22": 5, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "edgebow": + { + "DisplayName": "Edge Bow", + "NTIPAliasClassID": 161, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "23": 6, + "24": 19 + }, + "dimensions": [2, 3], + "uniques": ["SKYSTRIKE"], + "NTIPAliasClass": 1 + }, + "elderstaff": + { + "DisplayName": "Elder Staff", + "NTIPAliasClassID": 261, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "23": 80, + "24": 93, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "sets": ["NAJSPUZZLER"], + "uniques": ["ONDALSWISDOM"], + "NTIPAliasClass": 2 + }, + "eldritchorb": + { + "DisplayName": "Eldritch Orb", + "NTIPAliasClassID": 297, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "21": 18, + "22": 50, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["ESCHUTASTEMPER"], + "NTIPAliasClass": 2 + }, + "elegantblade": + { + "DisplayName": "Elegant Blade", + "NTIPAliasClassID": 223, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "21": 33, + "22": 45, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BLOODMOON"], + "NTIPAliasClass": 2 + }, + "espandon": + { + "DisplayName": "Espandon", + "NTIPAliasClassID": 126, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 44, + "73": 44, + "21": 8, + "22": 26, + "23": 18, + "24": 40, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["CRAINTEVOMIR"], + "NTIPAliasClass": 1 + }, + "ettinaxe": + { + "DisplayName": "Ettin Axe", + "NTIPAliasClassID": 198, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 24, + "73": 24, + "21": 33, + "22": 66, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["RUNEMASTER"], + "NTIPAliasClass": 2 + }, + "executionersword": + { + "DisplayName": "Executioner Sword", + "NTIPAliasClassID": 131, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "21": 24, + "22": 40, + "23": 47, + "24": 80, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["SWORDGUARD"], + "NTIPAliasClass": 1 + }, + "explodingpotion": + { + "DisplayName": "Exploding Potion", + "NTIPAliasClassID": 83, + "NTIPAliasType": 38, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 1], + "NTIPAliasClass": 0 + }, + "falcata": + { + "DisplayName": "Falcata", + "NTIPAliasClassID": 221, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 31, + "22": 59, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "falchion": + { + "DisplayName": "Falchion", + "NTIPAliasClassID": 28, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "21": 9, + "22": 17, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["GLEAMSCYTHE"], + "NTIPAliasClass": 0 + }, + "fangedknife": + { + "DisplayName": "Fanged Knife", + "NTIPAliasClassID": 237, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 36, + "73": 36, + "21": 15, + "22": 57, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["FLESHRIPPER"], + "NTIPAliasClass": 2 + }, + "fascia": + { + "DisplayName": "Fascia", + "NTIPAliasClassID": 184, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 64, + "73": 64, + "21": 8, + "22": 37, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "feralaxe": + { + "DisplayName": "Feral Axe", + "NTIPAliasClassID": 201, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "23": 25, + "24": 123, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "feralclaws": + { + "DisplayName": "Feral Claws", + "NTIPAliasClassID": 193, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 52, + "73": 52, + "21": 22, + "22": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["FIRELIZARDSTALONS"], + "NTIPAliasClass": 2 + }, + "flail": + { + "DisplayName": "Flail", + "NTIPAliasClassID": 21, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 30, + "73": 30, + "21": 1, + "22": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THEGENERALSTANDOLIGA"], + "NTIPAliasClass": 0 + }, + "flamberge": + { + "DisplayName": "Flamberge", + "NTIPAliasClassID": 37, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 50, + "73": 50, + "21": 9, + "22": 15, + "23": 13, + "24": 26, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["RIPSAW"], + "NTIPAliasClass": 0 + }, + "flangedmace": + { + "DisplayName": "Flanged Mace", + "NTIPAliasClassID": 112, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 60, + "73": 60, + "21": 15, + "22": 23, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["SURESHRILLFROST"], + "NTIPAliasClass": 1 + }, + "flyingaxe": + { + "DisplayName": "Flying Axe", + "NTIPAliasClassID": 240, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "72": 15, + "73": 15, + "21": 17, + "22": 65, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["GIMMERSHRED"], + "NTIPAliasClass": 2 + }, + "flyingknife": + { + "DisplayName": "Flying Knife", + "NTIPAliasClassID": 239, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 23, + "22": 54, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "francisca": + { + "DisplayName": "Francisca", + "NTIPAliasClassID": 137, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "72": 15, + "73": 15, + "21": 11, + "22": 22, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["THESCALPER"], + "NTIPAliasClass": 1 + }, + "fulminatingpotion": + { + "DisplayName": "Fulminating Potion", + "NTIPAliasClassID": 85, + "NTIPAliasType": 38, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 1], + "NTIPAliasClass": 0 + }, + "fuscina": + { + "DisplayName": "Fuscina", + "NTIPAliasClassID": 146, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "23": 19, + "24": 37, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["KELPIESNARE"], + "NTIPAliasClass": 1 + }, + "ghostglaive": + { + "DisplayName": "Ghost Glaive", + "NTIPAliasClassID": 246, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "21": 19, + "22": 60, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["WRAITHFLIGHT"], + "NTIPAliasClass": 2 + }, + "ghostspear": + { + "DisplayName": "Ghost Spear", + "NTIPAliasClassID": 251, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 28, + "73": 28, + "23": 18, + "24": 155, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "ghostwand": + { + "DisplayName": "Ghost Wand", + "NTIPAliasClassID": 207, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 14, + "73": 14, + "21": 20, + "22": 40, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "giantaxe": + { + "DisplayName": "Giant Axe", + "NTIPAliasClassID": 9, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 22, + "24": 45, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HUMONGOUS"], + "NTIPAliasClass": 0 + }, + "giantsword": + { + "DisplayName": "Giant Sword", + "NTIPAliasClassID": 35, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 3, + "22": 16, + "23": 9, + "24": 28, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["KINEMILSAWL"], + "NTIPAliasClass": 0 + }, + "giantthresher": + { + "DisplayName": "Giant Thresher", + "NTIPAliasClassID": 258, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 40, + "24": 114, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["STORMSPIRE"], + "NTIPAliasClass": 2 + }, + "gladius": + { + "DisplayName": "Gladius", + "NTIPAliasClassID": 118, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 8, + "22": 22, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BLOODLETTER"], + "NTIPAliasClass": 1 + }, + "glaive": + { + "DisplayName": "Glaive", + "NTIPAliasClassID": 50, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 5, + "73": 5, + "21": 5, + "22": 17, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 0 + }, + "gloriousaxe": + { + "DisplayName": "Glorious Axe", + "NTIPAliasClassID": 205, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 60, + "24": 124, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["EXECUTIONERSJUSTICE"], + "NTIPAliasClass": 2 + }, + "glowingorb": + { + "DisplayName": "Glowing Orb", + "NTIPAliasClassID": 286, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 20, + "73": 20, + "21": 8, + "22": 21, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 1 + }, + "gnarledstaff": + { + "DisplayName": "Gnarled Staff", + "NTIPAliasClassID": 65, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "23": 4, + "24": 12, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["SPIREOFLAZARUS"], + "NTIPAliasClass": 0 + }, + "gorgoncrossbow": + { + "DisplayName": "Gorgon Crossbow", + "NTIPAliasClassID": 273, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "23": 25, + "24": 87 + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "gothicaxe": + { + "DisplayName": "Gothic Axe", + "NTIPAliasClassID": 101, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 18, + "24": 70, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["BONESLAYERBLADE"], + "NTIPAliasClass": 1 + }, + "gothicbow": + { + "DisplayName": "Gothic Bow", + "NTIPAliasClassID": 168, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 10, + "24": 50 + }, + "dimensions": [2, 4], + "uniques": ["GOLDSTRIKEARCH"], + "NTIPAliasClass": 1 + }, + "gothicstaff": + { + "DisplayName": "Gothic Staff", + "NTIPAliasClassID": 159, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "23": 14, + "24": 34, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["WARPSPEAR"], + "NTIPAliasClass": 1 + }, + "gothicsword": + { + "DisplayName": "Gothic Sword", + "NTIPAliasClassID": 129, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "21": 14, + "22": 40, + "23": 39, + "24": 60, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["CLOUDCRACK"], + "NTIPAliasClass": 1 + }, + "grandmatronbow": + { + "DisplayName": "Grand Matron Bow", + "NTIPAliasClassID": 302, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 55, + "73": 55, + "23": 14, + "24": 72 + }, + "dimensions": [2, 4], + "sets": ["MAVINASCASTER"], + "NTIPAliasClass": 2 + }, + "grandscepter": + { + "DisplayName": "Grand Scepter", + "NTIPAliasClassID": 16, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "21": 8, + "22": 18, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["CIVERBSCUDGEL"], + "uniques": ["RUSTHANDLE"], + "NTIPAliasClass": 0 + }, + "gravewand": + { + "DisplayName": "Grave Wand", + "NTIPAliasClassID": 106, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 15, + "73": 15, + "21": 13, + "22": 29, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["BLACKHANDKEY"], + "NTIPAliasClass": 1 + }, + "greataxe": + { + "DisplayName": "Great Axe", + "NTIPAliasClassID": 8, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 9, + "24": 30, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["BRAINHEW"], + "NTIPAliasClass": 0 + }, + "greatbow": + { + "DisplayName": "Great Bow", + "NTIPAliasClassID": 267, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 36, + "73": 36, + "23": 12, + "24": 52 + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "greatmaul": + { + "DisplayName": "Great Maul", + "NTIPAliasClassID": 24, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 60, + "73": 60, + "23": 38, + "24": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["STEELDRIVER"], + "NTIPAliasClass": 0 + }, + "greatpilum": + { + "DisplayName": "Great Pilum", + "NTIPAliasClassID": 141, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "21": 11, + "22": 26, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "greatpoleaxe": + { + "DisplayName": "Great Poleaxe", + "NTIPAliasClassID": 257, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 46, + "24": 127, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "greatsword": + { + "DisplayName": "Great Sword", + "NTIPAliasClassID": 38, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "21": 12, + "22": 20, + "23": 25, + "24": 42, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEPATRIARCH"], + "NTIPAliasClass": 0 + }, + "greaterclaws": + { + "DisplayName": "Greater Claws", + "NTIPAliasClassID": 186, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 52, + "73": 52, + "21": 18, + "22": 37, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "greatertalons": + { + "DisplayName": "Greater Talons", + "NTIPAliasClassID": 187, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 69, + "73": 69, + "21": 21, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BARTUCSCUTTHROAT"], + "NTIPAliasClass": 1 + }, + "grimscythe": + { + "DisplayName": "Grim Scythe", + "NTIPAliasClassID": 155, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 30, + "24": 70, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["GRIMSBURNINGDEAD"], + "NTIPAliasClass": 1 + }, + "grimwand": + { + "DisplayName": "Grim Wand", + "NTIPAliasClassID": 13, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 15, + "73": 15, + "21": 5, + "22": 11, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "sets": ["INFERNALTORCH"], + "uniques": ["UMESLAMENT"], + "NTIPAliasClass": 0 + }, + "halberd": + { + "DisplayName": "Halberd", + "NTIPAliasClassID": 61, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 12, + "24": 45, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["WOESTAVE"], + "NTIPAliasClass": 0 + }, + "handaxe": + { + "DisplayName": "Hand Axe", + "NTIPAliasClassID": 0, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 28, + "73": 28, + "21": 3, + "22": 6, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["THEGNASHER"], + "NTIPAliasClass": 0 + }, + "handscythe": + { + "DisplayName": "Hand Scythe", + "NTIPAliasClassID": 185, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 72, + "73": 72, + "21": 16, + "22": 37, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "harpoon": + { + "DisplayName": "Harpoon", + "NTIPAliasClassID": 144, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "21": 13, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 1 + }, + "hatchet": + { + "DisplayName": "Hatchet", + "NTIPAliasClassID": 93, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 28, + "73": 28, + "21": 10, + "22": 21, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["COLDKILL"], + "NTIPAliasClass": 1 + }, + "hatchethands": + { + "DisplayName": "Hatchet Hands", + "NTIPAliasClassID": 177, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 56, + "73": 56, + "21": 2, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "heavenlystone": + { + "DisplayName": "Heavenly Stone", + "NTIPAliasClassID": 296, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 20, + "73": 20, + "21": 21, + "22": 46, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "heavycrossbow": + { + "DisplayName": "Heavy Crossbow", + "NTIPAliasClassID": 78, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 14, + "24": 26 + }, + "dimensions": [2, 4], + "uniques": ["HELLCAST"], + "NTIPAliasClass": 0 + }, + "hellforgehammer": + { + "DisplayName": "Hell Forge Hammer", + "NTIPAliasClassID": 90, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 55, + "73": 55, + "21": 6, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HELLFORGEHAMMER"], + "NTIPAliasClass": 0 + }, + "highlandblade": + { + "DisplayName": "Highland Blade", + "NTIPAliasClassID": 230, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 22, + "22": 62, + "23": 67, + "24": 96, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 2 + }, + "holywatersprinkler": + { + "DisplayName": "Holy Water Sprinkler", + "NTIPAliasClassID": 109, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "21": 14, + "22": 36, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["THEFETIDSPRINKLER"], + "NTIPAliasClass": 1 + }, + "horadricmalus": + { + "DisplayName": "Horadric Malus", + "NTIPAliasClassID": 89, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "72": 55, + "73": 55, + "21": 6, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "horadricstaff": + { + "DisplayName": "Horadric Staff", + "NTIPAliasClassID": 91, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "72": 50, + "73": 50, + "23": 12, + "24": 20, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["HORADRICSTAFF"], + "NTIPAliasClass": 0 + }, + "huntersbow": + { + "DisplayName": "Hunter's Bow", + "NTIPAliasClassID": 69, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "23": 2, + "24": 6 + }, + "dimensions": [2, 3], + "uniques": ["WITHERSTRING"], + "NTIPAliasClass": 0 + }, + "hurlbat": + { + "DisplayName": "Hurlbat", + "NTIPAliasClassID": 139, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "21": 13, + "22": 27, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 1 + }, + "hydrabow": + { + "DisplayName": "Hydra Bow", + "NTIPAliasClassID": 271, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 10, + "24": 68 + }, + "dimensions": [2, 4], + "uniques": ["WINDFORCE"], + "NTIPAliasClass": 2 + }, + "hydraedge": + { + "DisplayName": "Hydra Edge", + "NTIPAliasClassID": 224, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "21": 28, + "22": 68, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "hyperionjavelin": + { + "DisplayName": "Hyperion Javelin", + "NTIPAliasClassID": 243, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 10, + "73": 10, + "21": 21, + "22": 57, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "hyperionspear": + { + "DisplayName": "Hyperion Spear", + "NTIPAliasClassID": 248, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 35, + "24": 119, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["ARIOCSNEEDLE"], + "NTIPAliasClass": 2 + }, + "jaggedstar": + { + "DisplayName": "Jagged Star", + "NTIPAliasClassID": 113, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 72, + "73": 72, + "21": 20, + "22": 31, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["ALDURSRHYTHM"], + "uniques": ["MOONFALL"], + "NTIPAliasClass": 1 + }, + "jaredsstone": + { + "DisplayName": "Jared's Stone", + "NTIPAliasClassID": 280, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 8, + "22": 18, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "javelin": + { + "DisplayName": "Javelin", + "NTIPAliasClassID": 47, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "21": 1, + "22": 5, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "jostaff": + { + "DisplayName": "Jo Staff", + "NTIPAliasClassID": 156, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "23": 6, + "24": 21, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["RAZORSWITCH"], + "NTIPAliasClass": 1 + }, + "katar": + { + "DisplayName": "Katar", + "NTIPAliasClassID": 175, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 48, + "73": 48, + "21": 4, + "22": 7, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "khalimsflail": + { + "DisplayName": "Khalim's Flail", + "NTIPAliasClassID": 173, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "21": 1, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["KHALIMSFLAIL"], + "NTIPAliasClass": 0 + }, + "khalimswill": + { + "DisplayName": "Khalim's Will", + "NTIPAliasClassID": 174, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "21": 1, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["KHALIMSWILL"], + "NTIPAliasClass": 0 + }, + "knout": + { + "DisplayName": "Knout", + "NTIPAliasClassID": 114, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 30, + "73": 30, + "21": 13, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["BAEZILSVORTEX"], + "NTIPAliasClass": 1 + }, + "kris": + { + "DisplayName": "Kris", + "NTIPAliasClassID": 41, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 24, + "73": 24, + "21": 2, + "22": 11, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["THEJADETANDO"], + "NTIPAliasClass": 0 + }, + "lance": + { + "DisplayName": "Lance", + "NTIPAliasClassID": 149, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 25, + "73": 25, + "23": 27, + "24": 114, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["SPIREOFHONOR"], + "NTIPAliasClass": 1 + }, + "largeaxe": + { + "DisplayName": "Large Axe", + "NTIPAliasClassID": 5, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "23": 6, + "24": 13, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["AXEOFFECHMAR"], + "NTIPAliasClass": 0 + }, + "largesiegebow": + { + "DisplayName": "Large Siege Bow", + "NTIPAliasClassID": 166, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 44, + "73": 44, + "23": 10, + "24": 42 + }, + "dimensions": [2, 4], + "uniques": ["CLIFFKILLER"], + "NTIPAliasClass": 1 + }, + "legendspike": + { + "DisplayName": "Legend Spike", + "NTIPAliasClassID": 238, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 47, + "73": 47, + "21": 31, + "22": 47, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["GHOSTFLAME"], + "NTIPAliasClass": 2 + }, + "legendsword": + { + "DisplayName": "Legend Sword", + "NTIPAliasClassID": 229, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 44, + "73": 44, + "21": 22, + "22": 56, + "23": 50, + "24": 94, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 2 + }, + "legendarymallet": + { + "DisplayName": "Legendary Mallet", + "NTIPAliasClassID": 218, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 65, + "73": 65, + "21": 50, + "22": 61, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["SCHAEFERSHAMMER", "STONECRUSHER"], + "NTIPAliasClass": 2 + }, + "lichwand": + { + "DisplayName": "Lich Wand", + "NTIPAliasClassID": 208, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 17, + "73": 17, + "21": 10, + "22": 31, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["BONESHADE"], + "NTIPAliasClass": 2 + }, + "lightcrossbow": + { + "DisplayName": "Light Crossbow", + "NTIPAliasClassID": 76, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 6, + "24": 9 + }, + "dimensions": [2, 3], + "uniques": ["LEADCROW"], + "NTIPAliasClass": 0 + }, + "lochaberaxe": + { + "DisplayName": "Lochaber Axe", + "NTIPAliasClassID": 150, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "23": 6, + "24": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEMEATSCRAPER"], + "NTIPAliasClass": 1 + }, + "longbattlebow": + { + "DisplayName": "Long Battle Bow", + "NTIPAliasClassID": 73, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 44, + "73": 44, + "23": 3, + "24": 18 + }, + "dimensions": [2, 4], + "sets": ["VIDALASBARB"], + "uniques": ["WIZENDRAW"], + "NTIPAliasClass": 0 + }, + "longbow": + { + "DisplayName": "Long Bow", + "NTIPAliasClassID": 70, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 28, + "73": 28, + "23": 3, + "24": 10 + }, + "dimensions": [2, 4], + "uniques": ["RAVENCLAW"], + "NTIPAliasClass": 0 + }, + "longstaff": + { + "DisplayName": "Long Staff", + "NTIPAliasClassID": 64, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 2, + "24": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["SERPENTLORD"], + "NTIPAliasClass": 0 + }, + "longsword": + { + "DisplayName": "Long Sword", + "NTIPAliasClassID": 31, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 44, + "73": 44, + "21": 3, + "22": 19, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["CLEGLAWSTOOTH"], + "uniques": ["HELLPLAGUE"], + "NTIPAliasClass": 0 + }, + "longwarbow": + { + "DisplayName": "Long War Bow", + "NTIPAliasClassID": 75, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 3, + "24": 23 + }, + "dimensions": [2, 4], + "uniques": ["BLASTBARK"], + "NTIPAliasClass": 0 + }, + "mace": + { + "DisplayName": "Mace", + "NTIPAliasClassID": 19, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 60, + "73": 60, + "21": 3, + "22": 10, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["CRUSHFLANGE"], + "NTIPAliasClass": 0 + }, + "maidenjavelin": + { + "DisplayName": "Maiden Javelin", + "NTIPAliasClassID": 285, + "NTIPAliasType": 87, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 8, + "22": 14, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "maidenpike": + { + "DisplayName": "Maiden Pike", + "NTIPAliasClassID": 284, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 25, + "73": 25, + "23": 23, + "24": 55, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 0 + }, + "maidenspear": + { + "DisplayName": "Maiden Spear", + "NTIPAliasClassID": 283, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 28, + "73": 28, + "23": 18, + "24": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 0 + }, + "mancatcher": + { + "DisplayName": "Mancatcher", + "NTIPAliasClassID": 250, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 28, + "73": 28, + "23": 42, + "24": 92, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["VIPERFORK"], + "NTIPAliasClass": 2 + }, + "marteldefer": + { + "DisplayName": "Martel de Fer", + "NTIPAliasClassID": 117, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 60, + "73": 60, + "23": 61, + "24": 99, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THEGAVELOFPAIN"], + "NTIPAliasClass": 1 + }, + "matriarchalbow": + { + "DisplayName": "Matriarchal Bow", + "NTIPAliasClassID": 301, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 48, + "73": 48, + "23": 20, + "24": 47 + }, + "dimensions": [2, 4], + "uniques": ["BLOODRAVENSCHARGE"], + "NTIPAliasClass": 2 + }, + "matriarchaljavelin": + { + "DisplayName": "Matriarchal Javelin", + "NTIPAliasClassID": 305, + "NTIPAliasType": 87, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 30, + "22": 54, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["THUNDERSTROKE"], + "NTIPAliasClass": 2 + }, + "matriarchalpike": + { + "DisplayName": "Matriarchal Pike", + "NTIPAliasClassID": 304, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 25, + "73": 25, + "23": 37, + "24": 153, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "matriarchalspear": + { + "DisplayName": "Matriarchal Spear", + "NTIPAliasClassID": 303, + "NTIPAliasType": 86, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 28, + "73": 28, + "23": 65, + "24": 95, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["STONERAVEN"], + "NTIPAliasClass": 2 + }, + "maul": + { + "DisplayName": "Maul", + "NTIPAliasClassID": 23, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 60, + "73": 60, + "23": 30, + "24": 43, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["BONESNAP"], + "NTIPAliasClass": 0 + }, + "mightyscepter": + { + "DisplayName": "Mighty Scepter", + "NTIPAliasClassID": 211, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 50, + "73": 50, + "21": 40, + "22": 52, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["HEAVENSLIGHT", "THEREDEEMER"], + "NTIPAliasClass": 2 + }, + "militaryaxe": + { + "DisplayName": "Military Axe", + "NTIPAliasClassID": 98, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "23": 14, + "24": 34, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["WARLORDSTRUST"], + "NTIPAliasClass": 1 + }, + "militarypick": + { + "DisplayName": "Military Pick", + "NTIPAliasClassID": 3, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "21": 7, + "22": 11, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["TANCREDSCROWBILL"], + "uniques": ["SKULLSPLITTER"], + "NTIPAliasClass": 0 + }, + "mithrilpoint": + { + "DisplayName": "Mithril Point", + "NTIPAliasClassID": 236, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 55, + "73": 55, + "21": 37, + "22": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "morningstar": + { + "DisplayName": "Morning Star", + "NTIPAliasClassID": 20, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 72, + "73": 72, + "21": 7, + "22": 16, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BLOODRISE"], + "NTIPAliasClass": 0 + }, + "mythicalsword": + { + "DisplayName": "Mythical Sword", + "NTIPAliasClassID": 228, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 44, + "73": 44, + "21": 40, + "22": 50, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["BULKATHOSTRIBALGUARDIAN"], + "NTIPAliasClass": 2 + }, + "naga": + { + "DisplayName": "Naga", + "NTIPAliasClassID": 97, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "21": 16, + "22": 45, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["GUARDIANNAGA"], + "NTIPAliasClass": 1 + }, + "ogreaxe": + { + "DisplayName": "Ogre Axe", + "NTIPAliasClassID": 253, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 50, + "73": 50, + "23": 28, + "24": 145, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["BONEHEW"], + "NTIPAliasClass": 2 + }, + "ogremaul": + { + "DisplayName": "Ogre Maul", + "NTIPAliasClassID": 219, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 60, + "73": 60, + "23": 77, + "24": 106, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "sets": ["IMMORTALKINGSSTONECRUSHER"], + "uniques": ["WINDHAMMER"], + "NTIPAliasClass": 2 + }, + "oilpotion": + { + "DisplayName": "Oil Potion", + "NTIPAliasClassID": 81, + "NTIPAliasType": 38, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 1], + "NTIPAliasClass": 0 + }, + "partizan": + { + "DisplayName": "Partizan", + "NTIPAliasClassID": 153, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "23": 34, + "24": 75, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["PIERRETOMBALECOUANT"], + "NTIPAliasClass": 1 + }, + "pelletbow": + { + "DisplayName": "Pellet Bow", + "NTIPAliasClassID": 272, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 28, + "24": 73 + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "petrifiedwand": + { + "DisplayName": "Petrified Wand", + "NTIPAliasClassID": 104, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 15, + "73": 15, + "21": 8, + "22": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["CARINSHARD"], + "NTIPAliasClass": 1 + }, + "phaseblade": + { + "DisplayName": "Phase Blade", + "NTIPAliasClassID": 225, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "21": 31, + "22": 35 + }, + "dimensions": [2, 3], + "uniques": ["LIGHTSABRE", "AZUREWRATH"], + "NTIPAliasClass": 2 + }, + "pike": + { + "DisplayName": "Pike", + "NTIPAliasClassID": 56, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 25, + "73": 25, + "23": 14, + "24": 63, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THETANNRGOREROD"], + "NTIPAliasClass": 0 + }, + "pilum": + { + "DisplayName": "Pilum", + "NTIPAliasClassID": 48, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 3, + "73": 3, + "21": 4, + "22": 9, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "poignard": + { + "DisplayName": "Poignard", + "NTIPAliasClassID": 132, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 16, + "73": 16, + "21": 6, + "22": 18, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["SPINERIPPER"], + "NTIPAliasClass": 1 + }, + "poleaxe": + { + "DisplayName": "Poleaxe", + "NTIPAliasClassID": 60, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "23": 18, + "24": 39, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEBATTLEBRANCH"], + "NTIPAliasClass": 0 + }, + "polishedwand": + { + "DisplayName": "Polished Wand", + "NTIPAliasClassID": 206, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 22, + "73": 22, + "21": 18, + "22": 33, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "quarterstaff": + { + "DisplayName": "Quarterstaff", + "NTIPAliasClassID": 157, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 8, + "24": 26, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["RIBCRACKER"], + "NTIPAliasClass": 1 + }, + "quhab": + { + "DisplayName": "Quhab", + "NTIPAliasClassID": 182, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 48, + "73": 48, + "21": 11, + "22": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "rancidgaspotion": + { + "DisplayName": "Rancid Gas Potion", + "NTIPAliasClassID": 80, + "NTIPAliasType": 38, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 1], + "NTIPAliasClass": 0 + }, + "razorbow": + { + "DisplayName": "Razor Bow", + "NTIPAliasClassID": 162, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 32, + "73": 32, + "23": 8, + "24": 22 + }, + "dimensions": [2, 3], + "uniques": ["RIPHOOK"], + "NTIPAliasClass": 1 + }, + "reflexbow": + { + "DisplayName": "Reflex Bow", + "NTIPAliasClassID": 282, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 55, + "73": 55, + "23": 9, + "24": 19 + }, + "dimensions": [2, 4], + "NTIPAliasClass": 0 + }, + "reinforcedmace": + { + "DisplayName": "Reinforced Mace", + "NTIPAliasClassID": 215, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 60, + "73": 60, + "21": 41, + "22": 49, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["DANGOONSTEACHING"], + "NTIPAliasClass": 2 + }, + "repeatingcrossbow": + { + "DisplayName": "Repeating Crossbow", + "NTIPAliasClassID": 79, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 6, + "24": 12 + }, + "dimensions": [2, 3], + "uniques": ["DOOMSLINGER"], + "NTIPAliasClass": 0 + }, + "rondel": + { + "DisplayName": "Rondel", + "NTIPAliasClassID": 133, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 20, + "73": 20, + "21": 10, + "22": 26, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["HEARTCARVER"], + "NTIPAliasClass": 1 + }, + "runebow": + { + "DisplayName": "Rune Bow", + "NTIPAliasClassID": 167, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 48, + "73": 48, + "23": 14, + "24": 35 + }, + "dimensions": [2, 3], + "uniques": ["MAGEWRATH"], + "NTIPAliasClass": 1 + }, + "runescepter": + { + "DisplayName": "Rune Scepter", + "NTIPAliasClassID": 108, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 50, + "73": 50, + "21": 13, + "22": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["ZAKARUMSHAND"], + "NTIPAliasClass": 1 + }, + "runestaff": + { + "DisplayName": "Rune Staff", + "NTIPAliasClassID": 160, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 24, + "24": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["SKULLCOLLECTOR"], + "NTIPAliasClass": 1 + }, + "runesword": + { + "DisplayName": "Rune Sword", + "NTIPAliasClassID": 124, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 44, + "73": 44, + "21": 10, + "22": 42, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["PLAGUEBEARER"], + "NTIPAliasClass": 1 + }, + "runictalons": + { + "DisplayName": "Runic Talons", + "NTIPAliasClassID": 194, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 69, + "73": 69, + "21": 24, + "22": 44, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "sabre": + { + "DisplayName": "Sabre", + "NTIPAliasClassID": 27, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "21": 3, + "22": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["ANGELICSICKLE"], + "uniques": ["SKEWEROFKRINTIZ"], + "NTIPAliasClass": 0 + }, + "sacredglobe": + { + "DisplayName": "Sacred Globe", + "NTIPAliasClassID": 277, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 30, + "73": 30, + "21": 3, + "22": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "scepter": + { + "DisplayName": "Scepter", + "NTIPAliasClassID": 15, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 50, + "73": 50, + "21": 6, + "22": 11, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["KNELLSTRIKER"], + "NTIPAliasClass": 0 + }, + "scimitar": + { + "DisplayName": "Scimitar", + "NTIPAliasClassID": 26, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 22, + "73": 22, + "21": 2, + "22": 6, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BLOODCRESCENT"], + "NTIPAliasClass": 0 + }, + "scissorskatar": + { + "DisplayName": "Scissors Katar", + "NTIPAliasClassID": 181, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 68, + "73": 68, + "21": 9, + "22": 17, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "scissorsquhab": + { + "DisplayName": "Scissors Quhab", + "NTIPAliasClassID": 188, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 68, + "73": 68, + "21": 19, + "22": 40, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "scissorssuwayyah": + { + "DisplayName": "Scissors Suwayyah", + "NTIPAliasClassID": 195, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 68, + "73": 68, + "21": 40, + "22": 51, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["NATALYASMARK"], + "NTIPAliasClass": 2 + }, + "scourge": + { + "DisplayName": "Scourge", + "NTIPAliasClassID": 217, + "NTIPAliasType": 36, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "21": 3, + "22": 80, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["HORIZONSTORNADO", "STORMLASH"], + "NTIPAliasClass": 2 + }, + "scythe": + { + "DisplayName": "Scythe", + "NTIPAliasClassID": 59, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "23": 8, + "24": 20, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["SOULHARVEST"], + "NTIPAliasClass": 0 + }, + "seraphrod": + { + "DisplayName": "Seraph Rod", + "NTIPAliasClassID": 212, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 60, + "73": 60, + "21": 45, + "22": 54, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "shadowbow": + { + "DisplayName": "Shadow Bow", + "NTIPAliasClassID": 266, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 28, + "73": 28, + "23": 15, + "24": 59 + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "shaftofthehoradricstaff": + { + "DisplayName": "Shaft of the Horadric Staff", + "NTIPAliasClassID": 92, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "72": 45, + "73": 45, + "23": 10, + "24": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["STAFFOFKINGS"], + "NTIPAliasClass": 0 + }, + "shamshir": + { + "DisplayName": "Shamshir", + "NTIPAliasClassID": 120, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "21": 10, + "22": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["HEXFIRE"], + "NTIPAliasClass": 1 + }, + "shillelagh": + { + "DisplayName": "Shillelagh", + "NTIPAliasClassID": 262, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "23": 65, + "24": 108, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 2 + }, + "shortbattlebow": + { + "DisplayName": "Short Battle Bow", + "NTIPAliasClassID": 72, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 5, + "24": 11 + }, + "dimensions": [2, 3], + "uniques": ["STORMSTRIKE"], + "NTIPAliasClass": 0 + }, + "shortbow": + { + "DisplayName": "Short Bow", + "NTIPAliasClassID": 68, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "23": 1, + "24": 4 + }, + "dimensions": [2, 3], + "uniques": ["PLUCKEYE"], + "NTIPAliasClass": 0 + }, + "shortsiegebow": + { + "DisplayName": "Short Siege Bow", + "NTIPAliasClassID": 165, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 13, + "24": 30 + }, + "dimensions": [2, 3], + "uniques": ["WITCHWILDSTRING"], + "NTIPAliasClass": 1 + }, + "shortspear": + { + "DisplayName": "Short Spear", + "NTIPAliasClassID": 49, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 4, + "73": 4, + "21": 2, + "22": 13, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "shortstaff": + { + "DisplayName": "Short Staff", + "NTIPAliasClassID": 63, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "23": 1, + "24": 5, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BANEASH"], + "NTIPAliasClass": 0 + }, + "shortsword": + { + "DisplayName": "Short Sword", + "NTIPAliasClassID": 25, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 2, + "22": 7, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["RIXOTSKEEN"], + "NTIPAliasClass": 0 + }, + "shortwarbow": + { + "DisplayName": "Short War Bow", + "NTIPAliasClassID": 74, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 48, + "73": 48, + "23": 6, + "24": 14 + }, + "dimensions": [2, 3], + "sets": ["ARCTICHORN"], + "uniques": ["HELLCLAP"], + "NTIPAliasClass": 0 + }, + "siegecrossbow": + { + "DisplayName": "Siege Crossbow", + "NTIPAliasClassID": 170, + "NTIPAliasType": 35, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "23": 20, + "24": 42 + }, + "dimensions": [2, 3], + "uniques": ["PUSSPITTER"], + "NTIPAliasClass": 1 + }, + "silveredgedaxe": + { + "DisplayName": "Silver-edged Axe", + "NTIPAliasClassID": 202, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 35, + "73": 35, + "23": 62, + "24": 110, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["ETHEREALEDGE"], + "NTIPAliasClass": 2 + }, + "simbilan": + { + "DisplayName": "Simbilan", + "NTIPAliasClassID": 142, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 14, + "73": 14, + "21": 8, + "22": 32, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "smallcrescent": + { + "DisplayName": "Small Crescent", + "NTIPAliasClassID": 197, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 24, + "73": 24, + "21": 38, + "22": 60, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "smokedsphere": + { + "DisplayName": "Smoked Sphere", + "NTIPAliasClassID": 278, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "21": 4, + "22": 10, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "sparklingball": + { + "DisplayName": "Sparkling Ball", + "NTIPAliasClassID": 289, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "21": 13, + "22": 32, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 1 + }, + "spear": + { + "DisplayName": "Spear", + "NTIPAliasClassID": 52, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 3, + "24": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEDRAGONCHANG"], + "NTIPAliasClass": 0 + }, + "spetum": + { + "DisplayName": "Spetum", + "NTIPAliasClassID": 55, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 28, + "73": 28, + "23": 15, + "24": 23, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["LANCEOFYAGGAI"], + "NTIPAliasClass": 0 + }, + "spiculum": + { + "DisplayName": "Spiculum", + "NTIPAliasClassID": 143, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "21": 13, + "22": 38, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 1 + }, + "spiderbow": + { + "DisplayName": "Spider Bow", + "NTIPAliasClassID": 264, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 20, + "73": 20, + "23": 23, + "24": 50 + }, + "dimensions": [2, 3], + "NTIPAliasClass": 2 + }, + "spikedclub": + { + "DisplayName": "Spiked Club", + "NTIPAliasClassID": 18, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 36, + "73": 36, + "21": 5, + "22": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["STOUTNAIL"], + "NTIPAliasClass": 0 + }, + "stagbow": + { + "DisplayName": "Stag Bow", + "NTIPAliasClassID": 281, + "NTIPAliasType": 85, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 48, + "73": 48, + "23": 7, + "24": 12 + }, + "dimensions": [2, 4], + "NTIPAliasClass": 0 + }, + "stalagmite": + { + "DisplayName": "Stalagmite", + "NTIPAliasClassID": 260, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 75, + "24": 107, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 2 + }, + "stiletto": + { + "DisplayName": "Stiletto", + "NTIPAliasClassID": 135, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 24, + "73": 24, + "21": 19, + "22": 36, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["STORMSPIKE"], + "NTIPAliasClass": 1 + }, + "stranglinggaspotion": + { + "DisplayName": "Strangling Gas Potion", + "NTIPAliasClassID": 84, + "NTIPAliasType": 38, + "NTIPAliasStatProps": + { + "72": 2, + "73": 2, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 1], + "NTIPAliasClass": 0 + }, + "stygianpike": + { + "DisplayName": "Stygian Pike", + "NTIPAliasClassID": 249, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "23": 29, + "24": 144, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "NTIPAliasClass": 2 + }, + "stygianpilum": + { + "DisplayName": "Stygian Pilum", + "NTIPAliasClassID": 244, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 12, + "73": 12, + "21": 14, + "22": 64, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "suwayyah": + { + "DisplayName": "Suwayyah", + "NTIPAliasClassID": 189, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 48, + "73": 48, + "21": 39, + "22": 52, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "swirlingcrystal": + { + "DisplayName": "Swirling Crystal", + "NTIPAliasClassID": 290, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 18, + "22": 42, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["TALRASHASLIDLESSEYE"], + "uniques": ["THEOCULUS"], + "NTIPAliasClass": 1 + }, + "tabar": + { + "DisplayName": "Tabar", + "NTIPAliasClassID": 100, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 40, + "73": 40, + "23": 24, + "24": 77, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["STORMRIDER"], + "NTIPAliasClass": 1 + }, + "thegidbinn": + { + "DisplayName": "The Gidbinn", + "NTIPAliasClassID": 87, + "NTIPAliasType": 32, + "NTIPAliasStatProps": + { + "72": 30, + "73": 30, + "21": 3, + "22": 7, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "thresher": + { + "DisplayName": "Thresher", + "NTIPAliasClassID": 255, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 65, + "73": 65, + "23": 12, + "24": 141, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEREAPERSTOLL"], + "NTIPAliasClass": 2 + }, + "throwingaxe": + { + "DisplayName": "Throwing Axe", + "NTIPAliasClassID": 44, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 4, + "22": 7, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "throwingknife": + { + "DisplayName": "Throwing Knife", + "NTIPAliasClassID": 43, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "72": 4, + "73": 4, + "21": 2, + "22": 3, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 0 + }, + "throwingspear": + { + "DisplayName": "Throwing Spear", + "NTIPAliasClassID": 51, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 6, + "73": 6, + "21": 5, + "22": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "NTIPAliasClass": 0 + }, + "thundermaul": + { + "DisplayName": "Thunder Maul", + "NTIPAliasClassID": 220, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 60, + "73": 60, + "23": 33, + "24": 180, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["THECRANIUMBASHER", "EARTHSHIFTER"], + "NTIPAliasClass": 2 + }, + "tomahawk": + { + "DisplayName": "Tomahawk", + "NTIPAliasClassID": 196, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 28, + "73": 28, + "21": 33, + "22": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["RAZORSEDGE"], + "NTIPAliasClass": 2 + }, + "tombwand": + { + "DisplayName": "Tomb Wand", + "NTIPAliasClassID": 105, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 15, + "73": 15, + "21": 10, + "22": 22, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["ARMOFKINGLEORIC"], + "NTIPAliasClass": 1 + }, + "trident": + { + "DisplayName": "Trident", + "NTIPAliasClassID": 53, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 35, + "73": 35, + "23": 9, + "24": 15, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["RAZORTINE"], + "NTIPAliasClass": 0 + }, + "truncheon": + { + "DisplayName": "Truncheon", + "NTIPAliasClassID": 210, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 55, + "73": 55, + "21": 35, + "22": 43, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["NORDSTENDERIZER"], + "NTIPAliasClass": 2 + }, + "tulwar": + { + "DisplayName": "Tulwar", + "NTIPAliasClassID": 121, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 32, + "73": 32, + "21": 16, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["BLADEOFALIBABA"], + "NTIPAliasClass": 1 + }, + "tusksword": + { + "DisplayName": "Tusk Sword", + "NTIPAliasClassID": 128, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "21": 10, + "22": 37, + "23": 19, + "24": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["THEVILEHUSK"], + "NTIPAliasClass": 1 + }, + "twinaxe": + { + "DisplayName": "Twin Axe", + "NTIPAliasClassID": 95, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 24, + "73": 24, + "21": 13, + "22": 38, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["ISLESTRIKE"], + "NTIPAliasClass": 1 + }, + "twohandedsword": + { + "DisplayName": "Two-Handed Sword", + "NTIPAliasClassID": 33, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 44, + "73": 44, + "21": 2, + "22": 9, + "23": 8, + "24": 17, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["SHADOWFANG"], + "NTIPAliasClass": 0 + }, + "tyrantclub": + { + "DisplayName": "Tyrant Club", + "NTIPAliasClassID": 214, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 65, + "73": 65, + "21": 32, + "22": 58, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["DEMONLIMB"], + "NTIPAliasClass": 2 + }, + "unearthedwand": + { + "DisplayName": "Unearthed Wand", + "NTIPAliasClassID": 209, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 18, + "73": 18, + "21": 22, + "22": 28, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["DEATHSWEB"], + "NTIPAliasClass": 2 + }, + "vortexorb": + { + "DisplayName": "Vortex Orb", + "NTIPAliasClassID": 299, + "NTIPAliasType": 68, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 40, + "73": 40, + "21": 12, + "22": 66, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 2 + }, + "voulge": + { + "DisplayName": "Voulge", + "NTIPAliasClassID": 58, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 50, + "73": 50, + "23": 6, + "24": 21, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["STEELGOAD"], + "NTIPAliasClass": 0 + }, + "walkingstick": + { + "DisplayName": "Walking Stick", + "NTIPAliasClassID": 259, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 20, + "73": 20, + "23": 69, + "24": 85, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "wand": + { + "DisplayName": "Wand", + "NTIPAliasClassID": 10, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 15, + "73": 15, + "21": 2, + "22": 4, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["TORCHOFIRO"], + "NTIPAliasClass": 0 + }, + "waraxe": + { + "DisplayName": "War Axe", + "NTIPAliasClassID": 4, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "21": 10, + "22": 18, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["RAKESCAR"], + "NTIPAliasClass": 0 + }, + "warclub": + { + "DisplayName": "War Club", + "NTIPAliasClassID": 116, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 60, + "73": 60, + "23": 53, + "24": 78, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["BLOODTREESTUMP"], + "NTIPAliasClass": 1 + }, + "wardart": + { + "DisplayName": "War Dart", + "NTIPAliasClassID": 138, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "72": 20, + "73": 20, + "21": 6, + "22": 24, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "NTIPAliasClass": 1 + }, + "warfist": + { + "DisplayName": "War Fist", + "NTIPAliasClassID": 191, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 64, + "73": 64, + "21": 44, + "22": 53, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 2 + }, + "warfork": + { + "DisplayName": "War Fork", + "NTIPAliasClassID": 147, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 28, + "73": 28, + "23": 16, + "24": 40, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["SOULFEASTTINE"], + "NTIPAliasClass": 1 + }, + "warhammer": + { + "DisplayName": "War Hammer", + "NTIPAliasClassID": 22, + "NTIPAliasType": 31, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 4 + }, + "72": 55, + "73": 55, + "21": 19, + "22": 29, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["IRONSTONE"], + "NTIPAliasClass": 0 + }, + "warjavelin": + { + "DisplayName": "War Javelin", + "NTIPAliasClassID": 140, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 10, + "73": 10, + "21": 6, + "22": 19, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "warpike": + { + "DisplayName": "War Pike", + "NTIPAliasClassID": 252, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 25, + "73": 25, + "23": 33, + "24": 178, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["STEELPILLAR"], + "NTIPAliasClass": 2 + }, + "warscepter": + { + "DisplayName": "War Scepter", + "NTIPAliasClassID": 17, + "NTIPAliasType": 24, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 70, + "73": 70, + "21": 10, + "22": 17, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "sets": ["MILABREGASROD"], + "uniques": ["STORMEYE"], + "NTIPAliasClass": 0 + }, + "warscythe": + { + "DisplayName": "War Scythe", + "NTIPAliasClassID": 62, + "NTIPAliasType": 34, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 55, + "73": 55, + "23": 15, + "24": 36, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEGRIMREAPER"], + "NTIPAliasClass": 0 + }, + "warspear": + { + "DisplayName": "War Spear", + "NTIPAliasClassID": 145, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 30, + "73": 30, + "23": 10, + "24": 37, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["THEIMPALER"], + "NTIPAliasClass": 1 + }, + "warspike": + { + "DisplayName": "War Spike", + "NTIPAliasClassID": 199, + "NTIPAliasType": 28, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 26, + "73": 26, + "21": 30, + "22": 48, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["CRANEBEAK"], + "NTIPAliasClass": 2 + }, + "warstaff": + { + "DisplayName": "War Staff", + "NTIPAliasClassID": 67, + "NTIPAliasType": 26, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 50, + "73": 50, + "23": 12, + "24": 28, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "sets": ["ARCANNASDEATHWAND"], + "uniques": ["THEIRONJANGBONG"], + "NTIPAliasClass": 0 + }, + "warsword": + { + "DisplayName": "War Sword", + "NTIPAliasClassID": 32, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 44, + "73": 44, + "21": 8, + "22": 20, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "sets": ["DEATHSTOUCH"], + "uniques": ["CULWENSPOINT"], + "NTIPAliasClass": 0 + }, + "wardbow": + { + "DisplayName": "Ward Bow", + "NTIPAliasClassID": 270, + "NTIPAliasType": 27, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 48, + "73": 48, + "23": 20, + "24": 53 + }, + "dimensions": [2, 3], + "uniques": ["WIDOWMAKER"], + "NTIPAliasClass": 2 + }, + "wingedaxe": + { + "DisplayName": "Winged Axe", + "NTIPAliasClassID": 242, + "NTIPAliasType": 43, + "NTIPAliasStatProps": + { + "72": 16, + "73": 16, + "21": 11, + "22": 56, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 3], + "uniques": ["LACERATOR"], + "NTIPAliasClass": 2 + }, + "wingedharpoon": + { + "DisplayName": "Winged Harpoon", + "NTIPAliasClassID": 247, + "NTIPAliasType": 44, + "NTIPAliasStatProps": + { + "72": 18, + "73": 18, + "21": 27, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 4], + "uniques": ["GARGOYLESBITE"], + "NTIPAliasClass": 2 + }, + "wingedknife": + { + "DisplayName": "Winged Knife", + "NTIPAliasClassID": 241, + "NTIPAliasType": 42, + "NTIPAliasStatProps": + { + "72": 20, + "73": 20, + "21": 27, + "22": 35, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["WARSHRIKE"], + "NTIPAliasClass": 2 + }, + "wirtsleg": + { + "DisplayName": "Wirt's Leg", + "NTIPAliasClassID": 88, + "NTIPAliasType": 29, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 66, + "73": 66, + "21": 2, + "22": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "wristblade": + { + "DisplayName": "Wrist Blade", + "NTIPAliasClassID": 176, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 52, + "73": 52, + "21": 5, + "22": 9, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 0 + }, + "wristspike": + { + "DisplayName": "Wrist Spike", + "NTIPAliasClassID": 183, + "NTIPAliasType": 67, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 2 + }, + "72": 56, + "73": 56, + "21": 13, + "22": 27, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "NTIPAliasClass": 1 + }, + "wristsword": + { + "DisplayName": "Wrist Sword", + "NTIPAliasClassID": 190, + "NTIPAliasType": 65, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 3 + }, + "72": 56, + "73": 56, + "21": 34, + "22": 45, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 3], + "uniques": ["JADETALON"], + "NTIPAliasClass": 2 + }, + "yari": + { + "DisplayName": "Yari", + "NTIPAliasClassID": 148, + "NTIPAliasType": 33, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 6 + }, + "72": 28, + "73": 28, + "23": 29, + "24": 59, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["HONESUNDAN"], + "NTIPAliasClass": 1 + }, + "yewwand": + { + "DisplayName": "Yew Wand", + "NTIPAliasClassID": 11, + "NTIPAliasType": 25, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 1 + }, + "72": 15, + "73": 15, + "21": 2, + "22": 8, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [1, 2], + "uniques": ["MAELSTROM"], + "NTIPAliasClass": 0 + }, + "zweihander": + { + "DisplayName": "Zweihander", + "NTIPAliasClassID": 130, + "NTIPAliasType": 30, + "NTIPAliasStatProps": + { + "194": + { + "min": 0, + "max": 5 + }, + "72": 50, + "73": 50, + "21": 19, + "22": 35, + "23": 29, + "24": 54, + "0x400000": + { + "min": 0, + "max": 1 + } + }, + "dimensions": [2, 4], + "uniques": ["TODESFAELLEFLAMME"], + "NTIPAliasClass": 1 + } +} + +REF_PATTERNS = { + "Adds {:d}-{:d} cold damage": [ + "dmg-cold", + "itemcolddamage", + "dmg-elem", + "itemelementaldamage" + ], + "Adds {:d}-{:d} damage": [ + "dmg-norm", + "damagebonus", + "bonusdamage", + "adddamage" + ], + "Adds {:d}-{:d} fire damage": [ + "dmg-elem", + "itemelementaldamage", + "dmg-fire", + "itemfiredamage" + ], + "Adds {:d}-{:d} lightning damage": [ + "dmg-elem", + "itemelementaldamage", + "dmg-ltng", + "itemlightningdamage", + "itemltngdamage" + ], + "Adds {:d}-{:d} magic damage": [ + "dmg-mag" + ], + "Adds {:d}-{:d} poison damage over {:d} seconds": [ + "dmg-pois", + "itempoisondamage" + ], + "All Resistances {:d}": [ + "res-all", + "allresist" + ], + "Attacker Takes Damage of {:d}": [ + "thorns", + "item_attackertakesdamage", + "itemattackertakesdamage" + ], + "Attacker Takes Damage of {:d} (Based on Character Level)": [ + "thorns/lvl", + "item_thorns_perlevel", + "itemthornsperlevel" + ], + "Attacker Takes Lightning Damage of {:d}": [ + "light-thorns", + "item_attackertakeslightdamage", + "itemattackertakeslightdamage" + ], + "Cannot Be Frozen": [ + "nofreeze", + "item_cannotbefrozen", + "itemcannotbefrozen" + ], + "Cold Absorb {:d}%": [ + "abs-cold%", + "item_absorbcold_percent", + "itemabsorbcoldpercent", + "coldabsorb" + ], + "Cold Resist {:d}": [ + "res-cold/time", + "item_resist_cold_bytime", + "itemresistcoldbytime" + ], + "Cold Resist {:d}%": [ + "res-cold", + "coldresist" + ], + "Cold Resist {:d}% (Based on Character Level)": [ + "res-cold/lvl", + "item_resist_cold_perlevel", + "itemresistcoldperlevel" + ], + "Damage Reduced by {:d}": [ + "red-dmg", + "normal_damage_reduction", + "normaldamagereduction" + ], + "Damage Reduced by {:d}%": [ + "red-dmg%", + "damageresist", + "damagereduction" + ], + "Damage {:d}": [ + "dmg", + "item_normaldamage", + "itemnormaldamage", + "damagebonus", + "bonusdamage", + "adddamage" + ], + "Defense: {:d}": [ + "defense" + ], + "Durability: {:d} of {:d}": [ + "durability" + ], + "Ethereal (Cannot be Repaired)": [ + "ethereal" + ], + "Extra Gold from Monsters {:d}": [ + "gold%/time", + "item_find_gold_bytime", + "itemfindgoldbytime" + ], + "Fire Absorb {:d}%": [ + "abs-fire%", + "item_absorbfire_percent", + "itemabsorbfirepercent", + "fireabsorb" + ], + "Fire Resist {:d}": [ + "res-fire/time", + "item_resist_fire_bytime", + "itemresistfirebytime" + ], + "Fire Resist {:d}%": [ + "res-fire", + "fireresist" + ], + "Fire Resist {:d}% (Based on Character Level)": [ + "res-fire/lvl", + "item_resist_fire_perlevel", + "itemresistfireperlevel" + ], + "Fires Explosive Arrows or Bolts": [ + "explosivearrow", + "item_explosivearrow", + "itemexplosivearrow" + ], + "Fires Magic Arrows": [ + "magicarrow", + "item_magicarrow", + "itemmagicarrow" + ], + "Freezes target {:d}": [ + "freeze", + "item_freeze", + "itemfreeze", + "freezetarget" + ], + "Half Freeze Duration": [ + "half-freeze", + "item_halffreezeduration", + "itemhalffreezeduration" + ], + "Heal Stamina Plus {:d}": [ + "regen-stam/time", + "item_regenstamina_bytime", + "itemregenstaminabytime" + ], + "Heal Stamina Plus {:d}%": [ + "regen-stam", + "staminarecoverybonus" + ], + "Heal Stamina Plus {:d}% (Based on Character Level)": [ + "regen-stam/lvl", + "item_regenstamina_perlevel", + "itemregenstaminaperlevel" + ], + "Hit Blinds Target {:d}": [ + "stupidity", + "item_stupidity", + "itemstupidity", + "hitblindstarget" + ], + "Hit Causes Monster to Flee {:d}%": [ + "howl", + "item_howl", + "itemhowl" + ], + "Ignore Target's Defense": [ + "ignore-ac", + "item_ignoretargetac", + "itemignoretargetac" + ], + "Increase Maximum Durability {:d}%": [ + "dur%", + "item_maxdurability_percent", + "itemmaxdurabilitypercent", + "maxdurabilitypercent" + ], + "Increase Maximum Life {:d}%": [ + "hp%", + "item_maxhp_percent", + "itemmaxhppercent" + ], + "Increase Maximum Mana {:d}%": [ + "mana%", + "item_maxmana_percent", + "itemmaxmanapercent" + ], + "Increased Stack Size": [ + "stack", + "item_extra_stack", + "itemextrastack" + ], + "Knockback": [ + "knock", + "item_knockback", + "itemknockback", + "knockback" + ], + "Level {:d} {} ({:d}/{:d} Charges)": [ + "charged", + "item_charged_skill", + "itemchargedskill", + "chargedskill" + ], + "Level {:d} {} Aura When Equipped": [ + "aura", + "item_aura", + "itemaura" + ], + "Lightning Absorb {:d}%": [ + "abs-ltng%", + "item_absorblight_percent", + "itemabsorblightpercent", + "lightningabsorb" + ], + "Lightning Resist {:d}": [ + "res-ltng/time", + "item_resist_ltng_bytime", + "itemresistltngbytime" + ], + "Lightning Resist {:d}%": [ + "res-ltng", + "lightresist" + ], + "Lightning Resist {:d}% (Based on Character Level)": [ + "res-ltng/lvl", + "item_resist_ltng_perlevel", + "itemresistltngperlevel" + ], + "Magic Absorb {:d}%": [ + "abs-mag%", + "item_absorbmagic_percent", + "itemabsorbmagicpercent" + ], + "Magic Damage Reduced by {:d}": [ + "red-mag", + "magic_damage_reduction", + "magicdamagereduction" + ], + "Magic Resist {:d}%": [ + "res-mag", + "magicresist" + ], + "One-Hand Damage: {:d}": [ + "damage-1hand" + ], + "One-Hand Damage: {:d} to {:d}": [ + "damage-1hand" + ], + "{:d}% Piercing Attack": [ + "pierce", + "item_pierce", + "itempierce" + ], + "Poison Length Reduced by {:d}%": [ + "res-pois-len", + "item_poisonlengthresist", + "itempoisonlengthresist" + ], + "Poison Resist {:d}": [ + "res-pois/time", + "item_resist_pois_bytime", + "itemresistpoisbytime" + ], + "Poison Resist {:d}%": [ + "res-pois", + "poisonresist" + ], + "Poison Resist {:d}% (Based on Character Level)": [ + "res-pois/lvl", + "item_resist_pois_perlevel", + "itemresistpoisperlevel" + ], + "Prevent Monster Heal": [ + "noheal", + "item_preventheal", + "itempreventheal" + ], + "Reduces all Vendor Prices {:d}%": [ + "cheap", + "item_reducedprices", + "itemreducedprices", + "reduceprices", + "reducedvendorprices" + ], + "Regenerate Mana {:d}%": [ + "regen-mana", + "manarecoverybonus" + ], + "Repairs {} durability {}": [ + "rep-dur", + "item_replenish_durability", + "itemreplenishdurability" + ], + "Replenish Life {:d}": [ + "regen", + "hpregen" + ], + "Replenishes quantity": [ + "rep-quant", + "item_replenish_quantity", + "itemreplenishquantity" + ], + "Requirements {:d}%": [ + "ease", + "item_req_percent", + "itemreqpercent" + ], + "Slain Monsters Rest in Peace": [ + "rip", + "item_restinpeace", + "itemrestinpeace" + ], + "Slows Target by {:d}%": [ + "slow", + "item_slow", + "itemslow" + ], + "Socketed ({:d})": [ + "sock", + "item_numsockets", + "itemnumsockets", + "sockets" + ], + "Throwable": [ + "throw", + "item_throwable", + "itemthrowable" + ], + "Two-Hand Damage: {:d}": [ + "damage-2hand" + ], + "Two-Hand Damage: {:d} to {:d}": [ + "damage-2hand" + ], + "{:d} Absorbs Cold Damage": [ + "abs-cold/time", + "item_absorb_cold_bytime", + "itemabsorbcoldbytime", + "coldabsorb" + ], + "{:d} Absorbs Cold Damage (Based on Character Level)": [ + "abs-cold/lvl", + "item_absorb_cold_perlevel", + "itemabsorbcoldperlevel" + ], + "{:d} Absorbs Fire Damage": [ + "abs-fire/time", + "item_absorb_fire_bytime", + "itemabsorbfirebytime", + "fireabsorb" + ], + "{:d} Absorbs Fire Damage (Based on Character Level)": [ + "abs-fire/lvl", + "item_absorb_fire_perlevel", + "itemabsorbfireperlevel" + ], + "{:d} Absorbs Lightning Damage": [ + "abs-ltng/time", + "item_absorb_ltng_bytime", + "itemabsorbltngbytime", + "lightningabsorb" + ], + "{:d} Absorbs Lightning Damage (Based on Character Level)": [ + "abs-ltng/lvl", + "item_absorb_ltng_perlevel", + "itemabsorbltngperlevel" + ], + "{:d} Better Chance of Getting Magic Items": [ + "mag%/time", + "item_find_magic_bytime", + "itemfindmagicbytime" + ], + "{:d} Bonus to Attack Rating": [ + "att%/time", + "item_tohitpercent_bytime", + "itemtohitpercentbytime" + ], + "{:d} Chance of Crushing Blow": [ + "crush/time", + "item_crushingblow_bytime", + "itemcrushingblowbytime", + "crushingblow" + ], + "{:d} Chance of Open Wounds": [ + "wounds/time", + "item_openwounds_bytime", + "itemopenwoundsbytime", + "openwounds" + ], + "{:d} Cold Absorb": [ + "abs-cold", + "item_absorbcold", + "itemabsorbcold", + "coldabsorb" + ], + "{:d} Damage to Demons": [ + "dmg-dem/time", + "item_damage_demon_bytime", + "itemdamagedemonbytime" + ], + "{:d} Damage to Undead": [ + "dmg-und/time", + "item_damage_undead_bytime", + "itemdamageundeadbytime" + ], + "{:d} Deadly Strike": [ + "deadly/time", + "item_deadlystrike_bytime", + "itemdeadlystrikebytime", + "deadlystrike" + ], + "{:d} Defense": [ + "ac", + "armorclass", + "defensebonus", + "bonusdefense", + "adddefense", + "ac/time", + "item_armor_bytime", + "itemarmorbytime" + ], + "{:d} Defense (Based on Character Level)": [ + "ac/lvl", + "item_armor_perlevel", + "itemarmorperlevel" + ], + "{:d} Defense vs. Melee": [ + "ac-hth", + "armorclass_vs_hth", + "armorclassvshth", + "enhanceddefense" + ], + "{:d} Defense vs. Missile": [ + "ac-miss", + "armorclass_vs_missile", + "armorclassvsmissile" + ], + "{:d} Enhanced Defense": [ + "ac%/time", + "item_armorpercent_bytime", + "itemarmorpercentbytime", + "enhanceddefense" + ], + "{:d} Enhanced Maximum Damage": [ + "dmg%/time", + "item_maxdamage_percent_bytime", + "itemmaxdamagepercentbytime", + "enhanceddamage" + ], + "{:d} Fire Absorb": [ + "abs-fire", + "item_absorbfire", + "itemabsorbfire", + "fireabsorb" + ], + "{:d} Kick Damage": [ + "kick", + "item_kickdamage", + "itemkickdamage", + "kick/time", + "item_kick_damage_bytime", + "itemkickdamagebytime" + ], + "{:d} Kick Damage (Based on Character Level)": [ + "kick/lvl", + "item_kick_damage_perlevel", + "itemkickdamageperlevel" + ], + "{:d} Life after each Demon Kill": [ + "demon-heal", + "item_healafterdemonkill", + "itemhealafterdemonkill" + ], + "{:d} Life after each Kill": [ + "heal-kill", + "item_healafterkill", + "itemhealafterkill" + ], + "{:d} Lightning Absorb": [ + "abs-ltng", + "item_absorblight", + "itemabsorblight", + "lightningabsorb" + ], + "{:d} Magic Absorb": [ + "abs-mag", + "item_absorbmagic", + "itemabsorbmagic" + ], + "{:d} Maximum Stamina": [ + "stam", + "maxstamina", + "stam/time", + "item_stamina_bytime", + "itemstaminabytime" + ], + "{:d} Maximum Stamina (Based on Character Level)": [ + "stam/lvl", + "item_stamina_perlevel", + "itemstaminaperlevel" + ], + "{:d} cold damage": [ + "dmg-cold", + "itemcolddamage" + ], + "{:d} damage": [ + "dmg-norm", + "damagebonus", + "bonusdamage", + "adddamage" + ], + "{:d} fire damage": [ + "dmg-fire", + "itemfiredamage" + ], + "{:d} lightning damage": [ + "dmg-ltng", + "itemlightningdamage", + "itemltngdamage" + ], + "{:d} magic damage": [ + "dmg-mag" + ], + "{:d} poison damage over {:d} seconds": [ + "dmg-pois", + "itempoisondamage" + ], + "{:d} to All Skills": [ + "allskills", + "item_allskills", + "itemallskills" + ], + "{:d} to Amazon Skill Levels": [ + "ama", + "item_addclassskills", + "itemaddclassskills", + "itemaddamazonskills", + "amazonskills" + ], + "{:d} to Assassin Skill Levels": [ + "ass", + "item_addclassskills", + "itemaddclassskills", + "itemaddassassinskills", + "assassinskills" + ], + "{:d} to Attack Rating": [ + "att", + "tohit", + "attackrating", + "att/time", + "item_tohit_bytime", + "itemtohitbytime" + ], + "{:d} to Attack Rating (Based on Character Level)": [ + "att/lvl", + "item_tohit_perlevel", + "itemtohitperlevel" + ], + "{:d} to Attack Rating against Demons": [ + "att-dem/time", + "item_tohit_demon_bytime", + "itemtohitdemonbytime", + "att-demon", + "item_demon_tohit", + "itemdemontohit" + ], + "{:d} to Attack Rating against Demons (Based on Character Level)": [ + "att-dem/lvl", + "item_tohit_demon_perlevel", + "itemtohitdemonperlevel" + ], + "{:d} to Attack Rating against Undead": [ + "att-und/time", + "item_tohit_undead_bytime", + "itemtohitundeadbytime", + "att-undead", + "item_undead_tohit", + "itemundeadtohit" + ], + "{:d} to Attack Rating against Undead (Based on Character Level)": [ + "att-und/lvl", + "item_tohit_undead_perlevel", + "itemtohitundeadperlevel" + ], + "{:d} to Attack Rating versus {}": [ + "att-mon%", + "attack_vs_montype", + "attackvsmontype", + "dmg-mon%", + "damage_vs_montype", + "damagevsmontype" + ], + "{:d} to Barbarian Skill Levels": [ + "bar", + "item_addclassskills", + "itemaddclassskills", + "itemaddbarbarianskills", + "barbarianskills" + ], + "{:d} to Dexterity": [ + "dex", + "dexterity", + "dex/time", + "item_dexterity_bytime", + "itemdexteritybytime" + ], + "{:d} to Dexterity (Based on Character Level)": [ + "dex/lvl", + "item_dexterity_perlevel", + "itemdexterityperlevel" + ], + "{:d} to Druid Skill Levels": [ + "dru", + "item_addclassskills", + "itemaddclassskills", + "druidskills", + "itemadddruidskills" + ], + "{:d} to Energy": [ + "enr", + "energy", + "enr/time", + "item_energy_bytime", + "itemenergybytime" + ], + "{:d} to Energy (Based on Character Level)": [ + "enr/lvl", + "item_energy_perlevel", + "itemenergyperlevel" + ], + "{:d} to Fire Skills": [ + "fireskill", + "item_elemskill", + "itemelemskill", + "fireskills" + ], + "{:d} to Life": [ + "hp", + "maxhp", + "life", + "hp/time", + "item_hp_bytime", + "itemhpbytime" + ], + "{:d} to Life (Based on Character Level)": [ + "hp/lvl", + "item_hp_perlevel", + "itemhpperlevel" + ], + "{:d} to Light Radius": [ + "light", + "item_lightradius", + "itemlightradius" + ], + "{:d} to Mana": [ + "mana", + "maxmana", + "mana/time", + "item_mana_bytime", + "itemmanabytime" + ], + "{:d} to Mana (Based on Character Level)": [ + "mana/lvl", + "item_mana_perlevel", + "itemmanaperlevel" + ], + "{:d} to Mana after each Kill": [ + "mana-kill", + "item_manaafterkill", + "itemmanaafterkill" + ], + "{:d} to Maximum Cold Damage": [ + "cold-max", + "coldmaxdam", + "dmg-cold/time", + "item_cold_damagemax_bytime", + "itemcolddamagemaxbytime", + "itemcolddamagemax", + "dmg-elem-max", + "itemelementaldamagemax" + ], + "{:d} to Maximum Cold Damage (Based on Character Level)": [ + "dmg-cold/lvl", + "item_cold_damagemax_perlevel", + "itemcolddamagemaxperlevel" + ], + "{:d} to Maximum Damage": [ + "maxdamage", + "dmg/time", + "item_maxdamage_bytime", + "itemmaxdamagebytime", + "damagebonus", + "bonusdamage", + "adddamage", + "itemmaxdamage" + ], + "{:d} to Maximum Damage (Based on Character Level)": [ + "dmg/lvl", + "item_maxdamage_perlevel", + "itemmaxdamageperlevel" + ], + "{:d} to Maximum Fire Damage": [ + "dmg-elem-max", + "itemelementaldamagemax", + "dmg-fire/time", + "item_fire_damagemax_bytime", + "itemfiredamagemaxbytime", + "itemfiredamagemax", + "fire-max", + "firemaxdam" + ], + "{:d} to Maximum Fire Damage (Based on Character Level)": [ + "dmg-fire/lvl", + "item_fire_damagemax_perlevel", + "itemfiredamagemaxperlevel" + ], + "{:d} to Maximum Lightning Damage": [ + "dmg-elem-max", + "itemelementaldamagemax", + "dmg-ltng/time", + "item_ltng_damagemax_bytime", + "itemltngdamagemaxbytime", + "itemlightningdamagemax", + "itemltngdamagemax", + "ltng-max", + "lightmaxdam" + ], + "{:d} to Maximum Lightning Damage (Based on Character Level)": [ + "dmg-ltng/lvl", + "item_ltng_damagemax_perlevel", + "itemltngdamagemaxperlevel" + ], + "{:d} to Maximum Poison Damage": [ + "dmg-pois/time", + "item_pois_damagemax_bytime", + "itempoisdamagemaxbytime", + "itempoisondamagemax", + "pois-max", + "poisonmaxdam" + ], + "{:d} to Maximum Poison Damage (Based on Character Level)": [ + "dmg-pois/lvl", + "item_pois_damagemax_perlevel", + "itempoisdamagemaxperlevel" + ], + "{:d} to Minimum Cold Damage": [ + "cold-min", + "coldmindam", + "dmg-elem-min", + "itemelementaldamagemin" + ], + "{:d} to Minimum Fire Damage": [ + "dmg-elem-min", + "itemelementaldamagemin", + "fire-min", + "firemindam" + ], + "{:d} to Minimum Lightning Damage": [ + "dmg-elem-min", + "itemelementaldamagemin", + "ltng-min", + "lightmindam" + ], + "{:d} to Minimum Poison Damage": [ + "pois-min", + "poisonmindam" + ], + "{:d} to Monster Defense Per Hit": [ + "dmg-ac", + "item_damagetargetac", + "itemdamagetargetac" + ], + "{:d} to Necromancer Skill Levels": [ + "nec", + "item_addclassskills", + "itemaddclassskills", + "itemaddnecromancerskills", + "necromancerskills" + ], + "{:d} to Paladin Skill Levels": [ + "pal", + "item_addclassskills", + "itemaddclassskills", + "itemaddpaladinskills", + "paladinskills" + ], + "{:d} to Sorceress Skill Levels": [ + "sor", + "item_addclassskills", + "itemaddclassskills", + "itemaddsorceressskills", + "sorceressskills" + ], + "{:d} to Strength": [ + "str", + "strength", + "str/time", + "item_strength_bytime", + "itemstrengthbytime" + ], + "{:d} to Strength (Based on Character Level)": [ + "str/lvl", + "item_strength_perlevel", + "itemstrengthperlevel" + ], + "{:d} to Vitality": [ + "vit", + "vitality", + "vit/time", + "item_vitality_bytime", + "itemvitalitybytime" + ], + "{:d} to Vitality (Based on Character Level)": [ + "vit/lvl", + "item_vitality_perlevel", + "itemvitalityperlevel" + ], + "{:d} to all Attributes": [ + "all-stats" + ], + "{:d} to {}": [ + "oskill", + "item_nonclassskill", + "itemnonclassskill" + ], + "{:d} to {} ({} only)": [ + "skill", + "item_singleskill", + "itemsingleskill", + "skills", + "skill-rand", + "skilltab", + "item_addskill_tab", + "itemaddskilltab" + ], + "{:d} to {} Skill Levels": [ + "randclassskill", + "item_addclassskills", + "itemaddclassskills" + ], + "{:d}% Better Chance of Getting Magic Items": [ + "mag%", + "item_magicbonus", + "itemmagicbonus", + "magicfind" + ], + "{:d}% Better Chance of Getting Magic Items (Based on Character Level)": [ + "mag%/lvl", + "item_find_magic_perlevel", + "itemfindmagicperlevel" + ], + "{:d}% Bonus to Attack Rating": [ + "att%", + "item_tohit_percent", + "itemtohitpercent", + "attackratingpercent" + ], + "{:d}% Bonus to Attack Rating (Based on Character Level)": [ + "att%/lvl", + "item_tohitpercent_perlevel", + "itemtohitpercentperlevel" + ], + "{:d}% Chance of Crushing Blow": [ + "crush", + "item_crushingblow", + "itemcrushingblow", + "crushingblow" + ], + "{:d}% Chance of Crushing Blow (Based on Character Level)": [ + "crush/lvl", + "item_crushingblow_perlevel", + "itemcrushingblowperlevel" + ], + "{:d}% Chance of Open Wounds": [ + "openwounds", + "item_openwounds", + "itemopenwounds" + ], + "{:d}% Chance of Open Wounds (Based on Character Level)": [ + "wounds/lvl", + "item_openwounds_perlevel", + "itemopenwoundsperlevel" + ], + "{:d}% Chance to cast level {:d} {} on attack": [ + "att-skill", + "item_skillonattack", + "itemskillonattack" + ], + "{:d}% Chance to cast level {:d} {} on striking": [ + "hit-skill", + "item_skillonhit", + "itemskillonhit", + "chancetocastonstrike" + ], + "{:d}% Chance to cast level {:d} {} when struck": [ + "gethit-skill", + "item_skillongethit", + "itemskillongethit", + "chancetocastwhenstruck" + ], + "{:d}% Chance to cast level {:d} {} when you Die": [ + "death-skill", + "item_skillondeath", + "itemskillondeath" + ], + "{:d}% Chance to cast level {:d} {} when you Kill an Enemy": [ + "kill-skill", + "item_skillonkill", + "itemskillonkill", + "chancetocastonkill" + ], + "{:d}% Chance to cast level {:d} {} when you Level-Up": [ + "levelup-skill", + "item_skillonlevelup", + "itemskillonlevelup", + "chancetocastonlevelup" + ], + "{:d}% Damage Taken Goes To Mana": [ + "dmg-to-mana", + "item_damagetomana", + "itemdamagetomana" + ], + "{:d}% Damage to Demons": [ + "dmg-demon", + "item_demondamage_percent", + "itemdemondamagepercent" + ], + "{:d}% Damage to Demons (Based on Character Level)": [ + "dmg-dem/lvl", + "item_damage_demon_perlevel", + "itemdamagedemonperlevel" + ], + "{:d}% Damage to Undead": [ + "dmg-undead", + "item_undeaddamage_percent", + "itemundeaddamagepercent" + ], + "{:d}% Damage to Undead (Based on Character Level)": [ + "dmg-und/lvl", + "item_damage_undead_perlevel", + "itemdamageundeadperlevel" + ], + "{:d}% Deadly Strike": [ + "deadly", + "item_deadlystrike", + "itemdeadlystrike", + "deadlystrike" + ], + "{:d}% Deadly Strike (Based on Character Level)": [ + "deadly/lvl", + "item_deadlystrike_perlevel", + "itemdeadlystrikeperlevel" + ], + "{:d}% Enhanced Defense": [ + "ac%", + "item_armor_percent", + "itemarmorpercent", + "enhanceddefense" + ], + "{:d}% Enhanced Defense (Based on Character Level)": [ + "ac%/lvl", + "item_armorpercent_perlevel", + "itemarmorpercentperlevel" + ], + "{:d}% Enhanced Maximum Damage (Based on Character Level)": [ + "dmg%/lvl", + "item_maxdamage_percent_perlevel", + "itemmaxdamagepercentperlevel" + ], + "{:d}% Enhanced damage": [ + "dmg%", + "enhanceddamage" + ], + "{:d}% Extra Gold from Monsters": [ + "gold%", + "item_goldbonus", + "itemgoldbonus", + "extragold", + "goldfind" + ], + "{:d}% Extra Gold from Monsters (Based on Character Level)": [ + "gold%/lvl", + "item_find_gold_perlevel", + "itemfindgoldperlevel" + ], + "{:d}% Faster Block Rate": [ + "block1", + "item_fasterblockrate", + "itemfasterblockrate", + "fbr", + "fasterblockrate", + "block2", + "block3" + ], + "{:d}% Faster Cast Rate": [ + "cast1", + "item_fastercastrate", + "itemfastercastrate", + "fcr", + "fastercastrate", + "cast2", + "cast3" + ], + "{:d}% Faster Hit Recovery": [ + "balance1", + "item_fastergethitrate", + "itemfastergethitrate", + "fhr", + "fasterhitrecovery", + "balance2", + "balance3" + ], + "{:d}% Faster Run/Walk": [ + "move1", + "item_fastermovevelocity", + "itemfastermovevelocity", + "frw", + "fasterrunwalk", + "move2", + "move3" + ], + "{:d}% Increased Attack Speed": [ + "swing1", + "item_fasterattackrate", + "itemfasterattackrate", + "ias", + "increasedattackspeed", + "attackspeed", + "swing2", + "swing3" + ], + "{:d}% Increased Chance of Blocking": [ + "block", + "toblock", + "chanceofblocking" + ], + "{:d}% Life stolen per hit": [ + "lifesteal", + "lifedrainmindam", + "lifeleech" + ], + "{:d}% Mana stolen per hit": [ + "manasteal", + "manadrainmindam", + "manaleech" + ], + "{:d}% Reanimate as: {}": [ + "reanimate", + "item_reanimate", + "itemreanimate" + ], + "{:d}% Slower Stamina Drain": [ + "stamdrain", + "item_staminadrainpct", + "itemstaminadrainpct" + ], + "{:d}% Target Defense": [ + "reduce-ac", + "item_fractionaltargetac", + "itemfractionaltargetac", + "targetdefense" + ], + "{:d}% to Cold Skill Damage": [ + "extra-cold", + "passive_cold_mastery", + "passivecoldmastery", + "coldskilldamage" + ], + "{:d}% to Enemy Cold Resistance": [ + "pierce-cold", + "passive_cold_pierce", + "passivecoldpierce" + ], + "{:d}% to Enemy Fire Resistance": [ + "pierce-fire", + "passive_fire_pierce", + "passivefirepierce" + ], + "{:d}% to Enemy Lightning Resistance": [ + "pierce-ltng", + "passive_ltng_pierce", + "passiveltngpierce" + ], + "{:d}% to Enemy Poison Resistance": [ + "pierce-pois", + "passive_pois_pierce", + "passivepoispierce" + ], + "{:d}% to Experience Gained": [ + "addxp", + "item_addexperience", + "itemaddexperience" + ], + "{:d}% to Fire Skill Damage": [ + "extra-fire", + "passive_fire_mastery", + "passivefiremastery", + "fireskilldamage" + ], + "{:d}% to Lightning Skill Damage": [ + "extra-ltng", + "passive_ltng_mastery", + "passiveltngmastery", + "lightningskilldamage" + ], + "{:d}% to Maximum Cold Resist": [ + "res-all-max", + "allresistmax", + "res-cold-max", + "maxcoldresist" + ], + "{:d}% to Maximum Fire Resist": [ + "res-all-max", + "allresistmax", + "res-fire-max", + "maxfireresist" + ], + "{:d}% to Maximum Lightning Resist": [ + "res-all-max", + "allresistmax", + "res-ltng-max", + "maxlightresist" + ], + "{:d}% to Maximum Magic Resist": [ + "res-mag-max", + "maxmagicresist" + ], + "{:d}% to Maximum Poison Resist": [ + "res-all-max", + "allresistmax", + "res-pois-max", + "maxpoisonresist" + ], + "{:d}% to Poison Skill Damage": [ + "extra-pois", + "passive_pois_mastery", + "passivepoismastery", + "poisonskilldamage" + ] +} \ No newline at end of file diff --git a/src/d2r_image/d2data_lookup.py b/src/d2r_image/d2data_lookup.py new file mode 100644 index 000000000..3c0a8432c --- /dev/null +++ b/src/d2r_image/d2data_lookup.py @@ -0,0 +1,286 @@ +import os +import sys +from parse import compile as compile_pattern +from d2r_image.data_models import ItemQuality +from d2r_image.d2data_data import ITEM_ARMOR, ITEM_MISC, ITEM_SET_ITEMS, ITEM_TYPES, ITEM_UNIQUE_ITEMS, ITEM_WEAPONS, REF_PATTERNS +from d2r_image.strings_store import base_items +from utils.misc import find_best_match +from logger import Logger + +item_lookup: dict = { + "armor": ITEM_ARMOR, + "weapons": ITEM_WEAPONS, + "set_items": ITEM_SET_ITEMS, + "unique_items": ITEM_UNIQUE_ITEMS, + "misc": ITEM_MISC, + "types": ITEM_TYPES, +} +item_lookup_by_display_name: dict = { + "armor": None, + "weapons": None, + "set_items": None, + "unique_items": None, + "misc": None, + "types": None, +} +item_lookup_by_quality_and_display_name: dict = {} +bases_by_name: dict = {} +consumables_by_name: dict = {} +gems_by_name: dict = {} +runes_by_name: dict ={} + +if getattr(sys, 'frozen', False): + application_path = os.path.dirname(sys.executable) +elif __file__: + application_path = os.path.dirname(__file__) + +d2data_path = os.path.join(application_path, 'd2data') + +def magic_name(name: str): + magic_names = [base_item_name for base_item_name in bases_by_name if base_item_name in name] + return find_best_match(name, magic_names).match + +def load_lookup(): + for key, val in item_lookup.items(): + # file_path = os.path.join(d2data_path, f'item_{key}.json') + # with open(file_path, "r",encoding = 'utf-8') as f: + # data = json.load(f) + # print(f"Loaded {len(data)} records from item_{key}.json") + # item_lookup[key] = data + item_lookup_by_display_name[key] = {value:val[value] for value in val.keys()} + for quality_key in ['set_items', 'unique_items']: + item_quality = ItemQuality.Set if quality_key == 'set_items' else ItemQuality.Unique + if item_quality.value not in item_lookup_by_quality_and_display_name: + item_lookup_by_quality_and_display_name[item_quality.value] = {} + for quality_item in item_lookup_by_display_name[quality_key]: + item_lookup_by_quality_and_display_name[item_quality.value][quality_item.upper()] = item_lookup_by_display_name[quality_key][quality_item] + for quality_key in ['armor', 'weapons']: + for quality_item in item_lookup_by_display_name[quality_key]: + bases_by_name[quality_item.upper().replace(' ', '')] = item_lookup_by_display_name[quality_key][quality_item] + for extra_base in [ + 'amulet', + 'ring', + 'grandcharm', + 'largecharm', + 'smallcharm', + 'jewel', + 'tomeofidentify', + 'tomeoftownportal', + 'keyofterror', + 'keyofhate', + 'keyofdestruction', + 'twistedessenceofsuffering', + 'burningessenceofterror', + 'chargedessenceofhatred', + 'festeringessenceofdestruction' + ]: + bases_by_name[extra_base.upper()] = item_lookup_by_display_name['misc'][extra_base] + for consumable in [ + 'key', + 'scrollofidentify', 'scrolloftownportal', + 'arrows', 'bolts', + 'antidotepotion', 'thawingpotion', 'staminapotion', + #'Fulminatingpotion', 'Explodingpotion', 'Oilpotion', 'stranglinggaspotion', 'Chokinggaspotion', 'rancidgaspotion', + 'minorhealingpotion', 'lighthealingpotion', 'healingpotion', 'greaterhealingpotion', 'superhealingpotion', + 'minormanapotion', 'lightmanapotion', 'manapotion', 'greatermanapotion', 'supermanapotion', + 'rejuvenationpotion', 'fullrejuvenationpotion', + 'gold' + ]: + consumables_by_name[consumable.upper().replace(' ', '')] = item_lookup_by_display_name['misc'][consumable] + for gem in [ + 'chippedruby', 'flawedruby', 'ruby', 'flawlessruby', 'perfectruby', + 'chippedsapphire', 'flawedsapphire', 'sapphire', 'flawlesssapphire', 'perfectsapphire', + 'chippedtopaz', 'flawedtopaz', 'topaz', 'flawlesstopaz', 'perfecttopaz', + 'chippedemerald', 'flawedemerald', 'emerald', 'flawlessemerald', 'perfectemerald', + 'chippeddiamond', 'flaweddiamond', 'diamond', 'flawlessdiamond', 'perfectdiamond', + 'chippedamethyst', 'flawedamethyst', 'amethyst', 'flawlessamethyst', 'perfectamethyst', + 'chippedskull', 'flawedskull', 'skull', 'flawlessskull', 'perfectskull' + ]: + gems_by_name[gem.upper().replace(' ', '')] = item_lookup_by_display_name['misc'][gem] + for misc_item in item_lookup_by_display_name['misc']: + if 'rune' in misc_item: + runes_by_name[misc_item.upper().replace(' ', '')] = item_lookup_by_display_name['misc'][misc_item] + pass + +def load_parsers(): + for key, value in REF_PATTERNS.items(): + REF_PATTERNS[key] = { + "compiled_pattern": compile_pattern(key), + "identifiers": value + } + +def find_set_or_unique_item_by_name(name, quality: ItemQuality, fuzzy = False): + if quality.value == ItemQuality.Unique.value: + return find_unique_item_by_name(name, fuzzy) + elif quality.value == ItemQuality.Set.value: + return find_set_item_by_name(name, fuzzy) + return None + +def find_unique_item_by_name(name, fuzzy=False): + quality = ItemQuality.Unique.value + normalized_name = normalize_name(name) + if not fuzzy: + if normalized_name in item_lookup_by_quality_and_display_name[quality]: + return item_lookup_by_quality_and_display_name[quality][normalized_name] + else: + best_match = find_best_match(normalized_name, item_lookup_by_quality_and_display_name[quality].keys()).match + return item_lookup_by_quality_and_display_name[quality][best_match] + +def find_set_item_by_name(name, fuzzy=False): + quality = ItemQuality.Set.value + normalized_name = normalize_name(name) + if not fuzzy: + if normalized_name in item_lookup_by_quality_and_display_name[quality]: + return item_lookup_by_quality_and_display_name[quality][normalized_name] + else: + best_match = find_best_match(normalized_name, item_lookup_by_quality_and_display_name[quality].keys()).match + return item_lookup_by_quality_and_display_name[quality][best_match] + +def fuzzy_base_item_match(item_name: str, normalized_threshold: float = 0.7): + if not item_name in base_items(): + fuzzy_res = find_best_match(item_name, list(base_items())) + if fuzzy_res.match != item_name: + if fuzzy_res.score_normalized > normalized_threshold and fuzzy_res.match in base_items(): + Logger.debug(f"fuzzy_base_item_match: change {item_name} -> {fuzzy_res.match} (similarity: {fuzzy_res.score_normalized*100:.1f}%)") + return fuzzy_res.match + else: + # Logger.debug(f"fuzzy_base_item_match: proposed {item_name} -> {fuzzy_res.match} (similarity: {fuzzy_res.score_normalized*100:.1f}%) doesn't meet threshold of {normalized_threshold*100:.1f}% or doesn't exist in base items, ignore.") + pass + return item_name + +def find_base_item_from_magic_item_text(magic_item_text, item_is_identified): + base_item_str = None + magic_item_text = magic_item_text.strip() + if item_is_identified: + # strip suffix + of_index = magic_item_text.find(" OF ") + if of_index > 0: + words = magic_item_text[:of_index].split() + else: + words = magic_item_text.split() + # iterate through item name by sequentially stripping first word and checking for existence in item bases + for i in range(len(words)): + temp_name = ' '.join(words[i:]).strip() + if temp_name in base_items(): + base_item_str = temp_name + break + # failed to find, now try with string correction + if not base_item_str: + for i in range(len(words)): + temp_name = ' '.join(words[i:]).strip() + if (res := fuzzy_base_item_match(temp_name)) != temp_name: + base_item_str = res + break + else: + if magic_item_text in base_items(): + base_item_str = magic_item_text + elif (res := fuzzy_base_item_match(magic_item_text)) != magic_item_text: + base_item_str = res + + if not base_item_str: + Logger.warning(f"Could not find base item for {magic_item_text}, {item_is_identified}") + return None + return get_base(base_item_str) + + +def magic_item_is_identified(magic_item_name): + magic_item_name = magic_item_name.upper().replace("-", "").replace("'", "").replace(" ", "") + for base_by_name in bases_by_name: + if magic_item_name.upper() == base_by_name: + return False + return True + +def is_base(name: str) -> bool: + return normalize_name(name) in bases_by_name + +def get_base(name): + if normalize_name(name) in bases_by_name: + return bases_by_name[normalize_name(name)] + return None + +def is_consumable(name: str): + return normalize_name(name) in consumables_by_name + +def get_consumable(name: str): + if normalize_name(name) in consumables_by_name: + return consumables_by_name[normalize_name(name)] + return None + +def is_gem(name: str): + return normalize_name(name) in gems_by_name + +def get_gem(name: str): + if normalize_name(name) in gems_by_name: + return gems_by_name[normalize_name(name)] + return None + +def is_rune(name: str): + return normalize_name(name) in runes_by_name + +def get_rune(name: str): + if normalize_name(name) in runes_by_name: + return runes_by_name[normalize_name(name)] + return None + +def get_by_name(name: str, _call_count=1): + """ + Returns the item with the given name, if the item is not found, then recall the function with the hopefully corrected name. + """ + normalized_name = normalize_name(name) + if is_base(normalized_name): + return get_base(normalized_name) + elif is_consumable(normalized_name): + return get_consumable(normalized_name) + elif is_gem(normalized_name): + return get_gem(normalized_name) + elif is_rune(normalized_name): + return get_rune(normalized_name) + else: + if _call_count == 2: + raise Exception("Could not find item with name: " + name) + return get_by_name(correct_name(name), _call_count=2) + +def find_pattern_match(text): + match = None + for _, pattern in REF_PATTERNS.items(): + result = pattern["compiled_pattern"].parse(text) + if result: + # If the captured data points is an array of one thing, flatten in. + data_points = result.fixed + if type(data_points) == tuple and len(data_points) == 1: + data_points = data_points[0] + match = { + "property_id": pattern["identifiers"][0], + "property_values": data_points + } + break + return match + +def find_modifier_pattern_match(modifier_line): + match = None + for _, pattern in REF_PATTERNS.items(): + result = pattern["compiled_pattern"].parse(modifier_line) + if result: + data_points = result.fixed + if type(data_points) == tuple and len(data_points) == 1: + data_points = data_points[0] + match = { + "property_id": pattern["identifiers"][0], + "property_values": data_points + } + break + return match + + +def normalize_name(name: str): + return name.replace(' ', '').replace('\'', '').replace('-', '').upper() + + + +def correct_name(name: str): + items = bases_by_name | consumables_by_name | gems_by_name | runes_by_name + return find_best_match(name, items).match + + +load_lookup() +load_parsers() \ No newline at end of file diff --git a/src/d2r_image/d2data_ref_lookup.py b/src/d2r_image/d2data_ref_lookup.py new file mode 100644 index 000000000..c595e9c9b --- /dev/null +++ b/src/d2r_image/d2data_ref_lookup.py @@ -0,0 +1,119 @@ +CONSUMABLES = { + 'MINOR HEALING POTION': ['MINOR_HEALING_POTION', 'BELT_MINOR_HEALING_POTION'], + 'LIGHT HEALING POTION': ['LIGHT_HEALING_POTION', 'BELT_LIGHT_HEALING_POTION'], + 'HEALING POTION': ['HEALING_POTION', 'BELT_HEALING_POTION'], + 'GREATER HEALING POTION': ['GREATER_HEALING_POTION', 'BELT_GREATER_HEALING_POTION'], + 'SUPER HEALING POTION': ['SUPER_HEALING_POTION', 'BELT_SUPER_HEALING_POTION'], + # + 'MINOR MANA POTION': ['MINOR_MANA_POTION', 'BELT_MINOR_MANA_POTION'], + 'LIGHT MANA POTION': ['LIGHT_MANA_POTION', 'BELT_LIGHT_MANA_POTION'], + 'MANA POTION': ['MANA_POTION', 'BELT_MANA_POTION'], + 'GREATER MANA POTION': ['GREATER_MANA_POTION', 'BELT_GREATER_MANA_POTION'], + 'SUPER MANA POTION': ['SUPER_MANA_POTION', 'BELT_SUPER_MANA_POTION'], + # + 'REJUVENATION POTION': ['REJUV_POTION', 'BELT_REJUV_POTION'], + 'FULL REJUVENATION POTION': ['FULL_REJUV_POTION', 'BELT_FULL_REJUV_POTION'], + # + 'ANTIDOTE POTION': ['ANTIDOTE_POTION', 'BELT_ANTIDOTE_POTION'], + 'STAMINA POTION': ['STAMINA_POTION', 'BELT_STAMINA_POTION'], + 'THAWING POTION': ['THAWING_POTION', 'BELT_THAWING_POTION'], + # + 'SCROLL OF IDENTIFY': ['ID_SCROLL', 'BELT_ID_SCROLL'], + 'SCROLL OF TOWN PORTAL': ['TP_SCROLL', 'BELT_TP_SCROLL'], + # + 'KEY': ['KEY'], + # + 'ARROWS': ['ARROWS'], + 'BOLTS': ['BOLTS'], +} + +EMPTY_BELT_SLOT = {'EMPTY BELT SLOT': ['BELT_EMPTY_SLOT']} + +CHARMS = { + 'GRAND CHARM': ['GC1', 'GC2'], + 'SMALL CHARM': ['SC1', 'SC2', 'SC3'] +} + +GEMS = { + 'CHIPPED AMETHYST': ['CHIPPED_AMETHYST'], + 'FLAWED AMETHYST': ['FLAWED_AMETHYST'], + 'AMETHYST': ['AMETHYST'], + 'FLAWLESS AMETHYST': ['FLAWLESS_AMETHYST'], + 'PERFECT AMETHYST': ['PERFECT_AMETHYST'], + # + 'CHIPPED TOPAZ': ['CHIPPED_TOPAZ'], + 'FLAWED TOPAZ': ['FLAWED_TOPAZ'], + 'TOPAZ': ['TOPAZ'], + 'FLAWLESS TOPAZ': ['FLAWLESS_TOPAZ'], + 'PERFECT TOPAZ': ['PERFECT_TOPAZ'], + # + 'CHIPPED DIAMOND': ['CHIPPED_DIAMOND'], + 'FLAWED DIAMOND': ['FLAWED_DIAMOND'], + 'DIAMOND': ['DIAMOND'], + 'FLAWLESS DIAMOND': ['FLAWLESS_DIAMOND'], + 'PERFECT DIAMOND': ['PERFECT_DIAMOND'], + # + 'CHIPPED EMERALD': ['CHIPPED_EMERALD'], + 'FLAWED EMERALD': ['FLAWED_EMERALD'], + 'EMERALD': ['EMERALD'], + 'FLAWLESS EMERALD': ['FLAWLESS_EMERALD'], + 'PERFECT EMERALD': ['PERFECT_EMERALD'], + # + 'CHIPPED RUBY': ['CHIPPED_RUBY'], + 'FLAWED RUBY': ['FLAWED_RUBY'], + 'RUBY': ['RUBY'], + 'FLAWLESS RUBY': ['FLAWLESS_RUBY'], + 'PERFECT RUBY': ['PERFECT_RUBY'], + # + 'CHIPPED SAPPHIRE': ['CHIPPED_SAPPHIRE'], + 'FLAWED SAPPHIRE': ['FLAWED_SAPPHIRE'], + 'SAPPHIRE': ['SAPPHIRE'], + 'FLAWLESS SAPPHIRE': ['FLAWLESS_SAPPHIRE'], + 'PERFECT SAPPHIRE': ['PERFECT_SAPPHIRE'], + # + 'CHIPPED SKULL': ['CHIPPED_SKULL'], + 'FLAWED SKULL': ['FLAWED_SKULL'], + 'SKULL': ['SKULL'], + 'FLAWLESS SKULL': ['FLAWLESS_SKULL'], + 'PERFECT SKULL': ['PERFECT_SKULL'], +} + +RUNES = { + 'EL RUNE': ['EL'], + 'ELD RUNE': ['ELD'], + 'TIR RUNE': ['TIR'], + 'NEF RUNE': ['NEF'], + 'ETH RUNE': ['ETH'], + 'ITH RUNE': ['ITH'], + 'TAL RUNE': ['TAL'], + 'RAL RUNE': ['RAL'], + 'ORT RUNE': ['ORT'], + 'THUL RUNE': ['THUL'], + 'AMN RUNE': ['AMN'], + 'SOL RUNE': ['SOL'], + 'SHAEL RUNE': ['SHAEL'], + 'DOL RUNE': ['DOL'], + 'HEL RUNE': ['HEL'], + 'IO RUNE': ['IO'], + 'LUM RUNE': ['LUM'], + 'KO RUNE': ['KO'], + 'FAL RUNE': ['FAL'], + 'LEM RUNE': ['LEM'], + 'PUL RUNE': ['PUL'], + 'UM RUNE': ['UM'], + 'MAL RUNE': ['MAL'], + 'IST RUNE': ['IST'], + 'GUL RUNE': ['GUL'], + 'VEX RUNE': ['VEX'], + 'OHM RUNE': ['OHM'], + 'LO RUNE': ['LO'], + 'SUR RUNE': ['SUR'], + 'BER RUNE': ['BER'], + 'JAH RUNE': ['JAH'], + 'CHAM RUNE': ['CHAM'], + 'ZOD RUNE': ['ZOD'], +} + +LEFT_INVENTORY_MAP = {**CONSUMABLES, **CHARMS, **GEMS, **RUNES} +RIGHT_INVENTORY_MAP = {**CONSUMABLES, **CHARMS, **GEMS, **RUNES} +BELT_MAP = {**CONSUMABLES, **EMPTY_BELT_SLOT} \ No newline at end of file diff --git a/src/d2r_image/data_models.py b/src/d2r_image/data_models.py new file mode 100644 index 000000000..9adf2ea8a --- /dev/null +++ b/src/d2r_image/data_models.py @@ -0,0 +1,226 @@ +from enum import Enum +import numpy as np +import dataclasses +from dataclasses import dataclass +from dataclasses_json import dataclass_json +import json + +class EnhancedJSONEncoder(json.JSONEncoder): + def default(self, o): + if dataclasses.is_dataclass(o): + return dataclasses.asdict(o) + return super().default(o) + +@dataclass +class OcrResult: + text: str = None + original_text: str = None + #processed_img: np.ndarray = None + word_confidences: list = None + mean_confidence: float = None + + def __getitem__(self, key): + return super().__getattribute__(key) + +@dataclass +class ItemQuality(Enum): + Gray = 'gray' + Normal = 'normal' + Magic = 'magic' + Rare = 'rare' + Set = 'set' + Unique = 'unique' + Crafted = 'crafted' + Rune = 'rune' + Runeword = 'runeword' + Orange = 'orange' + Superior = 'superior' + LowQuality = 'lowquality' + Cracked = 'lowquality' + Crude = 'lowquality' + Damaged = 'lowquality' + + +@dataclass +class ItemText: + color: str = None + quality: ItemQuality = None + roi: list[int] = None + img: np.ndarray = None + clean_img: np.ndarray = None + ocr_result: OcrResult = None + + def __getitem__(self, key): + return super().__getattribute__(key) + + +@dataclass +class ItemQualityKeyword(Enum): + LowQuality = 'LOW QUALITY' + Cracked = 'CRACKED' + Crude = 'CRUDE' + Damaged = 'DAMAGED' + Superior = 'SUPERIOR' + + +@dataclass_json +@dataclass +class D2Item: + boundingBox: dict + name: str + color: str | None + quality: str | None + type: str | None + identified: bool + amount: int | None + baseItem: dict | None + item: dict | None + uniqueItems: list[dict] | None + setItems: list[dict] | None + itemModifiers: dict | None + + def __eq__(self, other): + if self and not other: + return False + return self.boundingBox == other.boundingBox and\ + self.name == other.name and\ + self.color == other.color and\ + self.type == other.type and\ + self.identified == other.identified and\ + self.amount == other.amount and\ + self.baseItem == other.baseItem and\ + self.item == other.item and\ + self.uniqueItems == other.uniqueItems and\ + self.setItems == other.setItems and\ + self.itemModifiers == other.itemModifiers + + +@dataclass_json +@dataclass +class D2Data: + BaseItem: dict + Item: dict | None + ItemModifiers: dict | None + + def __eq__(self, other): + if self and not other: + return False + return self.to_json() == other.to_json() + + +@dataclass_json +@dataclass +class GroundItem: + BoundingBox: dict = None + BoundingBoxMonitor: dict = None + Center: list[int] = None + CenterMonitor: list[int] = None + Distance: int = None + Name: str = None + Color: str = None + Quality: str = None + Text: str = None + Amount: int | None = None + BaseItem: dict = None + Item: dict | None = None + NTIPAliasType: list[str] = None + NTIPAliasClassID: int = None + NTIPAliasClass: int | None = None + NTIPAliasQuality: int = None + NTIPAliasFlag: dict = None + ID: str = "" + UID: str = "" + + def __eq__(self, other): + if self and not other: + return False + return self.to_json() == other.to_json() + + def __getitem__(self, key): + return super().__getattribute__(key) + + def as_dict(self): + return { + "Name": self.Name, + "Color": self.Color, + "Quality": self.Quality, + "Text": self.Text, + "Amount": self.Amount, + "BaseItem": self.BaseItem, + "Item": self.Item, + "NTIPAliasType": self.NTIPAliasType, + "NTIPAliasClassID": self.NTIPAliasClassID, + "NTIPAliasClass": self.NTIPAliasClass, + "NTIPAliasQuality": self.NTIPAliasQuality, + "NTIPAliasFlag": self.NTIPAliasFlag + } + +@dataclass_json +@dataclass +class GroundItemList: + items: list[GroundItem | None] + + +@dataclass_json +@dataclass +class HoveredItem: + Name: str + Quality: str + Text: str + BaseItem: dict + Item: dict | None + NTIPAliasIdName: str + NTIPAliasType: list[str] + NTIPAliasClassID: int + NTIPAliasClass: int | None + NTIPAliasQuality: int + NTIPAliasStat: dict + NTIPAliasFlag: dict + + def __eq__(self, other): + if self and not other: + return False + return self.to_json() == other.to_json() + + def as_dict(self): + return { + 'Name': self.Name, + 'Quality': self.Quality, + 'Text': self.Text, + 'BaseItem': self.BaseItem, + 'Item': self.Item, + "NTIPAliasIdName": self.NTIPAliasIdName, + 'NTIPAliasType': self.NTIPAliasType, + 'NTIPAliasClassID': self.NTIPAliasClassID, + 'NTIPAliasClass': self.NTIPAliasClass, + 'NTIPAliasQuality': self.NTIPAliasQuality, + 'NTIPAliasStat': self.NTIPAliasStat, + 'NTIPAliasFlag': self.NTIPAliasFlag, + } + + +@dataclass_json +@dataclass +class InventoryItem: + boundingBox: dict + type: str | None + item: dict | None + baseItems: list[dict] | None + uniqueItems: list[dict] | None + setItems: list[dict] | None + + def __eq__(self, other): + if self and not other: + return False + return self.boundingBox == other.boundingBox and\ + self.type == other.type and\ + self.item == other.item and\ + self.baseItems == other.baseItems and\ + self.uniqueItems == other.uniqueItems and\ + self.setItems == other.setItems + + +@dataclass_json +@dataclass +class D2ItemList: + items: list[D2Item | None] \ No newline at end of file diff --git a/src/d2r_image/demo.py b/src/d2r_image/demo.py new file mode 100644 index 000000000..7b0c6d6bc --- /dev/null +++ b/src/d2r_image/demo.py @@ -0,0 +1,174 @@ +from copy import deepcopy +from email.mime import base +import time +import cv2 +import keyboard +import os +import json +import screen +from utils.misc import cut_roi, slugify +from utils import download_test_assets + +import d2r_image.processing as processing +from d2r_image.processing import get_hovered_item +from d2r_image.processing_helpers import clean_img, crop_text_clusters +from d2r_image.data_models import ItemQuality, ItemQualityKeyword, ItemText, EnhancedJSONEncoder + +screen.set_window_position(0, 0) + + + +debug_line_map = {} +debug_line_map[ItemQualityKeyword.LowQuality.value] = (123, 123, 123) +debug_line_map[ItemQualityKeyword.Cracked.value] = (123, 123, 123) +debug_line_map[ItemQualityKeyword.Crude.value] = (123, 123, 123) +debug_line_map[ItemQualityKeyword.Superior.value] = (208, 208, 208) +debug_line_map[ItemQuality.Gray.value] = (123, 123, 123) +debug_line_map[ItemQuality.Normal.value] = (208, 208, 208) +debug_line_map[ItemQuality.Magic.value] = (178, 95, 95) +debug_line_map[ItemQuality.Rare.value] = (107, 214, 214) +debug_line_map[ItemQuality.Set.value] = (0, 238, 0) +debug_line_map[ItemQuality.Unique.value] = (126, 170, 184) +debug_line_map[ItemQuality.Crafted.value] = (0, 160, 219) +debug_line_map[ItemQuality.Rune.value] = (0, 160, 219) +debug_line_map[ItemQuality.Runeword.value] = (126, 170, 184) + +gen_truth = False + +def get_ground_loot(): + print('Loading demo ground images. This may take a few seconds...\n') + all_image_data = [] + all_images = [] + total_elapsed_time = 0 + demo_image_count = 0 + resource_paths = ['ground_loot'] + for resource_path in resource_paths: + base_dir = f'test/assets/{resource_path}' + for image_name in os.listdir(base_dir): + if not image_name.lower().endswith('.png'): + continue + image_data = cv2.imread(f"{base_dir}/{image_name}") + image = deepcopy(image_data) + start = time.time() + ground_loot_list = processing.get_ground_loot(image_data) + end = time.time() + elapsed = round(end-start, 2) + print(f'Processed {image_name} in {elapsed} seconds') + total_elapsed_time += elapsed + if ground_loot_list.items: + draw_items_on_image_data(ground_loot_list.items, image_data) + if gen_truth: + gen_truth_from_ground_loot(ground_loot_list.items, image) + filename_base=image_name[:-4] + cv2.imwrite(f"log/screenshots/info/{filename_base}.png", image_data) + with open(f"log/screenshots/info/{filename_base}.json", 'w', encoding='utf-8') as f: + json.dump(ground_loot_list, f, ensure_ascii=False, sort_keys=False, cls=EnhancedJSONEncoder, indent=2) + all_image_data.append(image_data) + all_images.append(image) + demo_image_count += 1 + # print('\n') + print(f'Processing all {demo_image_count} image(s) took {round(total_elapsed_time, 2)} ({round(total_elapsed_time / demo_image_count, 2)} avg)') + for image in all_image_data: + cv2.imshow('D2R Image Demo', image) + cv2.waitKey() + cv2.destroyAllWindows() + keyboard.add_hotkey('f12', lambda: os._exit(1)) + print('Press f12 to quit') + +def get_hovered_items(): + if gen_truth: + os.makedirs("log/screenshots/generated", exist_ok=True) + os.system(f"cd log/screenshots/generated && mkdir ground-truth") + print('Loading demo hover images. This may take a few seconds...\n') + all_image_data = [] + all_images = [] + total_elapsed_time = 0 + demo_image_count = 0 + resource_paths = ['hovered_items'] + for resource_path in resource_paths: + base_dir = f'test/assets/{resource_path}' + files = os.listdir(base_dir) + for cnt, image_name in enumerate(files): + if not image_name.lower().endswith('.png'): + continue + image_data = cv2.imread(f"{base_dir}/{image_name}") + image = deepcopy(image_data) + start = time.time() + item, res = processing.get_hovered_item(image) + end = time.time() + elapsed = round(end-start, 2) + total_elapsed_time += elapsed + if res.roi is not None: + x, y, w, h = res.roi + cv2.rectangle(image_data, (x, y), (x+w, y+h), (0, 255, 0), 1) + print(f'Processed {image_name} {cnt+1}/{len(files)} in {elapsed} seconds') + if gen_truth: + gen_truth_from_hovered_item(cut_roi(image, res.roi)) + else: + print(f'Failed: {image_name} {cnt+1}/{len(files)}') + if item and item.BaseItem: + filename_base=image_name[:-4] + cv2.imwrite(f"log/screenshots/info/{filename_base}.png", image_data) + with open(f"log/screenshots/info/{filename_base}.json", 'w', encoding='utf-8') as f: + json.dump(item, f, ensure_ascii=False, sort_keys=False, cls=EnhancedJSONEncoder, indent=2) + all_image_data.append(image_data) + all_images.append(image) + demo_image_count += 1 + print(f'Processing all {demo_image_count} image(s) took {round(total_elapsed_time, 2)} ({round(total_elapsed_time / demo_image_count, 2)} avg)') + for image in all_image_data: + cv2.imshow('D2R Image Demo', image) + cv2.waitKey() + cv2.destroyAllWindows() + keyboard.add_hotkey('f12', lambda: os._exit(1)) + print('Press f12 to quit') + +def draw_items_on_image_data(items, image): + for item in items: + x, y, w, h = item.BoundingBox.values() + cv2.rectangle( + image, + (x, y), + (x + w, y + h), + debug_line_map[item.Quality], + 1 + ) + +def gen_truth_from_ground_loot(items, image): + + image = clean_img(image) + for item in items: + x, y, w, h = item.BoundingBox.values() + item_drop = cut_roi(image, [x, y, w, h]) + item_drop = clean_img(item_drop) + item_slug = slugify({f"{item.Name} {item.Quality}"}) + filename = f"log/screenshots/pickit/ocr_{item_slug}" + with open(f"{filename}.gt.txt", 'w') as f: + f.write(item.Text.rstrip()) + cv2.imwrite(f"{filename}.png", item_drop) + +def gen_truth_from_hovered_item(tooltip_img): + contours = crop_text_clusters(tooltip_img, 5) + for contour in contours: + contour : ItemText + basename = f"log/screenshots/generated/ground-truth/{slugify(contour.ocr_result.text)}_{contour.color}" + if os.path.exists(f"{basename}.png"): + print(f"{basename} already exists, skip") + continue + cv2.imshow(basename, contour.clean_img) + cv2.waitKey(1) + print(f"new template: {contour.ocr_result.text}") + print(f"Enter 'a' to accept or enter true text:") + truth = input() + if truth: + if truth == "a": + string_to_write = contour.ocr_result.text.upper() + else: + string_to_write = truth.upper() + with open(f"{basename}.gt.txt", 'w') as f: + f.write(string_to_write) + cv2.imwrite(f"{basename}.png", contour.clean_img) + cv2.waitKey(1) + print(f"saved {basename}") + else: + print(f"skipped {basename}") + cv2.destroyAllWindows() \ No newline at end of file diff --git a/src/d2r_image/nip_lookup.py b/src/d2r_image/nip_lookup.py new file mode 100644 index 000000000..e072c9c5a --- /dev/null +++ b/src/d2r_image/nip_lookup.py @@ -0,0 +1,19 @@ +import re +from urllib import request + + +NTIP_ALIAS_CLASS_ID_BY_BASE = {} +NTIP_TYPE_ID_BY_TYPE = {} + +class_id_regex = re.compile(r'NTIPAliasClassID\[\"([0-9a-zA-Z\']+)\"\] = ([0-9]+)') +type_id_regex = re.compile(r'NTIPAliasType\[\"([0-9a-zA-Z\']+)\"\] = ([0-9]+)') +# data = request.urlopen(url='https://raw.githubusercontent.com/blizzhackers/kolbot/master/d2bs/kolbot/libs/NTItemAlias.dbl').read().decode('utf-8') +data = open("assets/NTItemAlias.dbl", "r").read() +result = class_id_regex.findall(data) +if result: + for class_id in result: + NTIP_ALIAS_CLASS_ID_BY_BASE[class_id[0]] = class_id[1] +result = type_id_regex.findall(data) +if result: + for type_id in result: + NTIP_TYPE_ID_BY_TYPE[type_id[0]] = type_id[1] \ No newline at end of file diff --git a/src/d2r_image/ocr.py b/src/d2r_image/ocr.py new file mode 100644 index 000000000..580184fb2 --- /dev/null +++ b/src/d2r_image/ocr.py @@ -0,0 +1,302 @@ +from tesserocr import PyTessBaseAPI, OEM +import numpy as np +import cv2 +from utils.misc import erode_to_black, find_best_match +from d2r_image.data_models import OcrResult +from d2r_image.ocr_data import ERROR_RESOLUTION_MAP, I_1, II_U, ONE_I, ONEONE_U +from d2r_image.strings_store import all_words +from logger import Logger + +def image_to_text( + images: np.ndarray | list[np.ndarray], + model: str = "hover-eng_inconsolata_inv_th_fast", + psm: int = 3, + word_list: str = "assets/word_lists/all_words.txt", + scale: float = 1.0, + crop_pad: bool = True, + erode: bool = False, + invert: bool = True, + threshold: int = 25, + digits_only: bool = False, + fix_regexps: bool = True, + check_known_errors: bool = True, + correct_words: bool = True, +) -> list[OcrResult]: + """ + Uses Tesseract to read image(s) + :param images (required): image or list of images to read in OpenCV format. + Use a list of images rather than looping over single images where possible for best performance. + :param model: OCR language model basename to use (in assets/tessdata folder) + :param psm: Tesseract PSM to use. 7=single uniform text line, 6=single block of text, 3=auto without orientation. + See https://www.pyimagesearch.com/2021/11/15/tesseract-page-segmentation-modes-psms-explained-how-to-improve-your-ocr-accuracy/ + :param word_list: predefined wordlist to use. Tesseract will use these to help with recognition + :param scale: scales input image, sometimes necessary for smaller text (but doesn't always improve accuracy). Engd2r_inv_th trained on ~1.6x scaled assets. + :param crop_pad: crop the outer part and then re-pad image. Intended for item drops. + :param erode: use erosion function to erode image to black borders (i.e. for item drops) + :param invert: invert and threshold the input image(s) + :param threshold: apply threshold to image (ex. 25 would threshold around V=25). Set to 0 to not threshold image. + :param digits_only: only look for digits + :param fix_regexps: use regex for various cases of common errors (I <-> 1, etc.) + :param check_known_errors: check for predefined common errors and replace + :param correct_words: check dictionary of words and match closest match + :return: Returns an OcrResult object + """ + if type(images) == np.ndarray: + images = [images] + results = [] + + with PyTessBaseAPI(psm=psm, oem=OEM.LSTM_ONLY, path=f"assets/tessdata", lang=model ) as api: + api.ReadConfigFile("assets/tessdata/ocr_config.txt") + if word_list: + api.SetVariable("user_words_file", word_list) + #api.SetSourceResolution(72 * scale) + for image in images: + processed_img = image + if scale: + processed_img = cv2.resize( + processed_img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR) + if erode: + processed_img = erode_to_black(processed_img) + if crop_pad: + processed_img = _crop_pad(processed_img) + image_is_binary = (image.shape[2] if len( + image.shape) == 3 else 1) == 1 and image.dtype == bool + if not image_is_binary and threshold: + processed_img = cv2.cvtColor(processed_img, cv2.COLOR_BGR2GRAY) + processed_img = cv2.threshold( + processed_img, threshold, 255, cv2.THRESH_BINARY)[1] + if invert: + if threshold or image_is_binary: + processed_img = cv2.bitwise_not(processed_img) + else: + processed_img = ~processed_img + api.SetImageBytes(*_img_to_bytes(processed_img)) + if digits_only: + api.SetVariable("tessedit_char_blacklist", + ".,!?@#$%&*()<>_-+=/:;'\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") + api.SetVariable("tessedit_char_whitelist", "0123456789") + api.SetVariable("classify_bln_numeric_mode", "1") + original_text = api.GetUTF8Text() + text = original_text + # replace newlines if image is a single line + if psm in (7, 8, 13): + text = text.replace('\n', '') + word_confidences = api.AllWordConfidences() + if fix_regexps: + text = _fix_regexps(text) + if check_known_errors: + text = _check_known_errors(text) + if correct_words: + text = _ocr_result_dictionary_check(text, word_confidences) + results.append(OcrResult( + original_text=original_text, + text=text, + #processed_img=processed_img, + word_confidences=word_confidences, + mean_confidence=api.MeanTextConf() + )) + return results + + +def _crop_pad(image: np.ndarray = None): + # crop + image = image[4: image.shape[0]-4, 5: image.shape[1]-5] + # re-pad + image = np.pad(image, pad_width=[(4, 4), (4, 4), (0, 0)], mode='constant') + return image + + +def _img_to_bytes(image: np.ndarray, colorspace: str = 'BGR'): + # Sets an OpenCV-style image for recognition: https://github.com/sirfz/tesserocr/issues/198 + bytes_per_pixel = image.shape[2] if len(image.shape) == 3 else 1 + height, width = image.shape[:2] + bytes_per_line = bytes_per_pixel * width + if bytes_per_pixel != 1 and colorspace != 'RGB': + # non-RGB color image -> convert to RGB + image = cv2.cvtColor(image, getattr(cv2, f'COLOR_{colorspace}2RGB')) + elif bytes_per_pixel == 1 and image.dtype == bool: + # binary image -> convert to bitstream + image = np.packbits(image, axis=1) + bytes_per_line = image.shape[1] + width = bytes_per_line * 8 + bytes_per_pixel = 0 + # else image already RGB or grayscale + return image.tobytes(), width, height, bytes_per_pixel, bytes_per_line + + +def _fix_regexps(ocr_output: str, repeat_count: int = 0) -> str: + # case: two 1's within a string; e.g., "SIIPER MANA POTION" + try: + text = II_U.sub('U', ocr_output) + except: + # logging.error(f"Error _II_ -> _U_ on {ocr_output}") + text = ocr_output + # case: two 1's within a string; e.g., "S11PER MANA POTION" + try: + text = ONEONE_U.sub('U', text) + except: + # logging.error(f"Error _11_ -> _U_ on {ocr_output}") + pass + # case: an I within a number or by a sign; e.g., "+32I to mana attack rating" + try: + text = I_1.sub('1', text) + except: + # logging.error(f"Error I -> 1 on {ocr_output}") + pass + # case: a 1 within a string; e.g., "W1RT'S LEG" + try: + text = ONE_I.sub('I', text) + except: + # logging.error(f"Error 1 -> I on {ocr_output}") + pass + # case: a solitary I; e.g., " I TO 5 DEFENSE" + cnt = 0 + while True: + cnt += 1 + if cnt > 30: + # logging.error(f"Error ' I ' -> ' 1 ' on {ocr_output}") + break + if " I " in text: + text = text.replace(" I ", " 1 ") + continue + elif ' I\n' in text: + text = text.replace(' I\n', ' 1\n') + continue + elif '\nI ' in text: + text = text.replace('\nI ', '\n1 ') + continue + break + # case: a solitary S; e.g., " 1 TO S DEFENSE" + cnt = 0 + while True: + cnt += 1 + if cnt > 30: + # logging.error(f"Error ' S ' -> ' 5 ' on {ocr_output}") + break + if " S " in text: + text = text.replace(" S ", " 5 ") + continue + elif ' I\n' in text: + text = text.replace(' S\n', ' 5\n') + continue + elif '\nI ' in text: + text = text.replace('\nS ', '\n5 ') + continue + break + # case: a solitary O; e.g., " O TO 5 DEFENSE" + cnt = 0 + while True: + cnt += 1 + if cnt > 30: + # logging.error(f"Error ' I ' -> ' 1 ' on {ocr_output}") + break + if (pattern := " O ") in text: + text = text.replace(pattern, " 0 ") + continue + elif (pattern := ' O\n') in text: + text = text.replace(pattern, ' 0\n') + continue + elif (pattern := '\nO ') in text: + text = text.replace(pattern, '\n0 ') + continue + break + # case: consecutive I's; e.g., "DEFENSE: II" + repeat = False + cnt = 0 + while "II" in text: + cnt += 1 + if cnt > 30: + # logging.error(f"Error 4 on {ocr_output}") + break + text = text.replace("II", "11") + repeat = True + repeat_count += 1 + if repeat and repeat_count < 10: + _fix_regexps(text) + return text + + +def _check_known_errors(text): + for word in text.split(): + for key in ERROR_RESOLUTION_MAP: + if key == word: + text = text.replace(key, ERROR_RESOLUTION_MAP[key]) + Logger.debug(f"_check_known_errors: {key} -> {ERROR_RESOLUTION_MAP[key]}") + return text + +def _contains_characters(word): + return any(c.isalpha() for c in word) + +def _ocr_result_dictionary_check( + original_text: str, + confidences: list, + word_list: set = all_words(), + normalized_lev_threshold: float = 0.6 + ) -> str: + confidences = [x/100 for x in confidences] + words_by_lines = [line.strip().split() for line in original_text.splitlines()] + total_word_count = -1 + new_text = "" + saved_result = "" + skip_next = False + for line_cnt, line in enumerate(words_by_lines): + new_line = [] + for word_cnt, word in enumerate(line): + total_word_count += 1 # increment before skip check to maintain relationship with confidences + # if the word was incorporated in the previous word as a combined substitution, skip + if skip_next: + skip_next = False + continue + # if word exists in list or is non-alphabetical, keep + if word in word_list or not _contains_characters(word): + new_line.append(word) + continue + # if the word is bounded by single quotes, then it's likely a runeword e.g. 'taltireth' + if word.startswith("'") and word.endswith("'") and len(word) > 1: + new_line.append(word) + continue + # fuzzy match the word + # if the word has already been calculated on a lookahead check, used stored result + if saved_result: + result = saved_result + saved_result = "" + else: + result = find_best_match(word, list(word_list)) + # if the word is the last word on the line don't lookahead + if word_cnt == (len(line) - 1): + if result.score_normalized >= normalized_lev_threshold: + # Logger.debug(f"_ocr_result_dictionary_check: change {word} -> {result.match} similarity: {result.score_normalized*100:.1f}%, OCR confidence: {int(confidences[total_word_count]*100)}%") + new_line.append(result.match) + else: + new_line.append(word) + continue + # if the word is not the last word, try lookahead in case of misread character -> space + next_word = line[word_cnt + 1] + # if next word is in wordlist or doesn't contain characters, save current word + if next_word in word_list or not _contains_characters(word): + if result.score_normalized >= normalized_lev_threshold: + # Logger.debug(f"_ocr_result_dictionary_check: change {word} -> {result.match} similarity: {result.score_normalized*100:.1f}%, OCR confidence: {int(confidences[total_word_count]*100)}%") + new_line.append(result.match) + else: + new_line.append(word) + continue + # fuzzy match the next word and a combination of both current and next words + next_result = find_best_match(next_word, list(word_list)) + combined_result = find_best_match(f"{word} {next_word}", list(word_list)) + if combined_result.score < (result.score + next_result.score): + # combined lev score is superior to sum of individual lev scores, replace with combined string + skip_next = True + # Logger.debug(f'_ocr_result_dictionary_check: change "{word} {next_word}" -> {combined_result.match} similarity: {combined_result.score_normalized*100:.1f}%, OCR confidence: {int(confidences[total_word_count]*100)}%, {int(confidences[total_word_count+1]*100)}%') + new_line.append(combined_result.match) + else: + if result.score_normalized >= normalized_lev_threshold: + # Logger.debug(f"_ocr_result_dictionary_check: change {word} -> {result.match} similarity: {result.score_normalized*100:.1f}%, OCR confidence: {int(confidences[total_word_count]*100)}%") + new_line.append(result.match) + else: + new_line.append(word) + # save next_result for next iteration + saved_result = next_result + new_text += f"{' '.join(new_line)}" + if line_cnt < (len(words_by_lines) - 1): + new_text += "\n" + return new_text \ No newline at end of file diff --git a/src/d2r_image/ocr_data.py b/src/d2r_image/ocr_data.py new file mode 100644 index 000000000..160f5bf46 --- /dev/null +++ b/src/d2r_image/ocr_data.py @@ -0,0 +1,41 @@ +import re +from enum import Enum + +I_1 = re.compile(r"(?<=[%I0-9\-+])I|I(?=[%I0-9\-+])") +II_U = re.compile(r"(?<=[A-Z])II|II(?=[A-Z])|1?=[a-z]") +ONE_I = re.compile(r"(?<=[A-Z])1|1(?=[A-Z])|1?=[a-z]") +ONEONE_U = re.compile(r"(?<=[A-Z])11|11(?=[A-Z])|1?=[a-z]") + +ERROR_RESOLUTION_MAP = { + 'SHIFLD': 'SHIELD', + 'SPFAR': 'SPEAR', + 'GLOVFS': 'GLOVES', + 'GOLP': 'GOLD', + 'TELEFORT': 'TELEPORT', + 'TROPHV': 'TROPHY', + 'CLAVMORE': 'CLAYMORE', + 'MAKIMUM': 'MAXIMUM', + 'DEKTERITY': 'DEXTERITY', + 'DERTERITY': 'DEXTERITY', + 'QUAHTITY': 'QUANTITY', + 'DEFERSE': 'DEFENSE', + 'ARMGR': 'ARMOR', + 'ARMER': 'ARMOR', + 'COMDAT': 'COMBAT', + 'WEAPORS': 'WEAPONS', + 'AXECLASS': 'AXE CLASS', + 'IOX%': '10%', + 'IO%': '10%', + 'TWYO': 'TWO', + 'ATTRIOUTES': 'ATTRIBUTES', + 'MONARCHI': 'MONARCH', + '10 RUNE': 'IO RUNE', + '1O RUNE': 'IO RUNE', + 'I0 RUNE': 'IO RUNE', + '1IST RUNE': 'IST RUNE', + 'JAR RUNE': 'JAH RUNE', + 'YO': 'TO', + 'QU AB': 'QUHAB', + 'QUAB': 'QUHAB', + ' :': ':' +} \ No newline at end of file diff --git a/src/d2r_image/processing.py b/src/d2r_image/processing.py new file mode 100644 index 000000000..91d349705 --- /dev/null +++ b/src/d2r_image/processing.py @@ -0,0 +1,87 @@ +import cv2 +import time + +import cv2 +import numpy as np +from d2r_image.data_models import GroundItemList, HoveredItem, ItemQuality, ItemText +from d2r_image.bnip_helpers import parse_item + +from d2r_image.processing_helpers import build_d2_items, crop_text_clusters, crop_item_tooltip, get_items_by_quality, consolidate_clusters, find_base_and_remove_items_without_a_base, set_set_and_unique_base_items +import numpy as np + +from logger import Logger + +import os + +os.makedirs("./log/screenshots/info", exist_ok=True) + +def get_ground_loot(image: np.ndarray, consolidate: bool = False) -> GroundItemList | None: + crop_result = crop_text_clusters(image) + items_by_quality = get_items_by_quality(crop_result) + if consolidate: + consolidate_clusters(items_by_quality) + find_base_and_remove_items_without_a_base(items_by_quality) + set_set_and_unique_base_items(items_by_quality) + return build_d2_items(items_by_quality) + +import traceback #TODO REMOV THIS + +def get_hovered_item(image: np.ndarray, model = "hover-eng_inconsolata_inv_th_fast") -> tuple[HoveredItem, ItemText]: + res, quality = crop_item_tooltip(image, model) + parsed_item = None + if res.ocr_result: + try: + parsed_item = parse_item(quality, res.ocr_result.text) + except Exception as e: + Logger.warning(f"\nparsed_item ERROR {e}\n {traceback.format_exc()}") + # * Log the screenshot to log/screenshots/info directory. + t = time.time() + cv2.imwrite(f"log/screenshots/info/02_{t}.png", res.img) + with open("log/screenshots/info/02_error_log.txt", "a") as f: + f.write(f"""-------------------------------------------------------------------------------- +[{t}] +{res.ocr_result.text} + +{traceback.format_exc()} +--------------------------------------------------------------------------------""") + return parsed_item, res + + +if __name__ == "__main__": + import keyboard + import os + from screen import start_detecting_window, stop_detecting_window, grab + from d2r_image import processing as d2r_image + from d2r_image.demo import draw_items_on_image_data, gen_truth_from_ground_loot + from bnip.actions import should_keep, should_pickup + import json + from logger import Logger + start_detecting_window() + keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or stop_detecting_window() or os._exit(1)) + Logger.info("Move to d2r window and press f11") + keyboard.wait("f11") + + gen_truth = False + + while 1: + img = grab().copy() + # look for item tooltip + item, res = d2r_image.get_hovered_item(img) + if res.roi is not None: + Logger.debug(f"Keep {item.Quality} {item.BaseItem['DisplayName']}?: {should_keep(item.as_dict())}") + x, y, w, h = res.roi + cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 1) + Logger.debug(f"{json.dumps(item.as_dict(), indent=4)}\n") + else: + # look for dropped items + all_loot = d2r_image.get_ground_loot(img) + if all_loot.items and len(all_loot.items) > 0: + for item in all_loot.items: + if item: + Logger.debug(f"Pick {item.Quality} {item.BaseItem['DisplayName']}?: {should_pickup(item.as_dict())}") + Logger.debug(item.as_dict()) + draw_items_on_image_data(all_loot.items, img) + if gen_truth: + gen_truth_from_ground_loot(all_loot.items, img) + cv2.imshow("res", img) + cv2.waitKey(3000) \ No newline at end of file diff --git a/src/d2r_image/processing_data.py b/src/d2r_image/processing_data.py new file mode 100644 index 000000000..66ff68baf --- /dev/null +++ b/src/d2r_image/processing_data.py @@ -0,0 +1,107 @@ +from enum import Enum +from d2r_image.data_models import ItemQuality +import cv2 + +ITEM_COLORS = ['white', 'gray', 'blue', 'green', 'yellow', 'gold', 'orange'] +GAUS_FILTER = (21, 1) +EXPECTED_HEIGHT_RANGE = [round(num) for num in [x / 1.5 for x in [14, 40]]] +EXPECTED_WIDTH_RANGE = [round(num) for num in [x / 1.5 for x in [60, 1280]]] +BOX_EXPECTED_WIDTH_RANGE = [200, 900] +BOX_EXPECTED_HEIGHT_RANGE = [24, 710] + +QUALITY_COLOR_MAP = { + 'white': ItemQuality.Normal, + 'gray': ItemQuality.Gray, + 'blue': ItemQuality.Magic, + 'green': ItemQuality.Set, + 'yellow': ItemQuality.Rare, + 'gold': ItemQuality.Unique, + 'orange': ItemQuality.Orange +} + +class Runeword(Enum): + AncientsPledge='ANCIENTS\'PLEDGE' + Beast='BEAST' + Black='BLACK' + Bone='BONE' + Bramble='BRAMBLE' + Brand='BRAND' + BreathOfTheDying = 'BREATHOFTHEDYING' + CallToArms = 'CALLTOARMS' + ChainsOfHonor = 'CHAINSOFHONOR' + Chaos = 'CHAOS' + CrescentMoon = 'CRESCENTMOON' + Death = 'DEATH' + Delirium = 'DELIRIUM' + Destruction = 'DESTRUCTION' + Doom = 'DOOM' + Dragon = 'DRAGON' + Dream = 'DREAM' + Duress = 'DURESS' + Edge = 'EDGE' + Enigma = 'EGNIMA' + Enlightenment = 'ENLIGHTENMENT' + Eternity = 'ETERNITY' + Exile = 'EXILE' + Faith = 'FAITH' + Famine = 'FAMINE' + FlickeringFlame = 'FLICKERINGFLAME' + Fortitude = 'FORTITUDE' + Fury = 'FURY' + Gloom = 'GLOOM' + Grief = 'GRIEF' + HandOfJustice = 'HANDOFJUSTICE' + Harmony = 'HARMONY' + HeartOfTheOak = 'HEARTOFTHEOAK' + HolyThunder = 'HOLYTHUNDER' + Honor = 'HONOR' + Ice = 'ICE' + Infinity = 'INFINITY' + Insight = 'INSIGHT' + KingsGrace = 'KING\'SGRACE' + Kingslayer = 'KINGSLAYER' + LastWish = 'LASTWISH' + Lawbringer = 'LAWBRINGER' + Leaf = 'LEAF' + Lionheart = 'LIONHEART' + Lore = 'LORE' + Malice = 'MALICE' + Melody = 'MELODY' + Memory = 'MEMORY' + Mist = 'MIST' + Myth = 'MYTH' + Nadir = 'NADIR' + Oath = 'OATH' + Obedience = 'OBEDIENCE' + Obsession = 'OBSESSION' + Passion = 'PASSION' + Pattern = 'PATTERN' + Peace = 'PEACE' + Phoenix = 'PHOENIX' + Plague = 'PLAGUE' + Pride = 'PRIDE' + Principle = 'PRINCIPLE' + Prudence = 'PRUDENCE' + Radiance = 'RADIANCE' + Rain = 'RAIN' + Rhyme = 'RHYME' + Rift = 'RIFT' + Sanctuary = 'SANCTUARY' + Silence = 'SILENCE' + Smoke = 'SMOKE' + Spirit = 'SPIRIT' + Splendor = 'SPLENDOR' + Stealth = 'STEALTH' + Steel = 'STEEL' + Stone = 'STONE' + Strength = 'STRENGTH' + Treachery = 'TREACHERY' + UnbendingWill = 'UNBENDINGWILL' + Venom = 'VENOM' + VoiceOfReason = 'VOICEOFREASON' + Wealth = 'WEALTH' + White = 'WHITE' + Wind = 'WIND' + Wisdom = 'WISDOM' + Wrath = 'WRATH' + Zephyr = 'ZEPHYR' diff --git a/src/d2r_image/processing_helpers.py b/src/d2r_image/processing_helpers.py new file mode 100644 index 000000000..3130b2e7b --- /dev/null +++ b/src/d2r_image/processing_helpers.py @@ -0,0 +1,637 @@ +import cv2 +import numpy as np +import re +import time +import math +import copy + +from d2r_image.data_models import GroundItem, GroundItemList, ItemQuality, ItemQualityKeyword, ItemText +from d2r_image.bnip_data import NTIP_ALIAS_QUALITY_MAP +from d2r_image.bnip_helpers import basename_to_types +from d2r_image.ocr import image_to_text +from d2r_image.processing_data import Runeword +import d2r_image.d2data_lookup as d2data_lookup +from d2r_image.d2data_lookup import fuzzy_base_item_match +from d2r_image.processing_data import EXPECTED_HEIGHT_RANGE, EXPECTED_WIDTH_RANGE, GAUS_FILTER, ITEM_COLORS, QUALITY_COLOR_MAP, Runeword, BOX_EXPECTED_HEIGHT_RANGE, BOX_EXPECTED_WIDTH_RANGE +from d2r_image.strings_store import base_items +from utils.misc import color_filter, erode_to_black, slugify +from d2r_image.ocr import image_to_text +from ui_manager import get_hud_mask + +from screen import convert_screen_to_monitor +from utils.misc import color_filter, cut_roi, roi_center +from logger import Logger +from config import Config +import template_finder + +gold_regex = re.compile(r'(^[0-9]+)\sGOLD') + +import time +def crop_text_clusters(inp_img: np.ndarray, padding_y: int = 5) -> list[ItemText]: + cleaned_img = clean_img(inp_img) + # Cluster item names + item_clusters = [] + for key in ITEM_COLORS: + _, filtered_img = color_filter(cleaned_img, Config().colors[key]) + filtered_img_gray = cv2.cvtColor(filtered_img, cv2.COLOR_BGR2GRAY) + gaus = GAUS_FILTER + if key == "gray": + # white text has some gray on border of glyphs, erode + filtered_img_gray = cv2.erode(filtered_img_gray, np.ones((2, 1), 'uint8'), None, iterations=1) + gaus = (GAUS_FILTER[0] + 4, GAUS_FILTER[1]) + blured_img = np.clip(cv2.GaussianBlur( + filtered_img_gray, gaus, cv2.BORDER_DEFAULT), 0, 255) + contours = cv2.findContours( + blured_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + contours = contours[0] if len(contours) == 2 else contours[1] + for cntr in contours: + x, y, w, h = cv2.boundingRect(cntr) + expected_height = EXPECTED_HEIGHT_RANGE[0] < h < EXPECTED_HEIGHT_RANGE[1] + expected_width = EXPECTED_WIDTH_RANGE[0] < w < EXPECTED_WIDTH_RANGE[1] + if not (expected_height and expected_width): continue + # increase height a bit to make sure we have the full item name in the cluster + y = y - padding_y if y > padding_y else 0 + h += padding_y * 2 + cropped_item = filtered_img[y:y+h, x:x+w] + avg = int(np.average(filtered_img_gray[y:y+h, x:x+w])) + contains_black = np.min(cropped_item) < 14 + mostly_dark = avg < 35 + if contains_black and mostly_dark: + # double-check item color + color_averages = [] + for key2 in ITEM_COLORS: + _, extracted_img = color_filter(cropped_item, Config().colors[key2]) + extr_avg = np.average(cv2.cvtColor( + extracted_img, cv2.COLOR_BGR2GRAY)) + color_averages.append(extr_avg) + max_idx = color_averages.index(max(color_averages)) + if key == ITEM_COLORS[max_idx]: + item_clusters.append(ItemText( + color=key, + quality=QUALITY_COLOR_MAP[key], + roi=[x, y, w, h], + img=inp_img[y:y+h, x:x+w], + clean_img=cleaned_img[y:y+h, x:x+w] + )) + cluster_images = [key["clean_img"] for key in item_clusters] + results = image_to_text(cluster_images, model="ground-eng_inconsolata_inv_th_fast", psm=7, erode=True) + for count, cluster in enumerate(item_clusters): + setattr(cluster, "ocr_result", results[count]) + return item_clusters + +def crop_item_tooltip(image: np.ndarray, model: str = "hover-eng_inconsolata_inv_th_fast") -> tuple[ItemText, str]: + """ + Crops visible item description boxes / tooltips + :inp_img: image from hover over item of interest. + :model: which ocr model to use + """ + res = ItemText() + quality = None + black_mask = color_filter(image, Config().colors["black"])[0] + contours = cv2.findContours( + black_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + contours = contours[0] if len(contours) == 2 else contours[1] + for cntr in contours: + x, y, w, h = cv2.boundingRect(cntr) + cropped_item = image[y:y+h, x:x+w] + + if not (expected_height := BOX_EXPECTED_HEIGHT_RANGE[0] < h < BOX_EXPECTED_HEIGHT_RANGE[1]): + continue + if not (expected_width := BOX_EXPECTED_WIDTH_RANGE[0] < w < BOX_EXPECTED_WIDTH_RANGE[1]): + continue + + avg = np.average(cv2.cvtColor(cropped_item, cv2.COLOR_BGR2GRAY)) + if not (mostly_dark := 0 < avg < 35): + continue + if not (contains_black := np.min(cropped_item) < 14): + continue + + contains_white = np.max(cropped_item) > 250 + contains_orange = False + if not contains_white: + # check for orange (like key of destruction, etc.) + orange_mask, _ = color_filter(cropped_item, Config().colors["orange"]) + contains_orange = np.min(orange_mask) > 0 + if not (contains_white or contains_orange): + continue + + # check to see if contour overlaps right inventory + right_inv = Config().ui_roi["right_inventory"] + overlaps_inventory = not ( + x+w < right_inv[0] or right_inv[0]+right_inv[2] < x or y+h+60 < right_inv[1] or right_inv[1]+right_inv[3] < y) + if not overlaps_inventory: + left_inv = Config().ui_roi["left_inventory"] + overlaps_inventory |= not ( + x+w < left_inv[0] or left_inv[0]+left_inv[2] < x or y+h+60 < left_inv[1] or left_inv[1]+left_inv[3] < y) + if not overlaps_inventory: + continue + + #print(f"x: {x}, y: {y}, w: {w}, h: {h}") + footer_y = (y + h) if (y + h) < 700 else 700 + footer_h = 720 - footer_y + found_footer = template_finder.search(["TO_TOOLTIP"], image, threshold=0.8, roi=[x, footer_y, w, footer_h]).valid + if found_footer: + res.ocr_result = image_to_text(cropped_item, psm=6, model=model)[0] + first_row = cut_roi(copy.deepcopy(cropped_item), (0, 0, w, 26)) + if _contains_color(first_row, "green"): + quality = ItemQuality.Set.value + elif _contains_color(first_row, "gold"): + quality = ItemQuality.Unique.value + elif _contains_color(first_row, "yellow"): + quality = ItemQuality.Rare.value + elif _contains_color(first_row, "blue"): + quality = ItemQuality.Magic.value + elif _contains_color(first_row, "orange"): + quality = ItemQuality.Crafted.value + elif _contains_color(first_row, "white"): + quality = ItemQuality.Normal.value + elif _contains_color(first_row, "gray"): + if "SUPERIOR" in res.ocr_result.text[:10]: + quality = ItemQuality.Superior.value + else: + quality = ItemQuality.Gray.value + else: + quality = ItemQuality.Normal.value + res.roi = [x, y, w, h] + res.img = cropped_item + break + return res, quality + +def _contains_color(img: np.ndarray, color: str) -> bool: + mask = color_filter(img, Config().colors[color])[0] + return np.average(mask) > 0 + + +def clean_img(inp_img: np.ndarray, black_thresh: int = 14) -> np.ndarray: + img = inp_img[:, :, :] + if img.shape[0] == get_hud_mask().shape[0] and img.shape[1] == get_hud_mask().shape[1]: + img = cv2.bitwise_and(img, img, mask=get_hud_mask()) + # In order to not filter out highlighted items, change their color to black + highlight_mask = color_filter(img, Config().colors["item_highlight"])[0] + img[highlight_mask > 0] = (0, 0, 0) + img = erode_to_black(img, black_thresh) + return img + + +def get_items_by_quality(crop_result: list[ItemText]): + items_by_quality = {} + for quality in ItemQuality: + items_by_quality[quality.value] = [] + for item in crop_result: + quality = None + if item.quality.value == ItemQuality.Orange.value: + is_rune = ' RUNE' in item.ocr_result.text + if is_rune: + quality = ItemQuality.Rune + else: + quality = ItemQuality.Crafted + elif item.quality.value == ItemQuality.Unique.value: + is_runeword = False + try: + Runeword(item.ocr_result.text) + is_runeword = True + except: + pass + quality = ItemQuality.Runeword if is_runeword else item.quality + elif item.quality.value == ItemQuality.Gray.value: + quality = ItemQuality.Gray + else: + quality = item.quality + items_by_quality[quality.value].append({ + 'color': item.color, + 'quality': quality, + 'x': item.roi[0], + 'y': item.roi[1], + 'w': item.roi[2], + 'h': item.roi[3], + 'text': item.ocr_result.text + }) + return items_by_quality + + +def consolidate_clusters(items_by_quality): + if len(items_by_quality) == 0: + return + cco_start = time.time() + consolidate_overlapping_names(items_by_quality) + cco_end = time.time() + cco = round(cco_end-cco_start, 2) + ccr_start = time.time() + consolidate_rares(items_by_quality) + ccr_end = time.time() + ccr = round(ccr_end-ccr_start, 2) + ccs_start = time.time() + consolidate_quality( + items_by_quality[ItemQuality.Set.value], + items_by_quality[ItemQuality.Set.value]) + ccs_end = time.time() + ccs = round(ccs_end-ccs_start, 2) + ccu_start = time.time() + consolidate_quality( + items_by_quality[ItemQuality.Unique.value], + items_by_quality[ItemQuality.Unique.value]) + ccu_end = time.time() + ccu = round(ccu_end-ccu_start, 2) + ccrw_start = time.time() + consolidate_quality( + items_by_quality[ItemQuality.Runeword.value], + items_by_quality[ItemQuality.Gray.value]) + ccrw_end = time.time() + ccrw = round(ccrw_end-ccrw_start, 2) + # print(f'CCO: {cco}\tCCR: {ccr}\tCCS: {ccs}\tCCU: {ccu}\tCCRW: {ccrw}') + + +def consolidate_overlapping_names(items_by_quality): + items_to_remove = {} + for quality in items_by_quality: + for item in items_by_quality[quality]: + overlapping_item = None + for item_to_check in items_by_quality[quality]: + if item == item_to_check or abs(item['y'] - item_to_check['y']) > 3: + continue + if quality in items_to_remove: + if item in items_to_remove[quality] or item_to_check in items_to_remove[quality]: + continue + if item['x'] < item_to_check['x'] + item_to_check['w'] and\ + item['x'] + item['w'] > item_to_check['x'] and\ + item['y'] < item_to_check['y'] + item_to_check['h'] and\ + item['y'] + item['h'] > item_to_check['y']: + overlapping_item = item_to_check + break + if overlapping_item: + first_item = item if item['x'] < overlapping_item['x'] else overlapping_item + second_item = item if first_item == overlapping_item else overlapping_item + first_item_text = first_item['text'].strip().replace('\'', '') + second_item_text = second_item['text'].strip().replace('\'', '').lstrip() + new_text = f"{first_item_text}\' {second_item_text}" + if quality == ItemQuality.Set.value: + if not d2data_lookup.find_set_item_by_name(new_text): + break + elif quality == ItemQuality.Unique.value: + if not d2data_lookup.find_unique_item_by_name(new_text): + break + first_item['text'] = new_text + first_item['name'] = new_text + first_item['x'] = first_item['x'] if second_item['x'] > first_item['x'] else second_item['x'] + first_item['y'] = first_item['y'] if second_item['y'] > first_item['y'] else second_item['y'] + first_item['w'] = second_item['x'] + second_item['w'] - first_item['x'] + first_item['h'] = first_item['h'] + if quality not in items_to_remove: + items_to_remove[quality] = [] + items_to_remove[quality].append(second_item) + for quality in items_to_remove: + for item in items_to_remove[quality]: + items_by_quality[quality].remove(item) + + +def consolidate_rares(items_by_quality): + for item in items_by_quality[ItemQuality.Rare.value]: + closest_dist = 99999 + closest_base = None + d2data_base = None + if not d2data_lookup.is_base(item['text']): + for base in items_by_quality[ItemQuality.Rare.value]: + if d2data_lookup.is_base(base['text']): + base_item = d2data_lookup.get_base(base['text']) + dist = round(math.dist( + (item['x'], item['y']), + (base['x'], base['y']) + ), 0) + if dist < closest_dist: + closest_dist = dist + closest_base = base + d2data_base = base_item + if not closest_base: + return + item['x'] = item['x'] if closest_base['x'] > item['x'] else closest_base['x'] + item['y'] = item['y'] if closest_base['y'] > item['y'] else closest_base['y'] + item['w'] = item['w'] if closest_base['w'] < item['w'] else closest_base['w'] + item['h'] = item['h'] + closest_base['h'] + item['base'] = d2data_base + item['item'] = d2data_base + item['identified'] = True + items_by_quality[ItemQuality.Rare.value].remove(closest_base) + + +def consolidate_quality(quality_items, potential_bases): + bases_to_remove = [] + for item in quality_items: + if not d2data_lookup.is_base(item['text']): + # result = d2data_lookup.find_item_by_display_name(item['text']) + result = d2data_lookup.find_set_or_unique_item_by_name(item['text'], item['quality']) + if not result: + continue + closest_dist = 99999 + closest_base = None + for base in potential_bases: + if base['y'] > item['y'] and d2data_lookup.is_base(base['text']): + dist = round(math.dist( + (item['x'], item['y']), + (base['x'], base['y']) + ), 0) + if dist < closest_dist: + closest_dist = dist + closest_base = base + if not closest_base: + continue + item['x'] = item['x'] if closest_base['x'] > item['x'] else closest_base['x'] + item['y'] = item['y'] if closest_base['y'] > item['y'] else closest_base['y'] + item['w'] = item['w'] if closest_base['w'] < item['w'] else closest_base['w'] + item['h'] = item['h'] + closest_base['h'] + item['item'] = result + item['name'] = result['DisplayName'] + item['base'] = d2data_lookup.get_base(closest_base['text']) + item['identified'] = True + bases_to_remove.append(closest_base) + for base_to_remove in bases_to_remove: + potential_bases.remove(base_to_remove) + + +def find_base_and_remove_items_without_a_base(items_by_quality) -> dict: + items_to_remove = {} + gray_normal_magic_removed = {} + items_to_add = {} + resolved_runewords = [] + for quality in items_by_quality: + if quality in [ItemQuality.Gray.value, ItemQuality.Normal.value, ItemQuality.Magic]: + gray_normal_magic_removed.update(set_gray_and_normal_and_magic_base_items(items_by_quality)) + for item in items_by_quality[quality]: + quality_keyword, normalized_text = get_normalized_normal_gray_item_text(item['text']) + if not normalized_text in base_items() and not any(chr.isdigit() for chr in item['text']) and not gold_regex.search(item['text']): + item['text'] = f"{quality_keyword} {fuzzy_base_item_match(normalized_text)}".strip() + if 'base' not in item: + if quality == ItemQuality.Magic.value: + base = d2data_lookup.get_base(item['text']) + if base: + item['base'] = base + elif quality == ItemQuality.Rune.value: + if d2data_lookup.is_rune(item['text']): + item['base'] = d2data_lookup.get_rune(item['text']) + item['item'] = d2data_lookup.get_rune(item['text']) + item['identified'] = True + elif d2data_lookup.is_base(item['text']): + item['base'] = d2data_lookup.get_base(item['text']) + item['name'] = item['base']['DisplayName'] + else: + if quality not in items_to_remove: + items_to_remove[quality] = [] + items_to_remove[quality].append(item) + for quality in items_to_remove: + for item in items_to_remove[quality]: + if quality == ItemQuality.Unique.value: + for unique_item in items_by_quality[quality]: + if 'item' not in unique_item and 'base' in unique_item and 'uniques' in unique_item['base']: + closest_dist = 99999 + closest_base = None + closest_unique_name = None + for possible_unique in unique_item['base']['uniques']: + normalized_name = possible_unique.replace('_', ' ').upper() + if normalized_name in item['text']: + dist = round(math.dist( + (item['x'], item['y']), + (unique_item['x'], unique_item['y']) + ), 0) + if dist < closest_dist: + closest_dist = dist + closest_base = unique_item + closest_unique_name = normalized_name + if closest_base: + unique_name_width = len(closest_unique_name) * 11 + offset = item['text'].find(closest_unique_name) * 11 + unique_item['x'] = item['x'] + offset + unique_item['y'] -= item['h'] + unique_item['w'] = unique_name_width if unique_name_width > item['w'] else item['w'] if item['w'] < unique_name_width * 1.4 else unique_name_width + unique_item['h'] += item['h'] + unique_item['text'] = closest_unique_name + unique_item['item'] = d2data_lookup.find_unique_item_by_name(closest_unique_name) + unique_item['identified'] = True + elif quality == ItemQuality.Runeword.value: + if 'item' not in item: + closest_dist = 99999 + closest_base = None + for possible_base in items_by_quality[ItemQuality.Gray.value]: + dist = round(math.dist( + (item['x'], item['y']), + (possible_base['x'], possible_base['y']) + ), 0) + if dist < closest_dist: + closest_dist = dist + closest_base = possible_base + if closest_base: + closest_base['quality'] = ItemQuality.Runeword + closest_base['name'] = item['text'] + closest_base['x'] = item['x'] if item['x'] < closest_base['x'] else closest_base['x'] + closest_base['y'] = item['y'] + closest_base['w'] = item['w'] if item['w'] > closest_base['w'] else closest_base['w'] + closest_base['h'] += item['h'] + closest_base['item'] = {} + closest_base['identified'] = True + if quality not in items_to_add: + items_to_add[quality] = [] + items_to_add[quality].append(closest_base) + items_by_quality[ItemQuality.Gray.value].remove(closest_base) + resolved_runewords.append(item) + items_by_quality[quality].remove(item) + for quality in items_to_add: + if quality not in items_by_quality: + items_by_quality[quality] = [] + for item in items_to_add[quality]: + items_by_quality[quality].append(item) + for runeword in resolved_runewords: + if runeword in items_to_remove[ItemQuality.Runeword.value]: + items_to_remove[ItemQuality.Runeword.value].remove(runeword) + for quality in gray_normal_magic_removed: + for item in gray_normal_magic_removed[quality]: + if item['quality'].value not in items_to_remove: + items_to_remove[item['quality'].value] = [] + items_to_remove[item['quality'].value].append(item) + # items_removed = items_to_remove.update(gray_normal_magic_removed) + return items_to_remove + + +def get_normalized_normal_gray_item_text(item_text): + found_keyword_text = None + if item_text.startswith('OW QUALITY'): + item_text = item_text.replace('OW QUALITY', ItemQualityKeyword.LowQuality.value) + if ItemQualityKeyword.LowQuality.value in item_text: + found_keyword_text = ItemQualityKeyword.LowQuality.value + elif ItemQualityKeyword.Cracked.value in item_text: + found_keyword_text = ItemQualityKeyword.Cracked.value + elif ItemQualityKeyword.Crude.value in item_text: + found_keyword_text = ItemQualityKeyword.Crude.value + elif ItemQualityKeyword.Damaged.value in item_text: + found_keyword_text = ItemQualityKeyword.Damaged.value + elif ItemQualityKeyword.Superior.value in item_text: + found_keyword_text = ItemQualityKeyword.Superior.value + if found_keyword_text: + return ItemQualityKeyword(found_keyword_text), item_text.replace(f'{found_keyword_text} ', '') + return None, item_text + + +def set_gray_and_normal_and_magic_base_items(items_by_quality): + items_to_remove = { + } + for quality in items_by_quality: + if quality in [ItemQuality.Gray.value, ItemQuality.Normal.value]: + for item in items_by_quality[quality]: + quality_keyword, normalized_text = get_normalized_normal_gray_item_text(item['text']) + result = d2data_lookup.get_base(normalized_text) + #print(f"{quality_keyword} {normalized_text} {result}") + if not result: + gold_match = gold_regex.search(item['text']) + if gold_match: + item['base'] = d2data_lookup.get_consumable('GOLD') + item['amount'] = gold_match.group(1) + continue + else: + # fuzzy match + new_string = "" + if quality_keyword: + new_string += f"{quality_keyword} " + new_string += f"{fuzzy_base_item_match(normalized_text)}" + item['text'] = new_string.strip() + quality_keyword, normalized_text = get_normalized_normal_gray_item_text(item['text']) + result = d2data_lookup.get_base(normalized_text) + if result: + item['base'] = result + item['item'] = result + item['identified'] = True + item['name'] = item['base']['DisplayName'] + if quality_keyword: + item['quality'] = quality_keyword + else: + if d2data_lookup.is_consumable(item['text']): + item['base'] = d2data_lookup.get_consumable(item['text']) + item['name'] = item['base']['DisplayName'] + elif d2data_lookup.is_gem(item['text']): + item['base'] = d2data_lookup.get_gem(item['text']) + item['name'] = item['base']['DisplayName'] + else: + if quality not in items_to_remove: + items_to_remove[quality] = [] + items_to_remove[quality].append(item) + # print(f'remove {item}') + elif quality == ItemQuality.Magic.value: + for item in items_by_quality[quality]: + item_is_identified = d2data_lookup.magic_item_is_identified(item['text']) + base = d2data_lookup.find_base_item_from_magic_item_text(item['text'], item_is_identified) + if base: + item['base'] = base + if len(item['text'].lower().replace(base['DisplayName'].lower(), '').replace(' ', '')) > 0: + item['item'] = base + item['identified'] = True + else: + item['name'] = base['DisplayName'] + else: + if quality not in items_to_remove: + items_to_remove[quality] = [] + items_to_remove[quality].append(item) + for quality in items_to_remove: + for item in items_to_remove[quality]: + items_by_quality[quality].remove(item) + return items_to_remove + + +def set_set_and_unique_base_items(items_by_quality): + for quality in items_by_quality: + for item in items_by_quality[quality]: + if 'item' in item: + continue + item['identified'] = False + if quality == ItemQuality.Unique.value and 'uniques' in item['base']: + if len(item['base']['uniques']) == 1: + unique_name = item['base']['uniques'][0].replace('_', ' ').upper() + item['item'] = d2data_lookup.find_unique_item_by_name(unique_name, True) + item['name'] = item['item']['DisplayName'] + else: + item['uniqueItems'] = [] + for unique_item in item['base']['uniques']: + unique_name = unique_item.replace('_', ' ').upper() + item['uniqueItems'].append(d2data_lookup.find_unique_item_by_name(unique_name, True)) + elif quality == ItemQuality.Set.value and 'sets' in item['base']: + if len(item['base']['sets']) == 1: + set_name = item['base']['sets'][0] + item['item'] = d2data_lookup.find_set_item_by_name(set_name, ItemQuality.Set) + item['name'] = item['item']['DisplayName'] + else: + item['setItems'] = [] + for unique_item in item['base']['sets']: + unique_name = unique_item.replace('_', ' ').upper() + item['setItems'].append(d2data_lookup.find_set_item_by_name(unique_name, True)) + + +def build_d2_items(items_by_quality: dict) -> GroundItemList | None: + + ground_item_list = GroundItemList([]) + d2_items = ground_item_list.items + for quality in items_by_quality: + for item in items_by_quality[quality]: + try: + bounding_box = [item['x'], item['y'], item['w'], item['h']] + bounding_box_monitor = [round(x) for x in [*convert_screen_to_monitor((item['x'], item['y'])), item['w'], item['h']]] + center = roi_center(bounding_box) + center_monitor = (round(x) for x in convert_screen_to_monitor(center)) + new_item = GroundItem( + BoundingBox=dict(zip(["x", "y", "w", "h"], bounding_box)), + BoundingBoxMonitor=dict(zip(["x", "y", "w", "h"], bounding_box_monitor)), + Center=dict(zip(["x", "y"], center)), + CenterMonitor=dict(zip(["x", "y"], center_monitor)), + Distance=round(math.dist((item['x'], item['y']), (Config().ui_pos["screen_width"] / 2, Config().ui_pos["screen_height"] / 2))), + Name=item['name'] if 'name' in item else item['text'], + Color=item['color'], + Quality=item['quality'].value, + Text=item['text'], + Amount=None if not "amount" in item else item['amount'], + BaseItem=item['base'], + Item=item['item'] if 'item' in item and item['item'] != item['base'] else None, + NTIPAliasType=basename_to_types(item['base']['DisplayName']), + # NTIPAliasType=None if item['base']['DisplayName'] not in BNIP_ITEM_TYPE_DATA else BNIP_ITEM_TYPE_DATA[item['base']['DisplayName']], + NTIPAliasClassID=item['base']['NTIPAliasClassID'], + NTIPAliasClass=item['base']['NTIPAliasClass'] if 'NTIPAliasClass' in item['base'] else None, + NTIPAliasQuality=NTIP_ALIAS_QUALITY_MAP[item['quality'].value], + NTIPAliasFlag={ + '0x10': item['identified'], + '0x4000000': item['quality'] == ItemQuality.Runeword.value, + "0x400000": item['quality'] == ItemQuality.Gray.value, + } + ) + new_item.ID = slugify(f"{new_item.Name}_{'_'.join([str(value) for _, value in new_item.as_dict().items()])}") + new_item.UID = f"{new_item.ID}_{'_'.join([str(value) for value in center])}" + if d2_items is None: + d2_items = [] + d2_items.append(new_item) + except Exception as e: + Logger.error(f'failed on item: {item} with error {e}') + return ground_item_list + +if __name__ == "__main__": + import keyboard + import os + from screen import start_detecting_window, grab, stop_detecting_window + start_detecting_window() + keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or stop_detecting_window() or os._exit(1)) + print("Go to D2R window and press f11 to start") + keyboard.wait("f11") + from config import Config + + # while 1: + # img_o = grab() + # img = img_o[:, :, :] + # # In order to not filter out highlighted items, change their color to black + # highlight_mask = color_filter(img, Config().colors["item_highlight"])[0] + # img[highlight_mask > 0] = (0, 0, 0) + # img = erode_to_black(img, 14) + # _, filtered_img = color_filter(img, Config().colors["gray"]) + # filtered_img_gray = cv2.cvtColor(filtered_img, cv2.COLOR_BGR2GRAY) + # eroded_img_gray = cv2.erode(filtered_img_gray, np.ones((2, 1), 'uint8'), None, iterations=1) + # blured_img = np.clip(cv2.GaussianBlur(eroded_img_gray, (17, 1), cv2.BORDER_DEFAULT), 0, 255) + # cv2.imshow('test', blured_img) + # key = cv2.waitKey(3000) + + while 1: + img_o = grab() + tooltip = crop_item_tooltip(img_o) + print(tooltip) + cv2.imshow('test', tooltip[0].img) + #cv2.imshow('test', tooltip[0].ocr_result.processed_img) + key = cv2.waitKey(20000) \ No newline at end of file diff --git a/src/d2r_image/strings_store.py b/src/d2r_image/strings_store.py new file mode 100644 index 000000000..8cade32c0 --- /dev/null +++ b/src/d2r_image/strings_store.py @@ -0,0 +1,23 @@ +from functools import cache + +_WORD_LIST_DIR = "assets/word_lists" + +@cache +def all_words(): + with open(f"{_WORD_LIST_DIR}/all_words.txt", 'r') as f: + return set(line.strip() for line in f.read().splitlines()) + +@cache +def base_items(): + with open(f"{_WORD_LIST_DIR}/base_items.txt", 'r') as f: + return set(line.strip() for line in f.read().splitlines()) + +@cache +def magic_prefixes(): + with open(f"{_WORD_LIST_DIR}/magic_prefixes.txt", 'r') as f: + return set(line.strip() for line in f.read().splitlines()) + +@cache +def magic_suffixes(): + with open(f"{_WORD_LIST_DIR}/magic_suffixes.txt", 'r') as f: + return set(line.strip() for line in f.read().splitlines()) \ No newline at end of file diff --git a/src/death_manager.py b/src/death_manager.py index e81926e24..ffb0b70f7 100644 --- a/src/death_manager.py +++ b/src/death_manager.py @@ -37,7 +37,7 @@ def handle_death_screen(self): if is_visible(ScreenObjects.YouHaveDied, img): Logger.warning("You have died!") if Config().general["info_screenshots"]: - self._last_death_screenshot = "./info_screenshots/info_debug_death_" + time.strftime("%Y%m%d_%H%M%S") + ".png" + self._last_death_screenshot = "./log/screenshots/info/info_debug_death_" + time.strftime("%Y%m%d_%H%M%S") + ".png" cv2.imwrite(self._last_death_screenshot, img) # first wait a bit to make sure health manager is done with its chicken stuff which obviously failed if self._callback is not None: diff --git a/src/game_controller.py b/src/game_controller.py index f22eb4205..3304de0d2 100644 --- a/src/game_controller.py +++ b/src/game_controller.py @@ -1,4 +1,3 @@ -import os import threading import time import cv2 @@ -13,7 +12,7 @@ from logger import Logger from messages import Messenger from screen import grab, get_offset_state -from utils.restart import restart_game, kill_game +from utils.restart import restart_game, safe_exit from utils.misc import kill_thread, set_d2r_always_on_top, restore_d2r_window_visibility @@ -41,15 +40,16 @@ def run_bot(self): self.health_manager.set_callback(lambda: self.bot.stop() or kill_thread(self.bot_thread)) do_restart = False messenger = Messenger() + force_stopped = False while 1: max_game_length_reached = self.game_stats.get_current_game_length() > Config().general["max_game_length_s"] max_consecutive_fails_reached = False if not Config().general["max_consecutive_fails"] else self.game_stats.get_consecutive_runs_failed() >= Config().general["max_consecutive_fails"] - if max_game_length_reached or max_consecutive_fails_reached or self.death_manager.died() or self.health_manager.did_chicken(): + if max_game_length_reached or max_consecutive_fails_reached or self.death_manager.died() or self.health_manager.did_chicken() or (force_stopped := self.bot._stopping): # Some debug and logging if max_game_length_reached: Logger.info(f"Max game length reached. Attempting to restart {Config().general['name']}!") if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/info_max_game_length_reached_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + cv2.imwrite("./log/screenshots/info/info_max_game_length_reached_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) elif self.death_manager.died(): self.game_stats.log_death(self.death_manager._last_death_screenshot) elif self.health_manager.did_chicken(): @@ -60,9 +60,9 @@ def run_bot(self): if max_consecutive_fails_reached: msg = f"Consecutive fails {self.game_stats.get_consecutive_runs_failed()} >= Max {Config().general['max_consecutive_fails']}. Quitting botty." Logger.error(msg) - if Config().general["custom_message_hook"]: + if messenger.enabled: messenger.send_message(msg) - self.safe_exit(1) + safe_exit(1) else: do_restart = self.game_recovery.go_to_hero_selection() break @@ -72,16 +72,16 @@ def run_bot(self): # Reset flags before running a new bot self.death_manager.reset_death_flag() self.health_manager.reset_chicken_flag() - self.game_stats.log_end_game(failed=max_game_length_reached) + self.game_stats.log_end_game(failed = (max_game_length_reached or force_stopped)) return self.run_bot() else: if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/info_could_not_recover_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + cv2.imwrite("./log/screenshots/info/info_could_not_recover_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) if Config().general['restart_d2r_when_stuck']: Logger.error("Could not recover from a max game length violation. Restarting the Game.") - if Config().general["custom_message_hook"]: + if messenger.enabled: messenger.send_message("Got stuck and will now restart D2R") - if restart_game(Config().general["d2r_path"]): + if restart_game(Config().general["d2r_path"], Config().advanced_options["launch_options"]): self.game_stats.log_end_game(failed=max_game_length_reached) if self.setup_screen(): self.start_health_manager_thread() @@ -89,12 +89,13 @@ def run_bot(self): self.game_recovery = GameRecovery(self.death_manager) return self.run_bot() Logger.error("Could not restart the game. Quitting.") - messenger.send_message("Got stuck and could not restart the game. Quitting.") + if messenger.enabled: + messenger.send_message("Got stuck and could not restart the game. Quitting.") else: Logger.error("Could not recover from a max game length violation. Quitting botty.") - if Config().general["custom_message_hook"]: + if messenger.enabled: messenger.send_message("Got stuck and will now quit botty") - self.safe_exit(1) + safe_exit(1) def start(self): # Check if we user should update the d2r settings @@ -147,7 +148,3 @@ def start_game_controller_thread(self): def toggle_pause_bot(self): if self.bot: self.bot.toggle_pause() - - def safe_exit(self, error_code=0): - kill_game() - os._exit(error_code) diff --git a/src/game_recovery.py b/src/game_recovery.py index 435d30eb5..c90d8f0b4 100644 --- a/src/game_recovery.py +++ b/src/game_recovery.py @@ -33,7 +33,7 @@ def go_to_hero_selection(self): time.sleep(1) continue # check for save/exit button - if is_visible(ScreenObjects.GameMenu): + if is_visible(ScreenObjects.SaveAndExit): view.save_and_exit() continue # maybe we are in-game in stash/inventory, press escape diff --git a/src/game_stats.py b/src/game_stats.py index c7b28217c..72a016f43 100644 --- a/src/game_stats.py +++ b/src/game_stats.py @@ -48,15 +48,19 @@ def populate_location_stat(self): if self._location not in self._location_stats: self._location_stats[self._location] = { "items": [], "deaths": 0, "chickens": 0, "merc_deaths": 0, "failed_runs": 0 } - def log_item_keep(self, item_name: str, send_message: bool, img: np.ndarray, ocr_text: str = None): - Logger.debug(f"Stashed and logged: {item_name}") - filtered_items = ["_potion", "misc_gold", "_amethyst", "_ruby", "misc_chipped_diamond", "misc_flawed_diamond", "misc_diamond", "misc_flawless_diamond", "_topaz", "_emerald", "_sapphire", "misc_chipped_skull", "misc_flawed_skull", "misc_skull", "misc_flawless_skull"] - if self._location is not None and not any(substring in item_name for substring in filtered_items): + def log_item_keep(self, item_name: str, send_message: bool, img: np.ndarray, ocr_text: str = '', expression: str = '', item_props: dict = {}): + filtered_substrings = [" POTION", " OF IDENTIFY", " OF TOWN PORTAL", " AMETHYST", " RUBY", " TOPAZ", " EMERALD", " SAPPHIRE", " DIAMOND"] + filtered_matches = ["DIAMOND", "AMETHYST", "RUBY", "TOPAZ", "EMERALD", "SAPPHIRE", "ARROWS", "BOLTS", + "CHIPPED SKULL", "FLAWED SKULL", "SKULL", "FLAWLESS SKULL", "PERFECT SKULL"] + skip_log = any(substring in item_name for substring in filtered_substrings) or any(match == item_name.strip() for match in filtered_matches) + if self._location is not None and not skip_log: + Logger.debug(f"Stashed and logged: {item_name}") self._location_stats[self._location]["items"].append(item_name) self._location_stats["totals"]["items"] += 1 - if send_message: - self._messenger.send_item(item_name, img, self._location, ocr_text) + if send_message and self._messenger.enabled and not skip_log: + if expression[0] != "@": + self._messenger.send_item(item_name, img, self._location, ocr_text, expression, item_props) def log_death(self, img: str): self._death_counter += 1 @@ -64,7 +68,8 @@ def log_death(self, img: str): self._location_stats[self._location]["deaths"] += 1 self._location_stats["totals"]["deaths"] += 1 - self._messenger.send_death(self._location, img) + if self._messenger.enabled: + self._messenger.send_death(self._location, img) def log_chicken(self, img: str): self._chicken_counter += 1 @@ -72,7 +77,7 @@ def log_chicken(self, img: str): self._location_stats[self._location]["chickens"] += 1 self._location_stats["totals"]["chickens"] += 1 - if Config().general["discord_log_chicken"]: + if Config().general["discord_log_chicken"] and self._messenger.enabled: self._messenger.send_chicken(self._location, img) def log_merc_death(self): @@ -210,7 +215,8 @@ def _create_msg(self): def _send_status_update(self): msg = f"Status Report\n{self._create_msg()}\nVersion: {__version__}" - self._messenger.send_message(msg) + if self._messenger.enabled: + self._messenger.send_message(msg) def _save_stats_to_file(self): msg = self._create_msg() @@ -223,7 +229,7 @@ def _save_stats_to_file(self): for item_name in stats["items"]: msg += f"\n {item_name}" - with open(file=f"stats/{self._stats_filename}", mode="w+", encoding="utf-8") as f: + with open(file=f"log/stats/{self._stats_filename}", mode="w+", encoding="utf-8") as f: f.write(msg) diff --git a/src/health_manager.py b/src/health_manager.py index 19f8a6743..b70945e32 100644 --- a/src/health_manager.py +++ b/src/health_manager.py @@ -15,19 +15,30 @@ from random import uniform pause_state = True +panel_check_paused = False def get_pause_state(): - global pause_state return pause_state def set_pause_state(state: bool): global pause_state prev = get_pause_state() if prev != state: - debug_str = "pausing" if state else "active" + debug_str = "paused" if state else "active" Logger.info(f"Health Manager is now {debug_str}") pause_state = state +def get_panel_check_paused(): + return panel_check_paused + +def set_panel_check_paused(state: bool): + global panel_check_paused + prev = get_panel_check_paused() + if prev != state: + debug_str = "pausing" if state else "activating" + Logger.info(f"Health Manager is now {debug_str} inventory panel check") + panel_check_paused = state + class HealthManager: def __init__(self): self._do_monitor = False @@ -64,7 +75,7 @@ def _do_chicken(self, img): mouse.release(button="right") view.save_and_exit() if Config().general["info_screenshots"]: - self._last_chicken_screenshot = "./info_screenshots/info_debug_chicken_" + time.strftime("%Y%m%d_%H%M%S") + ".png" + self._last_chicken_screenshot = "./log/screenshots/info/info_debug_chicken_" + time.strftime("%Y%m%d_%H%M%S") + ".png" cv2.imwrite(self._last_chicken_screenshot, img) self._did_chicken = True set_pause_state(True) @@ -76,9 +87,10 @@ def start_monitor(self): start = time.time() while self._do_monitor: - time.sleep(0.1) - # Wait until the flag is reset by main.py - if self._did_chicken or get_pause_state(): continue + if self._did_chicken or get_pause_state(): + wait(1) + continue + fn_start = time.perf_counter() img = grab() if is_visible(ScreenObjects.InGame, img): health_percentage = meters.get_health(img) @@ -111,20 +123,21 @@ def start_monitor(self): belt.drink_potion("mana", stats=[health_percentage, mana_percentage]) self._last_mana = time.time() # check merc - if is_visible(ScreenObjects.MercIcon, img): - merc_health_percentage = meters.get_merc_health(img) - merc_hp_potion_delay = 0 if merc_health_percentage == 1 else uniform(9, 10) - last_drink = time.time() - self._last_merc_heal - if merc_health_percentage <= Config().char["merc_chicken"]: - Logger.warning(f"Trying to chicken, merc HP {(merc_health_percentage*100):.1f}%!") - self._do_chicken(img) - if merc_health_percentage <= Config().char["heal_rejuv_merc"] and last_drink > 4.0: - belt.drink_potion("rejuv", merc=True, stats=[merc_health_percentage]) - self._last_merc_heal = time.time() - elif merc_health_percentage <= Config().char["heal_merc"] and last_drink > merc_hp_potion_delay: - belt.drink_potion("health", merc=True, stats=[merc_health_percentage]) - self._last_merc_heal = time.time() - if is_visible(ScreenObjects.LeftPanel, img) or is_visible(ScreenObjects.RightPanel, img): + if any([Config().char[x] for x in ["heal_rejuv_merc", "merc_chicken", "heal_merc"]]): + if is_visible(ScreenObjects.MercIcon, img): + merc_health_percentage = meters.get_merc_health(img) + merc_hp_potion_delay = 0 if merc_health_percentage == 1 else uniform(9, 10) + last_drink = time.time() - self._last_merc_heal + if Config().char["merc_chicken"] and (merc_health_percentage <= Config().char["merc_chicken"]): + Logger.warning(f"Trying to chicken, merc HP {(merc_health_percentage*100):.1f}%!") + self._do_chicken(img) + if Config().char["heal_rejuv_merc"] and (merc_health_percentage <= Config().char["heal_rejuv_merc"] and last_drink > 4.0): + belt.drink_potion("rejuv", merc=True, stats=[merc_health_percentage]) + self._last_merc_heal = time.time() + elif Config().char["heal_merc"] and (merc_health_percentage <= Config().char["heal_merc"] and last_drink > merc_hp_potion_delay): + belt.drink_potion("health", merc=True, stats=[merc_health_percentage]) + self._last_merc_heal = time.time() + if not get_panel_check_paused() and (is_visible(ScreenObjects.LeftPanel, img) or is_visible(ScreenObjects.RightPanel, img)): Logger.warning(f"Found an open inventory / quest / skill / stats page. Close it.") self._count_panel_detects += 1 if self._count_panel_detects >= 2: @@ -132,6 +145,10 @@ def start_monitor(self): Logger.warning(f"Found an open inventory / quest / skill / stats page again. Chicken to dismiss.") self._do_chicken(img) common.close() + fn_end = time.perf_counter() + wait_time = 3/25 - (fn_start - fn_end) + if wait_time > 0: + wait(wait_time) # wait 3 frames before rechecking Logger.debug("Stop health monitoring") @@ -141,9 +158,14 @@ def start_monitor(self): import keyboard import os from health_manager import set_pause_state - keyboard.add_hotkey('f12', lambda: Logger.info('Exit Health Manager') or os._exit(1)) + from screen import start_detecting_window, stop_detecting_window, grab + keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) + Logger.info("Open d2r window and press f11 to start health manager") + keyboard.wait("f11") + start_detecting_window() + manager = HealthManager() - set_pause_state(True) + set_pause_state(False) Logger.info("Press f12 to exit health manager") health_monitor_thread = threading.Thread(target=manager.start_monitor) health_monitor_thread.start() diff --git a/src/inventory/belt.py b/src/inventory/belt.py index 6c9f8b799..60e8b0139 100644 --- a/src/inventory/belt.py +++ b/src/inventory/belt.py @@ -1,9 +1,9 @@ import itertools +from item import consumables from logger import Logger -from typing import List import numpy as np -from template_finder import TemplateFinder -from inventory import common, consumables, personal +import template_finder +from inventory import common, personal from ui import view from ui_manager import is_visible, wait_until_visible, ScreenObjects, wait_until_hidden from utils.custom_mouse import mouse @@ -72,7 +72,7 @@ def _cut_potion_img(img: np.ndarray, column: int, row: int) -> np.ndarray: ] return cut_roi(img, roi) -def drink_potion(potion_type: str, merc: bool = False, stats: List = []) -> bool: +def drink_potion(potion_type: str, merc: bool = False, stats: list = []) -> bool: img = grab() for i in range(4): potion_img = _cut_potion_img(img, i, 0) @@ -151,7 +151,7 @@ def fill_up_belt_from_inventory(num_loot_columns: int): pot_positions = [] for column, row in itertools.product(range(num_loot_columns), range(4)): center_pos, slot_img = common.get_slot_pos_and_img(img, column, row) - found = TemplateFinder().search(["GREATER_HEALING_POTION", "GREATER_MANA_POTION", "SUPER_HEALING_POTION", "SUPER_MANA_POTION", "FULL_REJUV_POTION", "REJUV_POTION"], slot_img, threshold=0.9).valid + found = template_finder.search(["GREATER_HEALING_POTION", "GREATER_MANA_POTION", "SUPER_HEALING_POTION", "SUPER_MANA_POTION", "FULL_REJUV_POTION", "REJUV_POTION"], slot_img, threshold=0.9).valid if found: pot_positions.append(center_pos) keyboard.press("shift") diff --git a/src/inventory/common.py b/src/inventory/common.py index 93fbeffc5..0bedc1d04 100644 --- a/src/inventory/common.py +++ b/src/inventory/common.py @@ -3,16 +3,17 @@ import numpy as np import keyboard import time +import itertools from utils.custom_mouse import mouse -from template_finder import TemplateFinder -from ui_manager import detect_screen_object, ScreenObjects, is_visible, wait_until_hidden +from ui_manager import detect_screen_object, ScreenObjects, is_visible, wait_until_hidden, center_mouse +import template_finder from utils.misc import wait, trim_black, color_filter, cut_roi -from inventory import consumables +from item import consumables from ui import view from screen import convert_screen_to_monitor, grab from logger import Logger -from ocr import Ocr from template_finder import TemplateMatch +from d2r_image import ocr def get_slot_pos_and_img(img: np.ndarray, column: int, row: int) -> tuple[tuple[int, int], np.ndarray]: """ @@ -48,16 +49,33 @@ def slot_has_item(slot_img: np.ndarray) -> bool: avg_brightness = np.average(slot_img[:, :, 2]) return avg_brightness > 16.0 -def close(img: np.ndarray = None) -> np.ndarray: +def inventory_is_open(img: np.ndarray = None) -> bool: img = grab() if img is None else img - if is_visible(ScreenObjects.RightPanel, img) or is_visible(ScreenObjects.LeftPanel, img): + return ( + is_visible(ScreenObjects.RightPanel, img) + or is_visible(ScreenObjects.LeftPanel, img) + or is_visible(ScreenObjects.InventoryBackground, img) + ) + +def close(img: np.ndarray = None) -> np.ndarray | None: + img = grab() if img is None else img + if inventory_is_open(img): + # close open inventory keyboard.send("esc") - if not wait_until_hidden(ScreenObjects.RightPanel, 1) and not wait_until_hidden(ScreenObjects.LeftPanel, 1): + # check to ensure it closed + wait(0.04, 0.08) + timer = True + start = time.time() + while inventory_is_open() and (timer := time.time() - start < 1.5): + wait(0.04) + # if inventory still open, try another method + if not timer: success = view.return_to_play() if not success: return None return img + def calc_item_roi(img_pre, img_post): try: diff = cv2.absdiff(img_pre, img_post) @@ -78,14 +96,24 @@ def calc_item_roi(img_pre, img_post): Logger.error(f"_calc_item_roi: Unexpected {err=}, {type(err)=}") return None +def dimensions_to_slots(dimensions: list, row_col: tuple) -> list: + row_min = row_col[0] + row_max = row_min + dimensions[1] + col_min = row_col[1] + col_max = col_min + dimensions[0] + slots = set() + for row, col in itertools.product(range(row_min, row_max), range(col_min, col_max)): + slots.add((row, col)) + return slots + def tome_state(img: np.ndarray = None, tome_type: str = "tp", roi: list = None): img = img if img is not None else grab() - if (tome_found := TemplateFinder().search([f"{tome_type.upper()}_TOME", f"{tome_type.upper()}_TOME_RED"], img, roi = roi, threshold = 0.8, best_match = True, normalize_monitor = True)).valid: + if (tome_found := template_finder.search([f"{tome_type.upper()}_TOME", f"{tome_type.upper()}_TOME_RED"], img, roi = roi, threshold = 0.8, best_match = True)).valid: if tome_found.name == f"{tome_type.upper()}_TOME": state = "ok" else: state = "empty" - position = tome_found.center + position = tome_found.center_monitor else: state = position = None return state, position @@ -110,9 +138,9 @@ def read_gold(img: np.ndarray = None, type: str = "inventory"): img = cut_roi(img, Config().ui_roi[f"{type}_gold_digits"]) # _, img = color_filter(img, Config().colors["gold_numbers"]) img = np.pad(img, pad_width=[(8, 8),(8, 8),(0, 0)], mode='constant') - ocr_result = Ocr().image_to_text( + ocr_result = ocr.image_to_text( images = img, - model = "engd2r_inv_th_fast", + model = "hover-eng_inconsolata_inv_th_fast", psm = 13, scale = 1.2, crop_pad = False, @@ -122,7 +150,7 @@ def read_gold(img: np.ndarray = None, type: str = "inventory"): digits_only = True, fix_regexps = False, check_known_errors = False, - check_wordlist = False, + correct_words = False, )[0] number=int(ocr_result.text.strip()) Logger.debug(f"{type.upper()} gold: {number}") @@ -179,7 +207,11 @@ def get_active_tab(indicator: TemplateMatch = None) -> int: if indicator.valid: return indicator_location_to_tab_count(indicator.center) else: - Logger.error("common/get_active_tab(): Error finding tab indicator") + center_mouse() + if (indicator := detect_screen_object(ScreenObjects.TabIndicator)).valid: + return indicator_location_to_tab_count(indicator.center) + else: + Logger.error("common/get_active_tab(): Error finding tab indicator") return -1 def select_tab(idx: int): diff --git a/src/inventory/consumables.py b/src/inventory/consumables.py deleted file mode 100644 index 731659fce..000000000 --- a/src/inventory/consumables.py +++ /dev/null @@ -1,150 +0,0 @@ -from config import Config -import cv2 -import numpy as np -import time -import parse -from utils.custom_mouse import mouse -from template_finder import TemplateFinder -from inventory import personal -from utils.misc import wait -from screen import grab -from dataclasses import dataclass -from logger import Logger -from item import ItemCropper - -@dataclass -class Consumables: - tp: int = 0 - id: int = 0 - rejuv: int = 0 - health: int = 0 - mana: int = 0 - key: int = 0 - def __getitem__(self, key): - return super().__getattribute__(key) - def __setitem__(self, key, value): - setattr(self, key, value) - -consumable_needs = Consumables() -item_consumables_map = { - "misc_rejuvenation_potion": "rejuv", - "misc_full_rejuvenation_potion": "rejuv", - "misc_super_healing_potion": "health", - "misc_greater_healing_potion": "health", - "misc_super_mana_potion": "mana", - "misc_greater_mana_potion": "mana", - "misc_scroll_tp": "tp", - "misc_scroll_id": "id", - "misc_key": "key" -} -pot_cols = { - "rejuv": Config().char["belt_rejuv_columns"], - "health": Config().char["belt_hp_columns"], - "mana": Config().char["belt_mp_columns"], -} - -def get_needs(consumable_type: str = None): - global consumable_needs - if consumable_type: - consumable = reduce_name(consumable_type) - return consumable_needs[consumable] - return consumable_needs - -def set_needs(consumable_type: str, quantity: int): - global consumable_needs - consumable = reduce_name(consumable_type) - consumable_needs[consumable] = quantity - -def increment_need(consumable_type: str = None, quantity: int = 1): - """ - Adjust the consumable_needs of a specific consumable - :param consumable_type: Name of item in pickit or in consumable_map - :param quantity: Increase the need (+int) or decrease the need (-int) - """ - global consumable_needs - consumable = reduce_name(consumable_type) - consumable_needs[consumable] = max(0, consumable_needs[reduce_name(consumable)] + quantity) - -def reduce_name(consumable_type: str): - global item_consumables_map - if consumable_type in item_consumables_map: - consumable_type = item_consumables_map[consumable_type] - elif consumable_type in item_consumables_map.values(): - pass - else: - Logger.warning(f"adjust_consumable_need: unknown item: {consumable_type}") - return consumable_type - -def get_remaining(item_name: str = None) -> int: - global consumable_needs, pot_cols - if item_name is None: - Logger.error("get_remaining: param item_name is required") - return -1 - if item_name.lower() in ["health", "mana", "rejuv"]: - return pot_cols[item_name] * Config().char["belt_rows"] - consumable_needs[item_name] - elif item_name.lower() in ['tp', 'id']: - return 20 - consumable_needs[item_name] - elif item_name.lower() == "key": - return 12 - consumable_needs[item_name] - else: - Logger.error(f"get_remaining: error with item_name={item_name}") - return -1 - -def should_buy(item_name: str = None, min_remaining: int = None, min_needed: int = None) -> bool: - global consumable_needs - if item_name is None: - Logger.error("should_buy: param item_name is required") - return False - if min_needed: - return consumable_needs[item_name] >= min_needed - elif min_remaining: - return get_remaining(item_name) <= min_remaining - else: - Logger.error("should_buy: need to specify min_remaining or min_needed") - return False - -def update_tome_key_needs(img: np.ndarray = None, item_type: str = "tp") -> bool: - img = personal.open(img) - if item_type.lower() in ["tp", "id"]: - match = TemplateFinder().search( - [f"{item_type.upper()}_TOME", f"{item_type.upper()}_TOME_RED"], - img, - roi = Config().ui_roi["restricted_inventory_area"], - best_match = True, - normalize_monitor=True - ) - if match.valid: - if match.name == f"{item_type.upper()}_TOME_RED": - set_needs(item_type, 20) - return True - # else the tome exists and is not empty, continue - else: - Logger.debug(f"update_tome_key_needs: could not find {item_type}") - return False - elif item_type.lower() in ["key"]: - match = TemplateFinder().search("INV_KEY", img, roi = Config().ui_roi["restricted_inventory_area"], normalize_monitor = True) - if not match.valid: - return False - else: - Logger.error(f"update_tome_key_needs failed, item_type: {item_type} not supported") - return False - mouse.move(*match.center, randomize=4, delay_factor=[0.5, 0.7]) - wait(0.2, 0.2) - hovered_item = grab() - # get the item description box - item_box = ItemCropper().crop_item_descr(hovered_item, model="engd2r_inv_th_fast") - if item_box.valid: - try: - result = parse.search("Quantity: {:d}", item_box.ocr_result.text).fixed[0] - if item_type.lower() in ["tp", "id"]: - set_needs(item_type, 20 - result) - if item_type.lower() == "key": - set_needs(item_type, 12 - result) - except Exception as e: - Logger.error(f"update_tome_key_needs: unable to parse quantity for {item_type}. Exception: {e}") - else: - Logger.error(f"update_tome_key_needs: Failed to capture item description box for {item_type}") - if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/failed_capture_item_description_box" + time.strftime("%Y%m%d_%H%M%S") + ".png", hovered_item) - return False - return True \ No newline at end of file diff --git a/src/inventory/personal.py b/src/inventory/personal.py index 204bce8dd..d2f261fc6 100644 --- a/src/inventory/personal.py +++ b/src/inventory/personal.py @@ -1,28 +1,31 @@ import itertools from game_stats import GameStats -from item import ItemFinder, Item -from item.item_cropper import ItemText -from logger import Logger -from screen import grab, convert_screen_to_monitor import keyboard import cv2 import time import numpy as np from dataclasses import dataclass +import parse -from template_finder import TemplateFinder +from logger import Logger from config import Config +import template_finder from utils.misc import wait, is_in_roi, mask_by_roi from utils.custom_mouse import mouse from inventory import stash, common, vendor from ui import view from ui_manager import detect_screen_object, is_visible, select_screen_object_match, wait_until_visible, ScreenObjects, center_mouse, wait_for_update -from item import ItemCropper from messages import Messenger +from d2r_image import processing as d2r_image +from d2r_image.data_models import HoveredItem, ItemText +from screen import grab, convert_screen_to_monitor +from item import consumables +from bnip.NTIPAliasStat import NTIPAliasStat as NTIP_STATS +from bnip.actions import should_id, should_keep inv_gold_full = False messenger = Messenger() -item_finder = ItemFinder() + nontradable_items = ["key of ", "essense of", "wirt's", "jade figurine"] @dataclass @@ -40,12 +43,13 @@ def __setitem__(self, key, value): setattr(self, key, value) def get_inventory_gold_full(): - global inv_gold_full return inv_gold_full -def set_inventory_gold_full(bool): +def set_inventory_gold_full(new_value: bool): global inv_gold_full - inv_gold_full = bool + if get_inventory_gold_full() != new_value: + Logger.info(f"Set inventory gold full: {new_value}") + inv_gold_full = new_value def inventory_has_items(img: np.ndarray = None, close_window = False) -> bool: """ @@ -66,18 +70,19 @@ def inventory_has_items(img: np.ndarray = None, close_window = False) -> bool: return True return False + def stash_all_items(items: list = None): """ Stashing all items in inventory. Stash UI must be open when calling the function. """ global messenger - if items is None: + if not get_inventory_gold_full() and items is None: Logger.debug("No items to stash, skip") return None center_mouse() # Wait for stash to fully load if not common.wait_for_left_inventory(): - Logger.error("stash_all_items(): Could not determine to be in stash menu. Continue...") + Logger.error("stash_all_items(): Failed to find stash menu. Continue...") return items # stash gold if Config().char["stash_gold"]: @@ -93,19 +98,19 @@ def stash_all_items(items: list = None): # If gold read by OCR fails, fallback to old method gold_btn = detect_screen_object(ScreenObjects.GoldBtnInventory) select_screen_object_match(gold_btn) + # move cursor away from button to interfere with screen grab + mouse.move(-60, 0, absolute=False, randomize=15, delay_factor=[0.1, 0.3]) if wait_until_visible(ScreenObjects.DepositBtn, 3).valid: keyboard.send("enter") #if stash already full of gold just nothing happens -> gold stays on char -> no popup window else: Logger.error("stash_all_items(): deposit button not detected, failed to stash gold") - # move cursor away from button to interfere with screen grab - mouse.move(-120, 0, absolute=False, randomize=15, delay_factor=[0.3, 0.5]) # if 0 gold becomes visible in personal inventory then the stash tab still has room for gold - stash_full_of_gold = not wait_until_visible(ScreenObjects.GoldNone, 1.5).valid + stash_full_of_gold = not wait_until_visible(ScreenObjects.GoldNone, 2).valid if stash_full_of_gold: Logger.debug("Stash tab is full of gold, selecting next stash tab.") stash.set_curr_stash(gold = (stash.get_curr_stash()["gold"] + 1)) if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/info_gold_stash_full_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + cv2.imwrite("./log/screenshots/info/info_gold_stash_full_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) if stash.get_curr_stash()["gold"] > 3: #decide if gold pickup should be disabled or gambling is active vendor.set_gamble_status(True) @@ -114,6 +119,8 @@ def stash_all_items(items: list = None): return stash_all_items(items=items) else: set_inventory_gold_full(False) + if not items: + return [] # check if stash tab is completely full (no empty slots) common.select_tab(stash.get_curr_stash()["items"]) while stash.get_curr_stash()["items"] <= 3: @@ -123,7 +130,7 @@ def stash_all_items(items: list = None): else: Logger.debug(f"Stash tab completely full, advance to next") if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/stash_tab_completely_full_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) + cv2.imwrite("./log/screenshots/info/stash_tab_completely_full_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) if Config().char["fill_shared_stash_first"]: stash.set_curr_stash(items = (stash.get_curr_stash()["items"] - 1)) else: @@ -138,7 +145,7 @@ def stash_all_items(items: list = None): # could not stash all items, stash tab is likely full Logger.debug("Wanted to stash item, but it's still in inventory. Assumes full stash. Move to next.") if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/debug_info_inventory_not_empty_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + cv2.imwrite("./log/screenshots/info/debug_info_inventory_not_empty_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) if Config().char["fill_shared_stash_first"]: stash.set_curr_stash(items = (stash.get_curr_stash()["items"] - 1)) else: @@ -151,114 +158,9 @@ def stash_all_items(items: list = None): Logger.debug("Done stashing") return items -def keep_item(item_box: ItemText = None, found_item: Item = None, do_logging: bool = True) -> bool: - """ - Check if an item should be kept, the item should be hovered and in own inventory when function is called - :param img: Image in which the item is searched (item details should be visible) - :param do_logging: Bool value to turn on/off logging for items that are found and should be kept - :return: Bool if item should be kept - """ - ymax = 50 if item_box.data.shape[0] < 50 else item_box.data.shape[0] - img = item_box.data[0:ymax,:] - - if any(x in found_item.name for x in ["potion", "misc_scroll"]) or found_item.name == "misc_key" or (Config().items[found_item.name].pickit_type == 0): - return False - setattr(found_item, "ocr_result", item_box["ocr_result"]) - - include_props = Config().items[found_item.name].include - exclude_props = Config().items[found_item.name].exclude - - if ( - #Disable include/exclude params for uniq, rare, magical if ident is disabled in params.ini - ( - not Config().char["id_items"] - and any(item_type in found_item.name for item_type in ["uniq", "magic", "rare", "set"]) - ) - # items that are checked to be kept should all be identified unless an error occurred or user preferred unidentified - or is_visible(ScreenObjects.Unidentified, item_box.data) - ): - include_props = False - exclude_props = False - - if not (include_props or exclude_props): - if do_logging: - Logger.debug(f"{found_item.name}: Stashing") - return True - include = True - include_logic_type = Config().items[found_item.name].include_type - if include_props: - include = False - found_props=[] - for prop in include_props: - if len(prop)>1: - found_subprops=[] - for subprop in prop: - try: - template_match = TemplateFinder().search(subprop, img, threshold=0.95) - except: - Logger.error(f"{found_item.name}: can't find template file for required {prop}, ignore just in case") - template_match = lambda: None; template_match.valid = True - if template_match.valid: - if include_logic_type == "OR": - found_subprops.append(True) - else: - found_props.append (True) - break - else: - found_subprops.append(False) - break - if (len(found_subprops) > 0 and all(found_subprops)): - include = True - break - else: - try: - template_match = TemplateFinder().search(prop, img, threshold=0.95) - except: - Logger.error(f"{found_item.name}: can't find template file for required {prop}, ignore just in case") - template_match = lambda: None; template_match.valid = True - if template_match.valid: - if include_logic_type == "AND": - found_props.append(True) - else: - include = True - break - else: - found_props.append(False) - if include_logic_type == "AND" and len(found_props) > 0 and all(found_props): - include = True - if not include: - if do_logging: - Logger.debug(f"{found_item.name}: Discarding. Required {include_logic_type}({include_props})={include}") - return False - exclude = False - exclude_logic_type = Config().items[found_item.name].exclude_type - if exclude_props: - found_props = [] - for prop in exclude_props: - try: - template_match = TemplateFinder().search(prop, img, threshold=0.97) - except: - Logger.error(f"{found_item.name}: can't find template file for exclusion {prop}, ignore just in case") - template_match = lambda: None; template_match.valid = False - if template_match.valid: - if exclude_logic_type == "AND": - found_props.append(True) - else: - exclude = True - break - else: - found_props.append(False) - if exclude_logic_type == "AND" and len(exclude_props) > 0 and all(found_props): - exclude = True - if include and not exclude: - if do_logging: - Logger.debug(f"{found_item.name}: Stashing. Required {include_logic_type}({include_props})={include}, exclude {exclude_logic_type}({exclude_props})={exclude}") - return True - return False - def open(img: np.ndarray = None) -> np.ndarray: img = grab() if img is None else img - if not is_visible(ScreenObjects.RightPanel, img): + if not common.inventory_is_open(): keyboard.send(Config().char["inventory_screen"]) if not wait_until_visible(ScreenObjects.RightPanel, 1).valid: if not view.return_to_play(): @@ -270,7 +172,29 @@ def open(img: np.ndarray = None) -> np.ndarray: img = grab() return img -def inspect_items(inp_img: np.ndarray = None, close_window: bool = True, game_stats: GameStats = None) -> list[BoxInfo]: + +def log_item(item_box: ItemText, item_properties: HoveredItem): + if item_box is not None and item_box.ocr_result: + Logger.debug(f"OCR mean confidence: {item_box.ocr_result.mean_confidence}") + Logger.debug(item_properties.Text) + if Config().general["info_screenshots"]: + timestamp = time.strftime("%Y%m%d_%H%M%S") + found_low_confidence = False + for cnt, x in enumerate(item_box.ocr_result.word_confidences): + if x <= 88: + try: + Logger.debug(f"Low confidence word #{cnt}: {item_box.ocr_result.original_text.split()[cnt]} -> {item_box.ocr_result.text.split()[cnt]}, Conf: {x}, save screenshot") + found_low_confidence = True + except: pass + if found_low_confidence: + cv2.imwrite(f"./log/screenshots/info/ocr_low_confidence_box_{timestamp}.png", item_box.img) + +def log_item_fail(hovered_item, slot): + Logger.error(f"item segmentation failed for slot_pos: {slot[0]}") + if Config().general["info_screenshots"]: + cv2.imwrite("./log/screenshots/info/failed_item_box_" + time.strftime("%Y%m%d_%H%M%S") + ".png", hovered_item) + +def inspect_items(inp_img: np.ndarray = None, close_window: bool = True, game_stats: GameStats = None, ignore_sell: bool = False) -> list[BoxInfo]: """ Iterate over all picked items in inventory--ID items and decide which to stash :param img: Image in which the item is searched (item details should be visible) @@ -287,156 +211,166 @@ def inspect_items(inp_img: np.ndarray = None, close_window: bool = True, game_st boxes = [] # iterate over slots with items item_rois = [] + already_detected_slots = set() for count, slot in enumerate(slots): failed = False - # ignore this slot if it lies within in a previous item's ROI + # ignore this slot if it lies within the range of a previous item's dimension property + if (slot[1], slot[2]) in already_detected_slots: continue + # ignore this slot if it lies within in a previous item's ROI (no dimension property) if any(is_in_roi(item_roi, slot[0]) for item_roi in item_rois): continue - img = grab() + img = grab(True) x_m, y_m = convert_screen_to_monitor(slot[0]) delay = [0.2, 0.3] if count else [1, 1.3] mouse.move(x_m, y_m, randomize = 10, delay_factor = delay) wait(0.1, 0.2) - hovered_item = grab() + hovered_item = grab(True) # get the item description box - item_box = ItemCropper().crop_item_descr(hovered_item) - if item_box.valid: - # determine the item's ROI in inventory - cnt=0 - while True: - pre = mask_by_roi(img, Config().ui_roi["open_inventory_area"]) - post = mask_by_roi(hovered_item, Config().ui_roi["open_inventory_area"]) - # will sometimes have equivalent diff if mouse ends up in an inconvenient place. - if not np.array_equal(pre, post): - break - Logger.debug(f"inspect_items: pre=post, try again. slot {slot[0]}") - center_mouse() - img = grab() - mouse.move(x_m, y_m, randomize = 10, delay_factor = delay) - wait(0.3, 0.5) - hovered_item = grab() - cnt += 1 - if cnt >= 2: - Logger.error(f"inspect_items: Unable to get item's inventory ROI, slot {slot[0]}") - break - item_name = item_box.ocr_result.text.splitlines()[0] if not vendor_open else item_box.ocr_result.text.splitlines()[1] - extend_roi = item_box.roi[:] - extend_roi[3] = extend_roi[3] + 30 - item_roi = common.calc_item_roi(mask_by_roi(pre, extend_roi, type = "inverse"), mask_by_roi(post, extend_roi, type = "inverse")) - if item_roi: - item_rois.append(item_roi) - # determine whether the item can be sold - item_can_be_traded = not any(substring in item_name for substring in nontradable_items) - sell = Config().char["sell_junk"] and item_can_be_traded - # check and see if item exists in pickit - try: - found_item = item_finder.search(item_box.data)[0] - except: - Logger.debug(f"inspect_items: item_finder returned None or error for {item_name}, likely an accidental pick") - Logger.debug(f"Dropping {item_name}") - found_item = False - # attempt to identify item - need_id = False - if Config().char["id_items"] and found_item: - # if this item has no include or exclude properties, leave it unidentified - implied_no_id = not (Config().items[found_item.name].include or Config().items[found_item.name].exclude) - implied_no_id |= not any(item_type in found_item.name for item_type in ["uniq", "magic", "rare", "set"]) - if not implied_no_id: - if (is_unidentified := is_visible(ScreenObjects.Unidentified, item_box.data)): - need_id = True - center_mouse() - tome_state, tome_pos = common.tome_state(grab(), tome_type = "id", roi = Config().ui_roi["restricted_inventory_area"]) - if is_unidentified and tome_state is not None and tome_state == "ok": - common.id_item_with_tome([x_m, y_m], tome_pos) - need_id = False - # recapture box after ID - mouse.move(x_m, y_m, randomize = 4, delay_factor = delay) - wait(0.2, 0.3) - hovered_item = grab() - item_box = ItemCropper().crop_item_descr(hovered_item) + item_properties, item_box = (None, None) + try: # ! This happens because we don't know the items slot count. To get more context remove the try and catch and see what happens + item_properties, item_box = d2r_image.get_hovered_item(hovered_item) + except Exception as e: + Logger.error(f"personal.inspect_items(): Failed to get item properties for slot {slot}") + failed = True + if item_box is None: + failed = True + else: + if item_box.ocr_result: + if item_properties is not None and hasattr(item_properties, 'BaseItem') and "dimensions" in item_properties.BaseItem: + positions = common.dimensions_to_slots(item_properties.BaseItem["dimensions"], (slot[1], slot[2])) + already_detected_slots.update(positions) + else: + Logger.error(f"personal.inspect_items(): unable to determine dimensions for slot {slot}") + # determine the item's ROI in inventory + cnt=0 + while True: + pre = mask_by_roi(img, Config().ui_roi["open_inventory_area"]) + post = mask_by_roi(hovered_item, Config().ui_roi["open_inventory_area"]) + # will sometimes have equivalent diff if mouse ends up in an inconvenient place. + if not np.array_equal(pre, post): + break + Logger.debug(f"inspect_items: pre=post, try again. slot {slot[0]}") + center_mouse(delay_factor=[0.05, 0.1]) + img = grab(True) + mouse.move(x_m, y_m, randomize = 10, delay_factor = delay) + wait(0.05, 0.1) + hovered_item = grab(True) + cnt += 1 + if cnt >= 2: + Logger.error(f"inspect_items: Unable to get item's inventory ROI, slot {slot[0]}") + break + extend_roi = item_box.roi[:] + extend_roi[3] = extend_roi[3] + 30 + item_roi = common.calc_item_roi(mask_by_roi(pre, extend_roi, type = "inverse"), mask_by_roi(post, extend_roi, type = "inverse")) + if item_roi: + item_rois.append(item_roi) - if item_box.valid: - Logger.debug(f"OCR ITEM DESCR: Mean conf: {item_box.ocr_result.mean_confidence}") - for i, line in enumerate(list(filter(None, item_box.ocr_result.text.splitlines()))): - Logger.debug(f"OCR LINE{i}: {line}") - if Config().general["loot_screenshots"]: - timestamp = time.strftime("%Y%m%d_%H%M%S") - found_low_confidence = False - for cnt, x in enumerate(item_box.ocr_result['word_confidences']): - if x <= 88: - try: - Logger.debug(f"Low confidence word #{cnt}: {item_box.ocr_result['original_text'].split()[cnt]} -> {item_box.ocr_result['text'].split()[cnt]}, Conf: {x}, save screenshot") - found_low_confidence = True - except: pass - if found_low_confidence: - cv2.imwrite(f"./loot_screenshots/ocr_box_{timestamp}_o.png", item_box.ocr_result['original_img']) - cv2.imwrite(f"./loot_screenshots/ocr_box_{timestamp}_n.png", item_box.ocr_result['processed_img']) + # determine whether the item can be sold + ocr_result_split = item_box.ocr_result.text.splitlines() - # decide whether to keep item - keep = False - if not need_id: - keep = keep_item(item_box, found_item) if found_item else False - if keep: - sell = need_id = False + item_name = vendor_open and ocr_result_split[1] or ocr_result_split[0] + item_can_be_traded = not any(substring in item_name for substring in nontradable_items) + sell = Config().char["sell_junk"] and item_can_be_traded and not ignore_sell + is_unidentified = is_visible(ScreenObjects.Unidentified, item_box.img) box = BoxInfo( - img = item_box.data, + img = item_box.img, pos = (x_m, y_m), column = slot[2], row = slot[1], - need_id = need_id, sell = sell, - keep = keep + need_id = False, + keep = False ) - # sell if not keeping item, vendor is open, and item type can be traded - if not (keep or need_id) and vendor_open and item_can_be_traded: - Logger.debug(f"Selling {item_name}") - box.sell = True - transfer_items([box], action = "sell") - continue - # if item is to be kept and is already ID'd or doesn't need ID, log and stash - if game_stats is not None and (keep and not need_id): - game_stats.log_item_keep(found_item.name, Config().items[found_item.name].pickit_type == 2, item_box.data, item_box.ocr_result.text) - # if item is to be kept or still needs to be sold or identified, append to list - if keep or sell or need_id: - # save item info - boxes.append(box) - else: - # if item isn't going to be kept (or sold if vendor window not open), trash it - Logger.debug(f"Dropping {item_name}") + + tome_state = None + try: + if (is_unidentified and should_id(item_properties.as_dict())): + box.need_id = True + center_mouse() + tome_state, tome_pos = common.tome_state(grab(True), tome_type = "id", roi = Config().ui_roi["restricted_inventory_area"]) + if is_unidentified and tome_state is not None and tome_state == "ok": + common.id_item_with_tome([x_m, y_m], tome_pos) + box.need_id = False + is_unidentified = True + # recapture box after ID + mouse.move(x_m, y_m, randomize = 4, delay_factor = delay) + wait(0.05, 0.1) + hovered_item = grab(True) + item_properties, item_box = d2r_image.get_hovered_item(hovered_item) + + if item_box is not None: + log_item(item_box, item_properties) + # decide whether to keep item + box.keep, expression = should_keep(item_properties.as_dict()) + + # make sure it's not a consumable + # TODO: logic for trying to add potion to belt if there are needs + box.keep &= not bool(consumables.is_consumable(item_properties)) + + if box.keep: + Logger.info(f"Keep {item_name}. Expression: {expression}") + sell = False + elif box.need_id: + Logger.debug(f"Need to ID {item_name}.") + else: + #Logger.debug(f"Discarding {json.dumps(item_properties.as_dict(), indent = 4)}") + Logger.debug(f"Discarding {item_name}.") + + # sell if not keeping item, vendor is open, and item type can be traded + if vendor_open and item_can_be_traded and not (box.keep or box.need_id): + box.sell = True + transfer_items([box], action = "sell") + continue + + # if item is to be kept and is already ID'd or doesn't need ID, log and stash + if (box.keep and not box.need_id): + if game_stats is not None: + game_stats.log_item_keep(item_name, True, item_box.img, item_box.ocr_result.text, expression, item_properties.as_dict()) + # if item is to be kept or still needs to be sold or identified, append to list + if box.keep or sell or box.need_id: + # save item info + boxes.append(box) + else: + # if item isn't going to be kept (or sold if vendor window not open), trash it + transfer_items([box], action = "drop") + wait(0.05, 0.2) + else: + failed = True + except AttributeError as e: + failed = True + # * Drop item. + Logger.info(f"Dropping {item_name}. Failed with AttributeError {e}") transfer_items([box], action = "drop") - wait(0.3, 0.5) - else: - failed = True - else: - failed = True + + if failed: - Logger.error(f"item_cropper failed for slot_pos: {slot[0]}") - if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/failed_item_box_" + time.strftime("%Y%m%d_%H%M%S") + ".png", hovered_item) + log_item_fail(hovered_item, slot) + if close_window: - if not is_visible(ScreenObjects.RightPanel, img): - center_mouse() common.close() return boxes def transfer_items(items: list, action: str = "drop", img: np.ndarray = None) -> list: #requires open inventory / stash / vendor - img = img if img is not None else grab() + if not items: + return [] + img = img if img is not None else grab(True) filtered = [] left_panel_open = is_visible(ScreenObjects.LeftPanel, img) - if action == "drop": - filtered = [ item for item in items if item.keep == False and item.sell == False ] - elif action == "sell": - filtered = [ item for item in items if item.keep == False and item.sell == True ] - if not left_panel_open: - Logger.error(f"transfer_items: Can't perform, vendor is not open") - elif action == "stash": - if is_visible(ScreenObjects.GoldBtnStash, img): - filtered = [ item for item in items if item.keep == True ] - else: - Logger.error(f"transfer_items: Can't perform, stash is not open") - else: - Logger.error(f"transfer_items: incorrect action param={action}") + match action: + case "drop": + filtered = [ item for item in items if item.keep == False and item.sell == False ] + case "sell": + filtered = [ item for item in items if item.keep == False and item.sell == True ] + if not left_panel_open: + Logger.error(f"transfer_items: Can't perform, vendor is not open") + case "stash": + if is_visible(ScreenObjects.GoldBtnStash, img): + filtered = [ item for item in items if item.keep == True ] + else: + Logger.error(f"transfer_items: Can't perform, stash is not open") + case _: + Logger.error(f"transfer_items: incorrect action param={action}") if filtered: # if dropping, control+click to drop unless left panel is open, then drag to middle # if stashing, control+click to stash @@ -445,7 +379,7 @@ def transfer_items(items: list, action: str = "drop", img: np.ndarray = None) -> keyboard.send('ctrl', do_release=False) wait(0.1, 0.2) for item in filtered: - pre_hover_img = grab() + pre_hover_img = grab(True) _, slot_img = common.get_slot_pos_and_img(pre_hover_img, item.column, item.row) if not common.slot_has_item(slot_img): # item no longer exists in that position... @@ -458,7 +392,7 @@ def transfer_items(items: list, action: str = "drop", img: np.ndarray = None) -> # move to item position and left click mouse.move(*item.pos, randomize=4, delay_factor=[0.2, 0.4]) wait(0.2, 0.4) - pre_transfer_img = grab() + pre_transfer_img = grab(True) mouse.press(button="left") # wait for inventory image to update indicating successful transfer / item select success = wait_for_update(pre_transfer_img, Config().ui_roi["open_inventory_area"], 3) @@ -470,6 +404,7 @@ def transfer_items(items: list, action: str = "drop", img: np.ndarray = None) -> # if dropping, drag item to middle if vendor/stash is open if action == "drop" and left_panel_open: center_mouse() + wait(0.04, 0.08) mouse.press(button="left") wait(0.2, 0.3) mouse.release(button="left") @@ -485,4 +420,47 @@ def transfer_items(items: list, action: str = "drop", img: np.ndarray = None) -> Logger.info("Inventory gold is full, force stash") set_inventory_gold_full(gold_unchanged) keyboard.send('ctrl', do_press=False) - return items \ No newline at end of file + return items + +def update_tome_key_needs(img: np.ndarray = None, item_type: str = "tp") -> bool: + img = open(img) + if item_type.lower() in ["tp", "id"]: + match = template_finder.search( + [f"{item_type.upper()}_TOME", f"{item_type.upper()}_TOME_RED"], + img, + roi = Config().ui_roi["restricted_inventory_area"], + best_match = True, + ) + if match.valid: + if match.name == f"{item_type.upper()}_TOME_RED": + consumables.set_needs(item_type, 20) + return True + # else the tome exists and is not empty, continue + else: + Logger.debug(f"update_tome_key_needs: could not find {item_type}") + return False + elif item_type.lower() in ["key"]: + match = template_finder.search("INV_KEY", img, roi = Config().ui_roi["restricted_inventory_area"]) + if not match.valid: + return False + else: + Logger.error(f"update_tome_key_needs failed, item_type: {item_type} not supported") + return False + mouse.move(*match.center_monitor, randomize=4, delay_factor=[0.5, 0.7]) + wait(0.2, 0.2) + hovered_item = grab(True) + # get the item description box + item_properties, item_box = d2r_image.get_hovered_item(hovered_item) + if item_box is not None: + try: + quantity = int(item_properties.NTIPAliasStat[NTIP_STATS["quantity"]]) + max_quantity = int(item_properties.NTIPAliasStat[NTIP_STATS["quantitymax"]]) + consumables.set_needs(item_type, max_quantity - quantity) + except Exception as e: + Logger.error(f"update_tome_key_needs: unable to parse quantity for {item_type}. Exception: {e}") + else: + Logger.error(f"update_tome_key_needs: Failed to capture item description box for {item_type}") + if Config().general["info_screenshots"]: + cv2.imwrite("./log/screenshots/info/failed_capture_item_description_box" + time.strftime("%Y%m%d_%H%M%S") + ".png", hovered_item) + return False + return True \ No newline at end of file diff --git a/src/inventory/stash.py b/src/inventory/stash.py index 69b77c13b..28bf29e16 100644 --- a/src/inventory/stash.py +++ b/src/inventory/stash.py @@ -1,9 +1,6 @@ -from template_finder import TemplateFinder -from screen import grab, convert_screen_to_monitor from config import Config import os from utils.misc import wait -from utils.custom_mouse import mouse from logger import Logger from messages import Messenger diff --git a/src/inventory/vendor.py b/src/inventory/vendor.py index 257bf0b21..c64ec6586 100644 --- a/src/inventory/vendor.py +++ b/src/inventory/vendor.py @@ -1,13 +1,13 @@ from math import floor import keyboard -from template_finder import TemplateFinder +import template_finder from config import Config import numpy as np from utils.misc import wait from screen import grab from logger import Logger from utils.custom_mouse import mouse -from ui_manager import is_visible, select_screen_object_match, wait_until_visible, ScreenObjects +from ui_manager import center_mouse, is_visible, select_screen_object_match, wait_until_visible, ScreenObjects from inventory import personal, common, stash gamble_count = 0 @@ -49,20 +49,20 @@ def repair() -> bool: return True def gamble(): - if (refresh_btn := TemplateFinder().search_and_wait("REFRESH", threshold=0.79, timeout=4, normalize_monitor=True)).valid: + if (refresh_btn := template_finder.search_and_wait("REFRESH", threshold=0.79, timeout=4)).valid: #Gambling window is open. Starting to spent some coins max_gamble_count = floor(2000000/188000) # leave about 500k gold and assume buying coronets at ~188k while get_gamble_status() and get_gamble_count() < max_gamble_count: img=grab() for item in Config().char["gamble_items"]: # while desired gamble item is not on screen, refresh - while not (desired_item := TemplateFinder().search (item.upper(), grab(), roi=Config().ui_roi["left_inventory"], normalize_monitor=True)).valid: - mouse.move(*refresh_btn.center, randomize=12, delay_factor=[1.0, 1.5]) + while not (desired_item := template_finder.search (item.upper(), grab(), roi=Config().ui_roi["left_inventory"])).valid: + mouse.move(*refresh_btn.center_monitor, randomize=12, delay_factor=[1.0, 1.5]) wait(0.1, 0.15) mouse.click(button="left") wait(0.1, 0.15) # desired item found, purchase it - mouse.move(*desired_item.center, randomize=12, delay_factor=[1.0, 1.5]) + mouse.move(*desired_item.center_monitor, randomize=12, delay_factor=[1.0, 1.5]) wait(0.1, 0.15) mouse.click(button="right") wait(0.4, 0.6) @@ -109,8 +109,8 @@ def buy_item(template_name: str, quantity: int = 1, img: np.ndarray = None, shif """ if img is None: img = grab() - if (desired_item := TemplateFinder().search(template_name, inp_img=img, roi=Config().ui_roi["left_inventory"], normalize_monitor=True)).valid: - mouse.move(*desired_item.center, randomize=8, delay_factor=[1.0, 1.5]) + if (desired_item := template_finder.search(template_name, inp_img=img, roi=Config().ui_roi["left_inventory"])).valid: + mouse.move(*desired_item.center_monitor, randomize=8, delay_factor=[1.0, 1.5]) if shift_click: keyboard.send('shift', do_release=False) wait(0.5, 0.8) @@ -123,6 +123,7 @@ def buy_item(template_name: str, quantity: int = 1, img: np.ndarray = None, shif return False keyboard.send('shift', do_release=True) personal.set_inventory_gold_full(False) + center_mouse() return True if quantity: for _ in range(quantity): @@ -133,10 +134,10 @@ def buy_item(template_name: str, quantity: int = 1, img: np.ndarray = None, shif keyboard.send("esc") return False personal.set_inventory_gold_full(False) + center_mouse() return True else: Logger.error("buy_item: Quantity not specified") return False - Logger.error(f"buy_item: Desired item {template_name} not found") return False diff --git a/src/item/__init__.py b/src/item/__init__.py index 4913d48ae..e69de29bb 100644 --- a/src/item/__init__.py +++ b/src/item/__init__.py @@ -1,2 +0,0 @@ -from .item_cropper import ItemCropper -from .item_finder import ItemFinder, Item diff --git a/src/item/consumables.py b/src/item/consumables.py new file mode 100644 index 000000000..2d23358ac --- /dev/null +++ b/src/item/consumables.py @@ -0,0 +1,117 @@ +from config import Config +from dataclasses import dataclass +from logger import Logger +from d2r_image.data_models import HoveredItem + +@dataclass +class Consumables: + tp: int = 0 + id: int = 0 + rejuv: int = 0 + health: int = 0 + mana: int = 0 + key: int = 0 + def __getitem__(self, key): + return super().__getattribute__(key) + def __setitem__(self, key, value): + setattr(self, key, value) + def any_needs(self): + return sum([self.tp, self.id, self.rejuv, self.health, self.mana, self.key]) + def as_dict(self): + return { + "tp": self.tp, + "id": self.id, + "rejuv": self.rejuv, + "health": self.health, + "mana": self.mana, + "key": self.key + } +consumable_needs = Consumables() + +ITEM_CONSUMABLES_MAP = { + "rejuvenation potion": "rejuv", + "full rejuvenation potion": "rejuv", + "rejuvpotion": "rejuv", + "super healing potion": "health", + "greater healing potion": "health", + "healing potion": "health", + "healingpotion": "health", + "light healing potion": "health", + "minor healing potion": "health", + "super mana potion": "mana", + "greater mana potion": "mana", + "mana potion": "mana", + "manapotion": "mana", + "light mana potion": "mana", + "minor mana potion": "mana", + "scroll of town portal": "tp", + "scroll of identify": "id", + "key": "key" +} +pot_cols = { + "rejuv": Config().char["belt_rejuv_columns"], + "health": Config().char["belt_hp_columns"], + "mana": Config().char["belt_mp_columns"], +} + +def get_needs(consumable_type: str = None): + if consumable_type: + consumable = reduce_name(consumable_type) + return consumable_needs[consumable] + return consumable_needs + +def set_needs(consumable_type: str, quantity: int): + global consumable_needs + consumable = reduce_name(consumable_type) + consumable_needs[consumable] = quantity + +def increment_need(consumable_type: str = None, quantity: int = 1): + """ + Adjust the consumable_needs of a specific consumable + :param consumable_type: Name of item in pickit or in consumable_map + :param quantity: Increase the need (+int) or decrease the need (-int) + """ + global consumable_needs + consumable = reduce_name(consumable_type) + consumable_needs[consumable] = max(0, consumable_needs[reduce_name(consumable)] + quantity) + +def reduce_name(consumable_type: str): + if consumable_type.lower() in ITEM_CONSUMABLES_MAP: + consumable_type = ITEM_CONSUMABLES_MAP[consumable_type] + elif consumable_type.lower() in ITEM_CONSUMABLES_MAP.values(): + pass + else: + Logger.warning(f"adjust_consumable_need: unknown item: {consumable_type}") + return consumable_type + +def get_remaining(item_name: str = None) -> int: + if item_name is None: + Logger.error("get_remaining: param item_name is required") + return -1 + if item_name.lower() in ["health", "mana", "rejuv"]: + return pot_cols[item_name] * Config().char["belt_rows"] - consumable_needs[item_name] + elif item_name.lower() in ['tp', 'id']: + return 20 - consumable_needs[item_name] + elif item_name.lower() == "key": + return 12 - consumable_needs[item_name] + else: + Logger.error(f"get_remaining: error with item_name={item_name}") + return -1 + +def should_buy(item_name: str = None, min_remaining: int = None, min_needed: int = None) -> bool: + if item_name is None: + Logger.error("should_buy: param item_name is required") + return False + if min_needed: + return consumable_needs[item_name] >= min_needed + elif min_remaining: + return get_remaining(item_name) <= min_remaining + else: + Logger.error("should_buy: need to specify min_remaining or min_needed") + return False + +def is_consumable(item: HoveredItem) -> str | bool: + for consumable_type in ITEM_CONSUMABLES_MAP.keys(): + if item.Name.lower() == consumable_type: + return consumable_type + return False \ No newline at end of file diff --git a/src/item/item_cropper.py b/src/item/item_cropper.py deleted file mode 100644 index 909dd0a38..000000000 --- a/src/item/item_cropper.py +++ /dev/null @@ -1,174 +0,0 @@ -import cv2 -import numpy as np -from dataclasses import dataclass -import time - -from utils.misc import color_filter, erode_to_black -from template_finder import TemplateFinder -from ocr import Ocr, OcrResult -from config import Config -from logger import Logger - -# TODO: With OCR we can then add a "text" field to this class -@dataclass -class ItemText: - color: str = None - roi: list[int] = None - data: np.ndarray = None - ocr_result: OcrResult = None - clean_img: np.ndarray = None - valid: bool = False - def __getitem__(self, key): - return super().__getattribute__(key) - -class ItemCropper: - def __init__(self): - self._ocr = Ocr() - - self._gaus_filter = (19, 1) - self._expected_height_range = [round(num) for num in [x / 1.5 for x in [14, 40]]] - self._expected_width_range = [round(num) for num in [x / 1.5 for x in [60, 1280]]] - self._box_expected_width_range=[200, 900] - self._box_expected_height_range=[24, 710] - - self._hud_mask = cv2.imread(f"assets/hud_mask.png", cv2.IMREAD_GRAYSCALE) - self._hud_mask = cv2.threshold(self._hud_mask, 1, 255, cv2.THRESH_BINARY)[1] - - self._item_colors = ['white', 'gray', 'blue', 'green', 'yellow', 'gold', 'orange'] - - def clean_img(self, inp_img: np.ndarray, black_thresh: int = 14) -> np.ndarray: - img = inp_img[:, :, :] - if img.shape[0] == self._hud_mask.shape[0] and img.shape[1] == self._hud_mask.shape[1]: - img = cv2.bitwise_and(img, img, mask=self._hud_mask) - # In order to not filter out highlighted items, change their color to black - highlight_mask = color_filter(img, Config().colors["item_highlight"])[0] - img[highlight_mask > 0] = (0, 0, 0) - img = erode_to_black(img, black_thresh) - return img - - def crop(self, inp_img: np.ndarray, padding_y: int = 5) -> list[ItemText]: - start = time.time() - cleaned_img = self.clean_img(inp_img) - debug_str = f" | clean: {time.time() - start}" - - # Cluster item names - start = time.time() - item_clusters = [] - for key in self._item_colors: - _, filtered_img = color_filter(cleaned_img, Config().colors[key]) - filtered_img_gray = cv2.cvtColor(filtered_img, cv2.COLOR_BGR2GRAY) - blured_img = np.clip(cv2.GaussianBlur(filtered_img_gray, self._gaus_filter, cv2.BORDER_DEFAULT), 0, 255) - contours = cv2.findContours(blured_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - contours = contours[0] if len(contours) == 2 else contours[1] - for cntr in contours: - x, y, w, h = cv2.boundingRect(cntr) - expected_height = 1 if (self._expected_height_range[0] < h < self._expected_height_range[1]) else 0 - # increase height a bit to make sure we have the full item name in the cluster - y = y - padding_y if y > padding_y else 0 - h += padding_y * 2 - cropped_item = filtered_img[y:y+h, x:x+w] - # save most likely item drop contours - avg = int(np.average(filtered_img_gray[y:y+h, x:x+w])) - contains_black = True if np.min(cropped_item) < 14 else False - expected_width = True if (self._expected_width_range[0] < w < self._expected_width_range[1]) else False - mostly_dark = True if 4 < avg < 25 else False - if contains_black and mostly_dark and expected_height and expected_width: - # double-check item color - color_averages=[] - for key2 in self._item_colors: - _, extracted_img = color_filter(cropped_item, Config().colors[key2]) - extr_avg = np.average(cv2.cvtColor(extracted_img, cv2.COLOR_BGR2GRAY)) - color_averages.append(extr_avg) - max_idx = color_averages.index(max(color_averages)) - if key == self._item_colors[max_idx]: - item_clusters.append(ItemText( - color = key, - roi = [x, y, w, h], - data = cropped_item, - clean_img = cleaned_img[y:y+h, x:x+w] - )) - debug_str += f" | cluster: {time.time() - start}" - # print(debug_str) - if Config().advanced_options["ocr_during_pickit"]: - cluster_images = [ key["clean_img"] for key in item_clusters ] - results = self._ocr.image_to_text(cluster_images, model = "engd2r_inv_th_fast", psm = 7) - for count, cluster in enumerate(item_clusters): - setattr(cluster, "ocr_result", results[count]) - return item_clusters - - def crop_item_descr(self, inp_img: np.ndarray, inventory_side: str = "right", model = "engd2r_inv_th") -> ItemText: - """ - Crops visible item description boxes / tooltips - :inp_img: image from hover over item of interest. - :inventory_side: enter either "left" for stash/vendor region or "right" for user inventory region - :model: which ocr model to use - returns cropped item tooltip box - """ - result = ItemText() - black_mask, _ = color_filter(inp_img, Config().colors["black"]) - contours = cv2.findContours(black_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - contours = contours[0] if len(contours) == 2 else contours[1] - for cntr in contours: - x, y, w, h = cv2.boundingRect(cntr) - cropped_item = inp_img[y:y+h, x:x+w] - avg = np.average(cv2.cvtColor(cropped_item, cv2.COLOR_BGR2GRAY)) - mostly_dark = True if 0 < avg < 25 else False - contains_black = True if np.min(cropped_item) < 14 else False - contains_white = True if np.max(cropped_item) > 250 else False - contains_orange = False - if not contains_white: - #check for orange (like key of destruction, etc.) - orange_mask, _ = color_filter(cropped_item, Config().colors["orange"]) - contains_orange = np.min(orange_mask) > 0 - expected_height = True if (self._box_expected_height_range[0] < h < self._box_expected_height_range[1]) else False - expected_width = True if (self._box_expected_width_range[0] < w < self._box_expected_width_range[1]) else False - box2 = Config().ui_roi[f"{inventory_side}_inventory"] - overlaps_inventory = False if (x+w 720 else 35 - found_footer = TemplateFinder().search(["TO_TOOLTIP"], inp_img, threshold=0.8, roi=[x, y+h, w, footer_height_max]).valid - if found_footer: - ocr_result = self._ocr.image_to_text(cropped_item, psm=6, model=model)[0] - result.color = "black" - result.roi = [x, y, w, h] - result.data = cropped_item - result.ocr_result = ocr_result - result.valid = True - break - return result - -if __name__ == "__main__": - import keyboard - import os - from screen import start_detecting_window, grab - start_detecting_window() - keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) - print("Move to d2r window and press f11") - keyboard.wait("f11") - - keyboard.add_hotkey('f12', lambda: os._exit(1)) - cropper = ItemCropper() - - while 1: - img = grab().copy() - res = cropper.crop_item_descr(img, model="engd2r_inv_th_fast") - if res.valid: - x, y, w, h = res.roi - cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 1) - #Logger.debug(f"{res.ocr_result['text']}") - - Logger.debug(f"OCR ITEM DESCR: Mean conf: {res.ocr_result.mean_confidence}") - for i, line in enumerate(list(filter(None, res.ocr_result.text.splitlines()))): - Logger.debug(f"OCR LINE{i}: {line}") - timestamp = time.strftime("%Y%m%d_%H%M%S") - found_low_confidence = False - for cnt, x in enumerate(res.ocr_result['word_confidences']): - if x <= 88: - try: - Logger.debug(f"Low confidence word #{cnt}: {res.ocr_result['original_text'].split()[cnt]} -> {res.ocr_result['text'].split()[cnt]}, Conf: {x}") - found_low_confidence = True - except: pass - - - cv2.imshow("res", img) - cv2.waitKey(5000) diff --git a/src/item/item_finder.py b/src/item/item_finder.py deleted file mode 100644 index 91362c15d..000000000 --- a/src/item/item_finder.py +++ /dev/null @@ -1,157 +0,0 @@ -import cv2 -from typing import Tuple -import numpy as np -import time -import os -from dataclasses import dataclass -import math - -from config import Config -from utils.misc import color_filter, cut_roi -from item import ItemCropper -from template_finder import TemplateFinder -from ocr import OcrResult, Ocr - - -@dataclass -class Template: - data: np.ndarray = None - hist = None - blacklist: bool = False - -@dataclass -class Item: - center: Tuple[float, float] = None # (x, y) in screen coordinates - name: str = None - score: float = -1.0 - dist: float = -1.0 - roi: list[int] = None - color: str = None - ocr_result: OcrResult = None - def __getitem__(self, key): - return super().__getattribute__(key) - -class ItemFinder: - def __init__(self): - self._item_cropper = ItemCropper() - # color range for each type of item - # hsv ranges in opencv h: [0-180], s: [0-255], v: [0, 255] - self._template_color_ranges = { - "white": [np.array([0, 0, 150]), np.array([0, 0, 245])], - "gray": [np.array([0, 0, 90]), np.array([0, 0, 126])], - "magic": [np.array([120, 120, 190]), np.array([120, 126, 255])], - "set": [np.array([60, 250, 190]), np.array([60, 255, 255])], - "rare": [np.array([30, 128, 190]), np.array([30, 137, 255])], - "unique": [np.array([23, 80, 140]), np.array([23, 89, 216])], - "runes": [np.array([21, 251, 190]), np.array([22, 255, 255])] - } - self._items_to_pick = Config().items - self._folder_name = "items" - self._min_score = 0.86 - # load all templates - self._templates = {} - for filename in os.listdir(f'assets/{self._folder_name}'): - filename = filename.lower() - if filename.endswith('.png'): - item_name = filename[:-4] - # assets with bl__ are black listed items and will not be picke up - blacklist_item = item_name.startswith("bl__") - # these items will be searched for regardless of pickit setting (e.g. for runes to avoid mixup) - force_search = item_name.startswith("rune_") - if blacklist_item or ((item_name in Config().items and Config().items[item_name].pickit_type) or force_search): - data = cv2.imread(f"assets/{self._folder_name}/" + filename) - filtered_template = np.zeros(data.shape, np.uint8) - for key in self._template_color_ranges: - _, extracted_template = color_filter(data, self._template_color_ranges[key]) - filtered_template = cv2.bitwise_or(filtered_template, extracted_template) - grayscale = cv2.cvtColor(filtered_template, cv2.COLOR_BGR2GRAY) - _, mask = cv2.threshold(grayscale, 0, 255, cv2.THRESH_BINARY) - hist = cv2.calcHist([filtered_template], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256]) - template = Template() - template.data = filtered_template - template.hist = hist - if blacklist_item: - template.blacklist = True - self._templates[item_name] = template - - def search(self, inp_img: np.ndarray) -> list[Item]: - img = inp_img[:,:,:] - start = time.time() - item_text_clusters = self._item_cropper.crop(img, 7) - item_list = [] - for cluster in item_text_clusters: - x, y, w, h = cluster.roi - # cv2.rectangle(inp_img, (x, y), (x+w, y+h), (0, 255, 0), 1) - cropped_input = cluster.data - best_score = None - item = None - for key in self._templates: - template: Template = self._templates[key] - if cropped_input.shape[1] > template.data.shape[1] and cropped_input.shape[0] > template.data.shape[0]: - # sanity check if there is any color overlap of template and cropped_input - grayscale = cv2.cvtColor(cropped_input, cv2.COLOR_BGR2GRAY) - _, mask = cv2.threshold(grayscale, 0, 255, cv2.THRESH_BINARY) - hist = cv2.calcHist([cropped_input], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256]) - hist_result = cv2.compareHist(template.hist, hist, cv2.HISTCMP_CORREL) - same_type = hist_result > 0.0 and hist_result is not np.inf - if same_type: - result = cv2.matchTemplate(cropped_input, template.data, cv2.TM_CCOEFF_NORMED) - _, max_val, _, max_loc = cv2.minMaxLoc(result) - if max_val > self._min_score: - if template.blacklist: - max_val += 0.02 - if (best_score is None or max_val > best_score): - best_score = max_val - if template.blacklist: - item = None - else: - # Do another color hist check with the actuall found item template - # TODO: After cropping the "cropped_input" with "cropped_item", check if "cropped_input" might need to be - # checked for other items. This would solve the issue of many items in one line being in one cluster - roi = [max_loc[0], max_loc[1], template.data.shape[1], template.data.shape[0]] - cropped_item = cut_roi(cropped_input, roi) - grayscale = cv2.cvtColor(cropped_item, cv2.COLOR_BGR2GRAY) - _, mask = cv2.threshold(grayscale, 0, 255, cv2.THRESH_BINARY) - hist = cv2.calcHist([cropped_item], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256]) - hist_result = cv2.compareHist(template.hist, hist, cv2.HISTCMP_CORREL) - same_type = hist_result > 0.65 and hist_result is not np.inf - # if ocr_during_pickit is off, min_gold_to_pick is set, and matched template is gold, OCR the image - if not Config().advanced_options['ocr_during_pickit'] \ - and Config().char['min_gold_to_pick'] and 'misc_gold' == key: - results = Ocr().image_to_text([cluster["clean_img"]], model = "engd2r_inv_th_fast", psm = 7) - setattr(cluster, "ocr_result", results[0]) - if same_type: - item = Item() - item.center = (int(max_loc[0] + x + int(template.data.shape[1] * 0.5)), int(max_loc[1] + y + int(template.data.shape[0] * 0.5))) - item.name = key - item.score = max_val - item.roi = [max_loc[0] + x, max_loc[1] + y, template.data.shape[1], template.data.shape[0]] - center_abs = (item.center[0] - (inp_img.shape[1] // 2), item.center[1] - (inp_img.shape[0] // 2)) - item.dist = math.dist(center_abs, (0, 0)) - item.ocr_result = cluster.ocr_result - item.color = cluster.color - if item is not None and self._items_to_pick[item.name].pickit_type: - item_list.append(item) - elapsed = time.time() - start - # print(f"Item Search: {elapsed}") - return item_list - - -# Testing: Throw some stuff on the ground see if it is found -if __name__ == "__main__": - from screen import grab - from config import Config - - item_finder = ItemFinder() - while 1: - # img = cv2.imread("") - img = grab().copy() - item_list = item_finder.search(img) - for item in item_list: - # print(item.name + " " + str(item.score)) - cv2.circle(img, item.center, 5, (255, 0, 255), thickness=3) - cv2.rectangle(img, item.roi[:2], (item.roi[0] + item.roi[2], item.roi[1] + item.roi[3]), (0, 0, 255), 1) - cv2.putText(img, item.ocr_result["text"], item.center, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA) - # img = cv2.resize(img, None, fx=0.5, fy=0.5) - cv2.imshow('test', img) - cv2.waitKey(1) \ No newline at end of file diff --git a/src/item/pickit.py b/src/item/pickit.py index def328175..94375d286 100644 --- a/src/item/pickit.py +++ b/src/item/pickit.py @@ -1,192 +1,208 @@ -import time -import keyboard +from enum import Enum +from numpy import ndarray import cv2 -from operator import itemgetter -from ui_manager import ScreenObjects, is_visible -from utils.custom_mouse import mouse +import json +import keyboard +import os +import time +import uuid + +from char import IChar from config import Config +from d2r_image import processing as d2r_image +from d2r_image.data_models import GroundItemList, GroundItem, EnhancedJSONEncoder +from inventory import personal +from item import consumables +from item.consumables import ITEM_CONSUMABLES_MAP from logger import Logger -from screen import grab, convert_abs_to_monitor, convert_screen_to_monitor -from item import ItemFinder, Item -from char import IChar -from inventory import consumables -import parse +from bnip.actions import should_pickup +from bnip.NTIPAliasType import NTIPAliasType as NTIP_TYPES +from screen import grab, convert_abs_to_monitor +from ui_manager import ScreenObjects, is_visible +from utils.custom_mouse import mouse +from utils.misc import wait + +class PickedUpResult(Enum): + TeleportedTo = 0 + PickedUp = 1 + PickedUpFailed = 3 + InventoryFull = 4 + GoldFull = 5 class PickIt: - def __init__(self, item_finder: ItemFinder): - self._item_finder = item_finder - self._last_closest_item: Item = None + def __init__(self): + self._cached_pickit_items = {} # * Cache the result of whether or not we should pick up the item. this should save some time + self._prev_item_pickup_attempt = None + self._fail_pickup_count = 0 + self._picked_up_items = [] + self._picked_up_item = False + self.timeout = 30 + + @staticmethod + def _log_data(items: GroundItemList, img: ndarray, counter: int, _uuid: str): + if Config().general["pickit_screenshots"]: + cv2.imwrite(f"log/screenshots/pickit/{_uuid }_{counter}.png", img) + with open(f"log/screenshots/pickit/{_uuid }_{counter}.json", 'w', encoding='utf-8') as f: + json.dump(items, f, ensure_ascii=False, sort_keys=False, cls=EnhancedJSONEncoder, indent=2) + + @staticmethod + def _locate_items() -> tuple[GroundItemList, ndarray]: + img = grab() + start = time.time() + items = d2r_image.get_ground_loot(img).items.copy() + Logger.debug(f"Read {len(items)} ground items in {round(time.time() - start, 3)} seconds") + items = sorted(items, key=lambda item: item.Distance) + return items, img + + def _reset_state(self): + """Reset the pickit state""" + self._prev_item_pickup_attempt = GroundItem() + self._fail_pickup_count = 0 + self._picked_up_items = [] + self._picked_up_item = False + + @staticmethod + def _ignore_gold(item: GroundItem): + if personal.get_inventory_gold_full() and str(item.BaseItem["DisplayName"]).lower() == "gold": + # Logger.debug("Gold is full, skip gold") + return True + return False + + @staticmethod + def _ignore_consumable(item: GroundItem): + # ignore item if it's a consumable AND there's no need for that consumable + need_exists = True + for consumable_type in ITEM_CONSUMABLES_MAP.keys(): + if not item.Name.lower() == consumable_type: + continue + need_exists = consumables.get_needs(consumable_type) > 0 + if need_exists: + consumables.increment_need(consumable_type, -1) + return (not need_exists) + + @staticmethod + def _yoink_item(item: GroundItem, char: IChar, force_tp=False) -> PickedUpResult: + if item.Distance > Config().ui_pos["item_dist"] or force_tp: + char.pre_move() + char.move((item.CenterMonitor['x'], item.CenterMonitor['y']), force_move=force_tp) + wait(0.09, 0.12) + # * Move mouse to the middle of the screen and click on the item you teleported to + pos_m = convert_abs_to_monitor((0,-45)) + mouse.move(*pos_m) + mouse.click(button="left") + else: + char.pick_up_item((item.CenterMonitor['x'], item.CenterMonitor['y']), item_name=item.Name, prev_cast_start=0.1) + return PickedUpResult.PickedUp + + def _pick_up_item(self, char: IChar, item: GroundItem) -> PickedUpResult: + pickup_failed = False + # gold moves when you try to pick it and are overburdened + if (item.ID == self._prev_item_pickup_attempt.ID) and item.BaseItem["DisplayName"] == "Gold": + self._fail_pickup_count += 1 + if is_visible(ScreenObjects.Overburdened): + personal.set_inventory_gold_full(True) + return PickedUpResult.GoldFull + pickup_failed = self._fail_pickup_count >= 1 + # other items don't move, so should have same location + if (item.UID == self._prev_item_pickup_attempt.UID): + self._fail_pickup_count += 1 + wait(0.25, 0.35) + if is_visible(ScreenObjects.Overburdened): + return PickedUpResult.InventoryFull + elif self._fail_pickup_count >= 1: + # * +1 because we failed at picking it up once already, we just can't detect the first failure (unless it is due to full inventory) + if char.capabilities.can_teleport_natively or char.capabilities.can_teleport_with_charges: + Logger.warning(f"Failed to pick up '{item.Name}' {self._fail_pickup_count + 1} times in a row, trying to teleport") + return self._yoink_item(item, char, force_tp=True) + pickup_failed = True + + if pickup_failed: + Logger.warning(f"Failed to pick up '{item.Name}' {self._fail_pickup_count + 1} times in a row, moving on to the next item.") + return PickedUpResult.PickedUpFailed + + self._prev_item_pickup_attempt = item + return self._yoink_item(item, char) def pick_up_items(self, char: IChar) -> bool: """ - Pick up all items with specified char - :param char: The character used to pick up the item - :return: Bool if any items were picked up or not. (Does not account for picking up scrolls and pots) + To be called everytime the bot wants to pick up items + Pick up items that with a specified char + :param char: The character used to pick up the item + TODO :return: return a list of the items that were picked up """ - found_nothing = 0 - found_items = False + self._reset_state() keyboard.send(Config().char["show_items"]) - time.sleep(1.0) # sleep needed here to give d2r time to display items on screen on keypress - #Creating a screenshot of the current loot - if Config().general["loot_screenshots"]: - img = grab() - cv2.imwrite("./loot_screenshots/info_debug_drop_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) - Logger.debug("Took a screenshot of current loot") - start = prev_cast_start = time.time() - timeout = False - picked_up_items = [] - skip_items = [] - curr_item_to_pick: Item = None - same_item_timer = None - did_force_move = False - done_ocr=False - - while not timeout: - if (time.time() - start) > 28: - timeout = True - Logger.warning("Got stuck during pickit, skipping it this time...") - break - img = grab() - item_list = self._item_finder.search(img) - - if Config().advanced_options["ocr_during_pickit"] and not done_ocr: - timestamp = time.strftime("%Y%m%d_%H%M%S") - for cnt, item in enumerate(item_list): - for cnt2, x in enumerate(item.ocr_result['word_confidences']): - found_low_confidence = False - if x <= 88: - try: - Logger.debug(f"Low confidence word #{cnt2}: {item.ocr_result['original_text'].split()[cnt2]} -> {item.ocr_result['text'].split()[cnt2]}, Conf: {x}, save screenshot") - found_low_confidence = True - except: pass - if found_low_confidence and Config().general["loot_screenshots"]: - cv2.imwrite(f"./loot_screenshots/ocr_drop_{timestamp}_{cnt}_o.png", item.ocr_result['original_img']) - cv2.imwrite(f"./loot_screenshots/ocr_drop_{timestamp}_{cnt}_n.png", item.ocr_result['processed_img']) - with open(f"./loot_screenshots/ocr_drop_{timestamp}_{cnt}_o.gt.txt", 'w') as f: - f.write(item.ocr_result['text']) - done_ocr = True - - # Check if we need to pick up any consumables - needs = consumables.get_needs() - if needs["mana"] <= 0: - item_list = [x for x in item_list if "mana_potion" not in x.name] - if needs["health"] <= 0: - item_list = [x for x in item_list if "healing_potion" not in x.name] - if needs["rejuv"] <= 0: - item_list = [x for x in item_list if "rejuvenation_potion" not in x.name] - if needs["tp"] <= 0: - item_list = [x for x in item_list if "scroll_tp" not in x.name] - if needs["id"] <= 0: - item_list = [x for x in item_list if "scroll_id" not in x.name] - if needs["key"] <= 0: - item_list = [x for x in item_list if "misc_key" != x.name] - - # filter out gold less than desired quantity - if (min_gold := Config().char['min_gold_to_pick']): - for item in item_list[:]: - if "misc_gold" == item.name: - try: - ocr_gold = int(parse.search("{:d} GOLD", item.ocr_result.text).fixed[0]) - except: - ocr_gold = 0 - if ocr_gold < min_gold: - item_list.remove(item) - - if len(item_list) == 0: - # if twice no item was found, break - found_nothing += 1 - if found_nothing > 1: + wait(0.15, 0.25) + pickit_phase_start = time.time() + + items, img = self._locate_items() + counter = 1 + _uuid = uuid.uuid4() + self._log_data(items, img, counter, _uuid) + item_count = 0 + while item_count < len(items) and time.time() - pickit_phase_start < self.timeout: + # If you previously up an item, get dropped item data again and reset the loop + if self._picked_up_item: + wait(0.38, 0.46) + items, img = self._locate_items() + counter += 1 + self._log_data(items, img, counter, _uuid) + item_count=0 + if not items: break - else: - # Maybe we need to move cursor to another position to avoid highlighting items - pos_m = convert_abs_to_monitor((0, 0)) - mouse.move(*pos_m, randomize=[90, 160]) - time.sleep(0.2) + # Otherwise continue to next item in the list + item = items[item_count] + + pick_up_res=None + pickup, raw_expression = (False, "") + # Check if we already decided whether this item type should be picked + if item.ID in self._cached_pickit_items: + if self._cached_pickit_items[item.ID] and not (self._ignore_consumable(item) or self._ignore_gold(item)): + pick_up_res = self._pick_up_item(char, item) else: - found_nothing = 0 - item_list.sort(key=itemgetter('dist')) - closest_item = next((obj for obj in item_list if not any(map(obj["name"].__contains__, ["misc_gold", "misc_scroll", "misc_key"]))), None) - if not closest_item: - closest_item = item_list[0] - - # check if we trying to pickup the same item for a longer period of time - force_move = False - if curr_item_to_pick is not None: - is_same_item = (curr_item_to_pick.name == closest_item.name and \ - abs(curr_item_to_pick.dist - closest_item.dist) < 20) - if same_item_timer is None or not is_same_item: - same_item_timer = time.time() - did_force_move = False - elif time.time() - same_item_timer > 1 and not did_force_move: - force_move = True - did_force_move = True - elif time.time() - same_item_timer > 3: - # backlist this item type for this pickit round - Logger.warning(f"Could not pick up: {closest_item.name}. Continue with other items") - skip_items.append(closest_item.name) - curr_item_to_pick = closest_item - - # To avoid endless teleport or telekinesis loop - force_pick_up = char.capabilities.can_teleport_natively and \ - self._last_closest_item is not None and \ - self._last_closest_item.name == closest_item.name and \ - abs(self._last_closest_item.dist - closest_item.dist) < 20 - - x_m, y_m = convert_screen_to_monitor(closest_item.center) - if not force_move and (closest_item.dist < Config().ui_pos["item_dist"] or force_pick_up): - self._last_closest_item = None - # no need to stash potions, scrolls, gold, keys - if ("potion" not in closest_item.name) and ("misc_scroll" not in closest_item.name) and ("misc_key" != closest_item.name): - if ("misc_gold" != closest_item.name): - found_items = True - if Config().advanced_options["ocr_during_pickit"]: - for item in item_list: - Logger.debug(f"OCR DROP: Name: {item.ocr_result['text']}, Conf: {item.ocr_result['word_confidences']}") - else: - # note: key pickup appears to be random between 1 and 5, but set here at minimum of 1 for now - consumables.increment_need(closest_item.name, -1) - - prev_cast_start = char.pick_up_item((x_m, y_m), item_name=closest_item.name, prev_cast_start=prev_cast_start) - if not char.capabilities.can_teleport_natively: - time.sleep(0.2) - - if is_visible(ScreenObjects.Overburdened): - found_items = True - Logger.warning("Inventory full, terminating pickit!") - # TODO: Could think about sth like: Go back to town, stash, come back picking up stuff - break - else: - # send log to discord - if found_items and closest_item.name not in picked_up_items: - Logger.info(f"Picking up: {closest_item.name} ({closest_item.score*100:.1f}% confidence)") - picked_up_items.append(closest_item.name) - else: - char.pre_move() - char.move((x_m, y_m), force_move=True) - if not char.capabilities.can_teleport_natively: - time.sleep(0.3) - time.sleep(0.1) - # save closeset item for next time to check potential endless loops of not reaching it or of telekinsis/teleport - self._last_closest_item = closest_item + item_dict = item.as_dict() + # if the item shouldn't be ignored, check if it should be picked up + if not (self._ignore_gold(item) or self._ignore_consumable(item)): + pickup, raw_expression = should_pickup(item_dict) + self._cached_pickit_items[item.ID] = pickup + if pickup: + pick_up_res = self._pick_up_item(char, item) + Logger.debug(f"Pick up expression: {raw_expression}") + Logger.info(f"Attempt to pick up {item.Name}") + match pick_up_res: + case PickedUpResult.InventoryFull: + if pickup: + Logger.warning(f"Inventory is full, could not pick {item.Name}. Stop pickit") #TODO Create logic to handle inventory full + break + case PickedUpResult.PickedUp: + self._picked_up_items.append(item) + self._picked_up_item = pick_up_res == PickedUpResult.PickedUp + item_count+=1 keyboard.send(Config().char["show_items"]) - return found_items + return len(self._picked_up_items) >= 1 if __name__ == "__main__": import os from config import Config from char.sorceress import LightSorc - from char.hammerdin import Hammerdin - from template_finder import TemplateFinder + from char.paladin import Hammerdin from pather import Pather import keyboard + from logger import Logger + from screen import start_detecting_window, stop_detecting_window - keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) + keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or stop_detecting_window() or os._exit(1)) + start_detecting_window() + print("Move to d2r window and press f11") keyboard.wait("f11") + pather = Pather() - item_finder = ItemFinder() - char = Hammerdin(Config().hammerdin, Config().char, pather) - pickit = PickIt(item_finder) + pickit = PickIt() + char = Hammerdin(Config().hammerdin, pather, pickit) + + char.discover_capabilities() + print(pickit.pick_up_items(char)) diff --git a/src/logger.py b/src/logger.py index dedb7f6d3..f4516c2a5 100644 --- a/src/logger.py +++ b/src/logger.py @@ -5,6 +5,7 @@ import warnings from version import __version__ from colorama import Fore, Back, Style, init +import time init() @@ -27,9 +28,10 @@ def format(self, record): class Logger: """Manage logging""" + os.makedirs("log", exist_ok=True) _logger_level = None _log_contents = io.StringIO() - _current_log_file_path = "info.log" + _current_log_file_path = "log/log.txt" _output = "" # intercepted output from stdout and stderr string_handler = None file_handler = None @@ -118,4 +120,4 @@ def remove_file_logger(delete_current_log: bool = False): try: os.remove(Logger._current_log_file_path) except PermissionError: - warnings.warn("Could not remove info.log, permission denied") + warnings.warn(f"Could not remove {Logger._current_log_file_path}, permission denied") diff --git a/src/main.py b/src/main.py index f3d780f84..20cf4a8f4 100644 --- a/src/main.py +++ b/src/main.py @@ -5,6 +5,7 @@ import logging import traceback import screen +import string from version import __version__ from config import Config from logger import Logger @@ -45,7 +46,24 @@ def on_exit(): restore_d2r_window_visibility() os._exit(1) +def startup_checks(): + # check if paths contain non-ascii characters + check_for_non_ascii = { + "D2R path": Config().general["d2r_path"], + "Windows username": os.getlogin(), + "Botty path": os.getcwd() + } + for key, value in check_for_non_ascii.items(): + strip_punctuation = value.translate(str.maketrans('', '', string.punctuation)) + if not len(strip_punctuation) == len(strip_punctuation.encode()): + print(f"\n!! WARNING: {key} ({value}) contains incompatible characters. This could result in Botty encoding errors.\n") + + def main(): + # Create folder for debug screenshots if they dont exist yet + for dir_name in ["log", "log/stats", "log/screenshots", "log/screenshots/info", "log/screenshots/items", "log/screenshots/pickit", "log/screenshots/generated"]: + os.makedirs(dir_name, exist_ok=True) + controllers = Controllers( GameController(), GraphicDebuggerController() @@ -56,14 +74,7 @@ def main(): Logger.init(logging.DEBUG) else: print(f"ERROR: Unkown logg_lvl {Config().advanced_options['logg_lvl']}. Must be one of [info, debug]") - - # Create folder for debug screenshots if they dont exist yet - if not os.path.exists("stats"): - os.system("mkdir stats") - if not os.path.exists("info_screenshots") and (Config().general["info_screenshots"] or Config().general["message_api_type"] == "discord"): - os.system("mkdir info_screenshots") - if not os.path.exists("loot_screenshots") and (Config().general["loot_screenshots"] or Config().general["message_api_type"] == "discord"): - os.system("mkdir loot_screenshots") + startup_checks() print(f"============ Botty {__version__} [name: {Config().general['name']}] ============") print("\nFor gettings started and documentation\nplease read https://github.com/aeon0/botty\n") @@ -98,4 +109,3 @@ def main(): traceback.print_exc() print("Press Enter to exit ...") input() - \ No newline at end of file diff --git a/src/messages/discord_embeds.py b/src/messages/discord_embeds.py index 713aa4496..6fce4a619 100644 --- a/src/messages/discord_embeds.py +++ b/src/messages/discord_embeds.py @@ -8,24 +8,32 @@ from version import __version__ import numpy as np from discord import Webhook, RequestsWebhookAdapter, Color, InvalidArgument - +import json class DiscordEmbeds(GenericApi): def __init__(self): self._file = None self._psnURL = "https://i.psnprofiles.com/games/3bffee/trophies/" - if Config().general["custom_message_hook"]: + self._webhook = self._get_webhook(Config().general["custom_message_hook"]) + self._loot_webhook = self._get_webhook(Config().general["custom_loot_message_hook"]) + + def _get_webhook(self, hook_url: str): + hook = None + if not hook_url: + hook_url = Config().general['custom_message_hook'] + if hook_url: try: - self._webhook = Webhook.from_url(Config().general['custom_message_hook'], adapter=RequestsWebhookAdapter(), ) - except InvalidArgument: - self._webhook = None - Logger.warning(f"Your custom_message_hook URL {Config().general['custom_message_hook']} is invalid, Discord updates will not be sent") + hook = Webhook.from_url(hook_url, adapter=RequestsWebhookAdapter(), ) + except BaseException as e: + Logger.warning(f"Your custom_message_hook URL {hook_url} is invalid, Discord updates will not be sent") + Logger.error(f"Error initializing webhook {hook_url}: {e}") + return hook - def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str = None): + def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str = '', bnip_keep_expression: str = '', item_props: dict = {}): imgName = item.replace('_', '-') _, w, _ = image.shape - cv2.imwrite(f"./loot_screenshots/{item}.png", image) - file = self._add_file(f"./loot_screenshots/{item}.png", f"{imgName}.png") + cv2.imwrite(f"./log/screenshots/items/{item}.png", image) + file = self._add_file(f"./log/screenshots/items/{item}.png", f"{imgName}.png") e = discord.Embed( title="Item Stashed!", description=f"{item} at {location}", @@ -34,7 +42,20 @@ def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str e.set_thumbnail(url=f"{self._psnURL}41L6bd712.png") e.set_image(url=f"attachment://{imgName}.png") e.add_field(name="OCR Text", value=f"{ocr_text}", inline=False) - self._send_embed(e, file) + e.add_field(name="BNIP", value=f"`{bnip_keep_expression}`", inline=False) + # Escape the quotes + + new_dict = { + "NTIPAliasIdName": item_props["NTIPAliasIdName"], + "NTIPAliasType": item_props["NTIPAliasType"], + "NTIPAliasClassID": item_props["NTIPAliasClassID"], + "NTIPAliasClass": item_props["NTIPAliasClass"], + "NTIPAliasQuality": item_props["NTIPAliasQuality"], + "NTIPAliasStat": item_props["NTIPAliasStat"], + "NTIPAliasFlag": item_props["NTIPAliasFlag"] + } + e.add_field(name="ItemProps", value= '`' + json.dumps(new_dict, sort_keys=True) + '`', inline=False) + self._send_embed(e, self._loot_webhook, file) def send_death(self, location, image_path): file = self._add_file(image_path, "death.png") @@ -43,7 +64,7 @@ def send_death(self, location, image_path): e.description=(f"Died at {location}") e.set_thumbnail(url=f"{self._psnURL}33L5e3600.png") e.set_image(url="attachment://death.png") - self._send_embed(e, file) + self._send_embed(e, self._webhook, file) def send_chicken(self, location, image_path): file = self._add_file(image_path, "chicken.png") @@ -52,32 +73,32 @@ def send_chicken(self, location, image_path): e.description=(f"chickened at {location}") e.set_thumbnail(url=f"{self._psnURL}39Ldf113b.png") e.set_image(url="attachment://chicken.png") - self._send_embed(e, file) + self._send_embed(e, self._webhook, file) def send_stash(self): e = discord.Embed(title=f"{Config().general['name']} has a full stash!", color=Color.dark_grey()) e.title=(f"{Config().general['name']} has a full stash!") e.description=(f"{Config().general['name']} has to quit. \n They cannot store anymore items!") e.set_thumbnail(url=f"{self._psnURL}35L63a9df.png") - self._send_embed(e) + self._send_embed(e, self._webhook) def send_gold(self): e = discord.Embed(title=f"{Config().general['name']} is rich!", color=Color.dark_grey()) e.title=(f"{Config().general['name']} is Rich!") e.description=(f"{Config().general['name']} can't store any more money!\n turning off gold pickup.") e.set_thumbnail(url=f"{self._psnURL}6L341955.png") - self._send_embed(e) + self._send_embed(e, self._webhook) def send_message(self, msg: str): msg = f"{Config().general['name']}: {msg}" e = discord.Embed(title=f"Update:", description=f"```{msg}```", color=Color.dark_teal()) - self._send_embed(e) + self._send_embed(e, self._webhook) - def _send_embed(self, e, file = None): + def _send_embed(self, e, webhook, file = None): e.set_footer(text=f'Botty v.{__version__} by Aeon') e.timestamp=datetime.datetime.now(datetime.timezone.utc) try: - if self._webhook: self._webhook.send(embed=e, file=file, username=Config().general['name']) + webhook.send(embed=e, file=file, username=Config().general['name']) except BaseException as err: Logger.error(f"Error sending Discord embed: {err}") diff --git a/src/messages/generic_api.py b/src/messages/generic_api.py index 081f5bbee..fd6d70644 100644 --- a/src/messages/generic_api.py +++ b/src/messages/generic_api.py @@ -6,9 +6,9 @@ class GenericApi: - def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str = None): + def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str = None, bnip_keep_expression: str = None, item_props = {}): msg = f"Found {item} at {location}" - self._send(msg) + self._send(msg, loot = True) def send_death(self, location: str, image_path: str = None): msg = f"You have died at {location}" @@ -29,12 +29,13 @@ def send_stash(self): def send_message(self, msg: str): self._send(msg) - def _send(self, msg: str): + def _send(self, msg: str, loot = False): msg = f"{Config().general['name']}: {msg}" - url = Config().general['custom_message_hook'] - if not url: + if not (url := Config().general['custom_message_hook']): return + if loot and (loot_url := Config().general['custom_loot_message_hook']): + url = loot_url headers = {} if Config().advanced_options['message_headers']: diff --git a/src/messages/messenger.py b/src/messages/messenger.py index ec09638ef..5067589af 100644 --- a/src/messages/messenger.py +++ b/src/messages/messenger.py @@ -14,9 +14,11 @@ def __init__(self): self._message_api = DiscordEmbeds() else: self._message_api = None + self.enabled = Config().general["message_api_type"] and Config().general["custom_message_hook"] - def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str = None): - self._message_api.send_item(item, image, location, ocr_text) + + def send_item(self, item: str, image: np.ndarray, location: str, ocr_text: str = '', bnip_keep_expression: str = '', item_props = {}): + self._message_api.send_item(item, image, location, ocr_text, bnip_keep_expression, item_props) def send_death(self, location: str, image_path: str = None): self._message_api.send_death(location, image_path) @@ -41,8 +43,8 @@ def send_message(self, msg: str): location = "Shenk" # messenger.send_item(item, img, location) - # messenger.send_death(location, "./info_screenshots/info_debug_chicken_20211220_110621.png") - # messenger.send_chicken(location, "./info_screenshots/info_debug_chicken_20211220_110621.png") + # messenger.send_death(location, "./log/screenshots/info/info_debug_chicken_20211220_110621.png") + # messenger.send_chicken(location, "./log/screenshots/info/info_debug_chicken_20211220_110621.png") messenger.send_stash() messenger.send_gold() messenger.send_message("This is a test message") diff --git a/src/npc_manager.py b/src/npc_manager.py index 783d81de3..663035889 100644 --- a/src/npc_manager.py +++ b/src/npc_manager.py @@ -2,7 +2,7 @@ import os import numpy as np import keyboard -from template_finder import TemplateFinder +import template_finder from config import Config from screen import grab from ui_manager import ScreenObjects, center_mouse, is_visible, wait_until_hidden @@ -35,12 +35,12 @@ class Npc: npcs = { Npc.QUAL_KEHK: { - "name_tag_white": color_filter(TemplateFinder().get_template("QUAL_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("QUAL_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("QUAL_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("QUAL_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "resurrect": { - "white": color_filter(TemplateFinder().get_template("RESURRECT"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("RESURRECT_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("RESURRECT"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("RESURRECT_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["QUAL_0", "QUAL_45", "QUAL_45_B", "QUAL_90", "QUAL_135", "QUAL_135_B", "QUAL_135_C", "QUAL_180", "QUAL_180_B", "QUAL_225", "QUAL_225_B", "QUAL_270", "QUAL_315"], @@ -48,12 +48,12 @@ class Npc: "poses": [[350, 140], [310, 268], [385, 341], [481, 196], [502, 212], [771, 254]] }, Npc.MALAH: { - "name_tag_white": color_filter(TemplateFinder().get_template("MALAH_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("MALAH_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("MALAH_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("MALAH_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["MALAH_FRONT", "MALAH_BACK", "MALAH_45", "MALAH_SIDE", "MALAH_SIDE_2"], @@ -61,12 +61,12 @@ class Npc: "poses": [[445, 485], [526, 473], [602, 381], [623, 368], [641, 323], [605, 300], [622, 272], [638, 284], [677, 308], [710, 288]] }, Npc.LARZUK: { - "name_tag_white": color_filter(TemplateFinder().get_template("LARZUK_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("LARZUK_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("LARZUK_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("LARZUK_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade_repair": { - "white": color_filter(TemplateFinder().get_template("TRADE_REPAIR"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE_REPAIR"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], } }, "roi": [570, 70, (1038-570), (290-70)], @@ -74,35 +74,35 @@ class Npc: "poses": [[733, 192], [911, 143]] }, Npc.ANYA: { - "name_tag_white": color_filter(TemplateFinder().get_template("ANYA_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("ANYA_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("ANYA_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("ANYA_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["ANYA_FRONT", "ANYA_BACK", "ANYA_SIDE"] }, Npc.TYRAEL: { - "name_tag_white": color_filter(TemplateFinder().get_template("TYRAEL_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("TYRAEL_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("TYRAEL_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("TYRAEL_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "resurrect": { - "white": color_filter(TemplateFinder().get_template("RESURRECT"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("RESURRECT_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("RESURRECT"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("RESURRECT_BLUE"), Config().colors["blue"])[1], } }, "roi": [569, 86, (852-569), (357-86)], "template_group": ["TYRAEL_1", "TYRAEL_2"] }, Npc.ORMUS: { - "name_tag_white": color_filter(TemplateFinder().get_template("ORMUS_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("ORMUS_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("ORMUS_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("ORMUS_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], } }, "roi": [444, 13, (816-444), (331-13)], @@ -110,82 +110,82 @@ class Npc: "template_group": ["ORMUS_0", "ORMUS_1", "ORMUS_2", "ORMUS_3", "ORMUS_4", "ORMUS_5"] }, Npc.FARA: { - "name_tag_white": color_filter(TemplateFinder().get_template("FARA_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("FARA_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("FARA_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("FARA_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade_repair": { - "white": color_filter(TemplateFinder().get_template("TRADE_REPAIR"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE_REPAIR"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["FARA_LIGHT_1", "FARA_LIGHT_2", "FARA_LIGHT_3", "FARA_LIGHT_4", "FARA_LIGHT_5", "FARA_LIGHT_6", "FARA_LIGHT_7", "FARA_LIGHT_8", "FARA_LIGHT_9", "FARA_MEDIUM_1", "FARA_MEDIUM_2", "FARA_MEDIUM_3", "FARA_MEDIUM_4", "FARA_MEDIUM_5", "FARA_MEDIUM_6", "FARA_MEDIUM_7", "FARA_DARK_1", "FARA_DARK_2", "FARA_DARK_3", "FARA_DARK_4", "FARA_DARK_5", "FARA_DARK_6", "FARA_DARK_7"] }, Npc.DROGNAN: { - "name_tag_white": color_filter(TemplateFinder().get_template("DROGNAN_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("DROGNAN_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("DROGNAN_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("DROGNAN_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["DROGNAN_FRONT", "DROGNAN_LEFT", "DROGNAN_RIGHT_SIDE"] }, Npc.LYSANDER: { - "name_tag_white": color_filter(TemplateFinder().get_template("LYSANDER_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("LYSANDER_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("LYSANDER_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("LYSANDER_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["LYSANDER_FRONT", "LYSANDER_BACK", "LYSANDER_SIDE", "LYSANDER_SIDE_2"] }, Npc.CAIN: { - "name_tag_white": color_filter(TemplateFinder().get_template("CAIN_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("CAIN_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("CAIN_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("CAIN_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "identify": { - "white": color_filter(TemplateFinder().get_template("IDENTIFY"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("IDENTIFY_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("IDENTIFY"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("IDENTIFY_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["CAIN_0", "CAIN_1", "CAIN_2", "CAIN_3"] }, Npc.JAMELLA: { - "name_tag_white": color_filter(TemplateFinder().get_template("JAMELLA_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("JAMELLA_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("JAMELLA_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("JAMELLA_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], }, "gamble": { - "white": color_filter(TemplateFinder().get_template("GAMBLE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("GAMBLE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("GAMBLE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("GAMBLE_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["JAMELLA_FRONT", "JAMELLA_BACK", "JAMELLA_SIDE", "JAMELLA_SIDE_2", "JAMELLA_SIDE_3", "JAMELLA_DRAWING"] }, Npc.HALBU: { - "name_tag_white": color_filter(TemplateFinder().get_template("HALBU_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("HALBU_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("HALBU_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("HALBU_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade_repair": { - "white": color_filter(TemplateFinder().get_template("TRADE_REPAIR"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE_REPAIR"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["HALBU_FRONT", "HALBU_BACK", "HALBU_SIDE", "HALBU_SIDE_2"] }, Npc.AKARA: { - "name_tag_white": color_filter(TemplateFinder().get_template("AKARA_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("AKARA_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("AKARA_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("AKARA_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade": { - "white": color_filter(TemplateFinder().get_template("TRADE"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_BLUE"), Config().colors["blue"])[1], } }, "roi": [603, 176, (1002-603), (478-176)], @@ -193,12 +193,12 @@ class Npc: "template_group": ["AKARA_FRONT", "AKARA_BACK", "AKARA_SIDE", "AKARA_SIDE_2"] }, Npc.CHARSI: { - "name_tag_white": color_filter(TemplateFinder().get_template("CHARSI_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("CHARSI_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("CHARSI_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("CHARSI_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "trade_repair": { - "white": color_filter(TemplateFinder().get_template("TRADE_REPAIR"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("TRADE_REPAIR"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("TRADE_REPAIR_BLUE"), Config().colors["blue"])[1], } }, "roi": [249, 76, (543-249), (363-76)], @@ -206,12 +206,12 @@ class Npc: "template_group": ["CHARSI_FRONT", "CHARSI_BACK", "CHARSI_SIDE", "CHARSI_SIDE_2", "CHARSI_SIDE_3"] }, Npc.KASHYA: { - "name_tag_white": color_filter(TemplateFinder().get_template("KASHYA_NAME_TAG_WHITE"), Config().colors["white"])[1], - "name_tag_gold": color_filter(TemplateFinder().get_template("KASHYA_NAME_TAG_GOLD"), Config().colors["gold"])[1], + "name_tag_white": color_filter(template_finder.get_template("KASHYA_NAME_TAG_WHITE"), Config().colors["white"])[1], + "name_tag_gold": color_filter(template_finder.get_template("KASHYA_NAME_TAG_GOLD"), Config().colors["gold"])[1], "action_btns": { "resurrect": { - "white": color_filter(TemplateFinder().get_template("RESURRECT"), Config().colors["white"])[1], - "blue": color_filter(TemplateFinder().get_template("RESURRECT_BLUE"), Config().colors["blue"])[1], + "white": color_filter(template_finder.get_template("RESURRECT"), Config().colors["white"])[1], + "blue": color_filter(template_finder.get_template("RESURRECT_BLUE"), Config().colors["blue"])[1], } }, "template_group": ["KASHYA_FRONT", "KASHYA_BACK", "KASHYA_SIDE", "KASHYA_SIDE_2"] @@ -242,11 +242,11 @@ def open_npc_menu(npc_key: Npc) -> bool: roi_npc = npcs[npc_key]["roi"] else: roi_npc = roi_npc_search - res = TemplateFinder().search(key, img, threshold=0.35, roi=roi_npc, normalize_monitor=True) + res = template_finder.search(key, img, threshold=0.35, roi=roi_npc) if res.valid: is_unique = True for r in results: - if (abs(r["pos"][0] - res.center[0]) + abs(r["pos"][1] - res.center[1])) < 22: + if (abs(r["pos"][0] - res.center_monitor[0]) + abs(r["pos"][1] - res.center_monitor[1])) < 22: is_unique = False break if is_unique: @@ -254,9 +254,9 @@ def open_npc_menu(npc_key: Npc) -> bool: if attempts == 0 and "poses" in npcs[npc_key]: # find distance between template match and nearest pose (([x2] - x1)**2 + (y2 - y1)**2) for pose in npcs[npc_key]["poses"]: - dist = sqrt((res.center[0] - pose[0])**2 + (res.center[1] - pose[1])**2) + dist = sqrt((res.center_monitor[0] - pose[0])**2 + (res.center_monitor[1] - pose[1])**2) min_dist = dist if dist < min_dist else min_dist - results.append({"pos": res.center, "score": res.score, "combo": min_dist / (res.score**2)}) + results.append({"pos": res.center_monitor, "score": res.score, "combo": min_dist / (res.score**2)}) # sort by composite of template match score and distance to NPC pose results = sorted(results, key=lambda r: r["combo"]) for result in results: @@ -266,14 +266,14 @@ def open_npc_menu(npc_key: Npc) -> bool: img = escape_dialogue(img) _, filtered_inp_w = color_filter(img, Config().colors["white"]) _, filtered_inp_g = color_filter(img, Config().colors["gold"]) - res_w = TemplateFinder().search(npcs[npc_key]["name_tag_white"], filtered_inp_w, 0.9, roi=roi).valid - res_g = TemplateFinder().search(npcs[npc_key]["name_tag_gold"], filtered_inp_g, 0.9, roi=roi).valid + res_w = template_finder.search(npcs[npc_key]["name_tag_white"], filtered_inp_w, 0.9, roi=roi).valid + res_g = template_finder.search(npcs[npc_key]["name_tag_gold"], filtered_inp_g, 0.9, roi=roi).valid if res_w: mouse.click(button="left") attempts += 1 wait(0.7, 1.0) _, filtered_inp = color_filter(grab(), Config().colors["gold"]) - res = TemplateFinder().search(npcs[npc_key]["name_tag_gold"], filtered_inp, 0.9, roi=roi).valid + res = template_finder.search(npcs[npc_key]["name_tag_gold"], filtered_inp, 0.9, roi=roi).valid if res: return True elif res_g: @@ -285,23 +285,22 @@ def press_npc_btn(npc_key: Npc, action_btn_key: str): img = grab() img = escape_dialogue(img) _, filtered_inp_w = color_filter(img, Config().colors["white"]) - res = TemplateFinder().search( + res = template_finder.search( npcs[npc_key]["action_btns"][action_btn_key]["white"], - filtered_inp_w, 0.85, roi=Config().ui_roi["cut_skill_bar"], - normalize_monitor=True + filtered_inp_w, 0.85, roi=Config().ui_roi["cut_skill_bar"] ) if not res.valid and "blue" in npcs[npc_key]["action_btns"][action_btn_key]: # search for highlighted / blue action btn _, filtered_inp_b = color_filter(img, Config().colors["blue"]) - res = TemplateFinder().search( + res = template_finder.search( npcs[npc_key]["action_btns"][action_btn_key]["blue"], - filtered_inp_b, 0.85, roi=Config().ui_roi["cut_skill_bar"], - normalize_monitor=True + filtered_inp_b, 0.85, roi=Config().ui_roi["cut_skill_bar"] ) if res.valid: - mouse.move(*res.center, randomize=3, delay_factor=[1.0, 1.5]) + mouse.move(*res.center_monitor, randomize=3, delay_factor=[1.0, 1.5]) wait(0.2, 0.4) mouse.click(button="left") + wait(0.04, 0.08) center_mouse() else: Logger.error(f"Could not find {action_btn_key} btn. Should not happen! Continue...") diff --git a/src/ocr.py b/src/ocr.py deleted file mode 100644 index 24a176e7d..000000000 --- a/src/ocr.py +++ /dev/null @@ -1,309 +0,0 @@ -from tesserocr import PyTessBaseAPI, PSM, OEM -import numpy as np -import cv2 -import re -from rapidfuzz.process import extractOne -from rapidfuzz.string_metric import levenshtein -import csv -from utils.misc import erode_to_black -from logger import Logger -from typing import List, Union -from dataclasses import dataclass - -@dataclass -class OcrResult: - text: str = None - original_text: str = None - word_confidences: list = None - mean_confidence: float = None - # these are kept to help train OCR - original_img: np.ndarray = None - processed_img: np.ndarray = None - def __getitem__(self, key): - return super().__getattribute__(key) - -class Ocr: - def __init__(self): - self._I_1 = re.compile(r"(?<=[%I0-9\-+])I|I(?=[%I0-9\-+])") - self._II_U = re.compile(r"(?<=[A-Z])II|II(?=[A-Z])|1?=[a-z]") - self._One_I = re.compile(r"(?<=[A-Z])1|1(?=[A-Z])|1?=[a-z]") - self._OneOne_U = re.compile(r"(?<=[A-Z])11|11(?=[A-Z])|1?=[a-z]") - with open('assets/tessdata/ocr_errors.csv') as file: - self._ocr_errors = dict(csv.reader(file, skipinitialspace = False, delimiter = ',', quoting = csv.QUOTE_NONE)) - - """ - OCR input processing functions: - """ - def _crop_pad(self, image: np.ndarray = None): - # crop - image = image[4: image.shape[0]-4, 5: image.shape[1]-5] - # re-pad - image = np.pad(image, pad_width=[(4, 4),(4, 4),(0, 0)], mode='constant') - return image - - """ - OCR functions: - """ - - def _img_to_bytes(self, image: np.ndarray, colorspace: str = 'BGR'): - # Sets an OpenCV-style image for recognition: https://github.com/sirfz/tesserocr/issues/198 - bytes_per_pixel = image.shape[2] if len(image.shape) == 3 else 1 - height, width = image.shape[:2] - bytes_per_line = bytes_per_pixel * width - - if bytes_per_pixel != 1 and colorspace != 'RGB': - # non-RGB color image -> convert to RGB - image = cv2.cvtColor(image, getattr(cv2, f'COLOR_{colorspace}2RGB')) - elif bytes_per_pixel == 1 and image.dtype == bool: - # binary image -> convert to bitstream - image = np.packbits(image, axis=1) - bytes_per_line = image.shape[1] - width = bytes_per_line * 8 - bytes_per_pixel = 0 - # else image already RGB or grayscale - - return image.tobytes(), width, height, bytes_per_pixel, bytes_per_line - - def image_to_text(self, - images: Union[np.ndarray, List[np.ndarray]], - model: str = "engd2r_inv_th", - psm: int = 3, - word_list: str = "all_strings.txt", - scale: float = 1.0, - crop_pad: bool = True, - erode: bool = True, - invert: bool = True, - threshold: int = 25, - digits_only: bool = False, - fix_regexps: bool = True, - check_known_errors: bool = True, - check_wordlist: bool = True, - word_match_threshold: float = 0.5 - ) -> list[str]: - """ - Uses Tesseract to read image(s) - :param images (required): image or list of images to read in OpenCV format. - Use a list of images rather than looping over single images where possible for best performance. - :param model: OCR language model basename to use (in assets/tessdata folder) - :param psm: Tesseract PSM to use. 7=single uniform text line, 6=single block of text, 3=auto without orientation. - See https://www.pyimagesearch.com/2021/11/15/tesseract-page-segmentation-modes-psms-explained-how-to-improve-your-ocr-accuracy/ - :param word_list: predefined wordlist to use. Tesseract will use these to help with recognition - :param scale: scales input image, sometimes necessary for smaller text (but doesn't always improve accuracy). Engd2r_inv_th trained on ~1.6x scaled assets. - :param crop_pad: crop the outer part and then re-pad image. Intended for item drops. - :param erode: use erosion function to erode image to black borders (i.e. for item drops) - :param invert: invert and threshold the input image(s) - :param threshold: apply threshold to image (ex. 25 would threshold around V=25). Set to 0 to not threshold image. - :param digits_only: only look for digits - :param fix_regexps: use regex for various cases of common errors (I <-> 1, etc.) - :param check_known_errors: check for predefined common errors and replace - :param check_wordlist: check dictionary of words and match closest match if proximity is greater than word_match_threshold - :param word_match_threshold: (see check_wordlist) - :return: Returns an OcrResult object - """ - - if type(images) == np.ndarray: - images = [images] - results = [] - - with PyTessBaseAPI(psm=psm, oem=OEM.LSTM_ONLY, path=f"assets/tessdata", lang=model ) as api: - api.ReadConfigFile("assets/tessdata/ocr_config.txt") - if word_list: - api.SetVariable("user_words_file", word_list) - #api.SetSourceResolution(72 * scale) - for image in images: - processed_img = image - if scale: - processed_img = cv2.resize(processed_img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR) - if erode: - processed_img = erode_to_black(processed_img) - if crop_pad: - processed_img = self._crop_pad(processed_img) - image_is_binary = (image.shape[2] if len(image.shape) == 3 else 1) == 1 and image.dtype == bool - if not image_is_binary and threshold: - processed_img = cv2.cvtColor(processed_img, cv2.COLOR_BGR2GRAY) - processed_img = cv2.threshold(processed_img, threshold, 255, cv2.THRESH_BINARY)[1] - if invert: - if threshold or image_is_binary: - processed_img = cv2.bitwise_not(processed_img) - else: - processed_img = ~processed_img - api.SetImageBytes(*self._img_to_bytes(processed_img)) - if digits_only: - api.SetVariable("tessedit_char_blacklist", ".,!?@#$%&*()<>_-+=/:;'\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") - api.SetVariable("tessedit_char_whitelist", "0123456789") - api.SetVariable("classify_bln_numeric_mode", "1") - original_text = api.GetUTF8Text() - text = original_text - # replace newlines if image is a single line - if psm in (7, 8, 13): - text = text.replace('\n', '') - word_confidences = api.AllWordConfidences() - if fix_regexps: - text = self._fix_regexps(text) - if check_known_errors: - text = self._check_known_errors(text) - if check_wordlist and any([x <= 88 for x in word_confidences]): - text = self._check_wordlist(text, word_list, word_confidences, word_match_threshold) - results.append(OcrResult( - original_text = original_text, - text = text, - word_confidences = word_confidences, - mean_confidence = api.MeanTextConf(), - original_img = image, - processed_img = processed_img - )) - return results - - """ - OCR output processing functions: - """ - - def _check_known_errors(self, text): - for key, value in self._ocr_errors.items(): - if key in text: - text = text.replace(key, value) - return text - - def _check_wordlist(self, text: str = None, word_list: str = None, confidences: list = [], match_threshold: float = 0.5) -> str: - with open(f'assets/tessdata/word_lists/{word_list}') as file: - word_list = [line.rstrip() for line in file] - - word_count=0 - new_string="" - text = text.replace('\n',' NEWLINEHERE ') - for word in text.split(' '): - word = word.strip() - if word and word != "NEWLINEHERE": - try: - if confidences[word_count] <= 90: - alphanumeric = re.sub(r"[^a-zA-Z0-9]", "", word) - if not alphanumeric.isnumeric() and (word not in word_list) and alphanumeric not in word_list: - closest_match, similarity, _ = extractOne(word, word_list, scorer=levenshtein) - normalized_similarity = 1 - similarity / len(word) - if (normalized_similarity) >= (match_threshold): - new_string += f"{closest_match} " - Logger.debug(f"check_wordlist: Replacing {word} ({confidences[word_count]}%) with {closest_match}, similarity={normalized_similarity*100:.1f}%") - else: - new_string += f"{word} " - else: - new_string += f"{word} " - else: - new_string += f"{word} " - word_count += 1 - except IndexError: - # bizarre word_count index exceeded sometimes... can't reproduce and words otherwise seem to match up - Logger.error(f"check_wordlist: IndexError for word: {word}, index: {word_count}, text: {text}") - return text - except Exception as e: - Logger.error(f"check_wordlist: Unknown error for word: {word}, index: {word_count}, text: {text}, exception: {e}") - return text - elif word == "NEWLINEHERE": - new_string += "\n" - return new_string.strip() - - def _fix_regexps(self, ocr_output: str, repeat_count: int = 0) -> str: - # case: two 1's within a string; e.g., "SIIPER MANA POTION" - try: - text = self._II_U.sub('U', ocr_output) - except: - Logger.error(f"Error _II_ -> _U_ on {ocr_output}") - text = ocr_output - # case: two 1's within a string; e.g., "S11PER MANA POTION" - try: - text = self._OneOne_U.sub('U', text) - except: - Logger.error(f"Error _11_ -> _U_ on {ocr_output}") - # case: an I within a number or by a sign; e.g., "+32I to mana attack rating" - try: - text = self._I_1.sub('1', text) - except: - Logger.error(f"Error I -> 1 on {ocr_output}") - # case: a 1 within a string; e.g., "W1RT'S LEG" - try: - text = self._One_I.sub('I', text) - except: - Logger.error(f"Error 1 -> I on {ocr_output}") - - # case: a solitary I; e.g., " I TO 5 DEFENSE" - cnt=0 - while True: - cnt += 1 - if cnt >30: - Logger.error(f"Error ' I ' -> ' 1 ' on {ocr_output}") - break - if " I " in text: - text = text.replace(" I ", " 1 ") - continue - elif ' I\n' in text: - text = text.replace(' I\n', ' 1\n') - continue - elif '\nI ' in text: - text = text.replace('\nI ', '\n1 ') - continue - break - - # case: a solitary S; e.g., " 1 TO S DEFENSE" - cnt=0 - while True: - cnt += 1 - if cnt >30: - Logger.error(f"Error ' S ' -> ' 5 ' on {ocr_output}") - break - if " S " in text: - text = text.replace(" S ", " 5 ") - continue - elif ' I\n' in text: - text = text.replace(' S\n', ' 5\n') - continue - elif '\nI ' in text: - text = text.replace('\nS ', '\n5 ') - continue - break - - # case: consecutive I's; e.g., "DEFENSE: II" - repeat=False - cnt=0 - while "II" in text: - cnt += 1 - if cnt >30: - Logger.error(f"Error 4 on {ocr_output}") - break - text = text.replace("II", "11") - repeat=True - repeat_count += 1 - if repeat and repeat_count < 10: - self._fix_regexps(text) - - return text - -if __name__ == "__main__": - import os - import keyboard - keyboard.add_hotkey('f12', lambda: os._exit(1)) - keyboard.wait("f11") - from utils.misc import cut_roi - from config import Config - - from screen import grab - ocr = Ocr() - img = grab() - # img = cut_roi(img, Config().ui_roi["char_selection_top"]) - - Logger.debug("OCR result:") - ocr_result = ocr.image_to_text( - images = img, - model = "engd2r_ui", - psm = 3, - word_list = "all_strings.txt", - scale = 1.0, - crop_pad = False, - erode = False, - invert = False, - threshold = 0, - digits_only = False, - fix_regexps = False, - check_known_errors = False, - check_wordlist = False, - word_match_threshold = 0.5 - )[0] - Logger.debug(ocr_result.text) \ No newline at end of file diff --git a/src/pather.py b/src/pather.py index 0179505c9..98db4eb7d 100644 --- a/src/pather.py +++ b/src/pather.py @@ -3,7 +3,6 @@ import time import os import random -from typing import Tuple, Union, List import cv2 import numpy as np from utils.custom_mouse import mouse @@ -12,9 +11,9 @@ from config import Config from logger import Logger from screen import convert_screen_to_monitor, convert_abs_to_screen, convert_abs_to_monitor, convert_screen_to_abs, grab, stop_detecting_window -from template_finder import TemplateFinder +import template_finder from char import IChar -from ui_manager import detect_screen_object, ScreenObjects, is_visible, select_screen_object_match +from ui_manager import detect_screen_object, ScreenObjects, is_visible, select_screen_object_match, get_closest_non_hud_pixel class Location: # A5 Town @@ -125,8 +124,12 @@ def __init__(self): 123: {'ELDRITCH_3': (-99, -252), 'ELDRITCH_2': (403, -279), 'ELDRITCH_2_V2': (403, -279), 'ELDRITCH_4': (-62, -109), 'ELDRITCH_9': (-204, -254), 'ELDRITCH_8': (454, -104), 'ELDRITCH_8_V2': (454, -104)}, # Shenk 141: {'SHENK_0': (-129, 44), 'SHENK_1': (464, 107), 'SHENK_2': (-167, -34), 'SHENK_17': (-520, 528), 'SHENK_15': (77, 293), 'SHENK_18': (518, 512)}, - 142: {'SHENK_1': (584, 376), 'SHENK_4': (-443, -103), 'SHENK_2': (-52, 235), 'SHENK_3': (357, -129)}, - 143: {'SHENK_4': (-251, 165), 'SHENK_2': (141, 505), 'SHENK_3': (549, 139), 'SHENK_6': (-339, -69)}, + 142: {'SHENK_1': (584, 376), 'SHENK_4': (-443, -103), 'SHENK_2': (-52, 235), 'SHENK_3': (357, -129), + "ELDRITCH_2_V2": (516, 195), 'ELDRITCH_1': (-233, -77), "ELDRITCH_0_V2": (360, -140), "ELDRITCH_3": (20, 219) + }, + 143: {'SHENK_4': (-251, 165), 'SHENK_2': (141, 505), 'SHENK_3': (549, 139), 'SHENK_6': (-339, -69), + 'ELDRITCH_1': (10, 204), 'SHENK_7': (264, -37), 'ELDRITCH_0_V2': (591, 141), 'ELDRITCH_3': (252, 500) + }, 144: {'SHENK_6': (-108, 123), 'SHENK_7': (481, 151)}, 145: {'SHENK_7': (803, 372), 'SHENK_12': (97, -133), 'SHENK_6': (209, 347), 'SHENK_8': (-245, 18)}, 146: {'SHENK_12': (272, 111), 'SHENK_9': (-331, -144), 'SHENK_8': (-72, 258), 'SHENK_19': (-120, -221)}, @@ -164,13 +167,15 @@ def __init__(self): 222: {"TRAV_5": (-218, 106), "TRAV_4": (120, 230), "TRAV_2": (426, 7), "TRAV_7": (-719, -166), "TRAV_7_V2": (-719, -166), "TRAV_1": (862, -153)}, 223: {"TRAV_5": (344, 123), 'TRAV_4': (682, 247), "TRAV_8": (-353, -31), "TRAV_7": (-157, -149), "TRAV_7_V2": (-157, -149), "TRAV_22": (-368, -222), "TRAV_22_V2": (-368, -222), "TRAV_23": (-579, 116)}, 224: {'TRAV_7': (411, -129), 'TRAV_7_V2': (411, -129), 'TRAV_27': (-363, 163), "TRAV_8": (214, -11), "TRAV_23": (-11, 136), "TRAV_10": (-130, -187), "TRAV_10_V2": (-130, -187), "TRAV_24": (-274, 15), "TRAV_22": (200, -202), "TRAV_22_V2": (200, -202)}, - 225: {'TRAV_27': (96, 359), 'TRAV_8': (670, 187), 'TRAV_7': (867, 69), 'TRAV_7_V2': (867, 69), "TRAV_11": (10, 214), "TRAV_19": (-298, 539), "TRAV_24": (181, 213), "TRAV_12": (-408, -73), "TRAV_25": (-538, 132)}, + 225: {'TRAV_27': (96, 359), 'TRAV_8': (670, 187), 'TRAV_7': (867, 69), 'TRAV_7_V2': (867, 69), "TRAV_11": (10, 214), "TRAV_19": (-298, 539), "TRAV_24": (181, 213), "TRAV_12": (-408, -73), "TRAV_25": (-538, 132), 'TRAV_225_V3_0': (549, -147), 'TRAV_225_V3_1': (555, 125), 'TRAV_225_V3_3': (-149, -229), 'TRAV_225_V3_7': (-242, 13), 'TRAV_V2_2': (-27, 103), 'TRAV_225_V3_2': (31, 135)}, 226: {"TRAV_12": (-75, -172), "TRAV_25": (-205, 33), "TRAV_13": (-252, 195), "TRAV_11": (343, 115), "TRAV_18": (-514, 373), "TRAV_19": (35, 440), "TRAV_17": (-231, 242), "TRAV_27": (428, 263), "TRAV_29": (-929, 334), "TRAV_28": (-614, 338)}, 227: {"TRAV_11": (65, -42), "TRAV_24": (236, -43), "TRAV_19": (-243, 283), 'TRAV_18': (-792, 216), "TRAV_12": (-356, -330), "TRAV_25": (-483, -124), 'TRAV_27': (154, 104)}, 228: {"TRAV_13": (8, 9), "TRAV_17": (29, 56), "TRAV_25": (58, -152), "TRAV_16": (-198, -110), "TRAV_18": (-251, 188)}, 229: {"TRAV_18": (-250, 58), "TRAV_25": (59, -282), "TRAV_17": (30, -74), "TRAV_13": (9, -121), "TRAV_16": (-138, -241)}, 230: {"TRAV_19": (157, 39), "TRAV_18": (-392, -28), "TRAV_17": (-112, -160), "TRAV_13": (-133, -207), "TRAV_25": (-83, -368)}, - 300: {"TRAV_V3_4": (-101, 134), "TRAV_V3_5": (72, 220), "TRAV_V3_1": (237, -24), "TRAV_V3_3": (-318, 224), "TRAV_V3_11": (472, 39)}, + 300: {"TRAV_V3_4": (-101, 134), "TRAV_V3_5": (72, 220), "TRAV_V3_1": (237, -24), "TRAV_V3_3": (-318, 224), "TRAV_V3_11": (472, 39), + "TRAV_16": (129, -86), "TRAV_V2_0": (472, 65), "TRAV_17": (357, 84), "TRAV_12": (512, -333), + }, 301: {"TRAV_V3_7": (178, -33), "TRAV_V3_6": (170, 157), "TRAV_V3_0": (88, -235), "TRAV_V3_5": (-335, -95), "TRAV_V3_8": (444, -108)}, 302: {"TRAV_V3_0": (-18, 6), "TRAV_V3_7": (73, 208), "TRAV_V3_8": (339, 133), "TRAV_V3_6": (65, 398), "TRAV_V3_5": (-440, 146)}, 304: {"TRAV_V2_4": (125, -148), "TRAV_V2_3": (-187, 55), "TRAV_V2_1": (-207, 59), "TRAV_V2_2": (267, 183), "TRAV_V2_0": (-159, 403)}, @@ -492,10 +497,10 @@ def _get_node(self, key: int, template: str): ) @staticmethod - def _convert_rel_to_abs(rel_loc: Tuple[float, float], pos_abs: Tuple[float, float]) -> Tuple[float, float]: + def _convert_rel_to_abs(rel_loc: tuple[float, float], pos_abs: tuple[float, float]) -> tuple[float, float]: return (rel_loc[0] + pos_abs[0], rel_loc[1] + pos_abs[1]) - def traverse_nodes_fixed(self, key: Union[str, List[Tuple[float, float]]], char: IChar) -> bool: + def traverse_nodes_fixed(self, key: str | list[tuple[float, float]], char: IChar) -> bool: if not char.capabilities.can_teleport_natively: error_msg = "Teleport is required for static pathing" Logger.error(error_msg) @@ -511,9 +516,9 @@ def traverse_nodes_fixed(self, key: Union[str, List[Tuple[float, float]]], char: x_m, y_m = convert_screen_to_monitor(path[i]) x_m += int(random.random() * 6 - 3) y_m += int(random.random() * 6 - 3) - t0 = grab() + t0 = grab(force_new=True) char.move((x_m, y_m)) - t1 = grab() + t1 = grab(force_new=True) # check difference between the two frames to determine if tele was good or not diff = cv2.absdiff(t0, t1) diff = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY) @@ -527,51 +532,13 @@ def traverse_nodes_fixed(self, key: Union[str, List[Tuple[float, float]]], char: if stuck_count >= 5: return False # if type(key) == str and ("_save_dist" in key or "_end" in key): - # cv2.imwrite(f"./info_screenshots/nil_path_{key}_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + # cv2.imwrite(f"./log/screenshots/info/nil_path_{key}_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return True - def _adjust_abs_range_to_screen(self, abs_pos: Tuple[float, float]) -> Tuple[float, float]: - """ - Adjust an absolute coordinate so it will not go out of screen or click on any ui which will not move the char - :param abs_pos: Absolute position of the desired position to move to - :return: Absolute position of a valid position that can be clicked on - """ - f = 1.0 - # Check for x-range - if abs_pos[0] > self._range_x[1]: - f = min(f, abs(self._range_x[1] / float(abs_pos[0]))) - elif abs_pos[0] < self._range_x[0]: - f = min(f, abs(self._range_x[0] / float(abs_pos[0]))) - # Check y-range - if abs_pos[1] > self._range_y[1]: - f = min(f, abs(self._range_y[1] / float(abs_pos[1]))) - if abs_pos[1] < self._range_y[0]: - f = min(f, abs(self._range_y[0] / float(abs_pos[1]))) - # Scale the position by the factor f - if f < 1.0: - abs_pos = (int(abs_pos[0] * f), int(abs_pos[1] * f)) - # Check if adjusted position is "inside globe" - screen_pos = convert_abs_to_screen(abs_pos) - if is_in_roi(Config().ui_roi["mana_globe"], screen_pos) or is_in_roi(Config().ui_roi["health_globe"], screen_pos): - # convert any of health or mana roi top coordinate to abs (x-coordinate is just a dummy 0 value) - new_range_y_bottom = convert_screen_to_abs((0, Config().ui_roi["mana_globe"][1]))[1] - f = abs(new_range_y_bottom / float(abs_pos[1])) - abs_pos = (int(abs_pos[0] * f), int(abs_pos[1] * f)) - # Check if clicking on merc img - screen_pos = convert_abs_to_screen(abs_pos) - if is_in_roi(Config().ui_roi["merc_icon"], screen_pos): - width = Config().ui_roi["merc_icon"][2] - height = Config().ui_roi["merc_icon"][3] - w_abs, h_abs = convert_screen_to_abs((width, height)) - fw = abs(w_abs / float(abs_pos[0])) - fh = abs(h_abs / float(abs_pos[1])) - f = max(fw, fh) - abs_pos = (int(abs_pos[0] * f), int(abs_pos[1] * f)) - return abs_pos - - def find_abs_node_pos(self, node_idx: int, img: np.ndarray, threshold: float = 0.68) -> Tuple[float, float]: + + def find_abs_node_pos(self, node_idx: int, img: np.ndarray, threshold: float = 0.68) -> tuple[float, float]: node = self._nodes[node_idx] - template_match = TemplateFinder().search( + template_match = template_finder.search( [*node], img, best_match=False, @@ -585,13 +552,13 @@ def find_abs_node_pos(self, node_idx: int, img: np.ndarray, threshold: float = 0 # Calc the abs node position with the relative coordinates (relative to ref) node_pos_rel = self._get_node(node_idx, template_match.name) node_pos_abs = self._convert_rel_to_abs(node_pos_rel, ref_pos_abs) - node_pos_abs = self._adjust_abs_range_to_screen(node_pos_abs) + node_pos_abs = get_closest_non_hud_pixel(pos = node_pos_abs, pos_type="abs") return node_pos_abs return None def traverse_nodes( self, - path: Union[tuple[Location, Location], list[int]], + path: tuple[Location, Location] | list[int], char: IChar, timeout: float = 5, force_tp: bool = False, @@ -638,10 +605,10 @@ def traverse_nodes( did_force_move = False teleport_count = 0 while not continue_to_next_node: - img = grab() + img = grab(force_new=True) # Handle timeout if (time.time() - last_move) > timeout: - if is_visible(ScreenObjects.WaypointLabel): + if is_visible(ScreenObjects.WaypointLabel, img): # sometimes bot opens waypoint menu, close it to find templates again Logger.debug("Opened wp, closing it again") keyboard.send("esc") @@ -652,16 +619,18 @@ def traverse_nodes( # Don't want to spam the log with errors in this case because it most likely worked out just fine if timeout > 3.1: if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/info_pather_got_stuck_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) + cv2.imwrite("./log/screenshots/info/info_pather_got_stuck_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) Logger.error("Got stuck exit pather") return False # Sometimes we get stuck at rocks and stuff, after a few seconds force a move into the last known direction if not did_force_move and time.time() - last_move > 3.1: - pos_abs = (0, 150) if last_direction is not None: pos_abs = last_direction - pos_abs = self._adjust_abs_range_to_screen(pos_abs) + else: + angle = random.random() * math.pi * 2 + pos_abs = (round(math.cos(angle) * 150), round(math.sin(angle) * 150)) + pos_abs = get_closest_non_hud_pixel(pos = pos_abs, pos_type="abs") Logger.debug(f"Pather: taking a random guess towards " + str(pos_abs)) x_m, y_m = convert_abs_to_monitor(pos_abs) char.move((x_m, y_m), force_move=True) @@ -670,11 +639,13 @@ def traverse_nodes( # Sometimes we get stuck at a Shrine or Stash, after a few seconds check if the screen was different, if force a left click. if (teleport_count + 1) % 30 == 0: - if (match := detect_screen_object(ScreenObjects.ShrineArea)).valid: - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_shrine_check_before" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if (match := detect_screen_object(ScreenObjects.ShrineArea, img)).valid: + if Config().general["info_screenshots"]: + cv2.imwrite(f"./log/screenshots/info_shrine_check_before" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) Logger.debug(f"Shrine found, activating it") select_screen_object_match(match) - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_shrine_check_after" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: + cv2.imwrite(f"./log/screenshots/info/info_shrine_check_after" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) teleport_count = 0 break teleport_count += 1 @@ -699,21 +670,24 @@ def traverse_nodes( if __name__ == "__main__": # debug method to display all nodes - def display_all_nodes(pather: Pather, filter: str = None): + def display_all_nodes(pather: Pather, filters: list | str = None): start = time.time() while 1: img = grab() display_img = img.copy() template_map = {} template_scores = {} - for template_type in TemplateFinder()._templates: - if filter is None or filter in template_type: - template_match = TemplateFinder().search(template_type, img, use_grayscale=True, threshold=0.78) - if template_match.valid: - template_map[template_type] = template_match.center - template_scores[template_type] = template_match.score + for template_type in template_finder.stored_templates().keys(): + if type(filters) != list: + filters = [filters] + for filter in filters: + if filter is None or filter in template_type: + template_match = template_finder.search(template_type, img, use_grayscale=True, threshold=0.78) + if template_match.valid: + template_map[template_type] = template_match.center + template_scores[template_type] = round(template_match.score, 3) #print(f"{template_scores:0.2f}") - print(template_scores) + print(f"Matching template scores: {template_scores}") # print(template_map) for node_idx in pather._nodes: for template_type in pather._nodes[node_idx]: @@ -724,18 +698,20 @@ def display_all_nodes(pather: Pather, filter: str = None): # Calc the abs node position with the relative coordinates (relative to ref) node_pos_rel = pather._get_node(node_idx, template_type) node_pos_abs = pather._convert_rel_to_abs(node_pos_rel, ref_pos_abs) - node_pos_abs = pather._adjust_abs_range_to_screen(node_pos_abs) + node_pos_abs = get_closest_non_hud_pixel(pos = node_pos_abs, pos_type="abs") x, y = convert_abs_to_screen(node_pos_abs) + print(f"Draw circle for node {node_idx} at abs coordinates: {node_pos_abs}") cv2.circle(display_img, (x, y), 5, (255, 0, 0), 3) cv2.putText(display_img, str(node_idx), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) x, y = convert_abs_to_screen(ref_pos_abs) cv2.circle(display_img, (x, y), 5, (0, 255, 0), 3) cv2.putText(display_img, template_type, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) wrt_origin = (-ref_pos_abs[0], -ref_pos_abs[1]) - print(f'"{template_type}": {wrt_origin}') + print(f'Found template "{template_type}" at abs coordinates: {ref_pos_abs}') + # print(f'Template: "{template_type}", coordinates with respect to origin: {wrt_origin}') # display_img = cv2.resize(display_img, None, fx=0.5, fy=0.5) # if round(time.time() - start) % 3 == 0: - # cv2.imwrite("./info_screenshots/pather_" + time.strftime("%Y%m%d_%H%M%S") + ".png", display_img) + # cv2.imwrite("./log/screenshots/info/pather_" + time.strftime("%Y%m%d_%H%M%S") + ".png", display_img) cv2.imshow("debug", display_img) cv2.waitKey(1) @@ -746,16 +722,16 @@ def display_all_nodes(pather: Pather, filter: str = None): start_detecting_window() from config import Config from char.sorceress import LightSorc - from char.hammerdin import Hammerdin + from char.paladin.hammerdin import Hammerdin from item.pickit import PickIt pather = Pather() #char = Hammerdin(Config().hammerdin, pather, PickIt) #Config().char, #char.discover_capabilities() - #display_all_nodes(pather, "ELD") + display_all_nodes(pather, ["ELD", "SHENK_"]) #pather.traverse_nodes([120, 121, 122, 123, 122, 121, 120], char) #works! #pather.traverse_nodes_fixed("dia_trash_c", char) #display_all_nodes(pather, "SHENK") #pather.traverse_nodes([141,142,143], char) - #stop_detecting_window() \ No newline at end of file + #stop_detecting_window() diff --git a/src/run/arcane.py b/src/run/arcane.py index 7ca60233e..d9403b89a 100644 --- a/src/run/arcane.py +++ b/src/run/arcane.py @@ -2,9 +2,8 @@ from config import Config from logger import Logger from pather import Location, Pather -from typing import Union from item.pickit import PickIt -from template_finder import TemplateFinder +import template_finder from town.town_manager import TownManager from utils.misc import wait from dataclasses import dataclass @@ -13,20 +12,25 @@ from health_manager import set_pause_state class Arcane: + + name = "run_arcane" + def __init__( self, pather: Pather, town_manager: TownManager, char: IChar, pickit: PickIt, + runs: list[str] ): self._pather = pather self._town_manager = town_manager self._char = char self._pickit = pickit self._chest = Chest(self._char, 'arcane') + self._runs = runs - def approach(self, start_loc: Location) -> Union[bool, Location]: + def approach(self, start_loc: Location) -> bool | Location: Logger.info("Run Arcane") set_pause_state(True) if not self._char.capabilities.can_teleport_natively: @@ -42,13 +46,13 @@ def _find_summoner(self, traverse_to_summoner: list[tuple[float, float]]) -> boo # Check if we arrived at platform templates_platform = ["ARC_PLATFORM_1", "ARC_PLATFORM_2", "ARC_PLATFORM_3", "ARC_CENTER"] tempaltes_summoner = ["ARC_ALTAR", "ARC_ALTAR3", "ARC_END_STAIRS", "ARC_END_STAIRS_2"] - match_platform = TemplateFinder().search_and_wait(templates_platform, threshold=0.55, timeout=0.5, use_grayscale=True, take_ss=False) - match_summoner = TemplateFinder().search_and_wait(tempaltes_summoner, threshold=0.79, timeout=0.5, use_grayscale=True, take_ss=False) + match_platform = template_finder.search_and_wait(templates_platform, threshold=0.55, timeout=0.5, use_grayscale=True) + match_summoner = template_finder.search_and_wait(tempaltes_summoner, threshold=0.79, timeout=0.5, use_grayscale=True) if not match_platform.valid and not match_summoner.valid: # We might have arrived at summoner, move up stairs with static traverse self._pather.traverse_nodes_fixed(traverse_to_summoner, self._char) # try to match summoner again - match_summoner = TemplateFinder().search_and_wait(tempaltes_summoner, threshold=0.79, timeout=1.0, use_grayscale=True, take_ss=False) + match_summoner = template_finder.search_and_wait(tempaltes_summoner, threshold=0.79, timeout=1.0, use_grayscale=True) if match_summoner.valid: if self._pather.traverse_nodes([461], self._char, timeout=2.2, force_tp=True): return True @@ -57,7 +61,7 @@ def _find_summoner(self, traverse_to_summoner: list[tuple[float, float]]) -> boo self._pather.traverse_nodes([462], self._char, timeout=1.3, force_tp=True) return False - def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: + def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]: picked_up_items = False @dataclass class PathData: diff --git a/src/run/diablo.py b/src/run/diablo.py index c1014e87c..5fabe69b5 100644 --- a/src/run/diablo.py +++ b/src/run/diablo.py @@ -4,9 +4,8 @@ from config import Config from logger import Logger from pather import Location, Pather -from typing import Union from item.pickit import PickIt -from template_finder import TemplateFinder +import template_finder from town.town_manager import TownManager, A4 from utils.misc import wait from utils.custom_mouse import mouse @@ -16,12 +15,16 @@ from inventory import belt, personal class Diablo: + + name = "run_diablo" + def __init__( self, pather: Pather, town_manager: TownManager, char: IChar, - pickit: PickIt + pickit: PickIt, + runs: list[str] ): self._pather = pather self._town_manager = town_manager @@ -29,9 +32,10 @@ def __init__( self._pickit = pickit self._picked_up_items = False self.used_tps = 0 - self._curr_loc: Union[bool, Location] = Location.A4_TOWN_START + self._curr_loc: bool | Location = Location.A4_TOWN_START + self._runs = runs - def approach(self, start_loc: Location) -> Union[bool, Location, bool]: + def approach(self, start_loc: Location) -> bool | Location: Logger.info("Run Diablo") Logger.debug("settings for trash =" + str(Config().char["kill_cs_trash"])) @@ -61,11 +65,10 @@ def _cs_town_visit(self, location:str) -> bool: force_stash = False force_stash = personal.inventory_has_items(close_window=True) if force_stash: - if Config().char["id_items"]: - Logger.debug(location + ": Identifying items") - self._curr_loc = self._town_manager.identify(self._curr_loc) - if not self._curr_loc: - return self.trigger_or_stop("end_game", failed=True) + Logger.debug(location + ": Identifying items") + self._curr_loc = self._town_manager.identify(self._curr_loc) + if not self._curr_loc: + return self.trigger_or_stop("end_game", failed=True) Logger.debug(location + ":Stashing items") self._curr_loc = self._town_manager.stash(self._curr_loc) if not self._curr_loc: @@ -82,7 +85,7 @@ def _cs_town_visit(self, location:str) -> bool: if not self._pather.traverse_nodes([164, 163], self._char, timeout=2): return False wait(0.22, 0.28) if (template_match := detect_screen_object(ScreenObjects.TownPortalReduced)).valid: - pos = template_match.center + pos = template_match.center_monitor pos = (pos[0], pos[1] + 30) Logger.debug(location + ": Going through portal...") # Note: Template is top of portal, thus move the y-position a bit to the bottom @@ -96,9 +99,9 @@ def _cs_town_visit(self, location:str) -> bool: if not self._pather.traverse_nodes([602], self._char, threshold=0.80): return False self._pather.traverse_nodes_fixed("dia_pent_rudijump", self._char) Logger.debug("CS after town: Re-open TP") - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/TP_after_town" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/TP_after_town" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) if not skills.has_tps(): - Logger.warning("CS after Town: failed to open TP, higher chance of failing runs from now on, you should buy new TPs! (hint: always_repair=1)") + Logger.warning("CS after Town: failed to open TP, higher chance of failing runs from now on, you should buy new TPs!") self.used_tps += 20 mouse.click(button="right") self.used_tps += 1 @@ -109,11 +112,11 @@ def _cs_town_visit(self, location:str) -> bool: # OPEN SEALS def _sealdance(self, seal_opentemplates: list[str], seal_closedtemplates: list[str], seal_layout: str, seal_node: str) -> bool: i = 0 - while i < 4: + while i < 8: Logger.debug(seal_layout + ": trying to open (try #" + str(i+1)+")") self._char.select_by_template(seal_closedtemplates, threshold=0.5, timeout=0.1, telekinesis=True) wait(i*0.5) - found = TemplateFinder().search_and_wait(seal_opentemplates, threshold=0.75, timeout=0.1, best_match=True, take_ss=False).valid + found = template_finder.search_and_wait(seal_opentemplates, threshold=0.7, timeout=0.1).valid if found: Logger.info(seal_layout +": is open - "+'\033[92m'+" open"+'\033[0m') break @@ -133,7 +136,7 @@ def _sealdance(self, seal_opentemplates: list[str], seal_closedtemplates: list[s x_m, y_m = convert_abs_to_monitor([50 * direction, direction]) self._char.move((x_m, y_m), force_move=True) i += 1 - if Config().general["info_screenshots"] and not found: cv2.imwrite(f"./info_screenshots/info_failed_seal_" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"] and not found: cv2.imwrite(f"./log/screenshots/info/info_failed_seal_" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return found @@ -143,10 +146,10 @@ def _loop_pentagram(self, path) -> bool: templates = ["DIA_NEW_PENT_TP", "DIA_NEW_PENT_0", "DIA_NEW_PENT_1", "DIA_NEW_PENT_2"] start_time = time.time() while not found and time.time() - start_time < 15: - found = TemplateFinder().search_and_wait(templates, threshold=0.83, timeout=0.1, best_match=True, take_ss=False, suppress_debug=True).valid + found = template_finder.search_and_wait(templates, threshold=0.83, timeout=0.1, suppress_debug=True).valid if not found: self._pather.traverse_nodes_fixed(path, self._char) if not found: - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_failed_loop_pentagram_" + path + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_failed_loop_pentagram_" + path + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False return True @@ -161,13 +164,13 @@ def _entrance_hall(self) -> bool: if not self._pather.traverse_nodes([605], self._char): return False templates = ["DIABLO_ENTRANCE_53", "DIABLO_ENTRANCE_51","DIABLO_ENTRANCE_50", "DIABLO_ENTRANCE_52", "DIABLO_ENTRANCE_54", "DIABLO_ENTRANCE_55"] - if TemplateFinder().search_and_wait(templates, threshold=0.8, timeout=0.1, best_match=False, take_ss=False).valid: + if template_finder.search_and_wait(templates, threshold=0.8, timeout=0.1).valid: Logger.debug("CS Trash (A): Layout_check step 1/2: Layout A templates found") templates = ["DIABLO_ENTRANCE2_55", "DIABLO_ENTRANCE2_50", "DIABLO_ENTRANCE2_51", "DIABLO_ENTRANCE2_52","DIABLO_ENTRANCE2_53","DIABLO_ENTRANCE2_54","DIABLO_ENTRANCE2_15","DIABLO_ENTRANCE2_56"] - if not TemplateFinder().search_and_wait(templates, threshold=0.8, timeout=0.5, best_match=True, take_ss=False).valid: + if not template_finder.search_and_wait(templates, threshold=0.8, timeout=0.5).valid: Logger.debug("CS Trash (A): Layout_check step 2/2: Layout B templates NOT found - "+'\033[95m'+"all fine, proceeding with Layout A"+'\033[0m') entrance1_layout = "CS Trash (A):" - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_" + entrance1_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_" + entrance1_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) Logger.debug(entrance1_layout + " clearing second hall (1/3) location: entrance1_01") self._char.kill_cs_trash("entrance1_01") Logger.debug(entrance1_layout + " clearing second hall (2/3) location: entrance1_02") @@ -179,16 +182,16 @@ def _entrance_hall(self) -> bool: return True else: Logger.warning("CS Trash (A): Layout_check failed to determine the right Layout, "+'\033[91m'+"trying to loop to pentagram to save the run"+'\033[0m') - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_entrance_a_failed_layoutcheck_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_entrance_a_failed_layoutcheck_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return True else: Logger.debug("CS Trash (B): Layout_check step 1/2: Layout A templates NOT found") templates = ["DIABLO_ENTRANCE2_55", "DIABLO_ENTRANCE2_50", "DIABLO_ENTRANCE2_51", "DIABLO_ENTRANCE2_52","DIABLO_ENTRANCE2_53","DIABLO_ENTRANCE2_54","DIABLO_ENTRANCE2_15","DIABLO_ENTRANCE2_56"] - if TemplateFinder().search_and_wait(templates, threshold=0.8, timeout=0.1, best_match=False, take_ss=False).valid: + if template_finder.search_and_wait(templates, threshold=0.8, timeout=0.1).valid: Logger.debug("CS Trash (B): Layout_check step 2/2: Layout B templates found - "+'\033[96m'+"all fine, proceeding with Layout B"+'\033[0m') entrance2_layout = "CS Trash (B):" - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_" + entrance2_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_" + entrance2_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) Logger.debug(entrance2_layout + " clearing second hall (1/3) - location: entrance2_01") self._char.kill_cs_trash("entrance2_01") Logger.debug(entrance2_layout + " clearing second hall (2/3) - location: entrance2_02") @@ -200,7 +203,7 @@ def _entrance_hall(self) -> bool: return True else: Logger.warning("CS Trash (B): Layout_check failed to determine the right Layout, "+'\033[91m'+"trying to loop to pentagram to save the run"+'\033[0m') - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_entrance_b_failed_layoutcheck_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_entrance_b_failed_layoutcheck_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return True #GET FROM WP TO PENTAGRAM (clear_trash=0) @@ -214,11 +217,11 @@ def _river_of_flames(self) -> bool: templates = ["DIA_NEW_PENT_0", "DIA_NEW_PENT_1", "DIA_NEW_PENT_2"] start_time = time.time() while not found and time.time() - start_time < 10: - found = TemplateFinder().search_and_wait(templates, threshold=0.8, timeout=0.1, best_match=True, take_ss=False, suppress_debug=True).valid + found = template_finder.search_and_wait(templates, threshold=0.8, timeout=0.1, suppress_debug=True).valid if not found: self._pather.traverse_nodes_fixed("diablo_wp_pentagram_loop", self._char) if not found: - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_failed_pent_loop_no_trash_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_failed_pent_loop_no_trash_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False return True @@ -235,11 +238,11 @@ def _river_of_flames_trash(self) -> bool: templates = ["DIABLO_CS_ENTRANCE_0", "DIABLO_CS_ENTRANCE_2", "DIABLO_CS_ENTRANCE_3"] start_time = time.time() while not found and time.time() - start_time < 10: - found = TemplateFinder().search_and_wait(templates, threshold=0.8, timeout=0.1, best_match=True, take_ss=False, suppress_debug=True).valid + found = template_finder.search_and_wait(templates, threshold=0.8, timeout=0.1, suppress_debug=True).valid if not found: self._pather.traverse_nodes_fixed("diablo_wp_entrance_loop", self._char) if not found: - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_failed_cs_entrance_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_failed_cs_entrance_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False Logger.debug("Kill trash at location: rof_02") self._char.kill_cs_trash("rof_02") @@ -251,10 +254,10 @@ def _river_of_flames_trash(self) -> bool: templates = ["DIA_NEW_PENT_TP", "DIA_NEW_PENT_0", "DIA_NEW_PENT_1", "DIA_NEW_PENT_2"] start_time = time.time() while not found and time.time() - start_time < 15: - found = TemplateFinder().search_and_wait(templates, threshold=0.83, timeout=0.1, best_match=True, take_ss=False, suppress_debug=True).valid + found = template_finder.search_and_wait(templates, threshold=0.83, timeout=0.1, suppress_debug=True).valid if not found: self._pather.traverse_nodes_fixed("diablo_wp_pentagram_loop", self._char) if not found: - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_failed_loop_pentagram_diablo_wp_pentagram_loop_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_failed_loop_pentagram_diablo_wp_pentagram_loop_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False return True @@ -288,10 +291,10 @@ def _trash_seals(self, seal:str, path:str, node_calibration:str, loop_path:str, templates = ["DIA_NEW_PENT_TP", "DIA_NEW_PENT_0", "DIA_NEW_PENT_1", "DIA_NEW_PENT_2"] start_time = time.time() while not found and time.time() - start_time < 15: - found = TemplateFinder().search_and_wait(templates, threshold=0.83, timeout=0.1, best_match=True, take_ss=False).valid + found = template_finder.search_and_wait(templates, threshold=0.83, timeout=0.1).valid if not found: self._pather.traverse_nodes_fixed(loop_path, self._char) if not found: - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_failed_loop_pentagram_" + path + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_failed_loop_pentagram_" + path + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False if not self._pather.traverse_nodes([602], self._char, timeout=2): return False Logger.info("CS TRASH: " + str(seal) + " calibrated at PENTAGRAM") @@ -304,7 +307,7 @@ def _trash_seals(self) -> bool: self._pather.traverse_nodes_fixed("dia_trash_a", self._char) Logger.debug("CS TRASH: A Pent to LC") self._char.kill_cs_trash("dia_trash_a") - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_Trash_A_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_Trash_A_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) Logger.debug("CS TRASH: A looping to PENTAGRAM") if not self._loop_pentagram("dia_a1l_home_loop"): return False if not self._pather.traverse_nodes([602], self._char): return False @@ -313,7 +316,7 @@ def _trash_seals(self) -> bool: self._pather.traverse_nodes_fixed("dia_trash_b", self._char) Logger.debug("CS TRASH: B Pent to LC") self._char.kill_cs_trash("dia_trash_b") - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_Trash_B_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_Trash_B_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) Logger.debug("CS TRASH: B looping to PENTAGRAM") if not self._loop_pentagram("dia_b1s_home_loop"): return False if not self._pather.traverse_nodes([602], self._char): return False @@ -322,7 +325,7 @@ def _trash_seals(self) -> bool: self._pather.traverse_nodes_fixed("dia_trash_c", self._char) Logger.debug("CS TRASH: C Pent to LC") self._char.kill_cs_trash("dia_trash_c") - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_Trash_C_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_Trash_C_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) Logger.debug("CS TRASH: C looping to PENTAGRAM") if not self._loop_pentagram("dia_c1f_home_loop"): return False if not self._pather.traverse_nodes([602], self._char): return False @@ -331,53 +334,53 @@ def _trash_seals(self) -> bool: #CHECK SEAL LAYOUT def _layoutcheck(self, sealname:str, boss:str, static_layoutcheck:str, trash_location:str , calibration_node:str, calibration_threshold:str, confirmation_node:str, templates_primary:list[str], templates_confirmation:list[str]): - if sealname == "A": - seal_layout1:str = "A1-L" - seal_layout2:str = "A2-Y" - params_seal1 = seal_layout1, [614], [615], [611], "dia_a1l_home", "dia_a1l_home_loop", [602], ["DIA_A1L2_14_OPEN"], ["DIA_A1L2_14_CLOSED", "DIA_A1L2_14_CLOSED_DARK", "DIA_A1L2_14_MOUSEOVER"], ["DIA_A1L2_5_OPEN"], ["DIA_A1L2_5_CLOSED","DIA_A1L2_5_MOUSEOVER"] - params_seal2 = seal_layout2, [625], [626], [622], "dia_a2y_home", "dia_a2y_home_loop", [602], ["DIA_A2Y4_29_OPEN"], ["DIA_A2Y4_29_CLOSED", "DIA_A2Y4_29_MOUSEOVER"], ["DIA_A2Y4_36_OPEN"], ["DIA_A2Y4_36_CLOSED", "DIA_A2Y4_36_MOUSEOVER"] - threshold_primary=0.8 - threshold_confirmation=0.85 - threshold_confirmation2=0.8 - confirmation_node2=None - elif sealname == "B": - seal_layout2:str = "B1-S" - seal_layout1:str = "B2-U" - params_seal2 = seal_layout2, None, [634], [632], "dia_b1s_home", "dia_b1s_home_loop", [602], None, None, ["DIA_B1S2_23_OPEN"], ["DIA_B1S2_23_CLOSED","DIA_B1S2_23_MOUSEOVER"] - params_seal1 = seal_layout1, None, [644], [640], "dia_b2u_home", "dia_b2u_home_loop", [602], None, None, ["DIA_B2U2_16_OPEN"], ["DIA_B2U2_16_CLOSED", "DIA_B2U2_16_MOUSEOVER"] - confirmation_node2=[634] - threshold_primary=0.8 - threshold_confirmation2=0.8 - threshold_confirmation=0.75 - elif sealname == "C": - seal_layout1:str = "C1-F" - seal_layout2:str = "C2-G" - params_seal1 = seal_layout1, [655], [652], [654], "dia_c1f_home", "dia_c1f_home_loop", [602], ["DIA_C1F_OPEN_NEAR"], ["DIA_C1F_CLOSED_NEAR","DIA_C1F_MOUSEOVER_NEAR"], ["DIA_B2U2_16_OPEN", "DIA_C1F_BOSS_OPEN_RIGHT", "DIA_C1F_BOSS_OPEN_LEFT"], ["DIA_C1F_BOSS_MOUSEOVER_LEFT", "DIA_C1F_BOSS_CLOSED_NEAR_LEFT", "DIA_C1F_BOSS_CLOSED_NEAR_RIGHT"] - params_seal2 = seal_layout2, [661], [665], [665], "dia_c2g_home", "dia_c2g_home_loop", [602], ["DIA_C2G2_7_OPEN"], ["DIA_C2G2_7_CLOSED", "DIA_C2G2_7_MOUSEOVER"], ["DIA_C2G2_21_OPEN"], ["DIA_C2G2_21_CLOSED", "DIA_C2G2_21_MOUSEOVER"] - threshold_primary=0.8 - confirmation_node2=None - threshold_confirmation=0.8 - threshold_confirmation2=0.8 - - else: - Logger.warning(sealname + ": something is wrong - cannot check layouts: Aborting run.") - return False + match sealname: + case "A": + seal_layout1:str = "A1-L" + seal_layout2:str = "A2-Y" + params_seal1 = seal_layout1, [614], [615], [611], "dia_a1l_home", "dia_a1l_home_loop", [602], ["DIA_A1L2_14_OPEN"], ["DIA_A1L2_14_CLOSED", "DIA_A1L2_14_CLOSED_DARK", "DIA_A1L2_14_MOUSEOVER"], ["DIA_A1L2_5_OPEN"], ["DIA_A1L2_5_CLOSED","DIA_A1L2_5_MOUSEOVER"] + params_seal2 = seal_layout2, [625], [626], [622], "dia_a2y_home", "dia_a2y_home_loop", [602], ["DIA_A2Y4_29_OPEN"], ["DIA_A2Y4_29_CLOSED", "DIA_A2Y4_29_MOUSEOVER"], ["DIA_A2Y4_36_OPEN"], ["DIA_A2Y4_36_CLOSED", "DIA_A2Y4_36_MOUSEOVER"] + threshold_primary=0.8 + threshold_confirmation=0.85 + threshold_confirmation2=0.8 + confirmation_node2=None + case "B": + seal_layout2:str = "B1-S" + seal_layout1:str = "B2-U" + params_seal2 = seal_layout2, None, [634], [632], "dia_b1s_home", "dia_b1s_home_loop", [602], None, None, ["DIA_B1S2_23_OPEN"], ["DIA_B1S2_23_CLOSED","DIA_B1S2_23_MOUSEOVER"] + params_seal1 = seal_layout1, None, [644], [640], "dia_b2u_home", "dia_b2u_home_loop", [602], None, None, ["DIA_B2U2_16_OPEN"], ["DIA_B2U2_16_CLOSED", "DIA_B2U2_16_MOUSEOVER"] + confirmation_node2=[634] + threshold_primary=0.8 + threshold_confirmation2=0.8 + threshold_confirmation=0.75 + case "C": + seal_layout1:str = "C1-F" + seal_layout2:str = "C2-G" + params_seal1 = seal_layout1, [655], [652], [654], "dia_c1f_home", "dia_c1f_home_loop", [602], ["DIA_C1F_OPEN_NEAR"], ["DIA_C1F_CLOSED_NEAR","DIA_C1F_MOUSEOVER_NEAR"], ["DIA_B2U2_16_OPEN", "DIA_C1F_BOSS_OPEN_RIGHT", "DIA_C1F_BOSS_OPEN_LEFT"], ["DIA_C1F_BOSS_MOUSEOVER_LEFT", "DIA_C1F_BOSS_CLOSED_NEAR_LEFT", "DIA_C1F_BOSS_CLOSED_NEAR_RIGHT"] + params_seal2 = seal_layout2, [661], [665], [665], "dia_c2g_home", "dia_c2g_home_loop", [602], ["DIA_C2G2_7_OPEN"], ["DIA_C2G2_7_CLOSED", "DIA_C2G2_7_MOUSEOVER"], ["DIA_C2G2_21_OPEN"], ["DIA_C2G2_21_CLOSED", "DIA_C2G2_21_MOUSEOVER"] + threshold_primary=0.8 + confirmation_node2=None + threshold_confirmation=0.8 + threshold_confirmation2=0.8 + case _: + Logger.warning(sealname + ": something is wrong - cannot check layouts: Aborting run.") + return False self._pather.traverse_nodes_fixed(static_layoutcheck, self._char) self._char.kill_cs_trash(trash_location) Logger.debug(f"{sealname}: Checking Layout for "f"{boss}") if not calibration_node == None: if not self._pather.traverse_nodes(calibration_node, self._char, threshold=calibration_threshold,): return False - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_LC_" + sealname + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_LC_" + sealname + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) #check1 using primary templates - if not TemplateFinder().search_and_wait(templates_primary, threshold =threshold_primary, timeout=0.1, best_match=True, take_ss=False).valid: + if not template_finder.search_and_wait(templates_primary, threshold =threshold_primary, timeout=0.1).valid: Logger.debug(f"{seal_layout1}: Layout_check step 1/2 - templates NOT found for "f"{seal_layout2}") #cross-check for confirmation if not confirmation_node == None: if not self._pather.traverse_nodes(confirmation_node, self._char, threshold=calibration_threshold,): return False - if not TemplateFinder().search_and_wait(templates_confirmation, threshold=threshold_confirmation, timeout=0.1, best_match=True, take_ss=False).valid: + if not template_finder.search_and_wait(templates_confirmation, threshold=threshold_confirmation, timeout=0.1).valid: Logger.warning(f"{seal_layout2}: Layout_check failure - could not determine the seal Layout at" f"{sealname} ("f"{boss}) - "+'\033[91m'+"aborting run"+'\033[0m') - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_" + seal_layout1 + "_LC_fail" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_" + seal_layout1 + "_LC_fail" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False else: Logger.info(f"{seal_layout1}: Layout_check step 2/2 - templates found for "f"{seal_layout1} - "+'\033[93m'+"all fine, proceeding with "f"{seal_layout1}"+'\033[0m') @@ -387,19 +390,19 @@ def _layoutcheck(self, sealname:str, boss:str, static_layoutcheck:str, trash_loc #cross-check for confirmation if not confirmation_node2 == None: if not self._pather.traverse_nodes(confirmation_node2, self._char, threshold=calibration_threshold,): return False - if not TemplateFinder().search_and_wait(templates_confirmation, threshold=threshold_confirmation2, timeout=0.1, best_match=True, take_ss=False).valid: + if not template_finder.search_and_wait(templates_confirmation, threshold=threshold_confirmation2, timeout=0.1).valid: Logger.info(f"{seal_layout2}: Layout_check step 2/2 - templates NOT found for "f"{seal_layout1} - "+'\033[96m'+"all fine, proceeding with "f"{seal_layout2}"+'\033[0m') if not self._seal(*params_seal2): return False else: Logger.warning(f"{seal_layout2}: Layout_check failure - could not determine the seal Layout at" f"{sealname} ("f"{boss}) - "+'\033[91m'+"aborting run"+'\033[0m') - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_" + seal_layout2 + "_LC_fail_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_" + seal_layout2 + "_LC_fail_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return False return True #CLEAR SEAL def _seal(self, seal_layout:str, node_seal1:str, node_seal2:str, node_calibrate_to_pent:str, static_pent:str, static_loop_pent:str, node_calibrate_at_pent:str, seal1_opentemplates:list[str], seal1_closedtemplates:list[str], seal2_opentemplates:list[str], seal2_closedtemplates:list[str], ) -> bool: - #if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) Logger.info(seal_layout +": Starting to clear Seal") ### CLEAR TRASH ### Logger.debug(seal_layout + "_01: Kill trash") @@ -421,18 +424,19 @@ def _seal(self, seal_layout:str, node_seal1:str, node_seal2:str, node_calibrate_ if not self._pather.traverse_nodes(node_seal2, self._char): return False if not self._sealdance(seal2_opentemplates, seal2_closedtemplates, seal_layout + ": Seal2", node_seal2): return False ### KILL BOSS ### - if seal_layout == ("A1-L") or seal_layout == ("A2-Y"): - Logger.debug(seal_layout + ": Kill Boss A (Vizier)") - self._char.kill_vizier(seal_layout) - elif seal_layout == ("B1-S") or seal_layout == ("B2-U"): - Logger.debug(seal_layout + ": Kill Boss B (De Seis)") - self._char.kill_deseis(seal_layout) - elif seal_layout == ("C1-F") or seal_layout == ("C2-G"): - Logger.debug(seal_layout + ": Kill Boss C (Infector)") - self._char.kill_infector(seal_layout) - else: - Logger.warning(seal_layout + ": Error - no Boss known here - aborting run") - return False + match seal_layout: + case "A1-L" | "A2-Y": + Logger.debug(seal_layout + ": Kill Boss A (Vizier)") + self._char.kill_vizier(seal_layout) + case "B1-S" | "B2-U": + Logger.debug(seal_layout + ": Kill Boss B (De Seis)") + self._char.kill_deseis(seal_layout) + case "C1-F" | "C2-G": + Logger.debug(seal_layout + ": Kill Boss C (Infector)") + self._char.kill_infector(seal_layout) + case _: + Logger.warning(seal_layout + ": Error - no Boss known here - aborting run") + return False ### GO HOME ### if not self._pather.traverse_nodes(node_calibrate_to_pent, self._char): return False Logger.debug(seal_layout + ": Static Pathing to Pentagram") @@ -444,7 +448,7 @@ def _seal(self, seal_layout:str, node_seal1:str, node_seal2:str, node_calibrate_ return True - def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: + def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]: self._picked_up_items = False self.used_tps = 0 if do_pre_buff: self._char.pre_buff() @@ -459,14 +463,10 @@ def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: #Arrive at and clear Pentagram if not self._cs_pentagram(): return False - """ NEW APPROACH ONLY HAS 50% SUCCESS RATE - #if Config().char["kill_cs_trash"]: if not self._trash_seals("A", "dia_trash_a", [606], "dia_trash_a_loop", 0.78): return False - #if Config().char["kill_cs_trash"]: if not self._trash_seals("B", "dia_trash_b", [607], "dia_trash_b_loop", 0.85): return False #high threshold needed to avoid chasing 607 ghosts - #if Config().char["kill_cs_trash"]: if not self._trash_seals("C", "dia_trash_c", [608], "dia_trash_c_loop", 0.78): return False - """ #OLD APPROACH HAS 80% SUCCESS RATE if Config().char["kill_cs_trash"]: self._trash_seals() + # Maintenance at Pentagram after Trash & clear Seal A: Vizier (to the left) if Config().char["kill_cs_trash"]: self._char.kill_cs_trash("pent_before_a") if not self._pather.traverse_nodes([602], self._char): return False @@ -487,12 +487,10 @@ def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: if Config().char["cs_town_visits"]: self._cs_town_visit("C") if do_pre_buff: self._char.pre_buff() if not self._layoutcheck("C", "Infector", "dia_c_layout_bold", "layoutcheck_c", [650660], 0.83, None, ["DIA_C2G_BOSS_CLOSED_LAYOUTCHECK1", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK4", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK5", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK2", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK3",], ["DIA_C1F_LAYOUTCHECK1", "DIA_C1F_LAYOUTCHECK2", "DIA_C1F_LAYOUTCHECK3"]): return False - - # Kill Diablo Logger.info("Waiting for Diablo to spawn") if not self._pather.traverse_nodes([602], self._char): return False self._char.kill_diablo() - if Config().general["info_screenshots"]: cv2.imwrite(f"./info_screenshots/info_dia_kill_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_dia_kill_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) self._picked_up_items = self._pickit.pick_up_items(char=self._char) wait(0.5, 0.7) return (Location.A4_DIABLO_END, self._picked_up_items) diff --git a/src/run/nihlathak.py b/src/run/nihlathak.py index f6b9025d9..fc2f1d3ff 100644 --- a/src/run/nihlathak.py +++ b/src/run/nihlathak.py @@ -1,10 +1,8 @@ from char.i_char import IChar -from config import Config from logger import Logger from pather import Location, Pather -from typing import Union from item.pickit import PickIt -from template_finder import TemplateFinder +import template_finder from town.town_manager import TownManager from utils.misc import wait from dataclasses import dataclass @@ -14,19 +12,24 @@ from ui import loading, waypoint class Nihlathak: + + name = "run_nihlathak" + def __init__( self, pather: Pather, town_manager: TownManager, char: IChar, - pickit: PickIt + pickit: PickIt, + runs: list[str] ): self._pather = pather self._town_manager = town_manager self._char = char self._pickit = pickit + self._runs = runs - def approach(self, start_loc: Location) -> Union[bool, Location, bool]: + def approach(self, start_loc: Location) -> bool | Location: Logger.info("Run Nihlathak") if not self._char.capabilities.can_teleport_natively: raise ValueError("Nihlathak requires teleport") @@ -37,10 +40,10 @@ def approach(self, start_loc: Location) -> Union[bool, Location, bool]: return Location.A5_NIHLATHAK_START return False - def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: + def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]: # TODO: We might need a second template for each option as merc might run into the template and we dont find it then # Let's check which layout ("NI1_A = bottom exit" , "NI1_B = large room", "NI1_C = small room") - template_match = TemplateFinder().search_and_wait(["NI1_A", "NI1_B", "NI1_C"], threshold=0.65, timeout=20) + template_match = template_finder.search_and_wait(["NI1_A", "NI1_B", "NI1_C"], threshold=0.65, timeout=20) if not template_match.valid: return False if do_pre_buff: @@ -50,7 +53,7 @@ def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: # Its xpects that the static routes defined in game.ini are named: "ni1_a", "ni1_b", "ni1_c" self._pather.traverse_nodes_fixed(template_match.name.lower(), self._char) found_loading_screen_func = lambda: loading.wait_for_loading_screen(2.0) or \ - TemplateFinder().search_and_wait(["NI2_SEARCH_0", "NI2_SEARCH_1"], threshold=0.8, timeout=0.5).valid + template_finder.search_and_wait(["NI2_SEARCH_0", "NI2_SEARCH_1"], threshold=0.8, timeout=0.5).valid # look for stairs if not self._char.select_by_template(["NI1_STAIRS", "NI1_STAIRS_2", "NI1_STAIRS_3", "NI1_STAIRS_4"], found_loading_screen_func, threshold=0.63, timeout=4): # do a random tele jump and try again @@ -59,7 +62,7 @@ def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: if not self._char.select_by_template(["NI1_STAIRS", "NI1_STAIRS_2", "NI1_STAIRS_3", "NI1_STAIRS_4"], found_loading_screen_func, threshold=0.63, timeout=4): return False # Wait until templates in lvl 2 entrance are found - if not TemplateFinder().search_and_wait(["NI2_SEARCH_0", "NI2_SEARCH_1", "NI2_SEARCH_2"], threshold=0.8, timeout=20).valid: + if not template_finder.search_and_wait(["NI2_SEARCH_0", "NI2_SEARCH_1", "NI2_SEARCH_2"], threshold=0.8, timeout=20).valid: return False wait(1.0) # wait to make sure the red writing is gone once we check for the eye @dataclass @@ -82,7 +85,7 @@ class EyeCheckData: # Move to spot where eye would be visible self._pather.traverse_nodes_fixed(data.circle_static_path_key, self._char) # Search for eye - template_match = TemplateFinder().search_and_wait(data.template_name, threshold=0.7, best_match=True, timeout=3) + template_match = template_finder.search_and_wait(data.template_name, threshold=0.7, best_match=True, timeout=3) # If it is found, move down that hallway if template_match.valid and template_match.name.endswith("_SAFE_DIST"): self._pather.traverse_nodes_fixed(data.destination_static_path_key, self._char) diff --git a/src/run/pindle.py b/src/run/pindle.py index 1ec7b3681..5eb6d07bf 100644 --- a/src/run/pindle.py +++ b/src/run/pindle.py @@ -1,28 +1,31 @@ from char import IChar -from config import Config from logger import Logger from pather import Location, Pather -from typing import Union from item.pickit import PickIt -from template_finder import TemplateFinder +import template_finder from town.town_manager import TownManager from utils.misc import wait from ui import loading class Pindle: + + name = "run_pindle" + def __init__( self, pather: Pather, town_manager: TownManager, char: IChar, - pickit: PickIt + pickit: PickIt, + runs: list[str] ): self._pather = pather self._town_manager = town_manager self._char = char self._pickit = pickit + self.runs = runs - def approach(self, start_loc: Location) -> Union[bool, Location]: + def approach(self, start_loc: Location) -> bool | Location: # Go through Red Portal in A5 Logger.info("Run Pindle") loc = self._town_manager.go_to_act(5, start_loc) @@ -36,9 +39,9 @@ def approach(self, start_loc: Location) -> Union[bool, Location]: return False return Location.A5_PINDLE_START - def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: + def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]: # Kill Pindle - if not TemplateFinder().search_and_wait(["PINDLE_0", "PINDLE_1"], threshold=0.65, timeout=20).valid: + if not template_finder.search_and_wait(["PINDLE_0", "PINDLE_1"], threshold=0.65, timeout=20).valid: return False if do_pre_buff: self._char.pre_buff() diff --git a/src/run/shenk_eld.py b/src/run/shenk_eld.py index 08c540a9d..9d0c72d6c 100644 --- a/src/run/shenk_eld.py +++ b/src/run/shenk_eld.py @@ -1,28 +1,31 @@ from char import IChar -from config import Config from logger import Logger from pather import Location, Pather -from typing import Union from item.pickit import PickIt -from template_finder import TemplateFinder +import template_finder from town.town_manager import TownManager from utils.misc import wait from ui import waypoint class ShenkEld: + + name = "run_shenk" + def __init__( self, pather: Pather, town_manager: TownManager, char: IChar, - pickit: PickIt + pickit: PickIt, + runs: list[str] ): self._pather = pather self._town_manager = town_manager self._char = char self._pickit = pickit + self._runs = runs - def approach(self, start_loc: Location) -> Union[bool, Location, bool]: + def approach(self, start_loc: Location) -> bool | Location: Logger.info("Run Eldritch") # Go to Frigid Highlands if not self._town_manager.open_wp(start_loc): @@ -32,10 +35,10 @@ def approach(self, start_loc: Location) -> Union[bool, Location, bool]: return Location.A5_ELDRITCH_START return False - def battle(self, do_shenk: bool, do_pre_buff: bool, game_stats) -> Union[bool, tuple[Location, bool]]: + def battle(self, do_shenk: bool, do_pre_buff: bool, game_stats) -> bool | tuple[Location, bool]: # Eldritch game_stats.update_location("Eld") - if not TemplateFinder().search_and_wait(["ELDRITCH_0", "ELDRITCH_0_V2", "ELDRITCH_0_V3", "ELDRITCH_START", "ELDRITCH_START_V2"], threshold=0.65, timeout=20).valid: + if not template_finder.search_and_wait(["ELDRITCH_0", "ELDRITCH_0_V2", "ELDRITCH_0_V3", "ELDRITCH_START", "ELDRITCH_START_V2"], threshold=0.65, timeout=20).valid: return False if do_pre_buff: self._char.pre_buff() diff --git a/src/run/trav.py b/src/run/trav.py index a44dc1297..3726e2bc3 100644 --- a/src/run/trav.py +++ b/src/run/trav.py @@ -1,29 +1,32 @@ from char import IChar -from config import Config from logger import Logger from pather import Location, Pather -from typing import Union from item.pickit import PickIt -from template_finder import TemplateFinder +import template_finder from town.town_manager import TownManager from utils.misc import wait from ui import waypoint class Trav: + + name = "run_trav" + def __init__( self, pather: Pather, town_manager: TownManager, char: IChar, - pickit: PickIt + pickit: PickIt, + runs: list[str] ): self._pather = pather self._town_manager = town_manager self._char = char self._pickit = pickit + self._runs = runs - def approach(self, start_loc: Location) -> Union[bool, Location]: + def approach(self, start_loc: Location) -> bool | Location: # Go to Travincal via waypoint Logger.info("Run Trav") if not self._town_manager.open_wp(start_loc): @@ -33,9 +36,9 @@ def approach(self, start_loc: Location) -> Union[bool, Location]: return Location.A3_TRAV_START return False - def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: + def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]: # Kill Council - if not TemplateFinder().search_and_wait(["TRAV_0", "TRAV_1", "TRAV_20"], threshold=0.65, timeout=20).valid: + if not template_finder.search_and_wait(["TRAV_0", "TRAV_1", "TRAV_20"], threshold=0.65, timeout=20).valid: return False if do_pre_buff: self._char.pre_buff() @@ -49,9 +52,11 @@ def battle(self, do_pre_buff: bool) -> Union[bool, tuple[Location, bool]]: wait(0.2, 0.3) # If we can teleport we want to move back inside and also check loot there if self._char.capabilities.can_teleport_natively or self._char.capabilities.can_teleport_with_charges: - if not self._pather.traverse_nodes([229], self._char, timeout=2.5, use_tp_charge=True): + if not self._pather.traverse_nodes([229], self._char, timeout=2.5, use_tp_charge=self._char.capabilities.can_teleport_natively): self._pather.traverse_nodes([228, 229], self._char, timeout=2.5, use_tp_charge=True) picked_up_items |= self._pickit.pick_up_items(self._char) - # Make sure we go back to the center to not hide the tp - self._pather.traverse_nodes([230], self._char, timeout=2.5) + # If travincal run is not the last run + if self.name != self._runs[-1]: + # Make sure we go back to the center to not hide the tp + self._pather.traverse_nodes([230], self._char, timeout=2.5) return (Location.A3_TRAV_CENTER_STAIRS, picked_up_items) diff --git a/src/screen.py b/src/screen.py index 005ac66d2..78b788f6c 100644 --- a/src/screen.py +++ b/src/screen.py @@ -1,10 +1,10 @@ import numpy as np from mss import mss from logger import Logger -from typing import Tuple from utils.misc import WindowSpec, find_d2r_window, wait from config import Config import threading +import time sct = mss() monitor_roi = sct.monitors[0] @@ -13,6 +13,9 @@ monitor_y_range = None detect_window = True detect_window_thread = None +last_grab = None +cached_img = None +cached_img_lock = threading.Lock() FIND_WINDOW = WindowSpec( title_regex=Config().advanced_options["hwnd_window_title"], @@ -65,21 +68,31 @@ def stop_detecting_window(): if detect_window_thread: detect_window_thread.join() -def grab() -> np.ndarray: +def grab(force_new: bool = False) -> np.ndarray: global monitor_roi - img = np.array(sct.grab(monitor_roi)) - return img[:, :, :3] + global cached_img + global last_grab + # with 25fps we have 40ms per frame. If we check for 20ms range to make sure we can still get each frame if we want. + if not force_new and cached_img is not None and last_grab is not None and time.perf_counter() - last_grab < 0.04: + return cached_img + else: + with cached_img_lock: + last_grab = time.perf_counter() + img = np.array(sct.grab(monitor_roi)) + with cached_img_lock: + cached_img = img[:, :, :3] + return cached_img # TODO: Move the below funcs to utils(?) -def convert_monitor_to_screen(screen_coord: Tuple[float, float]) -> Tuple[float, float]: +def convert_monitor_to_screen(screen_coord: tuple[float, float]) -> tuple[float, float]: global monitor_roi if screen_coord is None: Logger.error("convert_monitor_to_screen: empty coordinates passed") return None return (screen_coord[0] - monitor_roi["left"], screen_coord[1] - monitor_roi["top"]) -def convert_screen_to_monitor(screen_coord: Tuple[float, float]) -> Tuple[float, float]: +def convert_screen_to_monitor(screen_coord: tuple[float, float]) -> tuple[float, float]: global monitor_roi if screen_coord is None: Logger.error("convert_screen_to_monitor: empty coordinates passed") @@ -88,7 +101,7 @@ def convert_screen_to_monitor(screen_coord: Tuple[float, float]) -> Tuple[float, y = screen_coord[1] + monitor_roi["top"] return (np.clip(x, *monitor_x_range), np.clip(y, *monitor_y_range)) -def convert_abs_to_screen(abs_coord: Tuple[float, float]) -> Tuple[float, float]: +def convert_abs_to_screen(abs_coord: tuple[float, float]) -> tuple[float, float]: global monitor_roi if abs_coord is None: Logger.error("convert_screen_to_monitor: empty coordinates passed") @@ -96,14 +109,14 @@ def convert_abs_to_screen(abs_coord: Tuple[float, float]) -> Tuple[float, float] # abs has it's center on char which is the center of the screen return ((monitor_roi["width"] // 2) + abs_coord[0], (monitor_roi["height"] // 2) + abs_coord[1]) -def convert_screen_to_abs(screen_coord: Tuple[float, float]) -> Tuple[float, float]: +def convert_screen_to_abs(screen_coord: tuple[float, float]) -> tuple[float, float]: global monitor_roi if screen_coord is None: Logger.error("convert_screen_to_abs: empty coordinates passed") return None return (screen_coord[0] - (monitor_roi["width"] // 2), screen_coord[1] - (monitor_roi["height"] // 2)) -def convert_abs_to_monitor(abs_coord: Tuple[float, float]) -> Tuple[float, float]: +def convert_abs_to_monitor(abs_coord: tuple[float, float]) -> tuple[float, float]: if abs_coord is None: Logger.error("convert_abs_to_monitor: empty coordinates passed") return None diff --git a/src/shop/anya.py b/src/shop/anya.py index 130933f9a..f5ab3d534 100644 --- a/src/shop/anya.py +++ b/src/shop/anya.py @@ -10,7 +10,7 @@ from config import Config from logger import Logger from npc_manager import Npc, open_npc_menu, press_npc_btn -from template_finder import TemplateFinder +import template_finder from utils.custom_mouse import mouse from utils.misc import wait, load_template @@ -93,30 +93,30 @@ def shop_loop(self): img = grab() # 20 IAS gloves have a unique color so we can skip all others - ias_glove = TemplateFinder(True).search( - ref=load_template(asset_folder + "ias_gloves.png", 1.0), + ias_glove = template_finder.search( + ref=load_template(asset_folder + "ias_gloves.png"), inp_img=img, threshold=0.96, - roi=Config().ui_roi["left_inventory"], - normalize_monitor=True, + roi=Config().ui_roi["left_inventory"] ) if ias_glove.valid: self.ias_gloves_seen += 1 - mouse.move(*ias_glove.center) + mouse.move(*ias_glove.center_monitor) time.sleep(0.1) img = grab() if self.look_for_plus_3_gloves is True: - gg_gloves = TemplateFinder(True).search( + gg_gloves = template_finder.search( ref=load_template( - asset_folder + "gg_gloves.png", 1.0 # assets for javazon gloves are mixed up, this one need +3 as in the 1080p version + asset_folder + "gg_gloves.png" # assets for javazon gloves are mixed up, this one need +3 as in the 1080p version ), inp_img=img, threshold=0.80 ) if gg_gloves.valid: mouse.click(button="right") - self._messenger.send_message("Bought awesome IAS/+3 gloves!") + if self._messenger.enabled: + self._messenger.send_message("Bought awesome IAS/+3 gloves!") Logger.info("IAS/+3 gloves bought!") self.gloves_bought += 1 @@ -124,16 +124,17 @@ def shop_loop(self): else: if self.look_for_plus_2_gloves is True: - g_gloves = TemplateFinder(True).search( + g_gloves = template_finder.search( ref=load_template( - asset_folder + "g_gloves.png", 1.0 + asset_folder + "g_gloves.png" ), inp_img=img, threshold=0.80 ) if g_gloves.valid: mouse.click(button="right") - self._messenger.send_message("Bought some decent IAS/+2 gloves") + if self._messenger.enabled: + self._messenger.send_message("Bought some decent IAS/+2 gloves") Logger.info("IAS/+2 gloves bought!") self.gloves_bought += 1 time.sleep(1) @@ -148,35 +149,33 @@ def shop_loop(self): claw_pos = [] img = grab().copy() claw_keys = ["CLAW1", "CLAW2", "CLAW3"] - for ck in claw_keys: - template_match = TemplateFinder(True).search(ck, img, roi=self.roi_vendor) - if template_match.valid: - claw_pos.append(template_match.center) + template_matches = template_finder.search_all(claw_keys, img, roi=self.roi_vendor) + for template_match in template_matches: + claw_pos.append(template_match.center_monitor) # check out each claw for pos in claw_pos: # cv2.circle(img, pos, 3, (0, 255, 0), 2) - x_m, y_m = convert_screen_to_monitor(pos) - mouse.move(x_m, y_m, randomize=3, delay_factor=[0.5, 0.6]) + mouse.move(*pos, randomize=3, delay_factor=[0.5, 0.6]) wait(0.5, 0.6) img_stats = grab() trap_score = 0 melee_score = 0 - if TemplateFinder(True).search("3_TO_TRAPS", img_stats, roi=self.roi_claw_stats, threshold=0.94).valid: + if template_finder.search("3_TO_TRAPS", img_stats, roi=self.roi_claw_stats, threshold=0.94).valid: trap_score += 12 - elif TemplateFinder(True).search("TO_TRAPS", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: + elif template_finder.search("TO_TRAPS", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: trap_score += 8 - if TemplateFinder(True).search("2_TO_ASSA", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: + if template_finder.search("2_TO_ASSA", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: trap_score += 10 melee_score += 10 - if TemplateFinder(True).search("TO_VENOM", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: + if template_finder.search("TO_VENOM", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: melee_score += 6 - if TemplateFinder(True).search("TO_LIGHT", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: + if template_finder.search("TO_LIGHT", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: trap_score += 6 - if TemplateFinder(True).search("TO_WB", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: + if template_finder.search("TO_WB", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: melee_score += 2 trap_score += 1 - if TemplateFinder(True).search("TO_DS", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: + if template_finder.search("TO_DS", img_stats, roi=self.roi_claw_stats, threshold=0.9).valid: trap_score += 4 self.claws_evaluated += 1 @@ -184,7 +183,8 @@ def shop_loop(self): if trap_score > self.trap_claw_min_score and self.look_for_trap_claws is True: # pick it up mouse.click(button="right") - self._messenger.send_message(f"Bought some terrific trap Claws (score: {trap_score})") + if self._messenger.enabled: + self._messenger.send_message(f"Bought some terrific trap Claws (score: {trap_score})") Logger.info(f"Trap Claws (score: {trap_score}) bought!") self.claws_bought += 1 @@ -193,7 +193,8 @@ def shop_loop(self): if melee_score > self.melee_claw_min_score and self.look_for_melee_claws is True: # pick it up mouse.click(button="right") - self._messenger.send_message(f"Bought some mad melee Claws (score: {melee_score})") + if self._messenger.enabled: + self._messenger.send_message(f"Bought some mad melee Claws (score: {melee_score})") Logger.info(f"Melee Claws (score: {melee_score}) bought!") self.claws_bought += 1 time.sleep(1) @@ -221,9 +222,9 @@ def reset_shop(self): def select_by_template(self, template_type: str) -> bool: Logger.debug(f"Select {template_type}") - template_match = TemplateFinder(True).search_and_wait(template_type, timeout=10, normalize_monitor=True) + template_match = template_finder.search_and_wait(template_type, timeout=10) if template_match.valid: - mouse.move(*template_match.center) + mouse.move(*template_match.center_monitor) wait(0.1, 0.2) mouse.click(button="left") return True diff --git a/src/shop/drognan.py b/src/shop/drognan.py index f9ba3acf8..83fea96ac 100644 --- a/src/shop/drognan.py +++ b/src/shop/drognan.py @@ -3,7 +3,7 @@ import time import math import random -from typing import Dict, Tuple, Union, List, Callable +from typing import Callable import keyboard import numpy as np @@ -12,7 +12,7 @@ from config import Config from logger import Logger from npc_manager import Npc, open_npc_menu, press_npc_btn -from template_finder import TemplateFinder +import template_finder from utils.custom_mouse import mouse from utils.misc import wait @@ -90,24 +90,22 @@ def shop_loop(self): item_pos = [] img = grab().copy() item_keys = ["SCEPTER1", "SCEPTER2", "SCEPTER3", "SCEPTER4", "SCEPTER5"] - for ck in item_keys: - template_match = TemplateFinder(True).search(ck, img, roi=self.roi_vendor) - if template_match.valid: - item_pos.append(template_match.center) + template_matches = template_finder.search_all(item_keys, img, roi=self.roi_vendor) + for template_match in template_matches: + item_pos.append(template_match.center_monitor) # check out each item for pos in item_pos: - x_m, y_m = convert_screen_to_monitor(pos) - mouse.move(x_m, y_m, randomize=3, delay_factor=[0.5, 0.6]) + mouse.move(*pos, randomize=3, delay_factor=[0.5, 0.6]) wait(0.5, 0.6) img_stats = grab() # First check for +2 Paladin Skills. This weeds out most scepters right away. - if TemplateFinder(True).search("2_TO_PALADIN_SKILLS", img_stats, roi=self.roi_shop_item_stats, threshold=0.94).valid: + if template_finder.search("2_TO_PALADIN_SKILLS", img_stats, roi=self.roi_shop_item_stats, threshold=0.94).valid: # Has 2 Pally skills, check blessed hammers next - if TemplateFinder(True).search("TO_BLESSED_HAMMERS", img_stats, roi=self.roi_shop_item_stats, threshold=0.9).valid: + if template_finder.search("TO_BLESSED_HAMMERS", img_stats, roi=self.roi_shop_item_stats, threshold=0.9).valid: # Has 2 Pally skills AND Blessed Hammers, check Concentration next - if TemplateFinder(True).search("TO_CONCENTRATION", img_stats, roi=self.roi_shop_item_stats, threshold=0.9).valid: + if template_finder.search("TO_CONCENTRATION", img_stats, roi=self.roi_shop_item_stats, threshold=0.9).valid: # Has 2 Pally skills AND Blessed Hammers AND Concentration. We're good! Buy it! mouse.click(button="right") Logger.info(f"Item bought!") @@ -137,7 +135,7 @@ def reset_shop(self): self.hold_move(pos_m, time_held=(2.0 / self.speed_factor)) # A variation of the move() function from pather.py - def hold_move(self, pos_monitor: Tuple[float, float], time_held: float = 2.0): + def hold_move(self, pos_monitor: tuple[float, float], time_held: float = 2.0): factor = Config().advanced_options["pathing_delay_factor"] # in case we want to walk we actually want to move a bit before the point cause d2r will always "overwalk" pos_screen = convert_monitor_to_screen(pos_monitor) diff --git a/src/target_detect.py b/src/target_detect.py index 0ff1bd064..914bd7143 100644 --- a/src/target_detect.py +++ b/src/target_detect.py @@ -1,59 +1,73 @@ import cv2 import numpy as np import time -from screen import grab, convert_screen_to_abs, convert_abs_to_monitor +from screen import convert_screen_to_monitor, grab, convert_screen_to_abs, convert_abs_to_monitor from logger import Logger from math import dist -from utils.misc import color_filter +from utils.misc import color_filter, is_in_roi import json +from dataclasses import dataclass +from ui_manager import get_hud_mask FILTER_RANGES=[ {"erode": 1, "blur": 3, "lh": 38, "ls": 169, "lv": 50, "uh": 70, "us": 255, "uv": 255}, # poison {"erode": 1, "blur": 3, "lh": 110, "ls": 169, "lv": 50, "uh": 120, "us": 255, "uv": 255} # frozen ] -def _dist_to_center(pos): - return dist(pos, (1280/2, 720/2)) +@dataclass +class TargetInfo: + roi: tuple = None + center: tuple = None + center_abs: tuple = None + center_monitor: tuple = None + distance: int = 0 -def _sort_targets_by_dist(targets): - return sorted(targets, key=lambda pos: _dist_to_center(pos)) +def log_targets(targets: list[TargetInfo]): + if (num_targets := len(targets)) > 0: + if num_targets == 1: + msg = f"{num_targets} target detected" + elif num_targets > 1: + msg = f"{num_targets} targets detected, closest" + Logger.debug(f"{msg} at {targets[0].center}, distance: {round(targets[0].distance)}") -def _ignore_targets_within_radius(targets, ignore_radius:int=0): - return [pos for pos in targets if _dist_to_center(pos) > ignore_radius] #ignore targets that are too close +def _dist_to_center(pos): + return dist(pos, (1280/2, 720/2)) -def mob_check(img: np.ndarray = None, info_ss: bool = False) -> bool: +def get_visible_targets( + img: np.ndarray = None, + radius_min: int = 150, + radius_max: int = 1280, + ignore_roi: list[int] = [600, 300, (1280/2 - 600)*2, (720/2 - 300)*2], + use_radius: bool = False +) -> list[TargetInfo]: + """ + :param img: The image to find targets in + :param radius_min: The minimum radius of the target [Default: 150, Integer 0 - 1280] + :param radius_max: The maximum radius of the target [Default: 1280, Integer 0 - 1280] + :param ignore_roi: The region of interest to ignore [Default: [600, 300, (1280/2 - 600)*2, (720/2 - 300)*2]] + :param use_radius: Whether to use the radius of the target (True) or the ignore_roi parameter (False) + Returns a list of TargetInfo objects + """ img = grab() if img is None else img - combo_image = np.zeros(img.shape, np.uint8) - combo_markers = [] - filtered_targets = [] - if info_ss: cv2.imwrite(f"./info_screenshots/info_mob_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) + targets = [] for filter in FILTER_RANGES: - filterimage, threshz = _process_image(img, mask_char=True, mask_hud=True, info_ss=False, **filter) # HSV Filter for BLUE and GREEN (Posison Nova & Holy Freeze) - filterimage, _, pos_markers = _add_markers(filterimage, threshz, info_ss=False, rect_min_size=100, rect_max_size=200, marker=True) # rather large rectangles - combo_image = cv2.add(combo_image, filterimage) - if pos_markers: - combo_markers.extend(pos_markers) - if info_ss: cv2.imwrite(f"./info_screenshots/info_mob__filtered" + time.strftime("%Y%m%d_%H%M%S") + ".png", combo_image) - if combo_markers: - sorted_targets = _sort_targets_by_dist(combo_markers) - filtered_targets = _ignore_targets_within_radius(sorted_targets, 150) - if not filtered_targets: - Logger.debug('\033[93m' + "Mobcheck: no Mob detected" + '\033[0m') - else: - # disabled screen operations to allow pytest to use this function - #pos_m = convert_screen_to_abs(filtered_targets[0]) #nearest marker - #pos_m = convert_abs_to_monitor(pos_m) - #Logger.debug('\033[92m' + "Mobcheck: Found Mob at " + str(pos_m) + " attacking now!" + '\033[0m') - Logger.debug('\033[92m' + "Mobcheck: Found Mob attacking now!" + '\033[0m') - if info_ss: - #draw an arrow on a screenshot where a mob was found - pt2 = (640,360) - x1, y1 = filtered_targets[0] - pt1 = (int(x1),int(y1)) - input = np.ascontiguousarray(img) - cv2.arrowedLine(input, pt2, pt1, line_type=cv2.LINE_4, thickness=2, tipLength=0.3, color=(255, 0, 255)) - cv2.imwrite(f"./info_screenshots/info_mob_add_line" + time.strftime("%Y%m%d_%H%M%S") + ".png", input) - return len(filtered_targets) + filterimage, threshz = _process_image(img, mask_char=True, mask_hud=True, **filter) # HSV Filter for BLUE and GREEN (Posison Nova & Holy Freeze) + filterimage, rectangles, positions = _add_markers(filterimage, threshz, rect_min_size=100, rect_max_size=200, marker=True) # rather large rectangles + if positions: + for cnt, position in enumerate(positions): + distance = _dist_to_center(position) + condition = (radius_min <= distance <= radius_max) if use_radius else (not is_in_roi(ignore_roi, position)) + if condition: + targets.append(TargetInfo( + roi = rectangles[cnt], + center = position, + center_monitor = convert_screen_to_monitor(position), + center_abs = convert_screen_to_abs(position), + distance = distance + )) + if targets: + targets = sorted(targets, key=lambda obj: obj.distance) + return targets def _bright_contrast(img: np.ndarray, brightness: int = 255, contrast: int = 127): """ @@ -84,13 +98,12 @@ def _bright_contrast(img: np.ndarray, brightness: int = 255, contrast: int = 127 cal = cv2.addWeighted(cal, alpha, cal, 0, gamma) return cal -def _process_image(img, mask_char:bool=False, mask_hud:bool=True, info_ss:bool=False, erode:int=None, dilate:int=None, blur:int=None, lh:int=None, ls:int=None, lv:int=None, uh:int=None, us:int=None, uv:int=None, bright:int=None, contrast:int=None, thresh:int=None, invert:int=None): +def _process_image(img, mask_char:bool=False, mask_hud:bool=True, erode:int=None, dilate:int=None, blur:int=None, lh:int=None, ls:int=None, lv:int=None, uh:int=None, us:int=None, uv:int=None, bright:int=None, contrast:int=None, thresh:int=None, invert:int=None): """ Helper function that will apply HSV filters :param img: The image to which filters should be applied :param mask_char: apply a black rectangle to mask your char (e.g. filter out Set-Item glow effect or auras) [Default: False, Bool] :param hud_mask: removes the HUD from the returned image [Default: True, Bool] - :param info_ss: Save an image of the applied filters in folder INFO_SCREENSHOTS [Default: False, Bool] :param erode: erode (thin lines) in the picture [Default: None, Integer, no filter: 0, 0 - 36] :param dilate: dilate (thicken lines) in the picture [Default: None, Integer, no filter: 0, 0 - 36] :param blur: blur the picture [Default: None, no filter: 0, Integer, 0 - 30] @@ -107,10 +120,8 @@ def _process_image(img, mask_char:bool=False, mask_hud:bool=True, info_ss:bool=F Returns variables filterimage and threshz """ img = img - if info_ss: cv2.imwrite(f"./info_screenshots/info_apply_filter_input_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) if mask_hud: - hud_mask = cv2.imread(f"./assets/hud_mask.png", cv2.IMREAD_GRAYSCALE) - img = cv2.bitwise_and(img, img, mask=hud_mask) + img = cv2.bitwise_and(img, img, mask=get_hud_mask()) if mask_char: img = cv2.rectangle(img, (600,250), (700,400), (0,0,0), -1) # black out character by drawing a black box above him (e.g. ignore set glow) if erode: kernel = np.ones((erode, erode), 'uint8') @@ -127,16 +138,14 @@ def _process_image(img, mask_char:bool=False, mask_hud:bool=True, info_ss:bool=F if thresh: _, threshz = cv2.threshold(threshz, thresh, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) if invert: img = 255 - img filterimage = img - if info_ss: cv2.imwrite(f"./info_screenshots/info_apply_filter_output_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) return filterimage, threshz # add rectangles and crosses - adapted from Nathan's Live-View -def _add_markers(img:str, threshz:str, info_ss:bool=False, rect_min_size:int=20, rect_max_size:int=50, line_color:str=(0, 255, 0), line_type:str=cv2.LINE_4, marker:bool=False, marker_color:str=(0, 255, 255), marker_type:str=cv2.MARKER_CROSS): +def _add_markers(img:str, threshz:str, rect_min_size:int=20, rect_max_size:int=50, line_color:str=(0, 255, 0), line_type:str=cv2.LINE_4, marker:bool=False, marker_color:str=(0, 255, 255), marker_type:str=cv2.MARKER_CROSS): """ Helper function that will add rectangles and crosshairs to allow object detection :param img: The image to which filters should be applied :param threshz: The image that had the threshold adjusted (obtained from _process_image()) - :param info_ss: Take a screenshot for each step [Default: False, Bool] :param rect_min_size: Minimum size for the rectangle to be drawn [Default: 20, Integer] :param rect_max_size: Minimum size for the rectangle to be drawn [Default: 50, Integer] :param line_color: Color of the rectangle line [Default: (0, 255, 0)] @@ -148,8 +157,8 @@ def _add_markers(img:str, threshz:str, info_ss:bool=False, rect_min_size:int=20, """ #add rectangles n_labels, _, stats, _ = cv2.connectedComponentsWithStats(threshz) - pos_rectangles = [] - pos_marker = [] + rectangles = [] + markers = [] for i in range(1, n_labels): if stats[i, cv2.CC_STAT_AREA] >= rect_min_size <= rect_max_size: x = stats[i, cv2.CC_STAT_LEFT] @@ -157,28 +166,20 @@ def _add_markers(img:str, threshz:str, info_ss:bool=False, rect_min_size:int=20, w = stats[i, cv2.CC_STAT_WIDTH] h = stats[i, cv2.CC_STAT_HEIGHT] cv2.rectangle(img, (x, y), (x + w, y + h), color=line_color, thickness=1) - rect = [int(x), int(y), int(w), int(h)] - pos_rectangles.append(rect) - if marker:#draw crosshairs on center of rectangle. - #line_color = (0, 255, 0) - #line_type = cv2.LINE_4 - #marker_color = (255, 0, 255) - #marker_type = cv2.MARKER_CROSS + rect = (int(x), int(y), int(w), int(h)) + rectangles.append(rect) + if marker: center_x = x + int(w/2) center_y = y + int(h/2) cv2.drawMarker(img, (center_x, center_y), color=marker_color, markerType=marker_type, markerSize=15, thickness=2) - mark = [int(center_x), int(center_y)] - pos_marker.append(mark) - img = img - if info_ss: cv2.imwrite(f"./info_screenshots/info_add_markers" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) - return img, pos_rectangles, pos_marker + mark = (int(center_x), int(center_y)) + markers.append(mark) + return img, rectangles, markers class LiveViewer: def __init__(self): with open("./src/utils/live-view-last-settings.json") as f: self.settings = json.loads(f.read()) - self.hud_mask = cv2.imread(f"./assets/hud_mask.png", cv2.IMREAD_GRAYSCALE) - self.hud_mask = cv2.threshold(self.hud_mask, 1, 255, cv2.THRESH_BINARY)[1] self.use_existing_image = False self.existing_image_path = "test/assets/mobs.png" self.setup() @@ -206,7 +207,7 @@ def value_update(self, ignore: bool = False): self.image = grab() else: self.image = cv2.imread(self.existing_image_path) - self.image = cv2.bitwise_and(self.image, self.image, mask=self.hud_mask) + self.image = cv2.bitwise_and(self.image, self.image, mask=get_hud_mask()) # black out character self.image = cv2.rectangle(self.image, (550,250), (700,400), (0,0,0), -1) try: @@ -228,7 +229,7 @@ def value_update(self, ignore: bool = False): except cv2.error: return self.image, threshz = _process_image(self.image, **self.settings) - filterimage, _, _ = _add_markers(self.image, threshz, info_ss=False, rect_min_size=100, rect_max_size=200, marker=True) + filterimage, _, _ = _add_markers(self.image, threshz, rect_min_size=100, rect_max_size=200, marker=True) cv2.imshow("Results", filterimage) cv2.waitKey(1) @@ -247,4 +248,22 @@ def live_view(self): start_detecting_window() print("Move to d2r window and press f11") keyboard.wait("f11") - l = LiveViewer() \ No newline at end of file + # l = LiveViewer() + + masked_image = False + + def _toggle_masked_image(): + global masked_image + masked_image = not masked_image + + while 1: + img = grab() + targets = get_visible_targets() + + display_img = img.copy() + + for target in targets: + x, y = target.center + cv2.rectangle(display_img, target.roi[:2], (target.roi[0] + target.roi[2], target.roi[1] + target.roi[3]), (0, 0, 255), 1) + cv2.imshow('test', display_img) + key = cv2.waitKey(1) diff --git a/src/template_finder.py b/src/template_finder.py index 6dfc96b8c..e166caeee 100644 --- a/src/template_finder.py +++ b/src/template_finder.py @@ -1,243 +1,226 @@ import cv2 import threading -from copy import deepcopy from screen import convert_screen_to_monitor, grab -from typing import Union from dataclasses import dataclass import numpy as np from logger import Logger import time import os from config import Config -from utils.misc import cut_roi, load_template, list_files_in_folder, alpha_to_mask, roi_center, color_filter +from utils.misc import cut_roi, load_template, list_files_in_folder, alpha_to_mask, roi_center, color_filter, mask_by_roi +from functools import cache -template_finder_lock = threading.Lock() +templates_lock = threading.Lock() + +@dataclass +class Template: + name: str = None + img_bgra: np.ndarray = None + img_bgr: np.ndarray = None + img_gray: np.ndarray = None + alpha_mask: np.ndarray = None @dataclass class TemplateMatch: name: str = None score: float = -1.0 - center: tuple[float, float] = None + center: tuple[int, int] = None + center_monitor: tuple[int, int] = None region: list[float] = None + region_monitor: list[float] = None valid: bool = False -class TemplateFinder: + +TEMPLATE_PATHS = [ + "assets\\templates", + "assets\\npc", + "assets\\shop", + "assets\\item_properties", + "assets\\chests", + "assets\\gamble", +] + +@cache +def stored_templates() -> dict[Template]: + paths = [] + templates = {} + for path in TEMPLATE_PATHS: + paths += list_files_in_folder(path) + for file_path in paths: + file_name: str = os.path.basename(file_path) + if file_name.lower().endswith('.png'): + key = file_name[:-4].upper() + template_img = load_template(file_path) + templates[key] = Template( + name = key, + img_bgra = template_img, + img_bgr = cv2.cvtColor(template_img, cv2.COLOR_BGRA2BGR), + img_gray = cv2.cvtColor(template_img, cv2.COLOR_BGRA2GRAY), + alpha_mask = alpha_to_mask(template_img) + ) + return templates + +def get_template(key): + with templates_lock: + return stored_templates()[key].img_bgr + +def _process_template_refs(ref: str | np.ndarray | list[str]) -> list[Template]: + templates = [] + if type(ref) != list: + ref = [ref] + for i in ref: + # if the reference is a string, then it's a reference to a named template asset + if type(i) == str: + templates.append(stored_templates()[i.upper()]) + # if the reference is an image, append new Template class object + elif type(i) == np.ndarray: + templates.append(Template( + img_bgr = i, + img_gray = cv2.cvtColor(i, cv2.COLOR_BGR2GRAY), + alpha_mask = alpha_to_mask(i) + )) + return templates + +def _single_template_match(template: Template, inp_img: np.ndarray = None, roi: list = None, color_match: list = None, use_grayscale: bool = False) -> TemplateMatch: + inp_img = inp_img if inp_img is not None else grab() + template_match = TemplateMatch() + + # crop image to roi + if roi is None: + # if no roi is provided roi = full inp_img + roi = [0, 0, inp_img.shape[1], inp_img.shape[0]] + rx, ry, rw, rh = roi + img = inp_img[ry:ry + rh, rx:rx + rw] + + # filter for desired color or make grayscale + if color_match: + template_img, = color_filter(template.img_bgr, color_match)[1], + img = color_filter(img, color_match)[1] + elif use_grayscale: + template_img = template.img_gray + img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + else: + template_img = template.img_bgr + + if not (img.shape[0] > template_img.shape[0] and img.shape[1] > template_img.shape[1]): + Logger.error(f"Image shape and template shape are incompatible: {template.name}. Image: {img.shape}, Template: {template_img.shape}, roi: {roi}") + else: + res = cv2.matchTemplate(img, template_img, cv2.TM_CCOEFF_NORMED, mask = template.alpha_mask) + np.nan_to_num(res, copy=False, nan=0.0, posinf=0.0, neginf=0.0) + _, max_val, _, max_pos = cv2.minMaxLoc(res) + + # save rectangle corresponding to matched region + rec_x = int((max_pos[0] + rx)) + rec_y = int((max_pos[1] + ry)) + rec_w = int(template_img.shape[1]) + rec_h = int(template_img.shape[0]) + template_match.region = [rec_x, rec_y, rec_w, rec_h] + template_match.region_monitor = [*convert_screen_to_monitor((rec_x, rec_y)), rec_w, rec_h] + template_match.center = roi_center(template_match.region) + template_match.center_monitor = convert_screen_to_monitor(template_match.center) + template_match.name = template.name + template_match.score = max_val + template_match.valid = True + + return template_match + + +def search( + ref: str | np.ndarray | list[str], + inp_img: np.ndarray, + threshold: float = 0.68, + roi: list[float] = None, + use_grayscale: bool = False, + color_match: list = False, + best_match: bool = False +) -> TemplateMatch: """ - Loads images from assets/templates and assets/npc and provides search functions - to find these assets within another image - IMPORTANT: This method must be thread safe! + Search for a template in an image + :param ref: Either key of a already loaded template, list of such keys, or a image which is used as template + :param inp_img: Image in which the template will be searched + :param threshold: Threshold which determines if a template is found or not + :param roi: Region of Interest of the inp_img to restrict search area. Format [left, top, width, height] + :param use_grayscale: Use grayscale template matching for speed up + :param color_match: Pass a color to be used by misc.color_filter to filter both image of interest and template image (format Config().colors["color"]) + :param best_match: If list input, will search for list of templates by best match. Default behavior is first match. + :return: Returns a TemplateMatch object with a valid flag """ - TEMPLATE_PATHS = [ - "assets\\templates", - "assets\\npc", - "assets\\shop", - "assets\\item_properties", - "assets\\chests", - "assets\\gamble", - ] - _instance = None - - def __new__(cls, save_last_res=False): - if cls._instance is None: - cls._instance = super(TemplateFinder, cls).__new__(cls) - cls._instance._save_last_res = save_last_res - if cls._instance._save_last_res: - # do not use this when running botty as it is used accross multiple threads! Just used in shopper as a workaround for now - cls._instance.last_res = None - # load templates with their filename as key in the dict - pathes = [] - for path in TemplateFinder.TEMPLATE_PATHS: - pathes += list_files_in_folder(path) - cls._instance._templates = {} - for file_path in pathes: - file_name: str = os.path.basename(file_path) - if file_name.lower().endswith('.png'): - key = file_name[:-4].upper() - template_img = load_template(file_path, 1.0, True) - mask = alpha_to_mask(template_img) - cls._instance._templates[key] = [ - cv2.cvtColor(template_img, cv2.COLOR_BGRA2BGR), - cv2.cvtColor(template_img, cv2.COLOR_BGRA2GRAY), - 1.0, - mask - ] - return cls._instance - - def get_template(self, key): - return cv2.cvtColor(self._templates[key][0], cv2.COLOR_BGRA2BGR) - - def search( - self, - ref: Union[str, np.ndarray, list[str]], - inp_img: np.ndarray, - threshold: float = 0.68, - roi: list[float] = None, - normalize_monitor: bool = False, - best_match: bool = False, - use_grayscale: bool = False, - color_match: list = False, - ) -> TemplateMatch: - """ - Search for a template in an image - :param ref: Either key of a already loaded template, list of such keys, or a image which is used as template - :param inp_img: Image in which the template will be searched - :param threshold: Threshold which determines if a template is found or not - :param roi: Region of Interest of the inp_img to restrict search area. Format [left, top, width, height] - :param normalize_monitor: If True will return positions in monitor coordinates. Otherwise in coordinates of the input image. - :param best_match: If list input, will search for list of templates by best match. Default behavior is first match. - :param use_grayscale: Use grayscale template matching for speed up - :param color_match: Pass a color to be used by misc.color_filter to filter both image of interest and template image (format Config().colors["color"]) - :return: Returns a TemplateMatch object with a valid flag - """ - if roi is None: - # if no roi is provided roi = full inp_img - roi = [0, 0, inp_img.shape[1], inp_img.shape[0]] - rx, ry, rw, rh = roi - inp_img = inp_img[ry:ry + rh, rx:rx + rw] - - if type(ref) == str: - if not color_match: - templates = [self._templates[ref][use_grayscale]] - else: - templates = [color_filter(self._templates[ref][0], color_match)[1]] - if use_grayscale: - templates = [cv2.cvtColor(templates[0], cv2.COLOR_BGR2GRAY)] - scales = [self._templates[ref][2]] - masks = [self._templates[ref][3]] - names = [ref] - best_match = False - elif type(ref) == list: - if type(ref[0]) == str: - if not color_match: - templates = [self._templates[i][use_grayscale] for i in ref] - else: - templates = [color_filter(self._templates[i][0], color_match)[1] for i in ref] - if use_grayscale: - templates = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in templates] - scales = [self._templates[i][2] for i in ref] - masks = [self._templates[i][3] for i in ref] - names = ref + templates = _process_template_refs(ref) + matches = [] + for template in templates: + match = _single_template_match(template, inp_img, roi, color_match, use_grayscale) + if match.score >= threshold: + if not best_match: + return match else: - if not color_match: - templates = ref - else: - templates = [color_filter(i, color_match)[1] for i in ref] - if use_grayscale: - templates = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in templates] - scales = [1.0] * len(ref) - masks = [None] * len(ref) - else: - if not color_match: - templates = [ref] - else: - templates = [color_filter(ref, color_match)[1]] - if use_grayscale: - templates = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in templates] - scales = [1.0] - masks = [None] - best_match = False - - scores = [0] * len(templates) - ref_points = [(0, 0)] * len(templates) - recs = [[0, 0, 0, 0]] * len(templates) - - if color_match: - inp_img = color_filter(inp_img, color_match)[1] - - for count, template in enumerate(templates): - template_match = TemplateMatch() - scale = scales[count] - mask = masks[count] - - if scale != 1: - img: np.ndarray = cv2.resize(inp_img, None, fx=scale, fy=scale, interpolation=cv2.INTER_NEAREST) - rx *= scale - ry *= scale - rw *= scale - rh *= scale - else: - img: np.ndarray = inp_img - - if img.shape[0] > template.shape[0] and img.shape[1] > template.shape[1]: - if use_grayscale: - img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED, mask=mask) - np.nan_to_num(res, copy=False, nan=0.0, posinf=0.0, neginf=0.0) - _, max_val, _, max_pos = cv2.minMaxLoc(res) - if self._save_last_res: - with template_finder_lock: - self.last_res = deepcopy(res) - if max_val > threshold: - rec = [int((max_pos[0] + rx) // scale), int((max_pos[1] +ry) // scale), int(template.shape[1] // scale), int(template.shape[0] // scale)] - ref_point = roi_center(rec) - - if normalize_monitor: - ref_point = convert_screen_to_monitor(ref_point) - rec[0], rec[1] = convert_screen_to_monitor((rec[0], rec[1])) - if best_match: - scores[count] = max_val - ref_points[count] = ref_point - recs[count] = rec - else: - try: template_match.name = names[count] - except: pass - template_match.center = ref_point - template_match.score = max_val - template_match.region = rec - template_match.valid = True - return template_match - - if len(scores) > 0 and max(scores) > 0: - idx=scores.index(max(scores)) - try: template_match.name = names[idx] - except: pass - template_match.center = ref_points[idx] - template_match.score = scores[idx] - template_match.region = recs[idx] - template_match.valid = True - else: - template_match = TemplateMatch() - - return template_match - - def search_and_wait( - self, - ref: Union[str, list[str]], - roi: list[float] = None, - timeout: float = None, - threshold: float = 0.68, - normalize_monitor: bool = False, - best_match: bool = False, - take_ss: bool = True, - use_grayscale: bool = False, - suppress_debug: bool = False, - color_match: list = False, - ) -> TemplateMatch: - """ - Helper function that will loop and keep searching for a template - :param timeout: After this amount of time the search will stop and it will return [False, None] - :param take_ss: Bool value to take screenshot on timeout or not (flag must still be set in params!) - Other params are the same as for TemplateFinder.search() - """ - if type(ref) is str: - ref = [ref] - if not suppress_debug: - Logger.debug(f"Waiting for templates: {ref}") - start = time.time() - while 1: - img = grab() - template_match = self.search(ref, img, roi=roi, threshold=threshold, best_match=best_match, use_grayscale=use_grayscale, normalize_monitor=normalize_monitor, color_match=color_match) - is_loading_black_roi = np.average(img[:, 0:Config().ui_roi["loading_left_black"][2]]) < 1.0 - if not is_loading_black_roi or "LOADING" in ref: - if template_match.valid: - Logger.debug(f"Found Match: {template_match.name} ({template_match.score*100:.1f}% confidence)") - return template_match - if timeout is not None and (time.time() - start) > timeout: - if Config().general["info_screenshots"] and take_ss: - cv2.imwrite(f"./info_screenshots/info_wait_for_{ref}_timeout_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img) - if take_ss: - Logger.debug(f"Could not find any of the above templates") - return template_match + matches.append(match) + if matches: + matches = sorted(matches, key=lambda obj: obj.score, reverse=True) + return matches[0] + return TemplateMatch() + + +def search_and_wait( + ref: str | list[str], + roi: list[float] = None, + timeout: float = 30, + threshold: float = 0.68, + use_grayscale: bool = False, + color_match: list = False, + best_match: bool = False, + suppress_debug: bool = False, +) -> TemplateMatch: + """ + Helper function that will loop and keep searching for a template + :param timeout: After this amount of time the search will stop and it will return [False, None] + :Other params are the same as for template_finder.search() + :returns a TemplateMatch object + """ + if not suppress_debug: + Logger.debug(f"Waiting for templates: {ref}") + start = time.time() + template_match = TemplateMatch() + while (time_remains := time.time() - start < timeout): + img = grab() + is_loading_black_roi = np.average(img[:, 0:Config().ui_roi["loading_left_black"][2]]) < 1.0 + if not is_loading_black_roi or "LOADING" in ref: + template_match = search(ref, img, roi=roi, threshold=threshold, use_grayscale=use_grayscale, color_match=color_match, best_match=best_match) + if template_match.valid: + break + if not time_remains: + Logger.debug(f"Could not find desired templates") + else: + Logger.debug(f"Found match: {template_match.name} ({template_match.score*100:.1f}% confidence)") + return template_match + + +def search_all( + ref: str | np.ndarray | list[str], + inp_img: np.ndarray, + threshold: float = 0.68, + roi: list[float] = None, + use_grayscale: bool = False, + color_match: list = False, +) -> list[TemplateMatch]: + """ + Returns a list of all templates scoring above set threshold on the screen + :Other params are the same as for template_finder.search() + :return: Returns a list of TemplateMatch objects + """ + templates = _process_template_refs(ref) + matches = [] + img = inp_img.copy() + while True: + any_found = False + for template in templates: + match = _single_template_match(template, img, roi, color_match, use_grayscale) + if (ind_found := match.score >= threshold): + matches.append(match) + img = mask_by_roi(img, match.region, "inverse") + any_found |= ind_found + if not any_found: + break + return matches # Testing: Have whatever you want to find on the screen @@ -246,7 +229,7 @@ def search_and_wait( import os from screen import start_detecting_window, stop_detecting_window from utils.misc import wait - from template_finder import TemplateFinder + import template_finder start_detecting_window() wait(0.1) @@ -267,19 +250,20 @@ def search_and_wait( _template_list = ["SHENK_0","SHENK_1","SHENK_10","SHENK_11","SHENK_12","SHENK_13","SHENK_15","SHENK_16","SHENK_17","SHENK_18","SHENK_19","SHENK_2","SHENK_20","SHENK_3","SHENK_4","SHENK_6","SHENK_7","SHENK_8","SHENK_9","SHENK_DEATH_0","SHENK_DEATH_1","SHENK_DEATH_2","SHENK_DEATH_3","SHENK_DEATH_4","SHENK_V2_3","SHENK_V2_4","SHENK_V2_6","SHENK_V2_7","SHENK_V2_8"] + _template_list += ["ELDRITCH_0","ELDRITCH_0_V2","ELDRITCH_0_V3","ELDRITCH_1","ELDRITCH_1_V2","ELDRITCH_2","ELDRITCH_2_V2","ELDRITCH_3","ELDRITCH_4","ELDRITCH_5","ELDRITCH_6","ELDRITCH_7","ELDRITCH_7_V2","ELDRITCH_8","ELDRITCH_8_V2","ELDRITCH_9","ELDRITCH_START","ELDRITCH_START_V2"] + _current_template_idx = -1 _last_stored_idx = 0 - _current_threshold = 0.5 + _current_threshold = 0.6 _visible_templates = [] def _save_visible_templates(): - if not os.path.exists("info_screenshots"): - os.system("mkdir info_screenshots") + os.makedirs("log/screenshots/info", exist_ok=True) for match in _visible_templates: cv2.imwrite(match['filename'], match['img']) Logger.info(f"{match['filename']} saved") - def _toggle_all_templates(): + def _toggle_templates(): global _current_template_idx _current_template_idx = -1 if _current_template_idx != -1 else _last_stored_idx if _current_template_idx == -1: @@ -310,7 +294,7 @@ def _incr_threshold(direction: int = 1): keyboard.add_hotkey('up', lambda: _incr_threshold(0.05)) keyboard.add_hotkey('left', lambda: _incr_template_idx(-1)) keyboard.add_hotkey('right', lambda: _incr_template_idx(1)) - keyboard.add_hotkey('f9', lambda: _toggle_all_templates()) + keyboard.add_hotkey('f9', lambda: _toggle_templates()) keyboard.add_hotkey('f10', lambda: _save_visible_templates()) while 1: @@ -322,7 +306,7 @@ def _incr_threshold(direction: int = 1): else: templates = [_template_list[_current_template_idx]] for key in templates: - template_match = TemplateFinder().search(key, img, threshold=_current_threshold) + template_match = template_finder.search(key, img, threshold=_current_threshold) if template_match.valid: x, y = template_match.center cv2.putText(display_img, str(template_match.name), template_match.center, cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) @@ -330,7 +314,7 @@ def _incr_threshold(direction: int = 1): cv2.rectangle(display_img, template_match.region[:2], (template_match.region[0] + template_match.region[2], template_match.region[1] + template_match.region[3]), (0, 0, 255), 1) print(f"Name: {template_match.name} Pos: {template_match.center}, Dist: {625-x, 360-y}, Score: {template_match.score}") match = { - 'filename': f"./info_screenshots/{key.lower()}.png", + 'filename': f"./log/screenshots/info/{key.lower()}.png", 'img': cut_roi(img, template_match.region) } _visible_templates.append(match) diff --git a/src/town/a1.py b/src/town/a1.py index f032f5f36..6bfcbafbe 100644 --- a/src/town/a1.py +++ b/src/town/a1.py @@ -1,11 +1,9 @@ from char import IChar from town.i_act import IAct from screen import grab -from config import Config from npc_manager import Npc, open_npc_menu, press_npc_btn from pather import Pather, Location -from typing import Union -from template_finder import TemplateFinder +import template_finder from ui_manager import ScreenObjects, is_visible from utils.misc import wait @@ -23,7 +21,7 @@ def can_heal(self) -> bool: return True def can_stash(self) -> bool: return True def can_trade_and_repair(self) -> bool: return True - def resurrect(self, curr_loc: Location) -> Union[Location, bool]: + def resurrect(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_KASHYA_CAIN), self._char, force_move=True): return False if open_npc_menu(Npc.KASHYA): @@ -34,7 +32,7 @@ def resurrect(self, curr_loc: Location) -> Union[Location, bool]: def open_wp(self, curr_loc: Location) -> bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_WP_SOUTH), self._char, force_move=True): return False wait(0.5, 0.7) - if not TemplateFinder().search("A1_WP", grab()).valid: + if not template_finder.search("A1_WP", grab()).valid: curr_loc = Location.A1_WP_SOUTH if not self._pather.traverse_nodes((curr_loc, Location.A1_WP_NORTH), self._char, force_move=True): return False wait(0.5, 0.7) @@ -42,27 +40,27 @@ def open_wp(self, curr_loc: Location) -> bool: # decreased threshold because we sometimes walk "over" it during pathing return self._char.select_by_template(["A1_WP"], found_wp_func, threshold=0.62) - def wait_for_tp(self) -> Union[Location, bool]: - success = TemplateFinder().search_and_wait(["A1_TOWN_7", "A1_TOWN_9"], timeout=20).valid + def wait_for_tp(self) -> Location | bool: + success = template_finder.search_and_wait(["A1_TOWN_7", "A1_TOWN_9"], timeout=20).valid if not self._pather.traverse_nodes([Location.A1_TOWN_TP, Location.A1_KASHYA_CAIN], self._char, force_move=True): return False if success: return Location.A1_KASHYA_CAIN return False - def identify(self, curr_loc: Location) -> Union[Location, bool]: + def identify(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_KASHYA_CAIN), self._char, force_move=True): return False if open_npc_menu(Npc.CAIN): press_npc_btn(Npc.CAIN, "identify") return Location.A1_KASHYA_CAIN return False - def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_AKARA), self._char, force_move=True): return False open_npc_menu(Npc.AKARA) press_npc_btn(Npc.AKARA, "trade") return Location.A1_AKARA - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: + def open_stash(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_STASH), self._char, force_move=True): return False wait(0.5, 0.6) @@ -75,12 +73,12 @@ def stash_is_open_func(): return False return Location.A1_STASH - def heal(self, curr_loc: Location) -> Union[Location, bool]: + def heal(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_AKARA), self._char, force_move=True): return False open_npc_menu(Npc.AKARA) return Location.A1_AKARA - def open_trade_and_repair_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_and_repair_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A1_CHARSI), self._char, force_move=True): return False open_npc_menu(Npc.CHARSI) press_npc_btn(Npc.CHARSI, "trade_repair") diff --git a/src/town/a2.py b/src/town/a2.py index 8cf1d2aaf..d8a93c128 100644 --- a/src/town/a2.py +++ b/src/town/a2.py @@ -3,8 +3,7 @@ from screen import grab from npc_manager import Npc, open_npc_menu, press_npc_btn from pather import Pather, Location -from typing import Union -from template_finder import TemplateFinder +import template_finder from utils.misc import wait from ui_manager import ScreenObjects, is_visible @@ -20,13 +19,13 @@ def can_identify(self) -> bool: return True def can_heal(self) -> bool: return True def can_trade_and_repair(self) -> bool: return True - def heal(self, curr_loc: Location) -> Union[Location, bool]: + def heal(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A2_FARA_STASH), self._char, force_move=True): return False if open_npc_menu(Npc.FARA): return Location.A2_FARA_STASH return False - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: + def open_stash(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A2_FARA_STASH), self._char, force_move=True): return False wait(0.3) @@ -39,21 +38,21 @@ def stash_is_open_func(): return False return Location.A2_FARA_STASH - def identify(self, curr_loc: Location) -> Union[Location, bool]: + def identify(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A2_FARA_STASH), self._char, force_move=True): return False if open_npc_menu(Npc.CAIN): press_npc_btn(Npc.CAIN, "identify") return Location.A2_FARA_STASH return False - def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A2_DROGNAN), self._char, force_move=True): return False if open_npc_menu(Npc.DROGNAN): press_npc_btn(Npc.DROGNAN, "trade") return Location.A2_DROGNAN return False - def open_trade_and_repair_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_and_repair_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A2_FARA_STASH), self._char, force_move=True): return if open_npc_menu(Npc.FARA): press_npc_btn(Npc.FARA, "trade_repair") @@ -66,8 +65,8 @@ def open_wp(self, curr_loc: Location) -> bool: found_wp_func = lambda: is_visible(ScreenObjects.WaypointLabel) return self._char.select_by_template(["A2_WP_LIGHT", "A2_WP_DARK"], found_wp_func, telekinesis=True) - def wait_for_tp(self) -> Union[Location, bool]: - template_match = TemplateFinder().search_and_wait(["A2_TOWN_21", "A2_TOWN_22", "A2_TOWN_20", "A2_TOWN_19"], timeout=20) + def wait_for_tp(self) -> Location | bool: + template_match = template_finder.search_and_wait(["A2_TOWN_21", "A2_TOWN_22", "A2_TOWN_20", "A2_TOWN_19", "A2_TOWN_26"], timeout=20) if template_match.valid: self._pather.traverse_nodes((Location.A2_TP, Location.A2_FARA_STASH), self._char, force_move=True) return Location.A2_FARA_STASH diff --git a/src/town/a3.py b/src/town/a3.py index 2d361ea3a..75264e38a 100644 --- a/src/town/a3.py +++ b/src/town/a3.py @@ -3,8 +3,7 @@ from screen import grab from npc_manager import Npc, open_npc_menu, press_npc_btn from pather import Pather, Location -from typing import Union -from template_finder import TemplateFinder +import template_finder from utils.misc import wait from ui_manager import ScreenObjects, is_visible @@ -21,19 +20,19 @@ def can_heal(self) -> bool: return True def can_identify(self) -> bool: return True def can_stash(self) -> bool: return True - def heal(self, curr_loc: Location) -> Union[Location, bool]: + def heal(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A3_ORMUS), self._char, force_move=True): return False open_npc_menu(Npc.ORMUS) return Location.A3_ORMUS - def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A3_ORMUS), self._char, force_move=True): return False if open_npc_menu(Npc.ORMUS): press_npc_btn(Npc.ORMUS, "trade") return Location.A3_ORMUS return False - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: + def open_stash(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A3_STASH_WP), self._char, force_move=True): return False wait(0.3) @@ -52,14 +51,14 @@ def open_wp(self, curr_loc: Location) -> bool: found_wp_func = lambda: is_visible(ScreenObjects.WaypointLabel) return self._char.select_by_template("A3_WP", found_wp_func, telekinesis=True) - def wait_for_tp(self) -> Union[Location, bool]: - template_match = TemplateFinder().search_and_wait("A3_TOWN_10", timeout=20) + def wait_for_tp(self) -> Location | bool: + template_match = template_finder.search_and_wait("A3_TOWN_10", timeout=20) if template_match.valid: self._pather.traverse_nodes((Location.A3_STASH_WP, Location.A3_STASH_WP), self._char, force_move=True) return Location.A3_STASH_WP return False - def identify(self, curr_loc: Location) -> Union[Location, bool]: + def identify(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A3_STASH_WP), self._char, force_move=True): return False if open_npc_menu(Npc.CAIN): press_npc_btn(Npc.CAIN, "identify") diff --git a/src/town/a4.py b/src/town/a4.py index fc791e387..d4d57389a 100644 --- a/src/town/a4.py +++ b/src/town/a4.py @@ -3,8 +3,7 @@ from screen import grab from npc_manager import Npc, open_npc_menu, press_npc_btn from pather import Pather, Location -from typing import Union -from template_finder import TemplateFinder +import template_finder from utils.misc import wait from ui_manager import ScreenObjects, is_visible @@ -23,7 +22,7 @@ def can_heal(self) -> bool: return True def can_stash(self) -> bool: return True def can_trade_and_repair(self) -> bool: return True - def resurrect(self, curr_loc: Location) -> Union[Location, bool]: + def resurrect(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_TYRAEL_STASH), self._char, force_move=True): return False if open_npc_menu(Npc.TYRAEL): @@ -38,34 +37,34 @@ def open_wp(self, curr_loc: Location) -> bool: # decreased threshold because we sometimes walk "over" it during pathing return self._char.select_by_template(["A4_WP", "A4_WP_2"], found_wp_func, threshold=0.62, telekinesis=False) - def wait_for_tp(self) -> Union[Location, bool]: - success = TemplateFinder().search_and_wait(["A4_TOWN_4", "A4_TOWN_5", "A4_TOWN_6"], timeout=20).valid + def wait_for_tp(self) -> Location | bool: + success = template_finder.search_and_wait(["A4_TOWN_4", "A4_TOWN_5", "A4_TOWN_6"], timeout=20).valid if success: return Location.A4_TOWN_START return False - def identify(self, curr_loc: Location) -> Union[Location, bool]: + def identify(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_TYRAEL_STASH), self._char, force_move=True): return False if open_npc_menu(Npc.CAIN): press_npc_btn(Npc.CAIN, "identify") return Location.A4_TYRAEL_STASH return False - def gamble (self, curr_loc: Location) -> Union[Location, bool]: + def gamble (self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_JAMELLA), self._char, force_move=True): return False if open_npc_menu(Npc.JAMELLA): press_npc_btn(Npc.JAMELLA, "gamble") return Location.A4_JAMELLA return False - def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_JAMELLA), self._char, force_move=True): return False if open_npc_menu(Npc.JAMELLA): press_npc_btn(Npc.JAMELLA, "trade") return Location.A4_JAMELLA return False - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: + def open_stash(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_TYRAEL_STASH), self._char, force_move=True): return False wait(0.5, 0.6) @@ -78,13 +77,13 @@ def stash_is_open_func(): return False return Location.A4_TYRAEL_STASH - def heal(self, curr_loc: Location) -> Union[Location, bool]: + def heal(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_JAMELLA), self._char, force_move=True): return False if open_npc_menu(Npc.JAMELLA): return Location.A4_JAMELLA return False - def open_trade_and_repair_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_and_repair_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A4_HALBU), self._char, force_move=True): return False if open_npc_menu(Npc.HALBU): press_npc_btn(Npc.HALBU, "trade_repair") diff --git a/src/town/a5.py b/src/town/a5.py index 279990f2a..89fe06b67 100644 --- a/src/town/a5.py +++ b/src/town/a5.py @@ -3,8 +3,7 @@ from screen import grab from npc_manager import Npc, open_npc_menu, press_npc_btn from pather import Pather, Location -from typing import Union -from template_finder import TemplateFinder +import template_finder from utils.misc import wait from ui_manager import ScreenObjects, is_visible @@ -22,34 +21,34 @@ def can_identify(self) -> bool: return True def can_stash(self) -> bool: return True def can_trade_and_repair(self) -> bool: return True - def heal(self, curr_loc: Location) -> Union[Location, bool]: + def heal(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A5_MALAH), self._char, force_move=True): return False if not open_npc_menu(Npc.MALAH): return False if not self._pather.traverse_nodes((Location.A5_MALAH, Location.A5_TOWN_START), self._char, force_move=True): return False return Location.A5_TOWN_START - def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A5_MALAH), self._char, force_move=True): return False if open_npc_menu(Npc.MALAH): press_npc_btn(Npc.MALAH, "trade") return Location.A5_MALAH return False - def resurrect(self, curr_loc: Location) -> Union[Location, bool]: + def resurrect(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A5_QUAL_KEHK), self._char, force_move=True): return False if open_npc_menu(Npc.QUAL_KEHK): press_npc_btn(Npc.QUAL_KEHK, "resurrect") return Location.A5_QUAL_KEHK return False - def identify(self, curr_loc: Location) -> Union[Location, bool]: + def identify(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A5_QUAL_KEHK), self._char, force_move=True): return False if open_npc_menu(Npc.CAIN): press_npc_btn(Npc.CAIN, "identify") return Location.A5_QUAL_KEHK return False - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: + def open_stash(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A5_STASH), self._char, force_move=True): return False wait(0.5, 0.6) @@ -62,7 +61,7 @@ def stash_is_open_func(): return False return Location.A5_STASH - def open_trade_and_repair_menu(self, curr_loc: Location) -> Union[Location, bool]: + def open_trade_and_repair_menu(self, curr_loc: Location) -> Location | bool: if not self._pather.traverse_nodes((curr_loc, Location.A5_LARZUK), self._char, force_move=True): return False open_npc_menu(Npc.LARZUK) press_npc_btn(Npc.LARZUK, "trade_repair") @@ -74,8 +73,8 @@ def open_wp(self, curr_loc: Location) -> bool: found_wp_func = lambda: is_visible(ScreenObjects.WaypointLabel) return self._char.select_by_template("A5_WP", found_wp_func, telekinesis=True) - def wait_for_tp(self) -> Union[Location, bool]: - success = TemplateFinder().search_and_wait(["A5_TOWN_1", "A5_TOWN_0"], timeout=20).valid + def wait_for_tp(self) -> Location | bool: + success = template_finder.search_and_wait(["A5_TOWN_1", "A5_TOWN_0"], timeout=20).valid if success: return Location.A5_TOWN_START return False diff --git a/src/town/i_act.py b/src/town/i_act.py index ddb068994..cdfe800f2 100644 --- a/src/town/i_act.py +++ b/src/town/i_act.py @@ -1,4 +1,3 @@ -from typing import Union from pather import Location @@ -8,7 +7,7 @@ def open_wp(self, curr_loc: Location) -> bool: return False # Get Location that is closest to waypoint to continue pathing from there def get_wp_location(self) -> Location: pass # Wait until we arrive in town after using town portal (by searching for templates close it) - def wait_for_tp(self) -> Union[Location, bool]: return False + def wait_for_tp(self) -> Location | bool: return False # Is buying pots implemented for this Town? def can_buy_pots(self) -> bool: return False @@ -24,10 +23,10 @@ def can_trade_and_repair(self) -> bool: return False def can_identify(self) -> bool: return False def can_gamble (self) -> bool: return False # If any of the above functions return True for the Town, the respective method must be implemented - def open_trade_menu(self, curr_loc: Location) -> Union[Location, bool]: return False - def heal(self, curr_loc: Location) -> Union[Location, bool]: return False - def resurrect(self, curr_loc: Location) -> Union[Location, bool]: return False - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: return False - def open_trade_and_repair_menu(self, curr_loc: Location) -> Union[Location, bool]: return False - def identify(self, curr_loc: Location) -> Union[Location, bool]: return False - def gamble (self, curr_loc: Location) -> Union[Location, bool]: return False + def open_trade_menu(self, curr_loc: Location) -> Location | bool: return False + def heal(self, curr_loc: Location) -> Location | bool: return False + def resurrect(self, curr_loc: Location) -> Location | bool: return False + def open_stash(self, curr_loc: Location) -> Location | bool: return False + def open_trade_and_repair_menu(self, curr_loc: Location) -> Location | bool: return False + def identify(self, curr_loc: Location) -> Location | bool: return False + def gamble (self, curr_loc: Location) -> Location | bool: return False diff --git a/src/town/town_manager.py b/src/town/town_manager.py index 74662726e..1980ca74d 100644 --- a/src/town/town_manager.py +++ b/src/town/town_manager.py @@ -1,5 +1,6 @@ -from typing import Union -from template_finder import TemplateFinder +from item import consumables +import keyboard +import template_finder from config import Config from pather import Location from logger import Logger @@ -7,7 +8,7 @@ from utils.misc import wait from screen import grab from ui import waypoint, view -from inventory import consumables, personal, vendor, common +from inventory import personal, vendor, common TOWN_MARKERS = [ "A5_TOWN_0", "A5_TOWN_1", @@ -43,12 +44,12 @@ def get_act_from_location(loc: Location) -> Location: location = Location.A1_TOWN_START return location - def wait_for_town_spawn(self, timeout: float = None) -> Location: + def wait_for_town_spawn(self, timeout: float = 30) -> Location: """Wait for the char to spawn in town after starting a new game :param timeout: Optional float value for time out in seconds, defaults to None :return: Location of the town (e.g. Location.A4_TOWN_START) or None if nothing was found within timeout time """ - template_match = TemplateFinder().search_and_wait(TOWN_MARKERS, best_match=True, timeout=timeout) + template_match = template_finder.search_and_wait(TOWN_MARKERS, best_match=True, timeout=timeout) if template_match.valid: return TownManager.get_act_from_location(template_match.name) return None @@ -63,7 +64,7 @@ def open_wp(self, curr_loc: Location): if curr_act is None: return False return self._acts[curr_act].open_wp(curr_loc) - def go_to_act(self, act_idx: int, curr_loc: Location) -> Union[Location, bool]: + def go_to_act(self, act_idx: int, curr_loc: Location) -> Location | bool: curr_act = TownManager.get_act_from_location(curr_loc) if curr_act is None: return False # check if we already are in the desired act @@ -82,7 +83,7 @@ def go_to_act(self, act_idx: int, curr_loc: Location) -> Union[Location, bool]: waypoint.use_wp(act = act_idx, idx = 0) return self._acts[act].get_wp_location() - def heal(self, curr_loc: Location) -> Union[Location, bool]: + def heal(self, curr_loc: Location) -> Location | bool: curr_act = TownManager.get_act_from_location(curr_loc) if curr_act is None: return False # check if we can heal in current act @@ -146,7 +147,7 @@ def buy_consumables(self, curr_loc: Location, items: list = None): Logger.warning(f"Could not buy consumables in {curr_act}. Continue.") return curr_loc, items - def resurrect(self, curr_loc: Location) -> Union[Location, bool]: + def resurrect(self, curr_loc: Location) -> Location | bool: curr_act = TownManager.get_act_from_location(curr_loc) if curr_act is None: return False # check if we can resurrect in current act @@ -156,21 +157,31 @@ def resurrect(self, curr_loc: Location) -> Union[Location, bool]: if not new_loc: return False return self._acts[Location.A4_TOWN_START].resurrect(new_loc) - def identify(self, curr_loc: Location) -> Union[Location, bool]: + def identify(self, curr_loc: Location) -> Location | bool: curr_act = TownManager.get_act_from_location(curr_loc) if curr_act is None: return False # check if we can Identify in current act if self._acts[curr_act].can_identify(): success = self._acts[curr_act].identify(curr_loc) - view.return_to_play() + if success: + wait(0.2) + # close cain dialog so inventory key is not blocked + keyboard.send("esc") + else: + view.return_to_play() return success new_loc = self.go_to_act(5, curr_loc) if not new_loc: return False success = self._acts[Location.A5_TOWN_START].identify(new_loc) - view.return_to_play() + if success: + wait(0.2) + # close cain dialog so inventory key is not blocked + keyboard.send("esc") + else: + view.return_to_play() return success - def open_stash(self, curr_loc: Location) -> Union[Location, bool]: + def open_stash(self, curr_loc: Location) -> Location | bool: curr_act = TownManager.get_act_from_location(curr_loc) new_loc = curr_loc @@ -183,7 +194,7 @@ def open_stash(self, curr_loc: Location) -> Union[Location, bool]: if not new_loc: return False return new_loc - def gamble(self, curr_loc: Location) -> Union[Location, bool]: + def gamble(self, curr_loc: Location) -> Location | bool: curr_act = TownManager.get_act_from_location(curr_loc) if curr_act is None: return False # check if we can Identify in current act @@ -244,7 +255,7 @@ def repair(self, curr_loc: Location, items: list = None): keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1)) print("Move to d2r window and press f11") keyboard.wait("f11") - from char.hammerdin import Hammerdin + from char.paladin.hammerdin import Hammerdin from pather import Pather pather = Pather() char = Hammerdin(Config().hammerdin, Config().char, pather) diff --git a/src/transmute/inventory_collection.py b/src/transmute/inventory_collection.py index 9d8025469..46fd23983 100644 --- a/src/transmute/inventory_collection.py +++ b/src/transmute/inventory_collection.py @@ -8,7 +8,7 @@ from screen import grab import cv2 import numpy as np -from template_finder import TemplateFinder +import template_finder def _is_slot_empty(img, treshold=16.0): @@ -66,7 +66,7 @@ def inspect_area( result.set_empty((column, row)) if len(known_items) > 0: - match = TemplateFinder().search( + match = template_finder.search( known_items, slot_img, threshold=0.91, best_match=True ) diff --git a/src/transmute/transmute.py b/src/transmute/transmute.py index 28c9b8fe2..6cd832696 100644 --- a/src/transmute/transmute.py +++ b/src/transmute/transmute.py @@ -11,12 +11,42 @@ from version import __version__ from logger import Logger from game_stats import GameStats -from template_finder import TemplateFinder +import template_finder import numpy as np import keyboard import cv2 from inventory import personal, common +CHIPPED_GEMS = [ + "INVENTORY_TOPAZ_CHIPPED", + "INVENTORY_AMETHYST_CHIPPED", + "INVENTORY_SAPPHIRE_CHIPPED", + "INVENTORY_DIAMOND_CHIPPED", + "INVENTORY_RUBY_CHIPPED", + "INVENTORY_EMERALD_CHIPPED", + "INVENTORY_SKULL_CHIPPED" +] + +FLAWED_GEMS = [ + "INVENTORY_TOPAZ_FLAWED", + "INVENTORY_AMETHYST_FLAWED", + "INVENTORY_SAPPHIRE_FLAWED", + "INVENTORY_DIAMOND_FLAWED", + "INVENTORY_RUBY_FLAWED", + "INVENTORY_EMERALD_FLAWED", + "INVENTORY_SKULL_FLAWED" +] + +STANDARD_GEMS = [ + "INVENTORY_TOPAZ_STANDARD", + "INVENTORY_AMETHYST_STANDARD", + "INVENTORY_SAPPHIRE_STANDARD", + "INVENTORY_DIAMOND_STANDARD", + "INVENTORY_RUBY_STANDARD", + "INVENTORY_EMERALD_STANDARD", + "INVENTORY_SKULL_STANDARD" +] + FLAWLESS_GEMS = [ "INVENTORY_TOPAZ_FLAWLESS", "INVENTORY_AMETHYST_FLAWLESS", @@ -67,7 +97,7 @@ def pick_from_area(self, column, row, roi): def open_cube(self): common.select_tab(0) if (match := detect_screen_object(ScreenObjects.CubeInventory)).valid: - mouse.move(*match.center) + mouse.move(*match.center_monitor) self._wait() mouse.click("right") self._wait() @@ -107,7 +137,7 @@ def inspect_area(self, total_rows, total_columns, roi, known_items) -> Inventory slot_img = img[y_start:y_end, x_start:x_end] if not self._is_slot_empty(slot_img[+4:-4, +4:-4], treshold=36): result.set_empty((column, row)) - match = TemplateFinder().search( + match = template_finder.search( known_items, slot_img, threshold=0.91, best_match=True) if match.valid: @@ -123,13 +153,13 @@ def _is_slot_empty(self, img, treshold=16.0): def inspect_inventory_area(self, known_items) -> InventoryCollection: return self.inspect_area(4, Config().char["num_loot_columns"], Config().ui_roi["right_inventory"], known_items) - def inspect_stash(self) -> Stash: + def inspect_stash(self, gemsToTransmute) -> Stash: stash = Stash() for i in range(4): common.select_tab(i) wait(0.4, 0.5) tab = self.inspect_area( - 10, 10, Config().ui_roi["left_inventory"], FLAWLESS_GEMS) + 10, 10, Config().ui_roi["left_inventory"], gemsToTransmute) stash.add_tab(i, tab) return stash @@ -151,62 +181,80 @@ def select_tab_with_enough_space(self, s: Stash) -> None: common.select_tab(tab) break - def put_back_all_gems(self, s: Stash) -> None: + def put_back_all_gems(self, s: Stash, gemsToTransmute,gemsToPutBack) -> None: Logger.info( f'Putting back gems in the following stash tabs (by priority): {Config().configs["transmute"]["parser"]["stash_destination"]}') - perfect_gems = self.inspect_inventory_area( - PERFECT_GEMS + FLAWLESS_GEMS) + inventory_gems = self.inspect_inventory_area( + gemsToPutBack + gemsToTransmute) - for gem in perfect_gems.all_items(): - while perfect_gems.count_by(gem) > 0: + for gem in inventory_gems.all_items(): + while inventory_gems.count_by(gem) > 0: self.select_tab_with_enough_space(s) - self.pick_from_inventory_at(*perfect_gems.pop(gem)) + self.pick_from_inventory_at(*inventory_gems.pop(gem)) def should_transmute(self) -> bool: every_x_game = Config().configs["transmute"]["parser"]["transmute_every_x_game"] - + if every_x_game is None or every_x_game == "" or int(every_x_game) <= 0: return False return self._game_stats._game_counter - self._last_game >= int(every_x_game) def run_transmutes(self, force=False) -> None: if not wait_until_visible(ScreenObjects.GoldBtnStash, timeout = 8).valid: - Logger.error("Could not determine to be in stash menu. Continue...") + Logger.error("Could not find stash menu. Continue...") return if not force and not self.should_transmute(): Logger.info(f"Skipping transmutes. Force: {force}, Game#: {self._game_stats._game_counter}") return None - self._run_gem_transmutes() + transmute_gems=Config().configs["transmute"]["parser"]["transmute"] + gemsToTransmute=[] + gemsToPutBack=[] + gemLoggerName="" + for gem in transmute_gems: + gemLoggerName+=gem+" " + if gem == "chipped": + gemsToTransmute+=CHIPPED_GEMS + gemsToPutBack+=FLAWED_GEMS + if gem == "flawed": + gemsToTransmute+=FLAWED_GEMS + gemsToPutBack+=STANDARD_GEMS + if gem == "standard": + gemsToTransmute+=STANDARD_GEMS + gemsToPutBack+=FLAWLESS_GEMS + if gem == "flawless": + gemsToTransmute+=FLAWLESS_GEMS + gemsToPutBack+=PERFECT_GEMS + self._run_gem_transmutes(gemsToTransmute,gemsToPutBack,gemLoggerName) - def check_cube_empty(self) -> bool: + def check_cube_empty(self,gemsToTransmute) -> bool: self.open_cube() - area = self.inspect_cube() + area = self.inspect_cube(gemsToTransmute) self.close_cube() return area.count_empty() == 12 - def inspect_cube(self)-> InventoryCollection: - return self.inspect_area(4, 3, roi=Config().ui_roi["cube_area_roi"], known_items=FLAWLESS_GEMS) + def inspect_cube(self,gemsToTransmute)-> InventoryCollection: + return self.inspect_area(4, 3, roi=Config().ui_roi["cube_area_roi"], known_items=gemsToTransmute) - def _run_gem_transmutes(self) -> None: - Logger.info("Starting gem transmute") + def _run_gem_transmutes(self, gemsToTransmute,gemsToPutBack, gemLoggerName) -> None: + Logger.info(f"Starting {gemLoggerName}gem transmute") self._last_game = self._game_stats._game_counter - s = self.inspect_stash() + s = self.inspect_stash(gemsToTransmute) algorithm = SimpleGemPicking(s) - inv = self.inspect_inventory_area(FLAWLESS_GEMS) + inv = self.inspect_inventory_area(gemsToTransmute) is_cube_empty = None while True: while inv.count_empty() >= 3: next_batch = algorithm.next_batch() - is_cube_empty = self.check_cube_empty() if is_cube_empty is None else is_cube_empty + is_cube_empty = self.check_cube_empty(gemsToTransmute) if is_cube_empty is None else is_cube_empty if not is_cube_empty: Logger.warning("Some items detected in the cube. Skipping transmute") break if next_batch is None: - Logger.info("No more gems to cube") + Logger.info(f"No more {gemLoggerName}gems to cube") break for tab, gem, x, y in next_batch: self.pick_from_stash_at(tab, x, y) - inv = self.inspect_inventory_area(FLAWLESS_GEMS) + inv = self.inspect_inventory_area(gemsToTransmute) if inv.count() >= 3: self.open_cube() for gem in inv.all_items(): @@ -217,8 +265,8 @@ def _run_gem_transmutes(self) -> None: self.transmute() self.pick_from_cube_at(2, 3) self.close_cube() - self.put_back_all_gems(s) + self.put_back_all_gems(s,gemsToTransmute,gemsToPutBack) else: - self.put_back_all_gems(s) + self.put_back_all_gems(s,gemsToTransmute,gemsToPutBack) break - Logger.info("Finished gem transmute") + Logger.info(f"Finished {gemLoggerName}gem transmute") diff --git a/src/ui/character_select.py b/src/ui/character_select.py index a083a5c73..b46df69c9 100644 --- a/src/ui/character_select.py +++ b/src/ui/character_select.py @@ -1,17 +1,19 @@ from utils.custom_mouse import mouse from utils.misc import cut_roi, roi_center, wait, is_in_roi + from config import Config from screen import convert_screen_to_monitor, grab -from template_finder import TemplateFinder +import template_finder from utils.misc import wait from logger import Logger -from ocr import Ocr +from d2r_image import ocr +import numpy as np from ui_manager import detect_screen_object, ScreenObjects last_char_template = None online_character = None -def select_online_tab(region, center): +def select_online_tab(region, center) -> bool: btn_width = center[0] - region[0] if online_character: Logger.debug(f"Selecting online tab") @@ -22,9 +24,20 @@ def select_online_tab(region, center): pos = convert_screen_to_monitor((x, center[1])) # move cursor to appropriate tab and select mouse.move(*pos) - wait(0.4, 0.6) - mouse.click(button="left") - wait(0.4, 0.6) + wait(0.3, 0.5) + attempts = 0 + while attempts <= 4: + attempts += 1 + mouse.click(button="left") + if (match := detect_screen_object(ScreenObjects.OnlineStatus, grab())).valid and online_character == online_active(match): + return True + wait(1.5) + online_str = "online" if online_character else "offline" + Logger.error(f"select_online_tab: unable to select {online_str} tab after {attempts} attempts") + return False + +def get_saved_char_template() -> np.ndarray | None: + return None if not has_char_template_saved() else last_char_template def has_char_template_saved(): return last_char_template is not None @@ -48,63 +61,65 @@ def save_char_template(): x, y, w, h = Config().ui_roi["character_name_sub_roi"] x, y = x + match.region[0], y + match.region[1] char_template = cut_roi(img, [x, y, w, h]) - ocr_result = Ocr().image_to_text( - images = char_template, - model = "engd2r_ui", - psm = 6, - scale = 1.2, - crop_pad = False, - erode = False, - invert = False, - threshold = 0, - digits_only = False, - fix_regexps = False, - check_known_errors = False, - check_wordlist = False, - )[0] - Logger.debug(f"Saved character template: {ocr_result.text.splitlines()[0]}") + msg="" + try: + ocr_result = ocr.image_to_text( + images = cut_roi(img, [x, y, w, h]), + model = "hover-eng_inconsolata_inv_th_fast", + psm = 6, + scale = 1.2, + crop_pad = False, + erode = False, + invert = False, + threshold = 0, + digits_only = False, + fix_regexps = False, + check_known_errors = False, + correct_words = False, + )[0] + msg += f": {ocr_result.text.splitlines()[0]}" + except: + pass + Logger.debug(f"Saved character template{msg}") else: Logger.error("save_char_template: Could not save character template") return global last_char_template last_char_template = char_template -def select_char(): +def select_char() -> bool: if last_char_template is not None: img = grab() if (match := detect_screen_object(ScreenObjects.OnlineStatus, img)).valid: - if online_active(match) and (not online_character): - select_online_tab(match.region, match.center) - img = grab() - elif not online_active(match) and (online_character): - select_online_tab(match.region, match.center) + if online_active(match) != online_character: + if not select_online_tab(match.region, match.center): + return False img = grab() wait(1, 1.5) else: Logger.error("select_char: Could not find online/offline tabs") - return + return False if not (match := detect_screen_object(ScreenObjects.SelectedCharacter, img)).valid: Logger.error("select_char: Could not find highlighted profile") - return + return False scrolls_attempts = 0 while scrolls_attempts < 2: if scrolls_attempts > 0: img = grab() # TODO: can cleanup logic here, can we utilize a generic ScreenObject or use custom locator? - desired_char = TemplateFinder().search(last_char_template, img, roi = Config().ui_roi["character_select"], threshold = 0.8, normalize_monitor = False) + desired_char = template_finder.search(last_char_template, img, roi = Config().ui_roi["character_select"], threshold = 0.8) if desired_char.valid: - print(f"{match.region} {desired_char.center}") + #print(f"{match.region} {desired_char.center}") if is_in_roi(match.region, desired_char.center) and scrolls_attempts == 0: Logger.debug("Saved character template found and already highlighted, continue") - return + return True else: Logger.debug("Selecting saved character") - pos = convert_screen_to_monitor(desired_char.center) - mouse.move(*pos) + mouse.move(*desired_char.center_monitor) wait(0.4, 0.6) mouse.click(button="left") - wait(0.4), 0.6 - return + wait(0.4, 0.6) + return True else: Logger.debug("Highlighted profile found but saved character not in view, scroll") # We can scroll the characters only if we have the mouse in the char names selection so move the mouse there @@ -116,3 +131,4 @@ def select_char(): scrolls_attempts += 1 wait(0.4, 0.6) Logger.error(f"select_char: unable to find saved profile after {scrolls_attempts} scroll attempts") + return False \ No newline at end of file diff --git a/src/ui/loading.py b/src/ui/loading.py index 599c7f4b5..9ab64f838 100644 --- a/src/ui/loading.py +++ b/src/ui/loading.py @@ -17,4 +17,5 @@ def wait_for_loading_screen(timeout: float = 10.0) -> bool: while time.time() - start < timeout: if check_for_black_screen(): return True + time.sleep(0.02) return False diff --git a/src/ui/main_menu.py b/src/ui/main_menu.py index 5fc8fc4b8..42c63ccd6 100644 --- a/src/ui/main_menu.py +++ b/src/ui/main_menu.py @@ -6,6 +6,7 @@ from ui import error_screens from ui_manager import detect_screen_object, is_visible, select_screen_object_match, ScreenObjects +MAIN_MENU_MARKERS = ["MAIN_MENU_TOP_LEFT","MAIN_MENU_TOP_LEFT_DARK"] def _play_active(match) -> bool: return match.name == "PLAY_BTN" @@ -44,7 +45,7 @@ def start_game() -> bool: keyboard.release(difficulty_key) break else: - wait(1,2) + wait(0.2) # check for server issue if is_visible(ScreenObjects.ServerError): error_screens.handle_error() diff --git a/src/ui/player_bar.py b/src/ui/player_bar.py index fdb4ab77c..05e2d8816 100644 --- a/src/ui/player_bar.py +++ b/src/ui/player_bar.py @@ -4,7 +4,7 @@ from utils.misc import cut_roi, wait from logger import Logger from config import Config -from ocr import Ocr +from d2r_image import ocr def get_experience(): # mouseover exp bar @@ -17,9 +17,9 @@ def get_experience(): mouse.move(x_m, y_m-50, randomize = (8,1)) crop = cut_roi(img, Config().ui_roi["xp_bar_text"]) - ocr_result = Ocr().image_to_text( + ocr_result = ocr.image_to_text( images = crop, - model = "engd2r_inv_th", + model = "ground-eng_inconsolata_inv_th_fast", psm = 7, scale = 1.3, crop_pad = True, @@ -28,8 +28,7 @@ def get_experience(): digits_only = False, fix_regexps = False, check_known_errors = False, - check_wordlist = False, - word_match_threshold = 0.5 + correct_words = False )[0] split_text = ocr_result.text.split(' ') @@ -40,8 +39,7 @@ def get_experience(): required_exp = int(split_text[3].replace(',', '').replace('.', '')) return current_exp, required_exp except Exception as e: - Logger.error(f"EXP OCR Error: {split_text}") - Logger.error(f"EXP OCR Error: {str(e)}") + Logger.warning(f"EXP OCR Error: {split_text}. Exception: {e}") return 0,0 diff --git a/src/ui/skills.py b/src/ui/skills.py index 60dc4ad6d..1b0926743 100644 --- a/src/ui/skills.py +++ b/src/ui/skills.py @@ -6,8 +6,9 @@ from utils.misc import cut_roi, color_filter, wait from screen import grab from config import Config -from template_finder import TemplateFinder +import template_finder from ui_manager import wait_until_visible, ScreenObjects +from d2r_image import ocr def is_left_skill_selected(template_list: list[str]) -> bool: """ @@ -15,7 +16,7 @@ def is_left_skill_selected(template_list: list[str]) -> bool: """ skill_left_ui_roi = Config().ui_roi["skill_left"] for template in template_list: - if TemplateFinder().search(template, grab(), threshold=0.84, roi=skill_left_ui_roi).valid: + if template_finder.search(template, grab(), threshold=0.84, roi=skill_left_ui_roi).valid: return True return False @@ -23,12 +24,12 @@ def has_tps() -> bool: """ :return: Returns True if botty has town portals available. False otherwise """ - if Config().char["tp"]: - keyboard.send(Config().char["tp"]) + if Config().char["town_portal"]: + keyboard.send(Config().char["town_portal"]) if not (tps_remain := wait_until_visible(ScreenObjects.TownPortalSkill, timeout=4).valid): Logger.warning("You are out of tps") if Config().general["info_screenshots"]: - cv2.imwrite("./info_screenshots/debug_out_of_tps_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) + cv2.imwrite("./log/screenshots/info/debug_out_of_tps_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) return tps_remain else: return False @@ -60,11 +61,11 @@ def is_right_skill_selected(template_list: list[str]) -> bool: """ skill_right_ui_roi = Config().ui_roi["skill_right"] for template in template_list: - if TemplateFinder().search(template, grab(), threshold=0.84, roi=skill_right_ui_roi).valid: + if template_finder.search(template, grab(), threshold=0.84, roi=skill_right_ui_roi).valid: return True return False -def get_skill_charges(ocr, img: np.ndarray = None): +def get_skill_charges(img: np.ndarray = None): if img is None: img = grab() x, y, w, h = Config().ui_roi["skill_right"] @@ -75,7 +76,7 @@ def get_skill_charges(ocr, img: np.ndarray = None): mask, _ = color_filter(img, Config().colors["skill_charges"]) ocr_result = ocr.image_to_text( images = mask, - model = "engd2r_inv_th", + model = "hover-eng_inconsolata_inv_th_fast", psm = 7, word_list = "", scale = 1.4, @@ -86,8 +87,7 @@ def get_skill_charges(ocr, img: np.ndarray = None): digits_only = True, fix_regexps = False, check_known_errors = False, - check_wordlist = False, - word_match_threshold = 0.5 + correct_words = False )[0] try: return int(ocr_result.text) diff --git a/src/ui/view.py b/src/ui/view.py index 7ae037dd7..be16192a2 100644 --- a/src/ui/view.py +++ b/src/ui/view.py @@ -10,19 +10,19 @@ from screen import convert_screen_to_monitor def enable_no_pickup() -> bool: - """ - Checks the best match between enabled and disabled an retrys if already set. - :return: Returns True if we succesfully set the nopickup option - """ + # """ + # Checks the best match between enabled and disabled an retrys if already set. + # :return: Returns True if we succesfully set the nopickup option + # """ keyboard.send('enter') wait(0.1, 0.25) keyboard.write('/nopickup',delay=.20) keyboard.send('enter') wait(0.1, 0.25) if not (item_pickup_text := wait_until_visible(ScreenObjects.ItemPickupText, timeout=1.3)).valid: - return False + return False if item_pickup_text.name == "ITEM_PICKUP_DISABLED": - return True + return True keyboard.send('enter') wait(0.1, 0.25) keyboard.send('up') @@ -36,18 +36,24 @@ def save_and_exit() -> bool: Performes save and exit action from within game :return: Bool if action was successful """ + # if exit button isn't detected already, press escape attempts = 1 success = False - while attempts < 2 and not success: - # if exit button isn't detected already, press escape - while not (highlight := detect_screen_object(ScreenObjects.GameMenu)).valid: + while attempts <= 2 and not success: + if not (exit_button := detect_screen_object(ScreenObjects.SaveAndExit)).valid: keyboard.send("esc") - time.sleep(0.1) - keyboard.send("up,up,down+enter") - # if center icon on player bar disappears then save/exit was successful - if not (success := wait_until_hidden(ScreenObjects.InGame, 3)): - Logger.debug("Failed to find or click save/exit button") + # wait for exit button to appear + exit_button = wait_until_visible(ScreenObjects.SaveAndExit, 3) + # if exit button is found, double click it to be sure + if exit_button.valid: + select_screen_object_match(exit_button, delay_factor=(0.02, 0.05)) + wait(0.02, 0.05) + mouse.click(button="left") + # if center icon on player bar disappears then save/exit was successful + success = wait_until_hidden(ScreenObjects.InGame, 3) attempts += 1 + if not success: + Logger.debug("Failed to find or click save/exit button") return success def dismiss_skills_icon() -> bool: @@ -72,10 +78,10 @@ def move_to_corpse(): mouse.move(*pos) def return_to_play() -> bool: - substrings = ["NPC", "Panel", "GameMenu"] + substrings = ["NPC", "Panel", "SaveAndExit"] img=grab() start=time.time() - while (elapsed := (time.time() - start) < 8): + while (elapsed := (time.time() - start) < 5): need_escape = False match = detect_screen_object(ScreenObjects.InGame, img) if match.valid and "DARK" in match.name: @@ -86,7 +92,7 @@ def return_to_play() -> bool: break if need_escape: keyboard.send("esc") - wait(1.7) + wait(1) img=grab() else: break @@ -105,6 +111,6 @@ def return_to_play() -> bool: print("Go to D2R window and press f11 to start game") keyboard.wait("f11") from config import Config - from template_finder import TemplateFinder + import template_finder return_to_play() diff --git a/src/ui_manager.py b/src/ui_manager.py index f7b3fe3fd..18ba1a465 100644 --- a/src/ui_manager.py +++ b/src/ui_manager.py @@ -3,13 +3,16 @@ import numpy as np import time import cv2 -from typing import Union, TypeVar, Callable +from functools import cache + +from typing import TypeVar, Callable from utils.custom_mouse import mouse from utils.misc import wait, cut_roi, image_is_equal from logger import Logger from config import Config -from screen import grab, convert_screen_to_monitor, convert_abs_to_monitor -from template_finder import TemplateFinder, TemplateMatch +from screen import convert_abs_to_screen, convert_monitor_to_screen, convert_screen_to_abs, convert_screen_to_monitor, grab, convert_abs_to_monitor +import template_finder +from template_finder import TemplateMatch from dataclasses import dataclass from messages import Messenger from game_stats import GameStats @@ -24,9 +27,7 @@ class ScreenObject: ref: list[str] inp_img: np.ndarray = None roi: list[float] = None - timeout: float = 30 threshold: float = 0.68 - normalize_monitor: bool = True best_match: bool = False use_grayscale: bool = False color_match: list[np.array] = None @@ -97,23 +98,20 @@ class ScreenObjects: ref=["CHARACTER_STATE_ONLINE", "CHARACTER_STATE_OFFLINE"], roi="character_online_status", best_match=True, - normalize_monitor=False ) SelectedCharacter=ScreenObject( ref=["CHARACTER_ACTIVE"], roi="character_select", threshold=0.8, - normalize_monitor=False ) ServerError=ScreenObject( ref=["SERVER_ISSUES"] ) - GameMenu=ScreenObject( - ref=["GAME_MENU_HIGHLIGHT"], - roi="game_menu_left", - best_match=True, - threshold=0.95, - normalize_monitor=False + SaveAndExit=ScreenObject( + ref=["SAVE_AND_EXIT_NO_HIGHLIGHT", "SAVE_AND_EXIT_HIGHLIGHT"], + roi="save_and_exit", + threshold=0.85, + use_grayscale=True ) NeedRepair=ScreenObject( ref="REPAIR_NEEDED", @@ -178,10 +176,11 @@ class ScreenObjects: Overburdened=ScreenObject( ref=["INVENTORY_FULL_MSG_0", "INVENTORY_FULL_MSG_1"], roi="chat_line_1", + #color_match=Config().colors["gold"], threshold=0.9 ) Corpse=ScreenObject( - ref=["CORPSE", "CORPSE_BARB", "CORPSE_DRU", "CORPSE_NEC", "CORPSE_PAL", "CORPSE_SIN", "CORPSE_SORC", "CORPSE_ZON"], + ref=["CORPSE", "CORPSE_2", "CORPSE_BARB", "CORPSE_DRU", "CORPSE_NEC", "CORPSE_PAL", "CORPSE_SIN", "CORPSE_SORC", "CORPSE_ZON"], roi="corpse", threshold=0.8 ) @@ -254,30 +253,32 @@ class ScreenObjects: TabIndicator=ScreenObject( ref="TAB_INDICATOR", roi="tab_indicator", - normalize_monitor=False ) DepositBtn=ScreenObject( ref=["DEPOSIT_BTN", "DEPOSIT_BTN_BRIGHT"], threshold=0.8, roi="deposit_btn", ) + InventoryBackground=ScreenObject( + ref="INVENTORY_BG_PATTERN", + roi="inventory_bg_pattern", + threshold=0.8, + ) def detect_screen_object(screen_object: ScreenObject, img: np.ndarray = None) -> TemplateMatch: roi = Config().ui_roi[screen_object.roi] if screen_object.roi else None img = grab() if img is None else img - return TemplateFinder().search( + return template_finder.search( ref = screen_object.ref, inp_img = img, threshold = screen_object.threshold, roi = roi, best_match = screen_object.best_match, use_grayscale = screen_object.use_grayscale, - normalize_monitor = screen_object.normalize_monitor ) -def select_screen_object_match(match: TemplateMatch, delay_factor: tuple[float, float] = (0.9, 1.1), normalize_monitor: bool = False) -> None: - pos = match.center if not normalize_monitor else convert_screen_to_monitor(match.center) - mouse.move(*pos, delay_factor=delay_factor) +def select_screen_object_match(match: TemplateMatch, delay_factor: tuple[float, float] = (0.9, 1.1)) -> None: + mouse.move(*match.center_monitor, delay_factor=delay_factor) wait(0.05, 0.09) mouse.click("left") wait(0.05, 0.09) @@ -285,23 +286,26 @@ def select_screen_object_match(match: TemplateMatch, delay_factor: tuple[float, def is_visible(screen_object: ScreenObject, img: np.ndarray = None) -> bool: return detect_screen_object(screen_object, img).valid -def wait_until_visible(screen_object: ScreenObject, timeout: float = 30) -> TemplateMatch: - if not (match := wait_until(lambda: detect_screen_object(screen_object), lambda match: match.valid, timeout)[0]).valid: - Logger.debug(f"{screen_object.ref} not found after {timeout} seconds") +def wait_until_visible(screen_object: ScreenObject, timeout: float = 30, suppress_debug: bool = False) -> TemplateMatch: + if not (match := _wait_until(lambda: detect_screen_object(screen_object), lambda match: match.valid, timeout)[0]).valid: + if not suppress_debug: + Logger.debug(f"{screen_object.ref} not found after {timeout} seconds") return match -def wait_until_hidden(screen_object: ScreenObject, timeout: float = 3) -> bool: - if not (hidden := wait_until(lambda: detect_screen_object(screen_object).valid, lambda res: not res, timeout)[1]): - Logger.debug(f"{screen_object.ref} still found after {timeout} seconds") +def wait_until_hidden(screen_object: ScreenObject, timeout: float = 3, suppress_debug: bool = False) -> bool: + if not (hidden := _wait_until(lambda: detect_screen_object(screen_object).valid, lambda res: not res, timeout)[1]): + if not suppress_debug: + Logger.debug(f"{screen_object.ref} still found after {timeout} seconds") return hidden -def wait_for_update(img: np.ndarray, roi: list[int] = None, timeout: float = 3) -> bool: +def wait_for_update(img: np.ndarray, roi: list[int] = None, timeout: float = 3, suppress_debug: bool = False) -> bool: roi = roi if roi is not None else [0, 0, img.shape[0]-1, img.shape[1] -1] - if not (change := wait_until(lambda: cut_roi(grab(), roi), lambda res: not image_is_equal(cut_roi(img, roi), res), timeout)[1]): - Logger.debug(f"ROI: '{roi}' unchanged after {timeout} seconds") + if not (change := _wait_until(lambda: cut_roi(grab(), roi), lambda res: not image_is_equal(cut_roi(img, roi), res), timeout)[1]): + if not suppress_debug: + Logger.debug(f"ROI: '{roi}' unchanged after {timeout} seconds") return change -def wait_until(func: Callable[[], T], is_success: Callable[[T], bool], timeout = None) -> Union[T, None]: +def _wait_until(func: Callable[[], T], is_success: Callable[[T], bool], timeout = None) -> T | None: start = time.time() while (time.time() - start) < timeout: res = func() @@ -310,8 +314,8 @@ def wait_until(func: Callable[[], T], is_success: Callable[[T], bool], timeout = wait(0.05) return res, success -def hover_over_screen_object_match(match) -> None: - mouse.move(*convert_screen_to_monitor(match.center)) +def hover_over_screen_object_match(match : TemplateMatch) -> None: + mouse.move(*match.center_monitor) wait(0.2, 0.4) def list_visible_objects(img: np.ndarray = None) -> list: @@ -327,7 +331,71 @@ def center_mouse(delay_factor: list = None): if delay_factor: mouse.move(*center_m, randomize=20, delay_factor = delay_factor) else: - mouse.move(*center_m, randomize=20) + mouse.move(*center_m, randomize=20, delay_factor = [0.1, 0.2]) + +@cache +def get_hud_mask() -> np.ndarray: + mask = cv2.imread(f"assets/hud_mask.png", cv2.IMREAD_GRAYSCALE) + return cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY)[1] + +def _find_nearest_nonzero(img: np.ndarray, pos: tuple[int, int]) -> tuple[int, int]: + """ + Finds the nearest nonzero pixel to the target pixel. + :param img: The image to search in. + :param pos: The target pixel + :return: The nearest nonzero pixel + """ + + x, y = pos + if x < 0: + x = 0 + elif x >= img.shape[1]: + x = img.shape[1] - 1 + if y < 0: + y = 0 + elif y >= img.shape[0]: + y = img.shape[0] - 1 + if img[y,x]: + return (x, y) + + nonzero = cv2.findNonZero(img) + distances = np.sqrt((nonzero[:,:,0] - x) ** 2 + (nonzero[:,:,1] - y) ** 2) + nearest_index = np.argmin(distances) + x, y = nonzero[nearest_index, :, :][0] + return (x, y) + +@cache +def get_closest_non_hud_pixel(pos : tuple[int, int], pos_type: str = "abs") -> tuple[int, int]: + """ + Finds the closest non-hud pixel to the target pixel. + :param pos: The target pixel + :return: The closest non-hud pixel + """ + if pos is None: + Logger.error(f"get_closest_non_hud_pixel: Received empty position!") + return (0,0) + if isinstance(pos[0], float): + pos = tuple([round(x) for x in pos]) + match pos_type: + case "abs": + pos = convert_abs_to_screen(pos) + case "monitor": + pos = convert_monitor_to_screen(pos) + case "screen": + pass + case _: + Logger.error(f"Unknown pos type: {pos_type}") + return pos + screen_pos = _find_nearest_nonzero(get_hud_mask(), pos) + match pos_type: + case "abs": + new_pos = convert_screen_to_abs(screen_pos) + case "monitor": + new_pos = convert_screen_to_monitor(screen_pos) + case "screen": + new_pos = screen_pos + return new_pos + # Testing: Move to whatever ui to test and run if __name__ == "__main__": diff --git a/src/utils/auto_settings.py b/src/utils/auto_settings.py index a73005eb0..cfc59677f 100644 --- a/src/utils/auto_settings.py +++ b/src/utils/auto_settings.py @@ -4,7 +4,7 @@ from config import Config from mss import mss -from utils.misc import close_down_bnet_launcher, close_down_d2 +from utils.misc import close_down_bnet_launcher, close_down_d2, only_lowercase_letters def get_d2r_folder() -> str: @@ -57,8 +57,12 @@ def restore_settings_from_backup(): print("No D2R settings backup file was found, couldn't restore.") return close_down_d2() - shutil.copyfile(backup_file, current_file) - print("D2R settings restored successfully.") + try: + shutil.copyfile(backup_file, current_file) + print("D2R settings restored successfully.") + except Exception as e: + print("D2R settings restored unsuccessfully.") + print(f"Error: {e}") backup_file = f"{d2_saved_games}/launch_options_backup.txt" current_file = f"{os.getenv('APPDATA')}/Battle.net/Battle.net.config" @@ -72,21 +76,46 @@ def restore_settings_from_backup(): def set_launch_settings(launch_options): close_down_bnet_launcher() + # open bnet config setts f = open(f"{os.getenv('APPDATA')}/Battle.net/Battle.net.config") curr_settings = json.load(f) - curr_settings["Games"]["osi"]["AdditionalLaunchArguments"] = launch_options - with open(f"{os.getenv('APPDATA')}/Battle.net/Battle.net.config", 'w') as outfile: - json.dump(curr_settings, outfile, indent=4) + # write launch options to bnet config + try: + curr_settings["Games"]["osi"]["AdditionalLaunchArguments"] = launch_options + with open(f"{os.getenv('APPDATA')}/Battle.net/Battle.net.config", 'w') as outfile: + json.dump(curr_settings, outfile, indent=4) + except: + print("Error: Could not set launch options.") + print(f"You might need to set the launch options manually. Add launch options to D2R in BNet launcher: {launch_options}") + +def copy_mod_files(): + mod_name = only_lowercase_letters(Config().general["name"].lower()) + if not mod_name: + mod_name = "botty" + old_path = "assets/mods/botty" + if not os.path.exists(Config().general["d2r_path"]): + raise ValueError(f"Could not copy mod files because d2r_path {Config().general['d2r_path']} does not exist, please review your params.ini settings and set to your true D2R installation directory") -def copy_mod_files(): - new_path = os.path.join(Config().general['d2r_path'], "mods\\botty") - if not os.path.exists(new_path): - os.makedirs(new_path) + new_path = os.path.join(Config().general['d2r_path'], f"mods/{mod_name}") + os.makedirs(new_path, exist_ok=True) try: + # copy mod files to d2r directory shutil.rmtree(new_path) - shutil.copytree("assets/mods/botty", new_path) - except OSError as error: - print(error) + shutil.copytree(old_path, new_path) + os.rename(f"{new_path}/botty.mpq", f"{new_path}/{mod_name}.mpq") + + # modify modinfo.json to use mod_name + mod_info_path = f"{new_path}/{mod_name}.mpq/modinfo.json" + with open(mod_info_path, "rb") as file: + data=file.read() + mod_info=json.loads(data) + mod_info["name"] = mod_name + with open(mod_info_path, 'w') as outfile: + json.dump(mod_info, outfile, indent=4) + + except Exception as e: + print(f"Error copying mod files: {e}") + print(f"You might need to copy the mod files from {old_path} to {new_path} manually.") def adjust_settings(): close_down_d2() diff --git a/src/utils/custom_mouse.py b/src/utils/custom_mouse.py index 3d285f9e9..04956beda 100644 --- a/src/utils/custom_mouse.py +++ b/src/utils/custom_mouse.py @@ -6,12 +6,11 @@ import random import math import time -from typing import Union, Tuple import screen from config import Config from utils.misc import is_in_roi from logger import Logger -from template_finder import TemplateFinder +import template_finder def isNumeric(val): return isinstance(val, (float, int, np.int32, np.int64, np.float32, np.float64)) @@ -228,7 +227,7 @@ def _move_to(x, y, absolute=True, duration=0): else: _winmouse.move_to(x, y) - def move(x, y, absolute: bool = True, randomize: Union[int, Tuple[int, int]] = 5, delay_factor: Tuple[float, float] = [0.9, 1.1]): + def move(x, y, absolute: bool = True, randomize: int | tuple[int, int] = 5, delay_factor: tuple[float, float] = [0.4, 0.6]): from_point = _mouse.get_position() dist = math.dist((x, y), from_point) offsetBoundaryX = max(10, int(0.08 * dist)) @@ -262,7 +261,7 @@ def move(x, y, absolute: bool = True, randomize: Union[int, Tuple[int, int]] = 5 def _is_clicking_safe(): # Because of reports that botty lost equiped items, let's check if the inventory is open, and if it is, restrict the mouse move mouse_pos = screen.convert_monitor_to_screen(_mouse.get_position()) - is_inventory_open = TemplateFinder().search( + is_inventory_open = template_finder.search( "INVENTORY_GOLD_BTN", screen.grab(), threshold=0.8, diff --git a/src/utils/dclone_ip.py b/src/utils/dclone_ip.py deleted file mode 100644 index 8b4d047ab..000000000 --- a/src/utils/dclone_ip.py +++ /dev/null @@ -1,52 +0,0 @@ -import psutil -from config import Config -from messages import Messenger - -def get_d2r_game_ip(): - blacklist_ip = ["127.0.0.1", "34.117", "137.221", "37.244", "117.52"] - region_ips = [] - for tmp in Config().dclone["region_ips"].split(","): - region_ips.append(tmp.strip()) - for proc in psutil.process_iter(): - if proc.name() == "D2R.exe": - D2R_pid = proc.pid - for connection in psutil.net_connections(): - if connection.status == "ESTABLISHED" and connection.pid == D2R_pid and connection.raddr[1] == 443: - if not any(tmp in connection.raddr[0] for tmp in blacklist_ip): - return connection.raddr[0] - if any(tmp in connection.raddr[0] for tmp in region_ips): - return connection.raddr[0] - return "Unknown game server" - -def get_d2r_game_server_region_by_ip(ip): - us_server = ["158.115.222", "158.115.221"] - eu_server = ["37.244.11", "37.244.48"] - asia_server = ["34.92"] - asia_mumbai = ["34.93", "35.200", "35.244"] - us_sao_paolo = ["34.95", "35.198", "35.199", "35.247"] - asia_jakarta = ["34.101"] - if any(tmp in ip for tmp in us_server): - return "Us Server" - if any(tmp in ip for tmp in eu_server): - return "Eu Server" - if any(tmp in ip for tmp in asia_mumbai): - return "Asia Mumbai Server" - if any(tmp in ip for tmp in us_sao_paolo): - return "Us Sao Paolo Server" - if any(tmp in ip for tmp in asia_jakarta): - return "Asia Jakarta Server" - if any(tmp in ip for tmp in asia_server): - return "Asia Server" - if ip == "Unknown game server": - return "Unknown Server" - else: - return "Blizzard Server" - -if __name__ == "__main__": - messenger = Messenger() - if Config().dclone["region_ips"] != "" and Config().dclone["dclone_hotip"] != "": - print(f"Current Game IP: {get_d2r_game_ip()}") - print(f"Current Game Server: {get_d2r_game_server_region_by_ip(get_d2r_game_ip())}") - messenger.send_message(f"Dclone IP Found on {get_d2r_game_server_region_by_ip(get_d2r_game_ip())} on IP: {get_d2r_game_ip()}") - else: - print(f"Please Enter the region ip and hot ip on config to use") \ No newline at end of file diff --git a/src/utils/diablo_log_parser.py b/src/utils/diablo_log_parser.py index b7037022b..59f6f4e5c 100644 --- a/src/utils/diablo_log_parser.py +++ b/src/utils/diablo_log_parser.py @@ -9,10 +9,10 @@ #initialize strings simple_string = [ - "Run Diablo", + "Run Diablo", "ROF: Calibrated at WAYPOINT", - "ROF: Teleporting directly to PENTAGRAM", - + "ROF: Teleporting directly to PENTAGRAM", + "ROF: Teleporting to CS ENTRANCE", "CS Trash: Calibrated at CS ENTRANCE", "CS Trash: Starting to clear Trash", @@ -23,7 +23,7 @@ "CS Trash (A): Layout_check step 1/2", "CS Trash (A): Layout_check step 2/2", "CS Trash (A): Layout_check failed", - + "CS Trash (A): clearing second hall (1/3)", "CS Trash (A): clearing second hall (2/3)", "CS Trash (A): clearing second hall (3/3)", @@ -40,11 +40,11 @@ "CS Trash (B): clearing third hall (1/1)", - "CS Trash: looping to PENTAGRAM", - "CS: Calibrated at PENTAGRAM", + "CS Trash: looping to PENTAGRAM", + "CS: Calibrated at PENTAGRAM", "CS: OPEN TP", "CS: failed to open TP", - + "CS TRASH: A Pent to LC", "CS TRASH: A looping to PENTAGRAM", "CS TRASH: A calibrated at PENTAGRAM", @@ -57,15 +57,15 @@ "CS TRASH: C looping to PENTAGRAM", "CS TRASH: C calibrated at PENTAGRAM", - "Checking Layout for Vizier", - "Checking Layout for De Seis", - "Checking Layout for Infector", - - "Waiting for Diablo to spawn", - - "End game", - "End failed game", - "Trying to chicken", + "Checking Layout for Vizier", + "Checking Layout for De Seis", + "Checking Layout for Infector", + + "Waiting for Diablo to spawn", + + "End game", + "End failed game", + "Trying to chicken", "You have died", "Shrine found, activating it", @@ -85,13 +85,13 @@ lc_prefix=["Found Match:"] lc_event=[ 'DIA_NEW_PENT_0', 'DIA_NEW_PENT_1', 'DIA_NEW_PENT_TP', 'DIA_NEW_PENT_2', - "DIA_A2Y_LAYOUTCHECK0", "DIA_A2Y_LAYOUTCHECK1", "DIA_A2Y_LAYOUTCHECK2", "DIA_A2Y_LAYOUTCHECK4", "DIA_A2Y_LAYOUTCHECK5", "DIA_A2Y_LAYOUTCHECK6", - "DIA_A1L_LAYOUTCHECK0", "DIA_A1L_LAYOUTCHECK4", "DIA_A1L_LAYOUTCHECK4LEFT", "DIA_A1L_LAYOUTCHECK1", "DIA_A1L_LAYOUTCHECK2", "DIA_A1L_LAYOUTCHECK3","DIA_A1L_LAYOUTCHECK4RIGHT","DIA_A1L_LAYOUTCHECK5", - "DIA_B1S_BOSS_CLOSED_LAYOUTCHECK1", "DIA_B1S_BOSS_CLOSED_LAYOUTCHECK2", "DIA_B1S_BOSS_CLOSED_LAYOUTCHECK3", - "DIA_B2U_LAYOUTCHECK2", "DIA_B2U_LAYOUTCHECK1", "DIA_B2U_LAYOUTCHECK2SMALL","DIA_B2U_LAYOUTCHECK3", "DIA_B2U_LAYOUTCHECK4", "DIA_B2U_LAYOUTCHECK5","DIA_B2U_LAYOUTCHECK6","DIA_B2U_LAYOUTCHECK7","DIA_B2U_LAYOUTCHECK8","DIA_B2U_LAYOUTCHECK9", - "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK1", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK4", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK5", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK2", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK3", + "DIA_A2Y_LAYOUTCHECK0", "DIA_A2Y_LAYOUTCHECK1", "DIA_A2Y_LAYOUTCHECK2", "DIA_A2Y_LAYOUTCHECK4", "DIA_A2Y_LAYOUTCHECK5", "DIA_A2Y_LAYOUTCHECK6", + "DIA_A1L_LAYOUTCHECK0", "DIA_A1L_LAYOUTCHECK4", "DIA_A1L_LAYOUTCHECK4LEFT", "DIA_A1L_LAYOUTCHECK1", "DIA_A1L_LAYOUTCHECK2", "DIA_A1L_LAYOUTCHECK3","DIA_A1L_LAYOUTCHECK4RIGHT","DIA_A1L_LAYOUTCHECK5", + "DIA_B1S_BOSS_CLOSED_LAYOUTCHECK1", "DIA_B1S_BOSS_CLOSED_LAYOUTCHECK2", "DIA_B1S_BOSS_CLOSED_LAYOUTCHECK3", + "DIA_B2U_LAYOUTCHECK2", "DIA_B2U_LAYOUTCHECK1", "DIA_B2U_LAYOUTCHECK2SMALL","DIA_B2U_LAYOUTCHECK3", "DIA_B2U_LAYOUTCHECK4", "DIA_B2U_LAYOUTCHECK5","DIA_B2U_LAYOUTCHECK6","DIA_B2U_LAYOUTCHECK7","DIA_B2U_LAYOUTCHECK8","DIA_B2U_LAYOUTCHECK9", + "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK1", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK4", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK5", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK2", "DIA_C2G_BOSS_CLOSED_LAYOUTCHECK3", "DIA_C1F_LAYOUTCHECK1", "DIA_C1F_LAYOUTCHECK2", "DIA_C1F_LAYOUTCHECK3", - "DIABLO_ENTRANCE_12", "DIABLO_ENTRANCE_13", "DIABLO_ENTRANCE_15", "DIABLO_ENTRANCE_16", "DIABLO_ENTRANCE_19", "DIABLO_ENTRANCE_18","DIABLO_ENTRANCE_50", "DIABLO_ENTRANCE_51", "DIABLO_ENTRANCE_52", "DIABLO_ENTRANCE_53", "DIABLO_ENTRANCE_54", "DIABLO_ENTRANCE_55", + "DIABLO_ENTRANCE_12", "DIABLO_ENTRANCE_13", "DIABLO_ENTRANCE_15", "DIABLO_ENTRANCE_16", "DIABLO_ENTRANCE_19", "DIABLO_ENTRANCE_18","DIABLO_ENTRANCE_50", "DIABLO_ENTRANCE_51", "DIABLO_ENTRANCE_52", "DIABLO_ENTRANCE_53", "DIABLO_ENTRANCE_54", "DIABLO_ENTRANCE_55", "DIABLO_ENTRANCE2_15", "DIABLO_ENTRANCE2_23", "DIABLO_ENTRANCE2_19", "DIABLO_ENTRANCE2_17", "DIABLO_ENTRANCE2_50", "DIABLO_ENTRANCE2_51", "DIABLO_ENTRANCE2_52","DIABLO_ENTRANCE2_53","DIABLO_ENTRANCE2_54","DIABLO_ENTRANCE2_55","DIABLO_ENTRANCE2_56" ] error_string = ["End failed game"] @@ -104,7 +104,7 @@ #initialize counter simple_counter = numpy.zeros (len (simple_string)+1) complex_counter = numpy.zeros ((len (prefix_string)+1, len (complex_string)+1)) -lc_counter = numpy.zeros ((len (lc_prefix)+1, len (lc_event)+1)) +lc_counter = numpy.zeros ((len (lc_prefix)+1, len (lc_event)+1)) layout_check_counter = 0 #check where layoutcheck 2/2 is @@ -114,7 +114,7 @@ layout_check_counter += 1 #open file and gather information line by line -log_str = wkdir + "/info.log" +log_str = wkdir + "/log/log.txt" log_file = open (log_str, "r") log_lines = log_file.readlines () traverse_line = 0 @@ -128,10 +128,10 @@ prefix_counter = 0 lc_cl_counter = 0 #check simple strings - for string in simple_string: + for string in simple_string: if string in line: simple_counter [simple_item_counter] += 1 - break + break simple_item_counter += 1 #check concat strings for prefix in prefix_string: @@ -239,7 +239,7 @@ table4.columns.alignment["TEMPLATES CHECKED"] = BeautifulTable.ALIGN_LEFT result_file.write (str (table4)) result_file.write ("\n") - + result_file.write ("\n") result_file.write ("\n") result_file.write ("========================================================\n") @@ -265,6 +265,6 @@ result_file.write (line) Logger.info ("=================================================================================================") -Logger.info ("Parsed info.log - results & details for failed runs stored in " + str(result_file) + " in botty root folder") +Logger.info ("Parsed log/log.txt - results & details for failed runs stored in " + str(result_file) + " in botty root folder") Logger.info ("=================================================================================================") -#Logger.info ("\n" + str(table1)) \ No newline at end of file +#Logger.info ("\n" + str(table1)) \ No newline at end of file diff --git a/src/utils/download_test_assets.py b/src/utils/download_test_assets.py new file mode 100644 index 000000000..04a7c2e47 --- /dev/null +++ b/src/utils/download_test_assets.py @@ -0,0 +1,22 @@ +import urllib.request +import zipfile +import os +import shutil + +url = "https://github.com/bottytools/botty-test-assets/archive/refs/heads/main.zip" +extract_dir = "tmp" +asset_dir = "test/assets" + +if not os.path.exists(asset_dir): + print(f"Downloading test assets...") + try: + zip_path, _ = urllib.request.urlretrieve(url) + print(f"Extracting {zip_path}...") + with zipfile.ZipFile(zip_path, "r") as f: + f.extractall(extract_dir) + shutil.move(f"{extract_dir}/botty-test-assets-main/assets", asset_dir) + shutil.rmtree(f"{extract_dir}") + os.remove(zip_path) + print(f"Download complete, delete {zip_path}") + except: + print(f"Could not retrieve test assets...") diff --git a/src/utils/gen_ocr_samples.py b/src/utils/gen_ocr_samples.py index 1ec3314df..b281b54b7 100644 --- a/src/utils/gen_ocr_samples.py +++ b/src/utils/gen_ocr_samples.py @@ -10,9 +10,8 @@ class GenOcrTruth: def __init__(self): - if not os.path.exists("generated"): - os.system("mkdir generated") - os.system(f"cd generated && mkdir ground-truth") + os.makedirs("log/screenshots/generated", exist_ok=True) + os.system(f"cd log/screenshots/generated && mkdir ground-truth") self._half_width = Config().ui_pos["screen_width"] // 2 self._half_height = Config().ui_pos["screen_height"] // 2 self._upper_left = None @@ -43,7 +42,7 @@ def hook(self, e): width = (bottom_right[0] - self._upper_left[0]) height = (bottom_right[1] - self._upper_left[1]) template_img = cut_roi(img, [*self._upper_left, width, height]) - basename = f"generated/ground-truth/{time.strftime('%Y%m%d_%H%M%S')}" + basename = f"log/screenshots/generated/ground-truth/{time.strftime('%Y%m%d_%H%M%S')}" cv2.imshow(time.strftime('%Y%m%d_%H%M%S'), template_img) cv2.waitKey(1) print(f"new template: {basename} = ") diff --git a/src/utils/graphic_debugger.py b/src/utils/graphic_debugger.py index a1b25a78f..33dff0d41 100644 --- a/src/utils/graphic_debugger.py +++ b/src/utils/graphic_debugger.py @@ -6,10 +6,9 @@ from utils import mttkinter from utils.misc import color_filter, kill_thread from screen import grab -from item import ItemFinder from config import Config import tkinter as tk -from template_finder import TemplateFinder +import template_finder from PIL import ImageTk, Image import re @@ -26,7 +25,6 @@ class GraphicDebuggerController: window_name_images = "Graphic Debugger - Images" def __init__(self): - self.item_finder = None self.debugger_thread = None self.ui_thread = None self.app = None @@ -39,7 +37,6 @@ def __init__(self): self.is_running = False def start(self): - self.item_finder = ItemFinder() if Config().advanced_options['graphic_debugger_layer_creator']: self.debugger_thread = threading.Thread(target=self.run_debugger_processor, daemon=False, name="Debugger-processor") self.debugger_thread.start() @@ -74,7 +71,6 @@ def run_debgger_ui(self): ########### Variables ########### self.display_only_current_layer = tk.IntVar(value=0) - self.item_finder_enabled = tk.IntVar(value=1) self.h_l = tk.IntVar(value=0) self.s_l = tk.IntVar(value=0) self.v_l = tk.IntVar(value=0) @@ -140,11 +136,6 @@ def run_debgger_ui(self): variable=self.display_only_current_layer, command=self.update_displayed_layers) display_only_current_layer_button.grid(column=0, row=7, sticky=tk.N+tk.W) - enable_item_finder_button = tk.Checkbutton( - frame, - text="Enable Item Finder (performance will be impacted)", - variable=self.item_finder_enabled) - enable_item_finder_button.grid(column=0, row=8, sticky=tk.N+tk.W) self.update_text_box() frame.grid(column=3, row=0) @@ -287,25 +278,6 @@ def run_debugger_processor(self): mask, filtered_img = color_filter(img, layer) combined_img = cv2.bitwise_or(filtered_img, combined_img) - # Show item detections - if self.item_finder_enabled.get(): - item_list = self.item_finder.search(img) - for item in item_list: - cv2.circle(combined_img, item.center, 7, (0, 0, 255), 4) - cv2.putText(combined_img, item.name, item.center, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA) - if len(item_list) > 0: - print(item_list) - # Show Town A5 template matches - scores = {} - for template_name in search_templates: - template_match = TemplateFinder().search(template_name, img, threshold=0.65) - if template_match.valid: - scores[template_match.name] = template_match.score - cv2.putText(combined_img, str(template_name), template_match.center, cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) - cv2.circle(combined_img, template_match.center, 7, (255, 0, 0), thickness=5) - if len(scores) > 0: - print(scores) - if self.image_resize_ratio.get() != 1: combined_img = cv2.resize(combined_img, None, fx=self.image_resize_ratio.get(), fy=self.image_resize_ratio.get()) # The processing was done in this thread, now pass it to the ui to display it on the window @@ -315,21 +287,10 @@ def run_old_debugger(self): search_templates = ["A5_TOWN_0", "A5_TOWN_1", "A5_TOWN_2", "A5_TOWN_3"] while 1: img = grab() - # Show item detections - combined_img = np.zeros(img.shape, dtype="uint8") - for key in Config().colors: - _, filterd_img = color_filter(img, Config().colors[key]) - combined_img = cv2.bitwise_or(filterd_img, combined_img) - item_list = self.item_finder.search(img) - for item in item_list: - cv2.circle(combined_img, item.center, 7, (0, 0, 255), 4) - cv2.putText(combined_img, item.name, item.center, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA) - if len(item_list) > 0: - print(item_list) # Show Town A5 template matches scores = {} for template_name in search_templates: - template_match = TemplateFinder().search(template_name, img, threshold=0.65) + template_match = template_finder.search(template_name, img, threshold=0.65) if template_match.valid: scores[template_match.name] = template_match.score cv2.putText(combined_img, str(template_name), template_match.center, cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) diff --git a/src/utils/item_extractor.py b/src/utils/item_extractor.py deleted file mode 100644 index ed983f214..000000000 --- a/src/utils/item_extractor.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Script to autocrop items. Input image with items in the correct resolution and the script will auto crop it for you and ask for names for each of them. -""" -import argparse -import os -import cv2 -import numpy as np - -from item.item_cropper import ItemCropper -import time - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Script to autocrop items.") - parser.add_argument("--file_path", type=str, help="Path to screenshots e.g. C:/data") - args = parser.parse_args() - - args.file_path = "C:\\Users\\aliig\\Desktop\\bot\\botty-gleed-ocr\\input_images" - gen_truth = 1 - - item_cropper = ItemCropper() - - for filename in os.listdir(args.file_path): - if filename.endswith(".png"): - start = time.time() - inp_img = cv2.imread(f"{args.file_path}\\{filename}") - filename = filename[:-4] - img = inp_img[:,:,:] - img_clean = item_cropper.clean_img(img) - item_clusters = item_cropper.crop(img) - for count, cluster in enumerate(item_clusters): - x, y, w, h = cluster.roi - key = cluster.color_key - if gen_truth: - cv2.namedWindow("item") - cv2.moveWindow("item", 100, 100) - cv2.imshow("item", img_clean[y:y+h, x:x+w]) - cv2.waitKey(1) - print(f"{count} Input item name and press enter (converts to all caps)...") - item_name = input() - if item_name != "": - out_filename = f"{key}_{item_name.replace(' ','_')}" - if not os.path.exists(f"./ground_truth/{out_filename}.png"): - cv2.imwrite(f"./ground_truth/{out_filename}.png", img_clean[y:y+h, x:x+w]) - file1 = open(f"./ground_truth/{out_filename}.gt.txt","w") - file1.write(item_name.upper()) - file1.close() - else: - print("Skipping") - time.sleep(0.1) - cv2.destroyAllWindows() - else: - avg = int(np.average(cv2.cvtColor(cluster.data, cv2.COLOR_BGR2GRAY))) - cv2.imwrite(f"./generated/z_{filename}_{key}_{count}_{avg}.png", cluster.data) - cv2.rectangle(inp_img, (x, y), (x+w, y+h), (0, 255, 0), 1) - cv2.putText(inp_img, key, (x+5, y+5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA) - - finish=time.time() - print(f"{filename} total: {finish-start}s") - cv2.imwrite(f"./generated/{filename}.png", inp_img) diff --git a/src/utils/misc.py b/src/utils/misc.py index 881e2eecc..68827647e 100644 --- a/src/utils/misc.py +++ b/src/utils/misc.py @@ -1,17 +1,17 @@ from dataclasses import dataclass from decimal import InvalidOperation -from re import RegexFlag import time import random import ctypes import numpy as np from copy import deepcopy +import unicodedata +import re from pyparsing import Regex from logger import Logger import cv2 -from typing import List, Tuple, Union import os from math import cos, sin, dist import subprocess @@ -21,6 +21,8 @@ from win32process import GetWindowThreadProcessId import psutil +from rapidfuzz.process import extractOne +from rapidfuzz.string_metric import levenshtein def close_down_d2(): subprocess.call(["taskkill","/F","/IM","D2R.exe"], stderr=subprocess.DEVNULL) @@ -30,8 +32,8 @@ def close_down_bnet_launcher(): @dataclass class WindowSpec: - title_regex: 'Union[str, None]' = None - process_name_regex: 'Union[str, None]' = None + title_regex: 'str | None' = None + process_name_regex: 'str | None' = None def match(self, hwnd) -> bool: result = True @@ -107,7 +109,7 @@ def mask_by_roi(img, roi, type: str = "regular"): return None return masked -def is_in_roi(roi: List[float], pos: Tuple[float, float]): +def is_in_roi(roi: list[float], pos: tuple[float, float]): x, y, w, h = roi is_in_x_range = x < pos[0] < x + w is_in_y_range = y < pos[1] < y + h @@ -180,15 +182,16 @@ def hms(seconds: int): s = seconds % 3600 % 60 return '{:02d}:{:02d}:{:02d}'.format(h, m, s) -def load_template(path, scale_factor: float = 1.0, alpha: bool = False): +def load_template(path): if os.path.isfile(path): try: - template_img = cv2.imread(path, cv2.IMREAD_UNCHANGED) if alpha else cv2.imread(path) - template_img = cv2.resize(template_img, None, fx=scale_factor, fy=scale_factor, interpolation=cv2.INTER_NEAREST) + template_img = cv2.imread(path, cv2.IMREAD_UNCHANGED) return template_img except Exception as e: print(e) raise ValueError(f"Could not load template: {path}") + else: + Logger.error(f"Template does not exist: {path}") return None def alpha_to_mask(img: np.ndarray): @@ -220,8 +223,8 @@ def image_is_equal(img1: np.ndarray, img2: np.ndarray) -> bool: Logger.debug("image_is_equal: Image shape is not equal") return False return not(np.bitwise_xor(img1, img2).any()) - -def arc_spread(cast_dir: Tuple[float,float], spread_deg: float=10, radius_spread: Tuple[float, float] = [.95, 1.05]): + +def arc_spread(cast_dir: tuple[float,float], spread_deg: float=10, radius_spread: tuple[float, float] = [.95, 1.05]): """ Given an x,y vec (target), generate a new target that is the same vector but rotated by +/- spread_deg/2 """ @@ -232,6 +235,34 @@ def arc_spread(cast_dir: Tuple[float,float], spread_deg: float=10, radius_spread return rotate_vec(unit_vector(cast_dir)*(length+adj), rot) -# if __name__ == "__main__": - # print(find_d2r_window()) - # print(find_d2r_window()) \ No newline at end of file +@dataclass +class BestMatchResult: + match: str + score: float + score_normalized: float + +def find_best_match(in_str: str, str_list: list[str]) -> BestMatchResult: + best_match, best_lev, _ = extractOne(in_str, str_list, scorer=levenshtein) + best_lev_normalized = 1 - best_lev / max(1, len(in_str)) + return BestMatchResult(best_match, best_lev, best_lev_normalized) + +def slugify(value, allow_unicode=False): + """ + Taken from https://github.com/django/django/blob/master/django/utils/text.py + Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated + dashes to single dashes. Remove characters that aren't alphanumerics, + underscores, or hyphens. Convert to lowercase. Also strip leading and + trailing whitespace, dashes, and underscores. + """ + value = str(value) + if allow_unicode: + value = unicodedata.normalize('NFKC', value) + else: + value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii') + value = re.sub(r'[^\w\s-]', '', value.lower()) + return re.sub(r'[-\s]+', '-', value).strip('-_') + +def only_lowercase_letters(value): + if not (x := ''.join(filter( lambda x: x in 'abcdefghijklmnopqrstuvwxyz', value ))): + x = "botty" + return x \ No newline at end of file diff --git a/src/utils/node_recorder.py b/src/utils/node_recorder.py index e8e7a798d..31f92471a 100644 --- a/src/utils/node_recorder.py +++ b/src/utils/node_recorder.py @@ -1,28 +1,27 @@ -from screen import grab, convert_monitor_to_screen, convert_abs_to_screen +from screen import grab, convert_monitor_to_screen, convert_abs_to_screen, convert_screen_to_abs import cv2 from config import Config -from template_finder import TemplateFinder +import template_finder from utils.misc import load_template, cut_roi import mouse import keyboard import os import shutil from pathlib import Path -from typing import Tuple import math class NodeRecorder: def __init__(self, run_name): - if os.path.exists("generated"): - for path in Path("generated").glob("**/*"): + if os.path.exists("log/screenshots/generated"): + for path in Path("log/screenshots/generated").glob("**/*"): if path.is_file(): os.remove(path) elif path.is_dir(): shutil.rmtree(path) - shutil.rmtree("generated") - os.system("mkdir generated") - os.system(f"cd generated && mkdir templates && cd templates && mkdir {run_name} && cd {run_name} && mkdir nodes") + shutil.rmtree("log/screenshots/generated") + os.makedirs("log/screenshots/generated", exist_ok=True) + os.system(f"cd log/screenshots/generated && mkdir templates && cd templates && mkdir {run_name} && cd {run_name} && mkdir nodes") self._run_name = run_name self._offset = 100 self._template_counter = 0 @@ -30,8 +29,8 @@ def __init__(self, run_name): self._half_height = Config().ui_pos["screen_height"] // 2 self._curr_state = 0 self._upper_left = None - TemplateFinder()._templates = {} - self._pather_code_file = "generated/pather_generated.py" + template_finder._templates = {} + self._pather_code_file = "log/screenshots/generated/pather_generated.py" self.ref_points = {} self.nodes = {} self.debug_node_pos = {} @@ -39,13 +38,13 @@ def __init__(self, run_name): print("1 - Select top-left corner and press f8") @staticmethod - def _convert_rel_to_abs(rel_loc: Tuple[float, float], pos_abs: Tuple[float, float]) -> Tuple[float, float]: + def _convert_rel_to_abs(rel_loc: tuple[float, float], pos_abs: tuple[float, float]) -> tuple[float, float]: return (rel_loc[0] + pos_abs[0], rel_loc[1] + pos_abs[1]) def find_templates(self, img): ref_points = {} - for key in TemplateFinder()._templates: - found = TemplateFinder().search(key, img, use_grayscale=False, threshold=0.77) + for key in template_finder._templates: + found = template_finder.search(key, img, use_grayscale=False, threshold=0.77) if found.valid: ref_points[key] = found.center return ref_points @@ -73,11 +72,11 @@ def hook(self, e): self._template_counter += 1 # save as png template_img = cut_roi(img, [*self._upper_left, width, height]) - template_path = f"generated/templates/{self._run_name}/{ref_point_name}.png" + template_path = f"log/screenshots/generated/templates/{self._run_name}/{ref_point_name}.png" cv2.imwrite(template_path, template_img) self._upper_left = None - template_img = load_template(template_path, 1.0, False) - TemplateFinder()._templates[ref_point_name] = [template_img, cv2.cvtColor(template_img, cv2.COLOR_BGRA2GRAY), 1.0, None] + template_img = load_template(template_path) + template_finder._templates[ref_point_name] = [template_img, cv2.cvtColor(template_img, cv2.COLOR_BGRA2GRAY), 1.0, None] elif e.name == "f7": self.ref_points = {} else: diff --git a/src/utils/restart.py b/src/utils/restart.py index 7374bae09..9c7b3f7d3 100644 --- a/src/utils/restart.py +++ b/src/utils/restart.py @@ -1,11 +1,11 @@ -import subprocess import os, sys import keyboard -from bot import Bot -from template_finder import TemplateFinder +import subprocess + +import template_finder from utils.misc import wait, set_d2r_always_on_top from screen import get_offset_state, grab -from config import Config +from ui.main_menu import MAIN_MENU_MARKERS def process_exists(process_name): @@ -17,19 +17,23 @@ def process_exists(process_name): # because Fail message could be translated return last_line.lower().startswith(process_name.lower()) +def safe_exit(error_code=0): + kill_game() + os._exit(error_code) + def kill_game(): while process_exists("D2R.exe"): os.system("taskkill /f /im BlizzardError.exe") os.system("taskkill /f /im D2R.exe") wait(1.0, 1.5) -def restart_game(d2_path): +def restart_game(d2r_path, launch_options): kill_game() wait(1.0, 1.5) # This method should function similar to opening the exe via double-click - os.startfile(f"{d2_path}/D2R.exe") + os.startfile(f"{d2r_path}/D2R.exe", arguments = launch_options) wait(4.4, 5.5) - for i in range(20): + for _ in range(20): keyboard.send("space") wait(0.5, 1.0) success = False @@ -39,8 +43,7 @@ def restart_game(d2_path): success = get_offset_state() wait(0.5, 1.0) - - while not TemplateFinder().search(Bot._MAIN_MENU_MARKERS, grab(), best_match=True).valid: + while not template_finder.search(MAIN_MENU_MARKERS, grab(), best_match=True).valid: keyboard.send("space") wait(2.0, 4.0) attempts += 1 diff --git a/src/version.py b/src/version.py index 0818dbaea..e06ec96ea 100644 --- a/src/version.py +++ b/src/version.py @@ -1 +1 @@ -__version__ = '0.7.3-dev' +__version__ = '0.8.1-dev' \ No newline at end of file diff --git a/test/assets/hero_select.png b/test/assets/hero_select.png deleted file mode 100644 index d79cbaf4a..000000000 Binary files a/test/assets/hero_select.png and /dev/null differ diff --git a/test/assets/item_finder.png b/test/assets/item_finder.png deleted file mode 100644 index ff3514f83..000000000 Binary files a/test/assets/item_finder.png and /dev/null differ diff --git a/test/assets/mobs.png b/test/assets/mobs.png deleted file mode 100644 index 4fe642122..000000000 Binary files a/test/assets/mobs.png and /dev/null differ diff --git a/test/assets/mobs_no_green_or_blue.png b/test/assets/mobs_no_green_or_blue.png deleted file mode 100644 index 9b2473db9..000000000 Binary files a/test/assets/mobs_no_green_or_blue.png and /dev/null differ diff --git a/test/assets/stash_slot_cross.png b/test/assets/stash_slot_cross.png deleted file mode 100644 index 67c30296c..000000000 Binary files a/test/assets/stash_slot_cross.png and /dev/null differ diff --git a/test/assets/stash_slot_empty.png b/test/assets/stash_slot_empty.png deleted file mode 100644 index 92948a154..000000000 Binary files a/test/assets/stash_slot_empty.png and /dev/null differ diff --git a/test/assets/stash_slot_slash.png b/test/assets/stash_slot_slash.png deleted file mode 100644 index cc6567d1d..000000000 Binary files a/test/assets/stash_slot_slash.png and /dev/null differ diff --git a/test/assets/stash_slots.png b/test/assets/stash_slots.png deleted file mode 100644 index bcf8abd80..000000000 Binary files a/test/assets/stash_slots.png and /dev/null differ diff --git a/test/closest_non_hud_test.py b/test/closest_non_hud_test.py new file mode 100644 index 000000000..f05e5962c --- /dev/null +++ b/test/closest_non_hud_test.py @@ -0,0 +1,20 @@ +import pytest +import screen +from ui_manager import get_closest_non_hud_pixel + + +@pytest.mark.parametrize("pos, pos_type, should_adapt", [ + ((40, 40), "screen", True), # over merc portrait + ((1241, 19), "screen", True), # over clock + ((291, 663), "screen", True), # over health globe + ((650, 300), "screen", False), # mid screen + ((783, 618), "screen", True), # over active skill bar + ((1062, 594), "screen", True), # over gargoyle + ((0, 0), "abs", False), # mid screen + ((221, 327), "abs", True), # near right skill +]) +def test_get_closest_non_hud_pixel(pos, pos_type, should_adapt): + screen.set_window_position(0, 0) + new_pos = get_closest_non_hud_pixel(pos, pos_type) + is_adapted = not (pos == new_pos) + assert(is_adapted == should_adapt) \ No newline at end of file diff --git a/test/config_test.py b/test/config_test.py deleted file mode 100644 index e856b9249..000000000 --- a/test/config_test.py +++ /dev/null @@ -1,34 +0,0 @@ -import pytest -import os -import sys -sys.path.append (os.getcwd () + "/src") -from config import Config - -class TestConfig: - @pytest.mark.parametrize ("string, pickit_type, include, exclude, include_type", - [ - ("0",0, [], [], "OR"), ("1",1, [], [], "OR"), ("2",2, [], [], "OR"), - ("1, (AMAZONSKILLER, ASSASINSKILLER, BARBARIANSKILLER, DRUIDSKILLER, NECROMANCERSKILLER, PALADINSKILLER, SORCERESSSKILLER, (LIFE, 3_MAXIMUM_DAMAGE, ATTACK_RATING))", - 1, - [["AMAZONSKILLER"], ["ASSASINSKILLER"], ["BARBARIANSKILLER"], ["DRUIDSKILLER"], ["NECROMANCERSKILLER"], ["PALADINSKILLER"], ["SORCERESSSKILLER"], ["LIFE", "3_MAXIMUM_DAMAGE", "ATTACK_RATING"]], - [], - "OR" - ), - ( - "1, AND(15_INCREASED_ATTACK_SPEED, ENHANCED_DAMAGE)", 1, [["15_INCREASED_ATTACK_SPEED"], ["ENHANCED_DAMAGE"]], [],"AND"), - ("1, SOCKETED_4, ETHEREAL", 1, [["SOCKETED_4"]], [["ETHEREAL"]], "OR"), - ("1, 2_ASSASIN_SKILLS", 1, [["2_ASSASIN_SKILLS"]], [], "OR"), - ("1, ENHANCED_DEFENSE, ETHEREAL", 1, [["ENHANCED_DEFENSE"]], [["ETHEREAL"]], "OR"), - ("1, AND(LIGHTNING_RESIST, FIRE_RESIST, COLD_RESIST), ETHEREAL", 1, [["LIGHTNING_RESIST"], ["FIRE_RESIST"], ["COLD_RESIST"]], [["ETHEREAL"]], "AND"), - ("1, AND(ENHANCED_DEFENSE, SOCKETED), (SOCKETED_1, SOCKETED_2)", 1, [["ENHANCED_DEFENSE"], ["SOCKETED"]], [["SOCKETED_1"], ["SOCKETED_2"]],"AND") - ]) - def test_string_to_item_prop (self, string, pickit_type, include, exclude, include_type): - Itemprops = Config().string_to_item_prop (string) - assert (Itemprops.pickit_type == pickit_type) - assert (Itemprops.include == include) - assert (Itemprops.exclude == exclude) - assert (Itemprops.include_type == include_type) - - def test_123 (self): - print (os.getcwd()) - print (sys.path) \ No newline at end of file diff --git a/test/game_stats_test.py b/test/game_stats_test.py index a5f11600b..e82195840 100644 --- a/test/game_stats_test.py +++ b/test/game_stats_test.py @@ -11,11 +11,11 @@ def setup_method(self): self.game_stats = GameStats() @pytest.mark.parametrize("item_name, item_should_be_added", [ - ("some_magic_item", True), - ("misc_jewel", True), - ("misc_gold", False), - ("some_potion", False), - ("super_healing_potion", False), + ("MAGIC ITEM", True), + ("JEWEL", True), + ("GREATER HEALING POTION", False), + ("CHIPPED SKULL", False), + ("FLAWLESS SKULL", False), ]) def test_log_item_keep(self, item_name: str, item_should_be_added: bool): self.game_stats.update_location("test_location") diff --git a/test/item/item_finder_test.py b/test/item/item_finder_test.py deleted file mode 100644 index 6a7e530c1..000000000 --- a/test/item/item_finder_test.py +++ /dev/null @@ -1,28 +0,0 @@ -import pytest -import numpy as np -import cv2 -from logger import Logger -from item.item_finder import ItemFinder, Item -from config import Config, ItemProps - - -class TestItemFinder: - def setup_method(self): - Logger.init() - Logger.remove_file_logger() - - Config().items["misc_flawless_amethyst"] = ItemProps(pickit_type=1) - Config().items["uniq_armor_ormus_robes"] = ItemProps(pickit_type=1) - Config().items["rune_26_vex"] = ItemProps(pickit_type=1) - Config().items["misc_super_healing_potion"] = ItemProps(pickit_type=1) - Config().items["magic_small_charm"] = ItemProps(pickit_type=1) - Config().items["rare_stag_bow"] = ItemProps(pickit_type=1) - self.item_finder = ItemFinder() - - @pytest.mark.parametrize("img_path, expected", [ - ("test/assets/item_finder.png", 6), - ]) - def test_search(self, img_path: str, expected: int): - inp_img = cv2.imread(img_path) - item_list = self.item_finder.search(inp_img) - assert(len(item_list) == expected) diff --git a/test/mocks/screen_mock.py b/test/mocks/screen_mock.py index 3c65edf4e..c58c8003a 100644 --- a/test/mocks/screen_mock.py +++ b/test/mocks/screen_mock.py @@ -1,6 +1,9 @@ import cv2 class ScreenMock(): + def __init__(self, filename): + self._filename = filename + def grab(self): - img = cv2.imread("test/assets/hero_select.png") + img = cv2.imread(self._filename) return img diff --git a/test/nip/common.py b/test/nip/common.py new file mode 100644 index 000000000..ea4156def --- /dev/null +++ b/test/nip/common.py @@ -0,0 +1,40 @@ +from dataclasses import dataclass + +@dataclass +class ExpressionTest: + basename: str = None + expression: str = None + transpiled: str = None + read_json: dict = None + pick_expected: bool = False + keep_expected: bool = False + id_expected: bool = False + +# for when json.dumps() fails... +def pretty_dict(dictionary): + + def _nested(obj, level=1): + indentation_values = "\t" * level + indentation_braces = "\t" * (level - 1) + if isinstance(obj, dict): + return "{\n%(body)s%(indent_braces)s}" % { + "body": "".join("%(indent_values)s\'%(key)s\': %(value)s,\n" % { + "key": str(key), + "value": _nested(value, level + 1), + "indent_values": indentation_values + } for key, value in obj.items()), + "indent_braces": indentation_braces + } + if isinstance(obj, list): + return "[\n%(body)s\n%(indent_braces)s]" % { + "body": "".join("%(indent_values)s%(value)s,\n" % { + "value": _nested(value, level + 1), + "indent_values": indentation_values + } for value in obj), + "indent_braces": indentation_braces + } + else: + return "\'%(value)s\'" % {"value": str(obj)} + + dict_text = _nested(dictionary) + return dict_text \ No newline at end of file diff --git a/test/nip/keep_item_test_cases.py b/test/nip/keep_item_test_cases.py new file mode 100644 index 000000000..40765de47 --- /dev/null +++ b/test/nip/keep_item_test_cases.py @@ -0,0 +1,1046 @@ +BNIP_KEEP_TESTS = { + # monarch + "D2R_0lR7EfbRGT": [ + { + "expression": "[name] == Monarch && [quality] == magic && [flag] != ethereal # [sockets] >= 4 && [toblock] >= 20 && [fbr] >= 30", + "should_keep": True + }, + { + "expression": "[name] == Monarch && [quality] == magic && [flag] != ethereal # [defense] > 150", + "should_keep": False + }, + { + "expression": "[name] == Monarch && [quality] == magic", + "should_keep": True + }, + { + "expression": "[name] == Monarch && [flag] == ethereal", + "should_keep": False + }, + { + "expression": "[type] == anyshield", + "should_keep": True + }, + { + "expression": "[type] == shield", + "should_keep": True + }, + { + "expression": "[type] == assassinclaw", + "should_keep": False + }, + ], + # ettin axe + "D2R_1HfJDuUXhe": [ + { + "expression": "[name] == EttinAxe && [quality] == normal && [flag] == ethereal", + "should_keep": True + }, + { + "expression": "[type] == axe && [quality] == normal && [flag] == ethereal", + "should_keep": True + }, + { + "expression": "[type] == assassinclaw && [quality] == normal && [flag] == ethereal", + "should_keep": False + }, + { + "expression": "[type] == meleeweapon", + "should_keep": True + }, + ], + # rare bec-de-corbin + "D2R_1ZMKfTQO7Q": [ + { + "expression": "[name] == BecdeCorbin && [quality] == rare && [flag] != ethereal # [enhanceddamage] >= 61 && [tohit] >= 71 && [lightresist] >= 8 && [plusmindamage] >= 18 && [manaleech] >= 9 && [itemchargedskill] == 126", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [enhanceddamage] >= 61", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [tohit] >= 71", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [plusmindamage] >= 18", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [manaleech] >= 9", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [enhanceddamage] >= 65", + "should_keep": False + }, + { + "expression": "[name] == BecdeCorbin # [lightresist] >= 8", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [itemchargedskill] == 126", + "should_keep": True + }, + { + "expression": "[name] == BecdeCorbin # [itemchargedskill] == 127", + "should_keep": False + }, + ], + # white phase blade + "D2R_3BGDpVHQQS": [ + { + "expression": "[name] == PhaseBlade && [quality] == normal && [flag] != ethereal", + "should_keep": True + }, + { + "expression": "[name] == PhaseBlade && [quality] == normal && [flag] == ethereal", + "should_keep": False + }, + { + "expression": "[name] == PhaseBlade && [quality] == normal", + "should_keep": True + }, + { + "expression": "[name] == PhaseBlade", + "should_keep": True + }, + { + "expression": "[type] == shield", + "should_keep": False + }, + ], + # shako + "D2R_4IPy7u4fwt": [ + { + "expression": "[Name] == Shako && [quality] == unique && [flag] != ethereal", + "should_keep": True + }, + { + "expression": "[Name] == Shako && [quality] == unique # [itemmagicbonus] > 51", + "should_keep": False + }, + { + "expression": "[Name] == Shako && [quality] == unique # [itemallskills] >= 2", + "should_keep": True + }, + { + "expression": "[Name] == Shako && [quality] == unique # [allstats] >= 2", + "should_keep": True + }, + { + "expression": "[Name] == Shako && [quality] == unique # [strength] == 2 && [dexterity] == 2 && [energy] == 2", + "should_keep": True + }, + { + "expression": "[Name] == Shako && [quality] == unique # [damageresist] == 10", + "should_keep": True + }, + ], + # rare ring + "D2R_5vhnOkej0W": [ + { + "expression": "[name] == Ring && [quality] == rare && [flag] != ethereal # [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 44 && [itemmagicbonus] >= 10 && [lightresist] >= 30 && [dexterity] >= 15 && [fcr] >= 10 && [maxhp] >= 40", + "should_keep": True + }, + { + "expression": "[name] == Ring && [quality] == rare # [itemmagicbonus] >= 10 && [dexterity] >= 15 && [fcr] >= 10 && [maxhp] >= 40", + "should_keep": True + }, + { + "expression": "[name] == Ring && [quality] == rare # [lightresist] >= 30 && [maxhp] >= 40", + "should_keep": True + }, + { + "expression": "[name] == Ring && [quality] == rare && [flag] == ethereal", + "should_keep": False + }, + { + "expression": "[name] == Ring && [quality] == unique", + "should_keep": False + }, + ], + # magic feral claws + "D2R_6AHfXLJO4l": [ + { + "expression": "[name] == FeralClaws && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [ias] >= 40 && [skillLightningSentry] >= 3 && [skillDeathSentry] >= 3 && [skillFade] >= 3", + "should_keep": True + }, + { + "expression": "[name] == FeralClaws && [quality] == magic && [flag] != ethereal", + "should_keep": True + }, + { + "expression": "[name] == FeralClaws # [itemaddskilltab] >= 4", + "should_keep": False + }, + { + "expression": "[name] == FeralClaws && [quality] == magic && [flag] != ethereal # [ias] >= 40", + "should_keep": True + }, + { + "expression": "[name] == FeralClaws && [quality] == magic && [flag] != ethereal # [ias] >= 41", + "should_keep": False + }, + { + "expression": "[type] == assassinclaw && [class] == elite", + "should_keep": True + }, + { + "expression": "[type] == assassinclaw && [class] == exceptional", + "should_keep": False + }, + ], + # rare cantor trophy + "D2R_7CAuD9VcLh": [ + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [itemaddskilltab] >= 2 && [itemarmorperlevel] >= 4 && [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 80 && [itemreplenishdurability] >= 1 && [poisonmindam] >= 13 && [poisonmaxdam] >= 28 && [skillBoneSpirit] >= 3 && [skillBoneSpear] >= 3 && [skillBoneWall] >= 3", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [skillBoneSpear] >= 3 && [skillBoneWall] >= 3", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [itemaddskilltab] >= 2", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [itemreplenishdurability] >= 1", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [poisonmindam] >= 13 && [poisonmaxdam] >= 28", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 80", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [allres] >= 20", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [allres] >= 21", + "should_keep": False + }, + ], + # magic matriarchal spear + "D2R_7ov1FGVkvQ": [ + { + "expression": "[name] == MatriarchalSpear && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 6 && [ias] >= 40", + "should_keep": True + }, + { + "expression": "[type] == amazonspear", + "should_keep": True + }, + ], + # rare arbalest + "D2R_7wqOnPKCxN": [ + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal # [coldmindam] >= 35 && [coldmaxdam] >= 116 && [lightresist] >= 26 && [poisonmindam] >= 150 && [plusmaxdamage] >= 1 && [lightmindam] >= 1 && [lightmaxdam] >= 29 && [itemchargedskill] == 12", + "should_keep": True + }, + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal # [coldmindam] >= 35 && [coldmaxdam] >= 116", + "should_keep": True + }, + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal # [plusmaxdamage] >= 1", + "should_keep": True + }, + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal # [lightmindam] >= 1 && [lightmaxdam] >= 29 && [itemchargedskill] == 12", + "should_keep": True + }, + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal # [itemchargedskill] == 12", + "should_keep": True + }, + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal", + "should_keep": True + }, + { + "expression": "[name] == Arbalest && [quality] == rare && [flag] != ethereal # [poisonmindam] >= 150", + "should_keep": True + }, + ], + # giant thresher eth + "D2R_60FdSnzNbq": [ + { + "expression": "[name] == GiantThresher && [quality] <= superior && [flag] == ethereal", + "should_keep": True + }, + ], + # blue mighty scepter + "D2R_65KHCMvsK6": [ + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [fcr] >= 10 && [skillHolyShock] >= 3 && [skillFistoftheHeavens] >= 3 && [skillConviction] >= 3", + "should_keep": True + }, + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3", + "should_keep": True + }, + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [fcr] >= 10", + "should_keep": True + }, + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [skillHolyShock] >= 3 && [skillFistoftheHeavens] >= 3 && [skillConviction] >= 3", + "should_keep": True + }, + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [skillHolyShock] >= 3", + "should_keep": True + }, + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [skillFistoftheHeavens] >= 3", + "should_keep": True + }, + { + "expression": "[name] == MightyScepter && [quality] == magic && [flag] != ethereal # [skillConviction] >= 3", + "should_keep": True + }, + ], + # riphook + "D2R_a6D8Kmv3uT": [ + { + "expression": "[Name] == Razorbow && [quality] == unique # [enhanceddamage] >= 220 && [lifeleech] >= 10", + "should_keep": True + }, + { + "expression": "[Name] == Razorbow && [quality] == unique # [lifeleech] >= 10", + "should_keep": True + }, + { + "expression": "[Name] == Razorbow && [quality] == unique # [enhanceddamage] >= 220", + "should_keep": True + }, + ], + # white unearthed wand + "D2R_ARmKCSdJnI": [ + { + "expression": "[Name] == UnearthedWand && [quality] == normal && [flag] != ethereal", + "should_keep": True + }, + ], + # chance guards + "D2R_AUakVcxMGp": [ + { + "expression": "[name] == ChainGloves && [quality] == unique # [itemgoldbonus] >= 200 && [itemmagicbonus] >= 40", + "should_keep": True + }, + ], + # rare archon staff + "D2R_bE0gVUl4R7": [ + { + "expression": "[name] == ArchonStaff && [quality] == rare && [flag] != ethereal # [sorceressskills] >= 2 && [maxmana] >= 76 && [itemdamagetomana] >= 10 && [energy] >= 20 && [ias] >= 20 && [fcr] >= 20 && [skillGlacialSpike] >= 3 && [skillFrozenOrb] >= 3 && [skillColdMastery] >= 3", + "should_keep": True + }, + ], + # rare amulet + "D2R_cCgyl3NTq9": [ + { + "expression": "[name] == Amulet && [quality] == rare && [flag] != ethereal # [fireresist] >= 10 && [coldresist] >= 30 && [itemmagicbonus] >= 10 && [itempoisonlengthresist] >= 25 && [magicdamagereduction] >= 3 && [fcr] >= 10", + "should_keep": True + }, + ], + # rare amulet + "D2R_cCgyl3NTq9": [ + { + "expression": "[name] == Amulet && [quality] == rare && [flag] != ethereal # [fireresist] >= 10 && [coldresist] >= 30 && [itemmagicbonus] >= 10 && [itempoisonlengthresist] >= 25 && [magicdamagereduction] >= 3 && [fcr] >= 10", + "should_keep": False + }, + { + "expression": "[name] == Amulet && [quality] == rare && [flag] != ethereal # [sorceressskills] >= 2 && [itemdamagetomana] >= 12 && [maxmana] >= 90 && [fcr] >= 10 && [strength] >= 26 && [energy] >= 20", + "should_keep": True + }, + ], + # white flail + "D2R_cPszZcBC81": [ + { + "expression": "[name] == Flail && [quality] == normal && [flag] != ethereal", + "should_keep": True + }, + ], + # white large siege bow + "D2R_d7clAOFrFY": [ + { + "expression": "[name] == LargeSiegeBow && [quality] == normal && [flag] != ethereal", + "should_keep": True + }, + ], + # magic gladius + "D2R_DaDAU5n7GJ": [ + { + "expression": "[name] == Gladius && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [strength] >= 2", + "should_keep": True + }, + ], + # rare ancient axe + "D2R_dvAVQGnYzc": [ + { + "expression": "[name] == AncientAxe && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 350 && [tohit] >= 550 && [ias] >= 40 && [plusmaxdamage] >= 20 && [itemreplenishdurability] >= 1", + "should_keep": True + }, + ], + # magic lich wand + "D2R_DyLF3Fj0FK": [ + { + "expression": "[name] == LichWand && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [fcr] >= 20 && [skillBoneSpirit] >= 3 && [skillBoneWall] >= 3 && [skillBoneSpear] >= 3", + "should_keep": True + }, + ], + # magic cloudy sphere + "D2R_EYVbkOSvLp": [ + { + "expression": "[name] == CloudySphere && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [fcr] >= 20 && [skillNova] >= 3 && [skillLightningMastery] >= 3 && [skillEnergyShield] >= 3", + "should_keep": True + }, + ], + # white lochaber axe + "D2R_fBh9PdCvNz": [ + { + "expression": "[name] == LochaberAxe && [quality] == normal && [flag] != ethereal", + "should_keep": True + }, + ], + # rare amulet + "D2R_gE6A96ftDw": [ + { + "expression": "[name] == Amulet && [quality] == rare && [flag] != ethereal # [sorceressskills] >= 2 && [itemdamagetomana] >= 12 && [maxmana] >= 90 && [fcr] >= 10 && [strength] >= 26 && [energy] >= 20", + "should_keep": False + }, + { + "expression": "[name] == Amulet && [quality] == rare && [flag] != ethereal # [fireresist] >= 10 && [coldresist] >= 30 && [itemmagicbonus] >= 10 && [itempoisonlengthresist] >= 25 && [magicdamagereduction] >= 3 && [fcr] >= 10", + "should_keep": True + }, + ], + # rare archon plate + "D2R_Ghwf32hhjz": [ + { + "expression": "[name] == ArchonPlate && [quality] == rare && [flag] != ethereal # [coldresist] >= 26 && [fireresist] >= 26 && [lightresist] >= 26 && [hpregen] >= 5 && [dexterity] >= 8 && [strength] >= 18", + "should_keep": True + }, + ], + # ormus robes + "D2R_gIVrKehVNq": [ + { + "expression": "[name] == DuskShroud && [quality] == unique # [fcr] >= 20 && [Passivecoldmastery] >= 15 && [Skillfrozenorb] >= 3", + "should_keep": True + }, + ], + # rare ceremonial javelin + "D2R_GOnpYcQ539": [ + { + "expression": "[name] == CeremonialJavelin && [quality] == rare && [flag] != ethereal # [enhanceddamage] >= 300 && [amazonskills] >= 2 && [itemmaxdamageperlevel] >= 1 && [itemtohitperlevel] >= 1 && [itemskillonhit] == 66 && [strength] >= 15 && [ias] >= 40 && [itemaddskilltab] >= 2", + "should_keep": True + }, + ], + # magic grand matron bow + "D2R_gxlIdIHuBX": [ + { + "expression": "[name] == GrandMatronBow && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 6 && [ias] >= 20", + "should_keep": True + }, + ], + # magic rondache + "D2R_gZNEsYkfkj": [ + { + "expression": "[name] == Rondache && [quality] == magic && [flag] != ethereal # [sockets] >= 4 && [toblock] >= 20 && [fbr] >= 30", + "should_keep": True + }, + ], + # rare battle belt + "D2R_h8bXDXTwYm": [ + { + "expression": "[name] == BattleBelt && [quality] == rare && [flag] != ethereal # [lightresist] >= 30 && [fireresist] >= 30 && [maxmana] >= 20 && [fhr] >= 24 && [itemgoldbonus] >= 80 && [strength] >= 30", + "should_keep": True + }, + ], + # crown of ages + "D2R_HPHrNWjUkD": [ + { + "expression": "[Name] == Corona && [quality] == unique # [sockets] >= 2 && [damageresist] >= 15", + "should_keep": True + }, + ], + # magic gladius + "D2R_HyHbbZZA1n": [ + { + "expression": "[name] == Gladius && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [itemchargedskill] == 36", + "should_keep": True + }, + ], + # reaper's toll + "D2R_I5LbjVIYvy": [ + { + "expression": "[name] == Thresher && [quality] == unique # [enhanceddamage] >= 220", + "should_keep": True + }, + ], + # magic akaran targe + "D2R_iEAZAhsn0m": [ + { + "expression": "[name] == AkaranTarge && [quality] == magic && [flag] != ethereal # [sockets] >= 4 && [toblock] >= 20 && [fbr] >= 30 && [tohit] >= 111 && [enhanceddamage] >= 58", + "should_keep": True + }, + ], + # rare akaran rondache + "D2R_j91F4T3G0M": [ + { + "expression": "[name] == AkaranRondache && [quality] == rare && [flag] != ethereal # [enhanceddefense] >= 200 && [sockets] >= 2 && [itemdamagetomana] >= 12 && [normaldamagereduction] >= 7 && [itemreplenishdurability] >= 1 && [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 120", + "should_keep": True + }, + ], + # rare ancient armor + "D2R_jdSojrLyHn": [ + { + "expression": "[name] == AncientArmor && [quality] == rare && [flag] != ethereal # [itemarmorperlevel] >= 24 && [sockets] >= 2 && [fireresist] >= 10 && [dexterity] >= 3 && [normaldamagereduction] >= 3 && [fhr] >= 24", + "should_keep": True + }, + ], + # swordback hold + "D2R_jiUGpeejOO": [ + { + "expression": "[Name] == Spikedshield && [quality] == unique && [flag] != ethereal # [enhanceddefense] >= 60", + "should_keep": True + }, + ], + # white cedar staff + "D2R_JKj1ONC0Qo": [ + { + "expression": "[name] == CedarStaff && [quality] == normal && [flag] != ethereal", + "should_keep": True + }, + ], + # rare alpha helm + "D2R_JOTQPzIIre": [ + { + "expression": "[name] == AlphaHelm && [quality] == rare && [flag] != ethereal # [itemtohitpercentperlevel] >= 2 && [enhanceddefense] >= 200 && [maxmana] >= 5 && [itempoisonlengthresist] >= 25 && [maxhp] >= 40 && [itemreplenishdurability] >= 1 && [skillVolcano] >= 3 && [skillFissure] >= 3 && [skillArmageddon] >= 3", + "should_keep": True + }, + ], + # rare alpha helm + "D2R_JOTQPzIIre": [ + { + "expression": "[name] == AlphaHelm && [quality] == rare && [flag] != ethereal # [itemtohitpercentperlevel] >= 2 && [enhanceddefense] >= 200 && [maxmana] >= 5 && [itempoisonlengthresist] >= 25 && [maxhp] >= 40 && [itemreplenishdurability] >= 1 && [skillVolcano] >= 3 && [skillFissure] >= 3 && [skillArmageddon] >= 3", + "should_keep": True + }, + ], + # rare antlers + "D2R_JxJMLkkrcO": [ + { + "expression": "[name] == Antlers && [quality] == rare && [flag] != ethereal # [druidskills] >= 2 && [sockets] >= 2 && [enhanceddefense] >= 100 && [energy] >= 9 && [maxhp] >= 36 && [fhr] >= 10 && [skillCycloneArmor] >= 3 && [skillRabies] >= 3 && [skillFeralRage] >= 3", + "should_keep": True + }, + ], + # magic long staff + "D2R_jYVm7kYbXA": [ + { + "expression": "[name] == LongStaff && [quality] == magic && [flag] != ethereal # [sorceressskills] >= 2 && [fcr] >= 20 && [skillFireMastery] >= 3 && [skillMeteor] >= 3 && [skillFireBall] >= 3", + "should_keep": True + }, + ], + # valkyrie wing + "D2R_K0SM6iiTyD": [ + { + "expression": "[name] == WingedHelm && [quality] == unique # [enhanceddefense] >= 200", + "should_keep": True + }, + ], + # magic fury visor + "D2R_LsXL0Ym8Ys": [ + { + "expression": "[name] == FuryVisor && [quality] == magic && [flag] != ethereal # [barbarianskills] >= 2 && [maxhp] >= 36 && [skillBattleOrders] >= 3 && [skillWarCry] >= 3 && [skillBattleCommand] >= 3", + "should_keep": True + }, + ], + # magic ring + "D2R_lVJEBucdd8": [ + { + "expression": "[name] == Ring && [quality] == magic && [flag] != ethereal # [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 60 && [fcr] >= 10", + "should_keep": True + }, + { + "expression": "[name] == Ring && [quality] == magic && [flag] != ethereal # [allres] >= 15 && [fcr] >= 10", + "should_keep": True + }, + { + "expression": "[name] == Ring && [quality] == magic && [flag] != ethereal # [allres] >= 16 && [fcr] >= 10", + "should_keep": False + }, + ], + # magic maiden javelin + "D2R_MJjAgKQABC": [ + { + "expression": "[name] == MaidenJavelin && [quality] == magic && [flag] != ethereal # [amazonskills] >= 2 && [ias] >= 40 && [itemaddskilltab] >= 3", + "should_keep": True + }, + ], + # rare ancient sword + "D2R_MnN9IaI0NA": [ + { + "expression": "[name] == AncientSword && [quality] == rare && [flag] != ethereal # [itemaddskilltab] >= 1 && [itemundeadtohit] >= 126 && [itemundeaddamagepercent] >= 101 && [tohit] >= 201 && [enhanceddamage] >= 126 && [ias] >= 40 && [firemindam] >= 15 && [firemaxdam] >= 48 && [itemchargedskill] == 144", + "should_keep": True + }, + ], + # magic eldritch orb + "D2R_MTB3TGtfgu": [ + { + "expression": "[name] == EldritchOrb && [quality] == magic && [flag] != ethereal # [maxmana] >= 186 && [fcr] >= 20 && [skillEnergyShield] >= 3 && [skillLightningMastery] >= 3 && [skillChainLightning] >= 3", + "should_keep": True + }, + ], + # rare eth blade talons + "D2R_O0WUcFkvIA": [ + { + "expression": "[name] == BladeTalons && [quality] == rare && [flag] == ethereal # [enhanceddamage] >= 350 && [tohit] >= 550 && [ias] >= 40 && [itemreplenishdurability] >= 1 && [plusmaxdamage] >= 20", + "should_keep": True + }, + { + "expression": "[name] == BladeTalons && [quality] == rare && [flag] != ethereal", + "should_keep": False + }, + ], + # magic coronet + "D2R_o1NZtzmhmF": [ + { + "expression": "[name] == Coronet && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [fcr] >= 20", + "should_keep": True + }, + ], + # magic griffon headdress + "D2R_OYgwehN2Ah": [ + { + "expression": "[name] == GriffonHeaddress && [quality] == magic && [flag] != ethereal # [sockets] >= 3 && [maxhp] >= 40 && [skillVolcano] >= 3 && [skillFissure] >= 3 && [skillArmageddon] >= 3", + "should_keep": True + }, + ], + # doombringer champion sword + "D2R_PTvvNUuaHq": [ + { + "expression": "[name] == ChampionSword && [quality] == unique # [enhanceddamage] >= 220", + "should_keep": True + }, + ], + # magic socketed diadem + "D2R_q45vGxNCeu": [ + { + "expression": "[name] == Diadem && [quality] == magic && [flag] != ethereal # [sockets] >= 2 && [fcr] >= 20", + "should_keep": True + }, + { + "expression": "[name] == Diadem && [quality] == magic && [flag] != ethereal # [sockets] >= 3", + "should_keep": False + }, + ], + # rare ancient shield + "D2R_QJo13V7ET2": [ + { + "expression": "[name] == AncientShield && [quality] == rare && [flag] != ethereal # [enhanceddefense] >= 100 && [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 80 && [itemaddskilltab] >= 1 && [itemskillongethit] == 48 && [toblock] >= 20 && [fbr] >= 30 && [itemreplenishdurability] >= 1", + "should_keep": True + }, + { + "expression": "[name] == AncientShield && [quality] == rare && [flag] != ethereal # [itemskillongethit] == 48", + "should_keep": True + }, + { + "expression": "[name] == AncientShield && [quality] == rare && [flag] != ethereal # [fbr] >= 30", + "should_keep": True + }, + { + "expression": "[name] == AncientShield && [quality] == rare && [flag] != ethereal # [toblock] >= 20", + "should_keep": True + }, + { + "expression": "[name] == AncientShield && [quality] == rare && [flag] != ethereal # [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 80", + "should_keep": True + }, + { + "expression": "[type] == assassinclaw", + "should_keep": False + }, + ], + # wizardspike + "D2R_qwgERVLYvQ": [ + { + "expression": "[Name] == BoneKnife && [quality] == unique # [fcr] >= 50", + "should_keep": True + }, + ], + # magic preserved head + "D2R_tB0MNZqKsc": [ + { + "expression": "[name] == PreservedHead && [quality] == magic && [flag] != ethereal # [sockets] >= 2 && [toblock] >= 20 && [fbr] >= 30 && [skillIronGolem] >= 3 && [skillPoisonNova] >= 3 && [skillPoisonExplosion] >= 3", + "should_keep": True + }, + { + "expression": "[type] == necromanceritem", + "should_keep": True + }, + { + "expression": "[type] == amazonitem", + "should_keep": False + }, + ], + # magic heavy bracers + "D2R_UIyDDtROVY": [ + { + "expression": "[name] == HeavyBracers && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [ias] >= 20", + "should_keep": True + }, + ], + # magic hydra bow + "D2R_URqU8bUiyv": [ + { + "expression": "[name] == HydraBow && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 3 && [ias] >= 20", + "should_keep": True + }, + ], + # hellslayer + "D2R_V4HkMaiIiI": [ + { + "expression": "[name] == Decapitator && [quality] == unique && [flag] != ethereal # [enhanceddamage] >= 100", + "should_keep": True + }, + ], + # rare cantor trophy + "D2R_w7DvFnRl6c": [ + { + "expression": "[name] == CantorTrophy && [quality] == rare && [flag] == ethereal # [itemaddskilltab] >= 2 && [itemarmorperlevel] >= 4 && [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 80 && [toblock] >= 10 && [fbr] >= 15 && [itemreplenishdurability] >= 1 && [itemhalffreezeduration] >= 1 && [skillBoneSpirit] >= 3 && [skillBoneSpear] >= 3 && [skillBoneWall] >= 3", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy # [itemaddskilltab] >= 2 && [itemarmorperlevel] >= 4", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy # [fireresist]+[coldresist]+[lightresist]+[poisonresist] >= 80", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy # [toblock] >= 10 && [fbr] >= 15", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy # [itemreplenishdurability] >= 1 && [itemhalffreezeduration] >= 1", + "should_keep": True + }, + { + "expression": "[name] == CantorTrophy # [skillBoneSpirit] >= 3 && [skillBoneSpear] >= 3 && [skillBoneWall] >= 3", + "should_keep": True + }, + ], + # magic ballista + "D2R_wASxol7GDr": [ + { + "expression": "[name] == Ballista && [quality] == magic && [flag] != ethereal # [poisonresist] >= 26 && [itemchargedskill] == 6", + "should_keep": True + }, + ], + # magefist + "D2R_wYl0iQwct8": [ + { + "expression": "[name] == LightGauntlets && [quality] == unique # [fcr] >= 20", + "should_keep": True + }, + ], + # magic ghost glaive + "D2R_XmiUAD2hC6": [ + { + "expression": "[name] == GhostGlaive && [quality] == magic && [flag] == ethereal # [enhanceddamage] >= 300 && [itemreplenishquantity] >= 1", + "should_keep": True + }, + ], + # 4os eth cryptic axe + "D2R_Xmiw3PsbcD": [ + { + "expression": "[name] == CrypticAxe && [quality] == normal && [flag] == ethereal", + "should_keep": True + }, + { + "expression": "[name] == CrypticAxe && [quality] == normal # [sockets] >= 4", + "should_keep": True + }, + { + "expression": "[name] == CrypticAxe && [quality] == normal && [flag] == ethereal # [sockets] >= 4", + "should_keep": True + }, + ], + # vampgaze + "D2R_xP50v8yBqQ": [ + { + "expression": "[name] == GrimHelm && [quality] == unique # [lifeleech] >= 8 && [manaleech] >= 8", + "should_keep": True + }, + ], + # andys + "D2R_Xq0aFuN5cj": [ + { + "expression": "[name] == Demonhead && [quality] == unique # [ias] >= 20", + "should_keep": True + }, + ], + # superior mancatcher + "D2R_YhXVS8Q4j6": [ + { + "expression": "[name] == ManCatcher && [quality] == superior", + "should_keep": True + }, + { + "expression": "[name] == ManCatcher && [quality] == normal", + "should_keep": False + }, + ], + # rare bone wand + "D2R_ZI6fzNFd3E": [ + { + "expression": "[name] == BoneWand && [quality] == rare && [flag] != ethereal # [sockets] >= 2 && [maxmana] >= 76 && [necromancerskills] >= 2 && [fcr] >= 20 && [hpregen] >= 5 && [energy] >= 20 && [skillBoneSpirit] >= 3 && [skillIronGolem] >= 3 && [skillBoneSpear] >= 3", + "should_keep": True + }, + { + "expression": "[name] == BoneWand # [necromancerskills] >= 2", + "should_keep": True + }, + { + "expression": "[name] == BoneWand # [hpregen] >= 5 && [energy] >= 20", + "should_keep": True + }, + { + "expression": "[name] == BoneWand # [skillBoneSpirit] >= 3 && [skillIronGolem] >= 3 && [skillBoneSpear] >= 3", + "should_keep": True + }, + { + "expression": "[name] == BoneWand # [skillBoneSpirit] >= 3", + "should_keep": True + }, + { + "expression": "[name] == BoneWand # [skillIronGolem] >= 3", + "should_keep": True + }, + { + "expression": "[name] == BoneWand # [skillBoneSpear] >= 3", + "should_keep": True + }, + ], + # griffs + "D2R_zKf6cKX5gZ": [ + { + "expression": "[Name] == Diadem && [quality] == unique && [flag] != ethereal", + "should_keep": True + }, + ], + # rare battle boots + "D2R_ZtRedtGBPB": [ + { + "expression": "[name] == BattleBoots && [quality] == rare && [flag] != ethereal # [fireresist] >= 40 && [lightresist] >= 40 && [enhanceddefense] >= 200 && [fhr] >= 10 && [frw] >= 30 && [itemgoldbonus] >= 80", + "should_keep": True + }, + ], + # sorc torch + "hovered_item_20220504_160228": [ + { + "expression": "[name] == largecharm && [quality] == unique # [itemaddsorceressskills] == 3 && [allstats] >= 10 && [allres] >= 10", + "should_keep": True + }, + ], + # carrion wind + "hovered_item_20220504_160419": [ + { + "expression": "[type] == ring && [quality] == unique # [lifeleech] >= 8 // carrion wind", + "should_keep": True, + "should_id": True, + }, + ], + # burning essence of terror + "hovered_item_20220504_161113": [ + { + "expression": "[Name] == Burningessenceofterror", + "should_keep": True, + "should_id": False, + }, + { + "expression": "[Type] == quest", + "should_keep": True + }, + ], + # thul rune + "hovered_item_20220504_161131": [ + { + "expression": "[Name] == Thulrune", + "should_keep": True + }, + { + "expression": "[Type] == rune", + "should_keep": True + }, + { + "expression": "[name] >= eldrune", + "should_keep": True + }, + ], + # tal helm + "hovered_item_20220504_161338": [ + { + "expression": "[Name] == Deathmask && [Quality] == Set", + "should_keep": True + }, + { + "expression": "[Name] == Deathmask # [defense] >= 100", + "should_keep": True + }, + ], + # unidentified rare ring + "positional_ring": [ + { + "expression": "[Name] == ring && [Quality] == rare", + "should_keep": True, + "should_id": False, + }, + ], + # magic jewel + "hovered_item_20220504_161003": [ + { + "expression": "[Name] == jewel && [Quality] == magic # [ias] >= 15 && [enhanceddamage] >= 15", + "should_keep": True + }, + ], + # magic large charm + "D2R_0tY8VkpM8T": [ + { + "expression": "[name] == LargeCharm && [quality] == magic && [flag] != ethereal # [plusmaxdamage] >= 2 && [fhr] >= 8", + "should_keep": True + }, + ], + # rare jewel + "D2R_1Iu96WxakK": [ + { + "expression": "[name] == Jewel && [quality] == rare && [flag] != ethereal # [plusmindamage] >= 7 && [maxmana] >= 13 && [poisonresist] >= 23 && [lightmindam] >= 1 && [lightmaxdam] >= 81", + "should_keep": True + }, + ], + # rare jewel + "D2R_3sLDs3uUMd": [ + { + "expression": "[name] == Jewel && [quality] == magic && [flag] != ethereal # [itemundeadtohit] >= 30 && [itemundeaddamagepercent] >= 38 && [strength] >= 3", + "should_keep": True + }, + ], + # magic grand charm + "D2R_Z7AVNV8X27": [ + { + "expression": "[name] == GrandCharm && [quality] == magic && [flag] != ethereal # [itemaddskilltab] == 1 && [lightmindam] >= 1 && [lightmaxdam] >= 3", + "should_keep": True + }, + { + "expression": "[name] == GrandCharm && [quality] == magic && [flag] != ethereal # [passiveandmagicskilltab] >= 1", + "should_keep": True + }, + { + "expression": "[name] == GrandCharm && [quality] == magic && [flag] != ethereal # [itemaddskilltab] >= 1", + "should_keep": True + }, + { + "expression": "[name] == GrandCharm && [quality] == magic && [flag] != ethereal # [passiveandmagicskilltab] >= 1", + "should_keep": True + }, + { + "expression": "[name] == GrandCharm && [quality] == magic && [flag] != ethereal # [passiveandmagicskilltab] >= 5", + "should_keep": False + }, + ], + # magic large charm + "D2R_Y0YlR268P3": [ + { + "expression": "[name] == LargeCharm && [quality] == magic && [flag] != ethereal # [itemmagicbonus] >= 6 && [frw] >= 5", + "should_keep": True + }, + ], + # magic jewel + "D2R_aOyb5TqkIm": [ + { + "expression": "[name] == Jewel && [quality] == magic && [flag] != ethereal # [lightresist] >= 23 && [poisonmindam] >= 20", + "should_keep": True + }, + { + "expression": "[name] == Jewel && [quality] == magic && [flag] != ethereal # [lightresist] >= 23", + "should_keep": True + }, + ], + # magic grand charm + "D2R_aXKcy7ITEB": [ + # TODO: I had to change from [defense] >= 47 to [plusdefense] >= 47. [defense] is probably a calculated property depending on base item type + { + "expression": "[name] == GrandCharm && [quality] == magic && [flag] != ethereal # [plusdefense] >= 47", + "should_keep": True + }, + ], + # magic small charm + "D2R_KKoeMHxUsp": [ + { + "expression": "[name] == SmallCharm && [quality] == magic && [flag] != ethereal # [plusmaxdamage] >= 1 && [frw] >= 3", + "should_keep": True + }, + ], + # rare jewel + "D2R_lYkkSS0qCi": [ + { + "expression": "[name] == Jewel && [quality] == rare && [flag] != ethereal # [itemlightradius] >= 1 && [tohit] >= 10 && [strength] >= 8 && [coldmindam] >= 1 && [coldmaxdam] >= 4 && [firemindam] >= 7 && [firemaxdam] >= 21", + "should_keep": True + }, + ], + # rare jewel + "D2R_vBBOGsinxA": [ + { + "expression": "[name] == Jewel && [quality] == rare && [flag] != ethereal # [itemundeadtohit] >= 38 && [itemundeaddamagepercent] >= 38 && [strength] >= 3 && [itemmagicbonus] >= 8 && [itemreqpercent] <= -15", + "should_keep": True + }, + ], + # rainbow facet, poison + "D2R_nLSBZYixOe": [ + { + "expression": "[Name] == jewel && [quality] == unique # [passivecoldpierce]+[passivecoldmastery] >= 10 || [passivepoispierce]+[passivepoismastery] >= 10 || [passiveltngpierce]+[passiveltngmastery] >= 10 || [passivefirepierce]+[passivefiremastery] >= 10", + "should_keep": True + }, + { + "expression": "[Name] == jewel && [quality] == unique # [passivepoispierce]+[passivepoismastery] >= 10", + "should_keep": True + }, + ], + # rainbow facet, fire + "D2R_5ctnVauZr1": [ + { + "expression": "[Name] == jewel && [quality] == unique # [passivefirepierce]+[passivefiremastery] >= 10", + "should_keep": True + }, + { + "expression": "[idname] == rainbowfacet", + "should_keep": True + }, + { + "expression": "[idname] == harlequincrest", + "should_keep": False + }, + ], + # nightwing veil + "nightwing": [ + { + "expression": "[name] == spiredhelm && [quality] == unique && [flag] != ethereal # [dexterity] >= 10 && [passivecoldmastery] >= 8", + "should_keep": True + }, + { + "expression": "[name] == spiredhelm && [quality] == unique && [flag] != ethereal # [dexterity] >= 10 && [itemabsorbcold] >= 8", + "should_keep": True + }, + { + "expression": "[name] == spiredhelm && [quality] == unique && [flag] != ethereal # [dexterity] >= 10 && [itemabsorbcold] >= 9", + "should_keep": False + }, + ], +} \ No newline at end of file diff --git a/test/nip/pick_item_test_cases.py b/test/nip/pick_item_test_cases.py new file mode 100644 index 000000000..283a22271 --- /dev/null +++ b/test/nip/pick_item_test_cases.py @@ -0,0 +1,417 @@ +BNIP_PICK_TESTS = { + # monarch + "001": [ + { + "Text": "SUPERIOR AEGIS", + "Color": "gray", + "expressions": [ + { + "expression": "[type] == shield && [quality] >= normal && [flag] != ethereal # [sockets] >= 4", + "should_pickup": True + }, + { + "expression": "[type] == shield", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [flag] != ethereal", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == superior", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == superior && [flag] == ethereal", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == superior && [flag] == ethereal # [sockets] >= 4", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [flag] == ethereal # [sockets] >= 4", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == superior && [flag] != ethereal # [sockets] == 0", + "should_pickup": False + }, + { + "expression": "[name] == Aegis && [flag] == ethereal", + "should_pickup": True + }, + { + "expression": "[name] == Aegis # [sockets] >= 4", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == normal", + "should_pickup": False + }, + { + "expression": "[quality] == normal", + "should_pickup": False + }, + ], + }, + { + "Color": "gray", + "Text": "AEGIS", + "expressions": [ + { + "expression": "[name] == Aegis && [quality] == normal", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == superior", + "should_pickup": False + }, + { + "expression": "[name] == Aegis && [flag] == ethereal", + "should_pickup": True + }, + { + "expression": "[name] == Aegis # [sockets] > 0", + "should_pickup": True + }, + ], + }, + { + "Color": "gray", + "Text": "AERIN SHIELD", + "expressions": [ + { + "expression": "[type] == auricshields # [sockets] > 0", + "should_pickup": True + }, + { + "expression": "[name] == aerinshield # [sockets] > 0", + "should_pickup": True + }, + { + "expression": "[type] == auricshields && [flag] != ethereal # [sockets] == 0", + "should_pickup": False + }, + { + "expression": "[type] == auricshields && [flag] != ethereal # [sockets] > 0", + "should_pickup": True + }, + { + "expression": "[name] == aerinshield && [flag] != ethereal # [sockets] == 0", + "should_pickup": False + }, + { + "expression": "[name] == aerinshield && [flag] != ethereal # [sockets] > 0", + "should_pickup": True + }, + { + "expression": "[name] == aerinshield", + "should_pickup": True + }, + ], + }, + { + "Color": "gray", + "Text": "SUPERIOR AERIN SHIELD", + "expressions": [ + { + "expression": "[type] == auricshields && [quality] == superior && [flag] != ethereal # [sockets] > 0", + "should_pickup": True + }, + ], + }, + { + "Color": "white", + "Text": "13935 GOLD", + "expressions": [ + { + "expression": "[Type] == Gold # [Gold] >= 1000", + "should_pickup": True + }, + { + "expression": "[Type] == Gold # [Gold] < 1000", + "should_pickup": False + }, + ], + }, + { + "Color": "white", + "Text": "AEGIS", + "expressions": [ + { + "expression": "[name] == Aegis # [sockets] == 0", + "should_pickup": True + }, + { + "expression": "[name] == Aegis # [sockets] > 0", + "should_pickup": False + }, + { + "expression": "[name] == Aegis && [quality] == normal", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == superior", + "should_pickup": False + }, + { + "expression": "[name] == Aegis && [quality] > normal", + "should_pickup": False + }, + { + "expression": "[name] == Aegis && [class] == elite", + "should_pickup": True + }, + ], + }, + { + "Color": "blue", + "Text": "AEGIS", + "expressions": [ + { + "expression": "[name] == Aegis && [quality] == magic", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] == magic # [sockets] == 0", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] >= superior", + "should_pickup": True + }, + { + "expression": "[name] == Aegis && [quality] <= superior", + "should_pickup": False + }, + ], + }, + { + "Color": "yellow", + "Text": "AEGIS", + "expressions": [ + { + "expression": "[name] == Aegis && [quality] == rare", + "should_pickup": True + }, + ], + }, + { + "Color": "gold", + "Text": "AEGIS", + "expressions": [ + { + "expression": "[name] == aegis && [quality] == unique", + "should_pickup": True + }, + ], + }, + ], + "045": [ + { + "Color": "gray", + "Text": "GREATER CLAWS", + "expressions": [ + { + "expression": "[name] == greaterclaws && [quality] == normal", + "should_pickup": True + }, + { + "expression": "[name] == greaterclaws && [class] == exceptional", + "should_pickup": True + }, + { + "expression": "[type] == assassinclaw && [quality] == normal", + "should_pickup": True + }, + { + "expression": "[type] == handtohand && [quality] == normal", + "should_pickup": True + }, + ], + }, + { + "Color": "gray", + "Text": "SUPERIOR GREATER CLAWS", + "expressions": [ + { + "expression": "[type] == handtohand && [quality] == superior", + "should_pickup": True + }, + { + "expression": "[name] == greaterclaws && [quality] == superior", + "should_pickup": True + }, + ], + }, + { + "Color": "white", + "Text": "GREATER CLAWS", + "expressions": [ + { + "expression": "[name] == greaterclaws && [flag] != ethereal && [quality] <= superior # [sockets] == 0 && [skilldragonflight] >= 2 && [skilllightningsentry] >= 2 ", + "should_pickup": True + }, + ], + }, + { + "Color": "gold", + "Text": "GREAT SWORD", + "expressions": [ + + ], + }, + ], + "139": [ + { + "Color": "white", + "Text": "SUPERIOR HIEROPHANT TROPHY", + "expressions": [ + { + "expression": "[name] == hierophanttrophy", + "should_pickup": True + }, + { + "expression": "[type] == voodooheads", + "should_pickup": True + }, + ], + }, + ], + "188": [ + { + "Color": "white", + "Text": "FLAWED EMERALD", + "expressions": [ + { + "expression": "[name] >= chippedemerald && [name] <= perfectemerald", + "should_pickup": True + }, + { + "expression": "[name] == flawedemerald", + "should_pickup": True + }, + { + "expression": "[name] == emerald", + "should_pickup": False + }, + ], + }, + { + "Color": "white", + "Text": "FULL REJUVENATION POTION", + "expressions": [ + { + "expression": "[name] == fullrejuvenationpotion", + "should_pickup": True + }, + { + "expression": "[name] == rejuvenationpotion", + "should_pickup": False + }, + ], + }, + { + "Color": "white", + "Text": "FLAWLESS SKULL", + "expressions": [ + + ], + }, + { + "Color": "orange", + "Text": "FESTERING ESSENCE OF DESTRUCTION", + "expressions": [ + { + "expression": "[name] == festeringessenceofdestruction", + "should_pickup": True + }, + ], + }, + ], + "191": [ + { + "Color": "white", + "Text": "REJUVENATION POTION", + "expressions": [ + { + "expression": "[name] == fullrejuvenationpotion", + "should_pickup": False + }, + { + "expression": "[name] == rejuvenationpotion", + "should_pickup": True + }, + ], + }, + { + "Color": "white", + "Text": "SUPER MANA POTION", + "expressions": [ + { + "expression": "[name] == supermanapotion", + "should_pickup": True + }, + ], + }, + { + "Color": "white", + "Text": "SCROLL OF TOWN PORTAL", + "expressions": [ + { + "expression": "[name] == scrolloftownportal", + "should_pickup": True + }, + ], + }, + { + "Color": "white", + "Text": "SCROLL OF IDENTIFY", + "expressions": [ + { + "expression": "[name] == scrollofidentify", + "should_pickup": True + }, + ], + }, + { + "Color": "white", + "Text": "SUPER HEALING POTION", + "expressions": [ + { + "expression": "[name] == superhealingpotion", + "should_pickup": True + }, + ], + }, + { + "Color": "green", + "Text": "RING", + "expressions": [ + { + "expression": "[name] == ring && [quality] == set", + "should_pickup": True + }, + { + "expression": "[type] == ring && [quality] == set # [hpregen] >= 2 && [maxhp] >= 15 // Angelic Halo", + "should_pickup": True + }, + ], + }, + { + "Color": "orange", + "Text": "SUR RUNE", + "expressions": [ + { + "expression": "[name] >= elrune && [name] <= zodrune", + "should_pickup": True + }, + { + "expression": "[name] == surrune", + "should_pickup": True + }, + ], + }, + ], +} \ No newline at end of file diff --git a/test/nip/test_get_ground_loot.py b/test/nip/test_get_ground_loot.py new file mode 100644 index 000000000..cdc02ab98 --- /dev/null +++ b/test/nip/test_get_ground_loot.py @@ -0,0 +1,77 @@ +import cv2 +import os +import json +import pytest +from dataclasses import asdict +from d2r_image import processing +from d2r_image.data_models import GroundItemList +from common import ExpressionTest, pretty_dict +from functools import cache +from pick_item_test_cases import BNIP_PICK_TESTS +from bnip.transpile import generate_expression_object, transpile_bnip_expression +import bnip.actions as bnip_actions +import screen +import utils.download_test_assets # downloads assets if they don't already exist, doesn't need to be called + +PATH='test/assets/ground_loot' +screen.set_window_position(0, 0) + +@cache +def load_ground_loot() -> dict: + test_objs = {} + for filename in os.listdir(PATH): + filename = filename + if filename.lower().endswith('.png'): + basename = filename[:-4] + image = cv2.imread(f"{PATH}/{basename}.png") + test_objs[basename] = processing.get_ground_loot(image) + return test_objs + +@cache +def expressions_test_list() -> list[ExpressionTest]: + expressions = [] + for key, value in BNIP_PICK_TESTS.items(): # key = basename, value = list[dict] + for val in value: # for dict in list[dict] + items_json: GroundItemList = load_ground_loot()[key] + for ground_item in items_json.items: + if ground_item.Text == val["Text"] and ground_item.Color == val["Color"]: + for expr in val["expressions"]: + expressions.append(ExpressionTest( + basename=key, + read_json=ground_item.as_dict(), + expression=expr["expression"], + pick_expected=expr["should_pickup"], + transpiled=transpile_bnip_expression(expr["expression"]) + )) + break + return expressions + +# this test has essentially been made obsolete by the nip should_pick() tests + +# @pytest.mark.parametrize('ground_items', load_ground_loot().items()) +# def test_ground_loot(ground_items: list[str, dict]): +# basename = ground_items[0] +# result = ground_items[1] +# x = open(f"{PATH}/{basename}.json").read() +# expected_properties = GroundItemList.from_json(x) +# # print(f"expected_properties: {expected_properties}") +# assert result == expected_properties + + +@pytest.mark.parametrize('should_pick_expression', expressions_test_list()) +def test_pick_item(should_pick_expression: ExpressionTest, mocker): + mocker.patch.object(bnip_actions, 'bnip_expressions', [ + generate_expression_object(should_pick_expression.expression) + ]) + result, matching_expression = bnip_actions.should_pickup(should_pick_expression.read_json) + if bool(result) != should_pick_expression.pick_expected: + print("\n") + print("bnip_expressions object:") + print(pretty_dict(asdict(bnip_actions.bnip_expressions[0]))) + print("test expression object:") + print(json.dumps(asdict(should_pick_expression), indent=4)) + if matching_expression: + print(f"matching expression: {matching_expression}") + print(f"should_pickup() result: {result}; test pass/fail below") + print("\n") + assert bool(result) == should_pick_expression.pick_expected diff --git a/test/nip/test_get_hovered_item.py b/test/nip/test_get_hovered_item.py new file mode 100644 index 000000000..91f6384a3 --- /dev/null +++ b/test/nip/test_get_hovered_item.py @@ -0,0 +1,89 @@ +import os +import cv2 +import json +from dataclasses import asdict +import pytest +from d2r_image import processing +from d2r_image.data_models import HoveredItem +from functools import cache +from keep_item_test_cases import BNIP_KEEP_TESTS +from common import ExpressionTest, pretty_dict +import screen +import utils.download_test_assets # downloads assets if they don't already exist, doesn't need to be called +from bnip.transpile import generate_expression_object, transpile_bnip_expression +import bnip.actions as bnip_actions + + +PATH='test/assets/hovered_items' +screen.set_window_position(0, 0) + +@cache +def load_hovered_items() -> dict: + test_objs = {} + for filename in os.listdir(PATH): + filename = filename + if filename.lower().endswith('.png'): + basename = filename[:-4] + image = cv2.imread(f"{PATH}/{basename}.png") + result, _ = processing.get_hovered_item(image) + test_objs[basename] = result + return test_objs + +@cache +def expressions_test_list() -> list[ExpressionTest]: + expressions = [] + for key, value in BNIP_KEEP_TESTS.items(): + for val in value: + expressions.append(ExpressionTest( + basename=key, + read_json=load_hovered_items()[key].as_dict(), + expression=val["expression"], + keep_expected=val["should_keep"], + id_expected=None if not "should_id" in val else val["should_id"], + transpiled=transpile_bnip_expression(val["expression"]) + )) + return expressions + +# this test has essentially been made obsolete by the bnip should_keep() tests + +# @pytest.mark.parametrize('hovered_item', load_hovered_items().items()) +# def test_hovered_item(hovered_item: list[str, dict]): +# basename = hovered_item[0] +# result = hovered_item[1] +# expected_properties = HoveredItem.from_json(open(f"{PATH}/{basename}.json").read()) +# assert result == expected_properties + +@pytest.mark.parametrize('should_keep_expression', expressions_test_list()) +def test_keep_item(should_keep_expression: ExpressionTest, mocker): + mocker.patch.object(bnip_actions, 'bnip_expressions', [ + generate_expression_object(should_keep_expression.expression) + ]) + result, matching_expression = bnip_actions.should_keep(should_keep_expression.read_json) + if bool(result) != should_keep_expression.keep_expected: + print("\n") + print("bnip_expressions object:") + print(pretty_dict(asdict(bnip_actions.bnip_expressions[0]))) + print("test expression object:") + print(json.dumps(asdict(should_keep_expression), indent=4)) + if matching_expression: + print(f"matching expression: {matching_expression}") + print(f"should_keep() result: {result}; test pass/fail below") + print("\n") + assert bool(result) == should_keep_expression.keep_expected + + +@pytest.mark.parametrize('should_id_expression', [expression for expression in expressions_test_list() if expression.id_expected is not None]) +def test_should_id(should_id_expression: ExpressionTest, mocker): + mocker.patch.object(bnip_actions, 'bnip_expressions', [ + generate_expression_object(should_id_expression.expression) + ]) + result = bnip_actions.should_id(should_id_expression.read_json) + if bool(result) != should_id_expression.id_expected: + print("\n") + print("bnip_expressions object:") + print(pretty_dict(asdict(bnip_actions.bnip_expressions[0]))) + print("test expression object:") + print(json.dumps(asdict(should_id_expression), indent=4)) + print(f"should_id() result: {result}; test pass/fail below") + print("\n") + assert bool(result) == should_id_expression.id_expected \ No newline at end of file diff --git a/test/nip/test_text_correction.py b/test/nip/test_text_correction.py new file mode 100644 index 000000000..e9979f3f1 --- /dev/null +++ b/test/nip/test_text_correction.py @@ -0,0 +1,24 @@ +import pytest +from d2r_image import ocr, processing_helpers, d2data_lookup + + +@pytest.mark.parametrize("ocr_string, expected_string", [ + ("SUPERIER ZWEIHANDRE", 'SUPERIOR ZWEIHANDER'), + ("PARFECT RUBV", 'PERFECT RUBY'), + ("SUPERIOR QU AB", 'SUPERIOR QUHAB') +]) +def test_wordwise_check(ocr_string, expected_string): + confidences = [0.5 for x in ocr_string.split()] + result = ocr._ocr_result_dictionary_check(ocr_string, confidences) + assert result == expected_string + +@pytest.mark.parametrize("ocr_string, expected", [ + ("JAR RUNE", (None, 'JAH RUNE')), + ("LOW QUALITY RUNE BONG", ("LOW QUALITY", 'RUNE BOW')), + ("SUPERIOR CHAMPION WORD", ("SUPERIOR", 'CHAMPION SWORD')) +]) +def test_base_item_check(ocr_string, expected): + quality, normalized_text = processing_helpers.get_normalized_normal_gray_item_text(ocr_string) + base_item = f"{processing_helpers.fuzzy_base_item_match(normalized_text)}".strip() + quality = quality.value if quality else None + assert (quality, base_item) == expected \ No newline at end of file diff --git a/test/nip/test_transpile.py b/test/nip/test_transpile.py new file mode 100644 index 000000000..87496e9c3 --- /dev/null +++ b/test/nip/test_transpile.py @@ -0,0 +1,28 @@ +import pytest + +from bnip.BNipExceptions import BNipSyntaxError +from bnip.transpile import generate_expression_object, transpile_bnip_expression +from transpile_test_cases import GENERAL_SYNTAX_TESTS, SYNTAX_ERROR_TESTS + + +def test_general_syntax(): + for general_syntax_test in GENERAL_SYNTAX_TESTS: + try: + transpile_bnip_expression(general_syntax_test["raw_expression"]) + if general_syntax_test["should_fail"]: + pytest.fail(f"Syntax test failed to fail: {general_syntax_test['raw_expression']}") + except BNipSyntaxError: + if general_syntax_test["should_fail"]: + continue + else: + pytest.fail(f"Syntax error should not have been raised for {general_syntax_test['raw_expression']}") + + +@pytest.mark.parametrize('syntax_test', SYNTAX_ERROR_TESTS) +def test_syntax_errors(syntax_test: dict): + try: + generate_expression_object(syntax_test["raw_expression"]) + assert True == False # should always fail + except Exception as e: + if isinstance(e, BNipSyntaxError): + assert e.error_code == f"BNIP_{syntax_test['expected_code']}" \ No newline at end of file diff --git a/test/nip/transpile_test_cases.py b/test/nip/transpile_test_cases.py new file mode 100644 index 000000000..f3ae29be1 --- /dev/null +++ b/test/nip/transpile_test_cases.py @@ -0,0 +1,114 @@ +GENERAL_SYNTAX_TESTS = [ + { + "raw_expression": "[name] == ring", + "should_fail": False, + }, + { + "raw_expression": "[name] = ring", + "should_fail": True, + }, + { + "raw_expression": "[name] > ring", + "should_fail": False, + }, + { + "raw_expression": "[name] < ring", + "should_fail": False, + }, + { + "raw_expression": "[name] >= ring", + "should_fail": False + }, + { + "raw_expression": "[name] <= ring", + "should_fail": False, + }, + { + "raw_expression": "[name] >== ring", + "should_fail": True, + }, + { + "raw_expression": "[name] ==> ring", + "should_fail": True, + }, + { + "raw_expression": "[name] != ring", + "should_fail": False, + }, + { + "raw_expression": "[name] =! ring", + "should_fail": True, + } +] + +SYNTAX_ERROR_TESTS = [ + # BNIP_0x1:Unknown token: 電:[sockets] 電話 1 + { + "raw_expression": "[name] == ring # [sockets] 電話 1", + "expected_code": "0x1", + }, + # BNIP_0x2:Missing ] after keyword:[name == ring + { + "raw_expression": "[name == ring # [sockets] > 1", + "expected_code": "0x2", + }, + # BNIP_0x3:unexpected token on left of math operator: + { + "raw_expression": "[idname] + 3", + "expected_code": "0x3", + }, + # BNIP_0x4:unexpected token on right of math operator: + { + "raw_expression": "3 + [idname]", + "expected_code": "0x4", + }, + # BNIP_0x5, Invalid logical operator: '=': [sockets] = 1 + { + "raw_expression": "[name] == ring # [sockets] = 1", + "expected_code": "0x5", + }, + # BNIP_0x6:unclosed parenthesis: + { + "raw_expression": "[name] == ring # (sockets == 4 || sockets == 3", + "expected_code": "0x6", + }, + # BNIP_0x7:unopened parenthesis + { + "raw_expression": "[name] == ring # sockets == 4 || sockets == 3)", + "expected_code": "0x7", + }, + # BNIP_0x8 -- I don't know how to make this one happen! + # BNIP_0x9:Expected operator on right of number: + { + "raw_expression": "[name] == ring # 8 8", + "expected_code": "0x9", + }, + # BNIP_0x10:Expected token on left of logical operator + { + "raw_expression": "[Name] == ring # (< 8)", + "expected_code": "0x10", + }, + # BNIP_0x11:Expected token on right of logical operator + { + "raw_expression": "[idname] > ring", + "expected_code": "0x11", + }, + # BNIP_0x12 -- I don't know how to make this one happen! + # BNIP_0x13:Invalid token 'xyaerrsddabd' in property section + { + "raw_expression": "[xyaerrsddabd] == ring", + "expected_code": "0x13", + }, + # BNIP_0x14:Invalid token 'xyaerrsddabd' in stats + { + "raw_expression": "[name] == ring # [xyaerrsddabd] >= 1", + "expected_code": "0x14", + }, + # BNIP_0x15 -- Impossible to force this error for now as maxquantity is cut out in prepare_bnip_expression() + # BNIP_0x16:unexpected sectionand (#) at end of expression + { + "raw_expression": "[Name] == Lightgauntlets && [Quality] == Unique && [Flag] != Ethereal #", + "expected_code": "0x16", + }, + # BNIP_Ox17 -- I don't know how to make this one happen! +] \ No newline at end of file diff --git a/test/pather_test.py b/test/pather_test.py deleted file mode 100644 index eeaa68d2b..000000000 --- a/test/pather_test.py +++ /dev/null @@ -1,30 +0,0 @@ -import pytest -from mocks.screen_mock import ScreenMock -from logger import Logger -from pather import Pather -from screen import convert_screen_to_abs - - -class TestPather: - def setup_method(self): - Logger.init() - Logger.remove_file_logger() - - screen = ScreenMock() - self.pather = Pather() - - @pytest.mark.parametrize("test_input, expected", [ - ((90, 90), True), - ((25, 70), True), - ((150, 120), False), - ((500, 400), False), - ((400, 1300), True), - ]) - def test_adjust_abs_range_to_screen(self, test_input, expected): - should_be_adapted = expected - pos_abs = convert_screen_to_abs(test_input) - new_pos_abs = self.pather._adjust_abs_range_to_screen(pos_abs) - is_adapted = new_pos_abs != pos_abs - assert(should_be_adapted == is_adapted) - new_pos_abs_2 = self.pather._adjust_abs_range_to_screen(new_pos_abs) - assert(new_pos_abs == new_pos_abs_2) diff --git a/test/smoke_test.py b/test/smoke_test.py index f301ec59f..64ceaf0bf 100644 --- a/test/smoke_test.py +++ b/test/smoke_test.py @@ -2,9 +2,9 @@ from logger import Logger from game_stats import GameStats from bot import Bot -from template_finder import TemplateFinder +import template_finder from mocks.screen_mock import ScreenMock - +import utils.download_test_assets # downloads assets if they don't already exist, doesn't need to be called class TestSmoke: """ @@ -15,6 +15,6 @@ def setup_method(self): Logger.remove_file_logger() def test_smoke(self): - screen = ScreenMock() + screen = ScreenMock("test/assets/hero_select.png") game_stats = GameStats() bot = Bot(game_stats) diff --git a/test/target_detect_test.py b/test/target_detect_test.py index 324a4af83..f837e3b11 100644 --- a/test/target_detect_test.py +++ b/test/target_detect_test.py @@ -1,11 +1,16 @@ -from target_detect import mob_check import cv2 import pytest +import screen + +import utils.download_test_assets # downloads assets if they don't already exist, doesn't need to be called +from target_detect import get_visible_targets +import screen @pytest.mark.parametrize("screen_path, expected_res", [ ("test/assets/mobs.png", True), ("test/assets/mobs_no_green_or_blue.png", False), ]) -def test_mob_detect(screen_path, expected_res): +def test_target_detect(screen_path, expected_res): + screen.set_window_position(0, 0) img = cv2.imread(screen_path) - assert bool(mob_check(img)) == expected_res + assert bool(len(get_visible_targets(img))) == expected_res diff --git a/test/template_finder_test.py b/test/template_finder_test.py index 6cacd3ce0..644eae399 100644 --- a/test/template_finder_test.py +++ b/test/template_finder_test.py @@ -1,34 +1,71 @@ import cv2 import pytest -from template_finder import TemplateFinder +import template_finder from utils.misc import is_in_roi +import screen +import utils.download_test_assets # downloads assets if they don't already exist, doesn't need to be called -@pytest.mark.parametrize("template1_path, template2_path, template3_path, screen_path, expected_roi", [( - "test/assets/stash_slot_empty.png", # empty stash slot - "test/assets/stash_slot_slash.png", # empty stash slot but has a drawn slash - "test/assets/stash_slot_cross.png", # empty stash slot but has a drawn X - "test/assets/stash_slots.png", # image with three empty slots and one slot with a draw slash - [38, 0, 38, 38]) # region of slash -]) -def test_match_behavior(template1_path, template2_path, template3_path, screen_path, expected_roi): - image = cv2.imread(screen_path) - empty = cv2.imread(template1_path) - slash = cv2.imread(template2_path) - cross = cv2.imread(template3_path) - threshold=0.6 +screen.set_window_position(0, 0) + +def test_search(): """ - Test first match + Test default search behavior (first match) - searches first for cross, which doesn't perfectly match but should reach above threshold - if cross matches above threshold as expected, then it won't bother to search for slash, which has a perfect match on the image - test passes if the template match score is not perfect """ - match = TemplateFinder().search([cross, slash], image, threshold) + image = cv2.imread("test/assets/stash_slots.png") + slash = cv2.imread("test/assets/stash_slot_slash.png") + cross = cv2.imread("test/assets/stash_slot_cross.png") + threshold=0.6 + match = template_finder.search([cross, slash], image, threshold) assert threshold <= match.score < 1 + +def test_search_best_match(): """ - Test best match + Test search "best_match" behavior - searches first for cross, which doesn't perfectly match - searches next for slash, which perfectly matches on image - test passes if the center of the template match lies within the expected region of the slash """ - match = TemplateFinder().search([cross, slash], image, threshold=0.6, best_match=True) - assert is_in_roi(expected_roi, match.center) \ No newline at end of file + image = cv2.imread("test/assets/stash_slots.png") + slash = cv2.imread("test/assets/stash_slot_slash.png") + cross = cv2.imread("test/assets/stash_slot_cross.png") + slash_expected_roi = [38, 0, 38, 38] + match = template_finder.search([cross, slash], image, threshold=0.6, best_match=True) + assert is_in_roi(slash_expected_roi, match.center) + +def test_search_all(): + """ + Test all matches for a single template in argument + - searches for empty slots with high threshold + - test passes if 3 matches result + """ + image = cv2.imread("test/assets/stash_slots.png") + empty = cv2.imread("test/assets/stash_slot_empty.png") + matches = template_finder.search_all(empty, image, threshold=0.98) + assert len(matches) == 3 + +def test_search_all_multiple_templates(): + """ + Test all matches with multiple templates in argument + - searches for empty slots and slash with high threshold + - test passes if 4 matches result + """ + image = cv2.imread("test/assets/stash_slots.png") + empty = cv2.imread("test/assets/stash_slot_empty.png") + slash = cv2.imread("test/assets/stash_slot_slash.png") + matches = template_finder.search_all([empty, slash], image, threshold=0.98) + assert len(matches) == 4 + +if __name__ == "__main__": + image = cv2.imread("test/assets/stash_slots.png") + empty = cv2.imread("test/assets/stash_slot_empty.png") + slash = cv2.imread("test/assets/stash_slot_slash.png") + cross = cv2.imread("test/assets/stash_slot_cross.png") + slash_expected_roi = [38, 0, 38, 38] + + + matches = template_finder.search_all([empty, slash], image, threshold=0.98) + print(len(matches)) + print(matches) diff --git a/test/utils/misc_test.py b/test/utils/misc_test.py index e5c025b96..cd99c3331 100644 --- a/test/utils/misc_test.py +++ b/test/utils/misc_test.py @@ -1,7 +1,7 @@ import pytest from logger import Logger from utils.misc import load_template - +import utils.download_test_assets # downloads assets if they don't already exist, doesn't need to be called class TestUtilsMisc: def setup_method(self): @@ -13,6 +13,6 @@ def setup_method(self): ("some/random/path/that/not/a/file.png", False), ]) def test_load_template(self, path: str, should_be_success: bool): - template_img = load_template(path, 1.0, alpha=True) + template_img = load_template(path) success = template_img is not None assert(success == should_be_success)