From cbb512ab4b58eda328d8f7d2b484b5b4e407138b Mon Sep 17 00:00:00 2001 From: Brendan Porter Date: Wed, 9 Sep 2020 07:21:27 -0500 Subject: [PATCH] Help Overlay Added (#724) * Adds help overlay frame and some text and bullets * Finished basic layout, still need cancel button graphic, behavior --- d2common/d2resource/resource_paths.go | 7 + d2game/d2player/game_controls.go | 11 + d2game/d2player/help/help.go | 438 ++++++++++++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 d2game/d2player/help/help.go diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index a77d809d..f22523e6 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -90,6 +90,13 @@ const ( HealthManaIndicator = "/data/global/ui/PANEL/hlthmana.DC6" AddSkillButton = "/data/global/ui/PANEL/level.DC6" + // --- Help Overlay --- + + //HelpBorder = "/data/global/ui/MENU/helpborder.DC6" + HelpBorder = "/data/global/ui/MENU/800helpborder.DC6" + HelpYellowBullet = "/data/global/ui/MENU/helpyellowbullet.DC6" + HelpWhiteBullet = "/data/global/ui/MENU/helpwhitebullet.DC6" + // Issue #685 - used in the mini-panel GameSmallMenuButton = "/data/global/ui/PANEL/menubutton.DC6" SkillIcon = "/data/global/ui/PANEL/Skillicon.DC6" diff --git a/d2game/d2player/game_controls.go b/d2game/d2player/game_controls.go index 5a2df5de..7b915bf9 100644 --- a/d2game/d2player/game_controls.go +++ b/d2game/d2player/game_controls.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" + "github.com/OpenDiablo2/OpenDiablo2/d2game/d2player/help" "image" "image/color" "log" @@ -53,6 +54,7 @@ type GameControls struct { uiManager *d2ui.UIManager inventory *Inventory heroStatsPanel *HeroStatsPanel + helpOverlay *help.Overlay miniPanel *miniPanel lastMouseX int lastMouseY int @@ -166,6 +168,7 @@ func NewGameControls( mapRenderer: mapRenderer, inventory: NewInventory(ui, inventoryRecord), heroStatsPanel: NewHeroStatsPanel(ui, hero.Name(), hero.Class, hero.Stats), + helpOverlay: help.NewHelpOverlay(renderer), miniPanel: newMiniPanel(ui, isSinglePlayer), missileID: missileID, nameLabel: hoverLabel, @@ -260,6 +263,9 @@ func (g *GameControls) OnKeyDown(event d2interface.KeyEvent) bool { g.updateLayout() case d2enum.KeyR: g.onToggleRunButton() + case d2enum.KeyH: + g.helpOverlay.Toggle() + g.updateLayout() default: return false } @@ -391,6 +397,7 @@ func (g *GameControls) Load() { g.inventory.Load() g.heroStatsPanel.Load() + g.helpOverlay.Load() } func (g *GameControls) loadUIButtons() { @@ -752,6 +759,10 @@ func (g *GameControls) Render(target d2interface.Surface) error { g.hpManaStatsLabel.Render(target) } + if err := g.helpOverlay.Render(target); err != nil { + return err + } + return nil } diff --git a/d2game/d2player/help/help.go b/d2game/d2player/help/help.go new file mode 100644 index 00000000..568310c7 --- /dev/null +++ b/d2game/d2player/help/help.go @@ -0,0 +1,438 @@ +package help + +import ( + "fmt" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" + "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 +) + +// HelpOverlay represents the in-game overlay that toggles visibility when the h key is pressed +type Overlay struct { + isOpen bool + renderer d2interface.Renderer + frames []*d2ui.Sprite + text []*d2ui.Label + lines []line + uiManager *d2ui.UIManager + originX int + originY int + layout *d2gui.Layout +} + +func NewHelpOverlay(renderer d2interface.Renderer) *Overlay { + h := &Overlay{ + renderer: renderer, + } + + return h +} + +func (h *Overlay) onHoverElement(n int) { + +} + +func (h *Overlay) setLayout(id int) { + h.onHoverElement(0) +} + +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 + d2gui.SetLayout(nil) +} + +func (h *Overlay) open() { + h.isOpen = true + if h.layout == nil { + h.layout = d2gui.CreateLayout(h.renderer, d2gui.PositionTypeHorizontal) + // layoutLeft := h.layout.AddLayout(d2gui.PositionTypeVertical) + + // tlCorner, _ := layoutLeft.AddSprite(d2resource.HelpBorder, d2resource.PaletteSky) + // tlCorner.SetSegmented(0, 0, 0) + + //layoutLeft.AddSprite(imagePath, palettePath) + } + d2gui.SetLayout(h.layout) +} + +func (h *Overlay) Load() { + + var ( + x = 0 + y = 0 + prevX = 0 + prevY = 0 + ) + for frameIndex := 0; frameIndex < 7; frameIndex++ { + animation, _ := d2asset.LoadAnimation(d2resource.HelpBorder, d2resource.PaletteSky) + _ = animation.SetCurrentFrame(frameIndex) + f, _ := h.uiManager.NewSprite(animation) + + 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 + + anim, _ := d2asset.LoadAnimation(d2resource.SquareButton, d2resource.PaletteSky) + close, _ := h.uiManager.NewSprite(anim) + _ = close.SetCurrentFrame(0) + close.SetPosition(685, 57) + h.frames = append(h.frames, 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 to Run", + LabelX: 100, + LabelY: yOffset, + DotX: 100 - 12, + DotY: yOffset, + }) + + yOffset += 12 + h.createBullet(callout{ + LabelText: "Hold down to highlight items on the ground", + LabelX: 100, + LabelY: yOffset, + DotX: 100 - 12, + DotY: yOffset, + }) + + yOffset += 12 + h.createBullet(callout{ + LabelText: "Hold down to attack while standing still", + LabelX: 100, + LabelY: yOffset, + DotX: 100 - 12, + DotY: yOffset, + }) + + yOffset += 12 + h.createBullet(callout{ + LabelText: "Hit to toggle the automap on and off", + LabelX: 100, + LabelY: yOffset, + DotX: 100 - 12, + DotY: yOffset, + }) + + yOffset += 12 + h.createBullet(callout{ + LabelText: "Hit to bring up the Game Menu", + LabelX: 100, + LabelY: yOffset, + DotX: 100 - 12, + DotY: yOffset, + }) + + yOffset += 12 + h.createBullet(callout{ + LabelText: "Hit 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 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) + + anim, _ := d2asset.LoadAnimation(d2resource.HelpYellowBullet, d2resource.PaletteSky) + newDot, _ := h.uiManager.NewSprite(anim) + _ = 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] = d2util.Color(0xff0000_ff) + 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) + + anim, _ := d2asset.LoadAnimation(d2resource.HelpWhiteBullet, d2resource.PaletteSky) + newDot, _ := h.uiManager.NewSprite(anim) + _ = 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() + + // target.DrawLine(0, entityHeight, color.White) + // target.DrawLine(entityWidth, 0, color.White) + } + + // x, y := h.originX, h.originY + + // y += 20 + + // frameIndex := 0 + + // // Frame + // // Top left + // if err := h.frame.SetCurrentFrame(frameIndex); err != nil { + // return err + // } + + // h.frame.SetCurrentFrame(frameIndex) + // h.frame.Render(target) + // frameIndex++ + + // width, height := h.frame.GetCurrentFrameSize() + // _ = width + // y += height + // h.frame.SetPosition(x, y) + + // if err := h.frame.SetCurrentFrame(frameIndex); err != nil { + // return err + // } + + // h.frame.SetCurrentFrame(frameIndex) + // h.frame.Render(target) + // frameIndex++ + + // // _ = width + + // h.frame.SetPosition(x, y) + + // if err := h.frame.Render(target); err != nil { + // return err + // } + + //d2gui.Render(target) + + return nil +}