1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-20 06:05:23 +00:00

remove d2asset singleton (#726)

* export d2asset singleton

* add *d2asset.AssetManager to d2app

- d2app now has a reference to an asset manager which it will use for loading
- added asset loader methods to the asset manager
- functions in d2asset are now wrappers for asset manager methods

* add asset manager reference to audio provider

- d2app asset manager reference is now passed to audio provider
- asset manager is created in main.go for now to pass into audio provider
- CreateSoundEffect is now a method, no longer exported, uses the asset manager reference

* d2app passes asset manager refence to map engine test

* in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile

* blizzard intro and credits screen

- d2app passes reference to the asset manager to these screens

* asset manager for d2map

- adding MapStampFactory, takes an asset manager reference
- embedded MapStampFactory into the MapEngine
- LoadStamp is now a method of the MapStampFactory

* d2asset: removed LoadFileStream, LoadFile, and FileExists

* d2gui changes

- singleton now has an asset manager reference
- calls to d2asset loader functions removed
- createButton is now a method of LayoutManager
- moved LayoutEntry to its own file

* map entity factory

- Map engine has an embedded map entity factory
- Map stamp factory gets a reference to the map engine's entity factory
- Stamps are given a reference to the map engine entity factory when created
- Character select gets a map entity factory
- Embedded the stamp factory into the MapEngine

* asset manager for d2ui

- d2ui is passed an asset manager reference when created
- all calls to d2asset loader functions in d2ui now refer to the asset manager
- d2gamescreen gets a ui manager when created
- help overlay is now passed a ui manager when created

* d2gamescreen + d2player: asset manager references

added an asset manager reference to
- inventory panel + inventory grid
- mini panel
- game controls
- help overlay
- character select
- main menu
- select hero class
- hero stats panel

* Removed d2asset.LoadAnimation

all references to this function have been replaced with calls to the asset manager method

* adding asset to help overlay, bugfix for 4d59c91

* Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect

all references to these have been replaced with calls to the asset manager methods

* MapRenderer now gets an asset manager reference

* removed d2asset.LoadPalette

all references have been replaced with calls to an asset manager instance

* merged d2object with d2mapentity

d2object was only being used to create objects in the map, so the provider
function is now a method of the map entity factory. calls to d2asset have
been removed.

* removed d2asset.LoadComposite

all calls are now made to the asset manager method

* removed d2asset singleton

all singleton references have been removed, a single instance of the
asset manager is passed around the entire app

* rename Initialize to NewAssetManager
This commit is contained in:
lord 2020-09-12 13:51:30 -07:00 committed by GitHub
parent f4a71c72e4
commit 854fce3b14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 790 additions and 669 deletions

View File

@ -60,6 +60,7 @@ type App struct {
captureFrames []*image.RGBA captureFrames []*image.RGBA
gitBranch string gitBranch string
gitCommit string gitCommit string
asset *d2asset.AssetManager
inputManager d2interface.InputManager inputManager d2interface.InputManager
terminal d2interface.Terminal terminal d2interface.Terminal
scriptEngine *d2script.ScriptEngine scriptEngine *d2script.ScriptEngine
@ -89,8 +90,9 @@ func Create(gitBranch, gitCommit string,
scriptEngine *d2script.ScriptEngine, scriptEngine *d2script.ScriptEngine,
audio d2interface.AudioProvider, audio d2interface.AudioProvider,
renderer d2interface.Renderer, renderer d2interface.Renderer,
asset *d2asset.AssetManager,
) *App { ) *App {
uiManager := d2ui.NewUIManager(renderer, inputManager, audio) uiManager := d2ui.NewUIManager(asset, renderer, inputManager, audio)
screenManager := d2screen.NewScreenManager(uiManager) screenManager := d2screen.NewScreenManager(uiManager)
result := &App{ result := &App{
@ -103,6 +105,7 @@ func Create(gitBranch, gitCommit string,
renderer: renderer, renderer: renderer,
ui: uiManager, ui: uiManager,
screen: screenManager, screen: screenManager,
asset: asset,
tAllocSamples: createZeroedRing(nSamplesTAlloc), tAllocSamples: createZeroedRing(nSamplesTAlloc),
} }
@ -174,11 +177,7 @@ func (a *App) initialize() error {
} }
} }
if err := d2asset.Initialize(a.renderer, a.terminal); err != nil { if err := d2gui.Initialize(a.asset, a.inputManager); err != nil {
return err
}
if err := d2gui.Initialize(a.inputManager); err != nil {
return err return err
} }
@ -208,7 +207,7 @@ func (a *App) loadStrings() error {
} }
for _, tablePath := range tablePaths { for _, tablePath := range tablePaths {
data, err := d2asset.LoadFile(tablePath) data, err := a.asset.LoadFile(tablePath)
if err != nil { if err != nil {
return err return err
} }
@ -298,7 +297,7 @@ func (a *App) loadDataDict() error {
d2datadict.InitObjectRecords() d2datadict.InitObjectRecords()
for _, entry := range entries { for _, entry := range entries {
data, err := d2asset.LoadFile(entry.path) data, err := a.asset.LoadFile(entry.path)
if err != nil { if err != nil {
return err return err
} }
@ -678,42 +677,51 @@ func updateInitError(target d2interface.Surface) error {
// ToMainMenu forces the game to transition to the Main Menu // ToMainMenu forces the game to transition to the Main Menu
func (a *App) ToMainMenu() { func (a *App) ToMainMenu() {
buildInfo := d2gamescreen.BuildInfo{Branch: a.gitBranch, Commit: a.gitCommit} buildInfo := d2gamescreen.BuildInfo{Branch: a.gitBranch, Commit: a.gitCommit}
mainMenu := d2gamescreen.CreateMainMenu(a, a.renderer, a.inputManager, a.audio, a.ui, buildInfo)
mainMenu := d2gamescreen.CreateMainMenu(a, a.asset, a.renderer, a.inputManager, a.audio, a.ui,
buildInfo)
a.screen.SetNextScreen(mainMenu) a.screen.SetNextScreen(mainMenu)
} }
// ToSelectHero forces the game to transition to the Select Hero (create character) screen // ToSelectHero forces the game to transition to the Select Hero (create character) screen
func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConnectionType, host string) { func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConnectionType, host string) {
selectHero := d2gamescreen.CreateSelectHeroClass(a, a.renderer, a.audio, a.ui, connType, host) selectHero := d2gamescreen.CreateSelectHeroClass(a, a.asset, a.renderer, a.audio, a.ui,
connType, host)
a.screen.SetNextScreen(selectHero) a.screen.SetNextScreen(selectHero)
} }
// ToCreateGame forces the game to transition to the Create Game screen // ToCreateGame forces the game to transition to the Create Game screen
func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.ClientConnectionType, host string) { func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.ClientConnectionType, host string) {
gameClient, _ := d2client.Create(connType, a.scriptEngine) gameClient, _ := d2client.Create(connType, a.asset, a.scriptEngine)
if err := gameClient.Open(host, filePath); err != nil { if err := gameClient.Open(host, filePath); err != nil {
// TODO an error screen should be shown in this case // TODO an error screen should be shown in this case
fmt.Printf("can not connect to the host: %s", host) fmt.Printf("can not connect to the host: %s", host)
} }
a.screen.SetNextScreen(d2gamescreen.CreateGame(a, a.renderer, a.inputManager, a.audio, gameClient, a.terminal)) a.screen.SetNextScreen(d2gamescreen.CreateGame(a, a.asset, a.ui, a.renderer, a.inputManager,
a.audio, gameClient, a.terminal))
} }
// ToCharacterSelect forces the game to transition to the Character Select (load character) screen // ToCharacterSelect forces the game to transition to the Character Select (load character) screen
func (a *App) ToCharacterSelect(connType d2clientconnectiontype.ClientConnectionType, connHost string) { func (a *App) ToCharacterSelect(connType d2clientconnectiontype.ClientConnectionType, connHost string) {
characterSelect := d2gamescreen.CreateCharacterSelect(a, a.renderer, a.inputManager, a.audio, a.ui, connType, connHost)
characterSelect := d2gamescreen.CreateCharacterSelect(a, a.asset, a.renderer, a.inputManager,
a.audio, a.ui, connType, connHost)
a.screen.SetNextScreen(characterSelect) a.screen.SetNextScreen(characterSelect)
} }
// ToMapEngineTest forces the game to transition to the map engine test screen // ToMapEngineTest forces the game to transition to the map engine test screen
func (a *App) ToMapEngineTest(region, level int) { func (a *App) ToMapEngineTest(region, level int) {
met := d2gamescreen.CreateMapEngineTest(region, level, a.terminal, a.renderer, a.inputManager, met := d2gamescreen.CreateMapEngineTest(region, level, a.asset, a.terminal, a.renderer,
a.inputManager,
a.audio, a.screen) a.audio, a.screen)
a.screen.SetNextScreen(met) a.screen.SetNextScreen(met)
} }
// ToCredits forces the game to transition to the credits screen // ToCredits forces the game to transition to the credits screen
func (a *App) ToCredits() { func (a *App) ToCredits() {
a.screen.SetNextScreen(d2gamescreen.CreateCredits(a, a.renderer, a.ui)) a.screen.SetNextScreen(d2gamescreen.CreateCredits(a, a.asset, a.renderer, a.ui))
} }

View File

@ -5,8 +5,9 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
@ -19,6 +20,7 @@ var _ d2interface.AnimationManager = &animationManager{}
var _ d2interface.Cacher = &animationManager{} var _ d2interface.Cacher = &animationManager{}
type animationManager struct { type animationManager struct {
*AssetManager
cache d2interface.Cache cache d2interface.Cache
renderer d2interface.Renderer renderer d2interface.Renderer
} }
@ -31,13 +33,6 @@ func (am *animationManager) GetCache() d2interface.Cache {
return am.cache return am.cache
} }
func createAnimationManager(renderer d2interface.Renderer) *animationManager {
return &animationManager{
renderer: renderer,
cache: d2cache.CreateCache(animationBudget),
}
}
func (am *animationManager) LoadAnimation( func (am *animationManager) LoadAnimation(
animationPath, palettePath string, animationPath, palettePath string,
effect d2enum.DrawEffect) (d2interface.Animation, error) { effect d2enum.DrawEffect) (d2interface.Animation, error) {
@ -51,22 +46,22 @@ func (am *animationManager) LoadAnimation(
ext := strings.ToLower(filepath.Ext(animationPath)) ext := strings.ToLower(filepath.Ext(animationPath))
switch ext { switch ext {
case ".dc6": case ".dc6":
palette, err := LoadPalette(palettePath) palette, err := am.LoadPalette(palettePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
animation, err = CreateDC6Animation(am.renderer, animationPath, palette, d2enum.DrawEffectNone) animation, err = am.CreateDC6Animation(animationPath, palette, d2enum.DrawEffectNone)
if err != nil { if err != nil {
return nil, err return nil, err
} }
case ".dcc": case ".dcc":
palette, err := LoadPalette(palettePath) palette, err := am.LoadPalette(palettePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
animation, err = CreateDCCAnimation(am.renderer, animationPath, palette, effect) animation, err = am.CreateDCCAnimation(animationPath, palette, effect)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -80,3 +75,85 @@ func (am *animationManager) LoadAnimation(
return animation, nil return animation, nil
} }
// CreateDC6Animation creates an Animation from d2dc6.DC6 and d2dat.DATPalette
func (am *animationManager) CreateDC6Animation(dc6Path string,
palette d2interface.Palette, effect d2enum.DrawEffect) (d2interface.Animation, error) {
dc6, err := am.loadDC6(dc6Path)
if err != nil {
return nil, err
}
anim := DC6Animation{
animation: animation{
directions: make([]animationDirection, dc6.Directions),
playLength: defaultPlayLength,
playLoop: true,
originAtBottom: true,
effect: effect,
},
dc6Path: dc6Path,
dc6: dc6,
palette: palette,
renderer: am.renderer,
}
err = anim.SetDirection(0)
return &anim, err
}
// CreateDCCAnimation creates an animation from d2dcc.DCC and d2dat.DATPalette
func (am *animationManager) CreateDCCAnimation(dccPath string,
palette d2interface.Palette,
effect d2enum.DrawEffect) (d2interface.Animation, error) {
dcc, err := am.loadDCC(dccPath)
if err != nil {
return nil, err
}
anim := animation{
playLength: defaultPlayLength,
playLoop: true,
directions: make([]animationDirection, dcc.NumberOfDirections),
effect: effect,
}
DCC := DCCAnimation{
animation: anim,
animationManager: am,
dccPath: dccPath,
palette: palette,
renderer: am.renderer,
}
err = DCC.SetDirection(0)
if err != nil {
return nil, err
}
return &DCC, nil
}
func (am *animationManager) loadDC6(path string) (*d2dc6.DC6, error) {
dc6Data, err := am.LoadFile(path)
if err != nil {
return nil, err
}
dc6, err := d2dc6.Load(dc6Data)
if err != nil {
return nil, err
}
return dc6, nil
}
func (am *animationManager) loadDCC(path string) (*d2dcc.DCC, error) {
dccData, err := am.LoadFile(path)
if err != nil {
return nil, err
}
return d2dcc.Load(dccData)
}

View File

@ -5,7 +5,6 @@ import (
"path" "path"
"sync" "sync"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
@ -16,6 +15,7 @@ var _ d2interface.ArchiveManager = &archiveManager{}
var _ d2interface.Cacher = &archiveManager{} var _ d2interface.Cacher = &archiveManager{}
type archiveManager struct { type archiveManager struct {
*AssetManager
cache d2interface.Cache cache d2interface.Cache
config *d2config.Configuration config *d2config.Configuration
archives []d2interface.Archive archives []d2interface.Archive
@ -26,10 +26,6 @@ const (
archiveBudget = 1024 * 1024 * 512 archiveBudget = 1024 * 1024 * 512
) )
func createArchiveManager(config *d2config.Configuration) d2interface.ArchiveManager {
return &archiveManager{cache: d2cache.CreateCache(archiveBudget), config: config}
}
// LoadArchiveForFile loads the archive for the given (in-archive) file path // LoadArchiveForFile loads the archive for the given (in-archive) file path
func (am *archiveManager) LoadArchiveForFile(filePath string) (d2interface.Archive, error) { func (am *archiveManager) LoadArchiveForFile(filePath string) (d2interface.Archive, error) {
am.mutex.Lock() am.mutex.Lock()

View File

@ -3,7 +3,6 @@ package d2asset
import ( import (
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
@ -18,20 +17,12 @@ var _ d2interface.FileManager = &fileManager{}
var _ d2interface.Cacher = &fileManager{} var _ d2interface.Cacher = &fileManager{}
type fileManager struct { type fileManager struct {
*AssetManager
cache d2interface.Cache cache d2interface.Cache
archiveManager d2interface.ArchiveManager archiveManager d2interface.ArchiveManager
config *d2config.Configuration config *d2config.Configuration
} }
func createFileManager(config *d2config.Configuration,
archiveManager d2interface.ArchiveManager) d2interface.FileManager {
return &fileManager{
d2cache.CreateCache(fileBudget),
archiveManager,
config,
}
}
// LoadFileStream loads a file as a stream automatically from an archive // LoadFileStream loads a file as a stream automatically from an archive
func (fm *fileManager) LoadFileStream(filePath string) (d2interface.ArchiveDataStream, error) { func (fm *fileManager) LoadFileStream(filePath string) (d2interface.ArchiveDataStream, error) {
filePath = fm.fixupFilePath(filePath) filePath = fm.fixupFilePath(filePath)

View File

@ -1,13 +1,14 @@
package d2asset package d2asset
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2cof" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
type assetManager struct { // AssetManager loads files and game objects
type AssetManager struct {
archiveManager d2interface.ArchiveManager archiveManager d2interface.ArchiveManager
archivedFileManager d2interface.FileManager archivedFileManager d2interface.FileManager
paletteManager d2interface.PaletteManager paletteManager d2interface.PaletteManager
@ -16,39 +17,66 @@ type assetManager struct {
fontManager d2interface.FontManager fontManager d2interface.FontManager
} }
func loadDC6(dc6Path string) (*d2dc6.DC6, error) { // LoadFileStream streams an MPQ file from a source file path
dc6Data, err := LoadFile(dc6Path) func (am *AssetManager) LoadFileStream(filePath string) (d2interface.ArchiveDataStream, error) {
data, err := am.archivedFileManager.LoadFileStream(filePath)
if err != nil { if err != nil {
return nil, err log.Printf("error loading file stream %s (%v)", filePath, err.Error())
} }
dc6, err := d2dc6.Load(dc6Data) return data, err
}
// LoadFile loads an entire file from a source file path as a []byte
func (am *AssetManager) LoadFile(filePath string) ([]byte, error) {
data, err := am.archivedFileManager.LoadFile(filePath)
if err != nil { if err != nil {
return nil, err log.Printf("error loading file %s (%v)", filePath, err.Error())
} }
return dc6, nil return data, err
} }
func loadDCC(dccPath string) (*d2dcc.DCC, error) { // FileExists checks if a file exists on the underlying file system at the given file path.
dccData, err := LoadFile(dccPath) func (am *AssetManager) FileExists(filePath string) (bool, error) {
if err != nil { return am.archivedFileManager.FileExists(filePath)
return nil, err
} }
return d2dcc.Load(dccData) // LoadAnimation loads an animation by its resource path and its palette path
func (am *AssetManager) LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) {
return am.LoadAnimationWithEffect(animationPath, palettePath, d2enum.DrawEffectNone)
} }
func loadCOF(cofPath string) (*d2cof.COF, error) { // LoadAnimationWithEffect loads an animation by its resource path and its palette path with a given transparency value
cofData, err := LoadFile(cofPath) func (am *AssetManager) LoadAnimationWithEffect(animationPath, palettePath string,
if err != nil { drawEffect d2enum.DrawEffect) (d2interface.Animation, error) {
return nil, err return am.animationManager.LoadAnimation(animationPath, palettePath, drawEffect)
} }
return d2cof.Load(cofData) // LoadComposite creates a composite object from a ObjectLookupRecord and palettePath describing it
func (am *AssetManager) LoadComposite(baseType d2enum.ObjectType, token, palettePath string) (*Composite, error) {
c := &Composite{
AssetManager: am,
baseType: baseType,
basePath: baseString(baseType),
token: token,
palettePath: palettePath,
} }
func (am *assetManager) BindTerminalCommands(term d2interface.Terminal) error { return c, nil
}
// LoadFont loads a font the resource files
func (am *AssetManager) LoadFont(tablePath, spritePath, palettePath string) (d2interface.Font, error) {
return am.fontManager.LoadFont(tablePath, spritePath, palettePath)
}
// LoadPalette loads a palette from a given palette path
func (am *AssetManager) LoadPalette(palettePath string) (d2interface.Palette, error) {
return am.paletteManager.LoadPalette(palettePath)
}
func (am *AssetManager) BindTerminalCommands(term d2interface.Terminal) error {
if err := term.BindAction("assetspam", "display verbose asset manager logs", func(verbose bool) { if err := term.BindAction("assetspam", "display verbose asset manager logs", func(verbose bool) {
if verbose { if verbose {
term.OutputInfof("asset manager verbose logging enabled") term.OutputInfof("asset manager verbose logging enabled")

View File

@ -13,6 +13,7 @@ import (
// Composite is a composite entity animation // Composite is a composite entity animation
type Composite struct { type Composite struct {
*AssetManager
baseType d2enum.ObjectType baseType d2enum.ObjectType
basePath string basePath string
token string token string
@ -28,12 +29,6 @@ type size struct {
Height int Height int
} }
// CreateComposite creates a Composite from a given ObjectLookupRecord and palettePath.
func CreateComposite(baseType d2enum.ObjectType, token, palettePath string) *Composite {
return &Composite{baseType: baseType, basePath: baseString(baseType),
token: token, palettePath: palettePath}
}
// Advance moves the composite animation forward for a given elapsed time in nanoseconds. // Advance moves the composite animation forward for a given elapsed time in nanoseconds.
func (c *Composite) Advance(elapsed float64) error { func (c *Composite) Advance(elapsed float64) error {
if c.mode == nil { if c.mode == nil {
@ -233,11 +228,11 @@ type compositeMode struct {
func (c *Composite) createMode(animationMode animationMode, weaponClass string) (*compositeMode, error) { func (c *Composite) createMode(animationMode animationMode, weaponClass string) (*compositeMode, error) {
cofPath := fmt.Sprintf("%s/%s/COF/%s%s%s.COF", c.basePath, c.token, c.token, animationMode, weaponClass) cofPath := fmt.Sprintf("%s/%s/COF/%s%s%s.COF", c.basePath, c.token, c.token, animationMode, weaponClass)
if exists, _ := FileExists(cofPath); !exists { if exists, _ := c.FileExists(cofPath); !exists {
return nil, errors.New("composite not found") return nil, errors.New("composite not found")
} }
cof, err := loadCOF(cofPath) cof, err := c.loadCOF(cofPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -296,8 +291,9 @@ func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weap
} }
for _, animationPath := range animationPaths { for _, animationPath := range animationPaths {
if exists, _ := FileExists(animationPath); exists { if exists, _ := c.FileExists(animationPath); exists {
animation, err := LoadAnimationWithEffect(animationPath, palettePath, drawEffect) animation, err := c.LoadAnimationWithEffect(animationPath, palettePath,
drawEffect)
if err == nil { if err == nil {
return animation, nil return animation, nil
} }
@ -345,6 +341,15 @@ func (c *Composite) updateSize() {
c.size.Height = biggestH c.size.Height = biggestH
} }
func (c *Composite) loadCOF(cofPath string) (*d2cof.COF, error) {
cofData, err := c.LoadFile(cofPath)
if err != nil {
return nil, err
}
return d2cof.Load(cofData)
}
func baseString(baseType d2enum.ObjectType) string { func baseString(baseType d2enum.ObjectType) string {
switch baseType { switch baseType {
case d2enum.ObjectTypePlayer: case d2enum.ObjectTypePlayer:

View File

@ -1,90 +1,51 @@
package d2asset package d2asset
import ( import (
"log" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"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"
) )
var singleton *assetManager //nolint:gochecknoglobals // Currently global by design // NewAssetManager creates and assigns all necessary dependencies for the AssetManager top-level functions to work correctly
func NewAssetManager(renderer d2interface.Renderer,
term d2interface.Terminal) (*AssetManager, error) {
// Initialize creates and assigns all necessary dependencies for the assetManager top-level functions to work correctly manager := &AssetManager{}
func Initialize(renderer d2interface.Renderer,
term d2interface.Terminal) error {
var (
archiveManager = createArchiveManager(d2config.Config)
archivedFileManager = createFileManager(d2config.Config, archiveManager)
paletteManager = createPaletteManager()
paletteTransformManager = createPaletteTransformManager()
animationManager = createAnimationManager(renderer)
fontManager = createFontManager()
)
singleton = &assetManager{ manager.archiveManager = &archiveManager{
archiveManager, AssetManager: manager,
archivedFileManager, cache: d2cache.CreateCache(archiveBudget),
paletteManager, config: d2config.Config,
paletteTransformManager,
animationManager,
fontManager,
} }
manager.archivedFileManager = &fileManager{
manager,
d2cache.CreateCache(fileBudget),
manager.archiveManager,
d2config.Config,
}
manager.paletteManager = &paletteManager{
manager,
d2cache.CreateCache(paletteBudget),
}
manager.paletteTransformManager = &paletteTransformManager{
manager,
d2cache.CreateCache(paletteTransformBudget),
}
manager.animationManager = &animationManager{
AssetManager: manager,
renderer: renderer,
cache: d2cache.CreateCache(animationBudget),
}
manager.fontManager = &fontManager{manager, d2cache.CreateCache(fontBudget)}
if term != nil { if term != nil {
return singleton.BindTerminalCommands(term) return manager, manager.BindTerminalCommands(term)
} }
return nil return manager, nil
}
// LoadFileStream streams an MPQ file from a source file path
func LoadFileStream(filePath string) (d2interface.ArchiveDataStream, error) {
data, err := singleton.archivedFileManager.LoadFileStream(filePath)
if err != nil {
log.Printf("error loading file stream %s (%v)", filePath, err.Error())
}
return data, err
}
// LoadFile loads an entire file from a source file path as a []byte
func LoadFile(filePath string) ([]byte, error) {
data, err := singleton.archivedFileManager.LoadFile(filePath)
if err != nil {
log.Printf("error loading file %s (%v)", filePath, err.Error())
}
return data, err
}
// FileExists checks if a file exists on the underlying file system at the given file path.
func FileExists(filePath string) (bool, error) {
return singleton.archivedFileManager.FileExists(filePath)
}
// LoadAnimation loads an animation by its resource path and its palette path
func LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) {
return LoadAnimationWithEffect(animationPath, palettePath, d2enum.DrawEffectNone)
}
// LoadAnimationWithEffect loads an animation by its resource path and its palette path with a given transparency value
func LoadAnimationWithEffect(animationPath, palettePath string,
drawEffect d2enum.DrawEffect) (d2interface.Animation, error) {
return singleton.animationManager.LoadAnimation(animationPath, palettePath, drawEffect)
}
// LoadComposite creates a composite object from a ObjectLookupRecord and palettePath describing it
func LoadComposite(baseType d2enum.ObjectType, token, palettePath string) (*Composite, error) {
return CreateComposite(baseType, token, palettePath), nil
}
// LoadFont loads a font the resource files
func LoadFont(tablePath, spritePath, palettePath string) (d2interface.Font, error) {
return singleton.fontManager.LoadFont(tablePath, spritePath, palettePath)
}
// LoadPalette loads a palette from a given palette path
func LoadPalette(palettePath string) (d2interface.Palette, error) {
return singleton.paletteManager.LoadPalette(palettePath)
} }

View File

@ -3,6 +3,8 @@ package d2asset
import ( import (
"errors" "errors"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
d2iface "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" d2iface "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
@ -14,36 +16,11 @@ var _ d2iface.Animation = &DC6Animation{} // Static check to confirm struct conf
type DC6Animation struct { type DC6Animation struct {
animation animation
dc6Path string dc6Path string
dc6 *d2dc6.DC6
palette d2iface.Palette palette d2iface.Palette
renderer d2iface.Renderer renderer d2iface.Renderer
} }
// CreateDC6Animation creates an Animation from d2dc6.DC6 and d2dat.DATPalette
func CreateDC6Animation(renderer d2iface.Renderer, dc6Path string,
palette d2iface.Palette, effect d2enum.DrawEffect) (d2iface.Animation, error) {
dc6, err := loadDC6(dc6Path)
if err != nil {
return nil, err
}
anim := DC6Animation{
animation: animation{
directions: make([]animationDirection, dc6.Directions),
playLength: defaultPlayLength,
playLoop: true,
originAtBottom: true,
effect: effect,
},
dc6Path: dc6Path,
palette: palette,
renderer: renderer,
}
err = anim.SetDirection(0)
return &anim, err
}
// SetDirection decodes and sets the direction // SetDirection decodes and sets the direction
func (a *DC6Animation) SetDirection(directionIndex int) error { func (a *DC6Animation) SetDirection(directionIndex int) error {
const smallestInvalidDirectionIndex = 64 const smallestInvalidDirectionIndex = 64
@ -66,11 +43,7 @@ func (a *DC6Animation) SetDirection(directionIndex int) error {
} }
func (a *DC6Animation) decodeDirection(directionIndex int) error { func (a *DC6Animation) decodeDirection(directionIndex int) error {
dc6, err := loadDC6(a.dc6Path) dc6 := a.dc6
if err != nil {
return err
}
startFrame := directionIndex * int(dc6.FramesPerDirection) startFrame := directionIndex * int(dc6.FramesPerDirection)
for i := 0; i < int(dc6.FramesPerDirection); i++ { for i := 0; i < int(dc6.FramesPerDirection); i++ {

View File

@ -16,41 +16,12 @@ var _ d2iface.Animation = &DCCAnimation{} // Static check to confirm struct conf
// DCCAnimation represents an animation decoded from DCC // DCCAnimation represents an animation decoded from DCC
type DCCAnimation struct { type DCCAnimation struct {
animation animation
*animationManager
dccPath string dccPath string
palette d2iface.Palette palette d2iface.Palette
renderer d2iface.Renderer renderer d2iface.Renderer
} }
// CreateDCCAnimation creates an animation from d2dcc.DCC and d2dat.DATPalette
func CreateDCCAnimation(renderer d2iface.Renderer, dccPath string, palette d2iface.Palette,
effect d2enum.DrawEffect) (d2iface.Animation, error) {
dcc, err := loadDCC(dccPath)
if err != nil {
return nil, err
}
anim := animation{
playLength: defaultPlayLength,
playLoop: true,
directions: make([]animationDirection, dcc.NumberOfDirections),
effect: effect,
}
DCC := DCCAnimation{
animation: anim,
dccPath: dccPath,
palette: palette,
renderer: renderer,
}
err = DCC.SetDirection(0)
if err != nil {
return nil, err
}
return &DCC, nil
}
// Clone creates a copy of the animation // Clone creates a copy of the animation
func (a *DCCAnimation) Clone() d2iface.Animation { func (a *DCCAnimation) Clone() d2iface.Animation {
animation := *a animation := *a
@ -79,7 +50,7 @@ func (a *DCCAnimation) SetDirection(directionIndex int) error {
} }
func (a *DCCAnimation) decodeDirection(directionIndex int) error { func (a *DCCAnimation) decodeDirection(directionIndex int) error {
dcc, err := loadDCC(a.dccPath) dcc, err := a.loadDCC(a.dccPath)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,8 +1,6 @@
package d2asset package d2asset
import ( import (
"encoding/binary"
"errors"
"image/color" "image/color"
"strings" "strings"
@ -25,45 +23,6 @@ type Font struct {
color color.Color color color.Color
} }
func loadFont(tablePath, spritePath, palettePath string) (d2interface.Font, error) {
sheet, err := LoadAnimation(spritePath, palettePath)
if err != nil {
return nil, err
}
data, err := LoadFile(tablePath)
if err != nil {
return nil, err
}
if string(data[:5]) != "Woo!\x01" {
return nil, errors.New("invalid font table format")
}
_, maxCharHeight := sheet.GetFrameBounds()
glyphs := make(map[rune]fontGlyph)
for i := 12; i < len(data); i += 14 {
code := rune(binary.LittleEndian.Uint16(data[i : i+2]))
var glyph fontGlyph
glyph.frame = int(binary.LittleEndian.Uint16(data[i+8 : i+10]))
glyph.width = int(data[i+3])
glyph.height = maxCharHeight
glyphs[code] = glyph
}
font := &Font{
sheet: sheet,
glyphs: glyphs,
color: color.White,
}
return font, nil
}
// SetColor sets the fonts color // SetColor sets the fonts color
func (f *Font) SetColor(c color.Color) { func (f *Font) SetColor(c color.Color) {
f.color = c f.color = c

View File

@ -1,9 +1,11 @@
package d2asset package d2asset
import ( import (
"encoding/binary"
"errors"
"fmt" "fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
@ -16,13 +18,10 @@ var _ d2interface.FontManager = &fontManager{}
var _ d2interface.Cacher = &fontManager{} var _ d2interface.Cacher = &fontManager{}
type fontManager struct { type fontManager struct {
*AssetManager
cache d2interface.Cache cache d2interface.Cache
} }
func createFontManager() d2interface.FontManager {
return &fontManager{d2cache.CreateCache(fontBudget)}
}
// LoadFont loads a font from the archives managed by the ArchiveManager // LoadFont loads a font from the archives managed by the ArchiveManager
func (fm *fontManager) LoadFont(tablePath, spritePath, palettePath string) (d2interface.Font, func (fm *fontManager) LoadFont(tablePath, spritePath, palettePath string) (d2interface.Font,
error) { error) {
@ -31,7 +30,41 @@ func (fm *fontManager) LoadFont(tablePath, spritePath, palettePath string) (d2in
return font.(d2interface.Font), nil return font.(d2interface.Font), nil
} }
font, err := loadFont(tablePath, spritePath, palettePath) sheet, err := fm.LoadAnimation(spritePath, palettePath)
if err != nil {
return nil, err
}
data, err := fm.LoadFile(tablePath)
if err != nil {
return nil, err
}
if string(data[:5]) != "Woo!\x01" {
return nil, errors.New("invalid font table format")
}
_, maxCharHeight := sheet.GetFrameBounds()
glyphs := make(map[rune]fontGlyph)
for i := 12; i < len(data); i += 14 {
code := rune(binary.LittleEndian.Uint16(data[i : i+2]))
var glyph fontGlyph
glyph.frame = int(binary.LittleEndian.Uint16(data[i+8 : i+10]))
glyph.width = int(data[i+3])
glyph.height = maxCharHeight
glyphs[code] = glyph
}
font := &Font{
sheet: sheet,
glyphs: glyphs,
color: color.White,
}
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,7 +1,6 @@
package d2asset package d2asset
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
@ -11,6 +10,7 @@ var _ d2interface.PaletteManager = &paletteManager{}
var _ d2interface.Cacher = &paletteManager{} var _ d2interface.Cacher = &paletteManager{}
type paletteManager struct { type paletteManager struct {
*AssetManager
cache d2interface.Cache cache d2interface.Cache
} }
@ -18,17 +18,13 @@ const (
paletteBudget = 64 paletteBudget = 64
) )
func createPaletteManager() d2interface.PaletteManager {
return &paletteManager{d2cache.CreateCache(paletteBudget)}
}
// LoadPalette loads a palette from archives managed by the ArchiveManager // LoadPalette loads a palette from archives managed by the ArchiveManager
func (pm *paletteManager) LoadPalette(palettePath string) (d2interface.Palette, error) { func (pm *paletteManager) LoadPalette(palettePath string) (d2interface.Palette, error) {
if palette, found := pm.cache.Retrieve(palettePath); found { if palette, found := pm.cache.Retrieve(palettePath); found {
return palette.(d2interface.Palette), nil return palette.(d2interface.Palette), nil
} }
paletteData, err := LoadFile(palettePath) paletteData, err := pm.LoadFile(palettePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,12 +1,12 @@
package d2asset package d2asset
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2pl2" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2pl2"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
type paletteTransformManager struct { type paletteTransformManager struct {
*AssetManager
cache d2interface.Cache cache d2interface.Cache
} }
@ -14,16 +14,12 @@ const (
paletteTransformBudget = 64 paletteTransformBudget = 64
) )
func createPaletteTransformManager() *paletteTransformManager {
return &paletteTransformManager{d2cache.CreateCache(paletteTransformBudget)}
}
func (pm *paletteTransformManager) loadPaletteTransform(path string) (*d2pl2.PL2, error) { func (pm *paletteTransformManager) loadPaletteTransform(path string) (*d2pl2.PL2, error) {
if pl2, found := pm.cache.Retrieve(path); found { if pl2, found := pm.cache.Retrieve(path); found {
return pl2.(*d2pl2.PL2), nil return pl2.(*d2pl2.PL2), nil
} }
data, err := LoadFile(path) data, err := pm.LoadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,6 +4,7 @@ package ebiten
import ( import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -15,18 +16,11 @@ const sampleRate = 44100
var _ d2interface.AudioProvider = &AudioProvider{} // Static check to confirm struct conforms to interface var _ d2interface.AudioProvider = &AudioProvider{} // Static check to confirm struct conforms to interface
// AudioProvider represents a provider capable of playing audio
type AudioProvider struct {
audioContext *audio.Context // The Audio context
bgmAudio *audio.Player // The audio player
lastBgm string
sfxVolume float64
bgmVolume float64
}
// CreateAudio creates an instance of ebiten's audio provider // CreateAudio creates an instance of ebiten's audio provider
func CreateAudio() (*AudioProvider, error) { func CreateAudio(am *d2asset.AssetManager) (*AudioProvider, error) {
result := &AudioProvider{} result := &AudioProvider{
assetManager: am,
}
var err error var err error
result.audioContext, err = audio.NewContext(sampleRate) result.audioContext, err = audio.NewContext(sampleRate)
@ -39,6 +33,16 @@ func CreateAudio() (*AudioProvider, error) {
return result, nil return result, nil
} }
// AudioProvider represents a provider capable of playing audio
type AudioProvider struct {
assetManager *d2asset.AssetManager
audioContext *audio.Context // The Audio context
bgmAudio *audio.Player // The audio player
lastBgm string
sfxVolume float64
bgmVolume float64
}
// PlayBGM loads an audio stream and plays it in the background // PlayBGM loads an audio stream and plays it in the background
func (eap *AudioProvider) PlayBGM(song string) { func (eap *AudioProvider) PlayBGM(song string) {
if eap.lastBgm == song { if eap.lastBgm == song {
@ -61,7 +65,7 @@ func (eap *AudioProvider) PlayBGM(song string) {
} }
} }
audioStream, err := d2asset.LoadFileStream(song) audioStream, err := eap.assetManager.LoadFileStream(song)
if err != nil { if err != nil {
panic(err) panic(err)
@ -103,7 +107,7 @@ func (eap *AudioProvider) LoadSound(sfx string, loop, bgm bool) (d2interface.Sou
volume = eap.bgmVolume volume = eap.bgmVolume
} }
result := CreateSoundEffect(sfx, eap.audioContext, loop) result := eap.createSoundEffect(sfx, eap.audioContext, loop)
result.volumeScale = volume result.volumeScale = volume
result.SetVolume(volume) result.SetVolume(volume)
@ -116,3 +120,53 @@ func (eap *AudioProvider) SetVolumes(bgmVolume, sfxVolume float64) {
eap.sfxVolume = sfxVolume eap.sfxVolume = sfxVolume
eap.bgmVolume = bgmVolume eap.bgmVolume = bgmVolume
} }
// createSoundEffect creates a new instance of ebiten's sound effect implementation.
func (eap *AudioProvider) createSoundEffect(sfx string, context *audio.Context,
loop bool) *SoundEffect {
result := &SoundEffect{}
soundFile := "/data/global/sfx/"
if _, exists := d2datadict.Sounds[sfx]; exists {
soundEntry := d2datadict.Sounds[sfx]
soundFile += soundEntry.FileName
} else {
soundFile += sfx
}
audioData, err := eap.assetManager.LoadFileStream(soundFile)
if err != nil {
audioData, err = eap.assetManager.LoadFileStream("/data/global/music/" + sfx)
}
if err != nil {
panic(err)
}
d, err := wav.Decode(context, audioData)
if err != nil {
log.Fatal(err)
}
var player *audio.Player
if loop {
s := audio.NewInfiniteLoop(d, d.Length())
result.panStream = newPanStreamFromReader(s)
player, err = audio.NewPlayer(context, result.panStream)
} else {
result.panStream = newPanStreamFromReader(d)
player, err = audio.NewPlayer(context, result.panStream)
}
if err != nil {
log.Fatal(err)
}
result.player = player
return result
}

View File

@ -1,14 +1,9 @@
package ebiten package ebiten
import ( import (
"log"
"math" "math"
"github.com/hajimehoshi/ebiten/audio" "github.com/hajimehoshi/ebiten/audio"
"github.com/hajimehoshi/ebiten/audio/wav"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
type panStream struct { type panStream struct {
@ -56,55 +51,6 @@ type SoundEffect struct {
panStream *panStream panStream *panStream
} }
// CreateSoundEffect creates a new instance of ebiten's sound effect implementation.
func CreateSoundEffect(sfx string, context *audio.Context, loop bool) *SoundEffect {
result := &SoundEffect{}
soundFile := "/data/global/sfx/"
if _, exists := d2datadict.Sounds[sfx]; exists {
soundEntry := d2datadict.Sounds[sfx]
soundFile += soundEntry.FileName
} else {
soundFile += sfx
}
audioData, err := d2asset.LoadFileStream(soundFile)
if err != nil {
audioData, err = d2asset.LoadFileStream("/data/global/music/" + sfx)
}
if err != nil {
panic(err)
}
d, err := wav.Decode(context, audioData)
if err != nil {
log.Fatal(err)
}
var player *audio.Player
if loop {
s := audio.NewInfiniteLoop(d, d.Length())
result.panStream = newPanStreamFromReader(s)
player, err = audio.NewPlayer(context, result.panStream)
} else {
result.panStream = newPanStreamFromReader(d)
player, err = audio.NewPlayer(context, result.panStream)
}
if err != nil {
log.Fatal(err)
}
result.player = player
return result
}
// SetPan sets the audio pan, left is -1.0, center is 0.0, right is 1.0 // SetPan sets the audio pan, left is -1.0, center is 0.0, right is 1.0
func (v *SoundEffect) SetPan(pan float64) { func (v *SoundEffect) SetPan(pan float64) {
v.panStream.pan = pan v.panStream.pan = pan

View File

@ -1,11 +1,7 @@
package d2gui package d2gui
import ( import (
"errors"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
type buttonState int type buttonState int
@ -30,90 +26,6 @@ type Button struct {
surfaces []d2interface.Surface surfaces []d2interface.Surface
} }
func createButton(renderer d2interface.Renderer, text string, buttonStyle ButtonStyle) (*Button, error) {
config := getButtonStyleConfig(buttonStyle)
if config == nil {
return nil, errors.New("invalid button style")
}
animation, loadErr := d2asset.LoadAnimation(config.animationPath, config.palettePath)
if loadErr != nil {
return nil, loadErr
}
var buttonWidth int
for i := 0; i < config.segmentsX; i++ {
w, _, err := animation.GetFrameSize(i)
if err != nil {
return nil, err
}
buttonWidth += w
}
var buttonHeight int
for i := 0; i < config.segmentsY; i++ {
_, h, err := animation.GetFrameSize(i * config.segmentsY)
if err != nil {
return nil, err
}
buttonHeight += h
}
font, loadErr := loadFont(config.fontStyle)
if loadErr != nil {
return nil, loadErr
}
textColor := rgbaColor(grey)
textWidth, textHeight := font.GetTextMetrics(text)
textX := half(buttonWidth) - half(textWidth)
textY := half(buttonHeight) - half(textHeight) + config.textOffset
surfaceCount := animation.GetFrameCount() / (config.segmentsX * config.segmentsY)
surfaces := make([]d2interface.Surface, surfaceCount)
for i := 0; i < surfaceCount; i++ {
surface, surfaceErr := renderer.NewSurface(buttonWidth, buttonHeight, d2enum.FilterNearest)
if surfaceErr != nil {
return nil, surfaceErr
}
segX, segY, frame := config.segmentsX, config.segmentsY, i
if segErr := renderSegmented(animation, segX, segY, frame, surface); segErr != nil {
return nil, segErr
}
font.SetColor(textColor)
var textOffsetX, textOffsetY int
switch buttonState(i) {
case buttonStatePressed, buttonStatePressedToggled:
textOffsetX = -2
textOffsetY = 2
}
surface.PushTranslation(textX+textOffsetX, textY+textOffsetY)
surfaceErr = font.RenderText(text, surface)
surface.Pop()
if surfaceErr != nil {
return nil, surfaceErr
}
surfaces[i] = surface
}
button := &Button{width: buttonWidth, height: buttonHeight, surfaces: surfaces}
button.SetVisible(true)
return button, nil
}
func (b *Button) onMouseButtonDown(_ d2interface.MouseEvent) bool { func (b *Button) onMouseButtonDown(_ d2interface.MouseEvent) bool {
b.state = buttonStatePressed b.state = buttonStatePressed
return false return false

View File

@ -6,7 +6,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
func loadFont(fontStyle FontStyle) (d2interface.Font, error) { func loadFont(fontStyle FontStyle) (d2interface.Font, error) {
@ -15,7 +14,8 @@ func loadFont(fontStyle FontStyle) (d2interface.Font, error) {
return nil, errors.New("invalid font style") return nil, errors.New("invalid font style")
} }
return d2asset.LoadFont(config.fontBasePath+".tbl", config.fontBasePath+".dc6", config.palettePath) return singleton.asset.LoadFont(config.fontBasePath+".tbl", config.fontBasePath+".dc6",
config.palettePath)
} }
func renderSegmented(animation d2interface.Animation, segmentsX, segmentsY, frameOffset int, func renderSegmented(animation d2interface.Animation, segmentsX, segmentsY, frameOffset int,

View File

@ -3,6 +3,8 @@ package d2gui
import ( import (
"errors" "errors"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
@ -14,11 +16,11 @@ var (
var singleton *manager // nolint:gochecknoglobals // currently global by design var singleton *manager // nolint:gochecknoglobals // currently global by design
// Initialize creates a singleton gui manager // Initialize creates a singleton gui manager
func Initialize(inputManager d2interface.InputManager) error { func Initialize(asset *d2asset.AssetManager, inputManager d2interface.InputManager) error {
verifyNotInit() verifyNotInit()
var err error var err error
if singleton, err = createGuiManager(inputManager); err != nil { if singleton, err = createGuiManager(asset, inputManager); err != nil {
return err return err
} }

View File

@ -1,23 +1,13 @@
package d2gui package d2gui
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom" "errors"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
) )
type layoutEntry struct {
widget widget
x int
y int
width int
height int
mouseOver bool
mouseDown [3]bool
}
const layoutDebug = false // turns on debug rendering stuff for layouts const layoutDebug = false // turns on debug rendering stuff for layouts
const ( const (
@ -168,7 +158,7 @@ func (l *Layout) AddLabel(text string, fontStyle FontStyle) (*Label, error) {
// AddButton given a string and ButtonStyle, adds a button as a layout entry // AddButton given a string and ButtonStyle, adds a button as a layout entry
func (l *Layout) AddButton(text string, buttonStyle ButtonStyle) (*Button, error) { func (l *Layout) AddButton(text string, buttonStyle ButtonStyle) (*Button, error) {
button, err := createButton(l.renderer, text, buttonStyle) button, err := l.createButton(l.renderer, text, buttonStyle)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -421,10 +411,88 @@ func (l *Layout) handleEntryVerticalAlign(width int, entry *layoutEntry) {
} }
} }
// IsIn layout entry, spc. of an event. func (l *Layout) createButton(renderer d2interface.Renderer, text string,
func (l *layoutEntry) IsIn(event d2interface.HandlerEvent) bool { buttonStyle ButtonStyle) (*Button,
sx, sy := l.widget.ScreenPos() error) {
rect := d2geom.Rectangle{Left: sx, Top: sy, Width: l.width, Height: l.height} config := getButtonStyleConfig(buttonStyle)
if config == nil {
return rect.IsInRect(event.X(), event.Y()) return nil, errors.New("invalid button style")
}
animation, loadErr := singleton.asset.LoadAnimation(config.animationPath, config.palettePath)
if loadErr != nil {
return nil, loadErr
}
var buttonWidth int
for i := 0; i < config.segmentsX; i++ {
w, _, err := animation.GetFrameSize(i)
if err != nil {
return nil, err
}
buttonWidth += w
}
var buttonHeight int
for i := 0; i < config.segmentsY; i++ {
_, h, err := animation.GetFrameSize(i * config.segmentsY)
if err != nil {
return nil, err
}
buttonHeight += h
}
font, loadErr := loadFont(config.fontStyle)
if loadErr != nil {
return nil, loadErr
}
textColor := rgbaColor(grey)
textWidth, textHeight := font.GetTextMetrics(text)
textX := half(buttonWidth) - half(textWidth)
textY := half(buttonHeight) - half(textHeight) + config.textOffset
surfaceCount := animation.GetFrameCount() / (config.segmentsX * config.segmentsY)
surfaces := make([]d2interface.Surface, surfaceCount)
for i := 0; i < surfaceCount; i++ {
surface, surfaceErr := renderer.NewSurface(buttonWidth, buttonHeight, d2enum.FilterNearest)
if surfaceErr != nil {
return nil, surfaceErr
}
segX, segY, frame := config.segmentsX, config.segmentsY, i
if segErr := renderSegmented(animation, segX, segY, frame, surface); segErr != nil {
return nil, segErr
}
font.SetColor(textColor)
var textOffsetX, textOffsetY int
switch buttonState(i) {
case buttonStatePressed, buttonStatePressedToggled:
textOffsetX = -2
textOffsetY = 2
}
surface.PushTranslation(textX+textOffsetX, textY+textOffsetY)
surfaceErr = font.RenderText(text, surface)
surface.Pop()
if surfaceErr != nil {
return nil, surfaceErr
}
surfaces[i] = surface
}
button := &Button{width: buttonWidth, height: buttonHeight, surfaces: surfaces}
button.SetVisible(true)
return button, nil
} }

View File

@ -0,0 +1,26 @@
package d2gui
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
type layoutEntry struct {
widget widget
x int
y int
width int
height int
mouseOver bool
mouseDown [3]bool
}
// IsIn layout entry, spc. of an event.
func (l *layoutEntry) IsIn(event d2interface.HandlerEvent) bool {
sx, sy := l.widget.ScreenPos()
rect := d2geom.Rectangle{Left: sx, Top: sy, Width: l.width, Height: l.height}
return rect.IsInRect(event.X(), event.Y())
}

View File

@ -5,12 +5,12 @@ import (
"math" "math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
type manager struct { type manager struct {
asset *d2asset.AssetManager
layout *Layout layout *Layout
cursorAnim d2interface.Animation cursorAnim d2interface.Animation
cursorX int cursorX int
@ -20,18 +20,19 @@ type manager struct {
loading bool loading bool
} }
func createGuiManager(inputManager d2interface.InputManager) (*manager, error) { func createGuiManager(asset *d2asset.AssetManager, inputManager d2interface.InputManager) (*manager, error) {
cursorAnim, err := d2asset.LoadAnimation(d2resource.CursorDefault, d2resource.PaletteUnits) cursorAnim, err := asset.LoadAnimation(d2resource.CursorDefault, d2resource.PaletteUnits)
if err != nil { if err != nil {
return nil, err return nil, err
} }
loadingAnim, err := d2asset.LoadAnimation(d2resource.LoadingScreen, d2resource.PaletteLoading) loadingAnim, err := asset.LoadAnimation(d2resource.LoadingScreen, d2resource.PaletteLoading)
if err != nil { if err != nil {
return nil, err return nil, err
} }
manager := &manager{ manager := &manager{
asset: asset,
cursorAnim: cursorAnim, cursorAnim: cursorAnim,
loadingAnim: loadingAnim, loadingAnim: loadingAnim,
cursorVisible: true, cursorVisible: true,

View File

@ -3,7 +3,6 @@ package d2gui
import ( import (
"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/d2asset"
) )
// AnimationDirection is a the animation play direction // AnimationDirection is a the animation play direction
@ -32,7 +31,7 @@ type AnimatedSprite struct {
} }
func createSprite(imagePath, palettePath string) (*Sprite, error) { func createSprite(imagePath, palettePath string) (*Sprite, error) {
animation, err := d2asset.LoadAnimation(imagePath, palettePath) animation, err := singleton.asset.LoadAnimation(imagePath, palettePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -45,7 +44,7 @@ func createSprite(imagePath, palettePath string) (*Sprite, error) {
} }
func createAnimatedSprite(imagePath, palettePath string, direction AnimationDirection) (*AnimatedSprite, error) { func createAnimatedSprite(imagePath, palettePath string, direction AnimationDirection) (*AnimatedSprite, error) {
animation, err := d2asset.LoadAnimation(imagePath, palettePath) animation, err := singleton.asset.LoadAnimation(imagePath, palettePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,6 +4,8 @@ import (
"log" "log"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"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/d2fileformats/d2ds1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
@ -16,6 +18,9 @@ import (
// MapEngine loads the tiles which make up the isometric map and the entities // MapEngine loads the tiles which make up the isometric map and the entities
type MapEngine struct { type MapEngine struct {
asset *d2asset.AssetManager
*d2mapstamp.StampFactory
*d2mapentity.MapEntityFactory
seed int64 // The map seed seed int64 // The map seed
entities map[string]d2interface.MapEntity // Entities on the map entities map[string]d2interface.MapEntity // Entities on the map
tiles []MapTile tiles []MapTile
@ -28,8 +33,16 @@ type MapEngine struct {
} }
// CreateMapEngine creates a new instance of the map engine and returns a pointer to it. // CreateMapEngine creates a new instance of the map engine and returns a pointer to it.
func CreateMapEngine() *MapEngine { func CreateMapEngine(asset *d2asset.AssetManager) *MapEngine {
engine := &MapEngine{} entity := d2mapentity.NewMapEntityFactory(asset)
stamp := d2mapstamp.NewStampFactory(asset, entity)
engine := &MapEngine{
asset: asset,
MapEntityFactory: entity,
StampFactory: stamp,
}
return engine return engine
} }
@ -64,7 +77,7 @@ func (m *MapEngine) addDT1(fileName string) {
} }
} }
fileData, err := d2asset.LoadFile("/data/global/tiles/" + fileName) fileData, err := m.asset.LoadFile("/data/global/tiles/" + fileName)
if err != nil { if err != nil {
log.Printf("Could not load /data/global/tiles/%s", fileName) log.Printf("Could not load /data/global/tiles/%s", fileName)
// panic(err) // panic(err)
@ -84,7 +97,7 @@ func (m *MapEngine) AddDS1(fileName string) {
return return
} }
fileData, err := d2asset.LoadFile("/data/global/tiles/" + fileName) fileData, err := m.asset.LoadFile("/data/global/tiles/" + fileName)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -289,7 +302,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, fileIndex int) { func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset, fileIndex int) {
region := d2mapstamp.LoadStamp(regionType, levelPreset, fileIndex) region := m.LoadStamp(regionType, levelPreset, fileIndex)
regionSize := region.Size() regionSize := region.Size()
m.ResetMap(regionType, regionSize.Width, regionSize.Height) m.ResetMap(regionType, regionSize.Width, regionSize.Height)
m.PlaceStamp(region, 0, 0) m.PlaceStamp(region, 0, 0)

View File

@ -4,6 +4,9 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
uuid "github.com/satori/go.uuid"
"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/d2fileformats/d2tbl" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2tbl"
@ -15,6 +18,16 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2item/diablo2item" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2item/diablo2item"
) )
// NewMapEntityFactory creates a MapEntityFactory instance with the given asset manager
func NewMapEntityFactory(asset *d2asset.AssetManager) *MapEntityFactory {
return &MapEntityFactory{asset}
}
// MapEntityFactory creates map entities for the MapEngine
type MapEntityFactory struct {
asset *d2asset.AssetManager
}
// NewAnimatedEntity creates an instance of AnimatedEntity // NewAnimatedEntity creates an instance of AnimatedEntity
func NewAnimatedEntity(x, y int, animation d2interface.Animation) *AnimatedEntity { func NewAnimatedEntity(x, y int, animation d2interface.Animation) *AnimatedEntity {
entity := &AnimatedEntity{ entity := &AnimatedEntity{
@ -27,7 +40,7 @@ func NewAnimatedEntity(x, y int, animation d2interface.Animation) *AnimatedEntit
} }
// NewPlayer creates a new player entity and returns a pointer to it. // NewPlayer creates a new player entity and returns a pointer to it.
func NewPlayer(id, name string, x, y, direction int, heroType d2enum.Hero, func (f *MapEntityFactory) NewPlayer(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(),
@ -40,7 +53,7 @@ func NewPlayer(id, name string, x, y, direction int, heroType d2enum.Hero,
d2enum.CompositeTypeShield: equipment.Shield.GetItemCode(), d2enum.CompositeTypeShield: equipment.Shield.GetItemCode(),
} }
composite, err := d2asset.LoadComposite(d2enum.ObjectTypePlayer, heroType.GetToken(), composite, err := f.asset.LoadComposite(d2enum.ObjectTypePlayer, heroType.GetToken(),
d2resource.PaletteUnits) d2resource.PaletteUnits)
if err != nil { if err != nil {
panic(err) panic(err)
@ -81,8 +94,8 @@ func NewPlayer(id, name string, x, y, direction int, heroType d2enum.Hero,
} }
// NewMissile creates a new Missile and initializes it's animation. // NewMissile creates a new Missile and initializes it's animation.
func NewMissile(x, y int, record *d2datadict.MissileRecord) (*Missile, error) { func (f *MapEntityFactory) NewMissile(x, y int, record *d2datadict.MissileRecord) (*Missile, error) {
animation, err := d2asset.LoadAnimation( animation, err := f.asset.LoadAnimation(
fmt.Sprintf("%s/%s.dcc", d2resource.MissileData, record.Animation.CelFileName), fmt.Sprintf("%s/%s.dcc", d2resource.MissileData, record.Animation.CelFileName),
d2resource.PaletteUnits, d2resource.PaletteUnits,
) )
@ -109,7 +122,7 @@ func NewMissile(x, y int, record *d2datadict.MissileRecord) (*Missile, error) {
} }
// NewItem creates an item map entity // NewItem creates an item map entity
func NewItem(x, y int, codes ...string) (*Item, error) { func (f *MapEntityFactory) NewItem(x, y int, codes ...string) (*Item, error) {
item := diablo2item.NewItem(codes...) item := diablo2item.NewItem(codes...)
if item == nil { if item == nil {
@ -118,7 +131,7 @@ func NewItem(x, y int, codes ...string) (*Item, error) {
filename := item.CommonRecord().FlippyFile filename := item.CommonRecord().FlippyFile
filepath := fmt.Sprintf("%s/%s.DC6", d2resource.ItemGraphics, filename) filepath := fmt.Sprintf("%s/%s.DC6", d2resource.ItemGraphics, filename)
animation, err := d2asset.LoadAnimation(filepath, d2resource.PaletteUnits) animation, err := f.asset.LoadAnimation(filepath, d2resource.PaletteUnits)
if err != nil { if err != nil {
return nil, err return nil, err
@ -137,7 +150,7 @@ func NewItem(x, y int, codes ...string) (*Item, error) {
} }
// NewNPC creates a new NPC and returns a pointer to it. // NewNPC creates a new NPC and returns a pointer to it.
func NewNPC(x, y int, monstat *d2datadict.MonStatsRecord, direction int) (*NPC, error) { func (f *MapEntityFactory) NewNPC(x, y int, monstat *d2datadict.MonStatsRecord, direction int) (*NPC, error) {
result := &NPC{ result := &NPC{
mapEntity: newMapEntity(x, y), mapEntity: newMapEntity(x, y),
HasPaths: false, HasPaths: false,
@ -151,7 +164,7 @@ func NewNPC(x, y int, monstat *d2datadict.MonStatsRecord, direction int) (*NPC,
equipment[compType] = selectEquip(opts) equipment[compType] = selectEquip(opts)
} }
composite, _ := d2asset.LoadComposite(d2enum.ObjectTypeCharacter, monstat.AnimationDirectoryToken, composite, _ := f.asset.LoadComposite(d2enum.ObjectTypeCharacter, monstat.AnimationDirectoryToken,
d2resource.PaletteUnits) d2resource.PaletteUnits)
result.composite = composite result.composite = composite
@ -175,3 +188,30 @@ func NewNPC(x, y int, monstat *d2datadict.MonStatsRecord, direction int) (*NPC,
return result, nil return result, nil
} }
// NewObject creates an instance of AnimatedComposite
func (f *MapEntityFactory) NewObject(x, y int, objectRec *d2datadict.ObjectRecord,
palettePath string) (*Object, error) {
locX, locY := float64(x), float64(y)
entity := &Object{
uuid: uuid.NewV4().String(),
objectRecord: objectRec,
Position: d2vector.NewPosition(locX, locY),
name: d2tbl.TranslateString(objectRec.Name),
}
objectType := &d2datadict.ObjectTypes[objectRec.Index]
composite, err := f.asset.LoadComposite(d2enum.ObjectTypeItem, objectType.Token,
palettePath)
if err != nil {
return nil, err
}
entity.composite = composite
entity.setMode(d2enum.ObjectAnimationModeNeutral, 0, false)
initObject(entity)
return entity, nil
}

View File

@ -1,18 +1,14 @@
// Package d2object implements objects placed on the map and their functionality // Package d2object implements objects placed on the map and their functionality
package d2object package d2mapentity
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
uuid "github.com/satori/go.uuid"
"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/d2fileformats/d2tbl"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
@ -28,36 +24,6 @@ type Object struct {
name string name string
} }
// CreateObject creates an instance of AnimatedComposite
func CreateObject(x, y int, objectRec *d2datadict.ObjectRecord, palettePath string) (*Object, error) {
locX, locY := float64(x), float64(y)
entity := &Object{
uuid: uuid.NewV4().String(),
objectRecord: objectRec,
Position: d2vector.NewPosition(locX, locY),
name: d2tbl.TranslateString(objectRec.Name),
}
objectType := &d2datadict.ObjectTypes[objectRec.Index]
composite, err := d2asset.LoadComposite(d2enum.ObjectTypeItem, objectType.Token,
d2resource.PaletteUnits)
if err != nil {
return nil, err
}
entity.composite = composite
if err := entity.setMode(d2enum.ObjectAnimationModeNeutral, 0, false); err != nil {
return nil, err
}
if _, err := initObject(entity); err != nil {
return nil, err
}
return entity, nil
}
// setMode changes the graphical mode of this animated entity // setMode changes the graphical mode of this animated entity
func (ob *Object) setMode(animationMode d2enum.ObjectAnimationMode, direction int, randomFrame bool) error { func (ob *Object) setMode(animationMode d2enum.ObjectAnimationMode, direction int, randomFrame bool) error {
err := ob.composite.SetMode(animationMode, "HTH") err := ob.composite.SetMode(animationMode, "HTH")

View File

@ -1,4 +1,4 @@
package d2object package d2mapentity
import ( import (
"math/rand" "math/rand"

View File

@ -1,4 +1,3 @@
//nolint:gomnd
package d2mapgen package d2mapgen
import ( import (
@ -20,7 +19,7 @@ func loadPreset(mapEngine *d2mapengine.MapEngine, id, index int) *d2mapstamp.Sta
mapEngine.AddDS1(file) mapEngine.AddDS1(file)
} }
return d2mapstamp.LoadStamp(d2enum.RegionAct1Wilderness, id, index) return mapEngine.LoadStamp(d2enum.RegionAct1Wilderness, id, index)
} }
// GenerateAct1Overworld generates the map and entities for the first town and surrounding area. // GenerateAct1Overworld generates the map and entities for the first town and surrounding area.
@ -33,7 +32,7 @@ func GenerateAct1Overworld(mapEngine *d2mapengine.MapEngine) {
mapWidth := mapEngine.Size().Width mapWidth := mapEngine.Size().Width
mapHeight := mapEngine.Size().Height mapHeight := mapEngine.Size().Height
townStamp := d2mapstamp.LoadStamp(d2enum.RegionAct1Town, 1, -1) townStamp := mapEngine.LoadStamp(d2enum.RegionAct1Town, 1, -1)
townStamp.RegionPath() townStamp.RegionPath()
townSize := townStamp.Size() townSize := townStamp.Size()

View File

@ -48,6 +48,7 @@ const (
// MapRenderer manages the game viewport and Camera. It requests tile and entity data from MapEngine and renders it. // MapRenderer manages the game viewport and Camera. It requests tile and entity data from MapEngine and renders it.
type MapRenderer struct { type MapRenderer struct {
asset *d2asset.AssetManager
renderer d2interface.Renderer // Used for drawing operations renderer d2interface.Renderer // Used for drawing operations
mapEngine *d2mapengine.MapEngine // The map engine that is being rendered mapEngine *d2mapengine.MapEngine // The map engine that is being rendered
palette d2interface.Palette // The palette used for this map palette d2interface.Palette // The palette used for this map
@ -61,9 +62,11 @@ type MapRenderer struct {
} }
// CreateMapRenderer creates a new MapRenderer, sets the required fields and returns a pointer to it. // CreateMapRenderer creates a new MapRenderer, sets the required fields and returns a pointer to it.
func CreateMapRenderer(renderer d2interface.Renderer, mapEngine *d2mapengine.MapEngine, func CreateMapRenderer(asset *d2asset.AssetManager, renderer d2interface.Renderer,
mapEngine *d2mapengine.MapEngine,
term d2interface.Terminal, startX, startY float64) *MapRenderer { term d2interface.Terminal, startX, startY float64) *MapRenderer {
result := &MapRenderer{ result := &MapRenderer{
asset: asset,
renderer: renderer, renderer: renderer,
mapEngine: mapEngine, mapEngine: mapEngine,
viewport: NewViewport(0, 0, 800, 600), viewport: NewViewport(0, 0, 800, 600),
@ -563,7 +566,8 @@ func (mr *MapRenderer) Advance(elapsed float64) {
mr.Camera.Advance(elapsed) mr.Camera.Advance(elapsed)
} }
func loadPaletteForAct(levelType d2enum.RegionIdType) (d2interface.Palette, error) { func (mr *MapRenderer) loadPaletteForAct(levelType d2enum.RegionIdType) (d2interface.Palette,
error) {
var palettePath string var palettePath string
switch levelType { switch levelType {
@ -586,7 +590,7 @@ func loadPaletteForAct(levelType d2enum.RegionIdType) (d2interface.Palette, erro
return nil, errors.New("failed to find palette for region") return nil, errors.New("failed to find palette for region")
} }
return d2asset.LoadPalette(palettePath) return mr.asset.LoadPalette(palettePath)
} }
// ViewportToLeft moves the viewport to the left. // ViewportToLeft moves the viewport to the left.

View File

@ -11,7 +11,7 @@ import (
) )
func (mr *MapRenderer) generateTileCache() { func (mr *MapRenderer) generateTileCache() {
mr.palette, _ = loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID)) mr.palette, _ = mr.loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
tiles := *mr.mapEngine.Tiles() tiles := *mr.mapEngine.Tiles()
for idx := range tiles { for idx := range tiles {

View File

@ -0,0 +1,74 @@
package d2mapstamp
import (
"math"
"math/rand"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
)
func NewStampFactory(asset *d2asset.AssetManager, entity *d2mapentity.MapEntityFactory) *StampFactory {
return &StampFactory{asset, entity}
}
type StampFactory struct {
asset *d2asset.AssetManager
entity *d2mapentity.MapEntityFactory
}
// LoadStamp loads the Stamp data from file.
func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fileIndex int) *Stamp {
stamp := &Stamp{
entity: f.entity,
regionID: levelType,
levelType: d2datadict.LevelTypes[levelType],
levelPreset: d2datadict.LevelPresets[levelPreset],
}
for _, levelTypeDt1 := range &stamp.levelType.Files {
if levelTypeDt1 != "" && levelTypeDt1 != "0" {
fileData, err := f.asset.LoadFile("/data/global/tiles/" + levelTypeDt1)
if err != nil {
panic(err)
}
dt1, _ := d2dt1.LoadDT1(fileData)
stamp.tiles = append(stamp.tiles, dt1.Tiles...)
}
}
var levelFilesToPick []string
for _, fileRecord := range stamp.levelPreset.Files {
if fileRecord != "" && fileRecord != "0" {
levelFilesToPick = append(levelFilesToPick, fileRecord)
}
}
levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * rand.Float64()))
if fileIndex >= 0 && fileIndex < len(levelFilesToPick) {
levelIndex = fileIndex
}
if levelFilesToPick == nil {
panic("no level files to pick from")
}
stamp.regionPath = levelFilesToPick[levelIndex]
fileData, err := f.asset.LoadFile("/data/global/tiles/" + stamp.regionPath)
if err != nil {
panic(err)
}
stamp.ds1, _ = d2ds1.LoadDS1(fileData)
return stamp
}

View File

@ -1,9 +1,6 @@
package d2mapstamp package d2mapstamp
import ( import (
"math"
"math/rand"
"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/d2fileformats/d2ds1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
@ -13,13 +10,16 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2path" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2path"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2object" )
const (
subtilesPerTile = 5
) )
// Stamp represents a pre-fabricated map stamp that can be placed on a map. // Stamp represents a pre-fabricated map stamp that can be placed on a map.
type Stamp struct { type Stamp struct {
entity *d2mapentity.MapEntityFactory
regionPath string // The file path of the region regionPath string // The file path of the region
regionID d2enum.RegionIdType regionID d2enum.RegionIdType
levelType d2datadict.LevelTypeRecord // The level type id for this stamp levelType d2datadict.LevelTypeRecord // The level type id for this stamp
@ -28,56 +28,6 @@ type Stamp struct {
ds1 *d2ds1.DS1 // The backing DS1 file for this stamp ds1 *d2ds1.DS1 // The backing DS1 file for this stamp
} }
// LoadStamp loads the Stamp data from file.
func LoadStamp(levelType d2enum.RegionIdType, levelPreset, fileIndex int) *Stamp {
stamp := &Stamp{
regionID: levelType,
levelType: d2datadict.LevelTypes[levelType],
levelPreset: d2datadict.LevelPresets[levelPreset],
}
for _, levelTypeDt1 := range &stamp.levelType.Files {
if levelTypeDt1 != "" && levelTypeDt1 != "0" {
fileData, err := d2asset.LoadFile("/data/global/tiles/" + levelTypeDt1)
if err != nil {
panic(err)
}
dt1, _ := d2dt1.LoadDT1(fileData)
stamp.tiles = append(stamp.tiles, dt1.Tiles...)
}
}
var levelFilesToPick []string
for _, fileRecord := range stamp.levelPreset.Files {
if fileRecord != "" && fileRecord != "0" {
levelFilesToPick = append(levelFilesToPick, fileRecord)
}
}
levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * rand.Float64()))
if fileIndex >= 0 && fileIndex < len(levelFilesToPick) {
levelIndex = fileIndex
}
if levelFilesToPick == nil {
panic("no level files to pick from")
}
stamp.regionPath = levelFilesToPick[levelIndex]
fileData, err := d2asset.LoadFile("/data/global/tiles/" + stamp.regionPath)
if err != nil {
panic(err)
}
stamp.ds1, _ = d2ds1.LoadDS1(fileData)
return stamp
}
// Size returns the size of the stamp in tiles. // Size returns the size of the stamp in tiles.
func (mr *Stamp) Size() d2geom.Size { func (mr *Stamp) Size() d2geom.Size {
return d2geom.Size{Width: int(mr.ds1.Width), Height: int(mr.ds1.Height)} return d2geom.Size{Width: int(mr.ds1.Width), Height: int(mr.ds1.Height)}
@ -132,7 +82,7 @@ func (mr *Stamp) Entities(tileOffsetX, tileOffsetY int) []d2interface.MapEntity
if monstat != nil { if monstat != nil {
// Temorary use of Lookup. // Temorary use of Lookup.
npcX, npcY := (tileOffsetX*5)+object.X, (tileOffsetY*5)+object.Y npcX, npcY := (tileOffsetX*5)+object.X, (tileOffsetY*5)+object.Y
npc, err := d2mapentity.NewNPC(npcX, npcY, monstat, 0) npc, err := mr.entity.NewNPC(npcX, npcY, monstat, 0)
if err == nil { if err == nil {
npc.SetPaths(convertPaths(tileOffsetX, tileOffsetY, object.Paths)) npc.SetPaths(convertPaths(tileOffsetX, tileOffsetY, object.Paths))
@ -153,7 +103,7 @@ func (mr *Stamp) Entities(tileOffsetX, tileOffsetY int) []d2interface.MapEntity
objectRecord := d2datadict.Objects[lookup.ObjectsTxtId] objectRecord := d2datadict.Objects[lookup.ObjectsTxtId]
if objectRecord != nil { if objectRecord != nil {
entity, err := d2object.CreateObject((tileOffsetX*5)+object.X, entity, err := mr.entity.NewObject((tileOffsetX*5)+object.X,
(tileOffsetY*5)+object.Y, objectRecord, d2resource.PaletteUnits) (tileOffsetY*5)+object.Y, objectRecord, d2resource.PaletteUnits)
if err != nil { if err != nil {
@ -173,8 +123,8 @@ func convertPaths(tileOffsetX, tileOffsetY int, paths []d2path.Path) []d2path.Pa
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
result[i].Action = paths[i].Action result[i].Action = paths[i].Action
result[i].Position = d2vector.NewPosition( result[i].Position = d2vector.NewPosition(
paths[i].Position.X()+float64(tileOffsetX*5), paths[i].Position.X()+float64(tileOffsetX*subtilesPerTile),
paths[i].Position.Y()+float64(tileOffsetY*5)) paths[i].Position.Y()+float64(tileOffsetY*subtilesPerTile))
} }
return result return result

View File

@ -8,7 +8,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
) )
@ -192,7 +191,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
lbl.Color[0] = d2util.Color(greyAlpha100) lbl.Color[0] = d2util.Color(greyAlpha100)
lbl.Alignment = d2gui.HorizontalAlignCenter lbl.Alignment = d2gui.HorizontalAlignCenter
animation, _ := d2asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName) animation, _ := ui.asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName)
buttonSprite, _ := ui.NewSprite(animation) buttonSprite, _ := ui.NewSprite(animation)
for i := 0; i < buttonLayout.XSegments; i++ { for i := 0; i < buttonLayout.XSegments; i++ {

View File

@ -4,7 +4,6 @@ import (
"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"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
// Checkbox represents a checkbox UI element // Checkbox represents a checkbox UI element
@ -32,7 +31,7 @@ func (ui *UIManager) NewCheckbox(checkState bool) *Checkbox {
enabled: true, enabled: true,
} }
animation, _ := d2asset.LoadAnimation(d2resource.Checkbox, d2resource.PaletteFechar) animation, _ := ui.asset.LoadAnimation(d2resource.Checkbox, d2resource.PaletteFechar)
checkboxSprite, _ := ui.NewSprite(animation) checkboxSprite, _ := ui.NewSprite(animation)
result.width, result.height, _ = checkboxSprite.GetFrameSize(0) result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
checkboxSprite.SetPosition(0, 0) checkboxSprite.SetPosition(0, 0)

View File

@ -2,6 +2,7 @@ package d2ui
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
// CursorButton represents a mouse button // CursorButton represents a mouse button
@ -16,11 +17,13 @@ const (
// NewUIManager creates a UIManager instance with the given input and audio provider // NewUIManager creates a UIManager instance with the given input and audio provider
func NewUIManager( func NewUIManager(
asset *d2asset.AssetManager,
renderer d2interface.Renderer, renderer d2interface.Renderer,
input d2interface.InputManager, input d2interface.InputManager,
audio d2interface.AudioProvider, audio d2interface.AudioProvider,
) *UIManager { ) *UIManager {
ui := &UIManager{ ui := &UIManager{
asset: asset,
renderer: renderer, renderer: renderer,
inputManager: input, inputManager: input,
audio: audio, audio: audio,

View File

@ -8,7 +8,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
) )
@ -26,7 +25,7 @@ type Label struct {
// NewLabel creates a new instance of a UI label // NewLabel creates a new instance of a UI label
func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label { func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
font, _ := d2asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath) font, _ := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath)
result := &Label{ result := &Label{
Alignment: d2gui.HorizontalAlignLeft, Alignment: d2gui.HorizontalAlignLeft,
Color: map[int]color.Color{0: color.White}, Color: map[int]color.Color{0: color.White},

View File

@ -3,7 +3,6 @@ package d2ui
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
const ( const (
@ -29,7 +28,7 @@ type Scrollbar struct {
// NewScrollbar creates a scrollbar instance // NewScrollbar creates a scrollbar instance
func (ui *UIManager) NewScrollbar(x, y, height int) *Scrollbar { func (ui *UIManager) NewScrollbar(x, y, height int) *Scrollbar {
animation, _ := d2asset.LoadAnimation(d2resource.Scrollbar, d2resource.PaletteSky) animation, _ := ui.asset.LoadAnimation(d2resource.Scrollbar, d2resource.PaletteSky)
scrollbarSprite, _ := ui.NewSprite(animation) scrollbarSprite, _ := ui.NewSprite(animation)
result := &Scrollbar{ result := &Scrollbar{
visible: true, visible: true,

View File

@ -7,7 +7,6 @@ import (
"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"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
// TextBox represents a text input box // TextBox represents a text input box
@ -27,7 +26,7 @@ type TextBox struct {
// NewTextbox creates a new instance of a text box // NewTextbox creates a new instance of a text box
func (ui *UIManager) NewTextbox() *TextBox { func (ui *UIManager) NewTextbox() *TextBox {
animation, _ := d2asset.LoadAnimation(d2resource.TextBox2, d2resource.PaletteUnits) animation, _ := ui.asset.LoadAnimation(d2resource.TextBox2, d2resource.PaletteUnits)
bgSprite, _ := ui.NewSprite(animation) bgSprite, _ := ui.NewSprite(animation)
tb := &TextBox{ tb := &TextBox{
filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",

View File

@ -3,6 +3,8 @@ package d2ui
import ( import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"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"
@ -10,6 +12,7 @@ import (
// UIManager manages a collection of UI elements (buttons, textboxes, labels) // UIManager manages a collection of UI elements (buttons, textboxes, labels)
type UIManager struct { type UIManager struct {
asset *d2asset.AssetManager
renderer d2interface.Renderer renderer d2interface.Renderer
inputManager d2interface.InputManager inputManager d2interface.InputManager
audio d2interface.AudioProvider audio d2interface.AudioProvider

View File

@ -8,17 +8,20 @@ import (
// BlizzardIntro represents the Blizzard Intro screen // BlizzardIntro represents the Blizzard Intro screen
type BlizzardIntro struct { type BlizzardIntro struct {
asset *d2asset.AssetManager
videoDecoder *d2video.BinkDecoder videoDecoder *d2video.BinkDecoder
} }
// CreateBlizzardIntro creates a Blizzard Intro screen // CreateBlizzardIntro creates a Blizzard Intro screen
func CreateBlizzardIntro() *BlizzardIntro { func CreateBlizzardIntro(asset *d2asset.AssetManager) *BlizzardIntro {
return &BlizzardIntro{} return &BlizzardIntro{
asset: asset,
}
} }
// OnLoad loads the resources for the Blizzard Intro screen // OnLoad loads the resources for the Blizzard Intro screen
func (v *BlizzardIntro) OnLoad(loading d2screen.LoadingState) { func (v *BlizzardIntro) OnLoad(loading d2screen.LoadingState) {
videoBytes, err := d2asset.LoadFile("/data/local/video/BlizNorth640x480.bik") videoBytes, err := v.asset.LoadFile("/data/local/video/BlizNorth640x480.bik")
if err != nil { if err != nil {
loading.Error(err) loading.Error(err)
return return

View File

@ -21,6 +21,8 @@ import (
// CharacterSelect represents the character select screen // CharacterSelect represents the character select screen
type CharacterSelect struct { type CharacterSelect struct {
asset *d2asset.AssetManager
*d2mapentity.MapEntityFactory
background *d2ui.Sprite background *d2ui.Sprite
newCharButton *d2ui.Button newCharButton *d2ui.Button
convertCharButton *d2ui.Button convertCharButton *d2ui.Button
@ -54,6 +56,7 @@ type CharacterSelect struct {
// CreateCharacterSelect creates the character select screen and returns a pointer to it // CreateCharacterSelect creates the character select screen and returns a pointer to it
func CreateCharacterSelect( func CreateCharacterSelect(
navigator Navigator, navigator Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer, renderer d2interface.Renderer,
inputManager d2interface.InputManager, inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider, audioProvider d2interface.AudioProvider,
@ -63,6 +66,8 @@ func CreateCharacterSelect(
) *CharacterSelect { ) *CharacterSelect {
return &CharacterSelect{ return &CharacterSelect{
selectedCharacter: -1, selectedCharacter: -1,
asset: asset,
MapEntityFactory: d2mapentity.NewMapEntityFactory(asset),
renderer: renderer, renderer: renderer,
connectionType: connectionType, connectionType: connectionType,
connectionHost: connectionHost, connectionHost: connectionHost,
@ -133,7 +138,8 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
loading.Progress(tenPercent) loading.Progress(tenPercent)
animation, _ := d2asset.LoadAnimation(d2resource.CharacterSelectionBackground, d2resource.PaletteSky) animation, _ := v.asset.LoadAnimation(d2resource.CharacterSelectionBackground,
d2resource.PaletteSky)
bgX, bgY := 0, 0 bgX, bgY := 0, 0
v.background, _ = v.uiManager.NewSprite(animation) v.background, _ = v.uiManager.NewSprite(animation)
v.background.SetPosition(bgX, bgY) v.background.SetPosition(bgX, bgY)
@ -154,12 +160,13 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
deleteConfirmX, deleteConfirmY := 400, 185 deleteConfirmX, deleteConfirmY := 400, 185
v.deleteCharConfirmLabel.SetPosition(deleteConfirmX, deleteConfirmY) v.deleteCharConfirmLabel.SetPosition(deleteConfirmX, deleteConfirmY)
animation, _ = d2asset.LoadAnimation(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky) animation, _ = v.asset.LoadAnimation(d2resource.CharacterSelectionSelectBox,
d2resource.PaletteSky)
v.selectionBox, _ = v.uiManager.NewSprite(animation) v.selectionBox, _ = v.uiManager.NewSprite(animation)
selBoxX, selBoxY := 37, 86 selBoxX, selBoxY := 37, 86
v.selectionBox.SetPosition(selBoxX, selBoxY) v.selectionBox.SetPosition(selBoxX, selBoxY)
animation, _ = d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar) animation, _ = v.asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
v.okCancelBox, _ = v.uiManager.NewSprite(animation) v.okCancelBox, _ = v.uiManager.NewSprite(animation)
okCancelX, okCancelY := 270, 175 okCancelX, okCancelY := 270, 175
v.okCancelBox.SetPosition(okCancelX, okCancelY) v.okCancelBox.SetPosition(okCancelX, okCancelY)
@ -283,7 +290,7 @@ func (v *CharacterSelect) updateCharacterBoxes() {
equipment := d2inventory.HeroObjects[heroType] equipment := d2inventory.HeroObjects[heroType]
// TODO: Generate or load the object from the actual player data... // TODO: Generate or load the object from the actual player data...
v.characterImage[i] = d2mapentity.NewPlayer("", "", 0, 0, 0, v.characterImage[i] = v.NewPlayer("", "", 0, 0, 0,
v.gameStates[idx].HeroType, v.gameStates[idx].HeroType,
v.gameStates[idx].Stats, v.gameStates[idx].Stats,
&equipment, &equipment,

View File

@ -39,14 +39,17 @@ type Credits struct {
cyclesTillNextLine int cyclesTillNextLine int
doneWithCredits bool doneWithCredits bool
asset *d2asset.AssetManager
renderer d2interface.Renderer renderer d2interface.Renderer
navigator Navigator navigator Navigator
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
} }
// CreateCredits creates an instance of the credits screen // CreateCredits creates an instance of the credits screen
func CreateCredits(navigator Navigator, renderer d2interface.Renderer, ui *d2ui.UIManager) *Credits { func CreateCredits(navigator Navigator, asset *d2asset.AssetManager, renderer d2interface.Renderer,
ui *d2ui.UIManager) *Credits {
result := &Credits{ result := &Credits{
asset: asset,
labels: make([]*labelItem, 0), labels: make([]*labelItem, 0),
cycleTime: 0, cycleTime: 0,
doneWithCredits: false, doneWithCredits: false,
@ -86,7 +89,7 @@ func (v *Credits) LoadContributors() []string {
// OnLoad is called to load the resources for the credits screen // OnLoad is called to load the resources for the credits screen
func (v *Credits) OnLoad(loading d2screen.LoadingState) { func (v *Credits) OnLoad(loading d2screen.LoadingState) {
animation, _ := d2asset.LoadAnimation(d2resource.CreditsBackground, d2resource.PaletteSky) animation, _ := v.asset.LoadAnimation(d2resource.CreditsBackground, d2resource.PaletteSky)
v.creditsBackground, _ = v.uiManager.NewSprite(animation) v.creditsBackground, _ = v.uiManager.NewSprite(animation)
v.creditsBackground.SetPosition(creditsX, creditsY) v.creditsBackground.SetPosition(creditsX, creditsY)
loading.Progress(twentyPercent) loading.Progress(twentyPercent)
@ -96,7 +99,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
loading.Progress(fourtyPercent) loading.Progress(fourtyPercent)
fileData, err := d2asset.LoadFile(d2resource.CreditsText) fileData, err := v.asset.LoadFile(d2resource.CreditsText)
if err != nil { if err != nil {
loading.Error(err) loading.Error(err)
return return

View File

@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"image/color" "image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
@ -30,6 +32,8 @@ const (
// Game represents the Gameplay screen // Game represents the Gameplay screen
type Game struct { type Game struct {
*d2mapentity.MapEntityFactory
asset *d2asset.AssetManager
gameClient *d2client.GameClient gameClient *d2client.GameClient
mapRenderer *d2maprenderer.MapRenderer mapRenderer *d2maprenderer.MapRenderer
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
@ -50,6 +54,8 @@ type Game struct {
// CreateGame creates the Gameplay screen and returns a pointer to it // CreateGame creates the Gameplay screen and returns a pointer to it
func CreateGame( func CreateGame(
navigator Navigator, navigator Navigator,
asset *d2asset.AssetManager,
ui *d2ui.UIManager,
renderer d2interface.Renderer, renderer d2interface.Renderer,
inputManager d2interface.InputManager, inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider, audioProvider d2interface.AudioProvider,
@ -71,19 +77,21 @@ func CreateGame(
} }
result := &Game{ result := &Game{
asset: asset,
gameClient: gameClient, gameClient: gameClient,
gameControls: nil, gameControls: nil,
localPlayer: nil, localPlayer: nil,
lastRegionType: d2enum.RegionNone, lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0, ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(renderer, gameClient.MapEngine, term, startX, startY), mapRenderer: d2maprenderer.CreateMapRenderer(asset, renderer,
gameClient.MapEngine, term, startX, startY),
escapeMenu: NewEscapeMenu(navigator, renderer, audioProvider), escapeMenu: NewEscapeMenu(navigator, renderer, audioProvider),
inputManager: inputManager, inputManager: inputManager,
audioProvider: audioProvider, audioProvider: audioProvider,
renderer: renderer, renderer: renderer,
terminal: term, terminal: term,
soundEngine: d2audio.NewSoundEngine(audioProvider, term), soundEngine: d2audio.NewSoundEngine(audioProvider, term),
uiManager: d2ui.NewUIManager(renderer, inputManager, audioProvider), uiManager: ui,
} }
result.soundEnv = d2audio.NewSoundEnvironment(result.soundEngine) result.soundEnv = d2audio.NewSoundEnvironment(result.soundEngine)
@ -135,12 +143,13 @@ func (v *Game) OnLoad(_ d2screen.LoadingState) {
v.terminal.OutputErrorf("no monstat entry for \"%s\"", name) v.terminal.OutputErrorf("no monstat entry for \"%s\"", name)
return return
} }
var monster *d2mapentity.NPC
monster, err = d2mapentity.NewNPC(x, y, monstat, 0) monster, err := v.gameClient.MapEngine.NewNPC(x, y, monstat, 0)
if err != nil { if err != nil {
v.terminal.OutputErrorf("error generating monster \"%s\": %v", name, err) v.terminal.OutputErrorf("error generating monster \"%s\": %v", name, err)
return return
} }
v.gameClient.MapEngine.AddEntity(monster) v.gameClient.MapEngine.AddEntity(monster)
}, },
) )
@ -266,7 +275,7 @@ func (v *Game) bindGameControls() error {
v.localPlayer = player v.localPlayer = player
var err error var err error
v.gameControls, err = d2player.NewGameControls(v.renderer, player, v.gameControls, err = d2player.NewGameControls(v.asset, v.renderer, player,
v.gameClient.MapEngine, v.mapRenderer, v, v.terminal, v.uiManager, v.gameClient.IsSinglePlayer()) v.gameClient.MapEngine, v.mapRenderer, v, v.terminal, v.uiManager, v.gameClient.IsSinglePlayer())
if err != nil { if err != nil {

View File

@ -111,6 +111,7 @@ type MainMenu struct {
screenMode mainMenuScreenMode screenMode mainMenuScreenMode
leftButtonHeld bool leftButtonHeld bool
asset *d2asset.AssetManager
inputManager d2interface.InputManager inputManager d2interface.InputManager
renderer d2interface.Renderer renderer d2interface.Renderer
audioProvider d2interface.AudioProvider audioProvider d2interface.AudioProvider
@ -124,6 +125,7 @@ type MainMenu struct {
// CreateMainMenu creates an instance of MainMenu // CreateMainMenu creates an instance of MainMenu
func CreateMainMenu( func CreateMainMenu(
navigator Navigator, navigator Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer, renderer d2interface.Renderer,
inputManager d2interface.InputManager, inputManager d2interface.InputManager,
audioProvider d2interface.AudioProvider, audioProvider d2interface.AudioProvider,
@ -131,6 +133,7 @@ func CreateMainMenu(
buildInfo BuildInfo, buildInfo BuildInfo,
) *MainMenu { ) *MainMenu {
return &MainMenu{ return &MainMenu{
asset: asset,
screenMode: ScreenModeUnknown, screenMode: ScreenModeUnknown,
leftButtonHeld: true, leftButtonHeld: true,
renderer: renderer, renderer: renderer,
@ -169,19 +172,19 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
} }
func (v *MainMenu) loadBackgroundSprites() { func (v *MainMenu) loadBackgroundSprites() {
animation, _ := d2asset.LoadAnimation(d2resource.GameSelectScreen, d2resource.PaletteSky) animation, _ := v.asset.LoadAnimation(d2resource.GameSelectScreen, d2resource.PaletteSky)
v.background, _ = v.uiManager.NewSprite(animation) v.background, _ = v.uiManager.NewSprite(animation)
v.background.SetPosition(backgroundX, backgroundY) v.background.SetPosition(backgroundX, backgroundY)
animation, _ = d2asset.LoadAnimation(d2resource.TrademarkScreen, d2resource.PaletteSky) animation, _ = v.asset.LoadAnimation(d2resource.TrademarkScreen, d2resource.PaletteSky)
v.trademarkBackground, _ = v.uiManager.NewSprite(animation) v.trademarkBackground, _ = v.uiManager.NewSprite(animation)
v.trademarkBackground.SetPosition(backgroundX, backgroundY) v.trademarkBackground.SetPosition(backgroundX, backgroundY)
animation, _ = d2asset.LoadAnimation(d2resource.TCPIPBackground, d2resource.PaletteSky) animation, _ = v.asset.LoadAnimation(d2resource.TCPIPBackground, d2resource.PaletteSky)
v.tcpIPBackground, _ = v.uiManager.NewSprite(animation) v.tcpIPBackground, _ = v.uiManager.NewSprite(animation)
v.tcpIPBackground.SetPosition(backgroundX, backgroundY) v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
animation, _ = d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar) animation, _ = v.asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
v.serverIPBackground, _ = v.uiManager.NewSprite(animation) v.serverIPBackground, _ = v.uiManager.NewSprite(animation)
v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY) v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
} }
@ -233,24 +236,24 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
} }
func (v *MainMenu) createLogos(loading d2screen.LoadingState) { func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
animation, _ := d2asset.LoadAnimation(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits) animation, _ := v.asset.LoadAnimation(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
v.diabloLogoLeft, _ = v.uiManager.NewSprite(animation) v.diabloLogoLeft, _ = v.uiManager.NewSprite(animation)
v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate) v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
v.diabloLogoLeft.PlayForward() v.diabloLogoLeft.PlayForward()
v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY) v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY)
loading.Progress(sixtyPercent) loading.Progress(sixtyPercent)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits) animation, _ = v.asset.LoadAnimation(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
v.diabloLogoRight, _ = v.uiManager.NewSprite(animation) v.diabloLogoRight, _ = v.uiManager.NewSprite(animation)
v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate) v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
v.diabloLogoRight.PlayForward() v.diabloLogoRight.PlayForward()
v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY) v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits) animation, _ = v.asset.LoadAnimation(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
v.diabloLogoLeftBack, _ = v.uiManager.NewSprite(animation) v.diabloLogoLeftBack, _ = v.uiManager.NewSprite(animation)
v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY) v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits) animation, _ = v.asset.LoadAnimation(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
v.diabloLogoRightBack, _ = v.uiManager.NewSprite(animation) v.diabloLogoRightBack, _ = v.uiManager.NewSprite(animation)
v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY) v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
} }

View File

@ -7,17 +7,14 @@ import (
"strings" "strings"
"time" "time"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"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/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player" "github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
) )
@ -87,6 +84,7 @@ func getRegions() []regionSpec {
// MapEngineTest represents the MapEngineTest screen // MapEngineTest represents the MapEngineTest screen
type MapEngineTest struct { type MapEngineTest struct {
asset *d2asset.AssetManager
gameState *d2player.PlayerState gameState *d2player.PlayerState
mapEngine *d2mapengine.MapEngine mapEngine *d2mapengine.MapEngine
mapRenderer *d2maprenderer.MapRenderer mapRenderer *d2maprenderer.MapRenderer
@ -112,6 +110,7 @@ type MapEngineTest struct {
// CreateMapEngineTest creates the Map Engine Test screen and returns a pointer to it // CreateMapEngineTest creates the Map Engine Test screen and returns a pointer to it
func CreateMapEngineTest(currentRegion, func CreateMapEngineTest(currentRegion,
levelPreset int, levelPreset int,
asset *d2asset.AssetManager,
term d2interface.Terminal, term d2interface.Terminal,
renderer d2interface.Renderer, renderer d2interface.Renderer,
inputManager d2interface.InputManager, inputManager d2interface.InputManager,
@ -124,6 +123,7 @@ func CreateMapEngineTest(currentRegion,
fileIndex: 0, fileIndex: 0,
regionSpec: regionSpec{}, regionSpec: regionSpec{},
filesCount: 0, filesCount: 0,
asset: asset,
terminal: term, terminal: term,
renderer: renderer, renderer: renderer,
inputManager: inputManager, inputManager: inputManager,
@ -171,7 +171,7 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
met.mapEngine.SetSeed(time.Now().UnixNano()) met.mapEngine.SetSeed(time.Now().UnixNano())
d2mapgen.GenerateAct1Overworld(met.mapEngine) d2mapgen.GenerateAct1Overworld(met.mapEngine)
} else { } else {
met.mapEngine = d2mapengine.CreateMapEngine() // necessary for map name update met.mapEngine = d2mapengine.CreateMapEngine(met.asset) // 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) met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
} }
@ -193,11 +193,12 @@ func (met *MapEngineTest) OnLoad(loading d2screen.LoadingState) {
loading.Progress(twentyPercent) loading.Progress(twentyPercent)
met.mapEngine = d2mapengine.CreateMapEngine() met.mapEngine = d2mapengine.CreateMapEngine(met.asset)
loading.Progress(fiftyPercent) loading.Progress(fiftyPercent)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.renderer, met.mapEngine, met.terminal, 0.0, 0.0) met.mapRenderer = d2maprenderer.CreateMapRenderer(met.asset, met.renderer, met.mapEngine,
met.terminal, 0.0, 0.0)
loading.Progress(seventyPercent) loading.Progress(seventyPercent)
met.loadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex) met.loadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)

View File

@ -4,13 +4,12 @@ import (
"fmt" "fmt"
"image" "image"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2tbl"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"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/d2fileformats/d2tbl"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
@ -269,6 +268,7 @@ func (hri *HeroRenderInfo) advance(elapsed float64) {
// SelectHeroClass represents the Select Hero Class screen // SelectHeroClass represents the Select Hero Class screen
type SelectHeroClass struct { type SelectHeroClass struct {
asset *d2asset.AssetManager
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
bgImage *d2ui.Sprite bgImage *d2ui.Sprite
campfire *d2ui.Sprite campfire *d2ui.Sprite
@ -298,6 +298,7 @@ type SelectHeroClass struct {
// CreateSelectHeroClass creates an instance of a SelectHeroClass // CreateSelectHeroClass creates an instance of a SelectHeroClass
func CreateSelectHeroClass( func CreateSelectHeroClass(
navigator Navigator, navigator Navigator,
manager *d2asset.AssetManager,
renderer d2interface.Renderer, renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider, audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager, ui *d2ui.UIManager,
@ -732,7 +733,7 @@ func (v *SelectHeroClass) loadSprite(animationPath string, position image.Point,
return nil return nil
} }
animation, err := d2asset.LoadAnimation(animationPath, d2resource.PaletteFechar) animation, err := v.asset.LoadAnimation(animationPath, d2resource.PaletteFechar)
if err != nil { if err != nil {
fmt.Printf("could not load animation: %s\n", animationPath) fmt.Printf("could not load animation: %s\n", animationPath)
return nil return nil

View File

@ -47,6 +47,7 @@ const (
// GameControls represents the game's controls on the screen // GameControls represents the game's controls on the screen
type GameControls struct { type GameControls struct {
actionableRegions []ActionableRegion actionableRegions []ActionableRegion
asset *d2asset.AssetManager
renderer d2interface.Renderer // TODO: This shouldn't be a dependency renderer d2interface.Renderer // TODO: This shouldn't be a dependency
inputListener InputCallbackListener inputListener InputCallbackListener
hero *d2mapentity.Player hero *d2mapentity.Player
@ -103,6 +104,7 @@ const (
// NewGameControls creates a GameControls instance and returns a pointer to it // NewGameControls creates a GameControls instance and returns a pointer to it
func NewGameControls( func NewGameControls(
asset *d2asset.AssetManager,
renderer d2interface.Renderer, renderer d2interface.Renderer,
hero *d2mapentity.Player, hero *d2mapentity.Player,
mapEngine *d2mapengine.MapEngine, mapEngine *d2mapengine.MapEngine,
@ -161,16 +163,17 @@ func NewGameControls(
globeStatsLabel := hpManaStatsLabel globeStatsLabel := hpManaStatsLabel
gc := &GameControls{ gc := &GameControls{
asset: asset,
uiManager: ui, uiManager: ui,
renderer: renderer, renderer: renderer,
hero: hero, hero: hero,
mapEngine: mapEngine, mapEngine: mapEngine,
inputListener: inputListener, inputListener: inputListener,
mapRenderer: mapRenderer, mapRenderer: mapRenderer,
inventory: NewInventory(ui, inventoryRecord), inventory: NewInventory(asset, ui, inventoryRecord),
heroStatsPanel: NewHeroStatsPanel(ui, hero.Name(), hero.Class, hero.Stats), heroStatsPanel: NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats),
helpOverlay: help.NewHelpOverlay(renderer), helpOverlay: help.NewHelpOverlay(asset, renderer, ui),
miniPanel: newMiniPanel(ui, isSinglePlayer), miniPanel: newMiniPanel(asset, ui, isSinglePlayer),
missileID: missileID, missileID: missileID,
nameLabel: hoverLabel, nameLabel: hoverLabel,
zoneChangeText: zoneLabel, zoneChangeText: zoneLabel,
@ -378,20 +381,20 @@ func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
// Load loads the resources required for the GameControls // Load loads the resources required for the GameControls
func (g *GameControls) Load() { func (g *GameControls) Load() {
animation, _ := d2asset.LoadAnimation(d2resource.GameGlobeOverlap, d2resource.PaletteSky) animation, _ := g.asset.LoadAnimation(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
g.globeSprite, _ = g.uiManager.NewSprite(animation) g.globeSprite, _ = g.uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.HealthManaIndicator, d2resource.PaletteSky) animation, _ = g.asset.LoadAnimation(d2resource.HealthManaIndicator, d2resource.PaletteSky)
g.hpManaStatusSprite, _ = g.uiManager.NewSprite(animation) g.hpManaStatusSprite, _ = g.uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.GamePanels, d2resource.PaletteSky) animation, _ = g.asset.LoadAnimation(d2resource.GamePanels, d2resource.PaletteSky)
g.mainPanel, _ = g.uiManager.NewSprite(animation) g.mainPanel, _ = g.uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.MenuButton, d2resource.PaletteSky) animation, _ = g.asset.LoadAnimation(d2resource.MenuButton, d2resource.PaletteSky)
_ = animation.SetCurrentFrame(2) _ = animation.SetCurrentFrame(2)
g.menuButton, _ = g.uiManager.NewSprite(animation) g.menuButton, _ = g.uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.GenericSkills, d2resource.PaletteSky) animation, _ = g.asset.LoadAnimation(d2resource.GenericSkills, d2resource.PaletteSky)
g.skillIcon, _ = g.uiManager.NewSprite(animation) g.skillIcon, _ = g.uiManager.NewSprite(animation)
g.loadUIButtons() g.loadUIButtons()

View File

@ -2,9 +2,10 @@ package help
import ( import (
"fmt" "fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"image/color" "image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
@ -25,6 +26,7 @@ const (
// HelpOverlay represents the in-game overlay that toggles visibility when the h key is pressed // HelpOverlay represents the in-game overlay that toggles visibility when the h key is pressed
type Overlay struct { type Overlay struct {
asset *d2asset.AssetManager
isOpen bool isOpen bool
renderer d2interface.Renderer renderer d2interface.Renderer
frames []*d2ui.Sprite frames []*d2ui.Sprite
@ -36,9 +38,12 @@ type Overlay struct {
layout *d2gui.Layout layout *d2gui.Layout
} }
func NewHelpOverlay(renderer d2interface.Renderer) *Overlay { func NewHelpOverlay(asset *d2asset.AssetManager, renderer d2interface.Renderer,
ui *d2ui.UIManager) *Overlay {
h := &Overlay{ h := &Overlay{
asset: asset,
renderer: renderer, renderer: renderer,
uiManager: ui,
} }
return h return h
@ -89,7 +94,7 @@ func (h *Overlay) Load() {
prevY = 0 prevY = 0
) )
for frameIndex := 0; frameIndex < 7; frameIndex++ { for frameIndex := 0; frameIndex < 7; frameIndex++ {
animation, _ := d2asset.LoadAnimation(d2resource.HelpBorder, d2resource.PaletteSky) animation, _ := h.asset.LoadAnimation(d2resource.HelpBorder, d2resource.PaletteSky)
_ = animation.SetCurrentFrame(frameIndex) _ = animation.SetCurrentFrame(frameIndex)
f, _ := h.uiManager.NewSprite(animation) f, _ := h.uiManager.NewSprite(animation)
@ -139,7 +144,7 @@ func (h *Overlay) Load() {
// Close // Close
anim, _ := d2asset.LoadAnimation(d2resource.SquareButton, d2resource.PaletteSky) anim, _ := h.asset.LoadAnimation(d2resource.SquareButton, d2resource.PaletteSky)
close, _ := h.uiManager.NewSprite(anim) close, _ := h.uiManager.NewSprite(anim)
_ = close.SetCurrentFrame(0) _ = close.SetCurrentFrame(0)
close.SetPosition(685, 57) close.SetPosition(685, 57)
@ -339,7 +344,7 @@ func (h *Overlay) createBullet(c callout) {
newLabel.SetPosition(c.LabelX, c.LabelY) newLabel.SetPosition(c.LabelX, c.LabelY)
h.text = append(h.text, newLabel) h.text = append(h.text, newLabel)
anim, _ := d2asset.LoadAnimation(d2resource.HelpYellowBullet, d2resource.PaletteSky) anim, _ := h.asset.LoadAnimation(d2resource.HelpYellowBullet, d2resource.PaletteSky)
newDot, _ := h.uiManager.NewSprite(anim) newDot, _ := h.uiManager.NewSprite(anim)
_ = newDot.SetCurrentFrame(0) _ = newDot.SetCurrentFrame(0)
newDot.SetPosition(c.DotX, c.DotY+14) newDot.SetPosition(c.DotX, c.DotY+14)
@ -365,7 +370,7 @@ func (h *Overlay) createCallout(c callout) {
} }
h.lines = append(h.lines, l) h.lines = append(h.lines, l)
anim, _ := d2asset.LoadAnimation(d2resource.HelpWhiteBullet, d2resource.PaletteSky) anim, _ := h.asset.LoadAnimation(d2resource.HelpWhiteBullet, d2resource.PaletteSky)
newDot, _ := h.uiManager.NewSprite(anim) newDot, _ := h.uiManager.NewSprite(anim)
_ = newDot.SetCurrentFrame(0) _ = newDot.SetCurrentFrame(0)
newDot.SetPosition(c.DotX, c.DotY) newDot.SetPosition(c.DotX, c.DotY)

View File

@ -41,6 +41,7 @@ type StatsPanelLabels struct {
// HeroStatsPanel represents the hero status panel // HeroStatsPanel represents the hero status panel
type HeroStatsPanel struct { type HeroStatsPanel struct {
asset *d2asset.AssetManager
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
frame *d2ui.Sprite frame *d2ui.Sprite
panel *d2ui.Sprite panel *d2ui.Sprite
@ -57,12 +58,13 @@ type HeroStatsPanel struct {
} }
// NewHeroStatsPanel creates a new hero status panel // NewHeroStatsPanel creates a new hero status panel
func NewHeroStatsPanel(ui *d2ui.UIManager, heroName string, heroClass d2enum.Hero, func NewHeroStatsPanel(asset *d2asset.AssetManager, ui *d2ui.UIManager, heroName string, heroClass d2enum.Hero,
heroState *d2hero.HeroStatsState) *HeroStatsPanel { heroState *d2hero.HeroStatsState) *HeroStatsPanel {
originX := 0 originX := 0
originY := 0 originY := 0
return &HeroStatsPanel{ return &HeroStatsPanel{
asset: asset,
uiManager: ui, uiManager: ui,
renderer: ui.Renderer(), renderer: ui.Renderer(),
originX: originX, originX: originX,
@ -76,9 +78,9 @@ func NewHeroStatsPanel(ui *d2ui.UIManager, heroName string, heroClass d2enum.Her
// Load loads the data for the hero status panel // Load loads the data for the hero status panel
func (s *HeroStatsPanel) Load() { func (s *HeroStatsPanel) Load() {
animation, _ := d2asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky) animation, _ := s.asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky)
s.frame, _ = s.uiManager.NewSprite(animation) s.frame, _ = s.uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky) animation, _ = s.asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
s.panel, _ = s.uiManager.NewSprite(animation) s.panel, _ = s.uiManager.NewSprite(animation)
s.initStatValueLabels() s.initStatValueLabels()
} }

View File

@ -16,6 +16,7 @@ import (
// Inventory represents the inventory // Inventory represents the inventory
type Inventory struct { type Inventory struct {
asset *d2asset.AssetManager
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
frame *d2ui.Sprite frame *d2ui.Sprite
panel *d2ui.Sprite panel *d2ui.Sprite
@ -32,13 +33,15 @@ type Inventory struct {
} }
// NewInventory creates an inventory instance and returns a pointer to it // NewInventory creates an inventory instance and returns a pointer to it
func NewInventory(ui *d2ui.UIManager, record *d2datadict.InventoryRecord) *Inventory { func NewInventory(asset *d2asset.AssetManager, ui *d2ui.UIManager,
record *d2datadict.InventoryRecord) *Inventory {
hoverLabel := ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteStatic) hoverLabel := ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteStatic)
hoverLabel.Alignment = d2gui.HorizontalAlignCenter hoverLabel.Alignment = d2gui.HorizontalAlignCenter
return &Inventory{ return &Inventory{
asset: asset,
uiManager: ui, uiManager: ui,
grid: NewItemGrid(ui, record), grid: NewItemGrid(asset, ui, record),
originX: record.Panel.Left, originX: record.Panel.Left,
hoverLabel: hoverLabel, hoverLabel: hoverLabel,
// originY: record.Panel.Top, // originY: record.Panel.Top,
@ -68,10 +71,10 @@ func (g *Inventory) Close() {
// Load loads the resources required by the inventory // Load loads the resources required by the inventory
func (g *Inventory) Load() { func (g *Inventory) Load() {
animation, _ := d2asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky) animation, _ := g.asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky)
g.frame, _ = g.uiManager.NewSprite(animation) g.frame, _ = g.uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky) animation, _ = g.asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
g.panel, _ = g.uiManager.NewSprite(animation) g.panel, _ = g.uiManager.NewSprite(animation)
items := []InventoryItem{ items := []InventoryItem{
diablo2item.NewItem("kit", "Crimson", "of the Bat", "of Frost").Identify(), diablo2item.NewItem("kit", "Crimson", "of the Bat", "of Frost").Identify(),

View File

@ -33,6 +33,7 @@ var errorInventoryFull = errors.New("inventory full")
// ItemGrid is a reusable grid for use with player and merchant inventory. // ItemGrid is a reusable grid for use with player and merchant inventory.
// Handles layout and rendering item icons based on code. // Handles layout and rendering item icons based on code.
type ItemGrid struct { type ItemGrid struct {
asset *d2asset.AssetManager
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
items []InventoryItem items []InventoryItem
equipmentSlots map[d2enum.EquippedSlot]EquipmentSlot equipmentSlots map[d2enum.EquippedSlot]EquipmentSlot
@ -44,10 +45,12 @@ type ItemGrid struct {
slotSize int slotSize int
} }
func NewItemGrid(ui *d2ui.UIManager, record *d2datadict.InventoryRecord) *ItemGrid { func NewItemGrid(asset *d2asset.AssetManager, ui *d2ui.UIManager,
record *d2datadict.InventoryRecord) *ItemGrid {
grid := record.Grid grid := record.Grid
return &ItemGrid{ return &ItemGrid{
asset: asset,
uiManager: ui, uiManager: ui,
width: grid.Box.Width, width: grid.Box.Width,
height: grid.Box.Height, height: grid.Box.Height,
@ -118,7 +121,7 @@ func (g *ItemGrid) loadItem(item InventoryItem) {
var itemSprite *d2ui.Sprite var itemSprite *d2ui.Sprite
// TODO: Put the pattern into D2Shared // TODO: Put the pattern into D2Shared
animation, err := d2asset.LoadAnimation( animation, err := g.asset.LoadAnimation(
fmt.Sprintf("/data/global/items/inv%s.dc6", item.GetItemCode()), fmt.Sprintf("/data/global/items/inv%s.dc6", item.GetItemCode()),
d2resource.PaletteSky, d2resource.PaletteSky,
) )

View File

@ -9,6 +9,7 @@ import (
) )
type miniPanel struct { type miniPanel struct {
asset *d2asset.AssetManager
container *d2ui.Sprite container *d2ui.Sprite
button *d2ui.Sprite button *d2ui.Sprite
isOpen bool isOpen bool
@ -16,16 +17,16 @@ type miniPanel struct {
rectangle d2geom.Rectangle rectangle d2geom.Rectangle
} }
func newMiniPanel(uiManager *d2ui.UIManager, isSinglePlayer bool) *miniPanel { func newMiniPanel(asset *d2asset.AssetManager, uiManager *d2ui.UIManager, isSinglePlayer bool) *miniPanel {
miniPanelContainerPath := d2resource.Minipanel miniPanelContainerPath := d2resource.Minipanel
if isSinglePlayer { if isSinglePlayer {
miniPanelContainerPath = d2resource.MinipanelSmall miniPanelContainerPath = d2resource.MinipanelSmall
} }
animation, _ := d2asset.LoadAnimation(miniPanelContainerPath, d2resource.PaletteSky) animation, _ := asset.LoadAnimation(miniPanelContainerPath, d2resource.PaletteSky)
containerSprite, _ := uiManager.NewSprite(animation) containerSprite, _ := uiManager.NewSprite(animation)
animation, _ = d2asset.LoadAnimation(d2resource.MinipanelButton, d2resource.PaletteSky) animation, _ = asset.LoadAnimation(d2resource.MinipanelButton, d2resource.PaletteSky)
buttonSprite, _ := uiManager.NewSprite(animation) buttonSprite, _ := uiManager.NewSprite(animation)
rectangle := d2geom.Rectangle{Left: 325, Top: 526, Width: 156, Height: 26} rectangle := d2geom.Rectangle{Left: 325, Top: 526, Width: 156, Height: 26}
@ -34,7 +35,14 @@ func newMiniPanel(uiManager *d2ui.UIManager, isSinglePlayer bool) *miniPanel {
rectangle.Width = 182 rectangle.Width = 182
} }
return &miniPanel{container: containerSprite, button: buttonSprite, isOpen: true, isSinglePlayer: isSinglePlayer, rectangle: rectangle} return &miniPanel{
asset: asset,
container: containerSprite,
button: buttonSprite,
isOpen: true,
isSinglePlayer: isSinglePlayer,
rectangle: rectangle,
}
} }
func (m *miniPanel) IsOpen() bool { func (m *miniPanel) IsOpen() bool {

View File

@ -1,6 +1,7 @@
package d2localclient package d2localclient
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player" "github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
@ -13,6 +14,7 @@ import (
// LocalClientConnection is the implementation of ClientConnection // LocalClientConnection is the implementation of ClientConnection
// for a local client. // for a local client.
type LocalClientConnection struct { type LocalClientConnection struct {
asset *d2asset.AssetManager
clientListener d2networking.ClientListener // The game client clientListener d2networking.ClientListener // The game client
uniqueID string // Unique ID generated on construction uniqueID string // Unique ID generated on construction
openNetworkServer bool // True if this is a server openNetworkServer bool // True if this is a server
@ -38,8 +40,9 @@ func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket)
// Create constructs a new LocalClientConnection and returns // Create constructs a new LocalClientConnection and returns
// a pointer to it. // a pointer to it.
func Create(openNetworkServer bool) *LocalClientConnection { func Create(asset *d2asset.AssetManager, openNetworkServer bool) *LocalClientConnection {
result := &LocalClientConnection{ result := &LocalClientConnection{
asset: asset,
uniqueID: uuid.NewV4().String(), uniqueID: uuid.NewV4().String(),
openNetworkServer: openNetworkServer, openNetworkServer: openNetworkServer,
} }
@ -53,7 +56,7 @@ func (l *LocalClientConnection) Open(_, saveFilePath string) error {
l.SetPlayerState(d2player.LoadPlayerState(saveFilePath)) l.SetPlayerState(d2player.LoadPlayerState(saveFilePath))
l.gameServer, err = d2server.NewGameServer(l.openNetworkServer, 30) l.gameServer, err = d2server.NewGameServer(l.asset, l.openNetworkServer, 30)
if err != nil { if err != nil {
return err return err
} }

View File

@ -5,6 +5,8 @@ import (
"log" "log"
"os" "os"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
@ -31,6 +33,7 @@ const (
type GameClient struct { type GameClient struct {
clientConnection ServerConnection // Abstract local/remote connection clientConnection ServerConnection // Abstract local/remote connection
connectionType d2clientconnectiontype.ClientConnectionType // Type of connection (local or remote) connectionType d2clientconnectiontype.ClientConnectionType // Type of connection (local or remote)
asset *d2asset.AssetManager
scriptEngine *d2script.ScriptEngine scriptEngine *d2script.ScriptEngine
GameState *d2player.PlayerState // local player state GameState *d2player.PlayerState // local player state
MapEngine *d2mapengine.MapEngine // Map and entities MapEngine *d2mapengine.MapEngine // Map and entities
@ -41,9 +44,11 @@ type GameClient struct {
} }
// Create constructs a new GameClient and returns a pointer to it. // Create constructs a new GameClient and returns a pointer to it.
func Create(connectionType d2clientconnectiontype.ClientConnectionType, scriptEngine *d2script.ScriptEngine) (*GameClient, error) { func Create(connectionType d2clientconnectiontype.ClientConnectionType,
asset *d2asset.AssetManager, scriptEngine *d2script.ScriptEngine) (*GameClient, error) {
result := &GameClient{ result := &GameClient{
MapEngine: d2mapengine.CreateMapEngine(), // TODO: Mapgen - Needs levels.txt stuff asset: asset,
MapEngine: d2mapengine.CreateMapEngine(asset), // TODO: Mapgen - Needs levels.txt stuff
Players: make(map[string]*d2mapentity.Player), Players: make(map[string]*d2mapentity.Player),
connectionType: connectionType, connectionType: connectionType,
scriptEngine: scriptEngine, scriptEngine: scriptEngine,
@ -53,9 +58,9 @@ func Create(connectionType d2clientconnectiontype.ClientConnectionType, scriptEn
case d2clientconnectiontype.LANClient: case d2clientconnectiontype.LANClient:
result.clientConnection = d2remoteclient.Create() result.clientConnection = d2remoteclient.Create()
case d2clientconnectiontype.LANServer: case d2clientconnectiontype.LANServer:
result.clientConnection = d2localclient.Create(true) result.clientConnection = d2localclient.Create(asset, true)
case d2clientconnectiontype.Local: case d2clientconnectiontype.Local:
result.clientConnection = d2localclient.Create(false) result.clientConnection = d2localclient.Create(asset, false)
default: default:
return nil, fmt.Errorf("unknown client connection type specified: %d", connectionType) return nil, fmt.Errorf("unknown client connection type specified: %d", connectionType)
} }
@ -180,7 +185,7 @@ func (g *GameClient) handleAddPlayerPacket(packet d2netpacket.NetPacket) error {
return err return err
} }
newPlayer := d2mapentity.NewPlayer(player.ID, player.Name, player.X, player.Y, 0, newPlayer := g.MapEngine.NewPlayer(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
@ -195,7 +200,7 @@ func (g *GameClient) handleSpawnItemPacket(packet d2netpacket.NetPacket) error {
return err return err
} }
itemEntity, err := d2mapentity.NewItem(item.X, item.Y, item.Codes...) itemEntity, err := g.MapEngine.NewItem(item.X, item.Y, item.Codes...)
if err == nil { if err == nil {
g.MapEngine.AddEntity(itemEntity) g.MapEngine.AddEntity(itemEntity)
@ -255,7 +260,7 @@ func (g *GameClient) handleCastSkillPacket(packet d2netpacket.NetPacket) error {
player.ClearPath() player.ClearPath()
// currently hardcoded to missile skill // currently hardcoded to missile skill
missile, err := d2mapentity.NewMissile( missile, err := g.MapEngine.NewMissile(
int(player.Position.X()), int(player.Position.X()),
int(player.Position.Y()), int(player.Position.Y()),
d2datadict.Missiles[playerCast.SkillID], d2datadict.Missiles[playerCast.SkillID],

View File

@ -13,6 +13,7 @@ import (
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket" "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
@ -42,6 +43,7 @@ type GameServer struct {
networkServer bool networkServer bool
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
asset *d2asset.AssetManager
mapEngines []*d2mapengine.MapEngine mapEngines []*d2mapengine.MapEngine
scriptEngine *d2script.ScriptEngine scriptEngine *d2script.ScriptEngine
seed int64 seed int64
@ -57,7 +59,9 @@ var singletonServer *GameServer
// ctx: required context item // ctx: required context item
// networkServer: true = 0.0.0.0 | false = 127.0.0.1 // networkServer: true = 0.0.0.0 | false = 127.0.0.1
// maxConnections (default: 8): maximum number of TCP connections allowed open // maxConnections (default: 8): maximum number of TCP connections allowed open
func NewGameServer(networkServer bool, maxConnections ...int) (*GameServer, error) { func NewGameServer(asset *d2asset.AssetManager, networkServer bool,
maxConnections ...int) (*GameServer,
error) {
if len(maxConnections) == 0 { if len(maxConnections) == 0 {
maxConnections = []int{8} maxConnections = []int{8}
} }
@ -67,6 +71,7 @@ func NewGameServer(networkServer bool, maxConnections ...int) (*GameServer, erro
gameServer := &GameServer{ gameServer := &GameServer{
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
asset: asset,
connections: make(map[string]ClientConnection), connections: make(map[string]ClientConnection),
networkServer: networkServer, networkServer: networkServer,
maxConnections: maxConnections[0], maxConnections: maxConnections[0],
@ -78,7 +83,7 @@ func NewGameServer(networkServer bool, maxConnections ...int) (*GameServer, erro
// TODO: In order to support dedicated mode we need to load the levels txt and files. Revisit this once this we can // TODO: In order to support dedicated mode we need to load the levels txt and files. Revisit this once this we can
// load files independent of the app. // load files independent of the app.
mapEngine := d2mapengine.CreateMapEngine() mapEngine := d2mapengine.CreateMapEngine(asset)
mapEngine.SetSeed(gameServer.seed) mapEngine.SetSeed(gameServer.seed)
mapEngine.ResetMap(d2enum.RegionAct1Town, 100, 100) // TODO: Mapgen - Needs levels.txt stuff mapEngine.ResetMap(d2enum.RegionAct1Town, 100, 100) // TODO: Mapgen - Needs levels.txt stuff
d2mapgen.GenerateAct1Overworld(mapEngine) d2mapgen.GenerateAct1Overworld(mapEngine)

14
main.go
View File

@ -4,6 +4,7 @@ import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2app" "github.com/OpenDiablo2/OpenDiablo2/d2app"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
ebiten2 "github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio/ebiten" ebiten2 "github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
@ -28,13 +29,18 @@ func main() {
panic(err) panic(err)
} }
// Initialize our providers // NewAssetManager our providers
renderer, err := ebiten.CreateRenderer() renderer, err := ebiten.CreateRenderer()
if err != nil { if err != nil {
panic(err) panic(err)
} }
audio, err := ebiten2.CreateAudio() asset, err := d2asset.NewAssetManager(renderer, nil)
if err != nil {
panic(err)
}
audio, err := ebiten2.CreateAudio(asset)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -46,9 +52,11 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
asset.BindTerminalCommands(term)
scriptEngine := d2script.CreateScriptEngine() scriptEngine := d2script.CreateScriptEngine()
app := d2app.Create(GitBranch, GitCommit, inputManager, term, scriptEngine, audio, renderer) app := d2app.Create(GitBranch, GitCommit, inputManager, term, scriptEngine, audio, renderer, asset)
if err := app.Run(); err != nil { if err := app.Run(); err != nil {
log.Fatal(err) log.Fatal(err)
} }