diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index bf71c51e..eeb913f1 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -35,37 +35,37 @@ const ( CharacterSelectBarbarianForwardWalkOverlay = "/data/global/ui/FrontEnd/barbarian/BAFWs.DC6" CharacterSelectBarbarianBackWalk = "/data/global/ui/FrontEnd/barbarian/babw.DC6" - CharacterSelecSorceressUnselected = "/data/global/ui/FrontEnd/sorceress/SONU1.DC6" - CharacterSelecSorceressUnselectedH = "/data/global/ui/FrontEnd/sorceress/SONU2.DC6" - CharacterSelecSorceressSelected = "/data/global/ui/FrontEnd/sorceress/SONU3.DC6" - CharacterSelecSorceressSelectedOverlay = "/data/global/ui/FrontEnd/sorceress/SONU3s.DC6" - CharacterSelecSorceressForwardWalk = "/data/global/ui/FrontEnd/sorceress/SOFW.DC6" - CharacterSelecSorceressForwardWalkOverlay = "/data/global/ui/FrontEnd/sorceress/SOFWs.DC6" - CharacterSelecSorceressBackWalk = "/data/global/ui/FrontEnd/sorceress/SOBW.DC6" - CharacterSelecSorceressBackWalkOverlay = "/data/global/ui/FrontEnd/sorceress/SOBWs.DC6" + CharacterSelectSorceressUnselected = "/data/global/ui/FrontEnd/sorceress/SONU1.DC6" + CharacterSelectSorceressUnselectedH = "/data/global/ui/FrontEnd/sorceress/SONU2.DC6" + CharacterSelectSorceressSelected = "/data/global/ui/FrontEnd/sorceress/SONU3.DC6" + CharacterSelectSorceressSelectedOverlay = "/data/global/ui/FrontEnd/sorceress/SONU3s.DC6" + CharacterSelectSorceressForwardWalk = "/data/global/ui/FrontEnd/sorceress/SOFW.DC6" + CharacterSelectSorceressForwardWalkOverlay = "/data/global/ui/FrontEnd/sorceress/SOFWs.DC6" + CharacterSelectSorceressBackWalk = "/data/global/ui/FrontEnd/sorceress/SOBW.DC6" + CharacterSelectSorceressBackWalkOverlay = "/data/global/ui/FrontEnd/sorceress/SOBWs.DC6" - CharacterSelectNecromancerUnselected = "/data/global/ui/FrontEnd/necromancer/NENU1.DC6" - CharacterSelectNecromancerUnselectedH = "/data/global/ui/FrontEnd/necromancer/NENU2.DC6" - CharacterSelecNecromancerSelected = "/data/global/ui/FrontEnd/necromancer/NENU3.DC6" - CharacterSelecNecromancerSelectedOverlay = "/data/global/ui/FrontEnd/necromancer/NENU3s.DC6" - CharacterSelecNecromancerForwardWalk = "/data/global/ui/FrontEnd/necromancer/NEFW.DC6" - CharacterSelecNecromancerForwardWalkOverlay = "/data/global/ui/FrontEnd/necromancer/NEFWs.DC6" - CharacterSelecNecromancerBackWalk = "/data/global/ui/FrontEnd/necromancer/NEBW.DC6" - CharacterSelecNecromancerBackWalkOverlay = "/data/global/ui/FrontEnd/necromancer/NEBWs.DC6" + CharacterSelectNecromancerUnselected = "/data/global/ui/FrontEnd/necromancer/NENU1.DC6" + CharacterSelectNecromancerUnselectedH = "/data/global/ui/FrontEnd/necromancer/NENU2.DC6" + CharacterSelectNecromancerSelected = "/data/global/ui/FrontEnd/necromancer/NENU3.DC6" + CharacterSelectNecromancerSelectedOverlay = "/data/global/ui/FrontEnd/necromancer/NENU3s.DC6" + CharacterSelectNecromancerForwardWalk = "/data/global/ui/FrontEnd/necromancer/NEFW.DC6" + CharacterSelectNecromancerForwardWalkOverlay = "/data/global/ui/FrontEnd/necromancer/NEFWs.DC6" + CharacterSelectNecromancerBackWalk = "/data/global/ui/FrontEnd/necromancer/NEBW.DC6" + CharacterSelectNecromancerBackWalkOverlay = "/data/global/ui/FrontEnd/necromancer/NEBWs.DC6" - CharacterSelectPaladinUnselected = "/data/global/ui/FrontEnd/paladin/PANU1.DC6" - CharacterSelectPaladinUnselectedH = "/data/global/ui/FrontEnd/paladin/PANU2.DC6" - CharacterSelecPaladinSelected = "/data/global/ui/FrontEnd/paladin/PANU3.DC6" - CharacterSelecPaladinForwardWalk = "/data/global/ui/FrontEnd/paladin/PAFW.DC6" - CharacterSelecPaladinForwardWalkOverlay = "/data/global/ui/FrontEnd/paladin/PAFWs.DC6" - CharacterSelecPaladinBackWalk = "/data/global/ui/FrontEnd/paladin/PABW.DC6" + CharacterSelectPaladinUnselected = "/data/global/ui/FrontEnd/paladin/PANU1.DC6" + CharacterSelectPaladinUnselectedH = "/data/global/ui/FrontEnd/paladin/PANU2.DC6" + CharacterSelectPaladinSelected = "/data/global/ui/FrontEnd/paladin/PANU3.DC6" + CharacterSelectPaladinForwardWalk = "/data/global/ui/FrontEnd/paladin/PAFW.DC6" + CharacterSelectPaladinForwardWalkOverlay = "/data/global/ui/FrontEnd/paladin/PAFWs.DC6" + CharacterSelectPaladinBackWalk = "/data/global/ui/FrontEnd/paladin/PABW.DC6" - CharacterSelectAmazonUnselected = "/data/global/ui/FrontEnd/amazon/AMNU1.DC6" - CharacterSelectAmazonUnselectedH = "/data/global/ui/FrontEnd/amazon/AMNU2.DC6" - CharacterSelecAmazonSelected = "/data/global/ui/FrontEnd/amazon/AMNU3.DC6" - CharacterSelecAmazonForwardWalk = "/data/global/ui/FrontEnd/amazon/AMFW.DC6" - CharacterSelecAmazonForwardWalkOverlay = "/data/global/ui/FrontEnd/amazon/AMFWs.DC6" - CharacterSelecAmazonBackWalk = "/data/global/ui/FrontEnd/amazon/AMBW.DC6" + CharacterSelectAmazonUnselected = "/data/global/ui/FrontEnd/amazon/AMNU1.DC6" + CharacterSelectAmazonUnselectedH = "/data/global/ui/FrontEnd/amazon/AMNU2.DC6" + CharacterSelectAmazonSelected = "/data/global/ui/FrontEnd/amazon/AMNU3.DC6" + CharacterSelectAmazonForwardWalk = "/data/global/ui/FrontEnd/amazon/AMFW.DC6" + CharacterSelectAmazonForwardWalkOverlay = "/data/global/ui/FrontEnd/amazon/AMFWs.DC6" + CharacterSelectAmazonBackWalk = "/data/global/ui/FrontEnd/amazon/AMBW.DC6" CharacterSelectAssassinUnselected = "/data/global/ui/FrontEnd/assassin/ASNU1.DC6" CharacterSelectAssassinUnselectedH = "/data/global/ui/FrontEnd/assassin/ASNU2.DC6" diff --git a/d2game/d2gamescreen/blizzard_intro.go b/d2game/d2gamescreen/blizzard_intro.go index 8fb56334..e49a0f55 100644 --- a/d2game/d2gamescreen/blizzard_intro.go +++ b/d2game/d2gamescreen/blizzard_intro.go @@ -6,20 +6,24 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" ) +// BlizzardIntro represents the Blizzard Intro screen type BlizzardIntro struct { videoDecoder *d2video.BinkDecoder } +// CreateBlizzardIntro creates a Blizzard Intro screen func CreateBlizzardIntro() *BlizzardIntro { return &BlizzardIntro{} } +// OnLoad loads the resources for the Blizzard Intro screen func (v *BlizzardIntro) OnLoad(loading d2screen.LoadingState) { videoBytes, err := d2asset.LoadFile("/data/local/video/BlizNorth640x480.bik") if err != nil { loading.Error(err) return } + loading.Progress(0.5) v.videoDecoder = d2video.CreateBinkDecoder(videoBytes) diff --git a/d2game/d2gamescreen/game.go b/d2game/d2gamescreen/game.go index c7fb05f5..60ee62f8 100644 --- a/d2game/d2gamescreen/game.go +++ b/d2game/d2gamescreen/game.go @@ -1,7 +1,6 @@ package d2gamescreen import ( - "fmt" "image/color" "github.com/OpenDiablo2/OpenDiablo2/d2common" @@ -9,6 +8,8 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" + "fmt" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2input" @@ -19,6 +20,9 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket" ) +const hideZoneTextAfterSeconds = 2.0 + +// Game represents the Gameplay screen type Game struct { gameClient *d2client.GameClient mapRenderer *d2maprenderer.MapRenderer @@ -33,6 +37,7 @@ type Game struct { terminal d2interface.Terminal } +// CreateGame creates the Gameplay screen and returns a pointer to it func CreateGame(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient, term d2interface.Terminal) *Game { result := &Game{ @@ -48,30 +53,47 @@ func CreateGame(renderer d2interface.Renderer, audioProvider d2interface.AudioPr terminal: term, } result.escapeMenu.onLoad() - _ = d2input.BindHandler(result.escapeMenu) + + if err := d2input.BindHandler(result.escapeMenu); err != nil { + fmt.Println("failed to add gameplay screen as event handler") + } return result } +// OnLoad loads the resources for the Gameplay screen func (v *Game) OnLoad(_ d2screen.LoadingState) { v.audioProvider.PlayBGM("") } +// OnUnload releases the resources of Gameplay screen func (v *Game) OnUnload() error { - _ = d2input.UnbindHandler(v.gameControls) // TODO: hack - _ = d2input.UnbindHandler(v.escapeMenu) // TODO: hack - _ = v.gameClient.Close() + if err := d2input.UnbindHandler(v.gameControls); err != nil { // TODO: hack + return err + } + + if err := d2input.UnbindHandler(v.escapeMenu); err != nil { // TODO: hack + return err + } + + if err := v.gameClient.Close(); err != nil { + return err + } return nil } +// Render renders the Gameplay screen func (v *Game) Render(screen d2interface.Surface) error { if v.gameClient.RegenMap { v.gameClient.RegenMap = false v.mapRenderer.RegenerateTileCache() } - _ = screen.Clear(color.Black) + if err := screen.Clear(color.Black); err != nil { + return err + } + v.mapRenderer.Render(screen) if v.gameControls != nil { @@ -81,15 +103,16 @@ func (v *Game) Render(screen d2interface.Surface) error { return nil } -var hideZoneTextAfterSeconds = 2.0 - +// Advance runs the update logic on the Gameplay screen func (v *Game) Advance(tickTime float64) error { if (v.escapeMenu != nil && !v.escapeMenu.isOpen) || len(v.gameClient.Players) != 1 { v.gameClient.MapEngine.Advance(tickTime) // TODO: Hack } if v.gameControls != nil { - _ = v.gameControls.Advance(tickTime) + if err := v.gameControls.Advance(tickTime); err != nil { + return err + } } v.ticksSinceLevelCheck += tickTime @@ -116,18 +139,7 @@ func (v *Game) Advance(tickTime float64) error { // Bind the game controls to the player once it exists if v.gameControls == nil { - for _, player := range v.gameClient.Players { - if player.Id != v.gameClient.PlayerId { - continue - } - - v.localPlayer = player - v.gameControls = d2player.NewGameControls(v.renderer, player, v.gameClient.MapEngine, v.mapRenderer, v, v.terminal) - v.gameControls.Load() - _ = d2input.BindHandler(v.gameControls) - - break - } + v.bindGameControls() } // Update the camera to focus on the player @@ -139,12 +151,42 @@ func (v *Game) Advance(tickTime float64) error { return nil } +func (v *Game) bindGameControls() { + for _, player := range v.gameClient.Players { + if player.Id != v.gameClient.PlayerId { + continue + } + + v.localPlayer = player + v.gameControls = d2player.NewGameControls(v.renderer, player, v.gameClient.MapEngine, v.mapRenderer, v, v.terminal) + v.gameControls.Load() + + if err := d2input.BindHandler(v.gameControls); err != nil { + fmt.Printf("failed to add gameControls as input handler for player: %s\n", player.Id) + } + + break + } +} + +// OnPlayerMove sends the player move action to the server func (v *Game) OnPlayerMove(x, y float64) { heroPosX := v.localPlayer.LocationX / 5.0 heroPosY := v.localPlayer.LocationY / 5.0 - _ = v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, heroPosX, heroPosY, x, y)) + + err := v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, heroPosX, heroPosY, x, y)) + if err != nil { + fmt.Printf("failed to send MovePlayer packet to the server, playerId: %s, x: %g, x: %g\n", v.gameClient.PlayerId, x, y) + } } -func (v *Game) OnPlayerCast(missleID int, targetX, targetY float64) { - _ = v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerId, missleID, targetX, targetY)) +// OnPlayerCast sends the casting skill action to the server +func (v *Game) OnPlayerCast(missileID int, targetX, targetY float64) { + err := v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerId, missileID, targetX, targetY)) + if err != nil { + fmt.Printf( + "failed to send CastSkill packet to the server, playerId: %s, missileId: %d, x: %g, x: %g\n", + v.gameClient.PlayerId, missileID, targetX, targetY, + ) + } } diff --git a/d2game/d2gamescreen/gui_testing.go b/d2game/d2gamescreen/gui_testing.go index ef2f9279..3e6f0703 100644 --- a/d2game/d2gamescreen/gui_testing.go +++ b/d2game/d2gamescreen/gui_testing.go @@ -1,21 +1,26 @@ package d2gamescreen import ( + "fmt" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" ) +// GuiTestMain is a playground screen for the gui components type GuiTestMain struct { renderer d2interface.Renderer } +// CreateGuiTestMain creates a GuiTestMain screen func CreateGuiTestMain(renderer d2interface.Renderer) *GuiTestMain { return &GuiTestMain{ renderer: renderer, } } +// OnLoad loads the resources and creates the gui components func (g *GuiTestMain) OnLoad(loading d2screen.LoadingState) { layout := d2gui.CreateLayout(g.renderer, d2gui.PositionTypeHorizontal) @@ -23,34 +28,72 @@ func (g *GuiTestMain) OnLoad(loading d2screen.LoadingState) { // layoutLeft := layout.AddLayout(d2gui.PositionTypeVertical) layoutLeft.SetHorizontalAlign(d2gui.HorizontalAlignCenter) - _, _ = layoutLeft.AddLabel("FontStyle16Units", d2gui.FontStyle16Units) + + if _, err := layoutLeft.AddLabel("FontStyle16Units", d2gui.FontStyle16Units); err != nil { + fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyle16Units") + } + layoutLeft.AddSpacerStatic(0, 100) - _, _ = layoutLeft.AddLabel("FontStyle30Units", d2gui.FontStyle30Units) - _, _ = layoutLeft.AddLabel("FontStyle42Units", d2gui.FontStyle42Units) - _, _ = layoutLeft.AddLabel("FontStyleFormal10Static", d2gui.FontStyleFormal10Static) - _, _ = layoutLeft.AddLabel("FontStyleFormal11Units", d2gui.FontStyleFormal11Units) - _, _ = layoutLeft.AddLabel("FontStyleFormal12Static", d2gui.FontStyleFormal12Static) + + if _, err := layoutLeft.AddLabel("FontStyle30Units", d2gui.FontStyle30Units); err != nil { + fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyle30Units") + } + + if _, err := layoutLeft.AddLabel("FontStyle42Units", d2gui.FontStyle42Units); err != nil { + fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyle42Units") + } + + if _, err := layoutLeft.AddLabel("FontStyleFormal10Static", d2gui.FontStyleFormal10Static); err != nil { + fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyleFormal10Static") + } + + if _, err := layoutLeft.AddLabel("FontStyleFormal11Units", d2gui.FontStyleFormal11Units); err != nil { + fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyleFormal11Units") + } + + if _, err := layoutLeft.AddLabel("FontStyleFormal12Static", d2gui.FontStyleFormal12Static); err != nil { + fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyleFormal12Static") + } + loading.Progress(0.6) layout.AddSpacerDynamic() layoutRight := layout.AddLayout(d2gui.PositionTypeVertical) layoutRight.SetHorizontalAlign(d2gui.HorizontalAlignRight) - _, _ = layoutRight.AddButton("Medium", d2gui.ButtonStyleMedium) - _, _ = layoutRight.AddButton("Narrow", d2gui.ButtonStyleNarrow) - _, _ = layoutRight.AddButton("OkCancel", d2gui.ButtonStyleOkCancel) - _, _ = layoutRight.AddButton("Short", d2gui.ButtonStyleShort) - _, _ = layoutRight.AddButton("Wide", d2gui.ButtonStyleWide) + + if _, err := layoutRight.AddButton("Medium", d2gui.ButtonStyleMedium); err != nil { + fmt.Printf("could not add button: %s to the GuiTestMain screen\n", "Medium") + } + + if _, err := layoutRight.AddButton("Narrow", d2gui.ButtonStyleNarrow); err != nil { + fmt.Printf("could not add button: %s to the GuiTestMain screen\n", "Narrow") + } + + if _, err := layoutRight.AddButton("OkCancel", d2gui.ButtonStyleOkCancel); err != nil { + fmt.Printf("could not add button: %s to the GuiTestMain screen\n", "OkCancel") + } + + if _, err := layoutRight.AddButton("Short", d2gui.ButtonStyleShort); err != nil { + fmt.Printf("could not add button: %s to the GuiTestMain screen\n", "Short") + } + + if _, err := layoutRight.AddButton("Wide", d2gui.ButtonStyleWide); err != nil { + fmt.Printf("could not add button: %s to the GuiTestMain screen\n", "Wide") + } + loading.Progress(0.9) layout.SetVerticalAlign(d2gui.VerticalAlignMiddle) d2gui.SetLayout(layout) } +// Render does nothing for the GuiTestMain screen func (g *GuiTestMain) Render(_ d2interface.Surface) error { return nil } +// Advance does nothing for the GuiTestMain screen func (g *GuiTestMain) Advance(_ float64) error { return nil } diff --git a/d2game/d2gamescreen/main_menu.go b/d2game/d2gamescreen/main_menu.go index a40a45d4..b929a3e9 100644 --- a/d2game/d2gamescreen/main_menu.go +++ b/d2game/d2gamescreen/main_menu.go @@ -1,3 +1,4 @@ +// Package d2gamescreen contains the screens package d2gamescreen import ( diff --git a/d2game/d2gamescreen/map_engine_testing.go b/d2game/d2gamescreen/map_engine_testing.go index c786741a..7ca504f6 100644 --- a/d2game/d2gamescreen/map_engine_testing.go +++ b/d2game/d2gamescreen/map_engine_testing.go @@ -79,6 +79,7 @@ var regions = []regionSpec{ {d2enum.RegionAct5Lava, 1053, 1058, []int{}}, } +// MapEngineTest represents the MapEngineTest screen type MapEngineTest struct { gameState *d2player.PlayerState mapEngine *d2mapengine.MapEngine @@ -111,34 +112,36 @@ func CreateMapEngineTest(currentRegion, levelPreset int, term d2interface.Termin return result } -func (met *MapEngineTest) loadRegionByIndex(n int, levelPreset, fileIndex int) { +func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) { log.Printf("Loaded region: Type(%d) LevelPreset(%d) FileIndex(%d)", n, levelPreset, fileIndex) d2maprenderer.InvalidateImageCache() for _, spec := range regions { - if spec.regionType == d2enum.RegionIdType(n) { - met.regionSpec = spec - inExtra := false - - for _, e := range spec.extra { - if e == levelPreset { - inExtra = true - break - } - } - - if !inExtra { - if levelPreset < spec.startPresetIndex { - levelPreset = spec.startPresetIndex - } - - if levelPreset > spec.endPresetIndex { - levelPreset = spec.endPresetIndex - } - } - - met.levelPreset = levelPreset + if spec.regionType != d2enum.RegionIdType(n) { + continue } + + met.regionSpec = spec + inExtra := false + + for _, e := range spec.extra { + if e == levelPreset { + inExtra = true + break + } + } + + if !inExtra { + if levelPreset < spec.startPresetIndex { + levelPreset = spec.startPresetIndex + } + + if levelPreset > spec.endPresetIndex { + levelPreset = spec.endPresetIndex + } + } + + met.levelPreset = levelPreset } if n == 0 { @@ -186,99 +189,98 @@ func (met *MapEngineTest) OnUnload() error { func (met *MapEngineTest) Render(screen d2interface.Surface) error { met.mapRenderer.Render(screen) - // - //levelFilesToPick := make([]string, 0) - //fileIndex := met.fileIndex - //levelPreset := curRegion.LevelPreset() - //regionPath := curRegion.RegionPath() - //for n, fileRecord := range levelPreset.Files { - // if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" { - // continue - // } - // levelFilesToPick = append(levelFilesToPick, fileRecord) - // if fileRecord == regionPath { - // fileIndex = n - // } - //} - //if met.fileIndex == -1 { - // met.fileIndex = fileIndex - //} - //met.filesCount = len(levelFilesToPick) + // levelFilesToPick := make([]string, 0) + // fileIndex := met.fileIndex + // levelPreset := curRegion.LevelPreset() + // regionPath := curRegion.RegionPath() + // for n, fileRecord := range levelPreset.Files { + // if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" { + // continue + // } + // levelFilesToPick = append(levelFilesToPick, fileRecord) + // if fileRecord == regionPath { + // fileIndex = n + // } + // } + // if met.fileIndex == -1 { + // met.fileIndex = fileIndex + // } + // met.filesCount = len(levelFilesToPick) // // - //regionWidth, regionHeight := curRegion.GetTileSize() - //if tileX >= 0 && tileY >= 0 && tileX < regionWidth && tileY < regionHeight { - // tile := curRegion.Tile(tileX, tileY) - // screen.PushTranslation(5, 5) - // screen.DrawText("%d, %d (Tile %d.%d, %d.%d)", screenX, screenY, tileX, subtileX, tileY, subtileY) - // screen.PushTranslation(0, 16) - // screen.DrawText("Map: " + curRegion.LevelType().Name) - // screen.PushTranslation(0, 16) - // screen.DrawText("%v: %v/%v [%v, %v]", regionPath, fileIndex+1, met.filesCount, met.currentRegion, met.levelPreset) - // screen.PushTranslation(0, 16) - // screen.DrawText("N - next region, P - previous region") - // screen.PushTranslation(0, 16) - // screen.DrawText("Shift+N - next preset, Shift+P - previous preset") - // screen.PushTranslation(0, 16) - // screen.DrawText("Ctrl+N - next file, Ctrl+P - previous file") - // screen.PushTranslation(0, 16) - // popN := 7 - // if len(tile.Floors) > 0 { - // screen.PushTranslation(0, 16) - // screen.DrawText("Floors:") - // screen.PushTranslation(16, 0) - // for idx, floor := range tile.Floors { - // popN++ - // screen.PushTranslation(0, 16) - // tileData := curRegion.TileData(int32(floor.Style), int32(floor.Sequence), d2enum.Floor) - // tileSubAttrs := d2dt1.SubTileFlags{} - // if tileData != nil { - // tileSubAttrs = *tileData.GetSubTileFlags(subtileX, subtileY) - // } - // screen.DrawText("Floor %v: [ANI:%t] %s", idx, floor.Animated, tileSubAttrs.DebugString()) + // regionWidth, regionHeight := curRegion.GetTileSize() + // if tileX >= 0 && tileY >= 0 && tileX < regionWidth && tileY < regionHeight { + // tile := curRegion.Tile(tileX, tileY) + // screen.PushTranslation(5, 5) + // screen.DrawText("%d, %d (Tile %d.%d, %d.%d)", screenX, screenY, tileX, subtileX, tileY, subtileY) + // screen.PushTranslation(0, 16) + // screen.DrawText("Map: " + curRegion.LevelType().Name) + // screen.PushTranslation(0, 16) + // screen.DrawText("%v: %v/%v [%v, %v]", regionPath, fileIndex+1, met.filesCount, met.currentRegion, met.levelPreset) + // screen.PushTranslation(0, 16) + // screen.DrawText("N - next region, P - previous region") + // screen.PushTranslation(0, 16) + // screen.DrawText("Shift+N - next preset, Shift+P - previous preset") + // screen.PushTranslation(0, 16) + // screen.DrawText("Ctrl+N - next file, Ctrl+P - previous file") + // screen.PushTranslation(0, 16) + // popN := 7 + // if len(tile.Floors) > 0 { + // screen.PushTranslation(0, 16) + // screen.DrawText("Floors:") + // screen.PushTranslation(16, 0) + // for idx, floor := range tile.Floors { + // popN++ + // screen.PushTranslation(0, 16) + // tileData := curRegion.TileData(int32(floor.Style), int32(floor.Sequence), d2enum.Floor) + // tileSubAttrs := d2dt1.SubTileFlags{} + // if tileData != nil { + // tileSubAttrs = *tileData.GetSubTileFlags(subtileX, subtileY) + // } + // screen.DrawText("Floor %v: [ANI:%t] %s", idx, floor.Animated, tileSubAttrs.DebugString()) // - // } - // screen.PushTranslation(-16, 0) - // popN += 3 - // } - // if len(tile.Walls) > 0 { - // screen.PushTranslation(0, 16) - // screen.DrawText("Walls:") - // screen.PushTranslation(16, 0) - // for idx, wall := range tile.Walls { - // popN++ - // screen.PushTranslation(0, 16) - // tileData := curRegion.TileData(int32(wall.Style), int32(wall.Sequence), d2enum.Floor) - // tileSubAttrs := d2dt1.SubTileFlags{} - // if tileData != nil { - // tileSubAttrs = *tileData.GetSubTileFlags(subtileX, subtileY) - // } - // screen.DrawText("Wall %v: [HID:%t] %s", idx, wall.Hidden, tileSubAttrs.DebugString()) + // } + // screen.PushTranslation(-16, 0) + // popN += 3 + // } + // if len(tile.Walls) > 0 { + // screen.PushTranslation(0, 16) + // screen.DrawText("Walls:") + // screen.PushTranslation(16, 0) + // for idx, wall := range tile.Walls { + // popN++ + // screen.PushTranslation(0, 16) + // tileData := curRegion.TileData(int32(wall.Style), int32(wall.Sequence), d2enum.Floor) + // tileSubAttrs := d2dt1.SubTileFlags{} + // if tileData != nil { + // tileSubAttrs = *tileData.GetSubTileFlags(subtileX, subtileY) + // } + // screen.DrawText("Wall %v: [HID:%t] %s", idx, wall.Hidden, tileSubAttrs.DebugString()) // - // } - // screen.PushTranslation(-16, 0) - // popN += 3 - // } - // if len(tile.Walls) > 0 { - // screen.PushTranslation(0, 16) - // screen.DrawText("Shadows:") - // screen.PushTranslation(16, 0) - // for idx, shadow := range tile.Shadows { - // popN++ - // screen.PushTranslation(0, 16) - // tileData := curRegion.TileData(int32(shadow.Style), int32(shadow.Sequence), d2enum.Floor) - // tileSubAttrs := d2dt1.SubTileFlags{} - // if tileData != nil { - // tileSubAttrs = *tileData.GetSubTileFlags(subtileX, subtileY) - // } - // screen.DrawText("Wall %v: [HID:%t] %s", idx, shadow.Hidden, tileSubAttrs.DebugString()) + // } + // screen.PushTranslation(-16, 0) + // popN += 3 + // } + // if len(tile.Walls) > 0 { + // screen.PushTranslation(0, 16) + // screen.DrawText("Shadows:") + // screen.PushTranslation(16, 0) + // for idx, shadow := range tile.Shadows { + // popN++ + // screen.PushTranslation(0, 16) + // tileData := curRegion.TileData(int32(shadow.Style), int32(shadow.Sequence), d2enum.Floor) + // tileSubAttrs := d2dt1.SubTileFlags{} + // if tileData != nil { + // tileSubAttrs = *tileData.GetSubTileFlags(subtileX, subtileY) + // } + // screen.DrawText("Wall %v: [HID:%t] %s", idx, shadow.Hidden, tileSubAttrs.DebugString()) // - // } - // screen.PushTranslation(-16, 0) - // popN += 3 - // } - // screen.PopN(popN) - //} + // } + // screen.PushTranslation(-16, 0) + // popN += 3 + // } + // screen.PopN(popN) + // } return nil } diff --git a/d2game/d2gamescreen/select_hero_class.go b/d2game/d2gamescreen/select_hero_class.go index 06787ded..ae5fb96f 100644 --- a/d2game/d2gamescreen/select_hero_class.go +++ b/d2game/d2gamescreen/select_hero_class.go @@ -1,6 +1,7 @@ package d2gamescreen import ( + "fmt" "image" "image/color" @@ -21,6 +22,120 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" ) +type heroRenderConfig struct { + idleAnimationPath string + idleSelectedAnimationPath string + forwardWalkAnimationPath string + forwardWalkOverlayAnimationPath string + forwardWalkOverlayBlend bool + selectedAnimationPath string + selectedOverlayAnimationPath string + backWalkAnimationPath string + backWalkOverlayAnimationPath string + selectionBounds image.Rectangle + selectSfx string + deselectSfx string + position image.Point + idlePlayLengthMs int + forwardWalkPlayLengthMs int + backWalkPlayLengthMs int +} + +func getHeroRenderConfiguration() map[d2enum.Hero]*heroRenderConfig { + return map[d2enum.Hero]*heroRenderConfig{ + d2enum.HeroBarbarian: createHeroRenderConfig( + d2resource.CharacterSelectBarbarianUnselected, d2resource.CharacterSelectBarbarianUnselectedH, + d2resource.CharacterSelectBarbarianForwardWalk, d2resource.CharacterSelectBarbarianForwardWalkOverlay, + false, d2resource.CharacterSelectBarbarianSelected, "", + d2resource.CharacterSelectBarbarianBackWalk, "", + image.Rectangle{Min: image.Point{X: 364, Y: 201}, Max: image.Point{X: 90, Y: 170}}, + d2resource.SFXBarbarianSelect, d2resource.SFXBarbarianDeselect, image.Point{X: 400, Y: 330}, + 0, 2500, 1000, + ), + d2enum.HeroSorceress: createHeroRenderConfig( + d2resource.CharacterSelectSorceressUnselected, d2resource.CharacterSelectSorceressUnselectedH, + d2resource.CharacterSelectSorceressForwardWalk, d2resource.CharacterSelectSorceressForwardWalkOverlay, + true, d2resource.CharacterSelectSorceressSelected, d2resource.CharacterSelectSorceressSelectedOverlay, + d2resource.CharacterSelectSorceressBackWalk, d2resource.CharacterSelectSorceressBackWalkOverlay, + image.Rectangle{Min: image.Point{X: 580, Y: 240}, Max: image.Point{X: 65, Y: 160}}, + d2resource.SFXSorceressSelect, d2resource.SFXSorceressDeselect, image.Point{X: 626, Y: 352}, + 2500, 2300, 1200, + ), + d2enum.HeroNecromancer: createHeroRenderConfig( + d2resource.CharacterSelectNecromancerUnselected, d2resource.CharacterSelectNecromancerUnselectedH, + d2resource.CharacterSelectNecromancerForwardWalk, d2resource.CharacterSelectNecromancerForwardWalkOverlay, + true, d2resource.CharacterSelectNecromancerSelected, d2resource.CharacterSelectNecromancerSelectedOverlay, + d2resource.CharacterSelectNecromancerBackWalk, d2resource.CharacterSelectNecromancerBackWalkOverlay, + image.Rectangle{Min: image.Point{X: 265, Y: 220}, Max: image.Point{X: 55, Y: 175}}, + d2resource.SFXNecromancerSelect, d2resource.SFXNecromancerDeselect, image.Point{X: 300, Y: 335}, + 1200, 2000, 1500, + ), + d2enum.HeroPaladin: createHeroRenderConfig( + d2resource.CharacterSelectPaladinUnselected, d2resource.CharacterSelectPaladinUnselectedH, + d2resource.CharacterSelectPaladinForwardWalk, d2resource.CharacterSelectPaladinForwardWalkOverlay, + false, d2resource.CharacterSelectPaladinSelected, "", + d2resource.CharacterSelectPaladinBackWalk, "", + image.Rectangle{Min: image.Point{X: 490, Y: 210}, Max: image.Point{X: 65, Y: 180}}, + d2resource.SFXPaladinSelect, d2resource.SFXPaladinDeselect, image.Point{X: 521, Y: 338}, + 2500, 3400, 1300, + ), + d2enum.HeroAmazon: createHeroRenderConfig( + d2resource.CharacterSelectAmazonUnselected, d2resource.CharacterSelectAmazonUnselectedH, + d2resource.CharacterSelectAmazonForwardWalk, "", + false, d2resource.CharacterSelectAmazonSelected, "", + d2resource.CharacterSelectAmazonBackWalk, "", + image.Rectangle{Min: image.Point{X: 70, Y: 220}, Max: image.Point{X: 55, Y: 200}}, + d2resource.SFXAmazonSelect, d2resource.SFXAmazonDeselect, image.Point{X: 100, Y: 339}, + 2500, 2200, 1500, + ), + d2enum.HeroAssassin: createHeroRenderConfig( + d2resource.CharacterSelectAssassinUnselected, d2resource.CharacterSelectAssassinUnselectedH, + d2resource.CharacterSelectAssassinForwardWalk, "", + false, d2resource.CharacterSelectAssassinSelected, "", + d2resource.CharacterSelectAssassinBackWalk, "", + image.Rectangle{Min: image.Point{X: 175, Y: 235}, Max: image.Point{X: 50, Y: 180}}, + d2resource.SFXAssassinSelect, d2resource.SFXAssassinDeselect, image.Point{X: 231, Y: 365}, + 2500, 3800, 1500, + ), + d2enum.HeroDruid: createHeroRenderConfig( + d2resource.CharacterSelectDruidUnselected, d2resource.CharacterSelectDruidUnselectedH, + d2resource.CharacterSelectDruidForwardWalk, "", + false, d2resource.CharacterSelectDruidSelected, "", + d2resource.CharacterSelectDruidBackWalk, "", + image.Rectangle{Min: image.Point{X: 680, Y: 220}, Max: image.Point{X: 70, Y: 195}}, + d2resource.SFXDruidSelect, d2resource.SFXDruidDeselect, image.Point{X: 720, Y: 370}, + 1500, 4800, 1500, + ), + } +} + +func createHeroRenderConfig(idleAnimationPath, idleSelectedAnimationPath, forwardWalkAnimationPath, + forwardWalkOverlayAnimationPath string, forwardWalkOverlayBlend bool, selectedAnimationPath, + selectedOverlayAnimationPath, backWalkAnimationPath, backWalkOverlayAnimationPath string, + selectionBounds image.Rectangle, selectSfx, deselectSfx string, position image.Point, + idlePlayLengthMs, forwardWalkPlayLengthMs, backWalkPlayLengthMs int, +) *heroRenderConfig { + return &heroRenderConfig{ + idleAnimationPath: idleAnimationPath, + idleSelectedAnimationPath: idleSelectedAnimationPath, + forwardWalkAnimationPath: forwardWalkAnimationPath, + forwardWalkOverlayAnimationPath: forwardWalkOverlayAnimationPath, + forwardWalkOverlayBlend: forwardWalkOverlayBlend, + selectedAnimationPath: selectedAnimationPath, + selectedOverlayAnimationPath: selectedOverlayAnimationPath, + backWalkAnimationPath: backWalkAnimationPath, + backWalkOverlayAnimationPath: backWalkOverlayAnimationPath, + selectionBounds: selectionBounds, + selectSfx: selectSfx, + deselectSfx: deselectSfx, + position: position, + idlePlayLengthMs: idlePlayLengthMs, + forwardWalkPlayLengthMs: forwardWalkPlayLengthMs, + backWalkPlayLengthMs: backWalkPlayLengthMs, + } +} + +// HeroRenderInfo stores the rendering information of a hero for the Select Hero Class screen type HeroRenderInfo struct { Stance d2enum.HeroStance IdleSprite *d2ui.Sprite @@ -36,7 +151,7 @@ type HeroRenderInfo struct { DeselectSfx d2interface.SoundEffect } -func (hri *HeroRenderInfo) Advance(elapsed float64) { +func (hri *HeroRenderInfo) advance(elapsed float64) { advanceSprite(hri.IdleSprite, elapsed) advanceSprite(hri.IdleSelectedSprite, elapsed) advanceSprite(hri.ForwardWalkSprite, elapsed) @@ -47,6 +162,7 @@ func (hri *HeroRenderInfo) Advance(elapsed float64) { advanceSprite(hri.BackWalkSpriteOverlay, elapsed) } +// SelectHeroClass represents the Select Hero Class screen type SelectHeroClass struct { bgImage *d2ui.Sprite campfire *d2ui.Sprite @@ -72,6 +188,7 @@ type SelectHeroClass struct { renderer d2interface.Renderer } +// CreateSelectHeroClass creates an instance of a SelectHeroClass func CreateSelectHeroClass( renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, @@ -92,13 +209,51 @@ func CreateSelectHeroClass( return result } +// OnLoad loads the resources for the Select Hero Class screen func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) { v.audioProvider.PlayBGM(d2resource.BGMTitle) loading.Progress(0.1) - v.bgImage = loadSprite(d2resource.CharacterSelectBackground, d2resource.PaletteFechar) - v.bgImage.SetPosition(0, 0) + v.bgImage = loadSprite(d2resource.CharacterSelectBackground, image.Point{X: 0, Y: 0}, 0, true, false) + loading.Progress(0.3) + + v.createLabels() + loading.Progress(0.4) + v.createButtons() + + v.campfire = loadSprite(d2resource.CharacterSelectCampfire, image.Point{X: 380, Y: 335}, 0, true, true) + + v.createCheckboxes(v.renderer) + loading.Progress(0.5) + + for hero, config := range getHeroRenderConfiguration() { + position := config.position + forwardWalkOverlaySprite := loadSprite( + config.forwardWalkOverlayAnimationPath, + position, + config.forwardWalkPlayLengthMs, + false, + config.forwardWalkOverlayBlend, + ) + v.heroRenderInfo[hero] = &HeroRenderInfo{ + Stance: d2enum.HeroStanceIdle, + IdleSprite: loadSprite(config.idleAnimationPath, position, config.idlePlayLengthMs, true, false), + IdleSelectedSprite: loadSprite(config.idleSelectedAnimationPath, position, config.idlePlayLengthMs, true, false), + ForwardWalkSprite: loadSprite(config.forwardWalkAnimationPath, position, config.forwardWalkPlayLengthMs, false, false), + ForwardWalkSpriteOverlay: forwardWalkOverlaySprite, + SelectedSprite: loadSprite(config.selectedAnimationPath, position, config.idlePlayLengthMs, true, false), + SelectedSpriteOverlay: loadSprite(config.selectedOverlayAnimationPath, position, config.idlePlayLengthMs, true, true), + BackWalkSprite: loadSprite(config.backWalkAnimationPath, position, config.backWalkPlayLengthMs, false, false), + BackWalkSpriteOverlay: loadSprite(config.backWalkOverlayAnimationPath, position, config.backWalkPlayLengthMs, false, true), + SelectionBounds: config.selectionBounds, + SelectSfx: v.loadSoundEffect(config.selectSfx), + DeselectSfx: v.loadSoundEffect(config.deselectSfx), + } + } +} + +func (v *SelectHeroClass) createLabels() { v.headingLabel = d2ui.CreateLabel(v.renderer, d2resource.Font30, d2resource.PaletteUnits) fontWidth, _ := v.headingLabel.GetSize() v.headingLabel.SetPosition(400-fontWidth/2, 17) @@ -112,7 +267,6 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) { v.heroDesc1Label = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) v.heroDesc1Label.Alignment = d2ui.LabelAlignCenter v.heroDesc1Label.SetPosition(400, 100) - loading.Progress(0.3) v.heroDesc2Label = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) v.heroDesc2Label.Alignment = d2ui.LabelAlignCenter @@ -122,11 +276,26 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) { v.heroDesc3Label.Alignment = d2ui.LabelAlignCenter v.heroDesc3Label.SetPosition(400, 130) - v.campfire = loadSprite(d2resource.CharacterSelectCampfire, d2resource.PaletteFechar) - v.campfire.SetPosition(380, 335) - v.campfire.PlayForward() - v.campfire.SetBlend(true) + v.heroNameLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) + v.heroNameLabel.Alignment = d2ui.LabelAlignLeft + v.heroNameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255} + v.heroNameLabel.SetText("Character Name") + v.heroNameLabel.SetPosition(321, 475) + v.expansionCharLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) + v.expansionCharLabel.Alignment = d2ui.LabelAlignLeft + v.expansionCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255} + v.expansionCharLabel.SetText("EXPANSION CHARACTER") + v.expansionCharLabel.SetPosition(339, 526) + + v.hardcoreCharLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) + v.hardcoreCharLabel.Alignment = d2ui.LabelAlignLeft + v.hardcoreCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255} + v.hardcoreCharLabel.SetText("Hardcore") + v.hardcoreCharLabel.SetPosition(339, 548) +} + +func (v *SelectHeroClass) createButtons() { v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT") v.exitButton.SetPosition(33, 537) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) @@ -138,15 +307,10 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) { v.okButton.SetVisible(false) v.okButton.SetEnabled(false) d2ui.AddWidget(&v.okButton) +} - v.heroNameLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) - v.heroNameLabel.Alignment = d2ui.LabelAlignLeft - v.heroNameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255} - v.heroNameLabel.SetText("Character Name") - v.heroNameLabel.SetPosition(321, 475) - loading.Progress(0.4) - - v.heroNameTextbox = d2ui.CreateTextbox(v.renderer) +func (v *SelectHeroClass) createCheckboxes(renderer d2interface.Renderer) { + v.heroNameTextbox = d2ui.CreateTextbox(renderer) v.heroNameTextbox.SetPosition(318, 493) v.heroNameTextbox.SetVisible(false) d2ui.AddWidget(&v.heroNameTextbox) @@ -156,289 +320,21 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) { v.expansionCheckbox.SetVisible(false) d2ui.AddWidget(&v.expansionCheckbox) - v.expansionCharLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) - v.expansionCharLabel.Alignment = d2ui.LabelAlignLeft - v.expansionCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255} - v.expansionCharLabel.SetText("EXPANSION CHARACTER") - v.expansionCharLabel.SetPosition(339, 526) - - v.hardcoreCheckbox = d2ui.CreateCheckbox(v.renderer, false) + v.hardcoreCheckbox = d2ui.CreateCheckbox(renderer, false) v.hardcoreCheckbox.SetPosition(318, 548) v.hardcoreCheckbox.SetVisible(false) d2ui.AddWidget(&v.hardcoreCheckbox) - - v.hardcoreCharLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits) - v.hardcoreCharLabel.Alignment = d2ui.LabelAlignLeft - v.hardcoreCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255} - v.hardcoreCharLabel.SetText("Hardcore") - v.hardcoreCharLabel.SetPosition(339, 548) - loading.Progress(0.5) - - v.heroRenderInfo[d2enum.HeroBarbarian] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelectBarbarianUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectBarbarianUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectBarbarianForwardWalk, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectBarbarianForwardWalkOverlay, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectBarbarianSelected, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2resource.PaletteFechar), - nil, - image.Rectangle{Min: image.Point{X: 364, Y: 201}, Max: image.Point{X: 90, Y: 170}}, - v.loadSoundEffect(d2resource.SFXBarbarianSelect), - v.loadSoundEffect(d2resource.SFXBarbarianDeselect), - } - v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.SetPosition(400, 330) - v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.SetPosition(400, 330) - v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPosition(400, 330) - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPosition(400, 330) - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.SetPosition(400, 330) - v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPosition(400, 330) - v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPlayLengthMs(1000) - v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPlayLoop(false) - - v.heroRenderInfo[d2enum.HeroSorceress] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelecSorceressUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressForwardWalk, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressForwardWalkOverlay, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressSelected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressSelectedOverlay, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressBackWalk, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecSorceressBackWalkOverlay, d2resource.PaletteFechar), - image.Rectangle{Min: image.Point{X: 580, Y: 240}, Max: image.Point{X: 65, Y: 160}}, - v.loadSoundEffect(d2resource.SFXSorceressSelect), - v.loadSoundEffect(d2resource.SFXSorceressDeselect), - } - v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPlayLengthMs(2300) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetBlend(true) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPlayLengthMs(2300) - v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SetPlayLengthMs(450) - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetBlend(true) - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetPlayLengthMs(450) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPlayLengthMs(1200) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetBlend(true) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPosition(626, 352) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPlayLengthMs(1200) - v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPlayLoop(false) - loading.Progress(0.6) - - v.heroRenderInfo[d2enum.HeroNecromancer] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelectNecromancerUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectNecromancerUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecNecromancerForwardWalk, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecNecromancerForwardWalkOverlay, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecNecromancerSelected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecNecromancerSelectedOverlay, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecNecromancerBackWalk, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecNecromancerBackWalkOverlay, d2resource.PaletteFechar), - image.Rectangle{Min: image.Point{X: 265, Y: 220}, Max: image.Point{X: 55, Y: 175}}, - v.loadSoundEffect(d2resource.SFXNecromancerSelect), - v.loadSoundEffect(d2resource.SFXNecromancerDeselect), - } - v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SetPlayLengthMs(1200) - v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SetPlayLengthMs(1200) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPlayLengthMs(2000) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetBlend(true) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPlayLengthMs(2000) - v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.SetBlend(true) - v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetBlend(true) - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPosition(300, 335) - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPlayLoop(false) - - v.heroRenderInfo[d2enum.HeroPaladin] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelectPaladinUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectPaladinUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecPaladinForwardWalk, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecPaladinForwardWalkOverlay, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecPaladinSelected, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelecPaladinBackWalk, d2resource.PaletteFechar), - nil, - image.Rectangle{Min: image.Point{X: 490, Y: 210}, Max: image.Point{X: 65, Y: 180}}, - v.loadSoundEffect(d2resource.SFXPaladinSelect), - v.loadSoundEffect(d2resource.SFXPaladinDeselect), - } - v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SetPosition(521, 338) - v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SetPosition(521, 338) - v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPosition(521, 338) - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPlayLengthMs(3400) - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPosition(521, 338) - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.PlayForward() - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPlayLengthMs(3400) - v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SetPosition(521, 338) - v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SetPlayLengthMs(650) - v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPosition(521, 338) - v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPlayLengthMs(1300) - v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPlayLoop(false) - loading.Progress(0.7) - - v.heroRenderInfo[d2enum.HeroAmazon] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelectAmazonUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectAmazonUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelecAmazonForwardWalk, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelecAmazonSelected, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelecAmazonBackWalk, d2resource.PaletteFechar), - nil, - image.Rectangle{Min: image.Point{X: 70, Y: 220}, Max: image.Point{X: 55, Y: 200}}, - v.loadSoundEffect(d2resource.SFXAmazonSelect), - v.loadSoundEffect(d2resource.SFXAmazonDeselect), - } - v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SetPosition(100, 339) - v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SetPosition(100, 339) - v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPosition(100, 339) - v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPlayLengthMs(2200) - v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SetPosition(100, 339) - v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SetPlayLengthMs(1350) - v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPosition(100, 339) - v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPlayLoop(false) - - v.heroRenderInfo[d2enum.HeroAssassin] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelectAssassinUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectAssassinUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectAssassinForwardWalk, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelectAssassinSelected, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelectAssassinBackWalk, d2resource.PaletteFechar), - nil, - image.Rectangle{Min: image.Point{X: 175, Y: 235}, Max: image.Point{X: 50, Y: 180}}, - v.loadSoundEffect(d2resource.SFXAssassinSelect), - v.loadSoundEffect(d2resource.SFXAssassinDeselect), - } - v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SetPosition(231, 365) - v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SetPosition(231, 365) - v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPosition(231, 365) - v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPlayLengthMs(3800) - v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SetPosition(231, 365) - v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SetPlayLengthMs(2500) - v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPosition(231, 365) - v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPlayLoop(false) - loading.Progress(0.8) - - v.heroRenderInfo[d2enum.HeroDruid] = &HeroRenderInfo{ - d2enum.HeroStanceIdle, - loadSprite(d2resource.CharacterSelectDruidUnselected, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectDruidUnselectedH, d2resource.PaletteFechar), - loadSprite(d2resource.CharacterSelectDruidForwardWalk, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelectDruidSelected, d2resource.PaletteFechar), - nil, - loadSprite(d2resource.CharacterSelectDruidBackWalk, d2resource.PaletteFechar), - nil, - image.Rectangle{Min: image.Point{X: 680, Y: 220}, Max: image.Point{X: 70, Y: 195}}, - v.loadSoundEffect(d2resource.SFXDruidSelect), - v.loadSoundEffect(d2resource.SFXDruidDeselect), - } - v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SetPosition(720, 370) - v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SetPosition(720, 370) - v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPosition(720, 370) - v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPlayLengthMs(4800) - v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPlayLoop(false) - v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SetPosition(720, 370) - v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPosition(720, 370) - v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.PlayForward() - v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPlayLengthMs(1500) - v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPlayLoop(false) } +// OnUnload releases the resources of the Select Hero Class screen func (v *SelectHeroClass) OnUnload() error { for i := range v.heroRenderInfo { v.heroRenderInfo[i].SelectSfx.Stop() v.heroRenderInfo[i].DeselectSfx.Stop() } + v.heroRenderInfo = nil + return nil } @@ -448,16 +344,27 @@ func (v *SelectHeroClass) onExitButtonClicked() { } func (v *SelectHeroClass) onOkButtonClicked() { - gameState := d2player.CreatePlayerState(v.heroNameTextbox.GetText(), v.selectedHero, - d2datadict.CharStats[v.selectedHero], v.hardcoreCheckbox.GetCheckState()) + gameState := d2player.CreatePlayerState( + v.heroNameTextbox.GetText(), + v.selectedHero, + d2datadict.CharStats[v.selectedHero], + v.hardcoreCheckbox.GetCheckState(), + ) gameClient, _ := d2client.Create(d2clientconnectiontype.Local) - _ = gameClient.Open(v.connectionHost, gameState.FilePath) + if err := gameClient.Open(v.connectionHost, gameState.FilePath); err != nil { + fmt.Printf("can not connect to the host: %s\n", v.connectionHost) + } + d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal)) } +// Render renders the Select Hero Class screen func (v *SelectHeroClass) Render(screen d2interface.Surface) error { - _ = v.bgImage.RenderSegmented(screen, 4, 3, 0) + if err := v.bgImage.RenderSegmented(screen, 4, 3, 0); err != nil { + return err + } + v.headingLabel.Render(screen) if v.selectedHero != d2enum.HeroNone { @@ -492,6 +399,7 @@ func (v *SelectHeroClass) Render(screen d2interface.Surface) error { return nil } +// Advance runs the update logic on the Select Hero Class screen func (v *SelectHeroClass) Advance(tickTime float64) error { canSelect := true @@ -500,7 +408,8 @@ func (v *SelectHeroClass) Advance(tickTime float64) error { } for infoIdx := range v.heroRenderInfo { - v.heroRenderInfo[infoIdx].Advance(tickTime) + v.heroRenderInfo[infoIdx].advance(tickTime) + if v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceIdle && v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceIdleSelected && v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceSelected { @@ -508,8 +417,8 @@ func (v *SelectHeroClass) Advance(tickTime float64) error { } } - for heroTypeIdx := range v.heroRenderInfo { - v.updateHeroSelectionHover(heroTypeIdx, canSelect) + for heroType := range v.heroRenderInfo { + v.updateHeroSelectionHover(heroType, canSelect) } v.okButton.SetEnabled(len(v.heroNameTextbox.GetText()) >= 2 && v.selectedHero != d2enum.HeroNone) @@ -526,64 +435,80 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b setSpriteToFirstFrame(renderInfo.SelectedSprite) setSpriteToFirstFrame(renderInfo.SelectedSpriteOverlay) } + return case d2enum.HeroStanceRetreating: if renderInfo.BackWalkSprite.IsOnLastFrame() { renderInfo.Stance = d2enum.HeroStanceIdle setSpriteToFirstFrame(renderInfo.IdleSprite) } + return } - if !canSelect { - return - } - if renderInfo.Stance == d2enum.HeroStanceSelected { + + if !canSelect || renderInfo.Stance == d2enum.HeroStanceSelected { return } + mouseX, mouseY := d2ui.CursorPosition() b := renderInfo.SelectionBounds mouseHover := (mouseX >= b.Min.X) && (mouseX <= b.Min.X+b.Max.X) && (mouseY >= b.Min.Y) && (mouseY <= b.Min.Y+b.Max.Y) - if mouseHover && d2ui.CursorButtonPressed(d2ui.CursorButtonLeft) { - v.heroNameTextbox.SetVisible(true) - v.heroNameTextbox.Activate() - v.okButton.SetVisible(true) - v.expansionCheckbox.SetVisible(true) - v.hardcoreCheckbox.SetVisible(true) - renderInfo.Stance = d2enum.HeroStanceApproaching - setSpriteToFirstFrame(renderInfo.ForwardWalkSprite) - setSpriteToFirstFrame(renderInfo.ForwardWalkSpriteOverlay) - for _, heroInfo := range v.heroRenderInfo { - if heroInfo.Stance != d2enum.HeroStanceSelected { - continue - } - heroInfo.SelectSfx.Stop() - heroInfo.DeselectSfx.Play() - heroInfo.Stance = d2enum.HeroStanceRetreating - setSpriteToFirstFrame(heroInfo.BackWalkSprite) - setSpriteToFirstFrame(heroInfo.BackWalkSpriteOverlay) - } - v.selectedHero = hero - v.updateHeroText() - renderInfo.SelectSfx.Play() + if mouseHover && d2ui.CursorButtonPressed(d2ui.CursorButtonLeft) { + v.handleCursorButtonPress(hero, renderInfo) return } - if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected { - _ = renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame()) - - renderInfo.Stance = d2enum.HeroStanceIdleSelected - } else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle { - _ = renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame()) - - renderInfo.Stance = d2enum.HeroStanceIdle - } + v.setCurrentFrame(mouseHover, renderInfo) if v.selectedHero == d2enum.HeroNone && mouseHover { v.selectedHero = hero v.updateHeroText() } +} +func (v *SelectHeroClass) handleCursorButtonPress(hero d2enum.Hero, renderInfo *HeroRenderInfo) { + v.heroNameTextbox.SetVisible(true) + v.heroNameTextbox.Activate() + v.okButton.SetVisible(true) + v.expansionCheckbox.SetVisible(true) + v.hardcoreCheckbox.SetVisible(true) + + renderInfo.Stance = d2enum.HeroStanceApproaching + setSpriteToFirstFrame(renderInfo.ForwardWalkSprite) + setSpriteToFirstFrame(renderInfo.ForwardWalkSpriteOverlay) + + for _, heroInfo := range v.heroRenderInfo { + if heroInfo.Stance != d2enum.HeroStanceSelected { + continue + } + + heroInfo.SelectSfx.Stop() + heroInfo.DeselectSfx.Play() + heroInfo.Stance = d2enum.HeroStanceRetreating + setSpriteToFirstFrame(heroInfo.BackWalkSprite) + setSpriteToFirstFrame(heroInfo.BackWalkSpriteOverlay) + } + + v.selectedHero = hero + v.updateHeroText() + renderInfo.SelectSfx.Play() +} + +func (v *SelectHeroClass) setCurrentFrame(mouseHover bool, renderInfo *HeroRenderInfo) { + if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected { + if err := renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame()); err != nil { + fmt.Printf("could not set current frame to: %d\n", renderInfo.IdleSprite.GetCurrentFrame()) + } + + renderInfo.Stance = d2enum.HeroStanceIdleSelected + } else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle { + if err := renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame()); err != nil { + fmt.Printf("could not set current frame to: %d\n", renderInfo.IdleSelectedSprite.GetCurrentFrame()) + } + + renderInfo.Stance = d2enum.HeroStanceIdle + } } func (v *SelectHeroClass) renderHero(screen d2interface.Surface, hero d2enum.Hero) { @@ -632,35 +557,20 @@ func (v *SelectHeroClass) updateHeroText() { v.heroClassLabel.SetText(d2common.TranslateString("partychardru")) v.setDescLabels("Commanding the forces of nature, he summons wild beasts and raging storms to his side.") } - /* - if (selectedHero == null) - return; - - switch (selectedHero.Value) - { - - } - - heroClassLabel.Location = new Point(400 - (heroClassLabel.TextArea.Width / 2), 65); - heroDesc1Label.Location = new Point(400 - (heroDesc1Label.TextArea.Width / 2), 100); - heroDesc2Label.Location = new Point(400 - (heroDesc2Label.TextArea.Width / 2), 115); - heroDesc3Label.Location = new Point(400 - (heroDesc3Label.TextArea.Width / 2), 130); - */ } func (v *SelectHeroClass) setDescLabels(descKey string) { heroDesc := d2common.TranslateString(descKey) parts := d2common.SplitIntoLinesWithMaxWidth(heroDesc, 37) + if len(parts) > 1 { v.heroDesc1Label.SetText(parts[0]) - } else { - v.heroDesc1Label.SetText("") - } - if len(parts) > 1 { v.heroDesc2Label.SetText(parts[1]) } else { + v.heroDesc1Label.SetText("") v.heroDesc2Label.SetText("") } + if len(parts) > 2 { v.heroDesc3Label.SetText(parts[2]) } else { @@ -676,19 +586,48 @@ func setSpriteToFirstFrame(sprite *d2ui.Sprite) { func drawSprite(sprite *d2ui.Sprite, target d2interface.Surface) { if sprite != nil { - _ = sprite.Render(target) + if err := sprite.Render(target); err != nil { + x, y := sprite.GetPosition() + fmt.Printf("could not render the sprite to the position(x: %d, y: %d)\n", x, y) + } } } func advanceSprite(sprite *d2ui.Sprite, elapsed float64) { if sprite != nil { - _ = sprite.Advance(elapsed) + if err := sprite.Advance(elapsed); err != nil { + fmt.Printf("could not advance the sprite\n") + } } } -func loadSprite(animationPath, palettePath string) *d2ui.Sprite { - animation, _ := d2asset.LoadAnimation(animationPath, palettePath) - sprite, _ := d2ui.LoadSprite(animation) +func loadSprite(animationPath string, position image.Point, playLength int, playLoop, blend bool) *d2ui.Sprite { + if animationPath == "" { + return nil + } + + animation, err := d2asset.LoadAnimation(animationPath, d2resource.PaletteFechar) + if err != nil { + fmt.Printf("could not load animation: %s\n", animationPath) + return nil + } + + animation.PlayForward() + animation.SetPlayLoop(playLoop) + animation.SetBlend(blend) + + if playLength != 0 { + animation.SetPlayLengthMs(playLength) + } + + sprite, err := d2ui.LoadSprite(animation) + if err != nil { + fmt.Printf("could not load sprite for the animation: %s\n", animationPath) + return nil + } + + sprite.SetPosition(position.X, position.Y) + return sprite }