Scene and GUI rework (#300)

This commit is contained in:
Alex Yatskov 2020-02-08 18:02:37 -08:00 committed by GitHub
parent b957661915
commit 5e958b9174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1308 additions and 1153 deletions

View File

@ -1,10 +1,18 @@
package d2mpq
// CryptoBuffer contains the crypto bytes for filename hashing
var CryptoBuffer [0x500]uint32
var cryptoBuffer [0x500]uint32
var cryptoBufferReady bool
// InitializeCryptoBuffer initializes the crypto buffer
func InitializeCryptoBuffer() {
func cryptoLookup(index uint32) uint32 {
if !cryptoBufferReady {
cryptoInitialize()
cryptoBufferReady = true
}
return cryptoBuffer[index]
}
func cryptoInitialize() {
seed := uint32(0x00100001)
for index1 := 0; index1 < 0x100; index1++ {
index2 := index1
@ -13,7 +21,7 @@ func InitializeCryptoBuffer() {
temp1 := (seed & 0xFFFF) << 0x10
seed = (seed*125 + 3) % 0x2AAAAB
temp2 := seed & 0xFFFF
CryptoBuffer[index2] = temp1 | temp2
cryptoBuffer[index2] = temp1 | temp2
index2 += 0x100
}
}

View File

@ -202,7 +202,7 @@ func decrypt(data []uint32, seed uint32) {
seed2 := uint32(0xeeeeeeee)
for i := 0; i < len(data); i++ {
seed2 += CryptoBuffer[0x400+(seed&0xff)]
seed2 += cryptoLookup(0x400 + (seed & 0xff))
result := data[i]
result ^= seed + seed2
@ -215,7 +215,7 @@ func decrypt(data []uint32, seed uint32) {
func decryptBytes(data []byte, seed uint32) {
seed2 := uint32(0xEEEEEEEE)
for i := 0; i < len(data)-3; i += 4 {
seed2 += CryptoBuffer[0x400+(seed&0xFF)]
seed2 += cryptoLookup(0x400 + (seed & 0xFF))
result := binary.LittleEndian.Uint32(data[i : i+4])
result ^= seed + seed2
seed = ((^seed << 21) + 0x11111111) | (seed >> 11)
@ -235,7 +235,7 @@ func hashString(key string, hashType uint32) uint32 {
/* prepare seeds. */
for _, char := range strings.ToUpper(key) {
seed1 = CryptoBuffer[(hashType*0x100)+uint32(char)] ^ (seed1 + seed2)
seed1 = cryptoLookup((hashType*0x100)+uint32(char)) ^ (seed1 + seed2)
seed2 = uint32(char) + seed1 + seed2 + (seed2 << 5) + 3
}
return seed1

View File

@ -38,37 +38,36 @@ func (eap *AudioProvider) PlayBGM(song string) {
_ = eap.bgmAudio.Pause()
return
}
go func() {
if eap.bgmAudio != nil {
err := eap.bgmAudio.Close()
if err != nil {
log.Panic(err)
}
}
audioData, err := d2asset.LoadFile(song)
if eap.bgmAudio != nil {
err := eap.bgmAudio.Close()
if err != nil {
panic(err)
log.Panic(err)
}
d, err := wav.Decode(eap.audioContext, audio.BytesReadSeekCloser(audioData))
if err != nil {
log.Fatal(err)
}
s := audio.NewInfiniteLoop(d, d.Length())
eap.bgmAudio, err = audio.NewPlayer(eap.audioContext, s)
if err != nil {
log.Fatal(err)
}
eap.bgmAudio.SetVolume(eap.bgmVolume)
// Play the infinite-length stream. This never ends.
err = eap.bgmAudio.Rewind()
if err != nil {
panic(err)
}
err = eap.bgmAudio.Play()
if err != nil {
panic(err)
}
}()
}
audioData, err := d2asset.LoadFile(song)
if err != nil {
panic(err)
}
d, err := wav.Decode(eap.audioContext, audio.BytesReadSeekCloser(audioData))
if err != nil {
log.Fatal(err)
}
s := audio.NewInfiniteLoop(d, d.Length())
eap.bgmAudio, err = audio.NewPlayer(eap.audioContext, s)
if err != nil {
log.Fatal(err)
}
eap.bgmAudio.SetVolume(eap.bgmVolume)
// Play the infinite-length stream. This never ends.
err = eap.bgmAudio.Rewind()
if err != nil {
panic(err)
}
err = eap.bgmAudio.Play()
if err != nil {
panic(err)
}
}
func (eap *AudioProvider) LoadSoundEffect(sfx string) (d2audio.SoundEffect, error) {

76
d2core/d2gui/d2gui.go Normal file
View File

@ -0,0 +1,76 @@
package d2gui
import (
"errors"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
var (
ErrWasInit = errors.New("gui system is already initialized")
ErrNotInit = errors.New("gui system is not initialized")
)
var singleton *guiManager
func Initialize() error {
assertNotInit()
var err error
if singleton, err = createGuiManager(); err != nil {
return err
}
return nil
}
func Shutdown() {
singleton = nil
}
func Render(target d2render.Surface) error {
assertWasInit()
return singleton.render(target)
}
func Advance(elapsed float64) error {
assertWasInit()
return singleton.advance(elapsed)
}
func Clear() {
assertWasInit()
singleton.clear()
}
func ShowLoadScreen(progress float64) {
assertWasInit()
singleton.showLoadScreen(progress)
}
func HideLoadScreen() {
assertWasInit()
singleton.hideLoadScreen()
}
func ShowCursor() {
assertWasInit()
singleton.showCursor()
}
func HideCursor() {
assertWasInit()
singleton.hideCursor()
}
func assertWasInit() {
if singleton == nil {
panic(ErrNotInit)
}
}
func assertNotInit() {
if singleton != nil {
panic(ErrWasInit)
}
}

125
d2core/d2gui/gui_manager.go Normal file
View File

@ -0,0 +1,125 @@
package d2gui
import (
"image/color"
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type guiWidget interface {
getLayer() int
render(target d2render.Surface) error
advance(elapsed float64) error
}
type guiManager struct {
cursorSprite *Sprite
loadSprite *Sprite
widgets []guiWidget
loading bool
}
func createGuiManager() (*guiManager, error) {
cursorSprite, err := CreateSprite(d2resource.CursorDefault, d2resource.PaletteUnits)
if err != nil {
return nil, err
}
loadSprite, err := CreateSprite(d2resource.LoadingScreen, d2resource.PaletteLoading)
if err != nil {
return nil, err
}
width, height := loadSprite.getSize()
loadSprite.SetPosition(400-width/2, 300+height/2)
manager := &guiManager{
cursorSprite: cursorSprite,
loadSprite: loadSprite,
}
if err := d2input.BindHandler(manager); err != nil {
return nil, err
}
return manager, nil
}
func (gui *guiManager) OnMouseMove(event d2input.MouseMoveEvent) bool {
gui.cursorSprite.SetPosition(event.X, event.Y)
return false
}
func (gui *guiManager) render(target d2render.Surface) error {
if gui.loading {
target.Clear(color.Black)
if err := gui.loadSprite.render(target); err != nil {
return err
}
} else {
for _, widget := range gui.widgets {
if err := widget.render(target); err != nil {
return err
}
}
}
if err := gui.cursorSprite.render(target); err != nil {
return err
}
return nil
}
func (gui *guiManager) advance(elapsed float64) error {
if gui.loading {
gui.loadSprite.Show()
if err := gui.loadSprite.advance(elapsed); err != nil {
return err
}
} else {
gui.loadSprite.Hide()
for _, widget := range gui.widgets {
if err := widget.advance(elapsed); err != nil {
return err
}
}
}
if err := gui.loadSprite.advance(elapsed); err != nil {
return err
}
return nil
}
func (gui *guiManager) showLoadScreen(progress float64) {
progress = math.Min(progress, 1.0)
progress = math.Max(progress, 0.0)
animation := gui.loadSprite.animation
frameCount := animation.GetFrameCount()
animation.SetCurrentFrame(int(float64(frameCount-1.0) * progress))
gui.loading = true
}
func (gui *guiManager) hideLoadScreen() {
gui.loading = false
}
func (gui *guiManager) showCursor() {
gui.cursorSprite.Show()
}
func (gui *guiManager) hideCursor() {
gui.cursorSprite.Hide()
}
func (gui *guiManager) clear() {
gui.widgets = nil
gui.hideLoadScreen()
}

104
d2core/d2gui/sprite.go Normal file
View File

@ -0,0 +1,104 @@
package d2gui
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type Sprite struct {
x int
y int
segmentsX int
segmentsY int
frameOffset int
visible bool
animation *d2asset.Animation
}
func CreateSprite(imagePath, palettePath string) (*Sprite, error) {
animation, err := d2asset.LoadAnimation(imagePath, palettePath)
if err != nil {
return nil, err
}
sprite := &Sprite{
animation: animation,
visible: true,
}
return sprite, nil
}
func (s *Sprite) SetSegmented(segmentsX, segmentsY, frameOffset int) {
s.segmentsX = segmentsX
s.segmentsY = segmentsY
s.frameOffset = frameOffset
}
func (s *Sprite) SetPosition(x, y int) {
s.x = x
s.y = y
}
func (s *Sprite) Show() {
s.visible = true
}
func (s *Sprite) Hide() {
s.visible = false
}
func (s *Sprite) getPosition() (int, int) {
return s.x, s.y
}
func (s *Sprite) getSize() (int, int) {
return s.animation.GetCurrentFrameSize()
}
func (s *Sprite) render(target d2render.Surface) error {
if !s.visible {
return nil
}
_, height := s.animation.GetCurrentFrameSize()
target.PushTranslation(s.x, s.y-height)
defer target.Pop()
if s.segmentsX == 0 && s.segmentsY == 0 {
return s.animation.Render(target)
}
var currentY int
for y := 0; y < s.segmentsY; y++ {
var currentX int
var maxHeight int
for x := 0; x < s.segmentsX; x++ {
if err := s.animation.SetCurrentFrame(x + y*s.segmentsX + s.frameOffset*s.segmentsX*s.segmentsY); err != nil {
return err
}
target.PushTranslation(s.x+currentX, s.y+currentY)
err := s.animation.Render(target)
target.Pop()
if err != nil {
return err
}
width, height := s.animation.GetCurrentFrameSize()
maxHeight = d2common.MaxInt(maxHeight, height)
currentX += width
}
currentY += maxHeight
}
return nil
}
func (s *Sprite) advance(elapsed float64) error {
return s.animation.Advance(elapsed)
}

View File

@ -0,0 +1,13 @@
package d2gui
import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type widget interface {
Render(target d2render.Surface) error
Advance(elapsed float64) error
}
type widgetManager struct {
}

View File

@ -1,107 +1,88 @@
package d2scene
import (
"math"
"runtime"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
// Scene defines the function necessary for scene management
type Scene interface {
Load() []func()
Unload()
Render(target d2render.Surface)
Advance(tickTime float64)
type Scene interface{}
type SceneLoadHandler interface {
OnLoad() error
}
var nextScene Scene // The next scene to be loaded at the end of the game loop
var currentScene Scene // The current scene being rendered
var loadingIndex int // Determines which load function is currently being called
var thingsToLoad []func() // The load functions for the next scene
var loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
var stepLoadingSize float64 // The size for each loading step
type SceneUnloadHandler interface {
OnUnload() error
}
type SceneRenderHandler interface {
Render(target d2render.Surface) error
}
type SceneAdvanceHandler interface {
Advance(elapsed float64) error
}
var singleton struct {
nextScene Scene
loadingScene Scene
currentScene Scene
}
// SetNextScene tells the engine what scene to load on the next update cycle
func SetNextScene(scene Scene) {
nextScene = scene
singleton.nextScene = scene
}
func GetCurrentScene() Scene {
return currentScene
}
// updateScene handles the scene maintenance for the engine
func UpdateScene() {
if nextScene == nil {
if thingsToLoad != nil {
if loadingIndex < len(thingsToLoad) {
thingsToLoad[loadingIndex]()
loadingIndex++
if loadingIndex < len(thingsToLoad) {
StepLoading()
} else {
FinishLoading()
thingsToLoad = nil
}
return
func Advance(elapsed float64) error {
if singleton.nextScene != nil {
if handler, ok := singleton.currentScene.(SceneUnloadHandler); ok {
if err := handler.OnUnload(); err != nil {
return err
}
}
d2ui.Reset()
d2gui.Clear()
if _, ok := singleton.nextScene.(SceneLoadHandler); ok {
d2gui.ShowLoadScreen(0)
d2gui.HideCursor()
singleton.currentScene = nil
singleton.loadingScene = singleton.nextScene
} else {
singleton.currentScene = singleton.nextScene
singleton.loadingScene = nil
}
singleton.nextScene = nil
} else if singleton.loadingScene != nil {
handler := singleton.loadingScene.(SceneLoadHandler)
if err := handler.OnLoad(); err != nil {
return err
}
singleton.currentScene = singleton.loadingScene
singleton.loadingScene = nil
d2gui.ShowCursor()
d2gui.HideLoadScreen()
} else if singleton.currentScene != nil {
if handler, ok := singleton.currentScene.(SceneAdvanceHandler); ok {
if err := handler.Advance(elapsed); err != nil {
return err
}
}
return
}
if currentScene != nil {
currentScene.Unload()
runtime.GC()
return nil
}
func Render(surface d2render.Surface) error {
if handler, ok := singleton.currentScene.(SceneRenderHandler); ok {
if err := handler.Render(surface); err != nil {
return err
}
}
currentScene = nextScene
nextScene = nil
d2ui.Reset()
thingsToLoad = currentScene.Load()
loadingIndex = 0
SetLoadingStepSize(1.0 / float64(len(thingsToLoad)))
ResetLoading()
}
func Advance(time float64) {
if currentScene == nil {
return
}
currentScene.Advance(time)
}
func Render(surface d2render.Surface) {
if currentScene == nil {
return
}
currentScene.Render(surface)
}
// SetLoadingStepSize sets the size of the loading step
func SetLoadingStepSize(size float64) {
stepLoadingSize = size
}
// ResetLoading resets the loading progress
func ResetLoading() {
loadingProgress = 0.0
}
// StepLoading increments the loading progress
func StepLoading() {
loadingProgress = math.Min(1.0, loadingProgress+stepLoadingSize)
}
// FinishLoading terminates the loading phase
func FinishLoading() {
loadingProgress = 1.0
}
// IsLoading returns true if the engine is currently in a loading state
func IsLoading() bool {
return loadingProgress < 1.0
}
func GetLoadingProgress() float64 {
return loadingProgress
return nil
}

View File

@ -18,7 +18,6 @@ const (
)
var widgets []Widget
var cursorSprite *Sprite
var cursorButtons CursorButton
var pressedIndex int
var CursorX int
@ -26,8 +25,7 @@ var CursorY int
var clickSfx d2audio.SoundEffect
var waitForLeftMouseUp bool
func Initialize(curSprite *Sprite) {
cursorSprite = curSprite
func Initialize() {
pressedIndex = -1
clickSfx, _ = d2audio.LoadSoundEffect(d2resource.SFXButtonClick)
waitForLeftMouseUp = false
@ -56,10 +54,6 @@ func Render(target d2render.Surface) {
widget.Render(target)
}
}
cx, cy := ebiten.CursorPosition()
cursorSprite.SetPosition(cx, cy)
cursorSprite.Render(target)
}
// Update updates all of the UI elements
@ -142,7 +136,3 @@ func CursorButtonPressed(button CursorButton) bool {
func KeyPressed(key ebiten.Key) bool {
return ebiten.IsKeyPressed(key)
}
func GetCursorSprite() *Sprite {
return cursorSprite
}

View File

@ -1,153 +0,0 @@
package d2game
import (
"log"
"runtime"
"strconv"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
var singleton struct {
loadingSprite *d2ui.Sprite // The sprite shown when loading stuff
lastTime float64 // Last time we updated the scene
showFPS bool
timeScale float64
}
func Initialize(loadingSpr *d2ui.Sprite) error {
singleton.loadingSprite = loadingSpr
singleton.timeScale = 1.0
singleton.lastTime = d2common.Now()
d2term.BindAction("fullscreen", "toggles fullscreen", func() {
fullscreen, err := d2render.IsFullScreen()
if err == nil {
fullscreen = !fullscreen
d2render.SetFullScreen(fullscreen)
d2term.OutputInfo("fullscreen is now: %v", fullscreen)
} else {
d2term.OutputError(err.Error())
}
})
d2term.BindAction("vsync", "toggles vsync", func() {
vsync, err := d2render.GetVSyncEnabled()
if err == nil {
vsync = !vsync
d2render.SetVSyncEnabled(vsync)
d2term.OutputInfo("vsync is now: %v", vsync)
} else {
d2term.OutputError(err.Error())
}
})
d2term.BindAction("fps", "toggle fps counter", func() {
singleton.showFPS = !singleton.showFPS
d2term.OutputInfo("fps counter is now: %v", singleton.showFPS)
})
d2term.BindAction("timescale", "set scalar for elapsed time", func(timeScale float64) {
if timeScale <= 0 {
d2term.OutputError("invalid time scale value")
} else {
singleton.timeScale = timeScale
d2term.OutputInfo("timescale changed from %f to %f", singleton.timeScale, timeScale)
}
})
return nil
}
func Run(gitBranch string) error {
if err := d2render.Run(update, 800, 600, "OpenDiablo 2 ("+gitBranch+")"); err != nil {
log.Fatal(err)
}
return nil
}
// Advance updates the internal state of the engine
func Advance() {
d2scene.UpdateScene()
if d2scene.GetCurrentScene() == nil {
log.Fatal("no scene loaded")
}
if d2scene.IsLoading() {
return
}
currentTime := d2common.Now()
deltaTime := (currentTime - singleton.lastTime) * singleton.timeScale
singleton.lastTime = currentTime
d2scene.Advance(deltaTime)
d2ui.Advance(deltaTime)
d2term.Advance(deltaTime)
d2input.Advance(deltaTime)
}
// Draw draws the game
func render(target d2render.Surface) {
if d2scene.GetLoadingProgress() < 1.0 {
singleton.loadingSprite.SetCurrentFrame(
int(d2common.Max(0, d2common.Min(
uint32(singleton.loadingSprite.GetFrameCount()-1),
uint32(float64(singleton.loadingSprite.GetFrameCount()-1)*d2scene.GetLoadingProgress()),
))),
)
singleton.loadingSprite.Render(target)
} else {
if d2scene.GetCurrentScene() == nil {
log.Fatal("no scene loaded")
}
d2scene.Render(target)
d2ui.Render(target)
}
if singleton.showFPS {
target.PushTranslation(5, 565)
vsyncEnabled, _ := d2render.GetVSyncEnabled()
fps, _ := d2render.CurrentFPS()
target.DrawText("vsync:" + strconv.FormatBool(vsyncEnabled) + "\nFPS:" + strconv.Itoa(int(fps)))
target.Pop()
cx, cy, _ := d2render.GetCursorPos()
var m runtime.MemStats
runtime.ReadMemStats(&m)
target.PushTranslation(680, 0)
target.DrawText("Alloc " + strconv.FormatInt(int64(m.Alloc)/1024/1024, 10))
target.PushTranslation(0, 16)
target.DrawText("Pause " + strconv.FormatInt(int64(m.PauseTotalNs/1024/1024), 10))
target.PushTranslation(0, 16)
target.DrawText("HeapSys " + strconv.FormatInt(int64(m.HeapSys/1024/1024), 10))
target.PushTranslation(0, 16)
target.DrawText("NumGC " + strconv.FormatInt(int64(m.NumGC), 10))
target.PushTranslation(0, 16)
target.DrawText("Coords " + strconv.FormatInt(int64(cx), 10) + "," + strconv.FormatInt(int64(cy), 10))
target.PopN(5)
}
d2term.Render(target)
}
func update(screen d2render.Surface) error {
Advance()
err, drawingSkipped := d2render.IsDrawingSkipped()
if err != nil {
return err
}
if !drawingSkipped {
_, surface := d2render.CreateSurface(screen)
render(surface)
if surface.GetDepth() > 0 {
panic("detected surface stack leak")
}
}
return nil
}

View File

@ -3,7 +3,6 @@ package d2gamescene
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2video"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/hajimehoshi/ebiten"
)
type BlizzardIntro struct {
@ -11,31 +10,15 @@ type BlizzardIntro struct {
}
func CreateBlizzardIntro() *BlizzardIntro {
result := &BlizzardIntro{}
return result
return &BlizzardIntro{}
}
func (v *BlizzardIntro) Load() []func() {
return []func(){
func() {
videoBytes, err := d2asset.LoadFile("/data/local/video/BlizNorth640x480.bik")
if err != nil {
panic(err)
}
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
},
func (v *BlizzardIntro) OnLoad() error {
videoBytes, err := d2asset.LoadFile("/data/local/video/BlizNorth640x480.bik")
if err != nil {
return err
}
}
func (v *BlizzardIntro) Unload() {
}
func (v *BlizzardIntro) Render(screen *ebiten.Image) {
}
func (v *BlizzardIntro) Update(tickTime float64) {
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
return nil
}

View File

@ -47,109 +47,92 @@ type CharacterSelect struct {
}
func CreateCharacterSelect() *CharacterSelect {
result := &CharacterSelect{
selectedCharacter: -1,
}
return result
return &CharacterSelect{selectedCharacter: -1}
}
func (v *CharacterSelect) Load() []func() {
func (v *CharacterSelect) OnLoad() error {
d2audio.PlayBGM(d2resource.BGMTitle)
return []func(){
func() {
animation, _ := d2asset.LoadAnimation(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
v.background, _ = d2ui.LoadSprite(animation)
v.background.SetPosition(0, 0)
},
func() {
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, d2common.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
v.newCharButton.SetPosition(33, 468)
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
d2ui.AddWidget(&v.newCharButton)
},
func() {
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, d2common.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
v.convertCharButton.SetPosition(233, 468)
v.convertCharButton.SetEnabled(false)
d2ui.AddWidget(&v.convertCharButton)
},
func() {
v.deleteCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, d2common.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15)))
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
v.deleteCharButton.SetPosition(433, 468)
d2ui.AddWidget(&v.deleteCharButton)
},
func() {
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
v.exitButton.SetPosition(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
},
func() {
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4231"))
v.deleteCharCancelButton.SetPosition(282, 308)
v.deleteCharCancelButton.SetVisible(false)
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
d2ui.AddWidget(&v.deleteCharCancelButton)
},
func() {
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4227"))
v.deleteCharOkButton.SetPosition(422, 308)
v.deleteCharOkButton.SetVisible(false)
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
d2ui.AddWidget(&v.deleteCharOkButton)
},
func() {
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
v.okButton.SetPosition(625, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
d2ui.AddWidget(&v.okButton)
},
func() {
v.d2HeroTitle = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.d2HeroTitle.SetPosition(320, 23)
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
},
func() {
v.deleteCharConfirmLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
lines := dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#1878"), 29)
v.deleteCharConfirmLabel.SetText(strings.Join(lines, "\n"))
v.deleteCharConfirmLabel.Alignment = d2ui.LabelAlignCenter
v.deleteCharConfirmLabel.SetPosition(400, 185)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
v.selectionBox, _ = d2ui.LoadSprite(animation)
v.selectionBox.SetPosition(37, 86)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
v.okCancelBox, _ = d2ui.LoadSprite(animation)
v.okCancelBox.SetPosition(270, 175)
},
func() {
v.charScrollbar = d2ui.CreateScrollbar(586, 87, 369)
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
d2ui.AddWidget(&v.charScrollbar)
},
func() {
for i := 0; i < 8; i++ {
xOffset := 115
if i&1 > 0 {
xOffset = 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.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
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.refreshGameStates()
},
animation, _ := d2asset.LoadAnimation(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
v.background, _ = d2ui.LoadSprite(animation)
v.background.SetPosition(0, 0)
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, d2common.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
v.newCharButton.SetPosition(33, 468)
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
d2ui.AddWidget(&v.newCharButton)
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, d2common.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
v.convertCharButton.SetPosition(233, 468)
v.convertCharButton.SetEnabled(false)
d2ui.AddWidget(&v.convertCharButton)
v.deleteCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, d2common.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15)))
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
v.deleteCharButton.SetPosition(433, 468)
d2ui.AddWidget(&v.deleteCharButton)
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
v.exitButton.SetPosition(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4231"))
v.deleteCharCancelButton.SetPosition(282, 308)
v.deleteCharCancelButton.SetVisible(false)
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
d2ui.AddWidget(&v.deleteCharCancelButton)
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4227"))
v.deleteCharOkButton.SetPosition(422, 308)
v.deleteCharOkButton.SetVisible(false)
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
d2ui.AddWidget(&v.deleteCharOkButton)
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
v.okButton.SetPosition(625, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
d2ui.AddWidget(&v.okButton)
v.d2HeroTitle = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.d2HeroTitle.SetPosition(320, 23)
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
v.deleteCharConfirmLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
lines := dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#1878"), 29)
v.deleteCharConfirmLabel.SetText(strings.Join(lines, "\n"))
v.deleteCharConfirmLabel.Alignment = d2ui.LabelAlignCenter
v.deleteCharConfirmLabel.SetPosition(400, 185)
animation, _ = d2asset.LoadAnimation(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
v.selectionBox, _ = d2ui.LoadSprite(animation)
v.selectionBox.SetPosition(37, 86)
animation, _ = d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
v.okCancelBox, _ = d2ui.LoadSprite(animation)
v.okCancelBox.SetPosition(270, 175)
v.charScrollbar = d2ui.CreateScrollbar(586, 87, 369)
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
d2ui.AddWidget(&v.charScrollbar)
for i := 0; i < 8; i++ {
xOffset := 115
if i&1 > 0 {
xOffset = 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.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
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.refreshGameStates()
return nil
}
func (v *CharacterSelect) onScrollUpdate() {
@ -192,10 +175,7 @@ func (v *CharacterSelect) onExitButtonClicked() {
d2scene.SetNextScene(mainMenu)
}
func (v *CharacterSelect) Unload() {
}
func (v *CharacterSelect) Render(screen d2render.Surface) {
func (v *CharacterSelect) Render(screen d2render.Surface) error {
v.background.RenderSegmented(screen, 4, 3, 0)
v.d2HeroTitle.Render(screen)
actualSelectionIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
@ -219,6 +199,8 @@ func (v *CharacterSelect) Render(screen d2render.Surface) {
v.okCancelBox.RenderSegmented(screen, 2, 1, 0)
v.deleteCharConfirmLabel.Render(screen)
}
return nil
}
func (v *CharacterSelect) moveSelectionBox() {
@ -233,7 +215,7 @@ func (v *CharacterSelect) moveSelectionBox() {
v.d2HeroTitle.SetText(v.gameStates[v.selectedCharacter].HeroName)
}
func (v *CharacterSelect) Advance(tickTime float64) {
func (v *CharacterSelect) Advance(tickTime float64) error {
if !v.showDeleteConfirmation {
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
if !v.mouseButtonPressed {
@ -264,6 +246,8 @@ func (v *CharacterSelect) Advance(tickTime float64) {
hero.AnimatedEntity.Advance(tickTime)
}
}
return nil
}
func (v *CharacterSelect) onDeleteCharButtonClicked() {

View File

@ -8,16 +8,13 @@ import (
"path"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
dh "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
dh "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -56,7 +53,7 @@ func (v *Credits) LoadContributors() []string {
file, err := os.Open(path.Join("./", "CONTRIBUTORS"))
if err != nil || file == nil {
log.Print("CONTRIBUTORS file is missing")
return []string{ "MISSING CONTRIBUTOR FILES!" }
return []string{"MISSING CONTRIBUTOR FILES!"}
}
defer file.Close()
@ -68,41 +65,31 @@ func (v *Credits) LoadContributors() []string {
}
// Load is called to load the resources for the credits scene
func (v *Credits) Load() []func() {
return []func(){
func() {
animation, _ := d2asset.LoadAnimation(d2resource.CreditsBackground, d2resource.PaletteSky)
v.creditsBackground, _ = d2ui.LoadSprite(animation)
v.creditsBackground.SetPosition(0, 0)
},
func() {
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
v.exitButton.SetPosition(33, 543)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
},
func() {
fileData, err := d2asset.LoadFile(d2resource.CreditsText)
if err != nil {
panic(err)
}
creditData, _ := dh.Utf16BytesToString(fileData[2:])
v.creditsText = strings.Split(creditData, "\r\n")
for i := range v.creditsText {
v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
}
v.creditsText = append(v.LoadContributors(), v.creditsText...)
},
func (v *Credits) OnLoad() error {
animation, _ := d2asset.LoadAnimation(d2resource.CreditsBackground, d2resource.PaletteSky)
v.creditsBackground, _ = d2ui.LoadSprite(animation)
v.creditsBackground.SetPosition(0, 0)
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
v.exitButton.SetPosition(33, 543)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
fileData, err := d2asset.LoadFile(d2resource.CreditsText)
if err != nil {
return err
}
}
// Unload unloads the data for the credits scene
func (v *Credits) Unload() {
creditData, _ := dh.Utf16BytesToString(fileData[2:])
v.creditsText = strings.Split(creditData, "\r\n")
for i := range v.creditsText {
v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
}
v.creditsText = append(v.LoadContributors(), v.creditsText...)
return nil
}
// Render renders the credits scene
func (v *Credits) Render(screen d2render.Surface) {
func (v *Credits) Render(screen d2render.Surface) error {
v.creditsBackground.RenderSegmented(screen, 4, 3, 0)
for _, label := range v.labels {
if label.Available {
@ -110,12 +97,14 @@ func (v *Credits) Render(screen d2render.Surface) {
}
label.Label.Render(screen)
}
return nil
}
const secondsPerCycle = float64(0.02)
// Update runs the update logic on the credits scene
func (v *Credits) Advance(tickTime float64) {
func (v *Credits) Advance(tickTime float64) error {
v.cycleTime += tickTime
for v.cycleTime >= secondsPerCycle {
v.cycleTime -= secondsPerCycle
@ -135,6 +124,8 @@ func (v *Credits) Advance(tickTime float64) {
label.Label.Y--
}
}
return nil
}
func (v *Credits) onExitButtonClicked() {

View File

@ -12,7 +12,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
)
@ -26,72 +25,64 @@ type Game struct {
gameControls *d2player.GameControls
}
func CreateGame(
gameState *d2gamestate.GameState,
) *Game {
result := &Game{
gameState: gameState,
}
return result
func CreateGame(gameState *d2gamestate.GameState) *Game {
return &Game{gameState: gameState}
}
func (v *Game) Load() []func() {
return []func(){
func() {
animation, _ := d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
v.pentSpinLeft, _ = d2ui.LoadSprite(animation)
v.pentSpinLeft.PlayBackward()
v.pentSpinLeft.SetPlayLengthMs(475)
v.pentSpinLeft.SetPosition(100, 300)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
v.pentSpinRight, _ = d2ui.LoadSprite(animation)
v.pentSpinRight.PlayForward()
v.pentSpinRight.SetPlayLengthMs(475)
v.pentSpinRight.SetPosition(650, 300)
},
func() {
v.testLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.testLabel.Alignment = d2ui.LabelAlignCenter
v.testLabel.SetText("Soon :tm:")
v.testLabel.SetPosition(400, 250)
},
func() {
v.mapEngine = d2map.CreateMapEngine(v.gameState)
v.mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0)
func (v *Game) OnLoad() error {
animation, _ := d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
v.pentSpinLeft, _ = d2ui.LoadSprite(animation)
v.pentSpinLeft.PlayBackward()
v.pentSpinLeft.SetPlayLengthMs(475)
v.pentSpinLeft.SetPosition(100, 300)
startX, startY := v.mapEngine.GetStartPosition()
v.hero = d2map.CreateHero(
int32(startX*5)+3,
int32(startY*5)+3,
0,
v.gameState.HeroType,
v.gameState.Equipment,
)
v.mapEngine.AddEntity(v.hero)
},
func() {
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
v.gameControls.Load()
d2input.BindHandler(v.gameControls)
},
}
animation, _ = d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
v.pentSpinRight, _ = d2ui.LoadSprite(animation)
v.pentSpinRight.PlayForward()
v.pentSpinRight.SetPlayLengthMs(475)
v.pentSpinRight.SetPosition(650, 300)
v.testLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.testLabel.Alignment = d2ui.LabelAlignCenter
v.testLabel.SetText("Soon :tm:")
v.testLabel.SetPosition(400, 250)
v.mapEngine = d2map.CreateMapEngine(v.gameState)
v.mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0)
startX, startY := v.mapEngine.GetStartPosition()
v.hero = d2map.CreateHero(
int32(startX*5)+3,
int32(startY*5)+3,
0,
v.gameState.HeroType,
v.gameState.Equipment,
)
v.mapEngine.AddEntity(v.hero)
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
v.gameControls.Load()
d2input.BindHandler(v.gameControls)
return nil
}
func (v *Game) Unload() {
func (v *Game) OnUnload() error {
d2input.UnbindHandler(v.gameControls)
return nil
}
func (v Game) Render(screen d2render.Surface) {
func (v *Game) Render(screen d2render.Surface) error {
screen.Clear(color.Black)
v.mapEngine.Render(screen)
v.gameControls.Render(screen)
return nil
}
func (v *Game) Advance(tickTime float64) {
func (v *Game) Advance(tickTime float64) error {
v.mapEngine.Advance(tickTime)
rx, ry := v.mapEngine.WorldToOrtho(v.hero.AnimatedEntity.LocationX/5, v.hero.AnimatedEntity.LocationY/5)
v.mapEngine.MoveCameraTo(rx, ry)
return nil
}

View File

@ -8,18 +8,14 @@ import (
"os/exec"
"runtime"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -49,128 +45,110 @@ type MainMenu struct {
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu() *MainMenu {
result := &MainMenu{
return &MainMenu{
ShowTrademarkScreen: true,
leftButtonHeld: true,
}
return result
}
// Load is called to load the resources for the main menu
func (v *MainMenu) Load() []func() {
func (v *MainMenu) OnLoad() error {
d2audio.PlayBGM(d2resource.BGMTitle)
return []func(){
func() {
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.versionLabel.Alignment = d2ui.LabelAlignRight
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)
},
func() {
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.commitLabel.Alignment = d2ui.LabelAlignLeft
v.commitLabel.SetText(d2common.BuildInfo.Commit)
v.commitLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.commitLabel.SetPosition(2, 2)
},
func() {
v.copyrightLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel.Alignment = d2ui.LabelAlignCenter
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)
},
func() {
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2.Alignment = d2ui.LabelAlignCenter
v.copyrightLabel2.SetText(d2common.TranslateString("#1614"))
v.copyrightLabel2.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel2.SetPosition(400, 525)
},
func() {
v.openDiabloLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.openDiabloLabel.Alignment = d2ui.LabelAlignCenter
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)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.GameSelectScreen, d2resource.PaletteSky)
v.background, _ = d2ui.LoadSprite(animation)
v.background.SetPosition(0, 0)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.TrademarkScreen, d2resource.PaletteSky)
v.trademarkBackground, _ = d2ui.LoadSprite(animation)
v.trademarkBackground.SetPosition(0, 0)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
v.diabloLogoLeft, _ = d2ui.LoadSprite(animation)
v.diabloLogoLeft.SetBlend(true)
v.diabloLogoLeft.PlayForward()
v.diabloLogoLeft.SetPosition(400, 120)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
v.diabloLogoRight, _ = d2ui.LoadSprite(animation)
v.diabloLogoRight.SetBlend(true)
v.diabloLogoRight.PlayForward()
v.diabloLogoRight.SetPosition(400, 120)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
v.diabloLogoLeftBack, _ = d2ui.LoadSprite(animation)
v.diabloLogoLeftBack.SetPosition(400, 120)
},
func() {
animation, _ := d2asset.LoadAnimation(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
v.diabloLogoRightBack, _ = d2ui.LoadSprite(animation)
v.diabloLogoRightBack.SetPosition(400, 120)
},
func() {
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1625"))
v.exitDiabloButton.SetPosition(264, 535)
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitDiabloButton)
},
func() {
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1627"))
v.creditsButton.SetPosition(264, 505)
v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
d2ui.AddWidget(&v.creditsButton)
},
func() {
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1639"))
v.cinematicsButton.SetPosition(401, 505)
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
d2ui.AddWidget(&v.cinematicsButton)
},
func() {
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1620"))
v.singlePlayerButton.SetPosition(264, 290)
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
d2ui.AddWidget(&v.singlePlayerButton)
},
func() {
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
v.githubButton.SetPosition(264, 330)
v.githubButton.SetVisible(!v.ShowTrademarkScreen)
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
d2ui.AddWidget(&v.githubButton)
},
func() {
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
v.mapTestButton.SetPosition(264, 450)
v.mapTestButton.SetVisible(!v.ShowTrademarkScreen)
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
d2ui.AddWidget(&v.mapTestButton)
},
}
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.versionLabel.Alignment = d2ui.LabelAlignRight
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.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.commitLabel.Alignment = d2ui.LabelAlignLeft
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.copyrightLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel.Alignment = d2ui.LabelAlignCenter
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)
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2.Alignment = d2ui.LabelAlignCenter
v.copyrightLabel2.SetText(d2common.TranslateString("#1614"))
v.copyrightLabel2.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel2.SetPosition(400, 525)
v.openDiabloLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.openDiabloLabel.Alignment = d2ui.LabelAlignCenter
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)
animation, _ := d2asset.LoadAnimation(d2resource.GameSelectScreen, d2resource.PaletteSky)
v.background, _ = d2ui.LoadSprite(animation)
v.background.SetPosition(0, 0)
animation, _ = d2asset.LoadAnimation(d2resource.TrademarkScreen, d2resource.PaletteSky)
v.trademarkBackground, _ = d2ui.LoadSprite(animation)
v.trademarkBackground.SetPosition(0, 0)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
v.diabloLogoLeft, _ = d2ui.LoadSprite(animation)
v.diabloLogoLeft.SetBlend(true)
v.diabloLogoLeft.PlayForward()
v.diabloLogoLeft.SetPosition(400, 120)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
v.diabloLogoRight, _ = d2ui.LoadSprite(animation)
v.diabloLogoRight.SetBlend(true)
v.diabloLogoRight.PlayForward()
v.diabloLogoRight.SetPosition(400, 120)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
v.diabloLogoLeftBack, _ = d2ui.LoadSprite(animation)
v.diabloLogoLeftBack.SetPosition(400, 120)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
v.diabloLogoRightBack, _ = d2ui.LoadSprite(animation)
v.diabloLogoRightBack.SetPosition(400, 120)
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1625"))
v.exitDiabloButton.SetPosition(264, 535)
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitDiabloButton)
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1627"))
v.creditsButton.SetPosition(264, 505)
v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
d2ui.AddWidget(&v.creditsButton)
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1639"))
v.cinematicsButton.SetPosition(401, 505)
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
d2ui.AddWidget(&v.cinematicsButton)
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1620"))
v.singlePlayerButton.SetPosition(264, 290)
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
d2ui.AddWidget(&v.singlePlayerButton)
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
v.githubButton.SetPosition(264, 330)
v.githubButton.SetVisible(!v.ShowTrademarkScreen)
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
d2ui.AddWidget(&v.githubButton)
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
v.mapTestButton.SetPosition(264, 450)
v.mapTestButton.SetVisible(!v.ShowTrademarkScreen)
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
d2ui.AddWidget(&v.mapTestButton)
return nil
}
func (v *MainMenu) onMapTestClicked() {
@ -217,13 +195,8 @@ func (v *MainMenu) onCreditsButtonClicked() {
d2scene.SetNextScene(CreateCredits())
}
// Unload unloads the data for the main menu
func (v *MainMenu) Unload() {
}
// Render renders the main menu
func (v *MainMenu) Render(screen d2render.Surface) {
func (v *MainMenu) Render(screen d2render.Surface) error {
if v.ShowTrademarkScreen {
v.trademarkBackground.RenderSegmented(screen, 4, 3, 0)
} else {
@ -242,10 +215,12 @@ func (v *MainMenu) Render(screen d2render.Surface) {
v.versionLabel.Render(screen)
v.commitLabel.Render(screen)
}
return nil
}
// Update runs the update logic on the main menu
func (v *MainMenu) Advance(tickTime float64) {
func (v *MainMenu) Advance(tickTime float64) error {
v.diabloLogoLeftBack.Advance(tickTime)
v.diabloLogoRightBack.Advance(tickTime)
v.diabloLogoLeft.Advance(tickTime)
@ -254,7 +229,7 @@ func (v *MainMenu) Advance(tickTime float64) {
if v.ShowTrademarkScreen {
if d2ui.CursorButtonPressed(d2ui.CursorButtonLeft) {
if v.leftButtonHeld {
return
return nil
}
d2ui.WaitForMouseRelease()
v.leftButtonHeld = true
@ -268,6 +243,7 @@ func (v *MainMenu) Advance(tickTime float64) {
} else {
v.leftButtonHeld = false
}
return
}
return nil
}

View File

@ -4,20 +4,14 @@ import (
"math"
"os"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
)
type RegionSpec struct {
@ -140,23 +134,22 @@ func (met *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
met.mapEngine.MoveCameraTo(met.mapEngine.WorldToOrtho(met.mapEngine.GetCenterPosition()))
}
func (met *MapEngineTest) Load() []func() {
func (met *MapEngineTest) OnLoad() error {
// TODO: Game seed comes from the game state object
d2input.BindHandler(met)
d2audio.PlayBGM("")
return []func(){
func() {
met.mapEngine = d2map.CreateMapEngine(met.gameState)
met.LoadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)
},
}
met.mapEngine = d2map.CreateMapEngine(met.gameState)
met.LoadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)
return nil
}
func (met *MapEngineTest) Unload() {
func (met *MapEngineTest) OnUnload() error {
d2input.UnbindHandler(met)
return nil
}
func (met *MapEngineTest) Render(screen d2render.Surface) {
func (met *MapEngineTest) Render(screen d2render.Surface) error {
met.mapEngine.Render(screen)
screenX, screenY, _ := d2render.GetCursorPos()
@ -166,7 +159,7 @@ func (met *MapEngineTest) Render(screen d2render.Surface) {
curRegion := met.mapEngine.GetRegionAtTile(int(worldX), int(worldY))
if curRegion == nil {
return
return nil
}
tileRect := curRegion.GetTileRect()
@ -268,10 +261,13 @@ func (met *MapEngineTest) Render(screen d2render.Surface) {
}
screen.PopN(popN)
}
return nil
}
func (met *MapEngineTest) Advance(tickTime float64) {
func (met *MapEngineTest) Advance(tickTime float64) error {
met.mapEngine.Advance(tickTime)
return nil
}
func (met *MapEngineTest) OnKeyRepeat(event d2input.KeyEvent) bool {

View File

@ -4,21 +4,16 @@ import (
"image"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
dh "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
dh "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -76,370 +71,349 @@ func CreateSelectHeroClass() *SelectHeroClass {
return result
}
func (v *SelectHeroClass) Load() []func() {
func (v *SelectHeroClass) OnLoad() error {
d2audio.PlayBGM(d2resource.BGMTitle)
return []func(){
func() {
v.bgImage = loadSprite(d2resource.CharacterSelectBackground, d2resource.PaletteFechar)
v.bgImage.SetPosition(0, 0)
},
func() {
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
fontWidth, _ := v.headingLabel.GetSize()
v.headingLabel.SetPosition(400-fontWidth/2, 17)
v.headingLabel.SetText("Select Hero Class")
v.headingLabel.Alignment = d2ui.LabelAlignCenter
},
func() {
v.heroClassLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
v.heroClassLabel.Alignment = d2ui.LabelAlignCenter
v.heroClassLabel.SetPosition(400, 65)
},
func() {
v.heroDesc1Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc1Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc1Label.SetPosition(400, 100)
},
func() {
v.heroDesc2Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc2Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc2Label.SetPosition(400, 115)
},
func() {
v.heroDesc3Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc3Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc3Label.SetPosition(400, 130)
},
func() {
v.campfire = loadSprite(d2resource.CharacterSelectCampfire, d2resource.PaletteFechar)
v.campfire.SetPosition(380, 335)
v.campfire.PlayForward()
v.campfire.SetBlend(true)
},
func() {
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
v.exitButton.SetPosition(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
},
func() {
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
v.okButton.SetPosition(630, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
v.okButton.SetVisible(false)
v.okButton.SetEnabled(false)
d2ui.AddWidget(&v.okButton)
},
func() {
v.heroNameLabel = d2ui.CreateLabel(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(d2common.TranslateString("#1694"))
v.heroNameLabel.SetPosition(321, 475)
},
func() {
v.heroNameTextbox = d2ui.CreateTextbox()
v.heroNameTextbox.SetPosition(318, 493)
v.heroNameTextbox.SetVisible(false)
d2ui.AddWidget(&v.heroNameTextbox)
},
func() {
v.expansionCheckbox = d2ui.CreateCheckbox(true)
v.expansionCheckbox.SetPosition(318, 526)
v.expansionCheckbox.SetVisible(false)
d2ui.AddWidget(&v.expansionCheckbox)
},
func() {
v.expansionCharLabel = d2ui.CreateLabel(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(d2common.TranslateString("#803"))
v.expansionCharLabel.SetPosition(339, 526)
},
func() {
v.hardcoreCheckbox = d2ui.CreateCheckbox(false)
v.hardcoreCheckbox.SetPosition(318, 548)
v.hardcoreCheckbox.SetVisible(false)
d2ui.AddWidget(&v.hardcoreCheckbox)
},
func() {
v.hardcoreCharLabel = d2ui.CreateLabel(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(d2common.TranslateString("#1696"))
v.hardcoreCharLabel.SetPosition(339, 548)
},
func() {
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}},
loadSoundEffect(d2resource.SFXBarbarianSelect),
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)
},
func() {
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}},
loadSoundEffect(d2resource.SFXSorceressSelect),
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)
},
func() {
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}},
loadSoundEffect(d2resource.SFXNecromancerSelect),
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)
},
func() {
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}},
loadSoundEffect(d2resource.SFXPaladinSelect),
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)
},
func() {
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}},
loadSoundEffect(d2resource.SFXAmazonSelect),
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)
},
func() {
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}},
loadSoundEffect(d2resource.SFXAssassinSelect),
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)
},
func() {
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}},
loadSoundEffect(d2resource.SFXDruidSelect),
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)
},
v.bgImage = loadSprite(d2resource.CharacterSelectBackground, d2resource.PaletteFechar)
v.bgImage.SetPosition(0, 0)
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
fontWidth, _ := v.headingLabel.GetSize()
v.headingLabel.SetPosition(400-fontWidth/2, 17)
v.headingLabel.SetText("Select Hero Class")
v.headingLabel.Alignment = d2ui.LabelAlignCenter
v.heroClassLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
v.heroClassLabel.Alignment = d2ui.LabelAlignCenter
v.heroClassLabel.SetPosition(400, 65)
v.heroDesc1Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc1Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc1Label.SetPosition(400, 100)
v.heroDesc2Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc2Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc2Label.SetPosition(400, 115)
v.heroDesc3Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
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.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
v.exitButton.SetPosition(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
v.okButton.SetPosition(630, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
v.okButton.SetVisible(false)
v.okButton.SetEnabled(false)
d2ui.AddWidget(&v.okButton)
v.heroNameLabel = d2ui.CreateLabel(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(d2common.TranslateString("#1694"))
v.heroNameLabel.SetPosition(321, 475)
v.heroNameTextbox = d2ui.CreateTextbox()
v.heroNameTextbox.SetPosition(318, 493)
v.heroNameTextbox.SetVisible(false)
d2ui.AddWidget(&v.heroNameTextbox)
v.expansionCheckbox = d2ui.CreateCheckbox(true)
v.expansionCheckbox.SetPosition(318, 526)
v.expansionCheckbox.SetVisible(false)
d2ui.AddWidget(&v.expansionCheckbox)
v.expansionCharLabel = d2ui.CreateLabel(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(d2common.TranslateString("#803"))
v.expansionCharLabel.SetPosition(339, 526)
v.hardcoreCheckbox = d2ui.CreateCheckbox(false)
v.hardcoreCheckbox.SetPosition(318, 548)
v.hardcoreCheckbox.SetVisible(false)
d2ui.AddWidget(&v.hardcoreCheckbox)
v.hardcoreCharLabel = d2ui.CreateLabel(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(d2common.TranslateString("#1696"))
v.hardcoreCharLabel.SetPosition(339, 548)
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}},
loadSoundEffect(d2resource.SFXBarbarianSelect),
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}},
loadSoundEffect(d2resource.SFXSorceressSelect),
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)
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}},
loadSoundEffect(d2resource.SFXNecromancerSelect),
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}},
loadSoundEffect(d2resource.SFXPaladinSelect),
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)
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}},
loadSoundEffect(d2resource.SFXAmazonSelect),
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}},
loadSoundEffect(d2resource.SFXAssassinSelect),
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)
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}},
loadSoundEffect(d2resource.SFXDruidSelect),
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)
return nil
}
func (v *SelectHeroClass) Unload() {
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
}
func (v SelectHeroClass) onExitButtonClicked() {
@ -451,7 +425,7 @@ func (v SelectHeroClass) onOkButtonClicked() {
d2scene.SetNextScene(CreateGame(gameState))
}
func (v *SelectHeroClass) Render(screen d2render.Surface) {
func (v *SelectHeroClass) Render(screen d2render.Surface) error {
v.bgImage.RenderSegmented(screen, 4, 3, 0)
v.headingLabel.Render(screen)
if v.selectedHero != d2enum.HeroNone {
@ -476,9 +450,11 @@ func (v *SelectHeroClass) Render(screen d2render.Surface) {
v.expansionCharLabel.Render(screen)
v.hardcoreCharLabel.Render(screen)
}
return nil
}
func (v *SelectHeroClass) Advance(tickTime float64) {
func (v *SelectHeroClass) Advance(tickTime float64) error {
canSelect := true
v.campfire.Advance(tickTime)
for _, info := range v.heroRenderInfo {
@ -499,6 +475,7 @@ func (v *SelectHeroClass) Advance(tickTime float64) {
}
v.heroNameTextbox.Update()
v.okButton.SetEnabled(len(v.heroNameTextbox.GetText()) >= 2)
return nil
}
func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect bool) {

350
main.go
View File

@ -1,7 +1,12 @@
package main
import (
"errors"
"fmt"
"log"
"os"
"runtime"
"strconv"
"gopkg.in/alecthomas/kingpin.v2"
@ -9,7 +14,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2gamescene"
@ -17,14 +21,13 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
ebiten2 "github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2game"
)
// GitBranch is set by the CI build process to the name of the branch
@ -33,13 +36,19 @@ var GitBranch string
// GitCommit is set by the CI build process to the commit hash
var GitCommit string
var singleton struct {
lastTime float64
showFPS bool
timeScale float64
}
func main() {
if len(GitBranch) == 0 {
d2common.SetBuildInfo("Local Build", "")
} else {
d2common.SetBuildInfo(GitBranch, GitCommit)
GitBranch = "Local Build"
}
d2common.SetBuildInfo(GitBranch, GitCommit)
region := kingpin.Arg("region", "Region type id").Int()
preset := kingpin.Arg("preset", "Level preset").Int()
kingpin.Parse()
@ -47,7 +56,7 @@ func main() {
log.SetFlags(log.Lshortfile)
log.Println("OpenDiablo2 - Open source Diablo 2 engine")
if err := initializeEverything(); err != nil {
if err := initialize(); err != nil {
log.Fatal(err)
}
@ -57,28 +66,222 @@ func main() {
d2scene.SetNextScene(d2gamescene.CreateMapEngineTest(*region, *preset))
}
if err := d2game.Run(GitBranch); err != nil {
windowTitle := fmt.Sprintf("OpenDiablo2 (%s)", GitBranch)
if err := d2render.Run(update, 800, 600, windowTitle); err != nil {
log.Fatal(err)
}
}
func loadStrings() error {
tablePaths := []string{
d2resource.PatchStringTable,
d2resource.ExpansionStringTable,
d2resource.StringTable,
func initialize() error {
singleton.timeScale = 1.0
singleton.lastTime = d2common.Now()
if err := d2config.Initialize(); err != nil {
return err
}
for _, tablePath := range tablePaths {
data, err := d2asset.LoadFile(tablePath)
config, err := d2config.Get()
if err != nil {
return err
}
d2resource.LanguageCode = config.Language
renderer, err := ebiten.CreateRenderer()
if err != nil {
return err
}
if err := d2render.Initialize(renderer); err != nil {
return err
}
if err := d2render.SetWindowIcon("d2logo.png"); err != nil {
return err
}
if err := d2asset.Initialize(); err != nil {
return err
}
if err := d2input.Initialize(); err != nil {
return err
}
if err := d2gui.Initialize(); err != nil {
return err
}
if err := d2term.Initialize(); err != nil {
return err
}
d2term.BindLogger()
d2term.BindAction("fullscreen", "toggles fullscreen", func() {
fullscreen, err := d2render.IsFullScreen()
if err == nil {
fullscreen = !fullscreen
d2render.SetFullScreen(fullscreen)
d2term.OutputInfo("fullscreen is now: %v", fullscreen)
} else {
d2term.OutputError(err.Error())
}
})
d2term.BindAction("vsync", "toggles vsync", func() {
vsync, err := d2render.GetVSyncEnabled()
if err == nil {
vsync = !vsync
d2render.SetVSyncEnabled(vsync)
d2term.OutputInfo("vsync is now: %v", vsync)
} else {
d2term.OutputError(err.Error())
}
})
d2term.BindAction("fps", "toggle fps counter", func() {
singleton.showFPS = !singleton.showFPS
d2term.OutputInfo("fps counter is now: %v", singleton.showFPS)
})
d2term.BindAction("timescale", "set scalar for elapsed time", func(timeScale float64) {
if timeScale <= 0 {
d2term.OutputError("invalid time scale value")
} else {
d2term.OutputInfo("timescale changed from %f to %f", singleton.timeScale, timeScale)
singleton.timeScale = timeScale
}
})
d2term.BindAction("quit", "exits the game", func() {
os.Exit(0)
})
audioProvider, err := ebiten2.CreateAudio()
if err != nil {
return err
}
if err := d2audio.Initialize(audioProvider); err != nil {
return err
}
if err := d2audio.SetVolumes(config.BgmVolume, config.SfxVolume); err != nil {
return err
}
if err := loadDataDict(); err != nil {
return err
}
if err := loadPalettes(); err != nil {
return err
}
if err := loadStrings(); err != nil {
return err
}
d2ui.Initialize()
return nil
}
func update(target d2render.Surface) error {
currentTime := d2common.Now()
elapsedTime := (currentTime - singleton.lastTime) * singleton.timeScale
singleton.lastTime = currentTime
if err := advance(elapsedTime); err != nil {
return err
}
if err := render(target); err != nil {
return err
}
if target.GetDepth() > 0 {
return errors.New("detected surface stack leak")
}
return nil
}
func advance(elapsed float64) error {
if err := d2scene.Advance(elapsed); err != nil {
return err
}
d2ui.Advance(elapsed)
if err := d2input.Advance(elapsed); err != nil {
return err
}
if err := d2gui.Advance(elapsed); err != nil {
return err
}
if err := d2term.Advance(elapsed); err != nil {
return err
}
return nil
}
func render(target d2render.Surface) error {
if err := d2scene.Render(target); err != nil {
return err
}
d2ui.Render(target)
if err := d2gui.Render(target); err != nil {
return err
}
if err := d2term.Render(target); err != nil {
return err
}
if err := renderDebug(target); err != nil {
return err
}
return nil
}
func renderDebug(target d2render.Surface) error {
if singleton.showFPS {
vsyncEnabled, err := d2render.GetVSyncEnabled()
if err != nil {
return err
}
d2common.LoadDictionary(data)
fps, err := d2render.CurrentFPS()
if err != nil {
return err
}
target.PushTranslation(5, 565)
target.DrawText("vsync:" + strconv.FormatBool(vsyncEnabled) + "\nFPS:" + strconv.Itoa(int(fps)))
target.Pop()
cx, cy, err := d2render.GetCursorPos()
if err != nil {
return err
}
var m runtime.MemStats
runtime.ReadMemStats(&m)
target.PushTranslation(680, 0)
target.DrawText("Alloc " + strconv.FormatInt(int64(m.Alloc)/1024/1024, 10))
target.PushTranslation(0, 16)
target.DrawText("Pause " + strconv.FormatInt(int64(m.PauseTotalNs/1024/1024), 10))
target.PushTranslation(0, 16)
target.DrawText("HeapSys " + strconv.FormatInt(int64(m.HeapSys/1024/1024), 10))
target.PushTranslation(0, 16)
target.DrawText("NumGC " + strconv.FormatInt(int64(m.NumGC), 10))
target.PushTranslation(0, 16)
target.DrawText("Coords " + strconv.FormatInt(int64(cx), 10) + "," + strconv.FormatInt(int64(cy), 10))
target.PopN(5)
}
log.Printf("Loaded %d entries from the string table", d2common.GetDictionaryEntryCount())
return nil
}
@ -149,110 +352,21 @@ func loadDataDict() error {
return nil
}
func loadLoadingSprite() (*d2ui.Sprite, error) {
animation, err := d2asset.LoadAnimation(d2resource.LoadingScreen, d2resource.PaletteLoading)
if err != nil {
return nil, err
func loadStrings() error {
tablePaths := []string{
d2resource.PatchStringTable,
d2resource.ExpansionStringTable,
d2resource.StringTable,
}
loadingSprite, err := d2ui.LoadSprite(animation)
if err != nil {
return nil, err
for _, tablePath := range tablePaths {
data, err := d2asset.LoadFile(tablePath)
if err != nil {
return err
}
d2common.LoadDictionary(data)
}
loadingSpriteSizeX, loadingSpriteSizeY := loadingSprite.GetCurrentFrameSize()
loadingSprite.SetPosition(400-(loadingSpriteSizeX/2), 300+(loadingSpriteSizeY/2))
return loadingSprite, nil
}
func loadCursorSprite() (*d2ui.Sprite, error) {
animation, err := d2asset.LoadAnimation(d2resource.CursorDefault, d2resource.PaletteUnits)
if err != nil {
return nil, err
}
cursorSprite, err := d2ui.LoadSprite(animation)
if err != nil {
return nil, err
}
return cursorSprite, nil
}
func initializeEverything() error {
if err := d2config.Initialize(); err != nil {
return err
}
config, err := d2config.Get()
if err != nil {
return err
}
d2resource.LanguageCode = config.Language
renderer, err := ebiten.CreateRenderer()
if err != nil {
return err
}
if err := d2render.Initialize(renderer); err != nil {
return err
}
if err := d2render.SetWindowIcon("d2logo.png"); err != nil {
return err
}
if err := d2input.Initialize(); err != nil {
return err
}
if err := d2term.Initialize(); err != nil {
return err
}
d2term.BindLogger()
d2mpq.InitializeCryptoBuffer()
if err := d2asset.Initialize(); err != nil {
return err
}
audioProvider, err := ebiten2.CreateAudio()
if err != nil {
return err
}
if err := d2audio.Initialize(audioProvider); err != nil {
return err
}
if err := d2audio.SetVolumes(config.BgmVolume, config.SfxVolume); err != nil {
return err
}
if err := loadDataDict(); err != nil {
return err
}
if err := loadPalettes(); err != nil {
return err
}
if err := loadStrings(); err != nil {
return err
}
cursorSprite, err := loadCursorSprite()
if err != nil {
return err
}
d2ui.Initialize(cursorSprite)
loadingSprite, err := loadLoadingSprite()
if err != nil {
return err
}
d2game.Initialize(loadingSprite)
return nil
}