1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2025-02-02 14:46:28 -05:00

lint fixes (#615)

This commit is contained in:
Gürkan Kaymak 2020-07-23 19:56:50 +03:00 committed by GitHub
parent 80e655964e
commit 7a49f3637f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 504 additions and 428 deletions

View File

@ -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)
} }

View File

@ -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,
}
}

View File

@ -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"),

View File

@ -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"),

View File

@ -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"),

View File

@ -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

View File

@ -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
// dont do it. This 'HarcCodedInDeX' is used for several things, such as // dont 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"),

View File

@ -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"),

View File

@ -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

View File

@ -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"),

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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)
}
} }
} }
} }

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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 (

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)
}
} }

View File

@ -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

View File

@ -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)

View File

@ -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"
) )

View File

@ -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

View File

@ -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)
} }

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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 (

View File

@ -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 (

View File

@ -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}
} }

View File

@ -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
} }

View File

@ -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

View File

@ -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)

View File

@ -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()
} }

View File

@ -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)
} }
}) })
} }

View File

@ -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
} }