- Add ReadOrbSlicePercentage: thin vertical strip method for accurate fill reading - Support HSV hue wrapping in colorInRange (for red hues crossing 360°) - Health HSV: H 350-370 (wrapping), S 60+, V 20+ (calibrated from screenshot) - Mana HSV: H 226-240, S 100+, V 20+ (calibrated from screenshot) - Add health_slice/mana_slice regions (10px wide vertical strips through orb centers) - Update health_globe/mana_globe to full botty-referenced regions - Verified: health 96.3%, mana 100% on testdata/d2r_1080p.png (both at 100% fill)
139 lines
4.5 KiB
Go
139 lines
4.5 KiB
Go
// D2R-specific configuration: colors, timings, and resolution profiles.
|
|
package d2r
|
|
|
|
import (
|
|
"image"
|
|
|
|
"git.cloonar.com/openclawd/iso-bot/pkg/engine/resolution"
|
|
)
|
|
|
|
// HSVRange defines a color range in HSV space.
|
|
type HSVRange struct {
|
|
LowerH, LowerS, LowerV int
|
|
UpperH, UpperS, UpperV int
|
|
}
|
|
|
|
// Colors defines HSV ranges for game elements.
|
|
type Colors struct {
|
|
HealthFilled HSVRange
|
|
ManaFilled HSVRange
|
|
ItemUnique HSVRange
|
|
ItemSet HSVRange
|
|
ItemRare HSVRange
|
|
ItemRuneword HSVRange
|
|
PortalBlue HSVRange
|
|
}
|
|
|
|
// Timings defines game-specific delay constants.
|
|
type Timings struct {
|
|
LoadingScreenMaxMs int
|
|
TownPortalCastMs int
|
|
TeleportDelayMs int
|
|
PotionCooldownMs int
|
|
PickupDelayMs int
|
|
}
|
|
|
|
// Config holds all D2R-specific configuration.
|
|
type Config struct {
|
|
Colors Colors
|
|
Timings Timings
|
|
|
|
// Loot settings
|
|
PickupUniques bool
|
|
PickupSets bool
|
|
PickupRares bool
|
|
PickupRunes bool
|
|
MinRuneTier int
|
|
PickupGems bool
|
|
|
|
// Safety thresholds (0.0 - 1.0)
|
|
HealthPotionThreshold float64
|
|
ManaPotionThreshold float64
|
|
ChickenThreshold float64 // exit game if health below this
|
|
}
|
|
|
|
// DefaultConfig returns the default D2R configuration.
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
Colors: Colors{
|
|
// Calibrated from botty reference (720p scaled to 1080p)
|
|
// Health orb RED: OpenCV H 178-183 → our H 356-366, wraps around 360
|
|
// Using H 350-360 + H 0-10 range (handled by wrapping in colorInRange)
|
|
HealthFilled: HSVRange{350, 60, 20, 370, 255, 255}, // H wraps: 350-370 means 350-360,0-10
|
|
// Mana orb BLUE: actual H 228-236 from screenshot
|
|
ManaFilled: HSVRange{226, 100, 20, 240, 255, 255},
|
|
ItemUnique: HSVRange{15, 100, 180, 30, 255, 255},
|
|
ItemSet: HSVRange{35, 100, 150, 55, 255, 255},
|
|
ItemRare: HSVRange{15, 50, 200, 25, 150, 255},
|
|
ItemRuneword: HSVRange{15, 100, 180, 30, 255, 255},
|
|
PortalBlue: HSVRange{90, 150, 150, 120, 255, 255},
|
|
},
|
|
Timings: Timings{
|
|
LoadingScreenMaxMs: 15000,
|
|
TownPortalCastMs: 3500,
|
|
TeleportDelayMs: 150,
|
|
PotionCooldownMs: 1000,
|
|
PickupDelayMs: 300,
|
|
},
|
|
PickupUniques: true,
|
|
PickupSets: true,
|
|
PickupRares: true,
|
|
PickupRunes: true,
|
|
MinRuneTier: 10,
|
|
PickupGems: false,
|
|
HealthPotionThreshold: 0.5,
|
|
ManaPotionThreshold: 0.3,
|
|
ChickenThreshold: 0.2,
|
|
}
|
|
}
|
|
|
|
// RegisterProfiles registers D2R resolution profiles with the resolution registry.
|
|
func RegisterProfiles(registry *resolution.Registry) error {
|
|
profiles := []*resolution.Profile{
|
|
// 1920x1080 (1080p) - Primary resolution
|
|
// Calibrated from real D2R screenshot (testdata/d2r_1080p.png)
|
|
{
|
|
Width: 1920,
|
|
Height: 1080,
|
|
Label: "1080p",
|
|
Regions: map[string]image.Rectangle{
|
|
"health_globe": image.Rect(240, 870, 600, 1080), // Full health globe region
|
|
"mana_globe": image.Rect(1330, 870, 1690, 1080), // Full mana globe region
|
|
"health_slice": image.Rect(415, 915, 425, 1060), // Thin vertical strip through orb center
|
|
"mana_slice": image.Rect(1505, 915, 1515, 1060), // Thin vertical strip through orb center
|
|
"health_orb": image.Rect(240, 870, 600, 1080), // Alias for backward compat
|
|
"mana_orb": image.Rect(1330, 870, 1690, 1080), // Alias for backward compat
|
|
"xp_bar": image.Rect(0, 1058, 1920, 1080),
|
|
"belt": image.Rect(500, 990, 900, 1040),
|
|
"minimap": image.Rect(1600, 0, 1920, 320),
|
|
"inventory": image.Rect(960, 330, 1490, 770),
|
|
"stash": image.Rect(430, 330, 960, 770),
|
|
"skill_left": image.Rect(200, 1030, 250, 1078),
|
|
"skill_right": image.Rect(1670, 1030, 1730, 1078),
|
|
},
|
|
},
|
|
// 1280x720 (720p) - Secondary resolution (scaled from 1080p)
|
|
{
|
|
Width: 1280,
|
|
Height: 720,
|
|
Label: "720p",
|
|
Regions: map[string]image.Rectangle{
|
|
"health_globe": image.Rect(160, 580, 400, 720),
|
|
"mana_globe": image.Rect(887, 580, 1127, 720),
|
|
"health_slice": image.Rect(309, 610, 316, 711),
|
|
"mana_slice": image.Rect(961, 610, 968, 711),
|
|
"health_orb": image.Rect(160, 580, 400, 720),
|
|
"mana_orb": image.Rect(887, 580, 1127, 720),
|
|
"xp_bar": image.Rect(0, 705, 1280, 720),
|
|
"belt": image.Rect(333, 660, 600, 693),
|
|
"minimap": image.Rect(1067, 0, 1280, 213),
|
|
"inventory": image.Rect(640, 220, 993, 513),
|
|
"stash": image.Rect(287, 220, 640, 513),
|
|
"skill_left": image.Rect(133, 687, 167, 718),
|
|
"skill_right": image.Rect(1113, 687, 1153, 718),
|
|
},
|
|
},
|
|
}
|
|
|
|
return registry.RegisterMultiple("d2r", profiles)
|
|
}
|