Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower Kurast Chest(simplified) + Duriel run fix. #539

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ type CharacterCfg struct {
Eldritch struct {
KillShenk bool `yaml:"killShenk"`
} `yaml:"eldritch"`
LowerKurastChest struct {
OpenRacks bool `yaml:"openRacks"`
} `yaml:"lowerkurastchests"`
TerrorZone struct {
FocusOnElitePacks bool `yaml:"focusOnElitePacks"`
SkipOnImmunities []stat.Resist `yaml:"skipOnImmunities"`
Expand Down
86 changes: 69 additions & 17 deletions internal/run/duriel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ package run

import (
"errors"

"github.com/hectorgimenez/d2go/pkg/data"
"github.com/hectorgimenez/d2go/pkg/data/area"
"github.com/hectorgimenez/d2go/pkg/data/mode"
"github.com/hectorgimenez/d2go/pkg/data/object"
"github.com/hectorgimenez/koolo/internal/action"
"github.com/hectorgimenez/koolo/internal/config"
"github.com/hectorgimenez/koolo/internal/context"
"github.com/hectorgimenez/koolo/internal/utils"
)

const (
maxOrificeAttempts = 10
orificeCheckDelay = 200
)

var talTombs = []area.ID{area.TalRashasTomb1, area.TalRashasTomb2, area.TalRashasTomb3, area.TalRashasTomb4, area.TalRashasTomb5, area.TalRashasTomb6, area.TalRashasTomb7}
Expand All @@ -33,33 +39,79 @@ func (d Duriel) Run() error {
return err
}

// Move to the real Tal Rasha tomb
if realTalRashaTomb, err := d.findRealTomb(); err != nil {
// Find and move to the real Tal Rasha tomb
realTalRashaTomb, err := d.findRealTomb()
if err != nil {
return err
}

err = action.MoveToArea(realTalRashaTomb)
if err != nil {
return err
}

// Wait for area to fully load and get synchronized
utils.Sleep(500)
d.ctx.RefreshGameData()

// Find orifice with retry logic
var orifice data.Object
var found bool

for attempts := 0; attempts < maxOrificeAttempts; attempts++ {
orifice, found = d.ctx.Data.Objects.FindOne(object.HoradricOrifice)
if found && orifice.Mode == mode.ObjectModeOpened {
break
}
utils.Sleep(orificeCheckDelay)
d.ctx.RefreshGameData()
}

if !found {
return errors.New("failed to find Duriel's Lair entrance after multiple attempts")
}

// Move to orifice and clear the area
err = action.MoveToCoords(orifice.Position)
if err != nil {
return err
} else {
action.MoveToArea(realTalRashaTomb)
}

// Get Orifice position and move to it, clear surrounding area
if orifice, found := d.ctx.Data.Objects.FindOne(object.HoradricOrifice); found {
action.MoveToCoords(orifice.Position)
action.ClearAreaAroundPlayer(10, data.MonsterAnyFilter())
} else {
return errors.New("failed to find Duriel's Lair entrance")
err = action.ClearAreaAroundPlayer(10, data.MonsterAnyFilter())
if err != nil {
return err
}

// Buff before we enter :)
// Pre-fight buff
action.Buff()

// Find Duriel's entrance and enter
if portal, found := d.ctx.Data.Objects.FindOne(object.DurielsLairPortal); found {
action.InteractObject(portal, func() bool {
return d.ctx.Data.PlayerUnit.Area == area.DurielsLair
})
// Find portal and enter Duriel's Lair
var portal data.Object
for attempts := 0; attempts < maxOrificeAttempts; attempts++ {
portal, found = d.ctx.Data.Objects.FindOne(object.DurielsLairPortal)
if found && portal.Mode == mode.ObjectModeOpened {
break
}
utils.Sleep(orificeCheckDelay)
d.ctx.RefreshGameData()
}

if !found {
return errors.New("failed to find Duriel's portal after multiple attempts")
}

err = action.InteractObject(portal, func() bool {
return d.ctx.Data.PlayerUnit.Area == area.DurielsLair
})
if err != nil {
return err
}

// Final refresh before fight
d.ctx.RefreshGameData()

utils.Sleep(700)

return d.ctx.Char.KillDuriel()
}

Expand Down
70 changes: 42 additions & 28 deletions internal/run/lower_kurast_chests.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,42 @@ func NewLowerKurastChest() *LowerKurastChests {
}

func (run LowerKurastChests) Name() string {
return string(config.LowerKurastRun)
return string(config.LowerKurastChestRun)
}

func (run LowerKurastChests) Run() error {
run.ctx.Logger.Debug("Running a Lower Kurast Chest run")
var bonFirePositions []data.Position

// Use Waypoint to Lower Kurast
err := action.WayPoint(area.LowerKurast)
if err != nil {
return err
}

// Find the bonfires
for _, o := range run.ctx.Data.Objects {
if o.Name == object.SmallFire {
bonFirePositions = append(bonFirePositions, o.Position)
// Get bonfires from cached map data
var bonFirePositions []data.Position
if areaData, ok := run.ctx.GameReader.GetData().Areas[area.LowerKurast]; ok {
for _, obj := range areaData.Objects {
if obj.Name == object.Name(160) { // SmallFire
run.ctx.Logger.Debug("Found bonfire at:", "position", obj.Position)
bonFirePositions = append(bonFirePositions, obj.Position)
}
}
}

run.ctx.Logger.Debug("Found bonfires", "bonfires", bonFirePositions)
run.ctx.Logger.Debug("Total bonfires found", "count", len(bonFirePositions))

var chestsIds = []object.Name{object.JungleMediumChestLeft, object.JungleChest}
// Define objects to interact with : chests + weapon racks/armor stands (if enabled)
interactableObjects := []object.Name{object.JungleMediumChestLeft, object.JungleChest}

if run.ctx.CharacterCfg.Game.LowerKurastChest.OpenRacks {
interactableObjects = append(interactableObjects,
object.ArmorStandRight,
object.ArmorStandLeft,
object.WeaponRackRight,
object.WeaponRackLeft,
)
}

// Move to each of the bonfires one by one
for _, bonfirePos := range bonFirePositions {
Expand All @@ -58,38 +72,38 @@ func (run LowerKurastChests) Run() error {
if err != nil {
return err
}
// Find the chests
var chests []data.Object

// Find the interactable objects
var objects []data.Object
for _, o := range run.ctx.Data.Objects {
if slices.Contains(chestsIds, o.Name) && isChestWithinBonfireRange(o, bonfirePos) {
chests = append(chests, o)
if slices.Contains(interactableObjects, o.Name) && isChestWithinBonfireRange(o, bonfirePos) {
objects = append(objects, o)
}
}

// Interact with chests in the order of shortest travel
for len(chests) > 0 {
// Get the player's current position
// Interact with objects in the order of shortest travel
for len(objects) > 0 {

playerPos := run.ctx.Data.PlayerUnit.Position

// Sort chests by distance from the player
sort.Slice(chests, func(i, j int) bool {
return pather.DistanceFromPoint(chests[i].Position, playerPos) <
pather.DistanceFromPoint(chests[j].Position, playerPos)
sort.Slice(objects, func(i, j int) bool {
return pather.DistanceFromPoint(objects[i].Position, playerPos) <
pather.DistanceFromPoint(objects[j].Position, playerPos)
})

// Interact with the closest chest
closestChest := chests[0]
err = action.InteractObject(closestChest, func() bool {
chest, _ := run.ctx.Data.Objects.FindByID(closestChest.ID)
return !chest.Selectable
// Interact with the closest object
closestObject := objects[0]
err = action.InteractObject(closestObject, func() bool {
object, _ := run.ctx.Data.Objects.FindByID(closestObject.ID)
return !object.Selectable
})
if err != nil {
run.ctx.Logger.Warn("Failed interacting with chest: %v", err)
run.ctx.Logger.Warn("Failed interacting with object: %v", err)
}
utils.Sleep(500) // Add small delay to allow the game to open the chest and drop the content
utils.Sleep(500) // Add small delay to allow the game to open the object and drop the content

// Remove the interacted chest from the list
chests = chests[1:]
// Remove the interacted container from the list
objects = objects[1:]
}
}

Expand Down
1 change: 1 addition & 0 deletions internal/server/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ func (s *HttpServer) characterSettings(w http.ResponseWriter, r *http.Request) {
cfg.Game.Baal.OnlyElites = r.Form.Has("gameBaalOnlyElites")

cfg.Game.Eldritch.KillShenk = r.Form.Has("gameEldritchKillShenk")
cfg.Game.LowerKurastChest.OpenRacks = r.Form.Has("gameLowerKurastChestOpenRacks")
cfg.Game.Diablo.StartFromStar = r.Form.Has("gameDiabloStartFromStar")
cfg.Game.Diablo.KillDiablo = r.Form.Has("gameDiabloKillDiablo")
cfg.Game.Diablo.FocusOnElitePacks = r.Form.Has("gameDiabloFocusOnElitePacks")
Expand Down
1 change: 1 addition & 0 deletions internal/server/templates/character_settings.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
<input id="close_mini_panel" type="checkbox" name="close_mini_panel" {{ if .Config.CloseMiniPanel }}checked{{ end }}/>
Close the mini panel at game start (Legacy Graphics)
</label>

</fieldset>
<h3>Battle.net settings</h3><br>
<fieldset class="grid">
Expand Down
14 changes: 10 additions & 4 deletions internal/server/templates/run_settings_components.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@
</fieldset>
{{ end }}

{{ define "lower_kurast_chest" }}
<fieldset>
<label><input type="checkbox" name="gameLowerKurastChestOpenRacks" {{ if .Config.Game.LowerKurastChest.OpenRacks }}checked{{ end }}> Weapon Racks + Armor Stands</label>
</fieldset>
{{ end }}

{{ define "diablo" }}
<fieldset class="options-group">
<legend>Boss Options</legend>
Expand Down Expand Up @@ -132,14 +138,14 @@
<label>Act 1</label>
<label><input type="checkbox" name="gameQuestsClearDen" {{ if .Config.Game.Quests.ClearDen }}checked{{ end }}> Clear Den</label>
<label><input type="checkbox" name="gameQuestsRescueCain" {{ if .Config.Game.Quests.RescueCain }}checked{{ end }}> Rescue Cain</label>
<label><input type="checkbox" name="gameQuestsRetrieveHammer" {{ if .Config.Game.Quests.RetrieveHammer }}checked{{ end }}> Retrieve Hammer</label>
<label><input type="checkbox" name="gameQuestsRetrieveHammer" {{ if .Config.Game.Quests.RetrieveHammer }}checked{{ end }}> Retrieve Hammer</label>
<label>Act 2</label>
<label><input type="checkbox" name="gameQuestsGetCube" {{ if .Config.Game.Quests.GetCube }}checked{{ end }}> Get Cube</label>
<label><input type="checkbox" name="gameQuestsKillRadament" {{ if .Config.Game.Quests.KillRadament }}checked{{ end }}> Kill Radament</label>
<label><input type="checkbox" name="gameQuestsKillRadament" {{ if .Config.Game.Quests.KillRadament }}checked{{ end }}> Kill Radament</label>
<label>Act 3</label>
<label><input type="checkbox" name="gameQuestsRetrieveBook" {{ if .Config.Game.Quests.RetrieveBook }}checked{{ end }}> Retrieve Book</label>
<label><input type="checkbox" name="gameQuestsRetrieveBook" {{ if .Config.Game.Quests.RetrieveBook }}checked{{ end }}> Retrieve Book</label>
<label>Act 4</label>
<label><input type="checkbox" name="gameQuestsKillIzual" {{ if .Config.Game.Quests.KillIzual }}checked{{ end }}> Kill Izual</label>
<label><input type="checkbox" name="gameQuestsKillIzual" {{ if .Config.Game.Quests.KillIzual }}checked{{ end }}> Kill Izual</label>
<label>Act 5</label>
<label><input type="checkbox" name="gameQuestsKillShenk" {{ if .Config.Game.Quests.KillShenk }}checked{{ end }}> Kill Shenk</label>
<label><input type="checkbox" name="gameQuestsRescueAnya" {{ if .Config.Game.Quests.RescueAnya }}checked{{ end }}> Rescue Anya</label>
Expand Down