1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-18 02:16:23 -05:00
OpenDiablo2/d2game/d2player/help/help.go

412 lines
8.0 KiB
Go
Raw Normal View History

package help
import (
"fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
const (
tlCornerFrame = iota
lFrame
tFrameLHalf
tFrameRHalf
trCornerFrameTHalf
trCornerFrameRHalf
rFrame
)
// Overlay represents the in-game overlay that toggles visibility when the h key is pressed
type Overlay struct {
asset *d2asset.AssetManager
isOpen bool
renderer d2interface.Renderer
frames []*d2ui.Sprite
text []*d2ui.Label
lines []line
uiManager *d2ui.UIManager
originX int
originY int
layout *d2gui.Layout
closeButton *d2ui.Button
guiManager *d2gui.GuiManager
}
func NewHelpOverlay(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
) *Overlay {
h := &Overlay{
asset: asset,
renderer: renderer,
uiManager: ui,
guiManager: guiManager,
}
return h
}
func (h *Overlay) onMouseDown() {
// If mouse over close button
// close()
}
func (h *Overlay) Toggle() {
fmt.Print("Help overlay toggled\n")
if h.isOpen {
h.close()
} else {
h.open()
}
}
func (h *Overlay) close() {
h.isOpen = false
h.closeButton.SetVisible(false)
h.guiManager.SetLayout(nil)
}
func (h *Overlay) open() {
h.isOpen = true
if h.layout == nil {
h.layout = d2gui.CreateLayout(h.renderer, d2gui.PositionTypeHorizontal, h.asset)
}
h.closeButton.SetVisible(true)
h.closeButton.SetPressed(false)
h.guiManager.SetLayout(h.layout)
}
func (h *Overlay) IsOpen() bool {
return h.isOpen
}
func (h *Overlay) IsInRect(px, py int) bool {
ww, hh := h.closeButton.GetSize()
x, y := h.closeButton.GetPosition()
if px >= x && px <= x+ww && py >= y && py <= y+hh {
return true
}
return false
}
func (h *Overlay) Load() {
var (
x = 0
y = 0
prevX = 0
prevY = 0
)
for frameIndex := 0; frameIndex < 7; frameIndex++ {
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
f, _ := h.uiManager.NewSprite(d2resource.HelpBorder, d2resource.PaletteSky)
_ = f.SetCurrentFrame(frameIndex)
ww, hh := f.GetCurrentFrameSize()
//fmt.Printf("Help frame %d size: %d, %d\n", frameIndex, ww, hh)
switch frameIndex {
case tlCornerFrame:
y = hh
case lFrame:
y = hh + prevY
case tFrameLHalf:
y = hh
x = 65
case tFrameRHalf:
y = hh
x = 800 - ww - 245
case trCornerFrameTHalf:
y = hh
x = 800 - ww - 20
case trCornerFrameRHalf:
y = hh
x = 800 - ww
case rFrame:
y = hh + prevY
x = 800 - ww
}
//y += 50
_ = prevX
prevX = x
prevY = y
f.SetPosition(x, y)
h.frames = append(h.frames, f)
}
// Title
text := "Diablo II Help"
newLabel := h.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky)
newLabel.SetText(text)
ww, _ := newLabel.GetSize()
newLabel.SetPosition((800/2)-(ww/2)-30, 0)
h.text = append(h.text, newLabel)
// Close
h.closeButton = h.uiManager.NewButton(d2ui.ButtonTypeSquareClose, "")
h.closeButton.SetPosition(685, 25)
h.closeButton.SetVisible(false)
h.closeButton.OnActivated(func() { h.close() })
newLabel = h.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky)
newLabel.SetText("Close")
newLabel.SetPosition(680, 60)
h.text = append(h.text, newLabel)
// Bullets
yOffset := 60
h.createBullet(callout{
LabelText: "Hold Down <Ctrl> to Run",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Hold down <Alt> to highlight items on the ground",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Hold down <Shift> to attack while standing still",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Hit <Tab> to toggle the automap on and off",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Hit <Esc> to bring up the Game Menu",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Hit <Enter> to go into chat mode",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Use F1-F8 to set your Left or Right Mouse Button Skills",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
yOffset += 12
h.createBullet(callout{
LabelText: "Hit <H> to toggle this screen open and closed",
LabelX: 100,
LabelY: yOffset,
DotX: 100 - 12,
DotY: yOffset,
})
// Callouts
h.createCallout(callout{
LabelText: "New Stats",
LabelX: 220,
LabelY: 350,
DotX: 215,
DotY: 575,
})
h.createCallout(callout{
LabelText: "New Skill",
LabelX: 575,
LabelY: 350,
DotX: 570,
DotY: 575,
})
h.createCallout(callout{
LabelText: "Left Mouse-\nButton Skill\n(Click to Change)",
LabelX: 135,
LabelY: 380,
DotX: 130,
DotY: 565,
})
h.createCallout(callout{
LabelText: "Mini-Panel\n(Opens Character,\ninventory, and\nother screens)",
LabelX: 450,
LabelY: 365,
DotX: 445,
DotY: 540,
})
h.createCallout(callout{
LabelText: "Right Mouse-\nButton Skill\n(Click to Change)",
LabelX: 675,
LabelY: 375,
DotX: 670,
DotY: 560,
})
h.createCallout(callout{
LabelText: "Life Orb",
LabelX: 65,
LabelY: 460,
DotX: 60,
DotY: 535,
})
h.createCallout(callout{
LabelText: "Stamina Bar",
LabelX: 315,
LabelY: 460,
DotX: 310,
DotY: 585,
})
h.createCallout(callout{
LabelText: "Mana Orb",
LabelX: 745,
LabelY: 460,
DotX: 740,
DotY: 535,
})
h.createCallout(callout{
LabelText: "Run/Walk\nToggle",
LabelX: 263,
LabelY: 480,
DotX: 258,
DotY: 585,
})
h.createCallout(callout{
LabelText: "Experience\nBar",
LabelX: 370,
LabelY: 480,
DotX: 365,
DotY: 565,
})
h.createCallout(callout{
LabelText: "Belt",
LabelX: 535,
LabelY: 490,
DotX: 530,
DotY: 568,
})
}
type line struct {
StartX int
StartY int
MoveX int
MoveY int
Color color.Color
}
type callout struct {
LabelText string
LabelX int
LabelY int
DotX int
DotY int
}
func (h *Overlay) createBullet(c callout) {
newLabel := h.uiManager.NewLabel(d2resource.FontFormal11, d2resource.PaletteSky)
newLabel.SetText(c.LabelText)
//ww, hh = newLabel.GetSize()
newLabel.SetPosition(c.LabelX, c.LabelY)
h.text = append(h.text, newLabel)
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
newDot, _ := h.uiManager.NewSprite(d2resource.HelpYellowBullet, d2resource.PaletteSky)
_ = newDot.SetCurrentFrame(0)
newDot.SetPosition(c.DotX, c.DotY+14)
h.frames = append(h.frames, newDot)
}
func (h *Overlay) createCallout(c callout) {
newLabel := h.uiManager.NewLabel(d2resource.FontFormal11, d2resource.PaletteSky)
newLabel.Color[0] = color.White
newLabel.SetText(c.LabelText)
newLabel.SetPosition(c.LabelX, c.LabelY)
newLabel.Alignment = d2gui.HorizontalAlignCenter
ww, hh := newLabel.GetTextMetrics(c.LabelText)
h.text = append(h.text, newLabel)
_ = ww
l := line{
StartX: c.LabelX,
StartY: c.LabelY + hh + 5,
MoveX: 0,
MoveY: c.DotY - c.LabelY - hh - 5,
Color: color.White,
}
h.lines = append(h.lines, l)
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
newDot, _ := h.uiManager.NewSprite(d2resource.HelpWhiteBullet, d2resource.PaletteSky)
_ = newDot.SetCurrentFrame(0)
newDot.SetPosition(c.DotX, c.DotY)
h.frames = append(h.frames, newDot)
}
func (h *Overlay) Render(target d2interface.Surface) error {
if !h.isOpen {
return nil
}
for _, f := range h.frames {
_ = f.Render(target)
}
for _, t := range h.text {
t.Render(target)
}
for _, l := range h.lines {
target.PushTranslation(l.StartX, l.StartY)
target.DrawLine(l.MoveX, l.MoveY, l.Color)
target.Pop()
}
return nil
}