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"
|
||||
"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/d2data"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
@ -32,9 +36,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
"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
|
||||
@ -91,7 +92,7 @@ func Create(gitBranch, gitCommit string,
|
||||
}
|
||||
|
||||
// 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()
|
||||
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 err := p.initialize(); err != nil {
|
||||
if gameErr := p.renderer.Run(updateInitError, 800, 600, windowTitle); gameErr != nil {
|
||||
if err := a.initialize(); err != nil {
|
||||
if gameErr := a.renderer.Run(updateInitError, 800, 600, windowTitle); gameErr != nil {
|
||||
return gameErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
p.ToMainMenu()
|
||||
a.ToMainMenu()
|
||||
|
||||
if p.gitBranch == "" {
|
||||
p.gitBranch = "Local Build"
|
||||
if a.gitBranch == "" {
|
||||
a.gitBranch = "Local Build"
|
||||
}
|
||||
|
||||
d2common.SetBuildInfo(p.gitBranch, p.gitCommit)
|
||||
|
||||
if err := p.renderer.Run(p.update, 800, 600, windowTitle); err != nil {
|
||||
if err := a.renderer.Run(a.update, 800, 600, windowTitle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) initialize() error {
|
||||
p.timeScale = 1.0
|
||||
p.lastTime = d2common.Now()
|
||||
p.lastScreenAdvance = p.lastTime
|
||||
func (a *App) initialize() error {
|
||||
a.timeScale = 1.0
|
||||
a.lastTime = d2common.Now()
|
||||
a.lastScreenAdvance = a.lastTime
|
||||
|
||||
p.renderer.SetWindowIcon("d2logo.png")
|
||||
p.terminal.BindLogger()
|
||||
a.renderer.SetWindowIcon("d2logo.png")
|
||||
a.terminal.BindLogger()
|
||||
|
||||
terminalActions := [...]bindTerminalEntry{
|
||||
{"dumpheap", "dumps the heap to pprof/heap.pprof", p.dumpHeap},
|
||||
{"fullscreen", "toggles fullscreen", p.toggleFullScreen},
|
||||
{"capframe", "captures a still frame", p.captureFrame},
|
||||
{"capgifstart", "captures an animation (start)", p.startAnimationCapture},
|
||||
{"capgifstop", "captures an animation (stop)", p.stopAnimationCapture},
|
||||
{"vsync", "toggles vsync", p.toggleVsync},
|
||||
{"fps", "toggle fps counter", p.toggleFpsCounter},
|
||||
{"timescale", "set scalar for elapsed time", p.setTimeScale},
|
||||
{"quit", "exits the game", p.quitGame},
|
||||
{"screen-gui", "enters the gui playground screen", p.enterGuiPlayground},
|
||||
{"js", "eval JS scripts", p.evalJS},
|
||||
{"dumpheap", "dumps the heap to pprof/heap.pprof", a.dumpHeap},
|
||||
{"fullscreen", "toggles fullscreen", a.toggleFullScreen},
|
||||
{"capframe", "captures a still frame", a.captureFrame},
|
||||
{"capgifstart", "captures an animation (start)", a.startAnimationCapture},
|
||||
{"capgifstop", "captures an animation (stop)", a.stopAnimationCapture},
|
||||
{"vsync", "toggles vsync", a.toggleVsync},
|
||||
{"fps", "toggle fps counter", a.toggleFpsCounter},
|
||||
{"timescale", "set scalar for elapsed time", a.setTimeScale},
|
||||
{"quit", "exits the game", a.quitGame},
|
||||
{"screen-gui", "enters the gui playground screen", a.enterGuiPlayground},
|
||||
{"js", "eval JS scripts", a.evalJS},
|
||||
}
|
||||
|
||||
for idx := range terminalActions {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
if err := d2asset.Initialize(p.renderer, p.terminal); err != nil {
|
||||
if err := d2asset.Initialize(a.renderer, a.terminal); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d2gui.Initialize(p.inputManager); err != nil {
|
||||
if err := d2gui.Initialize(a.inputManager); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if err := p.loadStrings(); err != nil {
|
||||
if err := a.loadStrings(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d2inventory.LoadHeroObjects()
|
||||
|
||||
d2ui.Initialize(p.inputManager, p.audio)
|
||||
d2ui.Initialize(a.inputManager, a.audio)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) loadStrings() error {
|
||||
func (a *App) loadStrings() error {
|
||||
tablePaths := []string{
|
||||
d2resource.PatchStringTable,
|
||||
d2resource.ExpansionStringTable,
|
||||
@ -202,7 +201,7 @@ func (p *App) loadStrings() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) loadDataDict() error {
|
||||
func (a *App) loadDataDict() error {
|
||||
entries := []struct {
|
||||
path string
|
||||
loader func(data []byte)
|
||||
@ -256,14 +255,14 @@ func (p *App) loadDataDict() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) renderDebug(target d2interface.Surface) error {
|
||||
if !p.showFPS {
|
||||
func (a *App) renderDebug(target d2interface.Surface) error {
|
||||
if !a.showFPS {
|
||||
return nil
|
||||
}
|
||||
|
||||
vsyncEnabled := p.renderer.GetVSyncEnabled()
|
||||
fps := p.renderer.CurrentFPS()
|
||||
cx, cy := p.renderer.GetCursorPos()
|
||||
vsyncEnabled := a.renderer.GetVSyncEnabled()
|
||||
fps := a.renderer.CurrentFPS()
|
||||
cx, cy := a.renderer.GetCursorPos()
|
||||
|
||||
target.PushTranslation(5, 565)
|
||||
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.DrawTextf("Alloc " + strconv.FormatInt(int64(m.Alloc)/bytesToMegabyte, 10))
|
||||
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.DrawTextf("Pause " + strconv.FormatInt(int64(m.PauseTotalNs/bytesToMegabyte), 10))
|
||||
target.PushTranslation(0, 16)
|
||||
@ -289,18 +288,18 @@ func (p *App) renderDebug(target d2interface.Surface) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) renderCapture(target d2interface.Surface) error {
|
||||
func (a *App) renderCapture(target d2interface.Surface) error {
|
||||
cleanupCapture := func() {
|
||||
p.captureState = captureStateNone
|
||||
p.capturePath = ""
|
||||
p.captureFrames = nil
|
||||
a.captureState = captureStateNone
|
||||
a.capturePath = ""
|
||||
a.captureFrames = nil
|
||||
}
|
||||
|
||||
switch p.captureState {
|
||||
switch a.captureState {
|
||||
case captureStateFrame:
|
||||
defer cleanupCapture()
|
||||
|
||||
fp, err := os.Create(p.capturePath)
|
||||
fp, err := os.Create(a.capturePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -316,15 +315,15 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("saved frame to %s", p.capturePath)
|
||||
log.Printf("saved frame to %s", a.capturePath)
|
||||
case captureStateGif:
|
||||
screenshot := target.Screenshot()
|
||||
p.captureFrames = append(p.captureFrames, screenshot)
|
||||
a.captureFrames = append(a.captureFrames, screenshot)
|
||||
case captureStateNone:
|
||||
if len(p.captureFrames) > 0 {
|
||||
if len(a.captureFrames) > 0 {
|
||||
defer cleanupCapture()
|
||||
|
||||
fp, err := os.Create(p.capturePath)
|
||||
fp, err := os.Create(a.capturePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -336,7 +335,7 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
||||
}()
|
||||
|
||||
var (
|
||||
framesTotal = len(p.captureFrames)
|
||||
framesTotal = len(a.captureFrames)
|
||||
framesPal = make([]*image.Paletted, framesTotal)
|
||||
frameDelays = make([]int, framesTotal)
|
||||
framesPerCPU = framesTotal / runtime.NumCPU()
|
||||
@ -352,7 +351,7 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
||||
|
||||
for j := start; j < end; j++ {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -373,14 +372,14 @@ func (p *App) renderCapture(target d2interface.Surface) error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("saved animation to %s", p.capturePath)
|
||||
log.Printf("saved animation to %s", a.capturePath)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -391,26 +390,26 @@ func (p *App) render(target d2interface.Surface) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.renderDebug(target); err != nil {
|
||||
if err := a.renderDebug(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.renderCapture(target); err != nil {
|
||||
if err := a.renderCapture(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.terminal.Render(target); err != nil {
|
||||
if err := a.terminal.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) advance(elapsed, current float64) error {
|
||||
elapsedLastScreenAdvance := (current - p.lastScreenAdvance) * p.timeScale
|
||||
func (a *App) advance(elapsed, current float64) error {
|
||||
elapsedLastScreenAdvance := (current - a.lastScreenAdvance) * a.timeScale
|
||||
|
||||
if elapsedLastScreenAdvance > defaultFPS {
|
||||
p.lastScreenAdvance = current
|
||||
a.lastScreenAdvance = current
|
||||
|
||||
if err := d2screen.Advance(elapsedLastScreenAdvance); err != nil {
|
||||
return err
|
||||
@ -419,7 +418,7 @@ func (p *App) advance(elapsed, current float64) error {
|
||||
|
||||
d2ui.Advance(elapsed)
|
||||
|
||||
if err := p.inputManager.Advance(elapsed, current); err != nil {
|
||||
if err := a.inputManager.Advance(elapsed, current); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -427,23 +426,23 @@ func (p *App) advance(elapsed, current float64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.terminal.Advance(elapsed); err != nil {
|
||||
if err := a.terminal.Advance(elapsed); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) update(target d2interface.Surface) error {
|
||||
func (a *App) update(target d2interface.Surface) error {
|
||||
currentTime := d2common.Now()
|
||||
elapsedTime := (currentTime - p.lastTime) * p.timeScale
|
||||
p.lastTime = currentTime
|
||||
elapsedTime := (currentTime - a.lastTime) * a.timeScale
|
||||
a.lastTime = currentTime
|
||||
|
||||
if err := p.advance(elapsedTime, currentTime); err != nil {
|
||||
if err := a.advance(elapsedTime, currentTime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.render(target); err != nil {
|
||||
if err := a.render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -454,15 +453,15 @@ func (p *App) update(target d2interface.Surface) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *App) allocRate(totalAlloc uint64, fps float64) float64 {
|
||||
p.tAllocSamples.Value = totalAlloc
|
||||
p.tAllocSamples = p.tAllocSamples.Next()
|
||||
deltaAllocPerFrame := float64(totalAlloc-p.tAllocSamples.Value.(uint64)) / nSamplesTAlloc
|
||||
func (a *App) allocRate(totalAlloc uint64, fps float64) float64 {
|
||||
a.tAllocSamples.Value = totalAlloc
|
||||
a.tAllocSamples = a.tAllocSamples.Next()
|
||||
deltaAllocPerFrame := float64(totalAlloc-a.tAllocSamples.Value.(uint64)) / nSamplesTAlloc
|
||||
|
||||
return deltaAllocPerFrame * fps / bytesToMegabyte
|
||||
}
|
||||
|
||||
func (p *App) dumpHeap() {
|
||||
func (a *App) dumpHeap() {
|
||||
if err := os.Mkdir("./pprof/", 0750); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -478,64 +477,64 @@ func (p *App) dumpHeap() {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *App) evalJS(code string) {
|
||||
val, err := p.scriptEngine.Eval(code)
|
||||
func (a *App) evalJS(code string) {
|
||||
val, err := a.scriptEngine.Eval(code)
|
||||
if err != nil {
|
||||
p.terminal.OutputErrorf("%s", err)
|
||||
a.terminal.OutputErrorf("%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("%s", val)
|
||||
}
|
||||
|
||||
func (p *App) toggleFullScreen() {
|
||||
fullscreen := !p.renderer.IsFullScreen()
|
||||
p.renderer.SetFullScreen(fullscreen)
|
||||
p.terminal.OutputInfof("fullscreen is now: %v", fullscreen)
|
||||
func (a *App) toggleFullScreen() {
|
||||
fullscreen := !a.renderer.IsFullScreen()
|
||||
a.renderer.SetFullScreen(fullscreen)
|
||||
a.terminal.OutputInfof("fullscreen is now: %v", fullscreen)
|
||||
}
|
||||
|
||||
func (p *App) captureFrame(path string) {
|
||||
p.captureState = captureStateFrame
|
||||
p.capturePath = path
|
||||
p.captureFrames = nil
|
||||
func (a *App) captureFrame(path string) {
|
||||
a.captureState = captureStateFrame
|
||||
a.capturePath = path
|
||||
a.captureFrames = nil
|
||||
}
|
||||
|
||||
func (p *App) startAnimationCapture(path string) {
|
||||
p.captureState = captureStateGif
|
||||
p.capturePath = path
|
||||
p.captureFrames = nil
|
||||
func (a *App) startAnimationCapture(path string) {
|
||||
a.captureState = captureStateGif
|
||||
a.capturePath = path
|
||||
a.captureFrames = nil
|
||||
}
|
||||
|
||||
func (p *App) stopAnimationCapture() {
|
||||
p.captureState = captureStateNone
|
||||
func (a *App) stopAnimationCapture() {
|
||||
a.captureState = captureStateNone
|
||||
}
|
||||
|
||||
func (p *App) toggleVsync() {
|
||||
vsync := !p.renderer.GetVSyncEnabled()
|
||||
p.renderer.SetVSyncEnabled(vsync)
|
||||
p.terminal.OutputInfof("vsync is now: %v", vsync)
|
||||
func (a *App) toggleVsync() {
|
||||
vsync := !a.renderer.GetVSyncEnabled()
|
||||
a.renderer.SetVSyncEnabled(vsync)
|
||||
a.terminal.OutputInfof("vsync is now: %v", vsync)
|
||||
}
|
||||
|
||||
func (p *App) toggleFpsCounter() {
|
||||
p.showFPS = !p.showFPS
|
||||
p.terminal.OutputInfof("fps counter is now: %v", p.showFPS)
|
||||
func (a *App) toggleFpsCounter() {
|
||||
a.showFPS = !a.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 {
|
||||
p.terminal.OutputErrorf("invalid time scale value")
|
||||
a.terminal.OutputErrorf("invalid time scale value")
|
||||
} else {
|
||||
p.terminal.OutputInfof("timescale changed from %f to %f", p.timeScale, timeScale)
|
||||
p.timeScale = timeScale
|
||||
a.terminal.OutputInfof("timescale changed from %f to %f", a.timeScale, timeScale)
|
||||
a.timeScale = timeScale
|
||||
}
|
||||
}
|
||||
|
||||
func (p *App) quitGame() {
|
||||
func (a *App) quitGame() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func (p *App) enterGuiPlayground() {
|
||||
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(p.renderer))
|
||||
func (a *App) enterGuiPlayground() {
|
||||
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(a.renderer))
|
||||
}
|
||||
|
||||
func createZeroedRing(n int) *ring.Ring {
|
||||
@ -604,7 +603,7 @@ func updateInitError(target d2interface.Surface) error {
|
||||
}
|
||||
|
||||
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)
|
||||
d2screen.SetNextScreen(mainMenu)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
var _ d2interface.BitStream = &BitStream{} // Static check to confirm struct conforms to interface
|
||||
|
||||
const (
|
||||
maxBits = 16
|
||||
maxBits = 16
|
||||
bitsPerByte = 8
|
||||
)
|
||||
|
||||
|
@ -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: d.String("Hireling"),
|
||||
SubType: d.String("SubType"),
|
||||
ID: d.Number("Id"),
|
||||
ID: d.Number("ID"),
|
||||
Class: d.Number("Class"),
|
||||
Act: d.Number("Act"),
|
||||
Difficulty: d.Number("Difficulty"),
|
||||
@ -109,7 +109,7 @@ func LoadHireling(file []byte) {
|
||||
HP: d.Number("HP"),
|
||||
HPPerLvl: d.Number("HP/Lvl"),
|
||||
Defense: d.Number("Defense"),
|
||||
DefPerLvl: d.Number("Id"),
|
||||
DefPerLvl: d.Number("ID"),
|
||||
Str: d.Number("Str"),
|
||||
StrPerLvl: d.Number("Str/Lvl"),
|
||||
Dex: d.Number("Dex"),
|
||||
|
@ -36,7 +36,7 @@ func LoadLevelWarps(file []byte) {
|
||||
for d.Next() {
|
||||
record := &LevelWarpRecord{
|
||||
Name: d.String("Name"),
|
||||
ID: d.Number("Id"),
|
||||
ID: d.Number("ID"),
|
||||
SelectX: d.Number("SelectX"),
|
||||
SelectY: d.Number("SelectY"),
|
||||
SelectDX: d.Number("SelectDX"),
|
||||
|
@ -74,7 +74,7 @@ type LevelDetailsRecord struct {
|
||||
MonsterUniqueID9 string // umon9
|
||||
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
|
||||
// in monstats2.txt. Critters are in reality only present clientside.
|
||||
MonsterCritterID1 string // cmon1
|
||||
@ -93,9 +93,9 @@ type LevelDetailsRecord struct {
|
||||
// present in the expension folders)
|
||||
TitleImageName string // EntryFile
|
||||
|
||||
// Id
|
||||
// ID
|
||||
// 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 int // Pal
|
||||
@ -138,7 +138,7 @@ type LevelDetailsRecord struct {
|
||||
// location.
|
||||
DependantLevelID int // Depend
|
||||
|
||||
// The type of the Level (Id from lvltypes.txt)
|
||||
// The type of the Level (ID from lvltypes.txt)
|
||||
LevelType int // LevelType
|
||||
|
||||
// Controls if teleport is allowed in that level.
|
||||
@ -367,7 +367,7 @@ type LevelDetailsRecord struct {
|
||||
//nolint:gochecknoglobals // Currently global by design, only written once
|
||||
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 {
|
||||
for i := 0; i < len(LevelDetails); i++ {
|
||||
if LevelDetails[i].Id == id {
|
||||
@ -387,7 +387,7 @@ func LoadLevelDetails(file []byte) {
|
||||
for d.Next() {
|
||||
record := &LevelDetailsRecord{
|
||||
Name: d.String("Name "),
|
||||
Id: d.Number("Id"),
|
||||
Id: d.Number("ID"),
|
||||
Palette: d.Number("Pal"),
|
||||
Act: d.Number("Act"),
|
||||
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
|
||||
// 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
|
||||
ClientCollisionFunc int
|
||||
|
@ -17,9 +17,9 @@ type (
|
||||
|
||||
// Key contains the pointer that will be used in other txt files
|
||||
// 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,
|
||||
// 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
|
||||
@ -80,10 +80,10 @@ type (
|
||||
// which animation mode will the spawned monster be spawned in.
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
// SoundKeyNormal, SoundKeySpecial
|
||||
@ -690,7 +690,7 @@ func LoadMonStats(file []byte) { // nolint:funlen // Makes no sense to split
|
||||
d := d2common.LoadDataDictionary(file)
|
||||
for d.Next() {
|
||||
record := &MonStatsRecord{
|
||||
Key: d.String("Id"),
|
||||
Key: d.String("ID"),
|
||||
Id: d.Number("hcIdx"),
|
||||
BaseKey: d.String("BaseId"),
|
||||
NextKey: d.String("NextInClass"),
|
||||
|
@ -177,7 +177,7 @@ func LoadMonStats2(file []byte) {
|
||||
d := d2common.LoadDataDictionary(file)
|
||||
for d.Next() {
|
||||
record := &MonStats2Record{
|
||||
Key: d.String("Id"),
|
||||
Key: d.String("ID"),
|
||||
Height: d.Number("Height"),
|
||||
OverlayHeight: d.Number("OverlayHeight"),
|
||||
PixelHeight: d.Number("pixHeight"),
|
||||
|
@ -10,11 +10,11 @@ import (
|
||||
type ObjectLookupRecord struct {
|
||||
Act int
|
||||
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
|
||||
Description string
|
||||
ObjectsTxtId int //nolint:golint,stylecheck // Id is the right key
|
||||
MonstatsTxtId 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
|
||||
Direction int
|
||||
Base string
|
||||
Token string
|
||||
@ -44,7 +44,7 @@ type ObjectLookupRecord struct {
|
||||
func LookupObject(act, typ, id int) *ObjectLookupRecord {
|
||||
object := lookupObject(act, typ, id, indexedObjects)
|
||||
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
|
||||
@ -96,6 +96,6 @@ func indexObjects(objects []ObjectLookupRecord) [][][]*ObjectLookupRecord {
|
||||
|
||||
// IndexedObjects is a slice of object records for quick lookups.
|
||||
// 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
|
||||
var indexedObjects [][][]*ObjectLookupRecord
|
||||
|
@ -281,7 +281,7 @@ func LoadSkills(file []byte) {
|
||||
for d.Next() {
|
||||
record := &SkillRecord{
|
||||
Skill: d.String("skill"),
|
||||
ID: d.Number("Id"),
|
||||
ID: d.Number("ID"),
|
||||
Charclass: d.String("charclass"),
|
||||
Skilldesc: d.String("skilldesc"),
|
||||
Srvstfunc: d.Number("srvstfunc"),
|
||||
|
@ -22,7 +22,7 @@ type SuperUniqueRecord struct {
|
||||
// Name for this SuperUnique which must be retrieved from a .TBL file
|
||||
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
|
||||
|
||||
// This is the "hardcoded index".
|
||||
@ -39,7 +39,7 @@ type SuperUniqueRecord struct {
|
||||
MonSound string
|
||||
|
||||
// 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.
|
||||
// 0. None
|
||||
// 1. Inits the random name seed, automatically added to monster, you don't need to add this UMod.
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
|
||||
// Object is a game world object
|
||||
type Object struct {
|
||||
Type int
|
||||
Id int //nolint:golint Id is the right key
|
||||
X int
|
||||
Y int
|
||||
Flags int
|
||||
Paths []d2common.Path
|
||||
Type int
|
||||
Id int //nolint:golint ID is the right key
|
||||
X int
|
||||
Y int
|
||||
Flags int
|
||||
Paths []d2common.Path
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
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
|
||||
|
||||
// Regions
|
||||
|
@ -78,17 +78,17 @@ func (rn *RangedNumber) Add(other *RangedNumber) *RangedNumber {
|
||||
|
||||
// Sub subtracts the given ranged number from this one, returning this one
|
||||
func (rn *RangedNumber) Sub(other *RangedNumber) *RangedNumber {
|
||||
return rn.Set(rn.min - other.min, rn.max - other.max)
|
||||
return rn.Set(rn.min-other.min, rn.max-other.max)
|
||||
}
|
||||
|
||||
// Mul multiplies this ranged number by the given ranged number, returning this one
|
||||
func (rn *RangedNumber) Mul(other *RangedNumber) *RangedNumber {
|
||||
return rn.Set(rn.min * other.min, rn.max * other.max)
|
||||
return rn.Set(rn.min*other.min, rn.max*other.max)
|
||||
}
|
||||
|
||||
// Div divides this ranged number by the given ranged number, returning this one
|
||||
func (rn *RangedNumber) Div(other *RangedNumber) *RangedNumber {
|
||||
return rn.Set(rn.min / other.min, rn.max / other.max)
|
||||
return rn.Set(rn.min/other.min, rn.max/other.max)
|
||||
}
|
||||
|
||||
func (rn *RangedNumber) String() string {
|
||||
@ -98,4 +98,3 @@ func (rn *RangedNumber) String() string {
|
||||
|
||||
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) {
|
||||
// TODO remove this method
|
||||
const millisecondsPerSecond = 1000.0
|
||||
|
||||
a.SetPlayLength(float64(playLengthMs) / millisecondsPerSecond)
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,9 @@ func (c *Composite) SetDirection(direction int) {
|
||||
for layerIdx := range c.mode.layers {
|
||||
layer := c.mode.layers[layerIdx]
|
||||
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 {
|
||||
layer := c.mode.layers[layerIdx]
|
||||
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,19 +26,17 @@ func CreateDC6Animation(renderer d2iface.Renderer, dc6Path string,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
animation := animation{
|
||||
directions: make([]animationDirection, dc6.Directions),
|
||||
playLength: defaultPlayLength,
|
||||
playLoop: true,
|
||||
originAtBottom: true,
|
||||
effect: effect,
|
||||
}
|
||||
|
||||
anim := DC6Animation{
|
||||
animation: animation,
|
||||
dc6Path: dc6Path,
|
||||
palette: palette,
|
||||
renderer: renderer,
|
||||
animation: animation{
|
||||
directions: make([]animationDirection, dc6.Directions),
|
||||
playLength: defaultPlayLength,
|
||||
playLoop: true,
|
||||
originAtBottom: true,
|
||||
effect: effect,
|
||||
},
|
||||
dc6Path: dc6Path,
|
||||
palette: palette,
|
||||
renderer: renderer,
|
||||
}
|
||||
|
||||
err = anim.SetDirection(0)
|
||||
|
@ -21,7 +21,7 @@ type DCCAnimation struct {
|
||||
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,
|
||||
effect d2enum.DrawEffect) (d2iface.Animation, error) {
|
||||
dcc, err := loadDCC(dccPath)
|
||||
|
@ -3,10 +3,11 @@ package ebiten
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/hajimehoshi/ebiten/audio"
|
||||
"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
|
||||
|
@ -2,9 +2,10 @@
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/inpututil"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -31,21 +31,18 @@ type MapEngine struct {
|
||||
dt1Files []string // List of DS1 strings
|
||||
}
|
||||
|
||||
// CreateMapEngine creates a new instance of the map engine and
|
||||
// returns a pointer to it.
|
||||
// CreateMapEngine creates a new instance of the map engine and returns a pointer to it.
|
||||
func CreateMapEngine() *MapEngine {
|
||||
engine := &MapEngine{}
|
||||
return engine
|
||||
}
|
||||
|
||||
// GetStartingPosition returns the starting position on the map in
|
||||
// sub-tiles.
|
||||
func (m *MapEngine) GetStartingPosition() (int, int) {
|
||||
// GetStartingPosition returns the starting position on the map in sub-tiles.
|
||||
func (m *MapEngine) GetStartingPosition() (x, y int) {
|
||||
return m.startSubTileX, m.startSubTileY
|
||||
}
|
||||
|
||||
// ResetMap clears all map and entity data and reloads it from the
|
||||
// cached files.
|
||||
// ResetMap clears all map and entity data and reloads it from the cached files.
|
||||
func (m *MapEngine) ResetMap(levelType d2enum.RegionIdType, width, height int) {
|
||||
m.entities = make([]d2interface.MapEntity, 0)
|
||||
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
|
||||
func (m *MapEngine) tileIndexToCoordinate(index int) (int, int) {
|
||||
return (index % m.size.Width), (index / m.size.Width)
|
||||
func (m *MapEngine) tileIndexToCoordinate(index int) (x, y int) {
|
||||
return index % m.size.Width, index / m.size.Width
|
||||
}
|
||||
|
||||
// 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,
|
||||
// sequence and tileType.
|
||||
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 {
|
||||
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.
|
||||
func (m *MapEngine) GetStartPosition() (float64, float64) {
|
||||
func (m *MapEngine) GetStartPosition() (x, y float64) {
|
||||
for tileY := 0; tileY < m.size.Height; tileY++ {
|
||||
for tileX := 0; tileX < m.size.Width; tileX++ {
|
||||
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.
|
||||
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
|
||||
}
|
||||
|
||||
@ -290,7 +287,7 @@ func (m *MapEngine) TileExists(tileX, tileY int) bool {
|
||||
}
|
||||
|
||||
// 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)
|
||||
regionSize := region.Size()
|
||||
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
|
||||
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
|
||||
tileSeed = uint64(seed) + uint64(x)
|
||||
tileSeed *= uint64(y)
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"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 {
|
||||
points := make([]d2vector.Position, 0)
|
||||
_, point := m.checkLos(start, dest)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package d2mapentity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
)
|
||||
|
||||
@ -34,7 +36,10 @@ func (ae *AnimatedEntity) Render(target d2interface.Surface) {
|
||||
)
|
||||
|
||||
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.
|
||||
@ -46,11 +51,15 @@ func (ae *AnimatedEntity) GetDirection() int {
|
||||
func (ae *AnimatedEntity) rotate(direction int) {
|
||||
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
|
||||
// single game tick.
|
||||
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 (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
|
||||
)
|
||||
|
||||
// mapEntity represents an entity on the map that can be animated
|
||||
|
@ -19,10 +19,12 @@ type Missile struct {
|
||||
record *d2datadict.MissileRecord
|
||||
}
|
||||
|
||||
// GetPosition returns the position of the missile
|
||||
func (m *Missile) GetPosition() d2vector.Position {
|
||||
return m.AnimatedEntity.Position
|
||||
}
|
||||
|
||||
// GetVelocity returns the velocity vector of the missile
|
||||
func (m *Missile) GetVelocity() d2vector.Vector {
|
||||
return m.AnimatedEntity.velocity
|
||||
}
|
||||
@ -42,7 +44,6 @@ func CreateMissile(x, y int, record *d2datadict.MissileRecord) (*Missile, error)
|
||||
}
|
||||
|
||||
animation.SetEffect(d2enum.DrawEffectModulate)
|
||||
// animation.SetPlaySpeed(float64(record.Animation.AnimationSpeed))
|
||||
animation.SetPlayLoop(record.Animation.LoopAnimation)
|
||||
animation.PlayForward()
|
||||
entity := CreateAnimatedEntity(x, y, animation)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package d2mapentity
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"math/rand"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -9,6 +8,7 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package d2mapentity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -14,19 +16,21 @@ import (
|
||||
// Player is the player character entity.
|
||||
type Player struct {
|
||||
mapEntity
|
||||
composite *d2asset.Composite
|
||||
Equipment *d2inventory.CharacterEquipment
|
||||
Stats *d2hero.HeroStatsState
|
||||
Class d2enum.Hero
|
||||
Id string
|
||||
name string
|
||||
// nameLabel d2ui.Label
|
||||
ID string
|
||||
name string
|
||||
animationMode string
|
||||
composite *d2asset.Composite
|
||||
Equipment *d2inventory.CharacterEquipment
|
||||
Stats *d2hero.HeroStatsState
|
||||
Class d2enum.Hero
|
||||
lastPathSize int
|
||||
isInTown bool
|
||||
animationMode string
|
||||
isRunToggled bool
|
||||
isRunning 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.
|
||||
@ -34,7 +38,7 @@ const baseWalkSpeed = 6.0
|
||||
const baseRunSpeed = 9.0
|
||||
|
||||
// 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 {
|
||||
layerEquipment := &[d2enum.CompositeTypeMax]string{
|
||||
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
|
||||
|
||||
result := &Player{
|
||||
Id: id,
|
||||
ID: id,
|
||||
mapEntity: newMapEntity(x, y),
|
||||
composite: composite,
|
||||
Equipment: equipment,
|
||||
@ -71,16 +75,17 @@ func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero
|
||||
}
|
||||
result.SetSpeed(baseRunSpeed)
|
||||
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())
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
composite.SetDirection(direction)
|
||||
composite.Equip(layerEquipment)
|
||||
|
||||
if err := composite.Equip(layerEquipment); err != nil {
|
||||
fmt.Printf("failed to equip, err: %v\n", err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@ -119,64 +124,69 @@ func (p *Player) SetIsRunning(isRunning bool) {
|
||||
}
|
||||
|
||||
// IsInTown returns true if the player is currently in town.
|
||||
func (p Player) IsInTown() bool {
|
||||
func (p *Player) IsInTown() bool {
|
||||
return p.isInTown
|
||||
}
|
||||
|
||||
// Advance is called once per frame and processes a
|
||||
// single game tick.
|
||||
func (v *Player) Advance(tickTime float64) {
|
||||
v.Step(tickTime)
|
||||
func (p *Player) Advance(tickTime float64) {
|
||||
p.Step(tickTime)
|
||||
|
||||
if v.IsCasting() && v.composite.GetPlayedCount() >= 1 {
|
||||
v.isCasting = false
|
||||
v.SetAnimationMode(v.GetAnimationMode())
|
||||
}
|
||||
v.composite.Advance(tickTime)
|
||||
|
||||
if v.lastPathSize != len(v.path) {
|
||||
v.lastPathSize = len(v.path)
|
||||
if p.IsCasting() && p.composite.GetPlayedCount() >= 1 {
|
||||
p.isCasting = false
|
||||
if err := p.SetAnimationMode(p.GetAnimationMode()); err != nil {
|
||||
fmt.Printf("failed to set animationMode to: %d, err: %v\n", p.GetAnimationMode(), err)
|
||||
}
|
||||
}
|
||||
|
||||
if v.composite.GetAnimationMode() != v.animationMode {
|
||||
v.animationMode = v.composite.GetAnimationMode()
|
||||
if err := p.composite.Advance(tickTime); err != nil {
|
||||
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.
|
||||
func (v *Player) Render(target d2interface.Surface) {
|
||||
renderOffset := v.Position.RenderOffset()
|
||||
func (p *Player) Render(target d2interface.Surface) {
|
||||
renderOffset := p.Position.RenderOffset()
|
||||
target.PushTranslation(
|
||||
int((renderOffset.X()-renderOffset.Y())*16),
|
||||
int(((renderOffset.X()+renderOffset.Y())*8)-5),
|
||||
)
|
||||
|
||||
defer target.Pop()
|
||||
v.composite.Render(target)
|
||||
// v.nameLabel.X = v.offsetX
|
||||
// v.nameLabel.Y = v.offsetY - 100
|
||||
// v.nameLabel.Render(target)
|
||||
|
||||
if err := p.composite.Render(target); err != nil {
|
||||
fmt.Printf("failed to render the composite of player: %s, err: %v\n", p.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetAnimationMode returns the current animation mode based on what the player is doing and where they are.
|
||||
func (v *Player) GetAnimationMode() d2enum.PlayerAnimationMode {
|
||||
if v.IsRunning() && !v.atTarget() {
|
||||
func (p *Player) GetAnimationMode() d2enum.PlayerAnimationMode {
|
||||
if p.IsRunning() && !p.atTarget() {
|
||||
return d2enum.PlayerAnimationModeRun
|
||||
}
|
||||
|
||||
if v.IsInTown() {
|
||||
if !v.atTarget() {
|
||||
if p.IsInTown() {
|
||||
if !p.atTarget() {
|
||||
return d2enum.PlayerAnimationModeTownWalk
|
||||
}
|
||||
|
||||
return d2enum.PlayerAnimationModeTownNeutral
|
||||
}
|
||||
|
||||
if !v.atTarget() {
|
||||
if !p.atTarget() {
|
||||
return d2enum.PlayerAnimationModeWalk
|
||||
}
|
||||
|
||||
if v.IsCasting() {
|
||||
if p.IsCasting() {
|
||||
return d2enum.PlayerAnimationModeCast
|
||||
}
|
||||
|
||||
@ -184,44 +194,48 @@ func (v *Player) GetAnimationMode() d2enum.PlayerAnimationMode {
|
||||
}
|
||||
|
||||
// SetAnimationMode sets the Composite's animation mode weapon class and direction.
|
||||
func (v *Player) SetAnimationMode(animationMode d2enum.PlayerAnimationMode) error {
|
||||
return v.composite.SetMode(animationMode, v.composite.GetWeaponClass())
|
||||
func (p *Player) SetAnimationMode(animationMode d2enum.PlayerAnimationMode) error {
|
||||
return p.composite.SetMode(animationMode, p.composite.GetWeaponClass())
|
||||
}
|
||||
|
||||
// rotate sets direction and changes animation
|
||||
func (v *Player) rotate(direction int) {
|
||||
newAnimationMode := v.GetAnimationMode()
|
||||
func (p *Player) rotate(direction int) {
|
||||
newAnimationMode := p.GetAnimationMode()
|
||||
|
||||
if newAnimationMode.String() != v.composite.GetAnimationMode() {
|
||||
v.composite.SetMode(newAnimationMode, v.composite.GetWeaponClass())
|
||||
if newAnimationMode.String() != p.composite.GetAnimationMode() {
|
||||
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() {
|
||||
v.composite.SetDirection(direction)
|
||||
if direction != p.composite.GetDirection() {
|
||||
p.composite.SetDirection(direction)
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the player name.
|
||||
func (v *Player) Name() string {
|
||||
return v.name
|
||||
func (p *Player) Name() string {
|
||||
return p.name
|
||||
}
|
||||
|
||||
// IsCasting returns true if
|
||||
func (v *Player) IsCasting() bool {
|
||||
return v.isCasting
|
||||
func (p *Player) IsCasting() bool {
|
||||
return p.isCasting
|
||||
}
|
||||
|
||||
// SetCasting sets a flag indicating the player is casting a skill and
|
||||
// sets the animation mode to the casting animation.
|
||||
func (v *Player) SetCasting() {
|
||||
v.isCasting = true
|
||||
v.SetAnimationMode(d2enum.PlayerAnimationModeCast)
|
||||
func (p *Player) SetCasting() {
|
||||
p.isCasting = true
|
||||
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.
|
||||
func (v *Player) Selectable() bool {
|
||||
func (p *Player) Selectable() bool {
|
||||
// Players are selectable when in town
|
||||
return v.IsInTown()
|
||||
return p.IsInTown()
|
||||
}
|
||||
|
||||
// GetPosition returns the entity's position
|
||||
|
@ -23,12 +23,13 @@ func (c *Camera) SetTarget(target *d2vector.Position) {
|
||||
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) {
|
||||
if c.target == nil {
|
||||
v := c.position.Clone()
|
||||
c.target = &d2vector.Position{v}
|
||||
c.target = &d2vector.Position{Vector: v}
|
||||
}
|
||||
|
||||
c.target.Add(vector)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package d2maprenderer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"log"
|
||||
"math"
|
||||
@ -43,14 +44,23 @@ func CreateMapRenderer(renderer d2interface.Renderer, mapEngine *d2mapengine.Map
|
||||
result.Camera.position = &startPosition
|
||||
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
|
||||
})
|
||||
|
||||
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
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("could not bind the entitydebugvis action, err: %v\n", err)
|
||||
}
|
||||
|
||||
if mapEngine.LevelType().ID != 0 {
|
||||
result.generateTileCache()
|
||||
}
|
||||
@ -122,18 +132,18 @@ func (mr *MapRenderer) MoveCameraTargetBy(vector *d2vector.Vector) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// ScreenToOrtho returns the orthogonal position, without accounting for the isometric angle, for the given screen
|
||||
// (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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -278,7 +288,9 @@ func (mr *MapRenderer) renderFloor(tile d2ds1.FloorShadowRecord, target d2interf
|
||||
target.PushTranslation(mr.viewport.GetTranslationScreen())
|
||||
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) {
|
||||
@ -294,7 +306,9 @@ func (mr *MapRenderer) renderWall(tile d2ds1.WallRecord, viewport *Viewport, tar
|
||||
target.PushTranslation(viewport.GetTranslationScreen())
|
||||
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) {
|
||||
@ -311,7 +325,9 @@ func (mr *MapRenderer) renderShadow(tile d2ds1.FloorShadowRecord, target d2inter
|
||||
|
||||
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) {
|
||||
@ -333,7 +349,6 @@ func (mr *MapRenderer) renderEntityDebug(target d2interface.Surface) {
|
||||
x, y := world.X()/5, world.Y()/5
|
||||
velocity := e.GetVelocity()
|
||||
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())
|
||||
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.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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}
|
||||
tileColor := color.RGBA{R: 255, G: 255, B: 255, 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)
|
||||
|
||||
/*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 {
|
||||
if wall.Type.Special() {
|
||||
target.PushTranslation(-20, 10+(i+1)*14)
|
||||
|
@ -12,33 +12,32 @@ import (
|
||||
|
||||
func (mr *MapRenderer) generateTileCache() {
|
||||
mr.palette, _ = loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
||||
mapEngineSize := mr.mapEngine.Size()
|
||||
|
||||
for idx, tile := range *mr.mapEngine.Tiles() {
|
||||
tileX := idx % mapEngineSize.Width
|
||||
tileY := (idx - tileX) / mapEngineSize.Width
|
||||
tiles := *mr.mapEngine.Tiles()
|
||||
for idx := range tiles {
|
||||
tile := &tiles[idx]
|
||||
|
||||
for i := range tile.Components.Floors {
|
||||
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 {
|
||||
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 {
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
var tileData *d2dt1.Tile
|
||||
|
||||
if tileOptions == nil {
|
||||
return
|
||||
} else {
|
||||
tileData = &tileOptions[tile.RandomIndex]
|
||||
}
|
||||
|
||||
tileData = &tileOptions[tile.RandomIndex]
|
||||
|
||||
if tileData.Width == 0 || tileData.Height == 0 {
|
||||
return
|
||||
}
|
||||
@ -133,7 +132,7 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX,
|
||||
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))
|
||||
|
||||
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)
|
||||
tileYOffset := -tileMinY
|
||||
/*tileHeight := int(tileMaxY - tileMinY)*/
|
||||
|
||||
if tile.Type == 15 {
|
||||
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.
|
||||
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))
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// OrthoToWorld returns the world position for the given orthogonal coordinates.
|
||||
func (v *Viewport) OrthoToWorld(x, y float64) (float64, float64) {
|
||||
worldX := (x/80 + y/40) / 2
|
||||
worldY := (y/40 - x/80) / 2
|
||||
func (v *Viewport) OrthoToWorld(x, y float64) (worldX, worldY float64) {
|
||||
worldX = (x/80 + y/40) / 2
|
||||
worldY = (y/40 - x/80) / 2
|
||||
|
||||
return worldX, worldY
|
||||
}
|
||||
|
||||
// WorldToOrtho returns the orthogonal position for the given world coordinates.
|
||||
func (v *Viewport) WorldToOrtho(x, y float64) (float64, float64) {
|
||||
orthoX := (x - y) * 80
|
||||
orthoY := (x + y) * 40
|
||||
func (v *Viewport) WorldToOrtho(x, y float64) (orthoX, orthoY float64) {
|
||||
orthoX = (x - y) * 80
|
||||
orthoY = (x + y) * 40
|
||||
|
||||
return orthoX, orthoY
|
||||
}
|
||||
|
||||
// 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()
|
||||
screenX := float64(x) + camX - float64(v.screenRect.Left)
|
||||
screenY := float64(y) + camY - float64(v.screenRect.Top)
|
||||
orthoX = float64(x) + camX - float64(v.screenRect.Left)
|
||||
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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (v *Viewport) OrthoToScreenF(x, y float64) (float64, float64) {
|
||||
func (v *Viewport) OrthoToScreenF(x, y float64) (screenX, screenY float64) {
|
||||
camOrthoX, camOrthoY := v.getCameraOffset()
|
||||
orthoX := x - camOrthoX + float64(v.screenRect.Left)
|
||||
orthoY := y - camOrthoY + float64(v.screenRect.Top)
|
||||
screenX = x - camOrthoX + float64(v.screenRect.Left)
|
||||
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.
|
||||
@ -136,12 +136,12 @@ func (v *Viewport) IsOrthoRectVisible(x1, y1, x2, y2 float64) bool {
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -175,8 +175,7 @@ func (v *Viewport) PopTranslation() {
|
||||
v.transStack = v.transStack[:count-1]
|
||||
}
|
||||
|
||||
func (v *Viewport) getCameraOffset() (float64, float64) {
|
||||
var camX, camY float64
|
||||
func (v *Viewport) getCameraOffset() (camX, camY float64) {
|
||||
if v.camera != nil {
|
||||
camPosition := v.camera.GetPosition()
|
||||
camX, camY = camPosition.X(), camPosition.Y()
|
||||
|
@ -3,11 +3,12 @@ package ebiten
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -6,11 +6,12 @@ import (
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2DebugUtil"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -56,14 +56,18 @@ func Advance(elapsed float64) error {
|
||||
if !ok {
|
||||
log.Println("loadingState chan should not be closed while in a loading screen")
|
||||
}
|
||||
|
||||
if load.err != nil {
|
||||
log.Printf("PROBLEM LOADING THE SCREEN: %v", load.err)
|
||||
return load.err
|
||||
}
|
||||
|
||||
d2gui.ShowLoadScreen(load.progress)
|
||||
|
||||
if load.done {
|
||||
singleton.currentScreen = singleton.loadingScreen
|
||||
singleton.loadingScreen = nil
|
||||
|
||||
d2gui.ShowCursor()
|
||||
d2gui.HideLoadScreen()
|
||||
}
|
||||
@ -80,17 +84,21 @@ func Advance(elapsed float64) error {
|
||||
if handler, ok := singleton.nextScreen.(ScreenLoadHandler); ok {
|
||||
d2gui.ShowLoadScreen(0)
|
||||
d2gui.HideCursor()
|
||||
|
||||
singleton.loadingState = LoadingState{updates: make(chan loadingUpdate)}
|
||||
|
||||
go func() {
|
||||
handler.OnLoad(singleton.loadingState)
|
||||
singleton.loadingState.Done()
|
||||
}()
|
||||
|
||||
singleton.currentScreen = nil
|
||||
singleton.loadingScreen = singleton.nextScreen
|
||||
} else {
|
||||
singleton.currentScreen = singleton.nextScreen
|
||||
singleton.loadingScreen = nil
|
||||
}
|
||||
|
||||
singleton.nextScreen = nil
|
||||
case singleton.currentScreen != nil:
|
||||
if handler, ok := singleton.currentScreen.(ScreenAdvanceHandler); ok {
|
||||
@ -119,6 +127,8 @@ type LoadingState struct {
|
||||
updates chan loadingUpdate
|
||||
}
|
||||
|
||||
const progressCompleted = 1.0
|
||||
|
||||
type loadingUpdate struct {
|
||||
progress float64
|
||||
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.
|
||||
func (l *LoadingState) Done() {
|
||||
l.updates <- loadingUpdate{progress: 1.0}
|
||||
l.updates <- loadingUpdate{progress: progressCompleted}
|
||||
l.updates <- loadingUpdate{done: true}
|
||||
}
|
||||
|
@ -26,11 +26,11 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
darkGrey = 0x2e3436b0
|
||||
darkGrey = 0x2e3436b0
|
||||
lightGrey = 0x555753b0
|
||||
lightBlue = 0x3465a4b0
|
||||
yellow = 0xfce94fb0
|
||||
red = 0xcc0000b0
|
||||
yellow = 0xfce94fb0
|
||||
red = 0xcc0000b0
|
||||
)
|
||||
|
||||
type termVis int
|
||||
@ -496,7 +496,7 @@ func rgbaColor(rgba uint32) color.RGBA {
|
||||
byteWidth := 8
|
||||
byteMask := 0xff
|
||||
|
||||
for idx :=0; idx < 4; idx ++ {
|
||||
for idx := 0; idx < 4; idx++ {
|
||||
shift := idx * byteWidth
|
||||
component := uint8(rgba>>shift) & uint8(byteMask)
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
@ -14,6 +16,7 @@ import (
|
||||
// ButtonType defines the type of button
|
||||
type ButtonType int
|
||||
|
||||
// ButtonType constants
|
||||
const (
|
||||
ButtonTypeWide ButtonType = 1
|
||||
ButtonTypeMedium ButtonType = 2
|
||||
@ -42,64 +45,59 @@ const (
|
||||
|
||||
// ButtonLayout defines the type of buttons
|
||||
type ButtonLayout struct {
|
||||
XSegments int // 1
|
||||
YSegments int // 1
|
||||
ResourceName string // Font Name
|
||||
PaletteName string // PaletteType
|
||||
Toggleable bool // false
|
||||
BaseFrame int // 0
|
||||
DisabledFrame int // -1
|
||||
FontPath string // ResourcePaths.FontExocet10
|
||||
ClickableRect *image.Rectangle // nil
|
||||
AllowFrameChange bool // true
|
||||
TextOffset int // 0
|
||||
ResourceName string
|
||||
PaletteName string
|
||||
FontPath string
|
||||
XSegments int
|
||||
YSegments int
|
||||
BaseFrame int
|
||||
DisabledFrame int
|
||||
ClickableRect *image.Rectangle
|
||||
TextOffset int
|
||||
Toggleable bool
|
||||
AllowFrameChange bool
|
||||
}
|
||||
|
||||
// ButtonLayouts define the type of buttons you can have
|
||||
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
||||
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
||||
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
||||
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
||||
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
||||
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
||||
ButtonTypeRun: {1, 1, d2resource.RunButton, d2resource.PaletteSky, true, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
||||
/*
|
||||
{eButtonType.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } },
|
||||
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } },
|
||||
{eButtonType.Cancel, new ButtonLayout { ResourceName = ResourcePaths.CancelButton, PaletteName = PaletteDefs.Units } },
|
||||
// Minipanel
|
||||
{eButtonType.MinipanelCharacter, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 0 } },
|
||||
{eButtonType.MinipanelInventory, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 2 } },
|
||||
{eButtonType.MinipanelSkill, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 4 } },
|
||||
{eButtonType.MinipanelAutomap, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 8 } },
|
||||
{eButtonType.MinipanelMessage, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 10 } },
|
||||
{eButtonType.MinipanelQuest, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 12 } },
|
||||
{eButtonType.MinipanelMenu, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = PaletteDefs.Units, BaseFrame = 14 } },
|
||||
|
||||
{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
|
||||
*/
|
||||
func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
return map[ButtonType]ButtonLayout{
|
||||
ButtonTypeWide: {
|
||||
XSegments: 2, YSegments: 1, ResourceName: d2resource.WideButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||
DisabledFrame: -1, FontPath: d2resource.FontExocet10, AllowFrameChange: true, TextOffset: 1},
|
||||
ButtonTypeShort: {
|
||||
XSegments: 1, YSegments: 1, ResourceName: d2resource.ShortButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||
DisabledFrame: -1, FontPath: d2resource.FontRediculous, AllowFrameChange: true, TextOffset: -1},
|
||||
ButtonTypeMedium: {
|
||||
XSegments: 1, YSegments: 1, ResourceName: d2resource.MediumButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||
FontPath: d2resource.FontExocet10, AllowFrameChange: true},
|
||||
ButtonTypeTall: {
|
||||
XSegments: 1, YSegments: 1, ResourceName: d2resource.TallButtonBlank, PaletteName: d2resource.PaletteUnits,
|
||||
FontPath: d2resource.FontExocet10, AllowFrameChange: true, TextOffset: 5},
|
||||
ButtonTypeOkCancel: {
|
||||
XSegments: 1, YSegments: 1, ResourceName: d2resource.CancelButton, PaletteName: d2resource.PaletteUnits,
|
||||
DisabledFrame: -1, FontPath: d2resource.FontRediculous, AllowFrameChange: true},
|
||||
ButtonTypeRun: {
|
||||
XSegments: 1, YSegments: 1, ResourceName: d2resource.RunButton, PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: true, DisabledFrame: -1, FontPath: d2resource.FontRediculous, AllowFrameChange: true},
|
||||
}
|
||||
}
|
||||
|
||||
// Button defines a standard wide UI button
|
||||
type Button struct {
|
||||
enabled bool
|
||||
x, y int
|
||||
width, height int
|
||||
visible bool
|
||||
pressed bool
|
||||
toggled bool
|
||||
buttonLayout ButtonLayout
|
||||
normalSurface d2interface.Surface
|
||||
pressedSurface d2interface.Surface
|
||||
toggledSurface d2interface.Surface
|
||||
pressedToggledSurface d2interface.Surface
|
||||
disabledSurface d2interface.Surface
|
||||
buttonLayout ButtonLayout
|
||||
x int
|
||||
y int
|
||||
width int
|
||||
height int
|
||||
onClick func()
|
||||
enabled bool
|
||||
visible bool
|
||||
pressed bool
|
||||
toggled bool
|
||||
}
|
||||
|
||||
// CreateButton creates an instance of Button
|
||||
@ -111,68 +109,102 @@ func CreateButton(renderer d2interface.Renderer, buttonType ButtonType, text str
|
||||
enabled: true,
|
||||
pressed: false,
|
||||
}
|
||||
buttonLayout := ButtonLayouts[buttonType]
|
||||
buttonLayout := getButtonLayouts()[buttonType]
|
||||
result.buttonLayout = buttonLayout
|
||||
lbl := CreateLabel(buttonLayout.FontPath, d2resource.PaletteUnits)
|
||||
lbl := CreateLabel(buttonLayout.FontPath, d2resource.PaletteUnits)
|
||||
lbl.SetText(text)
|
||||
lbl.Color = color.RGBA{R: 100, G: 100, B: 100, A: 255}
|
||||
lbl.Alignment = d2gui.HorizontalAlignCenter
|
||||
|
||||
animation, _ := d2asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
||||
buttonSprite, _ := LoadSprite(animation)
|
||||
totalButtonTypes := buttonSprite.GetFrameCount() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
||||
|
||||
for i := 0; i < buttonLayout.XSegments; i++ {
|
||||
w, _, _ := buttonSprite.GetFrameSize(i)
|
||||
result.width += w
|
||||
}
|
||||
|
||||
for i := 0; i < buttonLayout.YSegments; i++ {
|
||||
_, h, _ := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
||||
result.height += h
|
||||
}
|
||||
|
||||
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.SetEffect(d2enum.DrawEffectModulate)
|
||||
buttonSprite.RenderSegmented(result.normalSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
||||
|
||||
lbl.SetPosition(xOffset, textY)
|
||||
lbl.Render(result.normalSurface)
|
||||
result.renderFrames(renderer, buttonSprite, &buttonLayout, &lbl)
|
||||
|
||||
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 totalButtonTypes > 1 {
|
||||
result.pressedSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
||||
buttonSprite.RenderSegmented(result.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
||||
v.pressedSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||
err = buttonSprite.RenderSegmented(v.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
||||
|
||||
lbl.SetPosition(xOffset-2, textY + 2)
|
||||
lbl.Render(result.pressedSurface)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to render button pressedSurface, err: %v\n", err)
|
||||
}
|
||||
|
||||
label.SetPosition(xOffset-2, textY+2)
|
||||
label.Render(v.pressedSurface)
|
||||
}
|
||||
|
||||
if totalButtonTypes > 2 {
|
||||
result.toggledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
||||
buttonSprite.RenderSegmented(result.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
||||
v.toggledSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||
err = buttonSprite.RenderSegmented(v.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
||||
|
||||
lbl.SetPosition(xOffset, textY)
|
||||
lbl.Render(result.toggledSurface)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to render button toggledSurface, err: %v\n", err)
|
||||
}
|
||||
|
||||
label.SetPosition(xOffset, textY)
|
||||
label.Render(v.toggledSurface)
|
||||
}
|
||||
|
||||
if totalButtonTypes > 3 {
|
||||
result.pressedToggledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
||||
buttonSprite.RenderSegmented(result.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
||||
v.pressedToggledSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||
err = buttonSprite.RenderSegmented(v.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
||||
|
||||
lbl.SetPosition(xOffset, textY)
|
||||
lbl.Render(result.pressedToggledSurface)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to render button pressedToggledSurface, err: %v\n", err)
|
||||
}
|
||||
|
||||
label.SetPosition(xOffset, textY)
|
||||
label.Render(v.pressedToggledSurface)
|
||||
}
|
||||
if buttonLayout.DisabledFrame != -1 {
|
||||
result.disabledSurface, _ = renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
||||
buttonSprite.RenderSegmented(result.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
||||
|
||||
lbl.SetPosition(xOffset, textY)
|
||||
lbl.Render(result.disabledSurface)
|
||||
if buttonLayout.DisabledFrame != -1 {
|
||||
v.disabledSurface, _ = renderer.NewSurface(v.width, v.height, d2enum.FilterNearest)
|
||||
err = buttonSprite.RenderSegmented(v.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
||||
|
||||
if err != nil {
|
||||
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
|
||||
@ -185,6 +217,7 @@ func (v *Button) Activate() {
|
||||
if v.onClick == nil {
|
||||
return
|
||||
}
|
||||
|
||||
v.onClick()
|
||||
}
|
||||
|
||||
@ -192,27 +225,37 @@ func (v *Button) Activate() {
|
||||
func (v *Button) Render(target d2interface.Surface) {
|
||||
target.PushFilter(d2enum.FilterNearest)
|
||||
target.PushTranslation(v.x, v.y)
|
||||
|
||||
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})
|
||||
defer target.Pop()
|
||||
target.Render(v.disabledSurface)
|
||||
} else if v.toggled && v.pressed {
|
||||
target.Render(v.pressedToggledSurface)
|
||||
} else if v.pressed {
|
||||
target.Render(v.pressedSurface)
|
||||
} else if v.toggled {
|
||||
target.Render(v.toggledSurface)
|
||||
} else {
|
||||
target.Render(v.normalSurface)
|
||||
err = target.Render(v.disabledSurface)
|
||||
case v.toggled && v.pressed:
|
||||
err = target.Render(v.pressedToggledSurface)
|
||||
case v.pressed:
|
||||
err = target.Render(v.pressedSurface)
|
||||
case v.toggled:
|
||||
err = target.Render(v.toggledSurface)
|
||||
default:
|
||||
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() {
|
||||
v.toggled = !v.toggled
|
||||
}
|
||||
|
||||
// Advance advances the button state
|
||||
func (v *Button) Advance(elapsed float64) {
|
||||
|
||||
}
|
||||
@ -227,8 +270,8 @@ func (v *Button) SetEnabled(enabled bool) {
|
||||
v.enabled = enabled
|
||||
}
|
||||
|
||||
// Size returns the size of the button
|
||||
func (v *Button) GetSize() (int, int) {
|
||||
// GetSize returns the size of the button
|
||||
func (v *Button) GetSize() (width, height int) {
|
||||
return v.width, v.height
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,10 @@ package d2gamescreen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
@ -170,7 +171,7 @@ func (v *Game) Advance(elapsed float64) error {
|
||||
|
||||
func (v *Game) bindGameControls() {
|
||||
for _, player := range v.gameClient.Players {
|
||||
if player.Id != v.gameClient.PlayerID {
|
||||
if player.ID != v.gameClient.PlayerID {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -179,7 +180,7 @@ func (v *Game) bindGameControls() {
|
||||
v.gameControls.Load()
|
||||
|
||||
if err := v.inputManager.BindHandler(v.gameControls); err != nil {
|
||||
fmt.Printf(bindControlsErrStr, player.Id)
|
||||
fmt.Printf(bindControlsErrStr, player.ID)
|
||||
}
|
||||
|
||||
break
|
||||
|
@ -71,6 +71,11 @@ const (
|
||||
joinGameCharacterFilter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:"
|
||||
)
|
||||
|
||||
// BuildInfo contains information about the current build
|
||||
type BuildInfo struct {
|
||||
Branch, Commit string
|
||||
}
|
||||
|
||||
// MainMenu represents the main menu
|
||||
type MainMenu struct {
|
||||
tcpIPBackground *d2ui.Sprite
|
||||
@ -111,6 +116,8 @@ type MainMenu struct {
|
||||
audioProvider d2interface.AudioProvider
|
||||
scriptEngine *d2script.ScriptEngine
|
||||
navigator Navigator
|
||||
|
||||
buildInfo BuildInfo
|
||||
}
|
||||
|
||||
// CreateMainMenu creates an instance of MainMenu
|
||||
@ -119,6 +126,7 @@ func CreateMainMenu(
|
||||
renderer d2interface.Renderer,
|
||||
inputManager d2interface.InputManager,
|
||||
audioProvider d2interface.AudioProvider,
|
||||
buildInfo BuildInfo,
|
||||
) *MainMenu {
|
||||
return &MainMenu{
|
||||
screenMode: ScreenModeUnknown,
|
||||
@ -178,13 +186,13 @@ func (v *MainMenu) loadBackgroundSprites() {
|
||||
func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
||||
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.versionLabel.Alignment = d2gui.HorizontalAlignRight
|
||||
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
|
||||
v.versionLabel.SetText("OpenDiablo2 - " + v.buildInfo.Branch)
|
||||
v.versionLabel.Color = rgbaColor(white)
|
||||
v.versionLabel.SetPosition(versionLabelX, versionLabelY)
|
||||
|
||||
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
v.commitLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||
v.commitLabel.SetText(d2common.BuildInfo.Commit)
|
||||
v.commitLabel.SetText(v.buildInfo.Commit)
|
||||
v.commitLabel.Color = rgbaColor(white)
|
||||
v.commitLabel.SetPosition(commitLabelX, commitLabelY)
|
||||
|
||||
|
@ -165,7 +165,7 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
|
||||
} else {
|
||||
met.mapEngine = d2mapengine.CreateMapEngine() // necessary for map name update
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ func (g *GameClient) handleAddPlayerPacket(packet d2netpacket.NetPacket) error {
|
||||
newPlayer := d2mapentity.CreatePlayer(player.ID, player.Name, player.X, player.Y, 0,
|
||||
player.HeroType, player.Stats, &player.Equipment)
|
||||
|
||||
g.Players[newPlayer.Id] = newPlayer
|
||||
g.Players[newPlayer.ID] = newPlayer
|
||||
g.MapEngine.AddEntity(newPlayer)
|
||||
|
||||
return nil
|
||||
@ -199,7 +199,7 @@ func (g *GameClient) handleMovePlayerPacket(packet d2netpacket.NetPacket) error
|
||||
err := player.SetAnimationMode(player.GetAnimationMode())
|
||||
|
||||
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())
|
||||
return otto.Value{}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("could not bind the 'debugPrint' to the given function in script engine")
|
||||
}
|
||||
|
||||
return &ScriptEngine{
|
||||
vm: vm,
|
||||
isEvalAllowed: false,
|
||||
@ -37,7 +39,7 @@ func (s *ScriptEngine) AllowEval() {
|
||||
s.isEvalAllowed = true
|
||||
}
|
||||
|
||||
// AllowEval disallows the evaluation of JS code.
|
||||
// DisallowEval disallows the evaluation of JS code.
|
||||
func (s *ScriptEngine) DisallowEval() {
|
||||
s.isEvalAllowed = false
|
||||
}
|
||||
@ -82,5 +84,6 @@ func (s *ScriptEngine) Eval(code string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return val.String(), nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user