1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-12-25 19:46:50 -05:00

removed most lint errors in d2gamescreen, except for map_engine_testing.go (#603)

This commit is contained in:
lord 2020-07-18 06:54:10 -07:00 committed by GitHub
parent 093ea3682e
commit c92ad67eaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 558 additions and 240 deletions

View File

@ -23,8 +23,8 @@ func (v *BlizzardIntro) OnLoad(loading d2screen.LoadingState) {
loading.Error(err)
return
}
loading.Progress(0.5)
loading.Progress(fiftyPercent)
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
}

View File

@ -70,6 +70,56 @@ func CreateCharacterSelect(
}
}
const (
tenPercent = 0.1 * iota
twentyPercent
thirtyPercent
fourtyPercent
fiftyPercent
sixtyPercent
seventyPercent
eightyPercent
ninetyPercent
)
const (
rootLabelOffsetX = 115
rootLabelOffsetY = 100
labelHeight = 15
)
const (
selectionBoxNumColumns = 2
selectionBoxNumRows = 4
selectionBoxWidth = 272
selectionBoxHeight = 92
selectionBoxOffsetX = 37
selectionBoxOffsetY = 86
selectionBoxImageOffsetX = 40
selectionBoxImageOffsetY = 50
)
const (
blackHalfOpacity = 0x0000007f
lightBrown = 0xbca88cff
lightGreen = 0x18ff00ff
)
const (
screenWidth = 800
screenHeight = 600
)
const (
newCharBtnX, newCharBtnY = 33, 468
convertCharBtnX, convertCharBtnY = 233, 468
deleteCharBtnX, deleteCharBtnY = 433, 468
deleteCancelX, deleteCancelY = 282, 308
deleteOkX, deleteOkY = 422, 308
exitBtnX, exitBtnY = 33, 537
okBtnX, okBtnY = 625, 537
)
// OnLoad loads the resources for the Character Select screen
func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
v.audioProvider.PlayBGM(d2resource.BGMTitle)
@ -78,64 +128,101 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
fmt.Println("failed to add Character Select screen as event handler")
}
loading.Progress(0.1)
loading.Progress(tenPercent)
animation, _ := d2asset.LoadAnimation(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
bgX, bgY := 0, 0
v.background, _ = d2ui.LoadSprite(animation)
v.background.SetPosition(0, 0)
v.background.SetPosition(bgX, bgY)
v.createButtons(loading)
heroTitleX, heroTitleY := 320, 23
v.d2HeroTitle = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.d2HeroTitle.SetPosition(320, 23)
v.d2HeroTitle.SetPosition(heroTitleX, heroTitleY)
v.d2HeroTitle.Alignment = d2gui.HorizontalAlignCenter
loading.Progress(0.3)
loading.Progress(thirtyPercent)
v.deleteCharConfirmLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
lines := "Are you sure that you want\nto delete this character?\nTake note: this will delete all\nversions of this Character."
v.deleteCharConfirmLabel.SetText(lines)
v.deleteCharConfirmLabel.Alignment = d2gui.HorizontalAlignCenter
v.deleteCharConfirmLabel.SetPosition(400, 185)
deleteConfirmX, deleteConfirmY := 400, 185
v.deleteCharConfirmLabel.SetPosition(deleteConfirmX, deleteConfirmY)
animation, _ = d2asset.LoadAnimation(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
v.selectionBox, _ = d2ui.LoadSprite(animation)
v.selectionBox.SetPosition(37, 86)
selBoxX, selBoxY := 37, 86
v.selectionBox.SetPosition(selBoxX, selBoxY)
animation, _ = d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
v.okCancelBox, _ = d2ui.LoadSprite(animation)
v.okCancelBox.SetPosition(270, 175)
okCancelX, okCancelY := 270, 175
v.okCancelBox.SetPosition(okCancelX, okCancelY)
v.charScrollbar = d2ui.CreateScrollbar(586, 87, 369)
scrollBarX, scrollBarY, scrollBarHeight := 586, 87, 369
v.charScrollbar = d2ui.CreateScrollbar(scrollBarX, scrollBarY, scrollBarHeight)
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
d2ui.AddWidget(&v.charScrollbar)
loading.Progress(0.5)
loading.Progress(fiftyPercent)
for i := 0; i < 8; i++ {
xOffset := 115
offsetX, offsetY := rootLabelOffsetX, rootLabelOffsetY+((i/2)*95)
if i&1 > 0 {
xOffset = 385
offsetX = 385
}
v.characterNameLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterNameLabel[i].Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.characterNameLabel[i].SetPosition(xOffset, 100+((i/2)*95))
v.characterNameLabel[i].Color = rgbaColor(lightBrown)
v.characterNameLabel[i].SetPosition(offsetX, offsetY)
offsetY += labelHeight
v.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
v.characterStatsLabel[i].SetPosition(offsetX, offsetY)
offsetY += labelHeight
v.characterExpLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteStatic)
v.characterExpLabel[i].Color = color.RGBA{R: 24, G: 255, A: 255}
v.characterExpLabel[i].SetPosition(xOffset, 130+((i/2)*95))
v.characterExpLabel[i].Color = rgbaColor(lightGreen)
v.characterExpLabel[i].SetPosition(offsetX, offsetY)
}
v.refreshGameStates()
}
func rgbaColor(rgba uint32) color.RGBA {
result := color.RGBA{}
a, b, g, r := 0, 1, 2, 3
byteWidth := 8
byteMask := 0xff
for idx := 0; idx < 4; idx++ {
shift := idx * byteWidth
component := uint8(rgba>>shift) & uint8(byteMask)
switch idx {
case a:
result.A = component
case b:
result.B = component
case g:
result.G = component
case r:
result.R = component
}
}
return result
}
func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
v.newCharButton = d2ui.CreateButton(
v.renderer,
d2ui.ButtonTypeTall,
"CREATE NEW\nCHARACTER",
)
v.newCharButton.SetPosition(33, 468)
v.newCharButton.SetPosition(newCharBtnX, newCharBtnY)
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
d2ui.AddWidget(&v.newCharButton)
@ -144,7 +231,8 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
d2ui.ButtonTypeTall,
"CONVERT TO\nEXPANSION",
)
v.convertCharButton.SetPosition(233, 468)
v.convertCharButton.SetPosition(convertCharBtnX, convertCharBtnY)
v.convertCharButton.SetEnabled(false)
d2ui.AddWidget(&v.convertCharButton)
@ -154,29 +242,30 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
"DELETE\nCHARACTER",
)
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
v.deleteCharButton.SetPosition(433, 468)
v.deleteCharButton.SetPosition(deleteCharBtnX, deleteCharBtnY)
d2ui.AddWidget(&v.deleteCharButton)
v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(33, 537)
v.exitButton.SetPosition(exitBtnX, exitBtnY)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
loading.Progress(0.2)
loading.Progress(twentyPercent)
v.deleteCharCancelButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "NO")
v.deleteCharCancelButton.SetPosition(282, 308)
v.deleteCharCancelButton.SetPosition(deleteCancelX, deleteCancelY)
v.deleteCharCancelButton.SetVisible(false)
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
d2ui.AddWidget(&v.deleteCharCancelButton)
v.deleteCharOkButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "YES")
v.deleteCharOkButton.SetPosition(422, 308)
v.deleteCharOkButton.SetPosition(deleteOkX, deleteOkY)
v.deleteCharOkButton.SetVisible(false)
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
d2ui.AddWidget(&v.deleteCharOkButton)
v.okButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "OK")
v.okButton.SetPosition(625, 537)
v.okButton.SetPosition(okBtnX, okBtnY)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
d2ui.AddWidget(&v.okButton)
}
@ -248,13 +337,16 @@ func (v *CharacterSelect) Render(screen d2interface.Surface) error {
v.characterNameLabel[i].Render(screen)
v.characterStatsLabel[i].Render(screen)
v.characterExpLabel[i].Render(screen)
screen.PushTranslation(v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
charImgX := v.characterNameLabel[i].X - selectionBoxImageOffsetX
charImgY := v.characterNameLabel[i].Y + selectionBoxImageOffsetY
screen.PushTranslation(charImgX, charImgY)
v.characterImage[i].Render(screen)
screen.Pop()
}
if v.showDeleteConfirmation {
screen.DrawRect(800, 600, color.RGBA{A: 128})
screen.DrawRect(screenWidth, screenHeight, rgbaColor(blackHalfOpacity))
if err := v.okCancelBox.RenderSegmented(screen, 2, 1, 0); err != nil {
return err
@ -275,7 +367,10 @@ func (v *CharacterSelect) moveSelectionBox() {
bw := 272
bh := 92
selectedIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
v.selectionBox.SetPosition(37+((selectedIndex&1)*bw), 86+(bh*(selectedIndex/2)))
selBoxX := selectionBoxOffsetX + ((selectedIndex & 1) * bw)
selBoxY := selectionBoxOffsetY + (bh * (selectedIndex / 2))
v.selectionBox.SetPosition(selBoxX, selBoxY)
v.d2HeroTitle.SetText(v.gameStates[v.selectedCharacter].HeroName)
}
@ -284,14 +379,15 @@ func (v *CharacterSelect) OnMouseButtonDown(event d2interface.MouseEvent) bool {
if !v.showDeleteConfirmation {
if event.Button() == d2enum.MouseButtonLeft {
mx, my := event.X(), event.Y()
bw := 272
bh := 92
localMouseX := mx - 37
localMouseY := my - 86
bw := selectionBoxWidth
bh := selectionBoxHeight
localMouseX := mx - selectionBoxOffsetX
localMouseY := my - selectionBoxOffsetY
if localMouseX > 0 && localMouseX < bw*2 && localMouseY >= 0 && localMouseY < bh*4 {
adjustY := localMouseY / bh
selectedIndex := adjustY * 2
selectedIndex := adjustY * selectionBoxNumColumns
if localMouseX > bw {
selectedIndex++
@ -354,8 +450,11 @@ func (v *CharacterSelect) refreshGameStates() {
if len(v.gameStates) > 0 {
v.selectedCharacter = 0
numStates := selectionBoxNumColumns * selectionBoxNumRows
byHalf := 2.0
v.d2HeroTitle.SetText(v.gameStates[0].HeroName)
v.charScrollbar.SetMaxOffset(int(math.Ceil(float64(len(v.gameStates)-8) / float64(2))))
v.charScrollbar.SetMaxOffset(int(math.Ceil(float64(len(v.gameStates)-numStates) / byHalf)))
} else {
v.selectedCharacter = -1
v.charScrollbar.SetMaxOffset(0)

View File

@ -3,7 +3,6 @@ package d2gamescreen
import (
"bufio"
"fmt"
"image/color"
"log"
"os"
"path"
@ -17,6 +16,13 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
const (
creditsX, creditsY = 0, 0
charSelExitBtnX, charSelExitBtnY = 33, 543
)
const secondsPerCycle float64 = 0.02
type labelItem struct {
Label d2ui.Label
IsHeading bool
@ -80,14 +86,14 @@ func (v *Credits) LoadContributors() []string {
func (v *Credits) OnLoad(loading d2screen.LoadingState) {
animation, _ := d2asset.LoadAnimation(d2resource.CreditsBackground, d2resource.PaletteSky)
v.creditsBackground, _ = d2ui.LoadSprite(animation)
v.creditsBackground.SetPosition(0, 0)
loading.Progress(0.2)
v.creditsBackground.SetPosition(creditsX, creditsY)
loading.Progress(twentyPercent)
v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(33, 543)
v.exitButton.SetPosition(charSelExitBtnX, charSelExitBtnY)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
loading.Progress(0.4)
loading.Progress(fourtyPercent)
fileData, err := d2asset.LoadFile(d2resource.CreditsText)
if err != nil {
@ -95,7 +101,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
return
}
loading.Progress(0.6)
loading.Progress(sixtyPercent)
creditData, _ := d2common.Utf16BytesToString(fileData[2:])
v.creditsText = strings.Split(creditData, "\r\n")
@ -104,7 +110,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
}
loading.Progress(0.8)
loading.Progress(eightyPercent)
v.creditsText = append(v.LoadContributors(), v.creditsText...)
}
@ -127,8 +133,6 @@ func (v *Credits) Render(screen d2interface.Surface) error {
return nil
}
const secondsPerCycle = float64(0.02)
// Advance runs the update logic on the credits screen
func (v *Credits) Advance(tickTime float64) error {
v.cycleTime += tickTime
@ -210,13 +214,22 @@ func (v *Credits) addNextItem() {
}
}
const(
itemLabelY = 605
itemLabelX = 400
itemLabel2offsetX = 10
halfItemLabel2offsetX = itemLabel2offsetX/2
)
func (v *Credits) setItemLabelPosition(label *d2ui.Label, isHeading, isNextHeading, isNextSpace bool) (isDoubled, nextHeading bool) {
width, _ := label.GetSize()
half := 2
halfWidth := width/half
if !isHeading && !isNextHeading && !isNextSpace {
isDoubled = true
// Gotta go side by side
label.SetPosition(400-width, 605)
label.SetPosition(itemLabelX-width, itemLabelY)
text2 := v.creditsText[0]
v.creditsText = v.creditsText[1:]
@ -225,24 +238,29 @@ func (v *Credits) setItemLabelPosition(label *d2ui.Label, isHeading, isNextHeadi
label2 := v.getNewFontLabel(isHeading)
label2.SetText(text2)
label2.SetPosition(410, 605)
label2.SetPosition(itemLabelX+itemLabel2offsetX, itemLabelY)
return isDoubled, nextHeading
}
label.SetPosition(405-width/2, 605)
label.SetPosition(itemLabelX+halfItemLabel2offsetX-halfWidth, itemLabelY)
return isDoubled, isNextHeading
}
const (
lightRed = 0xff5852ff
beige = 0xc6b296ff
)
func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
for _, label := range v.labels {
if label.Available {
label.Available = false
if isHeading {
label.Label.Color = color.RGBA{R: 255, G: 88, B: 82, A: 255}
label.Label.Color = rgbaColor(lightRed)
} else {
label.Label.Color = color.RGBA{R: 198, G: 178, B: 150, A: 255}
label.Label.Color = rgbaColor(beige)
}
return &label.Label
@ -256,9 +274,9 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
}
if isHeading {
newLabelItem.Label.Color = color.RGBA{R: 255, G: 88, B: 82, A: 255}
newLabelItem.Label.Color = rgbaColor(lightRed)
} else {
newLabelItem.Label.Color = color.RGBA{R: 198, G: 178, B: 150, A: 255}
newLabelItem.Label.Color = rgbaColor(beige)
}
v.labels = append(v.labels, newLabelItem)

View File

@ -22,6 +22,7 @@ const (
sidePanelsSize = 80
pentSize = 52
menuSize = 500
spacerWidth = 10
// layouts
noLayoutID layoutID = iota - 2
@ -247,7 +248,7 @@ func (m *EscapeMenu) addTitle(l *layout, text string) {
fmt.Printf("could not add label: %s to the escape menu\n", text)
}
l.AddSpacerStatic(10, labelGutter)
l.AddSpacerStatic(spacerWidth, labelGutter)
}
func (m *EscapeMenu) addBigSelectionLabel(l *layout, text string, targetLayout layoutID) {
@ -262,12 +263,12 @@ func (m *EscapeMenu) addBigSelectionLabel(l *layout, text string, targetLayout l
label.SetMouseEnterHandler(func(_ d2interface.MouseMoveEvent) {
m.onHoverElement(elID)
})
l.AddSpacerStatic(10, labelGutter)
l.AddSpacerStatic(spacerWidth, labelGutter)
l.actionableElements = append(l.actionableElements, label)
}
func (m *EscapeMenu) addPreviousMenuLabel(l *layout) {
l.AddSpacerStatic(10, labelGutter)
l.AddSpacerStatic(spacerWidth, labelGutter)
guiLabel, _ := l.AddLabel("PREVIOUS MENU", d2gui.FontStyle30Units)
label := &showLayoutLabel{Label: guiLabel, target: optionsLayoutID, showLayout: m.showLayout}
label.SetMouseClickHandler(func(_ d2interface.MouseEvent) {
@ -313,7 +314,7 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
layout.SetMouseClickHandler(func(_ d2interface.MouseEvent) {
label.Trigger()
})
l.AddSpacerStatic(10, labelGutter)
l.AddSpacerStatic(spacerWidth, labelGutter)
l.actionableElements = append(l.actionableElements, label)
}
@ -378,9 +379,9 @@ func (m *EscapeMenu) onHoverElement(id int) {
m.layouts[m.currentLayout].currentEl = id
x, _ := m.leftPent.GetPosition()
m.leftPent.SetPosition(x, y+10)
m.leftPent.SetPosition(x, y+spacerWidth)
x, _ = m.rightPent.GetPosition()
m.rightPent.SetPosition(x, y+10)
m.rightPent.SetPosition(x, y+spacerWidth)
}
func (m *EscapeMenu) onUpdateValue(optID optionID, value string) {

View File

@ -18,6 +18,12 @@ import (
const hideZoneTextAfterSeconds = 2.0
const (
moveErrStr = "failed to send MovePlayer packet to the server, playerId: %s, x: %g, x: %g\n"
bindControlsErrStr = "failed to add gameControls as input handler for player: %s\n"
castErrStr = "failed to send CastSkill packet to the server, playerId: %s, missileId: %d, x: %g, x: %g\n"
)
// Game represents the Gameplay screen
type Game struct {
gameClient *d2client.GameClient
@ -35,7 +41,14 @@ type Game struct {
}
// CreateGame creates the Gameplay screen and returns a pointer to it
func CreateGame(navigator Navigator, renderer d2interface.Renderer, inputManager d2interface.InputManager, audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient, term d2interface.Terminal) *Game {
func CreateGame(
navigator Navigator,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
gameClient *d2client.GameClient,
term d2interface.Terminal,
) *Game {
result := &Game{
gameClient: gameClient,
gameControls: nil,
@ -126,7 +139,9 @@ func (v *Game) Advance(tickTime float64) error {
// skip showing zone change text the first time we enter the world
if v.lastRegionType != d2enum.RegionNone && v.lastRegionType != tile.RegionType {
//TODO: Should not be using RegionType as an index - this will return incorrect LevelDetails record for most of the zones.
v.gameControls.SetZoneChangeText(fmt.Sprintf("Entering The %s", d2datadict.LevelDetails[int(tile.RegionType)].LevelDisplayName))
areaName := d2datadict.LevelDetails[int(tile.RegionType)].LevelDisplayName
areaChgStr := fmt.Sprintf("Entering The %s", areaName)
v.gameControls.SetZoneChangeText(areaChgStr)
v.gameControls.ShowZoneChangeText()
v.gameControls.HideZoneChangeTextAfter(hideZoneTextAfterSeconds)
}
@ -162,7 +177,7 @@ func (v *Game) bindGameControls() {
v.gameControls.Load()
if err := v.inputManager.BindHandler(v.gameControls); err != nil {
fmt.Printf("failed to add gameControls as input handler for player: %s\n", player.Id)
fmt.Printf(bindControlsErrStr, player.Id)
}
break
@ -170,12 +185,15 @@ func (v *Game) bindGameControls() {
}
// OnPlayerMove sends the player move action to the server
func (v *Game) OnPlayerMove(x, y float64) {
func (v *Game) OnPlayerMove(targetX, targetY float64) {
worldPosition := v.localPlayer.Position.World()
err := v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerID, worldPosition.X(), worldPosition.Y(), x, y))
playerID, worldX, worldY := v.gameClient.PlayerID, worldPosition.X(), worldPosition.Y()
createPlayerPacket := d2netpacket.CreateMovePlayerPacket(playerID, worldX, worldY, targetX, targetY)
err := v.gameClient.SendPacketToServer(createPlayerPacket)
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)
fmt.Printf(moveErrStr, v.gameClient.PlayerID, targetX, targetY)
}
}
@ -183,9 +201,6 @@ func (v *Game) OnPlayerMove(x, y float64) {
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,
)
fmt.Printf(castErrStr, v.gameClient.PlayerID, missileID, targetX, targetY)
}
}

View File

@ -24,7 +24,7 @@ func CreateGuiTestMain(renderer d2interface.Renderer) *GuiTestMain {
func (g *GuiTestMain) OnLoad(loading d2screen.LoadingState) {
layout := d2gui.CreateLayout(g.renderer, d2gui.PositionTypeHorizontal)
loading.Progress(0.3)
loading.Progress(thirtyPercent)
//
layoutLeft := layout.AddLayout(d2gui.PositionTypeVertical)
layoutLeft.SetHorizontalAlign(d2gui.HorizontalAlignCenter)
@ -55,7 +55,7 @@ func (g *GuiTestMain) OnLoad(loading d2screen.LoadingState) {
fmt.Printf("could not add label: %s to the GuiTestMain screen\n", "FontStyleFormal12Static")
}
loading.Progress(0.6)
loading.Progress(sixtyPercent)
layout.AddSpacerDynamic()
@ -82,7 +82,7 @@ func (g *GuiTestMain) OnLoad(loading d2screen.LoadingState) {
fmt.Printf("could not add button: %s to the GuiTestMain screen\n", "Wide")
}
loading.Progress(0.9)
loading.Progress(ninetyPercent)
layout.SetVerticalAlign(d2gui.VerticalAlignMiddle)
d2gui.SetLayout(layout)

View File

@ -3,7 +3,6 @@ package d2gamescreen
import (
"fmt"
"image/color"
"log"
"os"
"os/exec"
@ -22,10 +21,11 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
type MainMenuScreenMode int
type mainMenuScreenMode int
// mainMenuScreenMode types
const (
ScreenModeUnknown MainMenuScreenMode = iota
ScreenModeUnknown mainMenuScreenMode = iota
ScreenModeTrademark
ScreenModeMainMenu
ScreenModeMultiplayer
@ -33,6 +33,44 @@ const (
ScreenModeServerIP
)
const (
joinGameDialogX, joinGameDialogY = 318, 245
serverIPbackgroundX, serverIPbackgroundY = 270, 175
backgroundX, backgroundY = 0, 0
versionLabelX, versionLabelY = 795, -10
commitLabelX, commitLabelY = 2, 2
copyrightX, copyrightY = 400, 500
copyright2X, copyright2Y = 400, 525
od2LabelX, od2LabelY = 400, 580
tcpOptionsX, tcpOptionsY = 400, 23
joinGameX, joinGameY = 400, 190
diabloLogoX, diabloLogoY = 400, 120
exitDiabloBtnX, exitDiabloBtnY = 264, 535
creditBtnX, creditBtnY = 264, 505
cineBtnX, cineBtnY = 401, 505
singlePlayerBtnX, singlePlayerBtnY = 264, 290
githubBtnX, githubBtnY = 264, 400
mapTestBtnX, mapTestBtnY = 264, 440
tcpBtnX, tcpBtnY = 33, 543
srvCancelBtnX, srvCancelBtnY = 285, 305
srvOkBtnX, srvOkBtnY = 420, 305
multiplayerBtnX, multiplayerBtnY = 264, 330
tcpNetBtnX, tcpNetBtnY = 264, 280
networkCancelBtnX, networkCancelBtnY = 264, 540
tcpHostBtnX, tcpHostBtnY = 264, 280
tcpJoinBtnX, tcpJoinBtnY = 264, 320
)
const (
white = 0xffffffff
lightYellow = 0xffff8cff
gold = 0xd8c480ff
)
const (
joinGameCharacterFilter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:"
)
// MainMenu represents the main menu
type MainMenu struct {
tcpIPBackground *d2ui.Sprite
@ -65,7 +103,7 @@ type MainMenu struct {
tcpIPOptionsLabel d2ui.Label
tcpJoinGameLabel d2ui.Label
tcpJoinGameEntry d2ui.TextBox
screenMode MainMenuScreenMode
screenMode mainMenuScreenMode
leftButtonHeld bool
inputManager d2interface.InputManager
@ -76,7 +114,12 @@ type MainMenu struct {
}
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu(navigator Navigator, renderer d2interface.Renderer, inputManager d2interface.InputManager, audioProvider d2interface.AudioProvider) *MainMenu {
func CreateMainMenu(
navigator Navigator,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
) *MainMenu {
return &MainMenu{
screenMode: ScreenModeUnknown,
leftButtonHeld: true,
@ -90,7 +133,7 @@ func CreateMainMenu(navigator Navigator, renderer d2interface.Renderer, inputMan
// OnLoad is called to load the resources for the main menu
func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
v.audioProvider.PlayBGM(d2resource.BGMTitle)
loading.Progress(0.2)
loading.Progress(twentyPercent)
v.createLabels(loading)
v.loadBackgroundSprites()
@ -98,10 +141,10 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
v.createButtons(loading)
v.tcpJoinGameEntry = d2ui.CreateTextbox(v.renderer)
v.tcpJoinGameEntry.SetPosition(318, 245)
v.tcpJoinGameEntry.SetFilter("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:")
v.tcpJoinGameEntry.SetPosition(joinGameDialogX, joinGameDialogY)
v.tcpJoinGameEntry.SetFilter(joinGameCharacterFilter)
d2ui.AddWidget(&v.tcpJoinGameEntry)
loading.Progress(0.9)
loading.Progress(ninetyPercent)
if v.screenMode == ScreenModeUnknown {
v.SetScreenMode(ScreenModeTrademark)
@ -117,56 +160,56 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
func (v *MainMenu) loadBackgroundSprites() {
animation, _ := d2asset.LoadAnimation(d2resource.GameSelectScreen, d2resource.PaletteSky)
v.background, _ = d2ui.LoadSprite(animation)
v.background.SetPosition(0, 0)
v.background.SetPosition(backgroundX, backgroundY)
animation, _ = d2asset.LoadAnimation(d2resource.TrademarkScreen, d2resource.PaletteSky)
v.trademarkBackground, _ = d2ui.LoadSprite(animation)
v.trademarkBackground.SetPosition(0, 0)
v.trademarkBackground.SetPosition(backgroundX, backgroundY)
animation, _ = d2asset.LoadAnimation(d2resource.TCPIPBackground, d2resource.PaletteSky)
v.tcpIPBackground, _ = d2ui.LoadSprite(animation)
v.tcpIPBackground.SetPosition(0, 0)
v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
animation, _ = d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
v.serverIPBackground, _ = d2ui.LoadSprite(animation)
v.serverIPBackground.SetPosition(270, 175)
v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
}
func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.versionLabel.Alignment = d2gui.HorizontalAlignRight
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
v.versionLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.versionLabel.SetPosition(795, -10)
v.versionLabel.Color = rgbaColor(white)
v.versionLabel.SetPosition(versionLabelX, versionLabelY)
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.commitLabel.Alignment = d2gui.HorizontalAlignLeft
v.commitLabel.SetText(d2common.BuildInfo.Commit)
v.commitLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.commitLabel.SetPosition(2, 2)
v.commitLabel.Color = rgbaColor(white)
v.commitLabel.SetPosition(commitLabelX, commitLabelY)
v.copyrightLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel.Alignment = d2gui.HorizontalAlignCenter
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
v.copyrightLabel.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel.SetPosition(400, 500)
loading.Progress(0.3)
v.copyrightLabel.Color = rgbaColor(lightBrown)
v.copyrightLabel.SetPosition(copyrightX, copyrightY)
loading.Progress(thirtyPercent)
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2.Alignment = d2gui.HorizontalAlignCenter
v.copyrightLabel2.SetText("All Rights Reserved.")
v.copyrightLabel2.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel2.SetPosition(400, 525)
v.copyrightLabel2.Color = rgbaColor(lightBrown)
v.copyrightLabel2.SetPosition(copyright2X, copyright2Y)
v.openDiabloLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.openDiabloLabel.Alignment = d2gui.HorizontalAlignCenter
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
v.openDiabloLabel.Color = color.RGBA{R: 255, G: 255, B: 140, A: 255}
v.openDiabloLabel.SetPosition(400, 580)
loading.Progress(0.5)
v.openDiabloLabel.Color = rgbaColor(lightYellow)
v.openDiabloLabel.SetPosition(od2LabelX, od2LabelY)
loading.Progress(fiftyPercent)
v.tcpIPOptionsLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.tcpIPOptionsLabel.SetPosition(400, 23)
v.tcpIPOptionsLabel.SetPosition(tcpOptionsX, tcpOptionsY)
v.tcpIPOptionsLabel.Alignment = d2gui.HorizontalAlignCenter
v.tcpIPOptionsLabel.SetText("TCP/IP Options")
@ -174,8 +217,8 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
v.tcpJoinGameLabel.Alignment = d2gui.HorizontalAlignCenter
v.tcpJoinGameLabel.SetText("Enter Host IP Address\nto Join Game")
v.tcpJoinGameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.tcpJoinGameLabel.SetPosition(400, 190)
v.tcpJoinGameLabel.Color = rgbaColor(gold)
v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY)
}
func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
@ -183,97 +226,97 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
v.diabloLogoLeft, _ = d2ui.LoadSprite(animation)
v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
v.diabloLogoLeft.PlayForward()
v.diabloLogoLeft.SetPosition(400, 120)
loading.Progress(0.6)
v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY)
loading.Progress(sixtyPercent)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
v.diabloLogoRight, _ = d2ui.LoadSprite(animation)
v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
v.diabloLogoRight.PlayForward()
v.diabloLogoRight.SetPosition(400, 120)
v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
v.diabloLogoLeftBack, _ = d2ui.LoadSprite(animation)
v.diabloLogoLeftBack.SetPosition(400, 120)
v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
v.diabloLogoRightBack, _ = d2ui.LoadSprite(animation)
v.diabloLogoRightBack.SetPosition(400, 120)
v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
}
func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
v.exitDiabloButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "EXIT DIABLO II")
v.exitDiabloButton.SetPosition(264, 535)
v.exitDiabloButton.SetPosition(exitDiabloBtnX, exitDiabloBtnY)
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitDiabloButton)
v.creditsButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeShort, "CREDITS")
v.creditsButton.SetPosition(264, 505)
v.creditsButton.SetPosition(creditBtnX, creditBtnY)
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
d2ui.AddWidget(&v.creditsButton)
v.cinematicsButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeShort, "CINEMATICS")
v.cinematicsButton.SetPosition(401, 505)
v.cinematicsButton.SetPosition(cineBtnX, cineBtnY)
d2ui.AddWidget(&v.cinematicsButton)
loading.Progress(0.7)
loading.Progress(seventyPercent)
v.singlePlayerButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "SINGLE PLAYER")
v.singlePlayerButton.SetPosition(264, 290)
v.singlePlayerButton.SetPosition(singlePlayerBtnX, singlePlayerBtnY)
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
d2ui.AddWidget(&v.singlePlayerButton)
v.githubButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "PROJECT WEBSITE")
v.githubButton.SetPosition(264, 400)
v.githubButton.SetPosition(githubBtnX, githubBtnY)
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
d2ui.AddWidget(&v.githubButton)
v.mapTestButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "MAP ENGINE TEST")
v.mapTestButton.SetPosition(264, 440)
v.mapTestButton.SetPosition(mapTestBtnX, mapTestBtnY)
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
d2ui.AddWidget(&v.mapTestButton)
v.btnTCPIPCancel = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, d2common.TranslateString("cancel"))
v.btnTCPIPCancel.SetPosition(33, 543)
v.btnTCPIPCancel.SetPosition(tcpBtnX, tcpBtnY)
v.btnTCPIPCancel.OnActivated(func() { v.onTCPIPCancelClicked() })
d2ui.AddWidget(&v.btnTCPIPCancel)
v.btnServerIPCancel = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "CANCEL")
v.btnServerIPCancel.SetPosition(285, 305)
v.btnServerIPCancel.SetPosition(srvCancelBtnX, srvCancelBtnY)
v.btnServerIPCancel.OnActivated(func() { v.onBtnTCPIPCancelClicked() })
d2ui.AddWidget(&v.btnServerIPCancel)
v.btnServerIPOk = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "OK")
v.btnServerIPOk.SetPosition(420, 305)
v.btnServerIPOk.SetPosition(srvOkBtnX, srvOkBtnY)
v.btnServerIPOk.OnActivated(func() { v.onBtnTCPIPOkClicked() })
d2ui.AddWidget(&v.btnServerIPOk)
v.createMultiplayerMenuButtons()
loading.Progress(0.8)
loading.Progress(eightyPercent)
}
func (v *MainMenu) createMultiplayerMenuButtons() {
v.multiplayerButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "MULTIPLAYER")
v.multiplayerButton.SetPosition(264, 330)
v.multiplayerButton.SetPosition(multiplayerBtnX, multiplayerBtnY)
v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() })
d2ui.AddWidget(&v.multiplayerButton)
v.networkTCPIPButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "TCP/IP GAME")
v.networkTCPIPButton.SetPosition(264, 280)
v.networkTCPIPButton.SetPosition(tcpNetBtnX, tcpNetBtnY)
v.networkTCPIPButton.OnActivated(func() { v.onNetworkTCPIPClicked() })
d2ui.AddWidget(&v.networkTCPIPButton)
v.networkCancelButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, d2common.TranslateString("cancel"))
v.networkCancelButton.SetPosition(264, 540)
v.networkCancelButton.SetPosition(networkCancelBtnX, networkCancelBtnY)
v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() })
d2ui.AddWidget(&v.networkCancelButton)
v.btnTCPIPHostGame = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "HOST GAME")
v.btnTCPIPHostGame.SetPosition(264, 280)
v.btnTCPIPHostGame.SetPosition(tcpHostBtnX, tcpHostBtnY)
v.btnTCPIPHostGame.OnActivated(func() { v.onTCPIPHostGameClicked() })
d2ui.AddWidget(&v.btnTCPIPHostGame)
v.btnTCPIPJoinGame = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "JOIN GAME")
v.btnTCPIPJoinGame.SetPosition(264, 320)
v.btnTCPIPJoinGame.SetPosition(tcpJoinBtnX, tcpJoinBtnY)
v.btnTCPIPJoinGame.OnActivated(func() { v.onTCPIPJoinGameClicked() })
d2ui.AddWidget(&v.btnTCPIPJoinGame)
}
@ -436,7 +479,8 @@ func (v *MainMenu) OnMouseButtonDown(event d2interface.MouseEvent) bool {
return false
}
func (v *MainMenu) SetScreenMode(screenMode MainMenuScreenMode) {
// SetScreenMode sets the screen mode (which sub-menu the screen is on)
func (v *MainMenu) SetScreenMode(screenMode mainMenuScreenMode) {
v.screenMode = screenMode
isMainMenu := screenMode == ScreenModeMainMenu
isMultiplayer := screenMode == ScreenModeMultiplayer

View File

@ -103,7 +103,12 @@ type MapEngineTest struct {
}
// CreateMapEngineTest creates the Map Engine Test screen and returns a pointer to it
func CreateMapEngineTest(currentRegion, levelPreset int, term d2interface.Terminal, renderer d2interface.Renderer, inputManager d2interface.InputManager) *MapEngineTest {
func CreateMapEngineTest(currentRegion,
levelPreset int,
term d2interface.Terminal,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
) *MapEngineTest {
result := &MapEngineTest{
currentRegion: currentRegion,
levelPreset: levelPreset,
@ -171,15 +176,15 @@ func (met *MapEngineTest) OnLoad(loading d2screen.LoadingState) {
fmt.Printf("could not add MapEngineTest as event handler")
}
loading.Progress(0.2)
loading.Progress(twentyPercent)
met.mapEngine = d2mapengine.CreateMapEngine()
loading.Progress(0.5)
loading.Progress(fiftyPercent)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.renderer, met.mapEngine, met.terminal)
loading.Progress(0.7)
loading.Progress(seventyPercent)
met.loadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)
}

View File

@ -4,6 +4,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
)
// Navigator is used for transitioning between game screens
type Navigator interface {
ToMainMenu()
ToSelectHero(connType d2clientconnectiontype.ClientConnectionType, connHost string)

View File

@ -3,7 +3,6 @@ package d2gamescreen
import (
"fmt"
"image"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
@ -37,98 +36,206 @@ type heroRenderConfig struct {
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 point(x, y int) image.Point {
return image.Point{X: x, Y: y}
}
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,
func rect(x1, y1, x2, y2 int) image.Rectangle {
return image.Rectangle{Min: point(x1, y1), Max: point(x2, y2)}
}
// animation position, selection box bound, animation play lengths in ms
const (
barbPosX, barbPosY = 400, 330
barbRectMinX, barbRectMinY, barbRectMaxX, barbRectMaxY = 364, 201, 90, 170
barbIdleLength, barbForwardLength, barbBackLength = 0, 2500, 1000
sorcPosX, sorcPosY = 626, 352
sorcRectMinX, sorcRectMinY, sorcRectMaxX, sorcRectMaxY = 580, 240, 65, 160
sorcIdleLength, sorcForwardLength, sorcBackLength = 2500, 2300, 1200
necPosX, necPosY = 300, 335
necRectMinX, necRectMinY, necRectMaxX, necRectMaxY = 265, 220, 55, 175
necIdleLength, necForwardLength, necBackLength = 1200, 2000, 1500
palPosX, palPosY = 521, 338
palRectMinX, palRectMinY, palRectMaxX, palRectMaxY = 490, 210, 65, 180
palIdleLength, palForwardLength, palBackLength = 2500, 3400, 1300
amaPosX, amaPosY = 100, 339
amaRectMinX, amaRectMinY, amaRectMaxX, amaRectMaxY = 70, 220, 55, 200
amaIdleLength, amaForwardLength, amaBackLength = 2500, 2200, 1500
assPosX, assPosY = 231, 365
assRectMinX, assRectMinY, assRectMaxX, assRectMaxY = 175, 235, 50, 180
assIdleLength, assForwardLength, assBackLength = 2500, 3800, 1500
druPosX, druPosY = 720, 370
druRectMinX, druRectMinY, druRectMaxX, druRectMaxY = 680, 220, 70, 195
druIdleLength, druForwardLength, druBackLength = 1500, 4800, 1500
campfirePosX, campfirePosY = 380, 335
)
// label and button positions
const (
headingX, headingY = 400, 17
heroClassLabelX, heroClassLabelY = 400, 65
heroDescLine1X, heroDescLine1Y = 400, 100
heroDescLine2X, heroDescLine2Y = 400, 115
heroDescLine3X, heroDescLine3Y = 400, 130
heroNameLabelX, heroNameLabelY = 321, 475
expansionLabelX, expansionLabelY = 339, 526
hardcoreLabelX, hardcoreLabelY = 339, 548
selHeroExitBtnX, selHeroExitBtnY = 33, 537
selHeroOkBtnX, selHeroOkBtnY = 630, 537
heroNameTextBoxX, heoNameTextBoxY = 318, 493
expandsionCheckboxX, expansionCheckboxY = 318, 526
hardcoreCheckoxX, hardcoreCheckboxY = 318, 548
)
const heroDescCharWidth = 37
//nolint:funlen // this func returns a map of structs and the structs are big, deal with it
func getHeroRenderConfiguration() map[d2enum.Hero]*heroRenderConfig {
configs := make(map[d2enum.Hero]*heroRenderConfig)
configs[d2enum.HeroBarbarian] = &heroRenderConfig{
d2resource.CharacterSelectBarbarianUnselected,
d2resource.CharacterSelectBarbarianUnselectedH,
d2resource.CharacterSelectBarbarianForwardWalk,
d2resource.CharacterSelectBarbarianForwardWalkOverlay,
false,
d2resource.CharacterSelectBarbarianSelected,
"",
d2resource.CharacterSelectBarbarianBackWalk,
"",
rect(barbRectMinX, barbRectMinY, barbRectMaxX, barbRectMaxY),
d2resource.SFXBarbarianSelect,
d2resource.SFXBarbarianDeselect,
point(barbPosX, barbPosY),
barbIdleLength,
barbForwardLength,
barbBackLength,
}
configs[d2enum.HeroSorceress] = &heroRenderConfig{
d2resource.CharacterSelectSorceressUnselected,
d2resource.CharacterSelectSorceressUnselectedH,
d2resource.CharacterSelectSorceressForwardWalk,
d2resource.CharacterSelectSorceressForwardWalkOverlay,
true,
d2resource.CharacterSelectSorceressSelected,
d2resource.CharacterSelectSorceressSelectedOverlay,
d2resource.CharacterSelectSorceressBackWalk,
d2resource.CharacterSelectSorceressBackWalkOverlay,
rect(sorcRectMinX, sorcRectMinY, sorcRectMaxX, sorcRectMaxY),
d2resource.SFXSorceressSelect,
d2resource.SFXSorceressDeselect,
point(sorcPosX, sorcPosY),
sorcIdleLength,
sorcForwardLength,
sorcBackLength,
}
configs[d2enum.HeroNecromancer] = &heroRenderConfig{
d2resource.CharacterSelectNecromancerUnselected,
d2resource.CharacterSelectNecromancerUnselectedH,
d2resource.CharacterSelectNecromancerForwardWalk,
d2resource.CharacterSelectNecromancerForwardWalkOverlay,
true,
d2resource.CharacterSelectNecromancerSelected,
d2resource.CharacterSelectNecromancerSelectedOverlay,
d2resource.CharacterSelectNecromancerBackWalk,
d2resource.CharacterSelectNecromancerBackWalkOverlay,
rect(necRectMinX, necRectMinY, necRectMaxX, necRectMaxY),
d2resource.SFXNecromancerSelect,
d2resource.SFXNecromancerDeselect,
point(necPosX, necPosY),
necIdleLength,
necForwardLength,
necBackLength,
}
configs[d2enum.HeroPaladin] = &heroRenderConfig{
d2resource.CharacterSelectPaladinUnselected,
d2resource.CharacterSelectPaladinUnselectedH,
d2resource.CharacterSelectPaladinForwardWalk,
d2resource.CharacterSelectPaladinForwardWalkOverlay,
false,
d2resource.CharacterSelectPaladinSelected,
"",
d2resource.CharacterSelectPaladinBackWalk,
"",
rect(palRectMinX, palRectMinY, palRectMaxX, palRectMaxY),
d2resource.SFXPaladinSelect,
d2resource.SFXPaladinDeselect,
point(palPosX, palPosY),
palIdleLength,
palForwardLength,
palBackLength,
}
configs[d2enum.HeroAmazon] = &heroRenderConfig{
d2resource.CharacterSelectAmazonUnselected,
d2resource.CharacterSelectAmazonUnselectedH,
d2resource.CharacterSelectAmazonForwardWalk,
"",
false,
d2resource.CharacterSelectAmazonSelected,
"",
d2resource.CharacterSelectAmazonBackWalk,
"",
rect(amaRectMinX, amaRectMinY, amaRectMaxX, amaRectMaxY),
d2resource.SFXAmazonSelect,
d2resource.SFXAmazonDeselect,
point(amaPosX, amaPosY),
amaIdleLength,
amaForwardLength,
amaBackLength,
}
configs[d2enum.HeroAssassin] = &heroRenderConfig{
d2resource.CharacterSelectAssassinUnselected,
d2resource.CharacterSelectAssassinUnselectedH,
d2resource.CharacterSelectAssassinForwardWalk,
"",
false,
d2resource.CharacterSelectAssassinSelected,
"",
d2resource.CharacterSelectAssassinBackWalk,
"",
rect(assRectMinX, assRectMinY, assRectMaxX, assRectMaxY),
d2resource.SFXAssassinSelect,
d2resource.SFXAssassinDeselect,
point(assPosX, assPosY),
assIdleLength,
assForwardLength,
assBackLength,
}
configs[d2enum.HeroDruid] = &heroRenderConfig{
d2resource.CharacterSelectDruidUnselected,
d2resource.CharacterSelectDruidUnselectedH,
d2resource.CharacterSelectDruidForwardWalk,
"",
false,
d2resource.CharacterSelectDruidSelected,
"",
d2resource.CharacterSelectDruidBackWalk,
"",
rect(druRectMinX, druRectMinY, druRectMaxX, druRectMaxY),
d2resource.SFXDruidSelect,
d2resource.SFXDruidDeselect,
point(druPosX, druPosY),
druIdleLength,
druForwardLength,
druBackLength,
}
return configs
}
// HeroRenderInfo stores the rendering information of a hero for the Select Hero Class screen
@ -186,7 +293,13 @@ type SelectHeroClass struct {
}
// CreateSelectHeroClass creates an instance of a SelectHeroClass
func CreateSelectHeroClass(navigator Navigator, renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, connectionType d2clientconnectiontype.ClientConnectionType, connectionHost string) *SelectHeroClass {
func CreateSelectHeroClass(
navigator Navigator,
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string,
) *SelectHeroClass {
result := &SelectHeroClass{
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
selectedHero: d2enum.HeroNone,
@ -203,20 +316,32 @@ func CreateSelectHeroClass(navigator Navigator, renderer d2interface.Renderer, a
// 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)
loading.Progress(tenPercent)
v.bgImage = loadSprite(d2resource.CharacterSelectBackground, image.Point{X: 0, Y: 0}, 0, true, false)
v.bgImage = loadSprite(
d2resource.CharacterSelectBackground,
point(0, 0),
0,
true,
false,
)
loading.Progress(0.3)
loading.Progress(thirtyPercent)
v.createLabels()
loading.Progress(0.4)
loading.Progress(fourtyPercent)
v.createButtons()
v.campfire = loadSprite(d2resource.CharacterSelectCampfire, image.Point{X: 380, Y: 335}, 0, true, true)
v.campfire = loadSprite(
d2resource.CharacterSelectCampfire,
point(campfirePosX, campfirePosY),
0,
true,
true,
)
v.createCheckboxes(v.renderer)
loading.Progress(0.5)
loading.Progress(fiftyPercent)
for hero, config := range getHeroRenderConfiguration() {
position := config.position
@ -247,53 +372,56 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) {
func (v *SelectHeroClass) createLabels() {
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
fontWidth, _ := v.headingLabel.GetSize()
v.headingLabel.SetPosition(400-fontWidth/2, 17)
half := 2
halfFontWidth := fontWidth / half
v.headingLabel.SetPosition(headingX-halfFontWidth, headingY)
v.headingLabel.SetText("Select Hero Class")
v.headingLabel.Alignment = d2gui.HorizontalAlignCenter
v.heroClassLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
v.heroClassLabel.Alignment = d2gui.HorizontalAlignCenter
v.heroClassLabel.SetPosition(400, 65)
v.heroClassLabel.SetPosition(heroClassLabelX, heroClassLabelY)
v.heroDesc1Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc1Label.Alignment = d2gui.HorizontalAlignCenter
v.heroDesc1Label.SetPosition(400, 100)
v.heroDesc1Label.SetPosition(heroDescLine1X, heroDescLine1Y)
v.heroDesc2Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc2Label.Alignment = d2gui.HorizontalAlignCenter
v.heroDesc2Label.SetPosition(400, 115)
v.heroDesc2Label.SetPosition(heroDescLine2X, heroDescLine2Y)
v.heroDesc3Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc3Label.Alignment = d2gui.HorizontalAlignCenter
v.heroDesc3Label.SetPosition(400, 130)
v.heroDesc3Label.SetPosition(heroDescLine3X, heroDescLine3Y)
v.heroNameLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroNameLabel.Alignment = d2gui.HorizontalAlignLeft
v.heroNameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.heroNameLabel.Color = rgbaColor(gold)
v.heroNameLabel.SetText("Character Name")
v.heroNameLabel.SetPosition(321, 475)
v.heroNameLabel.SetPosition(heroNameLabelX, heroNameLabelY)
v.expansionCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.expansionCharLabel.Alignment = d2gui.HorizontalAlignLeft
v.expansionCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.expansionCharLabel.Color = rgbaColor(gold)
v.expansionCharLabel.SetText("EXPANSION CHARACTER")
v.expansionCharLabel.SetPosition(339, 526)
v.expansionCharLabel.SetPosition(expansionLabelX, expansionLabelY)
v.hardcoreCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.hardcoreCharLabel.Alignment = d2gui.HorizontalAlignLeft
v.hardcoreCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.hardcoreCharLabel.Color = rgbaColor(gold)
v.hardcoreCharLabel.SetText("Hardcore")
v.hardcoreCharLabel.SetPosition(339, 548)
v.hardcoreCharLabel.SetPosition(hardcoreLabelX, hardcoreLabelY)
}
func (v *SelectHeroClass) createButtons() {
v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(33, 537)
v.exitButton.SetPosition(selHeroExitBtnX, selHeroExitBtnY)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
v.okButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "OK")
v.okButton.SetPosition(630, 537)
v.okButton.SetPosition(selHeroOkBtnX, selHeroOkBtnY)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
v.okButton.SetVisible(false)
v.okButton.SetEnabled(false)
@ -302,17 +430,17 @@ func (v *SelectHeroClass) createButtons() {
func (v *SelectHeroClass) createCheckboxes(renderer d2interface.Renderer) {
v.heroNameTextbox = d2ui.CreateTextbox(renderer)
v.heroNameTextbox.SetPosition(318, 493)
v.heroNameTextbox.SetPosition(heroNameTextBoxX, heoNameTextBoxY)
v.heroNameTextbox.SetVisible(false)
d2ui.AddWidget(&v.heroNameTextbox)
v.expansionCheckbox = d2ui.CreateCheckbox(v.renderer, true)
v.expansionCheckbox.SetPosition(318, 526)
v.expansionCheckbox.SetPosition(expandsionCheckboxX, expansionCheckboxY)
v.expansionCheckbox.SetVisible(false)
d2ui.AddWidget(&v.expansionCheckbox)
v.hardcoreCheckbox = d2ui.CreateCheckbox(renderer, false)
v.hardcoreCheckbox.SetPosition(318, 548)
v.hardcoreCheckbox.SetPosition(hardcoreCheckoxX, hardcoreCheckboxY)
v.hardcoreCheckbox.SetVisible(false)
d2ui.AddWidget(&v.hardcoreCheckbox)
}
@ -543,11 +671,18 @@ func (v *SelectHeroClass) updateHeroText() {
}
}
const (
oneLine = 1
twoLine = 2
)
func (v *SelectHeroClass) setDescLabels(descKey string) {
heroDesc := d2common.TranslateString(descKey)
parts := d2common.SplitIntoLinesWithMaxWidth(heroDesc, 37)
parts := d2common.SplitIntoLinesWithMaxWidth(heroDesc, heroDescCharWidth)
if len(parts) > 1 {
numLines := len(parts)
if numLines > oneLine {
v.heroDesc1Label.SetText(parts[0])
v.heroDesc2Label.SetText(parts[1])
} else {
@ -555,7 +690,7 @@ func (v *SelectHeroClass) setDescLabels(descKey string) {
v.heroDesc2Label.SetText("")
}
if len(parts) > 2 {
if numLines > twoLine {
v.heroDesc3Label.SetText(parts[2])
} else {
v.heroDesc3Label.SetText("")