From 08e590f3e4874d9665d28fa32d99fce263543e87 Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Wed, 16 Dec 2020 15:08:39 +0100 Subject: [PATCH 1/4] quest animation initial. --- d2common/d2resource/resource_paths.go | 1 + d2game/d2gamescreen/game.go | 3 +- d2game/d2player/game_controls.go | 4 +- d2game/d2player/quest_log.go | 74 ++++++++++++++++++++------- 4 files changed, 62 insertions(+), 20 deletions(-) diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index a18a196f..ed74d366 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -193,6 +193,7 @@ const ( QuestLogQDescrBtn = "/data/global/ui/MENU/questlast.dc6" QuestLogSocket = "/data/global/ui/MENU/questsockets.dc6" QuestLogAQuestAnimation = "/data/global/ui/MENU/a%dq%d.dc6" + QuestLogDoneSfx = "cursor/questdone.wav" // --- Mouse Pointers --- diff --git a/d2game/d2gamescreen/game.go b/d2game/d2gamescreen/game.go index 07a826c1..2b339a01 100644 --- a/d2game/d2gamescreen/game.go +++ b/d2game/d2gamescreen/game.go @@ -304,7 +304,8 @@ func (v *Game) bindGameControls() error { var err error v.gameControls, err = d2player.NewGameControls(v.asset, v.renderer, player, v.gameClient.MapEngine, - v.escapeMenu, v.mapRenderer, v, v.terminal, v.uiManager, v.keyMap, v.logLevel, v.gameClient.IsSinglePlayer()) + v.escapeMenu, v.mapRenderer, v, v.terminal, v.uiManager, v.keyMap, v.audioProvider, v.logLevel, + v.gameClient.IsSinglePlayer()) if err != nil { return err diff --git a/d2game/d2player/game_controls.go b/d2game/d2player/game_controls.go index 2335cc52..f1fc3b5e 100644 --- a/d2game/d2player/game_controls.go +++ b/d2game/d2player/game_controls.go @@ -124,6 +124,7 @@ func NewGameControls( term d2interface.Terminal, ui *d2ui.UIManager, keyMap *KeyMap, + audioProvider d2interface.AudioProvider, l d2util.LogLevel, isSinglePlayer bool, ) (*GameControls, error) { @@ -207,7 +208,7 @@ func NewGameControls( inventoryRecord := asset.Records.Layout.Inventory[inventoryRecordKey] heroStatsPanel := NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, l, hero.Stats) - questLog := NewQuestLog(asset, ui, l, hero.Act) + questLog := NewQuestLog(asset, ui, l, audioProvider, hero.Act) inventory, err := NewInventory(asset, ui, l, hero.Gold, inventoryRecord) if err != nil { @@ -728,6 +729,7 @@ func (g *GameControls) Advance(elapsed float64) error { g.mapRenderer.Advance(elapsed) g.hud.Advance(elapsed) g.inventory.Advance(elapsed) + g.questLog.Advance(elapsed) if err := g.escapeMenu.Advance(elapsed); err != nil { return err diff --git a/d2game/d2player/quest_log.go b/d2game/d2player/quest_log.go index e064eb11..1d0eace8 100644 --- a/d2game/d2player/quest_log.go +++ b/d2game/d2player/quest_log.go @@ -71,6 +71,7 @@ func (s *QuestLog) getPositionForSocket(number int) (x, y int) { func NewQuestLog(asset *d2asset.AssetManager, ui *d2ui.UIManager, l d2util.LogLevel, + audioProvider d2interface.AudioProvider, act int) *QuestLog { originX := 0 originY := 0 @@ -106,9 +107,9 @@ func NewQuestLog(asset *d2asset.AssetManager, 26: 0, } - var quests [d2enum.ActsNumber]*d2ui.WidgetGroup + var quests [d2enum.ActsNumber]*questEntire for i := 0; i < d2enum.ActsNumber; i++ { - quests[i] = ui.NewWidgetGroup(d2ui.RenderPriorityQuestLog) + quests[i] = &questEntire{WidgetGroup: ui.NewWidgetGroup(d2ui.RenderPriorityQuestLog)} } var tabs [d2enum.ActsNumber]questLogTab @@ -129,6 +130,7 @@ func NewQuestLog(asset *d2asset.AssetManager, quests: quests, questStatus: qs, maxPlayersAct: mpa, + audioProvider: audioProvider, } ql.Logger = d2util.NewLogger() @@ -149,10 +151,12 @@ type QuestLog struct { selectedQuest int act int tab [d2enum.ActsNumber]questLogTab + audioProvider d2interface.AudioProvider + completeSound d2interface.SoundEffect questName *d2ui.Label questDescr *d2ui.Label - quests [d2enum.ActsNumber]*d2ui.WidgetGroup + quests [d2enum.ActsNumber]*questEntire questStatus map[int]int maxPlayersAct int @@ -163,6 +167,11 @@ type QuestLog struct { *d2util.Logger } +type questEntire struct { + *d2ui.WidgetGroup + icons []*d2ui.Sprite +} + /* questIconTab returns path to quest animation using its act and number. From d2resource: QuestLogAQuestAnimation = "/data/global/ui/MENU/a%dq%d.dc6"*/ @@ -187,6 +196,8 @@ type questLogTab struct { func (s *QuestLog) Load() { var err error + s.completeSound, err = s.audioProvider.LoadSound(d2resource.QuestLogDoneSfx, false, false) + s.panelGroup = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) frame := d2ui.NewUIFrame(s.asset, s.uiManager, d2ui.FrameLeft) @@ -228,7 +239,8 @@ func (s *QuestLog) Load() { s.loadTabs() for i := 0; i < d2enum.ActsNumber; i++ { - s.quests[i] = s.loadQuestIconsForAct(i + 1) + item, icons := s.loadQuestIconsForAct(i + 1) + s.quests[i] = &questEntire{item, icons} } s.panelGroup.SetVisible(false) @@ -268,7 +280,7 @@ func (s *QuestLog) loadTabs() { s.setTab(s.act - 1) } -func (s *QuestLog) loadQuestIconsForAct(act int) *d2ui.WidgetGroup { +func (s *QuestLog) loadQuestIconsForAct(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite) { wg := s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) var questsInAct int @@ -282,6 +294,8 @@ func (s *QuestLog) loadQuestIconsForAct(act int) *d2ui.WidgetGroup { var buttons []*d2ui.Button + var icons []*d2ui.Sprite + var icon *d2ui.Sprite for n := 0; n < questsInAct; n++ { @@ -307,7 +321,8 @@ func (s *QuestLog) loadQuestIconsForAct(act int) *d2ui.WidgetGroup { } icon.SetPosition(x+questOffsetX, y+questOffsetY+iconOffsetY) - wg.AddWidget(icon) + + icons = append(icons, icon) } for i := 0; i < questsInAct; i++ { @@ -338,9 +353,13 @@ func (s *QuestLog) loadQuestIconsForAct(act int) *d2ui.WidgetGroup { wg.AddWidget(b) } + for _, i := range icons { + wg.AddWidget(i) + } + wg.SetVisible(false) - return wg + return wg, icons } func (s *QuestLog) makeQuestIconForAct(act, n int) (*d2ui.Sprite, error) { @@ -355,16 +374,6 @@ func (s *QuestLog) makeQuestIconForAct(act, n int) (*d2ui.Sprite, error) { case d2enum.QuestStatusCompleted: err = icon.SetCurrentFrame(completedFrame) case d2enum.QuestStatusCompleting: - // that's not complet now - err = icon.SetCurrentFrame(0) - if err != nil { - s.Error(err.Error()) - } - - icon.PlayForward() - icon.SetPlayLoop(false) - err = icon.SetCurrentFrame(completedFrame) - s.questStatus[s.cordsToQuestID(act, n)] = d2enum.QuestStatusCompleted case d2enum.QuestStatusNotStarted: err = icon.SetCurrentFrame(notStartedFrame) default: @@ -374,6 +383,26 @@ func (s *QuestLog) makeQuestIconForAct(act, n int) (*d2ui.Sprite, error) { return icon, err } +func (s *QuestLog) playQuestAnimations() { + var err error + + for j, i := range s.quests[s.selectedTab].icons { + questID := s.cordsToQuestID(s.selectedTab+1, j) + if s.questStatus[questID] == d2enum.QuestStatusCompleting { + s.completeSound.Play() + err = i.SetCurrentFrame(0) + if err != nil { + s.Error(err.Error()) + } + + i.SetPlayLength(3) + i.PlayForward() + i.SetPlayLoop(false) + s.questStatus[questID] = d2enum.QuestStatusCompleted + } + } +} + func (s *QuestLog) setQuestLabel() { if s.selectedQuest == 0 { s.questName.SetText("") @@ -466,6 +495,7 @@ func (s *QuestLog) Open() { s.isOpen = true s.panelGroup.SetVisible(true) s.setTab(s.selectedTab) + s.playQuestAnimations() } // Close closed the hero status panel @@ -487,7 +517,15 @@ func (s *QuestLog) SetOnCloseCb(cb func()) { // Advance updates labels on the panel func (s *QuestLog) Advance(elapsed float64) { - // + if !s.IsOpen() { + return + } + + for _, i := range s.quests[s.selectedTab].icons { + if err := i.Advance(elapsed); err != nil { + s.Error(err.Error()) + } + } } func (s *QuestLog) renderStaticMenu(target d2interface.Surface) { From 856138dacaacf83eb3b6ff5ab8d540d188a30870 Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Wed, 16 Dec 2020 19:06:12 +0100 Subject: [PATCH 2/4] animation is played and last frame is completedFrame --- d2game/d2player/quest_log.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/d2game/d2player/quest_log.go b/d2game/d2player/quest_log.go index 1d0eace8..960ea73d 100644 --- a/d2game/d2player/quest_log.go +++ b/d2game/d2player/quest_log.go @@ -374,6 +374,8 @@ func (s *QuestLog) makeQuestIconForAct(act, n int) (*d2ui.Sprite, error) { case d2enum.QuestStatusCompleted: err = icon.SetCurrentFrame(completedFrame) case d2enum.QuestStatusCompleting: + // animation will be played after quest-log panel is opened (see s.playQuestAnimation) + err = icon.SetCurrentFrame(0) case d2enum.QuestStatusNotStarted: err = icon.SetCurrentFrame(notStartedFrame) default: @@ -398,7 +400,6 @@ func (s *QuestLog) playQuestAnimations() { i.SetPlayLength(3) i.PlayForward() i.SetPlayLoop(false) - s.questStatus[questID] = d2enum.QuestStatusCompleted } } } @@ -521,9 +522,15 @@ func (s *QuestLog) Advance(elapsed float64) { return } - for _, i := range s.quests[s.selectedTab].icons { - if err := i.Advance(elapsed); err != nil { - s.Error(err.Error()) + for j, i := range s.quests[s.selectedTab].icons { + questID := s.cordsToQuestID(s.selectedTab+1, j) + if s.questStatus[questID] == d2enum.QuestStatusCompleting { + if err := i.Advance(elapsed); err != nil { + s.Error(err.Error()) + } + if i.GetCurrentFrame() == completedFrame { + s.questStatus[questID] = d2enum.QuestStatusCompleted + } } } } From 8a027eb48deb0736a098c53ec12edd3c7e7183fd Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Thu, 17 Dec 2020 11:02:39 +0100 Subject: [PATCH 3/4] animation stops playing, when quest log is closed & quest socket gets highlighted, when animation is playing & fixed highlight bug --- d2game/d2player/quest_log.go | 114 ++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 28 deletions(-) diff --git a/d2game/d2player/quest_log.go b/d2game/d2player/quest_log.go index 960ea73d..12bd8144 100644 --- a/d2game/d2player/quest_log.go +++ b/d2game/d2player/quest_log.go @@ -51,6 +51,8 @@ const ( questTabXOffset = 61 ) +const questCompleteAnimationDuration = 3 + func (s *QuestLog) getPositionForSocket(number int) (x, y int) { pos := []struct { x int @@ -80,12 +82,12 @@ func NewQuestLog(asset *d2asset.AssetManager, qs := map[int]int{ 0: -2, 1: -2, - 2: -1, + 2: -2, 3: 0, 4: 1, 5: 2, 6: 3, - 7: 0, + 7: -1, 8: 0, 9: 0, 10: 0, @@ -169,7 +171,9 @@ type QuestLog struct { type questEntire struct { *d2ui.WidgetGroup - icons []*d2ui.Sprite + icons []*d2ui.Sprite + buttons []*d2ui.Button + sockets []*d2ui.Sprite } /* questIconTab returns path to quest animation using its @@ -185,6 +189,11 @@ const ( notStartedFrame = 26 ) +const ( + socketNormalFrame = 0 + socketHighlightedFrame = 1 +) + const questDescriptionLenght = 30 type questLogTab struct { @@ -197,6 +206,9 @@ func (s *QuestLog) Load() { var err error s.completeSound, err = s.audioProvider.LoadSound(d2resource.QuestLogDoneSfx, false, false) + if err != nil { + s.Error(err.Error()) + } s.panelGroup = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) @@ -238,9 +250,10 @@ func (s *QuestLog) Load() { s.loadTabs() + // creates quest boards for each act for i := 0; i < d2enum.ActsNumber; i++ { - item, icons := s.loadQuestIconsForAct(i + 1) - s.quests[i] = &questEntire{item, icons} + item, icons, buttons, sockets := s.loadQuestBoard(i + 1) + s.quests[i] = &questEntire{item, icons, buttons, sockets} } s.panelGroup.SetVisible(false) @@ -280,7 +293,8 @@ func (s *QuestLog) loadTabs() { s.setTab(s.act - 1) } -func (s *QuestLog) loadQuestIconsForAct(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite) { +// loadQuestBoard creates quest fields (socket, button, icon) for specified act +func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, []*d2ui.Button, []*d2ui.Sprite) { wg := s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) var questsInAct int @@ -307,62 +321,68 @@ func (s *QuestLog) loadQuestIconsForAct(act int) (*d2ui.WidgetGroup, []*d2ui.Spr s.Error(err.Error()) } - socket.SetPosition(x+questOffsetX, y+iconOffsetY+2*questOffsetY) + socket.SetPosition(x, y+iconOffsetY+questOffsetY) sockets = append(sockets, socket) + icon, err = s.makeQuestIconForAct(act, n, x, y) + if err != nil { + s.Error(err.Error()) + } + + icons = append(icons, icon) + button := s.uiManager.NewButton(d2ui.ButtonTypeBlankQuestBtn, "") button.SetPosition(x+questOffsetX, y+questOffsetY) button.SetEnabled(s.questStatus[s.cordsToQuestID(act, cw)] != d2enum.QuestStatusNotStarted) buttons = append(buttons, button) - icon, err = s.makeQuestIconForAct(act, n) - if err != nil { - s.Error(err.Error()) - } - - icon.SetPosition(x+questOffsetX, y+questOffsetY+iconOffsetY) - - icons = append(icons, icon) } for i := 0; i < questsInAct; i++ { currentQuest := i + // creates callback for quest button buttons[i].OnActivated(func() { var err error + + // set normal (not-highlighted) frame for each quest socket for j := 0; j < questsInAct; j++ { - err = sockets[j].SetCurrentFrame(0) + err = sockets[j].SetCurrentFrame(socketNormalFrame) if err != nil { s.Error(err.Error()) } } - if act-1 == s.selectedTab { - err = sockets[currentQuest].SetCurrentFrame(1) - if err != nil { - s.Error(err.Error()) - } + + // highlights appropiate socket + err = sockets[currentQuest].SetCurrentFrame(socketHighlightedFrame) + if err != nil { + s.Error(err.Error()) } + s.onQuestClicked(currentQuest + 1) }) } + // adds sockets to widget group for _, s := range sockets { wg.AddWidget(s) } + // adds buttons to widget group for _, b := range buttons { wg.AddWidget(b) } + // adds icons to widget group for _, i := range icons { wg.AddWidget(i) } wg.SetVisible(false) - return wg, icons + return wg, icons, buttons, sockets } -func (s *QuestLog) makeQuestIconForAct(act, n int) (*d2ui.Sprite, error) { +func (s *QuestLog) makeQuestIconForAct(act, n int, x, y int) (*d2ui.Sprite, error) { iconResource := s.questIconsTable(act, n) icon, err := s.uiManager.NewSprite(iconResource, d2resource.PaletteSky) @@ -382,9 +402,12 @@ func (s *QuestLog) makeQuestIconForAct(act, n int) (*d2ui.Sprite, error) { err = icon.SetCurrentFrame(inProgresFrame) } + icon.SetPosition(x+questOffsetX, y+questOffsetY+iconOffsetY) + return icon, err } +// playQuestAnimations plays animations for quests (when status=questStatusCompleting) func (s *QuestLog) playQuestAnimations() { var err error @@ -392,20 +415,25 @@ func (s *QuestLog) playQuestAnimations() { questID := s.cordsToQuestID(s.selectedTab+1, j) if s.questStatus[questID] == d2enum.QuestStatusCompleting { s.completeSound.Play() + + // quest should be highlighted and it's label should be displayed + s.quests[s.selectedTab].buttons[j].Activate() + err = i.SetCurrentFrame(0) if err != nil { s.Error(err.Error()) } - i.SetPlayLength(3) + i.SetPlayLength(questCompleteAnimationDuration) i.PlayForward() i.SetPlayLoop(false) } } } +// setQuestLabel loads quest labels text (title and description) func (s *QuestLog) setQuestLabel() { - if s.selectedQuest == 0 { + if s.selectedQuest == d2enum.QuestNone { s.questName.SetText("") s.questDescr.SetText("") @@ -416,7 +444,7 @@ func (s *QuestLog) setQuestLabel() { status := s.questStatus[s.cordsToQuestID(s.selectedTab+1, s.selectedQuest)-1] switch status { - case d2enum.QuestStatusCompleted: + case d2enum.QuestStatusCompleted, d2enum.QuestStatusCompleting: s.questDescr.SetText( strings.Join( d2util.SplitIntoLinesWithMaxWidth( @@ -424,8 +452,6 @@ func (s *QuestLog) setQuestLabel() { questDescriptionLenght), "\n"), ) - case d2enum.QuestStatusCompleting: - s.questDescr.SetText("") case d2enum.QuestStatusNotStarted: s.questDescr.SetText("") default: @@ -440,12 +466,26 @@ func (s *QuestLog) setQuestLabel() { } } +func (s *QuestLog) clearHighlightment() { + for _, i := range s.quests[s.selectedTab].sockets { + err := i.SetCurrentFrame(socketNormalFrame) + if err != nil { + s.Error(err.Error()) + } + } +} + func (s *QuestLog) setTab(tab int) { var mod int + // before we leafe current tab, we need to switch highlighted + // quest socket to normal frame + s.clearHighlightment() + s.selectedTab = tab s.selectedQuest = d2enum.QuestNone s.setQuestLabel() + s.playQuestAnimations() for i := 0; i < s.maxPlayersAct; i++ { s.quests[i].SetVisible(tab == i) @@ -508,9 +548,26 @@ func (s *QuestLog) Close() { s.quests[i].SetVisible(false) } + s.stopPlayedAnimations() + s.onCloseCb() } +func (s *QuestLog) stopPlayedAnimations() { + // stops all played animations + for j, i := range s.quests[s.selectedTab].icons { + questID := s.cordsToQuestID(s.selectedTab+1, j) + if s.questStatus[questID] == d2enum.QuestStatusCompleting { + s.questStatus[questID] = d2enum.QuestStatusCompleted + + err := i.SetCurrentFrame(completedFrame) + if err != nil { + s.Error(err.Error()) + } + } + } +} + // SetOnCloseCb the callback run on closing the HeroStatsPanel func (s *QuestLog) SetOnCloseCb(cb func()) { s.onCloseCb = cb @@ -528,6 +585,7 @@ func (s *QuestLog) Advance(elapsed float64) { if err := i.Advance(elapsed); err != nil { s.Error(err.Error()) } + if i.GetCurrentFrame() == completedFrame { s.questStatus[questID] = d2enum.QuestStatusCompleted } From d58ed6202f99e138a6b19ef99664c56e39a5f324 Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Thu, 17 Dec 2020 12:04:37 +0100 Subject: [PATCH 4/4] fixed quest descr bug & added code description --- d2game/d2player/quest_log.go | 131 +++++++++++++++-------------------- 1 file changed, 55 insertions(+), 76 deletions(-) diff --git a/d2game/d2player/quest_log.go b/d2game/d2player/quest_log.go index 12bd8144..1c1ab5c5 100644 --- a/d2game/d2player/quest_log.go +++ b/d2game/d2player/quest_log.go @@ -85,7 +85,7 @@ func NewQuestLog(asset *d2asset.AssetManager, 2: -2, 3: 0, 4: 1, - 5: 2, + 5: 4, 6: 3, 7: -1, 8: 0, @@ -205,13 +205,14 @@ type questLogTab struct { func (s *QuestLog) Load() { var err error + s.panelGroup = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) + + // quest completion sound. s.completeSound, err = s.audioProvider.LoadSound(d2resource.QuestLogDoneSfx, false, false) if err != nil { s.Error(err.Error()) } - s.panelGroup = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) - frame := d2ui.NewUIFrame(s.asset, s.uiManager, d2ui.FrameLeft) s.panelGroup.AddWidget(frame) @@ -221,7 +222,7 @@ func (s *QuestLog) Load() { } w, h := frame.GetSize() - staticPanel := s.uiManager.NewCustomWidgetCached(s.renderStaticMenu, w, h) + staticPanel := s.uiManager.NewCustomWidgetCached(s.renderStaticPanelFrames, w, h) s.panelGroup.AddWidget(staticPanel) closeButton := s.uiManager.NewButton(d2ui.ButtonTypeSquareClose, "") @@ -259,11 +260,13 @@ func (s *QuestLog) Load() { s.panelGroup.SetVisible(false) } +// loadTabs loads quest log tabs func (s *QuestLog) loadTabs() { var err error tabsResource := d2resource.WPTabs + // create tabs only for 'discovered' acts for i := 0; i < s.maxPlayersAct; i++ { currentValue := i @@ -272,7 +275,8 @@ func (s *QuestLog) loadTabs() { s.Error(err.Error()) } - // nolint:gomnd // it's constant + // nolint:gomnd // it's constant. + // each tab has two frames (active / inactive) frame := 2 * currentValue err := s.tab[i].sprite.SetCurrentFrame(frame) @@ -290,13 +294,15 @@ func (s *QuestLog) loadTabs() { s.panelGroup.AddWidget(s.tab[i].invisibleButton) } + // sets tab to current player's act. s.setTab(s.act - 1) } // loadQuestBoard creates quest fields (socket, button, icon) for specified act -func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, []*d2ui.Button, []*d2ui.Sprite) { - wg := s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) +func (s *QuestLog) loadQuestBoard(act int) (wg *d2ui.WidgetGroup, icons []*d2ui.Sprite, buttons []*d2ui.Button, sockets []*d2ui.Sprite) { + wg = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityQuestLog) + // sets number of quests in act (for act 4 it's only 3, else 6) var questsInAct int if act == d2enum.Act4 { questsInAct = d2enum.HalfQuestsNumber @@ -304,14 +310,6 @@ func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, [ questsInAct = d2enum.NormalActQuestsNumber } - var sockets []*d2ui.Sprite - - var buttons []*d2ui.Button - - var icons []*d2ui.Sprite - - var icon *d2ui.Sprite - for n := 0; n < questsInAct; n++ { cw := n x, y := s.getPositionForSocket(n) @@ -324,7 +322,7 @@ func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, [ socket.SetPosition(x, y+iconOffsetY+questOffsetY) sockets = append(sockets, socket) - icon, err = s.makeQuestIconForAct(act, n, x, y) + icon, err := s.makeQuestIconForAct(act, n, x, y) if err != nil { s.Error(err.Error()) } @@ -335,11 +333,11 @@ func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, [ button.SetPosition(x+questOffsetX, y+questOffsetY) button.SetEnabled(s.questStatus[s.cordsToQuestID(act, cw)] != d2enum.QuestStatusNotStarted) buttons = append(buttons, button) - } for i := 0; i < questsInAct; i++ { currentQuest := i + // creates callback for quest button buttons[i].OnActivated(func() { var err error @@ -352,12 +350,13 @@ func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, [ } } - // highlights appropiate socket + // highlights appropriate socket err = sockets[currentQuest].SetCurrentFrame(socketHighlightedFrame) if err != nil { s.Error(err.Error()) } + // sets quest labels s.onQuestClicked(currentQuest + 1) }) } @@ -382,7 +381,7 @@ func (s *QuestLog) loadQuestBoard(act int) (*d2ui.WidgetGroup, []*d2ui.Sprite, [ return wg, icons, buttons, sockets } -func (s *QuestLog) makeQuestIconForAct(act, n int, x, y int) (*d2ui.Sprite, error) { +func (s *QuestLog) makeQuestIconForAct(act, n, x, y int) (*d2ui.Sprite, error) { iconResource := s.questIconsTable(act, n) icon, err := s.uiManager.NewSprite(iconResource, d2resource.PaletteSky) @@ -409,8 +408,6 @@ func (s *QuestLog) makeQuestIconForAct(act, n int, x, y int) (*d2ui.Sprite, erro // playQuestAnimations plays animations for quests (when status=questStatusCompleting) func (s *QuestLog) playQuestAnimations() { - var err error - for j, i := range s.quests[s.selectedTab].icons { questID := s.cordsToQuestID(s.selectedTab+1, j) if s.questStatus[questID] == d2enum.QuestStatusCompleting { @@ -419,11 +416,6 @@ func (s *QuestLog) playQuestAnimations() { // quest should be highlighted and it's label should be displayed s.quests[s.selectedTab].buttons[j].Activate() - err = i.SetCurrentFrame(0) - if err != nil { - s.Error(err.Error()) - } - i.SetPlayLength(questCompleteAnimationDuration) i.PlayForward() i.SetPlayLoop(false) @@ -431,6 +423,23 @@ func (s *QuestLog) playQuestAnimations() { } } +// stopPlayedAnimation stops currently played animations and sets quests in +// completing state to completed (should be used, when quest log is closing) +func (s *QuestLog) stopPlayedAnimations() { + // stops all played animations + for j, i := range s.quests[s.selectedTab].icons { + questID := s.cordsToQuestID(s.selectedTab+1, j) + if s.questStatus[questID] == d2enum.QuestStatusCompleting { + s.questStatus[questID] = d2enum.QuestStatusCompleted + + err := i.SetCurrentFrame(completedFrame) + if err != nil { + s.Error(err.Error()) + } + } + } +} + // setQuestLabel loads quest labels text (title and description) func (s *QuestLog) setQuestLabel() { if s.selectedQuest == d2enum.QuestNone { @@ -455,17 +464,23 @@ func (s *QuestLog) setQuestLabel() { case d2enum.QuestStatusNotStarted: s.questDescr.SetText("") default: - s.questDescr.SetText(strings.Join( - d2util.SplitIntoLinesWithMaxWidth( - s.asset.TranslateString( - fmt.Sprintf("qstsa%dq%d%d", s.selectedTab+1, s.selectedQuest, status), - ), - questDescriptionLenght), - "\n"), - ) + str := fmt.Sprintf("qstsa%dq%d%d", s.selectedTab+1, s.selectedQuest, status) + descr := s.asset.TranslateString(str) + + // if description not found + if str == descr { + s.questDescr.SetText("") + } else { + s.questDescr.SetText(strings.Join( + d2util.SplitIntoLinesWithMaxWidth( + descr, questDescriptionLenght), + "\n"), + ) + } } } +// switch all socket (in current tab) to normal state func (s *QuestLog) clearHighlightment() { for _, i := range s.quests[s.selectedTab].sockets { err := i.SetCurrentFrame(socketNormalFrame) @@ -487,19 +502,23 @@ func (s *QuestLog) setTab(tab int) { s.setQuestLabel() s.playQuestAnimations() + // displays appropriate quests board for i := 0; i < s.maxPlayersAct; i++ { s.quests[i].SetVisible(tab == i) } + // "highlights" appropriate tab for i := 0; i < s.maxPlayersAct; i++ { cv := i + // converts bool to 1/0 if cv == s.selectedTab { mod = 0 } else { mod = 1 } + // sets tab sprite to highlighted/non-highlighted err := s.tab[cv].sprite.SetCurrentFrame(2*cv + mod) if err != nil { s.Error(err.Error()) @@ -513,8 +532,9 @@ func (s *QuestLog) onQuestClicked(number int) { s.Infof("Quest number %d in tab %d clicked", number, s.selectedTab) } +// func (s *QuestLog) onDescrClicked() { - // + s.Info("Quest description button clicked") } // IsOpen returns true if the hero status panel is open @@ -553,21 +573,6 @@ func (s *QuestLog) Close() { s.onCloseCb() } -func (s *QuestLog) stopPlayedAnimations() { - // stops all played animations - for j, i := range s.quests[s.selectedTab].icons { - questID := s.cordsToQuestID(s.selectedTab+1, j) - if s.questStatus[questID] == d2enum.QuestStatusCompleting { - s.questStatus[questID] = d2enum.QuestStatusCompleted - - err := i.SetCurrentFrame(completedFrame) - if err != nil { - s.Error(err.Error()) - } - } - } -} - // SetOnCloseCb the callback run on closing the HeroStatsPanel func (s *QuestLog) SetOnCloseCb(cb func()) { s.onCloseCb = cb @@ -593,10 +598,6 @@ func (s *QuestLog) Advance(elapsed float64) { } } -func (s *QuestLog) renderStaticMenu(target d2interface.Surface) { - s.renderStaticPanelFrames(target) -} - // nolint:dupl // I think it is OK, to duplicate this function func (s *QuestLog) renderStaticPanelFrames(target d2interface.Surface) { frames := []int{ @@ -641,25 +642,3 @@ func (s *QuestLog) cordsToQuestID(act, number int) int { return key } - -//nolint:deadcode,unused // I think, it will be used, if not, we can just remove it -func (s *QuestLog) questIDToCords(id int) (act, number int) { - act = 1 - - for i := 0; i < d2enum.ActsNumber; i++ { - if id < d2enum.NormalActQuestsNumber { - break - } - - act++ - - id -= d2enum.NormalActQuestsNumber - } - - number = id - if act > d2enum.Act4 { - number -= d2enum.HalfQuestsNumber - } - - return act, number -}