1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-09-16 00:08:29 -04:00
OpenDiablo2/d2core/d2scene/character_select.go
ndechiara 1c2b4869a1 Migrate out d2common d2helper d2data modules (#195)
* Switch items to dynamic load with a common struct, add misc.txt loading
* Update Ebiten Reference
* Switch references to point to D2Shared
* Migrate part 2
2019-11-17 00:16:33 -05:00

318 lines
11 KiB
Go

package d2scene
import (
"image/color"
"math"
"os"
"strings"
"github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/D2Shared/d2common"
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
dh "github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
)
type CharacterSelect struct {
uiManager *d2ui.Manager
soundManager *d2audio.Manager
fileProvider d2interface.FileProvider
sceneProvider d2coreinterface.SceneProvider
background d2render.Sprite
newCharButton d2ui.Button
convertCharButton d2ui.Button
deleteCharButton d2ui.Button
exitButton d2ui.Button
okButton d2ui.Button
deleteCharCancelButton d2ui.Button
deleteCharOkButton d2ui.Button
selectionBox d2render.Sprite
okCancelBox d2render.Sprite
d2HeroTitle d2ui.Label
deleteCharConfirmLabel d2ui.Label
charScrollbar d2ui.Scrollbar
characterNameLabel [8]d2ui.Label
characterStatsLabel [8]d2ui.Label
characterExpLabel [8]d2ui.Label
characterImage [8]*d2core.Hero
gameStates []*d2core.GameState
selectedCharacter int
mouseButtonPressed bool
showDeleteConfirmation bool
}
func CreateCharacterSelect(
fileProvider d2interface.FileProvider,
sceneProvider d2coreinterface.SceneProvider,
uiManager *d2ui.Manager,
soundManager *d2audio.Manager,
) *CharacterSelect {
result := &CharacterSelect{
selectedCharacter: -1,
uiManager: uiManager,
sceneProvider: sceneProvider,
fileProvider: fileProvider,
soundManager: soundManager,
}
return result
}
func (v *CharacterSelect) Load() []func() {
v.soundManager.PlayBGM(d2resource.BGMTitle)
return []func(){
func() {
v.background = d2render.CreateSprite(v.fileProvider.LoadFile(d2resource.CharacterSelectionBackground), d2datadict.Palettes[d2enum.Sky])
v.background.MoveTo(0, 0)
},
func() {
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
v.newCharButton.MoveTo(33, 468)
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
v.uiManager.AddWidget(&v.newCharButton)
},
func() {
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
v.convertCharButton.MoveTo(233, 468)
v.convertCharButton.SetEnabled(false)
v.uiManager.AddWidget(&v.convertCharButton)
},
func() {
v.deleteCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15)))
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
v.deleteCharButton.MoveTo(433, 468)
v.uiManager.AddWidget(&v.deleteCharButton)
},
func() {
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
v.exitButton.MoveTo(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
v.uiManager.AddWidget(&v.exitButton)
},
func() {
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, v.fileProvider, d2common.TranslateString("#4231"))
v.deleteCharCancelButton.MoveTo(282, 308)
v.deleteCharCancelButton.SetVisible(false)
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
v.uiManager.AddWidget(&v.deleteCharCancelButton)
},
func() {
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, v.fileProvider, d2common.TranslateString("#4227"))
v.deleteCharOkButton.MoveTo(422, 308)
v.deleteCharOkButton.SetVisible(false)
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
v.uiManager.AddWidget(&v.deleteCharOkButton)
},
func() {
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971"))
v.okButton.MoveTo(625, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
v.uiManager.AddWidget(&v.okButton)
},
func() {
v.d2HeroTitle = d2ui.CreateLabel(v.fileProvider, d2resource.Font42, d2enum.Units)
v.d2HeroTitle.MoveTo(320, 23)
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
},
func() {
v.deleteCharConfirmLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
lines := dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#1878"), 29)
v.deleteCharConfirmLabel.SetText(strings.Join(lines, "\n"))
v.deleteCharConfirmLabel.Alignment = d2ui.LabelAlignCenter
v.deleteCharConfirmLabel.MoveTo(400, 185)
},
func() {
v.selectionBox = d2render.CreateSprite(v.fileProvider.LoadFile(d2resource.CharacterSelectionSelectBox), d2datadict.Palettes[d2enum.Sky])
v.selectionBox.MoveTo(37, 86)
},
func() {
v.okCancelBox = d2render.CreateSprite(v.fileProvider.LoadFile(d2resource.PopUpOkCancel), d2datadict.Palettes[d2enum.Fechar])
v.okCancelBox.MoveTo(270, 175)
},
func() {
v.charScrollbar = d2ui.CreateScrollbar(v.fileProvider, 586, 87, 369)
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
v.uiManager.AddWidget(&v.charScrollbar)
},
func() {
for i := 0; i < 8; i++ {
xOffset := 115
if i&1 > 0 {
xOffset = 385
}
v.characterNameLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
v.characterNameLabel[i].Color = color.RGBA{188, 168, 140, 255}
v.characterNameLabel[i].MoveTo(xOffset, 100+((i/2)*95))
v.characterStatsLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
v.characterStatsLabel[i].MoveTo(xOffset, 115+((i/2)*95))
v.characterExpLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Static)
v.characterExpLabel[i].Color = color.RGBA{24, 255, 0, 255}
v.characterExpLabel[i].MoveTo(xOffset, 130+((i/2)*95))
}
v.refreshGameStates()
},
}
}
func (v *CharacterSelect) onScrollUpdate() {
v.moveSelectionBox()
v.updateCharacterBoxes()
}
func (v *CharacterSelect) updateCharacterBoxes() {
expText := d2common.TranslateString("#803")
for i := 0; i < 8; i++ {
idx := i + (v.charScrollbar.GetCurrentOffset() * 2)
if idx >= len(v.gameStates) {
v.characterNameLabel[i].SetText("")
v.characterStatsLabel[i].SetText("")
v.characterExpLabel[i].SetText("")
v.characterImage[i] = nil
continue
}
v.characterNameLabel[i].SetText(v.gameStates[idx].HeroName)
v.characterStatsLabel[i].SetText("Level 1 " + v.gameStates[idx].HeroType.String())
v.characterExpLabel[i].SetText(expText)
// TODO: Generate or load the object from the actual player data...
v.characterImage[i] = d2core.CreateHero(
0,
0,
5,
v.gameStates[idx].HeroType,
d2core.HeroObjects[v.gameStates[idx].HeroType],
v.fileProvider,
)
}
}
func (v *CharacterSelect) onNewCharButtonClicked() {
v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
}
func (v *CharacterSelect) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)
mainMenu.ShowTrademarkScreen = false
v.sceneProvider.SetNextScene(mainMenu)
}
func (v *CharacterSelect) Unload() {
}
func (v *CharacterSelect) Render(screen *ebiten.Image) {
v.background.DrawSegments(screen, 4, 3, 0)
v.d2HeroTitle.Draw(screen)
actualSelectionIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
if v.selectedCharacter > -1 && actualSelectionIndex >= 0 && actualSelectionIndex < 8 {
v.selectionBox.DrawSegments(screen, 2, 1, 0)
}
for i := 0; i < 8; i++ {
idx := i + (v.charScrollbar.GetCurrentOffset() * 2)
if idx >= len(v.gameStates) {
continue
}
v.characterNameLabel[i].Draw(screen)
v.characterStatsLabel[i].Draw(screen)
v.characterExpLabel[i].Draw(screen)
v.characterImage[i].Render(screen, v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
}
if v.showDeleteConfirmation {
ebitenutil.DrawRect(screen, 0.0, 0.0, 800.0, 600.0, color.RGBA{0, 0, 0, 128})
v.okCancelBox.DrawSegments(screen, 2, 1, 0)
v.deleteCharConfirmLabel.Draw(screen)
}
}
func (v *CharacterSelect) moveSelectionBox() {
if v.selectedCharacter == -1 {
v.d2HeroTitle.SetText("")
return
}
bw := 272
bh := 92
selectedIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
v.selectionBox.MoveTo(37+((selectedIndex&1)*int(bw)), 86+(int(bh)*(selectedIndex/2)))
v.d2HeroTitle.SetText(v.gameStates[v.selectedCharacter].HeroName)
}
func (v *CharacterSelect) Update(tickTime float64) {
if !v.showDeleteConfirmation {
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
if !v.mouseButtonPressed {
v.mouseButtonPressed = true
mx, my := ebiten.CursorPosition()
bw := 272
bh := 92
localMouseX := mx - 37
localMouseY := my - 86
if localMouseX > 0 && localMouseX < int(bw*2) && localMouseY >= 0 && localMouseY < int(bh*4) {
adjustY := localMouseY / int(bh)
selectedIndex := adjustY * 2
if localMouseX > int(bw) {
selectedIndex += 1
}
if (v.charScrollbar.GetCurrentOffset()*2)+selectedIndex < len(v.gameStates) {
v.selectedCharacter = (v.charScrollbar.GetCurrentOffset() * 2) + selectedIndex
v.moveSelectionBox()
}
}
}
} else {
v.mouseButtonPressed = false
}
}
}
func (v *CharacterSelect) onDeleteCharButtonClicked() {
v.toggleDeleteCharacterDialog(true)
}
func (v *CharacterSelect) onDeleteCharacterConfirmClicked() {
_ = os.Remove(v.gameStates[v.selectedCharacter].FilePath)
v.charScrollbar.SetCurrentOffset(0)
v.refreshGameStates()
v.toggleDeleteCharacterDialog(false)
v.deleteCharButton.SetEnabled(len(v.gameStates) > 0)
v.okButton.SetEnabled(len(v.gameStates) > 0)
}
func (v *CharacterSelect) onDeleteCharacterCancelClicked() {
v.toggleDeleteCharacterDialog(false)
}
func (v *CharacterSelect) toggleDeleteCharacterDialog(showDialog bool) {
v.showDeleteConfirmation = showDialog
v.okButton.SetEnabled(!showDialog)
v.deleteCharButton.SetEnabled(!showDialog)
v.exitButton.SetEnabled(!showDialog)
v.newCharButton.SetEnabled(!showDialog)
v.deleteCharOkButton.SetVisible(showDialog)
v.deleteCharCancelButton.SetVisible(showDialog)
}
func (v *CharacterSelect) refreshGameStates() {
v.gameStates = d2core.GetAllGameStates()
v.updateCharacterBoxes()
if len(v.gameStates) > 0 {
v.selectedCharacter = 0
v.d2HeroTitle.SetText(v.gameStates[0].HeroName)
v.charScrollbar.SetMaxOffset(int(math.Ceil(float64(len(v.gameStates)-8) / float64(2))))
} else {
v.selectedCharacter = -1
v.charScrollbar.SetMaxOffset(0)
}
v.moveSelectionBox()
}
func (v *CharacterSelect) onOkButtonClicked() {
v.sceneProvider.SetNextScene(CreateGame(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager, v.gameStates[v.selectedCharacter]))
}