mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-02 22:57:04 -05:00
0a78a1adcc
The split between d2ui and d2asset Font version caused incorrect caching between the two. After looking at d2interface.Font, I saw the d2asset was the most recent and more tightly and cleanly packaged. I therefore removed the old d2ui.Font and embedded the d2asset version in the d2ui.Label and d2ui.Button. Looking at the code of d2ui, it would be logical to completly swap it for their d2gui version. But at least for the moment, the d2ui.Button as more functionality since it embeds a Label (instead of a font), and this label now has multiline horizontal alignement.
289 lines
9.0 KiB
Go
289 lines
9.0 KiB
Go
package d2player
|
|
|
|
import (
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
|
"strconv"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
|
)
|
|
|
|
type PanelText struct {
|
|
X int
|
|
Y int
|
|
Height int
|
|
Text string
|
|
Font string
|
|
AlignCenter bool
|
|
}
|
|
|
|
type StatsPanelLabels struct {
|
|
Level d2ui.Label
|
|
Experience d2ui.Label
|
|
NextLevelExp d2ui.Label
|
|
Strength d2ui.Label
|
|
Dexterity d2ui.Label
|
|
Vitality d2ui.Label
|
|
Energy d2ui.Label
|
|
Health d2ui.Label
|
|
MaxHealth d2ui.Label
|
|
Mana d2ui.Label
|
|
MaxMana d2ui.Label
|
|
MaxStamina d2ui.Label
|
|
Stamina d2ui.Label
|
|
}
|
|
|
|
var StaticTextLabels = []PanelText{
|
|
{X: 110, Y: 100, Text: "Level", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 200, Y: 100, Text: "Experience", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 330, Y: 100, Text: "Next Level", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 100, Y: 150, Text: "Strength", Font: d2resource.Font6},
|
|
{X: 100, Y: 213, Text: "Dexterity", Font: d2resource.Font6},
|
|
{X: 100, Y: 300, Text: "Vitality", Font: d2resource.Font6},
|
|
{X: 100, Y: 360, Text: "Energy", Font: d2resource.Font6},
|
|
{X: 280, Y: 260, Text: "Defense", Font: d2resource.Font6},
|
|
{X: 280, Y: 300, Text: "Stamina", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 280, Y: 322, Text: "Life", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 280, Y: 360, Text: "Mana", Font: d2resource.Font6, AlignCenter: true},
|
|
|
|
// can't use "Fire\nResistance" because line spacing is too big and breaks the layout
|
|
{X: 310, Y: 395, Text: "Fire", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 310, Y: 402, Text: "Resistance", Font: d2resource.Font6, AlignCenter: true},
|
|
|
|
{X: 310, Y: 420, Text: "Cold", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 310, Y: 427, Text: "Resistance", Font: d2resource.Font6, AlignCenter: true},
|
|
|
|
{X: 310, Y: 445, Text: "Lightning", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 310, Y: 452, Text: "Resistance", Font: d2resource.Font6, AlignCenter: true},
|
|
|
|
{X: 310, Y: 468, Text: "Poison", Font: d2resource.Font6, AlignCenter: true},
|
|
{X: 310, Y: 477, Text: "Resistance", Font: d2resource.Font6, AlignCenter: true},
|
|
}
|
|
|
|
// stores all the labels that can change during gameplay(e.g. current level, current hp, mana, etc.)
|
|
var StatValueLabels = make([]d2ui.Label, 13)
|
|
|
|
type HeroStatsPanel struct {
|
|
frame *d2ui.Sprite
|
|
panel *d2ui.Sprite
|
|
heroState *d2hero.HeroStatsState
|
|
heroName string
|
|
heroClass d2enum.Hero
|
|
renderer d2interface.Renderer
|
|
staticMenuImageCache *d2interface.Surface
|
|
labels *StatsPanelLabels
|
|
|
|
originX int
|
|
originY int
|
|
isOpen bool
|
|
}
|
|
|
|
func NewHeroStatsPanel(renderer d2interface.Renderer, heroName string, heroClass d2enum.Hero,
|
|
heroState d2hero.HeroStatsState) *HeroStatsPanel {
|
|
originX := 0
|
|
originY := 0
|
|
|
|
return &HeroStatsPanel{
|
|
renderer: renderer,
|
|
originX: originX,
|
|
originY: originY,
|
|
heroState: &heroState,
|
|
heroName: heroName,
|
|
heroClass: heroClass,
|
|
labels: &StatsPanelLabels{},
|
|
}
|
|
}
|
|
|
|
func (s *HeroStatsPanel) Load() {
|
|
animation, _ := d2asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky)
|
|
s.frame, _ = d2ui.LoadSprite(animation)
|
|
animation, _ = d2asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
|
|
s.panel, _ = d2ui.LoadSprite(animation)
|
|
s.initStatValueLabels()
|
|
}
|
|
|
|
func (s *HeroStatsPanel) IsOpen() bool {
|
|
return s.isOpen
|
|
}
|
|
|
|
func (s *HeroStatsPanel) Toggle() {
|
|
s.isOpen = !s.isOpen
|
|
}
|
|
|
|
func (s *HeroStatsPanel) Open() {
|
|
s.isOpen = true
|
|
}
|
|
|
|
func (s *HeroStatsPanel) Close() {
|
|
s.isOpen = false
|
|
}
|
|
|
|
func (s *HeroStatsPanel) Render(target d2interface.Surface) {
|
|
if !s.isOpen {
|
|
return
|
|
}
|
|
|
|
if s.staticMenuImageCache == nil {
|
|
frameWidth, frameHeight := s.frame.GetFrameBounds()
|
|
framesCount := s.frame.GetFrameCount()
|
|
surface, err := s.renderer.NewSurface(frameWidth*framesCount, frameHeight*framesCount, d2enum.FilterNearest)
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
s.staticMenuImageCache = &surface
|
|
s.renderStaticMenu(*s.staticMenuImageCache)
|
|
}
|
|
target.Render(*s.staticMenuImageCache)
|
|
s.renderStatValues(target)
|
|
}
|
|
|
|
func (s *HeroStatsPanel) renderStaticMenu(target d2interface.Surface) {
|
|
x, y := s.originX, s.originY
|
|
|
|
// Frame
|
|
// Top left
|
|
s.frame.SetCurrentFrame(0)
|
|
w, h := s.frame.GetCurrentFrameSize()
|
|
s.frame.SetPosition(x, y+h)
|
|
s.frame.Render(target)
|
|
x += w
|
|
y += h
|
|
|
|
// Top right
|
|
s.frame.SetCurrentFrame(1)
|
|
w, h = s.frame.GetCurrentFrameSize()
|
|
s.frame.SetPosition(x, s.originY+h)
|
|
s.frame.Render(target)
|
|
x = s.originX
|
|
|
|
// Right
|
|
s.frame.SetCurrentFrame(2)
|
|
w, h = s.frame.GetCurrentFrameSize()
|
|
s.frame.SetPosition(x, y+h)
|
|
s.frame.Render(target)
|
|
y += h
|
|
|
|
// Bottom left
|
|
s.frame.SetCurrentFrame(3)
|
|
w, h = s.frame.GetCurrentFrameSize()
|
|
s.frame.SetPosition(x, y+h)
|
|
s.frame.Render(target)
|
|
x += w
|
|
|
|
// Bottom right
|
|
s.frame.SetCurrentFrame(4)
|
|
w, h = s.frame.GetCurrentFrameSize()
|
|
s.frame.SetPosition(x, y+h)
|
|
s.frame.Render(target)
|
|
|
|
x, y = s.originX, s.originY
|
|
y += 64
|
|
x += 80
|
|
|
|
// Panel
|
|
// Top left
|
|
s.panel.SetCurrentFrame(0)
|
|
w, h = s.panel.GetCurrentFrameSize()
|
|
s.panel.SetPosition(x, y+h)
|
|
s.panel.Render(target)
|
|
x += w
|
|
|
|
// Top right
|
|
s.panel.SetCurrentFrame(1)
|
|
w, h = s.panel.GetCurrentFrameSize()
|
|
s.panel.SetPosition(x, y+h)
|
|
s.panel.Render(target)
|
|
y += h
|
|
|
|
// Bottom right
|
|
s.panel.SetCurrentFrame(3)
|
|
w, h = s.panel.GetCurrentFrameSize()
|
|
s.panel.SetPosition(x, y+h)
|
|
s.panel.Render(target)
|
|
|
|
// Bottom left
|
|
s.panel.SetCurrentFrame(2)
|
|
w, h = s.panel.GetCurrentFrameSize()
|
|
s.panel.SetPosition(x-w, y+h)
|
|
s.panel.Render(target)
|
|
|
|
var label d2ui.Label
|
|
// all static labels are not stored since we use them only once to generate the image cache
|
|
for _, textElement := range StaticTextLabels {
|
|
label = s.createTextLabel(textElement)
|
|
label.Render(target)
|
|
}
|
|
// hero name and class are part of the static image cache since they don't change after we enter the world
|
|
label = s.createTextLabel(PanelText{X: 165, Y: 72, Text: s.heroName, Font: d2resource.Font16, AlignCenter: true})
|
|
label.Render(target)
|
|
label = s.createTextLabel(PanelText{X: 330, Y: 72, Text: s.heroClass.String(), Font: d2resource.Font16, AlignCenter: true})
|
|
label.Render(target)
|
|
}
|
|
|
|
func (s *HeroStatsPanel) initStatValueLabels() {
|
|
s.labels.Level = s.createStatValueLabel(s.heroState.Level, 112, 110)
|
|
s.labels.Experience = s.createStatValueLabel(s.heroState.Experience, 200, 110)
|
|
s.labels.NextLevelExp = s.createStatValueLabel(s.heroState.NextLevelExp, 330, 110)
|
|
|
|
s.labels.Strength = s.createStatValueLabel(s.heroState.Strength, 175, 147)
|
|
s.labels.Dexterity = s.createStatValueLabel(s.heroState.Dexterity, 175, 207)
|
|
s.labels.Vitality = s.createStatValueLabel(s.heroState.Vitality, 175, 295)
|
|
s.labels.Energy = s.createStatValueLabel(s.heroState.Energy, 175, 355)
|
|
|
|
s.labels.MaxStamina = s.createStatValueLabel(s.heroState.MaxStamina, 330, 295)
|
|
s.labels.Stamina = s.createStatValueLabel(s.heroState.Stamina, 370, 295)
|
|
|
|
s.labels.MaxHealth = s.createStatValueLabel(s.heroState.MaxHealth, 330, 320)
|
|
s.labels.Health = s.createStatValueLabel(s.heroState.Health, 370, 320)
|
|
|
|
s.labels.MaxMana = s.createStatValueLabel(s.heroState.MaxMana, 330, 355)
|
|
s.labels.Mana = s.createStatValueLabel(s.heroState.Mana, 370, 355)
|
|
}
|
|
|
|
func (s *HeroStatsPanel) renderStatValues(target d2interface.Surface) {
|
|
s.renderStatValueNum(s.labels.Level, s.heroState.Level, target)
|
|
s.renderStatValueNum(s.labels.Experience, s.heroState.Experience, target)
|
|
s.renderStatValueNum(s.labels.NextLevelExp, s.heroState.NextLevelExp, target)
|
|
|
|
s.renderStatValueNum(s.labels.Strength, s.heroState.Strength, target)
|
|
s.renderStatValueNum(s.labels.Dexterity, s.heroState.Dexterity, target)
|
|
s.renderStatValueNum(s.labels.Vitality, s.heroState.Vitality, target)
|
|
s.renderStatValueNum(s.labels.Energy, s.heroState.Energy, target)
|
|
|
|
s.renderStatValueNum(s.labels.MaxHealth, s.heroState.MaxHealth, target)
|
|
s.renderStatValueNum(s.labels.Health, s.heroState.Health, target)
|
|
|
|
s.renderStatValueNum(s.labels.MaxStamina, s.heroState.MaxStamina, target)
|
|
s.renderStatValueNum(s.labels.Stamina, s.heroState.Stamina, target)
|
|
|
|
s.renderStatValueNum(s.labels.MaxMana, s.heroState.MaxMana, target)
|
|
s.renderStatValueNum(s.labels.Mana, s.heroState.Mana, target)
|
|
}
|
|
|
|
func (s *HeroStatsPanel) renderStatValueNum(label d2ui.Label, value int, target d2interface.Surface) {
|
|
label.SetText(strconv.Itoa(value))
|
|
label.Render(target)
|
|
}
|
|
|
|
func (s *HeroStatsPanel) createStatValueLabel(stat int, x int, y int) d2ui.Label {
|
|
text := strconv.Itoa(stat)
|
|
return s.createTextLabel(PanelText{X: x, Y: y, Text: text, Font: d2resource.Font16, AlignCenter: true})
|
|
}
|
|
|
|
func (s *HeroStatsPanel) createTextLabel(element PanelText) d2ui.Label {
|
|
label := d2ui.CreateLabel(element.Font, d2resource.PaletteStatic)
|
|
if element.AlignCenter {
|
|
label.Alignment = d2gui.HorizontalAlignCenter
|
|
}
|
|
|
|
label.SetText(element.Text)
|
|
label.SetPosition(element.X, element.Y)
|
|
return label
|
|
}
|