From 57bf4078b613df6182185d61a84d58db0282dada Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Tue, 19 Jan 2021 14:09:22 +0100 Subject: [PATCH] party panel: tooltip over players' names, players' colors, invite button, level -> lvl, relationships button has gets ret if disabled; d2ui improvement: addeded switcher's enabled methods --- d2core/d2ui/button.go | 19 ++++- d2core/d2ui/switchable_button.go | 25 ++++++- d2game/d2player/game_controls.go | 1 + d2game/d2player/party_panel.go | 121 ++++++++++++++++++++++++++----- 4 files changed, 145 insertions(+), 21 deletions(-) diff --git a/d2core/d2ui/button.go b/d2core/d2ui/button.go index 47fa968f..d576fd8f 100644 --- a/d2core/d2ui/button.go +++ b/d2core/d2ui/button.go @@ -56,6 +56,7 @@ const ( ButtonTypeTabBlank ButtonType = 36 ButtonTypeBlankQuestBtn ButtonType = 37 ButtonTypeAddSkill ButtonType = 38 + ButtonTypePartyButton ButtonType = 39 ButtonNoFixedWidth int = -1 ButtonNoFixedHeight int = -1 @@ -215,7 +216,6 @@ func getButtonLayouts() map[ButtonType]*ButtonLayout { YSegments: buttonWideSegmentsY, DisabledFrame: buttonWideDisabledFrame, DisabledColor: lightGreyAlpha75, - TextOffset: buttonWideTextOffset, ResourceName: d2resource.WideButtonBlank, PaletteName: d2resource.PaletteUnits, FontPath: d2resource.FontExocet10, @@ -765,6 +765,21 @@ func getButtonLayouts() map[ButtonType]*ButtonLayout { FixedWidth: ButtonNoFixedWidth, FixedHeight: ButtonNoFixedHeight, }, + ButtonTypePartyButton: { + XSegments: 1, + YSegments: 1, + DisabledFrame: buttonWideDisabledFrame, + DisabledColor: lightGreyAlpha75, + TextOffset: buttonWideTextOffset, + ResourceName: d2resource.PartyButton, + PaletteName: d2resource.PaletteUnits, + FontPath: d2resource.FontFormal10, + AllowFrameChange: true, + HasImage: true, + FixedWidth: ButtonNoFixedWidth, + FixedHeight: ButtonNoFixedHeight, + LabelColor: whiteAlpha100, + }, } } @@ -801,7 +816,7 @@ func (ui *UIManager) NewCustomButton(path string, frame int) *Button { layout := &ButtonLayout{ XSegments: 1, YSegments: 1, - DisabledFrame: -1, + DisabledFrame: frame, DisabledColor: whiteAlpha100, ResourceName: path, PaletteName: d2resource.PaletteSky, diff --git a/d2core/d2ui/switchable_button.go b/d2core/d2ui/switchable_button.go index a80d21d4..348d6126 100644 --- a/d2core/d2ui/switchable_button.go +++ b/d2core/d2ui/switchable_button.go @@ -1,6 +1,8 @@ package d2ui -import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" +import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" +) // static check if SwitchableButton implemented widget var _ Widget = &SwitchableButton{} @@ -116,6 +118,27 @@ func (sbtn *SwitchableButton) GetSize() (x, y int) { return x, y } +// SetEnabled sets button's enabled +func (sbtn *SwitchableButton) SetEnabled(enabled bool) { + sbtn.active.SetEnabled(enabled) + sbtn.inactive.SetEnabled(enabled) +} + +// GetEnabled returns true if current switcher position is enabled +func (sbtn *SwitchableButton) GetEnabled() bool { + if sbtn.state { + return sbtn.active.GetEnabled() + } + + return sbtn.inactive.GetEnabled() +} + +// SetDisabledColor sets switcher's disabled color +func (sbtn *SwitchableButton) SetDisabledColor(color uint32) { + sbtn.active.buttonLayout.DisabledColor = color + sbtn.inactive.buttonLayout.DisabledColor = color +} + // Advance advances widget func (sbtn *SwitchableButton) Advance(_ float64) error { // noop diff --git a/d2game/d2player/game_controls.go b/d2game/d2player/game_controls.go index 12a0eda6..975b90d3 100644 --- a/d2game/d2player/game_controls.go +++ b/d2game/d2player/game_controls.go @@ -503,6 +503,7 @@ func (g *GameControls) OnMouseMove(event d2interface.MouseMoveEvent) bool { } g.hud.OnMouseMove(event) + g.PartyPanel.OnMouseMove(event) return false } diff --git a/d2game/d2player/party_panel.go b/d2game/d2player/party_panel.go index 75085575..8e8065c1 100644 --- a/d2game/d2player/party_panel.go +++ b/d2game/d2player/party_panel.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" @@ -17,6 +18,12 @@ import ( const ( lightGreen = 0x18ff00ff red = 0xff0000ff + lightRed = 0xdb3f3dff + orange = 0xffa800ff +) + +const ( + playerHostileLevel = 9 ) const ( // for the dc6 frames @@ -56,33 +63,44 @@ const ( listeningSwitcherX = 345 seeingSwitcherX = 365 nameLabelX = 115 + nameTooltipX = 100 classLabelX = 115 levelLabelX = 383 + inviteAcceptButtonX = 250 baseBarY = 134 baseRelationshipSwitcherY = 150 baseSeeingSwitcherY = 140 baseListeningSwitcherY = 140 - baseNameLabelY = 145 + baseNameLabelY = 144 + baseNameTooltipY = 120 baseClassLabelY = 158 baseLevelLabelY = 160 - nextBar = 52 + baseInviteAcceptButtonY = 140 + indexOffset = 52 ) // newPartyIndex creates new party index func (s *PartyPanel) newPartyIndex() *partyIndex { - result := &partyIndex{} + result := &partyIndex{ + asset: s.asset, + me: s.me, + } nameLabel := s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky) + result.nameTooltip = s.uiManager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, d2ui.TooltipXCenter, d2ui.TooltipYTop) result.name = nameLabel classLabel := s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky) result.class = classLabel + result.nameRect = d2geom.Rectangle{} + levelLabel := s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky) levelLabel.Alignment = d2ui.HorizontalAlignRight result.level = levelLabel relationships := s.createSwitcher(relationshipsFrame) + relationships.SetDisabledColor(lightRed) result.relationshipsActiveTooltip = s.uiManager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, d2ui.TooltipXCenter, d2ui.TooltipYTop) result.relationshipsActiveTooltip.SetText(s.asset.TranslateString("strParty7") + "\n" + s.asset.TranslateString("strParty8")) @@ -119,13 +137,21 @@ func (s *PartyPanel) newPartyIndex() *partyIndex { result.listeningSwitcher = listening + result.inviteAcceptButton = s.uiManager.NewButton(d2ui.ButtonTypePartyButton, s.asset.TranslateString("Invite")) + result.inviteAcceptButton.SetVisible(false) + return result } // partyIndex represents a party index type partyIndex struct { + asset *d2asset.AssetManager + me *d2mapentity.Player + hero *d2mapentity.Player name *d2ui.Label + nameTooltip *d2ui.Tooltip + nameRect d2geom.Rectangle class *d2ui.Label level *d2ui.Label relationshipSwitcher *d2ui.SwitchableButton @@ -137,9 +163,19 @@ type partyIndex struct { listeningSwitcher *d2ui.SwitchableButton listeningActiveTooltip *d2ui.Tooltip listeningInactiveTooltip *d2ui.Tooltip + inviteAcceptButton *d2ui.Button relationships d2enum.PlayersRelationships } +func (pi *partyIndex) setNameTooltipText() { + switch pi.relationships { + case d2enum.PlayerRelationNeutral, d2enum.PlayerRelationFriend: + pi.nameTooltip.SetText(pi.asset.TranslateString("Party17")) + case d2enum.PlayerRelationEnemy: + pi.nameTooltip.SetText(pi.asset.TranslateString("Party12")) + } +} + // setColor sets appropriate labels' colors func (pi *partyIndex) setColor(relations d2enum.PlayersRelationships) { var color = d2util.Color(white) @@ -151,6 +187,13 @@ func (pi *partyIndex) setColor(relations d2enum.PlayersRelationships) { pi.relationshipSwitcher.SetState(false) case d2enum.PlayerRelationFriend: color = d2util.Color(lightGreen) + case d2enum.PlayerRelationNeutral: + if pi.CanGoHostile() { + color = d2util.Color(white) + } else { + color = d2util.Color(orange) + pi.relationshipSwitcher.SetEnabled(false) + } } pi.name.Color[0] = color @@ -160,35 +203,54 @@ func (pi *partyIndex) setColor(relations d2enum.PlayersRelationships) { // setPositions sets party-index's position to given func (pi *partyIndex) setPositions(idx int) { - var h int + var w, h int - pi.name.SetPosition(nameLabelX, baseNameLabelY+nextBar*idx) - pi.class.SetPosition(classLabelX, baseClassLabelY+nextBar*idx) - pi.level.SetPosition(levelLabelX, baseLevelLabelY+nextBar*idx) + pi.name.SetPosition(nameLabelX, baseNameLabelY+indexOffset*idx) + pi.nameTooltip.SetPosition(nameTooltipX, baseNameTooltipY+indexOffset*idx) + pi.class.SetPosition(classLabelX, baseClassLabelY+indexOffset*idx) + pi.level.SetPosition(levelLabelX, baseLevelLabelY+indexOffset*idx) - pi.relationshipSwitcher.SetPosition(relationshipSwitcherX, baseRelationshipSwitcherY+nextBar*idx) + w, h1 := pi.class.GetSize() + + _, h = pi.name.GetSize() + + pi.nameRect = d2geom.Rectangle{ + Left: nameLabelX, + Top: baseNameLabelY + idx*indexOffset, + Width: w, + Height: h + h1, + } + + pi.relationshipSwitcher.SetPosition(relationshipSwitcherX, baseRelationshipSwitcherY+indexOffset*idx) _, h = pi.relationshipsActiveTooltip.GetSize() - pi.relationshipsActiveTooltip.SetPosition(relationshipSwitcherX+buttonSize, baseRelationshipSwitcherY+idx*nextBar-h) + pi.relationshipsActiveTooltip.SetPosition(relationshipSwitcherX+buttonSize, baseRelationshipSwitcherY+idx*indexOffset-h) _, h = pi.relationshipsInactiveTooltip.GetSize() - pi.relationshipsInactiveTooltip.SetPosition(relationshipSwitcherX+buttonSize, baseRelationshipSwitcherY+idx*nextBar-h) + pi.relationshipsInactiveTooltip.SetPosition(relationshipSwitcherX+buttonSize, baseRelationshipSwitcherY+idx*indexOffset-h) - pi.seeingSwitcher.SetPosition(seeingSwitcherX, baseSeeingSwitcherY+idx*nextBar) + pi.seeingSwitcher.SetPosition(seeingSwitcherX, baseSeeingSwitcherY+idx*indexOffset) _, h = pi.seeingActiveTooltip.GetSize() - pi.seeingActiveTooltip.SetPosition(seeingSwitcherX+buttonSize, baseSeeingSwitcherY+idx*nextBar-h) + pi.seeingActiveTooltip.SetPosition(seeingSwitcherX+buttonSize, baseSeeingSwitcherY+idx*indexOffset-h) _, h = pi.seeingInactiveTooltip.GetSize() - pi.seeingInactiveTooltip.SetPosition(seeingSwitcherX+buttonSize, baseSeeingSwitcherY+idx*nextBar-h) + pi.seeingInactiveTooltip.SetPosition(seeingSwitcherX+buttonSize, baseSeeingSwitcherY+idx*indexOffset-h) - pi.listeningSwitcher.SetPosition(listeningSwitcherX, baseListeningSwitcherY+idx*nextBar) + pi.listeningSwitcher.SetPosition(listeningSwitcherX, baseListeningSwitcherY+idx*indexOffset) _, h = pi.listeningActiveTooltip.GetSize() - pi.listeningActiveTooltip.SetPosition(listeningSwitcherX+buttonSize, baseListeningSwitcherY+idx*nextBar-h) + pi.listeningActiveTooltip.SetPosition(listeningSwitcherX+buttonSize, baseListeningSwitcherY+idx*indexOffset-h) _, h = pi.listeningInactiveTooltip.GetSize() - pi.listeningInactiveTooltip.SetPosition(listeningSwitcherX+buttonSize, baseListeningSwitcherY+idx*nextBar-h) + pi.listeningInactiveTooltip.SetPosition(listeningSwitcherX+buttonSize, baseListeningSwitcherY+idx*indexOffset-h) + + pi.inviteAcceptButton.SetPosition(inviteAcceptButtonX, baseInviteAcceptButtonY+idx*indexOffset) +} + +func (pi *partyIndex) CanGoHostile() bool { + return pi.hero.Stats.Level >= playerHostileLevel && pi.me.Stats.Level >= playerHostileLevel } // AddPlayer adds a new player to the party panel func (s *PartyPanel) AddPlayer(player *d2mapentity.Player, relations d2enum.PlayersRelationships) { idx := 0 + // search for free index for n, i := range s.partyIndexes { if i.hero == nil { idx = n @@ -202,12 +264,14 @@ func (s *PartyPanel) AddPlayer(player *d2mapentity.Player, relations d2enum.Play s.partyIndexes[idx].class.SetText(s.asset.TranslateString(player.Class.String())) - s.partyIndexes[idx].level.SetText(s.asset.TranslateString("level") + ": " + strconv.Itoa(player.Stats.Level)) + s.partyIndexes[idx].level.SetText(s.asset.TranslateString("Level") + ":" + strconv.Itoa(player.Stats.Level)) s.partyIndexes[idx].relationships = relations s.partyIndexes[idx].setColor(relations) s.partyIndexes[idx].setPositions(idx) + + s.partyIndexes[idx].setNameTooltipText() } // DeletePlayer deletes player from PartyIndexes @@ -302,7 +366,7 @@ func (s *PartyPanel) setBarPosition() { currentN := n if i.hero == nil { - s.barX, s.barY = barX, baseBarY+currentN*nextBar + s.barX, s.barY = barX, baseBarY+currentN*indexOffset break } } @@ -434,6 +498,10 @@ func (s *PartyPanel) Load() { heroName.Alignment = d2ui.HorizontalAlignCenter s.panelGroup.AddWidget(heroName) + m0 := s.me + m0.Class = d2enum.HeroNecromancer + s.AddPlayer(m0, d2enum.PlayerRelationNeutral) + // create WidgetGroups of party indexes for n, i := range s.partyIndexes { s.indexes[n].AddWidget(i.name) @@ -442,6 +510,7 @@ func (s *PartyPanel) Load() { s.indexes[n].AddWidget(i.seeingSwitcher) s.indexes[n].AddWidget(i.listeningSwitcher) s.indexes[n].AddWidget(i.level) + s.indexes[n].AddWidget(i.inviteAcceptButton) } // create bar @@ -524,6 +593,22 @@ func (s *PartyPanel) UpdatePlayersList(list map[string]*d2mapentity.Player) { s.players = list } +// OnMouseMove handles mouse movement events +func (s *PartyPanel) OnMouseMove(event d2interface.MouseMoveEvent) bool { + mx, my := event.X(), event.Y() + + for _, i := range s.partyIndexes { + // Mouse over a game control element + if i.nameRect.IsInRect(mx, my) { + i.nameTooltip.SetVisible(true) + } else { + i.nameTooltip.SetVisible(false) + } + } + + return true +} + // nolint:dupl // see quest_log.go.renderStaticPanelFrames comment func (s *PartyPanel) renderStaticPanelFrames(target d2interface.Surface) { frames := []int{