1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2025-02-04 07:37:48 -05:00

One last restructure for now

This commit is contained in:
Tim Sarbin 2019-10-25 19:37:04 -04:00
parent 56eb461f1f
commit 6562816710
14 changed files with 161 additions and 156 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
__debug_bin
**/*__debug_bin
.vscode/*.*
**/Client.exe
**/Client

Binary file not shown.

9
Common/FileProvider.go Normal file
View File

@ -0,0 +1,9 @@
package Common
import "github.com/essial/OpenDiablo2/Palettes"
// FileProvider is an instance that can provide different types of files
type FileProvider interface {
LoadFile(fileName string) []byte
LoadSprite(fileName string, palette Palettes.Palette) *Sprite
}

View File

@ -1,8 +0,0 @@
package Common
import "github.com/essial/OpenDiablo2/Palettes"
// SpriteProvider is an instance that can provide sprites
type SpriteProvider interface {
LoadSprite(fileName string, palette Palettes.Palette) *Sprite
}

View File

@ -9,6 +9,7 @@ import (
"sync"
"github.com/essial/OpenDiablo2/Common"
"github.com/essial/OpenDiablo2/MPQ"
"github.com/essial/OpenDiablo2/Palettes"
"github.com/essial/OpenDiablo2/ResourcePaths"
"github.com/essial/OpenDiablo2/UI"
@ -53,7 +54,6 @@ type Engine struct {
CurrentScene Common.SceneInterface // The current scene being rendered
UIManager *UI.Manager // The UI manager
nextScene Common.SceneInterface // The next scene to be loaded at the end of the game loop
fontCache map[string]*MPQFont // The font cash
audioContext *audio.Context // The Audio context
bgmAudio *audio.Player // The audio player
fullscreenKey bool // When true, the fullscreen toggle is still being pressed
@ -65,7 +65,6 @@ func CreateEngine() *Engine {
LoadingProgress: float64(0.0),
CurrentScene: nil,
nextScene: nil,
fontCache: make(map[string]*MPQFont),
}
result.loadConfigurationFile()
result.mapMpqFiles()
@ -102,7 +101,7 @@ func (v *Engine) mapMpqFiles() {
lock := sync.RWMutex{}
for _, mpqFileName := range v.Settings.MpqLoadOrder {
mpqPath := path.Join(v.Settings.MpqPath, mpqFileName)
mpq, err := LoadMPQ(mpqPath)
mpq, err := MPQ.Load(mpqPath)
if err != nil {
log.Fatal(err)
}
@ -121,20 +120,20 @@ func (v *Engine) mapMpqFiles() {
}
}
// GetFile loads a file from the specified mpq and returns the data as a byte array
func (v *Engine) GetFile(fileName string) []byte {
// LoadFile loads a file from the specified mpq and returns the data as a byte array
func (v *Engine) LoadFile(fileName string) []byte {
// TODO: May want to cache some things if performance becomes an issue
mpqFile := v.Files[strings.ToLower(fileName)]
mpq, err := LoadMPQ(mpqFile)
mpq, err := MPQ.Load(mpqFile)
if err != nil {
log.Fatal(err)
}
fileName = strings.ReplaceAll(fileName, `/`, `\`)[1:]
blockTableEntry, err := mpq.getFileBlockData(fileName)
blockTableEntry, err := mpq.GetFileBlockData(fileName)
if err != nil {
log.Fatal(err)
}
mpqStream := CreateMPQStream(mpq, blockTableEntry, fileName)
mpqStream := MPQ.CreateStream(mpq, blockTableEntry, fileName)
result := make([]byte, blockTableEntry.UncompressedFileSize)
mpqStream.Read(result, 0, blockTableEntry.UncompressedFileSize)
@ -155,7 +154,7 @@ func (v *Engine) loadPalettes() {
}
nameParts := strings.Split(file, `/`)
paletteName := Palettes.Palette(nameParts[len(nameParts)-2])
palette := Common.CreatePalette(paletteName, v.GetFile(file))
palette := Common.CreatePalette(paletteName, v.LoadFile(file))
v.Palettes[paletteName] = palette
}
}
@ -163,7 +162,7 @@ func (v *Engine) loadPalettes() {
func (v *Engine) loadSoundEntries() {
log.Println("loading sound configurations")
v.SoundEntries = make(map[string]SoundEntry)
soundData := strings.Split(string(v.GetFile(ResourcePaths.SoundSettings)), "\r\n")[1:]
soundData := strings.Split(string(v.LoadFile(ResourcePaths.SoundSettings)), "\r\n")[1:]
for _, line := range soundData {
if len(line) == 0 {
continue
@ -175,7 +174,7 @@ func (v *Engine) loadSoundEntries() {
// LoadSprite loads a sprite from the game's data files
func (v *Engine) LoadSprite(fileName string, palette Palettes.Palette) *Common.Sprite {
data := v.GetFile(fileName)
data := v.LoadFile(fileName)
sprite := Common.CreateSprite(data, v.Palettes[palette])
return sprite
}
@ -249,24 +248,13 @@ func (v *Engine) SetNextScene(nextScene Common.SceneInterface) {
v.nextScene = nextScene
}
// GetFont creates or loads an existing font
func (v *Engine) GetFont(font string, palette Palettes.Palette) *MPQFont {
cacheItem, exists := v.fontCache[font+"_"+string(palette)]
if exists {
return cacheItem
}
newFont := CreateMPQFont(v, font, palette)
v.fontCache[font+"_"+string(palette)] = newFont
return newFont
}
// PlayBGM plays an infinitely looping background track
func (v *Engine) PlayBGM(song string) {
go func() {
if v.bgmAudio != nil {
v.bgmAudio.Close()
}
audioData := v.GetFile(song)
audioData := v.LoadFile(song)
d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData))
if err != nil {
log.Fatal(err)

View File

@ -1,4 +1,4 @@
package OpenDiablo2
package MPQ
// CryptoBuffer contains the crypto bytes for filename hashing
var CryptoBuffer [0x500]uint32

View File

@ -1,4 +1,4 @@
package OpenDiablo2
package MPQ
import (
"encoding/binary"
@ -12,13 +12,13 @@ import (
// MPQ represents an MPQ archive
type MPQ struct {
File *os.File
HashTableEntries []MPQHashTableEntry
BlockTableEntries []MPQBlockTableEntry
Data MPQData
HashTableEntries []HashTableEntry
BlockTableEntries []BlockTableEntry
Data Data
}
// MPQData Represents a MPQ file
type MPQData struct {
// Data Represents a MPQ file
type Data struct {
Magic [4]byte
HeaderSize uint32
ArchiveSize uint32
@ -30,8 +30,8 @@ type MPQData struct {
BlockTableEntries uint32
}
// MPQHashTableEntry represents a hashed file entry in the MPQ file
type MPQHashTableEntry struct { // 16 bytes
// HashTableEntry represents a hashed file entry in the MPQ file
type HashTableEntry struct { // 16 bytes
NamePartA uint32
NamePartB uint32
Locale uint16
@ -39,50 +39,50 @@ type MPQHashTableEntry struct { // 16 bytes
BlockIndex uint32
}
// MPQFileFlag represents flags for a file record in the MPQ archive
type MPQFileFlag uint32
// FileFlag represents flags for a file record in the MPQ archive
type FileFlag uint32
const (
// MpqFileImplode - File is compressed using PKWARE Data compression library
MpqFileImplode MPQFileFlag = 0x00000100
MpqFileImplode FileFlag = 0x00000100
// MpqFileCompress - File is compressed using combination of compression methods
MpqFileCompress MPQFileFlag = 0x00000200
MpqFileCompress FileFlag = 0x00000200
// MpqFileEncrypted - The file is encrypted
MpqFileEncrypted MPQFileFlag = 0x00010000
MpqFileEncrypted FileFlag = 0x00010000
// MpqFileFixKey - The decryption key for the file is altered according to the position of the file in the archive
MpqFileFixKey MPQFileFlag = 0x00020000
MpqFileFixKey FileFlag = 0x00020000
// MpqFilePatchFile - The file contains incremental patch for an existing file in base MPQ
MpqFilePatchFile MPQFileFlag = 0x00100000
MpqFilePatchFile FileFlag = 0x00100000
// MpqFileSingleUnit - Instead of being divided to 0x1000-bytes blocks, the file is stored as single unit
MpqFileSingleUnit MPQFileFlag = 0x01000000
MpqFileSingleUnit FileFlag = 0x01000000
// FileDeleteMarker - File is a deletion marker, indicating that the file no longer exists. This is used to allow patch
// archives to delete files present in lower-priority archives in the search chain. The file usually
// has length of 0 or 1 byte and its name is a hash
FileDeleteMarker MPQFileFlag = 0x02000000
FileDeleteMarker FileFlag = 0x02000000
// FileSEctorCrc - File has checksums for each sector. Ignored if file is not compressed or imploded.
FileSEctorCrc MPQFileFlag = 0x04000000
FileSEctorCrc FileFlag = 0x04000000
// MpqFileExists - Set if file exists, reset when the file was deleted
MpqFileExists MPQFileFlag = 0x80000000
MpqFileExists FileFlag = 0x80000000
)
// MPQBlockTableEntry represents an entry in the block table
type MPQBlockTableEntry struct { // 16 bytes
// BlockTableEntry represents an entry in the block table
type BlockTableEntry struct { // 16 bytes
FilePosition uint32
CompressedFileSize uint32
UncompressedFileSize uint32
Flags MPQFileFlag
Flags FileFlag
// Local Stuff...
FileName string
EncryptionSeed uint32
}
// HasFlag returns true if the specified flag is present
func (v MPQBlockTableEntry) HasFlag(flag MPQFileFlag) bool {
func (v BlockTableEntry) HasFlag(flag FileFlag) bool {
return (v.Flags & flag) != 0
}
// LoadMPQ loads an MPQ file and returns a MPQ structure
func LoadMPQ(fileName string) (MPQ, error) {
// Load loads an MPQ file and returns a MPQ structure
func Load(fileName string) (MPQ, error) {
result := MPQ{}
file, err := os.Open(fileName)
if err != nil {
@ -116,7 +116,7 @@ func (v *MPQ) loadHashTable() {
binary.Read(v.File, binary.LittleEndian, &hashData)
decrypt(hashData, hashString("(hash table)", 3))
for i := uint32(0); i < v.Data.HashTableEntries; i++ {
v.HashTableEntries = append(v.HashTableEntries, MPQHashTableEntry{
v.HashTableEntries = append(v.HashTableEntries, HashTableEntry{
NamePartA: hashData[i*4],
NamePartB: hashData[(i*4)+1],
// TODO: Verify that we're grabbing the right high/lo word for the vars below
@ -133,11 +133,11 @@ func (v *MPQ) loadBlockTable() {
binary.Read(v.File, binary.LittleEndian, &blockData)
decrypt(blockData, hashString("(block table)", 3))
for i := uint32(0); i < v.Data.BlockTableEntries; i++ {
v.BlockTableEntries = append(v.BlockTableEntries, MPQBlockTableEntry{
v.BlockTableEntries = append(v.BlockTableEntries, BlockTableEntry{
FilePosition: blockData[(i * 4)],
CompressedFileSize: blockData[(i*4)+1],
UncompressedFileSize: blockData[(i*4)+2],
Flags: MPQFileFlag(blockData[(i*4)+3]),
Flags: FileFlag(blockData[(i*4)+3]),
})
}
}
@ -185,7 +185,7 @@ func hashString(key string, hashType uint32) uint32 {
return seed1
}
func (v MPQ) getFileHashEntry(fileName string) (MPQHashTableEntry, error) {
func (v MPQ) getFileHashEntry(fileName string) (HashTableEntry, error) {
hashA := hashString(fileName, 1)
hashB := hashString(fileName, 2)
@ -196,13 +196,14 @@ func (v MPQ) getFileHashEntry(fileName string) (MPQHashTableEntry, error) {
return v.HashTableEntries[idx], nil
}
return MPQHashTableEntry{}, errors.New("file not found")
return HashTableEntry{}, errors.New("file not found")
}
func (v MPQ) getFileBlockData(fileName string) (MPQBlockTableEntry, error) {
// GetFileBlockData gets a block table entry
func (v MPQ) GetFileBlockData(fileName string) (BlockTableEntry, error) {
fileEntry, err := v.getFileHashEntry(fileName)
if err != nil {
return MPQBlockTableEntry{}, err
return BlockTableEntry{}, err
}
return v.BlockTableEntries[fileEntry.BlockIndex], nil
}
@ -214,13 +215,13 @@ func (v *MPQ) Close() {
// ReadFile reads a file from the MPQ and returns a memory stream
func (v MPQ) ReadFile(fileName string) ([]byte, error) {
fileBlockData, err := v.getFileBlockData(fileName)
fileBlockData, err := v.GetFileBlockData(fileName)
if err != nil {
return nil, err
}
fileBlockData.FileName = strings.ToLower(fileName)
fileBlockData.calculateEncryptionSeed()
mpqStream := CreateMPQStream(v, fileBlockData, fileName)
mpqStream := CreateStream(v, fileBlockData, fileName)
buffer := make([]byte, fileBlockData.UncompressedFileSize)
mpqStream.Read(buffer, 0, fileBlockData.UncompressedFileSize)
return buffer, nil
@ -235,7 +236,7 @@ func (v MPQ) ReadTextFile(fileName string) (string, error) {
return string(data), nil
}
func (v *MPQBlockTableEntry) calculateEncryptionSeed() {
func (v *BlockTableEntry) calculateEncryptionSeed() {
fileName := path.Base(v.FileName)
v.EncryptionSeed = hashString(fileName, 3)
if !v.HasFlag(MpqFileFixKey) {

View File

@ -1,4 +1,4 @@
package OpenDiablo2
package MPQ
import (
"bytes"
@ -12,10 +12,10 @@ import (
"github.com/essial/OpenDiablo2/Compression"
)
// MPQStream represents a stream of data in an MPQ archive
type MPQStream struct {
// Stream represents a stream of data in an MPQ archive
type Stream struct {
MPQData MPQ
BlockTableEntry MPQBlockTableEntry
BlockTableEntry BlockTableEntry
FileName string
EncryptionSeed uint32
BlockPositions []uint32
@ -25,9 +25,9 @@ type MPQStream struct {
BlockSize uint32
}
// CreateMPQStream creates an MPQ stream
func CreateMPQStream(mpq MPQ, blockTableEntry MPQBlockTableEntry, fileName string) *MPQStream {
result := &MPQStream{
// CreateStream creates an MPQ stream
func CreateStream(mpq MPQ, blockTableEntry BlockTableEntry, fileName string) *Stream {
result := &Stream{
MPQData: mpq,
BlockTableEntry: blockTableEntry,
CurrentBlockIndex: 0xFFFFFFFF,
@ -45,7 +45,7 @@ func CreateMPQStream(mpq MPQ, blockTableEntry MPQBlockTableEntry, fileName strin
return result
}
func (v *MPQStream) loadBlockOffsets() {
func (v *Stream) loadBlockOffsets() {
blockPositionCount := ((v.BlockTableEntry.UncompressedFileSize + v.BlockSize - 1) / v.BlockSize) + 1
v.BlockPositions = make([]uint32, blockPositionCount)
v.MPQData.File.Seek(int64(v.BlockTableEntry.FilePosition), 0)
@ -62,7 +62,7 @@ func (v *MPQStream) loadBlockOffsets() {
}
}
func (v *MPQStream) Read(buffer []byte, offset, count uint32) uint32 {
func (v *Stream) Read(buffer []byte, offset, count uint32) uint32 {
if v.BlockTableEntry.HasFlag(MpqFileSingleUnit) {
return v.readInternalSingleUnit(buffer, offset, count)
}
@ -80,7 +80,7 @@ func (v *MPQStream) Read(buffer []byte, offset, count uint32) uint32 {
return readTotal
}
func (v *MPQStream) readInternalSingleUnit(buffer []byte, offset, count uint32) uint32 {
func (v *Stream) readInternalSingleUnit(buffer []byte, offset, count uint32) uint32 {
if len(v.CurrentData) == 0 {
v.loadSingleUnit()
}
@ -91,7 +91,7 @@ func (v *MPQStream) readInternalSingleUnit(buffer []byte, offset, count uint32)
return bytesToCopy
}
func (v *MPQStream) readInternal(buffer []byte, offset, count uint32) uint32 {
func (v *Stream) readInternal(buffer []byte, offset, count uint32) uint32 {
v.bufferData()
localPosition := v.CurrentPosition % v.BlockSize
bytesToCopy := Common.Min(uint32(len(v.CurrentData))-localPosition, count)
@ -103,7 +103,7 @@ func (v *MPQStream) readInternal(buffer []byte, offset, count uint32) uint32 {
return bytesToCopy
}
func (v *MPQStream) bufferData() {
func (v *Stream) bufferData() {
requiredBlock := uint32(v.CurrentPosition / v.BlockSize)
if requiredBlock == v.CurrentBlockIndex {
return
@ -113,7 +113,7 @@ func (v *MPQStream) bufferData() {
v.CurrentBlockIndex = requiredBlock
}
func (v *MPQStream) loadSingleUnit() {
func (v *Stream) loadSingleUnit() {
fileData := make([]byte, v.BlockSize)
v.MPQData.File.Seek(int64(v.MPQData.Data.HeaderSize), 0)
binary.Read(v.MPQData.File, binary.LittleEndian, &fileData)
@ -124,7 +124,7 @@ func (v *MPQStream) loadSingleUnit() {
v.CurrentData = decompressMulti(fileData, v.BlockTableEntry.UncompressedFileSize)
}
func (v *MPQStream) loadBlock(blockIndex, expectedLength uint32) []byte {
func (v *Stream) loadBlock(blockIndex, expectedLength uint32) []byte {
var (
offset uint32
toRead uint32

View File

@ -1,41 +0,0 @@
package OpenDiablo2
import (
"github.com/essial/OpenDiablo2/Common"
"github.com/essial/OpenDiablo2/Palettes"
)
// MPQFontSize represents the size of a character in a font
type MPQFontSize struct {
Width uint8
Height uint8
}
// MPQFont represents a font
type MPQFont struct {
Engine *Engine
FontSprite *Common.Sprite
Metrics map[uint8]MPQFontSize
}
// CreateMPQFont creates an instance of a MPQ Font
func CreateMPQFont(engine *Engine, font string, palette Palettes.Palette) *MPQFont {
result := &MPQFont{
Engine: engine,
Metrics: make(map[uint8]MPQFontSize),
}
result.FontSprite = result.Engine.LoadSprite(font+".dc6", palette)
woo := "Woo!\x01"
fontData := result.Engine.GetFile(font + ".tbl")
if string(fontData[0:5]) != woo {
panic("No woo :(")
}
for i := 12; i < len(fontData); i += 14 {
fontSize := MPQFontSize{
Width: fontData[i+3],
Height: fontData[i+4],
}
result.Metrics[fontData[i+8]] = fontSize
}
return result
}

View File

@ -5,6 +5,7 @@ import (
"github.com/essial/OpenDiablo2/Common"
"github.com/essial/OpenDiablo2/Palettes"
"github.com/essial/OpenDiablo2/UI"
"github.com/essial/OpenDiablo2/ResourcePaths"
"github.com/hajimehoshi/ebiten"
@ -19,8 +20,8 @@ type MainMenu struct {
diabloLogoRight *Common.Sprite
diabloLogoLeftBack *Common.Sprite
diabloLogoRightBack *Common.Sprite
copyrightLabel *UILabel
copyrightLabel2 *UILabel
copyrightLabel *UI.Label
copyrightLabel2 *UI.Label
showTrademarkScreen bool
leftButtonHeld bool
}
@ -42,16 +43,16 @@ func (v *MainMenu) Load() {
loadStep := 1.0 / 8.0
v.engine.LoadingProgress = 0
{
v.copyrightLabel = CreateUILabel(v.engine, ResourcePaths.FontFormal12, Palettes.Static)
v.copyrightLabel.Alignment = UILabelAlignCenter
v.copyrightLabel = UI.CreateLabel(v.engine, ResourcePaths.FontFormal12, Palettes.Static)
v.copyrightLabel.Alignment = UI.LabelAlignCenter
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
v.copyrightLabel.ColorMod = color.RGBA{188, 168, 140, 255}
v.copyrightLabel.MoveTo(400, 500)
v.engine.LoadingProgress += loadStep
}
{
v.copyrightLabel2 = CreateUILabel(v.engine, ResourcePaths.FontFormal12, Palettes.Static)
v.copyrightLabel2.Alignment = UILabelAlignCenter
v.copyrightLabel2 = UI.CreateLabel(v.engine, ResourcePaths.FontFormal12, Palettes.Static)
v.copyrightLabel2.Alignment = UI.LabelAlignCenter
v.copyrightLabel2.SetText("All Rights Reserved.")
v.copyrightLabel2.ColorMod = color.RGBA{188, 168, 140, 255}
v.copyrightLabel2.MoveTo(400, 525)

52
UI/Font.go Normal file
View File

@ -0,0 +1,52 @@
package UI
import (
"github.com/essial/OpenDiablo2/Common"
"github.com/essial/OpenDiablo2/Palettes"
)
var fontCache = map[string]*Font{}
// FontSize represents the size of a character in a font
type FontSize struct {
Width uint8
Height uint8
}
// Font represents a font
type Font struct {
FontSprite *Common.Sprite
Metrics map[uint8]FontSize
}
// GetFont creates or loads an existing font
func GetFont(font string, palette Palettes.Palette, fileProvider Common.FileProvider) *Font {
cacheItem, exists := fontCache[font+"_"+string(palette)]
if exists {
return cacheItem
}
newFont := CreateFont(font, palette, fileProvider)
fontCache[font+"_"+string(palette)] = newFont
return newFont
}
// CreateFont creates an instance of a MPQ Font
func CreateFont(font string, palette Palettes.Palette, fileProvider Common.FileProvider) *Font {
result := &Font{
Metrics: make(map[uint8]FontSize),
}
result.FontSprite = fileProvider.LoadSprite(font+".dc6", palette)
woo := "Woo!\x01"
fontData := fileProvider.LoadFile(font + ".tbl")
if string(fontData[0:5]) != woo {
panic("No woo :(")
}
for i := 12; i < len(fontData); i += 14 {
fontSize := FontSize{
Width: fontData[i+3],
Height: fontData[i+4],
}
result.Metrics[fontData[i+8]] = fontSize
}
return result
}

View File

@ -14,7 +14,7 @@ type Manager struct {
}
// CreateManager creates a new instance of a UI manager
func CreateManager(provider Common.SpriteProvider) *Manager {
func CreateManager(provider Common.FileProvider) *Manager {
result := &Manager{
widgets: make([]*Widget, 0),
cursorSprite: provider.LoadSprite(ResourcePaths.CursorDefault, Palettes.Units),

View File

@ -1,4 +1,4 @@
package OpenDiablo2
package UI
import (
"image/color"
@ -8,53 +8,53 @@ import (
"github.com/hajimehoshi/ebiten"
)
// UILabelAlignment represents a label's alignment
type UILabelAlignment uint8
// LabelAlignment represents a label's alignment
type LabelAlignment uint8
const (
// UILabelAlignLeft represents a left-aligned label
UILabelAlignLeft UILabelAlignment = 0
// UILabelAlignCenter represents a center-aligned label
UILabelAlignCenter UILabelAlignment = 1
// UILabelAlignRight represents a right-aligned label
UILabelAlignRight UILabelAlignment = 2
// LabelAlignLeft represents a left-aligned label
LabelAlignLeft LabelAlignment = 0
// LabelAlignCenter represents a center-aligned label
LabelAlignCenter LabelAlignment = 1
// LabelAlignRight represents a right-aligned label
LabelAlignRight LabelAlignment = 2
)
// UILabel represents a user interface label
type UILabel struct {
// Label represents a user interface label
type Label struct {
text string
X int
Y int
Width uint32
Height uint32
Alignment UILabelAlignment
font *MPQFont
Alignment LabelAlignment
font *Font
imageData *ebiten.Image
ColorMod color.Color
}
// CreateUILabel creates a new instance of a UI label
func CreateUILabel(engine *Engine, font string, palette Palettes.Palette) *UILabel {
result := &UILabel{
Alignment: UILabelAlignLeft,
// CreateLabel creates a new instance of a UI label
func CreateLabel(provider Common.FileProvider, font string, palette Palettes.Palette) *Label {
result := &Label{
Alignment: LabelAlignLeft,
ColorMod: nil,
font: engine.GetFont(font, palette),
font: GetFont(font, palette, provider),
}
return result
}
// Draw draws the label on the screen
func (v *UILabel) Draw(target *ebiten.Image) {
func (v *Label) Draw(target *ebiten.Image) {
if len(v.text) == 0 {
return
}
v.cacheImage()
opts := &ebiten.DrawImageOptions{}
if v.Alignment == UILabelAlignCenter {
if v.Alignment == LabelAlignCenter {
opts.GeoM.Translate(float64(v.X-int(v.Width/2)), float64(v.Y))
} else if v.Alignment == UILabelAlignRight {
} else if v.Alignment == LabelAlignRight {
opts.GeoM.Translate(float64(v.X-int(v.Width)), float64(v.Y))
} else {
opts.GeoM.Translate(float64(v.X), float64(v.Y))
@ -64,7 +64,7 @@ func (v *UILabel) Draw(target *ebiten.Image) {
target.DrawImage(v.imageData, opts)
}
func (v *UILabel) calculateSize() (uint32, uint32) {
func (v *Label) calculateSize() (uint32, uint32) {
width := uint32(0)
height := uint32(0)
for _, ch := range v.text {
@ -76,12 +76,12 @@ func (v *UILabel) calculateSize() (uint32, uint32) {
}
// MoveTo moves the label to the specified location
func (v *UILabel) MoveTo(x, y int) {
func (v *Label) MoveTo(x, y int) {
v.X = x
v.Y = y
}
func (v *UILabel) cacheImage() {
func (v *Label) cacheImage() {
if v.imageData != nil {
return
}
@ -102,7 +102,7 @@ func (v *UILabel) cacheImage() {
}
// SetText sets the label's text
func (v *UILabel) SetText(newText string) {
func (v *Label) SetText(newText string) {
if v.text == newText {
return
}

View File

@ -4,6 +4,7 @@ import (
"log"
"github.com/essial/OpenDiablo2"
"github.com/essial/OpenDiablo2/MPQ"
"github.com/hajimehoshi/ebiten"
)
@ -11,7 +12,7 @@ var d2Engine *OpenDiablo2.Engine
func main() {
log.Println("OpenDiablo2 - Open source Diablo 2 engine")
OpenDiablo2.InitializeCryptoBuffer()
MPQ.InitializeCryptoBuffer()
d2Engine = OpenDiablo2.CreateEngine()
ebiten.SetCursorVisible(false)
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)