mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-12-24 11:06:51 -05:00
High level resource caching; resource cleanup (#264)
* Work on resource loading * Use new material flag name. (#261) Update ebiten ref while at it * Hopefully fix CI (#262) * Don't try to copy config.json on travis (#263) I doesn't exist anymore * Update D2Shared references * Fix character selection rect Co-authored-by: Ziemas <ziemas@ziemas.se>
This commit is contained in:
parent
29c5839876
commit
1b03e691b9
255
d2asset/animation.go
Normal file
255
d2asset/animation.go
Normal file
@ -0,0 +1,255 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type playMode int
|
||||
|
||||
const (
|
||||
playModePause playMode = iota
|
||||
playModeForward
|
||||
playModeBackward
|
||||
)
|
||||
|
||||
type animationFrame struct {
|
||||
width int
|
||||
height int
|
||||
offsetX int
|
||||
offsetY int
|
||||
|
||||
image *ebiten.Image
|
||||
}
|
||||
|
||||
type animationDirection struct {
|
||||
frames []*animationFrame
|
||||
}
|
||||
|
||||
type Animation struct {
|
||||
directions []*animationDirection
|
||||
frameIndex int
|
||||
directionIndex int
|
||||
lastFrameTime float64
|
||||
|
||||
compositeMode ebiten.CompositeMode
|
||||
colorMod color.Color
|
||||
|
||||
playMode playMode
|
||||
playLength float64
|
||||
playLoop bool
|
||||
}
|
||||
|
||||
func createAnimationFromDC6(dc6 *d2dc6.DC6File) (*Animation, error) {
|
||||
animation := &Animation{
|
||||
playLength: 1.0,
|
||||
playLoop: true,
|
||||
}
|
||||
|
||||
for frameIndex, frame := range dc6.Frames {
|
||||
image, err := ebiten.NewImage(int(frame.Width), int(frame.Height), ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := image.ReplacePixels(frame.ColorData()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
directionIndex := frameIndex / int(dc6.FramesPerDirection)
|
||||
if directionIndex >= len(animation.directions) {
|
||||
animation.directions = append(animation.directions, new(animationDirection))
|
||||
}
|
||||
|
||||
direction := animation.directions[directionIndex]
|
||||
direction.frames = append(direction.frames, &animationFrame{
|
||||
width: int(frame.Width),
|
||||
height: int(frame.Height),
|
||||
offsetX: int(frame.OffsetX),
|
||||
offsetY: int(frame.OffsetY),
|
||||
image: image,
|
||||
})
|
||||
}
|
||||
|
||||
return animation, nil
|
||||
}
|
||||
|
||||
func (a *Animation) clone() *Animation {
|
||||
animation := *a
|
||||
return &animation
|
||||
}
|
||||
|
||||
func (a *Animation) Advance(elapsed float64) error {
|
||||
if a.playMode == playModePause {
|
||||
return nil
|
||||
}
|
||||
|
||||
frameCount := a.GetFrameCount()
|
||||
frameLength := a.playLength / float64(frameCount)
|
||||
a.lastFrameTime += elapsed
|
||||
framesAdvanced := int(a.lastFrameTime / frameLength)
|
||||
a.lastFrameTime -= float64(framesAdvanced) * frameLength
|
||||
|
||||
for i := 0; i < framesAdvanced; i++ {
|
||||
switch a.playMode {
|
||||
case playModeForward:
|
||||
a.frameIndex++
|
||||
if a.frameIndex >= frameCount {
|
||||
if a.playLoop {
|
||||
a.frameIndex = 0
|
||||
} else {
|
||||
a.frameIndex = frameCount - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
case playModeBackward:
|
||||
a.frameIndex--
|
||||
if a.frameIndex < 0 {
|
||||
if a.playLoop {
|
||||
a.frameIndex = frameCount - 1
|
||||
} else {
|
||||
a.frameIndex = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Animation) Render(target *ebiten.Image, offsetX, offsetY int) error {
|
||||
direction := a.directions[a.directionIndex]
|
||||
frame := direction.frames[a.frameIndex]
|
||||
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
opts.GeoM.Translate(float64(frame.offsetX+offsetX), float64(frame.offsetY+offsetY))
|
||||
opts.CompositeMode = a.compositeMode
|
||||
if a.colorMod != nil {
|
||||
opts.ColorM = d2corehelper.ColorToColorM(a.colorMod)
|
||||
}
|
||||
|
||||
return target.DrawImage(frame.image, opts)
|
||||
}
|
||||
|
||||
func (a *Animation) GetFrameSize(frameIndex int) (int, int, error) {
|
||||
direction := a.directions[a.directionIndex]
|
||||
if frameIndex >= len(direction.frames) {
|
||||
return 0, 0, errors.New("invalid frame index")
|
||||
}
|
||||
|
||||
frame := direction.frames[frameIndex]
|
||||
return frame.width, frame.height, nil
|
||||
}
|
||||
|
||||
func (a *Animation) GetCurrentFrameSize() (int, int) {
|
||||
width, height, _ := a.GetFrameSize(a.frameIndex)
|
||||
return width, height
|
||||
}
|
||||
|
||||
func (a *Animation) GetFrameBounds() (int, int) {
|
||||
maxWidth, maxHeight := 0, 0
|
||||
|
||||
direction := a.directions[a.directionIndex]
|
||||
for _, frame := range direction.frames {
|
||||
maxWidth = d2helper.MaxInt(maxWidth, frame.width)
|
||||
maxHeight = d2helper.MaxInt(maxHeight, frame.height)
|
||||
}
|
||||
|
||||
return maxWidth, maxHeight
|
||||
}
|
||||
|
||||
func (a *Animation) GetCurrentFrame() int {
|
||||
return a.frameIndex
|
||||
}
|
||||
|
||||
func (a *Animation) GetFrameCount() int {
|
||||
direction := a.directions[a.directionIndex]
|
||||
return len(direction.frames)
|
||||
}
|
||||
|
||||
func (a *Animation) IsOnFirstFrame() bool {
|
||||
return a.frameIndex == 0
|
||||
}
|
||||
|
||||
func (a *Animation) IsOnLastFrame() bool {
|
||||
return a.frameIndex == a.GetFrameCount()-1
|
||||
}
|
||||
|
||||
func (a *Animation) GetDirectionCount() int {
|
||||
return len(a.directions)
|
||||
}
|
||||
|
||||
func (a *Animation) SetDirection(directionIndex int) error {
|
||||
if directionIndex >= len(a.directions) {
|
||||
return errors.New("invalid direction index")
|
||||
}
|
||||
|
||||
a.directionIndex = directionIndex
|
||||
a.frameIndex = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Animation) GetDirection() int {
|
||||
return a.directionIndex
|
||||
}
|
||||
|
||||
func (a *Animation) SetCurrentFrame(frameIndex int) error {
|
||||
if frameIndex >= a.GetFrameCount() {
|
||||
return errors.New("invalid frame index")
|
||||
}
|
||||
|
||||
a.frameIndex = frameIndex
|
||||
a.lastFrameTime = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Animation) Rewind() {
|
||||
a.SetCurrentFrame(0)
|
||||
}
|
||||
|
||||
func (a *Animation) PlayForward() {
|
||||
a.playMode = playModeForward
|
||||
a.lastFrameTime = 0
|
||||
}
|
||||
|
||||
func (a *Animation) PlayBackward() {
|
||||
a.playMode = playModeBackward
|
||||
a.lastFrameTime = 0
|
||||
}
|
||||
|
||||
func (a *Animation) Pause() {
|
||||
a.playMode = playModePause
|
||||
a.lastFrameTime = 0
|
||||
}
|
||||
|
||||
func (a *Animation) SetPlayLoop(loop bool) {
|
||||
a.playLoop = true
|
||||
}
|
||||
|
||||
func (a *Animation) SetPlayLength(playLength float64) {
|
||||
a.playLength = playLength
|
||||
a.lastFrameTime = 0
|
||||
}
|
||||
|
||||
func (a *Animation) SetPlayLengthMs(playLengthMs int) {
|
||||
a.SetPlayLength(float64(playLengthMs) / 1000.0)
|
||||
}
|
||||
|
||||
func (a *Animation) SetColorMod(color color.Color) {
|
||||
a.colorMod = color
|
||||
}
|
||||
|
||||
func (a *Animation) SetBlend(blend bool) {
|
||||
if blend {
|
||||
a.compositeMode = ebiten.CompositeModeLighter
|
||||
} else {
|
||||
a.compositeMode = ebiten.CompositeModeSourceOver
|
||||
}
|
||||
}
|
29
d2asset/animation_manager.go
Normal file
29
d2asset/animation_manager.go
Normal file
@ -0,0 +1,29 @@
|
||||
package d2asset
|
||||
|
||||
type animationManager struct {
|
||||
cache *cache
|
||||
}
|
||||
|
||||
func createAnimationManager() *animationManager {
|
||||
return &animationManager{cache: createCache(AnimationBudget)}
|
||||
}
|
||||
|
||||
func (sm *animationManager) loadAnimation(animationPath, palettePath string) (*Animation, error) {
|
||||
cachePath := animationPath + palettePath
|
||||
if animation, found := sm.cache.retrieve(cachePath); found {
|
||||
return animation.(*Animation).clone(), nil
|
||||
}
|
||||
|
||||
dc6, err := loadDC6(animationPath, palettePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
animation, err := createAnimationFromDC6(dc6)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sm.cache.insert(cachePath, animation.clone(), 1)
|
||||
return animation, err
|
||||
}
|
83
d2asset/archive_manager.go
Normal file
83
d2asset/archive_manager.go
Normal file
@ -0,0 +1,83 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2mpq"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
||||
)
|
||||
|
||||
type archiveEntry struct {
|
||||
archivePath string
|
||||
hashEntryMap d2mpq.HashEntryMap
|
||||
}
|
||||
|
||||
type archiveManager struct {
|
||||
cache *cache
|
||||
config *d2corecommon.Configuration
|
||||
entries []archiveEntry
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func createArchiveManager(config *d2corecommon.Configuration) *archiveManager {
|
||||
return &archiveManager{cache: createCache(ArchiveBudget), config: config}
|
||||
}
|
||||
|
||||
func (am *archiveManager) loadArchiveForFilePath(filePath string) (*d2mpq.MPQ, error) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
if err := am.cacheArchiveEntries(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, archiveEntry := range am.entries {
|
||||
if archiveEntry.hashEntryMap.Contains(filePath) {
|
||||
return am.loadArchive(archiveEntry.archivePath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("file not found: %s", filePath)
|
||||
}
|
||||
|
||||
func (am *archiveManager) loadArchive(archivePath string) (*d2mpq.MPQ, error) {
|
||||
if archive, found := am.cache.retrieve(archivePath); found {
|
||||
return archive.(*d2mpq.MPQ), nil
|
||||
}
|
||||
|
||||
archive, err := d2mpq.Load(archivePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := am.cache.insert(archivePath, archive, int(archive.Data.ArchiveSize)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return archive, nil
|
||||
}
|
||||
|
||||
func (am *archiveManager) cacheArchiveEntries() error {
|
||||
if len(am.entries) == len(am.config.MpqLoadOrder) {
|
||||
return nil
|
||||
}
|
||||
|
||||
am.entries = nil
|
||||
|
||||
for _, archiveName := range am.config.MpqLoadOrder {
|
||||
archivePath := path.Join(am.config.MpqPath, archiveName)
|
||||
archive, err := am.loadArchive(archivePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
am.entries = append(
|
||||
am.entries,
|
||||
archiveEntry{archivePath, archive.HashEntryMap},
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
149
d2asset/asset_manager.go
Normal file
149
d2asset/asset_manager.go
Normal file
@ -0,0 +1,149 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2cof"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2mpq"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
||||
)
|
||||
|
||||
const (
|
||||
// In megabytes
|
||||
ArchiveBudget = 1024 * 1024 * 512
|
||||
FileBudget = 1024 * 1024 * 32
|
||||
|
||||
// In counts
|
||||
PaletteBudget = 64
|
||||
PaperdollBudget = 64
|
||||
AnimationBudget = 64
|
||||
)
|
||||
|
||||
var (
|
||||
ErrHasInit error = errors.New("asset system is already initialized")
|
||||
ErrNoInit error = errors.New("asset system is not initialized")
|
||||
)
|
||||
|
||||
type assetManager struct {
|
||||
archiveManager *archiveManager
|
||||
fileManager *fileManager
|
||||
paletteManager *paletteManager
|
||||
paperdollManager *paperdollManager
|
||||
animationManager *animationManager
|
||||
}
|
||||
|
||||
var singleton *assetManager
|
||||
|
||||
func Initialize(config *d2corecommon.Configuration) error {
|
||||
if singleton != nil {
|
||||
return ErrHasInit
|
||||
}
|
||||
|
||||
var (
|
||||
archiveManager = createArchiveManager(config)
|
||||
fileManager = createFileManager(config, archiveManager)
|
||||
paletteManager = createPaletteManager()
|
||||
paperdollManager = createPaperdollManager()
|
||||
animationManager = createAnimationManager()
|
||||
)
|
||||
|
||||
singleton = &assetManager{
|
||||
archiveManager,
|
||||
fileManager,
|
||||
paletteManager,
|
||||
paperdollManager,
|
||||
animationManager,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadArchive(archivePath string) (*d2mpq.MPQ, error) {
|
||||
if singleton == nil {
|
||||
return nil, ErrNoInit
|
||||
}
|
||||
|
||||
return singleton.archiveManager.loadArchive(archivePath)
|
||||
}
|
||||
|
||||
func LoadFile(filePath string) ([]byte, error) {
|
||||
if singleton == nil {
|
||||
return nil, ErrNoInit
|
||||
}
|
||||
|
||||
return singleton.fileManager.loadFile(filePath)
|
||||
}
|
||||
|
||||
func LoadAnimation(animationPath, palettePath string) (*Animation, error) {
|
||||
if singleton == nil {
|
||||
return nil, ErrNoInit
|
||||
}
|
||||
|
||||
return singleton.animationManager.loadAnimation(animationPath, palettePath)
|
||||
}
|
||||
|
||||
func LoadPaperdoll(object *d2datadict.ObjectLookupRecord, palettePath string) (*Paperdoll, error) {
|
||||
if singleton == nil {
|
||||
return nil, ErrNoInit
|
||||
}
|
||||
|
||||
return singleton.paperdollManager.loadPaperdoll(object, palettePath)
|
||||
}
|
||||
|
||||
// TODO: remove transitional usage pattern
|
||||
func MustLoadFile(filePath string) []byte {
|
||||
data, err := LoadFile(filePath)
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func loadPalette(palettePath string) (*d2datadict.PaletteRec, error) {
|
||||
if singleton == nil {
|
||||
return nil, ErrNoInit
|
||||
}
|
||||
|
||||
return singleton.paletteManager.loadPalette(palettePath)
|
||||
}
|
||||
|
||||
func loadDC6(dc6Path, palettePath string) (*d2dc6.DC6File, error) {
|
||||
dc6Data, err := LoadFile(dc6Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paletteData, err := loadPalette(palettePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc6, err := d2dc6.LoadDC6(dc6Data, *paletteData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dc6, nil
|
||||
}
|
||||
|
||||
func LoadDCC(dccPath string) (*d2dcc.DCC, error) {
|
||||
dccData, err := LoadFile(dccPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d2dcc.LoadDCC(dccData)
|
||||
}
|
||||
|
||||
func LoadCOF(cofPath string) (*d2cof.COF, error) {
|
||||
cofData, err := LoadFile(cofPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d2cof.LoadCOF(cofData)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package d2core
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"errors"
|
56
d2asset/file_manager.go
Normal file
56
d2asset/file_manager.go
Normal file
@ -0,0 +1,56 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
||||
)
|
||||
|
||||
type fileManager struct {
|
||||
cache *cache
|
||||
archiveManager *archiveManager
|
||||
config *d2corecommon.Configuration
|
||||
}
|
||||
|
||||
func createFileManager(config *d2corecommon.Configuration, archiveManager *archiveManager) *fileManager {
|
||||
return &fileManager{createCache(FileBudget), archiveManager, config}
|
||||
}
|
||||
|
||||
func (fm *fileManager) loadFile(filePath string) ([]byte, error) {
|
||||
filePath = fm.fixupFilePath(filePath)
|
||||
if value, found := fm.cache.retrieve(filePath); found {
|
||||
return value.([]byte), nil
|
||||
}
|
||||
|
||||
archive, err := fm.archiveManager.loadArchiveForFilePath(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := archive.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := fm.cache.insert(filePath, data, len(data)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (fm *fileManager) fixupFilePath(filePath string) string {
|
||||
filePath = strings.ReplaceAll(filePath, "{LANG}", fm.config.Language)
|
||||
if strings.ToUpper(d2resource.LanguageCode) == "CHI" {
|
||||
filePath = strings.ReplaceAll(filePath, "{LANG_FONT}", fm.config.Language)
|
||||
} else {
|
||||
filePath = strings.ReplaceAll(filePath, "{LANG_FONT}", "latin")
|
||||
}
|
||||
|
||||
filePath = strings.ToLower(filePath)
|
||||
filePath = strings.ReplaceAll(filePath, `/`, "\\")
|
||||
filePath = strings.TrimPrefix(filePath, "\\")
|
||||
|
||||
return filePath
|
||||
}
|
28
d2asset/palette_manager.go
Normal file
28
d2asset/palette_manager.go
Normal file
@ -0,0 +1,28 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
)
|
||||
|
||||
type paletteManager struct {
|
||||
cache *cache
|
||||
}
|
||||
|
||||
func createPaletteManager() *paletteManager {
|
||||
return &paletteManager{createCache(PaletteBudget)}
|
||||
}
|
||||
|
||||
func (pm *paletteManager) loadPalette(palettePath string) (*d2datadict.PaletteRec, error) {
|
||||
if palette, found := pm.cache.retrieve(palettePath); found {
|
||||
return palette.(*d2datadict.PaletteRec), nil
|
||||
}
|
||||
|
||||
paletteData, err := LoadFile(palettePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
palette := d2datadict.CreatePalette("", paletteData)
|
||||
pm.cache.insert(palettePath, &palette, 1)
|
||||
return &palette, nil
|
||||
}
|
302
d2asset/paperdoll.go
Normal file
302
d2asset/paperdoll.go
Normal file
@ -0,0 +1,302 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type paperdollCacheEntry struct {
|
||||
sheetImage *ebiten.Image
|
||||
compositeMode ebiten.CompositeMode
|
||||
width int
|
||||
height int
|
||||
offsetX int
|
||||
offsetY int
|
||||
}
|
||||
|
||||
type Paperdoll struct {
|
||||
object *d2datadict.ObjectLookupRecord
|
||||
palette *d2datadict.PaletteRec
|
||||
|
||||
mode *paperdollMode
|
||||
}
|
||||
|
||||
func createPaperdoll(object *d2datadict.ObjectLookupRecord, palette *d2datadict.PaletteRec) *Paperdoll {
|
||||
return &Paperdoll{object: object, palette: palette}
|
||||
}
|
||||
|
||||
func (p *Paperdoll) Render(target *ebiten.Image, offsetX, offsetY int) {
|
||||
if p.mode == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if p.mode.animationSpeed > 0 {
|
||||
frameTime := d2helper.Now()
|
||||
framesToAdd := int(math.Floor((frameTime - p.mode.lastFrameTime) / p.mode.animationSpeed))
|
||||
if framesToAdd > 0 {
|
||||
p.mode.lastFrameTime += p.mode.animationSpeed * float64(framesToAdd)
|
||||
p.mode.currentFrame = (p.mode.currentFrame + framesToAdd) % p.mode.frameCount
|
||||
}
|
||||
}
|
||||
|
||||
for _, layerIndex := range p.mode.drawOrder[p.mode.currentFrame] {
|
||||
cacheEntry := p.mode.layerCache[layerIndex]
|
||||
|
||||
x := float64(offsetX) + float64(p.mode.layerCache[layerIndex].offsetX)
|
||||
y := float64(offsetY) + float64(p.mode.layerCache[layerIndex].offsetY)
|
||||
|
||||
sheetOffset := cacheEntry.width * p.mode.currentFrame
|
||||
sheetRect := image.Rect(sheetOffset, 0, sheetOffset+cacheEntry.width, cacheEntry.height)
|
||||
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
opts.GeoM.Translate(x, y)
|
||||
opts.CompositeMode = cacheEntry.compositeMode
|
||||
target.DrawImage(cacheEntry.sheetImage.SubImage(sheetRect).(*ebiten.Image), opts)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Paperdoll) SetMode(animationMode, weaponClass string, direction int) error {
|
||||
mode, err := p.createMode(animationMode, weaponClass, direction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.mode = mode
|
||||
return nil
|
||||
}
|
||||
|
||||
type paperdollMode struct {
|
||||
animationMode string
|
||||
weaponClass string
|
||||
direction int
|
||||
|
||||
layers []*d2dcc.DCC
|
||||
layerCache []*paperdollCacheEntry
|
||||
drawOrder [][]d2enum.CompositeType
|
||||
|
||||
frameCount int
|
||||
animationSpeed float64
|
||||
currentFrame int
|
||||
lastFrameTime float64
|
||||
}
|
||||
|
||||
func (p *Paperdoll) createMode(animationMode, weaponClass string, direction int) (*paperdollMode, error) {
|
||||
mode := &paperdollMode{
|
||||
animationMode: animationMode,
|
||||
weaponClass: weaponClass,
|
||||
direction: direction,
|
||||
}
|
||||
|
||||
cofPath := fmt.Sprintf(
|
||||
"%s/%s/COF/%s%s%s.COF",
|
||||
p.object.Base,
|
||||
p.object.Token,
|
||||
p.object.Token,
|
||||
mode.animationMode,
|
||||
mode.weaponClass,
|
||||
)
|
||||
|
||||
cof, err := LoadCOF(cofPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if mode.direction >= cof.NumberOfDirections {
|
||||
return nil, errors.New("invalid direction")
|
||||
}
|
||||
|
||||
mode.layers = make([]*d2dcc.DCC, d2enum.CompositeTypeMax)
|
||||
for _, cofLayer := range cof.CofLayers {
|
||||
var layerKey, layerValue string
|
||||
switch cofLayer.Type {
|
||||
case d2enum.CompositeTypeHead:
|
||||
layerKey = "HD"
|
||||
layerValue = p.object.HD
|
||||
case d2enum.CompositeTypeTorso:
|
||||
layerKey = "TR"
|
||||
layerValue = p.object.TR
|
||||
case d2enum.CompositeTypeLegs:
|
||||
layerKey = "LG"
|
||||
layerValue = p.object.LG
|
||||
case d2enum.CompositeTypeRightArm:
|
||||
layerKey = "RA"
|
||||
layerValue = p.object.RA
|
||||
case d2enum.CompositeTypeLeftArm:
|
||||
layerKey = "LA"
|
||||
layerValue = p.object.LA
|
||||
case d2enum.CompositeTypeRightHand:
|
||||
layerKey = "RH"
|
||||
layerValue = p.object.RH
|
||||
case d2enum.CompositeTypeLeftHand:
|
||||
layerKey = "LH"
|
||||
layerValue = p.object.LH
|
||||
case d2enum.CompositeTypeShield:
|
||||
layerKey = "SH"
|
||||
layerValue = p.object.SH
|
||||
case d2enum.CompositeTypeSpecial1:
|
||||
layerKey = "S1"
|
||||
layerValue = p.object.S1
|
||||
case d2enum.CompositeTypeSpecial2:
|
||||
layerKey = "S2"
|
||||
layerValue = p.object.S2
|
||||
case d2enum.CompositeTypeSpecial3:
|
||||
layerKey = "S3"
|
||||
layerValue = p.object.S3
|
||||
case d2enum.CompositeTypeSpecial4:
|
||||
layerKey = "S4"
|
||||
layerValue = p.object.S4
|
||||
case d2enum.CompositeTypeSpecial5:
|
||||
layerKey = "S5"
|
||||
layerValue = p.object.S5
|
||||
case d2enum.CompositeTypeSpecial6:
|
||||
layerKey = "S6"
|
||||
layerValue = p.object.S6
|
||||
case d2enum.CompositeTypeSpecial7:
|
||||
layerKey = "S7"
|
||||
layerValue = p.object.S7
|
||||
case d2enum.CompositeTypeSpecial8:
|
||||
layerKey = "S8"
|
||||
layerValue = p.object.S8
|
||||
default:
|
||||
return nil, errors.New("unknown layer type")
|
||||
}
|
||||
|
||||
layerPath := fmt.Sprintf(
|
||||
"%s/%s/%s/%s%s%s%s%s.dcc",
|
||||
p.object.Base,
|
||||
p.object.Token,
|
||||
layerKey,
|
||||
p.object.Token,
|
||||
layerKey,
|
||||
layerValue,
|
||||
mode.animationMode,
|
||||
mode.weaponClass,
|
||||
)
|
||||
|
||||
dcc, err := LoadDCC(layerPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode.layers[cofLayer.Type] = dcc
|
||||
}
|
||||
|
||||
animationKey := strings.ToLower(p.object.Token + mode.animationMode + mode.weaponClass)
|
||||
animationData := d2data.AnimationData[animationKey]
|
||||
if len(animationData) == 0 {
|
||||
return nil, errors.New("could not find animation data")
|
||||
}
|
||||
|
||||
mode.animationSpeed = 1.0 / ((float64(animationData[0].AnimationSpeed) * 25.0) / 256.0)
|
||||
mode.lastFrameTime = d2helper.Now()
|
||||
mode.frameCount = animationData[0].FramesPerDirection
|
||||
|
||||
var dccDirection int
|
||||
switch cof.NumberOfDirections {
|
||||
case 4:
|
||||
dccDirection = d2dcc.CofToDir4[mode.direction]
|
||||
case 8:
|
||||
dccDirection = d2dcc.CofToDir8[mode.direction]
|
||||
case 16:
|
||||
dccDirection = d2dcc.CofToDir16[mode.direction]
|
||||
case 32:
|
||||
dccDirection = d2dcc.CofToDir32[mode.direction]
|
||||
}
|
||||
|
||||
mode.drawOrder = make([][]d2enum.CompositeType, mode.frameCount)
|
||||
for frame := 0; frame < mode.frameCount; frame++ {
|
||||
mode.drawOrder[frame] = cof.Priority[direction][frame]
|
||||
}
|
||||
|
||||
mode.layerCache = make([]*paperdollCacheEntry, d2enum.CompositeTypeMax)
|
||||
for _, cofLayer := range cof.CofLayers {
|
||||
layer := mode.layers[cofLayer.Type]
|
||||
|
||||
minX, minY := math.MaxInt32, math.MaxInt32
|
||||
maxX, maxY := math.MinInt32, math.MinInt32
|
||||
for _, frame := range layer.Directions[dccDirection].Frames {
|
||||
minX = d2helper.MinInt(minX, frame.Box.Left)
|
||||
minY = d2helper.MinInt(minY, frame.Box.Top)
|
||||
maxX = d2helper.MaxInt(maxX, frame.Box.Right())
|
||||
maxY = d2helper.MaxInt(maxY, frame.Box.Bottom())
|
||||
}
|
||||
|
||||
cacheEntry := &paperdollCacheEntry{
|
||||
offsetX: minX,
|
||||
offsetY: minY,
|
||||
width: maxX - minX,
|
||||
height: maxY - minY,
|
||||
}
|
||||
|
||||
if cacheEntry.width <= 0 || cacheEntry.height <= 0 {
|
||||
return nil, errors.New("invalid animation size")
|
||||
}
|
||||
|
||||
var transparency int
|
||||
if cofLayer.Transparent {
|
||||
switch cofLayer.DrawEffect {
|
||||
case d2enum.DrawEffectPctTransparency25:
|
||||
transparency = 64
|
||||
case d2enum.DrawEffectPctTransparency50:
|
||||
transparency = 128
|
||||
case d2enum.DrawEffectPctTransparency75:
|
||||
transparency = 192
|
||||
case d2enum.DrawEffectModulate:
|
||||
cacheEntry.compositeMode = ebiten.CompositeModeLighter
|
||||
default:
|
||||
transparency = 255
|
||||
}
|
||||
}
|
||||
|
||||
pixels := make([]byte, mode.frameCount*cacheEntry.width*cacheEntry.height*4)
|
||||
|
||||
for i := 0; i < mode.frameCount; i++ {
|
||||
direction := layer.Directions[dccDirection]
|
||||
if i >= len(direction.Frames) {
|
||||
return nil, errors.New("invalid animation index")
|
||||
}
|
||||
|
||||
sheetOffset := cacheEntry.width * i
|
||||
sheetWidth := cacheEntry.height * mode.frameCount
|
||||
|
||||
frame := direction.Frames[i]
|
||||
for y := 0; y < direction.Box.Height; y++ {
|
||||
for x := 0; x < direction.Box.Width; x++ {
|
||||
if paletteIndex := frame.PixelData[x+(y*direction.Box.Width)]; paletteIndex != 0 {
|
||||
color := p.palette.Colors[paletteIndex]
|
||||
frameX := (x + direction.Box.Left) - minX
|
||||
frameY := (y + direction.Box.Top) - minY
|
||||
offset := (sheetOffset + frameX + (frameY * sheetWidth)) * 4
|
||||
pixels[offset] = color.R
|
||||
pixels[offset+1] = color.G
|
||||
pixels[offset+2] = color.B
|
||||
pixels[offset+3] = byte(transparency)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacheEntry.sheetImage, err = ebiten.NewImage(cacheEntry.width*mode.frameCount, cacheEntry.height, ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cacheEntry.sheetImage.ReplacePixels(pixels); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode.layerCache[cofLayer.Type] = cacheEntry
|
||||
}
|
||||
|
||||
return mode, nil
|
||||
}
|
22
d2asset/paperdoll_manager.go
Normal file
22
d2asset/paperdoll_manager.go
Normal file
@ -0,0 +1,22 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
)
|
||||
|
||||
type paperdollManager struct {
|
||||
cache *cache
|
||||
}
|
||||
|
||||
func createPaperdollManager() *paperdollManager {
|
||||
return &paperdollManager{cache: createCache(PaperdollBudget)}
|
||||
}
|
||||
|
||||
func (pm *paperdollManager) loadPaperdoll(object *d2datadict.ObjectLookupRecord, palettePath string) (*Paperdoll, error) {
|
||||
palette, err := loadPalette(palettePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createPaperdoll(object, palette), nil
|
||||
}
|
@ -3,15 +3,13 @@ package d2audio
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/hajimehoshi/ebiten/audio"
|
||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||
)
|
||||
|
||||
// Manager provides sound
|
||||
type Manager struct {
|
||||
fileProvider d2interface.FileProvider
|
||||
audioContext *audio.Context // The Audio context
|
||||
bgmAudio *audio.Player // The audio player
|
||||
lastBgm string
|
||||
@ -20,10 +18,8 @@ type Manager struct {
|
||||
}
|
||||
|
||||
// CreateManager creates a sound provider
|
||||
func CreateManager(fileProvider d2interface.FileProvider) *Manager {
|
||||
result := &Manager{
|
||||
fileProvider: fileProvider,
|
||||
}
|
||||
func CreateManager() *Manager {
|
||||
result := &Manager{}
|
||||
audioContext, err := audio.NewContext(44100)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -49,7 +45,7 @@ func (v *Manager) PlayBGM(song string) {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
audioData := v.fileProvider.LoadFile(song)
|
||||
audioData := d2asset.MustLoadFile(song)
|
||||
d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -73,7 +69,7 @@ func (v *Manager) PlayBGM(song string) {
|
||||
}
|
||||
|
||||
func (v *Manager) LoadSoundEffect(sfx string) *SoundEffect {
|
||||
result := CreateSoundEffect(sfx, v.fileProvider, v.audioContext, v.sfxVolume)
|
||||
result := CreateSoundEffect(sfx, v.audioContext, v.sfxVolume)
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,8 @@ package d2audio
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||
|
||||
@ -16,7 +15,7 @@ type SoundEffect struct {
|
||||
player *audio.Player
|
||||
}
|
||||
|
||||
func CreateSoundEffect(sfx string, fileProvider d2interface.FileProvider, context *audio.Context, volume float64) *SoundEffect {
|
||||
func CreateSoundEffect(sfx string, context *audio.Context, volume float64) *SoundEffect {
|
||||
result := &SoundEffect{}
|
||||
var soundFile string
|
||||
if _, exists := d2datadict.Sounds[sfx]; exists {
|
||||
@ -25,7 +24,7 @@ func CreateSoundEffect(sfx string, fileProvider d2interface.FileProvider, contex
|
||||
} else {
|
||||
soundFile = sfx
|
||||
}
|
||||
audioData := fileProvider.LoadFile(soundFile)
|
||||
audioData := d2asset.MustLoadFile(soundFile)
|
||||
d, err := wav.Decode(context, audio.BytesReadSeekCloser(audioData))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,137 +0,0 @@
|
||||
package d2core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2mpq"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
||||
)
|
||||
|
||||
type archiveEntry struct {
|
||||
archivePath string
|
||||
hashEntryMap d2mpq.HashEntryMap
|
||||
}
|
||||
|
||||
type assetManager struct {
|
||||
fileCache *cache
|
||||
archiveCache *cache
|
||||
archiveEntries []archiveEntry
|
||||
config *d2corecommon.Configuration
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func createAssetManager(config *d2corecommon.Configuration) *assetManager {
|
||||
return &assetManager{
|
||||
fileCache: createCache(1024 * 1024 * 32),
|
||||
archiveCache: createCache(1024 * 1024 * 128),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (am *assetManager) LoadFile(filePath string) []byte {
|
||||
data, err := am.loadFile(am.fixupFilePath(filePath))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func (am *assetManager) loadFile(filePath string) ([]byte, error) {
|
||||
if value, found := am.fileCache.retrieve(filePath); found {
|
||||
return value.([]byte), nil
|
||||
}
|
||||
|
||||
archive, err := am.loadArchiveForFilePath(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := archive.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := am.fileCache.insert(filePath, data, len(data)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (am *assetManager) loadArchiveForFilePath(filePath string) (*d2mpq.MPQ, error) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
if err := am.cacheArchiveEntries(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, archiveEntry := range am.archiveEntries {
|
||||
if archiveEntry.hashEntryMap.Contains(filePath) {
|
||||
return am.loadArchive(archiveEntry.archivePath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("file not found: %s", filePath)
|
||||
}
|
||||
|
||||
func (am *assetManager) loadArchive(archivePath string) (*d2mpq.MPQ, error) {
|
||||
if archive, found := am.archiveCache.retrieve(archivePath); found {
|
||||
return archive.(*d2mpq.MPQ), nil
|
||||
}
|
||||
|
||||
archive, err := d2mpq.Load(archivePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := am.archiveCache.insert(archivePath, archive, int(archive.Data.ArchiveSize)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return archive, nil
|
||||
}
|
||||
|
||||
func (am *assetManager) cacheArchiveEntries() error {
|
||||
if len(am.archiveEntries) == len(am.config.MpqLoadOrder) {
|
||||
return nil
|
||||
}
|
||||
|
||||
am.archiveEntries = nil
|
||||
|
||||
for _, archiveName := range am.config.MpqLoadOrder {
|
||||
archivePath := path.Join(am.config.MpqPath, archiveName)
|
||||
archive, err := am.loadArchive(archivePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
am.archiveEntries = append(
|
||||
am.archiveEntries,
|
||||
archiveEntry{archivePath, archive.HashEntryMap},
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *assetManager) fixupFilePath(filePath string) string {
|
||||
filePath = strings.ReplaceAll(filePath, "{LANG}", am.config.Language)
|
||||
if strings.ToUpper(d2resource.LanguageCode) == "CHI" {
|
||||
filePath = strings.ReplaceAll(filePath, "{LANG_FONT}", am.config.Language)
|
||||
} else {
|
||||
filePath = strings.ReplaceAll(filePath, "{LANG_FONT}", "latin")
|
||||
}
|
||||
|
||||
filePath = strings.ToLower(filePath)
|
||||
filePath = strings.ReplaceAll(filePath, `/`, "\\")
|
||||
filePath = strings.TrimPrefix(filePath, "\\")
|
||||
|
||||
return filePath
|
||||
}
|
@ -1,23 +1,19 @@
|
||||
package d2scene
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2video"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type BlizzardIntro struct {
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
videoDecoder *d2video.BinkDecoder
|
||||
}
|
||||
|
||||
func CreateBlizzardIntro(fileProvider d2interface.FileProvider, sceneProvider d2coreinterface.SceneProvider) *BlizzardIntro {
|
||||
result := &BlizzardIntro{
|
||||
fileProvider: fileProvider,
|
||||
sceneProvider: sceneProvider,
|
||||
}
|
||||
func CreateBlizzardIntro(sceneProvider d2coreinterface.SceneProvider) *BlizzardIntro {
|
||||
result := &BlizzardIntro{sceneProvider: sceneProvider}
|
||||
|
||||
return result
|
||||
}
|
||||
@ -25,7 +21,7 @@ func CreateBlizzardIntro(fileProvider d2interface.FileProvider, sceneProvider d2
|
||||
func (v *BlizzardIntro) Load() []func() {
|
||||
return []func(){
|
||||
func() {
|
||||
videoBytes := v.fileProvider.LoadFile("/data/local/video/BlizNorth640x480.bik")
|
||||
videoBytes := d2asset.MustLoadFile("/data/local/video/BlizNorth640x480.bik")
|
||||
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
|
||||
},
|
||||
}
|
||||
|
@ -6,15 +6,10 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
@ -27,9 +22,8 @@ import (
|
||||
type CharacterSelect struct {
|
||||
uiManager *d2ui.Manager
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
background d2render.Sprite
|
||||
background *d2render.Sprite
|
||||
newCharButton d2ui.Button
|
||||
convertCharButton d2ui.Button
|
||||
deleteCharButton d2ui.Button
|
||||
@ -37,8 +31,8 @@ type CharacterSelect struct {
|
||||
okButton d2ui.Button
|
||||
deleteCharCancelButton d2ui.Button
|
||||
deleteCharOkButton d2ui.Button
|
||||
selectionBox d2render.Sprite
|
||||
okCancelBox d2render.Sprite
|
||||
selectionBox *d2render.Sprite
|
||||
okCancelBox *d2render.Sprite
|
||||
d2HeroTitle d2ui.Label
|
||||
deleteCharConfirmLabel d2ui.Label
|
||||
charScrollbar d2ui.Scrollbar
|
||||
@ -52,17 +46,11 @@ type CharacterSelect struct {
|
||||
showDeleteConfirmation bool
|
||||
}
|
||||
|
||||
func CreateCharacterSelect(
|
||||
fileProvider d2interface.FileProvider,
|
||||
sceneProvider d2coreinterface.SceneProvider,
|
||||
uiManager *d2ui.Manager,
|
||||
soundManager *d2audio.Manager,
|
||||
) *CharacterSelect {
|
||||
func CreateCharacterSelect(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *CharacterSelect {
|
||||
result := &CharacterSelect{
|
||||
selectedCharacter: -1,
|
||||
uiManager: uiManager,
|
||||
sceneProvider: sceneProvider,
|
||||
fileProvider: fileProvider,
|
||||
soundManager: soundManager,
|
||||
}
|
||||
return result
|
||||
@ -72,78 +60,75 @@ func (v *CharacterSelect) Load() []func() {
|
||||
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
||||
return []func(){
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.CharacterSelectionBackground), d2datadict.Palettes[d2enum.Sky])
|
||||
v.background = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.background.MoveTo(0, 0)
|
||||
v.background, _ = d2render.LoadSprite(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
|
||||
v.background.SetPosition(0, 0)
|
||||
},
|
||||
func() {
|
||||
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
|
||||
v.newCharButton.MoveTo(33, 468)
|
||||
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
|
||||
v.newCharButton.SetPosition(33, 468)
|
||||
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.newCharButton)
|
||||
},
|
||||
func() {
|
||||
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
|
||||
v.convertCharButton.MoveTo(233, 468)
|
||||
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
|
||||
v.convertCharButton.SetPosition(233, 468)
|
||||
v.convertCharButton.SetEnabled(false)
|
||||
v.uiManager.AddWidget(&v.convertCharButton)
|
||||
},
|
||||
func() {
|
||||
v.deleteCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15)))
|
||||
v.deleteCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15)))
|
||||
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
|
||||
v.deleteCharButton.MoveTo(433, 468)
|
||||
v.deleteCharButton.SetPosition(433, 468)
|
||||
v.uiManager.AddWidget(&v.deleteCharButton)
|
||||
},
|
||||
func() {
|
||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
|
||||
v.exitButton.MoveTo(33, 537)
|
||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
|
||||
v.exitButton.SetPosition(33, 537)
|
||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.exitButton)
|
||||
},
|
||||
func() {
|
||||
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, v.fileProvider, d2common.TranslateString("#4231"))
|
||||
v.deleteCharCancelButton.MoveTo(282, 308)
|
||||
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4231"))
|
||||
v.deleteCharCancelButton.SetPosition(282, 308)
|
||||
v.deleteCharCancelButton.SetVisible(false)
|
||||
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
|
||||
v.uiManager.AddWidget(&v.deleteCharCancelButton)
|
||||
},
|
||||
func() {
|
||||
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, v.fileProvider, d2common.TranslateString("#4227"))
|
||||
v.deleteCharOkButton.MoveTo(422, 308)
|
||||
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4227"))
|
||||
v.deleteCharOkButton.SetPosition(422, 308)
|
||||
v.deleteCharOkButton.SetVisible(false)
|
||||
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
|
||||
v.uiManager.AddWidget(&v.deleteCharOkButton)
|
||||
},
|
||||
func() {
|
||||
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971"))
|
||||
v.okButton.MoveTo(625, 537)
|
||||
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
|
||||
v.okButton.SetPosition(625, 537)
|
||||
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.okButton)
|
||||
},
|
||||
func() {
|
||||
v.d2HeroTitle = d2ui.CreateLabel(v.fileProvider, d2resource.Font42, d2enum.Units)
|
||||
v.d2HeroTitle.MoveTo(320, 23)
|
||||
v.d2HeroTitle = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
v.d2HeroTitle.SetPosition(320, 23)
|
||||
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
|
||||
},
|
||||
func() {
|
||||
v.deleteCharConfirmLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.deleteCharConfirmLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
lines := dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#1878"), 29)
|
||||
v.deleteCharConfirmLabel.SetText(strings.Join(lines, "\n"))
|
||||
v.deleteCharConfirmLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.deleteCharConfirmLabel.MoveTo(400, 185)
|
||||
v.deleteCharConfirmLabel.SetPosition(400, 185)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.CharacterSelectionSelectBox), d2datadict.Palettes[d2enum.Sky])
|
||||
v.selectionBox = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.selectionBox.MoveTo(37, 86)
|
||||
v.selectionBox, _ = d2render.LoadSprite(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
|
||||
v.selectionBox.SetPosition(37, 86)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.PopUpOkCancel), d2datadict.Palettes[d2enum.Fechar])
|
||||
v.okCancelBox = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.okCancelBox.MoveTo(270, 175)
|
||||
v.okCancelBox, _ = d2render.LoadSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||
v.okCancelBox.SetPosition(270, 175)
|
||||
},
|
||||
func() {
|
||||
v.charScrollbar = d2ui.CreateScrollbar(v.fileProvider, 586, 87, 369)
|
||||
v.charScrollbar = d2ui.CreateScrollbar(586, 87, 369)
|
||||
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
|
||||
v.uiManager.AddWidget(&v.charScrollbar)
|
||||
},
|
||||
@ -153,14 +138,14 @@ func (v *CharacterSelect) Load() []func() {
|
||||
if i&1 > 0 {
|
||||
xOffset = 385
|
||||
}
|
||||
v.characterNameLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.characterNameLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.characterNameLabel[i].Color = color.RGBA{188, 168, 140, 255}
|
||||
v.characterNameLabel[i].MoveTo(xOffset, 100+((i/2)*95))
|
||||
v.characterStatsLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.characterStatsLabel[i].MoveTo(xOffset, 115+((i/2)*95))
|
||||
v.characterExpLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Static)
|
||||
v.characterNameLabel[i].SetPosition(xOffset, 100+((i/2)*95))
|
||||
v.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
|
||||
v.characterExpLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteStatic)
|
||||
v.characterExpLabel[i].Color = color.RGBA{24, 255, 0, 255}
|
||||
v.characterExpLabel[i].MoveTo(xOffset, 130+((i/2)*95))
|
||||
v.characterExpLabel[i].SetPosition(xOffset, 130+((i/2)*95))
|
||||
}
|
||||
v.refreshGameStates()
|
||||
},
|
||||
@ -193,17 +178,16 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
||||
0,
|
||||
v.gameStates[idx].HeroType,
|
||||
d2core.HeroObjects[v.gameStates[idx].HeroType],
|
||||
v.fileProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onNewCharButtonClicked() {
|
||||
v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
|
||||
v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.sceneProvider, v.uiManager, v.soundManager))
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onExitButtonClicked() {
|
||||
mainMenu := CreateMainMenu(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)
|
||||
mainMenu := CreateMainMenu(v.sceneProvider, v.uiManager, v.soundManager)
|
||||
mainMenu.ShowTrademarkScreen = false
|
||||
v.sceneProvider.SetNextScene(mainMenu)
|
||||
}
|
||||
@ -212,26 +196,26 @@ func (v *CharacterSelect) Unload() {
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) Render(screen *ebiten.Image) {
|
||||
v.background.DrawSegments(screen, 4, 3, 0)
|
||||
v.d2HeroTitle.Draw(screen)
|
||||
v.background.RenderSegmented(screen, 4, 3, 0)
|
||||
v.d2HeroTitle.Render(screen)
|
||||
actualSelectionIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
|
||||
if v.selectedCharacter > -1 && actualSelectionIndex >= 0 && actualSelectionIndex < 8 {
|
||||
v.selectionBox.DrawSegments(screen, 2, 1, 0)
|
||||
v.selectionBox.RenderSegmented(screen, 2, 1, 0)
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
idx := i + (v.charScrollbar.GetCurrentOffset() * 2)
|
||||
if idx >= len(v.gameStates) {
|
||||
continue
|
||||
}
|
||||
v.characterNameLabel[i].Draw(screen)
|
||||
v.characterStatsLabel[i].Draw(screen)
|
||||
v.characterExpLabel[i].Draw(screen)
|
||||
v.characterNameLabel[i].Render(screen)
|
||||
v.characterStatsLabel[i].Render(screen)
|
||||
v.characterExpLabel[i].Render(screen)
|
||||
v.characterImage[i].Render(screen, v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
|
||||
}
|
||||
if v.showDeleteConfirmation {
|
||||
ebitenutil.DrawRect(screen, 0.0, 0.0, 800.0, 600.0, color.RGBA{0, 0, 0, 128})
|
||||
v.okCancelBox.DrawSegments(screen, 2, 1, 0)
|
||||
v.deleteCharConfirmLabel.Draw(screen)
|
||||
v.okCancelBox.RenderSegmented(screen, 2, 1, 0)
|
||||
v.deleteCharConfirmLabel.Render(screen)
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +227,7 @@ func (v *CharacterSelect) moveSelectionBox() {
|
||||
bw := 272
|
||||
bh := 92
|
||||
selectedIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
|
||||
v.selectionBox.MoveTo(37+((selectedIndex&1)*int(bw)), 86+(int(bh)*(selectedIndex/2)))
|
||||
v.selectionBox.SetPosition(37+((selectedIndex&1)*int(bw)), 86+(int(bh)*(selectedIndex/2)))
|
||||
v.d2HeroTitle.SetText(v.gameStates[v.selectedCharacter].HeroName)
|
||||
}
|
||||
|
||||
@ -318,5 +302,5 @@ func (v *CharacterSelect) refreshGameStates() {
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onOkButtonClicked() {
|
||||
v.sceneProvider.SetNextScene(CreateGame(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager, v.gameStates[v.selectedCharacter]))
|
||||
v.sceneProvider.SetNextScene(CreateGame(v.sceneProvider, v.uiManager, v.soundManager, v.gameStates[v.selectedCharacter]))
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package d2scene
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"image/color"
|
||||
"log"
|
||||
"os"
|
||||
@ -11,18 +10,14 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
@ -37,9 +32,8 @@ type labelItem struct {
|
||||
type Credits struct {
|
||||
uiManager *d2ui.Manager
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
creditsBackground d2render.Sprite
|
||||
creditsBackground *d2render.Sprite
|
||||
exitButton d2ui.Button
|
||||
creditsText []string
|
||||
labels []*labelItem
|
||||
@ -49,9 +43,8 @@ type Credits struct {
|
||||
}
|
||||
|
||||
// CreateCredits creates an instance of the credits scene
|
||||
func CreateCredits(fileProvider d2interface.FileProvider, sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *Credits {
|
||||
func CreateCredits(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *Credits {
|
||||
result := &Credits{
|
||||
fileProvider: fileProvider,
|
||||
uiManager: uiManager,
|
||||
soundManager: soundManager,
|
||||
sceneProvider: sceneProvider,
|
||||
@ -84,18 +77,17 @@ func (v *Credits) LoadContributors() []string {
|
||||
func (v *Credits) Load() []func() {
|
||||
return []func(){
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.CreditsBackground), d2datadict.Palettes[d2enum.Sky])
|
||||
v.creditsBackground = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.creditsBackground.MoveTo(0, 0)
|
||||
v.creditsBackground, _ = d2render.LoadSprite(d2resource.CreditsBackground, d2resource.PaletteSky)
|
||||
v.creditsBackground.SetPosition(0, 0)
|
||||
},
|
||||
func() {
|
||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
|
||||
v.exitButton.MoveTo(33, 543)
|
||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
|
||||
v.exitButton.SetPosition(33, 543)
|
||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.exitButton)
|
||||
},
|
||||
func() {
|
||||
fileData, _ := dh.Utf16BytesToString(v.fileProvider.LoadFile(d2resource.CreditsText)[2:])
|
||||
fileData, _ := dh.Utf16BytesToString(d2asset.MustLoadFile(d2resource.CreditsText)[2:])
|
||||
v.creditsText = strings.Split(fileData, "\r\n")
|
||||
for i := range v.creditsText {
|
||||
v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
|
||||
@ -112,12 +104,12 @@ func (v *Credits) Unload() {
|
||||
|
||||
// Render renders the credits scene
|
||||
func (v *Credits) Render(screen *ebiten.Image) {
|
||||
v.creditsBackground.DrawSegments(screen, 4, 3, 0)
|
||||
v.creditsBackground.RenderSegmented(screen, 4, 3, 0)
|
||||
for _, label := range v.labels {
|
||||
if label.Available {
|
||||
continue
|
||||
}
|
||||
label.Label.Draw(screen)
|
||||
label.Label.Render(screen)
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +139,7 @@ func (v *Credits) Update(tickTime float64) {
|
||||
}
|
||||
|
||||
func (v *Credits) onExitButtonClicked() {
|
||||
mainMenu := CreateMainMenu(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)
|
||||
mainMenu := CreateMainMenu(v.sceneProvider, v.uiManager, v.soundManager)
|
||||
mainMenu.ShowTrademarkScreen = false
|
||||
v.sceneProvider.SetNextScene(mainMenu)
|
||||
}
|
||||
@ -182,7 +174,7 @@ func (v *Credits) addNextItem() {
|
||||
isDoubled = true
|
||||
|
||||
// Gotta go side by side
|
||||
label.MoveTo(400-int(width), 605)
|
||||
label.SetPosition(400-int(width), 605)
|
||||
|
||||
text2 := v.creditsText[0]
|
||||
v.creditsText = v.creditsText[1:]
|
||||
@ -191,9 +183,9 @@ func (v *Credits) addNextItem() {
|
||||
label2 := v.getNewFontLabel(isHeading)
|
||||
label2.SetText(text2)
|
||||
|
||||
label2.MoveTo(410, 605)
|
||||
label2.SetPosition(410, 605)
|
||||
} else {
|
||||
label.MoveTo(405-int(width/2), 605)
|
||||
label.SetPosition(405-int(width/2), 605)
|
||||
}
|
||||
|
||||
if isHeading && isNextHeading {
|
||||
@ -227,7 +219,7 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
|
||||
newLabelItem := &labelItem{
|
||||
Available: false,
|
||||
IsHeading: isHeading,
|
||||
Label: d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal10, d2enum.Sky),
|
||||
Label: d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteSky),
|
||||
}
|
||||
|
||||
if isHeading {
|
||||
|
@ -1,11 +1,10 @@
|
||||
package d2scene
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
@ -14,17 +13,15 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
gameState *d2core.GameState
|
||||
uiManager *d2ui.Manager
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
pentSpinLeft d2render.Sprite
|
||||
pentSpinRight d2render.Sprite
|
||||
pentSpinLeft *d2render.Sprite
|
||||
pentSpinRight *d2render.Sprite
|
||||
testLabel d2ui.Label
|
||||
mapEngine *d2mapengine.MapEngine
|
||||
hero *d2core.Hero
|
||||
@ -32,7 +29,6 @@ type Game struct {
|
||||
}
|
||||
|
||||
func CreateGame(
|
||||
fileProvider d2interface.FileProvider,
|
||||
sceneProvider d2coreinterface.SceneProvider,
|
||||
uiManager *d2ui.Manager,
|
||||
soundManager *d2audio.Manager,
|
||||
@ -40,7 +36,6 @@ func CreateGame(
|
||||
) *Game {
|
||||
result := &Game{
|
||||
gameState: gameState,
|
||||
fileProvider: fileProvider,
|
||||
uiManager: uiManager,
|
||||
soundManager: soundManager,
|
||||
sceneProvider: sceneProvider,
|
||||
@ -51,28 +46,25 @@ func CreateGame(
|
||||
func (v *Game) Load() []func() {
|
||||
return []func(){
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.PentSpin), d2datadict.Palettes[d2enum.Sky])
|
||||
v.pentSpinLeft = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.pentSpinLeft.Animate = true
|
||||
v.pentSpinLeft.AnimateBackwards = true
|
||||
v.pentSpinLeft.SpecialFrameTime = 475
|
||||
v.pentSpinLeft.MoveTo(100, 300)
|
||||
v.pentSpinLeft, _ = d2render.LoadSprite(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
v.pentSpinLeft.PlayBackward()
|
||||
v.pentSpinLeft.SetPlayLengthMs(475)
|
||||
v.pentSpinLeft.SetPosition(100, 300)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.PentSpin), d2datadict.Palettes[d2enum.Sky])
|
||||
v.pentSpinRight = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.pentSpinRight.Animate = true
|
||||
v.pentSpinRight.SpecialFrameTime = 475
|
||||
v.pentSpinRight.MoveTo(650, 300)
|
||||
v.pentSpinRight, _ = d2render.LoadSprite(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
v.pentSpinRight.PlayForward()
|
||||
v.pentSpinRight.SetPlayLengthMs(475)
|
||||
v.pentSpinRight.SetPosition(650, 300)
|
||||
},
|
||||
func() {
|
||||
v.testLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font42, d2enum.Units)
|
||||
v.testLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
v.testLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.testLabel.SetText("Soon :tm:")
|
||||
v.testLabel.MoveTo(400, 250)
|
||||
v.testLabel.SetPosition(400, 250)
|
||||
},
|
||||
func() {
|
||||
v.mapEngine = d2mapengine.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
|
||||
v.mapEngine = d2mapengine.CreateMapEngine(v.gameState, v.soundManager)
|
||||
v.mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0)
|
||||
|
||||
startX, startY := v.mapEngine.GetStartPosition()
|
||||
@ -82,12 +74,11 @@ func (v *Game) Load() []func() {
|
||||
0,
|
||||
v.gameState.HeroType,
|
||||
v.gameState.Equipment,
|
||||
v.fileProvider,
|
||||
)
|
||||
v.mapEngine.AddEntity(v.hero)
|
||||
},
|
||||
func() {
|
||||
v.gameControls = d2player.NewGameControls(v.fileProvider, v.hero, v.mapEngine)
|
||||
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
|
||||
v.gameControls.Load()
|
||||
},
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package d2scene
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"image/color"
|
||||
"log"
|
||||
"os"
|
||||
@ -13,17 +12,12 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
@ -33,14 +27,13 @@ import (
|
||||
type MainMenu struct {
|
||||
uiManager *d2ui.Manager
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
trademarkBackground d2render.Sprite
|
||||
background d2render.Sprite
|
||||
diabloLogoLeft d2render.Sprite
|
||||
diabloLogoRight d2render.Sprite
|
||||
diabloLogoLeftBack d2render.Sprite
|
||||
diabloLogoRightBack d2render.Sprite
|
||||
trademarkBackground *d2render.Sprite
|
||||
background *d2render.Sprite
|
||||
diabloLogoLeft *d2render.Sprite
|
||||
diabloLogoRight *d2render.Sprite
|
||||
diabloLogoLeftBack *d2render.Sprite
|
||||
diabloLogoRightBack *d2render.Sprite
|
||||
singlePlayerButton d2ui.Button
|
||||
githubButton d2ui.Button
|
||||
exitDiabloButton d2ui.Button
|
||||
@ -58,9 +51,8 @@ type MainMenu struct {
|
||||
}
|
||||
|
||||
// CreateMainMenu creates an instance of MainMenu
|
||||
func CreateMainMenu(fileProvider d2interface.FileProvider, sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *MainMenu {
|
||||
func CreateMainMenu(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *MainMenu {
|
||||
result := &MainMenu{
|
||||
fileProvider: fileProvider,
|
||||
uiManager: uiManager,
|
||||
soundManager: soundManager,
|
||||
sceneProvider: sceneProvider,
|
||||
@ -75,111 +67,105 @@ func (v *MainMenu) Load() []func() {
|
||||
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
||||
return []func(){
|
||||
func() {
|
||||
v.versionLabel = d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal12, d2enum.Static)
|
||||
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.versionLabel.Alignment = d2ui.LabelAlignRight
|
||||
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
|
||||
v.versionLabel.Color = color.RGBA{255, 255, 255, 255}
|
||||
v.versionLabel.MoveTo(795, -10)
|
||||
v.versionLabel.SetPosition(795, -10)
|
||||
},
|
||||
func() {
|
||||
v.commitLabel = d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal10, d2enum.Static)
|
||||
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
v.commitLabel.Alignment = d2ui.LabelAlignLeft
|
||||
v.commitLabel.SetText(d2common.BuildInfo.Commit)
|
||||
v.commitLabel.Color = color.RGBA{255, 255, 255, 255}
|
||||
v.commitLabel.MoveTo(2, 2)
|
||||
v.commitLabel.SetPosition(2, 2)
|
||||
},
|
||||
func() {
|
||||
v.copyrightLabel = d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal12, d2enum.Static)
|
||||
v.copyrightLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.copyrightLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
||||
v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255}
|
||||
v.copyrightLabel.MoveTo(400, 500)
|
||||
v.copyrightLabel.SetPosition(400, 500)
|
||||
},
|
||||
func() {
|
||||
v.copyrightLabel2 = d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal12, d2enum.Static)
|
||||
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.copyrightLabel2.Alignment = d2ui.LabelAlignCenter
|
||||
v.copyrightLabel2.SetText(d2common.TranslateString("#1614"))
|
||||
v.copyrightLabel2.Color = color.RGBA{188, 168, 140, 255}
|
||||
v.copyrightLabel2.MoveTo(400, 525)
|
||||
v.copyrightLabel2.SetPosition(400, 525)
|
||||
},
|
||||
func() {
|
||||
v.openDiabloLabel = d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal10, d2enum.Static)
|
||||
v.openDiabloLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
v.openDiabloLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
|
||||
v.openDiabloLabel.Color = color.RGBA{255, 255, 140, 255}
|
||||
v.openDiabloLabel.MoveTo(400, 580)
|
||||
v.openDiabloLabel.SetPosition(400, 580)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.GameSelectScreen), d2datadict.Palettes[d2enum.Sky])
|
||||
v.background = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.background.MoveTo(0, 0)
|
||||
v.background, _ = d2render.LoadSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
|
||||
v.background.SetPosition(0, 0)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.TrademarkScreen), d2datadict.Palettes[d2enum.Sky])
|
||||
v.trademarkBackground = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.trademarkBackground.MoveTo(0, 0)
|
||||
v.trademarkBackground, _ = d2render.LoadSprite(d2resource.TrademarkScreen, d2resource.PaletteSky)
|
||||
v.trademarkBackground.SetPosition(0, 0)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoFireLeft), d2datadict.Palettes[d2enum.Units])
|
||||
v.diabloLogoLeft = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.diabloLogoLeft.Blend = true
|
||||
v.diabloLogoLeft.Animate = true
|
||||
v.diabloLogoLeft.MoveTo(400, 120)
|
||||
v.diabloLogoLeft, _ = d2render.LoadSprite(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
||||
v.diabloLogoLeft.SetBlend(true)
|
||||
v.diabloLogoLeft.PlayForward()
|
||||
v.diabloLogoLeft.SetPosition(400, 120)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoFireRight), d2datadict.Palettes[d2enum.Units])
|
||||
v.diabloLogoRight = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.diabloLogoRight.Blend = true
|
||||
v.diabloLogoRight.Animate = true
|
||||
v.diabloLogoRight.MoveTo(400, 120)
|
||||
v.diabloLogoRight, _ = d2render.LoadSprite(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
|
||||
v.diabloLogoRight.SetBlend(true)
|
||||
v.diabloLogoRight.PlayForward()
|
||||
v.diabloLogoRight.SetPosition(400, 120)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoBlackLeft), d2datadict.Palettes[d2enum.Units])
|
||||
v.diabloLogoLeftBack = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.diabloLogoLeftBack.MoveTo(400, 120)
|
||||
v.diabloLogoLeftBack, _ = d2render.LoadSprite(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
|
||||
v.diabloLogoLeftBack.SetPosition(400, 120)
|
||||
},
|
||||
func() {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoBlackRight), d2datadict.Palettes[d2enum.Units])
|
||||
v.diabloLogoRightBack = d2render.CreateSpriteFromDC6(dc6)
|
||||
v.diabloLogoRightBack.MoveTo(400, 120)
|
||||
v.diabloLogoRightBack, _ = d2render.LoadSprite(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
|
||||
v.diabloLogoRightBack.SetPosition(400, 120)
|
||||
},
|
||||
func() {
|
||||
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1625"))
|
||||
v.exitDiabloButton.MoveTo(264, 535)
|
||||
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1625"))
|
||||
v.exitDiabloButton.SetPosition(264, 535)
|
||||
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.exitDiabloButton)
|
||||
},
|
||||
func() {
|
||||
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1627"))
|
||||
v.creditsButton.MoveTo(264, 505)
|
||||
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1627"))
|
||||
v.creditsButton.SetPosition(264, 505)
|
||||
v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.creditsButton)
|
||||
},
|
||||
func() {
|
||||
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1639"))
|
||||
v.cinematicsButton.MoveTo(401, 505)
|
||||
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1639"))
|
||||
v.cinematicsButton.SetPosition(401, 505)
|
||||
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.uiManager.AddWidget(&v.cinematicsButton)
|
||||
},
|
||||
func() {
|
||||
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1620"))
|
||||
v.singlePlayerButton.MoveTo(264, 290)
|
||||
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1620"))
|
||||
v.singlePlayerButton.SetPosition(264, 290)
|
||||
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
||||
v.uiManager.AddWidget(&v.singlePlayerButton)
|
||||
},
|
||||
func() {
|
||||
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, "PROJECT WEBSITE")
|
||||
v.githubButton.MoveTo(264, 330)
|
||||
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
|
||||
v.githubButton.SetPosition(264, 330)
|
||||
v.githubButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.githubButton)
|
||||
},
|
||||
func() {
|
||||
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, "MAP ENGINE TEST")
|
||||
v.mapTestButton.MoveTo(264, 450)
|
||||
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
|
||||
v.mapTestButton.SetPosition(264, 450)
|
||||
v.mapTestButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
||||
v.uiManager.AddWidget(&v.mapTestButton)
|
||||
@ -188,7 +174,7 @@ func (v *MainMenu) Load() []func() {
|
||||
}
|
||||
|
||||
func (v *MainMenu) onMapTestClicked() {
|
||||
v.sceneProvider.SetNextScene(CreateMapEngineTest(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager, 0, 1))
|
||||
v.sceneProvider.SetNextScene(CreateMapEngineTest(v.sceneProvider, v.uiManager, v.soundManager, 0, 1))
|
||||
}
|
||||
|
||||
func openbrowser(url string) {
|
||||
@ -213,10 +199,10 @@ func openbrowser(url string) {
|
||||
func (v *MainMenu) onSinglePlayerClicked() {
|
||||
// Go here only if existing characters are available to select
|
||||
if d2core.HasGameStates() {
|
||||
v.sceneProvider.SetNextScene(CreateCharacterSelect(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
|
||||
v.sceneProvider.SetNextScene(CreateCharacterSelect(v.sceneProvider, v.uiManager, v.soundManager))
|
||||
return
|
||||
}
|
||||
v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
|
||||
v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.sceneProvider, v.uiManager, v.soundManager))
|
||||
}
|
||||
|
||||
func (v *MainMenu) onGithubButtonClicked() {
|
||||
@ -228,7 +214,7 @@ func (v *MainMenu) onExitButtonClicked() {
|
||||
}
|
||||
|
||||
func (v *MainMenu) onCreditsButtonClicked() {
|
||||
v.sceneProvider.SetNextScene(CreateCredits(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
|
||||
v.sceneProvider.SetNextScene(CreateCredits(v.sceneProvider, v.uiManager, v.soundManager))
|
||||
}
|
||||
|
||||
// Unload unloads the data for the main menu
|
||||
@ -239,22 +225,22 @@ func (v *MainMenu) Unload() {
|
||||
// Render renders the main menu
|
||||
func (v *MainMenu) Render(screen *ebiten.Image) {
|
||||
if v.ShowTrademarkScreen {
|
||||
v.trademarkBackground.DrawSegments(screen, 4, 3, 0)
|
||||
v.trademarkBackground.RenderSegmented(screen, 4, 3, 0)
|
||||
} else {
|
||||
v.background.DrawSegments(screen, 4, 3, 0)
|
||||
v.background.RenderSegmented(screen, 4, 3, 0)
|
||||
}
|
||||
v.diabloLogoLeftBack.Draw(screen)
|
||||
v.diabloLogoRightBack.Draw(screen)
|
||||
v.diabloLogoLeft.Draw(screen)
|
||||
v.diabloLogoRight.Draw(screen)
|
||||
v.diabloLogoLeftBack.Render(screen)
|
||||
v.diabloLogoRightBack.Render(screen)
|
||||
v.diabloLogoLeft.Render(screen)
|
||||
v.diabloLogoRight.Render(screen)
|
||||
|
||||
if v.ShowTrademarkScreen {
|
||||
v.copyrightLabel.Draw(screen)
|
||||
v.copyrightLabel2.Draw(screen)
|
||||
v.copyrightLabel.Render(screen)
|
||||
v.copyrightLabel2.Render(screen)
|
||||
} else {
|
||||
v.openDiabloLabel.Draw(screen)
|
||||
v.versionLabel.Draw(screen)
|
||||
v.commitLabel.Draw(screen)
|
||||
v.openDiabloLabel.Render(screen)
|
||||
v.versionLabel.Render(screen)
|
||||
v.commitLabel.Render(screen)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
@ -83,7 +82,6 @@ var regions []RegionSpec = []RegionSpec{
|
||||
type MapEngineTest struct {
|
||||
uiManager *d2ui.Manager
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
gameState *d2core.GameState
|
||||
mapEngine *d2mapengine.MapEngine
|
||||
@ -97,14 +95,8 @@ type MapEngineTest struct {
|
||||
debugVisLevel int
|
||||
}
|
||||
|
||||
func CreateMapEngineTest(
|
||||
fileProvider d2interface.FileProvider,
|
||||
sceneProvider d2coreinterface.SceneProvider,
|
||||
uiManager *d2ui.Manager,
|
||||
soundManager *d2audio.Manager,
|
||||
currentRegion int, levelPreset int) *MapEngineTest {
|
||||
func CreateMapEngineTest(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager, currentRegion int, levelPreset int) *MapEngineTest {
|
||||
result := &MapEngineTest{
|
||||
fileProvider: fileProvider,
|
||||
uiManager: uiManager,
|
||||
soundManager: soundManager,
|
||||
sceneProvider: sceneProvider,
|
||||
@ -145,7 +137,7 @@ func (v *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
|
||||
if n == 0 {
|
||||
v.mapEngine.GenerateAct1Overworld()
|
||||
} else {
|
||||
v.mapEngine = d2mapengine.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider) // necessary for map name update
|
||||
v.mapEngine = d2mapengine.CreateMapEngine(v.gameState, v.soundManager) // necessary for map name update
|
||||
v.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
|
||||
}
|
||||
|
||||
@ -158,7 +150,7 @@ func (v *MapEngineTest) Load() []func() {
|
||||
v.soundManager.PlayBGM("")
|
||||
return []func(){
|
||||
func() {
|
||||
v.mapEngine = d2mapengine.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
|
||||
v.mapEngine = d2mapengine.CreateMapEngine(v.gameState, v.soundManager)
|
||||
v.LoadRegionByIndex(v.currentRegion, v.levelPreset, v.fileIndex)
|
||||
},
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package d2scene
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
@ -9,31 +8,28 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type HeroRenderInfo struct {
|
||||
Stance d2enum.HeroStance
|
||||
IdleSprite d2render.Sprite
|
||||
IdleSelectedSprite d2render.Sprite
|
||||
ForwardWalkSprite d2render.Sprite
|
||||
ForwardWalkSpriteOverlay d2render.Sprite
|
||||
SelectedSprite d2render.Sprite
|
||||
SelectedSpriteOverlay d2render.Sprite
|
||||
BackWalkSprite d2render.Sprite
|
||||
BackWalkSpriteOverlay d2render.Sprite
|
||||
IdleSprite *d2render.Sprite
|
||||
IdleSelectedSprite *d2render.Sprite
|
||||
ForwardWalkSprite *d2render.Sprite
|
||||
ForwardWalkSpriteOverlay *d2render.Sprite
|
||||
SelectedSprite *d2render.Sprite
|
||||
SelectedSpriteOverlay *d2render.Sprite
|
||||
BackWalkSprite *d2render.Sprite
|
||||
BackWalkSpriteOverlay *d2render.Sprite
|
||||
SelectionBounds image.Rectangle
|
||||
SelectSfx *d2audio.SoundEffect
|
||||
DeselectSfx *d2audio.SoundEffect
|
||||
@ -42,10 +38,9 @@ type HeroRenderInfo struct {
|
||||
type SelectHeroClass struct {
|
||||
uiManager *d2ui.Manager
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2coreinterface.SceneProvider
|
||||
bgImage d2render.Sprite
|
||||
campfire d2render.Sprite
|
||||
bgImage *d2render.Sprite
|
||||
campfire *d2render.Sprite
|
||||
headingLabel d2ui.Label
|
||||
heroClassLabel d2ui.Label
|
||||
heroDesc1Label d2ui.Label
|
||||
@ -63,15 +58,10 @@ type SelectHeroClass struct {
|
||||
hardcoreCharLabel d2ui.Label
|
||||
}
|
||||
|
||||
func CreateSelectHeroClass(
|
||||
fileProvider d2interface.FileProvider,
|
||||
sceneProvider d2coreinterface.SceneProvider,
|
||||
uiManager *d2ui.Manager, soundManager *d2audio.Manager,
|
||||
) *SelectHeroClass {
|
||||
func CreateSelectHeroClass(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *SelectHeroClass {
|
||||
result := &SelectHeroClass{
|
||||
uiManager: uiManager,
|
||||
sceneProvider: sceneProvider,
|
||||
fileProvider: fileProvider,
|
||||
soundManager: soundManager,
|
||||
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
|
||||
selectedHero: d2enum.HeroNone,
|
||||
@ -79,365 +69,360 @@ func CreateSelectHeroClass(
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *SelectHeroClass) loadSprite(path string, palette d2enum.PaletteType) d2render.Sprite {
|
||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(path), d2datadict.Palettes[palette])
|
||||
return d2render.CreateSpriteFromDC6(dc6)
|
||||
}
|
||||
|
||||
func (v *SelectHeroClass) Load() []func() {
|
||||
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
||||
return []func(){
|
||||
func() {
|
||||
v.bgImage = v.loadSprite(d2resource.CharacterSelectBackground, d2enum.Fechar)
|
||||
v.bgImage.MoveTo(0, 0)
|
||||
v.bgImage, _ = d2render.LoadSprite(d2resource.CharacterSelectBackground, d2resource.PaletteFechar)
|
||||
v.bgImage.SetPosition(0, 0)
|
||||
},
|
||||
func() {
|
||||
v.headingLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font30, d2enum.Units)
|
||||
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||
fontWidth, _ := v.headingLabel.GetSize()
|
||||
v.headingLabel.MoveTo(400-int(fontWidth/2), 17)
|
||||
v.headingLabel.SetPosition(400-int(fontWidth/2), 17)
|
||||
v.headingLabel.SetText("Select Hero Class")
|
||||
v.headingLabel.Alignment = d2ui.LabelAlignCenter
|
||||
},
|
||||
func() {
|
||||
v.heroClassLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font30, d2enum.Units)
|
||||
v.heroClassLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||
v.heroClassLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.heroClassLabel.MoveTo(400, 65)
|
||||
v.heroClassLabel.SetPosition(400, 65)
|
||||
},
|
||||
func() {
|
||||
v.heroDesc1Label = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.heroDesc1Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroDesc1Label.Alignment = d2ui.LabelAlignCenter
|
||||
v.heroDesc1Label.MoveTo(400, 100)
|
||||
v.heroDesc1Label.SetPosition(400, 100)
|
||||
},
|
||||
func() {
|
||||
v.heroDesc2Label = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.heroDesc2Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroDesc2Label.Alignment = d2ui.LabelAlignCenter
|
||||
v.heroDesc2Label.MoveTo(400, 115)
|
||||
v.heroDesc2Label.SetPosition(400, 115)
|
||||
},
|
||||
func() {
|
||||
v.heroDesc3Label = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.heroDesc3Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroDesc3Label.Alignment = d2ui.LabelAlignCenter
|
||||
v.heroDesc3Label.MoveTo(400, 130)
|
||||
v.heroDesc3Label.SetPosition(400, 130)
|
||||
},
|
||||
func() {
|
||||
v.campfire = v.loadSprite(d2resource.CharacterSelectCampfire, d2enum.Fechar)
|
||||
v.campfire.MoveTo(380, 335)
|
||||
v.campfire.Animate = true
|
||||
v.campfire.Blend = true
|
||||
v.campfire, _ = d2render.LoadSprite(d2resource.CharacterSelectCampfire, d2resource.PaletteFechar)
|
||||
v.campfire.SetPosition(380, 335)
|
||||
v.campfire.PlayForward()
|
||||
v.campfire.SetBlend(true)
|
||||
},
|
||||
func() {
|
||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
|
||||
v.exitButton.MoveTo(33, 537)
|
||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
|
||||
v.exitButton.SetPosition(33, 537)
|
||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
v.uiManager.AddWidget(&v.exitButton)
|
||||
},
|
||||
func() {
|
||||
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971"))
|
||||
v.okButton.MoveTo(630, 537)
|
||||
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
|
||||
v.okButton.SetPosition(630, 537)
|
||||
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
|
||||
v.okButton.SetVisible(false)
|
||||
v.okButton.SetEnabled(false)
|
||||
v.uiManager.AddWidget(&v.okButton)
|
||||
},
|
||||
func() {
|
||||
v.heroNameLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.heroNameLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroNameLabel.Alignment = d2ui.LabelAlignLeft
|
||||
v.heroNameLabel.Color = color.RGBA{216, 196, 128, 255}
|
||||
v.heroNameLabel.SetText(d2common.TranslateString("#1694"))
|
||||
v.heroNameLabel.MoveTo(321, 475)
|
||||
v.heroNameLabel.SetPosition(321, 475)
|
||||
},
|
||||
func() {
|
||||
v.heroNameTextbox = d2ui.CreateTextbox(v.fileProvider)
|
||||
v.heroNameTextbox.MoveTo(318, 493)
|
||||
v.heroNameTextbox = d2ui.CreateTextbox()
|
||||
v.heroNameTextbox.SetPosition(318, 493)
|
||||
v.heroNameTextbox.SetVisible(false)
|
||||
v.uiManager.AddWidget(&v.heroNameTextbox)
|
||||
},
|
||||
func() {
|
||||
v.expansionCheckbox = d2ui.CreateCheckbox(v.fileProvider, true)
|
||||
v.expansionCheckbox.MoveTo(318, 526)
|
||||
v.expansionCheckbox = d2ui.CreateCheckbox(true)
|
||||
v.expansionCheckbox.SetPosition(318, 526)
|
||||
v.expansionCheckbox.SetVisible(false)
|
||||
v.uiManager.AddWidget(&v.expansionCheckbox)
|
||||
},
|
||||
func() {
|
||||
v.expansionCharLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.expansionCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.expansionCharLabel.Alignment = d2ui.LabelAlignLeft
|
||||
v.expansionCharLabel.Color = color.RGBA{216, 196, 128, 255}
|
||||
v.expansionCharLabel.SetText(d2common.TranslateString("#803"))
|
||||
v.expansionCharLabel.MoveTo(339, 526)
|
||||
v.expansionCharLabel.SetPosition(339, 526)
|
||||
},
|
||||
func() {
|
||||
v.hardcoreCheckbox = d2ui.CreateCheckbox(v.fileProvider, false)
|
||||
v.hardcoreCheckbox.MoveTo(318, 548)
|
||||
v.hardcoreCheckbox = d2ui.CreateCheckbox(false)
|
||||
v.hardcoreCheckbox.SetPosition(318, 548)
|
||||
v.hardcoreCheckbox.SetVisible(false)
|
||||
v.uiManager.AddWidget(&v.hardcoreCheckbox)
|
||||
},
|
||||
func() {
|
||||
v.hardcoreCharLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
||||
v.hardcoreCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.hardcoreCharLabel.Alignment = d2ui.LabelAlignLeft
|
||||
v.hardcoreCharLabel.Color = color.RGBA{216, 196, 128, 255}
|
||||
v.hardcoreCharLabel.SetText(d2common.TranslateString("#1696"))
|
||||
v.hardcoreCharLabel.MoveTo(339, 548)
|
||||
v.hardcoreCharLabel.SetPosition(339, 548)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianForwardWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianForwardWalkOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianSelected, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianForwardWalk, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianForwardWalkOverlay, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianSelected, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.MoveTo(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.MoveTo(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.MoveTo(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.MoveTo(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.MoveTo(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.MoveTo(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SpecialFrameTime = 1000
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.SetPosition(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.SetPosition(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPosition(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPosition(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.SetPosition(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPosition(400, 330)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPlayLengthMs(1000)
|
||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPlayLoop(false)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroSorceress] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressForwardWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressForwardWalkOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressSelected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressSelectedOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressBackWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecSorceressBackWalkOverlay, d2enum.Fechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressForwardWalk, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressForwardWalkOverlay, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressSelected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressSelectedOverlay, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressBackWalk, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressBackWalkOverlay, d2resource.PaletteFechar),
|
||||
image.Rectangle{Min: image.Point{580, 240}, Max: image.Point{65, 160}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXSorceressSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXSorceressDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SpecialFrameTime = 2300
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.Blend = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SpecialFrameTime = 2300
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SpecialFrameTime = 450
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.Blend = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SpecialFrameTime = 450
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SpecialFrameTime = 1200
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.Blend = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.MoveTo(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SpecialFrameTime = 1200
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPlayLengthMs(2300)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetBlend(true)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPlayLengthMs(2300)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SetPlayLengthMs(450)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetBlend(true)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetPlayLengthMs(450)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPlayLengthMs(1200)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetBlend(true)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPosition(626, 352)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPlayLengthMs(1200)
|
||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPlayLoop(false)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelectNecromancerUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectNecromancerUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecNecromancerForwardWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecNecromancerForwardWalkOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecNecromancerSelected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecNecromancerSelectedOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecNecromancerBackWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecNecromancerBackWalkOverlay, d2enum.Fechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectNecromancerUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectNecromancerUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerForwardWalk, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerForwardWalkOverlay, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerSelected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerSelectedOverlay, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerBackWalk, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerBackWalkOverlay, d2resource.PaletteFechar),
|
||||
image.Rectangle{Min: image.Point{265, 220}, Max: image.Point{55, 175}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXNecromancerSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXNecromancerDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SpecialFrameTime = 1200
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SpecialFrameTime = 1200
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SpecialFrameTime = 2000
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.Blend = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SpecialFrameTime = 2000
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.Blend = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.Blend = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.MoveTo(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SetPlayLengthMs(1200)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SetPlayLengthMs(1200)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPlayLengthMs(2000)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetBlend(true)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPlayLengthMs(2000)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.SetBlend(true)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetBlend(true)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPosition(300, 335)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPlayLoop(false)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroPaladin] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelectPaladinUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectPaladinUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinForwardWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinForwardWalkOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinSelected, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinBackWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectPaladinUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectPaladinUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinForwardWalk, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinForwardWalkOverlay, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinSelected, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinBackWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.MoveTo(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.MoveTo(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.MoveTo(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SpecialFrameTime = 3400
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.MoveTo(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SpecialFrameTime = 3400
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.MoveTo(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SpecialFrameTime = 650
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.MoveTo(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SpecialFrameTime = 1300
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SetPosition(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SetPosition(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPosition(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPlayLengthMs(3400)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPosition(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPlayLengthMs(3400)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SetPosition(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SetPlayLengthMs(650)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPosition(521, 338)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPlayLengthMs(1300)
|
||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPlayLoop(false)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroAmazon] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelectAmazonUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectAmazonUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecAmazonForwardWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelecAmazonSelected, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelecAmazonBackWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAmazonUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAmazonUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecAmazonForwardWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecAmazonSelected, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelecAmazonBackWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.MoveTo(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.MoveTo(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.MoveTo(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SpecialFrameTime = 2200
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.MoveTo(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SpecialFrameTime = 1350
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.MoveTo(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SetPosition(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SetPosition(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPosition(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPlayLengthMs(2200)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SetPosition(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SetPlayLengthMs(1350)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPosition(100, 339)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPlayLoop(false)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroAssassin] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinForwardWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinSelected, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinBackWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinForwardWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinSelected, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinBackWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.MoveTo(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.MoveTo(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.MoveTo(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SpecialFrameTime = 3800
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.MoveTo(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SpecialFrameTime = 2500
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.MoveTo(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SetPosition(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SetPosition(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPosition(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPlayLengthMs(3800)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SetPosition(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SetPlayLengthMs(2500)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPosition(231, 365)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPlayLoop(false)
|
||||
},
|
||||
func() {
|
||||
v.heroRenderInfo[d2enum.HeroDruid] = &HeroRenderInfo{
|
||||
d2enum.HeroStanceIdle,
|
||||
v.loadSprite(d2resource.CharacterSelectDruidUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectDruidUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectDruidForwardWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectDruidSelected, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectDruidBackWalk, d2enum.Fechar),
|
||||
d2render.Sprite{},
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectDruidUnselected, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectDruidUnselectedH, d2resource.PaletteFechar),
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectDruidForwardWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectDruidSelected, d2resource.PaletteFechar),
|
||||
nil,
|
||||
d2render.MustLoadSprite(d2resource.CharacterSelectDruidBackWalk, d2resource.PaletteFechar),
|
||||
nil,
|
||||
image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXDruidSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXDruidDeselect),
|
||||
}
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.MoveTo(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.MoveTo(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.MoveTo(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SpecialFrameTime = 4800
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.MoveTo(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.MoveTo(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.Animate = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SpecialFrameTime = 1500
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.StopOnLastFrame = true
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SetPosition(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SetPosition(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPosition(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPlayLengthMs(4800)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPlayLoop(false)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SetPosition(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPosition(720, 370)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.PlayForward()
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPlayLengthMs(1500)
|
||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPlayLoop(false)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -451,22 +436,22 @@ func (v *SelectHeroClass) Unload() {
|
||||
}
|
||||
|
||||
func (v SelectHeroClass) onExitButtonClicked() {
|
||||
v.sceneProvider.SetNextScene(CreateCharacterSelect(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
|
||||
v.sceneProvider.SetNextScene(CreateCharacterSelect(v.sceneProvider, v.uiManager, v.soundManager))
|
||||
}
|
||||
|
||||
func (v SelectHeroClass) onOkButtonClicked() {
|
||||
gameState := d2core.CreateGameState(v.heroNameTextbox.GetText(), v.selectedHero, v.hardcoreCheckbox.GetCheckState())
|
||||
v.sceneProvider.SetNextScene(CreateGame(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager, gameState))
|
||||
v.sceneProvider.SetNextScene(CreateGame(v.sceneProvider, v.uiManager, v.soundManager, gameState))
|
||||
}
|
||||
|
||||
func (v *SelectHeroClass) Render(screen *ebiten.Image) {
|
||||
v.bgImage.DrawSegments(screen, 4, 3, 0)
|
||||
v.headingLabel.Draw(screen)
|
||||
v.bgImage.RenderSegmented(screen, 4, 3, 0)
|
||||
v.headingLabel.Render(screen)
|
||||
if v.selectedHero != d2enum.HeroNone {
|
||||
v.heroClassLabel.Draw(screen)
|
||||
v.heroDesc1Label.Draw(screen)
|
||||
v.heroDesc2Label.Draw(screen)
|
||||
v.heroDesc3Label.Draw(screen)
|
||||
v.heroClassLabel.Render(screen)
|
||||
v.heroDesc1Label.Render(screen)
|
||||
v.heroDesc2Label.Render(screen)
|
||||
v.heroDesc3Label.Render(screen)
|
||||
}
|
||||
for heroClass, heroInfo := range v.heroRenderInfo {
|
||||
if heroInfo.Stance == d2enum.HeroStanceIdle || heroInfo.Stance == d2enum.HeroStanceIdleSelected {
|
||||
@ -478,11 +463,11 @@ func (v *SelectHeroClass) Render(screen *ebiten.Image) {
|
||||
v.renderHero(screen, heroClass)
|
||||
}
|
||||
}
|
||||
v.campfire.Draw(screen)
|
||||
v.campfire.Render(screen)
|
||||
if v.heroNameTextbox.GetVisible() {
|
||||
v.heroNameLabel.Draw(screen)
|
||||
v.expansionCharLabel.Draw(screen)
|
||||
v.hardcoreCharLabel.Draw(screen)
|
||||
v.heroNameLabel.Render(screen)
|
||||
v.expansionCharLabel.Render(screen)
|
||||
v.hardcoreCharLabel.Render(screen)
|
||||
}
|
||||
}
|
||||
|
||||
@ -512,18 +497,16 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
renderInfo := v.heroRenderInfo[hero]
|
||||
switch renderInfo.Stance {
|
||||
case d2enum.HeroStanceApproaching:
|
||||
if renderInfo.ForwardWalkSprite.OnLastFrame() {
|
||||
if renderInfo.ForwardWalkSprite.IsOnLastFrame() {
|
||||
renderInfo.Stance = d2enum.HeroStanceSelected
|
||||
renderInfo.SelectedSprite.ResetAnimation()
|
||||
if renderInfo.SelectedSpriteOverlay.IsValid() {
|
||||
renderInfo.SelectedSpriteOverlay.ResetAnimation()
|
||||
}
|
||||
setSpriteToFirstFrame(renderInfo.SelectedSprite)
|
||||
setSpriteToFirstFrame(renderInfo.SelectedSpriteOverlay)
|
||||
}
|
||||
return
|
||||
case d2enum.HeroStanceRetreating:
|
||||
if renderInfo.BackWalkSprite.OnLastFrame() {
|
||||
if renderInfo.BackWalkSprite.IsOnLastFrame() {
|
||||
renderInfo.Stance = d2enum.HeroStanceIdle
|
||||
renderInfo.IdleSprite.ResetAnimation()
|
||||
setSpriteToFirstFrame(renderInfo.IdleSprite)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -543,10 +526,8 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
v.expansionCheckbox.SetVisible(true)
|
||||
v.hardcoreCheckbox.SetVisible(true)
|
||||
renderInfo.Stance = d2enum.HeroStanceApproaching
|
||||
renderInfo.ForwardWalkSprite.ResetAnimation()
|
||||
if renderInfo.ForwardWalkSpriteOverlay.IsValid() {
|
||||
renderInfo.ForwardWalkSpriteOverlay.ResetAnimation()
|
||||
}
|
||||
setSpriteToFirstFrame(renderInfo.ForwardWalkSprite)
|
||||
setSpriteToFirstFrame(renderInfo.ForwardWalkSpriteOverlay)
|
||||
for _, heroInfo := range v.heroRenderInfo {
|
||||
if heroInfo.Stance != d2enum.HeroStanceSelected {
|
||||
continue
|
||||
@ -554,10 +535,8 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
heroInfo.SelectSfx.Stop()
|
||||
heroInfo.DeselectSfx.Play()
|
||||
heroInfo.Stance = d2enum.HeroStanceRetreating
|
||||
heroInfo.BackWalkSprite.ResetAnimation()
|
||||
if heroInfo.BackWalkSpriteOverlay.IsValid() {
|
||||
heroInfo.BackWalkSpriteOverlay.ResetAnimation()
|
||||
}
|
||||
setSpriteToFirstFrame(heroInfo.BackWalkSprite)
|
||||
setSpriteToFirstFrame(heroInfo.BackWalkSpriteOverlay)
|
||||
}
|
||||
v.selectedHero = hero
|
||||
v.updateHeroText()
|
||||
@ -567,12 +546,10 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
}
|
||||
|
||||
if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected {
|
||||
renderInfo.IdleSelectedSprite.LastFrameTime = renderInfo.IdleSprite.LastFrameTime
|
||||
renderInfo.IdleSelectedSprite.Frame = renderInfo.IdleSprite.Frame
|
||||
renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame())
|
||||
renderInfo.Stance = d2enum.HeroStanceIdleSelected
|
||||
} else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle {
|
||||
renderInfo.IdleSprite.LastFrameTime = renderInfo.IdleSelectedSprite.LastFrameTime
|
||||
renderInfo.IdleSprite.Frame = renderInfo.IdleSelectedSprite.Frame
|
||||
renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame())
|
||||
renderInfo.Stance = d2enum.HeroStanceIdle
|
||||
}
|
||||
|
||||
@ -587,24 +564,18 @@ func (v *SelectHeroClass) renderHero(screen *ebiten.Image, hero d2enum.Hero) {
|
||||
renderInfo := v.heroRenderInfo[hero]
|
||||
switch renderInfo.Stance {
|
||||
case d2enum.HeroStanceIdle:
|
||||
renderInfo.IdleSprite.Draw(screen)
|
||||
drawSprite(renderInfo.IdleSprite, screen)
|
||||
case d2enum.HeroStanceIdleSelected:
|
||||
renderInfo.IdleSelectedSprite.Draw(screen)
|
||||
drawSprite(renderInfo.IdleSelectedSprite, screen)
|
||||
case d2enum.HeroStanceApproaching:
|
||||
renderInfo.ForwardWalkSprite.Draw(screen)
|
||||
if renderInfo.ForwardWalkSpriteOverlay.IsValid() {
|
||||
renderInfo.ForwardWalkSpriteOverlay.Draw(screen)
|
||||
}
|
||||
drawSprite(renderInfo.ForwardWalkSprite, screen)
|
||||
drawSprite(renderInfo.ForwardWalkSpriteOverlay, screen)
|
||||
case d2enum.HeroStanceSelected:
|
||||
renderInfo.SelectedSprite.Draw(screen)
|
||||
if renderInfo.SelectedSpriteOverlay.IsValid() {
|
||||
renderInfo.SelectedSpriteOverlay.Draw(screen)
|
||||
}
|
||||
drawSprite(renderInfo.SelectedSprite, screen)
|
||||
drawSprite(renderInfo.SelectedSpriteOverlay, screen)
|
||||
case d2enum.HeroStanceRetreating:
|
||||
renderInfo.BackWalkSprite.Draw(screen)
|
||||
if renderInfo.BackWalkSpriteOverlay.IsValid() {
|
||||
renderInfo.BackWalkSpriteOverlay.Draw(screen)
|
||||
}
|
||||
drawSprite(renderInfo.BackWalkSprite, screen)
|
||||
drawSprite(renderInfo.BackWalkSpriteOverlay, screen)
|
||||
}
|
||||
}
|
||||
|
||||
@ -669,3 +640,15 @@ func (v *SelectHeroClass) setDescLabels(descKey string) {
|
||||
v.heroDesc3Label.SetText("")
|
||||
}
|
||||
}
|
||||
|
||||
func setSpriteToFirstFrame(sprite *d2render.Sprite) {
|
||||
if sprite != nil {
|
||||
sprite.Rewind()
|
||||
}
|
||||
}
|
||||
|
||||
func drawSprite(sprite *d2render.Sprite, target *ebiten.Image) {
|
||||
if sprite != nil {
|
||||
sprite.Render(target)
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,12 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data"
|
||||
@ -26,6 +22,7 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||
|
||||
@ -38,7 +35,7 @@ import (
|
||||
type Engine struct {
|
||||
Settings *d2corecommon.Configuration // Engine configuration settings from json file
|
||||
CheckedPatch map[string]bool // First time we check a file, we'll check if it's in the patch. This notes that we've already checked that.
|
||||
LoadingSprite d2render.Sprite // The sprite shown when loading stuff
|
||||
LoadingSprite *d2render.Sprite // The sprite shown when loading stuff
|
||||
loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
|
||||
loadingIndex int // Determines which load function is currently being called
|
||||
thingsToLoad []func() // The load functions for the next scene
|
||||
@ -50,7 +47,6 @@ type Engine struct {
|
||||
fullscreenKey bool // When true, the fullscreen toggle is still being pressed
|
||||
lastTime float64 // Last time we updated the scene
|
||||
showFPS bool
|
||||
assetManager *assetManager
|
||||
}
|
||||
|
||||
// CreateEngine creates and instance of the OpenDiablo2 engine
|
||||
@ -62,7 +58,8 @@ func CreateEngine() Engine {
|
||||
log.Printf("could not load settings: %v", err)
|
||||
}
|
||||
|
||||
result.assetManager = createAssetManager(result.Settings)
|
||||
d2asset.Initialize(result.Settings)
|
||||
|
||||
d2resource.LanguageCode = result.Settings.Language
|
||||
d2datadict.LoadPalettes(nil, &result)
|
||||
d2common.LoadTextDictionary(&result)
|
||||
@ -80,17 +77,18 @@ func CreateEngine() Engine {
|
||||
d2data.LoadAnimationData(&result)
|
||||
d2datadict.LoadMonStats(&result)
|
||||
LoadHeroObjects()
|
||||
result.SoundManager = d2audio.CreateManager(&result)
|
||||
result.SoundManager = d2audio.CreateManager()
|
||||
result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume)
|
||||
result.UIManager = d2ui.CreateManager(&result, *result.SoundManager)
|
||||
result.LoadingSprite = result.LoadSprite(d2resource.LoadingScreen, d2enum.Loading)
|
||||
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize()
|
||||
result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
||||
result.UIManager = d2ui.CreateManager(*result.SoundManager)
|
||||
result.LoadingSprite, _ = d2render.LoadSprite(d2resource.LoadingScreen, d2resource.PaletteLoading)
|
||||
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetCurrentFrameSize()
|
||||
result.LoadingSprite.SetPosition(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *Engine) LoadFile(fileName string) []byte {
|
||||
return v.assetManager.LoadFile(fileName)
|
||||
data, _ := d2asset.LoadFile(fileName)
|
||||
return data
|
||||
}
|
||||
|
||||
// IsLoading returns true if the engine is currently in a loading state
|
||||
@ -98,13 +96,6 @@ func (v Engine) IsLoading() bool {
|
||||
return v.loadingProgress < 1.0
|
||||
}
|
||||
|
||||
// LoadSprite loads a sprite from the game's data files
|
||||
func (v Engine) LoadSprite(fileName string, palette d2enum.PaletteType) d2render.Sprite {
|
||||
dc6, _ := d2dc6.LoadDC6(v.LoadFile(fileName), d2datadict.Palettes[palette])
|
||||
sprite := d2render.CreateSpriteFromDC6(dc6)
|
||||
return sprite
|
||||
}
|
||||
|
||||
// updateScene handles the scene maintenance for the engine
|
||||
func (v *Engine) updateScene() {
|
||||
if v.nextScene == nil {
|
||||
@ -176,14 +167,14 @@ func (v *Engine) Update() {
|
||||
// Draw draws the game
|
||||
func (v Engine) Draw(screen *ebiten.Image) {
|
||||
if v.loadingProgress < 1.0 {
|
||||
v.LoadingSprite.Frame = int16(d2helper.Max(0, d2helper.Min(uint32(len(v.LoadingSprite.Frames)-1), uint32(float64(len(v.LoadingSprite.Frames)-1)*v.loadingProgress))))
|
||||
v.LoadingSprite.Draw(screen)
|
||||
v.LoadingSprite.SetCurrentFrame(int(d2helper.Max(0, d2helper.Min(uint32(v.LoadingSprite.GetFrameCount()-1), uint32(float64(v.LoadingSprite.GetFrameCount()-1)*v.loadingProgress)))))
|
||||
v.LoadingSprite.Render(screen)
|
||||
} else {
|
||||
if v.CurrentScene == nil {
|
||||
log.Fatal("no scene loaded")
|
||||
}
|
||||
v.CurrentScene.Render(screen)
|
||||
v.UIManager.Draw(screen)
|
||||
v.UIManager.Render(screen)
|
||||
}
|
||||
if v.showFPS {
|
||||
ebitenutil.DebugPrintAt(screen, "vsync:"+strconv.FormatBool(ebiten.IsVsyncEnabled())+"\nFPS:"+strconv.Itoa(int(ebiten.CurrentFPS())), 5, 565)
|
||||
|
@ -2,7 +2,6 @@ package d2core
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
@ -15,7 +14,7 @@ type Hero struct {
|
||||
direction int
|
||||
}
|
||||
|
||||
func CreateHero(x, y int32, direction int, heroType d2enum.Hero, equipment CharacterEquipment, fileProvider d2interface.FileProvider) *Hero {
|
||||
func CreateHero(x, y int32, direction int, heroType d2enum.Hero, equipment CharacterEquipment) *Hero {
|
||||
result := &Hero{
|
||||
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, &d2datadict.ObjectLookupRecord{
|
||||
Mode: d2enum.AnimationModePlayerNeutral.String(),
|
||||
@ -32,7 +31,6 @@ func CreateHero(x, y int32, direction int, heroType d2enum.Hero, equipment Chara
|
||||
RH: equipment.RightHand.GetItemCode(),
|
||||
LH: equipment.LeftHand.GetItemCode(),
|
||||
},
|
||||
fileProvider,
|
||||
d2enum.Units,
|
||||
),
|
||||
Equipment: equipment,
|
||||
|
@ -3,7 +3,6 @@ package d2core
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
@ -16,9 +15,9 @@ type NPC struct {
|
||||
path int
|
||||
}
|
||||
|
||||
func CreateNPC(x, y int32, object *d2datadict.ObjectLookupRecord, fileProvider d2interface.FileProvider, direction int) *NPC {
|
||||
func CreateNPC(x, y int32, object *d2datadict.ObjectLookupRecord, direction int) *NPC {
|
||||
result := &NPC{
|
||||
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, object, fileProvider, d2enum.Units),
|
||||
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, object, d2enum.Units),
|
||||
HasPaths: false,
|
||||
}
|
||||
result.AnimatedEntity.SetMode(object.Mode, object.Class, direction)
|
||||
|
@ -4,10 +4,10 @@ import "github.com/hajimehoshi/ebiten"
|
||||
|
||||
// Drawable represents an instance that can be drawn
|
||||
type Drawable interface {
|
||||
Draw(target *ebiten.Image)
|
||||
GetSize() (width, height uint32)
|
||||
MoveTo(x, y int)
|
||||
GetLocation() (x, y int)
|
||||
Render(target *ebiten.Image)
|
||||
GetSize() (width, height int)
|
||||
SetPosition(x, y int)
|
||||
GetPosition() (x, y int)
|
||||
GetVisible() bool
|
||||
SetVisible(visible bool)
|
||||
}
|
||||
|
@ -1,22 +1,16 @@
|
||||
package d2player
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"log"
|
||||
)
|
||||
|
||||
type GameControls struct {
|
||||
fileProvider d2interface.FileProvider
|
||||
hero *d2core.Hero
|
||||
mapEngine *d2mapengine.MapEngine
|
||||
hero *d2core.Hero
|
||||
mapEngine *d2mapengine.MapEngine
|
||||
|
||||
// UI
|
||||
globeSprite *d2render.Sprite
|
||||
@ -25,11 +19,10 @@ type GameControls struct {
|
||||
skillIcon *d2render.Sprite
|
||||
}
|
||||
|
||||
func NewGameControls(fileProvider d2interface.FileProvider, hero *d2core.Hero, mapEngine *d2mapengine.MapEngine) *GameControls {
|
||||
func NewGameControls(hero *d2core.Hero, mapEngine *d2mapengine.MapEngine) *GameControls {
|
||||
return &GameControls{
|
||||
fileProvider: fileProvider,
|
||||
hero: hero,
|
||||
mapEngine: mapEngine,
|
||||
hero: hero,
|
||||
mapEngine: mapEngine,
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,111 +60,86 @@ func (g *GameControls) Move(tickTime float64) {
|
||||
}
|
||||
|
||||
func (g *GameControls) Load() {
|
||||
dc6, err := d2dc6.LoadDC6(g.fileProvider.LoadFile(d2resource.GameGlobeOverlap), d2datadict.Palettes[d2enum.Sky])
|
||||
if err != nil {
|
||||
log.Panicf("failed to load %s: %v", d2resource.GameGlobeOverlap, err)
|
||||
}
|
||||
globeSprite := d2render.CreateSpriteFromDC6(dc6)
|
||||
g.globeSprite = &globeSprite
|
||||
|
||||
dc6, err = d2dc6.LoadDC6(g.fileProvider.LoadFile(d2resource.GamePanels), d2datadict.Palettes[d2enum.Sky])
|
||||
if err != nil {
|
||||
log.Panicf("failed to load %s: %v", d2resource.GamePanels, err)
|
||||
}
|
||||
mainPanel := d2render.CreateSpriteFromDC6(dc6)
|
||||
g.mainPanel = &mainPanel
|
||||
|
||||
dc6, err = d2dc6.LoadDC6(g.fileProvider.LoadFile(d2resource.MenuButton), d2datadict.Palettes[d2enum.Sky])
|
||||
if err != nil {
|
||||
log.Panicf("failed to load %s: %v", d2resource.MenuButton, err)
|
||||
}
|
||||
menuButton := d2render.CreateSpriteFromDC6(dc6)
|
||||
g.menuButton = &menuButton
|
||||
|
||||
dc6, err = d2dc6.LoadDC6(g.fileProvider.LoadFile(d2resource.GenericSkills), d2datadict.Palettes[d2enum.Sky])
|
||||
if err != nil {
|
||||
log.Panicf("failed to load %s: %v", d2resource.GenericSkills, err)
|
||||
}
|
||||
skillIcon := d2render.CreateSpriteFromDC6(dc6)
|
||||
g.skillIcon = &skillIcon
|
||||
|
||||
g.globeSprite, _ = d2render.LoadSprite(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
|
||||
g.mainPanel, _ = d2render.LoadSprite(d2resource.GamePanels, d2resource.PaletteSky)
|
||||
g.menuButton, _ = d2render.LoadSprite(d2resource.MenuButton, d2resource.PaletteSky)
|
||||
g.skillIcon, _ = d2render.LoadSprite(d2resource.GenericSkills, d2resource.PaletteSky)
|
||||
}
|
||||
|
||||
|
||||
// TODO: consider caching the panels to single image that is reused.
|
||||
func (g *GameControls) Render(target *ebiten.Image) {
|
||||
width, height := target.Size()
|
||||
offset := uint32(0)
|
||||
offset := int(0)
|
||||
|
||||
// Left globe holder
|
||||
g.mainPanel.Frame = 0
|
||||
w, _ := g.mainPanel.GetSize()
|
||||
g.mainPanel.MoveTo(int(offset), height)
|
||||
g.mainPanel.Draw(target)
|
||||
g.mainPanel.SetCurrentFrame(0)
|
||||
w, _ := g.mainPanel.GetCurrentFrameSize()
|
||||
g.mainPanel.SetPosition(int(offset), height)
|
||||
g.mainPanel.Render(target)
|
||||
|
||||
// Left globe
|
||||
g.globeSprite.Frame = 0
|
||||
g.globeSprite.MoveTo(int(offset+28), height - 5)
|
||||
g.globeSprite.Draw(target)
|
||||
g.globeSprite.SetCurrentFrame(0)
|
||||
g.globeSprite.SetPosition(int(offset+28), height-5)
|
||||
g.globeSprite.Render(target)
|
||||
offset += w
|
||||
|
||||
// Left skill
|
||||
g.skillIcon.Frame = 2
|
||||
w, _ = g.skillIcon.GetSize()
|
||||
g.skillIcon.MoveTo(int(offset), height)
|
||||
g.skillIcon.Draw(target)
|
||||
g.skillIcon.SetCurrentFrame(2)
|
||||
w, _ = g.skillIcon.GetCurrentFrameSize()
|
||||
g.skillIcon.SetPosition(int(offset), height)
|
||||
g.skillIcon.Render(target)
|
||||
offset += w
|
||||
|
||||
// Left skill selector
|
||||
g.mainPanel.Frame = 1
|
||||
w, _ = g.mainPanel.GetSize()
|
||||
g.mainPanel.MoveTo(int(offset), height)
|
||||
g.mainPanel.Draw(target)
|
||||
g.mainPanel.SetCurrentFrame(1)
|
||||
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||
g.mainPanel.SetPosition(int(offset), height)
|
||||
g.mainPanel.Render(target)
|
||||
offset += w
|
||||
|
||||
// Stamina
|
||||
g.mainPanel.Frame = 2
|
||||
w, _ = g.mainPanel.GetSize()
|
||||
g.mainPanel.MoveTo(int(offset), height)
|
||||
g.mainPanel.Draw(target)
|
||||
g.mainPanel.SetCurrentFrame(2)
|
||||
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||
g.mainPanel.SetPosition(int(offset), height)
|
||||
g.mainPanel.Render(target)
|
||||
offset += w
|
||||
|
||||
// Center menu button
|
||||
g.menuButton.Frame = 0
|
||||
w, _ = g.mainPanel.GetSize()
|
||||
g.menuButton.MoveTo((width / 2) - 8 , height - 16)
|
||||
g.menuButton.Draw(target)
|
||||
g.menuButton.SetCurrentFrame(0)
|
||||
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||
g.menuButton.SetPosition((width/2)-8, height-16)
|
||||
g.menuButton.Render(target)
|
||||
|
||||
// Potions
|
||||
g.mainPanel.Frame = 3
|
||||
w, _ = g.mainPanel.GetSize()
|
||||
g.mainPanel.MoveTo(int(offset), height)
|
||||
g.mainPanel.Draw(target)
|
||||
g.mainPanel.SetCurrentFrame(3)
|
||||
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||
g.mainPanel.SetPosition(int(offset), height)
|
||||
g.mainPanel.Render(target)
|
||||
offset += w
|
||||
|
||||
// Right skill selector
|
||||
g.mainPanel.Frame = 4
|
||||
w, _ = g.mainPanel.GetSize()
|
||||
g.mainPanel.MoveTo(int(offset), height)
|
||||
g.mainPanel.Draw(target)
|
||||
g.mainPanel.SetCurrentFrame(4)
|
||||
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||
g.mainPanel.SetPosition(int(offset), height)
|
||||
g.mainPanel.Render(target)
|
||||
offset += w
|
||||
|
||||
// Right skill
|
||||
g.skillIcon.Frame = 10
|
||||
w, _ = g.skillIcon.GetSize()
|
||||
g.skillIcon.MoveTo(int(offset), height)
|
||||
g.skillIcon.Draw(target)
|
||||
g.skillIcon.SetCurrentFrame(10)
|
||||
w, _ = g.skillIcon.GetCurrentFrameSize()
|
||||
g.skillIcon.SetPosition(int(offset), height)
|
||||
g.skillIcon.Render(target)
|
||||
offset += w
|
||||
|
||||
// Right globe holder
|
||||
g.mainPanel.Frame = 5
|
||||
w, _ = g.mainPanel.GetSize()
|
||||
g.mainPanel.MoveTo(int(offset), height)
|
||||
g.mainPanel.Draw(target)
|
||||
g.mainPanel.SetCurrentFrame(5)
|
||||
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||
g.mainPanel.SetPosition(int(offset), height)
|
||||
g.mainPanel.Render(target)
|
||||
|
||||
// Right globe
|
||||
g.globeSprite.Frame = 1
|
||||
g.globeSprite.MoveTo(int(offset) + 8, height - 8)
|
||||
g.globeSprite.Draw(target)
|
||||
g.globeSprite.SetCurrentFrame(1)
|
||||
g.globeSprite.SetPosition(int(offset)+8, height-8)
|
||||
g.globeSprite.Render(target)
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2render
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"log"
|
||||
@ -9,12 +10,12 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2cof"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
@ -30,12 +31,11 @@ type LayerCacheEntry struct {
|
||||
|
||||
// AnimatedEntity represents an entity on the map that can be animated
|
||||
type AnimatedEntity struct {
|
||||
fileProvider d2interface.FileProvider
|
||||
LocationX float64
|
||||
LocationY float64
|
||||
TileX, TileY int // Coordinates of the tile the unit is within
|
||||
subcellX, subcellY float64 // Subcell coordinates within the current tile
|
||||
dccLayers map[string]d2dcc.DCC
|
||||
dccLayers map[string]*d2dcc.DCC
|
||||
Cof *d2cof.COF
|
||||
palette d2enum.PaletteType
|
||||
base string
|
||||
@ -58,16 +58,15 @@ type AnimatedEntity struct {
|
||||
}
|
||||
|
||||
// CreateAnimatedEntity creates an instance of AnimatedEntity
|
||||
func CreateAnimatedEntity(x, y int32, object *d2datadict.ObjectLookupRecord, fileProvider d2interface.FileProvider, palette d2enum.PaletteType) AnimatedEntity {
|
||||
func CreateAnimatedEntity(x, y int32, object *d2datadict.ObjectLookupRecord, palette d2enum.PaletteType) AnimatedEntity {
|
||||
result := AnimatedEntity{
|
||||
fileProvider: fileProvider,
|
||||
base: object.Base,
|
||||
token: object.Token,
|
||||
object: object,
|
||||
palette: palette,
|
||||
layerCache: make([]LayerCacheEntry, d2enum.CompositeTypeMax),
|
||||
base: object.Base,
|
||||
token: object.Token,
|
||||
object: object,
|
||||
palette: palette,
|
||||
layerCache: make([]LayerCacheEntry, d2enum.CompositeTypeMax),
|
||||
}
|
||||
result.dccLayers = make(map[string]d2dcc.DCC)
|
||||
result.dccLayers = make(map[string]*d2dcc.DCC)
|
||||
result.LocationX = float64(x)
|
||||
result.LocationY = float64(y)
|
||||
result.TargetX = result.LocationX
|
||||
@ -84,7 +83,10 @@ func CreateAnimatedEntity(x, y int32, object *d2datadict.ObjectLookupRecord, fil
|
||||
// SetMode changes the graphical mode of this animated entity
|
||||
func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction int) {
|
||||
cofPath := fmt.Sprintf("%s/%s/COF/%s%s%s.COF", v.base, v.token, v.token, animationMode, weaponClass)
|
||||
v.Cof = d2cof.LoadCOF(cofPath, v.fileProvider)
|
||||
var err error
|
||||
if v.Cof, err = d2asset.LoadCOF(cofPath); err != nil {
|
||||
return
|
||||
}
|
||||
if v.Cof.NumberOfDirections == 0 || v.Cof.NumberOfLayers == 0 || v.Cof.FramesPerDirection == 0 {
|
||||
return
|
||||
}
|
||||
@ -95,11 +97,10 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
|
||||
if v.direction >= v.Cof.NumberOfDirections {
|
||||
v.direction = v.Cof.NumberOfDirections - 1
|
||||
}
|
||||
v.dccLayers = make(map[string]d2dcc.DCC)
|
||||
v.dccLayers = make(map[string]*d2dcc.DCC)
|
||||
for _, cofLayer := range v.Cof.CofLayers {
|
||||
layerName := DccLayerNames[cofLayer.Type]
|
||||
v.dccLayers[layerName] = v.LoadLayer(layerName, v.fileProvider)
|
||||
if !v.dccLayers[layerName].IsValid() {
|
||||
if v.dccLayers[layerName], err = v.LoadLayer(layerName); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -107,7 +108,7 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
|
||||
v.updateFrameCache(resetAnimation)
|
||||
}
|
||||
|
||||
func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FileProvider) d2dcc.DCC {
|
||||
func (v *AnimatedEntity) LoadLayer(layer string) (*d2dcc.DCC, error) {
|
||||
layerName := "TR"
|
||||
switch strings.ToUpper(layer) {
|
||||
case "HD": // Head
|
||||
@ -144,15 +145,19 @@ func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FilePr
|
||||
layerName = v.object.S8
|
||||
}
|
||||
if len(layerName) == 0 {
|
||||
return d2dcc.DCC{}
|
||||
return nil, errors.New("invalid layer")
|
||||
}
|
||||
dccPath := fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", v.base, v.token, layer, v.token, layer, layerName, v.animationMode, v.weaponClass)
|
||||
result := d2dcc.LoadDCC(dccPath, fileProvider)
|
||||
if !result.IsValid() {
|
||||
result, err := d2asset.LoadDCC(dccPath)
|
||||
if err != nil {
|
||||
dccPath = fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", v.base, v.token, layer, v.token, layer, layerName, v.animationMode, "HTH")
|
||||
result = d2dcc.LoadDCC(dccPath, fileProvider)
|
||||
result, err = d2asset.LoadDCC(dccPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// If an npc has a path to pause at each location.
|
||||
@ -240,7 +245,7 @@ func (v *AnimatedEntity) updateFrameCache(resetAnimation bool) {
|
||||
layerType := v.Cof.CofLayers[cofLayerIdx].Type
|
||||
layerName := DccLayerNames[layerType]
|
||||
dccLayer := v.dccLayers[layerName]
|
||||
if !dccLayer.IsValid() {
|
||||
if dccLayer == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
)
|
||||
@ -20,7 +19,6 @@ type MapEntity interface {
|
||||
type MapEngine struct {
|
||||
soundManager *d2audio.Manager
|
||||
gameState *d2core.GameState
|
||||
fileProvider d2interface.FileProvider
|
||||
|
||||
debugVisLevel int
|
||||
|
||||
@ -30,11 +28,10 @@ type MapEngine struct {
|
||||
camera Camera
|
||||
}
|
||||
|
||||
func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager, fileProvider d2interface.FileProvider) *MapEngine {
|
||||
func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager) *MapEngine {
|
||||
engine := &MapEngine{
|
||||
gameState: gameState,
|
||||
soundManager: soundManager,
|
||||
fileProvider: fileProvider,
|
||||
viewport: NewViewport(0, 0, 800, 600),
|
||||
}
|
||||
|
||||
@ -88,7 +85,7 @@ func (me *MapEngine) SetDebugVisLevel(debugVisLevel int) {
|
||||
}
|
||||
|
||||
func (me *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
|
||||
region, entities := loadRegion(me.gameState.Seed, 0, 0, regionType, levelPreset, me.fileProvider, fileIndex)
|
||||
region, entities := loadRegion(me.gameState.Seed, 0, 0, regionType, levelPreset, fileIndex)
|
||||
me.regions = append(me.regions, region)
|
||||
me.entities = append(me.entities, entities...)
|
||||
}
|
||||
@ -96,16 +93,16 @@ func (me *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int
|
||||
func (me *MapEngine) GenerateAct1Overworld() {
|
||||
me.soundManager.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
||||
|
||||
region, entities := loadRegion(me.gameState.Seed, 0, 0, d2enum.RegionAct1Town, 1, me.fileProvider, -1)
|
||||
region, entities := loadRegion(me.gameState.Seed, 0, 0, d2enum.RegionAct1Town, 1, -1)
|
||||
me.regions = append(me.regions, region)
|
||||
me.entities = append(me.entities, entities...)
|
||||
|
||||
if strings.Contains(region.regionPath, "E1") {
|
||||
region, entities := loadRegion(me.gameState.Seed, int(region.tileRect.Width-1), 0, d2enum.RegionAct1Town, 2, me.fileProvider, -1)
|
||||
region, entities := loadRegion(me.gameState.Seed, int(region.tileRect.Width-1), 0, d2enum.RegionAct1Town, 2, -1)
|
||||
me.regions = append(me.regions, region)
|
||||
me.entities = append(me.entities, entities...)
|
||||
} else if strings.Contains(region.regionPath, "S1") {
|
||||
region, entities := loadRegion(me.gameState.Seed, 0, int(region.tileRect.Height-1), d2enum.RegionAct1Town, 3, me.fileProvider, -1)
|
||||
region, entities := loadRegion(me.gameState.Seed, 0, int(region.tileRect.Height-1), d2enum.RegionAct1Town, 3, -1)
|
||||
me.regions = append(me.regions, region)
|
||||
me.entities = append(me.entities, entities...)
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2ds1"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dt1"
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
@ -39,7 +39,7 @@ type MapRegion struct {
|
||||
lastFrameTime float64
|
||||
}
|
||||
|
||||
func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.RegionIdType, levelPreset int, fileProvider d2interface.FileProvider, fileIndex int) (*MapRegion, []MapEntity) {
|
||||
func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.RegionIdType, levelPreset int, fileIndex int) (*MapRegion, []MapEntity) {
|
||||
region := &MapRegion{
|
||||
levelType: d2datadict.LevelTypes[levelType],
|
||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
||||
@ -54,7 +54,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
|
||||
|
||||
for _, levelTypeDt1 := range region.levelType.Files {
|
||||
if len(levelTypeDt1) != 0 && levelTypeDt1 != "" && levelTypeDt1 != "0" {
|
||||
dt1 := d2dt1.LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider)
|
||||
dt1 := d2dt1.LoadDT1(d2asset.MustLoadFile("/data/global/tiles/" + levelTypeDt1))
|
||||
region.tiles = append(region.tiles, dt1.Tiles...)
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
|
||||
}
|
||||
|
||||
region.regionPath = levelFilesToPick[levelIndex]
|
||||
region.ds1 = d2ds1.LoadDS1("/data/global/tiles/"+region.regionPath, fileProvider)
|
||||
region.ds1 = d2ds1.LoadDS1(d2asset.MustLoadFile("/data/global/tiles/" + region.regionPath))
|
||||
region.tileRect = d2common.Rectangle{
|
||||
Left: tileOffsetX,
|
||||
Top: tileOffsetY,
|
||||
@ -80,7 +80,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
|
||||
Height: int(region.ds1.Height),
|
||||
}
|
||||
|
||||
entities := region.loadEntities(fileProvider)
|
||||
entities := region.loadEntities()
|
||||
region.loadSpecials()
|
||||
region.generateTileCache()
|
||||
|
||||
@ -118,7 +118,7 @@ func (mr *MapRegion) loadSpecials() {
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *MapRegion) loadEntities(fileProvider d2interface.FileProvider) []MapEntity {
|
||||
func (mr *MapRegion) loadEntities() []MapEntity {
|
||||
var entities []MapEntity
|
||||
|
||||
for _, object := range mr.ds1.Objects {
|
||||
@ -127,13 +127,13 @@ func (mr *MapRegion) loadEntities(fileProvider d2interface.FileProvider) []MapEn
|
||||
switch object.Lookup.Type {
|
||||
case d2datadict.ObjectTypeCharacter:
|
||||
if object.Lookup.Base != "" && object.Lookup.Token != "" && object.Lookup.TR != "" {
|
||||
npc := d2core.CreateNPC(int32(worldX), int32(worldY), object.Lookup, fileProvider, 0)
|
||||
npc := d2core.CreateNPC(int32(worldX), int32(worldY), object.Lookup, 0)
|
||||
npc.SetPaths(object.Paths)
|
||||
entities = append(entities, npc)
|
||||
}
|
||||
case d2datadict.ObjectTypeItem:
|
||||
if object.ObjectInfo != nil && object.ObjectInfo.Draw && object.Lookup.Base != "" && object.Lookup.Token != "" {
|
||||
entity := d2render.CreateAnimatedEntity(int32(worldX), int32(worldY), object.Lookup, fileProvider, d2enum.Units)
|
||||
entity := d2render.CreateAnimatedEntity(int32(worldX), int32(worldY), object.Lookup, d2enum.Units)
|
||||
entity.SetMode(object.Lookup.Mode, object.Lookup.Class, 0)
|
||||
entities = append(entities, &entity)
|
||||
}
|
||||
|
@ -1,11 +1,7 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
@ -18,18 +14,18 @@ type Scrollbar struct {
|
||||
maxOffset int
|
||||
lastDirChange int
|
||||
onActivate func()
|
||||
scrollbarSprite d2render.Sprite
|
||||
scrollbarSprite *d2render.Sprite
|
||||
}
|
||||
|
||||
func CreateScrollbar(fileProvider d2interface.FileProvider, x, y, height int) Scrollbar {
|
||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.Scrollbar), d2datadict.Palettes[d2enum.Sky])
|
||||
func CreateScrollbar(x, y, height int) Scrollbar {
|
||||
scrollbarSprite, _ := d2render.LoadSprite(d2resource.Scrollbar, d2resource.PaletteSky)
|
||||
result := Scrollbar{
|
||||
visible: true,
|
||||
enabled: true,
|
||||
x: x,
|
||||
y: y,
|
||||
height: height,
|
||||
scrollbarSprite: d2render.CreateSpriteFromDC6(dc6),
|
||||
scrollbarSprite: scrollbarSprite,
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -76,7 +72,7 @@ func (v Scrollbar) GetLastDirChange() int {
|
||||
return v.lastDirChange
|
||||
}
|
||||
|
||||
func (v *Scrollbar) Draw(target *ebiten.Image) {
|
||||
func (v *Scrollbar) Render(target *ebiten.Image) {
|
||||
if !v.visible || v.maxOffset == 0 {
|
||||
return
|
||||
}
|
||||
@ -84,31 +80,31 @@ func (v *Scrollbar) Draw(target *ebiten.Image) {
|
||||
if !v.enabled {
|
||||
offset = 2
|
||||
}
|
||||
v.scrollbarSprite.MoveTo(v.x, v.y)
|
||||
v.scrollbarSprite.DrawSegments(target, 1, 1, 0+offset)
|
||||
v.scrollbarSprite.MoveTo(v.x, v.y+v.height-10)
|
||||
v.scrollbarSprite.DrawSegments(target, 1, 1, 1+offset)
|
||||
v.scrollbarSprite.SetPosition(v.x, v.y)
|
||||
v.scrollbarSprite.RenderSegmented(target, 1, 1, 0+offset)
|
||||
v.scrollbarSprite.SetPosition(v.x, v.y+v.height-10)
|
||||
v.scrollbarSprite.RenderSegmented(target, 1, 1, 1+offset)
|
||||
if v.maxOffset == 0 || v.currentOffset < 0 || v.currentOffset > v.maxOffset {
|
||||
return
|
||||
}
|
||||
v.scrollbarSprite.MoveTo(v.x, v.y+10+v.getBarPosition())
|
||||
v.scrollbarSprite.SetPosition(v.x, v.y+10+v.getBarPosition())
|
||||
offset = 0
|
||||
if !v.enabled {
|
||||
offset = 1
|
||||
}
|
||||
v.scrollbarSprite.DrawSegments(target, 1, 1, 4+offset)
|
||||
v.scrollbarSprite.RenderSegmented(target, 1, 1, 4+offset)
|
||||
}
|
||||
|
||||
func (v *Scrollbar) GetSize() (width, height uint32) {
|
||||
return 10, uint32(v.height)
|
||||
func (v *Scrollbar) GetSize() (width, height int) {
|
||||
return 10, int(v.height)
|
||||
}
|
||||
|
||||
func (v *Scrollbar) MoveTo(x, y int) {
|
||||
func (v *Scrollbar) SetPosition(x, y int) {
|
||||
v.x = x
|
||||
v.y = y
|
||||
}
|
||||
|
||||
func (v *Scrollbar) GetLocation() (x, y int) {
|
||||
func (v *Scrollbar) GetPosition() (x, y int) {
|
||||
return v.x, v.y
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,14 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
@ -50,26 +43,26 @@ const (
|
||||
|
||||
// ButtonLayout defines the type of buttons
|
||||
type ButtonLayout struct {
|
||||
XSegments int //1
|
||||
YSegments int // 1
|
||||
ResourceName string // Font Name
|
||||
PaletteName d2enum.PaletteType // PaletteType
|
||||
Toggleable bool // false
|
||||
BaseFrame int // 0
|
||||
DisabledFrame int // -1
|
||||
FontPath string // ResourcePaths.FontExocet10
|
||||
ClickableRect *image.Rectangle // nil
|
||||
AllowFrameChange bool // true
|
||||
TextOffset int // 0
|
||||
XSegments int //1
|
||||
YSegments int // 1
|
||||
ResourceName string // Font Name
|
||||
PaletteName string // PaletteType
|
||||
Toggleable bool // false
|
||||
BaseFrame int // 0
|
||||
DisabledFrame int // -1
|
||||
FontPath string // ResourcePaths.FontExocet10
|
||||
ClickableRect *image.Rectangle // nil
|
||||
AllowFrameChange bool // true
|
||||
TextOffset int // 0
|
||||
}
|
||||
|
||||
// ButtonLayouts define the type of buttons you can have
|
||||
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
||||
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2enum.Units, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
||||
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2enum.Units, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
||||
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2enum.Units, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
||||
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2enum.Units, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
||||
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2enum.Units, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
||||
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
||||
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
||||
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
||||
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
||||
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
||||
/*
|
||||
{eButtonType.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } },
|
||||
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } },
|
||||
@ -96,11 +89,10 @@ var ButtonLayouts = map[ButtonType]ButtonLayout{
|
||||
type Button struct {
|
||||
enabled bool
|
||||
x, y int
|
||||
width, height uint32
|
||||
width, height int
|
||||
visible bool
|
||||
pressed bool
|
||||
toggled bool
|
||||
fileProvider d2interface.FileProvider
|
||||
normalImage *ebiten.Image
|
||||
pressedImage *ebiten.Image
|
||||
toggledImage *ebiten.Image
|
||||
@ -111,59 +103,57 @@ type Button struct {
|
||||
}
|
||||
|
||||
// CreateButton creates an instance of Button
|
||||
func CreateButton(buttonType ButtonType, fileProvider d2interface.FileProvider, text string) Button {
|
||||
func CreateButton(buttonType ButtonType, text string) Button {
|
||||
result := Button{
|
||||
fileProvider: fileProvider,
|
||||
width: 0,
|
||||
height: 0,
|
||||
visible: true,
|
||||
enabled: true,
|
||||
pressed: false,
|
||||
width: 0,
|
||||
height: 0,
|
||||
visible: true,
|
||||
enabled: true,
|
||||
pressed: false,
|
||||
}
|
||||
buttonLayout := ButtonLayouts[buttonType]
|
||||
result.buttonLayout = buttonLayout
|
||||
font := GetFont(buttonLayout.FontPath, d2enum.Units, fileProvider)
|
||||
font := GetFont(buttonLayout.FontPath, d2resource.PaletteUnits)
|
||||
|
||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(buttonLayout.ResourceName), d2datadict.Palettes[buttonLayout.PaletteName])
|
||||
buttonSprite := d2render.CreateSpriteFromDC6(dc6)
|
||||
totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
||||
buttonSprite, _ := d2render.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
||||
totalButtonTypes := buttonSprite.GetFrameCount() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
||||
for i := 0; i < buttonLayout.XSegments; i++ {
|
||||
w, _ := buttonSprite.GetFrameSize(i)
|
||||
w, _, _ := buttonSprite.GetFrameSize(i)
|
||||
result.width += w
|
||||
}
|
||||
for i := 0; i < buttonLayout.YSegments; i++ {
|
||||
_, h := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
||||
_, h, _ := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
||||
result.height += h
|
||||
}
|
||||
|
||||
result.normalImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
_, fontHeight := font.GetTextMetrics(text)
|
||||
textY := int((result.height/2)-(fontHeight/2)) + buttonLayout.TextOffset
|
||||
textY := int((result.height/2)-(int(fontHeight)/2)) + buttonLayout.TextOffset
|
||||
|
||||
buttonSprite.MoveTo(0, 0)
|
||||
buttonSprite.Blend = true
|
||||
buttonSprite.DrawSegments(result.normalImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalImage)
|
||||
buttonSprite.SetPosition(0, 0)
|
||||
buttonSprite.SetBlend(true)
|
||||
buttonSprite.RenderSegmented(result.normalImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
||||
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalImage)
|
||||
if buttonLayout.AllowFrameChange {
|
||||
if totalButtonTypes > 1 {
|
||||
result.pressedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
buttonSprite.DrawSegments(result.pressedImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
||||
font.Draw(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
|
||||
buttonSprite.RenderSegmented(result.pressedImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
||||
font.Render(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
|
||||
}
|
||||
if totalButtonTypes > 2 {
|
||||
result.toggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
buttonSprite.DrawSegments(result.toggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
|
||||
buttonSprite.RenderSegmented(result.toggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
||||
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
|
||||
}
|
||||
if totalButtonTypes > 3 {
|
||||
result.pressedToggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
buttonSprite.DrawSegments(result.pressedToggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
|
||||
buttonSprite.RenderSegmented(result.pressedToggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
||||
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
|
||||
}
|
||||
if buttonLayout.DisabledFrame != -1 {
|
||||
result.disabledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
buttonSprite.DrawSegments(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
|
||||
buttonSprite.RenderSegmented(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
||||
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
|
||||
}
|
||||
}
|
||||
return result
|
||||
@ -182,8 +172,8 @@ func (v *Button) Activate() {
|
||||
v.onClick()
|
||||
}
|
||||
|
||||
// Draw renders the button
|
||||
func (v Button) Draw(target *ebiten.Image) {
|
||||
// Render renders the button
|
||||
func (v Button) Render(target *ebiten.Image) {
|
||||
opts := &ebiten.DrawImageOptions{
|
||||
CompositeMode: ebiten.CompositeModeSourceAtop,
|
||||
Filter: ebiten.FilterNearest,
|
||||
@ -216,18 +206,18 @@ func (v *Button) SetEnabled(enabled bool) {
|
||||
}
|
||||
|
||||
// GetSize returns the size of the button
|
||||
func (v Button) GetSize() (uint32, uint32) {
|
||||
func (v Button) GetSize() (int, int) {
|
||||
return v.width, v.height
|
||||
}
|
||||
|
||||
// MoveTo moves the button
|
||||
func (v *Button) MoveTo(x, y int) {
|
||||
// SetPosition moves the button
|
||||
func (v *Button) SetPosition(x, y int) {
|
||||
v.x = x
|
||||
v.y = y
|
||||
}
|
||||
|
||||
// GetLocation returns the location of the button
|
||||
func (v Button) GetLocation() (x, y int) {
|
||||
// GetPosition returns the location of the button
|
||||
func (v Button) GetPosition() (x, y int) {
|
||||
return v.x, v.y
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
@ -14,14 +10,14 @@ type Checkbox struct {
|
||||
x, y int
|
||||
checkState bool
|
||||
visible bool
|
||||
width, height uint32
|
||||
width, height int
|
||||
Image *ebiten.Image
|
||||
checkedImage *ebiten.Image
|
||||
onClick func()
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func CreateCheckbox(fileProvider d2interface.FileProvider, checkState bool) Checkbox {
|
||||
func CreateCheckbox(checkState bool) Checkbox {
|
||||
result := Checkbox{
|
||||
checkState: checkState,
|
||||
visible: true,
|
||||
@ -29,20 +25,19 @@ func CreateCheckbox(fileProvider d2interface.FileProvider, checkState bool) Chec
|
||||
height: 0,
|
||||
enabled: true,
|
||||
}
|
||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.Checkbox), d2datadict.Palettes[d2enum.Fechar])
|
||||
checkboxSprite := d2render.CreateSpriteFromDC6(dc6)
|
||||
result.width, result.height = checkboxSprite.GetFrameSize(0)
|
||||
checkboxSprite.MoveTo(0, 0)
|
||||
checkboxSprite, _ := d2render.LoadSprite(d2resource.Checkbox, d2resource.PaletteFechar)
|
||||
result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
|
||||
checkboxSprite.SetPosition(0, 0)
|
||||
|
||||
result.Image, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
checkboxSprite.DrawSegments(result.Image, 1, 1, 0)
|
||||
checkboxSprite.RenderSegmented(result.Image, 1, 1, 0)
|
||||
|
||||
result.checkedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
checkboxSprite.DrawSegments(result.checkedImage, 1, 1, 1)
|
||||
checkboxSprite.RenderSegmented(result.checkedImage, 1, 1, 1)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v Checkbox) Draw(target *ebiten.Image) {
|
||||
func (v Checkbox) Render(target *ebiten.Image) {
|
||||
opts := &ebiten.DrawImageOptions{
|
||||
CompositeMode: ebiten.CompositeModeSourceAtop,
|
||||
Filter: ebiten.FilterNearest,
|
||||
@ -89,11 +84,11 @@ func (v *Checkbox) Activate() {
|
||||
v.onClick()
|
||||
}
|
||||
|
||||
func (v Checkbox) GetLocation() (int, int) {
|
||||
func (v Checkbox) GetPosition() (int, int) {
|
||||
return v.x, v.y
|
||||
}
|
||||
|
||||
func (v Checkbox) GetSize() (uint32, uint32) {
|
||||
func (v Checkbox) GetSize() (int, int) {
|
||||
return v.width, v.height
|
||||
}
|
||||
|
||||
@ -101,7 +96,7 @@ func (v Checkbox) GetVisible() bool {
|
||||
return v.visible
|
||||
}
|
||||
|
||||
func (v *Checkbox) MoveTo(x int, y int) {
|
||||
func (v *Checkbox) SetPosition(x int, y int) {
|
||||
v.x = x
|
||||
v.y = y
|
||||
}
|
||||
|
@ -1,18 +1,12 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"image/color"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
@ -32,33 +26,32 @@ type FontSize struct {
|
||||
|
||||
// Font represents a font
|
||||
type Font struct {
|
||||
fontSprite d2render.Sprite
|
||||
fontSprite *d2render.Sprite
|
||||
fontTable map[uint16]uint16
|
||||
metrics map[uint16]FontSize
|
||||
}
|
||||
|
||||
// GetFont creates or loads an existing font
|
||||
func GetFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font {
|
||||
cacheItem, exists := fontCache[font+"_"+string(palette)]
|
||||
func GetFont(fontPath string, palettePath string) *Font {
|
||||
cacheItem, exists := fontCache[fontPath+"_"+palettePath]
|
||||
if exists {
|
||||
return cacheItem
|
||||
}
|
||||
newFont := CreateFont(font, palette, fileProvider)
|
||||
fontCache[font+"_"+string(palette)] = newFont
|
||||
newFont := CreateFont(fontPath, palettePath)
|
||||
fontCache[fontPath+"_"+palettePath] = newFont
|
||||
return newFont
|
||||
}
|
||||
|
||||
// CreateFont creates an instance of a MPQ Font
|
||||
func CreateFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font {
|
||||
func CreateFont(font string, palettePath string) *Font {
|
||||
result := &Font{
|
||||
fontTable: make(map[uint16]uint16),
|
||||
metrics: make(map[uint16]FontSize),
|
||||
}
|
||||
// bug: performance issue when using CJK fonts, because ten thousand frames will be rendered PER font
|
||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(font+".dc6"), d2datadict.Palettes[palette])
|
||||
result.fontSprite = d2render.CreateSpriteFromDC6(dc6)
|
||||
result.fontSprite, _ = d2render.LoadSprite(font+".dc6", palettePath)
|
||||
woo := "Woo!\x01"
|
||||
fontData := fileProvider.LoadFile(font + ".tbl")
|
||||
fontData := d2asset.MustLoadFile(font + ".tbl")
|
||||
if string(fontData[0:5]) != woo {
|
||||
panic("No woo :(")
|
||||
}
|
||||
@ -89,18 +82,14 @@ func CreateFont(font string, palette d2enum.PaletteType, fileProvider d2interfac
|
||||
}
|
||||
|
||||
// GetTextMetrics returns the size of the specified text
|
||||
func (v *Font) GetTextMetrics(text string) (width, height uint32) {
|
||||
width = uint32(0)
|
||||
curWidth := uint32(0)
|
||||
height = uint32(0)
|
||||
maxCharHeight := uint32(0)
|
||||
// todo: it can be saved as a struct member, since it only depends on `.Frames`
|
||||
for _, m := range v.fontSprite.Frames {
|
||||
maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height))
|
||||
}
|
||||
func (v *Font) GetTextMetrics(text string) (width, height int) {
|
||||
width = int(0)
|
||||
curWidth := int(0)
|
||||
height = int(0)
|
||||
_, maxCharHeight := v.fontSprite.GetFrameBounds()
|
||||
for _, ch := range text {
|
||||
if ch == '\n' {
|
||||
width = d2helper.Max(width, curWidth)
|
||||
width = d2helper.MaxInt(width, curWidth)
|
||||
curWidth = 0
|
||||
height += maxCharHeight + 6
|
||||
continue
|
||||
@ -108,15 +97,15 @@ func (v *Font) GetTextMetrics(text string) (width, height uint32) {
|
||||
|
||||
curWidth += v.getCharWidth(ch)
|
||||
}
|
||||
width = d2helper.Max(width, curWidth)
|
||||
width = d2helper.MaxInt(width, curWidth)
|
||||
height += maxCharHeight
|
||||
return
|
||||
}
|
||||
|
||||
// Draw draws the font on the target surface
|
||||
func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Image) {
|
||||
v.fontSprite.ColorMod = color
|
||||
v.fontSprite.Blend = false
|
||||
// Render draws the font on the target surface
|
||||
func (v *Font) Render(x, y int, text string, color color.Color, target *ebiten.Image) {
|
||||
v.fontSprite.SetColorMod(color)
|
||||
v.fontSprite.SetBlend(false)
|
||||
|
||||
maxCharHeight := uint32(0)
|
||||
for _, m := range v.metrics {
|
||||
@ -132,9 +121,10 @@ func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Ima
|
||||
for _, ch := range line {
|
||||
width := v.getCharWidth(ch)
|
||||
index := v.fontTable[uint16(ch)]
|
||||
v.fontSprite.Frame = int16(index)
|
||||
v.fontSprite.MoveTo(xPos, y+int(v.fontSprite.Frames[index].Height))
|
||||
v.fontSprite.Draw(target)
|
||||
v.fontSprite.SetCurrentFrame(int(index))
|
||||
_, height := v.fontSprite.GetCurrentFrameSize()
|
||||
v.fontSprite.SetPosition(xPos, y+int(height))
|
||||
v.fontSprite.Render(target)
|
||||
xPos += int(width)
|
||||
}
|
||||
|
||||
@ -147,9 +137,9 @@ func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Ima
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Font) getCharWidth(char rune) (width uint32) {
|
||||
func (v *Font) getCharWidth(char rune) (width int) {
|
||||
if char < unicode.MaxLatin1 {
|
||||
return uint32(v.metrics[uint16(char)].Width)
|
||||
return int(v.metrics[uint16(char)].Width)
|
||||
}
|
||||
return uint32(v.metrics[unicode.MaxLatin1].Width)
|
||||
return int(v.metrics[unicode.MaxLatin1].Width)
|
||||
}
|
||||
|
@ -3,10 +3,6 @@ package d2ui
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
@ -27,8 +23,8 @@ type Label struct {
|
||||
text string
|
||||
X int
|
||||
Y int
|
||||
Width uint32
|
||||
Height uint32
|
||||
Width int
|
||||
Height int
|
||||
Alignment LabelAlignment
|
||||
font *Font
|
||||
imageData *ebiten.Image
|
||||
@ -36,17 +32,17 @@ type Label struct {
|
||||
}
|
||||
|
||||
// CreateLabel creates a new instance of a UI label
|
||||
func CreateLabel(provider d2interface.FileProvider, font string, palette d2enum.PaletteType) Label {
|
||||
func CreateLabel(fontPath, palettePath string) Label {
|
||||
result := Label{
|
||||
Alignment: LabelAlignLeft,
|
||||
Color: color.White,
|
||||
font: GetFont(font, palette, provider),
|
||||
font: GetFont(fontPath, palettePath),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Draw draws the label on the screen
|
||||
func (v *Label) Draw(target *ebiten.Image) {
|
||||
// Render draws the label on the screen
|
||||
func (v *Label) Render(target *ebiten.Image) {
|
||||
if len(v.text) == 0 {
|
||||
return
|
||||
}
|
||||
@ -65,13 +61,13 @@ func (v *Label) Draw(target *ebiten.Image) {
|
||||
target.DrawImage(v.imageData, opts)
|
||||
}
|
||||
|
||||
// MoveTo moves the label to the specified location
|
||||
func (v *Label) MoveTo(x, y int) {
|
||||
// SetPosition moves the label to the specified location
|
||||
func (v *Label) SetPosition(x, y int) {
|
||||
v.X = x
|
||||
v.Y = y
|
||||
}
|
||||
|
||||
func (v *Label) GetTextMetrics(text string) (width, height uint32) {
|
||||
func (v *Label) GetTextMetrics(text string) (width, height int) {
|
||||
return v.font.GetTextMetrics(text)
|
||||
}
|
||||
|
||||
@ -83,7 +79,7 @@ func (v *Label) cacheImage() {
|
||||
v.Width = width
|
||||
v.Height = height
|
||||
v.imageData, _ = ebiten.NewImage(int(width), int(height), ebiten.FilterNearest)
|
||||
v.font.Draw(0, 0, v.text, v.Color, v.imageData)
|
||||
v.font.Render(0, 0, v.text, v.Color, v.imageData)
|
||||
}
|
||||
|
||||
// SetText sets the label's text
|
||||
@ -96,7 +92,7 @@ func (v *Label) SetText(newText string) {
|
||||
}
|
||||
|
||||
// GetSize returns the size of the label
|
||||
func (v Label) GetSize() (width, height uint32) {
|
||||
func (v Label) GetSize() (width, height int) {
|
||||
v.cacheImage()
|
||||
width = v.Width
|
||||
height = v.Height
|
||||
|
@ -1,12 +1,8 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
@ -24,7 +20,7 @@ const (
|
||||
// Manager represents the UI manager
|
||||
type Manager struct {
|
||||
widgets []Widget
|
||||
cursorSprite d2render.Sprite
|
||||
cursorSprite *d2render.Sprite
|
||||
cursorButtons CursorButton
|
||||
pressedIndex int
|
||||
CursorX int
|
||||
@ -34,12 +30,11 @@ type Manager struct {
|
||||
}
|
||||
|
||||
// CreateManager creates a new instance of a UI manager
|
||||
func CreateManager(fileProvider d2interface.FileProvider, soundManager d2audio.Manager) *Manager {
|
||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.CursorDefault), d2datadict.Palettes[d2enum.Units])
|
||||
func CreateManager(soundManager d2audio.Manager) *Manager {
|
||||
cursorSprite, _ := d2render.LoadSprite(d2resource.CursorDefault, d2resource.PaletteUnits)
|
||||
result := &Manager{
|
||||
pressedIndex: -1,
|
||||
widgets: make([]Widget, 0),
|
||||
cursorSprite: d2render.CreateSpriteFromDC6(dc6),
|
||||
cursorSprite: cursorSprite,
|
||||
clickSfx: soundManager.LoadSoundEffect(d2resource.SFXButtonClick),
|
||||
waitForLeftMouseUp: false,
|
||||
}
|
||||
@ -62,18 +57,18 @@ func (v *Manager) WaitForMouseRelease() {
|
||||
v.waitForLeftMouseUp = true
|
||||
}
|
||||
|
||||
// Draw renders all of the UI elements
|
||||
func (v *Manager) Draw(screen *ebiten.Image) {
|
||||
// Render renders all of the UI elements
|
||||
func (v *Manager) Render(screen *ebiten.Image) {
|
||||
for _, widget := range v.widgets {
|
||||
if !widget.GetVisible() {
|
||||
continue
|
||||
}
|
||||
widget.Draw(screen)
|
||||
widget.Render(screen)
|
||||
}
|
||||
|
||||
cx, cy := ebiten.CursorPosition()
|
||||
v.cursorSprite.MoveTo(cx, cy)
|
||||
v.cursorSprite.Draw(screen)
|
||||
v.cursorSprite.SetPosition(cx, cy)
|
||||
v.cursorSprite.Render(screen)
|
||||
}
|
||||
|
||||
// Update updates all of the UI elements
|
||||
@ -98,7 +93,7 @@ func (v *Manager) Update() {
|
||||
if !widget.GetVisible() || !widget.GetEnabled() {
|
||||
continue
|
||||
}
|
||||
wx, wy := widget.GetLocation()
|
||||
wx, wy := widget.GetPosition()
|
||||
ww, wh := widget.GetSize()
|
||||
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
||||
widget.SetPressed(true)
|
||||
@ -125,7 +120,7 @@ func (v *Manager) Update() {
|
||||
} else {
|
||||
if v.pressedIndex > -1 {
|
||||
widget := v.widgets[v.pressedIndex]
|
||||
wx, wy := widget.GetLocation()
|
||||
wx, wy := widget.GetPosition()
|
||||
ww, wh := widget.GetSize()
|
||||
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
||||
widget.Activate()
|
||||
|
@ -1,16 +1,12 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/inpututil"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
@ -22,17 +18,17 @@ type TextBox struct {
|
||||
y int
|
||||
visible bool
|
||||
enabled bool
|
||||
bgSprite d2render.Sprite
|
||||
bgSprite *d2render.Sprite
|
||||
textLabel Label
|
||||
lineBar Label
|
||||
}
|
||||
|
||||
func CreateTextbox(fileProvider d2interface.FileProvider) TextBox {
|
||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.TextBox2), d2datadict.Palettes[d2enum.Units])
|
||||
func CreateTextbox() TextBox {
|
||||
bgSprite, _ := d2render.LoadSprite(d2resource.TextBox2, d2resource.PaletteUnits)
|
||||
result := TextBox{
|
||||
bgSprite: d2render.CreateSpriteFromDC6(dc6),
|
||||
textLabel: CreateLabel(fileProvider, d2resource.FontFormal11, d2enum.Units),
|
||||
lineBar: CreateLabel(fileProvider, d2resource.FontFormal11, d2enum.Units),
|
||||
bgSprite: bgSprite,
|
||||
textLabel: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
||||
lineBar: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
||||
enabled: true,
|
||||
visible: true,
|
||||
}
|
||||
@ -55,14 +51,14 @@ func repeatingKeyPressed(key ebiten.Key) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (v TextBox) Draw(target *ebiten.Image) {
|
||||
func (v TextBox) Render(target *ebiten.Image) {
|
||||
if !v.visible {
|
||||
return
|
||||
}
|
||||
v.bgSprite.Draw(target)
|
||||
v.textLabel.Draw(target)
|
||||
v.bgSprite.Render(target)
|
||||
v.textLabel.Render(target)
|
||||
if (time.Now().UnixNano()/1e6)&(1<<8) > 0 {
|
||||
v.lineBar.Draw(target)
|
||||
v.lineBar.Render(target)
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,25 +101,25 @@ func (v *TextBox) SetText(newText string) {
|
||||
result = result[1:]
|
||||
continue
|
||||
}
|
||||
v.lineBar.MoveTo(v.x+6+int(tw), v.y+3)
|
||||
v.lineBar.SetPosition(v.x+6+int(tw), v.y+3)
|
||||
v.textLabel.SetText(result)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func (v TextBox) GetSize() (width, height uint32) {
|
||||
return v.bgSprite.GetSize()
|
||||
func (v TextBox) GetSize() (width, height int) {
|
||||
return v.bgSprite.GetCurrentFrameSize()
|
||||
}
|
||||
|
||||
func (v *TextBox) MoveTo(x, y int) {
|
||||
func (v *TextBox) SetPosition(x, y int) {
|
||||
v.x = x
|
||||
v.y = y
|
||||
v.textLabel.MoveTo(v.x+6, v.y+3)
|
||||
v.lineBar.MoveTo(v.x+6+int(v.textLabel.Width), v.y+3)
|
||||
v.bgSprite.MoveTo(v.x, v.y+26)
|
||||
v.textLabel.SetPosition(v.x+6, v.y+3)
|
||||
v.lineBar.SetPosition(v.x+6+int(v.textLabel.Width), v.y+3)
|
||||
v.bgSprite.SetPosition(v.x, v.y+26)
|
||||
}
|
||||
|
||||
func (v TextBox) GetLocation() (x, y int) {
|
||||
func (v TextBox) GetPosition() (x, y int) {
|
||||
return v.x, v.y
|
||||
}
|
||||
|
||||
|
@ -2,225 +2,179 @@ package d2render
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
// Sprite represents a type of object in D2 that is comprised of one or more frames and directions
|
||||
type Sprite struct {
|
||||
Directions uint32
|
||||
FramesPerDirection uint32
|
||||
Frames []SpriteFrame
|
||||
SpecialFrameTime int
|
||||
AnimateBackwards bool // Because why not
|
||||
StopOnLastFrame bool
|
||||
X, Y int
|
||||
Frame, Direction int16
|
||||
Blend bool
|
||||
LastFrameTime float64
|
||||
Animate bool
|
||||
ColorMod color.Color
|
||||
valid bool
|
||||
x int
|
||||
y int
|
||||
lastFrameTime float64
|
||||
animation *d2asset.Animation
|
||||
}
|
||||
|
||||
// SpriteFrame represents a single frame of a sprite
|
||||
type SpriteFrame struct {
|
||||
Flip uint32
|
||||
Width uint32
|
||||
Height uint32
|
||||
OffsetX int32
|
||||
OffsetY int32
|
||||
Unknown uint32
|
||||
NextBlock uint32
|
||||
Length uint32
|
||||
FrameData []byte
|
||||
Image *ebiten.Image
|
||||
}
|
||||
|
||||
func CreateSpriteFromDC6(dc6 d2dc6.DC6File) Sprite {
|
||||
result := Sprite{
|
||||
X: 50,
|
||||
Y: 50,
|
||||
Frame: 0,
|
||||
Direction: 0,
|
||||
Blend: false,
|
||||
ColorMod: nil,
|
||||
Directions: dc6.Directions,
|
||||
FramesPerDirection: dc6.FramesPerDirection,
|
||||
Animate: false,
|
||||
LastFrameTime: d2helper.Now(),
|
||||
SpecialFrameTime: -1,
|
||||
StopOnLastFrame: false,
|
||||
valid: true,
|
||||
AnimateBackwards: false,
|
||||
func LoadSprite(animationPath, palettePath string) (*Sprite, error) {
|
||||
animation, err := d2asset.LoadAnimation(animationPath, palettePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Frames = make([]SpriteFrame, len(dc6.Frames))
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(dc6.Frames))
|
||||
for i, f := range dc6.Frames {
|
||||
go func(i int, frame *d2dc6.DC6Frame) {
|
||||
defer wg.Done()
|
||||
|
||||
image, err := ebiten.NewImage(int(frame.Width), int(frame.Height), ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Printf("failed to create new image: %v", err)
|
||||
}
|
||||
if err := image.ReplacePixels(frame.ColorData()); err != nil {
|
||||
log.Printf("failed to replace pixels: %v", err)
|
||||
}
|
||||
|
||||
result.Frames[i] = SpriteFrame{
|
||||
Flip: frame.Flipped,
|
||||
Width: frame.Width,
|
||||
Height: frame.Height,
|
||||
OffsetX: frame.OffsetX,
|
||||
OffsetY: frame.OffsetY,
|
||||
Unknown: frame.Unknown,
|
||||
NextBlock: frame.NextBlock,
|
||||
Length: frame.Length,
|
||||
Image: image,
|
||||
}
|
||||
}(i, f)
|
||||
}
|
||||
wg.Wait()
|
||||
return result
|
||||
return &Sprite{lastFrameTime: d2helper.Now(), animation: animation}, nil
|
||||
}
|
||||
|
||||
func (v Sprite) IsValid() bool {
|
||||
return v.valid
|
||||
func MustLoadSprite(animationPath, palettePath string) *Sprite {
|
||||
sprite, err := LoadSprite(animationPath, palettePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return sprite
|
||||
}
|
||||
|
||||
// GetSize returns the size of the sprite
|
||||
func (v Sprite) GetSize() (uint32, uint32) {
|
||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||
return frame.Width, frame.Height
|
||||
func (s *Sprite) Render(target *ebiten.Image) error {
|
||||
if err := s.advance(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, frameHeight := s.animation.GetCurrentFrameSize()
|
||||
|
||||
if err := s.animation.Render(target, s.x, s.y-frameHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Sprite) updateAnimation() {
|
||||
if !v.Animate {
|
||||
return
|
||||
func (s *Sprite) RenderSegmented(target *ebiten.Image, segmentsX, segmentsY, frameOffset int) error {
|
||||
if err := s.advance(); err != nil {
|
||||
return err
|
||||
}
|
||||
var timePerFrame float64
|
||||
|
||||
if v.SpecialFrameTime >= 0 {
|
||||
timePerFrame = (float64(v.SpecialFrameTime) / float64(len(v.Frames))) / 1000.0
|
||||
} else {
|
||||
timePerFrame = 1.0 / float64(len(v.Frames))
|
||||
}
|
||||
now := d2helper.Now()
|
||||
for v.LastFrameTime+timePerFrame < now {
|
||||
v.LastFrameTime += timePerFrame
|
||||
if !v.AnimateBackwards {
|
||||
v.Frame++
|
||||
if v.Frame >= int16(v.FramesPerDirection) {
|
||||
if v.StopOnLastFrame {
|
||||
v.Frame = int16(v.FramesPerDirection) - 1
|
||||
} else {
|
||||
v.Frame = 0
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
v.Frame--
|
||||
if v.Frame < 0 {
|
||||
if v.StopOnLastFrame {
|
||||
v.Frame = 0
|
||||
} else {
|
||||
v.Frame = int16(v.FramesPerDirection) - 1
|
||||
var currentY int
|
||||
for y := 0; y < segmentsY; y++ {
|
||||
var currentX int
|
||||
var maxFrameHeight int
|
||||
for x := 0; x < segmentsX; x++ {
|
||||
if err := s.animation.SetCurrentFrame(x + y*segmentsX + frameOffset*segmentsX*segmentsY); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.animation.Render(target, s.x+currentX, s.y+currentY); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
frameWidth, frameHeight := s.GetCurrentFrameSize()
|
||||
maxFrameHeight = d2helper.MaxInt(maxFrameHeight, frameHeight)
|
||||
currentX += frameWidth
|
||||
}
|
||||
|
||||
currentY += maxFrameHeight
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Sprite) ResetAnimation() {
|
||||
v.LastFrameTime = d2helper.Now()
|
||||
v.Frame = 0
|
||||
func (s *Sprite) SetPosition(x, y int) {
|
||||
s.x = x
|
||||
s.y = y
|
||||
}
|
||||
|
||||
func (v Sprite) OnLastFrame() bool {
|
||||
return v.Frame == int16(v.FramesPerDirection-1)
|
||||
func (s *Sprite) GetPosition() (int, int) {
|
||||
return s.x, s.y
|
||||
}
|
||||
|
||||
// GetFrameSize returns the size of the specific frame
|
||||
func (v Sprite) GetFrameSize(frame int) (width, height uint32) {
|
||||
width = v.Frames[frame].Width
|
||||
height = v.Frames[frame].Height
|
||||
return
|
||||
func (s *Sprite) GetFrameSize(frameIndex int) (int, int, error) {
|
||||
return s.animation.GetFrameSize(frameIndex)
|
||||
}
|
||||
|
||||
// GetTotalFrames returns the number of frames in this sprite (for all directions)
|
||||
func (v Sprite) GetTotalFrames() int {
|
||||
return len(v.Frames)
|
||||
func (s *Sprite) GetCurrentFrameSize() (int, int) {
|
||||
return s.animation.GetCurrentFrameSize()
|
||||
}
|
||||
|
||||
// Draw draws the sprite onto the target
|
||||
func (v *Sprite) Draw(target *ebiten.Image) {
|
||||
v.updateAnimation()
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||
opts.GeoM.Translate(
|
||||
float64(int32(v.X)+frame.OffsetX),
|
||||
float64(int32(v.Y)-int32(frame.Height)+frame.OffsetY),
|
||||
)
|
||||
if v.Blend {
|
||||
opts.CompositeMode = ebiten.CompositeModeLighter
|
||||
} else {
|
||||
opts.CompositeMode = ebiten.CompositeModeSourceOver
|
||||
}
|
||||
if v.ColorMod != nil {
|
||||
opts.ColorM = d2corehelper.ColorToColorM(v.ColorMod)
|
||||
}
|
||||
if err := target.DrawImage(frame.Image, opts); err != nil {
|
||||
log.Panic(err.Error())
|
||||
func (s *Sprite) GetFrameBounds() (int, int) {
|
||||
return s.animation.GetFrameBounds()
|
||||
}
|
||||
|
||||
func (s *Sprite) GetCurrentFrame() int {
|
||||
return s.animation.GetCurrentFrame()
|
||||
}
|
||||
|
||||
func (s *Sprite) GetFrameCount() int {
|
||||
return s.animation.GetFrameCount()
|
||||
}
|
||||
|
||||
func (s *Sprite) IsOnFirstFrame() bool {
|
||||
return s.animation.IsOnFirstFrame()
|
||||
}
|
||||
|
||||
func (s *Sprite) IsOnLastFrame() bool {
|
||||
return s.animation.IsOnLastFrame()
|
||||
}
|
||||
|
||||
func (s *Sprite) GetDirectionCount() int {
|
||||
return s.animation.GetDirectionCount()
|
||||
}
|
||||
|
||||
func (s *Sprite) SetDirection(directionIndex int) error {
|
||||
return s.animation.SetDirection(directionIndex)
|
||||
}
|
||||
|
||||
func (s *Sprite) GetDirection() int {
|
||||
return s.animation.GetDirection()
|
||||
}
|
||||
|
||||
func (s *Sprite) SetCurrentFrame(frameIndex int) error {
|
||||
s.lastFrameTime = d2helper.Now()
|
||||
return s.animation.SetCurrentFrame(frameIndex)
|
||||
}
|
||||
|
||||
func (s *Sprite) Rewind() {
|
||||
s.lastFrameTime = d2helper.Now()
|
||||
s.animation.SetCurrentFrame(0)
|
||||
}
|
||||
|
||||
func (s *Sprite) PlayForward() {
|
||||
s.lastFrameTime = d2helper.Now()
|
||||
s.animation.PlayForward()
|
||||
}
|
||||
|
||||
func (s *Sprite) PlayBackward() {
|
||||
s.lastFrameTime = d2helper.Now()
|
||||
s.animation.PlayBackward()
|
||||
}
|
||||
|
||||
func (s *Sprite) Pause() {
|
||||
s.animation.Pause()
|
||||
}
|
||||
|
||||
func (s *Sprite) SetPlayLoop(loop bool) {
|
||||
s.animation.SetPlayLoop(loop)
|
||||
}
|
||||
|
||||
func (s *Sprite) SetPlayLength(playLength float64) {
|
||||
s.animation.SetPlayLength(playLength)
|
||||
}
|
||||
|
||||
func (s *Sprite) SetPlayLengthMs(playLengthMs int) {
|
||||
s.animation.SetPlayLengthMs(playLengthMs)
|
||||
}
|
||||
|
||||
func (s *Sprite) SetColorMod(color color.Color) {
|
||||
s.animation.SetColorMod(color)
|
||||
}
|
||||
|
||||
func (s *Sprite) SetBlend(blend bool) {
|
||||
s.animation.SetBlend(blend)
|
||||
}
|
||||
|
||||
func (s *Sprite) advance() error {
|
||||
lastFrameTime := d2helper.Now()
|
||||
if err := s.animation.Advance(lastFrameTime - s.lastFrameTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// DrawSegments draws the sprite via a grid of segments
|
||||
func (v *Sprite) DrawSegments(target *ebiten.Image, xSegments, ySegments, offset int) {
|
||||
v.updateAnimation()
|
||||
yOffset := int32(0)
|
||||
for y := 0; y < ySegments; y++ {
|
||||
xOffset := int32(0)
|
||||
biggestYOffset := int32(0)
|
||||
for x := 0; x < xSegments; x++ {
|
||||
frame := v.Frames[uint32(x+(y*xSegments)+(offset*xSegments*ySegments))]
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
opts.GeoM.Translate(
|
||||
float64(int32(v.X)+frame.OffsetX+xOffset),
|
||||
float64(int32(v.Y)+frame.OffsetY+yOffset),
|
||||
)
|
||||
if v.Blend {
|
||||
opts.CompositeMode = ebiten.CompositeModeLighter
|
||||
} else {
|
||||
opts.CompositeMode = ebiten.CompositeModeSourceOver
|
||||
}
|
||||
if v.ColorMod != nil {
|
||||
opts.ColorM = d2corehelper.ColorToColorM(v.ColorMod)
|
||||
}
|
||||
if err := target.DrawImage(frame.Image, opts); err != nil {
|
||||
log.Panic(err.Error())
|
||||
}
|
||||
xOffset += int32(frame.Width)
|
||||
biggestYOffset = d2helper.MaxInt32(biggestYOffset, int32(frame.Height))
|
||||
}
|
||||
yOffset += biggestYOffset
|
||||
}
|
||||
}
|
||||
|
||||
// MoveTo moves the sprite to the specified coordinates
|
||||
func (v *Sprite) MoveTo(x, y int) {
|
||||
v.X = x
|
||||
v.Y = y
|
||||
}
|
||||
|
||||
// GetLocation returns the location of the sprite
|
||||
func (v Sprite) GetLocation() (int, int) {
|
||||
return v.X, v.Y
|
||||
s.lastFrameTime = lastFrameTime
|
||||
return nil
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/OpenDiablo2/OpenDiablo2
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/OpenDiablo2/D2Shared v0.0.0-20191220005230-1cbc4e1fb658
|
||||
github.com/OpenDiablo2/D2Shared v0.0.0-20191222011122-c8cfab029ae6
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.1.0.20191219185932-f3712a7e620b
|
||||
|
4
go.sum
4
go.sum
@ -2,8 +2,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0 h1:tDnuU0igiBiQFjsvq1Bi7DpoUjqI76VVvW045vpeFeM=
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0/go.mod h1:h/5OEGj4G+fpYxluLjSMZbFY011ZxAntO98nCl8mrCs=
|
||||
github.com/OpenDiablo2/D2Shared v0.0.0-20191220005230-1cbc4e1fb658 h1:ZNi/kW/9Lt5vL/XLXeSlAGLcSwq+eqiWLowWfjPXfxw=
|
||||
github.com/OpenDiablo2/D2Shared v0.0.0-20191220005230-1cbc4e1fb658/go.mod h1:mY8Ll5/iLRAQsaHvIdqSZiHX3aFCys/Q4Sot+xYpero=
|
||||
github.com/OpenDiablo2/D2Shared v0.0.0-20191222011122-c8cfab029ae6 h1:9TXDUOedNtivxLPiuWMMPxH+aTbKZQv2QBb9lpiZb/8=
|
||||
github.com/OpenDiablo2/D2Shared v0.0.0-20191222011122-c8cfab029ae6/go.mod h1:mY8Ll5/iLRAQsaHvIdqSZiHX3aFCys/Q4Sot+xYpero=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
|
4
main.go
4
main.go
@ -47,9 +47,9 @@ func main() {
|
||||
d2Engine = d2core.CreateEngine()
|
||||
kingpin.Parse()
|
||||
if *region == 0 {
|
||||
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
|
||||
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
|
||||
} else {
|
||||
d2Engine.SetNextScene(d2scene.CreateMapEngineTest(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager, *region, *preset))
|
||||
d2Engine.SetNextScene(d2scene.CreateMapEngineTest(&d2Engine, d2Engine.UIManager, d2Engine.SoundManager, *region, *preset))
|
||||
}
|
||||
ebiten.SetCursorVisible(false)
|
||||
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
|
||||
|
Loading…
Reference in New Issue
Block a user