`d2game/d2player/` lint error cleanup (#788)
* d2game/d2player/inventory.go: magic number lint cleanup * d2game/d2player/mini_panel.go: magic number lint cleanup * d2game/d2player/skill_select_panel.go: lint cleanup * d2game/d2player/skilltree.go: removed all lint errors * removed the rest of the magic number errors from d2game * hotfix for bug i added in map engine test * all magic numbers removed (excluding mapgen)
This commit is contained in:
parent
fb8923185f
commit
18c9e85cbc
|
@ -250,7 +250,7 @@ func (m *MapEngine) RemoveEntity(entity d2interface.MapEntity) {
|
|||
|
||||
// GetTiles returns a slice of all tiles matching the given style,
|
||||
// sequence and tileType.
|
||||
func (m *MapEngine) GetTiles(style, sequence, tileType int) []d2dt1.Tile {
|
||||
func (m *MapEngine) GetTiles(style, sequence int, tileType d2enum.TileType) []d2dt1.Tile {
|
||||
tiles := make([]d2dt1.Tile, 0, len(m.dt1TileData))
|
||||
|
||||
for idx := range m.dt1TileData {
|
||||
|
|
|
@ -30,7 +30,7 @@ func (t *MapTile) GetSubTileFlags(x, y int) *d2dt1.SubTileFlags {
|
|||
func (t *MapTile) PrepareTile(x, y int, me *MapEngine) {
|
||||
for wIdx := range t.Components.Walls {
|
||||
wall := &t.Components.Walls[wIdx]
|
||||
options := me.GetTiles(int(wall.Style), int(wall.Sequence), int(wall.Type))
|
||||
options := me.GetTiles(int(wall.Style), int(wall.Sequence), wall.Type)
|
||||
|
||||
if options == nil {
|
||||
break
|
||||
|
|
|
@ -18,7 +18,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
subtilesPerTile = 5
|
||||
subtilesPerTile = 5
|
||||
retailFps = 25.0
|
||||
millisecondsPerSecond = 1000.0
|
||||
)
|
||||
|
||||
// NewMapEntityFactory creates a MapEntityFactory instance with the given asset manager
|
||||
|
@ -233,15 +235,15 @@ func (f *MapEntityFactory) NewCastOverlay(x, y int, overlayRecord *d2records.Ove
|
|||
d2enum.DrawEffectModulate,
|
||||
)
|
||||
|
||||
// TODO: Frame index and played count seem to be shared across the cloned animation objects when we retrieve the animation from the asset manager cache.
|
||||
animation.Rewind()
|
||||
animation.ResetPlayedCount()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
animationSpeed := float64(overlayRecord.AnimRate*25.0) / 1000.0
|
||||
// TODO: Frame index and played count seem to be shared across the cloned animation objects when we retrieve the animation from the asset manager cache.
|
||||
animation.Rewind()
|
||||
animation.ResetPlayedCount()
|
||||
|
||||
animationSpeed := float64(overlayRecord.AnimRate*retailFps) / millisecondsPerSecond
|
||||
playLoop := false // TODO: should be based on the overlay record, some overlays can repeat(e.g. Bone Shield, Frozen Armor)
|
||||
|
||||
animation.SetPlayLength(animationSpeed)
|
||||
|
|
|
@ -84,7 +84,7 @@ func (ob *Object) Render(target d2interface.Surface) {
|
|||
)
|
||||
|
||||
if ob.highlight {
|
||||
target.PushBrightness(2)
|
||||
target.PushBrightness(highlightBrightness)
|
||||
defer target.Pop()
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,10 @@ func (p *Player) IsInTown() bool {
|
|||
return p.isInTown
|
||||
}
|
||||
|
||||
const (
|
||||
half = 0.5
|
||||
)
|
||||
|
||||
// Advance is called once per frame and processes a
|
||||
// single game tick.
|
||||
func (p *Player) Advance(tickTime float64) {
|
||||
|
@ -92,7 +96,9 @@ func (p *Player) Advance(tickTime float64) {
|
|||
}
|
||||
|
||||
// skills are casted after the first half of the casting animation is played
|
||||
isHalfDoneCasting := float64(p.composite.GetCurrentFrame())/float64(p.composite.GetFrameCount()) >= 0.5
|
||||
percentDone := float64(p.composite.GetCurrentFrame()) / float64(p.composite.GetFrameCount())
|
||||
isHalfDoneCasting := percentDone >= half
|
||||
|
||||
if isHalfDoneCasting && p.onFinishedCasting != nil {
|
||||
p.onFinishedCasting()
|
||||
p.onFinishedCasting = nil
|
||||
|
|
|
@ -557,16 +557,20 @@ func (mr *MapRenderer) renderTileDebug(ax, ay, debugVisLevel int, target d2inter
|
|||
}
|
||||
}
|
||||
|
||||
// Advance is called once per frame and maintains the MapRenderer's record previous render timestamp and current frame.
|
||||
func (mr *MapRenderer) Advance(elapsed float64) {
|
||||
frameLength := 0.1
|
||||
const (
|
||||
frameOverflow = 10
|
||||
frameLength = 1.0 / frameOverflow
|
||||
)
|
||||
|
||||
// Advance is called once per frame and maintains the MapRenderer's previous
|
||||
// render timestamp and current frame.
|
||||
func (mr *MapRenderer) Advance(elapsed float64) {
|
||||
mr.lastFrameTime += elapsed
|
||||
framesAdvanced := int(mr.lastFrameTime / frameLength)
|
||||
mr.lastFrameTime -= float64(framesAdvanced) * frameLength
|
||||
|
||||
mr.currentFrame += framesAdvanced
|
||||
if mr.currentFrame > 9 {
|
||||
if mr.currentFrame >= frameOverflow {
|
||||
mr.currentFrame = 0
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,12 @@ const (
|
|||
defaultFloorTileHeight = 10
|
||||
)
|
||||
|
||||
const (
|
||||
blockOffsetY = 32
|
||||
tileSurfaceWidth = 160
|
||||
tileSurfaceHeight = 80
|
||||
)
|
||||
|
||||
func (mr *MapRenderer) generateTileCache() {
|
||||
var err error
|
||||
mr.palette, err = mr.loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
||||
|
@ -113,10 +119,8 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
|
|||
}
|
||||
}
|
||||
|
||||
const shadowTileType = 13
|
||||
|
||||
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord) {
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), shadowTileType)
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), d2enum.TileShadow)
|
||||
|
||||
var tileData *d2dt1.Tile
|
||||
|
||||
|
@ -165,7 +169,7 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord) {
|
|||
}
|
||||
|
||||
func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), int(tile.Type))
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), tile.Type)
|
||||
|
||||
var tileData *d2dt1.Tile
|
||||
|
||||
|
@ -177,8 +181,11 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
|
|||
|
||||
var newTileData *d2dt1.Tile = nil
|
||||
|
||||
if tile.Type == 3 {
|
||||
newTileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), int(4))
|
||||
if tile.Type == d2enum.TileRightPartOfNorthCornerWall {
|
||||
newTileOptions := mr.mapEngine.GetTiles(
|
||||
int(tile.Style), int(tile.Sequence),
|
||||
d2enum.TileLeftPartOfNorthCornerWall,
|
||||
)
|
||||
newTileData = &newTileOptions[tile.RandomIndex]
|
||||
}
|
||||
|
||||
|
@ -193,16 +200,16 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
|
|||
|
||||
for _, block := range target.Blocks {
|
||||
tileMinY = d2math.MinInt32(tileMinY, int32(block.Y))
|
||||
tileMaxY = d2math.MaxInt32(tileMaxY, int32(block.Y+32))
|
||||
tileMaxY = d2math.MaxInt32(tileMaxY, int32(block.Y+blockOffsetY))
|
||||
}
|
||||
|
||||
realHeight := d2math.MaxInt32(d2math.AbsInt32(tileData.Height), tileMaxY-tileMinY)
|
||||
tileYOffset := -tileMinY
|
||||
|
||||
if tile.Type == 15 {
|
||||
if tile.Type == d2enum.TileRoof {
|
||||
tile.YAdjust = -int(tileData.RoofHeight)
|
||||
} else {
|
||||
tile.YAdjust = int(tileMinY) + 80
|
||||
tile.YAdjust = int(tileMinY) + tileSurfaceHeight
|
||||
}
|
||||
|
||||
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
|
||||
|
@ -215,17 +222,17 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
|
|||
return
|
||||
}
|
||||
|
||||
image, err := mr.renderer.NewSurface(160, int(realHeight), d2enum.FilterNearest)
|
||||
image, err := mr.renderer.NewSurface(tileSurfaceWidth, int(realHeight), d2enum.FilterNearest)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
indexData := make([]byte, 160*realHeight)
|
||||
indexData := make([]byte, tileSurfaceWidth*realHeight)
|
||||
|
||||
d2dt1.DecodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, 160)
|
||||
d2dt1.DecodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileSurfaceWidth)
|
||||
|
||||
if newTileData != nil {
|
||||
d2dt1.DecodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, 160)
|
||||
d2dt1.DecodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, tileSurfaceWidth)
|
||||
}
|
||||
|
||||
pixels := d2util.ImgIndexToRGBA(indexData, mr.palette)
|
||||
|
|
|
@ -20,6 +20,10 @@ const (
|
|||
half = 2
|
||||
)
|
||||
|
||||
const (
|
||||
worldToOrthoOffsetX = 3
|
||||
)
|
||||
|
||||
// Viewport is used for converting vectors between screen (pixel), orthogonal (Camera) and world (isometric) space.
|
||||
type Viewport struct {
|
||||
defaultScreenRect d2geom.Rectangle
|
||||
|
@ -113,8 +117,8 @@ func (v *Viewport) OrthoToScreenF(x, y float64) (screenX, screenY float64) {
|
|||
|
||||
// IsTileVisible returns false if no part of the tile is within the game screen.
|
||||
func (v *Viewport) IsTileVisible(x, y float64) bool {
|
||||
orthoX1, orthoY1 := v.WorldToOrtho(x-3, y)
|
||||
orthoX2, orthoY2 := v.WorldToOrtho(x+3, y)
|
||||
orthoX1, orthoY1 := v.WorldToOrtho(x-worldToOrthoOffsetX, y)
|
||||
orthoX2, orthoY2 := v.WorldToOrtho(x+worldToOrthoOffsetX, y)
|
||||
|
||||
return v.IsOrthoRectVisible(orthoX1, orthoY1, orthoX2, orthoY2)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,10 @@ const (
|
|||
spawnItemErrStr = "failed to send SpawnItem packet to the server: (%d, %d) %+v"
|
||||
)
|
||||
|
||||
const (
|
||||
black50alpha = 0x0000007f // rgba
|
||||
)
|
||||
|
||||
// Game represents the Gameplay screen
|
||||
type Game struct {
|
||||
*d2mapentity.MapEntityFactory
|
||||
|
@ -205,8 +209,7 @@ func (v *Game) Render(screen d2interface.Surface) error {
|
|||
|
||||
if v.gameControls != nil {
|
||||
if v.gameControls.HelpOverlay != nil && v.gameControls.HelpOverlay.IsOpen() {
|
||||
// When help overlay is open, put transparent black screen. Magic noumber is hex for RGBA.
|
||||
screen.DrawRect(800, 600, d2util.Color(0x0000007f))
|
||||
screen.DrawRect(screenWidth, screenHeight, d2util.Color(black50alpha))
|
||||
}
|
||||
|
||||
if err := v.gameControls.Render(screen); err != nil {
|
||||
|
@ -232,7 +235,7 @@ func (v *Game) Advance(elapsed float64) error {
|
|||
}
|
||||
|
||||
v.ticksSinceLevelCheck += elapsed
|
||||
if v.ticksSinceLevelCheck > 1.0 {
|
||||
if v.ticksSinceLevelCheck > 1 {
|
||||
v.ticksSinceLevelCheck = 0
|
||||
if v.localPlayer != nil {
|
||||
tilePosition := v.localPlayer.Position.Tile()
|
||||
|
|
|
@ -20,6 +20,10 @@ import (
|
|||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
)
|
||||
|
||||
const (
|
||||
subtilesPerTile = 5
|
||||
)
|
||||
|
||||
type regionSpec struct {
|
||||
regionType d2enum.RegionIdType
|
||||
startPresetIndex int
|
||||
|
@ -226,108 +230,137 @@ func (met *MapEngineTest) OnUnload() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
lineSmallOffsetY = 12
|
||||
lineNormalOffsetY = 16
|
||||
lineSmallIndentX = 10
|
||||
lineNormalIndentX = 15
|
||||
lineBigIndentX = 170 // distance between text columns
|
||||
)
|
||||
|
||||
// Render renders the Map Engine Test screen
|
||||
func (met *MapEngineTest) Render(screen d2interface.Surface) error {
|
||||
met.mapRenderer.Render(screen)
|
||||
|
||||
screen.PushTranslation(0, 16)
|
||||
screen.DrawTextf("N - next region, P - previous region")
|
||||
screen.PushTranslation(0, 16)
|
||||
screen.DrawTextf("Shift+N - next preset, Shift+P - previous preset")
|
||||
screen.PushTranslation(0, 16)
|
||||
screen.DrawTextf("Ctrl+N - next file, Ctrl+P - previous file")
|
||||
screen.PushTranslation(0, 16)
|
||||
screen.DrawTextf("Left click selects tile, right click unselects")
|
||||
screen.PushTranslation(0, 16)
|
||||
screen.PushTranslation(0, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
popN := 5
|
||||
screen.DrawTextf("N - next region, P - previous region")
|
||||
|
||||
screen.PushTranslation(0, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
screen.DrawTextf("Shift+N - next preset, Shift+P - previous preset")
|
||||
|
||||
screen.PushTranslation(0, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
screen.DrawTextf("Ctrl+N - next file, Ctrl+P - previous file")
|
||||
|
||||
screen.PushTranslation(0, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
screen.DrawTextf("Left click selects tile, right click unselects")
|
||||
|
||||
screen.PushTranslation(0, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
if met.selectedTile == nil {
|
||||
screen.PushTranslation(15, 16)
|
||||
popN++
|
||||
screen.PushTranslation(lineNormalIndentX, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
screen.DrawTextf("No tile selected")
|
||||
} else {
|
||||
screen.PushTranslation(10, 32)
|
||||
screen.PushTranslation(lineSmallIndentX, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
screen.PushTranslation(0, lineNormalOffsetY) // extra vspace
|
||||
defer screen.Pop()
|
||||
|
||||
screen.DrawTextf("Tile %v,%v", met.selX, met.selY)
|
||||
|
||||
screen.PushTranslation(15, 16)
|
||||
screen.PushTranslation(lineNormalIndentX, lineNormalOffsetY)
|
||||
defer screen.Pop()
|
||||
|
||||
screen.DrawTextf("Walls")
|
||||
|
||||
tpop := 0
|
||||
for _, wall := range met.selectedTile.Components.Walls {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
tmpString := fmt.Sprintf("%#v", wall)
|
||||
stringSlice := strings.Split(tmpString, " ")
|
||||
tmp2 := strings.Split(stringSlice[0], "{")
|
||||
stringSlice[0] = tmp2[1]
|
||||
for _, str := range stringSlice {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
screen.DrawTextf(str)
|
||||
}
|
||||
}
|
||||
|
||||
screen.PopN(tpop)
|
||||
|
||||
screen.PushTranslation(170, 0)
|
||||
screen.PushTranslation(lineBigIndentX, 0)
|
||||
defer screen.Pop()
|
||||
screen.DrawTextf("Floors")
|
||||
|
||||
tpop = 0
|
||||
for _, floor := range met.selectedTile.Components.Floors {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
tmpString := fmt.Sprintf("%#v", floor)
|
||||
stringSlice := strings.Split(tmpString, " ")
|
||||
tmp2 := strings.Split(stringSlice[0], "{")
|
||||
stringSlice[0] = tmp2[1]
|
||||
for _, str := range stringSlice {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
screen.DrawTextf(str)
|
||||
}
|
||||
}
|
||||
screen.PopN(tpop)
|
||||
|
||||
tpop = 0
|
||||
screen.PushTranslation(170, 0)
|
||||
screen.PushTranslation(lineBigIndentX, 0)
|
||||
defer screen.Pop()
|
||||
screen.DrawTextf("Shadows")
|
||||
|
||||
tpop = 0
|
||||
for _, shadow := range met.selectedTile.Components.Shadows {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
tmpString := fmt.Sprintf("%#v", shadow)
|
||||
stringSlice := strings.Split(tmpString, " ")
|
||||
tmp2 := strings.Split(stringSlice[0], "{")
|
||||
stringSlice[0] = tmp2[1]
|
||||
for _, str := range stringSlice {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
screen.DrawTextf(str)
|
||||
}
|
||||
}
|
||||
screen.PopN(tpop)
|
||||
|
||||
tpop = 0
|
||||
screen.PushTranslation(170, 0)
|
||||
screen.PushTranslation(lineBigIndentX, 0)
|
||||
defer screen.Pop()
|
||||
screen.DrawTextf("Substitutions")
|
||||
|
||||
tpop = 0
|
||||
for _, subst := range met.selectedTile.Components.Substitutions {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
tmpString := fmt.Sprintf("%#v", subst)
|
||||
stringSlice := strings.Split(tmpString, " ")
|
||||
tmp2 := strings.Split(stringSlice[0], "{")
|
||||
stringSlice[0] = tmp2[1]
|
||||
for _, str := range stringSlice {
|
||||
screen.PushTranslation(0, 12)
|
||||
screen.PushTranslation(0, lineSmallOffsetY)
|
||||
tpop++
|
||||
screen.DrawTextf(str)
|
||||
}
|
||||
}
|
||||
screen.PopN(tpop)
|
||||
|
||||
popN += 5
|
||||
}
|
||||
|
||||
screen.PopN(popN)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -376,7 +409,11 @@ func (met *MapEngineTest) handleLeftClick() {
|
|||
|
||||
camVect := met.mapRenderer.Camera.GetPosition().Vector
|
||||
|
||||
x, y := float64(met.lastMouseX-400)/5, float64(met.lastMouseY-300)/5
|
||||
halfScreenWidth, halfScreenHeight := screenWidth>>1, screenHeight>>1
|
||||
|
||||
x := float64(met.lastMouseX-halfScreenWidth) / subtilesPerTile
|
||||
y := float64(met.lastMouseY-halfScreenHeight) / subtilesPerTile
|
||||
|
||||
targetPosition := d2vector.NewPositionTile(x, y)
|
||||
targetPosition.Add(&camVect)
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ type GameControls struct {
|
|||
escapeMenu *EscapeMenu
|
||||
ui *d2ui.UIManager
|
||||
inventory *Inventory
|
||||
skilltree *SkillTree
|
||||
skilltree *skillTree
|
||||
heroStatsPanel *HeroStatsPanel
|
||||
HelpOverlay *help.Overlay
|
||||
miniPanel *miniPanel
|
||||
|
@ -362,7 +362,7 @@ func NewGameControls(
|
|||
mapRenderer: mapRenderer,
|
||||
inventory: NewInventory(asset, ui, inventoryRecord),
|
||||
skillSelectMenu: NewSkillSelectMenu(asset, ui, hero),
|
||||
skilltree: NewSkillTree(hero.Skills, hero.Class, asset, renderer, ui, guiManager),
|
||||
skilltree: newSkillTree(hero.Skills, hero.Class, asset, renderer, ui, guiManager),
|
||||
heroStatsPanel: NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats),
|
||||
HelpOverlay: help.NewHelpOverlay(asset, renderer, ui, guiManager),
|
||||
miniPanel: newMiniPanel(asset, ui, isSinglePlayer),
|
||||
|
@ -817,7 +817,7 @@ func (g *GameControls) Load() {
|
|||
g.loadUIButtons()
|
||||
|
||||
g.inventory.Load()
|
||||
g.skilltree.Load()
|
||||
g.skilltree.load()
|
||||
g.heroStatsPanel.Load()
|
||||
g.HelpOverlay.Load()
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ package d2player
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
|
@ -15,6 +15,17 @@ import (
|
|||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
const (
|
||||
frameInventoryTopLeft = 4
|
||||
frameInventoryTopRight = 5
|
||||
frameInventoryBottomLeft = 6
|
||||
frameInventoryBottomRight = 7
|
||||
)
|
||||
|
||||
const (
|
||||
blackAlpha70 = 0x000000C8
|
||||
)
|
||||
|
||||
// Inventory represents the inventory
|
||||
type Inventory struct {
|
||||
asset *d2asset.AssetManager
|
||||
|
@ -135,14 +146,16 @@ func (g *Inventory) Render(target d2interface.Surface) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
g.frame.Render(target)
|
||||
if err := g.frame.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
x, y := g.originX+1, g.originY
|
||||
y += 64
|
||||
|
||||
// Panel
|
||||
// Top left
|
||||
if err := g.panel.SetCurrentFrame(4); err != nil {
|
||||
if err := g.panel.SetCurrentFrame(frameInventoryTopLeft); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -157,7 +170,7 @@ func (g *Inventory) Render(target d2interface.Surface) error {
|
|||
x += w
|
||||
|
||||
// Top right
|
||||
if err := g.panel.SetCurrentFrame(5); err != nil {
|
||||
if err := g.panel.SetCurrentFrame(frameInventoryTopRight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -172,7 +185,7 @@ func (g *Inventory) Render(target d2interface.Surface) error {
|
|||
y += h
|
||||
|
||||
// Bottom right
|
||||
if err := g.panel.SetCurrentFrame(7); err != nil {
|
||||
if err := g.panel.SetCurrentFrame(frameInventoryBottomRight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -184,7 +197,7 @@ func (g *Inventory) Render(target d2interface.Surface) error {
|
|||
}
|
||||
|
||||
// Bottom left
|
||||
if err := g.panel.SetCurrentFrame(6); err != nil {
|
||||
if err := g.panel.SetCurrentFrame(frameInventoryBottomLeft); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -241,21 +254,27 @@ func (g *Inventory) renderItemDescription(target d2interface.Surface, i Inventor
|
|||
maxH += h
|
||||
}
|
||||
|
||||
halfW, halfH := maxW/2, maxH/2
|
||||
halfW, halfH := maxW>>1, maxH>>1
|
||||
centerX, centerY := g.hoverX, iy-halfH
|
||||
|
||||
if (centerX + halfW) > 800 {
|
||||
centerX = 800 - halfW
|
||||
if (centerX + halfW) > screenWidth {
|
||||
centerX = screenWidth - halfW
|
||||
}
|
||||
|
||||
if (centerY + halfH) > 600 {
|
||||
centerY = 600 - halfH
|
||||
if (centerY + halfH) > screenHeight {
|
||||
centerY = screenHeight - halfH
|
||||
}
|
||||
|
||||
target.PushTranslation(centerX, centerY)
|
||||
defer target.Pop()
|
||||
|
||||
target.PushTranslation(-halfW, -halfH)
|
||||
target.DrawRect(maxW, maxH, color.RGBA{0, 0, 0, uint8(200)})
|
||||
defer target.Pop()
|
||||
|
||||
target.DrawRect(maxW, maxH, d2util.Color(blackAlpha70))
|
||||
|
||||
target.PushTranslation(halfW, 0)
|
||||
defer target.Pop()
|
||||
|
||||
for idx := range lines {
|
||||
g.hoverLabel.SetText(lines[idx])
|
||||
|
@ -265,5 +284,4 @@ func (g *Inventory) renderItemDescription(target d2interface.Surface, i Inventor
|
|||
}
|
||||
|
||||
target.PopN(len(lines))
|
||||
target.PopN(3)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,21 @@ import (
|
|||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
const (
|
||||
miniPanelX = 325
|
||||
miniPanelY = 526
|
||||
miniPanelWidth = 156
|
||||
miniPanelHeight = 26
|
||||
)
|
||||
|
||||
const (
|
||||
containerOffsetX = -75
|
||||
containerOffsetY = -48
|
||||
|
||||
buttonOffsetX = -72
|
||||
buttonOffsetY = -51
|
||||
)
|
||||
|
||||
type miniPanel struct {
|
||||
asset *d2asset.AssetManager
|
||||
container *d2ui.Sprite
|
||||
|
@ -37,7 +52,12 @@ func newMiniPanel(asset *d2asset.AssetManager, uiManager *d2ui.UIManager, isSing
|
|||
return nil
|
||||
}
|
||||
|
||||
rectangle := d2geom.Rectangle{Left: 325, Top: 526, Width: 156, Height: 26}
|
||||
rectangle := d2geom.Rectangle{
|
||||
Left: miniPanelX,
|
||||
Top: miniPanelY,
|
||||
Width: miniPanelWidth,
|
||||
Height: miniPanelHeight,
|
||||
}
|
||||
|
||||
if !isSinglePlayer {
|
||||
rectangle.Width = 182
|
||||
|
@ -79,8 +99,10 @@ func (m *miniPanel) Render(target d2interface.Surface) error {
|
|||
}
|
||||
|
||||
width, height := target.GetSize()
|
||||
halfW, halfH := width>>1, height>>1
|
||||
x, y := halfW+containerOffsetX, halfH+containerOffsetY
|
||||
|
||||
m.container.SetPosition((width/2)-75, height-48)
|
||||
m.container.SetPosition(x, y)
|
||||
|
||||
if err := m.container.Render(target); err != nil {
|
||||
return err
|
||||
|
@ -98,7 +120,10 @@ func (m *miniPanel) Render(target d2interface.Surface) error {
|
|||
return err
|
||||
}
|
||||
|
||||
m.button.SetPosition((width/2)-72+(buttonWidth*i), height-51)
|
||||
offsetX := buttonOffsetX + (buttonWidth * i)
|
||||
x, y := halfW+offsetX, height+buttonOffsetY
|
||||
|
||||
m.button.SetPosition(x, y)
|
||||
|
||||
if err := m.button.Render(target); err != nil {
|
||||
return err
|
||||
|
|
|
@ -2,10 +2,11 @@ package d2player
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2tbl"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
|
||||
|
@ -36,16 +37,16 @@ const (
|
|||
type SkillPanel struct {
|
||||
asset *d2asset.AssetManager
|
||||
activeSkill *d2hero.HeroSkill
|
||||
isOpen bool
|
||||
regenerateImageCache bool
|
||||
hero *d2mapentity.Player
|
||||
ListRows []*SkillListRow
|
||||
isLeftPanel bool
|
||||
renderer d2interface.Renderer
|
||||
ui *d2ui.UIManager
|
||||
hoveredSkill *d2hero.HeroSkill
|
||||
hoverTooltipRect *d2geom.Rectangle
|
||||
hoverTooltipText *d2ui.Label
|
||||
isOpen bool
|
||||
regenerateImageCache bool
|
||||
isLeftPanel bool
|
||||
}
|
||||
|
||||
// NewHeroSkillsPanel creates a new hero status panel
|
||||
|
@ -85,11 +86,10 @@ func (s *SkillPanel) Close() {
|
|||
}
|
||||
|
||||
// IsInRect returns whether the X Y coordinates are in some of the list rows of the panel.
|
||||
func (s *SkillPanel) IsInRect(X int, Y int) bool {
|
||||
func (s *SkillPanel) IsInRect(x, y int) bool {
|
||||
for _, listRow := range s.ListRows {
|
||||
|
||||
// TODO: investigate why listRow can be nil
|
||||
if listRow != nil && listRow.IsInRect(X, Y) {
|
||||
if listRow != nil && listRow.IsInRect(x, y) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -98,9 +98,9 @@ func (s *SkillPanel) IsInRect(X int, Y int) bool {
|
|||
}
|
||||
|
||||
// GetListRowByPos returns the skill list row for a given X and Y, based on the width and height of the skills list.
|
||||
func (s *SkillPanel) GetListRowByPos(X int, Y int) *SkillListRow {
|
||||
func (s *SkillPanel) GetListRowByPos(x, y int) *SkillListRow {
|
||||
for _, listRow := range s.ListRows {
|
||||
if listRow.IsInRect(X, Y) {
|
||||
if listRow.IsInRect(x, y) {
|
||||
return listRow
|
||||
}
|
||||
}
|
||||
|
@ -115,11 +115,15 @@ func (s *SkillPanel) Render(target d2interface.Surface) error {
|
|||
}
|
||||
|
||||
if s.regenerateImageCache {
|
||||
s.generateSkillRowImageCache(target)
|
||||
if err := s.generateSkillRowImageCache(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.regenerateImageCache = false
|
||||
}
|
||||
|
||||
renderedRows := 0
|
||||
|
||||
for _, skillListRow := range s.ListRows {
|
||||
if len(skillListRow.Skills) == 0 {
|
||||
continue
|
||||
|
@ -129,7 +133,11 @@ func (s *SkillPanel) Render(target d2interface.Surface) error {
|
|||
rowOffsetY := skillPanelOffsetY - (renderedRows * skillIconHeight)
|
||||
|
||||
target.PushTranslation(startX, rowOffsetY)
|
||||
target.Render(skillListRow.cachedImage)
|
||||
|
||||
if err := target.Render(skillListRow.cachedImage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
target.Pop()
|
||||
|
||||
renderedRows++
|
||||
|
@ -137,20 +145,25 @@ func (s *SkillPanel) Render(target d2interface.Surface) error {
|
|||
|
||||
if s.hoveredSkill != nil {
|
||||
target.PushTranslation(s.hoverTooltipRect.Left, s.hoverTooltipRect.Top)
|
||||
target.DrawRect(s.hoverTooltipRect.Width, s.hoverTooltipRect.Height, color.RGBA{0, 0, 0, uint8(200)})
|
||||
|
||||
black70 := d2util.Color(blackAlpha70)
|
||||
target.DrawRect(s.hoverTooltipRect.Width, s.hoverTooltipRect.Height, black70)
|
||||
|
||||
// the text should be centered horizontally in the tooltip rect
|
||||
target.PushTranslation(s.hoverTooltipRect.Width/2, 0)
|
||||
centerX := s.hoverTooltipRect.Width >> 1
|
||||
target.PushTranslation(centerX, 0)
|
||||
s.hoverTooltipText.Render(target)
|
||||
|
||||
target.PopN(2)
|
||||
target.Pop()
|
||||
target.Pop()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegenerateImageCache will force re-generating the cached menu image on next Render.
|
||||
// Somewhat expensive operation, should not be called often. Currently called every time the panel is opened or when the player learns a new skill.
|
||||
// Somewhat expensive operation, should not be called often.
|
||||
// Currently called every time the panel is opened or when the player learns a new skill.
|
||||
func (s *SkillPanel) RegenerateImageCache() {
|
||||
s.regenerateImageCache = true
|
||||
}
|
||||
|
@ -169,7 +182,7 @@ func (s *SkillPanel) Toggle() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SkillPanel) generateSkillRowImageCache(target d2interface.Surface) error {
|
||||
func (s *SkillPanel) generateSkillRowImageCache() error {
|
||||
for idx := range s.ListRows {
|
||||
s.ListRows[idx] = &SkillListRow{Skills: make([]*d2hero.HeroSkill, 0), Rectangle: d2geom.Rectangle{Height: 0, Width: 0}}
|
||||
}
|
||||
|
@ -189,6 +202,7 @@ func (s *SkillPanel) generateSkillRowImageCache(target d2interface.Surface) erro
|
|||
}
|
||||
|
||||
visibleRows := 0
|
||||
|
||||
for idx, skillListRow := range s.ListRows {
|
||||
// row won't be considered as visible
|
||||
if len(skillListRow.Skills) == 0 {
|
||||
|
@ -202,13 +216,15 @@ func (s *SkillPanel) generateSkillRowImageCache(target d2interface.Surface) erro
|
|||
Top: skillPanelOffsetY - (visibleRows * skillIconHeight),
|
||||
}
|
||||
|
||||
skillRow := skillListRow
|
||||
|
||||
sort.SliceStable(skillListRow.Skills, func(a, b int) bool {
|
||||
// left panel skills are aligned by ID (low to high), right panel is the opposite
|
||||
if s.isLeftPanel {
|
||||
return skillListRow.Skills[a].ID < skillListRow.Skills[b].ID
|
||||
return skillRow.Skills[a].ID < skillRow.Skills[b].ID
|
||||
}
|
||||
|
||||
return skillListRow.Skills[a].ID > skillListRow.Skills[b].ID
|
||||
return skillRow.Skills[a].ID > skillRow.Skills[b].ID
|
||||
})
|
||||
|
||||
cachedImage, err := s.createSkillListImage(skillListRow)
|
||||
|
@ -234,6 +250,7 @@ func (s *SkillPanel) createSkillListImage(skillsListRow *SkillListRow) (d2interf
|
|||
|
||||
lastSkillResourcePath := d2resource.GenericSkills
|
||||
skillSprite, _ := s.ui.NewSprite(s.getSkillResourceByClass(""), d2resource.PaletteSky)
|
||||
|
||||
for idx, skill := range skillsListRow.Skills {
|
||||
currentResourcePath := s.getSkillResourceByClass(skill.Charclass)
|
||||
// only load a new sprite if the DCC file path changed
|
||||
|
@ -257,6 +274,7 @@ func (s *SkillPanel) createSkillListImage(skillsListRow *SkillListRow) (d2interf
|
|||
if err := skillSprite.Render(surface); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
surface.Pop()
|
||||
}
|
||||
|
||||
|
@ -272,38 +290,39 @@ func (s *SkillPanel) getRowStartX(skillRow *SkillListRow) int {
|
|||
return rightPanelEndX - skillRow.GetWidth()
|
||||
}
|
||||
|
||||
func (s *SkillPanel) getSkillAtPos(X int, Y int) *d2hero.HeroSkill {
|
||||
listRow := s.GetListRowByPos(X, Y)
|
||||
func (s *SkillPanel) getSkillAtPos(x, y int) *d2hero.HeroSkill {
|
||||
listRow := s.GetListRowByPos(x, y)
|
||||
|
||||
if listRow == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
skillIndex := (X - s.getRowStartX(listRow)) / skillIconWidth
|
||||
skillIndex := (x - s.getRowStartX(listRow)) / skillIconWidth
|
||||
skill := listRow.Skills[skillIndex]
|
||||
|
||||
return skill
|
||||
}
|
||||
|
||||
func (s *SkillPanel) getSkillIdxAtPos(X int, Y int) int {
|
||||
listRow := s.GetListRowByPos(X, Y)
|
||||
func (s *SkillPanel) getSkillIdxAtPos(x, y int) int {
|
||||
listRow := s.GetListRowByPos(x, y)
|
||||
|
||||
if listRow == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
skillIndex := (X - s.getRowStartX(listRow)) / skillIconWidth
|
||||
skillIndex := (x - s.getRowStartX(listRow)) / skillIconWidth
|
||||
|
||||
return skillIndex
|
||||
}
|
||||
|
||||
// HandleClick will change the hero's active(left or right) skill and return true. Returns false if the given X, Y is out of panel boundaries.
|
||||
func (s *SkillPanel) HandleClick(X int, Y int) bool {
|
||||
if !s.isOpen || !s.IsInRect(X, Y) {
|
||||
// HandleClick will change the hero's active(left or right) skill and return true.
|
||||
// Returns false if the given X, Y is out of panel boundaries.
|
||||
func (s *SkillPanel) HandleClick(x, y int) bool {
|
||||
if !s.isOpen || !s.IsInRect(x, y) {
|
||||
return false
|
||||
}
|
||||
|
||||
clickedSkill := s.getSkillAtPos(X, Y)
|
||||
clickedSkill := s.getSkillAtPos(x, y)
|
||||
|
||||
if clickedSkill == nil {
|
||||
return false
|
||||
|
@ -319,28 +338,28 @@ func (s *SkillPanel) HandleClick(X int, Y int) bool {
|
|||
}
|
||||
|
||||
// HandleMouseMove will process a mouse move event, if inside the panel.
|
||||
func (s *SkillPanel) HandleMouseMove(X int, Y int) bool {
|
||||
func (s *SkillPanel) HandleMouseMove(x, y int) bool {
|
||||
if !s.isOpen {
|
||||
return false
|
||||
}
|
||||
|
||||
if !s.IsInRect(X, Y) {
|
||||
if !s.IsInRect(x, y) {
|
||||
// panel still open but player hovered outside panel - hide the previously hovered skill(if any)
|
||||
s.hoveredSkill = nil
|
||||
return false
|
||||
}
|
||||
|
||||
previousHovered := s.hoveredSkill
|
||||
s.hoveredSkill = s.getSkillAtPos(X, Y)
|
||||
s.hoveredSkill = s.getSkillAtPos(x, y)
|
||||
|
||||
if previousHovered != s.hoveredSkill && s.hoveredSkill != nil {
|
||||
skillDescription := d2tbl.TranslateString(s.hoveredSkill.ShortKey)
|
||||
s.hoverTooltipText.SetText(fmt.Sprintf("%s\n%s", s.hoveredSkill.Skill, skillDescription))
|
||||
|
||||
listRow := s.GetListRowByPos(X, Y)
|
||||
listRow := s.GetListRowByPos(x, y)
|
||||
textWidth, textHeight := s.hoverTooltipText.GetSize()
|
||||
|
||||
tooltipX := (s.getSkillIdxAtPos(X, Y) * skillIconWidth) + s.getRowStartX(listRow)
|
||||
tooltipX := (s.getSkillIdxAtPos(x, y) * skillIconWidth) + s.getRowStartX(listRow)
|
||||
tooltipWidth := textWidth + tooltipPadLeft + tooltipPadRight
|
||||
|
||||
if tooltipX+tooltipWidth >= screenWidth {
|
||||
|
|
|
@ -15,40 +15,72 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
TabButtonX = 628
|
||||
TabButton0Y = 385
|
||||
TabButton1Y = 277
|
||||
TabButton2Y = 170
|
||||
tabButtonX = 628
|
||||
tabButton0Y = 385
|
||||
tabButton1Y = 277
|
||||
tabButton2Y = 170
|
||||
|
||||
AvailSPLabelX = 677
|
||||
AvailSPLabelY = 72
|
||||
availSPLabelX = 677
|
||||
availSPLabelY = 72
|
||||
|
||||
SkillIconXOff = 346
|
||||
SkillIconYOff = 59
|
||||
SkillIconDistX = 69
|
||||
SkillIconDistY = 68
|
||||
skillIconXOff = 346
|
||||
skillIconYOff = 59
|
||||
skillIconDistX = 69
|
||||
skillIconDistY = 68
|
||||
)
|
||||
|
||||
type SkillTreeTab struct {
|
||||
buttonText string
|
||||
button *d2ui.Button
|
||||
const (
|
||||
firstTab = iota
|
||||
secondTab
|
||||
thirdTab
|
||||
)
|
||||
|
||||
const (
|
||||
tabIndexOffset = 4
|
||||
|
||||
frameOffsetTop = 4
|
||||
frameOffsetBottom = 6
|
||||
)
|
||||
|
||||
const (
|
||||
frameCommonTabTopLeft = iota
|
||||
frameCommonTabTopRight
|
||||
frameCommonTabBottomLeft
|
||||
frameCommonTabBottomRight
|
||||
)
|
||||
|
||||
const (
|
||||
frameSelectedTab1Full = 7
|
||||
frameSelectedTab2Top = 9 // tab2 top and bottom portions are in 2 frames :(
|
||||
frameSelectedTab2Bottom = 11
|
||||
frameSelectedTab3Full = 13
|
||||
)
|
||||
|
||||
const (
|
||||
skillTreePanelX = 401
|
||||
skillTreePanelY = 64
|
||||
)
|
||||
|
||||
type skillTreeTab struct {
|
||||
buttonText string
|
||||
button *d2ui.Button
|
||||
}
|
||||
|
||||
func (st *SkillTreeTab) CreateButton(uiManager *d2ui.UIManager, x int, y int) {
|
||||
func (st *skillTreeTab) createButton(uiManager *d2ui.UIManager, x, y int) {
|
||||
st.button = uiManager.NewButton(d2ui.ButtonTypeSkillTreeTab, st.buttonText)
|
||||
st.button.SetVisible(false)
|
||||
st.button.SetPosition(x, y)
|
||||
}
|
||||
|
||||
type SkillTreeHeroTypeResources struct {
|
||||
skillIcon *d2ui.Sprite
|
||||
skillIconPath string
|
||||
skillPanel *d2ui.Sprite
|
||||
type skillTreeHeroTypeResources struct {
|
||||
skillIcon *d2ui.Sprite
|
||||
skillIconPath string
|
||||
skillPanel *d2ui.Sprite
|
||||
skillPanelPath string
|
||||
}
|
||||
|
||||
type SkillTree struct {
|
||||
resources *SkillTreeHeroTypeResources
|
||||
type skillTree struct {
|
||||
resources *skillTreeHeroTypeResources
|
||||
asset *d2asset.AssetManager
|
||||
renderer d2interface.Renderer
|
||||
guiManager *d2gui.GuiManager
|
||||
|
@ -58,187 +90,192 @@ type SkillTree struct {
|
|||
heroClass d2enum.Hero
|
||||
frame *d2ui.UIFrame
|
||||
availSPLabel *d2ui.Label
|
||||
tab [3]*SkillTreeTab
|
||||
tab [3]*skillTreeTab
|
||||
isOpen bool
|
||||
originX int
|
||||
originY int
|
||||
selectedTab int
|
||||
}
|
||||
|
||||
func NewSkillTree(
|
||||
func newSkillTree(
|
||||
skills map[int]*d2hero.HeroSkill,
|
||||
heroClass d2enum.Hero,
|
||||
heroClass d2enum.Hero,
|
||||
asset *d2asset.AssetManager,
|
||||
renderer d2interface.Renderer,
|
||||
ui *d2ui.UIManager,
|
||||
guiManager *d2gui.GuiManager,
|
||||
) *SkillTree {
|
||||
st := &SkillTree {
|
||||
skills: skills,
|
||||
heroClass: heroClass,
|
||||
asset: asset,
|
||||
renderer: renderer,
|
||||
uiManager: ui,
|
||||
) *skillTree {
|
||||
st := &skillTree{
|
||||
skills: skills,
|
||||
heroClass: heroClass,
|
||||
asset: asset,
|
||||
renderer: renderer,
|
||||
uiManager: ui,
|
||||
guiManager: guiManager,
|
||||
originX: 401,
|
||||
originY: 64,
|
||||
tab: [3]*SkillTreeTab{
|
||||
originX: skillTreePanelX,
|
||||
originY: skillTreePanelY,
|
||||
tab: [3]*skillTreeTab{
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
return st
|
||||
}
|
||||
|
||||
func (s *SkillTree) Load() {
|
||||
|
||||
func (s *skillTree) load() {
|
||||
s.frame = d2ui.NewUIFrame(s.asset, s.uiManager, d2ui.FrameRight)
|
||||
|
||||
s.setHeroTypeResourcePath()
|
||||
s.LoadForHeroType()
|
||||
s.loadForHeroType()
|
||||
s.setTab(0)
|
||||
}
|
||||
|
||||
func (s *SkillTree) LoadForHeroType() {
|
||||
func (s *skillTree) loadForHeroType() {
|
||||
sp, err := s.uiManager.NewSprite(s.resources.skillPanelPath, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
s.resources.skillPanel = sp
|
||||
|
||||
si, err := s.uiManager.NewSprite(s.resources.skillIconPath, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
s.resources.skillIcon = si
|
||||
|
||||
s.tab[0].CreateButton(s.uiManager, TabButtonX, TabButton0Y)
|
||||
s.tab[0].button.OnActivated(func() { s.setTab(0) })
|
||||
s.tab[1].CreateButton(s.uiManager, TabButtonX, TabButton1Y)
|
||||
s.tab[1].button.OnActivated(func() { s.setTab(1) })
|
||||
s.tab[2].CreateButton(s.uiManager, TabButtonX, TabButton2Y)
|
||||
s.tab[2].button.OnActivated(func() { s.setTab(2) })
|
||||
s.tab[firstTab].createButton(s.uiManager, tabButtonX, tabButton0Y)
|
||||
s.tab[firstTab].button.OnActivated(func() { s.setTab(firstTab) })
|
||||
|
||||
s.tab[secondTab].createButton(s.uiManager, tabButtonX, tabButton1Y)
|
||||
s.tab[secondTab].button.OnActivated(func() { s.setTab(secondTab) })
|
||||
|
||||
s.tab[thirdTab].createButton(s.uiManager, tabButtonX, tabButton2Y)
|
||||
s.tab[thirdTab].button.OnActivated(func() { s.setTab(thirdTab) })
|
||||
|
||||
s.availSPLabel = s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky)
|
||||
s.availSPLabel.SetPosition(AvailSPLabelX, AvailSPLabelY)
|
||||
s.availSPLabel.SetPosition(availSPLabelX, availSPLabelY)
|
||||
s.availSPLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
s.availSPLabel.SetText(fmt.Sprintf("%s\n%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree1"),
|
||||
d2tbl.TranslateString("StrSklTree2"),
|
||||
d2tbl.TranslateString("StrSklTree3"),
|
||||
))
|
||||
s.availSPLabel.SetText(makeTabString("StrSklTree1", "StrSklTree2", "StrSklTree3"))
|
||||
}
|
||||
|
||||
func (s *SkillTree) setHeroTypeResourcePath() {
|
||||
var res *SkillTreeHeroTypeResources
|
||||
type heroTabData struct {
|
||||
resources *skillTreeHeroTypeResources
|
||||
str1, str2, str3 string
|
||||
}
|
||||
|
||||
switch s.heroClass {
|
||||
case d2enum.HeroBarbarian:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelBarbarian,
|
||||
skillIconPath: d2resource.BarbarianSkills,
|
||||
func makeTabString(keys ...interface{}) string {
|
||||
translations := make([]interface{}, len(keys))
|
||||
|
||||
token := "%s"
|
||||
format := token
|
||||
|
||||
for idx, key := range keys {
|
||||
if idx > 0 {
|
||||
format += "\n" + token
|
||||
}
|
||||
|
||||
s.tab[0].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree21"),
|
||||
d2tbl.TranslateString("StrSklTree4"))
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree21"),
|
||||
d2tbl.TranslateString("StrSklTree22"))
|
||||
s.tab[2].buttonText = d2tbl.TranslateString("StrSklTree20")
|
||||
|
||||
case d2enum.HeroNecromancer:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelNecromancer,
|
||||
skillIconPath: d2resource.NecromancerSkills,
|
||||
}
|
||||
|
||||
s.tab[0].buttonText = d2tbl.TranslateString("StrSklTree19")
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree17"),
|
||||
d2tbl.TranslateString("StrSklTree18"),
|
||||
d2tbl.TranslateString("StrSklTree5"))
|
||||
s.tab[2].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree16"),
|
||||
d2tbl.TranslateString("StrSklTree5"))
|
||||
case d2enum.HeroPaladin:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelPaladin,
|
||||
skillIconPath: d2resource.PaladinSkills,
|
||||
}
|
||||
|
||||
s.tab[0].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree15"),
|
||||
d2tbl.TranslateString("StrSklTree4"))
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree14"),
|
||||
d2tbl.TranslateString("StrSklTree13"))
|
||||
s.tab[2].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree12"),
|
||||
d2tbl.TranslateString("StrSklTree13"))
|
||||
case d2enum.HeroAssassin:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelAssassin,
|
||||
skillIconPath: d2resource.AssassinSkills,
|
||||
}
|
||||
|
||||
s.tab[0].buttonText = d2tbl.TranslateString("StrSklTree30")
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree31"),
|
||||
d2tbl.TranslateString("StrSklTree32"))
|
||||
s.tab[2].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree33"),
|
||||
d2tbl.TranslateString("StrSklTree34"))
|
||||
case d2enum.HeroSorceress:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelSorcerer,
|
||||
skillIconPath: d2resource.SorcererSkills,
|
||||
}
|
||||
s.tab[0].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree25"),
|
||||
d2tbl.TranslateString("StrSklTree5"))
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree24"),
|
||||
d2tbl.TranslateString("StrSklTree5"))
|
||||
s.tab[2].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree23"),
|
||||
d2tbl.TranslateString("StrSklTree5"))
|
||||
case d2enum.HeroAmazon:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelAmazon,
|
||||
skillIconPath: d2resource.AmazonSkills,
|
||||
}
|
||||
s.tab[0].buttonText = fmt.Sprintf("%s\n%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree10"),
|
||||
d2tbl.TranslateString("StrSklTree11"),
|
||||
d2tbl.TranslateString("StrSklTree4"))
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree8"),
|
||||
d2tbl.TranslateString("StrSklTree9"),
|
||||
d2tbl.TranslateString("StrSklTree4"))
|
||||
s.tab[2].buttonText = fmt.Sprintf("%s\n%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree6"),
|
||||
d2tbl.TranslateString("StrSklTree7"),
|
||||
d2tbl.TranslateString("StrSklTree4"))
|
||||
case d2enum.HeroDruid:
|
||||
res = &SkillTreeHeroTypeResources {
|
||||
skillPanelPath: d2resource.SkillsPanelDruid,
|
||||
skillIconPath: d2resource.DruidSkills,
|
||||
}
|
||||
s.tab[0].buttonText = d2tbl.TranslateString("StrSklTree26")
|
||||
s.tab[1].buttonText = fmt.Sprintf("%s\n%s",
|
||||
d2tbl.TranslateString("StrSklTree27"),
|
||||
d2tbl.TranslateString("StrSklTree28"))
|
||||
s.tab[2].buttonText = d2tbl.TranslateString("StrSklTree29")
|
||||
default:
|
||||
log.Fatal("Unknown Hero Type")
|
||||
translations[idx] = d2tbl.TranslateString(key.(string))
|
||||
}
|
||||
s.resources = res
|
||||
|
||||
return fmt.Sprintf(format, translations...)
|
||||
}
|
||||
|
||||
func (s *SkillTree) Toggle() {
|
||||
func (s *skillTree) getTab(class d2enum.Hero) (heroTabData, bool) {
|
||||
tabMap := map[d2enum.Hero]heroTabData{
|
||||
d2enum.HeroBarbarian: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelBarbarian,
|
||||
skillIconPath: d2resource.BarbarianSkills,
|
||||
},
|
||||
makeTabString("StrSklTree21", "StrSklTree4"),
|
||||
makeTabString("StrSklTree21", "StrSklTree22"),
|
||||
makeTabString("StrSklTree20"),
|
||||
},
|
||||
d2enum.HeroNecromancer: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelNecromancer,
|
||||
skillIconPath: d2resource.NecromancerSkills,
|
||||
},
|
||||
makeTabString("StrSklTree19"),
|
||||
makeTabString("StrSklTree17", "StrSklTree18", "StrSklTree5"),
|
||||
makeTabString("StrSklTree16", "StrSklTree5"),
|
||||
},
|
||||
d2enum.HeroPaladin: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelPaladin,
|
||||
skillIconPath: d2resource.PaladinSkills,
|
||||
},
|
||||
makeTabString("StrSklTree15", "StrSklTree4"),
|
||||
makeTabString("StrSklTree14", "StrSklTree13"),
|
||||
makeTabString("StrSklTree12", "StrSklTree13"),
|
||||
},
|
||||
|
||||
d2enum.HeroAssassin: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelAssassin,
|
||||
skillIconPath: d2resource.AssassinSkills,
|
||||
},
|
||||
|
||||
makeTabString("StrSklTree30"),
|
||||
makeTabString("StrSklTree31", "StrSklTree32"),
|
||||
makeTabString("StrSklTree33", "StrSklTree34"),
|
||||
},
|
||||
d2enum.HeroSorceress: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelSorcerer,
|
||||
skillIconPath: d2resource.SorcererSkills,
|
||||
},
|
||||
makeTabString("StrSklTree25", "StrSklTree5"),
|
||||
makeTabString("StrSklTree24", "StrSklTree5"),
|
||||
makeTabString("StrSklTree23", "StrSklTree5"),
|
||||
},
|
||||
|
||||
d2enum.HeroAmazon: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelAmazon,
|
||||
skillIconPath: d2resource.AmazonSkills,
|
||||
},
|
||||
makeTabString("StrSklTree10", "StrSklTree11", "StrSklTree4"),
|
||||
makeTabString("StrSklTree8", "StrSklTree9", "StrSklTree4"),
|
||||
makeTabString("StrSklTree6", "StrSklTree7", "StrSklTree4"),
|
||||
},
|
||||
|
||||
d2enum.HeroDruid: {
|
||||
&skillTreeHeroTypeResources{
|
||||
skillPanelPath: d2resource.SkillsPanelDruid,
|
||||
skillIconPath: d2resource.DruidSkills,
|
||||
},
|
||||
makeTabString("StrSklTree26"),
|
||||
makeTabString("StrSklTree27", "StrSklTree28"),
|
||||
makeTabString("StrSklTree29"),
|
||||
},
|
||||
}
|
||||
|
||||
entry, found := tabMap[class]
|
||||
|
||||
return entry, found
|
||||
}
|
||||
|
||||
func (s *skillTree) setHeroTypeResourcePath() {
|
||||
entry, found := s.getTab(s.heroClass)
|
||||
if !found {
|
||||
log.Fatal("Unknown Hero Type")
|
||||
}
|
||||
|
||||
s.resources = entry.resources
|
||||
s.tab[firstTab].buttonText = entry.str1
|
||||
s.tab[secondTab].buttonText = entry.str1
|
||||
s.tab[thirdTab].buttonText = entry.str1
|
||||
}
|
||||
|
||||
// Toggle the skill tree visibility
|
||||
func (s *skillTree) Toggle() {
|
||||
fmt.Println("SkillTree toggled")
|
||||
|
||||
if s.isOpen {
|
||||
s.Close()
|
||||
} else {
|
||||
|
@ -246,170 +283,219 @@ func (s *SkillTree) Toggle() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SkillTree) Close() {
|
||||
// Close the skill tree
|
||||
func (s *skillTree) Close() {
|
||||
s.isOpen = false
|
||||
s.guiManager.SetLayout(nil)
|
||||
for i:=0; i < 3; i++ {
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
s.tab[i].button.SetVisible(false)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SkillTree) Open() {
|
||||
// Open the skill tree
|
||||
func (s *skillTree) Open() {
|
||||
s.isOpen = true
|
||||
if s.layout == nil {
|
||||
s.layout = d2gui.CreateLayout(s.renderer, d2gui.PositionTypeHorizontal, s.asset)
|
||||
}
|
||||
|
||||
for i:=0; i < 3; i++ {
|
||||
for i := 0; i < 3; i++ {
|
||||
s.tab[i].button.SetVisible(true)
|
||||
}
|
||||
s.guiManager.SetLayout(s.layout)
|
||||
|
||||
s.guiManager.SetLayout(s.layout)
|
||||
}
|
||||
|
||||
func (s *SkillTree) IsOpen() bool {
|
||||
func (s *skillTree) IsOpen() bool {
|
||||
return s.isOpen
|
||||
}
|
||||
|
||||
func (s *SkillTree) setTab(tab int) {
|
||||
func (s *skillTree) setTab(tab int) {
|
||||
s.selectedTab = tab
|
||||
}
|
||||
|
||||
func (s *SkillTree) renderPanelSegment(
|
||||
func (s *skillTree) renderPanelSegment(
|
||||
target d2interface.Surface,
|
||||
frame int) error {
|
||||
if err := s.resources.skillPanel.SetCurrentFrame(frame); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.resources.skillPanel.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SkillTree) renderTabCommon (target d2interface.Surface) error {
|
||||
func (s *skillTree) renderTabCommon(target d2interface.Surface) error {
|
||||
skillPanel := s.resources.skillPanel
|
||||
x, y := s.originX, s.originY
|
||||
|
||||
// top
|
||||
w, h, err := skillPanel.GetFrameSize(0)
|
||||
w, h, err := skillPanel.GetFrameSize(frameCommonTabTopLeft)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
y += h
|
||||
|
||||
skillPanel.SetPosition(x, y)
|
||||
if err:= s.renderPanelSegment(target, 0); err != nil {
|
||||
|
||||
err = s.renderPanelSegment(target, frameCommonTabTopLeft)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
skillPanel.SetPosition(x+w, y)
|
||||
if err:= s.renderPanelSegment(target, 1); err != nil {
|
||||
|
||||
err = s.renderPanelSegment(target, frameCommonTabTopRight)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// bottom
|
||||
_, h, err = skillPanel.GetFrameSize(2)
|
||||
_, h, err = skillPanel.GetFrameSize(frameCommonTabBottomLeft)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
y += h
|
||||
|
||||
skillPanel.SetPosition(x, y)
|
||||
if err:= s.renderPanelSegment(target, 2); err != nil {
|
||||
|
||||
err = s.renderPanelSegment(target, frameCommonTabBottomLeft)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
skillPanel.SetPosition(x+w, y)
|
||||
if err:= s.renderPanelSegment(target, 3); err != nil {
|
||||
|
||||
err = s.renderPanelSegment(target, frameCommonTabBottomRight)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// available skill points label
|
||||
s.availSPLabel.Render(target)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SkillTree) renderTab (target d2interface.Surface, tab int) error {
|
||||
var frameID [2]int
|
||||
|
||||
frameID[0] = 4 + (4*tab)
|
||||
frameID[1] = 6 + (4*tab)
|
||||
func (s *skillTree) renderTab(target d2interface.Surface, tab int) error {
|
||||
topFrame := frameOffsetTop + (tabIndexOffset * tab)
|
||||
bottomFrame := frameOffsetBottom + (tabIndexOffset * tab)
|
||||
|
||||
skillPanel := s.resources.skillPanel
|
||||
x, y := s.originX, s.originY
|
||||
|
||||
// top
|
||||
_, h0, err := skillPanel.GetFrameSize(frameID[0])
|
||||
_, h0, err := skillPanel.GetFrameSize(topFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
y += h0
|
||||
|
||||
skillPanel.SetPosition(x, y)
|
||||
if err:= s.renderPanelSegment(target, frameID[0]); err != nil {
|
||||
|
||||
err = s.renderPanelSegment(target, topFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// bottom
|
||||
w, h1, err := skillPanel.GetFrameSize(frameID[1])
|
||||
w, h1, err := skillPanel.GetFrameSize(bottomFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
skillPanel.SetPosition(x, y+h1)
|
||||
if err:= s.renderPanelSegment(target, frameID[1]); err != nil {
|
||||
|
||||
if err := s.renderPanelSegment(target, bottomFrame); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// tab button highlighted
|
||||
switch tab {
|
||||
case 0:
|
||||
case firstTab:
|
||||
skillPanel.SetPosition(x+w, y+h1)
|
||||
if err:= s.renderPanelSegment(target, 7); err != nil {
|
||||
|
||||
if err := s.renderPanelSegment(target, frameSelectedTab1Full); err != nil {
|
||||
return err
|
||||
}
|
||||
case 1:
|
||||
case secondTab:
|
||||
x += w
|
||||
skillPanel.SetPosition(x, s.originY + h0)
|
||||
if err:= s.renderPanelSegment(target, 9); err != nil {
|
||||
skillPanel.SetPosition(x, s.originY+h0)
|
||||
|
||||
if err := s.renderPanelSegment(target, frameSelectedTab2Top); err != nil {
|
||||
return err
|
||||
}
|
||||
skillPanel.SetPosition(x, y + h1)
|
||||
if err:= s.renderPanelSegment(target, 11); err != nil {
|
||||
|
||||
skillPanel.SetPosition(x, y+h1)
|
||||
|
||||
if err := s.renderPanelSegment(target, frameSelectedTab2Bottom); err != nil {
|
||||
return err
|
||||
}
|
||||
case 2:
|
||||
case thirdTab:
|
||||
skillPanel.SetPosition(x+w, y)
|
||||
if err:= s.renderPanelSegment(target, 13); err != nil {
|
||||
|
||||
if err := s.renderPanelSegment(target, frameSelectedTab3Full); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SkillTree) renderSkillIcons(target d2interface.Surface, tab int) error {
|
||||
|
||||
func (s *skillTree) renderSkillIcons(target d2interface.Surface, tab int) error {
|
||||
skillIcon := s.resources.skillIcon
|
||||
for idx:=range s.skills {
|
||||
|
||||
for idx := range s.skills {
|
||||
skill := s.skills[idx]
|
||||
if skill.SkillPage != tab + 1 {
|
||||
if skill.SkillPage != tab+1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := skillIcon.SetCurrentFrame(skill.IconCel); err != nil {
|
||||
return err
|
||||
}
|
||||
skillIcon.SetPosition(SkillIconXOff + skill.SkillColumn * SkillIconDistX, SkillIconYOff + skill.SkillRow * SkillIconDistY)
|
||||
|
||||
x := skillIconXOff + skill.SkillColumn*skillIconDistX
|
||||
y := skillIconYOff + skill.SkillRow*skillIconDistY
|
||||
|
||||
skillIcon.SetPosition(x, y)
|
||||
|
||||
if err := skillIcon.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return nil
|
||||
}
|
||||
func (s *SkillTree) Render (target d2interface.Surface) error {
|
||||
|
||||
// Render the skill tree panel
|
||||
func (s *skillTree) Render(target d2interface.Surface) error {
|
||||
if !s.isOpen {
|
||||
return nil
|
||||
}
|
||||
s.frame.Render(target)
|
||||
s.renderTabCommon(target)
|
||||
s.renderTab(target, s.selectedTab)
|
||||
s.renderSkillIcons(target, s.selectedTab)
|
||||
|
||||
if err := s.frame.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.renderTabCommon(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.renderTab(target, s.selectedTab); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.renderSkillIcons(target, s.selectedTab); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue