Compare commits

...
35 Commits
Author SHA1 Message Date
mgleed ea77ac5fe7 Merge branch 'master' of https://github.com/bottytools/botty 2022-06-21 18:58:27 -04:00
mgleed 1df9e0a28f update test assets url 2022-06-21 18:58:15 -04:00
Sosa 54316a1eac Update default.nip (#918)
Fixed Stormshield using wrong mod for damage reduction
Fixed Crown of Ages using wrong mod for damage reduction
Added +Skill to Arkaine's Valor Perfect
Added Damage Reduction mod for Leviathan Perfect
2022-06-21 14:35:07 -04:00
Riddle 76b911f50f Merge pull request #917 from aeon0/nip-fix-subtraction
fixed subtraction for nip expressions
2022-06-21 12:31:47 -04:00
Riddle 5b9c56a2c6 fixed subtraction for nip expressions 2022-06-21 12:20:21 -04:00
Gleed 2b2de1baf3 Bugfix: Ignore merc death if merc chicken off (#916)
* init

* save as...

* move timer
2022-06-21 09:57:46 -04:00
Gleed 0e800cc3e2 Bugfix: pather passing floats that should be ints 2022-06-21 08:58:07 -04:00
Legit 42639c8273 Fix: /nopickup not working (#912)
No pickup was turned off permanently by mistake.
2022-06-21 08:14:55 -04:00
Riddle 9a5ee8cd5e Merge pull request #913 from aeon0/nip-fix-division
fix for divison
2022-06-21 06:57:56 -04:00
Riddle e6b65a6a10 fix for divison 2022-06-21 06:31:57 -04:00
Gleed 5597df55ca Fix: find_nearest_nonzero() NoneType error 2022-06-20 18:28:01 -04:00
Sosaandmgleed dc75cce5dc Enhancement/bugfix: Corrections for default.nip (#906)
* Corrections for default.nip

Corrected Chipped Amethyst
Corrected Bow sockets (Mist Runeword)
Corrected [Quality] issue on base items

Added Cryptic & Mythical Swords (Plague Bases)

* fix >=

Co-authored-by: mgleed <[email protected]>
2022-06-19 15:22:51 -04:00
Gleed 4a0396fe81 Enhancement: Replace pather.adjust_abs_range_to_screen() with ui_manager.get_closest_non_hud_pixel() (#908) 2022-06-19 15:06:15 -04:00
aeon0 0f34b4951c Fix bug that char will not id items even if supposed to (#901) 2022-06-18 17:42:05 +02:00
Riddle d7f776ad37 Merge pull request #899 from aeon0/nip-error-fix-2
Better error message
2022-06-18 01:48:23 -04:00
Riddle 723a75e672 Better error message 2022-06-18 01:46:58 -04:00
Gleed 541810f2e3 Revert "Bugfix?: give more time for select_tp() for detect capabilities (#895)" (#898)
This reverts commit 1c07b74f79.
2022-06-17 22:06:31 -04:00
Riddle e9b5cf6dc5 Merge pull request #897 from aeon0/nip-error-fix-2
Nip error fix 2
2022-06-17 22:04:29 -04:00
Riddle 4b2e1f7059 Better error message 2022-06-17 22:03:50 -04:00
Riddle 6d43868b4d added error msg 2022-06-17 22:00:50 -04:00
Gleed 1c07b74f79 Bugfix?: give more time for select_tp() for detect capabilities (#895) 2022-06-17 20:47:53 -04:00
Riddle 4deed0867a Merge pull request #896 from aeon0/nip-indexerror-fix
fix
2022-06-17 20:33:05 -04:00
Riddle 99579bfda4 fix 2022-06-17 20:06:09 -04:00
Gleed cb1f443d23 Fix tests failing on d2r_path validation 2022-06-17 16:31:10 -04:00
Riddle e890be4b38 Merge pull request #893 from aeon0/add-missing-nip-data
Add missing nip data
2022-06-17 16:10:41 -04:00
Riddle 2d3deb74ae added nip data 2022-06-17 15:58:56 -04:00
Gleed 0acd6d8cc9 Enhancement: Ensure d2r_path exists before starting Botty 2022-06-17 15:51:33 -04:00
Sosa d77ad0dc7c Update default.nip (#889)
Fixed B.O Helm Line
Added Griffon's Eye
Added Kira's Guardian
2022-06-17 15:37:10 -04:00
Gleed 8bc909eb72 Bugfix: Fix launch options (#891)
* init

* fix launch_options
2022-06-17 15:36:51 -04:00
Gleed 329f4fcb5c Bugfix: Character name -> mod directory name support 2022-06-17 15:17:09 -04:00
Gleed 5fd89b5b6b Update dev.md 2022-06-17 10:32:17 -04:00
Gleed f9780c5942 Bugfix: Build process (#887)
* Bump version to v0.8.0

* Bump version to v0.8.0

* init

* vers
2022-06-17 10:00:05 -04:00
Gleed d895dd0b40 Fix: bump version and fix build.py (#885) 2022-06-16 22:18:42 -04:00
Gleed a786ba4f08 Fix: max quantity in readme (#884) 2022-06-16 22:18:25 -04:00
Riddle 9d4c8681ca Fixed bug with @ next to paren throwing error 2022-06-16 18:00:30 -04:00
30 changed files with 391 additions and 316 deletions
+2
View File
@@ -51,6 +51,8 @@ Poison damage is no longer calculated, but is now read as it's raw value. Exampl
`[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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

+3 -1
View File
@@ -76,7 +76,7 @@ if __name__ == "__main__":
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 ..")
@@ -86,6 +86,8 @@ if __name__ == "__main__":
shutil.copy("config/game.ini", f"{botty_dir}/config/")
shutil.copy("config/params.ini", f"{botty_dir}/config/")
shutil.copy("config/shop.ini", f"{botty_dir}/config/")
shutil.copy("config/default.nip", f"{botty_dir}/config/")
os.makedirs(f"{botty_dir}/config/nip", exist_ok=True)
shutil.copy("README.md", f"{botty_dir}/")
shutil.copytree("assets", f"{botty_dir}/assets")
clean_up()
+152 -138
View File
@@ -91,7 +91,7 @@
//================= Gems ================
//---------------------------------------
//[Name] == Chippedaamethyst
//[Name] == Chippedamethyst
//[Name] == Chippeddiamond
//[Name] == Chippedemerald
//[Name] == Chippedruby
@@ -319,9 +319,9 @@
[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 # [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 ] >>>>>>>>>
@@ -346,7 +346,7 @@
//([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
//[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 ] >>>>>>>>>
@@ -377,7 +377,7 @@
// <<<<<<<<< [ B.O Sticks ] >>>>>>>>>
//[Name] == Throwingspear && [Quality] == Magic # [Warcriesskilltab] >= 3
// <<<<<<<<< [ GG Club ] >>>>>>>>>
// <<<<<<<<< [ Gg Club ] >>>>>>>>>
([Name] == Club || [Name] == Spikedclub) && [Quality] == Magic # [Warcriesskilltab] >= 3 && [Strength] > 0
// <<<<<<<<< [ Magic Scepters ] >>>>>>>>>
@@ -396,8 +396,8 @@
//[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
([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
@@ -454,16 +454,16 @@
[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 ] >>>>>>>>>
// <<<<<<<<< [ 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 # [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
[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
@@ -472,7 +472,7 @@
[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
[Type] == Jewel && [Quality] == Rare # [Enhanceddamage] >= 20 && [Strength] >= 5 && [Dexterity] >= 5 // Lld
//-------------------------------------------
//================= Circlets ================
@@ -491,7 +491,7 @@
[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 ] >>>>>>>>>
// <<<<<<<<< [ 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
@@ -587,8 +587,8 @@
//================= 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] >= 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
//----------------------------------------
@@ -643,15 +643,15 @@
//[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] == Sacredarmor && [Quality] == Superior && [Flag] != Ethereal # [Sockets] == 0 && [Enhanceddefense] >= 10 //Plain Superior
[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] == 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
@@ -699,26 +699,26 @@
//-------------------------------------------------------
// <<<<<<<<< [ Non-Ethereal Socketed/Non-Socketed Barbarian Helms ] >>>>>>>>>
[Type] == Primalhelm && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skillbattleorders]+[Skillbattlecommand] >= 4 || [Skillbattleorders]+[Skillfinditem] >= 4 || [Skillbattleorders]+[Skillshout] >= 4) && [Sockets] == 0
[Type] == Primalhelm && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skillbattleorders]+[Skillbattlecommand] >= 4 || [Skillbattleorders]+[Skillfinditem] >= 4 || [Skillbattleorders]+[Skillshout] >= 4) && [Sockets] == 3 // Socketed
[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] <= Superior && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 0
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 3 // Socketed
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 0
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 3 // Socketed
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 0
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 3 // Socketed
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 0
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillhurricane] >= 2 && [Skilltornado] >= 2 && [Sockets] == 3 // Socketed
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 0
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skillfissure] >= 2 && [Skillvolcano] >= 2 && [Sockets] == 3 // Socketed
[Type] == Pelt && [Quality] <= Superior && [Flag] != Ethereal # [Skilltornado] == 3 && ([Skillcyclonearmor] >= 2 || [Skillhurricane] >= 2 || [Skilloaksage] >= 2) && [Sockets] == 0
[Type] == Pelt && [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
[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
//-----------------------------------------------
@@ -726,49 +726,52 @@
//-----------------------------------------------
// <<<<<<<<< [ White/Eth Superior/Non-Superior Socketed/Non-Socketed Shields ] >>>>>>>>>
//([Name] == Akarantarge || [Name] == Akaranrondache || [Name] == Crownshield) && [Quality] <= Superior && [Flag] != Ethereal # [Allresist] >= 40 // V/LLD Paladin Shield Base
//[Name] == Monarch && [Quality] == Normal # [Sockets] == 0 //Plain Monarch
//([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] == 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] <= 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) // Suprior Eth Exile
[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] <= Superior && [Flag] != Ethereal # ([Skillbonespear]+[Skillbonespirit] >= 6 || [Skillpoisonexplosion]+[Skillpoisonnova] >= 6) && [Sockets] == 0
[Type] == Voodooheads && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skillbonespear]+[Skillbonespirit] >= 6 || [Skillpoisonexplosion]+[Skillpoisonnova] >= 6) && [Sockets] == 3 // Socketed
[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 ================
//================= 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] == 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 # [Sockets] == 0 && [Enhanceddamage] >= 10 //Plain Superior
[Name] == Crystalsword && [Quality] == Superior # [Sockets] == 0 && [Enhanceddamage] >= 10 //Plain Superior
[Name] == Flail && [Quality] == Superior # [Sockets] == 0 && [Enhanceddamage] >= 14 //Plain Superior
[Name] == Phaseblade && [Quality] == Superior # [Sockets] == 0 && [Enhanceddamage] >= 10 //Plain Superior
[Name] == Warscepter && [Quality] == Superior # [Sockets] == 0 && ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Enhanceddamage] >= 0 //Plain Superior
[Name] == Divinescepter && [Quality] == Superior # [Sockets] == 0 && ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Enhanceddamage] >= 0 //Plain Superior
[Name] == Caduceus && [Quality] == Superior # [Sockets] == 0 && ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Enhanceddamage] >= 0 //Plain Superior
// <<<<<<<<< [ 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
@@ -779,43 +782,49 @@
//[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 # [Sockets] >= 5 && [Enhanceddamage] >= 10 // Socketed Sup
[Name] == Crystalsword && [Quality] == Superior # [Sockets] >= 4 && [Enhanceddamage] >= 10 // Socketed Sup
[Name] == Flail && [Quality] == Superior # [Sockets] >= 4 && [Enhanceddamage] >= 14 // Socketed Sup
[Name] == Phaseblade && [Quality] == Superior # [Sockets] >= 5 && [Enhanceddamage] >= 10 // Socketed Sup
[Name] == Warscepter && [Quality] == Superior # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 && [Enhanceddamage] >= 0 // Socketed Sup
[Name] == Divinescepter && [Quality] == Superior # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 && [Enhanceddamage] >= 0 // Socketed Sup
[Name] == Caduceus && [Quality] == Superior # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && [Sockets] == 5 && [Enhanceddamage] >= 0 // Socketed Sup
// <<<<<<<<< [ 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 Socketed/Non-Socketed Weapons ] >>>>>>>>>
[Name] == Berserkeraxe && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 5) // Socketed Eth
[Name] == Crystalsword && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth
[Name] == Flail && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 4) // Socketed Eth
[Name] == Phaseblade && [Quality] == Normal && [Flag] == Ethereal # ([Sockets] == 0 || [Sockets] >= 5) // Socketed Eth
[Name] == Warscepter && [Quality] == Normal && [Flag] == Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && ([Sockets] == 0 || [Sockets] == 5) // Socketed Eth
[Name] == Divinescepter && [Quality] == Normal && [Flag] == Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && ([Sockets] == 0 || [Sockets] == 5) // Socketed Eth
[Name] == Caduceus && [Quality] == Normal && [Flag] == Ethereal # ([Skillblessedhammer] >= 3 || [Skillconviction] >= 3 || [Skillfistoftheheavens] >= 3 || [Skillfanaticism] >= 3 || [Skillholyshield] >= 3) && ([Sockets] == 0 || [Sockets] == 5) // Socketed Eth
// <<<<<<<<< [ 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
// <<<<<<<<< [ 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 ================
//================= 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 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 ] >>>>>>>>>
// <<<<<<<<< [ 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
@@ -826,18 +835,18 @@
//[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 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 ] >>>>>>>>>
// <<<<<<<<< [ 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
@@ -847,7 +856,7 @@
//[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 ] >>>>>>>>>
// <<<<<<<<< [ 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
@@ -857,7 +866,7 @@
[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 ] >>>>>>>>>
// <<<<<<<<< [ 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
@@ -872,38 +881,38 @@
//------------------------------------------------------
// <<<<<<<<< [ Non-Ethereal Superior/Non-Superior Assassin Claws ] >>>>>>>>>
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skilllightningsentry] >= 3 || [Skilldeathsentry] >= 3) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skilllightningsentry] >= 3 || [Skilldeathsentry] >= 3) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # [Skillbladeshield] >= 3 && ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # [Skillbladeshield] >= 3 && ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # [Skillweaponblock] >= 3 && ([Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && [Quality] <= Superior && [Flag] != Ethereal # [Skillweaponblock] >= 3 && ([Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skilllightningsentry] >= 3 || [Skilldeathsentry] >= 3) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skilllightningsentry] >= 3 || [Skilldeathsentry] >= 3) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillbladeshield] >= 3 && ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillbladeshield] >= 3 && ([Skillweaponblock] >= 3 || [Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 3 // Chaos Socketed
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillweaponblock] >= 3 && ([Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 2 || [Skillbladeshield] >= 2 || [Skilldragonflight] >= 2 || [Skillmindblast] >= 1) && [Sockets] == 0 // Chaos
[Type] == Assassinclaw && [Class] == Elite && ([Quality] == Normal || [Quality] == Superior) && [Flag] != Ethereal # [Skillweaponblock] >= 3 && ([Skillclawmastery] >= 2 || [Skillfade] >= 2 || [Skillvenom] >= 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] <= Superior # [Skillenergyshield] == 3 && [Skillchillingarmor] >= 1 && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillenergyshield] == 3 && [Skillchillingarmor] >= 1 && [Sockets] >= 4 // Memory Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillchillingarmor] >= 1) && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillchillingarmor] >= 1) && [Sockets] >= 4 // Memory Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillenergyshield] == 3 && [Skillenchant] >= 1 && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillenergyshield] == 3 && [Skillenchant] >= 1 && [Sockets] >= 4 // Memory Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillenchant] >= 1) && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && [Quality] <= Superior # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillenchant] >= 1) && [Sockets] >= 4 // Memory Socketed
([Name] == WarStaff || [Name] == RuneStaff || [Name] == ArchonStaff) && [Quality] <= Superior # [SkillLightningMastery] == 3 && ([SkillLightning] == 3 || [Skillchainlightning] == 3 || [Skillthunderstorm] == 3) && [Skillenergyshield] >= 1 && [Sockets] == 0 // CTA/Obsession
([Name] == WarStaff || [Name] == RuneStaff || [Name] == ArchonStaff) && [Quality] <= Superior # [SkillLightningMastery] == 3 && ([SkillLightning] == 3 || [Skillchainlightning] == 3 || [Skillthunderstorm] == 3) && [Skillenergyshield] >= 1 && [Sockets] >= 5 // CTA/Obsession Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenergyshield] == 3 && [Skillchillingarmor] >= 1 && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenergyshield] == 3 && [Skillchillingarmor] >= 1 && [Sockets] >= 4 // Memory Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillchillingarmor] >= 1) && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillchillingarmor] >= 1) && [Sockets] >= 4 // Memory Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenergyshield] == 3 && [Skillenchant] >= 1 && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillenergyshield] == 3 && [Skillenchant] >= 1 && [Sockets] >= 4 // Memory Socketed
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillenchant] >= 1) && [Sockets] == 0 // Memory
([Name] == Gnarledstaff || [Name] == Battlestaff) && ([Quality] == Normal || [Quality] == Superior) # [Skillthunderstorm] == 3 && ([Skillenergyshield] == 3 || [Skillenchant] >= 1) && [Sockets] >= 4 // Memory Socketed
([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skilllightningmastery] == 3 && ([Skilllightning] == 3 || [Skillchainlightning] == 3 || [Skillthunderstorm] == 3) && [Skillenergyshield] >= 1 && [Sockets] == 0 // Cta/Obsession
([Name] == Warstaff || [Name] == Runestaff || [Name] == Archonstaff) && ([Quality] == Normal || [Quality] == Superior) # [Skilllightningmastery] == 3 && ([Skilllightning] == 3 || [Skillchainlightning] == 3 || [Skillthunderstorm] == 3) && [Skillenergyshield] >= 1 && [Sockets] >= 5 // Cta/Obsession Socketed
//---------------------------------------------------------
//================= Necromancer Wand Bases ================
//---------------------------------------------------------
// <<<<<<<<< [ Ethereal/Non-Ethereal Superior/Non-Superior Socketed/Non-Socketed Necromancer Wands ] >>>>>>>>>
[Type] == Wand && [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] <= 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
[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 ================
@@ -911,9 +920,9 @@
// <<<<<<<<< [ Socketed Amazon Bows ] >>>>>>>>>
//[Type] == Bow && [Class] == Elite && [Quality] == Normal # [Sockets] == 0 // Faith
[Type] == Bow && [Class] == Elite && [Quality] == Normal # [Sockets] == 4 // 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
[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
@@ -1321,8 +1330,8 @@
//[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] == 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
@@ -1368,11 +1377,16 @@
[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 && [Normaldamagereduction] >= 10 && [Allres] >= 20 && [Sockets] >= 1 // Crown Of Ages
//[Name] == Corona && [Quality] == Unique && [Flag] != Ethereal # [Plusdefense] == 150 && [Normaldamagereduction] == 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] == 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 ================
@@ -1410,9 +1424,9 @@
[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 # [Enhanceddefense] == 180 && [Normaldamagereduction] == 15 // Arkaine's Valor Perfect
//[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 # [Enhanceddefense] == 200 && [Plusdefense] == 150 && [Strength] == 50 // Leviathan Perfect
//[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
@@ -1431,7 +1445,7 @@
//[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 # [Normaldamagereduction] >= 35 // Stormshield
[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
@@ -1455,8 +1469,8 @@
//[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] == 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
@@ -1498,7 +1512,7 @@
//[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] == Tyrantclub // Demon Limb
//[Idname] == Fleshrender // Fleshrender
//[Idname] == Baranarsstar // Baranar's Star
//[Idname] == Thegeneralstandoliga // The General's Tan Do Li Ga
@@ -1654,4 +1668,4 @@
//[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
//[Name] == Zakarumshield && [Quality] == Unique # [Enhanceddefense] >= 150 && [Itemabsorbfirepercent] >= 15 && [Strength] >= 20 // Dragonscale
+1 -1
View File
@@ -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 <PREVIOUS_TAG>..HEAD --oneline --decorate`
+1 -1
View File
@@ -11,7 +11,7 @@ dependencies:
- rapidfuzz
- pip:
- pyinstaller
- opencv-python
- opencv-python==4.5.5.64
- transitions
- mss
- numpy
+3 -2
View File
@@ -14,6 +14,7 @@ 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):
@@ -106,8 +107,8 @@ class Bone_Necro(IChar):
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
+3 -3
View File
@@ -15,7 +15,7 @@ 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
import template_finder
from ui_manager import detect_screen_object, ScreenObjects
from ui_manager import detect_screen_object, ScreenObjects, get_closest_non_hud_pixel
class IChar:
_CrossGameCapabilities: None | CharacterCapabilities = None
@@ -309,8 +309,8 @@ class IChar:
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)
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)
+3 -4
View File
@@ -13,7 +13,7 @@ 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):
@@ -352,11 +352,10 @@ class Necro(IChar):
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)
+3 -2
View File
@@ -13,6 +13,7 @@ import screen as screen
import numpy as np
import time
import os
from ui_manager import get_closest_non_hud_pixel
class Poison_Necro(IChar):
def __init__(self, skill_hotkeys: dict, pather: Pather):
@@ -372,8 +373,8 @@ class Poison_Necro(IChar):
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])
+2 -2
View File
@@ -6,7 +6,7 @@ import os
from dataclasses import dataclass
from logger import Logger
config_lock = threading.Lock()
from utils.misc import wait
from utils.misc import wait, only_lowercase_letters
def _default_iff(value, iff, default = None):
return default if value == iff else value
@@ -303,7 +303,7 @@ class Config:
"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").replace("<name>", self.general["name"]),
"launch_options": self._select_val("advanced_options", "launch_options").replace("<name>", only_lowercase_letters(self.general["name"].lower())),
"override_capabilities": _default_iff(Config()._select_optional("advanced_options", "override_capabilities"), ""),
}
+3
View File
@@ -7050,6 +7050,9 @@ NIP_ALIAS_STAT_PATTERNS = {
],
"{:d}% Enhanced Damage": [
"5007"
],
"{:d} to Summoning Skills (Necromancer Only)": [
"188,21"
]
}
-3
View File
@@ -2,9 +2,6 @@ from enum import Enum
from d2r_image.data_models import ItemQuality
import cv2
HUD_MASK = cv2.imread(f"assets/hud_mask.png", cv2.IMREAD_GRAYSCALE)
HUD_MASK = cv2.threshold(HUD_MASK, 1, 255, cv2.THRESH_BINARY)[1]
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]]]
+4 -3
View File
@@ -12,10 +12,11 @@ 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, HUD_MASK, BOX_EXPECTED_HEIGHT_RANGE, BOX_EXPECTED_WIDTH_RANGE
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
@@ -163,8 +164,8 @@ def _contains_color(img: np.ndarray, color: str) -> bool:
def clean_img(inp_img: np.ndarray, black_thresh: int = 14) -> np.ndarray:
img = inp_img[:, :, :]
if img.shape[0] == HUD_MASK.shape[0] and img.shape[1] == HUD_MASK.shape[1]:
img = cv2.bitwise_and(img, img, mask=HUD_MASK)
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)
+29 -18
View File
@@ -87,9 +87,10 @@ class HealthManager:
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)
@@ -122,19 +123,20 @@ class HealthManager:
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 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
@@ -143,6 +145,10 @@ class HealthManager:
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")
@@ -152,9 +158,14 @@ if __name__ == "__main__":
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()
+11 -14
View File
@@ -271,28 +271,26 @@ def inspect_items(inp_img: np.ndarray = None, close_window: bool = True, game_st
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)
need_id = None
keep = None
box = BoxInfo(
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
)
tome_state = None
try:
if (is_unidentified and should_id(item_properties.as_dict())):
need_id = True
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)
need_id = False
box.need_id = False
is_unidentified = True
# recapture box after ID
mouse.move(x_m, y_m, randomize = 4, delay_factor = delay)
@@ -303,34 +301,33 @@ def inspect_items(inp_img: np.ndarray = None, close_window: bool = True, game_st
if item_box is not None:
log_item(item_box, item_properties)
# decide whether to keep item
keep, expression = should_keep(item_properties.as_dict())
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
keep &= not bool(consumables.is_consumable(item_properties))
box.keep &= not bool(consumables.is_consumable(item_properties))
box.keep = keep
if keep:
if box.keep:
Logger.info(f"Keep {item_name}. Expression: {expression}")
sell = False
elif need_id:
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 (keep or need_id):
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 (keep and not need_id):
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 keep or sell or need_id:
if box.keep or sell or box.need_id:
# save item info
boxes.append(box)
else:
+12
View File
@@ -616,6 +616,16 @@ 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'
@@ -1189,6 +1199,8 @@ NTIPAliasStat['allres']='6969'
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'
+4 -3
View File
@@ -207,14 +207,15 @@ def _load_nip_expressions(filepath):
try:
load_nip_expression(line)
except Exception as e:
file = filepath.split('\\config/')[1].replace("/", "\\")
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_nip_file_path = os.path.join(os.path.abspath(os.path.join(os.path.join(os.path.dirname(__file__), os.pardir), os.pardir)), 'config/default.nip')
nip_path = os.path.join(os.path.abspath(os.path.join(os.path.join(os.path.dirname(__file__), os.pardir), os.pardir)), 'config/nip')
default_nip_file_path = f"{os.getcwd()}/config/default.nip"
nip_path = f"{os.getcwd()}/config/nip"
glob_nip_path = os.path.join(nip_path, '**', '*.nip')
nip_file_paths = glob.glob(glob_nip_path, recursive=True)
+27 -23
View File
@@ -22,7 +22,7 @@ init()
WHITESPACE = " \t\n\r\v\f"
DIGITS = "0123456789.-" # ! Put % back in here when ready to use percentages.
SYMBOLS = [">", "=> ", "<", "<=", "=", "!", "", "", ",", "&", "|", "#", "/"]
SYMBOLS = [">", "=> ", "<", "<=", "=", "!", "", "", ",", "&", "|", "#"]
MATH_SYMBOLS = ["(", ")", "^", "*", "/", "\\", "+", "-"]
CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'"
@@ -93,6 +93,16 @@ class Lexer:
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.
if self.tokens[-1].type == 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:
@@ -307,28 +317,22 @@ class Lexer:
if self.current_section == NipSections.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 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)
# if self.tokens[-2].type != TokenType.KeywordNTIPAliasIDName: # * Make sure the last token isn't [idname]
# # Add all the NTIPAlias* to a dict
# NTIPAliasAll = NTIPAliasClass | NTIPAliasQuality | NTIPAliasClassID | NTIPAliasFlag | NTIPAliasType
# for key in NTIPAliasAll:
# if levenshtein(lookup_key, key) < 3:
# raise NipSyntaxError( "NIP_0x4", f"Unknown NTIP lookup: {lookup_key} did you mean {key}?", self._get_text())
# else:
# return Token(TokenType.ValueNTIPAliasIDName, lookup_key)
return Token(TokenType.UNKNOWN, lookup_key)
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 NipSyntaxError("NIP_0x20", f"Bad token sequence: {self._get_text()}", self._get_text())
return Token(TokenType.UNKNOWN, lookup_key)
elif self.current_section == NipSections.STAT:
if lookup_key in NTIPAliasStat:
return Token(TokenType.ValueNTIPAliasStat, lookup_key)
+3
View File
@@ -139,6 +139,9 @@ def validate_correct_math_syntax(left_token=None, right_token=None):
TokenType.ValueNTIPAliasType,
TokenType.NUMBER,
TokenType.LPAREN,
TokenType.RPAREN,
]
if left_token and left_token.type not in allowed_left_and_right_tokens:
raise NipSyntaxError("NIP_0x3", "unexpected token on left of math operator")
+5 -43
View File
@@ -13,7 +13,7 @@ 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
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
@@ -535,44 +535,6 @@ class Pather:
# 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]:
node = self._nodes[node_idx]
@@ -590,7 +552,7 @@ class Pather:
# 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
@@ -667,8 +629,8 @@ class Pather:
pos_abs = last_direction
else:
angle = random.random() * math.pi * 2
pos_abs = (math.cos(angle) * 150, math.sin(angle) * 150)
pos_abs = self._adjust_abs_range_to_screen(pos_abs)
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)
@@ -733,7 +695,7 @@ if __name__ == "__main__":
# 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)
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)
+3 -5
View File
@@ -7,6 +7,7 @@ from math import dist
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
@@ -120,8 +121,7 @@ def _process_image(img, mask_char:bool=False, mask_hud:bool=True, erode:int=None
"""
img = 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')
@@ -180,8 +180,6 @@ 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()
@@ -209,7 +207,7 @@ class LiveViewer:
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:
+15 -15
View File
@@ -14,21 +14,21 @@ 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
# """
# 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
# if item_pickup_text.name == "ITEM_PICKUP_DISABLED":
# return True
# keyboard.send('enter')
# wait(0.1, 0.25)
# keyboard.send('up')
# wait(0.1, 0.25)
# keyboard.send('enter')
# wait(0.1, 0.25)
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
if item_pickup_text.name == "ITEM_PICKUP_DISABLED":
return True
keyboard.send('enter')
wait(0.1, 0.25)
keyboard.send('up')
wait(0.1, 0.25)
keyboard.send('enter')
wait(0.1, 0.25)
return True
def save_and_exit() -> bool:
+67 -1
View File
@@ -3,12 +3,14 @@ import os
import numpy as np
import time
import cv2
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_abs_to_monitor
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
@@ -331,6 +333,70 @@ def center_mouse(delay_factor: list = None):
else:
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__":
import keyboard
+7 -2
View File
@@ -4,7 +4,7 @@ import shutil
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:
@@ -89,8 +89,13 @@ def set_launch_settings(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 = Config().general["name"]
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")
new_path = os.path.join(Config().general['d2r_path'], f"mods/{mod_name}")
os.makedirs(new_path, exist_ok=True)
try:
+1 -1
View File
@@ -3,7 +3,7 @@ import zipfile
import os
import shutil
url = "https://github.com/mgleed/botty-test-assets/archive/refs/heads/main.zip"
url = "https://github.com/bottytools/botty-test-assets/archive/refs/heads/main.zip"
extract_dir = "tmp"
asset_dir = "test/assets"
+6 -1
View File
@@ -260,4 +260,9 @@ def slugify(value, allow_unicode=False):
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('-_')
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
+1 -1
View File
@@ -1 +1 @@
__version__ = '0.7.4-dev'
__version__ = '0.8.0-dev'
+20
View File
@@ -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)
-29
View File
@@ -1,29 +0,0 @@
import pytest
from logger import Logger
from pather import Pather
import screen
class TestPather:
def setup_method(self):
Logger.init()
Logger.remove_file_logger()
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):
screen.set_window_position(0, 0)
should_be_adapted = expected
pos_abs = screen.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)