Refectoring to reduce code warnings (#283)

This commit is contained in:
Tim Sarbin 2020-02-01 21:51:49 -05:00 committed by GitHub
parent ea4450f207
commit 6606774ece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 346 additions and 375 deletions

View File

@ -59,6 +59,7 @@ func (v *BitStream) EnsureBits(bitCount int) bool {
// WasteBits dry-reads the specified number of bits
func (v *BitStream) WasteBits(bitCount int) {
//noinspection GoRedundantConversion
v.current >>= uint(bitCount)
v.bitCount -= bitCount
}

View File

@ -65,7 +65,7 @@ func init() {
func indexObjects(objects []ObjectLookupRecord) [][][]*ObjectLookupRecord {
// Allocating 6 to allow Acts 1-5 without requiring a -1 at every read.
indexedObjects = make([][][]*ObjectLookupRecord, 6)
for i, _ := range objects {
for i := range objects {
record := &objects[i]
if indexedObjects[record.Act] == nil {
// Likewise allocating 3 so a -1 isn't necessary.

View File

@ -15,8 +15,8 @@ const (
HeroDruid Hero = 7 // Druid
)
func (v Hero) GetToken() string {
switch v {
func (h Hero) GetToken() string {
switch h {
case HeroBarbarian:
return "BA"
case HeroNecromancer:
@ -32,7 +32,7 @@ func (v Hero) GetToken() string {
case HeroDruid:
return "DZ"
default:
log.Fatalf("Unknown hero token: %d", v)
log.Fatalf("Unknown hero token: %d", h)
}
return ""
}

View File

@ -22,9 +22,9 @@ const _Hero_name = "BarbarianNecromancerPaladinAssassinSorceressAmazonDruid"
var _Hero_index = [...]uint8{0, 0, 9, 20, 27, 35, 44, 50, 55}
func (i Hero) String() string {
if i < 0 || i >= Hero(len(_Hero_index)-1) {
return "Hero(" + strconv.FormatInt(int64(i), 10) + ")"
func (h Hero) String() string {
if h < 0 || h >= Hero(len(_Hero_index)-1) {
return "Hero(" + strconv.FormatInt(int64(h), 10) + ")"
}
return _Hero_name[_Hero_index[i]:_Hero_index[i+1]]
return _Hero_name[_Hero_index[h]:_Hero_index[h+1]]
}

View File

@ -19,13 +19,13 @@ func LoadDCC(fileData []byte) (*DCC, error) {
var bm = d2common.CreateBitMuncher(fileData, 0)
result.Signature = int(bm.GetByte())
if result.Signature != 0x74 {
return nil, errors.New("Signature expected to be 0x74 but it is not.")
return nil, errors.New("signature expected to be 0x74 but it is not")
}
result.Version = int(bm.GetByte())
result.NumberOfDirections = int(bm.GetByte())
result.FramesPerDirection = int(bm.GetInt32())
if bm.GetInt32() != 1 {
return nil, errors.New("This value isn't 1. It has to be 1.")
return nil, errors.New("this value isn't 1. It has to be 1")
}
bm.GetInt32() // TotalSizeCoded
directionOffsets := make([]int, result.NumberOfDirections)

View File

@ -54,7 +54,7 @@ func CreateDCCDirection(bm *d2common.BitMuncher, file DCC) DCCDirection {
maxx = int(d2common.MaxInt32(int32(result.Frames[frameIdx].Box.Right()), int32(maxx)))
maxy = int(d2common.MaxInt32(int32(result.Frames[frameIdx].Box.Bottom()), int32(maxy)))
}
result.Box = d2common.Rectangle{minx, miny, (maxx - minx), (maxy - miny)}
result.Box = d2common.Rectangle{Left: minx, Top: miny, Width: maxx - minx, Height: maxy - miny}
if result.OptionalDataBits > 0 {
log.Panic("Optional bits in DCC data is not currently supported.")
}

View File

@ -36,10 +36,10 @@ func CreateDCCDirectionFrame(bits *d2common.BitMuncher, direction DCCDirection)
log.Panic("Bottom up frames are not implemented.")
} else {
result.Box = d2common.Rectangle{
result.XOffset,
result.YOffset - result.Height + 1,
result.Width,
result.Height,
Left: result.XOffset,
Top: result.YOffset - result.Height + 1,
Width: result.Width,
Height: result.Height,
}
}
result.valid = true

View File

@ -12,7 +12,7 @@ func InitializeCryptoBuffer() {
seed = (seed*125 + 3) % 0x2AAAAB
temp1 := (seed & 0xFFFF) << 0x10
seed = (seed*125 + 3) % 0x2AAAAB
temp2 := (seed & 0xFFFF)
temp2 := seed & 0xFFFF
CryptoBuffer[index2] = temp1 | temp2
index2 += 0x100
}

View File

@ -59,11 +59,11 @@ func (v *Stream) loadBlockOffsets() error {
v.BlockPositions = make([]uint32, blockPositionCount)
v.MPQData.File.Seek(int64(v.BlockTableEntry.FilePosition), 0)
reader := bufio.NewReader(v.MPQData.File)
bytes := make([]byte, blockPositionCount*4)
reader.Read(bytes)
mpqBytes := make([]byte, blockPositionCount*4)
reader.Read(mpqBytes)
for i := range v.BlockPositions {
idx := i * 4
v.BlockPositions[i] = binary.LittleEndian.Uint32(bytes[idx : idx+4])
v.BlockPositions[i] = binary.LittleEndian.Uint32(mpqBytes[idx : idx+4])
}
//binary.Read(v.MPQData.File, binary.LittleEndian, &v.BlockPositions)
blockPosSize := blockPositionCount << 2
@ -71,11 +71,11 @@ func (v *Stream) loadBlockOffsets() error {
decrypt(v.BlockPositions, v.EncryptionSeed-1)
if v.BlockPositions[0] != blockPosSize {
log.Println("Decryption of MPQ failed!")
return errors.New("Decryption of MPQ failed!")
return errors.New("decryption of MPQ failed")
}
if v.BlockPositions[1] > v.BlockSize+blockPosSize {
log.Println("Decryption of MPQ failed!")
return errors.New("Decryption of MPQ failed!")
return errors.New("decryption of MPQ failed")
}
}
return nil
@ -123,7 +123,7 @@ func (v *Stream) readInternal(buffer []byte, offset, count uint32) uint32 {
}
func (v *Stream) bufferData() {
requiredBlock := uint32(v.CurrentPosition / v.BlockSize)
requiredBlock := v.CurrentPosition / v.BlockSize
if requiredBlock == v.CurrentBlockIndex {
return
}

View File

@ -40,14 +40,6 @@ func MaxInt32(a, b int32) int32 {
return b
}
func NextPow2(x int32) int32 {
result := int32(1)
for result < x {
result *= 2
}
return result
}
func AbsInt32(a int32) int32 {
if a < 0 {
return -a
@ -64,24 +56,10 @@ func MinInt32(a, b int32) int32 {
}
// BytesToInt32 converts 4 bytes to int32
func BytesToInt32(b []byte) int32 {
// equivalnt of return int32(binary.LittleEndian.Uint32(b))
return int32(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
}
// IsoToScreen converts isometric coordinates to screenspace coordinates
func IsoToScreen(isoX, isoY, modX, modY float64) (float64, float64) {
screenX := (isoX - isoY) * 80
screenY := (isoX + isoY) * 40
return screenX + modX, screenY + modY
}
// ScreenToIso converts screenspace coordinates to isometric coordinates
func ScreenToIso(sx, sy float64) (float64, float64) {
x := (sx/80 + sy/40) / 2
y := (sy/40 - (sx / 80)) / 2
return x, y
}
// GetAngleBetween returns the angle between two points. 0deg is facing to the right.
func GetAngleBetween(p1X, p1Y, p2X, p2Y float64) int {

View File

@ -36,13 +36,6 @@ func StringToInt(text string) int {
}
// SafeStringToInt converts a string to an integer, or returns -1 on falure
func SafeStringToInt(text string) int {
result, err := strconv.Atoi(text)
if err != nil {
return -1
}
return result
}
// StringToUint converts a string to a uint32
func StringToUint(text string) uint {
@ -78,18 +71,11 @@ func StringToInt8(text string) int8 {
}
// StringToFloat64 converts a string to a float64
func StringToFloat64(text string) float64 {
result, err := strconv.ParseFloat(text, 64)
if err != nil {
panic(err)
}
return float64(result)
}
func Utf16BytesToString(b []byte) (string, error) {
if len(b)%2 != 0 {
return "", fmt.Errorf("Must have even length byte slice")
return "", fmt.Errorf("must have even length byte slice")
}
u16s := make([]uint16, 1)

View File

@ -73,11 +73,11 @@ func createAnimationFromDCC(dcc *d2dcc.DCC, palette *d2datadict.PaletteRec, tran
for y := 0; y < frameHeight; y++ {
for x := 0; x < frameWidth; x++ {
if paletteIndex := dccFrame.PixelData[y*frameWidth+x]; paletteIndex != 0 {
color := palette.Colors[paletteIndex]
palColor := palette.Colors[paletteIndex]
offset := (x + y*frameWidth) * 4
pixels[offset] = color.R
pixels[offset+1] = color.G
pixels[offset+2] = color.B
pixels[offset] = palColor.R
pixels[offset+1] = palColor.G
pixels[offset+2] = palColor.B
pixels[offset+3] = byte(transparency)
}
}
@ -98,8 +98,8 @@ func createAnimationFromDCC(dcc *d2dcc.DCC, palette *d2datadict.PaletteRec, tran
direction := animation.directions[directionIndex]
direction.frames = append(direction.frames, &animationFrame{
width: int(dccFrame.Width),
height: int(dccFrame.Height),
width: dccFrame.Width,
height: dccFrame.Height,
offsetX: minX,
offsetY: minY,
image: image,
@ -294,7 +294,7 @@ func (a *Animation) Pause() {
}
func (a *Animation) SetPlayLoop(loop bool) {
a.playLoop = true
a.playLoop = loop
}
func (a *Animation) SetPlaySpeed(playSpeed float64) {

View File

@ -10,8 +10,8 @@ import (
)
var (
ErrHasInit error = errors.New("asset system is already initialized")
ErrNoInit error = errors.New("asset system is not initialized")
ErrHasInit = errors.New("asset system is already initialized")
ErrNoInit = errors.New("asset system is not initialized")
)
type assetManager struct {

View File

@ -7,8 +7,8 @@ import (
var singleton AudioProvider
var (
ErrHasInit error = errors.New("audio system is already initialized")
ErrNotInit error = errors.New("audio system has not been initialized")
ErrHasInit = errors.New("audio system is already initialized")
ErrNotInit = errors.New("audio system has not been initialized")
)
type SoundEffect interface {

View File

@ -10,7 +10,7 @@ import (
"github.com/hajimehoshi/ebiten/audio"
)
type EbitenAudioProvider struct {
type AudioProvider struct {
audioContext *audio.Context // The Audio context
bgmAudio *audio.Player // The audio player
lastBgm string
@ -18,8 +18,8 @@ type EbitenAudioProvider struct {
bgmVolume float64
}
func CreateAudio() (*EbitenAudioProvider, error) {
result := &EbitenAudioProvider{}
func CreateAudio() (*AudioProvider, error) {
result := &AudioProvider{}
var err error
result.audioContext, err = audio.NewContext(44100)
if err != nil {
@ -29,7 +29,7 @@ func CreateAudio() (*EbitenAudioProvider, error) {
return result, nil
}
func (eap *EbitenAudioProvider) PlayBGM(song string) {
func (eap *AudioProvider) PlayBGM(song string) {
if eap.lastBgm == song {
return
}
@ -71,12 +71,12 @@ func (eap *EbitenAudioProvider) PlayBGM(song string) {
}()
}
func (eap *EbitenAudioProvider) LoadSoundEffect(sfx string) (d2audio.SoundEffect, error) {
func (eap *AudioProvider) LoadSoundEffect(sfx string) (d2audio.SoundEffect, error) {
result := CreateSoundEffect(sfx, eap.audioContext, eap.sfxVolume) // TODO: Split
return result, nil
}
func (eap *EbitenAudioProvider) SetVolumes(bgmVolume, sfxVolume float64) {
func (eap *AudioProvider) SetVolumes(bgmVolume, sfxVolume float64) {
eap.sfxVolume = sfxVolume
eap.bgmVolume = bgmVolume
}

View File

@ -9,12 +9,12 @@ import (
"github.com/hajimehoshi/ebiten/audio/wav"
)
type EbitenSoundEffect struct {
type SoundEffect struct {
player *audio.Player
}
func CreateSoundEffect(sfx string, context *audio.Context, volume float64) *EbitenSoundEffect {
result := &EbitenSoundEffect{}
func CreateSoundEffect(sfx string, context *audio.Context, volume float64) *SoundEffect {
result := &SoundEffect{}
var soundFile string
if _, exists := d2datadict.Sounds[sfx]; exists {
soundEntry := d2datadict.Sounds[sfx]
@ -42,11 +42,11 @@ func CreateSoundEffect(sfx string, context *audio.Context, volume float64) *Ebit
return result
}
func (v *EbitenSoundEffect) Play() {
func (v *SoundEffect) Play() {
v.player.Rewind()
v.player.Play()
}
func (v *EbitenSoundEffect) Stop() {
func (v *SoundEffect) Stop() {
v.player.Pause()
}

View File

@ -7,10 +7,10 @@ import (
)
var (
ErrHasInit error = errors.New("input system is already initialized")
ErrNotInit error = errors.New("input system is not initialized")
ErrHasReg error = errors.New("input system already has provided handler")
ErrNotReg error = errors.New("input system does not have provided handler")
ErrHasInit = errors.New("input system is already initialized")
ErrNotInit = errors.New("input system is not initialized")
ErrHasReg = errors.New("input system already has provided handler")
ErrNotReg = errors.New("input system does not have provided handler")
)
type Priority int
@ -23,107 +23,108 @@ const (
type Key int
//noinspection GoUnusedConst
const (
Key0 Key = Key(ebiten.Key0)
Key1 Key = Key(ebiten.Key1)
Key2 Key = Key(ebiten.Key2)
Key3 Key = Key(ebiten.Key3)
Key4 Key = Key(ebiten.Key4)
Key5 Key = Key(ebiten.Key5)
Key6 Key = Key(ebiten.Key6)
Key7 Key = Key(ebiten.Key7)
Key8 Key = Key(ebiten.Key8)
Key9 Key = Key(ebiten.Key9)
KeyA Key = Key(ebiten.KeyA)
KeyB Key = Key(ebiten.KeyB)
KeyC Key = Key(ebiten.KeyC)
KeyD Key = Key(ebiten.KeyD)
KeyE Key = Key(ebiten.KeyE)
KeyF Key = Key(ebiten.KeyF)
KeyG Key = Key(ebiten.KeyG)
KeyH Key = Key(ebiten.KeyH)
KeyI Key = Key(ebiten.KeyI)
KeyJ Key = Key(ebiten.KeyJ)
KeyK Key = Key(ebiten.KeyK)
KeyL Key = Key(ebiten.KeyL)
KeyM Key = Key(ebiten.KeyM)
KeyN Key = Key(ebiten.KeyN)
KeyO Key = Key(ebiten.KeyO)
KeyP Key = Key(ebiten.KeyP)
KeyQ Key = Key(ebiten.KeyQ)
KeyR Key = Key(ebiten.KeyR)
KeyS Key = Key(ebiten.KeyS)
KeyT Key = Key(ebiten.KeyT)
KeyU Key = Key(ebiten.KeyU)
KeyV Key = Key(ebiten.KeyV)
KeyW Key = Key(ebiten.KeyW)
KeyX Key = Key(ebiten.KeyX)
KeyY Key = Key(ebiten.KeyY)
KeyZ Key = Key(ebiten.KeyZ)
KeyApostrophe Key = Key(ebiten.KeyApostrophe)
KeyBackslash Key = Key(ebiten.KeyBackslash)
KeyBackspace Key = Key(ebiten.KeyBackspace)
KeyCapsLock Key = Key(ebiten.KeyCapsLock)
KeyComma Key = Key(ebiten.KeyComma)
KeyDelete Key = Key(ebiten.KeyDelete)
KeyDown Key = Key(ebiten.KeyDown)
KeyEnd Key = Key(ebiten.KeyEnd)
KeyEnter Key = Key(ebiten.KeyEnter)
KeyEqual Key = Key(ebiten.KeyEqual)
KeyEscape Key = Key(ebiten.KeyEscape)
KeyF1 Key = Key(ebiten.KeyF1)
KeyF2 Key = Key(ebiten.KeyF2)
KeyF3 Key = Key(ebiten.KeyF3)
KeyF4 Key = Key(ebiten.KeyF4)
KeyF5 Key = Key(ebiten.KeyF5)
KeyF6 Key = Key(ebiten.KeyF6)
KeyF7 Key = Key(ebiten.KeyF7)
KeyF8 Key = Key(ebiten.KeyF8)
KeyF9 Key = Key(ebiten.KeyF9)
KeyF10 Key = Key(ebiten.KeyF10)
KeyF11 Key = Key(ebiten.KeyF11)
KeyF12 Key = Key(ebiten.KeyF12)
KeyGraveAccent Key = Key(ebiten.KeyGraveAccent)
KeyHome Key = Key(ebiten.KeyHome)
KeyInsert Key = Key(ebiten.KeyInsert)
KeyKP0 Key = Key(ebiten.KeyKP0)
KeyKP1 Key = Key(ebiten.KeyKP1)
KeyKP2 Key = Key(ebiten.KeyKP2)
KeyKP3 Key = Key(ebiten.KeyKP3)
KeyKP4 Key = Key(ebiten.KeyKP4)
KeyKP5 Key = Key(ebiten.KeyKP5)
KeyKP6 Key = Key(ebiten.KeyKP6)
KeyKP7 Key = Key(ebiten.KeyKP7)
KeyKP8 Key = Key(ebiten.KeyKP8)
KeyKP9 Key = Key(ebiten.KeyKP9)
KeyKPAdd Key = Key(ebiten.KeyKPAdd)
KeyKPDecimal Key = Key(ebiten.KeyKPDecimal)
KeyKPDivide Key = Key(ebiten.KeyKPDivide)
KeyKPEnter Key = Key(ebiten.KeyKPEnter)
KeyKPEqual Key = Key(ebiten.KeyKPEqual)
KeyKPMultiply Key = Key(ebiten.KeyKPMultiply)
KeyKPSubtract Key = Key(ebiten.KeyKPSubtract)
KeyLeft Key = Key(ebiten.KeyLeft)
KeyLeftBracket Key = Key(ebiten.KeyLeftBracket)
KeyMenu Key = Key(ebiten.KeyMenu)
KeyMinus Key = Key(ebiten.KeyMinus)
KeyNumLock Key = Key(ebiten.KeyNumLock)
KeyPageDown Key = Key(ebiten.KeyPageDown)
KeyPageUp Key = Key(ebiten.KeyPageUp)
KeyPause Key = Key(ebiten.KeyPause)
KeyPeriod Key = Key(ebiten.KeyPeriod)
KeyPrintScreen Key = Key(ebiten.KeyPrintScreen)
KeyRight Key = Key(ebiten.KeyRight)
KeyRightBracket Key = Key(ebiten.KeyRightBracket)
KeyScrollLock Key = Key(ebiten.KeyScrollLock)
KeySemicolon Key = Key(ebiten.KeySemicolon)
KeySlash Key = Key(ebiten.KeySlash)
KeySpace Key = Key(ebiten.KeySpace)
KeyTab Key = Key(ebiten.KeyTab)
KeyUp Key = Key(ebiten.KeyUp)
KeyAlt Key = Key(ebiten.KeyAlt)
KeyControl Key = Key(ebiten.KeyControl)
KeyShift Key = Key(ebiten.KeyShift)
Key0 = Key(ebiten.Key0)
Key1 = Key(ebiten.Key1)
Key2 = Key(ebiten.Key2)
Key3 = Key(ebiten.Key3)
Key4 = Key(ebiten.Key4)
Key5 = Key(ebiten.Key5)
Key6 = Key(ebiten.Key6)
Key7 = Key(ebiten.Key7)
Key8 = Key(ebiten.Key8)
Key9 = Key(ebiten.Key9)
KeyA = Key(ebiten.KeyA)
KeyB = Key(ebiten.KeyB)
KeyC = Key(ebiten.KeyC)
KeyD = Key(ebiten.KeyD)
KeyE = Key(ebiten.KeyE)
KeyF = Key(ebiten.KeyF)
KeyG = Key(ebiten.KeyG)
KeyH = Key(ebiten.KeyH)
KeyI = Key(ebiten.KeyI)
KeyJ = Key(ebiten.KeyJ)
KeyK = Key(ebiten.KeyK)
KeyL = Key(ebiten.KeyL)
KeyM = Key(ebiten.KeyM)
KeyN = Key(ebiten.KeyN)
KeyO = Key(ebiten.KeyO)
KeyP = Key(ebiten.KeyP)
KeyQ = Key(ebiten.KeyQ)
KeyR = Key(ebiten.KeyR)
KeyS = Key(ebiten.KeyS)
KeyT = Key(ebiten.KeyT)
KeyU = Key(ebiten.KeyU)
KeyV = Key(ebiten.KeyV)
KeyW = Key(ebiten.KeyW)
KeyX = Key(ebiten.KeyX)
KeyY = Key(ebiten.KeyY)
KeyZ = Key(ebiten.KeyZ)
KeyApostrophe = Key(ebiten.KeyApostrophe)
KeyBackslash = Key(ebiten.KeyBackslash)
KeyBackspace = Key(ebiten.KeyBackspace)
KeyCapsLock = Key(ebiten.KeyCapsLock)
KeyComma = Key(ebiten.KeyComma)
KeyDelete = Key(ebiten.KeyDelete)
KeyDown = Key(ebiten.KeyDown)
KeyEnd = Key(ebiten.KeyEnd)
KeyEnter = Key(ebiten.KeyEnter)
KeyEqual = Key(ebiten.KeyEqual)
KeyEscape = Key(ebiten.KeyEscape)
KeyF1 = Key(ebiten.KeyF1)
KeyF2 = Key(ebiten.KeyF2)
KeyF3 = Key(ebiten.KeyF3)
KeyF4 = Key(ebiten.KeyF4)
KeyF5 = Key(ebiten.KeyF5)
KeyF6 = Key(ebiten.KeyF6)
KeyF7 = Key(ebiten.KeyF7)
KeyF8 = Key(ebiten.KeyF8)
KeyF9 = Key(ebiten.KeyF9)
KeyF10 = Key(ebiten.KeyF10)
KeyF11 = Key(ebiten.KeyF11)
KeyF12 = Key(ebiten.KeyF12)
KeyGraveAccent = Key(ebiten.KeyGraveAccent)
KeyHome = Key(ebiten.KeyHome)
KeyInsert = Key(ebiten.KeyInsert)
KeyKP0 = Key(ebiten.KeyKP0)
KeyKP1 = Key(ebiten.KeyKP1)
KeyKP2 = Key(ebiten.KeyKP2)
KeyKP3 = Key(ebiten.KeyKP3)
KeyKP4 = Key(ebiten.KeyKP4)
KeyKP5 = Key(ebiten.KeyKP5)
KeyKP6 = Key(ebiten.KeyKP6)
KeyKP7 = Key(ebiten.KeyKP7)
KeyKP8 = Key(ebiten.KeyKP8)
KeyKP9 = Key(ebiten.KeyKP9)
KeyKPAdd = Key(ebiten.KeyKPAdd)
KeyKPDecimal = Key(ebiten.KeyKPDecimal)
KeyKPDivide = Key(ebiten.KeyKPDivide)
KeyKPEnter = Key(ebiten.KeyKPEnter)
KeyKPEqual = Key(ebiten.KeyKPEqual)
KeyKPMultiply = Key(ebiten.KeyKPMultiply)
KeyKPSubtract = Key(ebiten.KeyKPSubtract)
KeyLeft = Key(ebiten.KeyLeft)
KeyLeftBracket = Key(ebiten.KeyLeftBracket)
KeyMenu = Key(ebiten.KeyMenu)
KeyMinus = Key(ebiten.KeyMinus)
KeyNumLock = Key(ebiten.KeyNumLock)
KeyPageDown = Key(ebiten.KeyPageDown)
KeyPageUp = Key(ebiten.KeyPageUp)
KeyPause = Key(ebiten.KeyPause)
KeyPeriod = Key(ebiten.KeyPeriod)
KeyPrintScreen = Key(ebiten.KeyPrintScreen)
KeyRight = Key(ebiten.KeyRight)
KeyRightBracket = Key(ebiten.KeyRightBracket)
KeyScrollLock = Key(ebiten.KeyScrollLock)
KeySemicolon = Key(ebiten.KeySemicolon)
KeySlash = Key(ebiten.KeySlash)
KeySpace = Key(ebiten.KeySpace)
KeyTab = Key(ebiten.KeyTab)
KeyUp = Key(ebiten.KeyUp)
KeyAlt = Key(ebiten.KeyAlt)
KeyControl = Key(ebiten.KeyControl)
KeyShift = Key(ebiten.KeyShift)
)
type KeyMod int
@ -137,9 +138,9 @@ const (
type MouseButton int
const (
MouseButtonLeft MouseButton = MouseButton(ebiten.MouseButtonLeft)
MouseButtonMiddle MouseButton = MouseButton(ebiten.MouseButtonMiddle)
MouseButtonRight MouseButton = MouseButton(ebiten.MouseButtonRight)
MouseButtonLeft = MouseButton(ebiten.MouseButtonLeft)
MouseButtonMiddle = MouseButton(ebiten.MouseButtonMiddle)
MouseButtonRight = MouseButton(ebiten.MouseButtonRight)
)
type MouseButtonMod int

View File

@ -38,20 +38,20 @@ func CreateMapEngine(gameState *d2gamestate.GameState) *MapEngine {
return engine
}
func (me *MapEngine) GetStartPosition() (float64, float64) {
func (m *MapEngine) GetStartPosition() (float64, float64) {
var startX, startY float64
if len(me.regions) > 0 {
region := me.regions[0]
if len(m.regions) > 0 {
region := m.regions[0]
startX, startY = region.getStartTilePosition()
}
return startX, startY
}
func (me *MapEngine) GetCenterPosition() (float64, float64) {
func (m *MapEngine) GetCenterPosition() (float64, float64) {
var centerX, centerY float64
if len(me.regions) > 0 {
region := me.regions[0]
if len(m.regions) > 0 {
region := m.regions[0]
centerX = float64(region.tileRect.Left) + float64(region.tileRect.Width)/2
centerY = float64(region.tileRect.Top) + float64(region.tileRect.Height)/2
}
@ -59,56 +59,56 @@ func (me *MapEngine) GetCenterPosition() (float64, float64) {
return centerX, centerY
}
func (me *MapEngine) MoveCameraTo(x, y float64) {
me.camera.MoveTo(x, y)
func (m *MapEngine) MoveCameraTo(x, y float64) {
m.camera.MoveTo(x, y)
}
func (me *MapEngine) MoveCameraBy(x, y float64) {
me.camera.MoveBy(x, y)
func (m *MapEngine) MoveCameraBy(x, y float64) {
m.camera.MoveBy(x, y)
}
func (me *MapEngine) ScreenToWorld(x, y int) (float64, float64) {
return me.viewport.ScreenToWorld(x, y)
func (m *MapEngine) ScreenToWorld(x, y int) (float64, float64) {
return m.viewport.ScreenToWorld(x, y)
}
func (me *MapEngine) ScreenToOrtho(x, y int) (float64, float64) {
return me.viewport.ScreenToOrtho(x, y)
func (m *MapEngine) ScreenToOrtho(x, y int) (float64, float64) {
return m.viewport.ScreenToOrtho(x, y)
}
func (me *MapEngine) WorldToOrtho(x, y float64) (float64, float64) {
return me.viewport.WorldToOrtho(x, y)
func (m *MapEngine) WorldToOrtho(x, y float64) (float64, float64) {
return m.viewport.WorldToOrtho(x, y)
}
func (me *MapEngine) SetDebugVisLevel(debugVisLevel int) {
me.debugVisLevel = debugVisLevel
func (m *MapEngine) SetDebugVisLevel(debugVisLevel int) {
m.debugVisLevel = debugVisLevel
}
func (me *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
region, entities := loadRegion(me.gameState.Seed, 0, 0, regionType, levelPreset, fileIndex)
me.regions = append(me.regions, region)
me.entities = append(me.entities, entities...)
func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
region, entities := loadRegion(m.gameState.Seed, 0, 0, regionType, levelPreset, fileIndex)
m.regions = append(m.regions, region)
m.entities = append(m.entities, entities...)
}
func (me *MapEngine) GenerateAct1Overworld() {
func (m *MapEngine) GenerateAct1Overworld() {
d2audio.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
region, entities := loadRegion(me.gameState.Seed, 0, 0, d2enum.RegionAct1Town, 1, -1)
me.regions = append(me.regions, region)
me.entities = append(me.entities, entities...)
region, entities := loadRegion(m.gameState.Seed, 0, 0, d2enum.RegionAct1Town, 1, -1)
m.regions = append(m.regions, region)
m.entities = append(m.entities, entities...)
if strings.Contains(region.regionPath, "E1") {
region, entities := loadRegion(me.gameState.Seed, int(region.tileRect.Width-1), 0, d2enum.RegionAct1Town, 2, -1)
me.regions = append(me.regions, region)
me.entities = append(me.entities, entities...)
region, entities := loadRegion(m.gameState.Seed, region.tileRect.Width-1, 0, d2enum.RegionAct1Town, 2, -1)
m.regions = append(m.regions, region)
m.entities = append(m.entities, entities...)
} else if strings.Contains(region.regionPath, "S1") {
region, entities := loadRegion(me.gameState.Seed, 0, int(region.tileRect.Height-1), d2enum.RegionAct1Town, 3, -1)
me.regions = append(me.regions, region)
me.entities = append(me.entities, entities...)
region, entities := loadRegion(m.gameState.Seed, 0, region.tileRect.Height-1, d2enum.RegionAct1Town, 3, -1)
m.regions = append(m.regions, region)
m.entities = append(m.entities, entities...)
}
}
func (me *MapEngine) GetRegionAtTile(x, y int) *MapRegion {
for _, region := range me.regions {
func (m *MapEngine) GetRegionAtTile(x, y int) *MapRegion {
for _, region := range m.regions {
if region.tileRect.IsInRect(x, y) {
return region
}
@ -117,29 +117,29 @@ func (me *MapEngine) GetRegionAtTile(x, y int) *MapRegion {
return nil
}
func (me *MapEngine) AddEntity(entity MapEntity) {
me.entities = append(me.entities, entity)
func (m *MapEngine) AddEntity(entity MapEntity) {
m.entities = append(m.entities, entity)
}
func (me *MapEngine) Advance(tickTime float64) {
for _, region := range me.regions {
if region.isVisbile(me.viewport) {
func (m *MapEngine) Advance(tickTime float64) {
for _, region := range m.regions {
if region.isVisbile(m.viewport) {
region.advance(tickTime)
}
}
for _, entity := range me.entities {
for _, entity := range m.entities {
entity.Advance(tickTime)
}
}
func (me *MapEngine) Render(target d2render.Surface) {
for _, region := range me.regions {
if region.isVisbile(me.viewport) {
region.renderPass1(me.viewport, target)
region.renderDebug(me.debugVisLevel, me.viewport, target)
region.renderPass2(me.entities, me.viewport, target)
region.renderPass3(me.viewport, target)
func (m *MapEngine) Render(target d2render.Surface) {
for _, region := range m.regions {
if region.isVisbile(m.viewport) {
region.renderPass1(m.viewport, target)
region.renderDebug(m.debugVisLevel, m.viewport, target)
region.renderPass2(m.entities, m.viewport, target)
region.renderPass3(m.viewport, target)
}
}
}

View File

@ -42,7 +42,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
seed: seed,
}
region.palette = d2datadict.Palettes[d2enum.PaletteType("act"+strconv.Itoa(int(region.levelType.Act)))]
region.palette = d2datadict.Palettes[d2enum.PaletteType("act"+strconv.Itoa(region.levelType.Act))]
if levelType == d2enum.RegionAct5Lava {
region.palette = d2datadict.Palettes[d2enum.PaletteType("act4")]
}
@ -71,6 +71,10 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
levelIndex = fileIndex
}
if levelFilesToPick == nil {
panic("no level files to pick from")
}
region.regionPath = levelFilesToPick[levelIndex]
fileData, err := d2asset.LoadFile("/data/global/tiles/" + region.regionPath)
if err != nil {
@ -175,7 +179,7 @@ func (mr *MapRegion) getRandomTile(tiles []d2dt1.Tile, x, y int, seed int64) byt
return 0
}
random := (tileSeed % uint64(weightSum))
random := tileSeed % uint64(weightSum)
sum := 0
for i, tile := range tiles {
@ -358,7 +362,7 @@ func (mr *MapRegion) renderShadow(tile d2ds1.FloorShadowRecord, viewport *Viewpo
defer viewport.PopTranslation()
target.PushTranslation(viewport.GetTranslationScreen())
target.PushColor(color.RGBA{255, 255, 255, 160})
target.PushColor(color.RGBA{R: 255, G: 255, B: 255, A: 160})
defer target.PopN(2)
target.Render(img)
@ -377,8 +381,8 @@ func (mr *MapRegion) renderDebug(debugVisLevel int, viewport *Viewport, target d
func (mr *MapRegion) renderTileDebug(x, y int, debugVisLevel int, viewport *Viewport, target d2render.Surface) {
if debugVisLevel > 0 {
subtileColor := color.RGBA{80, 80, 255, 100}
tileColor := color.RGBA{255, 255, 255, 255}
subtileColor := color.RGBA{R: 80, G: 80, B: 255, A: 100}
tileColor := color.RGBA{R: 255, G: 255, B: 255, A: 255}
screenX1, screenY1 := viewport.WorldToScreen(float64(x), float64(y))
screenX2, screenY2 := viewport.WorldToScreen(float64(x+1), float64(y))
@ -526,7 +530,7 @@ func (mr *MapRegion) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX, t
return
}
_, image := d2render.NewSurface(int(tileData.Width), int(tileHeight), d2render.FilterNearest)
_, image := d2render.NewSurface(int(tileData.Width), tileHeight, d2render.FilterNearest)
pixels := make([]byte, 4*tileData.Width*int32(tileHeight))
mr.decodeTileGfxData(tileData.Blocks, &pixels, tileYOffset, tileData.Width)
image.ReplacePixels(pixels)

View File

@ -5,42 +5,42 @@ type CompositeMode int
const (
// Regular alpha blending
// c_out = c_src + c_dst × (1 - α_src)
CompositeModeSourceOver CompositeMode = CompositeMode(1)
CompositeModeSourceOver = CompositeMode(1)
// c_out = 0
CompositeModeClear CompositeMode = CompositeMode(2)
CompositeModeClear = CompositeMode(2)
// c_out = c_src
CompositeModeCopy CompositeMode = CompositeMode(3)
CompositeModeCopy = CompositeMode(3)
// c_out = c_dst
CompositeModeDestination CompositeMode = CompositeMode(4)
CompositeModeDestination = CompositeMode(4)
// c_out = c_src × (1 - α_dst) + c_dst
CompositeModeDestinationOver CompositeMode = CompositeMode(5)
CompositeModeDestinationOver = CompositeMode(5)
// c_out = c_src × α_dst
CompositeModeSourceIn CompositeMode = CompositeMode(6)
CompositeModeSourceIn = CompositeMode(6)
// c_out = c_dst × α_src
CompositeModeDestinationIn CompositeMode = CompositeMode(7)
CompositeModeDestinationIn = CompositeMode(7)
// c_out = c_src × (1 - α_dst)
CompositeModeSourceOut CompositeMode = CompositeMode(8)
CompositeModeSourceOut = CompositeMode(8)
// c_out = c_dst × (1 - α_src)
CompositeModeDestinationOut CompositeMode = CompositeMode(9)
CompositeModeDestinationOut = CompositeMode(9)
// c_out = c_src × α_dst + c_dst × (1 - α_src)
CompositeModeSourceAtop CompositeMode = CompositeMode(10)
CompositeModeSourceAtop = CompositeMode(10)
// c_out = c_src × (1 - α_dst) + c_dst × α_src
CompositeModeDestinationAtop CompositeMode = CompositeMode(11)
CompositeModeDestinationAtop = CompositeMode(11)
// c_out = c_src × (1 - α_dst) + c_dst × (1 - α_src)
CompositeModeXor CompositeMode = CompositeMode(12)
CompositeModeXor = CompositeMode(12)
// Sum of source and destination (a.k.a. 'plus' or 'additive')
// c_out = c_src + c_dst
CompositeModeLighter CompositeMode = CompositeMode(13)
CompositeModeLighter = CompositeMode(13)
)

View File

@ -8,9 +8,9 @@ import (
)
var (
ErrHasInit error = errors.New("rendering system is already initialized")
ErrNotInit error = errors.New("rendering system has not been initialized")
ErrInvalidRenderer error = errors.New("invalid rendering system specified")
ErrHasInit = errors.New("rendering system is already initialized")
ErrNotInit = errors.New("rendering system has not been initialized")
ErrInvalidRenderer = errors.New("invalid rendering system specified")
)
var singleton Renderer

View File

@ -41,7 +41,7 @@ func ColorToColorM(clr color.Color) ebiten.ColorM {
if ca == 0 {
return emptyColorM
}
key := colorMCacheKey(uint32(cr) | (uint32(cg) << 8) | (uint32(cb) << 16) | (uint32(ca) << 24))
key := colorMCacheKey(cr | (cg << 8) | (cb << 16) | (ca << 24))
e, ok := colorMCache[key]
if ok {
e.atime = now()

View File

@ -11,11 +11,11 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type EbitenRenderer struct {
type Renderer struct {
}
func CreateRenderer() (*EbitenRenderer, error) {
result := &EbitenRenderer{}
func CreateRenderer() (*Renderer, error) {
result := &Renderer{}
config, err := d2config.Get()
if err != nil {
@ -32,11 +32,11 @@ func CreateRenderer() (*EbitenRenderer, error) {
return result, nil
}
func (*EbitenRenderer) GetRendererName() string {
func (*Renderer) GetRendererName() string {
return "Ebiten"
}
func (*EbitenRenderer) SetWindowIcon(fileName string) {
func (*Renderer) SetWindowIcon(fileName string) {
_, iconImage, err := ebitenutil.NewImageFromFile(fileName, ebiten.FilterLinear)
if err == nil {
ebiten.SetWindowIcon([]image.Image{iconImage})
@ -44,11 +44,11 @@ func (*EbitenRenderer) SetWindowIcon(fileName string) {
}
func (r *EbitenRenderer) IsDrawingSkipped() bool {
func (r *Renderer) IsDrawingSkipped() bool {
return ebiten.IsDrawingSkipped()
}
func (r *EbitenRenderer) Run(f func(surface d2render.Surface) error, width, height int, title string) error {
func (r *Renderer) Run(f func(surface d2render.Surface) error, width, height int, title string) error {
config, err := d2config.Get()
if err != nil {
log.Fatal(err)
@ -64,7 +64,7 @@ func (r *EbitenRenderer) Run(f func(surface d2render.Surface) error, width, heig
}, width, height, config.Scale, title)
}
func (r *EbitenRenderer) CreateSurface(surface d2render.Surface) (error, d2render.Surface) {
func (r *Renderer) CreateSurface(surface d2render.Surface) (error, d2render.Surface) {
result := &ebitenSurface{
image: surface.(*ebitenSurface).image,
stateCurrent: surfaceState{
@ -75,7 +75,7 @@ func (r *EbitenRenderer) CreateSurface(surface d2render.Surface) (error, d2rende
return nil, result
}
func (r *EbitenRenderer) NewSurface(width, height int, filter d2render.Filter) (error, d2render.Surface) {
func (r *Renderer) NewSurface(width, height int, filter d2render.Filter) (error, d2render.Surface) {
ebitenFilter := d2ToEbitenFilter(filter)
img, err := ebiten.NewImage(width, height, ebitenFilter)
if err != nil {
@ -87,29 +87,29 @@ func (r *EbitenRenderer) NewSurface(width, height int, filter d2render.Filter) (
return nil, result
}
func (r *EbitenRenderer) IsFullScreen() (bool, error) {
func (r *Renderer) IsFullScreen() (bool, error) {
return ebiten.IsFullscreen(), nil
}
func (r *EbitenRenderer) SetFullScreen(fullScreen bool) error {
func (r *Renderer) SetFullScreen(fullScreen bool) error {
ebiten.SetFullscreen(fullScreen)
return nil
}
func (r *EbitenRenderer) SetVSyncEnabled(vsync bool) error {
func (r *Renderer) SetVSyncEnabled(vsync bool) error {
ebiten.SetVsyncEnabled(vsync)
return nil
}
func (r *EbitenRenderer) GetVSyncEnabled() (bool, error) {
func (r *Renderer) GetVSyncEnabled() (bool, error) {
return ebiten.IsVsyncEnabled(), nil
}
func (r *EbitenRenderer) GetCursorPos() (int, int, error) {
func (r *Renderer) GetCursorPos() (int, int, error) {
cx, cy := ebiten.CursorPosition()
return cx, cy, nil
}
func (r *EbitenRenderer) CurrentFPS() float64 {
func (r *Renderer) CurrentFPS() float64 {
return ebiten.CurrentFPS()
}

View File

@ -8,8 +8,8 @@ const (
FilterDefault Filter = 0
// FilterNearest represents nearest (crisp-edged) filter
FilterNearest Filter = Filter(1)
FilterNearest = Filter(1)
// FilterLinear represents linear filter
FilterLinear Filter = Filter(2)
FilterLinear = Filter(2)
)

View File

@ -9,8 +9,8 @@ import (
)
var (
ErrHasInit error = errors.New("terminal system is already initialized")
ErrNotInit error = errors.New("terminal system is not initialized")
ErrHasInit = errors.New("terminal system is already initialized")
ErrNotInit = errors.New("terminal system is not initialized")
)
var singleton *terminal

View File

@ -46,11 +46,11 @@ const (
)
var (
termBgColor = color.RGBA{0x2e, 0x34, 0x36, 0xb0}
termFgColor = color.RGBA{0x55, 0x57, 0x53, 0xb0}
termInfoColor = color.RGBA{0x34, 0x65, 0xa4, 0xb0}
termWarningColor = color.RGBA{0xfc, 0xe9, 0x4f, 0xb0}
termErrorColor = color.RGBA{0xcc, 0x00, 0x00, 0xb0}
termBgColor = color.RGBA{R: 0x2e, G: 0x34, B: 0x36, A: 0xb0}
termFgColor = color.RGBA{R: 0x55, G: 0x57, B: 0x53, A: 0xb0}
termInfoColor = color.RGBA{R: 0x34, G: 0x65, B: 0xa4, A: 0xb0}
termWarningColor = color.RGBA{R: 0xfc, G: 0xe9, B: 0x4f, A: 0xb0}
termErrorColor = color.RGBA{R: 0xcc, A: 0xb0}
)
type termHistroyEntry struct {
@ -89,7 +89,7 @@ func createTerminal() (*terminal, error) {
terminal.bindAction("ls", "list available actions", func() {
var names []string
for name, _ := range terminal.actions {
for name := range terminal.actions {
names = append(names, name)
}
@ -455,12 +455,12 @@ func (t *terminalLogger) Write(p []byte) (int, error) {
}
reader := bufio.NewReader(&t.buffer)
bytes, _, err := reader.ReadLine()
termBytes, _, err := reader.ReadLine()
if err != nil {
return n, err
}
line := string(bytes[:])
line := string(termBytes[:])
lineLower := strings.ToLower(line)
if strings.Index(lineLower, "error") > 0 {

View File

@ -126,34 +126,34 @@ func CreateButton(buttonType ButtonType, text string) Button {
result.height += h
}
_, result.normalSurface = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.normalSurface = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
_, fontHeight := font.GetTextMetrics(text)
textY := int((result.height/2)-(int(fontHeight)/2)) + buttonLayout.TextOffset
textY := (result.height / 2) - (fontHeight / 2) + buttonLayout.TextOffset
buttonSprite.SetPosition(0, 0)
buttonSprite.SetBlend(true)
buttonSprite.RenderSegmented(result.normalSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalSurface)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.normalSurface)
if buttonLayout.AllowFrameChange {
if totalButtonTypes > 1 {
_, result.pressedSurface = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.pressedSurface = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
buttonSprite.RenderSegmented(result.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
font.Render(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedSurface)
font.Render(-2, textY+2, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.pressedSurface)
}
if totalButtonTypes > 2 {
_, result.toggledSurface = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.toggledSurface = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
buttonSprite.RenderSegmented(result.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledSurface)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.toggledSurface)
}
if totalButtonTypes > 3 {
_, result.pressedToggledSurface = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.pressedToggledSurface = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
buttonSprite.RenderSegmented(result.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledSurface)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.pressedToggledSurface)
}
if buttonLayout.DisabledFrame != -1 {
_, result.disabledSurface = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.disabledSurface = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
buttonSprite.RenderSegmented(result.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledSurface)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.disabledSurface)
}
}
return result
@ -180,7 +180,7 @@ func (v *Button) Render(target d2render.Surface) {
defer target.PopN(3)
if !v.enabled {
target.PushColor(color.RGBA{128, 128, 128, 195})
target.PushColor(color.RGBA{R: 128, G: 128, B: 128, A: 195})
defer target.Pop()
target.Render(v.disabledSurface)
} else if v.toggled && v.pressed {

View File

@ -31,10 +31,10 @@ func CreateCheckbox(checkState bool) Checkbox {
result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
checkboxSprite.SetPosition(0, 0)
_, result.Image = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.Image = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
checkboxSprite.RenderSegmented(result.Image, 1, 1, 0)
_, result.checkedImage = d2render.NewSurface(int(result.width), int(result.height), d2render.FilterNearest)
_, result.checkedImage = d2render.NewSurface(result.width, result.height, d2render.FilterNearest)
checkboxSprite.RenderSegmented(result.checkedImage, 1, 1, 1)
return result
}

View File

@ -92,7 +92,7 @@ func Advance(elapsed float64) {
}
wx, wy := widget.GetPosition()
ww, wh := widget.GetSize()
if CursorX >= wx && CursorX <= wx+int(ww) && CursorY >= wy && CursorY <= wy+int(wh) {
if CursorX >= wx && CursorX <= wx+ww && CursorY >= wy && CursorY <= wy+wh {
widget.SetPressed(true)
if pressedIndex == -1 {
found = true
@ -119,7 +119,7 @@ func Advance(elapsed float64) {
widget := widgets[pressedIndex]
wx, wy := widget.GetPosition()
ww, wh := widget.GetSize()
if CursorX >= wx && CursorX <= wx+int(ww) && CursorY >= wy && CursorY <= wy+int(wh) {
if CursorX >= wx && CursorX <= wx+ww && CursorY >= wy && CursorY <= wy+wh {
widget.Activate()
}
} else {

View File

@ -82,9 +82,9 @@ func CreateFont(font string, palettePath string) *Font {
// GetTextMetrics returns the size of the specified text
func (v *Font) GetTextMetrics(text string) (width, height int) {
width = int(0)
curWidth := int(0)
height = int(0)
width = 0
curWidth := 0
height = 0
_, maxCharHeight := v.fontSprite.GetFrameBounds()
for _, ch := range text {
if ch == '\n' {
@ -115,16 +115,16 @@ func (v *Font) Render(x, y int, text string, color color.Color, target d2render.
lines := strings.Split(text, "\n")
for lineIdx, line := range lines {
lineWidth, _ := v.GetTextMetrics(line)
xPos := x + ((targetWidth / 2) - int(lineWidth/2))
xPos := x + ((targetWidth / 2) - lineWidth/2)
for _, ch := range line {
width := v.getCharWidth(ch)
index := v.fontTable[uint16(ch)]
v.fontSprite.SetCurrentFrame(int(index))
_, height := v.fontSprite.GetCurrentFrameSize()
v.fontSprite.SetPosition(xPos, y+int(height))
v.fontSprite.SetPosition(xPos, y+height)
v.fontSprite.Render(target)
xPos += int(width)
xPos += width
}
if lineIdx >= len(lines)-1 {

View File

@ -50,9 +50,9 @@ func (v *Label) Render(target d2render.Surface) {
x, y := v.X, v.Y
if v.Alignment == LabelAlignCenter {
x, y = v.X-int(v.Width/2), v.Y
x, y = v.X-v.Width/2, v.Y
} else if v.Alignment == LabelAlignRight {
x, y = v.X-int(v.Width), v.Y
x, y = v.X-v.Width, v.Y
}
target.PushFilter(d2render.FilterNearest)
@ -80,7 +80,7 @@ func (v *Label) cacheImage() {
width, height := v.font.GetTextMetrics(v.text)
v.Width = width
v.Height = height
_, v.imageData = d2render.NewSurface(int(width), int(height), d2render.FilterNearest)
_, v.imageData = d2render.NewSurface(width, height, d2render.FilterNearest)
_, surface := d2render.CreateSurface(v.imageData)
v.font.Render(0, 0, v.text, v.Color, surface)
}

View File

@ -102,7 +102,7 @@ func (v *Scrollbar) Advance(elapsed float64) {
}
func (v *Scrollbar) GetSize() (width, height int) {
return 10, int(v.height)
return 10, v.height
}
func (v *Scrollbar) SetPosition(x, y int) {

View File

@ -16,7 +16,7 @@ type Sprite struct {
}
var (
ErrNoAnimation error = errors.New("No animation was specified")
ErrNoAnimation = errors.New("no animation was specified")
)
func LoadSprite(animation *d2asset.Animation) (*Sprite, error) {

View File

@ -108,7 +108,7 @@ func (v *TextBox) SetText(newText string) {
result = result[1:]
continue
}
v.lineBar.SetPosition(v.x+6+int(tw), v.y+3)
v.lineBar.SetPosition(v.x+6+tw, v.y+3)
v.textLabel.SetText(result)
break
}
@ -122,7 +122,7 @@ func (v *TextBox) SetPosition(x, y int) {
v.x = x
v.y = y
v.textLabel.SetPosition(v.x+6, v.y+3)
v.lineBar.SetPosition(v.x+6+int(v.textLabel.Width), v.y+3)
v.lineBar.SetPosition(v.x+6+v.textLabel.Width, v.y+3)
v.bgSprite.SetPosition(v.x, v.y+26)
}

View File

@ -139,12 +139,12 @@ func (v *CharacterSelect) Load() []func() {
xOffset = 385
}
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{R: 188, G: 168, B: 140, A: 255}
v.characterNameLabel[i].SetPosition(xOffset, 100+((i/2)*95))
v.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
v.characterExpLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteStatic)
v.characterExpLabel[i].Color = color.RGBA{24, 255, 0, 255}
v.characterExpLabel[i].Color = color.RGBA{R: 24, G: 255, A: 255}
v.characterExpLabel[i].SetPosition(xOffset, 130+((i/2)*95))
}
v.refreshGameStates()
@ -215,7 +215,7 @@ func (v *CharacterSelect) Render(screen d2render.Surface) {
screen.Pop()
}
if v.showDeleteConfirmation {
screen.DrawRect(800, 600, color.RGBA{0, 0, 0, 128})
screen.DrawRect(800, 600, color.RGBA{A: 128})
v.okCancelBox.RenderSegmented(screen, 2, 1, 0)
v.deleteCharConfirmLabel.Render(screen)
}
@ -229,7 +229,7 @@ func (v *CharacterSelect) moveSelectionBox() {
bw := 272
bh := 92
selectedIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
v.selectionBox.SetPosition(37+((selectedIndex&1)*int(bw)), 86+(int(bh)*(selectedIndex/2)))
v.selectionBox.SetPosition(37+((selectedIndex&1)*bw), 86+(bh*(selectedIndex/2)))
v.d2HeroTitle.SetText(v.gameStates[v.selectedCharacter].HeroName)
}
@ -243,10 +243,10 @@ func (v *CharacterSelect) Advance(tickTime float64) {
bh := 92
localMouseX := mx - 37
localMouseY := my - 86
if localMouseX > 0 && localMouseX < int(bw*2) && localMouseY >= 0 && localMouseY < int(bh*4) {
adjustY := localMouseY / int(bh)
if localMouseX > 0 && localMouseX < bw*2 && localMouseY >= 0 && localMouseY < bh*4 {
adjustY := localMouseY / bh
selectedIndex := adjustY * 2
if localMouseX > int(bw) {
if localMouseX > bw {
selectedIndex += 1
}
if (v.charScrollbar.GetCurrentOffset()*2)+selectedIndex < len(v.gameStates) {

View File

@ -52,10 +52,11 @@ func CreateCredits() *Credits {
// Load is called to load the contributors data from file
// TODO: use markdown for file and convert it to the suitable format
func (v *Credits) LoadContributors() []string {
contributors := []string{}
var contributors []string
file, err := os.Open(path.Join("./", "CONTRIBUTORS"))
if err != nil {
if err != nil || file == nil {
log.Print("CONTRIBUTORS file is missing")
return []string{ "MISSING CONTRIBUTOR FILES!" }
}
defer file.Close()
@ -172,7 +173,7 @@ func (v *Credits) addNextItem() {
isDoubled = true
// Gotta go side by side
label.SetPosition(400-int(width), 605)
label.SetPosition(400-width, 605)
text2 := v.creditsText[0]
v.creditsText = v.creditsText[1:]
@ -183,7 +184,7 @@ func (v *Credits) addNextItem() {
label2.SetPosition(410, 605)
} else {
label.SetPosition(405-int(width/2), 605)
label.SetPosition(405-width/2, 605)
}
if isHeading && isNextHeading {
@ -206,9 +207,9 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
if label.Available {
label.Available = false
if isHeading {
label.Label.Color = color.RGBA{255, 88, 82, 255}
label.Label.Color = color.RGBA{R: 255, G: 88, B: 82, A: 255}
} else {
label.Label.Color = color.RGBA{198, 178, 150, 255}
label.Label.Color = color.RGBA{R: 198, G: 178, B: 150, A: 255}
}
return &label.Label
}
@ -221,9 +222,9 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
}
if isHeading {
newLabelItem.Label.Color = color.RGBA{255, 88, 82, 255}
newLabelItem.Label.Color = color.RGBA{R: 255, G: 88, B: 82, A: 255}
} else {
newLabelItem.Label.Color = color.RGBA{198, 178, 150, 255}
newLabelItem.Label.Color = color.RGBA{R: 198, G: 178, B: 150, A: 255}
}

View File

@ -64,35 +64,35 @@ func (v *MainMenu) Load() []func() {
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.versionLabel.Alignment = d2ui.LabelAlignRight
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
v.versionLabel.Color = color.RGBA{255, 255, 255, 255}
v.versionLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.versionLabel.SetPosition(795, -10)
},
func() {
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.commitLabel.Alignment = d2ui.LabelAlignLeft
v.commitLabel.SetText(d2common.BuildInfo.Commit)
v.commitLabel.Color = color.RGBA{255, 255, 255, 255}
v.commitLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.commitLabel.SetPosition(2, 2)
},
func() {
v.copyrightLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel.Alignment = d2ui.LabelAlignCenter
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255}
v.copyrightLabel.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel.SetPosition(400, 500)
},
func() {
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2.Alignment = d2ui.LabelAlignCenter
v.copyrightLabel2.SetText(d2common.TranslateString("#1614"))
v.copyrightLabel2.Color = color.RGBA{188, 168, 140, 255}
v.copyrightLabel2.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel2.SetPosition(400, 525)
},
func() {
v.openDiabloLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.openDiabloLabel.Alignment = d2ui.LabelAlignCenter
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
v.openDiabloLabel.Color = color.RGBA{255, 255, 140, 255}
v.openDiabloLabel.Color = color.RGBA{R: 255, G: 255, B: 140, A: 255}
v.openDiabloLabel.SetPosition(400, 580)
},
func() {

View File

@ -25,7 +25,7 @@ type RegionSpec struct {
extra []int
}
var regions []RegionSpec = []RegionSpec{
var regions = []RegionSpec{
//Act I
{d2enum.RegionAct1Town, 1, 3, []int{}},
{d2enum.RegionAct1Wilderness, 4, 52, []int{
@ -104,10 +104,10 @@ func CreateMapEngineTest(currentRegion int, levelPreset int) *MapEngineTest {
return result
}
func (v *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
func (met *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
for _, spec := range regions {
if spec.regionType == d2enum.RegionIdType(n) {
v.regionSpec = spec
met.regionSpec = spec
inExtra := false
for _, e := range spec.extra {
if e == levelPreset {
@ -124,44 +124,44 @@ func (v *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
levelPreset = spec.endPresetIndex
}
}
v.levelPreset = levelPreset
met.levelPreset = levelPreset
}
}
if n == 0 {
v.mapEngine.GenerateAct1Overworld()
met.mapEngine.GenerateAct1Overworld()
} else {
v.mapEngine = d2map.CreateMapEngine(v.gameState) // necessary for map name update
v.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
met.mapEngine = d2map.CreateMapEngine(met.gameState) // necessary for map name update
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
}
v.mapEngine.MoveCameraTo(v.mapEngine.WorldToOrtho(v.mapEngine.GetCenterPosition()))
met.mapEngine.MoveCameraTo(met.mapEngine.WorldToOrtho(met.mapEngine.GetCenterPosition()))
}
func (v *MapEngineTest) Load() []func() {
func (met *MapEngineTest) Load() []func() {
// TODO: Game seed comes from the game state object
d2input.BindHandler(v)
d2input.BindHandler(met)
d2audio.PlayBGM("")
return []func(){
func() {
v.mapEngine = d2map.CreateMapEngine(v.gameState)
v.LoadRegionByIndex(v.currentRegion, v.levelPreset, v.fileIndex)
met.mapEngine = d2map.CreateMapEngine(met.gameState)
met.LoadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)
},
}
}
func (v *MapEngineTest) Unload() {
d2input.UnbindHandler(v)
func (met *MapEngineTest) Unload() {
d2input.UnbindHandler(met)
}
func (v *MapEngineTest) Render(screen d2render.Surface) {
v.mapEngine.Render(screen)
func (met *MapEngineTest) Render(screen d2render.Surface) {
met.mapEngine.Render(screen)
screenX, screenY, _ := d2render.GetCursorPos()
worldX, worldY := v.mapEngine.ScreenToWorld(screenX, screenY)
subtileX := int(math.Ceil(math.Mod((worldX*10), 10))) / 2
subtileY := int(math.Ceil(math.Mod((worldY*10), 10))) / 2
curRegion := v.mapEngine.GetRegionAtTile(int(worldX), int(worldY))
worldX, worldY := met.mapEngine.ScreenToWorld(screenX, screenY)
subtileX := int(math.Ceil(math.Mod(worldX*10, 10))) / 2
subtileY := int(math.Ceil(math.Mod(worldY*10, 10))) / 2
curRegion := met.mapEngine.GetRegionAtTile(int(worldX), int(worldY))
if curRegion == nil {
return
}
@ -169,7 +169,7 @@ func (v *MapEngineTest) Render(screen d2render.Surface) {
tileRect := curRegion.GetTileRect()
levelFilesToPick := make([]string, 0)
fileIndex := v.fileIndex
fileIndex := met.fileIndex
levelPreset := curRegion.GetLevelPreset()
regionPath := curRegion.GetPath()
for n, fileRecord := range levelPreset.Files {
@ -181,17 +181,17 @@ func (v *MapEngineTest) Render(screen d2render.Surface) {
fileIndex = n
}
}
if v.fileIndex == -1 {
v.fileIndex = fileIndex
if met.fileIndex == -1 {
met.fileIndex = fileIndex
}
v.filesCount = len(levelFilesToPick)
met.filesCount = len(levelFilesToPick)
screen.PushTranslation(5, 5)
screen.DrawText("%d, %d (Tile %d.%d, %d.%d)", screenX, screenY, int(math.Floor(worldX))-tileRect.Left, subtileX, int(math.Floor(worldY))-tileRect.Top, subtileY)
screen.PushTranslation(0, 16)
screen.DrawText("Map: " + curRegion.GetLevelType().Name)
screen.PushTranslation(0, 16)
screen.DrawText("%v: %v/%v [%v, %v]", regionPath, fileIndex+1, v.filesCount, v.currentRegion, v.levelPreset)
screen.DrawText("%met: %met/%met [%met, %met]", regionPath, fileIndex+1, met.filesCount, met.currentRegion, met.levelPreset)
screen.PushTranslation(0, 16)
screen.DrawText("N - next region, P - previous region")
screen.PushTranslation(0, 16)
@ -201,8 +201,8 @@ func (v *MapEngineTest) Render(screen d2render.Surface) {
screen.PopN(6)
}
func (v *MapEngineTest) Advance(tickTime float64) {
v.mapEngine.Advance(tickTime)
func (met *MapEngineTest) Advance(tickTime float64) {
met.mapEngine.Advance(tickTime)
}
func (met *MapEngineTest) OnKeyRepeat(event d2input.KeyEvent) bool {

View File

@ -86,7 +86,7 @@ func (v *SelectHeroClass) Load() []func() {
func() {
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
fontWidth, _ := v.headingLabel.GetSize()
v.headingLabel.SetPosition(400-int(fontWidth/2), 17)
v.headingLabel.SetPosition(400-fontWidth/2, 17)
v.headingLabel.SetText("Select Hero Class")
v.headingLabel.Alignment = d2ui.LabelAlignCenter
},
@ -133,7 +133,7 @@ func (v *SelectHeroClass) Load() []func() {
func() {
v.heroNameLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroNameLabel.Alignment = d2ui.LabelAlignLeft
v.heroNameLabel.Color = color.RGBA{216, 196, 128, 255}
v.heroNameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.heroNameLabel.SetText(d2common.TranslateString("#1694"))
v.heroNameLabel.SetPosition(321, 475)
},
@ -152,7 +152,7 @@ func (v *SelectHeroClass) Load() []func() {
func() {
v.expansionCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.expansionCharLabel.Alignment = d2ui.LabelAlignLeft
v.expansionCharLabel.Color = color.RGBA{216, 196, 128, 255}
v.expansionCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.expansionCharLabel.SetText(d2common.TranslateString("#803"))
v.expansionCharLabel.SetPosition(339, 526)
},
@ -165,7 +165,7 @@ func (v *SelectHeroClass) Load() []func() {
func() {
v.hardcoreCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.hardcoreCharLabel.Alignment = d2ui.LabelAlignLeft
v.hardcoreCharLabel.Color = color.RGBA{216, 196, 128, 255}
v.hardcoreCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.hardcoreCharLabel.SetText(d2common.TranslateString("#1696"))
v.hardcoreCharLabel.SetPosition(339, 548)
},
@ -180,7 +180,7 @@ func (v *SelectHeroClass) Load() []func() {
nil,
loadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2resource.PaletteFechar),
nil,
image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}},
image.Rectangle{Min: image.Point{X: 364, Y: 201}, Max: image.Point{X: 90, Y: 170}},
loadSoundEffect(d2resource.SFXBarbarianSelect),
loadSoundEffect(d2resource.SFXBarbarianDeselect),
}
@ -214,7 +214,7 @@ func (v *SelectHeroClass) Load() []func() {
loadSprite(d2resource.CharacterSelecSorceressSelectedOverlay, d2resource.PaletteFechar),
loadSprite(d2resource.CharacterSelecSorceressBackWalk, d2resource.PaletteFechar),
loadSprite(d2resource.CharacterSelecSorceressBackWalkOverlay, d2resource.PaletteFechar),
image.Rectangle{Min: image.Point{580, 240}, Max: image.Point{65, 160}},
image.Rectangle{Min: image.Point{X: 580, Y: 240}, Max: image.Point{X: 65, Y: 160}},
loadSoundEffect(d2resource.SFXSorceressSelect),
loadSoundEffect(d2resource.SFXSorceressDeselect),
}
@ -261,7 +261,7 @@ func (v *SelectHeroClass) Load() []func() {
loadSprite(d2resource.CharacterSelecNecromancerSelectedOverlay, d2resource.PaletteFechar),
loadSprite(d2resource.CharacterSelecNecromancerBackWalk, d2resource.PaletteFechar),
loadSprite(d2resource.CharacterSelecNecromancerBackWalkOverlay, d2resource.PaletteFechar),
image.Rectangle{Min: image.Point{265, 220}, Max: image.Point{55, 175}},
image.Rectangle{Min: image.Point{X: 265, Y: 220}, Max: image.Point{X: 55, Y: 175}},
loadSoundEffect(d2resource.SFXNecromancerSelect),
loadSoundEffect(d2resource.SFXNecromancerDeselect),
}
@ -306,7 +306,7 @@ func (v *SelectHeroClass) Load() []func() {
nil,
loadSprite(d2resource.CharacterSelecPaladinBackWalk, d2resource.PaletteFechar),
nil,
image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}},
image.Rectangle{Min: image.Point{X: 490, Y: 210}, Max: image.Point{X: 65, Y: 180}},
loadSoundEffect(d2resource.SFXPaladinSelect),
loadSoundEffect(d2resource.SFXPaladinDeselect),
}
@ -343,7 +343,7 @@ func (v *SelectHeroClass) Load() []func() {
nil,
loadSprite(d2resource.CharacterSelecAmazonBackWalk, d2resource.PaletteFechar),
nil,
image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}},
image.Rectangle{Min: image.Point{X: 70, Y: 220}, Max: image.Point{X: 55, Y: 200}},
loadSoundEffect(d2resource.SFXAmazonSelect),
loadSoundEffect(d2resource.SFXAmazonDeselect),
}
@ -376,7 +376,7 @@ func (v *SelectHeroClass) Load() []func() {
nil,
loadSprite(d2resource.CharacterSelectAssassinBackWalk, d2resource.PaletteFechar),
nil,
image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}},
image.Rectangle{Min: image.Point{X: 175, Y: 235}, Max: image.Point{X: 50, Y: 180}},
loadSoundEffect(d2resource.SFXAssassinSelect),
loadSoundEffect(d2resource.SFXAssassinDeselect),
}
@ -409,7 +409,7 @@ func (v *SelectHeroClass) Load() []func() {
nil,
loadSprite(d2resource.CharacterSelectDruidBackWalk, d2resource.PaletteFechar),
nil,
image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}},
image.Rectangle{Min: image.Point{X: 680, Y: 220}, Max: image.Point{X: 70, Y: 195}},
loadSoundEffect(d2resource.SFXDruidSelect),
loadSoundEffect(d2resource.SFXDruidDeselect),
}

View File

@ -76,7 +76,7 @@ func (g *GameControls) Render(target d2render.Surface) {
g.inventory.Render(target)
width, height := target.GetSize()
offset := int(0)
offset := 0
// Left globe holder
g.mainPanel.SetCurrentFrame(0)

View File

@ -55,7 +55,7 @@ h2 {
img.imgFrame {
display: inline-block;
clear: bloth;
clear: both;
border-radius: 6px;
box-shadow: 0 0 8px #000;
margin: 6px;

View File

@ -156,7 +156,7 @@ func initializeEverything() error {
return err
}
var audioProvider *ebiten2.EbitenAudioProvider
var audioProvider *ebiten2.AudioProvider
audioProvider, err = ebiten2.CreateAudio()
err = d2audio.Initialize(audioProvider)
if err != nil {