mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-09-27 13:46:00 -04: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 (
|
import (
|
||||||
"errors"
|
"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 (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/audio"
|
"github.com/hajimehoshi/ebiten/audio"
|
||||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manager provides sound
|
// Manager provides sound
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
audioContext *audio.Context // The Audio context
|
audioContext *audio.Context // The Audio context
|
||||||
bgmAudio *audio.Player // The audio player
|
bgmAudio *audio.Player // The audio player
|
||||||
lastBgm string
|
lastBgm string
|
||||||
@ -20,10 +18,8 @@ type Manager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateManager creates a sound provider
|
// CreateManager creates a sound provider
|
||||||
func CreateManager(fileProvider d2interface.FileProvider) *Manager {
|
func CreateManager() *Manager {
|
||||||
result := &Manager{
|
result := &Manager{}
|
||||||
fileProvider: fileProvider,
|
|
||||||
}
|
|
||||||
audioContext, err := audio.NewContext(44100)
|
audioContext, err := audio.NewContext(44100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -49,7 +45,7 @@ func (v *Manager) PlayBGM(song string) {
|
|||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
audioData := v.fileProvider.LoadFile(song)
|
audioData := d2asset.MustLoadFile(song)
|
||||||
d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData))
|
d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -73,7 +69,7 @@ func (v *Manager) PlayBGM(song string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Manager) LoadSoundEffect(sfx string) *SoundEffect {
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,8 @@ package d2audio
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ type SoundEffect struct {
|
|||||||
player *audio.Player
|
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{}
|
result := &SoundEffect{}
|
||||||
var soundFile string
|
var soundFile string
|
||||||
if _, exists := d2datadict.Sounds[sfx]; exists {
|
if _, exists := d2datadict.Sounds[sfx]; exists {
|
||||||
@ -25,7 +24,7 @@ func CreateSoundEffect(sfx string, fileProvider d2interface.FileProvider, contex
|
|||||||
} else {
|
} else {
|
||||||
soundFile = sfx
|
soundFile = sfx
|
||||||
}
|
}
|
||||||
audioData := fileProvider.LoadFile(soundFile)
|
audioData := d2asset.MustLoadFile(soundFile)
|
||||||
d, err := wav.Decode(context, audio.BytesReadSeekCloser(audioData))
|
d, err := wav.Decode(context, audio.BytesReadSeekCloser(audioData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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
|
package d2scene
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2video"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2video"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlizzardIntro struct {
|
type BlizzardIntro struct {
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
videoDecoder *d2video.BinkDecoder
|
videoDecoder *d2video.BinkDecoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateBlizzardIntro(fileProvider d2interface.FileProvider, sceneProvider d2coreinterface.SceneProvider) *BlizzardIntro {
|
func CreateBlizzardIntro(sceneProvider d2coreinterface.SceneProvider) *BlizzardIntro {
|
||||||
result := &BlizzardIntro{
|
result := &BlizzardIntro{sceneProvider: sceneProvider}
|
||||||
fileProvider: fileProvider,
|
|
||||||
sceneProvider: sceneProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -25,7 +21,7 @@ func CreateBlizzardIntro(fileProvider d2interface.FileProvider, sceneProvider d2
|
|||||||
func (v *BlizzardIntro) Load() []func() {
|
func (v *BlizzardIntro) Load() []func() {
|
||||||
return []func(){
|
return []func(){
|
||||||
func() {
|
func() {
|
||||||
videoBytes := v.fileProvider.LoadFile("/data/local/video/BlizNorth640x480.bik")
|
videoBytes := d2asset.MustLoadFile("/data/local/video/BlizNorth640x480.bik")
|
||||||
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
|
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"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/d2common/d2resource"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
|
||||||
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
@ -27,9 +22,8 @@ import (
|
|||||||
type CharacterSelect struct {
|
type CharacterSelect struct {
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
background d2render.Sprite
|
background *d2render.Sprite
|
||||||
newCharButton d2ui.Button
|
newCharButton d2ui.Button
|
||||||
convertCharButton d2ui.Button
|
convertCharButton d2ui.Button
|
||||||
deleteCharButton d2ui.Button
|
deleteCharButton d2ui.Button
|
||||||
@ -37,8 +31,8 @@ type CharacterSelect struct {
|
|||||||
okButton d2ui.Button
|
okButton d2ui.Button
|
||||||
deleteCharCancelButton d2ui.Button
|
deleteCharCancelButton d2ui.Button
|
||||||
deleteCharOkButton d2ui.Button
|
deleteCharOkButton d2ui.Button
|
||||||
selectionBox d2render.Sprite
|
selectionBox *d2render.Sprite
|
||||||
okCancelBox d2render.Sprite
|
okCancelBox *d2render.Sprite
|
||||||
d2HeroTitle d2ui.Label
|
d2HeroTitle d2ui.Label
|
||||||
deleteCharConfirmLabel d2ui.Label
|
deleteCharConfirmLabel d2ui.Label
|
||||||
charScrollbar d2ui.Scrollbar
|
charScrollbar d2ui.Scrollbar
|
||||||
@ -52,17 +46,11 @@ type CharacterSelect struct {
|
|||||||
showDeleteConfirmation bool
|
showDeleteConfirmation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateCharacterSelect(
|
func CreateCharacterSelect(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *CharacterSelect {
|
||||||
fileProvider d2interface.FileProvider,
|
|
||||||
sceneProvider d2coreinterface.SceneProvider,
|
|
||||||
uiManager *d2ui.Manager,
|
|
||||||
soundManager *d2audio.Manager,
|
|
||||||
) *CharacterSelect {
|
|
||||||
result := &CharacterSelect{
|
result := &CharacterSelect{
|
||||||
selectedCharacter: -1,
|
selectedCharacter: -1,
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
fileProvider: fileProvider,
|
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@ -72,78 +60,75 @@ func (v *CharacterSelect) Load() []func() {
|
|||||||
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
||||||
return []func(){
|
return []func(){
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.CharacterSelectionBackground), d2datadict.Palettes[d2enum.Sky])
|
v.background, _ = d2render.LoadSprite(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
|
||||||
v.background = d2render.CreateSpriteFromDC6(dc6)
|
v.background.SetPosition(0, 0)
|
||||||
v.background.MoveTo(0, 0)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
|
v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15)))
|
||||||
v.newCharButton.MoveTo(33, 468)
|
v.newCharButton.SetPosition(33, 468)
|
||||||
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
|
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.newCharButton)
|
v.uiManager.AddWidget(&v.newCharButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
|
v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15)))
|
||||||
v.convertCharButton.MoveTo(233, 468)
|
v.convertCharButton.SetPosition(233, 468)
|
||||||
v.convertCharButton.SetEnabled(false)
|
v.convertCharButton.SetEnabled(false)
|
||||||
v.uiManager.AddWidget(&v.convertCharButton)
|
v.uiManager.AddWidget(&v.convertCharButton)
|
||||||
},
|
},
|
||||||
func() {
|
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.OnActivated(func() { v.onDeleteCharButtonClicked() })
|
||||||
v.deleteCharButton.MoveTo(433, 468)
|
v.deleteCharButton.SetPosition(433, 468)
|
||||||
v.uiManager.AddWidget(&v.deleteCharButton)
|
v.uiManager.AddWidget(&v.deleteCharButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
|
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
|
||||||
v.exitButton.MoveTo(33, 537)
|
v.exitButton.SetPosition(33, 537)
|
||||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.exitButton)
|
v.uiManager.AddWidget(&v.exitButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, v.fileProvider, d2common.TranslateString("#4231"))
|
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4231"))
|
||||||
v.deleteCharCancelButton.MoveTo(282, 308)
|
v.deleteCharCancelButton.SetPosition(282, 308)
|
||||||
v.deleteCharCancelButton.SetVisible(false)
|
v.deleteCharCancelButton.SetVisible(false)
|
||||||
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
|
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
|
||||||
v.uiManager.AddWidget(&v.deleteCharCancelButton)
|
v.uiManager.AddWidget(&v.deleteCharCancelButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, v.fileProvider, d2common.TranslateString("#4227"))
|
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#4227"))
|
||||||
v.deleteCharOkButton.MoveTo(422, 308)
|
v.deleteCharOkButton.SetPosition(422, 308)
|
||||||
v.deleteCharOkButton.SetVisible(false)
|
v.deleteCharOkButton.SetVisible(false)
|
||||||
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
|
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
|
||||||
v.uiManager.AddWidget(&v.deleteCharOkButton)
|
v.uiManager.AddWidget(&v.deleteCharOkButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971"))
|
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
|
||||||
v.okButton.MoveTo(625, 537)
|
v.okButton.SetPosition(625, 537)
|
||||||
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
|
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.okButton)
|
v.uiManager.AddWidget(&v.okButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.d2HeroTitle = d2ui.CreateLabel(v.fileProvider, d2resource.Font42, d2enum.Units)
|
v.d2HeroTitle = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||||
v.d2HeroTitle.MoveTo(320, 23)
|
v.d2HeroTitle.SetPosition(320, 23)
|
||||||
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
|
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
|
||||||
},
|
},
|
||||||
func() {
|
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)
|
lines := dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#1878"), 29)
|
||||||
v.deleteCharConfirmLabel.SetText(strings.Join(lines, "\n"))
|
v.deleteCharConfirmLabel.SetText(strings.Join(lines, "\n"))
|
||||||
v.deleteCharConfirmLabel.Alignment = d2ui.LabelAlignCenter
|
v.deleteCharConfirmLabel.Alignment = d2ui.LabelAlignCenter
|
||||||
v.deleteCharConfirmLabel.MoveTo(400, 185)
|
v.deleteCharConfirmLabel.SetPosition(400, 185)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.CharacterSelectionSelectBox), d2datadict.Palettes[d2enum.Sky])
|
v.selectionBox, _ = d2render.LoadSprite(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
|
||||||
v.selectionBox = d2render.CreateSpriteFromDC6(dc6)
|
v.selectionBox.SetPosition(37, 86)
|
||||||
v.selectionBox.MoveTo(37, 86)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.PopUpOkCancel), d2datadict.Palettes[d2enum.Fechar])
|
v.okCancelBox, _ = d2render.LoadSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||||
v.okCancelBox = d2render.CreateSpriteFromDC6(dc6)
|
v.okCancelBox.SetPosition(270, 175)
|
||||||
v.okCancelBox.MoveTo(270, 175)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.charScrollbar = d2ui.CreateScrollbar(v.fileProvider, 586, 87, 369)
|
v.charScrollbar = d2ui.CreateScrollbar(586, 87, 369)
|
||||||
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
|
v.charScrollbar.OnActivated(func() { v.onScrollUpdate() })
|
||||||
v.uiManager.AddWidget(&v.charScrollbar)
|
v.uiManager.AddWidget(&v.charScrollbar)
|
||||||
},
|
},
|
||||||
@ -153,14 +138,14 @@ func (v *CharacterSelect) Load() []func() {
|
|||||||
if i&1 > 0 {
|
if i&1 > 0 {
|
||||||
xOffset = 385
|
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].Color = color.RGBA{188, 168, 140, 255}
|
||||||
v.characterNameLabel[i].MoveTo(xOffset, 100+((i/2)*95))
|
v.characterNameLabel[i].SetPosition(xOffset, 100+((i/2)*95))
|
||||||
v.characterStatsLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units)
|
v.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||||
v.characterStatsLabel[i].MoveTo(xOffset, 115+((i/2)*95))
|
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
|
||||||
v.characterExpLabel[i] = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Static)
|
v.characterExpLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteStatic)
|
||||||
v.characterExpLabel[i].Color = color.RGBA{24, 255, 0, 255}
|
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()
|
v.refreshGameStates()
|
||||||
},
|
},
|
||||||
@ -193,17 +178,16 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
|||||||
0,
|
0,
|
||||||
v.gameStates[idx].HeroType,
|
v.gameStates[idx].HeroType,
|
||||||
d2core.HeroObjects[v.gameStates[idx].HeroType],
|
d2core.HeroObjects[v.gameStates[idx].HeroType],
|
||||||
v.fileProvider,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *CharacterSelect) onNewCharButtonClicked() {
|
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() {
|
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
|
mainMenu.ShowTrademarkScreen = false
|
||||||
v.sceneProvider.SetNextScene(mainMenu)
|
v.sceneProvider.SetNextScene(mainMenu)
|
||||||
}
|
}
|
||||||
@ -212,26 +196,26 @@ func (v *CharacterSelect) Unload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *CharacterSelect) Render(screen *ebiten.Image) {
|
func (v *CharacterSelect) Render(screen *ebiten.Image) {
|
||||||
v.background.DrawSegments(screen, 4, 3, 0)
|
v.background.RenderSegmented(screen, 4, 3, 0)
|
||||||
v.d2HeroTitle.Draw(screen)
|
v.d2HeroTitle.Render(screen)
|
||||||
actualSelectionIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
|
actualSelectionIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
|
||||||
if v.selectedCharacter > -1 && actualSelectionIndex >= 0 && actualSelectionIndex < 8 {
|
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++ {
|
for i := 0; i < 8; i++ {
|
||||||
idx := i + (v.charScrollbar.GetCurrentOffset() * 2)
|
idx := i + (v.charScrollbar.GetCurrentOffset() * 2)
|
||||||
if idx >= len(v.gameStates) {
|
if idx >= len(v.gameStates) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
v.characterNameLabel[i].Draw(screen)
|
v.characterNameLabel[i].Render(screen)
|
||||||
v.characterStatsLabel[i].Draw(screen)
|
v.characterStatsLabel[i].Render(screen)
|
||||||
v.characterExpLabel[i].Draw(screen)
|
v.characterExpLabel[i].Render(screen)
|
||||||
v.characterImage[i].Render(screen, v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
|
v.characterImage[i].Render(screen, v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
|
||||||
}
|
}
|
||||||
if v.showDeleteConfirmation {
|
if v.showDeleteConfirmation {
|
||||||
ebitenutil.DrawRect(screen, 0.0, 0.0, 800.0, 600.0, color.RGBA{0, 0, 0, 128})
|
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.okCancelBox.RenderSegmented(screen, 2, 1, 0)
|
||||||
v.deleteCharConfirmLabel.Draw(screen)
|
v.deleteCharConfirmLabel.Render(screen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +227,7 @@ func (v *CharacterSelect) moveSelectionBox() {
|
|||||||
bw := 272
|
bw := 272
|
||||||
bh := 92
|
bh := 92
|
||||||
selectedIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
|
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)
|
v.d2HeroTitle.SetText(v.gameStates[v.selectedCharacter].HeroName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,5 +302,5 @@ func (v *CharacterSelect) refreshGameStates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *CharacterSelect) onOkButtonClicked() {
|
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 (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -11,18 +10,14 @@ import (
|
|||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
@ -37,9 +32,8 @@ type labelItem struct {
|
|||||||
type Credits struct {
|
type Credits struct {
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
creditsBackground d2render.Sprite
|
creditsBackground *d2render.Sprite
|
||||||
exitButton d2ui.Button
|
exitButton d2ui.Button
|
||||||
creditsText []string
|
creditsText []string
|
||||||
labels []*labelItem
|
labels []*labelItem
|
||||||
@ -49,9 +43,8 @@ type Credits struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateCredits creates an instance of the credits scene
|
// 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{
|
result := &Credits{
|
||||||
fileProvider: fileProvider,
|
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
@ -84,18 +77,17 @@ func (v *Credits) LoadContributors() []string {
|
|||||||
func (v *Credits) Load() []func() {
|
func (v *Credits) Load() []func() {
|
||||||
return []func(){
|
return []func(){
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.CreditsBackground), d2datadict.Palettes[d2enum.Sky])
|
v.creditsBackground, _ = d2render.LoadSprite(d2resource.CreditsBackground, d2resource.PaletteSky)
|
||||||
v.creditsBackground = d2render.CreateSpriteFromDC6(dc6)
|
v.creditsBackground.SetPosition(0, 0)
|
||||||
v.creditsBackground.MoveTo(0, 0)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
|
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
|
||||||
v.exitButton.MoveTo(33, 543)
|
v.exitButton.SetPosition(33, 543)
|
||||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.exitButton)
|
v.uiManager.AddWidget(&v.exitButton)
|
||||||
},
|
},
|
||||||
func() {
|
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")
|
v.creditsText = strings.Split(fileData, "\r\n")
|
||||||
for i := range v.creditsText {
|
for i := range v.creditsText {
|
||||||
v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
|
v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
|
||||||
@ -112,12 +104,12 @@ func (v *Credits) Unload() {
|
|||||||
|
|
||||||
// Render renders the credits scene
|
// Render renders the credits scene
|
||||||
func (v *Credits) Render(screen *ebiten.Image) {
|
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 {
|
for _, label := range v.labels {
|
||||||
if label.Available {
|
if label.Available {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
label.Label.Draw(screen)
|
label.Label.Render(screen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +139,7 @@ func (v *Credits) Update(tickTime float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Credits) onExitButtonClicked() {
|
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
|
mainMenu.ShowTrademarkScreen = false
|
||||||
v.sceneProvider.SetNextScene(mainMenu)
|
v.sceneProvider.SetNextScene(mainMenu)
|
||||||
}
|
}
|
||||||
@ -182,7 +174,7 @@ func (v *Credits) addNextItem() {
|
|||||||
isDoubled = true
|
isDoubled = true
|
||||||
|
|
||||||
// Gotta go side by side
|
// Gotta go side by side
|
||||||
label.MoveTo(400-int(width), 605)
|
label.SetPosition(400-int(width), 605)
|
||||||
|
|
||||||
text2 := v.creditsText[0]
|
text2 := v.creditsText[0]
|
||||||
v.creditsText = v.creditsText[1:]
|
v.creditsText = v.creditsText[1:]
|
||||||
@ -191,9 +183,9 @@ func (v *Credits) addNextItem() {
|
|||||||
label2 := v.getNewFontLabel(isHeading)
|
label2 := v.getNewFontLabel(isHeading)
|
||||||
label2.SetText(text2)
|
label2.SetText(text2)
|
||||||
|
|
||||||
label2.MoveTo(410, 605)
|
label2.SetPosition(410, 605)
|
||||||
} else {
|
} else {
|
||||||
label.MoveTo(405-int(width/2), 605)
|
label.SetPosition(405-int(width/2), 605)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isHeading && isNextHeading {
|
if isHeading && isNextHeading {
|
||||||
@ -227,7 +219,7 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
|
|||||||
newLabelItem := &labelItem{
|
newLabelItem := &labelItem{
|
||||||
Available: false,
|
Available: false,
|
||||||
IsHeading: isHeading,
|
IsHeading: isHeading,
|
||||||
Label: d2ui.CreateLabel(v.fileProvider, d2resource.FontFormal10, d2enum.Sky),
|
Label: d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteSky),
|
||||||
}
|
}
|
||||||
|
|
||||||
if isHeading {
|
if isHeading {
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package d2scene
|
package d2scene
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image/color"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"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/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
@ -14,17 +13,15 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
"image/color"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
gameState *d2core.GameState
|
gameState *d2core.GameState
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
pentSpinLeft d2render.Sprite
|
pentSpinLeft *d2render.Sprite
|
||||||
pentSpinRight d2render.Sprite
|
pentSpinRight *d2render.Sprite
|
||||||
testLabel d2ui.Label
|
testLabel d2ui.Label
|
||||||
mapEngine *d2mapengine.MapEngine
|
mapEngine *d2mapengine.MapEngine
|
||||||
hero *d2core.Hero
|
hero *d2core.Hero
|
||||||
@ -32,7 +29,6 @@ type Game struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateGame(
|
func CreateGame(
|
||||||
fileProvider d2interface.FileProvider,
|
|
||||||
sceneProvider d2coreinterface.SceneProvider,
|
sceneProvider d2coreinterface.SceneProvider,
|
||||||
uiManager *d2ui.Manager,
|
uiManager *d2ui.Manager,
|
||||||
soundManager *d2audio.Manager,
|
soundManager *d2audio.Manager,
|
||||||
@ -40,7 +36,6 @@ func CreateGame(
|
|||||||
) *Game {
|
) *Game {
|
||||||
result := &Game{
|
result := &Game{
|
||||||
gameState: gameState,
|
gameState: gameState,
|
||||||
fileProvider: fileProvider,
|
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
@ -51,28 +46,25 @@ func CreateGame(
|
|||||||
func (v *Game) Load() []func() {
|
func (v *Game) Load() []func() {
|
||||||
return []func(){
|
return []func(){
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.PentSpin), d2datadict.Palettes[d2enum.Sky])
|
v.pentSpinLeft, _ = d2render.LoadSprite(d2resource.PentSpin, d2resource.PaletteSky)
|
||||||
v.pentSpinLeft = d2render.CreateSpriteFromDC6(dc6)
|
v.pentSpinLeft.PlayBackward()
|
||||||
v.pentSpinLeft.Animate = true
|
v.pentSpinLeft.SetPlayLengthMs(475)
|
||||||
v.pentSpinLeft.AnimateBackwards = true
|
v.pentSpinLeft.SetPosition(100, 300)
|
||||||
v.pentSpinLeft.SpecialFrameTime = 475
|
|
||||||
v.pentSpinLeft.MoveTo(100, 300)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.PentSpin), d2datadict.Palettes[d2enum.Sky])
|
v.pentSpinRight, _ = d2render.LoadSprite(d2resource.PentSpin, d2resource.PaletteSky)
|
||||||
v.pentSpinRight = d2render.CreateSpriteFromDC6(dc6)
|
v.pentSpinRight.PlayForward()
|
||||||
v.pentSpinRight.Animate = true
|
v.pentSpinRight.SetPlayLengthMs(475)
|
||||||
v.pentSpinRight.SpecialFrameTime = 475
|
v.pentSpinRight.SetPosition(650, 300)
|
||||||
v.pentSpinRight.MoveTo(650, 300)
|
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.testLabel.SetText("Soon :tm:")
|
v.testLabel.SetText("Soon :tm:")
|
||||||
v.testLabel.MoveTo(400, 250)
|
v.testLabel.SetPosition(400, 250)
|
||||||
},
|
},
|
||||||
func() {
|
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)
|
v.mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0)
|
||||||
|
|
||||||
startX, startY := v.mapEngine.GetStartPosition()
|
startX, startY := v.mapEngine.GetStartPosition()
|
||||||
@ -82,12 +74,11 @@ func (v *Game) Load() []func() {
|
|||||||
0,
|
0,
|
||||||
v.gameState.HeroType,
|
v.gameState.HeroType,
|
||||||
v.gameState.Equipment,
|
v.gameState.Equipment,
|
||||||
v.fileProvider,
|
|
||||||
)
|
)
|
||||||
v.mapEngine.AddEntity(v.hero)
|
v.mapEngine.AddEntity(v.hero)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.gameControls = d2player.NewGameControls(v.fileProvider, v.hero, v.mapEngine)
|
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
|
||||||
v.gameControls.Load()
|
v.gameControls.Load()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package d2scene
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -13,17 +12,12 @@ import (
|
|||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"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/OpenDiablo2/d2render"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
@ -33,14 +27,13 @@ import (
|
|||||||
type MainMenu struct {
|
type MainMenu struct {
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
trademarkBackground d2render.Sprite
|
trademarkBackground *d2render.Sprite
|
||||||
background d2render.Sprite
|
background *d2render.Sprite
|
||||||
diabloLogoLeft d2render.Sprite
|
diabloLogoLeft *d2render.Sprite
|
||||||
diabloLogoRight d2render.Sprite
|
diabloLogoRight *d2render.Sprite
|
||||||
diabloLogoLeftBack d2render.Sprite
|
diabloLogoLeftBack *d2render.Sprite
|
||||||
diabloLogoRightBack d2render.Sprite
|
diabloLogoRightBack *d2render.Sprite
|
||||||
singlePlayerButton d2ui.Button
|
singlePlayerButton d2ui.Button
|
||||||
githubButton d2ui.Button
|
githubButton d2ui.Button
|
||||||
exitDiabloButton d2ui.Button
|
exitDiabloButton d2ui.Button
|
||||||
@ -58,9 +51,8 @@ type MainMenu struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateMainMenu creates an instance of MainMenu
|
// 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{
|
result := &MainMenu{
|
||||||
fileProvider: fileProvider,
|
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
@ -75,111 +67,105 @@ func (v *MainMenu) Load() []func() {
|
|||||||
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
||||||
return []func(){
|
return []func(){
|
||||||
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.Alignment = d2ui.LabelAlignRight
|
||||||
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
|
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
|
||||||
v.versionLabel.Color = color.RGBA{255, 255, 255, 255}
|
v.versionLabel.Color = color.RGBA{255, 255, 255, 255}
|
||||||
v.versionLabel.MoveTo(795, -10)
|
v.versionLabel.SetPosition(795, -10)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignLeft
|
||||||
v.commitLabel.SetText(d2common.BuildInfo.Commit)
|
v.commitLabel.SetText(d2common.BuildInfo.Commit)
|
||||||
v.commitLabel.Color = color.RGBA{255, 255, 255, 255}
|
v.commitLabel.Color = color.RGBA{255, 255, 255, 255}
|
||||||
v.commitLabel.MoveTo(2, 2)
|
v.commitLabel.SetPosition(2, 2)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
||||||
v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255}
|
v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255}
|
||||||
v.copyrightLabel.MoveTo(400, 500)
|
v.copyrightLabel.SetPosition(400, 500)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.copyrightLabel2.SetText(d2common.TranslateString("#1614"))
|
v.copyrightLabel2.SetText(d2common.TranslateString("#1614"))
|
||||||
v.copyrightLabel2.Color = color.RGBA{188, 168, 140, 255}
|
v.copyrightLabel2.Color = color.RGBA{188, 168, 140, 255}
|
||||||
v.copyrightLabel2.MoveTo(400, 525)
|
v.copyrightLabel2.SetPosition(400, 525)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
|
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.Color = color.RGBA{255, 255, 140, 255}
|
||||||
v.openDiabloLabel.MoveTo(400, 580)
|
v.openDiabloLabel.SetPosition(400, 580)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.GameSelectScreen), d2datadict.Palettes[d2enum.Sky])
|
v.background, _ = d2render.LoadSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
|
||||||
v.background = d2render.CreateSpriteFromDC6(dc6)
|
v.background.SetPosition(0, 0)
|
||||||
v.background.MoveTo(0, 0)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.TrademarkScreen), d2datadict.Palettes[d2enum.Sky])
|
v.trademarkBackground, _ = d2render.LoadSprite(d2resource.TrademarkScreen, d2resource.PaletteSky)
|
||||||
v.trademarkBackground = d2render.CreateSpriteFromDC6(dc6)
|
v.trademarkBackground.SetPosition(0, 0)
|
||||||
v.trademarkBackground.MoveTo(0, 0)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoFireLeft), d2datadict.Palettes[d2enum.Units])
|
v.diabloLogoLeft, _ = d2render.LoadSprite(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
||||||
v.diabloLogoLeft = d2render.CreateSpriteFromDC6(dc6)
|
v.diabloLogoLeft.SetBlend(true)
|
||||||
v.diabloLogoLeft.Blend = true
|
v.diabloLogoLeft.PlayForward()
|
||||||
v.diabloLogoLeft.Animate = true
|
v.diabloLogoLeft.SetPosition(400, 120)
|
||||||
v.diabloLogoLeft.MoveTo(400, 120)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoFireRight), d2datadict.Palettes[d2enum.Units])
|
v.diabloLogoRight, _ = d2render.LoadSprite(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
|
||||||
v.diabloLogoRight = d2render.CreateSpriteFromDC6(dc6)
|
v.diabloLogoRight.SetBlend(true)
|
||||||
v.diabloLogoRight.Blend = true
|
v.diabloLogoRight.PlayForward()
|
||||||
v.diabloLogoRight.Animate = true
|
v.diabloLogoRight.SetPosition(400, 120)
|
||||||
v.diabloLogoRight.MoveTo(400, 120)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoBlackLeft), d2datadict.Palettes[d2enum.Units])
|
v.diabloLogoLeftBack, _ = d2render.LoadSprite(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
|
||||||
v.diabloLogoLeftBack = d2render.CreateSpriteFromDC6(dc6)
|
v.diabloLogoLeftBack.SetPosition(400, 120)
|
||||||
v.diabloLogoLeftBack.MoveTo(400, 120)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
dc6, _ := d2dc6.LoadDC6(v.fileProvider.LoadFile(d2resource.Diablo2LogoBlackRight), d2datadict.Palettes[d2enum.Units])
|
v.diabloLogoRightBack, _ = d2render.LoadSprite(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
|
||||||
v.diabloLogoRightBack = d2render.CreateSpriteFromDC6(dc6)
|
v.diabloLogoRightBack.SetPosition(400, 120)
|
||||||
v.diabloLogoRightBack.MoveTo(400, 120)
|
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1625"))
|
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1625"))
|
||||||
v.exitDiabloButton.MoveTo(264, 535)
|
v.exitDiabloButton.SetPosition(264, 535)
|
||||||
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
|
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
|
||||||
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.exitDiabloButton)
|
v.uiManager.AddWidget(&v.exitDiabloButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1627"))
|
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1627"))
|
||||||
v.creditsButton.MoveTo(264, 505)
|
v.creditsButton.SetPosition(264, 505)
|
||||||
v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
|
v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
|
||||||
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.creditsButton)
|
v.uiManager.AddWidget(&v.creditsButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1639"))
|
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1639"))
|
||||||
v.cinematicsButton.MoveTo(401, 505)
|
v.cinematicsButton.SetPosition(401, 505)
|
||||||
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
|
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
|
||||||
v.uiManager.AddWidget(&v.cinematicsButton)
|
v.uiManager.AddWidget(&v.cinematicsButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1620"))
|
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1620"))
|
||||||
v.singlePlayerButton.MoveTo(264, 290)
|
v.singlePlayerButton.SetPosition(264, 290)
|
||||||
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
|
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
|
||||||
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
||||||
v.uiManager.AddWidget(&v.singlePlayerButton)
|
v.uiManager.AddWidget(&v.singlePlayerButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, "PROJECT WEBSITE")
|
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
|
||||||
v.githubButton.MoveTo(264, 330)
|
v.githubButton.SetPosition(264, 330)
|
||||||
v.githubButton.SetVisible(!v.ShowTrademarkScreen)
|
v.githubButton.SetVisible(!v.ShowTrademarkScreen)
|
||||||
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
|
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.githubButton)
|
v.uiManager.AddWidget(&v.githubButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, "MAP ENGINE TEST")
|
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
|
||||||
v.mapTestButton.MoveTo(264, 450)
|
v.mapTestButton.SetPosition(264, 450)
|
||||||
v.mapTestButton.SetVisible(!v.ShowTrademarkScreen)
|
v.mapTestButton.SetVisible(!v.ShowTrademarkScreen)
|
||||||
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
||||||
v.uiManager.AddWidget(&v.mapTestButton)
|
v.uiManager.AddWidget(&v.mapTestButton)
|
||||||
@ -188,7 +174,7 @@ func (v *MainMenu) Load() []func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) onMapTestClicked() {
|
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) {
|
func openbrowser(url string) {
|
||||||
@ -213,10 +199,10 @@ func openbrowser(url string) {
|
|||||||
func (v *MainMenu) onSinglePlayerClicked() {
|
func (v *MainMenu) onSinglePlayerClicked() {
|
||||||
// Go here only if existing characters are available to select
|
// Go here only if existing characters are available to select
|
||||||
if d2core.HasGameStates() {
|
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
|
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() {
|
func (v *MainMenu) onGithubButtonClicked() {
|
||||||
@ -228,7 +214,7 @@ func (v *MainMenu) onExitButtonClicked() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) onCreditsButtonClicked() {
|
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
|
// Unload unloads the data for the main menu
|
||||||
@ -239,22 +225,22 @@ func (v *MainMenu) Unload() {
|
|||||||
// Render renders the main menu
|
// Render renders the main menu
|
||||||
func (v *MainMenu) Render(screen *ebiten.Image) {
|
func (v *MainMenu) Render(screen *ebiten.Image) {
|
||||||
if v.ShowTrademarkScreen {
|
if v.ShowTrademarkScreen {
|
||||||
v.trademarkBackground.DrawSegments(screen, 4, 3, 0)
|
v.trademarkBackground.RenderSegmented(screen, 4, 3, 0)
|
||||||
} else {
|
} else {
|
||||||
v.background.DrawSegments(screen, 4, 3, 0)
|
v.background.RenderSegmented(screen, 4, 3, 0)
|
||||||
}
|
}
|
||||||
v.diabloLogoLeftBack.Draw(screen)
|
v.diabloLogoLeftBack.Render(screen)
|
||||||
v.diabloLogoRightBack.Draw(screen)
|
v.diabloLogoRightBack.Render(screen)
|
||||||
v.diabloLogoLeft.Draw(screen)
|
v.diabloLogoLeft.Render(screen)
|
||||||
v.diabloLogoRight.Draw(screen)
|
v.diabloLogoRight.Render(screen)
|
||||||
|
|
||||||
if v.ShowTrademarkScreen {
|
if v.ShowTrademarkScreen {
|
||||||
v.copyrightLabel.Draw(screen)
|
v.copyrightLabel.Render(screen)
|
||||||
v.copyrightLabel2.Draw(screen)
|
v.copyrightLabel2.Render(screen)
|
||||||
} else {
|
} else {
|
||||||
v.openDiabloLabel.Draw(screen)
|
v.openDiabloLabel.Render(screen)
|
||||||
v.versionLabel.Draw(screen)
|
v.versionLabel.Render(screen)
|
||||||
v.commitLabel.Draw(screen)
|
v.commitLabel.Render(screen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
@ -83,7 +82,6 @@ var regions []RegionSpec = []RegionSpec{
|
|||||||
type MapEngineTest struct {
|
type MapEngineTest struct {
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
gameState *d2core.GameState
|
gameState *d2core.GameState
|
||||||
mapEngine *d2mapengine.MapEngine
|
mapEngine *d2mapengine.MapEngine
|
||||||
@ -97,14 +95,8 @@ type MapEngineTest struct {
|
|||||||
debugVisLevel int
|
debugVisLevel int
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMapEngineTest(
|
func CreateMapEngineTest(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager, currentRegion int, levelPreset int) *MapEngineTest {
|
||||||
fileProvider d2interface.FileProvider,
|
|
||||||
sceneProvider d2coreinterface.SceneProvider,
|
|
||||||
uiManager *d2ui.Manager,
|
|
||||||
soundManager *d2audio.Manager,
|
|
||||||
currentRegion int, levelPreset int) *MapEngineTest {
|
|
||||||
result := &MapEngineTest{
|
result := &MapEngineTest{
|
||||||
fileProvider: fileProvider,
|
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
@ -145,7 +137,7 @@ func (v *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
|
|||||||
if n == 0 {
|
if n == 0 {
|
||||||
v.mapEngine.GenerateAct1Overworld()
|
v.mapEngine.GenerateAct1Overworld()
|
||||||
} else {
|
} 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)
|
v.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +150,7 @@ func (v *MapEngineTest) Load() []func() {
|
|||||||
v.soundManager.PlayBGM("")
|
v.soundManager.PlayBGM("")
|
||||||
return []func(){
|
return []func(){
|
||||||
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)
|
v.LoadRegionByIndex(v.currentRegion, v.levelPreset, v.fileIndex)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package d2scene
|
package d2scene
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
@ -9,31 +8,28 @@ import (
|
|||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
dh "github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HeroRenderInfo struct {
|
type HeroRenderInfo struct {
|
||||||
Stance d2enum.HeroStance
|
Stance d2enum.HeroStance
|
||||||
IdleSprite d2render.Sprite
|
IdleSprite *d2render.Sprite
|
||||||
IdleSelectedSprite d2render.Sprite
|
IdleSelectedSprite *d2render.Sprite
|
||||||
ForwardWalkSprite d2render.Sprite
|
ForwardWalkSprite *d2render.Sprite
|
||||||
ForwardWalkSpriteOverlay d2render.Sprite
|
ForwardWalkSpriteOverlay *d2render.Sprite
|
||||||
SelectedSprite d2render.Sprite
|
SelectedSprite *d2render.Sprite
|
||||||
SelectedSpriteOverlay d2render.Sprite
|
SelectedSpriteOverlay *d2render.Sprite
|
||||||
BackWalkSprite d2render.Sprite
|
BackWalkSprite *d2render.Sprite
|
||||||
BackWalkSpriteOverlay d2render.Sprite
|
BackWalkSpriteOverlay *d2render.Sprite
|
||||||
SelectionBounds image.Rectangle
|
SelectionBounds image.Rectangle
|
||||||
SelectSfx *d2audio.SoundEffect
|
SelectSfx *d2audio.SoundEffect
|
||||||
DeselectSfx *d2audio.SoundEffect
|
DeselectSfx *d2audio.SoundEffect
|
||||||
@ -42,10 +38,9 @@ type HeroRenderInfo struct {
|
|||||||
type SelectHeroClass struct {
|
type SelectHeroClass struct {
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
bgImage d2render.Sprite
|
bgImage *d2render.Sprite
|
||||||
campfire d2render.Sprite
|
campfire *d2render.Sprite
|
||||||
headingLabel d2ui.Label
|
headingLabel d2ui.Label
|
||||||
heroClassLabel d2ui.Label
|
heroClassLabel d2ui.Label
|
||||||
heroDesc1Label d2ui.Label
|
heroDesc1Label d2ui.Label
|
||||||
@ -63,15 +58,10 @@ type SelectHeroClass struct {
|
|||||||
hardcoreCharLabel d2ui.Label
|
hardcoreCharLabel d2ui.Label
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSelectHeroClass(
|
func CreateSelectHeroClass(sceneProvider d2coreinterface.SceneProvider, uiManager *d2ui.Manager, soundManager *d2audio.Manager) *SelectHeroClass {
|
||||||
fileProvider d2interface.FileProvider,
|
|
||||||
sceneProvider d2coreinterface.SceneProvider,
|
|
||||||
uiManager *d2ui.Manager, soundManager *d2audio.Manager,
|
|
||||||
) *SelectHeroClass {
|
|
||||||
result := &SelectHeroClass{
|
result := &SelectHeroClass{
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
fileProvider: fileProvider,
|
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
|
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
|
||||||
selectedHero: d2enum.HeroNone,
|
selectedHero: d2enum.HeroNone,
|
||||||
@ -79,365 +69,360 @@ func CreateSelectHeroClass(
|
|||||||
return result
|
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() {
|
func (v *SelectHeroClass) Load() []func() {
|
||||||
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
v.soundManager.PlayBGM(d2resource.BGMTitle)
|
||||||
return []func(){
|
return []func(){
|
||||||
func() {
|
func() {
|
||||||
v.bgImage = v.loadSprite(d2resource.CharacterSelectBackground, d2enum.Fechar)
|
v.bgImage, _ = d2render.LoadSprite(d2resource.CharacterSelectBackground, d2resource.PaletteFechar)
|
||||||
v.bgImage.MoveTo(0, 0)
|
v.bgImage.SetPosition(0, 0)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.headingLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font30, d2enum.Units)
|
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||||
fontWidth, _ := v.headingLabel.GetSize()
|
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.SetText("Select Hero Class")
|
||||||
v.headingLabel.Alignment = d2ui.LabelAlignCenter
|
v.headingLabel.Alignment = d2ui.LabelAlignCenter
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.heroClassLabel.MoveTo(400, 65)
|
v.heroClassLabel.SetPosition(400, 65)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.heroDesc1Label.MoveTo(400, 100)
|
v.heroDesc1Label.SetPosition(400, 100)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.heroDesc2Label.MoveTo(400, 115)
|
v.heroDesc2Label.SetPosition(400, 115)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignCenter
|
||||||
v.heroDesc3Label.MoveTo(400, 130)
|
v.heroDesc3Label.SetPosition(400, 130)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.campfire = v.loadSprite(d2resource.CharacterSelectCampfire, d2enum.Fechar)
|
v.campfire, _ = d2render.LoadSprite(d2resource.CharacterSelectCampfire, d2resource.PaletteFechar)
|
||||||
v.campfire.MoveTo(380, 335)
|
v.campfire.SetPosition(380, 335)
|
||||||
v.campfire.Animate = true
|
v.campfire.PlayForward()
|
||||||
v.campfire.Blend = true
|
v.campfire.SetBlend(true)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970"))
|
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#970"))
|
||||||
v.exitButton.MoveTo(33, 537)
|
v.exitButton.SetPosition(33, 537)
|
||||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
v.uiManager.AddWidget(&v.exitButton)
|
v.uiManager.AddWidget(&v.exitButton)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971"))
|
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("#971"))
|
||||||
v.okButton.MoveTo(630, 537)
|
v.okButton.SetPosition(630, 537)
|
||||||
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
|
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
|
||||||
v.okButton.SetVisible(false)
|
v.okButton.SetVisible(false)
|
||||||
v.okButton.SetEnabled(false)
|
v.okButton.SetEnabled(false)
|
||||||
v.uiManager.AddWidget(&v.okButton)
|
v.uiManager.AddWidget(&v.okButton)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignLeft
|
||||||
v.heroNameLabel.Color = color.RGBA{216, 196, 128, 255}
|
v.heroNameLabel.Color = color.RGBA{216, 196, 128, 255}
|
||||||
v.heroNameLabel.SetText(d2common.TranslateString("#1694"))
|
v.heroNameLabel.SetText(d2common.TranslateString("#1694"))
|
||||||
v.heroNameLabel.MoveTo(321, 475)
|
v.heroNameLabel.SetPosition(321, 475)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroNameTextbox = d2ui.CreateTextbox(v.fileProvider)
|
v.heroNameTextbox = d2ui.CreateTextbox()
|
||||||
v.heroNameTextbox.MoveTo(318, 493)
|
v.heroNameTextbox.SetPosition(318, 493)
|
||||||
v.heroNameTextbox.SetVisible(false)
|
v.heroNameTextbox.SetVisible(false)
|
||||||
v.uiManager.AddWidget(&v.heroNameTextbox)
|
v.uiManager.AddWidget(&v.heroNameTextbox)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.expansionCheckbox = d2ui.CreateCheckbox(v.fileProvider, true)
|
v.expansionCheckbox = d2ui.CreateCheckbox(true)
|
||||||
v.expansionCheckbox.MoveTo(318, 526)
|
v.expansionCheckbox.SetPosition(318, 526)
|
||||||
v.expansionCheckbox.SetVisible(false)
|
v.expansionCheckbox.SetVisible(false)
|
||||||
v.uiManager.AddWidget(&v.expansionCheckbox)
|
v.uiManager.AddWidget(&v.expansionCheckbox)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignLeft
|
||||||
v.expansionCharLabel.Color = color.RGBA{216, 196, 128, 255}
|
v.expansionCharLabel.Color = color.RGBA{216, 196, 128, 255}
|
||||||
v.expansionCharLabel.SetText(d2common.TranslateString("#803"))
|
v.expansionCharLabel.SetText(d2common.TranslateString("#803"))
|
||||||
v.expansionCharLabel.MoveTo(339, 526)
|
v.expansionCharLabel.SetPosition(339, 526)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.hardcoreCheckbox = d2ui.CreateCheckbox(v.fileProvider, false)
|
v.hardcoreCheckbox = d2ui.CreateCheckbox(false)
|
||||||
v.hardcoreCheckbox.MoveTo(318, 548)
|
v.hardcoreCheckbox.SetPosition(318, 548)
|
||||||
v.hardcoreCheckbox.SetVisible(false)
|
v.hardcoreCheckbox.SetVisible(false)
|
||||||
v.uiManager.AddWidget(&v.hardcoreCheckbox)
|
v.uiManager.AddWidget(&v.hardcoreCheckbox)
|
||||||
},
|
},
|
||||||
func() {
|
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.Alignment = d2ui.LabelAlignLeft
|
||||||
v.hardcoreCharLabel.Color = color.RGBA{216, 196, 128, 255}
|
v.hardcoreCharLabel.Color = color.RGBA{216, 196, 128, 255}
|
||||||
v.hardcoreCharLabel.SetText(d2common.TranslateString("#1696"))
|
v.hardcoreCharLabel.SetText(d2common.TranslateString("#1696"))
|
||||||
v.hardcoreCharLabel.MoveTo(339, 548)
|
v.hardcoreCharLabel.SetPosition(339, 548)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroBarbarian] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelectBarbarianUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectBarbarianUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectBarbarianForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianForwardWalk, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectBarbarianForwardWalkOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianForwardWalkOverlay, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectBarbarianSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianSelected, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}},
|
image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.MoveTo(400, 330)
|
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.SetPosition(400, 330)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.MoveTo(400, 330)
|
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.SetPosition(400, 330)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.MoveTo(400, 330)
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPosition(400, 330)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.MoveTo(400, 330)
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPosition(400, 330)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.MoveTo(400, 330)
|
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.SetPosition(400, 330)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.MoveTo(400, 330)
|
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPosition(400, 330)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SpecialFrameTime = 1000
|
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPlayLengthMs(1000)
|
||||||
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroSorceress] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressForwardWalk, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressForwardWalkOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressForwardWalkOverlay, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressSelected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressSelectedOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressSelectedOverlay, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressBackWalk, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecSorceressBackWalkOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecSorceressBackWalkOverlay, d2resource.PaletteFechar),
|
||||||
image.Rectangle{Min: image.Point{580, 240}, Max: image.Point{65, 160}},
|
image.Rectangle{Min: image.Point{580, 240}, Max: image.Point{65, 160}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXSorceressSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXSorceressSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXSorceressDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXSorceressDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SpecialFrameTime = 2300
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPlayLengthMs(2300)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.Blend = true
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetBlend(true)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SpecialFrameTime = 2300
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPlayLengthMs(2300)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SpecialFrameTime = 450
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.SetPlayLengthMs(450)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.Blend = true
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetBlend(true)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SpecialFrameTime = 450
|
v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.SetPlayLengthMs(450)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SpecialFrameTime = 1200
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPlayLengthMs(1200)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.Blend = true
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetBlend(true)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.MoveTo(626, 352)
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPosition(626, 352)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SpecialFrameTime = 1200
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPlayLengthMs(1200)
|
||||||
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroNecromancer] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelectNecromancerUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectNecromancerUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectNecromancerUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectNecromancerUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecNecromancerForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerForwardWalk, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecNecromancerForwardWalkOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerForwardWalkOverlay, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecNecromancerSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerSelected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecNecromancerSelectedOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerSelectedOverlay, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecNecromancerBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerBackWalk, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecNecromancerBackWalkOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecNecromancerBackWalkOverlay, d2resource.PaletteFechar),
|
||||||
image.Rectangle{Min: image.Point{265, 220}, Max: image.Point{55, 175}},
|
image.Rectangle{Min: image.Point{265, 220}, Max: image.Point{55, 175}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXNecromancerSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXNecromancerSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXNecromancerDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXNecromancerDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SpecialFrameTime = 1200
|
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.SetPlayLengthMs(1200)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SpecialFrameTime = 1200
|
v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.SetPlayLengthMs(1200)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SpecialFrameTime = 2000
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPlayLengthMs(2000)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.Blend = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetBlend(true)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SpecialFrameTime = 2000
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPlayLengthMs(2000)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.Blend = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.SetBlend(true)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.Blend = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetBlend(true)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.MoveTo(300, 335)
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPosition(300, 335)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroPaladin] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelectPaladinUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectPaladinUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectPaladinUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectPaladinUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecPaladinForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinForwardWalk, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecPaladinForwardWalkOverlay, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinForwardWalkOverlay, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecPaladinSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinSelected, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelecPaladinBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecPaladinBackWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}},
|
image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.MoveTo(521, 338)
|
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SetPosition(521, 338)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.MoveTo(521, 338)
|
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SetPosition(521, 338)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.MoveTo(521, 338)
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPosition(521, 338)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SpecialFrameTime = 3400
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPlayLengthMs(3400)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.MoveTo(521, 338)
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPosition(521, 338)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.Animate = true
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SpecialFrameTime = 3400
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPlayLengthMs(3400)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.MoveTo(521, 338)
|
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SetPosition(521, 338)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SpecialFrameTime = 650
|
v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.SetPlayLengthMs(650)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.MoveTo(521, 338)
|
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPosition(521, 338)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SpecialFrameTime = 1300
|
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPlayLengthMs(1300)
|
||||||
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroAmazon] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelectAmazonUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAmazonUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectAmazonUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAmazonUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelecAmazonForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecAmazonForwardWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelecAmazonSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecAmazonSelected, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelecAmazonBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelecAmazonBackWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}},
|
image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.MoveTo(100, 339)
|
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SetPosition(100, 339)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.MoveTo(100, 339)
|
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SetPosition(100, 339)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.MoveTo(100, 339)
|
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPosition(100, 339)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SpecialFrameTime = 2200
|
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPlayLengthMs(2200)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.MoveTo(100, 339)
|
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SetPosition(100, 339)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SpecialFrameTime = 1350
|
v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.SetPlayLengthMs(1350)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.MoveTo(100, 339)
|
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPosition(100, 339)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroAssassin] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelectAssassinUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectAssassinUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectAssassinForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinForwardWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelectAssassinSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinSelected, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelectAssassinBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectAssassinBackWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}},
|
image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.MoveTo(231, 365)
|
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SetPosition(231, 365)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.MoveTo(231, 365)
|
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SetPosition(231, 365)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.MoveTo(231, 365)
|
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPosition(231, 365)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SpecialFrameTime = 3800
|
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPlayLengthMs(3800)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.MoveTo(231, 365)
|
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SetPosition(231, 365)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SpecialFrameTime = 2500
|
v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.SetPlayLengthMs(2500)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.MoveTo(231, 365)
|
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPosition(231, 365)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
func() {
|
func() {
|
||||||
v.heroRenderInfo[d2enum.HeroDruid] = &HeroRenderInfo{
|
v.heroRenderInfo[d2enum.HeroDruid] = &HeroRenderInfo{
|
||||||
d2enum.HeroStanceIdle,
|
d2enum.HeroStanceIdle,
|
||||||
v.loadSprite(d2resource.CharacterSelectDruidUnselected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectDruidUnselected, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectDruidUnselectedH, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectDruidUnselectedH, d2resource.PaletteFechar),
|
||||||
v.loadSprite(d2resource.CharacterSelectDruidForwardWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectDruidForwardWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelectDruidSelected, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectDruidSelected, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
v.loadSprite(d2resource.CharacterSelectDruidBackWalk, d2enum.Fechar),
|
d2render.MustLoadSprite(d2resource.CharacterSelectDruidBackWalk, d2resource.PaletteFechar),
|
||||||
d2render.Sprite{},
|
nil,
|
||||||
image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}},
|
image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}},
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXDruidSelect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXDruidSelect),
|
||||||
v.soundManager.LoadSoundEffect(d2resource.SFXDruidDeselect),
|
v.soundManager.LoadSoundEffect(d2resource.SFXDruidDeselect),
|
||||||
}
|
}
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.MoveTo(720, 370)
|
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SetPosition(720, 370)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.MoveTo(720, 370)
|
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SetPosition(720, 370)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.MoveTo(720, 370)
|
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPosition(720, 370)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SpecialFrameTime = 4800
|
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPlayLengthMs(4800)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SetPlayLoop(false)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.MoveTo(720, 370)
|
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SetPosition(720, 370)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.MoveTo(720, 370)
|
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPosition(720, 370)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.Animate = true
|
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.PlayForward()
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SpecialFrameTime = 1500
|
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPlayLengthMs(1500)
|
||||||
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.StopOnLastFrame = true
|
v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SetPlayLoop(false)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,22 +436,22 @@ func (v *SelectHeroClass) Unload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v SelectHeroClass) onExitButtonClicked() {
|
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() {
|
func (v SelectHeroClass) onOkButtonClicked() {
|
||||||
gameState := d2core.CreateGameState(v.heroNameTextbox.GetText(), v.selectedHero, v.hardcoreCheckbox.GetCheckState())
|
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) {
|
func (v *SelectHeroClass) Render(screen *ebiten.Image) {
|
||||||
v.bgImage.DrawSegments(screen, 4, 3, 0)
|
v.bgImage.RenderSegmented(screen, 4, 3, 0)
|
||||||
v.headingLabel.Draw(screen)
|
v.headingLabel.Render(screen)
|
||||||
if v.selectedHero != d2enum.HeroNone {
|
if v.selectedHero != d2enum.HeroNone {
|
||||||
v.heroClassLabel.Draw(screen)
|
v.heroClassLabel.Render(screen)
|
||||||
v.heroDesc1Label.Draw(screen)
|
v.heroDesc1Label.Render(screen)
|
||||||
v.heroDesc2Label.Draw(screen)
|
v.heroDesc2Label.Render(screen)
|
||||||
v.heroDesc3Label.Draw(screen)
|
v.heroDesc3Label.Render(screen)
|
||||||
}
|
}
|
||||||
for heroClass, heroInfo := range v.heroRenderInfo {
|
for heroClass, heroInfo := range v.heroRenderInfo {
|
||||||
if heroInfo.Stance == d2enum.HeroStanceIdle || heroInfo.Stance == d2enum.HeroStanceIdleSelected {
|
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.renderHero(screen, heroClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.campfire.Draw(screen)
|
v.campfire.Render(screen)
|
||||||
if v.heroNameTextbox.GetVisible() {
|
if v.heroNameTextbox.GetVisible() {
|
||||||
v.heroNameLabel.Draw(screen)
|
v.heroNameLabel.Render(screen)
|
||||||
v.expansionCharLabel.Draw(screen)
|
v.expansionCharLabel.Render(screen)
|
||||||
v.hardcoreCharLabel.Draw(screen)
|
v.hardcoreCharLabel.Render(screen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,18 +497,16 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
|||||||
renderInfo := v.heroRenderInfo[hero]
|
renderInfo := v.heroRenderInfo[hero]
|
||||||
switch renderInfo.Stance {
|
switch renderInfo.Stance {
|
||||||
case d2enum.HeroStanceApproaching:
|
case d2enum.HeroStanceApproaching:
|
||||||
if renderInfo.ForwardWalkSprite.OnLastFrame() {
|
if renderInfo.ForwardWalkSprite.IsOnLastFrame() {
|
||||||
renderInfo.Stance = d2enum.HeroStanceSelected
|
renderInfo.Stance = d2enum.HeroStanceSelected
|
||||||
renderInfo.SelectedSprite.ResetAnimation()
|
setSpriteToFirstFrame(renderInfo.SelectedSprite)
|
||||||
if renderInfo.SelectedSpriteOverlay.IsValid() {
|
setSpriteToFirstFrame(renderInfo.SelectedSpriteOverlay)
|
||||||
renderInfo.SelectedSpriteOverlay.ResetAnimation()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case d2enum.HeroStanceRetreating:
|
case d2enum.HeroStanceRetreating:
|
||||||
if renderInfo.BackWalkSprite.OnLastFrame() {
|
if renderInfo.BackWalkSprite.IsOnLastFrame() {
|
||||||
renderInfo.Stance = d2enum.HeroStanceIdle
|
renderInfo.Stance = d2enum.HeroStanceIdle
|
||||||
renderInfo.IdleSprite.ResetAnimation()
|
setSpriteToFirstFrame(renderInfo.IdleSprite)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -543,10 +526,8 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
|||||||
v.expansionCheckbox.SetVisible(true)
|
v.expansionCheckbox.SetVisible(true)
|
||||||
v.hardcoreCheckbox.SetVisible(true)
|
v.hardcoreCheckbox.SetVisible(true)
|
||||||
renderInfo.Stance = d2enum.HeroStanceApproaching
|
renderInfo.Stance = d2enum.HeroStanceApproaching
|
||||||
renderInfo.ForwardWalkSprite.ResetAnimation()
|
setSpriteToFirstFrame(renderInfo.ForwardWalkSprite)
|
||||||
if renderInfo.ForwardWalkSpriteOverlay.IsValid() {
|
setSpriteToFirstFrame(renderInfo.ForwardWalkSpriteOverlay)
|
||||||
renderInfo.ForwardWalkSpriteOverlay.ResetAnimation()
|
|
||||||
}
|
|
||||||
for _, heroInfo := range v.heroRenderInfo {
|
for _, heroInfo := range v.heroRenderInfo {
|
||||||
if heroInfo.Stance != d2enum.HeroStanceSelected {
|
if heroInfo.Stance != d2enum.HeroStanceSelected {
|
||||||
continue
|
continue
|
||||||
@ -554,10 +535,8 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
|||||||
heroInfo.SelectSfx.Stop()
|
heroInfo.SelectSfx.Stop()
|
||||||
heroInfo.DeselectSfx.Play()
|
heroInfo.DeselectSfx.Play()
|
||||||
heroInfo.Stance = d2enum.HeroStanceRetreating
|
heroInfo.Stance = d2enum.HeroStanceRetreating
|
||||||
heroInfo.BackWalkSprite.ResetAnimation()
|
setSpriteToFirstFrame(heroInfo.BackWalkSprite)
|
||||||
if heroInfo.BackWalkSpriteOverlay.IsValid() {
|
setSpriteToFirstFrame(heroInfo.BackWalkSpriteOverlay)
|
||||||
heroInfo.BackWalkSpriteOverlay.ResetAnimation()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
v.selectedHero = hero
|
v.selectedHero = hero
|
||||||
v.updateHeroText()
|
v.updateHeroText()
|
||||||
@ -567,12 +546,10 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected {
|
if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected {
|
||||||
renderInfo.IdleSelectedSprite.LastFrameTime = renderInfo.IdleSprite.LastFrameTime
|
renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame())
|
||||||
renderInfo.IdleSelectedSprite.Frame = renderInfo.IdleSprite.Frame
|
|
||||||
renderInfo.Stance = d2enum.HeroStanceIdleSelected
|
renderInfo.Stance = d2enum.HeroStanceIdleSelected
|
||||||
} else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle {
|
} else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle {
|
||||||
renderInfo.IdleSprite.LastFrameTime = renderInfo.IdleSelectedSprite.LastFrameTime
|
renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame())
|
||||||
renderInfo.IdleSprite.Frame = renderInfo.IdleSelectedSprite.Frame
|
|
||||||
renderInfo.Stance = d2enum.HeroStanceIdle
|
renderInfo.Stance = d2enum.HeroStanceIdle
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,24 +564,18 @@ func (v *SelectHeroClass) renderHero(screen *ebiten.Image, hero d2enum.Hero) {
|
|||||||
renderInfo := v.heroRenderInfo[hero]
|
renderInfo := v.heroRenderInfo[hero]
|
||||||
switch renderInfo.Stance {
|
switch renderInfo.Stance {
|
||||||
case d2enum.HeroStanceIdle:
|
case d2enum.HeroStanceIdle:
|
||||||
renderInfo.IdleSprite.Draw(screen)
|
drawSprite(renderInfo.IdleSprite, screen)
|
||||||
case d2enum.HeroStanceIdleSelected:
|
case d2enum.HeroStanceIdleSelected:
|
||||||
renderInfo.IdleSelectedSprite.Draw(screen)
|
drawSprite(renderInfo.IdleSelectedSprite, screen)
|
||||||
case d2enum.HeroStanceApproaching:
|
case d2enum.HeroStanceApproaching:
|
||||||
renderInfo.ForwardWalkSprite.Draw(screen)
|
drawSprite(renderInfo.ForwardWalkSprite, screen)
|
||||||
if renderInfo.ForwardWalkSpriteOverlay.IsValid() {
|
drawSprite(renderInfo.ForwardWalkSpriteOverlay, screen)
|
||||||
renderInfo.ForwardWalkSpriteOverlay.Draw(screen)
|
|
||||||
}
|
|
||||||
case d2enum.HeroStanceSelected:
|
case d2enum.HeroStanceSelected:
|
||||||
renderInfo.SelectedSprite.Draw(screen)
|
drawSprite(renderInfo.SelectedSprite, screen)
|
||||||
if renderInfo.SelectedSpriteOverlay.IsValid() {
|
drawSprite(renderInfo.SelectedSpriteOverlay, screen)
|
||||||
renderInfo.SelectedSpriteOverlay.Draw(screen)
|
|
||||||
}
|
|
||||||
case d2enum.HeroStanceRetreating:
|
case d2enum.HeroStanceRetreating:
|
||||||
renderInfo.BackWalkSprite.Draw(screen)
|
drawSprite(renderInfo.BackWalkSprite, screen)
|
||||||
if renderInfo.BackWalkSpriteOverlay.IsValid() {
|
drawSprite(renderInfo.BackWalkSpriteOverlay, screen)
|
||||||
renderInfo.BackWalkSpriteOverlay.Draw(screen)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,3 +640,15 @@ func (v *SelectHeroClass) setDescLabels(descKey string) {
|
|||||||
v.heroDesc3Label.SetText("")
|
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"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data"
|
"github.com/OpenDiablo2/D2Shared/d2data"
|
||||||
@ -26,6 +22,7 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||||
|
|
||||||
@ -38,7 +35,7 @@ import (
|
|||||||
type Engine struct {
|
type Engine struct {
|
||||||
Settings *d2corecommon.Configuration // Engine configuration settings from json file
|
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.
|
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.
|
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
|
loadingIndex int // Determines which load function is currently being called
|
||||||
thingsToLoad []func() // The load functions for the next scene
|
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
|
fullscreenKey bool // When true, the fullscreen toggle is still being pressed
|
||||||
lastTime float64 // Last time we updated the scene
|
lastTime float64 // Last time we updated the scene
|
||||||
showFPS bool
|
showFPS bool
|
||||||
assetManager *assetManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateEngine creates and instance of the OpenDiablo2 engine
|
// CreateEngine creates and instance of the OpenDiablo2 engine
|
||||||
@ -62,7 +58,8 @@ func CreateEngine() Engine {
|
|||||||
log.Printf("could not load settings: %v", err)
|
log.Printf("could not load settings: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.assetManager = createAssetManager(result.Settings)
|
d2asset.Initialize(result.Settings)
|
||||||
|
|
||||||
d2resource.LanguageCode = result.Settings.Language
|
d2resource.LanguageCode = result.Settings.Language
|
||||||
d2datadict.LoadPalettes(nil, &result)
|
d2datadict.LoadPalettes(nil, &result)
|
||||||
d2common.LoadTextDictionary(&result)
|
d2common.LoadTextDictionary(&result)
|
||||||
@ -80,17 +77,18 @@ func CreateEngine() Engine {
|
|||||||
d2data.LoadAnimationData(&result)
|
d2data.LoadAnimationData(&result)
|
||||||
d2datadict.LoadMonStats(&result)
|
d2datadict.LoadMonStats(&result)
|
||||||
LoadHeroObjects()
|
LoadHeroObjects()
|
||||||
result.SoundManager = d2audio.CreateManager(&result)
|
result.SoundManager = d2audio.CreateManager()
|
||||||
result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume)
|
result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume)
|
||||||
result.UIManager = d2ui.CreateManager(&result, *result.SoundManager)
|
result.UIManager = d2ui.CreateManager(*result.SoundManager)
|
||||||
result.LoadingSprite = result.LoadSprite(d2resource.LoadingScreen, d2enum.Loading)
|
result.LoadingSprite, _ = d2render.LoadSprite(d2resource.LoadingScreen, d2resource.PaletteLoading)
|
||||||
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize()
|
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetCurrentFrameSize()
|
||||||
result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
result.LoadingSprite.SetPosition(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) LoadFile(fileName string) []byte {
|
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
|
// 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
|
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
|
// updateScene handles the scene maintenance for the engine
|
||||||
func (v *Engine) updateScene() {
|
func (v *Engine) updateScene() {
|
||||||
if v.nextScene == nil {
|
if v.nextScene == nil {
|
||||||
@ -176,14 +167,14 @@ func (v *Engine) Update() {
|
|||||||
// Draw draws the game
|
// Draw draws the game
|
||||||
func (v Engine) Draw(screen *ebiten.Image) {
|
func (v Engine) Draw(screen *ebiten.Image) {
|
||||||
if v.loadingProgress < 1.0 {
|
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.SetCurrentFrame(int(d2helper.Max(0, d2helper.Min(uint32(v.LoadingSprite.GetFrameCount()-1), uint32(float64(v.LoadingSprite.GetFrameCount()-1)*v.loadingProgress)))))
|
||||||
v.LoadingSprite.Draw(screen)
|
v.LoadingSprite.Render(screen)
|
||||||
} else {
|
} else {
|
||||||
if v.CurrentScene == nil {
|
if v.CurrentScene == nil {
|
||||||
log.Fatal("no scene loaded")
|
log.Fatal("no scene loaded")
|
||||||
}
|
}
|
||||||
v.CurrentScene.Render(screen)
|
v.CurrentScene.Render(screen)
|
||||||
v.UIManager.Draw(screen)
|
v.UIManager.Render(screen)
|
||||||
}
|
}
|
||||||
if v.showFPS {
|
if v.showFPS {
|
||||||
ebitenutil.DebugPrintAt(screen, "vsync:"+strconv.FormatBool(ebiten.IsVsyncEnabled())+"\nFPS:"+strconv.Itoa(int(ebiten.CurrentFPS())), 5, 565)
|
ebitenutil.DebugPrintAt(screen, "vsync:"+strconv.FormatBool(ebiten.IsVsyncEnabled())+"\nFPS:"+strconv.Itoa(int(ebiten.CurrentFPS())), 5, 565)
|
||||||
|
@ -2,7 +2,6 @@ package d2core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
@ -15,7 +14,7 @@ type Hero struct {
|
|||||||
direction int
|
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{
|
result := &Hero{
|
||||||
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, &d2datadict.ObjectLookupRecord{
|
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, &d2datadict.ObjectLookupRecord{
|
||||||
Mode: d2enum.AnimationModePlayerNeutral.String(),
|
Mode: d2enum.AnimationModePlayerNeutral.String(),
|
||||||
@ -32,7 +31,6 @@ func CreateHero(x, y int32, direction int, heroType d2enum.Hero, equipment Chara
|
|||||||
RH: equipment.RightHand.GetItemCode(),
|
RH: equipment.RightHand.GetItemCode(),
|
||||||
LH: equipment.LeftHand.GetItemCode(),
|
LH: equipment.LeftHand.GetItemCode(),
|
||||||
},
|
},
|
||||||
fileProvider,
|
|
||||||
d2enum.Units,
|
d2enum.Units,
|
||||||
),
|
),
|
||||||
Equipment: equipment,
|
Equipment: equipment,
|
||||||
|
@ -3,7 +3,6 @@ package d2core
|
|||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
@ -16,9 +15,9 @@ type NPC struct {
|
|||||||
path int
|
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{
|
result := &NPC{
|
||||||
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, object, fileProvider, d2enum.Units),
|
AnimatedEntity: d2render.CreateAnimatedEntity(x, y, object, d2enum.Units),
|
||||||
HasPaths: false,
|
HasPaths: false,
|
||||||
}
|
}
|
||||||
result.AnimatedEntity.SetMode(object.Mode, object.Class, direction)
|
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
|
// Drawable represents an instance that can be drawn
|
||||||
type Drawable interface {
|
type Drawable interface {
|
||||||
Draw(target *ebiten.Image)
|
Render(target *ebiten.Image)
|
||||||
GetSize() (width, height uint32)
|
GetSize() (width, height int)
|
||||||
MoveTo(x, y int)
|
SetPosition(x, y int)
|
||||||
GetLocation() (x, y int)
|
GetPosition() (x, y int)
|
||||||
GetVisible() bool
|
GetVisible() bool
|
||||||
SetVisible(visible bool)
|
SetVisible(visible bool)
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
package d2player
|
package d2player
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"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/d2core"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GameControls struct {
|
type GameControls struct {
|
||||||
fileProvider d2interface.FileProvider
|
hero *d2core.Hero
|
||||||
hero *d2core.Hero
|
mapEngine *d2mapengine.MapEngine
|
||||||
mapEngine *d2mapengine.MapEngine
|
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
globeSprite *d2render.Sprite
|
globeSprite *d2render.Sprite
|
||||||
@ -25,11 +19,10 @@ type GameControls struct {
|
|||||||
skillIcon *d2render.Sprite
|
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{
|
return &GameControls{
|
||||||
fileProvider: fileProvider,
|
hero: hero,
|
||||||
hero: hero,
|
mapEngine: mapEngine,
|
||||||
mapEngine: mapEngine,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,111 +60,86 @@ func (g *GameControls) Move(tickTime float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameControls) Load() {
|
func (g *GameControls) Load() {
|
||||||
dc6, err := d2dc6.LoadDC6(g.fileProvider.LoadFile(d2resource.GameGlobeOverlap), d2datadict.Palettes[d2enum.Sky])
|
g.globeSprite, _ = d2render.LoadSprite(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
|
||||||
if err != nil {
|
g.mainPanel, _ = d2render.LoadSprite(d2resource.GamePanels, d2resource.PaletteSky)
|
||||||
log.Panicf("failed to load %s: %v", d2resource.GameGlobeOverlap, err)
|
g.menuButton, _ = d2render.LoadSprite(d2resource.MenuButton, d2resource.PaletteSky)
|
||||||
}
|
g.skillIcon, _ = d2render.LoadSprite(d2resource.GenericSkills, d2resource.PaletteSky)
|
||||||
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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: consider caching the panels to single image that is reused.
|
// TODO: consider caching the panels to single image that is reused.
|
||||||
func (g *GameControls) Render(target *ebiten.Image) {
|
func (g *GameControls) Render(target *ebiten.Image) {
|
||||||
width, height := target.Size()
|
width, height := target.Size()
|
||||||
offset := uint32(0)
|
offset := int(0)
|
||||||
|
|
||||||
// Left globe holder
|
// Left globe holder
|
||||||
g.mainPanel.Frame = 0
|
g.mainPanel.SetCurrentFrame(0)
|
||||||
w, _ := g.mainPanel.GetSize()
|
w, _ := g.mainPanel.GetCurrentFrameSize()
|
||||||
g.mainPanel.MoveTo(int(offset), height)
|
g.mainPanel.SetPosition(int(offset), height)
|
||||||
g.mainPanel.Draw(target)
|
g.mainPanel.Render(target)
|
||||||
|
|
||||||
// Left globe
|
// Left globe
|
||||||
g.globeSprite.Frame = 0
|
g.globeSprite.SetCurrentFrame(0)
|
||||||
g.globeSprite.MoveTo(int(offset+28), height - 5)
|
g.globeSprite.SetPosition(int(offset+28), height-5)
|
||||||
g.globeSprite.Draw(target)
|
g.globeSprite.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Left skill
|
// Left skill
|
||||||
g.skillIcon.Frame = 2
|
g.skillIcon.SetCurrentFrame(2)
|
||||||
w, _ = g.skillIcon.GetSize()
|
w, _ = g.skillIcon.GetCurrentFrameSize()
|
||||||
g.skillIcon.MoveTo(int(offset), height)
|
g.skillIcon.SetPosition(int(offset), height)
|
||||||
g.skillIcon.Draw(target)
|
g.skillIcon.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Left skill selector
|
// Left skill selector
|
||||||
g.mainPanel.Frame = 1
|
g.mainPanel.SetCurrentFrame(1)
|
||||||
w, _ = g.mainPanel.GetSize()
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||||
g.mainPanel.MoveTo(int(offset), height)
|
g.mainPanel.SetPosition(int(offset), height)
|
||||||
g.mainPanel.Draw(target)
|
g.mainPanel.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Stamina
|
// Stamina
|
||||||
g.mainPanel.Frame = 2
|
g.mainPanel.SetCurrentFrame(2)
|
||||||
w, _ = g.mainPanel.GetSize()
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||||
g.mainPanel.MoveTo(int(offset), height)
|
g.mainPanel.SetPosition(int(offset), height)
|
||||||
g.mainPanel.Draw(target)
|
g.mainPanel.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Center menu button
|
// Center menu button
|
||||||
g.menuButton.Frame = 0
|
g.menuButton.SetCurrentFrame(0)
|
||||||
w, _ = g.mainPanel.GetSize()
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||||
g.menuButton.MoveTo((width / 2) - 8 , height - 16)
|
g.menuButton.SetPosition((width/2)-8, height-16)
|
||||||
g.menuButton.Draw(target)
|
g.menuButton.Render(target)
|
||||||
|
|
||||||
// Potions
|
// Potions
|
||||||
g.mainPanel.Frame = 3
|
g.mainPanel.SetCurrentFrame(3)
|
||||||
w, _ = g.mainPanel.GetSize()
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||||
g.mainPanel.MoveTo(int(offset), height)
|
g.mainPanel.SetPosition(int(offset), height)
|
||||||
g.mainPanel.Draw(target)
|
g.mainPanel.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Right skill selector
|
// Right skill selector
|
||||||
g.mainPanel.Frame = 4
|
g.mainPanel.SetCurrentFrame(4)
|
||||||
w, _ = g.mainPanel.GetSize()
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||||
g.mainPanel.MoveTo(int(offset), height)
|
g.mainPanel.SetPosition(int(offset), height)
|
||||||
g.mainPanel.Draw(target)
|
g.mainPanel.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Right skill
|
// Right skill
|
||||||
g.skillIcon.Frame = 10
|
g.skillIcon.SetCurrentFrame(10)
|
||||||
w, _ = g.skillIcon.GetSize()
|
w, _ = g.skillIcon.GetCurrentFrameSize()
|
||||||
g.skillIcon.MoveTo(int(offset), height)
|
g.skillIcon.SetPosition(int(offset), height)
|
||||||
g.skillIcon.Draw(target)
|
g.skillIcon.Render(target)
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Right globe holder
|
// Right globe holder
|
||||||
g.mainPanel.Frame = 5
|
g.mainPanel.SetCurrentFrame(5)
|
||||||
w, _ = g.mainPanel.GetSize()
|
w, _ = g.mainPanel.GetCurrentFrameSize()
|
||||||
g.mainPanel.MoveTo(int(offset), height)
|
g.mainPanel.SetPosition(int(offset), height)
|
||||||
g.mainPanel.Draw(target)
|
g.mainPanel.Render(target)
|
||||||
|
|
||||||
// Right globe
|
// Right globe
|
||||||
g.globeSprite.Frame = 1
|
g.globeSprite.SetCurrentFrame(1)
|
||||||
g.globeSprite.MoveTo(int(offset) + 8, height - 8)
|
g.globeSprite.SetPosition(int(offset)+8, height-8)
|
||||||
g.globeSprite.Draw(target)
|
g.globeSprite.Render(target)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package d2render
|
package d2render
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"log"
|
"log"
|
||||||
@ -9,12 +10,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data"
|
"github.com/OpenDiablo2/D2Shared/d2data"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2cof"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2cof"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,12 +31,11 @@ type LayerCacheEntry struct {
|
|||||||
|
|
||||||
// AnimatedEntity represents an entity on the map that can be animated
|
// AnimatedEntity represents an entity on the map that can be animated
|
||||||
type AnimatedEntity struct {
|
type AnimatedEntity struct {
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
LocationX float64
|
LocationX float64
|
||||||
LocationY float64
|
LocationY float64
|
||||||
TileX, TileY int // Coordinates of the tile the unit is within
|
TileX, TileY int // Coordinates of the tile the unit is within
|
||||||
subcellX, subcellY float64 // Subcell coordinates within the current tile
|
subcellX, subcellY float64 // Subcell coordinates within the current tile
|
||||||
dccLayers map[string]d2dcc.DCC
|
dccLayers map[string]*d2dcc.DCC
|
||||||
Cof *d2cof.COF
|
Cof *d2cof.COF
|
||||||
palette d2enum.PaletteType
|
palette d2enum.PaletteType
|
||||||
base string
|
base string
|
||||||
@ -58,16 +58,15 @@ type AnimatedEntity struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateAnimatedEntity creates an instance of AnimatedEntity
|
// 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{
|
result := AnimatedEntity{
|
||||||
fileProvider: fileProvider,
|
base: object.Base,
|
||||||
base: object.Base,
|
token: object.Token,
|
||||||
token: object.Token,
|
object: object,
|
||||||
object: object,
|
palette: palette,
|
||||||
palette: palette,
|
layerCache: make([]LayerCacheEntry, d2enum.CompositeTypeMax),
|
||||||
layerCache: make([]LayerCacheEntry, d2enum.CompositeTypeMax),
|
|
||||||
}
|
}
|
||||||
result.dccLayers = make(map[string]d2dcc.DCC)
|
result.dccLayers = make(map[string]*d2dcc.DCC)
|
||||||
result.LocationX = float64(x)
|
result.LocationX = float64(x)
|
||||||
result.LocationY = float64(y)
|
result.LocationY = float64(y)
|
||||||
result.TargetX = result.LocationX
|
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
|
// SetMode changes the graphical mode of this animated entity
|
||||||
func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction int) {
|
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)
|
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 {
|
if v.Cof.NumberOfDirections == 0 || v.Cof.NumberOfLayers == 0 || v.Cof.FramesPerDirection == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -95,11 +97,10 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
|
|||||||
if v.direction >= v.Cof.NumberOfDirections {
|
if v.direction >= v.Cof.NumberOfDirections {
|
||||||
v.direction = v.Cof.NumberOfDirections - 1
|
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 {
|
for _, cofLayer := range v.Cof.CofLayers {
|
||||||
layerName := DccLayerNames[cofLayer.Type]
|
layerName := DccLayerNames[cofLayer.Type]
|
||||||
v.dccLayers[layerName] = v.LoadLayer(layerName, v.fileProvider)
|
if v.dccLayers[layerName], err = v.LoadLayer(layerName); err != nil {
|
||||||
if !v.dccLayers[layerName].IsValid() {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +108,7 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
|
|||||||
v.updateFrameCache(resetAnimation)
|
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"
|
layerName := "TR"
|
||||||
switch strings.ToUpper(layer) {
|
switch strings.ToUpper(layer) {
|
||||||
case "HD": // Head
|
case "HD": // Head
|
||||||
@ -144,15 +145,19 @@ func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FilePr
|
|||||||
layerName = v.object.S8
|
layerName = v.object.S8
|
||||||
}
|
}
|
||||||
if len(layerName) == 0 {
|
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)
|
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)
|
result, err := d2asset.LoadDCC(dccPath)
|
||||||
if !result.IsValid() {
|
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")
|
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.
|
// 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
|
layerType := v.Cof.CofLayers[cofLayerIdx].Type
|
||||||
layerName := DccLayerNames[layerType]
|
layerName := DccLayerNames[layerType]
|
||||||
dccLayer := v.dccLayers[layerName]
|
dccLayer := v.dccLayers[layerName]
|
||||||
if !dccLayer.IsValid() {
|
if dccLayer == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
)
|
)
|
||||||
@ -20,7 +19,6 @@ type MapEntity interface {
|
|||||||
type MapEngine struct {
|
type MapEngine struct {
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
gameState *d2core.GameState
|
gameState *d2core.GameState
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
|
|
||||||
debugVisLevel int
|
debugVisLevel int
|
||||||
|
|
||||||
@ -30,11 +28,10 @@ type MapEngine struct {
|
|||||||
camera Camera
|
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{
|
engine := &MapEngine{
|
||||||
gameState: gameState,
|
gameState: gameState,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
fileProvider: fileProvider,
|
|
||||||
viewport: NewViewport(0, 0, 800, 600),
|
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) {
|
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.regions = append(me.regions, region)
|
||||||
me.entities = append(me.entities, entities...)
|
me.entities = append(me.entities, entities...)
|
||||||
}
|
}
|
||||||
@ -96,16 +93,16 @@ func (me *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int
|
|||||||
func (me *MapEngine) GenerateAct1Overworld() {
|
func (me *MapEngine) GenerateAct1Overworld() {
|
||||||
me.soundManager.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
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.regions = append(me.regions, region)
|
||||||
me.entities = append(me.entities, entities...)
|
me.entities = append(me.entities, entities...)
|
||||||
|
|
||||||
if strings.Contains(region.regionPath, "E1") {
|
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.regions = append(me.regions, region)
|
||||||
me.entities = append(me.entities, entities...)
|
me.entities = append(me.entities, entities...)
|
||||||
} else if strings.Contains(region.regionPath, "S1") {
|
} 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.regions = append(me.regions, region)
|
||||||
me.entities = append(me.entities, entities...)
|
me.entities = append(me.entities, entities...)
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common"
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2ds1"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2ds1"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dt1"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2dt1"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
@ -39,7 +39,7 @@ type MapRegion struct {
|
|||||||
lastFrameTime float64
|
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{
|
region := &MapRegion{
|
||||||
levelType: d2datadict.LevelTypes[levelType],
|
levelType: d2datadict.LevelTypes[levelType],
|
||||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
levelPreset: d2datadict.LevelPresets[levelPreset],
|
||||||
@ -54,7 +54,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
|
|||||||
|
|
||||||
for _, levelTypeDt1 := range region.levelType.Files {
|
for _, levelTypeDt1 := range region.levelType.Files {
|
||||||
if len(levelTypeDt1) != 0 && levelTypeDt1 != "" && levelTypeDt1 != "0" {
|
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...)
|
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.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{
|
region.tileRect = d2common.Rectangle{
|
||||||
Left: tileOffsetX,
|
Left: tileOffsetX,
|
||||||
Top: tileOffsetY,
|
Top: tileOffsetY,
|
||||||
@ -80,7 +80,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
|
|||||||
Height: int(region.ds1.Height),
|
Height: int(region.ds1.Height),
|
||||||
}
|
}
|
||||||
|
|
||||||
entities := region.loadEntities(fileProvider)
|
entities := region.loadEntities()
|
||||||
region.loadSpecials()
|
region.loadSpecials()
|
||||||
region.generateTileCache()
|
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
|
var entities []MapEntity
|
||||||
|
|
||||||
for _, object := range mr.ds1.Objects {
|
for _, object := range mr.ds1.Objects {
|
||||||
@ -127,13 +127,13 @@ func (mr *MapRegion) loadEntities(fileProvider d2interface.FileProvider) []MapEn
|
|||||||
switch object.Lookup.Type {
|
switch object.Lookup.Type {
|
||||||
case d2datadict.ObjectTypeCharacter:
|
case d2datadict.ObjectTypeCharacter:
|
||||||
if object.Lookup.Base != "" && object.Lookup.Token != "" && object.Lookup.TR != "" {
|
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)
|
npc.SetPaths(object.Paths)
|
||||||
entities = append(entities, npc)
|
entities = append(entities, npc)
|
||||||
}
|
}
|
||||||
case d2datadict.ObjectTypeItem:
|
case d2datadict.ObjectTypeItem:
|
||||||
if object.ObjectInfo != nil && object.ObjectInfo.Draw && object.Lookup.Base != "" && object.Lookup.Token != "" {
|
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)
|
entity.SetMode(object.Lookup.Mode, object.Lookup.Class, 0)
|
||||||
entities = append(entities, &entity)
|
entities = append(entities, &entity)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"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/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
@ -18,18 +14,18 @@ type Scrollbar struct {
|
|||||||
maxOffset int
|
maxOffset int
|
||||||
lastDirChange int
|
lastDirChange int
|
||||||
onActivate func()
|
onActivate func()
|
||||||
scrollbarSprite d2render.Sprite
|
scrollbarSprite *d2render.Sprite
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateScrollbar(fileProvider d2interface.FileProvider, x, y, height int) Scrollbar {
|
func CreateScrollbar(x, y, height int) Scrollbar {
|
||||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.Scrollbar), d2datadict.Palettes[d2enum.Sky])
|
scrollbarSprite, _ := d2render.LoadSprite(d2resource.Scrollbar, d2resource.PaletteSky)
|
||||||
result := Scrollbar{
|
result := Scrollbar{
|
||||||
visible: true,
|
visible: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
height: height,
|
height: height,
|
||||||
scrollbarSprite: d2render.CreateSpriteFromDC6(dc6),
|
scrollbarSprite: scrollbarSprite,
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -76,7 +72,7 @@ func (v Scrollbar) GetLastDirChange() int {
|
|||||||
return v.lastDirChange
|
return v.lastDirChange
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Scrollbar) Draw(target *ebiten.Image) {
|
func (v *Scrollbar) Render(target *ebiten.Image) {
|
||||||
if !v.visible || v.maxOffset == 0 {
|
if !v.visible || v.maxOffset == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -84,31 +80,31 @@ func (v *Scrollbar) Draw(target *ebiten.Image) {
|
|||||||
if !v.enabled {
|
if !v.enabled {
|
||||||
offset = 2
|
offset = 2
|
||||||
}
|
}
|
||||||
v.scrollbarSprite.MoveTo(v.x, v.y)
|
v.scrollbarSprite.SetPosition(v.x, v.y)
|
||||||
v.scrollbarSprite.DrawSegments(target, 1, 1, 0+offset)
|
v.scrollbarSprite.RenderSegmented(target, 1, 1, 0+offset)
|
||||||
v.scrollbarSprite.MoveTo(v.x, v.y+v.height-10)
|
v.scrollbarSprite.SetPosition(v.x, v.y+v.height-10)
|
||||||
v.scrollbarSprite.DrawSegments(target, 1, 1, 1+offset)
|
v.scrollbarSprite.RenderSegmented(target, 1, 1, 1+offset)
|
||||||
if v.maxOffset == 0 || v.currentOffset < 0 || v.currentOffset > v.maxOffset {
|
if v.maxOffset == 0 || v.currentOffset < 0 || v.currentOffset > v.maxOffset {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v.scrollbarSprite.MoveTo(v.x, v.y+10+v.getBarPosition())
|
v.scrollbarSprite.SetPosition(v.x, v.y+10+v.getBarPosition())
|
||||||
offset = 0
|
offset = 0
|
||||||
if !v.enabled {
|
if !v.enabled {
|
||||||
offset = 1
|
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) {
|
func (v *Scrollbar) GetSize() (width, height int) {
|
||||||
return 10, uint32(v.height)
|
return 10, int(v.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Scrollbar) MoveTo(x, y int) {
|
func (v *Scrollbar) SetPosition(x, y int) {
|
||||||
v.x = x
|
v.x = x
|
||||||
v.y = y
|
v.y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Scrollbar) GetLocation() (x, y int) {
|
func (v *Scrollbar) GetPosition() (x, y int) {
|
||||||
return v.x, v.y
|
return v.x, v.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,14 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,26 +43,26 @@ const (
|
|||||||
|
|
||||||
// ButtonLayout defines the type of buttons
|
// ButtonLayout defines the type of buttons
|
||||||
type ButtonLayout struct {
|
type ButtonLayout struct {
|
||||||
XSegments int //1
|
XSegments int //1
|
||||||
YSegments int // 1
|
YSegments int // 1
|
||||||
ResourceName string // Font Name
|
ResourceName string // Font Name
|
||||||
PaletteName d2enum.PaletteType // PaletteType
|
PaletteName string // PaletteType
|
||||||
Toggleable bool // false
|
Toggleable bool // false
|
||||||
BaseFrame int // 0
|
BaseFrame int // 0
|
||||||
DisabledFrame int // -1
|
DisabledFrame int // -1
|
||||||
FontPath string // ResourcePaths.FontExocet10
|
FontPath string // ResourcePaths.FontExocet10
|
||||||
ClickableRect *image.Rectangle // nil
|
ClickableRect *image.Rectangle // nil
|
||||||
AllowFrameChange bool // true
|
AllowFrameChange bool // true
|
||||||
TextOffset int // 0
|
TextOffset int // 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ButtonLayouts define the type of buttons you can have
|
// ButtonLayouts define the type of buttons you can have
|
||||||
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
||||||
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2enum.Units, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
ButtonTypeWide: {2, 1, d2resource.WideButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontExocet10, nil, true, 1},
|
||||||
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2enum.Units, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
ButtonTypeShort: {1, 1, d2resource.ShortButtonBlank, d2resource.PaletteUnits, false, 0, -1, d2resource.FontRediculous, nil, true, -1},
|
||||||
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2enum.Units, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
ButtonTypeMedium: {1, 1, d2resource.MediumButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 0},
|
||||||
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2enum.Units, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
ButtonTypeTall: {1, 1, d2resource.TallButtonBlank, d2resource.PaletteUnits, false, 0, 0, d2resource.FontExocet10, nil, true, 5},
|
||||||
ButtonTypeOkCancel: {1, 1, d2resource.CancelButton, d2enum.Units, false, 0, -1, d2resource.FontRediculous, nil, true, 0},
|
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.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } },
|
||||||
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, 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 {
|
type Button struct {
|
||||||
enabled bool
|
enabled bool
|
||||||
x, y int
|
x, y int
|
||||||
width, height uint32
|
width, height int
|
||||||
visible bool
|
visible bool
|
||||||
pressed bool
|
pressed bool
|
||||||
toggled bool
|
toggled bool
|
||||||
fileProvider d2interface.FileProvider
|
|
||||||
normalImage *ebiten.Image
|
normalImage *ebiten.Image
|
||||||
pressedImage *ebiten.Image
|
pressedImage *ebiten.Image
|
||||||
toggledImage *ebiten.Image
|
toggledImage *ebiten.Image
|
||||||
@ -111,59 +103,57 @@ type Button struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateButton creates an instance of Button
|
// 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{
|
result := Button{
|
||||||
fileProvider: fileProvider,
|
width: 0,
|
||||||
width: 0,
|
height: 0,
|
||||||
height: 0,
|
visible: true,
|
||||||
visible: true,
|
enabled: true,
|
||||||
enabled: true,
|
pressed: false,
|
||||||
pressed: false,
|
|
||||||
}
|
}
|
||||||
buttonLayout := ButtonLayouts[buttonType]
|
buttonLayout := ButtonLayouts[buttonType]
|
||||||
result.buttonLayout = buttonLayout
|
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.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
||||||
buttonSprite := d2render.CreateSpriteFromDC6(dc6)
|
totalButtonTypes := buttonSprite.GetFrameCount() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
||||||
totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
|
||||||
for i := 0; i < buttonLayout.XSegments; i++ {
|
for i := 0; i < buttonLayout.XSegments; i++ {
|
||||||
w, _ := buttonSprite.GetFrameSize(i)
|
w, _, _ := buttonSprite.GetFrameSize(i)
|
||||||
result.width += w
|
result.width += w
|
||||||
}
|
}
|
||||||
for i := 0; i < buttonLayout.YSegments; i++ {
|
for i := 0; i < buttonLayout.YSegments; i++ {
|
||||||
_, h := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
_, h, _ := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
||||||
result.height += h
|
result.height += h
|
||||||
}
|
}
|
||||||
|
|
||||||
result.normalImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
result.normalImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||||
_, fontHeight := font.GetTextMetrics(text)
|
_, 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.SetPosition(0, 0)
|
||||||
buttonSprite.Blend = true
|
buttonSprite.SetBlend(true)
|
||||||
buttonSprite.DrawSegments(result.normalImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
buttonSprite.RenderSegmented(result.normalImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
|
||||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalImage)
|
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalImage)
|
||||||
if buttonLayout.AllowFrameChange {
|
if buttonLayout.AllowFrameChange {
|
||||||
if totalButtonTypes > 1 {
|
if totalButtonTypes > 1 {
|
||||||
result.pressedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
result.pressedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||||
buttonSprite.DrawSegments(result.pressedImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
buttonSprite.RenderSegmented(result.pressedImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
|
||||||
font.Draw(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
|
font.Render(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
|
||||||
}
|
}
|
||||||
if totalButtonTypes > 2 {
|
if totalButtonTypes > 2 {
|
||||||
result.toggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
result.toggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||||
buttonSprite.DrawSegments(result.toggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
buttonSprite.RenderSegmented(result.toggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
|
||||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
|
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
|
||||||
}
|
}
|
||||||
if totalButtonTypes > 3 {
|
if totalButtonTypes > 3 {
|
||||||
result.pressedToggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
result.pressedToggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||||
buttonSprite.DrawSegments(result.pressedToggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
buttonSprite.RenderSegmented(result.pressedToggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
|
||||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
|
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
|
||||||
}
|
}
|
||||||
if buttonLayout.DisabledFrame != -1 {
|
if buttonLayout.DisabledFrame != -1 {
|
||||||
result.disabledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
result.disabledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||||
buttonSprite.DrawSegments(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
buttonSprite.RenderSegmented(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
|
||||||
font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
|
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@ -182,8 +172,8 @@ func (v *Button) Activate() {
|
|||||||
v.onClick()
|
v.onClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw renders the button
|
// Render renders the button
|
||||||
func (v Button) Draw(target *ebiten.Image) {
|
func (v Button) Render(target *ebiten.Image) {
|
||||||
opts := &ebiten.DrawImageOptions{
|
opts := &ebiten.DrawImageOptions{
|
||||||
CompositeMode: ebiten.CompositeModeSourceAtop,
|
CompositeMode: ebiten.CompositeModeSourceAtop,
|
||||||
Filter: ebiten.FilterNearest,
|
Filter: ebiten.FilterNearest,
|
||||||
@ -216,18 +206,18 @@ func (v *Button) SetEnabled(enabled bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetSize returns the size of the button
|
// GetSize returns the size of the button
|
||||||
func (v Button) GetSize() (uint32, uint32) {
|
func (v Button) GetSize() (int, int) {
|
||||||
return v.width, v.height
|
return v.width, v.height
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveTo moves the button
|
// SetPosition moves the button
|
||||||
func (v *Button) MoveTo(x, y int) {
|
func (v *Button) SetPosition(x, y int) {
|
||||||
v.x = x
|
v.x = x
|
||||||
v.y = y
|
v.y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocation returns the location of the button
|
// GetPosition returns the location of the button
|
||||||
func (v Button) GetLocation() (x, y int) {
|
func (v Button) GetPosition() (x, y int) {
|
||||||
return v.x, v.y
|
return v.x, v.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"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/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
@ -14,14 +10,14 @@ type Checkbox struct {
|
|||||||
x, y int
|
x, y int
|
||||||
checkState bool
|
checkState bool
|
||||||
visible bool
|
visible bool
|
||||||
width, height uint32
|
width, height int
|
||||||
Image *ebiten.Image
|
Image *ebiten.Image
|
||||||
checkedImage *ebiten.Image
|
checkedImage *ebiten.Image
|
||||||
onClick func()
|
onClick func()
|
||||||
enabled bool
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateCheckbox(fileProvider d2interface.FileProvider, checkState bool) Checkbox {
|
func CreateCheckbox(checkState bool) Checkbox {
|
||||||
result := Checkbox{
|
result := Checkbox{
|
||||||
checkState: checkState,
|
checkState: checkState,
|
||||||
visible: true,
|
visible: true,
|
||||||
@ -29,20 +25,19 @@ func CreateCheckbox(fileProvider d2interface.FileProvider, checkState bool) Chec
|
|||||||
height: 0,
|
height: 0,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.Checkbox), d2datadict.Palettes[d2enum.Fechar])
|
checkboxSprite, _ := d2render.LoadSprite(d2resource.Checkbox, d2resource.PaletteFechar)
|
||||||
checkboxSprite := d2render.CreateSpriteFromDC6(dc6)
|
result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
|
||||||
result.width, result.height = checkboxSprite.GetFrameSize(0)
|
checkboxSprite.SetPosition(0, 0)
|
||||||
checkboxSprite.MoveTo(0, 0)
|
|
||||||
|
|
||||||
result.Image, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
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)
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Checkbox) Draw(target *ebiten.Image) {
|
func (v Checkbox) Render(target *ebiten.Image) {
|
||||||
opts := &ebiten.DrawImageOptions{
|
opts := &ebiten.DrawImageOptions{
|
||||||
CompositeMode: ebiten.CompositeModeSourceAtop,
|
CompositeMode: ebiten.CompositeModeSourceAtop,
|
||||||
Filter: ebiten.FilterNearest,
|
Filter: ebiten.FilterNearest,
|
||||||
@ -89,11 +84,11 @@ func (v *Checkbox) Activate() {
|
|||||||
v.onClick()
|
v.onClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Checkbox) GetLocation() (int, int) {
|
func (v Checkbox) GetPosition() (int, int) {
|
||||||
return v.x, v.y
|
return v.x, v.y
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Checkbox) GetSize() (uint32, uint32) {
|
func (v Checkbox) GetSize() (int, int) {
|
||||||
return v.width, v.height
|
return v.width, v.height
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +96,7 @@ func (v Checkbox) GetVisible() bool {
|
|||||||
return v.visible
|
return v.visible
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Checkbox) MoveTo(x int, y int) {
|
func (v *Checkbox) SetPosition(x int, y int) {
|
||||||
v.x = x
|
v.x = x
|
||||||
v.y = y
|
v.y = y
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"image/color"
|
"image/color"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
@ -32,33 +26,32 @@ type FontSize struct {
|
|||||||
|
|
||||||
// Font represents a font
|
// Font represents a font
|
||||||
type Font struct {
|
type Font struct {
|
||||||
fontSprite d2render.Sprite
|
fontSprite *d2render.Sprite
|
||||||
fontTable map[uint16]uint16
|
fontTable map[uint16]uint16
|
||||||
metrics map[uint16]FontSize
|
metrics map[uint16]FontSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFont creates or loads an existing font
|
// GetFont creates or loads an existing font
|
||||||
func GetFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font {
|
func GetFont(fontPath string, palettePath string) *Font {
|
||||||
cacheItem, exists := fontCache[font+"_"+string(palette)]
|
cacheItem, exists := fontCache[fontPath+"_"+palettePath]
|
||||||
if exists {
|
if exists {
|
||||||
return cacheItem
|
return cacheItem
|
||||||
}
|
}
|
||||||
newFont := CreateFont(font, palette, fileProvider)
|
newFont := CreateFont(fontPath, palettePath)
|
||||||
fontCache[font+"_"+string(palette)] = newFont
|
fontCache[fontPath+"_"+palettePath] = newFont
|
||||||
return newFont
|
return newFont
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateFont creates an instance of a MPQ Font
|
// 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{
|
result := &Font{
|
||||||
fontTable: make(map[uint16]uint16),
|
fontTable: make(map[uint16]uint16),
|
||||||
metrics: make(map[uint16]FontSize),
|
metrics: make(map[uint16]FontSize),
|
||||||
}
|
}
|
||||||
// bug: performance issue when using CJK fonts, because ten thousand frames will be rendered PER font
|
// 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.LoadSprite(font+".dc6", palettePath)
|
||||||
result.fontSprite = d2render.CreateSpriteFromDC6(dc6)
|
|
||||||
woo := "Woo!\x01"
|
woo := "Woo!\x01"
|
||||||
fontData := fileProvider.LoadFile(font + ".tbl")
|
fontData := d2asset.MustLoadFile(font + ".tbl")
|
||||||
if string(fontData[0:5]) != woo {
|
if string(fontData[0:5]) != woo {
|
||||||
panic("No 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
|
// GetTextMetrics returns the size of the specified text
|
||||||
func (v *Font) GetTextMetrics(text string) (width, height uint32) {
|
func (v *Font) GetTextMetrics(text string) (width, height int) {
|
||||||
width = uint32(0)
|
width = int(0)
|
||||||
curWidth := uint32(0)
|
curWidth := int(0)
|
||||||
height = uint32(0)
|
height = int(0)
|
||||||
maxCharHeight := uint32(0)
|
_, maxCharHeight := v.fontSprite.GetFrameBounds()
|
||||||
// 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))
|
|
||||||
}
|
|
||||||
for _, ch := range text {
|
for _, ch := range text {
|
||||||
if ch == '\n' {
|
if ch == '\n' {
|
||||||
width = d2helper.Max(width, curWidth)
|
width = d2helper.MaxInt(width, curWidth)
|
||||||
curWidth = 0
|
curWidth = 0
|
||||||
height += maxCharHeight + 6
|
height += maxCharHeight + 6
|
||||||
continue
|
continue
|
||||||
@ -108,15 +97,15 @@ func (v *Font) GetTextMetrics(text string) (width, height uint32) {
|
|||||||
|
|
||||||
curWidth += v.getCharWidth(ch)
|
curWidth += v.getCharWidth(ch)
|
||||||
}
|
}
|
||||||
width = d2helper.Max(width, curWidth)
|
width = d2helper.MaxInt(width, curWidth)
|
||||||
height += maxCharHeight
|
height += maxCharHeight
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw draws the font on the target surface
|
// Render draws the font on the target surface
|
||||||
func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Image) {
|
func (v *Font) Render(x, y int, text string, color color.Color, target *ebiten.Image) {
|
||||||
v.fontSprite.ColorMod = color
|
v.fontSprite.SetColorMod(color)
|
||||||
v.fontSprite.Blend = false
|
v.fontSprite.SetBlend(false)
|
||||||
|
|
||||||
maxCharHeight := uint32(0)
|
maxCharHeight := uint32(0)
|
||||||
for _, m := range v.metrics {
|
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 {
|
for _, ch := range line {
|
||||||
width := v.getCharWidth(ch)
|
width := v.getCharWidth(ch)
|
||||||
index := v.fontTable[uint16(ch)]
|
index := v.fontTable[uint16(ch)]
|
||||||
v.fontSprite.Frame = int16(index)
|
v.fontSprite.SetCurrentFrame(int(index))
|
||||||
v.fontSprite.MoveTo(xPos, y+int(v.fontSprite.Frames[index].Height))
|
_, height := v.fontSprite.GetCurrentFrameSize()
|
||||||
v.fontSprite.Draw(target)
|
v.fontSprite.SetPosition(xPos, y+int(height))
|
||||||
|
v.fontSprite.Render(target)
|
||||||
xPos += int(width)
|
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 {
|
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 (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,8 +23,8 @@ type Label struct {
|
|||||||
text string
|
text string
|
||||||
X int
|
X int
|
||||||
Y int
|
Y int
|
||||||
Width uint32
|
Width int
|
||||||
Height uint32
|
Height int
|
||||||
Alignment LabelAlignment
|
Alignment LabelAlignment
|
||||||
font *Font
|
font *Font
|
||||||
imageData *ebiten.Image
|
imageData *ebiten.Image
|
||||||
@ -36,17 +32,17 @@ type Label struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateLabel creates a new instance of a UI label
|
// 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{
|
result := Label{
|
||||||
Alignment: LabelAlignLeft,
|
Alignment: LabelAlignLeft,
|
||||||
Color: color.White,
|
Color: color.White,
|
||||||
font: GetFont(font, palette, provider),
|
font: GetFont(fontPath, palettePath),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw draws the label on the screen
|
// Render draws the label on the screen
|
||||||
func (v *Label) Draw(target *ebiten.Image) {
|
func (v *Label) Render(target *ebiten.Image) {
|
||||||
if len(v.text) == 0 {
|
if len(v.text) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -65,13 +61,13 @@ func (v *Label) Draw(target *ebiten.Image) {
|
|||||||
target.DrawImage(v.imageData, opts)
|
target.DrawImage(v.imageData, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveTo moves the label to the specified location
|
// SetPosition moves the label to the specified location
|
||||||
func (v *Label) MoveTo(x, y int) {
|
func (v *Label) SetPosition(x, y int) {
|
||||||
v.X = x
|
v.X = x
|
||||||
v.Y = y
|
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)
|
return v.font.GetTextMetrics(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +79,7 @@ func (v *Label) cacheImage() {
|
|||||||
v.Width = width
|
v.Width = width
|
||||||
v.Height = height
|
v.Height = height
|
||||||
v.imageData, _ = ebiten.NewImage(int(width), int(height), ebiten.FilterNearest)
|
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
|
// SetText sets the label's text
|
||||||
@ -96,7 +92,7 @@ func (v *Label) SetText(newText string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetSize returns the size of the label
|
// GetSize returns the size of the label
|
||||||
func (v Label) GetSize() (width, height uint32) {
|
func (v Label) GetSize() (width, height int) {
|
||||||
v.cacheImage()
|
v.cacheImage()
|
||||||
width = v.Width
|
width = v.Width
|
||||||
height = v.Height
|
height = v.Height
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
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/d2common/d2resource"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
@ -24,7 +20,7 @@ const (
|
|||||||
// Manager represents the UI manager
|
// Manager represents the UI manager
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
widgets []Widget
|
widgets []Widget
|
||||||
cursorSprite d2render.Sprite
|
cursorSprite *d2render.Sprite
|
||||||
cursorButtons CursorButton
|
cursorButtons CursorButton
|
||||||
pressedIndex int
|
pressedIndex int
|
||||||
CursorX int
|
CursorX int
|
||||||
@ -34,12 +30,11 @@ type Manager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateManager creates a new instance of a UI manager
|
// CreateManager creates a new instance of a UI manager
|
||||||
func CreateManager(fileProvider d2interface.FileProvider, soundManager d2audio.Manager) *Manager {
|
func CreateManager(soundManager d2audio.Manager) *Manager {
|
||||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.CursorDefault), d2datadict.Palettes[d2enum.Units])
|
cursorSprite, _ := d2render.LoadSprite(d2resource.CursorDefault, d2resource.PaletteUnits)
|
||||||
result := &Manager{
|
result := &Manager{
|
||||||
pressedIndex: -1,
|
pressedIndex: -1,
|
||||||
widgets: make([]Widget, 0),
|
cursorSprite: cursorSprite,
|
||||||
cursorSprite: d2render.CreateSpriteFromDC6(dc6),
|
|
||||||
clickSfx: soundManager.LoadSoundEffect(d2resource.SFXButtonClick),
|
clickSfx: soundManager.LoadSoundEffect(d2resource.SFXButtonClick),
|
||||||
waitForLeftMouseUp: false,
|
waitForLeftMouseUp: false,
|
||||||
}
|
}
|
||||||
@ -62,18 +57,18 @@ func (v *Manager) WaitForMouseRelease() {
|
|||||||
v.waitForLeftMouseUp = true
|
v.waitForLeftMouseUp = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw renders all of the UI elements
|
// Render renders all of the UI elements
|
||||||
func (v *Manager) Draw(screen *ebiten.Image) {
|
func (v *Manager) Render(screen *ebiten.Image) {
|
||||||
for _, widget := range v.widgets {
|
for _, widget := range v.widgets {
|
||||||
if !widget.GetVisible() {
|
if !widget.GetVisible() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
widget.Draw(screen)
|
widget.Render(screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
cx, cy := ebiten.CursorPosition()
|
cx, cy := ebiten.CursorPosition()
|
||||||
v.cursorSprite.MoveTo(cx, cy)
|
v.cursorSprite.SetPosition(cx, cy)
|
||||||
v.cursorSprite.Draw(screen)
|
v.cursorSprite.Render(screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates all of the UI elements
|
// Update updates all of the UI elements
|
||||||
@ -98,7 +93,7 @@ func (v *Manager) Update() {
|
|||||||
if !widget.GetVisible() || !widget.GetEnabled() {
|
if !widget.GetVisible() || !widget.GetEnabled() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wx, wy := widget.GetLocation()
|
wx, wy := widget.GetPosition()
|
||||||
ww, wh := widget.GetSize()
|
ww, wh := widget.GetSize()
|
||||||
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
||||||
widget.SetPressed(true)
|
widget.SetPressed(true)
|
||||||
@ -125,7 +120,7 @@ func (v *Manager) Update() {
|
|||||||
} else {
|
} else {
|
||||||
if v.pressedIndex > -1 {
|
if v.pressedIndex > -1 {
|
||||||
widget := v.widgets[v.pressedIndex]
|
widget := v.widgets[v.pressedIndex]
|
||||||
wx, wy := widget.GetLocation()
|
wx, wy := widget.GetPosition()
|
||||||
ww, wh := widget.GetSize()
|
ww, wh := widget.GetSize()
|
||||||
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
||||||
widget.Activate()
|
widget.Activate()
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
package d2ui
|
package d2ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/inpututil"
|
"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/d2common/d2resource"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
@ -22,17 +18,17 @@ type TextBox struct {
|
|||||||
y int
|
y int
|
||||||
visible bool
|
visible bool
|
||||||
enabled bool
|
enabled bool
|
||||||
bgSprite d2render.Sprite
|
bgSprite *d2render.Sprite
|
||||||
textLabel Label
|
textLabel Label
|
||||||
lineBar Label
|
lineBar Label
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTextbox(fileProvider d2interface.FileProvider) TextBox {
|
func CreateTextbox() TextBox {
|
||||||
dc6, _ := d2dc6.LoadDC6(fileProvider.LoadFile(d2resource.TextBox2), d2datadict.Palettes[d2enum.Units])
|
bgSprite, _ := d2render.LoadSprite(d2resource.TextBox2, d2resource.PaletteUnits)
|
||||||
result := TextBox{
|
result := TextBox{
|
||||||
bgSprite: d2render.CreateSpriteFromDC6(dc6),
|
bgSprite: bgSprite,
|
||||||
textLabel: CreateLabel(fileProvider, d2resource.FontFormal11, d2enum.Units),
|
textLabel: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
||||||
lineBar: CreateLabel(fileProvider, d2resource.FontFormal11, d2enum.Units),
|
lineBar: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
visible: true,
|
visible: true,
|
||||||
}
|
}
|
||||||
@ -55,14 +51,14 @@ func repeatingKeyPressed(key ebiten.Key) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v TextBox) Draw(target *ebiten.Image) {
|
func (v TextBox) Render(target *ebiten.Image) {
|
||||||
if !v.visible {
|
if !v.visible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v.bgSprite.Draw(target)
|
v.bgSprite.Render(target)
|
||||||
v.textLabel.Draw(target)
|
v.textLabel.Render(target)
|
||||||
if (time.Now().UnixNano()/1e6)&(1<<8) > 0 {
|
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:]
|
result = result[1:]
|
||||||
continue
|
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)
|
v.textLabel.SetText(result)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v TextBox) GetSize() (width, height uint32) {
|
func (v TextBox) GetSize() (width, height int) {
|
||||||
return v.bgSprite.GetSize()
|
return v.bgSprite.GetCurrentFrameSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *TextBox) MoveTo(x, y int) {
|
func (v *TextBox) SetPosition(x, y int) {
|
||||||
v.x = x
|
v.x = x
|
||||||
v.y = y
|
v.y = y
|
||||||
v.textLabel.MoveTo(v.x+6, v.y+3)
|
v.textLabel.SetPosition(v.x+6, v.y+3)
|
||||||
v.lineBar.MoveTo(v.x+6+int(v.textLabel.Width), v.y+3)
|
v.lineBar.SetPosition(v.x+6+int(v.textLabel.Width), v.y+3)
|
||||||
v.bgSprite.MoveTo(v.x, v.y+26)
|
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
|
return v.x, v.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,225 +2,179 @@ package d2render
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"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 {
|
type Sprite struct {
|
||||||
Directions uint32
|
x int
|
||||||
FramesPerDirection uint32
|
y int
|
||||||
Frames []SpriteFrame
|
lastFrameTime float64
|
||||||
SpecialFrameTime int
|
animation *d2asset.Animation
|
||||||
AnimateBackwards bool // Because why not
|
|
||||||
StopOnLastFrame bool
|
|
||||||
X, Y int
|
|
||||||
Frame, Direction int16
|
|
||||||
Blend bool
|
|
||||||
LastFrameTime float64
|
|
||||||
Animate bool
|
|
||||||
ColorMod color.Color
|
|
||||||
valid bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpriteFrame represents a single frame of a sprite
|
func LoadSprite(animationPath, palettePath string) (*Sprite, error) {
|
||||||
type SpriteFrame struct {
|
animation, err := d2asset.LoadAnimation(animationPath, palettePath)
|
||||||
Flip uint32
|
if err != nil {
|
||||||
Width uint32
|
return nil, err
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Frames = make([]SpriteFrame, len(dc6.Frames))
|
return &Sprite{lastFrameTime: d2helper.Now(), animation: animation}, nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Sprite) IsValid() bool {
|
func MustLoadSprite(animationPath, palettePath string) *Sprite {
|
||||||
return v.valid
|
sprite, err := LoadSprite(animationPath, palettePath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprite
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSize returns the size of the sprite
|
func (s *Sprite) Render(target *ebiten.Image) error {
|
||||||
func (v Sprite) GetSize() (uint32, uint32) {
|
if err := s.advance(); err != nil {
|
||||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
return err
|
||||||
return frame.Width, frame.Height
|
}
|
||||||
|
|
||||||
|
_, 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() {
|
func (s *Sprite) RenderSegmented(target *ebiten.Image, segmentsX, segmentsY, frameOffset int) error {
|
||||||
if !v.Animate {
|
if err := s.advance(); err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
var timePerFrame float64
|
|
||||||
|
|
||||||
if v.SpecialFrameTime >= 0 {
|
var currentY int
|
||||||
timePerFrame = (float64(v.SpecialFrameTime) / float64(len(v.Frames))) / 1000.0
|
for y := 0; y < segmentsY; y++ {
|
||||||
} else {
|
var currentX int
|
||||||
timePerFrame = 1.0 / float64(len(v.Frames))
|
var maxFrameHeight int
|
||||||
}
|
for x := 0; x < segmentsX; x++ {
|
||||||
now := d2helper.Now()
|
if err := s.animation.SetCurrentFrame(x + y*segmentsX + frameOffset*segmentsX*segmentsY); err != nil {
|
||||||
for v.LastFrameTime+timePerFrame < now {
|
return err
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
func (s *Sprite) SetPosition(x, y int) {
|
||||||
v.LastFrameTime = d2helper.Now()
|
s.x = x
|
||||||
v.Frame = 0
|
s.y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Sprite) OnLastFrame() bool {
|
func (s *Sprite) GetPosition() (int, int) {
|
||||||
return v.Frame == int16(v.FramesPerDirection-1)
|
return s.x, s.y
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFrameSize returns the size of the specific frame
|
func (s *Sprite) GetFrameSize(frameIndex int) (int, int, error) {
|
||||||
func (v Sprite) GetFrameSize(frame int) (width, height uint32) {
|
return s.animation.GetFrameSize(frameIndex)
|
||||||
width = v.Frames[frame].Width
|
|
||||||
height = v.Frames[frame].Height
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTotalFrames returns the number of frames in this sprite (for all directions)
|
func (s *Sprite) GetCurrentFrameSize() (int, int) {
|
||||||
func (v Sprite) GetTotalFrames() int {
|
return s.animation.GetCurrentFrameSize()
|
||||||
return len(v.Frames)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw draws the sprite onto the target
|
func (s *Sprite) GetFrameBounds() (int, int) {
|
||||||
func (v *Sprite) Draw(target *ebiten.Image) {
|
return s.animation.GetFrameBounds()
|
||||||
v.updateAnimation()
|
}
|
||||||
opts := &ebiten.DrawImageOptions{}
|
|
||||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
func (s *Sprite) GetCurrentFrame() int {
|
||||||
opts.GeoM.Translate(
|
return s.animation.GetCurrentFrame()
|
||||||
float64(int32(v.X)+frame.OffsetX),
|
}
|
||||||
float64(int32(v.Y)-int32(frame.Height)+frame.OffsetY),
|
|
||||||
)
|
func (s *Sprite) GetFrameCount() int {
|
||||||
if v.Blend {
|
return s.animation.GetFrameCount()
|
||||||
opts.CompositeMode = ebiten.CompositeModeLighter
|
}
|
||||||
} else {
|
|
||||||
opts.CompositeMode = ebiten.CompositeModeSourceOver
|
func (s *Sprite) IsOnFirstFrame() bool {
|
||||||
}
|
return s.animation.IsOnFirstFrame()
|
||||||
if v.ColorMod != nil {
|
}
|
||||||
opts.ColorM = d2corehelper.ColorToColorM(v.ColorMod)
|
|
||||||
}
|
func (s *Sprite) IsOnLastFrame() bool {
|
||||||
if err := target.DrawImage(frame.Image, opts); err != nil {
|
return s.animation.IsOnLastFrame()
|
||||||
log.Panic(err.Error())
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
s.lastFrameTime = lastFrameTime
|
||||||
|
return nil
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/OpenDiablo2/OpenDiablo2
|
|||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
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/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.1.0.20191219185932-f3712a7e620b
|
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/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 h1:tDnuU0igiBiQFjsvq1Bi7DpoUjqI76VVvW045vpeFeM=
|
||||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0/go.mod h1:h/5OEGj4G+fpYxluLjSMZbFY011ZxAntO98nCl8mrCs=
|
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-20191222011122-c8cfab029ae6 h1:9TXDUOedNtivxLPiuWMMPxH+aTbKZQv2QBb9lpiZb/8=
|
||||||
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/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 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
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=
|
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()
|
d2Engine = d2core.CreateEngine()
|
||||||
kingpin.Parse()
|
kingpin.Parse()
|
||||||
if *region == 0 {
|
if *region == 0 {
|
||||||
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
|
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
|
||||||
} else {
|
} 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.SetCursorVisible(false)
|
||||||
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
|
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
|
||||||
|
Loading…
Reference in New Issue
Block a user