diff --git a/README.md b/README.md index 3f59402d3..a45b01f5f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ All settings will automatically be set when you execute `main.exe` and press the ### 2) Supported builds -Check the documentation for **params.ini** further down. Different Sorc builds, Hammerdin, Barb, Trapsin are already implemented to different extents. It is quite straightforward to implement new classes. Give it a go if you like! +Botty will auto-detect hotkeys for the character using **params.ini** saved_games_folder and key_file and use the **params.ini** type to "pilot" the character. + +The logic for "piloting", as well as supported **params.ini** types can be found in the [char folder](https://github.com/bottytools/botty/tree/master/src/char). ### 3) Start Location @@ -82,6 +84,7 @@ order=run_pindle, run_eldritch | name | Name used in terminal and discord messages. | | randomize_runs | Randomize the order of `[routes]` specified in `params.ini`. | | saved_games_folder | [Optional] Defaults to `~\Saved Games\Diablo II Resurrected`. Used to store configuration settings for `f9` / auto settings. | +| key_file | Key(o) file for the character (found in the Saved Games folder). 'key' is offline characters, 'keyo' is online characters. Some online characters may have a hash added to them: Paladin53672482.keyo. | | custom_loot_message_hook | Add your message hook here (such as Discord channel) to get info about loot | | custom_message_hook | Add your message hook here (such as Discord channel) to get info about botty status updates, discord webhook is default. | | discord_log_chicken | Set to `1` to enable messages about bot chickens, `0` to disable. | diff --git a/assets/templates/ui/skills/amplify_damage.png b/assets/templates/ui/skills/amplify_damage.png new file mode 100644 index 000000000..499c208fc Binary files /dev/null and b/assets/templates/ui/skills/amplify_damage.png differ diff --git a/assets/templates/ui/skills/arctic_blast.png b/assets/templates/ui/skills/arctic_blast.png new file mode 100644 index 000000000..fdcff83cf Binary files /dev/null and b/assets/templates/ui/skills/arctic_blast.png differ diff --git a/assets/templates/ui/skills/armageddon.png b/assets/templates/ui/skills/armageddon.png new file mode 100644 index 000000000..e9dac6bf3 Binary files /dev/null and b/assets/templates/ui/skills/armageddon.png differ diff --git a/assets/templates/ui/skills/attack.png b/assets/templates/ui/skills/attack.png new file mode 100644 index 000000000..2e148cdfd Binary files /dev/null and b/assets/templates/ui/skills/attack.png differ diff --git a/assets/templates/ui/skills/attract.png b/assets/templates/ui/skills/attract.png new file mode 100644 index 000000000..a81aa696c Binary files /dev/null and b/assets/templates/ui/skills/attract.png differ diff --git a/assets/templates/ui/skills/bash.png b/assets/templates/ui/skills/bash.png new file mode 100644 index 000000000..64c59851a Binary files /dev/null and b/assets/templates/ui/skills/bash.png differ diff --git a/assets/templates/ui/skills/battle_command.png b/assets/templates/ui/skills/battle_command.png new file mode 100644 index 000000000..ac26ae1cc Binary files /dev/null and b/assets/templates/ui/skills/battle_command.png differ diff --git a/assets/templates/ui/skills/battle_cry.png b/assets/templates/ui/skills/battle_cry.png new file mode 100644 index 000000000..109759cde Binary files /dev/null and b/assets/templates/ui/skills/battle_cry.png differ diff --git a/assets/templates/ui/skills/battle_orders.png b/assets/templates/ui/skills/battle_orders.png new file mode 100644 index 000000000..1bb240a87 Binary files /dev/null and b/assets/templates/ui/skills/battle_orders.png differ diff --git a/assets/templates/ui/skills/bc.png b/assets/templates/ui/skills/bc.png deleted file mode 100644 index 75d578b2a..000000000 Binary files a/assets/templates/ui/skills/bc.png and /dev/null differ diff --git a/assets/templates/ui/skills/berserk.png b/assets/templates/ui/skills/berserk.png new file mode 100644 index 000000000..0225c9536 Binary files /dev/null and b/assets/templates/ui/skills/berserk.png differ diff --git a/assets/templates/ui/skills/blade_fury.png b/assets/templates/ui/skills/blade_fury.png new file mode 100644 index 000000000..b138a957f Binary files /dev/null and b/assets/templates/ui/skills/blade_fury.png differ diff --git a/assets/templates/ui/skills/blade_sentinel.png b/assets/templates/ui/skills/blade_sentinel.png new file mode 100644 index 000000000..61498640c Binary files /dev/null and b/assets/templates/ui/skills/blade_sentinel.png differ diff --git a/assets/templates/ui/skills/blade_shield.png b/assets/templates/ui/skills/blade_shield.png new file mode 100644 index 000000000..d8ef34ab8 Binary files /dev/null and b/assets/templates/ui/skills/blade_shield.png differ diff --git a/assets/templates/ui/skills/blades_of_ice.png b/assets/templates/ui/skills/blades_of_ice.png new file mode 100644 index 000000000..71b7e25b3 Binary files /dev/null and b/assets/templates/ui/skills/blades_of_ice.png differ diff --git a/assets/templates/ui/skills/blaze.png b/assets/templates/ui/skills/blaze.png new file mode 100644 index 000000000..473f44d13 Binary files /dev/null and b/assets/templates/ui/skills/blaze.png differ diff --git a/assets/templates/ui/skills/blessed_aim.png b/assets/templates/ui/skills/blessed_aim.png new file mode 100644 index 000000000..591cc2348 Binary files /dev/null and b/assets/templates/ui/skills/blessed_aim.png differ diff --git a/assets/templates/ui/skills/blessed_hammer.png b/assets/templates/ui/skills/blessed_hammer.png new file mode 100644 index 000000000..c50729afc Binary files /dev/null and b/assets/templates/ui/skills/blessed_hammer.png differ diff --git a/assets/templates/ui/skills/blizzard.png b/assets/templates/ui/skills/blizzard.png new file mode 100644 index 000000000..fea6e4831 Binary files /dev/null and b/assets/templates/ui/skills/blizzard.png differ diff --git a/assets/templates/ui/skills/blood_golem.png b/assets/templates/ui/skills/blood_golem.png new file mode 100644 index 000000000..1e88ce5cc Binary files /dev/null and b/assets/templates/ui/skills/blood_golem.png differ diff --git a/assets/templates/ui/skills/bo.png b/assets/templates/ui/skills/bo.png deleted file mode 100644 index c31013665..000000000 Binary files a/assets/templates/ui/skills/bo.png and /dev/null differ diff --git a/assets/templates/ui/skills/bone_armor.png b/assets/templates/ui/skills/bone_armor.png new file mode 100644 index 000000000..983d1be32 Binary files /dev/null and b/assets/templates/ui/skills/bone_armor.png differ diff --git a/assets/templates/ui/skills/bone_prison.png b/assets/templates/ui/skills/bone_prison.png new file mode 100644 index 000000000..a23735b86 Binary files /dev/null and b/assets/templates/ui/skills/bone_prison.png differ diff --git a/assets/templates/ui/skills/bone_spear.png b/assets/templates/ui/skills/bone_spear.png new file mode 100644 index 000000000..88a6aa781 Binary files /dev/null and b/assets/templates/ui/skills/bone_spear.png differ diff --git a/assets/templates/ui/skills/bone_spirit.png b/assets/templates/ui/skills/bone_spirit.png new file mode 100644 index 000000000..db41f49c6 Binary files /dev/null and b/assets/templates/ui/skills/bone_spirit.png differ diff --git a/assets/templates/ui/skills/bone_wall.png b/assets/templates/ui/skills/bone_wall.png new file mode 100644 index 000000000..2d731f967 Binary files /dev/null and b/assets/templates/ui/skills/bone_wall.png differ diff --git a/assets/templates/ui/skills/burst_of_speed.png b/assets/templates/ui/skills/burst_of_speed.png new file mode 100644 index 000000000..cb9f850f0 Binary files /dev/null and b/assets/templates/ui/skills/burst_of_speed.png differ diff --git a/assets/templates/ui/skills/carrion_vine.png b/assets/templates/ui/skills/carrion_vine.png new file mode 100644 index 000000000..abd4d9dff Binary files /dev/null and b/assets/templates/ui/skills/carrion_vine.png differ diff --git a/assets/templates/ui/skills/chain_lightning.png b/assets/templates/ui/skills/chain_lightning.png new file mode 100644 index 000000000..14a9968db Binary files /dev/null and b/assets/templates/ui/skills/chain_lightning.png differ diff --git a/assets/templates/ui/skills/charge.png b/assets/templates/ui/skills/charge.png new file mode 100644 index 000000000..78e83c3fe Binary files /dev/null and b/assets/templates/ui/skills/charge.png differ diff --git a/assets/templates/ui/skills/charged_bolt.png b/assets/templates/ui/skills/charged_bolt.png new file mode 100644 index 000000000..fc384fe16 Binary files /dev/null and b/assets/templates/ui/skills/charged_bolt.png differ diff --git a/assets/templates/ui/skills/charged_bolt_sentry.png b/assets/templates/ui/skills/charged_bolt_sentry.png new file mode 100644 index 000000000..13c2f6ebb Binary files /dev/null and b/assets/templates/ui/skills/charged_bolt_sentry.png differ diff --git a/assets/templates/ui/skills/charged_strike.png b/assets/templates/ui/skills/charged_strike.png new file mode 100644 index 000000000..66e8bb451 Binary files /dev/null and b/assets/templates/ui/skills/charged_strike.png differ diff --git a/assets/templates/ui/skills/chilling_armor.png b/assets/templates/ui/skills/chilling_armor.png new file mode 100644 index 000000000..87c8ab10c Binary files /dev/null and b/assets/templates/ui/skills/chilling_armor.png differ diff --git a/assets/templates/ui/skills/claw_of_thunder.png b/assets/templates/ui/skills/claw_of_thunder.png new file mode 100644 index 000000000..49deffabe Binary files /dev/null and b/assets/templates/ui/skills/claw_of_thunder.png differ diff --git a/assets/templates/ui/skills/clay_golem.png b/assets/templates/ui/skills/clay_golem.png new file mode 100644 index 000000000..8c04fc586 Binary files /dev/null and b/assets/templates/ui/skills/clay_golem.png differ diff --git a/assets/templates/ui/skills/cleansing.png b/assets/templates/ui/skills/cleansing.png new file mode 100644 index 000000000..385bb67d1 Binary files /dev/null and b/assets/templates/ui/skills/cleansing.png differ diff --git a/assets/templates/ui/skills/cloak_of_shadows.png b/assets/templates/ui/skills/cloak_of_shadows.png new file mode 100644 index 000000000..cb2f13d61 Binary files /dev/null and b/assets/templates/ui/skills/cloak_of_shadows.png differ diff --git a/assets/templates/ui/skills/cobra_strike.png b/assets/templates/ui/skills/cobra_strike.png new file mode 100644 index 000000000..0a15d1349 Binary files /dev/null and b/assets/templates/ui/skills/cobra_strike.png differ diff --git a/assets/templates/ui/skills/cold_arrow.png b/assets/templates/ui/skills/cold_arrow.png new file mode 100644 index 000000000..086e39bcd Binary files /dev/null and b/assets/templates/ui/skills/cold_arrow.png differ diff --git a/assets/templates/ui/skills/concentrate.png b/assets/templates/ui/skills/concentrate.png new file mode 100644 index 000000000..147291bd6 Binary files /dev/null and b/assets/templates/ui/skills/concentrate.png differ diff --git a/assets/templates/ui/skills/concentration.png b/assets/templates/ui/skills/concentration.png new file mode 100644 index 000000000..42a521b2d Binary files /dev/null and b/assets/templates/ui/skills/concentration.png differ diff --git a/assets/templates/ui/skills/confuse.png b/assets/templates/ui/skills/confuse.png new file mode 100644 index 000000000..a93e6ca60 Binary files /dev/null and b/assets/templates/ui/skills/confuse.png differ diff --git a/assets/templates/ui/skills/conversion.png b/assets/templates/ui/skills/conversion.png new file mode 100644 index 000000000..993bd38f1 Binary files /dev/null and b/assets/templates/ui/skills/conversion.png differ diff --git a/assets/templates/ui/skills/conviction.png b/assets/templates/ui/skills/conviction.png new file mode 100644 index 000000000..044da722a Binary files /dev/null and b/assets/templates/ui/skills/conviction.png differ diff --git a/assets/templates/ui/skills/corpse_explosion.png b/assets/templates/ui/skills/corpse_explosion.png new file mode 100644 index 000000000..fb0e66ad6 Binary files /dev/null and b/assets/templates/ui/skills/corpse_explosion.png differ diff --git a/assets/templates/ui/skills/cyclone_armor.png b/assets/templates/ui/skills/cyclone_armor.png new file mode 100644 index 000000000..6fdc53344 Binary files /dev/null and b/assets/templates/ui/skills/cyclone_armor.png differ diff --git a/assets/templates/ui/skills/death_sentry.png b/assets/templates/ui/skills/death_sentry.png new file mode 100644 index 000000000..0091c8e4d Binary files /dev/null and b/assets/templates/ui/skills/death_sentry.png differ diff --git a/assets/templates/ui/skills/decoy.png b/assets/templates/ui/skills/decoy.png new file mode 100644 index 000000000..10be0edc2 Binary files /dev/null and b/assets/templates/ui/skills/decoy.png differ diff --git a/assets/templates/ui/skills/decrepify.png b/assets/templates/ui/skills/decrepify.png new file mode 100644 index 000000000..326463e9a Binary files /dev/null and b/assets/templates/ui/skills/decrepify.png differ diff --git a/assets/templates/ui/skills/defiance.png b/assets/templates/ui/skills/defiance.png new file mode 100644 index 000000000..b7b224781 Binary files /dev/null and b/assets/templates/ui/skills/defiance.png differ diff --git a/assets/templates/ui/skills/dim_vision.png b/assets/templates/ui/skills/dim_vision.png new file mode 100644 index 000000000..2525a186e Binary files /dev/null and b/assets/templates/ui/skills/dim_vision.png differ diff --git a/assets/templates/ui/skills/double_swing.png b/assets/templates/ui/skills/double_swing.png new file mode 100644 index 000000000..24e9e6984 Binary files /dev/null and b/assets/templates/ui/skills/double_swing.png differ diff --git a/assets/templates/ui/skills/double_throw.png b/assets/templates/ui/skills/double_throw.png new file mode 100644 index 000000000..d05cedf40 Binary files /dev/null and b/assets/templates/ui/skills/double_throw.png differ diff --git a/assets/templates/ui/skills/dragon_claw.png b/assets/templates/ui/skills/dragon_claw.png new file mode 100644 index 000000000..2f279e5e2 Binary files /dev/null and b/assets/templates/ui/skills/dragon_claw.png differ diff --git a/assets/templates/ui/skills/dragon_flight.png b/assets/templates/ui/skills/dragon_flight.png new file mode 100644 index 000000000..e129f487c Binary files /dev/null and b/assets/templates/ui/skills/dragon_flight.png differ diff --git a/assets/templates/ui/skills/dragon_tail.png b/assets/templates/ui/skills/dragon_tail.png new file mode 100644 index 000000000..847a8f620 Binary files /dev/null and b/assets/templates/ui/skills/dragon_tail.png differ diff --git a/assets/templates/ui/skills/dragon_talon.png b/assets/templates/ui/skills/dragon_talon.png new file mode 100644 index 000000000..16149dcb1 Binary files /dev/null and b/assets/templates/ui/skills/dragon_talon.png differ diff --git a/assets/templates/ui/skills/enchant.png b/assets/templates/ui/skills/enchant.png new file mode 100644 index 000000000..640ef73af Binary files /dev/null and b/assets/templates/ui/skills/enchant.png differ diff --git a/assets/templates/ui/skills/energy_shield.png b/assets/templates/ui/skills/energy_shield.png new file mode 100644 index 000000000..588d04c96 Binary files /dev/null and b/assets/templates/ui/skills/energy_shield.png differ diff --git a/assets/templates/ui/skills/exploding_arrow.png b/assets/templates/ui/skills/exploding_arrow.png new file mode 100644 index 000000000..c3c9da9ec Binary files /dev/null and b/assets/templates/ui/skills/exploding_arrow.png differ diff --git a/assets/templates/ui/skills/fade.png b/assets/templates/ui/skills/fade.png new file mode 100644 index 000000000..c393c6e00 Binary files /dev/null and b/assets/templates/ui/skills/fade.png differ diff --git a/assets/templates/ui/skills/fanaticism.png b/assets/templates/ui/skills/fanaticism.png new file mode 100644 index 000000000..39cc0f8f9 Binary files /dev/null and b/assets/templates/ui/skills/fanaticism.png differ diff --git a/assets/templates/ui/skills/fend.png b/assets/templates/ui/skills/fend.png new file mode 100644 index 000000000..2f089e62f Binary files /dev/null and b/assets/templates/ui/skills/fend.png differ diff --git a/assets/templates/ui/skills/feral_rage.png b/assets/templates/ui/skills/feral_rage.png new file mode 100644 index 000000000..2244778db Binary files /dev/null and b/assets/templates/ui/skills/feral_rage.png differ diff --git a/assets/templates/ui/skills/find_item.png b/assets/templates/ui/skills/find_item.png new file mode 100644 index 000000000..e3f54535e Binary files /dev/null and b/assets/templates/ui/skills/find_item.png differ diff --git a/assets/templates/ui/skills/find_potion.png b/assets/templates/ui/skills/find_potion.png new file mode 100644 index 000000000..497d7c489 Binary files /dev/null and b/assets/templates/ui/skills/find_potion.png differ diff --git a/assets/templates/ui/skills/fire_arrow.png b/assets/templates/ui/skills/fire_arrow.png new file mode 100644 index 000000000..137e95cdf Binary files /dev/null and b/assets/templates/ui/skills/fire_arrow.png differ diff --git a/assets/templates/ui/skills/fire_blast.png b/assets/templates/ui/skills/fire_blast.png new file mode 100644 index 000000000..88c75024f Binary files /dev/null and b/assets/templates/ui/skills/fire_blast.png differ diff --git a/assets/templates/ui/skills/fire_bolt.png b/assets/templates/ui/skills/fire_bolt.png new file mode 100644 index 000000000..8e3bac359 Binary files /dev/null and b/assets/templates/ui/skills/fire_bolt.png differ diff --git a/assets/templates/ui/skills/fire_claws.png b/assets/templates/ui/skills/fire_claws.png new file mode 100644 index 000000000..b2783b206 Binary files /dev/null and b/assets/templates/ui/skills/fire_claws.png differ diff --git a/assets/templates/ui/skills/fire_golem.png b/assets/templates/ui/skills/fire_golem.png new file mode 100644 index 000000000..8593a6b95 Binary files /dev/null and b/assets/templates/ui/skills/fire_golem.png differ diff --git a/assets/templates/ui/skills/fireball.png b/assets/templates/ui/skills/fireball.png new file mode 100644 index 000000000..e0b1e640c Binary files /dev/null and b/assets/templates/ui/skills/fireball.png differ diff --git a/assets/templates/ui/skills/firestorm.png b/assets/templates/ui/skills/firestorm.png new file mode 100644 index 000000000..c2476a9a7 Binary files /dev/null and b/assets/templates/ui/skills/firestorm.png differ diff --git a/assets/templates/ui/skills/firewall.png b/assets/templates/ui/skills/firewall.png new file mode 100644 index 000000000..492367ad6 Binary files /dev/null and b/assets/templates/ui/skills/firewall.png differ diff --git a/assets/templates/ui/skills/fissure.png b/assets/templates/ui/skills/fissure.png new file mode 100644 index 000000000..18735ea26 Binary files /dev/null and b/assets/templates/ui/skills/fissure.png differ diff --git a/assets/templates/ui/skills/fist_of_the_heavens.png b/assets/templates/ui/skills/fist_of_the_heavens.png new file mode 100644 index 000000000..fb61c4ed8 Binary files /dev/null and b/assets/templates/ui/skills/fist_of_the_heavens.png differ diff --git a/assets/templates/ui/skills/fists_of_fire.png b/assets/templates/ui/skills/fists_of_fire.png new file mode 100644 index 000000000..1385fa939 Binary files /dev/null and b/assets/templates/ui/skills/fists_of_fire.png differ diff --git a/assets/templates/ui/skills/freezing_arrow.png b/assets/templates/ui/skills/freezing_arrow.png new file mode 100644 index 000000000..38003b210 Binary files /dev/null and b/assets/templates/ui/skills/freezing_arrow.png differ diff --git a/assets/templates/ui/skills/frenzy.png b/assets/templates/ui/skills/frenzy.png new file mode 100644 index 000000000..9683a3a98 Binary files /dev/null and b/assets/templates/ui/skills/frenzy.png differ diff --git a/assets/templates/ui/skills/frost_nova.png b/assets/templates/ui/skills/frost_nova.png new file mode 100644 index 000000000..e849ccade Binary files /dev/null and b/assets/templates/ui/skills/frost_nova.png differ diff --git a/assets/templates/ui/skills/frozen_armor.png b/assets/templates/ui/skills/frozen_armor.png new file mode 100644 index 000000000..ace439367 Binary files /dev/null and b/assets/templates/ui/skills/frozen_armor.png differ diff --git a/assets/templates/ui/skills/frozen_orb.png b/assets/templates/ui/skills/frozen_orb.png new file mode 100644 index 000000000..abfc917c9 Binary files /dev/null and b/assets/templates/ui/skills/frozen_orb.png differ diff --git a/assets/templates/ui/skills/fury.png b/assets/templates/ui/skills/fury.png new file mode 100644 index 000000000..6ed7f0c24 Binary files /dev/null and b/assets/templates/ui/skills/fury.png differ diff --git a/assets/templates/ui/skills/glacial_spike.png b/assets/templates/ui/skills/glacial_spike.png new file mode 100644 index 000000000..d666fc826 Binary files /dev/null and b/assets/templates/ui/skills/glacial_spike.png differ diff --git a/assets/templates/ui/skills/grim_ward.png b/assets/templates/ui/skills/grim_ward.png new file mode 100644 index 000000000..5aa66d9f9 Binary files /dev/null and b/assets/templates/ui/skills/grim_ward.png differ diff --git a/assets/templates/ui/skills/guided_arrow.png b/assets/templates/ui/skills/guided_arrow.png new file mode 100644 index 000000000..03447b5dd Binary files /dev/null and b/assets/templates/ui/skills/guided_arrow.png differ diff --git a/assets/templates/ui/skills/heart_of_wolverine.png b/assets/templates/ui/skills/heart_of_wolverine.png new file mode 100644 index 000000000..c90ee8841 Binary files /dev/null and b/assets/templates/ui/skills/heart_of_wolverine.png differ diff --git a/assets/templates/ui/skills/holy_bolt.png b/assets/templates/ui/skills/holy_bolt.png new file mode 100644 index 000000000..7e57817b5 Binary files /dev/null and b/assets/templates/ui/skills/holy_bolt.png differ diff --git a/assets/templates/ui/skills/holy_fire.png b/assets/templates/ui/skills/holy_fire.png new file mode 100644 index 000000000..e818ee629 Binary files /dev/null and b/assets/templates/ui/skills/holy_fire.png differ diff --git a/assets/templates/ui/skills/holy_freeze.png b/assets/templates/ui/skills/holy_freeze.png new file mode 100644 index 000000000..7558c3631 Binary files /dev/null and b/assets/templates/ui/skills/holy_freeze.png differ diff --git a/assets/templates/ui/skills/holy_shield.png b/assets/templates/ui/skills/holy_shield.png new file mode 100644 index 000000000..8c27d7e8d Binary files /dev/null and b/assets/templates/ui/skills/holy_shield.png differ diff --git a/assets/templates/ui/skills/holy_shock.png b/assets/templates/ui/skills/holy_shock.png new file mode 100644 index 000000000..e9e8fe92c Binary files /dev/null and b/assets/templates/ui/skills/holy_shock.png differ diff --git a/assets/templates/ui/skills/howl.png b/assets/templates/ui/skills/howl.png new file mode 100644 index 000000000..90ee60fe6 Binary files /dev/null and b/assets/templates/ui/skills/howl.png differ diff --git a/assets/templates/ui/skills/hunger.png b/assets/templates/ui/skills/hunger.png new file mode 100644 index 000000000..62c6e2115 Binary files /dev/null and b/assets/templates/ui/skills/hunger.png differ diff --git a/assets/templates/ui/skills/hurricane.png b/assets/templates/ui/skills/hurricane.png new file mode 100644 index 000000000..5e0e6e9b7 Binary files /dev/null and b/assets/templates/ui/skills/hurricane.png differ diff --git a/assets/templates/ui/skills/hydra.png b/assets/templates/ui/skills/hydra.png new file mode 100644 index 000000000..a76b09297 Binary files /dev/null and b/assets/templates/ui/skills/hydra.png differ diff --git a/assets/templates/ui/skills/ice_arrow.png b/assets/templates/ui/skills/ice_arrow.png new file mode 100644 index 000000000..d43ea4172 Binary files /dev/null and b/assets/templates/ui/skills/ice_arrow.png differ diff --git a/assets/templates/ui/skills/ice_blast.png b/assets/templates/ui/skills/ice_blast.png new file mode 100644 index 000000000..2cb84608b Binary files /dev/null and b/assets/templates/ui/skills/ice_blast.png differ diff --git a/assets/templates/ui/skills/ice_bolt.png b/assets/templates/ui/skills/ice_bolt.png new file mode 100644 index 000000000..4c6a6c896 Binary files /dev/null and b/assets/templates/ui/skills/ice_bolt.png differ diff --git a/assets/templates/ui/skills/immolation_arrow.png b/assets/templates/ui/skills/immolation_arrow.png new file mode 100644 index 000000000..a71959587 Binary files /dev/null and b/assets/templates/ui/skills/immolation_arrow.png differ diff --git a/assets/templates/ui/skills/impale.png b/assets/templates/ui/skills/impale.png new file mode 100644 index 000000000..0a36f5bfb Binary files /dev/null and b/assets/templates/ui/skills/impale.png differ diff --git a/assets/templates/ui/skills/inferno.png b/assets/templates/ui/skills/inferno.png new file mode 100644 index 000000000..adc6793d2 Binary files /dev/null and b/assets/templates/ui/skills/inferno.png differ diff --git a/assets/templates/ui/skills/inner_sight.png b/assets/templates/ui/skills/inner_sight.png new file mode 100644 index 000000000..22a9f7bec Binary files /dev/null and b/assets/templates/ui/skills/inner_sight.png differ diff --git a/assets/templates/ui/skills/iron_golem.png b/assets/templates/ui/skills/iron_golem.png new file mode 100644 index 000000000..53306ab49 Binary files /dev/null and b/assets/templates/ui/skills/iron_golem.png differ diff --git a/assets/templates/ui/skills/iron_maiden.png b/assets/templates/ui/skills/iron_maiden.png new file mode 100644 index 000000000..3a3d780ad Binary files /dev/null and b/assets/templates/ui/skills/iron_maiden.png differ diff --git a/assets/templates/ui/skills/jab.png b/assets/templates/ui/skills/jab.png new file mode 100644 index 000000000..fdac92a60 Binary files /dev/null and b/assets/templates/ui/skills/jab.png differ diff --git a/assets/templates/ui/skills/leap.png b/assets/templates/ui/skills/leap.png index 4d9428387..64cb5118b 100644 Binary files a/assets/templates/ui/skills/leap.png and b/assets/templates/ui/skills/leap.png differ diff --git a/assets/templates/ui/skills/leap_attack.png b/assets/templates/ui/skills/leap_attack.png new file mode 100644 index 000000000..68da044e4 Binary files /dev/null and b/assets/templates/ui/skills/leap_attack.png differ diff --git a/assets/templates/ui/skills/left_hand_throw.png b/assets/templates/ui/skills/left_hand_throw.png new file mode 100644 index 000000000..029c3a3f5 Binary files /dev/null and b/assets/templates/ui/skills/left_hand_throw.png differ diff --git a/assets/templates/ui/skills/life_tap.png b/assets/templates/ui/skills/life_tap.png new file mode 100644 index 000000000..c9eda1da4 Binary files /dev/null and b/assets/templates/ui/skills/life_tap.png differ diff --git a/assets/templates/ui/skills/lightning.png b/assets/templates/ui/skills/lightning.png new file mode 100644 index 000000000..ca2741a3b Binary files /dev/null and b/assets/templates/ui/skills/lightning.png differ diff --git a/assets/templates/ui/skills/lightning_bolt.png b/assets/templates/ui/skills/lightning_bolt.png new file mode 100644 index 000000000..915f20060 Binary files /dev/null and b/assets/templates/ui/skills/lightning_bolt.png differ diff --git a/assets/templates/ui/skills/lightning_fury.png b/assets/templates/ui/skills/lightning_fury.png new file mode 100644 index 000000000..2bb3c4a0e Binary files /dev/null and b/assets/templates/ui/skills/lightning_fury.png differ diff --git a/assets/templates/ui/skills/lightning_sentry.png b/assets/templates/ui/skills/lightning_sentry.png new file mode 100644 index 000000000..6e5563430 Binary files /dev/null and b/assets/templates/ui/skills/lightning_sentry.png differ diff --git a/assets/templates/ui/skills/lightning_strike.png b/assets/templates/ui/skills/lightning_strike.png new file mode 100644 index 000000000..ef0ad6b19 Binary files /dev/null and b/assets/templates/ui/skills/lightning_strike.png differ diff --git a/assets/templates/ui/skills/lower_resist.png b/assets/templates/ui/skills/lower_resist.png new file mode 100644 index 000000000..d54c12c35 Binary files /dev/null and b/assets/templates/ui/skills/lower_resist.png differ diff --git a/assets/templates/ui/skills/magic_arrow.png b/assets/templates/ui/skills/magic_arrow.png new file mode 100644 index 000000000..c8d29c0d5 Binary files /dev/null and b/assets/templates/ui/skills/magic_arrow.png differ diff --git a/assets/templates/ui/skills/maul.png b/assets/templates/ui/skills/maul.png new file mode 100644 index 000000000..413518039 Binary files /dev/null and b/assets/templates/ui/skills/maul.png differ diff --git a/assets/templates/ui/skills/meditation.png b/assets/templates/ui/skills/meditation.png new file mode 100644 index 000000000..6bad45018 Binary files /dev/null and b/assets/templates/ui/skills/meditation.png differ diff --git a/assets/templates/ui/skills/meteor.png b/assets/templates/ui/skills/meteor.png new file mode 100644 index 000000000..bada24a9f Binary files /dev/null and b/assets/templates/ui/skills/meteor.png differ diff --git a/assets/templates/ui/skills/might.png b/assets/templates/ui/skills/might.png new file mode 100644 index 000000000..4a9bdf133 Binary files /dev/null and b/assets/templates/ui/skills/might.png differ diff --git a/assets/templates/ui/skills/mind_blast.png b/assets/templates/ui/skills/mind_blast.png new file mode 100644 index 000000000..72caaf0a8 Binary files /dev/null and b/assets/templates/ui/skills/mind_blast.png differ diff --git a/assets/templates/ui/skills/molten_boulder.png b/assets/templates/ui/skills/molten_boulder.png new file mode 100644 index 000000000..c9af24052 Binary files /dev/null and b/assets/templates/ui/skills/molten_boulder.png differ diff --git a/assets/templates/ui/skills/multiple_shot.png b/assets/templates/ui/skills/multiple_shot.png new file mode 100644 index 000000000..684e1430a Binary files /dev/null and b/assets/templates/ui/skills/multiple_shot.png differ diff --git a/assets/templates/ui/skills/nova.png b/assets/templates/ui/skills/nova.png new file mode 100644 index 000000000..9f7375771 Binary files /dev/null and b/assets/templates/ui/skills/nova.png differ diff --git a/assets/templates/ui/skills/oak_sage.png b/assets/templates/ui/skills/oak_sage.png new file mode 100644 index 000000000..1af4503a6 Binary files /dev/null and b/assets/templates/ui/skills/oak_sage.png differ diff --git a/assets/templates/ui/skills/phoenix_strike.png b/assets/templates/ui/skills/phoenix_strike.png new file mode 100644 index 000000000..5b16b71b4 Binary files /dev/null and b/assets/templates/ui/skills/phoenix_strike.png differ diff --git a/assets/templates/ui/skills/plague_javelin.png b/assets/templates/ui/skills/plague_javelin.png new file mode 100644 index 000000000..e6f12bd06 Binary files /dev/null and b/assets/templates/ui/skills/plague_javelin.png differ diff --git a/assets/templates/ui/skills/poison_creeper.png b/assets/templates/ui/skills/poison_creeper.png new file mode 100644 index 000000000..0d89cbabb Binary files /dev/null and b/assets/templates/ui/skills/poison_creeper.png differ diff --git a/assets/templates/ui/skills/poison_dagger.png b/assets/templates/ui/skills/poison_dagger.png new file mode 100644 index 000000000..4083e0021 Binary files /dev/null and b/assets/templates/ui/skills/poison_dagger.png differ diff --git a/assets/templates/ui/skills/poison_explosion.png b/assets/templates/ui/skills/poison_explosion.png new file mode 100644 index 000000000..a7f976a34 Binary files /dev/null and b/assets/templates/ui/skills/poison_explosion.png differ diff --git a/assets/templates/ui/skills/poison_javelin.png b/assets/templates/ui/skills/poison_javelin.png new file mode 100644 index 000000000..f904f558b Binary files /dev/null and b/assets/templates/ui/skills/poison_javelin.png differ diff --git a/assets/templates/ui/skills/poison_nova.png b/assets/templates/ui/skills/poison_nova.png new file mode 100644 index 000000000..0b20998db Binary files /dev/null and b/assets/templates/ui/skills/poison_nova.png differ diff --git a/assets/templates/ui/skills/power_strike.png b/assets/templates/ui/skills/power_strike.png new file mode 100644 index 000000000..98e13f3e7 Binary files /dev/null and b/assets/templates/ui/skills/power_strike.png differ diff --git a/assets/templates/ui/skills/prayer.png b/assets/templates/ui/skills/prayer.png new file mode 100644 index 000000000..4f8aa88b5 Binary files /dev/null and b/assets/templates/ui/skills/prayer.png differ diff --git a/assets/templates/ui/skills/psychic_hammer.png b/assets/templates/ui/skills/psychic_hammer.png new file mode 100644 index 000000000..9582f6e6a Binary files /dev/null and b/assets/templates/ui/skills/psychic_hammer.png differ diff --git a/assets/templates/ui/skills/rabies.png b/assets/templates/ui/skills/rabies.png new file mode 100644 index 000000000..5fec3cb22 Binary files /dev/null and b/assets/templates/ui/skills/rabies.png differ diff --git a/assets/templates/ui/skills/raise_skeletal_mage.png b/assets/templates/ui/skills/raise_skeletal_mage.png new file mode 100644 index 000000000..979ebefb0 Binary files /dev/null and b/assets/templates/ui/skills/raise_skeletal_mage.png differ diff --git a/assets/templates/ui/skills/raise_skeleton.png b/assets/templates/ui/skills/raise_skeleton.png new file mode 100644 index 000000000..de936e1b7 Binary files /dev/null and b/assets/templates/ui/skills/raise_skeleton.png differ diff --git a/assets/templates/ui/skills/raven.png b/assets/templates/ui/skills/raven.png new file mode 100644 index 000000000..99e8666e8 Binary files /dev/null and b/assets/templates/ui/skills/raven.png differ diff --git a/assets/templates/ui/skills/redemption.png b/assets/templates/ui/skills/redemption.png new file mode 100644 index 000000000..2b222f7a5 Binary files /dev/null and b/assets/templates/ui/skills/redemption.png differ diff --git a/assets/templates/ui/skills/resist_cold.png b/assets/templates/ui/skills/resist_cold.png new file mode 100644 index 000000000..cd4d63bb4 Binary files /dev/null and b/assets/templates/ui/skills/resist_cold.png differ diff --git a/assets/templates/ui/skills/resist_fire.png b/assets/templates/ui/skills/resist_fire.png new file mode 100644 index 000000000..a7413f212 Binary files /dev/null and b/assets/templates/ui/skills/resist_fire.png differ diff --git a/assets/templates/ui/skills/resist_lightning.png b/assets/templates/ui/skills/resist_lightning.png new file mode 100644 index 000000000..d7b321799 Binary files /dev/null and b/assets/templates/ui/skills/resist_lightning.png differ diff --git a/assets/templates/ui/skills/revive.png b/assets/templates/ui/skills/revive.png new file mode 100644 index 000000000..5aba9a280 Binary files /dev/null and b/assets/templates/ui/skills/revive.png differ diff --git a/assets/templates/ui/skills/sacrifice.png b/assets/templates/ui/skills/sacrifice.png new file mode 100644 index 000000000..67596cf0f Binary files /dev/null and b/assets/templates/ui/skills/sacrifice.png differ diff --git a/assets/templates/ui/skills/salvation.png b/assets/templates/ui/skills/salvation.png new file mode 100644 index 000000000..29b83b071 Binary files /dev/null and b/assets/templates/ui/skills/salvation.png differ diff --git a/assets/templates/ui/skills/sanctuary.png b/assets/templates/ui/skills/sanctuary.png new file mode 100644 index 000000000..54ed3b66c Binary files /dev/null and b/assets/templates/ui/skills/sanctuary.png differ diff --git a/assets/templates/ui/skills/shadow_master.png b/assets/templates/ui/skills/shadow_master.png new file mode 100644 index 000000000..86e3944b1 Binary files /dev/null and b/assets/templates/ui/skills/shadow_master.png differ diff --git a/assets/templates/ui/skills/shadow_warrior.png b/assets/templates/ui/skills/shadow_warrior.png new file mode 100644 index 000000000..3b85c66f8 Binary files /dev/null and b/assets/templates/ui/skills/shadow_warrior.png differ diff --git a/assets/templates/ui/skills/shiver_armor.png b/assets/templates/ui/skills/shiver_armor.png new file mode 100644 index 000000000..fcc2ee54b Binary files /dev/null and b/assets/templates/ui/skills/shiver_armor.png differ diff --git a/assets/templates/ui/skills/shock_wave.png b/assets/templates/ui/skills/shock_wave.png new file mode 100644 index 000000000..66fdb5c49 Binary files /dev/null and b/assets/templates/ui/skills/shock_wave.png differ diff --git a/assets/templates/ui/skills/shock_web.png b/assets/templates/ui/skills/shock_web.png new file mode 100644 index 000000000..ef63e513c Binary files /dev/null and b/assets/templates/ui/skills/shock_web.png differ diff --git a/assets/templates/ui/skills/shout.png b/assets/templates/ui/skills/shout.png new file mode 100644 index 000000000..c57994bea Binary files /dev/null and b/assets/templates/ui/skills/shout.png differ diff --git a/assets/templates/ui/skills/slow_missiles.png b/assets/templates/ui/skills/slow_missiles.png new file mode 100644 index 000000000..7c7943b64 Binary files /dev/null and b/assets/templates/ui/skills/slow_missiles.png differ diff --git a/assets/templates/ui/skills/smite.png b/assets/templates/ui/skills/smite.png new file mode 100644 index 000000000..b50c1ecda Binary files /dev/null and b/assets/templates/ui/skills/smite.png differ diff --git a/assets/templates/ui/skills/solar_creeper.png b/assets/templates/ui/skills/solar_creeper.png new file mode 100644 index 000000000..f8891342f Binary files /dev/null and b/assets/templates/ui/skills/solar_creeper.png differ diff --git a/assets/templates/ui/skills/spirit_of_barbs.png b/assets/templates/ui/skills/spirit_of_barbs.png new file mode 100644 index 000000000..ed4633e38 Binary files /dev/null and b/assets/templates/ui/skills/spirit_of_barbs.png differ diff --git a/assets/templates/ui/skills/static_field.png b/assets/templates/ui/skills/static_field.png new file mode 100644 index 000000000..211f1fb69 Binary files /dev/null and b/assets/templates/ui/skills/static_field.png differ diff --git a/assets/templates/ui/skills/strafe.png b/assets/templates/ui/skills/strafe.png new file mode 100644 index 000000000..3512a05fe Binary files /dev/null and b/assets/templates/ui/skills/strafe.png differ diff --git a/assets/templates/ui/skills/stun.png b/assets/templates/ui/skills/stun.png new file mode 100644 index 000000000..61ad8d06f Binary files /dev/null and b/assets/templates/ui/skills/stun.png differ diff --git a/assets/templates/ui/skills/summon_dire_wolf.png b/assets/templates/ui/skills/summon_dire_wolf.png new file mode 100644 index 000000000..54550f08c Binary files /dev/null and b/assets/templates/ui/skills/summon_dire_wolf.png differ diff --git a/assets/templates/ui/skills/summon_grizzly.png b/assets/templates/ui/skills/summon_grizzly.png new file mode 100644 index 000000000..5ab292ba3 Binary files /dev/null and b/assets/templates/ui/skills/summon_grizzly.png differ diff --git a/assets/templates/ui/skills/summon_spirit_wolf.png b/assets/templates/ui/skills/summon_spirit_wolf.png new file mode 100644 index 000000000..bf991381b Binary files /dev/null and b/assets/templates/ui/skills/summon_spirit_wolf.png differ diff --git a/assets/templates/ui/skills/taunt.png b/assets/templates/ui/skills/taunt.png new file mode 100644 index 000000000..f868da3fc Binary files /dev/null and b/assets/templates/ui/skills/taunt.png differ diff --git a/assets/templates/ui/skills/teeth.png b/assets/templates/ui/skills/teeth.png new file mode 100644 index 000000000..ef1f9f2b0 Binary files /dev/null and b/assets/templates/ui/skills/teeth.png differ diff --git a/assets/templates/ui/skills/tele_active.png b/assets/templates/ui/skills/tele_active.png deleted file mode 100644 index a4554b77a..000000000 Binary files a/assets/templates/ui/skills/tele_active.png and /dev/null differ diff --git a/assets/templates/ui/skills/tele_inactive.png b/assets/templates/ui/skills/tele_inactive.png deleted file mode 100644 index e1d78ad98..000000000 Binary files a/assets/templates/ui/skills/tele_inactive.png and /dev/null differ diff --git a/assets/templates/ui/skills/telekinesis.png b/assets/templates/ui/skills/telekinesis.png new file mode 100644 index 000000000..ae370fdb2 Binary files /dev/null and b/assets/templates/ui/skills/telekinesis.png differ diff --git a/assets/templates/ui/skills/teleport.png b/assets/templates/ui/skills/teleport.png new file mode 100644 index 000000000..5a3f91942 Binary files /dev/null and b/assets/templates/ui/skills/teleport.png differ diff --git a/assets/templates/ui/skills/terror.png b/assets/templates/ui/skills/terror.png new file mode 100644 index 000000000..2df2202d0 Binary files /dev/null and b/assets/templates/ui/skills/terror.png differ diff --git a/assets/templates/ui/skills/thorns.png b/assets/templates/ui/skills/thorns.png new file mode 100644 index 000000000..2389d8fc3 Binary files /dev/null and b/assets/templates/ui/skills/thorns.png differ diff --git a/assets/templates/ui/skills/throw.png b/assets/templates/ui/skills/throw.png new file mode 100644 index 000000000..4ac3000f9 Binary files /dev/null and b/assets/templates/ui/skills/throw.png differ diff --git a/assets/templates/ui/skills/thunder_storm.png b/assets/templates/ui/skills/thunder_storm.png new file mode 100644 index 000000000..2f46bbb05 Binary files /dev/null and b/assets/templates/ui/skills/thunder_storm.png differ diff --git a/assets/templates/ui/skills/tiger_strike.png b/assets/templates/ui/skills/tiger_strike.png new file mode 100644 index 000000000..df21cd873 Binary files /dev/null and b/assets/templates/ui/skills/tiger_strike.png differ diff --git a/assets/templates/ui/skills/tornado.png b/assets/templates/ui/skills/tornado.png new file mode 100644 index 000000000..a4d5b1848 Binary files /dev/null and b/assets/templates/ui/skills/tornado.png differ diff --git a/assets/templates/ui/skills/tp_active.png b/assets/templates/ui/skills/town_portal.png similarity index 100% rename from assets/templates/ui/skills/tp_active.png rename to assets/templates/ui/skills/town_portal.png diff --git a/assets/templates/ui/skills/tp_inactive.png b/assets/templates/ui/skills/tp_inactive.png deleted file mode 100644 index 8fb734bd1..000000000 Binary files a/assets/templates/ui/skills/tp_inactive.png and /dev/null differ diff --git a/assets/templates/ui/skills/twister.png b/assets/templates/ui/skills/twister.png new file mode 100644 index 000000000..447c298fe Binary files /dev/null and b/assets/templates/ui/skills/twister.png differ diff --git a/assets/templates/ui/skills/unsummon.png b/assets/templates/ui/skills/unsummon.png new file mode 100644 index 000000000..e0e45cbab Binary files /dev/null and b/assets/templates/ui/skills/unsummon.png differ diff --git a/assets/templates/ui/skills/valkyrie.png b/assets/templates/ui/skills/valkyrie.png new file mode 100644 index 000000000..98236d57e Binary files /dev/null and b/assets/templates/ui/skills/valkyrie.png differ diff --git a/assets/templates/ui/skills/vengeance.png b/assets/templates/ui/skills/vengeance.png new file mode 100644 index 000000000..dcf3d61c0 Binary files /dev/null and b/assets/templates/ui/skills/vengeance.png differ diff --git a/assets/templates/ui/skills/venom.png b/assets/templates/ui/skills/venom.png new file mode 100644 index 000000000..7b2278ba2 Binary files /dev/null and b/assets/templates/ui/skills/venom.png differ diff --git a/assets/templates/ui/skills/vigor.png b/assets/templates/ui/skills/vigor.png index 7bcf1c616..d1526fadc 100644 Binary files a/assets/templates/ui/skills/vigor.png and b/assets/templates/ui/skills/vigor.png differ diff --git a/assets/templates/ui/skills/volcano.png b/assets/templates/ui/skills/volcano.png new file mode 100644 index 000000000..7400f79a3 Binary files /dev/null and b/assets/templates/ui/skills/volcano.png differ diff --git a/assets/templates/ui/skills/wake_of_fire.png b/assets/templates/ui/skills/wake_of_fire.png new file mode 100644 index 000000000..32789dd05 Binary files /dev/null and b/assets/templates/ui/skills/wake_of_fire.png differ diff --git a/assets/templates/ui/skills/wake_of_inferno.png b/assets/templates/ui/skills/wake_of_inferno.png new file mode 100644 index 000000000..212a86dd0 Binary files /dev/null and b/assets/templates/ui/skills/wake_of_inferno.png differ diff --git a/assets/templates/ui/skills/war_cry.png b/assets/templates/ui/skills/war_cry.png new file mode 100644 index 000000000..b6d695905 Binary files /dev/null and b/assets/templates/ui/skills/war_cry.png differ diff --git a/assets/templates/ui/skills/weaken.png b/assets/templates/ui/skills/weaken.png new file mode 100644 index 000000000..6664f2005 Binary files /dev/null and b/assets/templates/ui/skills/weaken.png differ diff --git a/assets/templates/ui/skills/werebear.png b/assets/templates/ui/skills/werebear.png new file mode 100644 index 000000000..db49ef3bc Binary files /dev/null and b/assets/templates/ui/skills/werebear.png differ diff --git a/assets/templates/ui/skills/werewolf.png b/assets/templates/ui/skills/werewolf.png new file mode 100644 index 000000000..ba97154ca Binary files /dev/null and b/assets/templates/ui/skills/werewolf.png differ diff --git a/assets/templates/ui/skills/whirlwind.png b/assets/templates/ui/skills/whirlwind.png new file mode 100644 index 000000000..f4c773159 Binary files /dev/null and b/assets/templates/ui/skills/whirlwind.png differ diff --git a/assets/templates/ui/skills/zeal.png b/assets/templates/ui/skills/zeal.png new file mode 100644 index 000000000..9938186ce Binary files /dev/null and b/assets/templates/ui/skills/zeal.png differ diff --git a/config/game.ini b/config/game.ini index 3e6a2887b..bd6dbd4fa 100644 --- a/config/game.ini +++ b/config/game.ini @@ -106,9 +106,9 @@ tp_search=353,120,547,400 repair_btn=318,473,90,80 left_inventory=35,92,378,378 right_inventory=866,348,379,152 -skill_right=664,673,41,41 +skill_right=664,673,45,45 skill_right_expanded=655,375,385,255 -skill_left=574,673,41,41 +skill_left=574,673,45,45 main_menu_top_left=0,0,100,100 gamebar_anchor=600,650,90,90 gamebar_belt_expandable=792,659,28,28 diff --git a/config/params.ini b/config/params.ini index 21d5949ee..c394df713 100644 --- a/config/params.ini +++ b/config/params.ini @@ -4,6 +4,8 @@ difficulty=hell name=Botty randomize_runs=0 saved_games_folder= +; key_file should be the key(o) file for the character (found in the Saved Games folder). 'key' is offline characters, 'keyo' is online characters. Some online characters may have a hash added to them: Paladin53672482.keyo. +key_file= ; messaging custom_loot_message_hook= @@ -55,26 +57,6 @@ safer_routines=0 ; Store charms, etc. to the right of the inventory. num_loot_columns=5 -; game hotkeys: -force_move=e -inventory_screen=i -potion1=1 -potion2=2 -potion3=3 -potion4=4 -; show_belt is different from the default hotkey as "~" is for many keyboards not reachable without also pressing altgr -show_belt=k -show_items=alt -; stand_still cannot be the default "shift" as it would interfere with merc healing -stand_still=capslock -; teleport: leave empty if you can't use -teleport= -town_portal=f9 -; call to arms settings: -weapon_switch=x -battle_orders=f7 -battle_command=f8 - ; ========================== ; ==== Optional configs ==== ; ========================== @@ -140,57 +122,25 @@ transmute_every_x_game=20 ; ==== Builds: Sorceress ==== ; =========================== [sorceress] -energy_shield= -frozen_armor= -static_field= -telekinesis= -thunder_storm= - [light_sorc] ; chain_lightning must be bound to left skill (hotkey optional as it shouldnt change) -chain_lightning= ; lightning must be right skill, hotkey required -lightning= ; frozen orb must be right skill, hotkey recommended to increase safty for you and merc at trav! -frozen_orb= - [blizz_sorc] ; blizzard must be right skill, hotkey required -blizzard= ; ice_blast must be left skill (hotkey optional as it shouldnt change) -ice_blast= - [nova_sorc] ; nova must be right skill, hotkey required -nova= - [hydra_sorc] ; only supports Pindle and Eldritch currently -; alt_attack is any alternate attacking right skill. Fireball,Lightning,Frozen Orb, hotkey required -alt_attack= -; hydra must be right skill, hotkey required -hydra= ; ========================= ; ==== Builds: Paladin ==== ; ========================= [paladin] -cleansing= -holy_shield= -redemption= -vigor= - [fohdin] ; foh must be left skill, hotkey required -blessed_hammer= -concentration= -conviction= -foh= -holy_bolt= - [hammerdin] -blessed_hammer= -concentration= ; ========================== @@ -198,11 +148,6 @@ concentration= ; ========================== ; Currently no Trav implementaiton! [trapsin] -burst_of_speed= -death_sentry= -fade= -lightning_sentry= -shadow_warrior= skill_left= @@ -214,10 +159,6 @@ skill_left= ; Ensure Battle Order/Command hotkeys are set above in the [char] section [barbarian] cry_frequency=0.7 -find_item= -leap= -shout= -war_cry= ; ========================== @@ -231,40 +172,12 @@ war_cry= ;recomended to set skeleton mage to same as revive hot hey ;skeleton mages cause pathing issues not ideal to use yet [necro] -amp_dmg= -bone_armor= -clay_golem= -clear_pindle_pack= -corpse_explosion= -heart_of_wolverine= -raise_mage= -raise_revive= -raise_skeleton= skill_left= [poison_necro] -bone_armor= -# Can use any golem -clay_golem= -clear_pindle_pack= -corpse_explosion= -heart_of_wolverine= -# Can Use any curse -lower_res= -poison_nova= -raise_mage= -raise_revive= -raise_skeleton= -# Not Required skill_left= [bone_necro] -bone_armor= -bone_spear= -bone_spirit= -bone_wall= -clay_golem= -teeth= ; Damage scaling. One setting to adjust kill speed to account for better/worse gear. ; ex: 2 will cast all attack skills twice a long, .5 half as long. Currently only used by bone necro damage_scaling=1 diff --git a/src/bot.py b/src/bot.py index 01f8ee969..c45b3ee7a 100644 --- a/src/bot.py +++ b/src/bot.py @@ -11,6 +11,7 @@ from health_manager import set_pause_state from transmute import Transmute +from utils import hotkeys from utils.misc import wait, hms from utils.restart import safe_exit, restart_game from game_stats import GameStats @@ -34,6 +35,7 @@ from char.basic_ranged import Basic_Ranged from ui_manager import wait_until_hidden, wait_until_visible, ScreenObjects, is_visible, detect_screen_object from ui import meters, skills, view, character_select, main_menu +from ui.skills import SkillName from inventory import personal, vendor, belt, common from run import Pindle, ShenkEld, Trav, Nihlathak, Arcane, Diablo @@ -218,7 +220,8 @@ def _rebuild_as_asset_to_trigger(trigger_to_assets: dict): def on_init(self): self._game_stats.log_start_game() - keyboard.release(Config().char["stand_still"]) + if hotkeys.HotkeyName.StandStill in hotkeys.d2r_keymap: + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill]) transition_to_screens = Bot._rebuild_as_asset_to_trigger({ "select_character": main_menu.MAIN_MENU_MARKERS, "start_from_town": town_manager.TOWN_MARKERS, @@ -248,7 +251,7 @@ def on_create_game(self): # Start a game from hero selection if (m := wait_until_visible(ScreenObjects.MainMenu)).valid: if "DARK" in m.name: - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) main_menu.start_game() view.move_to_corpse() else: @@ -257,19 +260,27 @@ def on_create_game(self): def on_start_from_town(self): self._curr_loc = self._town_manager.wait_for_town_spawn() - # Handle picking up corpse in case of death if (corpse_present := is_visible(ScreenObjects.Corpse)): self._previous_run_failed = True view.pickup_corpse() wait_until_hidden(ScreenObjects.Corpse) belt.fill_up_belt_from_inventory(Config().char["num_loot_columns"]) + if not hotkeys.discovered: + saved_games_folder = Config().general["saved_games_folder"] + key_file = Config().general["key_file"] + hotkeys.discover_hotkey_mappings(saved_games_folder, key_file) self._char.discover_capabilities() - if corpse_present and self._char.capabilities.can_teleport_with_charges and not self._char.select_tp(): - keybind = Config().char["teleport"] + teleport_selected = skills.select_tp(hotkeys.right_skill_key_map[SkillName.Teleport]) if SkillName.Teleport in hotkeys.right_skill_key_map else None + if corpse_present and self._char.capabilities.can_teleport_with_charges and not teleport_selected: + keybind = hotkeys.right_skill_key_map[SkillName.Teleport] Logger.info(f"Teleport keybind is lost upon death. Rebinding teleport to '{keybind}'") - self._char.remap_right_skill_hotkey("TELE_ACTIVE", Config().char["teleport"]) - + hotkeys.remap_skill_hotkey( + SkillName.Teleport.value, + keybind, + Config().ui_roi["skill_right"], + Config().ui_roi["skill_right_expanded"] + ) # Run /nopickup command to avoid picking up stuff on accident if Config().char["enable_no_pickup"] and (not self._ran_no_pickup and not self._game_stats._nopickup_active): self._ran_no_pickup = True @@ -286,7 +297,6 @@ def on_start_from_town(self): def on_maintenance(self): # Pause health manager if not already paused set_pause_state(True) - # Dismiss skill/quest/help/stats icon if they are on screen if not view.dismiss_skills_icon(): view.return_to_play() @@ -368,7 +378,8 @@ def on_maintenance(self): # Check if we are out of tps or need repairing need_repair = is_visible(ScreenObjects.NeedRepair) need_routine_repair = False if not Config().char["runs_per_repair"] else self._game_stats._run_counter % Config().char["runs_per_repair"] == 0 - need_refill_teleport = self._char.capabilities.can_teleport_with_charges and (not self._char.select_tp() or self._char.is_low_on_teleport_charges()) + teleport_selected = skills.select_tp(hotkeys.right_skill_key_map[SkillName.Teleport]) if SkillName.Teleport in hotkeys.right_skill_key_map else None + need_refill_teleport = self._char.capabilities.can_teleport_with_charges and (not teleport_selected or self._char.is_low_on_teleport_charges()) if need_repair or need_routine_repair or need_refill_teleport or sell_items: if need_repair: Logger.info("Repair needed. Gear is about to break") diff --git a/src/char/barbarian.py b/src/char/barbarian.py index 50f3f0332..01fd3a4db 100644 --- a/src/char/barbarian.py +++ b/src/char/barbarian.py @@ -1,8 +1,8 @@ import keyboard -from ui import skills +from ui.skills import SkillName, is_left_skill_selected, is_right_skill_active +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar, CharacterCapabilities -import template_finder from pather import Pather from logger import Logger from screen import convert_abs_to_monitor @@ -24,10 +24,10 @@ def _cast_war_cry(self, time_in_s: float): # keyboard.send(self._skill_hotkeys["concentration"]) # wait(0.05, 0.1) cry_frequency = min(0.2, self._skill_hotkeys["cry_frequency"]) - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) wait(0.05, 0.1) - if self._skill_hotkeys["war_cry"]: - keyboard.send(self._skill_hotkeys["war_cry"]) + if SkillName.WarCry in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.WarCry]) wait(0.05, 0.1) start = time.time() while (time.time() - start) < time_in_s: @@ -36,7 +36,7 @@ def _cast_war_cry(self, time_in_s: float): wait(cry_frequency, cry_frequency + 0.2) mouse.click(button="right") wait(0.01, 0.05) - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def on_capabilities_discovered(self, capabilities: CharacterCapabilities): if capabilities.can_teleport_natively: @@ -44,8 +44,8 @@ def on_capabilities_discovered(self, capabilities: CharacterCapabilities): def _do_hork(self, hork_time: int): wait(0.5) - if self._skill_hotkeys["find_item"]: - keyboard.send(self._skill_hotkeys["find_item"]) + if SkillName.FindItem in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.FindItem]) wait(0.5, 0.15) pos_m = convert_abs_to_monitor((0, -20)) mouse.move(*pos_m) @@ -56,15 +56,15 @@ def _do_hork(self, hork_time: int): wait(1) def pre_buff(self): - keyboard.send(Config().char["battle_command"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.BattleCommand]) wait(0.08, 0.19) mouse.click(button="right") wait(self._cast_duration + 0.08, self._cast_duration + 0.1) - keyboard.send(Config().char["battle_orders"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.BattleOrders]) wait(0.08, 0.19) mouse.click(button="right") wait(self._cast_duration + 0.08, self._cast_duration + 0.1) - keyboard.send(self._skill_hotkeys["shout"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Shout]) wait(0.08, 0.19) mouse.click(button="right") wait(self._cast_duration + 0.08, self._cast_duration + 0.1) @@ -73,10 +73,10 @@ def pre_move(self): # select teleport if available super().pre_move() # in case teleport hotkey is not set or teleport can not be used, use leap if set - should_cast_leap = self._skill_hotkeys["leap"] and not skills.is_left_skill_selected(["LEAP"]) - can_teleport = self.capabilities.can_teleport_natively and skills.is_right_skill_active() + should_cast_leap = SkillName.Leap in hotkeys.right_skill_key_map and not is_left_skill_selected(SkillName.Leap.value) + can_teleport = self.capabilities.can_teleport_natively and is_right_skill_active() if should_cast_leap and not can_teleport: - keyboard.send(self._skill_hotkeys["leap"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Leap]) wait(0.15, 0.25) def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float): diff --git a/src/char/basic.py b/src/char/basic.py index 6703094f9..95c9ecbe0 100644 --- a/src/char/basic.py +++ b/src/char/basic.py @@ -1,5 +1,6 @@ import keyboard from ui import skills +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar,CharacterCapabilities import template_finder @@ -25,7 +26,7 @@ def on_capabilities_discovered(self, capabilities: CharacterCapabilities): self._pather.offset_node(149, [120, 70]) def _cast_attack_pattern(self, time_in_s: float): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) wait(0.05, 0.1) keyboard.send(self._skill_hotkeys["left_attack"]) wait(0.05, 0.1) @@ -40,7 +41,7 @@ def _cast_attack_pattern(self, time_in_s: float): wait(0.05, 0.1) mouse.click(button="left") wait(0.01, 0.05) - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def pre_buff(self): if Config().char["cta_available"]: diff --git a/src/char/basic_ranged.py b/src/char/basic_ranged.py index 50215ad5f..2767c03ed 100644 --- a/src/char/basic_ranged.py +++ b/src/char/basic_ranged.py @@ -1,5 +1,7 @@ import keyboard from ui import skills +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar import template_finder @@ -22,8 +24,8 @@ def __init__(self, skill_hotkeys: dict, pather: Pather): self._do_pre_move = True def _left_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: int = 10): - if self._skill_hotkeys["left_attack"]: - keyboard.send(self._skill_hotkeys["left_attack"]) + if SkillName.Attack in hotkeys.left_skill_key_map: + keyboard.send(hotkeys.left_skill_key_map[SkillName.Attack]) for _ in range(4): x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) @@ -32,9 +34,9 @@ def _left_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, fl mouse.click(button="left") def _right_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: float = 10): - if not self._skill_hotkeys["right_attack"]: + if not SkillName.Attack in hotkeys.right_skill_key_map: raise ValueError("You did not set right attack hotkey!") - keyboard.send(self._skill_hotkeys["right_attack"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Attack]) for _ in range(3): x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) @@ -63,7 +65,7 @@ def kill_pindle(self) -> bool: pindle_pos_abs = convert_screen_to_abs(Config().path["pindle_end"][0]) cast_pos_abs = [pindle_pos_abs[0] * 0.9, pindle_pos_abs[1] * 0.9] start = time.time() - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) while (time.time() - start) < Config().char["atk_len_pindle"]: if skills.is_right_skill_active(): wait(0.05, 0.1) @@ -71,7 +73,7 @@ def kill_pindle(self) -> bool: else: wait(0.05, 0.1) self._left_attack(cast_pos_abs, spray=11) - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) wait(self._cast_duration, self._cast_duration + 0.2) # Move to items self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, timeout=1.4, force_tp=True) @@ -82,7 +84,7 @@ def kill_eldritch(self) -> bool: eld_pos_abs = convert_screen_to_abs(Config().path["eldritch_end"][0]) cast_pos_abs = [eld_pos_abs[0] * 0.9, eld_pos_abs[1] * 0.9] start = time.time() - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) while (time.time() - start) < Config().char["atk_len_eldritch"]: if skills.is_right_skill_active(): wait(0.05, 0.1) @@ -90,7 +92,7 @@ def kill_eldritch(self) -> bool: else: wait(0.05, 0.1) self._left_attack(cast_pos_abs, spray=11) - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) wait(self._cast_duration, self._cast_duration + 0.2) # Move to items self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=1.4, force_tp=True) @@ -102,7 +104,7 @@ def kill_shenk(self) -> bool: shenk_pos_abs = convert_screen_to_abs(Config().path["shenk_end"][0]) cast_pos_abs = [shenk_pos_abs[0] * 0.9, shenk_pos_abs[1] * 0.9] start = time.time() - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) while (time.time() - start) < Config().char["atk_len_shenk"]: if skills.is_right_skill_active(): wait(0.05, 0.1) @@ -110,7 +112,7 @@ def kill_shenk(self) -> bool: else: wait(0.05, 0.1) self._left_attack(cast_pos_abs, spray=11) - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) wait(self._cast_duration, self._cast_duration + 0.2) # Move to items self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.4, force_tp=True) diff --git a/src/char/bone_necro.py b/src/char/bone_necro.py index b45f97b0e..5ba321422 100644 --- a/src/char/bone_necro.py +++ b/src/char/bone_necro.py @@ -1,4 +1,6 @@ import keyboard +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar import template_finder @@ -30,10 +32,10 @@ def move_to(self, x, y): self.move(pos_m, force_move=True) def bone_wall(self, cast_pos_abs: tuple[float, float], spray: int): - if not self._skill_hotkeys["bone_wall"]: + if SkillName.BoneWall not in hotkeys.right_skill_key_map: raise ValueError("You did not set bone_wall hotkey!") - keyboard.send(Config().char["stand_still"], do_release=False) - keyboard.send(self._skill_hotkeys["bone_wall"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneWall]) wait(0.02, 0.08) x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -42,7 +44,7 @@ def bone_wall(self, cast_pos_abs: tuple[float, float], spray: int): mouse.press(button="right") wait(self._cast_duration+.04, self._cast_duration+.08) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def pre_buff(self): self.bone_armor() @@ -53,36 +55,36 @@ def pre_buff(self): def _clay_golem(self): Logger.debug('Casting clay golem') - keyboard.send(self._skill_hotkeys["clay_golem"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.ClayGolem]) wait(0.05, 0.2) mouse.click(button="right") wait(self._cast_duration) def bone_armor(self): - if self._skill_hotkeys["bone_armor"]: - keyboard.send(self._skill_hotkeys["bone_armor"]) + if SkillName.BoneArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneArmor]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["clay_golem"]: - keyboard.send(self._skill_hotkeys["clay_golem"]) + if SkillName.ClayGolem in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.ClayGolem]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) def _bone_armor(self): - if self._skill_hotkeys["bone_armor"]: - keyboard.send(self._skill_hotkeys["bone_armor"]) + if SkillName.BoneArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneArmor]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) Logger.debug(f'casting corpse explosion {cast_count} times with spray = {spray}') for _ in range(cast_count): - if self._skill_hotkeys["corpse_explosion"]: - keyboard.send(self._skill_hotkeys["corpse_explosion"]) + if SkillName.CorpseExplosion in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.CorpseExplosion]) x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) cast_pos_monitor = convert_abs_to_monitor((x, y)) @@ -90,16 +92,16 @@ def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,c mouse.press(button="right") wait(0.075, 0.1) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) - def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_spell: str='raise_skeleton',delay: float=1.0, radius=120, hold_duration: float = 3, hold=True): + def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_spell: SkillName=SkillName.RaiseSkeleton,delay: float=1.0, radius=120, hold_duration: float = 3, hold=True): if hold: - Logger.info(f'Circle cast {cast_spell} from {cast_start_angle}º to {cast_end_angle}º over {hold_duration}s') + Logger.info(f'Circle cast {cast_spell.value} from {cast_start_angle}º to {cast_end_angle}º over {hold_duration}s') else: - Logger.info(f'Circle cast {cast_spell} from {cast_start_angle}º to {cast_end_angle}º over {cast_div} casts') + Logger.info(f'Circle cast {cast_spell.value} from {cast_start_angle}º to {cast_end_angle}º over {cast_div} casts') - keyboard.send(Config().char["stand_still"], do_release=False) - keyboard.send(self._skill_hotkeys[cast_spell]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + keyboard.send(hotkeys.right_skill_key_map[cast_spell]) if hold: mouse.press(button="right") @@ -124,15 +126,15 @@ def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, delay = delay*(expected/duration) if hold: mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def kill_pindle(self) -> bool: for pos in [[200,-100], [-150,100] ]: self.bone_wall(pos, spray=10) - self.cast_in_arc(ability='bone_spear', cast_pos_abs=[110,-50], spread_deg=15, time_in_s=5) + self.cast_in_arc(skill_name=SkillName.BoneSpear, cast_pos_abs=[110,-50], spread_deg=15, time_in_s=5) self._corpse_explosion([165,-75], spray=100, cast_count=5) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[110,-50], spread_deg=15, time_in_s=2.5) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[110,-50], spread_deg=15, time_in_s=2.5) self._pather.traverse_nodes_fixed("pindle_end", self) return True @@ -140,10 +142,10 @@ def kill_eldritch(self) -> bool: #build an arc of bone walls for pos in [[50,-200], [-200,-175], [-350,50]]: self.bone_wall(pos, spray=10) - self.cast_in_arc(ability='teeth', cast_pos_abs=[-20,-150], spread_deg=15, time_in_s=3) - self.cast_in_arc(ability='bone_spear', cast_pos_abs=[-20,-150], spread_deg=15, time_in_s=2) + self.cast_in_arc(skill_name=SkillName.Teeth, cast_pos_abs=[-20,-150], spread_deg=15, time_in_s=3) + self.cast_in_arc(skill_name=SkillName.BoneSpear, cast_pos_abs=[-20,-150], spread_deg=15, time_in_s=2) self._corpse_explosion([-20,-240], spray=100, cast_count=5) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[0,-80], spread_deg=60, time_in_s=2.5) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[0,-80], spread_deg=60, time_in_s=2.5) self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=0.6, force_tp=True) self.bone_armor() return True @@ -151,12 +153,12 @@ def kill_eldritch(self) -> bool: def kill_shenk(self) -> bool: self._cast_circle(cast_dir=[1,1],cast_start_angle=0,cast_end_angle=360,cast_div=5,cast_spell='bone_wall',delay=.8,radius=100, hold=False) - self.cast_in_arc(ability='teeth', cast_pos_abs=[160,75], spread_deg=360, time_in_s=6) - self.cast_in_arc(ability='teeth', cast_pos_abs=[160,75], spread_deg=30, time_in_s=2) + self.cast_in_arc(skill_name=SkillName.Teeth, cast_pos_abs=[160,75], spread_deg=360, time_in_s=6) + self.cast_in_arc(skill_name=SkillName.Teeth, cast_pos_abs=[160,75], spread_deg=30, time_in_s=2) self._corpse_explosion([0,0], spray=200, cast_count=4) - self.cast_in_arc(ability='bone_spear', cast_pos_abs=[160,75], spread_deg=30, time_in_s=3) + self.cast_in_arc(skill_name=SkillName.BoneSpear, cast_pos_abs=[160,75], spread_deg=30, time_in_s=3) self._corpse_explosion([240,112], spray=200, cast_count=8) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[80,37], spread_deg=60, time_in_s=3) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[80,37], spread_deg=60, time_in_s=3) self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0) return True @@ -169,13 +171,12 @@ def kill_council(self) -> bool: #moat on right side, encircle with bone walls on the other 3 sides for pos in [[100,-100], [-125,-25], [-50,100]]: self.bone_wall(pos, spray=10) - self.cast_in_arc(ability='teeth', cast_pos_abs=[40,-100], spread_deg=180, time_in_s=5) - self.cast_in_arc(ability='bone_spear', cast_pos_abs=[40,-100], spread_deg=120, time_in_s=8) - + self.cast_in_arc(skill_name=SkillName.Teeth, cast_pos_abs=[40,-100], spread_deg=180, time_in_s=5) + self.cast_in_arc(skill_name=SkillName.BoneSpear, cast_pos_abs=[40,-100], spread_deg=120, time_in_s=8) self._corpse_explosion([40,-100], spray=200, cast_count=8) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[20,-50], spread_deg=180, time_in_s=5) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[20,-50], spread_deg=180, time_in_s=5) self._corpse_explosion([40,-100], spray=200, cast_count=8) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[20,-50], spread_deg=360, time_in_s=4) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[20,-50], spread_deg=360, time_in_s=4) return True @@ -187,16 +188,16 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: return False cast_pos_abs = np.array(nihlathak_pos_abs)*.2 - self._cast_circle(cast_dir=[1,1],cast_start_angle=0,cast_end_angle=360,cast_div=5,cast_spell='bone_wall',delay=.8,radius=100, hold=False) + self._cast_circle(cast_dir=[1,1],cast_start_angle=0,cast_end_angle=360,cast_div=5,cast_spell=SkillName.BoneWall,delay=.8,radius=100, hold=False) self._bone_armor() - self.cast_in_arc(ability='teeth', cast_pos_abs=cast_pos_abs, spread_deg=150, time_in_s=5) + self.cast_in_arc(skill_name=SkillName.Teeth, cast_pos_abs=cast_pos_abs, spread_deg=150, time_in_s=5) self._bone_armor() self._corpse_explosion(cast_pos_abs, spray=200, cast_count=8) - self.cast_in_arc(ability='bone_spear', cast_pos_abs=cast_pos_abs, spread_deg=10, time_in_s=5) + self.cast_in_arc(skill_name=SkillName.BoneSpear, cast_pos_abs=cast_pos_abs, spread_deg=10, time_in_s=5) self._bone_armor() self._corpse_explosion(np.array(nihlathak_pos_abs)*.75, spray=200, cast_count=10) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=cast_pos_abs, spread_deg=30, time_in_s=2.5) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=cast_pos_abs, spread_deg=30, time_in_s=2.5) # Move to items wait(self._cast_duration, self._cast_duration + 0.2) @@ -205,10 +206,10 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: def kill_summoner(self) -> bool: # Attack - self.cast_in_arc(ability='teeth', cast_pos_abs=[30,30], spread_deg=360, time_in_s=3) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[30,30], spread_deg=360, time_in_s=2) + self.cast_in_arc(skill_name=SkillName.Teeth, cast_pos_abs=[30,30], spread_deg=360, time_in_s=3) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[30,30], spread_deg=360, time_in_s=2) self._corpse_explosion([0,0], spray=200, cast_count=8) - self.cast_in_arc(ability='bone_spirit', cast_pos_abs=[30,30], spread_deg=360, time_in_s=2) + self.cast_in_arc(skill_name=SkillName.BoneSpirit, cast_pos_abs=[30,30], spread_deg=360, time_in_s=2) return True diff --git a/src/char/i_char.py b/src/char/i_char.py index 4374b43ef..cc44bb825 100644 --- a/src/char/i_char.py +++ b/src/char/i_char.py @@ -9,6 +9,9 @@ from char.capabilities import CharacterCapabilities from ui_manager import is_visible, wait_until_visible from ui import skills +from ui.skills import SkillName +from utils import hotkeys +from utils.hotkeys import HotkeyName from utils.custom_mouse import mouse from utils.misc import wait, cut_roi, is_in_roi, color_filter, arc_spread from logger import Logger @@ -36,18 +39,17 @@ def __init__(self, skill_hotkeys: dict): def _set_active_skill(self, mouse_click_type: str = "left", skill: str =""): self._active_skill[mouse_click_type] = skill - def _select_skill(self, skill: str, mouse_click_type: str = "left", delay: float | list | tuple = None): - if not ( - skill in self._skill_hotkeys and (hotkey := self._skill_hotkeys[skill]) - or (skill in Config().char and (hotkey := Config().char[skill])) - ): - Logger.warning(f"No hotkey for skill: {skill}") - self._set_active_skill(mouse_click_type, "") + def _select_skill(self, skill: SkillName, mouse_click_type: str = "left", delay: float | list | tuple = None): + if mouse_click_type == 'right' and skill not in hotkeys.right_skill_key_map: + Logger.warning(f"No hotkey for skill: {skill.value}") return False - - if self._active_skill[mouse_click_type] != skill: - keyboard.send(hotkey) - self._set_active_skill(mouse_click_type, skill) + elif mouse_click_type == 'left' and (skill not in hotkeys.left_skill_key_map or skill.value != hotkeys.left_skill): + Logger.warning(f"No hotkey for skill: {skill.value}") + return False + if self._active_skill[mouse_click_type] != skill.value: + keyboard.send(hotkeys.right_skill_key_map[skill]) if mouse_click_type == 'right' else\ + keyboard.send(hotkeys.left_skill_key_map[skill]) + self._set_active_skill(mouse_click_type, skill.value) if delay: try: wait(*delay) @@ -61,8 +63,8 @@ def _select_skill(self, skill: str, mouse_click_type: str = "left", delay: float def _discover_capabilities(self) -> CharacterCapabilities: override = Config().advanced_options["override_capabilities"] if override is None: - if Config().char["teleport"]: - if self.select_tp(): + if SkillName.Teleport in hotkeys.right_skill_key_map: + if skills.select_tp(hotkeys.right_skill_key_map[SkillName.Teleport]): if self.skill_is_charged(): return CharacterCapabilities(can_teleport_natively=False, can_teleport_with_charges=True) else: @@ -113,7 +115,7 @@ def select_by_template( if type(template_type) == list and "A5_STASH" in template_type: # sometimes waypoint is opened and stash not found because of that, check for that if is_visible(ScreenObjects.WaypointLabel): - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) start = time.time() while timeout is None or (time.time() - start) < timeout: template_match = template_finder.search(template_type, grab(), threshold=threshold) @@ -151,39 +153,21 @@ def is_low_on_teleport_charges(self): Logger.error("is_low_on_teleport_charges: unable to determine skill charges, assume zero") return True - def _remap_skill_hotkey(self, skill_asset, hotkey, skill_roi, expanded_skill_roi): - x, y, w, h = skill_roi - x, y = convert_screen_to_monitor((x, y)) - mouse.move(x + w/2, y + h / 2) - mouse.click("left") - wait(0.3) - match = template_finder.search(skill_asset, grab(), threshold=0.84, roi=expanded_skill_roi) - if match.valid: - mouse.move(*match.center_monitor) - wait(0.3) - keyboard.send(hotkey) - wait(0.3) - mouse.click("left") - wait(0.3) - - def remap_right_skill_hotkey(self, skill_asset, hotkey): - return self._remap_skill_hotkey(skill_asset, hotkey, Config().ui_roi["skill_right"], Config().ui_roi["skill_right_expanded"]) - - def select_tp(self): - return skills.select_tp(Config().char["teleport"]) + def select_teleport(self): + return skills.select_tp(hotkeys.right_skill_key_map[SkillName.Teleport]) def pre_move(self): # if teleport hotkey is set and if teleport is not already selected - if self.capabilities.can_teleport_natively: - self.select_tp() + if SkillName.Teleport in hotkeys.right_skill_key_map: + skills.select_tp(hotkeys.right_skill_key_map[SkillName.Teleport]) self._set_active_skill("right", "teleport") def move(self, pos_monitor: tuple[float, float], force_tp: bool = False, force_move: bool = False): factor = Config().advanced_options["pathing_delay_factor"] - if "teleport" in Config().char and Config().char["teleport"] and ( + if SkillName.Teleport in hotkeys.right_skill_key_map and ( force_tp or ( - skills.is_right_skill_selected(["TELE_ACTIVE"]) + skills.is_right_skill_selected(["TELEPORT"]) and skills.is_right_skill_active() ) ): @@ -205,7 +189,7 @@ def move(self, pos_monitor: tuple[float, float], force_tp: bool = False, force_m mouse.move(x, y, randomize=5, delay_factor=[factor*0.1, factor*0.14]) wait(0.012, 0.02) if force_move: - keyboard.send(Config().char["force_move"]) + keyboard.send(hotkeys.d2r_keymap[HotkeyName.ForceMove]) else: mouse.click(button="left") @@ -223,7 +207,7 @@ def walk(self, pos_monitor: tuple[float, float], force_tp: bool = False, force_m mouse.move(x, y, randomize=5, delay_factor=[factor*0.1, factor*0.14]) wait(0.012, 0.02) if force_move: - keyboard.send(Config().char["force_move"]) + keyboard.send(hotkeys.d2r_keymap[HotkeyName.ForceMove]) else: mouse.click(button="left") @@ -275,14 +259,16 @@ def _pre_buff_cta(self): # Try to switch weapons and select bo until we find the skill on the right skill slot start = time.time() switch_sucess = False + if SkillName.BattleCommand not in hotkeys.right_skill_key_map: + return while time.time() - start < 4: - keyboard.send(Config().char["weapon_switch"]) + keyboard.send(hotkeys.d2r_keymap[HotkeyName.SwapWeapons]) wait(0.3, 0.35) - self._select_skill(skill = "battle_command", mouse_click_type="right", delay=(0.1, 0.2)) - if skills.is_right_skill_selected(["BC", "BO"]): + keyboard.send(hotkeys.right_skill_key_map[SkillName.BattleCommand]) + wait(0.15) + if skills.is_right_skill_selected([SkillName.BattleCommand.value, SkillName.BattleOrders.value]): switch_sucess = True break - if not switch_sucess: Logger.warning("You dont have Battle Command bound, or you do not have CTA. ending CTA buff") Config().char["cta_available"] = 0 @@ -290,14 +276,14 @@ def _pre_buff_cta(self): # We switched succesfully, let's pre buff mouse.click(button="right") wait(self._cast_duration + 0.16, self._cast_duration + 0.18) - self._select_skill(skill = "battle_orders", mouse_click_type="right", delay=(0.1, 0.2)) + self._select_skill(skill = SkillName.BattleOrders, mouse_click_type="right", delay=(0.1, 0.2)) mouse.click(button="right") wait(self._cast_duration + 0.16, self._cast_duration + 0.18) # Make sure the switch back to the original weapon is good start = time.time() while time.time() - start < 4: - keyboard.send(Config().char["weapon_switch"]) + keyboard.send(hotkeys.d2r_keymap[HotkeyName.SwapWeapons]) wait(0.3, 0.35) skill_after = cut_roi(grab(), Config().ui_roi["skill_right"]) _, max_val, _, _ = cv2.minMaxLoc(cv2.matchTemplate(skill_after, skill_before, cv2.TM_CCOEFF_NORMED)) @@ -315,14 +301,14 @@ def vec_to_monitor(self, target): def _lerp(self,a: float,b: float, f:float): return a + f * (b - a) - def cast_in_arc(self, ability: str, cast_pos_abs: tuple[float, float] = [0,-100], time_in_s: float = 3, spread_deg: float = 10, hold=True): + def cast_in_arc(self, skill_name: SkillName, cast_pos_abs: tuple[float, float] = [0,-100], time_in_s: float = 3, spread_deg: float = 10, hold=True): #scale cast time by damage_scaling time_in_s *= self.damage_scaling - Logger.debug(f'Casting {ability} for {time_in_s:.02f}s at {cast_pos_abs} with {spread_deg}°') - if not self._skill_hotkeys[ability]: - raise ValueError(f"You did not set {ability} hotkey!") - keyboard.send(Config().char["stand_still"], do_release=False) - self._select_skill(skill = ability, mouse_click_type="right", delay=(0.02, 0.08)) + Logger.debug(f'Casting {skill_name.value} for {time_in_s:.02f}s at {cast_pos_abs} with {spread_deg}°') + if skill_name not in hotkeys.right_skill_key_map: + raise ValueError(f"You did not set {skill_name.value} hotkey!") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + self._select_skill(skill = skill_name, mouse_click_type="right", delay=(0.02, 0.08)) target = self.vec_to_monitor(arc_spread(cast_pos_abs, spread_deg=spread_deg)) mouse.move(*target,delay_factor=[0.95, 1.05]) @@ -343,7 +329,7 @@ def cast_in_arc(self, ability: str, cast_pos_abs: tuple[float, float] = [0,-100] if hold: mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def pre_buff(self): diff --git a/src/char/necro.py b/src/char/necro.py index 02535d7fa..e53c694e8 100644 --- a/src/char/necro.py +++ b/src/char/necro.py @@ -1,4 +1,6 @@ import keyboard +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar import template_finder @@ -152,10 +154,11 @@ def _summon_stat(self): def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=12): Logger.info('\033[94m'+"raise revive"+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + if SkillName.Revive not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) for _ in range(cast_count): - if self._skill_hotkeys["raise_revive"]: - keyboard.send(self._skill_hotkeys["raise_revive"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Revive]) #Logger.info("revive -> cast") x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -177,14 +180,15 @@ def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count mouse.press(button="right") wait(0.075, 0.1) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise skeleton"+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + if SkillName.RaiseSkeleton not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) for _ in range(cast_count): - if self._skill_hotkeys["raise_skeleton"]: - keyboard.send(self._skill_hotkeys["raise_skeleton"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.RaiseSkeleton]) #Logger.info("raise skeleton -> cast") x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -206,14 +210,15 @@ def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, ca mouse.press(button="right") wait(0.02, 0.05) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise mage"+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + if SkillName.RaiseSkeletalMage not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) for _ in range(cast_count): - if self._skill_hotkeys["raise_mage"]: - keyboard.send(self._skill_hotkeys["raise_mage"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.RaiseSkeletalMage]) #Logger.info("raise skeleton -> cast") x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -235,7 +240,7 @@ def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_c mouse.press(button="right") wait(0.02, 0.05) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def pre_buff(self): @@ -250,34 +255,34 @@ def pre_buff(self): def _heart_of_wolverine(self): Logger.info('\033[94m'+"buff ~> heart_of_wolverine"+'\033[0m') - keyboard.send(self._skill_hotkeys["heart_of_wolverine"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.HeartOfWolverine]) wait(0.05, 0.2) mouse.click(button="right") wait(self._cast_duration) def _clay_golem(self): Logger.info('\033[94m'+"cast ~> clay golem"+'\033[0m') - keyboard.send(self._skill_hotkeys["clay_golem"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.ClayGolem]) wait(0.05, 0.2) mouse.click(button="right") wait(self._cast_duration) def bone_armor(self): - if self._skill_hotkeys["bone_armor"]: - keyboard.send(self._skill_hotkeys["bone_armor"]) + if SkillName.BoneArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneArmor]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["clay_golem"]: - keyboard.send(self._skill_hotkeys["clay_golem"]) + if SkillName.ClayGolem in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.ClayGolem]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) def _bone_armor(self): - if self._skill_hotkeys["bone_armor"]: - keyboard.send(self._skill_hotkeys["bone_armor"]) + if SkillName.BoneArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneArmor]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) @@ -285,7 +290,7 @@ def _bone_armor(self): def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) for _ in range(10): @@ -297,10 +302,10 @@ def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): wait(0.25, 0.3) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=6): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) for _ in range(cast_count): @@ -312,11 +317,11 @@ def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10 wait(0.25, 0.3) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10): - if self._skill_hotkeys["amp_dmg"]: - keyboard.send(self._skill_hotkeys["amp_dmg"]) + if SkillName.AmplifyDamage in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.AmplifyDamage]) x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -327,11 +332,11 @@ def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10): mouse.release(button="right") def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) Logger.info('\033[93m'+"corpse explosion~> random cast"+'\033[0m') for _ in range(cast_count): - if self._skill_hotkeys["corpse_explosion"]: - keyboard.send(self._skill_hotkeys["corpse_explosion"]) + if SkillName.CorpseExplosion in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.CorpseExplosion]) x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) cast_pos_monitor = convert_abs_to_monitor((x, y)) @@ -339,12 +344,12 @@ def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,c mouse.press(button="right") wait(0.075, 0.1) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) - def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0): - Logger.info('\033[93m'+"circle cast ~>"+cast_spell+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) - keyboard.send(self._skill_hotkeys[cast_spell]) + def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: SkillName=SkillName.RaiseSkeleton,delay: float=1.0,offset: float=1.0): + Logger.info('\033[93m'+"circle cast ~>"+cast_spell.value+'\033[0m') + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + keyboard.send(hotkeys.right_skill_key_map[cast_spell]) mouse.press(button="right") for i in range(cast_div): @@ -358,7 +363,7 @@ def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, #Logger.info("circle move") mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def kill_pindle(self) -> bool: @@ -372,9 +377,9 @@ def kill_pindle(self) -> bool: raise_skel_pos = [0,10] rot_deg=0 - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=32,cast_v_div=2,cast_spell='raise_skeleton',offset=2,delay=1.6) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=32,cast_v_div=2,cast_spell=SkillName.RaiseSkeleton,offset=2,delay=1.6) wait(self._cast_duration, self._cast_duration +.2) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='amp_dmg',delay=3.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.AmplifyDamage,delay=3.0) rot_deg=0 @@ -386,11 +391,11 @@ def kill_pindle(self) -> bool: if(pindle_pack_kill): Logger.info('\033[93m'+"optional pindle pack"+'\033[0m') - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=2,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) wait(self._cast_duration, self._cast_duration +.2) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=2,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) wait(self._cast_duration, self._cast_duration +.1) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=2,cast_spell='raise_revive',delay=1.2,offset=1.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=2,cast_spell=SkillName.Revive,delay=1.2,offset=1.8) #move to pindle combat position @@ -491,7 +496,7 @@ def kill_eldritch(self) -> bool: #get some more summons out for elite packs - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=4,cast_spell='raise_revive',delay=1.2,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=12,cast_v_div=4,cast_spell=SkillName.Revive,delay=1.2,offset=.8) #self._summon_count() #self._raise_skeleton([0,-40],80,cast_count=4) #self._raise_mage(cast_pos_abs,80,cast_count=10) @@ -522,7 +527,7 @@ def kill_shenk(self) -> bool: Logger.info('\033[93m'+"dealing with posible packs"+'\033[0m') self.bone_armor() - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='amp_dmg',delay=3.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.AmplifyDamage,delay=3.0) self._corpse_explosion([0,50], 80, cast_count=8) self._summon_stat() @@ -535,7 +540,7 @@ def kill_shenk(self) -> bool: cast_pos_abs = [shenk_pos_abs[0] * 0.9, shenk_pos_abs[1] * 0.9] self.bone_armor() - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='amp_dmg',delay=3.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.AmplifyDamage,delay=3.0) corpse_exp_pos = [200,80] for _ in range(int(Config().char["atk_len_shenk"])): @@ -748,7 +753,7 @@ def kill_council(self) -> bool: #try again result = self._pather.traverse_nodes((902,903,904,905,906,226,228,300), self, force_move=True,timeout = 2.5) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='amp_dmg',delay=3.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.AmplifyDamage,delay=3.0) enter = False while enter is False: @@ -756,7 +761,7 @@ def kill_council(self) -> bool: wait(.25) exit = self.to_trav() - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='amp_dmg',delay=3.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.AmplifyDamage,delay=3.0) #enter = False #while enter is False: diff --git a/src/char/paladin/fohdin.py b/src/char/paladin/fohdin.py index b2fcc186e..33d54709c 100644 --- a/src/char/paladin/fohdin.py +++ b/src/char/paladin/fohdin.py @@ -6,6 +6,8 @@ from health_manager import get_panel_check_paused, set_panel_check_paused from inventory.personal import inspect_items from screen import convert_abs_to_monitor, convert_screen_to_abs, grab, convert_abs_to_screen +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char.paladin import Paladin from logger import Logger @@ -21,17 +23,17 @@ def __init__(self, *args, **kwargs): self._pather.adapt_path((Location.A3_TRAV_START, Location.A3_TRAV_CENTER_STAIRS), [220, 221, 222, 903, 904, 905, 906]) - def _cast_foh(self, cast_pos_abs: tuple[float, float], spray: int = 10, min_duration: float = 0, aura: str = "conviction"): - return self._cast_skill_with_aura(skill_name = "foh", cast_pos_abs = cast_pos_abs, spray = spray, min_duration = min_duration, aura = aura) + def _cast_foh(self, cast_pos_abs: tuple[float, float], spray: int = 10, min_duration: float = 0, aura: SkillName = SkillName.Conviction): + return self._cast_skill_with_aura(skill_name = SkillName.FistOfTheHeavens, cast_pos_abs = cast_pos_abs, spray = spray, min_duration = min_duration, aura = aura) - def _cast_holy_bolt(self, cast_pos_abs: tuple[float, float], spray: int = 10, min_duration: float = 0, aura: str = "concentration"): + def _cast_holy_bolt(self, cast_pos_abs: tuple[float, float], spray: int = 10, min_duration: float = 0, aura: SkillName = SkillName.Concentration): #if skill is bound : concentration, use concentration, otherwise move on with conviction. alternatively use redemption whilst holybolting. conviction does not help holy bolt (its magic damage) - return self._cast_skill_with_aura(skill_name = "holy_bolt", cast_pos_abs = cast_pos_abs, spray = spray, min_duration = min_duration, aura = aura) + return self._cast_skill_with_aura(skill_name = SkillName.HolyBolt, cast_pos_abs = cast_pos_abs, spray = spray, min_duration = min_duration, aura = aura) - def _cast_hammers(self, min_duration: float = 0, aura: str = "concentration"): #for nihlathak - return self._cast_skill_with_aura(skill_name = "blessed_hammer", spray = 0, min_duration = min_duration, aura = aura) + def _cast_hammers(self, min_duration: float = 0, aura: SkillName = SkillName.Concentration): #for nihlathak + return self._cast_skill_with_aura(skill_name = SkillName.BlessedHammer, spray = 0, min_duration = min_duration, aura = aura) - def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float, aura: str = "concentration"): #for nihalthak + def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float, aura: SkillName = SkillName.Concentration): #for nihalthak pos_m = convert_abs_to_monitor(abs_move) self.pre_move() self.move(pos_m, force_move=True) @@ -49,8 +51,8 @@ def _generic_foh_attack_sequence( ) -> bool: start = time.time() target_check_count = 1 - foh_aura = aura if aura else "conviction" - holy_bolt_aura = aura if aura else "concentration" + foh_aura = aura if aura else SkillName.Conviction + holy_bolt_aura = aura if aura else SkillName.Concentration while (elapsed := (time.time() - start)) <= max_duration: cast_pos_abs = default_target_abs spray = default_spray @@ -108,7 +110,7 @@ def kill_pindle(self) -> bool: if not self._pather.traverse_nodes([103], self, timeout=1.0, do_pre_move=False, force_move=True, force_tp=False, use_tp_charge=False): return False else: - keyboard.send(self._skill_hotkeys["conviction"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Conviction]) wait(0.15) self._pather.traverse_nodes([103], self, timeout=1.0, do_pre_move=False) @@ -118,8 +120,7 @@ def kill_pindle(self) -> bool: if self.capabilities.can_teleport_natively: self._pather.traverse_nodes_fixed("pindle_end", self) else: - - keyboard.send(self._skill_hotkeys["redemption"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.15) self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, timeout=1.0, do_pre_move=False) @@ -133,7 +134,7 @@ def kill_pindle(self) -> bool: def kill_council(self) -> bool: atk_len_dur = float(Config().char["atk_len_trav"]) - keyboard.send(self._skill_hotkeys["conviction"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Conviction]) wait(.15) # traverse to nodes and attack nodes = [225, 226, 300] @@ -174,13 +175,13 @@ def kill_shenk(self): atk_len_dur = float(Config().char["atk_len_shenk"]) # traverse to shenk - keyboard.send(self._skill_hotkeys["conviction"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Conviction]) wait(0.15) self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) wait(0.05, 0.1) # bypass mob detect first - self._cast_foh((0, 0), spray=11, min_duration = 2, aura = "conviction") + self._cast_foh((0, 0), spray=11, min_duration = 2, aura = SkillName.Conviction) # then do generic mob detect sequence diff = atk_len_dur if atk_len_dur <= 2 else (atk_len_dur - 2) self._generic_foh_attack_sequence(min_duration=atk_len_dur - diff, max_duration=atk_len_dur*3 - diff, default_spray=10, target_detect=False) @@ -193,14 +194,14 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: atk_len_dur = Config().char["atk_len_nihlathak"] # Move close to nihlathak self._pather.traverse_nodes(end_nodes, self, timeout=0.8, do_pre_move=False) - if self._select_skill("blessed_hammer"): + if self._select_skill(SkillName.BlessedHammer): self._cast_hammers(atk_len_dur/4) - self._cast_hammers(2*atk_len_dur/4, "redemption") - self._move_and_attack((30, 15), atk_len_dur/4, "redemption") + self._cast_hammers(2*atk_len_dur/4, SkillName.Redemption) + self._move_and_attack((30, 15), atk_len_dur/4, SkillName.Redemption) else: Logger.warning("FOHDin without blessed hammer is not very strong vs. Nihlathak!") - self._generic_foh_attack_sequence(min_duration=atk_len_dur/2, max_duration=atk_len_dur, default_spray=70, aura="redemption") - self._generic_foh_attack_sequence(min_duration=atk_len_dur/2, max_duration=atk_len_dur, default_spray=70, aura="redemption") + self._generic_foh_attack_sequence(min_duration=atk_len_dur/2, max_duration=atk_len_dur, default_spray=70, aura=SkillName.Redemption) + self._generic_foh_attack_sequence(min_duration=atk_len_dur/2, max_duration=atk_len_dur, default_spray=70, aura=SkillName.Redemption) self._generic_foh_attack_sequence(max_duration=atk_len_dur*2, default_spray=70) self._activate_cleanse_redemption() return True @@ -760,4 +761,4 @@ def kill_diablo(self) -> bool: self._activate_cleanse_redemption() ### LOOT ### #self._cs_pickit() - return True \ No newline at end of file + return True diff --git a/src/char/paladin/hammerdin.py b/src/char/paladin/hammerdin.py index 8fa88ed1b..8cf043728 100644 --- a/src/char/paladin/hammerdin.py +++ b/src/char/paladin/hammerdin.py @@ -12,6 +12,8 @@ from screen import convert_abs_to_monitor, convert_screen_to_abs, grab from target_detect import get_visible_targets from ui import skills +from ui.skills import SkillName, is_right_skill_active, is_right_skill_selected +from utils import hotkeys from utils.custom_mouse import mouse from utils.misc import wait @@ -22,14 +24,14 @@ def __init__(self, *args, **kwargs): #hammerdin needs to be closer to shenk to reach it with hammers self._pather.offset_node(149, (70, 10)) - def _cast_hammers(self, time_in_s: float, aura: str = "concentration"): - if aura in self._skill_hotkeys and self._skill_hotkeys[aura]: - keyboard.send(self._skill_hotkeys[aura]) + def _cast_hammers(self, time_in_s: float, aura: SkillName = SkillName.Concentration): + if aura in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[aura]) wait(0.05, 0.1) - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) wait(0.05, 0.1) - if self._skill_hotkeys["blessed_hammer"]: - keyboard.send(self._skill_hotkeys["blessed_hammer"]) + if SkillName.BlessedHammer in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BlessedHammer]) wait(0.05, 0.1) start = time.time() while (time.time() - start) < time_in_s: @@ -38,12 +40,12 @@ def _cast_hammers(self, time_in_s: float, aura: str = "concentration"): wait(0.1, 0.2) mouse.release(button="left") wait(0.01, 0.05) - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def pre_buff(self): if Config().char["cta_available"]: self._pre_buff_cta() - keyboard.send(self._skill_hotkeys["holy_shield"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.HolyShield]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration, self._cast_duration + 0.06) @@ -52,10 +54,10 @@ def pre_move(self): # select teleport if available super().pre_move() # in case teleport hotkey is not set or teleport can not be used, use vigor if set - should_cast_vigor = self._skill_hotkeys["vigor"] and not skills.is_right_skill_selected(["VIGOR"]) - can_teleport = self.capabilities.can_teleport_natively and skills.is_right_skill_active() + should_cast_vigor = SkillName.Vigor in hotkeys.right_skill_key_map and not is_right_skill_selected([SkillName.Vigor]) + can_teleport = self.capabilities.can_teleport_natively and is_right_skill_active() if should_cast_vigor and not can_teleport: - keyboard.send(self._skill_hotkeys["vigor"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Vigor]) wait(0.15, 0.25) def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float): @@ -73,12 +75,12 @@ def kill_pindle(self) -> bool: if not self._pather.traverse_nodes_fixed("pindle_end", self): return False else: - keyboard.send(self._skill_hotkeys["concentration"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Concentration]) wait(0.15) self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) self._cast_hammers(Config().char["atk_len_pindle"]) wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") + self._cast_hammers(1.6, SkillName.Redemption) return True def kill_eldritch(self) -> bool: @@ -86,28 +88,28 @@ def kill_eldritch(self) -> bool: # Custom eld position for teleport that brings us closer to eld self._pather.traverse_nodes_fixed([(675, 30)], self) else: - keyboard.send(self._skill_hotkeys["concentration"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Concentration]) wait(0.15) # Traverse without pre_move, because we don't want to activate vigor when walking! self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) wait(0.05, 0.1) self._cast_hammers(Config().char["atk_len_eldritch"]) wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") + self._cast_hammers(1.6, SkillName.Redemption) return True def kill_shenk(self): - keyboard.send(self._skill_hotkeys["concentration"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Concentration]) wait(0.15) self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0, do_pre_move=False, force_tp=True, use_tp_charge=True) wait(0.05, 0.1) self._cast_hammers(Config().char["atk_len_shenk"]) wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") + self._cast_hammers(1.6, SkillName.Redemption) return True def kill_council(self) -> bool: - keyboard.send(self._skill_hotkeys["concentration"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Concentration]) wait(.15) # Check out the node screenshot in assets/templates/trav/nodes to see where each node is at atk_len = Config().char["atk_len_trav"] @@ -126,7 +128,7 @@ def kill_council(self) -> bool: # Stay inside and cast hammers again moving forward self._move_and_attack((40, 10), atk_len) self._move_and_attack((-40, -20), atk_len) - self._cast_hammers(1.6, "redemption") + self._cast_hammers(1.6, SkillName.Redemption) return True def kill_nihlathak(self, end_nodes: list[int]) -> bool: @@ -136,12 +138,12 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._cast_hammers(Config().char["atk_len_nihlathak"] * 0.4) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((30, 15), Config().char["atk_len_nihlathak"] * 0.3) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_nihlathak"] * 0.4) wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") + self._cast_hammers(1.2, SkillName.Redemption) return True def kill_summoner(self) -> bool: @@ -151,11 +153,11 @@ def kill_summoner(self) -> bool: # Attack self._cast_hammers(Config().char["atk_len_arc"]) wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") + self._cast_hammers(1.6, SkillName.Redemption) # Move a bit back and another round self._move_and_attack((0, 80), Config().char["atk_len_arc"] * 0.5) wait(0.1, 0.15) - self._cast_hammers(1.6, "redemption") + self._cast_hammers(1.6, SkillName.Redemption) return True ######################################################################################## @@ -175,13 +177,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.5, 1.0) #clear seal from corpses ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -201,14 +203,14 @@ def kill_cs_trash(self, location:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) ### LOOT ### - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -224,13 +226,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -244,13 +246,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -265,13 +267,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -290,13 +292,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -309,13 +311,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -329,13 +331,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -351,14 +353,14 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-50, -150), Config().char["atk_len_cs_trashmobs"]) self._move_and_attack((50, 150), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -372,13 +374,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -394,13 +396,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -419,13 +421,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -445,16 +447,16 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((0, 0), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-50, -150), Config().char["atk_len_cs_trashmobs"] * 0.5) self._move_and_attack((50, 150), Config().char["atk_len_cs_trashmobs"] * 0.2) self._move_and_attack((250, -150), Config().char["atk_len_cs_trashmobs"] * 0.5) self._move_and_attack((-250, -150), Config().char["atk_len_cs_trashmobs"] * 0.2) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -474,14 +476,14 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -493,14 +495,14 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -512,14 +514,14 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"]) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -100), Config().char["atk_len_cs_trashmobs"]) self._move_and_attack((30, 100), Config().char["atk_len_cs_trashmobs"]) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -535,13 +537,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -554,13 +556,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -572,13 +574,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -600,13 +602,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -618,13 +620,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -642,13 +644,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### # we loot at boss @@ -658,21 +660,21 @@ def kill_cs_trash(self, location:str) -> bool: if not self._pather.traverse_nodes([612], self): return False # , timeout=3): ### ATTACK ### if not Config().char['cs_mob_detect'] or get_visible_targets(): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._cast_hammers(0.5, "cleansing") - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + self._cast_hammers(0.75, SkillName.Redemption) + self._cast_hammers(0.5, SkillName.Cleansing) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### # we loot at boss @@ -685,17 +687,17 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") - self._cast_hammers(0.5, "cleansing") + self._cast_hammers(0.75, SkillName.Redemption) + self._cast_hammers(0.5, SkillName.Cleansing) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) case "A1-L_seal1": #node 613 seal layout A1-L: fake_seal @@ -703,8 +705,8 @@ def kill_cs_trash(self, location:str) -> bool: self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([614], self): return False ### ATTACK ### - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### # we loot at boss @@ -713,8 +715,8 @@ def kill_cs_trash(self, location:str) -> bool: ### APPROACH ### if not self._pather.traverse_nodes([613, 615], self): return False # , timeout=3): ### ATTACK ### - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### # we loot at boss @@ -731,20 +733,20 @@ def kill_cs_trash(self, location:str) -> bool: if not self._pather.traverse_nodes([622], self): return False wait(1)#give merc the chance to activate holy freeze if not Config().char['cs_mob_detect'] or get_visible_targets(): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### ATTACK ### pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### # we loot at boss @@ -757,13 +759,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### # we loot at boss @@ -781,8 +783,8 @@ def kill_cs_trash(self, location:str) -> bool: ### LOOT ### # we loot at boss if not self._pather.traverse_nodes([625], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) case "A2-Y_seal2": @@ -791,8 +793,8 @@ def kill_cs_trash(self, location:str) -> bool: ### LOOT ### # we loot at boss self._pather.traverse_nodes_fixed("dia_a2y_sealfake_sealboss", self) #instead of traversing node 626 which causes issues - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ########### @@ -824,8 +826,8 @@ def kill_cs_trash(self, location:str) -> bool: ### APPROACH ### if not self._pather.traverse_nodes([634], self): return False # , timeout=3): ### ATTACK ### - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### @@ -862,8 +864,8 @@ def kill_cs_trash(self, location:str) -> bool: ### ATTACK ### ### LOOT ### # we loot at boss - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) @@ -903,19 +905,19 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([655], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) case "C1-F_seal2": @@ -927,19 +929,19 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([652], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ########### @@ -979,18 +981,18 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) """ @@ -1005,16 +1007,16 @@ def kill_cs_trash(self, location:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) Logger.debug(seal_layout + ": Attacking Infector at position 1/1") self._cast_hammers(Config().char["atk_len_diablo_infector"]) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((30, 15), Config().char["atk_len_diablo_infector"]) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((30, -15), Config().char["atk_len_diablo_infector"]) wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") + self._cast_hammers(1.2, SkillName.Redemption) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) if not self._pather.traverse_nodes([664, 665], self): return False # , timeout=3): @@ -1026,13 +1028,13 @@ def kill_cs_trash(self, location:str) -> bool: pos_m = convert_abs_to_monitor((0, 0)) mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_cs_trashmobs"] * 0.5) - self._cast_hammers(0.75, "redemption") + self._cast_hammers(0.75, SkillName.Redemption) self._move_and_attack((-30, -15), Config().char["atk_len_cs_trashmobs"] * 0.5) - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -1051,25 +1053,25 @@ def kill_vizier(self, seal_layout:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") self._pather.traverse_nodes([611], self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses - self._cast_hammers(1, "redemption") - if self._skill_hotkeys["cleansing"]: - keyboard.send(self._skill_hotkeys["cleansing"]) + self._cast_hammers(1, SkillName.Redemption) + if SkillName.Cleansing in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Cleansing]) wait(0.1, 0.2) - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) wait(0.3, 1.2) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([612], self): return False # , timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([612], self): return False # , timeout=3): # recalibrate after loot @@ -1084,35 +1086,35 @@ def kill_vizier(self, seal_layout:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking Vizier at position 2/2") self._pather.traverse_nodes([623], self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"] * 0.5) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking Vizier at position 3/3") if not self._pather.traverse_nodes([624], self): return False if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((30, 15), Config().char["atk_len_diablo_vizier"] * 0.5) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_vizier"]) wait(0.1, 0.15) - self._cast_hammers(2, "redemption") - self._cast_hammers(1, "cleansing") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + self._cast_hammers(2, SkillName.Redemption) + self._cast_hammers(1, SkillName.Cleansing) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([624], self): return False if not self._pather.traverse_nodes_fixed("dia_a2y_hop_622", self): return False Logger.debug(seal_layout + ": Hop!") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) if not self._pather.traverse_nodes([622], self): return False #, timeout=3): - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) self._picked_up_items |= self._pickit.pick_up_items(self) if not self._pather.traverse_nodes([622], self): return False # , timeout=3): #recalibrate after loot @@ -1138,27 +1140,27 @@ def kill_deseis(self, seal_layout:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking De Seis at position 2/4") self._pather.traverse_nodes(nodes1, self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking De Seis at position 3/4") self._pather.traverse_nodes(nodes2, self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"] * 0.5) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking De Seis at position 4/4") self._pather.traverse_nodes(nodes3, self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses wait(0.1, 0.2) - self._cast_hammers(2, "redemption") - self._cast_hammers(1, "cleansing") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + self._cast_hammers(2, SkillName.Redemption) + self._cast_hammers(1, SkillName.Cleansing) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(2.5, 3.5) # to keep redemption on for a couple of seconds before the next teleport to have more corpses cleared & increase chance to find next template Logger.debug(seal_layout + ": Waiting with Redemption active to clear more corpses.") #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) @@ -1179,27 +1181,27 @@ def kill_deseis(self, seal_layout:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking De Seis at position 2/4") self._pather.traverse_nodes(nodes1, self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((30, 15), Config().char["atk_len_diablo_deseis"] * 0.2) self._move_and_attack((-30, -15), Config().char["atk_len_diablo_deseis"] * 0.2) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking De Seis at position 3/4") self._pather.traverse_nodes(nodes2, self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"] * 0.5) - self._cast_hammers(1, "redemption") + self._cast_hammers(1, SkillName.Redemption) Logger.debug(seal_layout + ": Attacking De Seis at position 4/4") self._pather.traverse_nodes(nodes3, self, timeout=3) if not Config().char['cs_mob_detect'] or get_visible_targets(): self._move_and_attack((0, 0), Config().char["atk_len_diablo_deseis"]) # no factor, so merc is not reset by teleport and he his some time to move & kill stray bosses wait(0.1, 0.2) - self._cast_hammers(2, "redemption") - self._cast_hammers(1, "cleansing") - if self._skill_hotkeys["redemption"]: - keyboard.send(self._skill_hotkeys["redemption"]) + self._cast_hammers(2, SkillName.Redemption) + self._cast_hammers(1, SkillName.Cleansing) + if SkillName.Redemption in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Redemption]) wait(0.3, 0.6) #if Config().general["info_screenshots"]: cv2.imwrite(f"./log/screenshots/info/info_check_deseis_dead" + seal_layout + "_" + time.strftime("%Y%m%d_%H%M%S") + ".png", grab()) ### LOOT ### @@ -1227,12 +1229,12 @@ def kill_infector(self, seal_layout:str) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) Logger.debug(seal_layout + ": Attacking Infector at position 1/1") self._cast_hammers(Config().char["atk_len_diablo_infector"] * 0.4) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((30, 15), Config().char["atk_len_diablo_infector"] * 0.3) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((30, -15), Config().char["atk_len_diablo_infector"] * 0.4) wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") + self._cast_hammers(1.2, SkillName.Redemption) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) @@ -1253,12 +1255,12 @@ def kill_diablo(self) -> bool: mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7]) Logger.debug("Attacking Diablo at position 1/1") self._cast_hammers(Config().char["atk_len_diablo"]) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((60, 30), Config().char["atk_len_diablo"]) - self._cast_hammers(0.8, "redemption") + self._cast_hammers(0.8, SkillName.Redemption) self._move_and_attack((-60, -30), Config().char["atk_len_diablo"]) wait(0.1, 0.15) - self._cast_hammers(1.2, "redemption") + self._cast_hammers(1.2, SkillName.Redemption) ### LOOT ### self._picked_up_items |= self._pickit.pick_up_items(self) return True diff --git a/src/char/paladin/paladin.py b/src/char/paladin/paladin.py index 283cc9baa..b0d719488 100644 --- a/src/char/paladin/paladin.py +++ b/src/char/paladin/paladin.py @@ -1,7 +1,8 @@ import keyboard -from ui import skills +from ui.skills import SkillName, is_right_skill_selected, is_right_skill_active import time import random +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar, CharacterCapabilities from pather import Pather @@ -24,7 +25,7 @@ def __init__(self, skill_hotkeys: dict, pather: Pather, pickit: PickIt): def pre_buff(self): if Config().char["cta_available"]: self._pre_buff_cta() - keyboard.send(self._skill_hotkeys["holy_shield"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.HolyShield]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration, self._cast_duration + 0.06) @@ -33,10 +34,10 @@ def pre_move(self): # select teleport if available super().pre_move() # in case teleport hotkey is not set or teleport can not be used, use vigor if set - should_cast_vigor = self._skill_hotkeys["vigor"] and not skills.is_right_skill_selected(["VIGOR"]) - can_teleport = self.capabilities.can_teleport_natively and skills.is_right_skill_active() + should_cast_vigor = SkillName.Vigor in hotkeys.right_skill_key_map and not is_right_skill_selected([SkillName.Vigor.value]) + can_teleport = self.capabilities.can_teleport_natively and is_right_skill_active() if should_cast_vigor and not can_teleport: - keyboard.send(self._skill_hotkeys["vigor"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Vigor]) wait(0.15, 0.25) def _log_cast(self, skill_name: str, cast_pos_abs: tuple[float, float], spray: int, min_duration: float, aura: str): @@ -65,7 +66,7 @@ def _click_cast(self, cast_pos_abs: tuple[float, float], spray: int, mouse_click wait(0.06, 0.08) mouse.release(button = mouse_click_type) - def _cast_skill_with_aura(self, skill_name: str, cast_pos_abs: tuple[float, float] = None, spray: int = 0, min_duration: float = 0, aura: str = ""): + def _cast_skill_with_aura(self, skill_name: SkillName, cast_pos_abs: tuple[float, float] = None, spray: int = 0, min_duration: float = 0, aura: SkillName=None): #self._log_cast(skill_name, cast_pos_abs, spray, min_duration, aura) # set aura if needed @@ -73,7 +74,7 @@ def _cast_skill_with_aura(self, skill_name: str, cast_pos_abs: tuple[float, floa self._select_skill(aura, mouse_click_type = "right") # ensure character stands still - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) # set left hand skill self._select_skill(skill_name, mouse_click_type = "left") @@ -88,13 +89,13 @@ def _cast_skill_with_aura(self, skill_name: str, cast_pos_abs: tuple[float, floa self._click_cast(cast_pos_abs, spray) # release stand still key - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _activate_redemption_aura(self, delay = [0.6, 0.8]): - self._select_skill("redemption", delay=delay) + self._select_skill(SkillName.Redemption, delay=delay) def _activate_cleanse_aura(self, delay = [0.3, 0.4]): - self._select_skill("cleansing", delay=delay) + self._select_skill(SkillName.Cleansing, delay=delay) def _activate_cleanse_redemption(self): self._activate_cleanse_aura() diff --git a/src/char/poison_necro.py b/src/char/poison_necro.py index 72ae64cac..e3abacba1 100644 --- a/src/char/poison_necro.py +++ b/src/char/poison_necro.py @@ -1,4 +1,6 @@ import keyboard +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar import template_finder @@ -92,9 +94,9 @@ def _count_revives(self): def poison_nova(self, time_in_s: float): - if not self._skill_hotkeys["poison_nova"]: + if SkillName.PoisonNova not in hotkeys.right_skill_key_map: raise ValueError("You did not set poison nova hotkey!") - keyboard.send(self._skill_hotkeys["poison_nova"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.PoisonNova]) wait(0.05, 0.1) start = time.time() while (time.time() - start) < time_in_s: @@ -160,10 +162,11 @@ def _summon_stat(self): def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=12): Logger.info('\033[94m'+"raise revive"+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + if SkillName.Revive not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) for _ in range(cast_count): - if self._skill_hotkeys["raise_revive"]: - keyboard.send(self._skill_hotkeys["raise_revive"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Revive]) #Logger.info("revive -> cast") x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -185,14 +188,15 @@ def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count mouse.press(button="right") wait(0.075, 0.1) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise skeleton"+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + if SkillName.RaiseSkeleton not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) for _ in range(cast_count): - if self._skill_hotkeys["raise_skeleton"]: - keyboard.send(self._skill_hotkeys["raise_skeleton"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.RaiseSkeleton]) #Logger.info("raise skeleton -> cast") x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -214,14 +218,15 @@ def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, ca mouse.press(button="right") wait(0.02, 0.05) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16): Logger.info('\033[94m'+"raise mage"+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + if SkillName.RaiseSkeletalMage not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) for _ in range(cast_count): - if self._skill_hotkeys["raise_mage"]: - keyboard.send(self._skill_hotkeys["raise_mage"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.RaiseSkeletalMage]) #Logger.info("raise skeleton -> cast") x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -243,7 +248,7 @@ def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_c mouse.press(button="right") wait(0.02, 0.05) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def pre_buff(self): @@ -258,34 +263,34 @@ def pre_buff(self): def _heart_of_wolverine(self): Logger.info('\033[94m'+"buff ~> heart_of_wolverine"+'\033[0m') - keyboard.send(self._skill_hotkeys["heart_of_wolverine"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.HeartOfWolverine]) wait(0.05, 0.2) mouse.click(button="right") wait(self._cast_duration) def _clay_golem(self): Logger.info('\033[94m'+"cast ~> clay golem"+'\033[0m') - keyboard.send(self._skill_hotkeys["clay_golem"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.ClayGolem]) wait(0.05, 0.2) mouse.click(button="right") wait(self._cast_duration) def bone_armor(self): - if self._skill_hotkeys["bone_armor"]: - keyboard.send(self._skill_hotkeys["bone_armor"]) + if SkillName.BoneArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneArmor]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["clay_golem"]: - keyboard.send(self._skill_hotkeys["clay_golem"]) + if SkillName.ClayGolem in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.ClayGolem]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) def _bone_armor(self): - if self._skill_hotkeys["bone_armor"]: - keyboard.send(self._skill_hotkeys["bone_armor"]) + if SkillName.BoneArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BoneArmor]) wait(0.04, 0.1) mouse.click(button="right") wait(self._cast_duration) @@ -293,7 +298,7 @@ def _bone_armor(self): def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) for _ in range(10): @@ -305,10 +310,10 @@ def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): wait(0.25, 0.3) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=6): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) for _ in range(cast_count): @@ -320,11 +325,12 @@ def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10 wait(0.25, 0.3) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10): - if self._skill_hotkeys["amp_dmg"]: - keyboard.send(self._skill_hotkeys["amp_dmg"]) + if SkillName.AmplifyDamage not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.right_skill_key_map[SkillName.AmplifyDamage]) x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -335,8 +341,9 @@ def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10): mouse.release(button="right") def _lower_res(self, cast_pos_abs: tuple[float, float], spray: float = 10): - if self._skill_hotkeys["lower_res"]: - keyboard.send(self._skill_hotkeys["lower_res"]) + if SkillName.LowerResist not in hotkeys.right_skill_key_map: + return + keyboard.send(hotkeys.right_skill_key_map[SkillName.LowerResist]) x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -347,25 +354,27 @@ def _lower_res(self, cast_pos_abs: tuple[float, float], spray: float = 10): mouse.release(button="right") def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + if SkillName.CorpseExplosion not in hotkeys.right_skill_key_map: + return Logger.info('\033[93m'+"corpse explosion~> random cast"+'\033[0m') for _ in range(cast_count): - if self._skill_hotkeys["corpse_explosion"]: - keyboard.send(self._skill_hotkeys["corpse_explosion"]) - x = cast_pos_abs[0] + (random.random() * 2*spray - spray) - y = cast_pos_abs[1] + (random.random() * 2*spray - spray) - cast_pos_monitor = screen.convert_abs_to_monitor((x, y)) - mouse.move(*cast_pos_monitor) - mouse.press(button="right") - wait(0.075, 0.1) - mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) - - - def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0): + keyboard.send(hotkeys.right_skill_key_map[SkillName.CorpseExplosion]) + x = cast_pos_abs[0] + (random.random() * 2*spray - spray) + y = cast_pos_abs[1] + (random.random() * 2*spray - spray) + cast_pos_monitor = screen.convert_abs_to_monitor((x, y)) + mouse.move(*cast_pos_monitor) + mouse.press(button="right") + wait(0.075, 0.1) + mouse.release(button="right") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) + + + def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: SkillName=SkillName.RaiseSkeleton,delay: float=1.0,offset: float=1.0): Logger.info('\033[93m'+"circle cast ~>"+cast_spell+'\033[0m') - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) keyboard.send(self._skill_hotkeys[cast_spell]) + keyboard.send(hotkeys.right_skill_key_map[cast_spell]) mouse.press(button="right") for i in range(cast_div): @@ -380,20 +389,20 @@ def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, #Logger.info("circle move") mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def kill_pindle(self) -> bool: pos_m = screen.convert_abs_to_monitor((0, 30)) self.walk(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) self.poison_nova(3.0) pos_m = screen.convert_abs_to_monitor((0, -50)) self.pre_move() self.move(pos_m, force_move=True) pos_m = screen.convert_abs_to_monitor((50, 0)) self.walk(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell='corpse_explosion',delay=1.1,offset=1.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell=SkillName.CorpseExplosion,delay=1.1,offset=1.8) self.poison_nova(3.0) return True @@ -402,7 +411,7 @@ def kill_eldritch(self) -> bool: self.pre_move() self.move(pos_m, force_move=True) self.bone_armor() - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) self.poison_nova(2.0) self._summon_stat() # move a bit back @@ -414,16 +423,16 @@ def kill_eldritch(self) -> bool: pos_m = screen.convert_abs_to_monitor((0, 170)) self.pre_move() self.move(pos_m, force_move=True) - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=8,cast_v_div=4,cast_spell='raise_revive',delay=1.2,offset=.8) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell='raise_skeleton',delay=1.1,offset=.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=8,cast_v_div=4,cast_spell=SkillName.Revive,delay=1.2,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell=SkillName.RaiseSkeleton,delay=1.1,offset=.8) pos_m = screen.convert_abs_to_monitor((0, -50)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell='raise_mage',delay=1.1,offset=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell=SkillName.RaiseSkeletalMage,delay=1.1,offset=1.0) pos_m = screen.convert_abs_to_monitor((-75, 0)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell='raise_skeleton',delay=1.1,offset=.5) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell=SkillName.RaiseSkeleton,delay=1.1,offset=.5) self._summon_count() self._summon_stat() @@ -435,22 +444,22 @@ def kill_shenk(self) -> bool: self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0) #pos_m = self._screen.convert_abs_to_monitor((50, 0)) #self.walk(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) self.poison_nova(3.0) pos_m = screen.convert_abs_to_monitor((0, -50)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.1,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=10,cast_v_div=4,cast_spell=SkillName.RaiseSkeletalMage,delay=1.1,offset=.8) pos_m = screen.convert_abs_to_monitor((50, 0)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=10,cast_v_div=4,cast_spell='raise_revive',delay=1.1,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=10,cast_v_div=4,cast_spell=SkillName.Revive,delay=1.1,offset=.8) pos_m = screen.convert_abs_to_monitor((-20, -20)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_skeleton',delay=1.1,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell=SkillName.RaiseSkeleton,delay=1.1,offset=.8) self._summon_count() - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=2,cast_v_div=1,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=2,cast_v_div=1,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) return True @@ -462,16 +471,16 @@ def kill_council(self) -> bool: pos_m = screen.convert_abs_to_monitor((50, 0)) self.walk(pos_m, force_move=True) #self._lower_res((-50, 0), spray=10) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) self.poison_nova(2.0) - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_skeleton',delay=1.2,offset=.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell=SkillName.RaiseSkeleton,delay=1.2,offset=.8) pos_m = screen.convert_abs_to_monitor((200, 50)) self.pre_move() self.move(pos_m, force_move=True) pos_m = screen.convert_abs_to_monitor((30, -50)) self.walk(pos_m, force_move=True) self.poison_nova(2.0) - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=2,cast_v_div=1,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=2,cast_v_div=1,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) #wait(self._cast_duration, self._cast_duration +.2) pos_m = screen.convert_abs_to_monitor((-200, 200)) self.pre_move() @@ -482,18 +491,18 @@ def kill_council(self) -> bool: self._pather.traverse_nodes([226], self, timeout=2.5, force_tp=True, use_tp_charge=True) pos_m = screen.convert_abs_to_monitor((0, 30)) self.walk(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) wait(0.5) self.poison_nova(4.0) - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=2,cast_v_div=1,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=2,cast_v_div=1,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) #wait(self._cast_duration, self._cast_duration +.2) #self.poison_nova(2.0) pos_m = screen.convert_abs_to_monitor((50, 0)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell='corpse_explosion',delay=0.5,offset=1.8) - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_skeleton',delay=1.2,offset=.8) - #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_mage',delay=1.2,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell=SkillName.CorpseExplosion,delay=0.5,offset=1.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell=SkillName.RaiseSkeleton,delay=1.2,offset=.8) + #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell=SkillName.RaiseSkeletalMage,delay=1.2,offset=.8) pos_m = screen.convert_abs_to_monitor((-200, -200)) self.pre_move() self.move(pos_m, force_move=True) @@ -504,12 +513,12 @@ def kill_council(self) -> bool: pos_m = screen.convert_abs_to_monitor((50, 0)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) pos_m = screen.convert_abs_to_monitor((-30, -20)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_skeleton',delay=1.2,offset=.8) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.2,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell=SkillName.RaiseSkeleton,delay=1.2,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell=SkillName.RaiseSkeletalMage,delay=1.2,offset=.8) return True def kill_nihlathak(self, end_nodes: list[int]) -> bool: @@ -517,12 +526,12 @@ def kill_nihlathak(self, end_nodes: list[int]) -> bool: self._pather.traverse_nodes(end_nodes, self, timeout=0.8, do_pre_move=True) pos_m = screen.convert_abs_to_monitor((20, 20)) self.walk(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) self.poison_nova(3.0) pos_m = screen.convert_abs_to_monitor((50, 0)) self.pre_move() self.move(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=7200,cast_div=2,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=7200,cast_div=2,cast_v_div=2,cast_spell=SkillName.CorpseExplosion,delay=3.0,offset=1.8) wait(self._cast_duration, self._cast_duration +.2) self.poison_nova(3.0) return True @@ -531,14 +540,14 @@ def kill_summoner(self) -> bool: # Attack pos_m = screen.convert_abs_to_monitor((0, 30)) self.walk(pos_m, force_move=True) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell=SkillName.LowerResist,delay=1.0) wait(0.5) self.poison_nova(3.0) pos_m = screen.convert_abs_to_monitor((50, 0)) self.pre_move() self.move(pos_m, force_move=True) wait(self._cast_duration, self._cast_duration + 0.2) - self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.2,offset=.8) + self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell=SkillName.RaiseSkeletalMage,delay=1.2,offset=.8) return True diff --git a/src/char/sorceress/blizz_sorc.py b/src/char/sorceress/blizz_sorc.py index 39cc7bd5d..fc4d3a305 100644 --- a/src/char/sorceress/blizz_sorc.py +++ b/src/char/sorceress/blizz_sorc.py @@ -1,5 +1,7 @@ import keyboard from char.sorceress import Sorceress +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from logger import Logger from utils.misc import wait, rotate_vec, unit_vector @@ -28,9 +30,9 @@ def __init__(self, *args, **kwargs): self._pather.offset_node(501, (10, -33)) def _ice_blast(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.16, 0.23), spray: float = 10): - keyboard.send(Config().char["stand_still"], do_release=False) - if self._skill_hotkeys["ice_blast"]: - keyboard.send(self._skill_hotkeys["ice_blast"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + if SkillName.IceBlast in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.IceBlast]) for _ in range(5): x = cast_pos_abs[0] + (random.random() * 2*spray - spray) y = cast_pos_abs[1] + (random.random() * 2*spray - spray) @@ -39,12 +41,12 @@ def _ice_blast(self, cast_pos_abs: tuple[float, float], delay: tuple[float, floa mouse.press(button="left") wait(delay[0], delay[1]) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _blizzard(self, cast_pos_abs: tuple[float, float], spray: float = 10): - if not self._skill_hotkeys["blizzard"]: + if SkillName.Blizzard not in hotkeys.right_skill_key_map: raise ValueError("You did not set a hotkey for blizzard!") - keyboard.send(self._skill_hotkeys["blizzard"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Blizzard]) x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) cast_pos_monitor = convert_abs_to_monitor((x, y)) diff --git a/src/char/sorceress/hydra_sorc.py b/src/char/sorceress/hydra_sorc.py index dd555ea17..29b89b398 100644 --- a/src/char/sorceress/hydra_sorc.py +++ b/src/char/sorceress/hydra_sorc.py @@ -1,6 +1,8 @@ import time import keyboard from char.sorceress import Sorceress +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from logger import Logger from utils.misc import wait @@ -13,12 +15,17 @@ class HydraSorc(Sorceress): def __init__(self, *args, **kwargs): Logger.info("Setting up HydraSorc Sorc") super().__init__(*args, **kwargs) - self._hydra_time = None + self._hydra_time = None def _alt_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.16, 0.23), spray: float = 10): - keyboard.send(Config().char["stand_still"], do_release=False) - if self._skill_hotkeys["alt_attack"]: - keyboard.send(self._skill_hotkeys["alt_attack"]) + alt_skill = SkillName.Fireball if SkillName.Fireball in hotkeys.right_skill_key_map else \ + SkillName.Lightning if SkillName.Lightning in hotkeys.right_skill_key_map else \ + SkillName.FrozenOrb if SkillName.FrozenOrb in hotkeys.right_skill_key_map else \ + None + if not alt_skill: + return + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + keyboard.send(alt_skill) for _ in range(5): x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) @@ -27,21 +34,21 @@ def _alt_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, flo mouse.press(button="right") wait(delay[0], delay[1]) mouse.release(button="right") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) def _hydra(self, cast_pos_abs: tuple[float, float], spray: float = 10): if self._hydra_time is None or time.time() - self._hydra_time > 10: - if not self._skill_hotkeys["hydra"]: + if SkillName.Hydra not in hotkeys.right_skill_key_map: raise ValueError("You did not set a hotkey for hydra!") - keyboard.send(self._skill_hotkeys["hydra"]) - self._hydra_time = time.time() + keyboard.send(hotkeys.right_skill_key_map[SkillName.Hydra]) + self._hydra_time = time.time() x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) cast_pos_monitor = convert_abs_to_monitor((x, y)) mouse.move(*cast_pos_monitor) mouse.press(button="right") wait(2,3) - mouse.release(button="right") + mouse.release(button="right") def kill_pindle(self) -> bool: pindle_pos_abs = convert_screen_to_abs(Config().path["pindle_end"][0]) diff --git a/src/char/sorceress/light_sorc.py b/src/char/sorceress/light_sorc.py index 10abcf1ae..525dcf571 100644 --- a/src/char/sorceress/light_sorc.py +++ b/src/char/sorceress/light_sorc.py @@ -1,5 +1,7 @@ import keyboard from char.sorceress import Sorceress +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from logger import Logger from utils.misc import wait, rotate_vec, unit_vector @@ -16,9 +18,9 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def _chain_lightning(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: int = 10): - keyboard.send(Config().char["stand_still"], do_release=False) - if self._skill_hotkeys["chain_lightning"]: - keyboard.send(self._skill_hotkeys["chain_lightning"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) + if SkillName.ChainLightning in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.ChainLightning]) for _ in range(4): x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) @@ -27,12 +29,12 @@ def _chain_lightning(self, cast_pos_abs: tuple[float, float], delay: tuple[float mouse.press(button="left") wait(delay[0], delay[1]) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _lightning(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: float = 10): - if not self._skill_hotkeys["lightning"]: + if SkillName.Lightning not in hotkeys.right_skill_key_map: raise ValueError("You did not set lightning hotkey!") - keyboard.send(self._skill_hotkeys["lightning"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Lightning]) for _ in range(3): x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) @@ -43,8 +45,8 @@ def _lightning(self, cast_pos_abs: tuple[float, float], delay: tuple[float, floa mouse.release(button="right") def _frozen_orb(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: float = 10): - if self._skill_hotkeys["frozen_orb"]: - keyboard.send(self._skill_hotkeys["frozen_orb"]) + if SkillName.FrozenOrb in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.FrozenOrb]) for _ in range(3): x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) @@ -75,7 +77,7 @@ def kill_eldritch(self) -> bool: wait(self._cast_duration, self._cast_duration + 0.2) pos_m = convert_abs_to_monitor((70, -200)) self.pre_move() - self.move(pos_m, force_move=True) + self.move(pos_m, force_move=True) self._pather.traverse_nodes(Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END) return True diff --git a/src/char/sorceress/nova_sorc.py b/src/char/sorceress/nova_sorc.py index 88a06749a..3a9068d3c 100644 --- a/src/char/sorceress/nova_sorc.py +++ b/src/char/sorceress/nova_sorc.py @@ -2,6 +2,8 @@ import time import numpy as np from char.sorceress import Sorceress +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from logger import Logger from utils.misc import wait @@ -18,9 +20,9 @@ def __init__(self, *args, **kwargs): self._pather.offset_node(149, (70, 10)) def _nova(self, time_in_s: float): - if not self._skill_hotkeys["nova"]: + if SkillName.Nova in hotkeys.right_skill_key_map: raise ValueError("You did not set nova hotkey!") - keyboard.send(self._skill_hotkeys["nova"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Nova]) wait(0.05, 0.1) start = time.time() while (time.time() - start) < time_in_s: diff --git a/src/char/sorceress/sorceress.py b/src/char/sorceress/sorceress.py index 0737d7fe6..6c54947cf 100644 --- a/src/char/sorceress/sorceress.py +++ b/src/char/sorceress/sorceress.py @@ -1,5 +1,7 @@ import keyboard from typing import Callable +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar import template_finder @@ -17,8 +19,8 @@ def __init__(self, skill_hotkeys: dict, pather: Pather): self._pather = pather def pick_up_item(self, pos: tuple[float, float], item_name: str = None, prev_cast_start: float = 0): - if self._skill_hotkeys["telekinesis"] and any(x in item_name for x in ['potion', 'misc_gold', 'tp_scroll']): - keyboard.send(self._skill_hotkeys["telekinesis"]) + if SkillName.Telekinesis in hotkeys.right_skill_key_map and any(x in item_name for x in ['potion', 'misc_gold', 'tp_scroll']): + keyboard.send(hotkeys.right_skill_key_map[SkillName.Telekinesis]) wait(0.1, 0.2) mouse.move(pos[0], pos[1]) wait(0.1, 0.2) @@ -42,17 +44,17 @@ def select_by_template( telekinesis: bool = False ) -> bool: # In case telekinesis is False or hotkey is not set, just call the base implementation - if not self._skill_hotkeys["telekinesis"] or not telekinesis: + if SkillName.Telekinesis not in hotkeys.right_skill_key_map or not telekinesis: return super().select_by_template(template_type, success_func, timeout, threshold) if type(template_type) == list and "A5_STASH" in template_type: # sometimes waypoint is opened and stash not found because of that, check for that if is_visible(ScreenObjects.WaypointLabel): - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) start = time.time() while timeout is None or (time.time() - start) < timeout: template_match = template_finder.search(template_type, grab(), threshold=threshold) if template_match.valid: - keyboard.send(self._skill_hotkeys["telekinesis"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.Telekinesis]) wait(0.1, 0.2) mouse.move(*template_match.center_monitor) wait(0.2, 0.3) @@ -68,25 +70,25 @@ def select_by_template( def pre_buff(self): if Config().char["cta_available"]: self._pre_buff_cta() - if self._skill_hotkeys["energy_shield"]: - keyboard.send(self._skill_hotkeys["energy_shield"]) + if SkillName.EnergyShield in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.EnergyShield]) wait(0.1, 0.13) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["thunder_storm"]: - keyboard.send(self._skill_hotkeys["thunder_storm"]) + if SkillName.ThunderStorm in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.ThunderStorm]) wait(0.1, 0.13) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["frozen_armor"]: - keyboard.send(self._skill_hotkeys["frozen_armor"]) + if SkillName.FrozenArmor in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.FrozenArmor]) wait(0.1, 0.13) mouse.click(button="right") wait(self._cast_duration) def _cast_static(self, duration: float = 1.4): - if self._skill_hotkeys["static_field"]: - keyboard.send(self._skill_hotkeys["static_field"]) + if SkillName.StaticField in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.StaticField]) wait(0.1, 0.13) start = time.time() while time.time() - start < duration: diff --git a/src/char/trapsin.py b/src/char/trapsin.py index f7117058f..fabc8c16a 100644 --- a/src/char/trapsin.py +++ b/src/char/trapsin.py @@ -1,4 +1,6 @@ import keyboard +from ui.skills import SkillName +from utils import hotkeys from utils.custom_mouse import mouse from char import IChar from pather import Pather @@ -20,24 +22,24 @@ def __init__(self, skill_hotkeys: dict, pather: Pather): def pre_buff(self): if Config().char["cta_available"]: self._pre_buff_cta() - if self._skill_hotkeys["fade"]: - keyboard.send(self._skill_hotkeys["fade"]) + if SkillName.Fade in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.Fade]) wait(0.1, 0.13) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["shadow_warrior"]: - keyboard.send(self._skill_hotkeys["shadow_warrior"]) + if SkillName.ShadowWarrior in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.ShadowWarrior]) wait(0.1, 0.13) mouse.click(button="right") wait(self._cast_duration) - if self._skill_hotkeys["burst_of_speed"]: - keyboard.send(self._skill_hotkeys["burst_of_speed"]) + if SkillName.BurstOfSpeed in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.BurstOfSpeed]) wait(0.1, 0.13) mouse.click(button="right") wait(self._cast_duration) def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): - keyboard.send(Config().char["stand_still"], do_release=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_release=False) if self._skill_hotkeys["skill_left"]: keyboard.send(self._skill_hotkeys["skill_left"]) for _ in range(4): @@ -48,11 +50,11 @@ def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10): mouse.press(button="left") wait(0.2, 0.3) mouse.release(button="left") - keyboard.send(Config().char["stand_still"], do_press=False) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill], do_press=False) def _right_attack(self, cast_pos_abs: tuple[float, float], spray: float = 10): - keyboard.send(self._skill_hotkeys["lightning_sentry"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.LightningSentry]) x = cast_pos_abs[0] + (random.random() * 2 * spray - spray) y = cast_pos_abs[1] + (random.random() * 2 * spray - spray) cast_pos_monitor = convert_abs_to_monitor((x, y)) @@ -64,7 +66,7 @@ def atk(num: int): mouse.release(button="right") wait(0.15) atk(4) - keyboard.send(self._skill_hotkeys["death_sentry"]) + keyboard.send(hotkeys.right_skill_key_map[SkillName.DeathSentry]) atk(1) def kill_pindle(self) -> bool: diff --git a/src/config.py b/src/config.py index daccc72c7..c37792363 100644 --- a/src/config.py +++ b/src/config.py @@ -96,6 +96,7 @@ def turn_on_goldpickup(self): self.char["stash_gold"] = True def load_data(self): + from utils.auto_settings import find_d2r_folder Logger.debug("Loading config") self.configs = { "config": {"parser": configparser.ConfigParser(), "vars": {}}, @@ -126,7 +127,8 @@ def load_data(self): self.general = { - "saved_games_folder": self._select_val("general", "saved_games_folder"), + "saved_games_folder": _default_iff(self._select_val("general", "saved_games_folder"), "", find_d2r_folder()), + "key_file": self._select_val("general", "key_file"), "name": _default_iff(self._select_val("general", "name"), "", "botty"), "max_game_length_s": float(self._select_val("general", "max_game_length_s")), "max_consecutive_fails": int(self._select_val("general", "max_consecutive_fails")), @@ -156,11 +158,6 @@ def load_data(self): self.char = { "type": self._select_val("char", "type"), - "show_items": self._select_val("char", "show_items"), - "inventory_screen": self._select_val("char", "inventory_screen"), - "teleport": self._select_val("char", "teleport"), - "stand_still": self._select_val("char", "stand_still"), - "force_move": self._select_val("char", "force_move"), "num_loot_columns": int(self._select_val("char", "num_loot_columns")), "take_health_potion": float(self._select_val("char", "take_health_potion")), "take_mana_potion": float(self._select_val("char", "take_mana_potion")), @@ -170,13 +167,7 @@ def load_data(self): "heal_rejuv_merc": float(self._select_val("char", "heal_rejuv_merc")), "chicken": float(self._select_val("char", "chicken")), "merc_chicken": float(self._select_val("char", "merc_chicken")), - "town_portal": self._select_val("char", "town_portal"), "belt_rows": int(self._select_val("char", "belt_rows")), - "show_belt": self._select_val("char", "show_belt"), - "potion1": self._select_val("char", "potion1"), - "potion2": self._select_val("char", "potion2"), - "potion3": self._select_val("char", "potion3"), - "potion4": self._select_val("char", "potion4"), "belt_rejuv_columns": int(self._select_val("char", "belt_rejuv_columns")), "belt_hp_columns": int(self._select_val("char", "belt_hp_columns")), "belt_mp_columns": int(self._select_val("char", "belt_mp_columns")), @@ -186,9 +177,6 @@ def load_data(self): "fill_shared_stash_first": bool(int(self._select_val("char", "fill_shared_stash_first"))), "pre_buff_every_run": bool(int(self._select_val("char", "pre_buff_every_run"))), "cta_available": bool(int(self._select_val("char", "cta_available"))), - "weapon_switch": self._select_val("char", "weapon_switch"), - "battle_orders": self._select_val("char", "battle_orders"), - "battle_command": self._select_val("char", "battle_command"), "casting_frames": int(self._select_val("char", "casting_frames")), "atk_len_arc": float(self._select_val("char", "atk_len_arc")), "atk_len_trav": float(self._select_val("char", "atk_len_trav")), diff --git a/src/death_manager.py b/src/death_manager.py index ffb0b70f7..94b0718f8 100644 --- a/src/death_manager.py +++ b/src/death_manager.py @@ -1,3 +1,4 @@ +from utils import hotkeys from utils.misc import wait from screen import grab from config import Config @@ -44,9 +45,9 @@ def handle_death_screen(self): self._callback() self._callback = None # clean up key presses that might be pressed - keyboard.release(Config().char["stand_still"]) + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill]) wait(0.1, 0.2) - keyboard.release(Config().char["show_items"]) + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.ShowItems]) wait(0.1, 0.2) mouse.release(button="right") wait(0.1, 0.2) @@ -55,7 +56,7 @@ def handle_death_screen(self): if is_visible(ScreenObjects.MainMenu): # in this case chicken executed and left the game, but we were still dead. return True - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) self._died = True return True return False diff --git a/src/game_controller.py b/src/game_controller.py index 3304de0d2..5b28a8c50 100644 --- a/src/game_controller.py +++ b/src/game_controller.py @@ -1,6 +1,12 @@ import threading import time import cv2 +import keyboard +import ui +from ui import character_select +from ui.character_select import select_online_tab +from ui.main_menu import MAIN_MENU_MARKERS +from ui_manager import ScreenObjects, detect_screen_object from utils.auto_settings import check_settings from bot import Bot @@ -12,8 +18,9 @@ from logger import Logger from messages import Messenger from screen import grab, get_offset_state -from utils.restart import restart_game, safe_exit -from utils.misc import kill_thread, set_d2r_always_on_top, restore_d2r_window_visibility +from utils.restart import restart_game, safe_exit, start_d2r +from utils.misc import get_d2r_window, kill_thread, set_d2r_always_on_top, restore_d2r_window_visibility, wait +import template_finder class GameController: @@ -103,7 +110,20 @@ def start(self): if len(diff) > 0: Logger.warning("Your D2R settings differ from the requiered ones. Please use Auto Settings to adjust them. The differences are:") Logger.warning(f"{diff}") - set_d2r_always_on_top() + if not get_d2r_window(): + start_d2r(Config().general["d2r_path"], Config().advanced_options["launch_options"]) + while not get_d2r_window(): + wait(0.3) + set_d2r_always_on_top() + while not template_finder.search(MAIN_MENU_MARKERS, grab(), best_match=True).valid: + keyboard.send("space") + wait(2.0, 4.0) + else: + set_d2r_always_on_top() + wait(1.5) + character_select.online_character = True if Config().general['key_file'] and Config().general['key_file'].endswith('o') else False + if (match := detect_screen_object(ScreenObjects.OnlineStatus)).valid: + select_online_tab(match.region, match.center) self.setup_screen() self.start_health_manager_thread() self.start_death_manager_thread() diff --git a/src/game_recovery.py b/src/game_recovery.py index c90d8f0b4..ea2191e40 100644 --- a/src/game_recovery.py +++ b/src/game_recovery.py @@ -4,6 +4,7 @@ import keyboard from ui_manager import ScreenObjects, is_visible from ui import view, loading +from utils import hotkeys from utils.misc import set_d2r_always_on_top class GameRecovery: @@ -14,9 +15,9 @@ def go_to_hero_selection(self): set_d2r_always_on_top() time.sleep(1) # clean up key presses that might be pressed in the run_thread - keyboard.release(Config().char["stand_still"]) + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill]) time.sleep(0.1) - keyboard.release(Config().char["show_items"]) + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.ShowItems]) start = time.time() while (time.time() - start) < 30: # make sure we are not on loading screen @@ -38,7 +39,7 @@ def go_to_hero_selection(self): continue # maybe we are in-game in stash/inventory, press escape elif is_visible(ScreenObjects.InGame): - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) time.sleep(1) return False diff --git a/src/health_manager.py b/src/health_manager.py index b70945e32..7d99ab890 100644 --- a/src/health_manager.py +++ b/src/health_manager.py @@ -3,6 +3,7 @@ import cv2 import time import keyboard +from utils import hotkeys from utils.custom_mouse import mouse from utils.misc import wait from logger import Logger @@ -69,8 +70,8 @@ def _do_chicken(self, img): self._callback() self._callback = None # clean up key presses that might be pressed in the run_thread - keyboard.release(Config().char["stand_still"]) - keyboard.release(Config().char["show_items"]) + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.StandStill]) + keyboard.release(hotkeys.d2r_keymap[hotkeys.HotkeyName.ShowItems]) mouse.release(button="left") mouse.release(button="right") view.save_and_exit() diff --git a/src/inventory/belt.py b/src/inventory/belt.py index 60e8b0139..1755b9d2a 100644 --- a/src/inventory/belt.py +++ b/src/inventory/belt.py @@ -6,7 +6,9 @@ from inventory import common, personal from ui import view from ui_manager import is_visible, wait_until_visible, ScreenObjects, wait_until_hidden +from utils import hotkeys from utils.custom_mouse import mouse +from utils.hotkeys import HotkeyName from utils.misc import cut_roi, wait, color_filter from config import Config from screen import convert_abs_to_monitor, convert_monitor_to_screen, convert_screen_to_monitor, grab @@ -16,7 +18,7 @@ def open(img: np.ndarray = None) -> np.ndarray: img = grab() if img is None else img if is_visible(ScreenObjects.BeltExpandable, img) and Config().char["belt_rows"] > 1: - keyboard.send(Config().char["show_belt"]) + keyboard.send(hotkeys.d2r_keymap[HotkeyName.ShowBelt]) if not wait_until_hidden(ScreenObjects.BeltExpandable, 1): return None img = grab() @@ -25,7 +27,7 @@ def open(img: np.ndarray = None) -> np.ndarray: def close(img: np.ndarray = None) -> np.ndarray: img = grab() if img is None else img if not is_visible(ScreenObjects.BeltExpandable, img): - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) if not wait_until_visible(ScreenObjects.BeltExpandable, 2).valid: success = view.return_to_play() if not success: @@ -77,13 +79,14 @@ def drink_potion(potion_type: str, merc: bool = False, stats: list = []) -> bool for i in range(4): potion_img = _cut_potion_img(img, i, 0) if _potion_type(potion_img) == potion_type: - key = f"potion{i+1}" + key = f"UseBelt{i+1}" + hotkey_name = HotkeyName(key) if merc: Logger.debug(f"Give {potion_type} potion in slot {i+1} to merc. HP: {(stats[0]*100):.1f}%") - keyboard.send(f"left shift + {Config().char[key]}") + keyboard.send(f"left shift + {hotkeys.d2r_keymap[hotkey_name]}") else: Logger.debug(f"Drink {potion_type} potion in slot {i+1}. HP: {(stats[0]*100):.1f}%, Mana: {(stats[1]*100):.1f}%") - keyboard.send(Config().char[key]) + keyboard.send(hotkeys.d2r_keymap[hotkey_name]) consumables.increment_need(potion_type, 1) return True return False @@ -115,9 +118,10 @@ def update_pot_needs(): rows_left[potion_type] -= 1 if rows_left[potion_type] < 0: rows_left[potion_type] += 1 - key = f"potion{column+1}" + key = f"UseBelt{column+1}" + key_name = HotkeyName(key) for _ in range(5): - keyboard.send(Config().char[key]) + keyboard.send(hotkeys.d2r_keymap[key_name]) wait(0.2, 0.3) # calc how many potions are needed img = grab() diff --git a/src/inventory/common.py b/src/inventory/common.py index 0bedc1d04..db7f9cb7a 100644 --- a/src/inventory/common.py +++ b/src/inventory/common.py @@ -4,6 +4,7 @@ import keyboard import time import itertools +from utils import hotkeys from utils.custom_mouse import mouse from ui_manager import detect_screen_object, ScreenObjects, is_visible, wait_until_hidden, center_mouse import template_finder @@ -61,7 +62,7 @@ def close(img: np.ndarray = None) -> np.ndarray | None: img = grab() if img is None else img if inventory_is_open(img): # close open inventory - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) # check to ensure it closed wait(0.04, 0.08) timer = True diff --git a/src/inventory/personal.py b/src/inventory/personal.py index ca007bbf2..b71675924 100644 --- a/src/inventory/personal.py +++ b/src/inventory/personal.py @@ -10,6 +10,7 @@ from logger import Logger from config import Config import template_finder +from utils import hotkeys from utils.misc import wait, is_in_roi, mask_by_roi from utils.custom_mouse import mouse from inventory import stash, common, vendor @@ -161,11 +162,11 @@ def stash_all_items(items: list = None): def open(img: np.ndarray = None) -> np.ndarray: img = grab() if img is None else img if not common.inventory_is_open(): - keyboard.send(Config().char["inventory_screen"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.InventoryScreen]) if not wait_until_visible(ScreenObjects.RightPanel, 1).valid: if not view.return_to_play(): return None - keyboard.send(Config().char["inventory_screen"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.InventoryScreen]) if not wait_until_visible(ScreenObjects.RightPanel, 1).valid: Logger.error(f"personal.open(): Failed to open inventory") return None diff --git a/src/inventory/vendor.py b/src/inventory/vendor.py index c64ec6586..acc40ee96 100644 --- a/src/inventory/vendor.py +++ b/src/inventory/vendor.py @@ -3,6 +3,7 @@ import template_finder from config import Config import numpy as np +from utils import hotkeys from utils.misc import wait from screen import grab from logger import Logger @@ -44,7 +45,7 @@ def repair() -> bool: select_screen_object_match(repair_btn) if wait_until_visible(ScreenObjects.NotEnoughGold, 1).valid: Logger.warning("Couldn't repair--out of gold. Continue.") - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) return False return True @@ -70,7 +71,7 @@ def gamble(): # make sure the "not enough gold" message doesn't exist if is_visible(ScreenObjects.NotEnoughGold, img): Logger.warning(f"Out of gold, stop gambling") - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) set_gamble_status(False) break new_count = get_gamble_count()+1 @@ -119,7 +120,7 @@ def buy_item(template_name: str, quantity: int = 1, img: np.ndarray = None, shif if is_visible(ScreenObjects.NotEnoughGold): Logger.warning(f"Out of gold, could not purchase {template_name}") keyboard.send('shift', do_release=True) - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) return False keyboard.send('shift', do_release=True) personal.set_inventory_gold_full(False) @@ -131,7 +132,7 @@ def buy_item(template_name: str, quantity: int = 1, img: np.ndarray = None, shif wait(0.9, 1.1) if is_visible(ScreenObjects.NotEnoughGold): Logger.warning(f"Out of gold, could not purchase {template_name}") - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) return False personal.set_inventory_gold_full(False) center_mouse() diff --git a/src/item/pickit.py b/src/item/pickit.py index 94375d286..efb3e407c 100644 --- a/src/item/pickit.py +++ b/src/item/pickit.py @@ -19,6 +19,7 @@ from bnip.NTIPAliasType import NTIPAliasType as NTIP_TYPES from screen import grab, convert_abs_to_monitor from ui_manager import ScreenObjects, is_visible +from utils import hotkeys from utils.custom_mouse import mouse from utils.misc import wait @@ -132,7 +133,7 @@ def pick_up_items(self, char: IChar) -> bool: TODO :return: return a list of the items that were picked up """ self._reset_state() - keyboard.send(Config().char["show_items"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.ShowItems]) wait(0.15, 0.25) pickit_phase_start = time.time() @@ -180,7 +181,7 @@ def pick_up_items(self, char: IChar) -> bool: self._picked_up_item = pick_up_res == PickedUpResult.PickedUp item_count+=1 - keyboard.send(Config().char["show_items"]) + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.ShowItems]) return len(self._picked_up_items) >= 1 diff --git a/src/npc_manager.py b/src/npc_manager.py index 02bc612ee..d86e5f96a 100644 --- a/src/npc_manager.py +++ b/src/npc_manager.py @@ -6,6 +6,7 @@ from config import Config from screen import grab from ui_manager import ScreenObjects, center_mouse, is_visible, wait_until_hidden +from utils import hotkeys from utils.misc import color_filter, wait from logger import Logger from utils.custom_mouse import mouse @@ -221,7 +222,7 @@ class Npc: def escape_dialogue(img) -> np.ndarray: while is_visible(ScreenObjects.NPCDialogue, img): - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) if wait_until_hidden(ScreenObjects.NPCDialogue, 0.5): break img = grab() @@ -303,7 +304,7 @@ def press_npc_btn(npc_key: Npc, action_btn_key: str): center_mouse() else: Logger.error(f"Could not find {action_btn_key} btn. Should not happen! Continue...") - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) # Testing: Stand close to Qual-Kehk or Malah and run diff --git a/src/pather.py b/src/pather.py index b10e4adfa..43284fd45 100644 --- a/src/pather.py +++ b/src/pather.py @@ -5,6 +5,8 @@ import random import cv2 import numpy as np +from ui.skills import SkillName, select_tp +from utils import hotkeys from utils.custom_mouse import mouse from utils.misc import wait # for stash/shrine tele cancel detection in traverse node from utils.misc import is_in_roi @@ -501,7 +503,7 @@ def _convert_rel_to_abs(rel_loc: tuple[float, float], pos_abs: tuple[float, floa return (rel_loc[0] + pos_abs[0], rel_loc[1] + pos_abs[1]) def traverse_nodes_fixed(self, key: str | list[tuple[float, float]], char: IChar) -> bool: - if not char.capabilities.can_teleport_natively: + if SkillName.Teleport not in hotkeys.right_skill_key_map: error_msg = "Teleport is required for static pathing" Logger.error(error_msg) raise ValueError(error_msg) @@ -591,7 +593,7 @@ def traverse_nodes( else: Logger.debug(f"Traverse: {path}") - if use_tp_charge and char.select_tp(): + if use_tp_charge and select_tp(hotkeys.right_skill_key_map[SkillName.Teleport]): # this means we want to use tele charge and we were able to select it pass elif do_pre_move: @@ -611,7 +613,7 @@ def traverse_nodes( if is_visible(ScreenObjects.WaypointLabel, img): # sometimes bot opens waypoint menu, close it to find templates again Logger.debug("Opened wp, closing it again") - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) last_move = time.time() else: # This is a bit hacky, but for moving into a boss location we set timeout usually quite low diff --git a/src/run/pindle.py b/src/run/pindle.py index 5eb6d07bf..cdf591d12 100644 --- a/src/run/pindle.py +++ b/src/run/pindle.py @@ -1,9 +1,12 @@ +import keyboard from char import IChar from logger import Logger from pather import Location, Pather from item.pickit import PickIt import template_finder from town.town_manager import TownManager +from ui.skills import SkillName +from utils import hotkeys from utils.misc import wait from ui import loading @@ -46,7 +49,7 @@ def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]: if do_pre_buff: self._char.pre_buff() # move to pindle - if self._char.capabilities.can_teleport_natively: + if SkillName.Teleport in hotkeys.right_skill_key_map: self._pather.traverse_nodes_fixed("pindle_safe_dist", self._char) else: if not self._pather.traverse_nodes((Location.A5_PINDLE_START, Location.A5_PINDLE_SAFE_DIST), self._char): diff --git a/src/shop/drognan.py b/src/shop/drognan.py index 83fea96ac..b860261e9 100644 --- a/src/shop/drognan.py +++ b/src/shop/drognan.py @@ -13,6 +13,7 @@ from logger import Logger from npc_manager import Npc, open_npc_menu, press_npc_btn import template_finder +from utils import hotkeys from utils.custom_mouse import mouse from utils.misc import wait @@ -114,7 +115,7 @@ def shop_loop(self): self.items_evaluated += 1 - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) # Done with this shopping round self.reset_shop() diff --git a/src/template_finder.py b/src/template_finder.py index e166caeee..86baea508 100644 --- a/src/template_finder.py +++ b/src/template_finder.py @@ -1,3 +1,4 @@ +import re import cv2 import threading from screen import convert_screen_to_monitor, grab @@ -48,6 +49,8 @@ def stored_templates() -> dict[Template]: paths += list_files_in_folder(path) for file_path in paths: file_name: str = os.path.basename(file_path) + file_abs_path = os.path.abspath(os.path.join(file_path, os.pardir)) + parent_path_key = re.sub(r'.*\\assets', 'assets', file_abs_path) if file_name.lower().endswith('.png'): key = file_name[:-4].upper() template_img = load_template(file_path) @@ -58,11 +61,24 @@ def stored_templates() -> dict[Template]: img_gray = cv2.cvtColor(template_img, cv2.COLOR_BGRA2GRAY), alpha_mask = alpha_to_mask(template_img) ) + if parent_path_key not in templates: + templates[parent_path_key] = [] + templates[parent_path_key].append(key) return templates def get_template(key): + return get_template_value_by_key(key).img_bgr + +def get_templates(template_names): + with templates_lock: + templates = [] + for template_name in template_names: + templates.append(stored_templates()[template_name]) + return templates + +def get_template_value_by_key(key): with templates_lock: - return stored_templates()[key].img_bgr + return stored_templates()[key] def _process_template_refs(ref: str | np.ndarray | list[str]) -> list[Template]: templates = [] @@ -195,34 +211,38 @@ def search_and_wait( def search_all( - ref: str | np.ndarray | list[str], + ref: str | np.ndarray | list[str] | list[Template], inp_img: np.ndarray, threshold: float = 0.68, roi: list[float] = None, use_grayscale: bool = False, color_match: list = False, + best_match: list = False ) -> list[TemplateMatch]: """ - Returns a list of all templates scoring above set threshold on the screen + Returns: + - a list of all TemplateMatches scoring above set threshold on the screen (when not best_match) + - the first TemplateMatch above set threshold on the screen (when best_match) :Other params are the same as for template_finder.search() :return: Returns a list of TemplateMatch objects """ - templates = _process_template_refs(ref) + templates = ref if type(ref) == list and len(ref) > 0 and isinstance(ref[0], Template) \ + else _process_template_refs(ref) matches = [] img = inp_img.copy() while True: any_found = False for template in templates: match = _single_template_match(template, img, roi, color_match, use_grayscale) - if (ind_found := match.score >= threshold): + if match.score >= threshold: matches.append(match) - img = mask_by_roi(img, match.region, "inverse") - any_found |= ind_found - if not any_found: + if not best_match and (ind_found := match.score >= threshold): + img = mask_by_roi(img, match.region, "inverse") + any_found |= ind_found + if not any_found or (best_match and len(matches) > 0): break return matches - # Testing: Have whatever you want to find on the screen if __name__ == "__main__": import keyboard diff --git a/src/town/town_manager.py b/src/town/town_manager.py index 1980ca74d..36a3ec3c6 100644 --- a/src/town/town_manager.py +++ b/src/town/town_manager.py @@ -5,6 +5,7 @@ from pather import Location from logger import Logger from town import IAct, A1, A2, A3, A4, A5 +from utils import hotkeys from utils.misc import wait from screen import grab from ui import waypoint, view @@ -166,7 +167,7 @@ def identify(self, curr_loc: Location) -> Location | bool: if success: wait(0.2) # close cain dialog so inventory key is not blocked - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) else: view.return_to_play() return success @@ -176,7 +177,7 @@ def identify(self, curr_loc: Location) -> Location | bool: if success: wait(0.2) # close cain dialog so inventory key is not blocked - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) else: view.return_to_play() return success diff --git a/src/transmute/transmute.py b/src/transmute/transmute.py index 6cd832696..83e846b34 100644 --- a/src/transmute/transmute.py +++ b/src/transmute/transmute.py @@ -2,6 +2,7 @@ from random import randint from config import Config from ui_manager import detect_screen_object, select_screen_object_match, wait_until_visible, ScreenObjects +from utils import hotkeys from .inventory_collection import InventoryCollection from .stash import Stash from .gem_picking import SimpleGemPicking @@ -110,7 +111,7 @@ def transmute(self): def close_cube(self): self._wait() - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) def stash_all_items(self): personal.stash_all_items() diff --git a/src/ui/error_screens.py b/src/ui/error_screens.py index 168440767..43361a8ad 100644 --- a/src/ui/error_screens.py +++ b/src/ui/error_screens.py @@ -1,5 +1,6 @@ from ui_manager import detect_screen_object, select_screen_object_match, ScreenObjects from logger import Logger +from utils import hotkeys from utils.misc import wait import keyboard @@ -8,5 +9,5 @@ def handle_error() -> bool: if (match := detect_screen_object(ScreenObjects.ServerError)).valid: select_screen_object_match(match) wait(1, 2) - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) wait(18, 22) \ No newline at end of file diff --git a/src/ui/skills.py b/src/ui/skills.py index 1b0926743..54d085bce 100644 --- a/src/ui/skills.py +++ b/src/ui/skills.py @@ -1,3 +1,4 @@ +from enum import Enum import keyboard from logger import Logger import cv2 @@ -10,6 +11,228 @@ from ui_manager import wait_until_visible, ScreenObjects from d2r_image import ocr +class SkillName(str, Enum): + """ + Convenience Enums for D2 skills with their corresponding template\\ui\\skills template name as the value + """ + Attack = 'attack', + TownPortal = 'town_portal', + Unsummon = 'unsummon', + Throw = 'throw', + # Sorceress + ## Cold + IceBolt = 'ice_bolt', + FrozenArmor = 'frozen_armor', + FrostNova = 'frost_nova', + IceBlast = 'ice_blast', + ShiverArmor = 'shiver_armor', + GlacialSpike = 'glacial_spike', + Blizzard = 'blizzard', + ChillingArmor = 'chilling_armor', + FrozenOrb = 'frozen_orb', + ## Lightning + ChargedBolt = 'charged_bolt', + StaticField = 'static_field', + Telekinesis = 'telekinesis', + Nova = 'nova', + Lightning = 'lightning', + ChainLightning = 'chain_lightning', + Teleport = 'teleport', + ThunderStorm = 'thunder_storm', + EnergyShield = 'energy_shield', + ## Fire + FireBolt = 'fire_bolt', + Inferno = 'inferno', + Blaze = 'blaze', + Fireball = 'fireball', + FireWall = 'fire_wall', + Enchant = 'enchant', + Meteor = 'meteor', + Hydra = 'hydra' + # Paladin + ## Defensive + Prayer = 'prayer', + ResistFire = 'resist_fire', + Defiance = 'defiance', + ResistCold = 'resist_cold', + Cleansing = 'cleansing', + ResistLightning = 'resist_lightning', + Vigor = 'vigor', + Meditation = 'meditation', + Redemption = 'redemption', + Salvation = 'salvation', + ## Offensive + Might = 'might', + HolyFire = 'holy_fire', + Thorns = 'thorns', + BlessedAim = 'blessed_aim', + Concentration = 'concentration', + HolyFreeze = 'holy_freeze', + HolyShock = 'holy_shock', + Sanctuary = 'sanctuary', + Fanaticism = 'fanaticism', + Conviction = 'conviction', + ## Combat + Sacrifice = 'sacrifice', + Smite = 'smite', + HolyBolt = 'holy_bolt', + Zeal = 'zeal', + Charge = 'charge', + Vengeance = 'vengeance', + BlessedHammer = 'blessed_hammer', + Conversion = 'conversion', + HolyShield = 'holy_shield', + FistOfTheHeavens = 'fist_of_the_heavens' + # Barbarian + ## Warcries + Howl = 'howl', + FindPotion = 'find_potion', + Taunt = 'taunt', + Shout = 'shout', + FindItem = 'find_item', + BattleCry = 'battle_cry', + BattleOrders = 'battle_orders', + GrimWard = 'grim_ward', + WarCry = 'war_cry', + BattleCommand = 'battle_command', + ## Combat + Bash = 'bash', + Leap = 'leap', + DoubleSwing = 'double_swing', + Stun = 'stun', + DoubleThrow = 'double_throw', + LeapAttack = 'leap_attack', + Concentrate = 'concentrate', + Frenzy = 'frenzy', + Whirlwind = 'whirlwind', + Berserk = 'berserk' + # Necromancer + ## Summoning + RaiseSkeleton = 'raise_skeleton', + ClayGolem = 'clay_golem', + RaiseSkeletalMage = 'raise_skeletal_mage', + BloodGolem = 'blood_golem', + IronGolem = 'iron_golem', + FireGolem = 'fire_golem', + Revive = 'revive', + ## Poison and Bone + Teeth = 'teeth', + BoneArmor = 'bone_armor', + PoisonDagger = 'poison_dagger', + CorpseExplosion = 'corpse_explosion', + BoneWall = 'bone_wall', + PosionExplosion = 'poison_explosion', + BoneSpear = 'bone_spear', + BonePrison = 'bone_prison', + PoisonNova = 'poison_nova', + BoneSpirit = 'bone_spirit', + ## Curses + AmplifyDamage = 'amplify_damage', + DimVision = 'dim_vision', + Weaken = 'weaken', + IronMaiden = 'iron_maiden', + Terror = 'terror', + Confuse = 'confuse', + LifeTap = 'life_tap', + Attract = 'attract', + Decrepify = 'decrepify', + LowerResist = 'lower_resist' + # Assassin + ## Martial Arts + TigerStrike = 'tiger_strike', + DragonTalon = 'dragon_talon', + FistsOfFire = 'fists_of_fire', + DragonClaw = 'dragon_claw', + CobraStrike = 'cobra_strike', + ClawsOfThunder = 'claws_of_thunder', + DragonTail = 'dragon_tail', + BladesOfIce = 'blades_of_ice', + DragonFlight = 'dragon_flight', + PhoenixStrike = 'phoenix_strike', + ## Shadow Disciplines + PsychicHammer = 'psychic_hammer', + BurstOfSpeed = 'burst_of_speed', + CloakOfShadows = 'cloak_of_shadows', + Fade = 'fade', + ShadowWarrior = 'shadow_warrior', + MindBlast = 'mind_blast', + Venom = 'venom', + ShadowMaster = 'shadow_master', + ## Traps + FireBlast = 'fire_blast', + ShockWeb = 'shock_web', + BladeSentinel = 'blade_sentinel', + ChargedBoltSentry = 'charged_bolt_sentry', + WakeOfFire = 'wake_of_fire', + BladeFury = 'blade_fury', + LightningSentry = 'lightning_sentry', + WakeOfInferno = 'wake_of_inferno', + DeathSentry = 'death_sentry', + BladeShield = 'blade_shield' + # Druid + ## Elemental + Firestorm = 'firestorm', + MoltenBoulder = 'molten_boulder', + ArcticBlast = 'arctic_blast', + Fissure = 'fissure', + CycloneArmor = 'cyclone_armor', + Twister = 'Twister', + Volcano = 'volcano', + Tornado = 'torando', + Armageddon = 'armageddon', + Hurricane = 'hurricane', + ## Shape Shifting + Werewolf = 'werewolf', + Werebear = 'werebear', + FeralRage = 'feral_rage', + Maul = 'maul', + Rabies = 'rabies', + FireClaws = 'fire_claws', + Hunger = 'hunger', + ShockWave = 'shock_wave', + Fury = 'fury', + ## Summoning + Raven = 'raven', + PoisonCreeper = 'poison_creeper', + OakSage = 'oak_sage', + SummonSpiritWolf = 'summon_spirit_wolf', + CarrionVine = 'carrion_vine', + HeartOfWolverine = 'heart_of_wolverine', + SummonDireWolf = 'summon_dire_wolf', + SolarCreeper = 'solar_creeper', + SpiritOfBarbs = 'spirit_of_barbs', + SummonGrizzly = 'summon_grizzly', + # Amazon + ## Javelin and Spear + Jab = 'jab', + PowerStrike = 'power_strike', + PoisonJavelin = 'poison_javelin', + Impale = 'impale', + LightningBolt = 'lightning_bolt', + ChargedStrike = 'charged_strike', + PlagueJavelin = 'plague_javelin', + Fend = 'fend', + LightningStrike = 'lightning_strike', + LightningFury = 'lightning_fury', + ## Passive and Magic + InnerSight = 'inner_sight', + SlowMissiles = 'slow_missiles', + Decoy = 'decoy', + Valkyrie = 'valkyrie', + ## Bow and Crossbow + MagicArrow = 'magic_arrow', + FireArrow = 'fire_arrow', + ColdArrow = 'cold_arrow', + MultipleShot = 'multiple_shot', + ExplodingArrow = 'exploding_arrow', + IceArrow = 'ice_arrow', + GuidedArrow = 'guided_arrow', + Strafe = 'strafe', + ImmolationArrow = 'immolation_arrow', + FreezingArrow = 'freezing_arrow' + + + def is_left_skill_selected(template_list: list[str]) -> bool: """ :return: Bool if skill is currently the selected skill on the left skill slot. @@ -24,8 +247,9 @@ def has_tps() -> bool: """ :return: Returns True if botty has town portals available. False otherwise """ - if Config().char["town_portal"]: - keyboard.send(Config().char["town_portal"]) + from utils import hotkeys + if SkillName.TownPortal in hotkeys.right_skill_key_map: + keyboard.send(hotkeys.right_skill_key_map[SkillName.TownPortal]) if not (tps_remain := wait_until_visible(ScreenObjects.TownPortalSkill, timeout=4).valid): Logger.warning("You are out of tps") if Config().general["info_screenshots"]: @@ -35,11 +259,14 @@ def has_tps() -> bool: return False def select_tp(tp_hotkey): - if tp_hotkey and not is_right_skill_selected( - ["TELE_ACTIVE", "TELE_INACTIVE"]): + template_names = template_finder.get_template_value_by_key('assets\\templates\\ui\\skills') + templates = template_finder.get_templates(template_names) + right_skill = get_selected_skill(templates, grab(), Config().ui_roi["skill_right"]) + if tp_hotkey and right_skill != SkillName.Teleport: keyboard.send(tp_hotkey) wait(0.1, 0.2) - return is_right_skill_selected(["TELE_ACTIVE", "TELE_INACTIVE"]) + right_skill = get_selected_skill(templates, grab(), Config().ui_roi["skill_right"]) + return right_skill == SkillName.Teleport def is_right_skill_active() -> bool: """ @@ -93,3 +320,20 @@ def get_skill_charges(img: np.ndarray = None): return int(ocr_result.text) except: return None + +def get_selected_skill(template_list: list[template_finder.Template], img: np.ndarray, roi) -> SkillName: + """ + :return: first SkillName if found + """ + matches = template_finder.search_all( + template_list, + img, + threshold=0.9, + roi=roi, + use_grayscale=True, + best_match=True) + if len(matches) > 0: + skill = SkillName(matches[0].name.lower()) + if skill: + return skill + return None \ No newline at end of file diff --git a/src/ui/view.py b/src/ui/view.py index be16192a2..ecaf00a87 100644 --- a/src/ui/view.py +++ b/src/ui/view.py @@ -2,6 +2,7 @@ from screen import grab from config import Config import keyboard +from utils import hotkeys from utils.custom_mouse import mouse from logger import Logger from utils.misc import wait @@ -41,7 +42,7 @@ def save_and_exit() -> bool: success = False while attempts <= 2 and not success: if not (exit_button := detect_screen_object(ScreenObjects.SaveAndExit)).valid: - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) # wait for exit button to appear exit_button = wait_until_visible(ScreenObjects.SaveAndExit, 3) # if exit button is found, double click it to be sure @@ -91,7 +92,7 @@ def return_to_play() -> bool: if (need_escape := any(substring in string for string in list_visible_objects(img))): break if need_escape: - keyboard.send("esc") + keyboard.send(hotkeys.d2r_keymap[hotkeys.HotkeyName.OpenMenu]) wait(1) img=grab() else: diff --git a/src/ui_manager.py b/src/ui_manager.py index 18ba1a465..88f986d5e 100644 --- a/src/ui_manager.py +++ b/src/ui_manager.py @@ -156,7 +156,7 @@ class ScreenObjects: threshold=0.83 ) TownPortalSkill=ScreenObject( - ref=["TP_ACTIVE", "TP_INACTIVE"], + ref=["TOWN_PORTAL"], roi="skill_right", best_match=True, threshold=0.79 diff --git a/src/utils/auto_settings.py b/src/utils/auto_settings.py index cfc59677f..d7ab5e3fe 100644 --- a/src/utils/auto_settings.py +++ b/src/utils/auto_settings.py @@ -14,10 +14,7 @@ def get_d2r_folder() -> str: :param config: the general config possibly containing 'saved_games_folder' :return: the D2r folder full path """ - d2_saved_games = Config().general["saved_games_folder"] - if not d2_saved_games: - # assign default value for en-us Windows users - d2_saved_games = f"C:\\Users\\{os.getlogin()}\\Saved Games\\Diablo II Resurrected" + d2_saved_games = Config().general["saved_games_folder"] if Config().general["saved_games_folder"] else find_d2r_folder() if not os.path.exists(d2_saved_games): print(f"Your D2R Saved Games folder could not be found here: {d2_saved_games}, input the correct location:") d2_saved_games = input() @@ -25,6 +22,11 @@ def get_d2r_folder() -> str: assert(f"Could not find D2R Saved Games at {d2_saved_games}") return d2_saved_games +def find_d2r_folder() -> str: + # assign default value for en-us Windows users + d2_saved_games = f"C:\\Users\\{os.getlogin()}\\Saved Games\\Diablo II Resurrected" + return d2_saved_games + def backup_settings(): d2_saved_games = get_d2r_folder() backup_file = f"{d2_saved_games}/Settings_backup.json" diff --git a/src/utils/hotkeys.py b/src/utils/hotkeys.py new file mode 100644 index 000000000..37d7f56ac --- /dev/null +++ b/src/utils/hotkeys.py @@ -0,0 +1,349 @@ +import os +from enum import Enum +from config import Config +from ui.skills import get_selected_skill +from screen import convert_screen_to_monitor, grab +import template_finder +import keyboard +from utils.custom_mouse import mouse +from utils.misc import wait +from logger import Logger + +# "Public" Variables +discovered = False +## d2r_keymap represents a kvp of key: HotkeyName value: key +d2r_keymap = {} +## left_skill and right_skill represent the (last) template names found during discover_hotkey_mappings +left_skill = None +right_skill = None +## skill_key_map represents a kvp of key: SkillName value: key +left_skill_key_map = {} +right_skill_key_map = {} +# Internal variables for better tracking of where the hotkeys were found +# e.g., if the skill was found in the weapon_swap left_skill slot then it would be added to _swap_left_skill_key_map +_default_right_skill_key_map = {} +_swap_right_skill_key_map = {} +_default_left_skill_key_map = {} +_swap_left_skill_key_map = {} + +class HotkeyName(str, Enum): + """ + Convenience Enums for D2 Controls with their corresponding expected parsed key(o) as the value + """ + CharacterScreen = 'CharacterScreen', + InventoryScreen = 'InventoryScreen', + PartyScreen = 'PartyScreen', + MercenaryScreen = 'MercenaryScreen', + MessageLog = 'MessageLog', + QuestLog = 'QuestLog', + HelpScreen = 'HelpScreen', + SkillTree = 'SkillTree', + SkillSpeedBar = 'SkillSpeedBar', + Skill1 = 'Skill1', + Skill2 = 'Skill2', + Skill3 = 'Skill3', + Skill4 = 'Skill4', + Skill5 = 'Skill5', + Skill6 = 'Skill6', + Skill7 = 'Skill7', + Skill8 = 'Skill8', + Skill9 = 'Skill9', + Skill10 = 'Skill10', + Skill11 = 'Skill11', + Skill12 = 'Skill12', + Skill13 = 'Skill13', + Skill14 = 'Skill14', + Skill15 = 'Skill15', + Skill16 = 'Skill16', + SelectPreviousSkill = 'SelectPreviousSkill', + SelectNextSkill = 'SelectNextSkill', + ShowBelt = 'ShowBelt', + UseBelt1 = 'UseBelt1', + UseBelt2 = 'UseBelt2', + UseBelt3 = 'UseBelt3', + UseBelt4 = 'UseBelt4', + SwapWeapons = 'SwapWeapons', + Chat = 'Chat', + Run = 'Run', + ToggleRunWalk = 'ToggleRunWalk', + StandStill = 'StandStill', + ForceMove = 'ForceMove', + ShowItems = 'ShowItems', + ShowPortraits = 'ShowPortraits', + Automap = 'Automap', + CenterAutomap = 'CenterAutomap', + FadeAutomap = 'FadeAutomap', + PartyOnAutomap = 'PartyOnAutomap', + NamesOnAutomap = 'NamesOnAutomap', + ToggleMiniMap = 'ToggleMiniMap', + SayHelp = 'SayHelp', + SayFollowMe = 'SayFollowMe', + SayThisIsForYou = 'SayThisIsForYou', + SayThanks = 'SayThanks', + SaySorry = 'SaySorry', + SayBye = 'SayBye', + SayNowYouDie = 'SayNowYouDie', + SayRetreat = 'SayRetreat', + ScreenShot = 'ScreenShot', + ClearScreen = 'ClearScreen', + ClearMessages = 'ClearMessages', + Zoom = 'Zoom', + LegacyToggle = 'LegacyToggle', + OpenMenu = 'OpenMenu(Esc)', + +def discover_hotkey_mappings(saved_games_folder, key_name): + """ + Main entry point for discovering hotkey mapping for a character. This fn will use the provided saved_games_folder and key_name to load and parse the key file. + Using the parsed key file, it will grab Skill1-Skill16 and the representative hotkey associated with it and try to deduce the hotkeys. + """ + global discovered + global d2r_keymap + global _default_left_skill_key_map, _swap_left_skill_key_map, left_skill_key_map, left_skill + global _default_right_skill_key_map, _swap_right_skill_key_map, right_skill_key_map, right_skill + Logger.debug("Detecting hotkeys") + template_names = template_finder.get_template_value_by_key('assets\\templates\\ui\\skills') + templates = template_finder.get_templates(template_names) + d2r_keymap = _parse_key_file(saved_games_folder, key_name) + key_list = [] + for i in range(1, 17): + hotkey_name = HotkeyName(f'Skill{i}') + if hotkey_name in d2r_keymap: + key_list.append(d2r_keymap[hotkey_name]) + found_keys = [] + _deduce_hotkeys(templates, key_list, found_keys) + if Config().char['cta_available'] and HotkeyName.SwapWeapons in d2r_keymap: + keyboard.press_and_release(d2r_keymap[HotkeyName.SwapWeapons]) + wait(0.3) + _deduce_hotkeys(templates, key_list, found_keys) + keyboard.press_and_release(d2r_keymap[HotkeyName.SwapWeapons]) + wait(0.3) + img = grab() + ending_left_skill = get_selected_skill(templates, img, Config().ui_roi["skill_left"]) + ending_right_skill = get_selected_skill(templates, img, Config().ui_roi["skill_right"]) + left_skill = ending_left_skill + right_skill = ending_right_skill + left_skill_key_map = {**_default_left_skill_key_map, **_swap_left_skill_key_map} + right_skill_key_map = {**_default_right_skill_key_map, **_swap_right_skill_key_map} + discovered = True + log_hotkeys() + +def _parse_key_file(saved_games_folder, key_name): + file = open(os.path.join(saved_games_folder, key_name), 'rb') + key_bytes = [] + while True: + byte = file.read(1) + if byte: + key_bytes.append(byte) + else: + break + offset = 2 + byte_blocks = [] + while offset < len(key_bytes): + byte_blocks.append(key_bytes[offset:offset+10]) + offset += 10 + bind_id_map = { + b'\x00': "CharacterScreen", + b'\x01': "InventoryScreen", + b'\x02': "PartyScreen", + b'\x03': "MessageLog", + b'\x04': "QuestLog", + b'\x05': "Chat", + b'\x06': "HelpScreen", + b'\x07': "Automap", + b'\x08': "CenterAutomap", + b'\t': "FadeAutomap", + b'\n': "PartyOnAutomap", + b'\x0b': "NamesOnAutomap", + b'\x0c': "SkillTree", + b'\r': "SkillSpeedBar", + b'\x0e': "Skill1", + b'\x0f': "Skill2", + b'\x10': "Skill3", + b'\x11': "Skill4", + b'\x12': "Skill5", + b'\x13': "Skill6", + b'\x14': "Skill7", + b'\x16': "ShowBelt", + b'\x17': "UseBelt1", + b'\x18': "UseBelt2", + b'\x19': "UseBelt3", + b'\x1a': "UseBelt4", + b'\x1b': "SayHelp", + b'\x1c': "SayFollowMe", + b'\x1d': "SayThisIsForYou", + b'\x1e': "SayThanks", + b'\x1f': "SaySorry", + b' ': "SayBye", + b'!': "SayNowYouDie", + b'"': "Run", + b'#': "ToggleRunWalk", + b'$': "StandStill", + b'%': "ShowItems", + b'&': "ClearScreen", + b"'": "SelectPreviousSkill", + b'(': "SelectNextSkill", + b')': "ClearMessages", + b'*': "ScreenShot", + b'+': "ShowPortraits", + b',': "SwapWeapons", + b'-': "ToggleMiniMap", + b'\x15': "Skill8", + b'.': "Skill9", + b'/': "Skill10", + b'0': "Skill11", + b'1': "Skill12", + b'2': "Skill13", + b'3': "Skill14", + b'4': "Skill15", + b'5': "Skill16", + b'6': "MercenaryScreen", + b'7': "SayRetreat", + b'8': "OpenMenu(Esc)", + b'9': "Zoom", + b':': "LegacyToggle", + b';': "ForceMove" + } + found_keymaps = {} + for block in byte_blocks: + id = block[0] + if id in bind_id_map: + hotkey = _determine_hotkey_from_block(block) + hotkey_name = HotkeyName(bind_id_map[id]) + if hotkey and hotkey_name not in found_keymaps: + found_keymaps[hotkey_name] = hotkey + return found_keymaps + +def _determine_hotkey_from_block(byte_block): + key_value = int(byte_block[4].hex(), 16) + modifier_value = int(byte_block[5].hex(), 16) + if key_value in [0, 255]: + return None + key = chr(key_value) + key_correction_map = { + '\r': 'enter', + '\t': 'tab', + ' ': 'space', + '`': 'NumPad0', + 'a': 'NumPad1', + 'b': 'NumPad2', + 'c': 'NumPad3', + 'd': 'NumPad4', + 'e': 'NumPad5', + 'f': 'NumPad6', + 'g': 'NumPad7', + 'h': 'NumPad8', + 'i': 'NumPad9', + '-': 'Insert', + ',': 'ScreenShot', + 'p': 'f1', + 'q': 'f2', + 'r': 'f3', + 's': 'f4', + 't': 'f5', + 'u': 'f6', + 'v': 'f7', + 'w': 'f8', + 'x': 'f9', + 'y': 'f10', + 'z': 'f11', + '{': 'f12', + '\x01': 'Mouse4', + '\x02': 'Mouse5', + '\x03': 'MouseWheelUp', + '\x04': 'MouseWheelDown', + '\x10': 'shift', + '\x11': 'ctrl', + '\x12': 'alt', + '\x14': 'capslock', + '\x1b': 'escape', + 'Ý': ']', + 'Û': '[', + 'À': '~' + } + if key in key_correction_map: + key = key_correction_map[key] + else: + key = key.lower() + modifier_map = { + 16: 'shift', + 32: 'ctrl', + 64: 'alt' + } + if modifier_value in modifier_map: + return f'{modifier_map[modifier_value]}+{key}' + return key + +def _deduce_hotkeys(templates, key_list, found_keys): + img = grab() + starting_left_skill = get_selected_skill(templates, img, Config().ui_roi["skill_left"]) + starting_right_skill = get_selected_skill(templates, img, Config().ui_roi["skill_right"]) + # We loop twice in order to try to confidently deduce that the key that was pressed changed the left or right skill + for _ in range(0, 2): + _find_keymapping( + templates, + key_list, + starting_left_skill, + starting_right_skill, + found_keys, + _default_left_skill_key_map, + _default_right_skill_key_map) + for key in found_keys: + if key in key_list: + key_list.remove(key) + +def _find_keymapping( + templates, + key_list, + starting_left_skill, + starting_right_skill, + found_keys, + left_key_template_map, + right_key_template_map): + previous_left_skill = starting_left_skill + previous_right_skill = starting_right_skill + for i in range(0, len(key_list)): + key = key_list[i] + keyboard.send(key) + wait(0.3) + img = grab() + left_skill = get_selected_skill(templates, img, Config().ui_roi["skill_left"]) + right_skill = get_selected_skill(templates, img, Config().ui_roi["skill_right"]) + if left_skill != previous_left_skill and left_skill not in left_key_template_map: + left_key_template_map[left_skill] = key + found_keys.append(key) + elif right_skill != previous_right_skill and right_skill not in right_key_template_map: + right_key_template_map[right_skill] = key + found_keys.append(key) + previous_left_skill = left_skill + previous_right_skill = right_skill + +def remap_skill_hotkey(skill_asset, hotkey, skill_roi, expanded_skill_roi): + x, y, w, h = skill_roi + x, y = convert_screen_to_monitor((x, y)) + mouse.move(x + w/2, y + h / 2) + mouse.click("left") + wait(0.3) + match = template_finder.search(skill_asset, grab(), threshold=0.84, roi=expanded_skill_roi) + if match.valid: + mouse.move(*match.center_monitor) + wait(0.3) + keyboard.send(hotkey) + wait(0.3) + mouse.click("left") + wait(0.3) + +def log_hotkeys(): + left_skill_keys = [] + for skill, key in left_skill_key_map.items(): + if skill: + left_skill_keys.append(f'{skill.value}: {key}') + left_skills = '\n\t'.join(left_skill_keys) + right_skill_keys = [] + for skill, key in right_skill_key_map.items(): + if skill: + right_skill_keys.append(f'{skill.value}: {key}') + right_skills = '\n\t'.join(right_skill_keys) + Logger.info(f"====== Hotkeys detected ======\n"+ + f"active_left_skill: {left_skill}\tactive_right_skill: {right_skill}\n"+ + f"left_skill_key_map:\n\t{left_skills}\n"+ + f"right_skill_key_map:\n\t{right_skills}") diff --git a/src/utils/misc.py b/src/utils/misc.py index 68827647e..52f1ccd51 100644 --- a/src/utils/misc.py +++ b/src/utils/misc.py @@ -61,15 +61,21 @@ def find_d2r_window(spec: WindowSpec, offset = (0, 0)) -> tuple[int, int]: def set_d2r_always_on_top(): if os.name == 'nt': - windows_list = [] - EnumWindows(lambda w, l: l.append((w, GetWindowText(w))), windows_list) - for w in windows_list: - if w[1] == "Diablo II: Resurrected": - SetWindowPos(w[0], HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) - print("Set D2R to be always on top") + d2r_window = get_d2r_window() + if d2r_window: + SetWindowPos(d2r_window[0], HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) + print("Set D2R to be always on top") else: print('OS not supported, unable to set D2R always on top') +def get_d2r_window(): + windows_list = [] + EnumWindows(lambda w, l: l.append((w, GetWindowText(w))), windows_list) + for w in windows_list: + if w[1] == "Diablo II: Resurrected": + return w + return None + def restore_d2r_window_visibility(): if os.name == 'nt': windows_list = [] diff --git a/src/utils/restart.py b/src/utils/restart.py index 9c7b3f7d3..b1c3c82d0 100644 --- a/src/utils/restart.py +++ b/src/utils/restart.py @@ -30,8 +30,7 @@ def kill_game(): def restart_game(d2r_path, launch_options): kill_game() wait(1.0, 1.5) - # This method should function similar to opening the exe via double-click - os.startfile(f"{d2r_path}/D2R.exe", arguments = launch_options) + start_d2r(d2r_path, launch_options) wait(4.4, 5.5) for _ in range(20): keyboard.send("space") @@ -51,6 +50,10 @@ def restart_game(d2r_path, launch_options): return False return True +def start_d2r(d2r_path, launch_options): + # This method should function similar to opening the exe via double-click + os.startfile(f"{d2r_path}/D2R.exe", arguments = launch_options) + # For testing if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/test/template_finder_test.py b/test/template_finder_test.py index 644eae399..5766e4da4 100644 --- a/test/template_finder_test.py +++ b/test/template_finder_test.py @@ -58,6 +58,18 @@ def test_search_all_multiple_templates(): matches = template_finder.search_all([empty, slash], image, threshold=0.98) assert len(matches) == 4 +def test_search_all_multiple_templates_best_match(): + """ + Test all best matches with multiple templates in argument + - searches for empty slots and slash with high threshold + - test passes if 2 matches result + """ + image = cv2.imread("test/assets/stash_slots.png") + empty = cv2.imread("test/assets/stash_slot_empty.png") + slash = cv2.imread("test/assets/stash_slot_slash.png") + matches = template_finder.search_all([empty, slash], image, best_match = True, threshold=0.98) + assert len(matches) == 2 + if __name__ == "__main__": image = cv2.imread("test/assets/stash_slots.png") empty = cv2.imread("test/assets/stash_slot_empty.png")