implemented logger in d2gamescreen (#925)

* implemented logger in d2gamescreen

* logger in d2game/d2player

* logger for app.go
This commit is contained in:
gucio321 2020-11-18 22:02:49 +01:00 committed by GitHub
parent f6410f8961
commit 2153f5ce64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 920 additions and 714 deletions

View File

@ -10,7 +10,6 @@ import (
"image"
"image/gif"
"image/png"
"log"
"os"
"os/signal"
"path/filepath"
@ -154,7 +153,7 @@ func (a *App) startDedicatedServer() error {
for {
for data := range srvChanLog {
log.Println(data)
a.logger.Info(data)
}
}
}
@ -327,7 +326,7 @@ func (a *App) Run() error {
// start profiler if argument was supplied
if len(*a.Options.profiler) > 0 {
profiler := enableProfiler(*a.Options.profiler)
profiler := enableProfiler(*a.Options.profiler, a)
if profiler != nil {
defer profiler.Stop()
}
@ -406,7 +405,7 @@ func (a *App) initialize() error {
action := &terminalActions[idx]
if err := a.terminal.BindAction(action.name, action.description, action.action); err != nil {
log.Fatal(err)
a.logger.Fatal(err.Error())
}
}
@ -684,21 +683,21 @@ func (a *App) allocRate(totalAlloc uint64, fps float64) float64 {
func (a *App) dumpHeap() {
if _, err := os.Stat("./pprof/"); os.IsNotExist(err) {
if err := os.Mkdir("./pprof/", 0750); err != nil {
log.Fatal(err)
a.logger.Fatal(err.Error())
}
}
fileOut, err := os.Create("./pprof/heap.pprof")
if err != nil {
log.Print(err)
a.logger.Error(err.Error())
}
if err := pprof.WriteHeapProfile(fileOut); err != nil {
log.Fatal(err)
a.logger.Fatal(err.Error())
}
if err := fileOut.Close(); err != nil {
log.Fatal(err)
a.logger.Fatal(err.Error())
}
}
@ -709,7 +708,7 @@ func (a *App) evalJS(code string) {
return
}
log.Printf("%s", val)
a.logger.Info("%s" + val)
}
func (a *App) toggleFullScreen() {
@ -732,7 +731,7 @@ func (a *App) doCaptureFrame(target d2interface.Surface) error {
defer func() {
if err := fp.Close(); err != nil {
log.Fatal(err)
a.logger.Fatal(err.Error())
}
}()
@ -741,7 +740,7 @@ func (a *App) doCaptureFrame(target d2interface.Surface) error {
return err
}
log.Printf("saved frame to %s", a.capturePath)
a.logger.Info(fmt.Sprintf("saved frame to %s", a.capturePath))
return nil
}
@ -759,7 +758,7 @@ func (a *App) convertFramesToGif() error {
defer func() {
if err := fp.Close(); err != nil {
log.Fatal(err)
a.logger.Fatal(err.Error())
}
}()
@ -801,7 +800,7 @@ func (a *App) convertFramesToGif() error {
return err
}
log.Printf("saved animation to %s", a.capturePath)
a.logger.Info(fmt.Sprintf("saved animation to %s", a.capturePath))
return nil
}
@ -841,7 +840,7 @@ func (a *App) quitGame() {
}
func (a *App) enterGuiPlayground() {
a.screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(a.renderer, a.guiManager, a.asset))
a.screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(a.renderer, a.guiManager, a.config.LogLevel, a.asset))
}
func createZeroedRing(n int) *ring.Ring {
@ -854,36 +853,36 @@ func createZeroedRing(n int) *ring.Ring {
return r
}
func enableProfiler(profileOption string) interface{ Stop() } {
func enableProfiler(profileOption string, a *App) interface{ Stop() } {
var options []func(*profile.Profile)
switch strings.ToLower(strings.Trim(profileOption, " ")) {
case "cpu":
log.Printf("CPU profiling is enabled.")
a.logger.Debug("CPU profiling is enabled.")
options = append(options, profile.CPUProfile)
case "mem":
log.Printf("Memory profiling is enabled.")
a.logger.Debug("Memory profiling is enabled.")
options = append(options, profile.MemProfile)
case "block":
log.Printf("Block profiling is enabled.")
a.logger.Debug("Block profiling is enabled.")
options = append(options, profile.BlockProfile)
case "goroutine":
log.Printf("Goroutine profiling is enabled.")
a.logger.Debug("Goroutine profiling is enabled.")
options = append(options, profile.GoroutineProfile)
case "trace":
log.Printf("Trace profiling is enabled.")
a.logger.Debug("Trace profiling is enabled.")
options = append(options, profile.TraceProfile)
case "thread":
log.Printf("Thread creation profiling is enabled.")
a.logger.Debug("Thread creation profiling is enabled.")
options = append(options, profile.ThreadcreationProfile)
case "mutex":
log.Printf("Mutex profiling is enabled.")
a.logger.Debug("Mutex profiling is enabled.")
options = append(options, profile.MutexProfile)
}
@ -909,9 +908,10 @@ func (a *App) updateInitError(target d2interface.Surface) error {
func (a *App) ToMainMenu(errorMessageOptional ...string) {
buildInfo := d2gamescreen.BuildInfo{Branch: a.gitBranch, Commit: a.gitCommit}
mainMenu, err := d2gamescreen.CreateMainMenu(a, a.asset, a.renderer, a.inputManager, a.audio, a.ui, buildInfo, errorMessageOptional...)
mainMenu, err := d2gamescreen.CreateMainMenu(a, a.asset, a.renderer, a.inputManager, a.audio, a.ui, buildInfo,
a.config.LogLevel, errorMessageOptional...)
if err != nil {
log.Print(err)
a.logger.Error(err.Error())
return
}
@ -920,9 +920,9 @@ func (a *App) ToMainMenu(errorMessageOptional ...string) {
// ToSelectHero forces the game to transition to the Select Hero (create character) screen
func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConnectionType, host string) {
selectHero, err := d2gamescreen.CreateSelectHeroClass(a, a.asset, a.renderer, a.audio, a.ui, connType, host)
selectHero, err := d2gamescreen.CreateSelectHeroClass(a, a.asset, a.renderer, a.audio, a.ui, connType, a.config.LogLevel, host)
if err != nil {
log.Print(err)
a.logger.Error(err.Error())
return
}
@ -933,7 +933,7 @@ func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConnectionType,
func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.ClientConnectionType, host string) {
gameClient, err := d2client.Create(connType, a.asset, a.scriptEngine)
if err != nil {
log.Print(err)
a.logger.Error(err.Error())
}
if err = gameClient.Open(host, filePath); err != nil {
@ -942,7 +942,7 @@ func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.Clie
a.ToMainMenu(errorMessage)
} else {
a.screen.SetNextScreen(d2gamescreen.CreateGame(
a, a.asset, a.ui, a.renderer, a.inputManager, a.audio, gameClient, a.terminal, a.guiManager,
a, a.asset, a.ui, a.renderer, a.inputManager, a.audio, gameClient, a.terminal, a.config.LogLevel, a.guiManager,
))
}
}
@ -950,7 +950,7 @@ func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.Clie
// ToCharacterSelect forces the game to transition to the Character Select (load character) screen
func (a *App) ToCharacterSelect(connType d2clientconnectiontype.ClientConnectionType, connHost string) {
characterSelect, err := d2gamescreen.CreateCharacterSelect(a, a.asset, a.renderer, a.inputManager,
a.audio, a.ui, connType, connHost)
a.audio, a.ui, connType, a.config.LogLevel, connHost)
if err != nil {
fmt.Printf("unable to create character select screen: %s", err)
}
@ -960,9 +960,10 @@ func (a *App) ToCharacterSelect(connType d2clientconnectiontype.ClientConnection
// ToMapEngineTest forces the game to transition to the map engine test screen
func (a *App) ToMapEngineTest(region, level int) {
met, err := d2gamescreen.CreateMapEngineTest(region, level, a.asset, a.terminal, a.renderer, a.inputManager, a.audio, a.screen)
met, err := d2gamescreen.CreateMapEngineTest(region, level, a.asset, a.terminal, a.renderer, a.inputManager, a.audio,
a.config.LogLevel, a.screen)
if err != nil {
log.Print(err)
a.logger.Error(err.Error())
return
}
@ -971,10 +972,10 @@ func (a *App) ToMapEngineTest(region, level int) {
// ToCredits forces the game to transition to the credits screen
func (a *App) ToCredits() {
a.screen.SetNextScreen(d2gamescreen.CreateCredits(a, a.asset, a.renderer, a.ui))
a.screen.SetNextScreen(d2gamescreen.CreateCredits(a, a.asset, a.renderer, a.config.LogLevel, a.ui))
}
// ToCinematics forces the game to transition to the cinematics menu
func (a *App) ToCinematics() {
a.screen.SetNextScreen(d2gamescreen.CreateCinematics(a, a.asset, a.renderer, a.audio, a.ui))
a.screen.SetNextScreen(d2gamescreen.CreateCinematics(a, a.asset, a.renderer, a.audio, a.config.LogLevel, a.ui))
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"io"
"log"
"os"
"runtime"
)
@ -13,6 +14,7 @@ type LogLevel = int
// Log levels
const (
LogLevelNone LogLevel = iota
LogLevelFatal
LogLevelError
LogLevelWarning
LogLevelInfo
@ -41,6 +43,7 @@ const (
LogFmtInfo = "[INFO]" + colorEscapeReset + " %s\r\n"
LogFmtWarning = "[WARNING]" + colorEscapeReset + " %s\r\n"
LogFmtError = "[ERROR]" + colorEscapeReset + " %s\r\n"
LogFmtFatal = "[FATAL]" + colorEscapeReset + " %s\r\n"
)
// NewLogger creates a new logger with a default
@ -131,6 +134,21 @@ func (l *Logger) Errorf(fmtMsg string, args ...interface{}) {
l.Error(fmt.Sprintf(fmtMsg, args...))
}
// Fatal logs an fatal error message and exits programm
func (l *Logger) Fatal(msg string) {
if l == nil || l.level < LogLevelFatal {
return
}
l.print(LogLevelFatal, msg)
os.Exit(1)
}
// Fatalf formats and then logs a error message
func (l *Logger) Fatalf(fmtMsg string, args ...interface{}) {
l.Fatal(fmt.Sprintf(fmtMsg, args...))
}
// Debug logs a debug message
func (l *Logger) Debug(msg string) {
if l == nil || l.level < LogLevelDebug {
@ -155,6 +173,7 @@ func (l *Logger) print(level LogLevel, msg string) {
LogLevelInfo: green,
LogLevelWarning: yellow,
LogLevelError: red,
LogLevelFatal: red,
}
fmtString := ""
@ -180,6 +199,8 @@ func (l *Logger) print(level LogLevel, msg string) {
fmtString += LogFmtWarning
case LogLevelError:
fmtString += LogFmtError
case LogLevelFatal:
fmtString += LogFmtFatal
case LogLevelNone:
default:
return

View File

@ -1,9 +1,7 @@
package d2gamescreen
import (
"fmt"
"image/color"
"log"
"math"
"os"
@ -12,6 +10,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
@ -19,6 +18,49 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
)
// CreateCharacterSelect creates the character select screen and returns a pointer to it
func CreateCharacterSelect(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
connectionType d2clientconnectiontype.ClientConnectionType,
l d2util.LogLevel,
connectionHost string,
) (*CharacterSelect, error) {
playerStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
entityFactory, err := d2mapentity.NewMapEntityFactory(asset)
if err != nil {
return nil, err
}
characterSelect := &CharacterSelect{
selectedCharacter: -1,
asset: asset,
MapEntityFactory: entityFactory,
renderer: renderer,
connectionType: connectionType,
connectionHost: connectionHost,
inputManager: inputManager,
audioProvider: audioProvider,
navigator: navigator,
uiManager: ui,
HeroStateFactory: playerStateFactory,
}
characterSelect.logger = d2util.NewLogger()
characterSelect.logger.SetLevel(l)
characterSelect.logger.SetPrefix(logPrefix)
return characterSelect, nil
}
// CharacterSelect represents the character select screen
type CharacterSelect struct {
asset *d2asset.AssetManager
@ -55,42 +97,7 @@ type CharacterSelect struct {
audioProvider d2interface.AudioProvider
renderer d2interface.Renderer
navigator d2interface.Navigator
}
// CreateCharacterSelect creates the character select screen and returns a pointer to it
func CreateCharacterSelect(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string,
) (*CharacterSelect, error) {
playerStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
entityFactory, err := d2mapentity.NewMapEntityFactory(asset)
if err != nil {
return nil, err
}
return &CharacterSelect{
selectedCharacter: -1,
asset: asset,
MapEntityFactory: entityFactory,
renderer: renderer,
connectionType: connectionType,
connectionHost: connectionHost,
inputManager: inputManager,
audioProvider: audioProvider,
navigator: navigator,
uiManager: ui,
HeroStateFactory: playerStateFactory,
}, nil
logger *d2util.Logger
}
const (
@ -153,7 +160,7 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
err := v.inputManager.BindHandler(v)
if err != nil {
fmt.Println("failed to add Character Select screen as event handler")
v.logger.Error("failed to add Character Select screen as event handler")
}
loading.Progress(tenPercent)
@ -205,7 +212,7 @@ func (v *CharacterSelect) loadBackground() {
v.background, err = v.uiManager.NewSprite(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.background.SetPosition(bgX, bgY)
@ -232,7 +239,7 @@ func (v *CharacterSelect) loadSelectionBox() {
v.selectionBox, err = v.uiManager.NewSprite(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
selBoxX, selBoxY := 37, 86
@ -244,7 +251,7 @@ func (v *CharacterSelect) loadOkCancelBox() {
v.okCancelBox, err = v.uiManager.NewSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
okCancelX, okCancelY := 270, 175
@ -494,7 +501,7 @@ func (v *CharacterSelect) onDeleteCharButtonClicked() {
func (v *CharacterSelect) onDeleteCharacterConfirmClicked() {
err := os.Remove(v.gameStates[v.selectedCharacter].FilePath)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.charScrollbar.SetCurrentOffset(0)

View File

@ -1,11 +1,10 @@
package d2gamescreen
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2video"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -24,6 +23,29 @@ const (
cinematicsExitBtnX, cinematicsExitBtnY = 340, 470
)
// CreateCinematics creates an instance of the credits screen
func CreateCinematics(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
aup d2interface.AudioProvider,
l d2util.LogLevel,
ui *d2ui.UIManager) *Cinematics {
cinematics := &Cinematics{
asset: asset,
renderer: renderer,
navigator: navigator,
uiManager: ui,
audioProvider: aup,
}
cinematics.logger = d2util.NewLogger()
cinematics.logger.SetPrefix(logPrefix)
cinematics.logger.SetLevel(l)
return cinematics
}
// Cinematics represents the cinematics screen
type Cinematics struct {
cinematicsBackground *d2ui.Sprite
@ -44,24 +66,7 @@ type Cinematics struct {
uiManager *d2ui.UIManager
videoDecoder *d2video.BinkDecoder
audioProvider d2interface.AudioProvider
}
// CreateCinematics creates an instance of the credits screen
func CreateCinematics(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
aup d2interface.AudioProvider,
ui *d2ui.UIManager) *Cinematics {
result := &Cinematics{
asset: asset,
renderer: renderer,
navigator: navigator,
uiManager: ui,
audioProvider: aup,
}
return result
logger *d2util.Logger
}
// OnLoad is called to load the resources for the credits screen
@ -73,7 +78,7 @@ func (v *Cinematics) OnLoad(_ d2screen.LoadingState) {
v.background, err = v.uiManager.NewSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.background.SetPosition(backgroundX, backgroundY)
@ -81,7 +86,7 @@ func (v *Cinematics) OnLoad(_ d2screen.LoadingState) {
v.cinematicsBackground, err = v.uiManager.NewSprite(d2resource.CinematicsBackground, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.cinematicsBackground.SetPosition(cinematicsX, cinematicsY)
@ -173,7 +178,7 @@ func (v *Cinematics) onEndCreditExpBtnClicked() {
func (v *Cinematics) playVideo(path string) {
videoBytes, err := v.asset.LoadFile(path)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
return
}

View File

@ -2,8 +2,6 @@ package d2gamescreen
import (
"bufio"
"fmt"
"log"
"os"
"path"
"strings"
@ -29,6 +27,30 @@ type labelItem struct {
Available bool
}
// CreateCredits creates an instance of the credits screen
func CreateCredits(navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
l d2util.LogLevel,
ui *d2ui.UIManager) *Credits {
credits := &Credits{
asset: asset,
labels: make([]*labelItem, 0),
cycleTime: 0,
doneWithCredits: false,
cyclesTillNextLine: 0,
renderer: renderer,
navigator: navigator,
uiManager: ui,
}
credits.logger = d2util.NewLogger()
credits.logger.SetLevel(l)
credits.logger.SetPrefix(logPrefix)
return credits
}
// Credits represents the credits screen
type Credits struct {
creditsBackground *d2ui.Sprite
@ -43,36 +65,20 @@ type Credits struct {
renderer d2interface.Renderer
navigator d2interface.Navigator
uiManager *d2ui.UIManager
}
// CreateCredits creates an instance of the credits screen
func CreateCredits(navigator d2interface.Navigator, asset *d2asset.AssetManager, renderer d2interface.Renderer,
ui *d2ui.UIManager) *Credits {
result := &Credits{
asset: asset,
labels: make([]*labelItem, 0),
cycleTime: 0,
doneWithCredits: false,
cyclesTillNextLine: 0,
renderer: renderer,
navigator: navigator,
uiManager: ui,
}
return result
logger *d2util.Logger
}
// LoadContributors loads the contributors data from file
func (v *Credits) LoadContributors() []string {
file, err := os.Open(path.Join("./", "CONTRIBUTORS"))
if err != nil || file == nil {
log.Print("CONTRIBUTORS file is missing")
v.logger.Warning("CONTRIBUTORS file is missing")
return []string{"MISSING CONTRIBUTOR FILES!"}
}
defer func() {
if err = file.Close(); err != nil {
fmt.Printf("an error occurred while closing file: %s, err: %q\n", file.Name(), err)
v.logger.Error("an error occurred while closing file: %s, err: %q\n" + file.Name() + err.Error())
}
}()
@ -92,7 +98,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
v.creditsBackground, err = v.uiManager.NewSprite(d2resource.CreditsBackground, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.creditsBackground.SetPosition(creditsX, creditsY)
@ -113,7 +119,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
creditData, err := d2util.Utf16BytesToString(fileData[2:])
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.creditsText = strings.Split(creditData, "\r\n")

View File

@ -35,6 +35,70 @@ const (
black50alpha = 0x0000007f // rgba
)
// CreateGame creates the Gameplay screen and returns a pointer to it
func CreateGame(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
ui *d2ui.UIManager,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
gameClient *d2client.GameClient,
term d2interface.Terminal,
l d2util.LogLevel,
guiManager *d2gui.GuiManager,
) *Game {
// find the local player and its initial location
var startX, startY float64
for _, player := range gameClient.Players {
if player.ID() != gameClient.PlayerID {
continue
}
worldPosition := player.Position.World()
startX, startY = worldPosition.X(), worldPosition.Y()
break
}
keyMap := d2player.GetDefaultKeyMap(asset)
game := &Game{
asset: asset,
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(asset, renderer,
gameClient.MapEngine, term, startX, startY),
escapeMenu: d2player.NewEscapeMenu(navigator, renderer, audioProvider, ui, guiManager, asset, l, keyMap),
inputManager: inputManager,
audioProvider: audioProvider,
renderer: renderer,
terminal: term,
soundEngine: d2audio.NewSoundEngine(audioProvider, asset, term),
uiManager: ui,
guiManager: guiManager,
keyMap: keyMap,
logLevel: l,
}
game.logger = d2util.NewLogger()
game.logger.SetLevel(l)
game.logger.SetPrefix(logPrefix)
game.soundEnv = d2audio.NewSoundEnvironment(game.soundEngine)
game.escapeMenu.OnLoad()
if err := inputManager.BindHandler(game.escapeMenu); err != nil {
game.logger.Error("failed to add gameplay screen as event handler")
}
return game
}
// Game represents the Gameplay screen
type Game struct {
*d2mapentity.MapEntityFactory
@ -56,64 +120,8 @@ type Game struct {
inputManager d2interface.InputManager
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
// CreateGame creates the Gameplay screen and returns a pointer to it
func CreateGame(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
ui *d2ui.UIManager,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
gameClient *d2client.GameClient,
term d2interface.Terminal,
guiManager *d2gui.GuiManager,
) *Game {
// find the local player and its initial location
var startX, startY float64
for _, player := range gameClient.Players {
if player.ID() != gameClient.PlayerID {
continue
}
worldPosition := player.Position.World()
startX, startY = worldPosition.X(), worldPosition.Y()
break
}
keyMap := d2player.GetDefaultKeyMap(asset)
result := &Game{
asset: asset,
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(asset, renderer,
gameClient.MapEngine, term, startX, startY),
escapeMenu: d2player.NewEscapeMenu(navigator, renderer, audioProvider, ui, guiManager, asset, keyMap),
inputManager: inputManager,
audioProvider: audioProvider,
renderer: renderer,
terminal: term,
soundEngine: d2audio.NewSoundEngine(audioProvider, asset, term),
uiManager: ui,
guiManager: guiManager,
keyMap: keyMap,
}
result.soundEnv = d2audio.NewSoundEnvironment(result.soundEngine)
result.escapeMenu.OnLoad()
if err := inputManager.BindHandler(result.escapeMenu); err != nil {
fmt.Println("failed to add gameplay screen as event handler")
}
return result
logger *d2util.Logger
logLevel d2util.LogLevel
}
// OnLoad loads the resources for the Gameplay screen
@ -129,7 +137,7 @@ func (v *Game) OnLoad(_ d2screen.LoadingState) {
},
)
if err != nil {
fmt.Printf("failed to bind the '%s' action, err: %v\n", "spawnitem", err)
v.logger.Error("failed to bind the '%s' action, err: %v\nspawnitem" + err.Error())
}
err = v.terminal.BindAction(
@ -141,7 +149,7 @@ func (v *Game) OnLoad(_ d2screen.LoadingState) {
},
)
if err != nil {
fmt.Printf("failed to bind the '%s' action, err: %v\n", "spawnitemat", err)
v.logger.Error("failed to bind the '%s' action, err: %v\nspawnitemat" + err.Error())
}
err = v.terminal.BindAction(
@ -166,7 +174,7 @@ func (v *Game) OnLoad(_ d2screen.LoadingState) {
},
)
if err != nil {
fmt.Printf("failed to bind the '%s' action, err: %v\n", "spawnmon", err)
v.logger.Error("failed to bind the '%s' action, err: %v\nspawnmon" + err.Error())
}
}
@ -294,7 +302,7 @@ func (v *Game) bindGameControls() error {
var err error
v.gameControls, err = d2player.NewGameControls(v.asset, v.renderer, player, v.gameClient.MapEngine,
v.escapeMenu, v.mapRenderer, v, v.terminal, v.uiManager, v.guiManager, v.keyMap, v.gameClient.IsSinglePlayer())
v.escapeMenu, v.mapRenderer, v, v.terminal, v.uiManager, v.guiManager, v.keyMap, v.logLevel, v.gameClient.IsSinglePlayer())
if err != nil {
return err
@ -303,7 +311,7 @@ func (v *Game) bindGameControls() error {
v.gameControls.Load()
if err := v.inputManager.BindHandler(v.gameControls); err != nil {
fmt.Printf(bindControlsErrStr, player.ID())
v.logger.Error(bindControlsErrStr + player.ID())
}
break
@ -321,7 +329,7 @@ func (v *Game) OnPlayerMove(targetX, targetY float64) {
err := v.gameClient.SendPacketToServer(createMovePlayerPacket)
if err != nil {
fmt.Printf(moveErrStr, v.gameClient.PlayerID, targetX, targetY)
v.logger.Error(fmt.Sprintf(moveErrStr, v.gameClient.PlayerID, targetX, targetY))
}
}
@ -341,7 +349,7 @@ func (v *Game) OnPlayerSave() error {
func (v *Game) OnPlayerCast(skillID int, targetX, targetY float64) {
err := v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerID, skillID, targetX, targetY))
if err != nil {
fmt.Printf(castErrStr, v.gameClient.PlayerID, skillID, targetX, targetY)
v.logger.Error(fmt.Sprintf(castErrStr, v.gameClient.PlayerID, skillID, targetX, targetY))
}
}
@ -362,6 +370,6 @@ func (v *Game) debugSpawnItemAtLocation(x, y int, codes ...string) {
err := v.gameClient.SendPacketToServer(packet)
if err != nil {
fmt.Printf(spawnItemErrStr, x, y, codes)
v.logger.Error(fmt.Sprintf(spawnItemErrStr, x, y, codes))
}
}

View File

@ -4,25 +4,36 @@ import (
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
)
// CreateGuiTestMain creates a GuiTestMain screen
func CreateGuiTestMain(renderer d2interface.Renderer,
guiManager *d2gui.GuiManager,
l d2util.LogLevel,
assetManager *d2asset.AssetManager) *GuiTestMain {
guiTestMain := &GuiTestMain{
renderer: renderer,
guiManager: guiManager,
assetManager: assetManager,
}
guiTestMain.logger = d2util.NewLogger()
guiTestMain.logger.SetLevel(l)
guiTestMain.logger.SetPrefix(logPrefix)
return guiTestMain
}
// GuiTestMain is a playground screen for the gui components
type GuiTestMain struct {
renderer d2interface.Renderer
guiManager *d2gui.GuiManager
assetManager *d2asset.AssetManager
}
// CreateGuiTestMain creates a GuiTestMain screen
func CreateGuiTestMain(renderer d2interface.Renderer, guiManager *d2gui.GuiManager, assetManager *d2asset.AssetManager) *GuiTestMain {
return &GuiTestMain{
renderer: renderer,
guiManager: guiManager,
assetManager: assetManager,
}
logger *d2util.Logger
}
// OnLoad loads the resources and creates the gui components

View File

@ -3,7 +3,6 @@ package d2gamescreen
import (
"fmt"
"log"
"net"
"os"
"os/exec"
@ -14,6 +13,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -74,11 +74,57 @@ const (
joinGameCharacterFilter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:"
)
const (
logPrefix = "Game Screen"
)
// BuildInfo contains information about the current build
type BuildInfo struct {
Branch, Commit string
}
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
buildInfo BuildInfo,
l d2util.LogLevel,
errorMessageOptional ...string,
) (*MainMenu, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
mainMenu := &MainMenu{
asset: asset,
screenMode: ScreenModeUnknown,
leftButtonHeld: true,
renderer: renderer,
inputManager: inputManager,
audioProvider: audioProvider,
navigator: navigator,
buildInfo: buildInfo,
uiManager: ui,
heroState: heroStateFactory,
}
mainMenu.logger = d2util.NewLogger()
mainMenu.logger.SetPrefix(logPrefix)
mainMenu.logger.SetLevel(l)
if len(errorMessageOptional) != 0 {
mainMenu.errorLabel = ui.NewLabel(d2resource.FontFormal12, d2resource.PaletteUnits)
mainMenu.errorLabel.SetText(errorMessageOptional[0])
}
return mainMenu, nil
}
// MainMenu represents the main menu
type MainMenu struct {
tcpIPBackground *d2ui.Sprite
@ -126,43 +172,8 @@ type MainMenu struct {
heroState *d2hero.HeroStateFactory
buildInfo BuildInfo
}
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
buildInfo BuildInfo,
errorMessageOptional ...string,
) (*MainMenu, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
mainMenu := &MainMenu{
asset: asset,
screenMode: ScreenModeUnknown,
leftButtonHeld: true,
renderer: renderer,
inputManager: inputManager,
audioProvider: audioProvider,
navigator: navigator,
buildInfo: buildInfo,
uiManager: ui,
heroState: heroStateFactory,
}
if len(errorMessageOptional) != 0 {
mainMenu.errorLabel = ui.NewLabel(d2resource.FontFormal12, d2resource.PaletteUnits)
mainMenu.errorLabel.SetText(errorMessageOptional[0])
}
return mainMenu, nil
logger *d2util.Logger
}
// OnLoad is called to load the resources for the main menu
@ -187,7 +198,7 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
}
if err := v.inputManager.BindHandler(v); err != nil {
fmt.Println("failed to add main menu as event handler")
v.logger.Error("failed to add main menu as event handler")
}
}
@ -196,28 +207,28 @@ func (v *MainMenu) loadBackgroundSprites() {
v.background, err = v.uiManager.NewSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.background.SetPosition(backgroundX, backgroundY)
v.trademarkBackground, err = v.uiManager.NewSprite(d2resource.TrademarkScreen, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.trademarkBackground.SetPosition(backgroundX, backgroundY)
v.tcpIPBackground, err = v.uiManager.NewSprite(d2resource.TCPIPBackground, d2resource.PaletteSky)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
v.serverIPBackground, err = v.uiManager.NewSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
@ -285,7 +296,7 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
v.diabloLogoLeft, err = v.uiManager.NewSprite(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
@ -295,7 +306,7 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
v.diabloLogoRight, err = v.uiManager.NewSprite(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
@ -304,14 +315,14 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
v.diabloLogoLeftBack, err = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
v.diabloLogoRightBack, err = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
}
v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
@ -415,7 +426,7 @@ func (v *MainMenu) onGithubButtonClicked() {
}
if err != nil {
log.Fatal(err)
v.logger.Error(err.Error())
}
}
@ -625,15 +636,13 @@ func (v *MainMenu) getLocalIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Println(err)
v.logger.Error(err.Error())
return "cannot reach network"
}
err = conn.Close()
if err != nil {
log.Println(err)
v.logger.Error(err.Error())
return "unexpected error occurred while closing test connection"
}

View File

@ -2,7 +2,6 @@ package d2gamescreen
import (
"fmt"
"log"
"os"
"strings"
"time"
@ -13,6 +12,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
@ -87,6 +87,46 @@ func getRegions() []regionSpec {
}
}
// CreateMapEngineTest creates the Map Engine Test screen and returns a pointer to it
func CreateMapEngineTest(currentRegion,
levelPreset int,
asset *d2asset.AssetManager,
term d2interface.Terminal,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
l d2util.LogLevel,
screen *d2screen.ScreenManager,
) (*MapEngineTest, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
mapEngineTest := &MapEngineTest{
currentRegion: currentRegion,
levelPreset: levelPreset,
fileIndex: 0,
regionSpec: regionSpec{},
filesCount: 0,
asset: asset,
terminal: term,
renderer: renderer,
inputManager: inputManager,
audioProvider: audioProvider,
screen: screen,
playerStateFactory: heroStateFactory,
}
mapEngineTest.playerState = heroStateFactory.CreateTestGameState()
mapEngineTest.logger = d2util.NewLogger()
mapEngineTest.logger.SetLevel(l)
mapEngineTest.logger.SetPrefix(logPrefix)
return mapEngineTest, nil
}
// MapEngineTest represents the MapEngineTest screen
type MapEngineTest struct {
asset *d2asset.AssetManager
@ -111,45 +151,12 @@ type MapEngineTest struct {
fileIndex int
regionSpec regionSpec
filesCount int
}
// CreateMapEngineTest creates the Map Engine Test screen and returns a pointer to it
func CreateMapEngineTest(currentRegion,
levelPreset int,
asset *d2asset.AssetManager,
term d2interface.Terminal,
renderer d2interface.Renderer,
inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider,
screen *d2screen.ScreenManager,
) (*MapEngineTest, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
result := &MapEngineTest{
currentRegion: currentRegion,
levelPreset: levelPreset,
fileIndex: 0,
regionSpec: regionSpec{},
filesCount: 0,
asset: asset,
terminal: term,
renderer: renderer,
inputManager: inputManager,
audioProvider: audioProvider,
screen: screen,
playerStateFactory: heroStateFactory,
}
result.playerState = heroStateFactory.CreateTestGameState()
return result, nil
logger *d2util.Logger
}
func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
log.Printf("Loaded region: Type(%d) LevelPreset(%d) FileIndex(%d)", n, levelPreset, fileIndex)
met.logger.Info(fmt.Sprintf("Loaded region: Type(%d) LevelPreset(%d) FileIndex(%d)", n, levelPreset, fileIndex))
met.mapRenderer.InvalidateImageCache()
for _, spec := range getRegions() {
@ -204,7 +211,7 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
// OnLoad loads the resources for the Map Engine Test screen
func (met *MapEngineTest) OnLoad(loading d2screen.LoadingState) {
if err := met.inputManager.BindHandler(met); err != nil {
fmt.Printf("could not add MapEngineTest as event handler")
met.logger.Error("could not add MapEngineTest as event handler")
}
loading.Progress(twentyPercent)

View File

@ -3,7 +3,6 @@ package d2gamescreen
import (
"fmt"
"image"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
@ -258,17 +257,60 @@ type HeroRenderInfo struct {
SelectionBounds image.Rectangle
SelectSfx d2interface.SoundEffect
DeselectSfx d2interface.SoundEffect
shc *SelectHeroClass
}
func (hri *HeroRenderInfo) advance(elapsed float64) {
advanceSprite(hri.IdleSprite, elapsed)
advanceSprite(hri.IdleSelectedSprite, elapsed)
advanceSprite(hri.ForwardWalkSprite, elapsed)
advanceSprite(hri.ForwardWalkSpriteOverlay, elapsed)
advanceSprite(hri.SelectedSprite, elapsed)
advanceSprite(hri.SelectedSpriteOverlay, elapsed)
advanceSprite(hri.BackWalkSprite, elapsed)
advanceSprite(hri.BackWalkSpriteOverlay, elapsed)
advanceSprite(hri.shc, hri.IdleSprite, elapsed)
advanceSprite(hri.shc, hri.IdleSelectedSprite, elapsed)
advanceSprite(hri.shc, hri.ForwardWalkSprite, elapsed)
advanceSprite(hri.shc, hri.ForwardWalkSpriteOverlay, elapsed)
advanceSprite(hri.shc, hri.SelectedSprite, elapsed)
advanceSprite(hri.shc, hri.SelectedSpriteOverlay, elapsed)
advanceSprite(hri.shc, hri.BackWalkSprite, elapsed)
advanceSprite(hri.shc, hri.BackWalkSpriteOverlay, elapsed)
}
// CreateSelectHeroClass creates an instance of a SelectHeroClass
func CreateSelectHeroClass(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
connectionType d2clientconnectiontype.ClientConnectionType,
l d2util.LogLevel,
connectionHost string,
) (*SelectHeroClass, error) {
playerStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
inventoryItemFactory, err := d2inventory.NewInventoryItemFactory(asset)
if err != nil {
return nil, err
}
selectHeroClass := &SelectHeroClass{
asset: asset,
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
selectedHero: d2enum.HeroNone,
connectionType: connectionType,
connectionHost: connectionHost,
audioProvider: audioProvider,
renderer: renderer,
navigator: navigator,
uiManager: ui,
HeroStateFactory: playerStateFactory,
InventoryItemFactory: inventoryItemFactory,
}
selectHeroClass.logger = d2util.NewLogger()
selectHeroClass.logger.SetLevel(l)
selectHeroClass.logger.SetPrefix(logPrefix)
return selectHeroClass, nil
}
// SelectHeroClass represents the Select Hero Class screen
@ -300,43 +342,7 @@ type SelectHeroClass struct {
audioProvider d2interface.AudioProvider
renderer d2interface.Renderer
navigator d2interface.Navigator
}
// CreateSelectHeroClass creates an instance of a SelectHeroClass
func CreateSelectHeroClass(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string,
) (*SelectHeroClass, error) {
playerStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
inventoryItemFactory, err := d2inventory.NewInventoryItemFactory(asset)
if err != nil {
return nil, err
}
result := &SelectHeroClass{
asset: asset,
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
selectedHero: d2enum.HeroNone,
connectionType: connectionType,
connectionHost: connectionHost,
audioProvider: audioProvider,
renderer: renderer,
navigator: navigator,
uiManager: ui,
HeroStateFactory: playerStateFactory,
InventoryItemFactory: inventoryItemFactory,
}
return result, nil
logger *d2util.Logger
}
// OnLoad loads the resources for the Select Hero Class screen
@ -494,13 +500,13 @@ func (v *SelectHeroClass) onOkButtonClicked() {
playerState, err := v.CreateHeroState(heroName, v.selectedHero, statsState)
if err != nil {
fmt.Printf("failed to create hero state!, err: %v\n", err)
v.logger.Error("failed to create hero state!, err: %v\n" + err.Error())
return
}
err = v.Save(playerState)
if err != nil {
fmt.Printf("failed to save game state!, err: %v\n", err)
v.logger.Error("failed to save game state!, err: %v\n" + err.Error())
return
}
@ -640,13 +646,13 @@ func (v *SelectHeroClass) handleCursorButtonPress(hero d2enum.Hero, renderInfo *
func (v *SelectHeroClass) setCurrentFrame(mouseHover bool, renderInfo *HeroRenderInfo) {
if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected {
if err := renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame()); err != nil {
fmt.Printf("could not set current frame to: %d\n", renderInfo.IdleSprite.GetCurrentFrame())
v.logger.Error(fmt.Sprintf("could not set current frame to: %d\n", renderInfo.IdleSprite.GetCurrentFrame()))
}
renderInfo.Stance = d2enum.HeroStanceIdleSelected
} else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle {
if err := renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame()); err != nil {
fmt.Printf("could not set current frame to: %d\n", renderInfo.IdleSelectedSprite.GetCurrentFrame())
v.logger.Error(fmt.Sprintf("could not set current frame to: %d\n", renderInfo.IdleSelectedSprite.GetCurrentFrame()))
}
renderInfo.Stance = d2enum.HeroStanceIdle
@ -739,10 +745,10 @@ func drawSprite(sprite *d2ui.Sprite, target d2interface.Surface) {
}
}
func advanceSprite(sprite *d2ui.Sprite, elapsed float64) {
func advanceSprite(v *SelectHeroClass, sprite *d2ui.Sprite, elapsed float64) {
if sprite != nil {
if err := sprite.Advance(elapsed); err != nil {
fmt.Printf("could not advance the sprite\n")
v.logger.Error("could not advance the sprite:" + err.Error())
}
}
}
@ -757,7 +763,7 @@ func (v *SelectHeroClass) loadSprite(animationPath string, position image.Point,
sprite, err := v.uiManager.NewSprite(animationPath, d2resource.PaletteFechar)
if err != nil {
fmt.Printf("could not load sprite for the animation: %s\n", animationPath)
v.logger.Error("could not load sprite for the animation: %s\n" + animationPath + "with error: " + err.Error())
return nil
}
@ -780,7 +786,7 @@ func (v *SelectHeroClass) loadSprite(animationPath string, position image.Point,
func (v *SelectHeroClass) loadSoundEffect(sfx string) d2interface.SoundEffect {
result, err := v.audioProvider.LoadSound(sfx, false, false)
if err != nil {
log.Print(err)
v.logger.Error(err.Error())
return nil
}

View File

@ -2,12 +2,12 @@ package d2player
import (
"fmt"
"log"
"time"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -62,6 +62,42 @@ const (
singleFrame = time.Millisecond * 16
)
// NewEscapeMenu creates a new escape menu
func NewEscapeMenu(navigator d2interface.Navigator,
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
uiManager *d2ui.UIManager,
guiManager *d2gui.GuiManager,
assetManager *d2asset.AssetManager,
l d2util.LogLevel,
keyMap *KeyMap,
) *EscapeMenu {
m := &EscapeMenu{
audioProvider: audioProvider,
renderer: renderer,
navigator: navigator,
guiManager: guiManager,
assetManager: assetManager,
keyMap: keyMap,
}
keyBindingMenu := NewKeyBindingMenu(assetManager, renderer, uiManager, guiManager, keyMap, l, m)
m.keyBindingMenu = keyBindingMenu
m.layouts = make(map[layoutID]*layout)
m.layouts[mainLayoutID] = m.newMainLayout()
m.layouts[optionsLayoutID] = m.newOptionsLayout()
m.layouts[soundOptionsLayoutID] = m.newSoundOptionsLayout()
m.layouts[videoOptionsLayoutID] = m.newVideoOptionsLayout()
m.layouts[automapOptionsLayoutID] = m.newAutomapOptionsLayout()
m.logger = d2util.NewLogger()
m.logger.SetLevel(l)
m.logger.SetPrefix(logPrefix)
return m
}
// EscapeMenu represents the in-game menu that shows up when the esc key is pressed
type EscapeMenu struct {
isOpen bool
@ -82,6 +118,8 @@ type EscapeMenu struct {
keyBindingMenu *KeyBindingMenu
onCloseCb func()
logger *d2util.Logger
}
type layout struct {
@ -116,6 +154,7 @@ type enumLabel struct {
current int
playSound func()
updateValue func(optID optionID, value string)
*EscapeMenu
}
func (l *enumLabel) Trigger() {
@ -125,7 +164,7 @@ func (l *enumLabel) Trigger() {
currentValue := l.values[l.current]
if err := l.textChangingLabel.SetText(currentValue); err != nil {
fmt.Printf("could not change the label text to: %s\n", currentValue)
l.EscapeMenu.logger.Error(fmt.Sprintf("could not change the label text to: %s\n", currentValue))
}
l.updateValue(l.optionID, currentValue)
@ -136,37 +175,6 @@ type actionableElement interface {
Trigger()
}
// NewEscapeMenu creates a new escape menu
func NewEscapeMenu(navigator d2interface.Navigator,
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
uiManager *d2ui.UIManager,
guiManager *d2gui.GuiManager,
assetManager *d2asset.AssetManager,
keyMap *KeyMap,
) *EscapeMenu {
m := &EscapeMenu{
audioProvider: audioProvider,
renderer: renderer,
navigator: navigator,
guiManager: guiManager,
assetManager: assetManager,
keyMap: keyMap,
}
keyBindingMenu := NewKeyBindingMenu(assetManager, renderer, uiManager, guiManager, keyMap, m)
m.keyBindingMenu = keyBindingMenu
m.layouts = make(map[layoutID]*layout)
m.layouts[mainLayoutID] = m.newMainLayout()
m.layouts[optionsLayoutID] = m.newOptionsLayout()
m.layouts[soundOptionsLayoutID] = m.newSoundOptionsLayout()
m.layouts[videoOptionsLayoutID] = m.newVideoOptionsLayout()
m.layouts[automapOptionsLayoutID] = m.newAutomapOptionsLayout()
return m
}
func (m *EscapeMenu) newMainLayout() *layout {
return m.wrapLayout(func(l *layout) {
m.addBigSelectionLabel(l, "OPTIONS", optionsLayoutID)
@ -243,7 +251,7 @@ func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
leftPent, err := left.AddAnimatedSprite(d2resource.PentSpin, d2resource.PaletteUnits, d2gui.DirectionBackward)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
return nil
}
@ -263,7 +271,7 @@ func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
rightPent, err := right.AddAnimatedSprite(d2resource.PentSpin, d2resource.PaletteUnits, d2gui.DirectionForward)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
return nil
}
@ -282,7 +290,7 @@ func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
func (m *EscapeMenu) addTitle(l *layout, text string) {
_, err := l.AddLabel(text, d2gui.FontStyle42Units)
if err != nil {
fmt.Printf("could not add label: %s to the escape menu\n", text)
m.logger.Error("could not add label: %s to the escape menu\n" + text)
}
l.AddSpacerStatic(spacerWidth, labelGutter)
@ -291,7 +299,7 @@ func (m *EscapeMenu) addTitle(l *layout, text string) {
func (m *EscapeMenu) addBigSelectionLabel(l *layout, text string, targetLayout layoutID) {
guiLabel, err := l.AddLabel(text, d2gui.FontStyle42Units)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
}
label := &showLayoutLabel{Label: guiLabel, target: targetLayout, showLayout: m.showLayout}
@ -314,7 +322,7 @@ func (m *EscapeMenu) addPreviousMenuLabel(l *layout) {
guiLabel, err := l.AddLabel("PREVIOUS MENU", d2gui.FontStyle30Units)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
}
label := &showLayoutLabel{Label: guiLabel, target: optionsLayoutID, showLayout: m.showLayout}
@ -338,7 +346,7 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
_, err := layout.AddLabel(text, d2gui.FontStyle30Units)
if err != nil {
fmt.Printf("could not add label: %s to the escape menu\n", text)
m.logger.Error("could not add label: %s to the escape menu\n" + text)
}
elID := len(l.actionableElements)
@ -351,7 +359,7 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
guiLabel, err := layout.AddLabel(values[0], d2gui.FontStyle30Units)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
}
label := &enumLabel{
@ -378,14 +386,14 @@ func (m *EscapeMenu) OnLoad() {
err = m.keyBindingMenu.Load()
if err != nil {
log.Printf("unable to load the configure controls window: %v", err)
m.logger.Error("unable to load the configure controls window: %v" + err.Error())
}
m.layouts[configureControlsLayoutID] = m.newConfigureControlsLayout(m.keyBindingMenu)
m.selectSound, err = m.audioProvider.LoadSound(d2resource.SFXCursorSelect, false, false)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
}
}
@ -403,7 +411,7 @@ func (m *EscapeMenu) OnEscKey() {
m.setLayout(optionsLayoutID)
if err := m.keyBindingMenu.Close(); err != nil {
log.Printf("unable to close the configure controls menu: %v", err)
m.logger.Error("unable to close the configure controls menu: %v" + err.Error())
}
return
@ -451,7 +459,7 @@ func (m *EscapeMenu) showLayout(id layoutID) {
if id == configureControlsLayoutID {
m.keyBindingMenu.Open()
} else if err := m.keyBindingMenu.Close(); err != nil {
fmt.Printf("unable to close the configure controls menu: %v", err)
m.logger.Error("unable to close the configure controls menu: %v" + err.Error())
}
}
@ -467,7 +475,7 @@ func (m *EscapeMenu) onHoverElement(id int) {
}
func (m *EscapeMenu) onUpdateValue(optID optionID, value string) {
fmt.Printf("updating value %d with %s\n", optID, value)
m.logger.Info(fmt.Sprintf("updating value %d with %s\n", optID, value))
}
func (m *EscapeMenu) setLayout(id layoutID) {
@ -574,7 +582,7 @@ func (m *EscapeMenu) OnMouseButtonDown(event d2interface.MouseEvent) bool {
if m.currentLayout == configureControlsLayoutID {
if err := m.keyBindingMenu.onMouseButtonDown(event); err != nil {
log.Printf("unable to handle mouse down on configure controls menu: %v", err)
m.logger.Error("unable to handle mouse down on configure controls menu: %v" + err.Error())
}
}
@ -611,7 +619,7 @@ func (m *EscapeMenu) OnMouseMove(event d2interface.MouseMoveEvent) bool {
func (m *EscapeMenu) OnKeyDown(event d2interface.KeyEvent) bool {
if m.keyBindingMenu.IsOpen() {
if err := m.keyBindingMenu.OnKeyDown(event); err != nil {
log.Printf("unable to handle key down on configure controls menu: %v", err)
m.logger.Error("unable to handle key down on configure controls menu: %v" + err.Error())
}
return false

View File

@ -2,7 +2,6 @@ package d2player
import (
"fmt"
"log"
"strings"
"time"
@ -22,6 +21,10 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
const (
logPrefix = "Player"
)
// Panel represents the panel at the bottom of the game screen
type Panel interface {
IsOpen() bool
@ -109,50 +112,6 @@ const (
menuRightRectH = 400, 0, 400, 600
)
// GameControls represents the game's controls on the screen
type GameControls struct {
keyMap *KeyMap
actionableRegions []actionableRegion
asset *d2asset.AssetManager
renderer d2interface.Renderer // https://github.com/OpenDiablo2/OpenDiablo2/issues/798
inputListener inputCallbackListener
hero *d2mapentity.Player
heroState *d2hero.HeroStateFactory
mapRenderer *d2maprenderer.MapRenderer
escapeMenu *EscapeMenu
ui *d2ui.UIManager
inventory *Inventory
hud *HUD
skilltree *skillTree
heroStatsPanel *HeroStatsPanel
HelpOverlay *HelpOverlay
bottomMenuRect *d2geom.Rectangle
leftMenuRect *d2geom.Rectangle
rightMenuRect *d2geom.Rectangle
lastMouseX int
lastMouseY int
lastLeftBtnActionTime float64
lastRightBtnActionTime float64
FreeCam bool
isSinglePlayer bool
}
type actionableType int
type actionableRegion struct {
actionableTypeID actionableType
rect d2geom.Rectangle
}
// SkillResource represents a Skill with its corresponding icon sprite, path to DC6 file and icon number.
// SkillResourcePath points to a DC6 resource which contains the icons of multiple skills as frames.
// The IconNumber is the frame at which we can find our skill sprite in the DC6 file.
type SkillResource struct {
SkillResourcePath string // path to a skills DC6 file(see getSkillResourceByClass)
IconNumber int // the index of the frame in the DC6 file
SkillIcon *d2ui.Sprite
}
// NewGameControls creates a GameControls instance and returns a pointer to it
// nolint:funlen // doesn't make sense to split this up
func NewGameControls(
@ -167,6 +126,7 @@ func NewGameControls(
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
keyMap *KeyMap,
l d2util.LogLevel,
isSinglePlayer bool,
) (*GameControls, error) {
var inventoryRecordKey string
@ -248,19 +208,19 @@ func NewGameControls(
}
inventoryRecord := asset.Records.Layout.Inventory[inventoryRecordKey]
heroStatsPanel := NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats)
inventory := NewInventory(asset, ui, inventoryRecord)
skilltree := newSkillTree(hero.Skills, hero.Class, asset, ui)
heroStatsPanel := NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, l, hero.Stats)
inventory := NewInventory(asset, ui, l, inventoryRecord)
skilltree := newSkillTree(hero.Skills, hero.Class, asset, l, ui)
miniPanel := newMiniPanel(asset, ui, isSinglePlayer)
miniPanel := newMiniPanel(asset, ui, l, isSinglePlayer)
heroState, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
helpOverlay := NewHelpOverlay(asset, renderer, ui, guiManager, keyMap)
hud := NewHUD(asset, ui, hero, helpOverlay, miniPanel, actionableRegions, mapEngine, mapRenderer)
helpOverlay := NewHelpOverlay(asset, renderer, ui, guiManager, l, keyMap)
hud := NewHUD(asset, ui, hero, helpOverlay, miniPanel, actionableRegions, mapEngine, l, mapRenderer)
const blackAlpha50percent = 0x0000007f
@ -317,9 +277,59 @@ func NewGameControls(
return nil, err
}
gc.logger = d2util.NewLogger()
gc.logger.SetLevel(l)
gc.logger.SetPrefix(logPrefix)
return gc, nil
}
// GameControls represents the game's controls on the screen
type GameControls struct {
keyMap *KeyMap
actionableRegions []actionableRegion
asset *d2asset.AssetManager
renderer d2interface.Renderer // https://github.com/OpenDiablo2/OpenDiablo2/issues/798
inputListener inputCallbackListener
hero *d2mapentity.Player
heroState *d2hero.HeroStateFactory
mapRenderer *d2maprenderer.MapRenderer
escapeMenu *EscapeMenu
ui *d2ui.UIManager
inventory *Inventory
hud *HUD
skilltree *skillTree
heroStatsPanel *HeroStatsPanel
HelpOverlay *HelpOverlay
bottomMenuRect *d2geom.Rectangle
leftMenuRect *d2geom.Rectangle
rightMenuRect *d2geom.Rectangle
lastMouseX int
lastMouseY int
lastLeftBtnActionTime float64
lastRightBtnActionTime float64
FreeCam bool
isSinglePlayer bool
logger *d2util.Logger
}
type actionableType int
type actionableRegion struct {
actionableTypeID actionableType
rect d2geom.Rectangle
}
// SkillResource represents a Skill with its corresponding icon sprite, path to DC6 file and icon number.
// SkillResourcePath points to a DC6 resource which contains the icons of multiple skills as frames.
// The IconNumber is the frame at which we can find our skill sprite in the DC6 file.
type SkillResource struct {
SkillResourcePath string // path to a skills DC6 file(see getSkillResourceByClass)
IconNumber int // the index of the frame in the DC6 file
SkillIcon *d2ui.Sprite
}
// OnKeyRepeat is called to handle repeated key presses
func (g *GameControls) OnKeyRepeat(event d2interface.KeyEvent) bool {
if g.FreeCam {
@ -800,7 +810,7 @@ func (g *GameControls) onHoverActionable(item actionableType) {
onHover, found := hoverMap[item]
if !found {
log.Printf("Unrecognized actionableType(%d) being hovered\n", item)
g.logger.Error(fmt.Sprintf("Unrecognized actionableType(%d) being hovered\n", item))
return
}
@ -815,23 +825,23 @@ func (g *GameControls) onClickActionable(item actionableType) {
},
newStats: func() {
log.Println("New Stats Selector Action Pressed")
g.logger.Info("New Stats Selector Action Pressed")
},
xp: func() {
log.Println("XP Action Pressed")
g.logger.Info("XP Action Pressed")
},
walkRun: func() {
log.Println("Walk/Run Action Pressed")
g.logger.Info("Walk/Run Action Pressed")
},
stamina: func() {
log.Println("Stamina Action Pressed")
g.logger.Info("Stamina Action Pressed")
},
newSkills: func() {
log.Println("New Skills Selector Action Pressed")
g.logger.Info("New Skills Selector Action Pressed")
},
rightSkill: func() {
@ -840,18 +850,19 @@ func (g *GameControls) onClickActionable(item actionableType) {
hpGlobe: func() {
g.ToggleHpStats()
log.Println("HP Globe Pressed")
g.logger.Info("HP Globe Pressed")
},
manaGlobe: func() {
g.ToggleManaStats()
log.Println("Mana Globe Pressed")
g.logger.Info("Mana Globe Pressed")
},
}
action, found := actionMap[item]
if !found {
log.Printf("Unrecognized actionableType(%d) being clicked\n", item)
// Warning, because some action types are still todo, and could return this error
g.logger.Warning(fmt.Sprintf("Unrecognized actionableType(%d) being clicked\n", item))
return
}
@ -961,7 +972,7 @@ func (g *GameControls) bindLearnSkillsCommand(term d2interface.Terminal) error {
}
g.hud.skillSelectMenu.RegenerateImageCache()
log.Printf("Learned %d skills", learnedSkillsCount)
g.logger.Info(fmt.Sprintf("Learned %d skills", learnedSkillsCount))
if err != nil {
term.OutputErrorf("cannot learn skill for class, error: %s", err)
@ -998,7 +1009,7 @@ func (g *GameControls) bindLearnSkillByIDCommand(term d2interface.Terminal) erro
}
g.hud.skillSelectMenu.RegenerateImageCache()
log.Println("Learned skill: ", skill.Skill)
g.logger.Info("Learned skill: " + skill.Skill)
}
return term.BindAction(

View File

@ -2,10 +2,10 @@ package d2player
import (
"image"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -40,11 +40,12 @@ type globeFrame struct {
offsetX int
offsetY int
idx int
gw *globeWidget
}
func (gf *globeFrame) setFrameIndex() {
if err := gf.sprite.SetCurrentFrame(gf.idx); err != nil {
log.Print(err)
gf.gw.logger.Error(err.Error())
}
}
@ -57,15 +58,7 @@ func (gf *globeFrame) getSize() (x, y int) {
return w + gf.offsetX, h + gf.offsetY
}
type globeWidget struct {
*d2ui.BaseWidget
value *int
valueMax *int
globe *globeFrame
overlap *globeFrame
}
func newGlobeWidget(ui *d2ui.UIManager, x, y int, gtype globeType, value, valueMax *int) *globeWidget {
func newGlobeWidget(ui *d2ui.UIManager, x, y int, gtype globeType, value *int, l d2util.LogLevel, valueMax *int) *globeWidget {
var globe, overlap *globeFrame
base := d2ui.NewBaseWidget(ui)
@ -95,13 +88,28 @@ func newGlobeWidget(ui *d2ui.UIManager, x, y int, gtype globeType, value, valueM
}
}
return &globeWidget{
gw := &globeWidget{
BaseWidget: base,
value: value,
valueMax: valueMax,
globe: globe,
overlap: overlap,
}
gw.logger = d2util.NewLogger()
gw.logger.SetLevel(l)
gw.logger.SetPrefix(logPrefix)
return gw
}
type globeWidget struct {
*d2ui.BaseWidget
value *int
valueMax *int
globe *globeFrame
overlap *globeFrame
logger *d2util.Logger
}
func (g *globeWidget) load() {
@ -109,14 +117,14 @@ func (g *globeWidget) load() {
g.globe.sprite, err = g.GetManager().NewSprite(d2resource.HealthManaIndicator, d2resource.PaletteSky)
if err != nil {
log.Print(err)
g.logger.Error(err.Error())
}
g.globe.setFrameIndex()
g.overlap.sprite, err = g.GetManager().NewSprite(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
if err != nil {
log.Print(err)
g.logger.Error(err.Error())
}
g.overlap.setFrameIndex()

View File

@ -3,12 +3,12 @@ package d2player
import (
"fmt"
"image/color"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -156,6 +156,30 @@ const (
beltDotY = 568
)
// NewHelpOverlay creates a new HelpOverlay instance
func NewHelpOverlay(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
l d2util.LogLevel,
keyMap *KeyMap,
) *HelpOverlay {
h := &HelpOverlay{
asset: asset,
renderer: renderer,
uiManager: ui,
guiManager: guiManager,
keyMap: keyMap,
}
h.logger = d2util.NewLogger()
h.logger.SetLevel(l)
h.logger.SetPrefix(logPrefix)
return h
}
// HelpOverlay represents the in-game overlay that toggles visibility when the h key is pressed
type HelpOverlay struct {
asset *d2asset.AssetManager
@ -169,30 +193,13 @@ type HelpOverlay struct {
closeButton *d2ui.Button
guiManager *d2gui.GuiManager
keyMap *KeyMap
}
// NewHelpOverlay creates a new HelpOverlay instance
func NewHelpOverlay(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
keyMap *KeyMap,
) *HelpOverlay {
h := &HelpOverlay{
asset: asset,
renderer: renderer,
uiManager: ui,
guiManager: guiManager,
keyMap: keyMap,
}
return h
logger *d2util.Logger
}
// Toggle the visibility state of the overlay
func (h *HelpOverlay) Toggle() {
fmt.Print("Help overlay toggled\n")
h.logger.Info("Help overlay toggled")
if h.isOpen {
h.Close()
@ -265,12 +272,12 @@ func (h *HelpOverlay) setupOverlayFrame() {
for _, frameIndex := range frames {
f, err := h.uiManager.NewSprite(d2resource.HelpBorder, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
err = f.SetCurrentFrame(frameIndex)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
frameWidth, frameHeight := f.GetCurrentFrameSize()
@ -559,12 +566,12 @@ func (h *HelpOverlay) createBullet(c callout) {
newDot, err := h.uiManager.NewSprite(d2resource.HelpYellowBullet, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
err = newDot.SetCurrentFrame(0)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
newDot.SetPosition(c.DotX, c.DotY+bulletOffsetY)
@ -601,12 +608,12 @@ func (h *HelpOverlay) createCallout(c callout) {
newDot, err := h.uiManager.NewSprite(d2resource.HelpWhiteBullet, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
err = newDot.SetCurrentFrame(0)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
newDot.SetPosition(c.DotX, c.DotY)

View File

@ -1,12 +1,12 @@
package d2player
import (
"log"
"strconv"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -82,6 +82,34 @@ type StatsPanelLabels struct {
Stamina *d2ui.Label
}
// NewHeroStatsPanel creates a new hero status panel
func NewHeroStatsPanel(asset *d2asset.AssetManager,
ui *d2ui.UIManager,
heroName string,
heroClass d2enum.Hero,
l d2util.LogLevel,
heroState *d2hero.HeroStatsState) *HeroStatsPanel {
originX := 0
originY := 0
hsp := &HeroStatsPanel{
asset: asset,
uiManager: ui,
originX: originX,
originY: originY,
heroState: heroState,
heroName: heroName,
heroClass: heroClass,
labels: &StatsPanelLabels{},
}
hsp.logger = d2util.NewLogger()
hsp.logger.SetLevel(l)
hsp.logger.SetPrefix(logPrefix)
return hsp
}
// HeroStatsPanel represents the hero status panel
type HeroStatsPanel struct {
asset *d2asset.AssetManager
@ -97,24 +125,8 @@ type HeroStatsPanel struct {
originX int
originY int
isOpen bool
}
// NewHeroStatsPanel creates a new hero status panel
func NewHeroStatsPanel(asset *d2asset.AssetManager, ui *d2ui.UIManager, heroName string, heroClass d2enum.Hero,
heroState *d2hero.HeroStatsState) *HeroStatsPanel {
originX := 0
originY := 0
return &HeroStatsPanel{
asset: asset,
uiManager: ui,
originX: originX,
originY: originY,
heroState: heroState,
heroName: heroName,
heroClass: heroClass,
labels: &StatsPanelLabels{},
}
logger *d2util.Logger
}
// Load the data for the hero status panel
@ -128,7 +140,7 @@ func (s *HeroStatsPanel) Load() {
s.panel, err = s.uiManager.NewSprite(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
if err != nil {
log.Print(err)
s.logger.Error(err.Error())
}
w, h := frame.GetSize()
@ -204,7 +216,7 @@ func (s *HeroStatsPanel) renderStaticPanelFrames(target d2interface.Surface) {
for _, frameIndex := range frames {
if err := s.panel.SetCurrentFrame(frameIndex); err != nil {
log.Printf("%e", err)
s.logger.Error(err.Error())
}
w, h := s.panel.GetCurrentFrameSize()

View File

@ -2,7 +2,6 @@ package d2player
import (
"fmt"
"log"
"math"
"strings"
@ -116,6 +115,7 @@ type HUD struct {
widgetLeftSkill *d2ui.CustomWidget
widgetRightSkill *d2ui.CustomWidget
panelBackground *d2ui.CustomWidget
logger *d2util.Logger
}
// NewHUD creates a HUD object
@ -127,6 +127,7 @@ func NewHUD(
miniPanel *miniPanel,
actionableRegions []actionableRegion,
mapEngine *d2mapengine.MapEngine,
l d2util.LogLevel,
mapRenderer *d2maprenderer.MapRenderer,
) *HUD {
nameLabel := ui.NewLabel(d2resource.Font16, d2resource.PaletteStatic)
@ -136,10 +137,10 @@ func NewHUD(
zoneLabel := ui.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
zoneLabel.Alignment = d2ui.HorizontalAlignCenter
healthGlobe := newGlobeWidget(ui, 0, screenHeight, typeHealthGlobe, &hero.Stats.Health, &hero.Stats.MaxHealth)
manaGlobe := newGlobeWidget(ui, screenWidth-manaGlobeScreenOffsetX, screenHeight, typeManaGlobe, &hero.Stats.Mana, &hero.Stats.MaxMana)
healthGlobe := newGlobeWidget(ui, 0, screenHeight, typeHealthGlobe, &hero.Stats.Health, l, &hero.Stats.MaxHealth)
manaGlobe := newGlobeWidget(ui, screenWidth-manaGlobeScreenOffsetX, screenHeight, typeManaGlobe, &hero.Stats.Mana, l, &hero.Stats.MaxMana)
return &HUD{
hud := &HUD{
asset: asset,
uiManager: ui,
hero: hero,
@ -149,11 +150,17 @@ func NewHUD(
miniPanel: miniPanel,
actionableRegions: actionableRegions,
nameLabel: nameLabel,
skillSelectMenu: NewSkillSelectMenu(asset, ui, hero),
skillSelectMenu: NewSkillSelectMenu(asset, ui, l, hero),
zoneChangeText: zoneLabel,
healthGlobe: healthGlobe,
manaGlobe: manaGlobe,
}
hud.logger = d2util.NewLogger()
hud.logger.SetPrefix(logPrefix)
hud.logger.SetLevel(l)
return hud
}
// Load creates the ui elemets
@ -173,7 +180,7 @@ func (h *HUD) loadCustomWidgets() {
// static background
_, height, err := h.mainPanel.GetFrameSize(0) // health globe is the frame with max height
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -210,7 +217,7 @@ func (h *HUD) loadSkillResources() {
// https://github.com/OpenDiablo2/OpenDiablo2/issues/799
genericSkillsSprite, err := h.uiManager.NewSprite(d2resource.GenericSkills, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
attackIconID := 2
@ -233,17 +240,17 @@ func (h *HUD) loadSprites() {
h.globeSprite, err = h.uiManager.NewSprite(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
h.hpManaStatusSprite, err = h.uiManager.NewSprite(d2resource.HealthManaIndicator, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
h.mainPanel, err = h.uiManager.NewSprite(d2resource.GamePanels, d2resource.PaletteSky)
if err != nil {
log.Print(err)
h.logger.Error(err.Error())
}
}
@ -348,7 +355,7 @@ func (h *HUD) renderPanelStatic(target d2interface.Surface) {
// Main panel background
if err := h.renderPanel(offsetX, offsetY, target); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -357,7 +364,7 @@ func (h *HUD) renderPanelStatic(target d2interface.Surface) {
offsetX += w + skillIconWidth
if err := h.renderNewStatsButton(offsetX, offsetY, target); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -366,7 +373,7 @@ func (h *HUD) renderPanelStatic(target d2interface.Surface) {
offsetX += w
if err := h.renderStamina(offsetX, offsetY, target); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -375,7 +382,7 @@ func (h *HUD) renderPanelStatic(target d2interface.Surface) {
offsetX += w
if err := h.renderPotions(offsetX, offsetY, target); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -384,7 +391,7 @@ func (h *HUD) renderPanelStatic(target d2interface.Surface) {
offsetX += w
if err := h.renderNewSkillsButton(offsetX, offsetY, target); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -393,7 +400,7 @@ func (h *HUD) renderPanelStatic(target d2interface.Surface) {
offsetX += w + skillIconWidth
if err := h.mainPanel.SetCurrentFrame(frameRightGlobeHolder); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -420,7 +427,7 @@ func (h *HUD) renderLeftSkill(x, y int, target d2interface.Surface) {
}
if err := h.leftSkillResource.SkillIcon.SetCurrentFrame(h.hero.LeftSkill.IconCel); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -438,7 +445,7 @@ func (h *HUD) renderRightSkill(x, _ int, target d2interface.Surface) {
}
if err := h.rightSkillResource.SkillIcon.SetCurrentFrame(h.hero.RightSkill.IconCel); err != nil {
log.Print(err)
h.logger.Error(err.Error())
return
}
@ -704,7 +711,7 @@ func (h *HUD) getSkillResourceByClass(class string) string {
entry, found := resourceMap[class]
if !found {
log.Fatalf("Unknown class token: '%s'", class)
h.logger.Error("Unknown class token: '%s'" + class)
}
return entry

View File

@ -1,14 +1,12 @@
package d2player
import (
"fmt"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2item/diablo2item"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -25,6 +23,34 @@ const (
invCloseButtonX, invCloseButtonY = 419, 449
)
// NewInventory creates an inventory instance and returns a pointer to it
func NewInventory(asset *d2asset.AssetManager,
ui *d2ui.UIManager,
l d2util.LogLevel,
record *d2records.InventoryRecord) *Inventory {
itemTooltip := ui.NewTooltip(d2resource.FontFormal11, d2resource.PaletteStatic, d2ui.TooltipXCenter, d2ui.TooltipYBottom)
// https://github.com/OpenDiablo2/OpenDiablo2/issues/797
itemFactory, _ := diablo2item.NewItemFactory(asset)
inventory := &Inventory{
asset: asset,
uiManager: ui,
item: itemFactory,
grid: NewItemGrid(asset, ui, l, record),
originX: record.Panel.Left,
itemTooltip: itemTooltip,
// originY: record.Panel.Top,
originY: 0, // expansion data has these all offset by +60 ...
}
inventory.logger = d2util.NewLogger()
inventory.logger.SetLevel(l)
inventory.logger.SetPrefix(logPrefix)
return inventory
}
// Inventory represents the inventory
type Inventory struct {
asset *d2asset.AssetManager
@ -44,26 +70,8 @@ type Inventory struct {
hovering bool
isOpen bool
onCloseCb func()
}
// NewInventory creates an inventory instance and returns a pointer to it
func NewInventory(asset *d2asset.AssetManager, ui *d2ui.UIManager,
record *d2records.InventoryRecord) *Inventory {
itemTooltip := ui.NewTooltip(d2resource.FontFormal11, d2resource.PaletteStatic, d2ui.TooltipXCenter, d2ui.TooltipYBottom)
// https://github.com/OpenDiablo2/OpenDiablo2/issues/797
itemFactory, _ := diablo2item.NewItemFactory(asset)
return &Inventory{
asset: asset,
uiManager: ui,
item: itemFactory,
grid: NewItemGrid(asset, ui, record),
originX: record.Panel.Left,
itemTooltip: itemTooltip,
// originY: record.Panel.Top,
originY: 0, // expansion data has these all offset by +60 ...
}
logger *d2util.Logger
}
// IsOpen returns true if the inventory is open
@ -154,7 +162,7 @@ func (g *Inventory) Load() {
_, err := g.grid.Add(inventoryItems...)
if err != nil {
fmt.Printf("could not add items to the inventory, err: %v\n", err)
g.logger.Error("could not add items to the inventory, err: %v\n" + err.Error())
}
}
@ -166,7 +174,7 @@ func (g *Inventory) Render(target d2interface.Surface) {
err := g.renderFrame(target)
if err != nil {
log.Println(err)
g.logger.Error(err.Error())
}
g.grid.Render(target)

View File

@ -3,7 +3,6 @@ package d2player
import (
"errors"
"fmt"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
@ -14,6 +13,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
)
// images for 1x1 grid tile items (rings and stuff) are 28x28 pixel
@ -36,6 +36,32 @@ type InventoryItem interface {
var errorInventoryFull = errors.New("inventory full")
// NewItemGrid creates a new ItemGrid instance
func NewItemGrid(asset *d2asset.AssetManager,
ui *d2ui.UIManager,
l d2util.LogLevel,
record *d2records.InventoryRecord) *ItemGrid {
grid := record.Grid
itemGrid := &ItemGrid{
asset: asset,
uiManager: ui,
width: grid.Box.Width,
height: grid.Box.Height,
originX: grid.Box.Left,
originY: grid.Box.Top + (grid.Rows * cellPadding),
slotSize: grid.CellWidth,
sprites: make(map[string]*d2ui.Sprite),
equipmentSlots: genEquipmentSlotsMap(record),
}
itemGrid.logger = d2util.NewLogger()
itemGrid.logger.SetLevel(l)
itemGrid.logger.SetPrefix(logPrefix)
return itemGrid
}
// ItemGrid is a reusable grid for use with player and merchant inventory.
// Handles layout and rendering item icons based on code.
type ItemGrid struct {
@ -49,24 +75,8 @@ type ItemGrid struct {
originY int
sprites map[string]*d2ui.Sprite
slotSize int
}
// NewItemGrid creates a new ItemGrid instance
func NewItemGrid(asset *d2asset.AssetManager, ui *d2ui.UIManager,
record *d2records.InventoryRecord) *ItemGrid {
grid := record.Grid
return &ItemGrid{
asset: asset,
uiManager: ui,
width: grid.Box.Width,
height: grid.Box.Height,
originX: grid.Box.Left,
originY: grid.Box.Top + (grid.Rows * cellPadding),
slotSize: grid.CellWidth,
sprites: make(map[string]*d2ui.Sprite),
equipmentSlots: genEquipmentSlotsMap(record),
}
logger *d2util.Logger
}
// SlotToScreen translates slot coordinates to screen coordinates
@ -135,7 +145,7 @@ func (g *ItemGrid) loadItem(item InventoryItem) {
itemSprite, err := g.uiManager.NewSprite(imgPath, d2resource.PaletteSky)
if err != nil {
log.Printf("Failed to load sprite, error: " + err.Error())
g.logger.Error("Failed to load sprite, error: " + err.Error())
}
g.sprites[item.GetItemCode()] = itemSprite

View File

@ -2,7 +2,6 @@ package d2player
import (
"image/color"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
@ -44,6 +43,66 @@ type bindingChange struct {
secondary d2enum.Key
}
// NewKeyBindingMenu generates a new instance of the "Configure Keys"
// menu found in the options
func NewKeyBindingMenu(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
keyMap *KeyMap,
l d2util.LogLevel,
escapeMenu *EscapeMenu,
) *KeyBindingMenu {
mainLayout := d2gui.CreateLayout(renderer, d2gui.PositionTypeAbsolute, asset)
contentLayout := mainLayout.AddLayout(d2gui.PositionTypeAbsolute)
ret := &KeyBindingMenu{
keyMap: keyMap,
asset: asset,
ui: ui,
guiManager: guiManager,
renderer: renderer,
mainLayout: mainLayout,
contentLayout: contentLayout,
bindingLayouts: []*bindingLayout{},
changesToBeSaved: make(map[d2enum.GameEvent]*bindingChange),
escapeMenu: escapeMenu,
}
ret.logger = d2util.NewLogger()
ret.logger.SetLevel(l)
ret.logger.SetPrefix(logPrefix)
ret.Box = d2gui.NewBox(
asset, renderer, ui, ret.mainLayout,
keyBindingMenuWidth, keyBindingMenuHeight,
keyBindingMenuX, keyBindingMenuY, "",
)
ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY)
ret.Box.SetOptions([]*d2gui.LabelButton{
d2gui.NewLabelButton(0, 0, "Cancel", d2util.Color(d2gui.ColorRed), func() {
if err := ret.onCancelClicked(); err != nil {
ret.logger.Error("error while clicking option Cancel: %v" + err.Error())
}
}),
d2gui.NewLabelButton(0, 0, "Default", d2util.Color(d2gui.ColorBlue), func() {
if err := ret.onDefaultClicked(); err != nil {
ret.logger.Error("error while clicking option Default: %v" + err.Error())
}
}),
d2gui.NewLabelButton(0, 0, "Accept", d2util.Color(d2gui.ColorGreen), func() {
if err := ret.onAcceptClicked(); err != nil {
ret.logger.Error("error while clicking option Accept: %v" + err.Error())
}
}),
})
return ret
}
// KeyBindingMenu represents the menu to view/edit the
// key bindings
type KeyBindingMenu struct {
@ -67,61 +126,8 @@ type KeyBindingMenu struct {
currentBindingModifier d2enum.GameEvent
currentBindingLayout *bindingLayout
lastBindingLayout *bindingLayout
}
// NewKeyBindingMenu generates a new instance of the "Configure Keys"
// menu found in the options
func NewKeyBindingMenu(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
keyMap *KeyMap,
escapeMenu *EscapeMenu,
) *KeyBindingMenu {
mainLayout := d2gui.CreateLayout(renderer, d2gui.PositionTypeAbsolute, asset)
contentLayout := mainLayout.AddLayout(d2gui.PositionTypeAbsolute)
ret := &KeyBindingMenu{
keyMap: keyMap,
asset: asset,
ui: ui,
guiManager: guiManager,
renderer: renderer,
mainLayout: mainLayout,
contentLayout: contentLayout,
bindingLayouts: []*bindingLayout{},
changesToBeSaved: make(map[d2enum.GameEvent]*bindingChange),
escapeMenu: escapeMenu,
}
ret.Box = d2gui.NewBox(
asset, renderer, ui, ret.mainLayout,
keyBindingMenuWidth, keyBindingMenuHeight,
keyBindingMenuX, keyBindingMenuY, "",
)
ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY)
ret.Box.SetOptions([]*d2gui.LabelButton{
d2gui.NewLabelButton(0, 0, "Cancel", d2util.Color(d2gui.ColorRed), func() {
if err := ret.onCancelClicked(); err != nil {
log.Printf("error while clicking option Cancel: %v", err)
}
}),
d2gui.NewLabelButton(0, 0, "Default", d2util.Color(d2gui.ColorBlue), func() {
if err := ret.onDefaultClicked(); err != nil {
log.Printf("error while clicking option Default: %v", err)
}
}),
d2gui.NewLabelButton(0, 0, "Accept", d2util.Color(d2gui.ColorGreen), func() {
if err := ret.onAcceptClicked(); err != nil {
log.Printf("error while clicking option Accept: %v", err)
}
}),
})
return ret
logger *d2util.Logger
}
// Close will disable the render of the menu and clear

View File

@ -1,9 +1,8 @@
package d2player
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -41,6 +40,24 @@ type miniPanelActions struct {
menuToggle func()
}
func newMiniPanel(asset *d2asset.AssetManager,
uiManager *d2ui.UIManager,
l d2util.LogLevel,
isSinglePlayer bool) *miniPanel {
mp := &miniPanel{
ui: uiManager,
asset: asset,
isOpen: false,
isSinglePlayer: isSinglePlayer,
}
mp.logger = d2util.NewLogger()
mp.logger.SetLevel(l)
mp.logger.SetPrefix(logPrefix)
return mp
}
type miniPanel struct {
ui *d2ui.UIManager
asset *d2asset.AssetManager
@ -52,15 +69,8 @@ type miniPanel struct {
movedRight bool
panelGroup *d2ui.WidgetGroup
tooltipGroup *d2ui.WidgetGroup
}
func newMiniPanel(asset *d2asset.AssetManager, uiManager *d2ui.UIManager, isSinglePlayer bool) *miniPanel {
return &miniPanel{
ui: uiManager,
asset: asset,
isOpen: false,
isSinglePlayer: isSinglePlayer,
}
logger *d2util.Logger
}
func (m *miniPanel) load(actions *miniPanelActions) {
@ -68,7 +78,7 @@ func (m *miniPanel) load(actions *miniPanelActions) {
m.sprite, err = m.ui.NewSprite(d2resource.MinipanelButton, d2resource.PaletteSky)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
return
}
@ -90,12 +100,12 @@ func (m *miniPanel) createWidgets(actions *miniPanelActions) {
m.container, err = m.ui.NewSprite(miniPanelContainerPath, d2resource.PaletteSky)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
return
}
if err = m.container.SetCurrentFrame(0); err != nil {
log.Print(err)
m.logger.Error(err.Error())
return
}
@ -106,7 +116,7 @@ func (m *miniPanel) createWidgets(actions *miniPanelActions) {
buttonWidth, buttonHeight, err := m.sprite.GetFrameSize(0)
if err != nil {
log.Print(err)
m.logger.Error(err.Error())
return
}

View File

@ -2,6 +2,7 @@ package d2player
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -14,10 +15,10 @@ type SkillSelectMenu struct {
}
// NewSkillSelectMenu creates a skill select menu.
func NewSkillSelectMenu(asset *d2asset.AssetManager, ui *d2ui.UIManager, hero *d2mapentity.Player) *SkillSelectMenu {
func NewSkillSelectMenu(asset *d2asset.AssetManager, ui *d2ui.UIManager, l d2util.LogLevel, hero *d2mapentity.Player) *SkillSelectMenu {
skillSelectMenu := &SkillSelectMenu{
LeftPanel: NewHeroSkillsPanel(asset, ui, hero, true),
RightPanel: NewHeroSkillsPanel(asset, ui, hero, false),
LeftPanel: NewHeroSkillsPanel(asset, ui, hero, l, true),
RightPanel: NewHeroSkillsPanel(asset, ui, hero, l, false),
}
return skillSelectMenu

View File

@ -2,12 +2,12 @@ package d2player
import (
"fmt"
"log"
"sort"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
@ -25,6 +25,40 @@ const (
skillListsLength = 5 // 0 to 4. 0 - General Skills, 1 to 3 - Class-specific skills(based on the 3 different skill trees), 4 - Other skills
)
// NewHeroSkillsPanel creates a new hero status panel
func NewHeroSkillsPanel(asset *d2asset.AssetManager,
ui *d2ui.UIManager,
hero *d2mapentity.Player,
l d2util.LogLevel,
isLeftPanel bool) *SkillPanel {
var activeSkill *d2hero.HeroSkill
if isLeftPanel {
activeSkill = hero.LeftSkill
} else {
activeSkill = hero.RightSkill
}
hoverTooltip := ui.NewTooltip(d2resource.Font16, d2resource.PaletteStatic, d2ui.TooltipXLeft, d2ui.TooltipYTop)
skillPanel := &SkillPanel{
asset: asset,
activeSkill: activeSkill,
ui: ui,
isOpen: false,
ListRows: make([]*SkillListRow, skillListsLength),
renderer: ui.Renderer(),
isLeftPanel: isLeftPanel,
hero: hero,
hoverTooltip: hoverTooltip,
}
skillPanel.logger = d2util.NewLogger()
skillPanel.logger.SetLevel(l)
skillPanel.logger.SetPrefix(logPrefix)
return skillPanel
}
// SkillPanel represents a skill select menu popup that is displayed when the player left clicks on his active left/right skill.
type SkillPanel struct {
asset *d2asset.AssetManager
@ -38,30 +72,8 @@ type SkillPanel struct {
isOpen bool
regenerateImageCache bool
isLeftPanel bool
}
// NewHeroSkillsPanel creates a new hero status panel
func NewHeroSkillsPanel(asset *d2asset.AssetManager, ui *d2ui.UIManager, hero *d2mapentity.Player, isLeftPanel bool) *SkillPanel {
var activeSkill *d2hero.HeroSkill
if isLeftPanel {
activeSkill = hero.LeftSkill
} else {
activeSkill = hero.RightSkill
}
hoverTooltip := ui.NewTooltip(d2resource.Font16, d2resource.PaletteStatic, d2ui.TooltipXLeft, d2ui.TooltipYTop)
return &SkillPanel{
asset: asset,
activeSkill: activeSkill,
ui: ui,
isOpen: false,
ListRows: make([]*SkillListRow, skillListsLength),
renderer: ui.Renderer(),
isLeftPanel: isLeftPanel,
hero: hero,
hoverTooltip: hoverTooltip,
}
logger *d2util.Logger
}
// Open opens the hero skills panel
@ -204,7 +216,7 @@ func (s *SkillPanel) generateSkillRowImageCache() error {
cachedImage, err := s.createSkillListImage(skillListRow)
if err != nil {
log.Println(err)
s.logger.Error(err.Error())
return err
}
@ -231,7 +243,7 @@ func (s *SkillPanel) createSkillListImage(skillsListRow *SkillListRow) (d2interf
if skillSprite.GetFrameCount() <= skill.IconCel {
// happens for non-player skills, since they do not have an icon
log.Printf("Invalid IconCel(sprite frame index) [%d] - Skill name: %s, skipping.", skill.IconCel, skill.Name)
s.logger.Error(fmt.Sprintf("Invalid IconCel(sprite frame index) [%d] - Skill name: %s, skipping.", skill.IconCel, skill.Name))
continue
}
@ -353,7 +365,7 @@ func (s *SkillPanel) getSkillResourceByClass(class string) string {
case "dru":
resource = d2resource.DruidSkills
default:
log.Fatalf("Unknown class token: '%s'", class)
s.logger.Error(fmt.Sprintf("Unknown class token: '%s'", class))
}
return resource

View File

@ -1,11 +1,11 @@
package d2player
import (
"log"
"strconv"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -20,14 +20,10 @@ const (
skillIconDistY = 68
)
type skillIcon struct {
*d2ui.BaseWidget
lvlLabel *d2ui.Label
sprite *d2ui.Sprite
skill *d2hero.HeroSkill
}
func newSkillIcon(ui *d2ui.UIManager, baseSprite *d2ui.Sprite, skill *d2hero.HeroSkill) *skillIcon {
func newSkillIcon(ui *d2ui.UIManager,
baseSprite *d2ui.Sprite,
l d2util.LogLevel,
skill *d2hero.HeroSkill) *skillIcon {
base := d2ui.NewBaseWidget(ui)
label := ui.NewLabel(d2resource.Font16, d2resource.PaletteSky)
@ -41,11 +37,24 @@ func newSkillIcon(ui *d2ui.UIManager, baseSprite *d2ui.Sprite, skill *d2hero.Her
lvlLabel: label,
}
res.logger = d2util.NewLogger()
res.logger.SetLevel(l)
res.logger.SetPrefix(logPrefix)
res.SetPosition(x, y)
return res
}
type skillIcon struct {
*d2ui.BaseWidget
lvlLabel *d2ui.Label
sprite *d2ui.Sprite
skill *d2hero.HeroSkill
logger *d2util.Logger
}
func (si *skillIcon) SetVisible(visible bool) {
si.BaseWidget.SetVisible(visible)
si.lvlLabel.SetVisible(visible)
@ -55,7 +64,7 @@ func (si *skillIcon) renderSprite(target d2interface.Surface) {
x, y := si.GetPosition()
if err := si.sprite.SetCurrentFrame(si.skill.IconCel); err != nil {
log.Printf("Cannot set Frame %e", err)
si.logger.Error("Cannot set Frame %e" + err.Error())
return
}

View File

@ -1,12 +1,13 @@
package d2player
import (
"errors"
"fmt"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -83,6 +84,35 @@ type skillTreeHeroTypeResources struct {
skillPanelPath string
}
func newSkillTree(
skills map[int]*d2hero.HeroSkill,
heroClass d2enum.Hero,
asset *d2asset.AssetManager,
l d2util.LogLevel,
ui *d2ui.UIManager,
) *skillTree {
st := &skillTree{
skills: skills,
heroClass: heroClass,
asset: asset,
uiManager: ui,
originX: skillTreePanelX,
originY: skillTreePanelY,
tab: [numTabs]*skillTreeTab{
{},
{},
{},
},
l: l,
}
st.logger = d2util.NewLogger()
st.logger.SetLevel(l)
st.logger.SetPrefix(logPrefix)
return st
}
type skillTree struct {
resources *skillTreeHeroTypeResources
asset *d2asset.AssetManager
@ -102,29 +132,9 @@ type skillTree struct {
panelGroup *d2ui.WidgetGroup
iconGroup *d2ui.WidgetGroup
panel *d2ui.CustomWidget
}
func newSkillTree(
skills map[int]*d2hero.HeroSkill,
heroClass d2enum.Hero,
asset *d2asset.AssetManager,
ui *d2ui.UIManager,
) *skillTree {
st := &skillTree{
skills: skills,
heroClass: heroClass,
asset: asset,
uiManager: ui,
originX: skillTreePanelX,
originY: skillTreePanelY,
tab: [numTabs]*skillTreeTab{
{},
{},
{},
},
}
return st
logger *d2util.Logger
l d2util.LogLevel
}
func (s *skillTree) load() {
@ -142,11 +152,14 @@ func (s *skillTree) load() {
s.closeButton.OnActivated(func() { s.Close() })
s.panelGroup.AddWidget(s.closeButton)
s.setHeroTypeResourcePath()
if err := s.setHeroTypeResourcePath(); err != nil {
s.logger.Error(err.Error())
}
s.loadForHeroType()
for _, skill := range s.skills {
si := newSkillIcon(s.uiManager, s.resources.skillSprite, skill)
si := newSkillIcon(s.uiManager, s.resources.skillSprite, s.l, skill)
s.skillIcons = append(s.skillIcons, si)
s.iconGroup.AddWidget(si)
}
@ -159,14 +172,14 @@ func (s *skillTree) load() {
func (s *skillTree) loadForHeroType() {
sp, err := s.uiManager.NewSprite(s.resources.skillPanelPath, d2resource.PaletteSky)
if err != nil {
log.Print(err)
s.logger.Error(err.Error())
}
s.resources.skillPanel = sp
si, err := s.uiManager.NewSprite(s.resources.skillIconPath, d2resource.PaletteSky)
if err != nil {
log.Print(err)
s.logger.Error(err.Error())
}
s.resources.skillSprite = si
@ -315,10 +328,11 @@ func (s *skillTree) getTab(class d2enum.Hero) *heroTabData {
return tabMap[class]
}
func (s *skillTree) setHeroTypeResourcePath() {
func (s *skillTree) setHeroTypeResourcePath() error {
entry := s.getTab(s.heroClass)
if entry == nil {
log.Fatal("Unknown Hero Type")
return errors.New("unknown hero type")
}
s.resources = entry.resources
@ -329,11 +343,13 @@ func (s *skillTree) setHeroTypeResourcePath() {
for i := 0; i < numTabs; i++ {
s.tab[i].closeButtonPosX = entry.closeButtonPos[i]
}
return nil
}
// Toggle the skill tree visibility
func (s *skillTree) Toggle() {
fmt.Println("SkillTree toggled")
s.logger.Info("SkillTree toggled")
if s.isOpen {
s.Close()
@ -385,7 +401,7 @@ func (s *skillTree) renderPanelSegment(
target d2interface.Surface,
frame int) {
if err := s.resources.skillPanel.SetCurrentFrame(frame); err != nil {
log.Printf("%e", err)
s.logger.Error("%e" + err.Error())
return
}
@ -399,7 +415,7 @@ func (s *skillTree) renderTabCommon(target d2interface.Surface) {
// top
w, h, err := skillPanel.GetFrameSize(frameCommonTabTopLeft)
if err != nil {
log.Printf("%e", err)
s.logger.Error("%e" + err.Error())
return
}
@ -414,7 +430,7 @@ func (s *skillTree) renderTabCommon(target d2interface.Surface) {
// bottom
_, h, err = skillPanel.GetFrameSize(frameCommonTabBottomLeft)
if err != nil {
log.Printf("%e", err)
s.logger.Error("%e" + err.Error())
return
}
@ -437,7 +453,7 @@ func (s *skillTree) renderTab(target d2interface.Surface, tab int) {
// top
_, h0, err := skillPanel.GetFrameSize(topFrame)
if err != nil {
log.Printf("%e", err)
s.logger.Error("%e" + err.Error())
return
}
@ -449,7 +465,7 @@ func (s *skillTree) renderTab(target d2interface.Surface, tab int) {
// bottom
w, h1, err := skillPanel.GetFrameSize(bottomFrame)
if err != nil {
log.Printf("%e", err)
s.logger.Error("%e" + err.Error())
return
}