mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-02 14:46:28 -05:00
lint fixes (#615)
This commit is contained in:
parent
80e655964e
commit
7a49f3637f
217
d2app/app.go
217
d2app/app.go
@ -17,6 +17,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/profile"
|
||||||
|
"golang.org/x/image/colornames"
|
||||||
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
@ -32,9 +36,6 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2script"
|
"github.com/OpenDiablo2/OpenDiablo2/d2script"
|
||||||
"github.com/pkg/profile"
|
|
||||||
"golang.org/x/image/colornames"
|
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// App represents the main application for the engine
|
// App represents the main application for the engine
|
||||||
@ -91,7 +92,7 @@ func Create(gitBranch, gitCommit string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run executes the application and kicks off the entire game process
|
// Run executes the application and kicks off the entire game process
|
||||||
func (p *App) Run() error {
|
func (a *App) Run() error {
|
||||||
profileOption := kingpin.Flag("profile", "Profiles the program, one of (cpu, mem, block, goroutine, trace, thread, mutex)").String()
|
profileOption := kingpin.Flag("profile", "Profiles the program, one of (cpu, mem, block, goroutine, trace, thread, mutex)").String()
|
||||||
kingpin.Parse()
|
kingpin.Parse()
|
||||||
|
|
||||||
@ -102,88 +103,86 @@ func (p *App) Run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
windowTitle := fmt.Sprintf("OpenDiablo2 (%s)", p.gitBranch)
|
windowTitle := fmt.Sprintf("OpenDiablo2 (%s)", a.gitBranch)
|
||||||
// If we fail to initialize, we will show the error screen
|
// If we fail to initialize, we will show the error screen
|
||||||
if err := p.initialize(); err != nil {
|
if err := a.initialize(); err != nil {
|
||||||
if gameErr := p.renderer.Run(updateInitError, 800, 600, windowTitle); gameErr != nil {
|
if gameErr := a.renderer.Run(updateInitError, 800, 600, windowTitle); gameErr != nil {
|
||||||
return gameErr
|
return gameErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.ToMainMenu()
|
a.ToMainMenu()
|
||||||
|
|
||||||
if p.gitBranch == "" {
|
if a.gitBranch == "" {
|
||||||
p.gitBranch = "Local Build"
|
a.gitBranch = "Local Build"
|
||||||
}
|
}
|
||||||
|
|
||||||
d2common.SetBuildInfo(p.gitBranch, p.gitCommit)
|
if err := a.renderer.Run(a.update, 800, 600, windowTitle); err != nil {
|
||||||
|
|
||||||
if err := p.renderer.Run(p.update, 800, 600, windowTitle); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) initialize() error {
|
func (a *App) initialize() error {
|
||||||
p.timeScale = 1.0
|
a.timeScale = 1.0
|
||||||
p.lastTime = d2common.Now()
|
a.lastTime = d2common.Now()
|
||||||
p.lastScreenAdvance = p.lastTime
|
a.lastScreenAdvance = a.lastTime
|
||||||
|
|
||||||
p.renderer.SetWindowIcon("d2logo.png")
|
a.renderer.SetWindowIcon("d2logo.png")
|
||||||
p.terminal.BindLogger()
|
a.terminal.BindLogger()
|
||||||
|
|
||||||
terminalActions := [...]bindTerminalEntry{
|
terminalActions := [...]bindTerminalEntry{
|
||||||
{"dumpheap", "dumps the heap to pprof/heap.pprof", p.dumpHeap},
|
{"dumpheap", "dumps the heap to pprof/heap.pprof", a.dumpHeap},
|
||||||
{"fullscreen", "toggles fullscreen", p.toggleFullScreen},
|
{"fullscreen", "toggles fullscreen", a.toggleFullScreen},
|
||||||
{"capframe", "captures a still frame", p.captureFrame},
|
{"capframe", "captures a still frame", a.captureFrame},
|
||||||
{"capgifstart", "captures an animation (start)", p.startAnimationCapture},
|
{"capgifstart", "captures an animation (start)", a.startAnimationCapture},
|
||||||
{"capgifstop", "captures an animation (stop)", p.stopAnimationCapture},
|
{"capgifstop", "captures an animation (stop)", a.stopAnimationCapture},
|
||||||
{"vsync", "toggles vsync", p.toggleVsync},
|
{"vsync", "toggles vsync", a.toggleVsync},
|
||||||
{"fps", "toggle fps counter", p.toggleFpsCounter},
|
{"fps", "toggle fps counter", a.toggleFpsCounter},
|
||||||
{"timescale", "set scalar for elapsed time", p.setTimeScale},
|
{"timescale", "set scalar for elapsed time", a.setTimeScale},
|
||||||
{"quit", "exits the game", p.quitGame},
|
{"quit", "exits the game", a.quitGame},
|
||||||
{"screen-gui", "enters the gui playground screen", p.enterGuiPlayground},
|
{"screen-gui", "enters the gui playground screen", a.enterGuiPlayground},
|
||||||
{"js", "eval JS scripts", p.evalJS},
|
{"js", "eval JS scripts", a.evalJS},
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx := range terminalActions {
|
for idx := range terminalActions {
|
||||||
action := &terminalActions[idx]
|
action := &terminalActions[idx]
|
||||||
|
|
||||||
if err := p.terminal.BindAction(action.name, action.description, action.action); err != nil {
|
if err := a.terminal.BindAction(action.name, action.description, action.action); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d2asset.Initialize(p.renderer, p.terminal); err != nil {
|
if err := d2asset.Initialize(a.renderer, a.terminal); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d2gui.Initialize(p.inputManager); err != nil {
|
if err := d2gui.Initialize(a.inputManager); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := d2config.Config
|
config := d2config.Config
|
||||||
p.audio.SetVolumes(config.BgmVolume, config.SfxVolume)
|
a.audio.SetVolumes(config.BgmVolume, config.SfxVolume)
|
||||||
|
|
||||||
if err := p.loadDataDict(); err != nil {
|
if err := a.loadDataDict(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.loadStrings(); err != nil {
|
if err := a.loadStrings(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d2inventory.LoadHeroObjects()
|
d2inventory.LoadHeroObjects()
|
||||||
|
|
||||||
d2ui.Initialize(p.inputManager, p.audio)
|
d2ui.Initialize(a.inputManager, a.audio)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) loadStrings() error {
|
func (a *App) loadStrings() error {
|
||||||
tablePaths := []string{
|
tablePaths := []string{
|
||||||
d2resource.PatchStringTable,
|
d2resource.PatchStringTable,
|
||||||
d2resource.ExpansionStringTable,
|
d2resource.ExpansionStringTable,
|
||||||
@ -202,7 +201,7 @@ func (p *App) loadStrings() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) loadDataDict() error {
|
func (a *App) loadDataDict() error {
|
||||||
entries := []struct {
|
entries := []struct {
|
||||||
path string
|
path string
|
||||||
loader func(data []byte)
|
loader func(data []byte)
|
||||||
@ -256,14 +255,14 @@ func (p *App) loadDataDict() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) renderDebug(target d2interface.Surface) error {
|
func (a *App) renderDebug(target d2interface.Surface) error {
|
||||||
if !p.showFPS {
|
if !a.showFPS {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
vsyncEnabled := p.renderer.GetVSyncEnabled()
|
vsyncEnabled := a.renderer.GetVSyncEnabled()
|
||||||
fps := p.renderer.CurrentFPS()
|
fps := a.renderer.CurrentFPS()
|
||||||
cx, cy := p.renderer.GetCursorPos()
|
cx, cy := a.renderer.GetCursorPos()
|
||||||
|
|
||||||
target.PushTranslation(5, 565)
|
target.PushTranslation(5, 565)
|
||||||
target.DrawTextf("vsync:" + strconv.FormatBool(vsyncEnabled) + "\nFPS:" + strconv.Itoa(int(fps)))
|
target.DrawTextf("vsync:" + strconv.FormatBool(vsyncEnabled) + "\nFPS:" + strconv.Itoa(int(fps)))
|
||||||
@ -275,7 +274,7 @@ func (p *App) renderDebug(target d2interface.Surface) error {
|
|||||||
target.PushTranslation(680, 0)
|
target.PushTranslation(680, 0)
|
||||||
target.DrawTextf("Alloc " + strconv.FormatInt(int64(m.Alloc)/bytesToMegabyte, 10))
|
target.DrawTextf("Alloc " + strconv.FormatInt(int64(m.Alloc)/bytesToMegabyte, 10))
|
||||||
target.PushTranslation(0, 16)
|
target.PushTranslation(0, 16)
|
||||||
target.DrawTextf("TAlloc/s " + strconv.FormatFloat(p.allocRate(m.TotalAlloc, fps), 'f', 2, 64))
|
target.DrawTextf("TAlloc/s " + strconv.FormatFloat(a.allocRate(m.TotalAlloc, fps), 'f', 2, 64))
|
||||||
target.PushTranslation(0, 16)
|
target.PushTranslation(0, 16)
|
||||||
target.DrawTextf("Pause " + strconv.FormatInt(int64(m.PauseTotalNs/bytesToMegabyte), 10))
|
target.DrawTextf("Pause " + strconv.FormatInt(int64(m.PauseTotalNs/bytesToMegabyte), 10))
|
||||||
target.PushTranslation(0, 16)
|
target.PushTranslation(0, 16)
|
||||||
@ -289,18 +288,18 @@ func (p *App) renderDebug(target d2interface.Surface) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) renderCapture(target d2interface.Surface) error {
|
func (a *App) renderCapture(target d2interface.Surface) error {
|
||||||
cleanupCapture := func() {
|
cleanupCapture := func() {
|
||||||
p.captureState = captureStateNone
|
a.captureState = captureStateNone
|
||||||
p.capturePath = ""
|
a.capturePath = ""
|
||||||
p.captureFrames = nil
|
a.captureFrames = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.captureState {
|
switch a.captureState {
|
||||||
case captureStateFrame:
|
case captureStateFrame:
|
||||||
defer cleanupCapture()
|
defer cleanupCapture()
|
||||||
|
|
||||||
fp, err := os.Create(p.capturePath)
|
fp, err := os.Create(a.capturePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -316,15 +315,15 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("saved frame to %s", p.capturePath)
|
log.Printf("saved frame to %s", a.capturePath)
|
||||||
case captureStateGif:
|
case captureStateGif:
|
||||||
screenshot := target.Screenshot()
|
screenshot := target.Screenshot()
|
||||||
p.captureFrames = append(p.captureFrames, screenshot)
|
a.captureFrames = append(a.captureFrames, screenshot)
|
||||||
case captureStateNone:
|
case captureStateNone:
|
||||||
if len(p.captureFrames) > 0 {
|
if len(a.captureFrames) > 0 {
|
||||||
defer cleanupCapture()
|
defer cleanupCapture()
|
||||||
|
|
||||||
fp, err := os.Create(p.capturePath)
|
fp, err := os.Create(a.capturePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -336,7 +335,7 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
framesTotal = len(p.captureFrames)
|
framesTotal = len(a.captureFrames)
|
||||||
framesPal = make([]*image.Paletted, framesTotal)
|
framesPal = make([]*image.Paletted, framesTotal)
|
||||||
frameDelays = make([]int, framesTotal)
|
frameDelays = make([]int, framesTotal)
|
||||||
framesPerCPU = framesTotal / runtime.NumCPU()
|
framesPerCPU = framesTotal / runtime.NumCPU()
|
||||||
@ -352,7 +351,7 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
|||||||
|
|
||||||
for j := start; j < end; j++ {
|
for j := start; j < end; j++ {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
if err := gif.Encode(&buffer, p.captureFrames[j], nil); err != nil {
|
if err := gif.Encode(&buffer, a.captureFrames[j], nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,14 +372,14 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("saved animation to %s", p.capturePath)
|
log.Printf("saved animation to %s", a.capturePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) render(target d2interface.Surface) error {
|
func (a *App) render(target d2interface.Surface) error {
|
||||||
if err := d2screen.Render(target); err != nil {
|
if err := d2screen.Render(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -391,26 +390,26 @@ func (p *App) render(target d2interface.Surface) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.renderDebug(target); err != nil {
|
if err := a.renderDebug(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.renderCapture(target); err != nil {
|
if err := a.renderCapture(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.terminal.Render(target); err != nil {
|
if err := a.terminal.Render(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) advance(elapsed, current float64) error {
|
func (a *App) advance(elapsed, current float64) error {
|
||||||
elapsedLastScreenAdvance := (current - p.lastScreenAdvance) * p.timeScale
|
elapsedLastScreenAdvance := (current - a.lastScreenAdvance) * a.timeScale
|
||||||
|
|
||||||
if elapsedLastScreenAdvance > defaultFPS {
|
if elapsedLastScreenAdvance > defaultFPS {
|
||||||
p.lastScreenAdvance = current
|
a.lastScreenAdvance = current
|
||||||
|
|
||||||
if err := d2screen.Advance(elapsedLastScreenAdvance); err != nil {
|
if err := d2screen.Advance(elapsedLastScreenAdvance); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -419,7 +418,7 @@ func (p *App) advance(elapsed, current float64) error {
|
|||||||
|
|
||||||
d2ui.Advance(elapsed)
|
d2ui.Advance(elapsed)
|
||||||
|
|
||||||
if err := p.inputManager.Advance(elapsed, current); err != nil {
|
if err := a.inputManager.Advance(elapsed, current); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,23 +426,23 @@ func (p *App) advance(elapsed, current float64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.terminal.Advance(elapsed); err != nil {
|
if err := a.terminal.Advance(elapsed); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) update(target d2interface.Surface) error {
|
func (a *App) update(target d2interface.Surface) error {
|
||||||
currentTime := d2common.Now()
|
currentTime := d2common.Now()
|
||||||
elapsedTime := (currentTime - p.lastTime) * p.timeScale
|
elapsedTime := (currentTime - a.lastTime) * a.timeScale
|
||||||
p.lastTime = currentTime
|
a.lastTime = currentTime
|
||||||
|
|
||||||
if err := p.advance(elapsedTime, currentTime); err != nil {
|
if err := a.advance(elapsedTime, currentTime); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.render(target); err != nil {
|
if err := a.render(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,15 +453,15 @@ func (p *App) update(target d2interface.Surface) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) allocRate(totalAlloc uint64, fps float64) float64 {
|
func (a *App) allocRate(totalAlloc uint64, fps float64) float64 {
|
||||||
p.tAllocSamples.Value = totalAlloc
|
a.tAllocSamples.Value = totalAlloc
|
||||||
p.tAllocSamples = p.tAllocSamples.Next()
|
a.tAllocSamples = a.tAllocSamples.Next()
|
||||||
deltaAllocPerFrame := float64(totalAlloc-p.tAllocSamples.Value.(uint64)) / nSamplesTAlloc
|
deltaAllocPerFrame := float64(totalAlloc-a.tAllocSamples.Value.(uint64)) / nSamplesTAlloc
|
||||||
|
|
||||||
return deltaAllocPerFrame * fps / bytesToMegabyte
|
return deltaAllocPerFrame * fps / bytesToMegabyte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) dumpHeap() {
|
func (a *App) dumpHeap() {
|
||||||
if err := os.Mkdir("./pprof/", 0750); err != nil {
|
if err := os.Mkdir("./pprof/", 0750); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -478,64 +477,64 @@ func (p *App) dumpHeap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) evalJS(code string) {
|
func (a *App) evalJS(code string) {
|
||||||
val, err := p.scriptEngine.Eval(code)
|
val, err := a.scriptEngine.Eval(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.terminal.OutputErrorf("%s", err)
|
a.terminal.OutputErrorf("%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("%s", val)
|
log.Printf("%s", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) toggleFullScreen() {
|
func (a *App) toggleFullScreen() {
|
||||||
fullscreen := !p.renderer.IsFullScreen()
|
fullscreen := !a.renderer.IsFullScreen()
|
||||||
p.renderer.SetFullScreen(fullscreen)
|
a.renderer.SetFullScreen(fullscreen)
|
||||||
p.terminal.OutputInfof("fullscreen is now: %v", fullscreen)
|
a.terminal.OutputInfof("fullscreen is now: %v", fullscreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) captureFrame(path string) {
|
func (a *App) captureFrame(path string) {
|
||||||
p.captureState = captureStateFrame
|
a.captureState = captureStateFrame
|
||||||
p.capturePath = path
|
a.capturePath = path
|
||||||
p.captureFrames = nil
|
a.captureFrames = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) startAnimationCapture(path string) {
|
func (a *App) startAnimationCapture(path string) {
|
||||||
p.captureState = captureStateGif
|
a.captureState = captureStateGif
|
||||||
p.capturePath = path
|
a.capturePath = path
|
||||||
p.captureFrames = nil
|
a.captureFrames = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) stopAnimationCapture() {
|
func (a *App) stopAnimationCapture() {
|
||||||
p.captureState = captureStateNone
|
a.captureState = captureStateNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) toggleVsync() {
|
func (a *App) toggleVsync() {
|
||||||
vsync := !p.renderer.GetVSyncEnabled()
|
vsync := !a.renderer.GetVSyncEnabled()
|
||||||
p.renderer.SetVSyncEnabled(vsync)
|
a.renderer.SetVSyncEnabled(vsync)
|
||||||
p.terminal.OutputInfof("vsync is now: %v", vsync)
|
a.terminal.OutputInfof("vsync is now: %v", vsync)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) toggleFpsCounter() {
|
func (a *App) toggleFpsCounter() {
|
||||||
p.showFPS = !p.showFPS
|
a.showFPS = !a.showFPS
|
||||||
p.terminal.OutputInfof("fps counter is now: %v", p.showFPS)
|
a.terminal.OutputInfof("fps counter is now: %v", a.showFPS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) setTimeScale(timeScale float64) {
|
func (a *App) setTimeScale(timeScale float64) {
|
||||||
if timeScale <= 0 {
|
if timeScale <= 0 {
|
||||||
p.terminal.OutputErrorf("invalid time scale value")
|
a.terminal.OutputErrorf("invalid time scale value")
|
||||||
} else {
|
} else {
|
||||||
p.terminal.OutputInfof("timescale changed from %f to %f", p.timeScale, timeScale)
|
a.terminal.OutputInfof("timescale changed from %f to %f", a.timeScale, timeScale)
|
||||||
p.timeScale = timeScale
|
a.timeScale = timeScale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) quitGame() {
|
func (a *App) quitGame() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *App) enterGuiPlayground() {
|
func (a *App) enterGuiPlayground() {
|
||||||
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(p.renderer))
|
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(a.renderer))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createZeroedRing(n int) *ring.Ring {
|
func createZeroedRing(n int) *ring.Ring {
|
||||||
@ -604,7 +603,7 @@ func updateInitError(target d2interface.Surface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) ToMainMenu() {
|
func (a *App) ToMainMenu() {
|
||||||
mainMenu := d2gamescreen.CreateMainMenu(a, a.renderer, a.inputManager, a.audio)
|
mainMenu := d2gamescreen.CreateMainMenu(a, a.renderer, a.inputManager, a.audio, d2gamescreen.BuildInfo{Branch: a.gitBranch, Commit: a.gitCommit})
|
||||||
mainMenu.SetScreenMode(d2gamescreen.ScreenModeMainMenu)
|
mainMenu.SetScreenMode(d2gamescreen.ScreenModeMainMenu)
|
||||||
d2screen.SetNextScreen(mainMenu)
|
d2screen.SetNextScreen(mainMenu)
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package d2common
|
|
||||||
|
|
||||||
// BuildInfoRecord is the structure used to hold information about the current build
|
|
||||||
type BuildInfoRecord struct {
|
|
||||||
// Branch is the branch this build is based on (or 'Local' if built locally)
|
|
||||||
Branch string
|
|
||||||
// Commit is the commit hash of the build (or blank if built locally)
|
|
||||||
Commit string
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildInfo contains information about the build currently being ran
|
|
||||||
var BuildInfo BuildInfoRecord
|
|
||||||
|
|
||||||
// SetBuildInfo is called at the start of the application to generate the global BuildInfo value
|
|
||||||
func SetBuildInfo(branch, commit string) {
|
|
||||||
BuildInfo = BuildInfoRecord{
|
|
||||||
Branch: branch,
|
|
||||||
Commit: commit,
|
|
||||||
}
|
|
||||||
}
|
|
@ -96,7 +96,7 @@ func LoadHireling(file []byte) {
|
|||||||
hireling := &HirelingRecord{
|
hireling := &HirelingRecord{
|
||||||
Hireling: d.String("Hireling"),
|
Hireling: d.String("Hireling"),
|
||||||
SubType: d.String("SubType"),
|
SubType: d.String("SubType"),
|
||||||
ID: d.Number("Id"),
|
ID: d.Number("ID"),
|
||||||
Class: d.Number("Class"),
|
Class: d.Number("Class"),
|
||||||
Act: d.Number("Act"),
|
Act: d.Number("Act"),
|
||||||
Difficulty: d.Number("Difficulty"),
|
Difficulty: d.Number("Difficulty"),
|
||||||
@ -109,7 +109,7 @@ func LoadHireling(file []byte) {
|
|||||||
HP: d.Number("HP"),
|
HP: d.Number("HP"),
|
||||||
HPPerLvl: d.Number("HP/Lvl"),
|
HPPerLvl: d.Number("HP/Lvl"),
|
||||||
Defense: d.Number("Defense"),
|
Defense: d.Number("Defense"),
|
||||||
DefPerLvl: d.Number("Id"),
|
DefPerLvl: d.Number("ID"),
|
||||||
Str: d.Number("Str"),
|
Str: d.Number("Str"),
|
||||||
StrPerLvl: d.Number("Str/Lvl"),
|
StrPerLvl: d.Number("Str/Lvl"),
|
||||||
Dex: d.Number("Dex"),
|
Dex: d.Number("Dex"),
|
||||||
|
@ -36,7 +36,7 @@ func LoadLevelWarps(file []byte) {
|
|||||||
for d.Next() {
|
for d.Next() {
|
||||||
record := &LevelWarpRecord{
|
record := &LevelWarpRecord{
|
||||||
Name: d.String("Name"),
|
Name: d.String("Name"),
|
||||||
ID: d.Number("Id"),
|
ID: d.Number("ID"),
|
||||||
SelectX: d.Number("SelectX"),
|
SelectX: d.Number("SelectX"),
|
||||||
SelectY: d.Number("SelectY"),
|
SelectY: d.Number("SelectY"),
|
||||||
SelectDX: d.Number("SelectDX"),
|
SelectDX: d.Number("SelectDX"),
|
||||||
|
@ -74,7 +74,7 @@ type LevelDetailsRecord struct {
|
|||||||
MonsterUniqueID9 string // umon9
|
MonsterUniqueID9 string // umon9
|
||||||
MonsterUniqueID10 string // umon10
|
MonsterUniqueID10 string // umon10
|
||||||
|
|
||||||
// Critter Species 1-4. Uses the Id from monstats2.txt and only monsters
|
// Critter Species 1-4. Uses the ID from monstats2.txt and only monsters
|
||||||
// with critter column set to 1 can spawn here. critter column is also found
|
// with critter column set to 1 can spawn here. critter column is also found
|
||||||
// in monstats2.txt. Critters are in reality only present clientside.
|
// in monstats2.txt. Critters are in reality only present clientside.
|
||||||
MonsterCritterID1 string // cmon1
|
MonsterCritterID1 string // cmon1
|
||||||
@ -93,9 +93,9 @@ type LevelDetailsRecord struct {
|
|||||||
// present in the expension folders)
|
// present in the expension folders)
|
||||||
TitleImageName string // EntryFile
|
TitleImageName string // EntryFile
|
||||||
|
|
||||||
// Id
|
// ID
|
||||||
// Level ID (used in columns like VIS0-7)
|
// Level ID (used in columns like VIS0-7)
|
||||||
Id int //nolint:golint,stylecheck // Id is the right key
|
Id int //nolint:golint,stylecheck // ID is the right key
|
||||||
|
|
||||||
// Palette is the Act Palette . Reference only
|
// Palette is the Act Palette . Reference only
|
||||||
Palette int // Pal
|
Palette int // Pal
|
||||||
@ -138,7 +138,7 @@ type LevelDetailsRecord struct {
|
|||||||
// location.
|
// location.
|
||||||
DependantLevelID int // Depend
|
DependantLevelID int // Depend
|
||||||
|
|
||||||
// The type of the Level (Id from lvltypes.txt)
|
// The type of the Level (ID from lvltypes.txt)
|
||||||
LevelType int // LevelType
|
LevelType int // LevelType
|
||||||
|
|
||||||
// Controls if teleport is allowed in that level.
|
// Controls if teleport is allowed in that level.
|
||||||
@ -367,7 +367,7 @@ type LevelDetailsRecord struct {
|
|||||||
//nolint:gochecknoglobals // Currently global by design, only written once
|
//nolint:gochecknoglobals // Currently global by design, only written once
|
||||||
var LevelDetails map[int]*LevelDetailsRecord
|
var LevelDetails map[int]*LevelDetailsRecord
|
||||||
|
|
||||||
// GetLevelDetails gets a LevelDetailsRecord by the record Id
|
// GetLevelDetails gets a LevelDetailsRecord by the record ID
|
||||||
func GetLevelDetails(id int) *LevelDetailsRecord {
|
func GetLevelDetails(id int) *LevelDetailsRecord {
|
||||||
for i := 0; i < len(LevelDetails); i++ {
|
for i := 0; i < len(LevelDetails); i++ {
|
||||||
if LevelDetails[i].Id == id {
|
if LevelDetails[i].Id == id {
|
||||||
@ -387,7 +387,7 @@ func LoadLevelDetails(file []byte) {
|
|||||||
for d.Next() {
|
for d.Next() {
|
||||||
record := &LevelDetailsRecord{
|
record := &LevelDetailsRecord{
|
||||||
Name: d.String("Name "),
|
Name: d.String("Name "),
|
||||||
Id: d.Number("Id"),
|
Id: d.Number("ID"),
|
||||||
Palette: d.Number("Pal"),
|
Palette: d.Number("Pal"),
|
||||||
Act: d.Number("Act"),
|
Act: d.Number("Act"),
|
||||||
QuestFlag: d.Number("QuestFlag"),
|
QuestFlag: d.Number("QuestFlag"),
|
||||||
|
@ -110,7 +110,7 @@ type MissileRecord struct {
|
|||||||
ExplosionMissile string // name of a missile from missiles.txt that is created upon collision
|
ExplosionMissile string // name of a missile from missiles.txt that is created upon collision
|
||||||
// or anytime it is destroyed if AlwaysExplode is true
|
// or anytime it is destroyed if AlwaysExplode is true
|
||||||
|
|
||||||
Id int //nolint:golint,stylecheck // Id is the correct key
|
Id int //nolint:golint,stylecheck // ID is the correct key
|
||||||
|
|
||||||
ClientMovementFunc int
|
ClientMovementFunc int
|
||||||
ClientCollisionFunc int
|
ClientCollisionFunc int
|
||||||
|
@ -17,9 +17,9 @@ type (
|
|||||||
|
|
||||||
// Key contains the pointer that will be used in other txt files
|
// Key contains the pointer that will be used in other txt files
|
||||||
// such as levels.txt and superuniques.txt.
|
// such as levels.txt and superuniques.txt.
|
||||||
Key string // called `Id` in monstats.txt
|
Key string // called `ID` in monstats.txt
|
||||||
|
|
||||||
// Id is the actual internal ID of the unit (this is what the ID pointer
|
// ID is the actual internal ID of the unit (this is what the ID pointer
|
||||||
// actually points at) remember that no two units can have the same ID,
|
// actually points at) remember that no two units can have the same ID,
|
||||||
// this will result in lots of unpredictable behavior and crashes so please
|
// this will result in lots of unpredictable behavior and crashes so please
|
||||||
// don’t do it. This 'HarcCodedInDeX' is used for several things, such as
|
// don’t do it. This 'HarcCodedInDeX' is used for several things, such as
|
||||||
@ -80,10 +80,10 @@ type (
|
|||||||
// which animation mode will the spawned monster be spawned in.
|
// which animation mode will the spawned monster be spawned in.
|
||||||
SpawnAnimationKey string // called `spawnmode` in monstats.txt
|
SpawnAnimationKey string // called `spawnmode` in monstats.txt
|
||||||
|
|
||||||
// MinionId1 is an Id of a minion that spawns when this monster is created
|
// MinionId1 is an ID of a minion that spawns when this monster is created
|
||||||
MinionId1 string //nolint:golint,stylecheck // called `minion1` in monstats.txt
|
MinionId1 string //nolint:golint,stylecheck // called `minion1` in monstats.txt
|
||||||
|
|
||||||
// MinionId2 is an Id of a minion that spawns when this monster is created
|
// MinionId2 is an ID of a minion that spawns when this monster is created
|
||||||
MinionId2 string //nolint:golint,stylecheck // called `minion2` in monstats.txt
|
MinionId2 string //nolint:golint,stylecheck // called `minion2` in monstats.txt
|
||||||
|
|
||||||
// SoundKeyNormal, SoundKeySpecial
|
// SoundKeyNormal, SoundKeySpecial
|
||||||
@ -690,7 +690,7 @@ func LoadMonStats(file []byte) { // nolint:funlen // Makes no sense to split
|
|||||||
d := d2common.LoadDataDictionary(file)
|
d := d2common.LoadDataDictionary(file)
|
||||||
for d.Next() {
|
for d.Next() {
|
||||||
record := &MonStatsRecord{
|
record := &MonStatsRecord{
|
||||||
Key: d.String("Id"),
|
Key: d.String("ID"),
|
||||||
Id: d.Number("hcIdx"),
|
Id: d.Number("hcIdx"),
|
||||||
BaseKey: d.String("BaseId"),
|
BaseKey: d.String("BaseId"),
|
||||||
NextKey: d.String("NextInClass"),
|
NextKey: d.String("NextInClass"),
|
||||||
|
@ -177,7 +177,7 @@ func LoadMonStats2(file []byte) {
|
|||||||
d := d2common.LoadDataDictionary(file)
|
d := d2common.LoadDataDictionary(file)
|
||||||
for d.Next() {
|
for d.Next() {
|
||||||
record := &MonStats2Record{
|
record := &MonStats2Record{
|
||||||
Key: d.String("Id"),
|
Key: d.String("ID"),
|
||||||
Height: d.Number("Height"),
|
Height: d.Number("Height"),
|
||||||
OverlayHeight: d.Number("OverlayHeight"),
|
OverlayHeight: d.Number("OverlayHeight"),
|
||||||
PixelHeight: d.Number("pixHeight"),
|
PixelHeight: d.Number("pixHeight"),
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
type ObjectLookupRecord struct {
|
type ObjectLookupRecord struct {
|
||||||
Act int
|
Act int
|
||||||
Type d2enum.ObjectType
|
Type d2enum.ObjectType
|
||||||
Id int //nolint:golint,stylecheck // Id is the right key
|
Id int //nolint:golint,stylecheck // ID is the right key
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
ObjectsTxtId int //nolint:golint,stylecheck // Id is the right key
|
ObjectsTxtId int //nolint:golint,stylecheck // ID is the right key
|
||||||
MonstatsTxtId int //nolint:golint,stylecheck // Id is the right key
|
MonstatsTxtId int //nolint:golint,stylecheck // ID is the right key
|
||||||
Direction int
|
Direction int
|
||||||
Base string
|
Base string
|
||||||
Token string
|
Token string
|
||||||
@ -44,7 +44,7 @@ type ObjectLookupRecord struct {
|
|||||||
func LookupObject(act, typ, id int) *ObjectLookupRecord {
|
func LookupObject(act, typ, id int) *ObjectLookupRecord {
|
||||||
object := lookupObject(act, typ, id, indexedObjects)
|
object := lookupObject(act, typ, id, indexedObjects)
|
||||||
if object == nil {
|
if object == nil {
|
||||||
log.Panicf("Failed to look up object Act: %d, Type: %d, Id: %d", act, typ, id)
|
log.Panicf("Failed to look up object Act: %d, Type: %d, ID: %d", act, typ, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return object
|
return object
|
||||||
@ -96,6 +96,6 @@ func indexObjects(objects []ObjectLookupRecord) [][][]*ObjectLookupRecord {
|
|||||||
|
|
||||||
// IndexedObjects is a slice of object records for quick lookups.
|
// IndexedObjects is a slice of object records for quick lookups.
|
||||||
// nil checks should be done for uninitialized values at each level.
|
// nil checks should be done for uninitialized values at each level.
|
||||||
// [Act 1-5][Type 1-2][Id 0-855]
|
// [Act 1-5][Type 1-2][ID 0-855]
|
||||||
//nolint:gochecknoglobals // Currently global by design
|
//nolint:gochecknoglobals // Currently global by design
|
||||||
var indexedObjects [][][]*ObjectLookupRecord
|
var indexedObjects [][][]*ObjectLookupRecord
|
||||||
|
@ -281,7 +281,7 @@ func LoadSkills(file []byte) {
|
|||||||
for d.Next() {
|
for d.Next() {
|
||||||
record := &SkillRecord{
|
record := &SkillRecord{
|
||||||
Skill: d.String("skill"),
|
Skill: d.String("skill"),
|
||||||
ID: d.Number("Id"),
|
ID: d.Number("ID"),
|
||||||
Charclass: d.String("charclass"),
|
Charclass: d.String("charclass"),
|
||||||
Skilldesc: d.String("skilldesc"),
|
Skilldesc: d.String("skilldesc"),
|
||||||
Srvstfunc: d.Number("srvstfunc"),
|
Srvstfunc: d.Number("srvstfunc"),
|
||||||
|
@ -22,7 +22,7 @@ type SuperUniqueRecord struct {
|
|||||||
// Name for this SuperUnique which must be retrieved from a .TBL file
|
// Name for this SuperUnique which must be retrieved from a .TBL file
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// the base monster type of the SuperUnique, refers to the "Key" field in monstats.go ("Id" column in the MonStats.txt)
|
// the base monster type of the SuperUnique, refers to the "Key" field in monstats.go ("ID" column in the MonStats.txt)
|
||||||
Class string
|
Class string
|
||||||
|
|
||||||
// This is the "hardcoded index".
|
// This is the "hardcoded index".
|
||||||
@ -39,7 +39,7 @@ type SuperUniqueRecord struct {
|
|||||||
MonSound string
|
MonSound string
|
||||||
|
|
||||||
// These three fields assign special abilities so SuperUnique monsters such as "Fire Enchanted" or "Stone Skin".
|
// These three fields assign special abilities so SuperUnique monsters such as "Fire Enchanted" or "Stone Skin".
|
||||||
// These fields refers to the Id's corresponding to the properties in MonUMod.txt.
|
// These fields refers to the ID's corresponding to the properties in MonUMod.txt.
|
||||||
// Here is the list of available properties.
|
// Here is the list of available properties.
|
||||||
// 0. None
|
// 0. None
|
||||||
// 1. Inits the random name seed, automatically added to monster, you don't need to add this UMod.
|
// 1. Inits the random name seed, automatically added to monster, you don't need to add this UMod.
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
// Object is a game world object
|
// Object is a game world object
|
||||||
type Object struct {
|
type Object struct {
|
||||||
Type int
|
Type int
|
||||||
Id int //nolint:golint Id is the right key
|
Id int //nolint:golint ID is the right key
|
||||||
X int
|
X int
|
||||||
Y int
|
Y int
|
||||||
Flags int
|
Flags int
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package d2enum
|
package d2enum
|
||||||
|
|
||||||
// RegionIdType represents a region Id
|
// RegionIdType represents a region ID
|
||||||
type RegionIdType int //nolint:golint,stylecheck // many changed needed when changing to ID
|
type RegionIdType int //nolint:golint,stylecheck // many changed needed when changing to ID
|
||||||
|
|
||||||
// Regions
|
// Regions
|
||||||
|
@ -98,4 +98,3 @@ func (rn *RangedNumber) String() string {
|
|||||||
|
|
||||||
return fmt.Sprintf("%d to %d", rn.min, rn.max)
|
return fmt.Sprintf("%d to %d", rn.min, rn.max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,6 +287,7 @@ func (a *animation) SetPlayLength(playLength float64) {
|
|||||||
func (a *animation) SetPlayLengthMs(playLengthMs int) {
|
func (a *animation) SetPlayLengthMs(playLengthMs int) {
|
||||||
// TODO remove this method
|
// TODO remove this method
|
||||||
const millisecondsPerSecond = 1000.0
|
const millisecondsPerSecond = 1000.0
|
||||||
|
|
||||||
a.SetPlayLength(float64(playLengthMs) / millisecondsPerSecond)
|
a.SetPlayLength(float64(playLengthMs) / millisecondsPerSecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,9 @@ func (c *Composite) SetDirection(direction int) {
|
|||||||
for layerIdx := range c.mode.layers {
|
for layerIdx := range c.mode.layers {
|
||||||
layer := c.mode.layers[layerIdx]
|
layer := c.mode.layers[layerIdx]
|
||||||
if layer != nil {
|
if layer != nil {
|
||||||
layer.SetDirection(c.direction)
|
if err := layer.SetDirection(c.direction); err != nil {
|
||||||
|
fmt.Printf("failed to set direction of layer: %d, err: %v\n", layerIdx, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +184,9 @@ func (c *Composite) SetCurrentFrame(frame int) {
|
|||||||
for layerIdx := range c.mode.layers {
|
for layerIdx := range c.mode.layers {
|
||||||
layer := c.mode.layers[layerIdx]
|
layer := c.mode.layers[layerIdx]
|
||||||
if layer != nil {
|
if layer != nil {
|
||||||
layer.SetCurrentFrame(frame)
|
if err := layer.SetCurrentFrame(frame); err != nil {
|
||||||
|
fmt.Printf("failed to set current frame of layer: %d, err: %v\n", layerIdx, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,16 +26,14 @@ func CreateDC6Animation(renderer d2iface.Renderer, dc6Path string,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
animation := animation{
|
anim := DC6Animation{
|
||||||
|
animation: animation{
|
||||||
directions: make([]animationDirection, dc6.Directions),
|
directions: make([]animationDirection, dc6.Directions),
|
||||||
playLength: defaultPlayLength,
|
playLength: defaultPlayLength,
|
||||||
playLoop: true,
|
playLoop: true,
|
||||||
originAtBottom: true,
|
originAtBottom: true,
|
||||||
effect: effect,
|
effect: effect,
|
||||||
}
|
},
|
||||||
|
|
||||||
anim := DC6Animation{
|
|
||||||
animation: animation,
|
|
||||||
dc6Path: dc6Path,
|
dc6Path: dc6Path,
|
||||||
palette: palette,
|
palette: palette,
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
|
@ -21,7 +21,7 @@ type DCCAnimation struct {
|
|||||||
renderer d2iface.Renderer
|
renderer d2iface.Renderer
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette
|
// CreateDCCAnimation creates an animation from d2dcc.DCC and d2dat.DATPalette
|
||||||
func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2iface.Palette,
|
func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2iface.Palette,
|
||||||
effect d2enum.DrawEffect) (d2iface.Animation, error) {
|
effect d2enum.DrawEffect) (d2iface.Animation, error) {
|
||||||
dcc, err := loadDCC(dccPath)
|
dcc, err := loadDCC(dccPath)
|
||||||
|
@ -3,10 +3,11 @@ package ebiten
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
|
||||||
"github.com/hajimehoshi/ebiten/audio"
|
"github.com/hajimehoshi/ebiten/audio"
|
||||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SoundEffect represents an ebiten implementation of a sound effect
|
// SoundEffect represents an ebiten implementation of a sound effect
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
package ebiten
|
package ebiten
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
"github.com/hajimehoshi/ebiten/inpututil"
|
"github.com/hajimehoshi/ebiten/inpututil"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -31,21 +31,18 @@ type MapEngine struct {
|
|||||||
dt1Files []string // List of DS1 strings
|
dt1Files []string // List of DS1 strings
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMapEngine creates a new instance of the map engine and
|
// CreateMapEngine creates a new instance of the map engine and returns a pointer to it.
|
||||||
// returns a pointer to it.
|
|
||||||
func CreateMapEngine() *MapEngine {
|
func CreateMapEngine() *MapEngine {
|
||||||
engine := &MapEngine{}
|
engine := &MapEngine{}
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStartingPosition returns the starting position on the map in
|
// GetStartingPosition returns the starting position on the map in sub-tiles.
|
||||||
// sub-tiles.
|
func (m *MapEngine) GetStartingPosition() (x, y int) {
|
||||||
func (m *MapEngine) GetStartingPosition() (int, int) {
|
|
||||||
return m.startSubTileX, m.startSubTileY
|
return m.startSubTileX, m.startSubTileY
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetMap clears all map and entity data and reloads it from the
|
// ResetMap clears all map and entity data and reloads it from the cached files.
|
||||||
// cached files.
|
|
||||||
func (m *MapEngine) ResetMap(levelType d2enum.RegionIdType, width, height int) {
|
func (m *MapEngine) ResetMap(levelType d2enum.RegionIdType, width, height int) {
|
||||||
m.entities = make([]d2interface.MapEntity, 0)
|
m.entities = make([]d2interface.MapEntity, 0)
|
||||||
m.levelType = d2datadict.LevelTypes[levelType]
|
m.levelType = d2datadict.LevelTypes[levelType]
|
||||||
@ -176,8 +173,8 @@ func (m *MapEngine) tileCoordinateToIndex(x, y int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// converts tile index from MapEngine.tiles to x,y coordinate
|
// converts tile index from MapEngine.tiles to x,y coordinate
|
||||||
func (m *MapEngine) tileIndexToCoordinate(index int) (int, int) {
|
func (m *MapEngine) tileIndexToCoordinate(index int) (x, y int) {
|
||||||
return (index % m.size.Width), (index / m.size.Width)
|
return index % m.size.Width, index / m.size.Width
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubTileAt gets the flags for the given subtile
|
// SubTileAt gets the flags for the given subtile
|
||||||
@ -224,7 +221,7 @@ func (m *MapEngine) RemoveEntity(entity d2interface.MapEntity) {
|
|||||||
// GetTiles returns a slice of all tiles matching the given style,
|
// GetTiles returns a slice of all tiles matching the given style,
|
||||||
// sequence and tileType.
|
// sequence and tileType.
|
||||||
func (m *MapEngine) GetTiles(style, sequence, tileType int) []d2dt1.Tile {
|
func (m *MapEngine) GetTiles(style, sequence, tileType int) []d2dt1.Tile {
|
||||||
var tiles []d2dt1.Tile
|
tiles := make([]d2dt1.Tile, 0, len(m.dt1TileData))
|
||||||
|
|
||||||
for idx := range m.dt1TileData {
|
for idx := range m.dt1TileData {
|
||||||
if m.dt1TileData[idx].Style != int32(style) || m.dt1TileData[idx].Sequence != int32(sequence) ||
|
if m.dt1TileData[idx].Style != int32(style) || m.dt1TileData[idx].Sequence != int32(sequence) ||
|
||||||
@ -244,7 +241,7 @@ func (m *MapEngine) GetTiles(style, sequence, tileType int) []d2dt1.Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetStartPosition returns the spawn point on entering the current map.
|
// GetStartPosition returns the spawn point on entering the current map.
|
||||||
func (m *MapEngine) GetStartPosition() (float64, float64) {
|
func (m *MapEngine) GetStartPosition() (x, y float64) {
|
||||||
for tileY := 0; tileY < m.size.Height; tileY++ {
|
for tileY := 0; tileY < m.size.Height; tileY++ {
|
||||||
for tileX := 0; tileX < m.size.Width; tileX++ {
|
for tileX := 0; tileX < m.size.Width; tileX++ {
|
||||||
tile := m.tiles[tileX+(tileY*m.size.Width)].Components
|
tile := m.tiles[tileX+(tileY*m.size.Width)].Components
|
||||||
@ -260,7 +257,7 @@ func (m *MapEngine) GetStartPosition() (float64, float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCenterPosition returns the center point of the map.
|
// GetCenterPosition returns the center point of the map.
|
||||||
func (m *MapEngine) GetCenterPosition() (float64, float64) {
|
func (m *MapEngine) GetCenterPosition() (x, y float64) {
|
||||||
return float64(m.size.Width) / 2.0, float64(m.size.Height) / 2.0
|
return float64(m.size.Width) / 2.0, float64(m.size.Height) / 2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +287,7 @@ func (m *MapEngine) TileExists(tileX, tileY int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GenerateMap clears the map and places the specified stamp.
|
// GenerateMap clears the map and places the specified stamp.
|
||||||
func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int, cacheTiles bool) {
|
func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset, fileIndex int) {
|
||||||
region := d2mapstamp.LoadStamp(regionType, levelPreset, fileIndex)
|
region := d2mapstamp.LoadStamp(regionType, levelPreset, fileIndex)
|
||||||
regionSize := region.Size()
|
regionSize := region.Size()
|
||||||
m.ResetMap(regionType, regionSize.Width, regionSize.Height)
|
m.ResetMap(regionType, regionSize.Width, regionSize.Height)
|
||||||
|
@ -79,11 +79,9 @@ func (t *MapTile) PrepareTile(x, y int, me *MapEngine) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Walker's Alias Method for weighted random selection with xorshifting for random numbers
|
||||||
// Selects a random tile from the slice, rest of args just used for seeding
|
// Selects a random tile from the slice, rest of args just used for seeding
|
||||||
func getRandomTile(tiles []d2dt1.Tile, x, y int, seed int64) byte {
|
func getRandomTile(tiles []d2dt1.Tile, x, y int, seed int64) byte {
|
||||||
/* Walker's Alias Method for weighted random selection
|
|
||||||
* with xorshifting for random numbers */
|
|
||||||
|
|
||||||
var tileSeed uint64
|
var tileSeed uint64
|
||||||
tileSeed = uint64(seed) + uint64(x)
|
tileSeed = uint64(seed) + uint64(x)
|
||||||
tileSeed *= uint64(y)
|
tileSeed *= uint64(y)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PathFind finds a path between given start and dest positions and returns the positions of the path
|
||||||
func (m *MapEngine) PathFind(start, dest d2vector.Position) []d2vector.Position {
|
func (m *MapEngine) PathFind(start, dest d2vector.Position) []d2vector.Position {
|
||||||
points := make([]d2vector.Position, 0)
|
points := make([]d2vector.Position, 0)
|
||||||
_, point := m.checkLos(start, dest)
|
_, point := m.checkLos(start, dest)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package d2mapentity
|
package d2mapentity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,7 +36,10 @@ func (ae *AnimatedEntity) Render(target d2interface.Surface) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
defer target.Pop()
|
defer target.Pop()
|
||||||
ae.animation.Render(target)
|
|
||||||
|
if err := ae.animation.Render(target); err != nil {
|
||||||
|
fmt.Printf("failed to render animated entity, err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDirection returns the current facing direction of this entity.
|
// GetDirection returns the current facing direction of this entity.
|
||||||
@ -46,11 +51,15 @@ func (ae *AnimatedEntity) GetDirection() int {
|
|||||||
func (ae *AnimatedEntity) rotate(direction int) {
|
func (ae *AnimatedEntity) rotate(direction int) {
|
||||||
ae.direction = direction
|
ae.direction = direction
|
||||||
|
|
||||||
ae.animation.SetDirection(ae.direction)
|
if err := ae.animation.SetDirection(ae.direction); err != nil {
|
||||||
|
fmt.Printf("failed to update the animation direction, err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance is called once per frame and processes a
|
// Advance is called once per frame and processes a
|
||||||
// single game tick.
|
// single game tick.
|
||||||
func (ae *AnimatedEntity) Advance(elapsed float64) {
|
func (ae *AnimatedEntity) Advance(elapsed float64) {
|
||||||
ae.animation.Advance(elapsed)
|
if err := ae.animation.Advance(elapsed); err != nil {
|
||||||
|
fmt.Printf("failed to advance the animation, err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package d2mapentity
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// mapEntity represents an entity on the map that can be animated
|
// mapEntity represents an entity on the map that can be animated
|
||||||
|
@ -19,10 +19,12 @@ type Missile struct {
|
|||||||
record *d2datadict.MissileRecord
|
record *d2datadict.MissileRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPosition returns the position of the missile
|
||||||
func (m *Missile) GetPosition() d2vector.Position {
|
func (m *Missile) GetPosition() d2vector.Position {
|
||||||
return m.AnimatedEntity.Position
|
return m.AnimatedEntity.Position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVelocity returns the velocity vector of the missile
|
||||||
func (m *Missile) GetVelocity() d2vector.Vector {
|
func (m *Missile) GetVelocity() d2vector.Vector {
|
||||||
return m.AnimatedEntity.velocity
|
return m.AnimatedEntity.velocity
|
||||||
}
|
}
|
||||||
@ -42,7 +44,6 @@ func CreateMissile(x, y int, record *d2datadict.MissileRecord) (*Missile, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
animation.SetEffect(d2enum.DrawEffectModulate)
|
animation.SetEffect(d2enum.DrawEffectModulate)
|
||||||
// animation.SetPlaySpeed(float64(record.Animation.AnimationSpeed))
|
|
||||||
animation.SetPlayLoop(record.Animation.LoopAnimation)
|
animation.SetPlayLoop(record.Animation.LoopAnimation)
|
||||||
animation.PlayForward()
|
animation.PlayForward()
|
||||||
entity := CreateAnimatedEntity(x, y, animation)
|
entity := CreateAnimatedEntity(x, y, animation)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package d2mapentity
|
package d2mapentity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
@ -9,6 +8,7 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package d2mapentity
|
package d2mapentity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
@ -14,19 +16,21 @@ import (
|
|||||||
// Player is the player character entity.
|
// Player is the player character entity.
|
||||||
type Player struct {
|
type Player struct {
|
||||||
mapEntity
|
mapEntity
|
||||||
|
ID string
|
||||||
|
name string
|
||||||
|
animationMode string
|
||||||
composite *d2asset.Composite
|
composite *d2asset.Composite
|
||||||
Equipment *d2inventory.CharacterEquipment
|
Equipment *d2inventory.CharacterEquipment
|
||||||
Stats *d2hero.HeroStatsState
|
Stats *d2hero.HeroStatsState
|
||||||
Class d2enum.Hero
|
Class d2enum.Hero
|
||||||
Id string
|
|
||||||
name string
|
|
||||||
// nameLabel d2ui.Label
|
|
||||||
lastPathSize int
|
lastPathSize int
|
||||||
isInTown bool
|
isInTown bool
|
||||||
animationMode string
|
|
||||||
isRunToggled bool
|
isRunToggled bool
|
||||||
isRunning bool
|
isRunning bool
|
||||||
isCasting bool
|
isCasting bool
|
||||||
|
|
||||||
|
// nameLabel d2ui.Label
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// run speed should be walkspeed * 1.5, since in the original game it is 6 yards walk and 9 yards run.
|
// run speed should be walkspeed * 1.5, since in the original game it is 6 yards walk and 9 yards run.
|
||||||
@ -34,7 +38,7 @@ const baseWalkSpeed = 6.0
|
|||||||
const baseRunSpeed = 9.0
|
const baseRunSpeed = 9.0
|
||||||
|
|
||||||
// CreatePlayer creates a new player entity and returns a pointer to it.
|
// CreatePlayer creates a new player entity and returns a pointer to it.
|
||||||
func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero,
|
func CreatePlayer(id, name string, x, y, direction int, heroType d2enum.Hero,
|
||||||
stats *d2hero.HeroStatsState, equipment *d2inventory.CharacterEquipment) *Player {
|
stats *d2hero.HeroStatsState, equipment *d2inventory.CharacterEquipment) *Player {
|
||||||
layerEquipment := &[d2enum.CompositeTypeMax]string{
|
layerEquipment := &[d2enum.CompositeTypeMax]string{
|
||||||
d2enum.CompositeTypeHead: equipment.Head.GetArmorClass(),
|
d2enum.CompositeTypeHead: equipment.Head.GetArmorClass(),
|
||||||
@ -57,7 +61,7 @@ func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero
|
|||||||
stats.Stamina = stats.MaxStamina
|
stats.Stamina = stats.MaxStamina
|
||||||
|
|
||||||
result := &Player{
|
result := &Player{
|
||||||
Id: id,
|
ID: id,
|
||||||
mapEntity: newMapEntity(x, y),
|
mapEntity: newMapEntity(x, y),
|
||||||
composite: composite,
|
composite: composite,
|
||||||
Equipment: equipment,
|
Equipment: equipment,
|
||||||
@ -71,16 +75,17 @@ func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero
|
|||||||
}
|
}
|
||||||
result.SetSpeed(baseRunSpeed)
|
result.SetSpeed(baseRunSpeed)
|
||||||
result.mapEntity.directioner = result.rotate
|
result.mapEntity.directioner = result.rotate
|
||||||
//result.nameLabel.Alignment = d2ui.LabelAlignCenter
|
|
||||||
//result.nameLabel.SetText(name)
|
|
||||||
//result.nameLabel.Color = color.White
|
|
||||||
err = composite.SetMode(d2enum.PlayerAnimationModeTownNeutral, equipment.RightHand.GetWeaponClass())
|
err = composite.SetMode(d2enum.PlayerAnimationModeTownNeutral, equipment.RightHand.GetWeaponClass())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
composite.SetDirection(direction)
|
composite.SetDirection(direction)
|
||||||
composite.Equip(layerEquipment)
|
|
||||||
|
if err := composite.Equip(layerEquipment); err != nil {
|
||||||
|
fmt.Printf("failed to equip, err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -119,64 +124,69 @@ func (p *Player) SetIsRunning(isRunning bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsInTown returns true if the player is currently in town.
|
// IsInTown returns true if the player is currently in town.
|
||||||
func (p Player) IsInTown() bool {
|
func (p *Player) IsInTown() bool {
|
||||||
return p.isInTown
|
return p.isInTown
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance is called once per frame and processes a
|
// Advance is called once per frame and processes a
|
||||||
// single game tick.
|
// single game tick.
|
||||||
func (v *Player) Advance(tickTime float64) {
|
func (p *Player) Advance(tickTime float64) {
|
||||||
v.Step(tickTime)
|
p.Step(tickTime)
|
||||||
|
|
||||||
if v.IsCasting() && v.composite.GetPlayedCount() >= 1 {
|
if p.IsCasting() && p.composite.GetPlayedCount() >= 1 {
|
||||||
v.isCasting = false
|
p.isCasting = false
|
||||||
v.SetAnimationMode(v.GetAnimationMode())
|
if err := p.SetAnimationMode(p.GetAnimationMode()); err != nil {
|
||||||
|
fmt.Printf("failed to set animationMode to: %d, err: %v\n", p.GetAnimationMode(), err)
|
||||||
}
|
}
|
||||||
v.composite.Advance(tickTime)
|
|
||||||
|
|
||||||
if v.lastPathSize != len(v.path) {
|
|
||||||
v.lastPathSize = len(v.path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.composite.GetAnimationMode() != v.animationMode {
|
if err := p.composite.Advance(tickTime); err != nil {
|
||||||
v.animationMode = v.composite.GetAnimationMode()
|
fmt.Printf("failed to advance composite animation of player: %s, err: %v\n", p.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.lastPathSize != len(p.path) {
|
||||||
|
p.lastPathSize = len(p.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.composite.GetAnimationMode() != p.animationMode {
|
||||||
|
p.animationMode = p.composite.GetAnimationMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders the animated composite for this entity.
|
// Render renders the animated composite for this entity.
|
||||||
func (v *Player) Render(target d2interface.Surface) {
|
func (p *Player) Render(target d2interface.Surface) {
|
||||||
renderOffset := v.Position.RenderOffset()
|
renderOffset := p.Position.RenderOffset()
|
||||||
target.PushTranslation(
|
target.PushTranslation(
|
||||||
int((renderOffset.X()-renderOffset.Y())*16),
|
int((renderOffset.X()-renderOffset.Y())*16),
|
||||||
int(((renderOffset.X()+renderOffset.Y())*8)-5),
|
int(((renderOffset.X()+renderOffset.Y())*8)-5),
|
||||||
)
|
)
|
||||||
|
|
||||||
defer target.Pop()
|
defer target.Pop()
|
||||||
v.composite.Render(target)
|
|
||||||
// v.nameLabel.X = v.offsetX
|
if err := p.composite.Render(target); err != nil {
|
||||||
// v.nameLabel.Y = v.offsetY - 100
|
fmt.Printf("failed to render the composite of player: %s, err: %v\n", p.ID, err)
|
||||||
// v.nameLabel.Render(target)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAnimationMode returns the current animation mode based on what the player is doing and where they are.
|
// GetAnimationMode returns the current animation mode based on what the player is doing and where they are.
|
||||||
func (v *Player) GetAnimationMode() d2enum.PlayerAnimationMode {
|
func (p *Player) GetAnimationMode() d2enum.PlayerAnimationMode {
|
||||||
if v.IsRunning() && !v.atTarget() {
|
if p.IsRunning() && !p.atTarget() {
|
||||||
return d2enum.PlayerAnimationModeRun
|
return d2enum.PlayerAnimationModeRun
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.IsInTown() {
|
if p.IsInTown() {
|
||||||
if !v.atTarget() {
|
if !p.atTarget() {
|
||||||
return d2enum.PlayerAnimationModeTownWalk
|
return d2enum.PlayerAnimationModeTownWalk
|
||||||
}
|
}
|
||||||
|
|
||||||
return d2enum.PlayerAnimationModeTownNeutral
|
return d2enum.PlayerAnimationModeTownNeutral
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v.atTarget() {
|
if !p.atTarget() {
|
||||||
return d2enum.PlayerAnimationModeWalk
|
return d2enum.PlayerAnimationModeWalk
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.IsCasting() {
|
if p.IsCasting() {
|
||||||
return d2enum.PlayerAnimationModeCast
|
return d2enum.PlayerAnimationModeCast
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,44 +194,48 @@ func (v *Player) GetAnimationMode() d2enum.PlayerAnimationMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetAnimationMode sets the Composite's animation mode weapon class and direction.
|
// SetAnimationMode sets the Composite's animation mode weapon class and direction.
|
||||||
func (v *Player) SetAnimationMode(animationMode d2enum.PlayerAnimationMode) error {
|
func (p *Player) SetAnimationMode(animationMode d2enum.PlayerAnimationMode) error {
|
||||||
return v.composite.SetMode(animationMode, v.composite.GetWeaponClass())
|
return p.composite.SetMode(animationMode, p.composite.GetWeaponClass())
|
||||||
}
|
}
|
||||||
|
|
||||||
// rotate sets direction and changes animation
|
// rotate sets direction and changes animation
|
||||||
func (v *Player) rotate(direction int) {
|
func (p *Player) rotate(direction int) {
|
||||||
newAnimationMode := v.GetAnimationMode()
|
newAnimationMode := p.GetAnimationMode()
|
||||||
|
|
||||||
if newAnimationMode.String() != v.composite.GetAnimationMode() {
|
if newAnimationMode.String() != p.composite.GetAnimationMode() {
|
||||||
v.composite.SetMode(newAnimationMode, v.composite.GetWeaponClass())
|
if err := p.composite.SetMode(newAnimationMode, p.composite.GetWeaponClass()); err != nil {
|
||||||
|
fmt.Printf("failed to update animationMode of %s, err: %v\n", p.composite.GetWeaponClass(), err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if direction != v.composite.GetDirection() {
|
if direction != p.composite.GetDirection() {
|
||||||
v.composite.SetDirection(direction)
|
p.composite.SetDirection(direction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the player name.
|
// Name returns the player name.
|
||||||
func (v *Player) Name() string {
|
func (p *Player) Name() string {
|
||||||
return v.name
|
return p.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsCasting returns true if
|
// IsCasting returns true if
|
||||||
func (v *Player) IsCasting() bool {
|
func (p *Player) IsCasting() bool {
|
||||||
return v.isCasting
|
return p.isCasting
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCasting sets a flag indicating the player is casting a skill and
|
// SetCasting sets a flag indicating the player is casting a skill and
|
||||||
// sets the animation mode to the casting animation.
|
// sets the animation mode to the casting animation.
|
||||||
func (v *Player) SetCasting() {
|
func (p *Player) SetCasting() {
|
||||||
v.isCasting = true
|
p.isCasting = true
|
||||||
v.SetAnimationMode(d2enum.PlayerAnimationModeCast)
|
if err := p.SetAnimationMode(d2enum.PlayerAnimationModeCast); err != nil {
|
||||||
|
fmt.Printf("failed to set animationMode of player: %s to: %d, err: %v\n", p.ID, d2enum.PlayerAnimationModeCast, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selectable returns true if the player is in town.
|
// Selectable returns true if the player is in town.
|
||||||
func (v *Player) Selectable() bool {
|
func (p *Player) Selectable() bool {
|
||||||
// Players are selectable when in town
|
// Players are selectable when in town
|
||||||
return v.IsInTown()
|
return p.IsInTown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPosition returns the entity's position
|
// GetPosition returns the entity's position
|
||||||
|
@ -23,12 +23,13 @@ func (c *Camera) SetTarget(target *d2vector.Position) {
|
|||||||
c.target = target
|
c.target = target
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveBy adds the given vector to the current position of the Camera.
|
// MoveTargetBy adds the given vector to the current position of the Camera.
|
||||||
func (c *Camera) MoveTargetBy(vector *d2vector.Vector) {
|
func (c *Camera) MoveTargetBy(vector *d2vector.Vector) {
|
||||||
if c.target == nil {
|
if c.target == nil {
|
||||||
v := c.position.Clone()
|
v := c.position.Clone()
|
||||||
c.target = &d2vector.Position{v}
|
c.target = &d2vector.Position{Vector: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.target.Add(vector)
|
c.target.Add(vector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package d2maprenderer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
@ -43,14 +44,23 @@ func CreateMapRenderer(renderer d2interface.Renderer, mapEngine *d2mapengine.Map
|
|||||||
result.Camera.position = &startPosition
|
result.Camera.position = &startPosition
|
||||||
result.viewport.SetCamera(&result.Camera)
|
result.viewport.SetCamera(&result.Camera)
|
||||||
|
|
||||||
term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
|
var err error
|
||||||
|
err = term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
|
||||||
result.mapDebugVisLevel = level
|
result.mapDebugVisLevel = level
|
||||||
})
|
})
|
||||||
|
|
||||||
term.BindAction("entitydebugvis", "set entity debug visualization level", func(level int) {
|
if err != nil {
|
||||||
|
fmt.Printf("could not bind the mapdebugvis action, err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = term.BindAction("entitydebugvis", "set entity debug visualization level", func(level int) {
|
||||||
result.entityDebugVisLevel = level
|
result.entityDebugVisLevel = level
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("could not bind the entitydebugvis action, err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
if mapEngine.LevelType().ID != 0 {
|
if mapEngine.LevelType().ID != 0 {
|
||||||
result.generateTileCache()
|
result.generateTileCache()
|
||||||
}
|
}
|
||||||
@ -122,18 +132,18 @@ func (mr *MapRenderer) MoveCameraTargetBy(vector *d2vector.Vector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ScreenToWorld returns the world position for the given screen (pixel) position.
|
// ScreenToWorld returns the world position for the given screen (pixel) position.
|
||||||
func (mr *MapRenderer) ScreenToWorld(x, y int) (float64, float64) {
|
func (mr *MapRenderer) ScreenToWorld(x, y int) (worldX, worldY float64) {
|
||||||
return mr.viewport.ScreenToWorld(x, y)
|
return mr.viewport.ScreenToWorld(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScreenToOrtho returns the orthogonal position, without accounting for the isometric angle, for the given screen
|
// ScreenToOrtho returns the orthogonal position, without accounting for the isometric angle, for the given screen
|
||||||
// (pixel) position.
|
// (pixel) position.
|
||||||
func (mr *MapRenderer) ScreenToOrtho(x, y int) (float64, float64) {
|
func (mr *MapRenderer) ScreenToOrtho(x, y int) (orthoX, orthoY float64) {
|
||||||
return mr.viewport.ScreenToOrtho(x, y)
|
return mr.viewport.ScreenToOrtho(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WorldToOrtho returns the orthogonal position for the given isometric world position.
|
// WorldToOrtho returns the orthogonal position for the given isometric world position.
|
||||||
func (mr *MapRenderer) WorldToOrtho(x, y float64) (float64, float64) {
|
func (mr *MapRenderer) WorldToOrtho(x, y float64) (orthoX, orthoY float64) {
|
||||||
return mr.viewport.WorldToOrtho(x, y)
|
return mr.viewport.WorldToOrtho(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +288,9 @@ func (mr *MapRenderer) renderFloor(tile d2ds1.FloorShadowRecord, target d2interf
|
|||||||
target.PushTranslation(mr.viewport.GetTranslationScreen())
|
target.PushTranslation(mr.viewport.GetTranslationScreen())
|
||||||
defer target.Pop()
|
defer target.Pop()
|
||||||
|
|
||||||
target.Render(img)
|
if err := target.Render(img); err != nil {
|
||||||
|
fmt.Printf("failed to render the floor, err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) renderWall(tile d2ds1.WallRecord, viewport *Viewport, target d2interface.Surface) {
|
func (mr *MapRenderer) renderWall(tile d2ds1.WallRecord, viewport *Viewport, target d2interface.Surface) {
|
||||||
@ -294,7 +306,9 @@ func (mr *MapRenderer) renderWall(tile d2ds1.WallRecord, viewport *Viewport, tar
|
|||||||
target.PushTranslation(viewport.GetTranslationScreen())
|
target.PushTranslation(viewport.GetTranslationScreen())
|
||||||
defer target.Pop()
|
defer target.Pop()
|
||||||
|
|
||||||
target.Render(img)
|
if err := target.Render(img); err != nil {
|
||||||
|
fmt.Printf("failed to render the wall, err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) renderShadow(tile d2ds1.FloorShadowRecord, target d2interface.Surface) {
|
func (mr *MapRenderer) renderShadow(tile d2ds1.FloorShadowRecord, target d2interface.Surface) {
|
||||||
@ -311,7 +325,9 @@ func (mr *MapRenderer) renderShadow(tile d2ds1.FloorShadowRecord, target d2inter
|
|||||||
|
|
||||||
defer target.PopN(2)
|
defer target.PopN(2)
|
||||||
|
|
||||||
target.Render(img)
|
if err := target.Render(img); err != nil {
|
||||||
|
fmt.Printf("failed to render the shadow, err: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) renderMapDebug(mapDebugVisLevel int, target d2interface.Surface, startX, startY, endX, endY int) {
|
func (mr *MapRenderer) renderMapDebug(mapDebugVisLevel int, target d2interface.Surface, startX, startY, endX, endY int) {
|
||||||
@ -333,7 +349,6 @@ func (mr *MapRenderer) renderEntityDebug(target d2interface.Surface) {
|
|||||||
x, y := world.X()/5, world.Y()/5
|
x, y := world.X()/5, world.Y()/5
|
||||||
velocity := e.GetVelocity()
|
velocity := e.GetVelocity()
|
||||||
velocity = velocity.Clone()
|
velocity = velocity.Clone()
|
||||||
// velocity.Scale(60) // arbitrary scale value, just to make it easy to see
|
|
||||||
vx, vy := mr.viewport.WorldToOrtho(velocity.X(), velocity.Y())
|
vx, vy := mr.viewport.WorldToOrtho(velocity.X(), velocity.Y())
|
||||||
screenX, screenY := mr.viewport.WorldToScreen(x, y)
|
screenX, screenY := mr.viewport.WorldToScreen(x, y)
|
||||||
|
|
||||||
@ -355,16 +370,16 @@ func (mr *MapRenderer) renderEntityDebug(target d2interface.Surface) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WorldToScreen returns the screen (pixel) position for the given isometric world position as two ints.
|
// WorldToScreen returns the screen (pixel) position for the given isometric world position as two ints.
|
||||||
func (mr *MapRenderer) WorldToScreen(x, y float64) (int, int) {
|
func (mr *MapRenderer) WorldToScreen(x, y float64) (screenX, screenY int) {
|
||||||
return mr.viewport.WorldToScreen(x, y)
|
return mr.viewport.WorldToScreen(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WorldToScreenF returns the screen (pixel) position for the given isometric world position as two float64s.
|
// WorldToScreenF returns the screen (pixel) position for the given isometric world position as two float64s.
|
||||||
func (mr *MapRenderer) WorldToScreenF(x, y float64) (float64, float64) {
|
func (mr *MapRenderer) WorldToScreenF(x, y float64) (screenX, screenY float64) {
|
||||||
return mr.viewport.WorldToScreenF(x, y)
|
return mr.viewport.WorldToScreenF(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) renderTileDebug(ax, ay int, debugVisLevel int, target d2interface.Surface) {
|
func (mr *MapRenderer) renderTileDebug(ax, ay, debugVisLevel int, target d2interface.Surface) {
|
||||||
subTileColor := color.RGBA{R: 80, G: 80, B: 255, A: 50}
|
subTileColor := color.RGBA{R: 80, G: 80, B: 255, A: 50}
|
||||||
tileColor := color.RGBA{R: 255, G: 255, B: 255, A: 100}
|
tileColor := color.RGBA{R: 255, G: 255, B: 255, A: 100}
|
||||||
tileCollisionColor := color.RGBA{R: 128, G: 0, B: 0, A: 100}
|
tileCollisionColor := color.RGBA{R: 128, G: 0, B: 0, A: 100}
|
||||||
@ -398,12 +413,6 @@ func (mr *MapRenderer) renderTileDebug(ax, ay int, debugVisLevel int, target d2i
|
|||||||
|
|
||||||
tile := mr.mapEngine.TileAt(ax, ay)
|
tile := mr.mapEngine.TileAt(ax, ay)
|
||||||
|
|
||||||
/*for i, floor := range tile.Floors {
|
|
||||||
target.PushTranslation(-20, 10+(i+1)*14)
|
|
||||||
target.DrawTextf("f: %v-%v", floor.Style, floor.Sequence)
|
|
||||||
target.Pop()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
for i, wall := range tile.Components.Walls {
|
for i, wall := range tile.Components.Walls {
|
||||||
if wall.Type.Special() {
|
if wall.Type.Special() {
|
||||||
target.PushTranslation(-20, 10+(i+1)*14)
|
target.PushTranslation(-20, 10+(i+1)*14)
|
||||||
|
@ -12,33 +12,32 @@ import (
|
|||||||
|
|
||||||
func (mr *MapRenderer) generateTileCache() {
|
func (mr *MapRenderer) generateTileCache() {
|
||||||
mr.palette, _ = loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
mr.palette, _ = loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
||||||
mapEngineSize := mr.mapEngine.Size()
|
|
||||||
|
|
||||||
for idx, tile := range *mr.mapEngine.Tiles() {
|
tiles := *mr.mapEngine.Tiles()
|
||||||
tileX := idx % mapEngineSize.Width
|
for idx := range tiles {
|
||||||
tileY := (idx - tileX) / mapEngineSize.Width
|
tile := &tiles[idx]
|
||||||
|
|
||||||
for i := range tile.Components.Floors {
|
for i := range tile.Components.Floors {
|
||||||
if !tile.Components.Floors[i].Hidden && tile.Components.Floors[i].Prop1 != 0 {
|
if !tile.Components.Floors[i].Hidden && tile.Components.Floors[i].Prop1 != 0 {
|
||||||
mr.generateFloorCache(&tile.Components.Floors[i], tileX, tileY)
|
mr.generateFloorCache(&tile.Components.Floors[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range tile.Components.Shadows {
|
for i := range tile.Components.Shadows {
|
||||||
if !tile.Components.Shadows[i].Hidden && tile.Components.Shadows[i].Prop1 != 0 {
|
if !tile.Components.Shadows[i].Hidden && tile.Components.Shadows[i].Prop1 != 0 {
|
||||||
mr.generateShadowCache(&tile.Components.Shadows[i], tileX, tileY)
|
mr.generateShadowCache(&tile.Components.Shadows[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range tile.Components.Walls {
|
for i := range tile.Components.Walls {
|
||||||
if !tile.Components.Walls[i].Hidden && tile.Components.Walls[i].Prop1 != 0 {
|
if !tile.Components.Walls[i].Hidden && tile.Components.Walls[i].Prop1 != 0 {
|
||||||
mr.generateWallCache(&tile.Components.Walls[i], tileX, tileY)
|
mr.generateWallCache(&tile.Components.Walls[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
|
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
|
||||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 0)
|
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 0)
|
||||||
|
|
||||||
var tileData []*d2dt1.Tile
|
var tileData []*d2dt1.Tile
|
||||||
@ -93,17 +92,17 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
|
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord) {
|
||||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 13)
|
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 13)
|
||||||
|
|
||||||
var tileData *d2dt1.Tile
|
var tileData *d2dt1.Tile
|
||||||
|
|
||||||
if tileOptions == nil {
|
if tileOptions == nil {
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
tileData = &tileOptions[tile.RandomIndex]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tileData = &tileOptions[tile.RandomIndex]
|
||||||
|
|
||||||
if tileData.Width == 0 || tileData.Height == 0 {
|
if tileData.Width == 0 || tileData.Height == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -133,7 +132,7 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX,
|
|||||||
mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex, image)
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY int) {
|
func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
|
||||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), int(tile.Type))
|
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), int(tile.Type))
|
||||||
|
|
||||||
var tileData *d2dt1.Tile
|
var tileData *d2dt1.Tile
|
||||||
@ -167,7 +166,6 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY in
|
|||||||
|
|
||||||
realHeight := d2common.MaxInt32(d2common.AbsInt32(tileData.Height), tileMaxY-tileMinY)
|
realHeight := d2common.MaxInt32(d2common.AbsInt32(tileData.Height), tileMaxY-tileMinY)
|
||||||
tileYOffset := -tileMinY
|
tileYOffset := -tileMinY
|
||||||
/*tileHeight := int(tileMaxY - tileMinY)*/
|
|
||||||
|
|
||||||
if tile.Type == 15 {
|
if tile.Type == 15 {
|
||||||
tile.YAdjust = -int(tileData.RoofHeight)
|
tile.YAdjust = -int(tileData.RoofHeight)
|
||||||
|
@ -52,61 +52,61 @@ func (v *Viewport) SetCamera(camera *Camera) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WorldToScreen returns the screen space for the given world coordinates as two integers.
|
// WorldToScreen returns the screen space for the given world coordinates as two integers.
|
||||||
func (v *Viewport) WorldToScreen(x, y float64) (int, int) {
|
func (v *Viewport) WorldToScreen(x, y float64) (screenX, screenY int) {
|
||||||
return v.OrthoToScreen(v.WorldToOrtho(x, y))
|
return v.OrthoToScreen(v.WorldToOrtho(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WorldToScreenF returns the screen space for the given world coordinates as two float64s.
|
// WorldToScreenF returns the screen space for the given world coordinates as two float64s.
|
||||||
func (v *Viewport) WorldToScreenF(x, y float64) (float64, float64) {
|
func (v *Viewport) WorldToScreenF(x, y float64) (screenX, screenY float64) {
|
||||||
return v.OrthoToScreenF(v.WorldToOrtho(x, y))
|
return v.OrthoToScreenF(v.WorldToOrtho(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScreenToWorld returns the world position for the given screen coordinates.
|
// ScreenToWorld returns the world position for the given screen coordinates.
|
||||||
func (v *Viewport) ScreenToWorld(x, y int) (float64, float64) {
|
func (v *Viewport) ScreenToWorld(x, y int) (worldX, worldY float64) {
|
||||||
return v.OrthoToWorld(v.ScreenToOrtho(x, y))
|
return v.OrthoToWorld(v.ScreenToOrtho(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrthoToWorld returns the world position for the given orthogonal coordinates.
|
// OrthoToWorld returns the world position for the given orthogonal coordinates.
|
||||||
func (v *Viewport) OrthoToWorld(x, y float64) (float64, float64) {
|
func (v *Viewport) OrthoToWorld(x, y float64) (worldX, worldY float64) {
|
||||||
worldX := (x/80 + y/40) / 2
|
worldX = (x/80 + y/40) / 2
|
||||||
worldY := (y/40 - x/80) / 2
|
worldY = (y/40 - x/80) / 2
|
||||||
|
|
||||||
return worldX, worldY
|
return worldX, worldY
|
||||||
}
|
}
|
||||||
|
|
||||||
// WorldToOrtho returns the orthogonal position for the given world coordinates.
|
// WorldToOrtho returns the orthogonal position for the given world coordinates.
|
||||||
func (v *Viewport) WorldToOrtho(x, y float64) (float64, float64) {
|
func (v *Viewport) WorldToOrtho(x, y float64) (orthoX, orthoY float64) {
|
||||||
orthoX := (x - y) * 80
|
orthoX = (x - y) * 80
|
||||||
orthoY := (x + y) * 40
|
orthoY = (x + y) * 40
|
||||||
|
|
||||||
return orthoX, orthoY
|
return orthoX, orthoY
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScreenToOrtho returns the orthogonal position for the given screen coordinates.
|
// ScreenToOrtho returns the orthogonal position for the given screen coordinates.
|
||||||
func (v *Viewport) ScreenToOrtho(x, y int) (float64, float64) {
|
func (v *Viewport) ScreenToOrtho(x, y int) (orthoX, orthoY float64) {
|
||||||
camX, camY := v.getCameraOffset()
|
camX, camY := v.getCameraOffset()
|
||||||
screenX := float64(x) + camX - float64(v.screenRect.Left)
|
orthoX = float64(x) + camX - float64(v.screenRect.Left)
|
||||||
screenY := float64(y) + camY - float64(v.screenRect.Top)
|
orthoY = float64(y) + camY - float64(v.screenRect.Top)
|
||||||
|
|
||||||
|
return orthoX, orthoY
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrthoToScreen returns the screen position for the given orthogonal coordinates as two ints.
|
||||||
|
func (v *Viewport) OrthoToScreen(x, y float64) (screenX, screenY int) {
|
||||||
|
camOrthoX, camOrthoY := v.getCameraOffset()
|
||||||
|
screenX = int(math.Floor(x - camOrthoX + float64(v.screenRect.Left)))
|
||||||
|
screenY = int(math.Floor(y - camOrthoY + float64(v.screenRect.Top)))
|
||||||
|
|
||||||
return screenX, screenY
|
return screenX, screenY
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrthoToScreen returns the screen position for the given orthogonal coordinates as two ints.
|
|
||||||
func (v *Viewport) OrthoToScreen(x, y float64) (int, int) {
|
|
||||||
camOrthoX, camOrthoY := v.getCameraOffset()
|
|
||||||
orthoX := int(math.Floor(x - camOrthoX + float64(v.screenRect.Left)))
|
|
||||||
orthoY := int(math.Floor(y - camOrthoY + float64(v.screenRect.Top)))
|
|
||||||
|
|
||||||
return orthoX, orthoY
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrthoToScreenF returns the screen position for the given orthogonal coordinates as two float64s.
|
// OrthoToScreenF returns the screen position for the given orthogonal coordinates as two float64s.
|
||||||
func (v *Viewport) OrthoToScreenF(x, y float64) (float64, float64) {
|
func (v *Viewport) OrthoToScreenF(x, y float64) (screenX, screenY float64) {
|
||||||
camOrthoX, camOrthoY := v.getCameraOffset()
|
camOrthoX, camOrthoY := v.getCameraOffset()
|
||||||
orthoX := x - camOrthoX + float64(v.screenRect.Left)
|
screenX = x - camOrthoX + float64(v.screenRect.Left)
|
||||||
orthoY := y - camOrthoY + float64(v.screenRect.Top)
|
screenY = y - camOrthoY + float64(v.screenRect.Top)
|
||||||
|
|
||||||
return orthoX, orthoY
|
return screenX, screenY
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTileVisible returns false if no part of the tile is within the game screen.
|
// IsTileVisible returns false if no part of the tile is within the game screen.
|
||||||
@ -136,12 +136,12 @@ func (v *Viewport) IsOrthoRectVisible(x1, y1, x2, y2 float64) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTranslationOrtho returns the viewport's current orthogonal space translation.
|
// GetTranslationOrtho returns the viewport's current orthogonal space translation.
|
||||||
func (v *Viewport) GetTranslationOrtho() (float64, float64) {
|
func (v *Viewport) GetTranslationOrtho() (orthoX, orthoY float64) {
|
||||||
return v.transCurrent.x, v.transCurrent.y
|
return v.transCurrent.x, v.transCurrent.y
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTranslationScreen returns the viewport's current screen space translation.
|
// GetTranslationScreen returns the viewport's current screen space translation.
|
||||||
func (v *Viewport) GetTranslationScreen() (int, int) {
|
func (v *Viewport) GetTranslationScreen() (screenX, screenY int) {
|
||||||
return v.OrthoToScreen(v.transCurrent.x, v.transCurrent.y)
|
return v.OrthoToScreen(v.transCurrent.x, v.transCurrent.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,8 +175,7 @@ func (v *Viewport) PopTranslation() {
|
|||||||
v.transStack = v.transStack[:count-1]
|
v.transStack = v.transStack[:count-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Viewport) getCameraOffset() (float64, float64) {
|
func (v *Viewport) getCameraOffset() (camX, camY float64) {
|
||||||
var camX, camY float64
|
|
||||||
if v.camera != nil {
|
if v.camera != nil {
|
||||||
camPosition := v.camera.GetPosition()
|
camPosition := v.camera.GetPosition()
|
||||||
camX, camY = camPosition.X(), camPosition.Y()
|
camX, camY = camPosition.X(), camPosition.Y()
|
||||||
|
@ -3,11 +3,12 @@ package ebiten
|
|||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten"
|
||||||
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||||
"github.com/hajimehoshi/ebiten"
|
|
||||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -6,11 +6,12 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten"
|
||||||
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2DebugUtil"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2DebugUtil"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
"github.com/hajimehoshi/ebiten"
|
|
||||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -56,14 +56,18 @@ func Advance(elapsed float64) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
log.Println("loadingState chan should not be closed while in a loading screen")
|
log.Println("loadingState chan should not be closed while in a loading screen")
|
||||||
}
|
}
|
||||||
|
|
||||||
if load.err != nil {
|
if load.err != nil {
|
||||||
log.Printf("PROBLEM LOADING THE SCREEN: %v", load.err)
|
log.Printf("PROBLEM LOADING THE SCREEN: %v", load.err)
|
||||||
return load.err
|
return load.err
|
||||||
}
|
}
|
||||||
|
|
||||||
d2gui.ShowLoadScreen(load.progress)
|
d2gui.ShowLoadScreen(load.progress)
|
||||||
|
|
||||||
if load.done {
|
if load.done {
|
||||||
singleton.currentScreen = singleton.loadingScreen
|
singleton.currentScreen = singleton.loadingScreen
|
||||||
singleton.loadingScreen = nil
|
singleton.loadingScreen = nil
|
||||||
|
|
||||||
d2gui.ShowCursor()
|
d2gui.ShowCursor()
|
||||||
d2gui.HideLoadScreen()
|
d2gui.HideLoadScreen()
|
||||||
}
|
}
|
||||||
@ -80,17 +84,21 @@ func Advance(elapsed float64) error {
|
|||||||
if handler, ok := singleton.nextScreen.(ScreenLoadHandler); ok {
|
if handler, ok := singleton.nextScreen.(ScreenLoadHandler); ok {
|
||||||
d2gui.ShowLoadScreen(0)
|
d2gui.ShowLoadScreen(0)
|
||||||
d2gui.HideCursor()
|
d2gui.HideCursor()
|
||||||
|
|
||||||
singleton.loadingState = LoadingState{updates: make(chan loadingUpdate)}
|
singleton.loadingState = LoadingState{updates: make(chan loadingUpdate)}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
handler.OnLoad(singleton.loadingState)
|
handler.OnLoad(singleton.loadingState)
|
||||||
singleton.loadingState.Done()
|
singleton.loadingState.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
singleton.currentScreen = nil
|
singleton.currentScreen = nil
|
||||||
singleton.loadingScreen = singleton.nextScreen
|
singleton.loadingScreen = singleton.nextScreen
|
||||||
} else {
|
} else {
|
||||||
singleton.currentScreen = singleton.nextScreen
|
singleton.currentScreen = singleton.nextScreen
|
||||||
singleton.loadingScreen = nil
|
singleton.loadingScreen = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
singleton.nextScreen = nil
|
singleton.nextScreen = nil
|
||||||
case singleton.currentScreen != nil:
|
case singleton.currentScreen != nil:
|
||||||
if handler, ok := singleton.currentScreen.(ScreenAdvanceHandler); ok {
|
if handler, ok := singleton.currentScreen.(ScreenAdvanceHandler); ok {
|
||||||
@ -119,6 +127,8 @@ type LoadingState struct {
|
|||||||
updates chan loadingUpdate
|
updates chan loadingUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const progressCompleted = 1.0
|
||||||
|
|
||||||
type loadingUpdate struct {
|
type loadingUpdate struct {
|
||||||
progress float64
|
progress float64
|
||||||
err error
|
err error
|
||||||
@ -137,6 +147,6 @@ func (l *LoadingState) Progress(ratio float64) {
|
|||||||
|
|
||||||
// Done provides a way for callers to report that screen loading has been completed.
|
// Done provides a way for callers to report that screen loading has been completed.
|
||||||
func (l *LoadingState) Done() {
|
func (l *LoadingState) Done() {
|
||||||
l.updates <- loadingUpdate{progress: 1.0}
|
l.updates <- loadingUpdate{progress: progressCompleted}
|
||||||
l.updates <- loadingUpdate{done: true}
|
l.updates <- loadingUpdate{done: true}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||||
@ -14,6 +16,7 @@ import (
|
|||||||
// ButtonType defines the type of button
|
// ButtonType defines the type of button
|
||||||
type ButtonType int
|
type ButtonType int
|
||||||
|
|
||||||
|
// ButtonType constants
|
||||||
const (
|
const (
|
||||||
ButtonTypeWide ButtonType = 1
|
ButtonTypeWide ButtonType = 1
|
||||||
ButtonTypeMedium ButtonType = 2
|
ButtonTypeMedium ButtonType = 2
|
||||||
@ -42,64 +45,59 @@ const (
|
|||||||
|
|
||||||
// ButtonLayout defines the type of buttons
|
// ButtonLayout defines the type of buttons
|
||||||
type ButtonLayout struct {
|
type ButtonLayout struct {
|
||||||
XSegments int // 1
|
ResourceName string
|
||||||
YSegments int // 1
|
PaletteName string
|
||||||
ResourceName string // Font Name
|
FontPath string
|
||||||
PaletteName string // PaletteType
|
XSegments int
|
||||||
Toggleable bool // false
|
YSegments int
|
||||||
BaseFrame int // 0
|
BaseFrame int
|
||||||
DisabledFrame int // -1
|
DisabledFrame int
|
||||||
FontPath string // ResourcePaths.FontExocet10
|
ClickableRect *image.Rectangle
|
||||||
ClickableRect *image.Rectangle // nil
|
TextOffset int
|
||||||
AllowFrameChange bool // true
|
Toggleable bool
|
||||||
TextOffset int // 0
|
AllowFrameChange bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ButtonLayouts define the type of buttons you can have
|
func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||||
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
return map[ButtonType]ButtonLayout{
|
||||||
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
ButtonTypeWide: {
|
||||||
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
XSegments: 2, YSegments: 1, ResourceName: d2resource.WideButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||||
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
DisabledFrame: -1, FontPath: d2resource.FontExocet10, AllowFrameChange: true, TextOffset: 1},
|
||||||
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
ButtonTypeShort: {
|
||||||
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
XSegments: 1, YSegments: 1, ResourceName: d2resource.ShortButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||||
ButtonTypeRun: {1, 1, d2resource.RunButton, d2resource.PaletteSky, true, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
DisabledFrame: -1, FontPath: d2resource.FontRediculous, AllowFrameChange: true, TextOffset: -1},
|
||||||
/*
|
ButtonTypeMedium: {
|
||||||
{eButtonType.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } },
|
XSegments: 1, YSegments: 1, ResourceName: d2resource.MediumButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||||
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } },
|
FontPath: d2resource.FontExocet10, AllowFrameChange: true},
|
||||||
{eButtonType.Cancel, new ButtonLayout { ResourceName = ResourcePaths.CancelButton, PaletteName = PaletteDefs.Units } },
|
ButtonTypeTall: {
|
||||||
// Minipanel
|
XSegments: 1, YSegments: 1, ResourceName: d2resource.TallButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||||
{eButtonType.MinipanelCharacter, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 0 } },
|
FontPath: d2resource.FontExocet10, AllowFrameChange: true, TextOffset: 5},
|
||||||
{eButtonType.MinipanelInventory, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 2 } },
|
ButtonTypeOkCancel: {
|
||||||
{eButtonType.MinipanelSkill, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 4 } },
|
XSegments: 1, YSegments: 1, ResourceName: d2resource.CancelButton, PaletteName: d2resource.PaletteUnits,
|
||||||
{eButtonType.MinipanelAutomap, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 8 } },
|
DisabledFrame: -1, FontPath: d2resource.FontRediculous, AllowFrameChange: true},
|
||||||
{eButtonType.MinipanelMessage, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 10 } },
|
ButtonTypeRun: {
|
||||||
{eButtonType.MinipanelQuest, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 12 } },
|
XSegments: 1, YSegments: 1, ResourceName: d2resource.RunButton, PaletteName: d2resource.PaletteSky,
|
||||||
{eButtonType.MinipanelMenu, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 14 } },
|
Toggleable: true, DisabledFrame: -1, FontPath: d2resource.FontRediculous, AllowFrameChange: true},
|
||||||
|
}
|
||||||
{eButtonType.SecondaryInvHand, new ButtonLayout { ResourceName = ResourcePaths.InventoryWeaponsTab, PaletteName = PaletteDefs.Units, ClickableRect = new Rectangle(0, 0, 0, 20), AllowFrameChange = false } },
|
|
||||||
{eButtonType.Run, new ButtonLayout { ResourceName = ResourcePaths.RunButton, PaletteName = PaletteDefs.Units, Toggleable = true } },
|
|
||||||
{eButtonType.Menu, new ButtonLayout { ResourceName = ResourcePaths.MenuButton, PaletteName = PaletteDefs.Units, Toggleable = true } },
|
|
||||||
{eButtonType.GoldCoin, new ButtonLayout { ResourceName = ResourcePaths.GoldCoinButton, PaletteName = PaletteDefs.Units } },
|
|
||||||
{eButtonType.Close, new ButtonLayout { ResourceName = ResourcePaths.SquareButton, PaletteName = PaletteDefs.Units, BaseFrame = 10 } },
|
|
||||||
{eButtonType.Skill, new ButtonLayout { ResourceName = ResourcePaths.AddSkillButton, PaletteName = PaletteDefs.Units, DisabledFrame = 2
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button defines a standard wide UI button
|
// Button defines a standard wide UI button
|
||||||
type Button struct {
|
type Button struct {
|
||||||
enabled bool
|
buttonLayout ButtonLayout
|
||||||
x, y int
|
|
||||||
width, height int
|
|
||||||
visible bool
|
|
||||||
pressed bool
|
|
||||||
toggled bool
|
|
||||||
normalSurface d2interface.Surface
|
normalSurface d2interface.Surface
|
||||||
pressedSurface d2interface.Surface
|
pressedSurface d2interface.Surface
|
||||||
toggledSurface d2interface.Surface
|
toggledSurface d2interface.Surface
|
||||||
pressedToggledSurface d2interface.Surface
|
pressedToggledSurface d2interface.Surface
|
||||||
disabledSurface d2interface.Surface
|
disabledSurface d2interface.Surface
|
||||||
buttonLayout ButtonLayout
|
x int
|
||||||
|
y int
|
||||||
|
width int
|
||||||
|
height int
|
||||||
onClick func()
|
onClick func()
|
||||||
|
enabled bool
|
||||||
|
visible bool
|
||||||
|
pressed bool
|
||||||
|
toggled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateButton creates an instance of Button
|
// CreateButton creates an instance of Button
|
||||||
@ -111,7 +109,7 @@ func CreateButton(renderer d2interface.Renderer, buttonType ButtonType, text str
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
pressed: false,
|
pressed: false,
|
||||||
}
|
}
|
||||||
buttonLayout := ButtonLayouts[buttonType]
|
buttonLayout := getButtonLayouts()[buttonType]
|
||||||
result.buttonLayout = buttonLayout
|
result.buttonLayout = buttonLayout
|
||||||
lbl := CreateLabel(buttonLayout.FontPath, d2resource.PaletteUnits)
|
lbl := CreateLabel(buttonLayout.FontPath, d2resource.PaletteUnits)
|
||||||
lbl.SetText(text)
|
lbl.SetText(text)
|
||||||
@ -120,59 +118,93 @@ func CreateButton(renderer d2interface.Renderer, buttonType ButtonType, text str
|
|||||||
|
|
||||||
animation, _ := d2asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
animation, _ := d2asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
||||||
buttonSprite, _ := LoadSprite(animation)
|
buttonSprite, _ := LoadSprite(animation)
|
||||||
totalButtonTypes := buttonSprite.GetFrameCount() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
|
||||||
for i := 0; i < buttonLayout.XSegments; i++ {
|
for i := 0; i < buttonLayout.XSegments; i++ {
|
||||||
w, _, _ := buttonSprite.GetFrameSize(i)
|
w, _, _ := buttonSprite.GetFrameSize(i)
|
||||||
result.width += w
|
result.width += w
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < buttonLayout.YSegments; i++ {
|
for i := 0; i < buttonLayout.YSegments; i++ {
|
||||||
_, h, _ := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
_, h, _ := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
||||||
result.height += h
|
result.height += h
|
||||||
}
|
}
|
||||||
|
|
||||||
result.normalSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
result.normalSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
||||||
_, labelHeight := lbl.GetSize()
|
|
||||||
|
|
||||||
textY := result.height / 2 - labelHeight / 2
|
|
||||||
xOffset := result.width / 2
|
|
||||||
|
|
||||||
buttonSprite.SetPosition(0, 0)
|
buttonSprite.SetPosition(0, 0)
|
||||||
buttonSprite.SetEffect(d2enum.DrawEffectModulate)
|
buttonSprite.SetEffect(d2enum.DrawEffectModulate)
|
||||||
buttonSprite.RenderSegmented(result.normalSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
|
||||||
|
|
||||||
lbl.SetPosition(xOffset, textY)
|
result.renderFrames(renderer, buttonSprite, &buttonLayout, &lbl)
|
||||||
lbl.Render(result.normalSurface)
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Button) renderFrames(renderer d2interface.Renderer, buttonSprite *Sprite, buttonLayout *ButtonLayout, label *Label) {
|
||||||
|
totalButtonTypes := buttonSprite.GetFrameCount() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
err = buttonSprite.RenderSegmented(v.normalSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to render button normalSurface, err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, labelHeight := label.GetSize()
|
||||||
|
textY := v.height/2 - labelHeight/2
|
||||||
|
xOffset := v.width / 2
|
||||||
|
|
||||||
|
label.SetPosition(xOffset, textY)
|
||||||
|
label.Render(v.normalSurface)
|
||||||
|
|
||||||
if buttonLayout.AllowFrameChange {
|
if buttonLayout.AllowFrameChange {
|
||||||
if totalButtonTypes > 1 {
|
if totalButtonTypes > 1 {
|
||||||
result.pressedSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
v.pressedSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||||
buttonSprite.RenderSegmented(result.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
err = buttonSprite.RenderSegmented(v.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
||||||
|
|
||||||
lbl.SetPosition(xOffset-2, textY + 2)
|
if err != nil {
|
||||||
lbl.Render(result.pressedSurface)
|
fmt.Printf("failed to render button pressedSurface, err: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label.SetPosition(xOffset-2, textY+2)
|
||||||
|
label.Render(v.pressedSurface)
|
||||||
|
}
|
||||||
|
|
||||||
if totalButtonTypes > 2 {
|
if totalButtonTypes > 2 {
|
||||||
result.toggledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
v.toggledSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||||
buttonSprite.RenderSegmented(result.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
err = buttonSprite.RenderSegmented(v.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
||||||
|
|
||||||
lbl.SetPosition(xOffset, textY)
|
if err != nil {
|
||||||
lbl.Render(result.toggledSurface)
|
fmt.Printf("failed to render button toggledSurface, err: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label.SetPosition(xOffset, textY)
|
||||||
|
label.Render(v.toggledSurface)
|
||||||
|
}
|
||||||
|
|
||||||
if totalButtonTypes > 3 {
|
if totalButtonTypes > 3 {
|
||||||
result.pressedToggledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
v.pressedToggledSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||||
buttonSprite.RenderSegmented(result.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
err = buttonSprite.RenderSegmented(v.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
||||||
|
|
||||||
lbl.SetPosition(xOffset, textY)
|
if err != nil {
|
||||||
lbl.Render(result.pressedToggledSurface)
|
fmt.Printf("failed to render button pressedToggledSurface, err: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label.SetPosition(xOffset, textY)
|
||||||
|
label.Render(v.pressedToggledSurface)
|
||||||
|
}
|
||||||
|
|
||||||
if buttonLayout.DisabledFrame != -1 {
|
if buttonLayout.DisabledFrame != -1 {
|
||||||
result.disabledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
v.disabledSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||||
buttonSprite.RenderSegmented(result.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
err = buttonSprite.RenderSegmented(v.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
||||||
|
|
||||||
lbl.SetPosition(xOffset, textY)
|
if err != nil {
|
||||||
lbl.Render(result.disabledSurface)
|
fmt.Printf("failed to render button disabledSurface, err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
label.SetPosition(xOffset, textY)
|
||||||
|
label.Render(v.disabledSurface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnActivated defines the callback handler for the activate event
|
// OnActivated defines the callback handler for the activate event
|
||||||
@ -185,6 +217,7 @@ func (v *Button) Activate() {
|
|||||||
if v.onClick == nil {
|
if v.onClick == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v.onClick()
|
v.onClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,27 +225,37 @@ func (v *Button) Activate() {
|
|||||||
func (v *Button) Render(target d2interface.Surface) {
|
func (v *Button) Render(target d2interface.Surface) {
|
||||||
target.PushFilter(d2enum.FilterNearest)
|
target.PushFilter(d2enum.FilterNearest)
|
||||||
target.PushTranslation(v.x, v.y)
|
target.PushTranslation(v.x, v.y)
|
||||||
|
|
||||||
defer target.PopN(2)
|
defer target.PopN(2)
|
||||||
|
|
||||||
if !v.enabled {
|
var err error
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case !v.enabled:
|
||||||
target.PushColor(color.RGBA{R: 128, G: 128, B: 128, A: 195})
|
target.PushColor(color.RGBA{R: 128, G: 128, B: 128, A: 195})
|
||||||
defer target.Pop()
|
defer target.Pop()
|
||||||
target.Render(v.disabledSurface)
|
err = target.Render(v.disabledSurface)
|
||||||
} else if v.toggled && v.pressed {
|
case v.toggled && v.pressed:
|
||||||
target.Render(v.pressedToggledSurface)
|
err = target.Render(v.pressedToggledSurface)
|
||||||
} else if v.pressed {
|
case v.pressed:
|
||||||
target.Render(v.pressedSurface)
|
err = target.Render(v.pressedSurface)
|
||||||
} else if v.toggled {
|
case v.toggled:
|
||||||
target.Render(v.toggledSurface)
|
err = target.Render(v.toggledSurface)
|
||||||
} else {
|
default:
|
||||||
target.Render(v.normalSurface)
|
err = target.Render(v.normalSurface)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to render button surface, err: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle negates the toggled state of the button
|
||||||
func (v *Button) Toggle() {
|
func (v *Button) Toggle() {
|
||||||
v.toggled = !v.toggled
|
v.toggled = !v.toggled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Advance advances the button state
|
||||||
func (v *Button) Advance(elapsed float64) {
|
func (v *Button) Advance(elapsed float64) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -227,8 +270,8 @@ func (v *Button) SetEnabled(enabled bool) {
|
|||||||
v.enabled = enabled
|
v.enabled = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the size of the button
|
// GetSize returns the size of the button
|
||||||
func (v *Button) GetSize() (int, int) {
|
func (v *Button) GetSize() (width, height int) {
|
||||||
return v.width, v.height
|
return v.width, v.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@ package d2gamescreen
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
@ -170,7 +171,7 @@ func (v *Game) Advance(elapsed float64) error {
|
|||||||
|
|
||||||
func (v *Game) bindGameControls() {
|
func (v *Game) bindGameControls() {
|
||||||
for _, player := range v.gameClient.Players {
|
for _, player := range v.gameClient.Players {
|
||||||
if player.Id != v.gameClient.PlayerID {
|
if player.ID != v.gameClient.PlayerID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +180,7 @@ func (v *Game) bindGameControls() {
|
|||||||
v.gameControls.Load()
|
v.gameControls.Load()
|
||||||
|
|
||||||
if err := v.inputManager.BindHandler(v.gameControls); err != nil {
|
if err := v.inputManager.BindHandler(v.gameControls); err != nil {
|
||||||
fmt.Printf(bindControlsErrStr, player.Id)
|
fmt.Printf(bindControlsErrStr, player.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -71,6 +71,11 @@ const (
|
|||||||
joinGameCharacterFilter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:"
|
joinGameCharacterFilter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BuildInfo contains information about the current build
|
||||||
|
type BuildInfo struct {
|
||||||
|
Branch, Commit string
|
||||||
|
}
|
||||||
|
|
||||||
// MainMenu represents the main menu
|
// MainMenu represents the main menu
|
||||||
type MainMenu struct {
|
type MainMenu struct {
|
||||||
tcpIPBackground *d2ui.Sprite
|
tcpIPBackground *d2ui.Sprite
|
||||||
@ -111,6 +116,8 @@ type MainMenu struct {
|
|||||||
audioProvider d2interface.AudioProvider
|
audioProvider d2interface.AudioProvider
|
||||||
scriptEngine *d2script.ScriptEngine
|
scriptEngine *d2script.ScriptEngine
|
||||||
navigator Navigator
|
navigator Navigator
|
||||||
|
|
||||||
|
buildInfo BuildInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMainMenu creates an instance of MainMenu
|
// CreateMainMenu creates an instance of MainMenu
|
||||||
@ -119,6 +126,7 @@ func CreateMainMenu(
|
|||||||
renderer d2interface.Renderer,
|
renderer d2interface.Renderer,
|
||||||
inputManager d2interface.InputManager,
|
inputManager d2interface.InputManager,
|
||||||
audioProvider d2interface.AudioProvider,
|
audioProvider d2interface.AudioProvider,
|
||||||
|
buildInfo BuildInfo,
|
||||||
) *MainMenu {
|
) *MainMenu {
|
||||||
return &MainMenu{
|
return &MainMenu{
|
||||||
screenMode: ScreenModeUnknown,
|
screenMode: ScreenModeUnknown,
|
||||||
@ -178,13 +186,13 @@ func (v *MainMenu) loadBackgroundSprites() {
|
|||||||
func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
||||||
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||||
v.versionLabel.Alignment = d2gui.HorizontalAlignRight
|
v.versionLabel.Alignment = d2gui.HorizontalAlignRight
|
||||||
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
|
v.versionLabel.SetText("OpenDiablo2 - " + v.buildInfo.Branch)
|
||||||
v.versionLabel.Color = rgbaColor(white)
|
v.versionLabel.Color = rgbaColor(white)
|
||||||
v.versionLabel.SetPosition(versionLabelX, versionLabelY)
|
v.versionLabel.SetPosition(versionLabelX, versionLabelY)
|
||||||
|
|
||||||
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||||
v.commitLabel.Alignment = d2gui.HorizontalAlignLeft
|
v.commitLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||||
v.commitLabel.SetText(d2common.BuildInfo.Commit)
|
v.commitLabel.SetText(v.buildInfo.Commit)
|
||||||
v.commitLabel.Color = rgbaColor(white)
|
v.commitLabel.Color = rgbaColor(white)
|
||||||
v.commitLabel.SetPosition(commitLabelX, commitLabelY)
|
v.commitLabel.SetPosition(commitLabelX, commitLabelY)
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
|
|||||||
} else {
|
} else {
|
||||||
met.mapEngine = d2mapengine.CreateMapEngine() // necessary for map name update
|
met.mapEngine = d2mapengine.CreateMapEngine() // necessary for map name update
|
||||||
met.mapEngine.SetSeed(time.Now().UnixNano())
|
met.mapEngine.SetSeed(time.Now().UnixNano())
|
||||||
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex, true)
|
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
|
||||||
//met.mapEngine.RegenerateWalkPaths()
|
//met.mapEngine.RegenerateWalkPaths()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ func (g *GameClient) handleAddPlayerPacket(packet d2netpacket.NetPacket) error {
|
|||||||
newPlayer := d2mapentity.CreatePlayer(player.ID, player.Name, player.X, player.Y, 0,
|
newPlayer := d2mapentity.CreatePlayer(player.ID, player.Name, player.X, player.Y, 0,
|
||||||
player.HeroType, player.Stats, &player.Equipment)
|
player.HeroType, player.Stats, &player.Equipment)
|
||||||
|
|
||||||
g.Players[newPlayer.Id] = newPlayer
|
g.Players[newPlayer.ID] = newPlayer
|
||||||
g.MapEngine.AddEntity(newPlayer)
|
g.MapEngine.AddEntity(newPlayer)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -199,7 +199,7 @@ func (g *GameClient) handleMovePlayerPacket(packet d2netpacket.NetPacket) error
|
|||||||
err := player.SetAnimationMode(player.GetAnimationMode())
|
err := player.SetAnimationMode(player.GetAnimationMode())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("GameClient: error setting animation mode for player %s: %s", player.Id, err)
|
log.Printf("GameClient: error setting animation mode for player %s: %s", player.ID, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,11 @@ func CreateScriptEngine() *ScriptEngine {
|
|||||||
fmt.Printf("Script: %s\n", call.Argument(0).String())
|
fmt.Printf("Script: %s\n", call.Argument(0).String())
|
||||||
return otto.Value{}
|
return otto.Value{}
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("could not bind the 'debugPrint' to the given function in script engine")
|
fmt.Printf("could not bind the 'debugPrint' to the given function in script engine")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ScriptEngine{
|
return &ScriptEngine{
|
||||||
vm: vm,
|
vm: vm,
|
||||||
isEvalAllowed: false,
|
isEvalAllowed: false,
|
||||||
@ -37,7 +39,7 @@ func (s *ScriptEngine) AllowEval() {
|
|||||||
s.isEvalAllowed = true
|
s.isEvalAllowed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllowEval disallows the evaluation of JS code.
|
// DisallowEval disallows the evaluation of JS code.
|
||||||
func (s *ScriptEngine) DisallowEval() {
|
func (s *ScriptEngine) DisallowEval() {
|
||||||
s.isEvalAllowed = false
|
s.isEvalAllowed = false
|
||||||
}
|
}
|
||||||
@ -82,5 +84,6 @@ func (s *ScriptEngine) Eval(code string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return val.String(), nil
|
return val.String(), nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user