Skip to content

Commit

Permalink
Implement quest switcher (#390)
Browse files Browse the repository at this point in the history
Add a button for switching quest dialogs when an NPC is the target of more than one quest state
  • Loading branch information
ethanmoffat authored Oct 28, 2024
1 parent cdffe68 commit 87445f7
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 65 deletions.
2 changes: 1 addition & 1 deletion EOLib.Localization/EOResourceID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ public enum EOResourceID
QUEST_HISTORY = 407,
QUEST_COMPLETED = 408,
QUEST_DID_NOT_FINISH_ANY = 409,

SELECT_A_QUEST = 410,
STATUS_LABEL_ITEM_EQUIP_THIS_ITEM_REQUIRES = 411,

ADMIN_INFO_WORD_DAMAGE = 412,
Expand Down
5 changes: 5 additions & 0 deletions EOLib/Domain/Interact/Quest/QuestActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public QuestActions(IPacketSendService packetSendService,
_questDataProvider = questDataProvider;
}

public void RequestQuest(int npcIndex, int questId) =>
_packetSendService.SendPacket(new QuestUseClientPacket { NpcIndex = npcIndex, QuestId = questId });

public void RespondToQuestDialog(DialogReply reply, int linkId = 0)
{
_questDataProvider.QuestDialogData.MatchSome(data =>
Expand Down Expand Up @@ -49,6 +52,8 @@ public void RequestQuestHistory(QuestPage page)

public interface IQuestActions
{
void RequestQuest(int npcIndex, int questId);

void RespondToQuestDialog(DialogReply reply, int linkId = 0);

void RequestQuestHistory(QuestPage page);
Expand Down
2 changes: 1 addition & 1 deletion EndlessClient/Dialogs/Actions/InGameDialogActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ private void UseQuestDialogSounds(QuestDialog dialog)
dialog.DialogClosing += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.DialogButtonClick);
dialog.BackAction += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.TextBoxFocus);
dialog.NextAction += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.TextBoxFocus);
dialog.LinkClickAction += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.ButtonClick);
dialog.ClickSoundEffect += (_, _) => _sfxPlayer.PlaySfx(SoundEffectID.ButtonClick);
}
}

Expand Down
9 changes: 7 additions & 2 deletions EndlessClient/Dialogs/Factories/QuestDialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using EOLib.Domain.Interact.Quest;
using EOLib.Graphics;
using EOLib.IO.Repositories;
using EOLib.Localization;

namespace EndlessClient.Dialogs.Factories
{
Expand All @@ -16,20 +17,23 @@ public class QuestDialogFactory : IQuestDialogFactory
private readonly IQuestDataProvider _questDataProvider;
private readonly IENFFileProvider _enfFileProvider;
private readonly IContentProvider _contentProvider;
private readonly ILocalizedStringFinder _localizedStringFinder;

public QuestDialogFactory(INativeGraphicsManager nativeGraphicsManager,
IQuestActions questActions,
IEODialogButtonService dialogButtonService,
IQuestDataProvider questDataProvider,
IENFFileProvider enfFileProvider,
IContentProvider contentProvider)
IContentProvider contentProvider,
ILocalizedStringFinder localizedStringFinder)
{
_nativeGraphicsManager = nativeGraphicsManager;
_questActions = questActions;
_dialogButtonService = dialogButtonService;
_questDataProvider = questDataProvider;
_enfFileProvider = enfFileProvider;
_contentProvider = contentProvider;
_localizedStringFinder = localizedStringFinder;
}

public QuestDialog Create()
Expand All @@ -39,7 +43,8 @@ public QuestDialog Create()
_dialogButtonService,
_questDataProvider,
_enfFileProvider,
_contentProvider);
_contentProvider,
_localizedStringFinder);
}
}

Expand Down
215 changes: 154 additions & 61 deletions EndlessClient/Dialogs/QuestDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using EOLib.Domain.Interact.Quest;
using EOLib.Graphics;
using EOLib.IO.Repositories;
using EOLib.Localization;
using Microsoft.Xna.Framework;
using Moffat.EndlessOnline.SDK.Protocol.Net.Client;
using Optional;
Expand All @@ -16,29 +17,40 @@ namespace EndlessClient.Dialogs
{
public class QuestDialog : ScrollingListDialog
{
private enum State
{
TalkToNpc,
SwitchQuest
}

private readonly IQuestActions _questActions;
private readonly IQuestDataProvider _questDataProvider;
private readonly IENFFileProvider _enfFileProvider;
private readonly IContentProvider _contentProvider;
private readonly ILocalizedStringFinder _localizedStringFinder;
private readonly XNAButton _questSwitcher;

private Option<QuestDialogData> _cachedData;

private int _pageIndex = 0;
private State _state = State.TalkToNpc;

public event EventHandler LinkClickAction;
public event EventHandler ClickSoundEffect;

public QuestDialog(INativeGraphicsManager nativeGraphicsManager,
IQuestActions questActions,
IEODialogButtonService dialogButtonService,
IQuestDataProvider questDataProvider,
IENFFileProvider enfFileProvider,
IContentProvider contentProvider)
IContentProvider contentProvider,
ILocalizedStringFinder localizedStringFinder)
: base(nativeGraphicsManager, dialogButtonService, dialogType: DialogType.NpcQuestDialog)
{
_questActions = questActions;
_questDataProvider = questDataProvider;
_enfFileProvider = enfFileProvider;
_contentProvider = contentProvider;
_localizedStringFinder = localizedStringFinder;

_cachedData = Option.None<QuestDialogData>();

Expand All @@ -51,6 +63,24 @@ public QuestDialog(INativeGraphicsManager nativeGraphicsManager,
if (e.Result == XNADialogResult.OK)
_questActions.RespondToQuestDialog(DialogReply.Ok);
};

_questSwitcher = new XNAButton(
nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27, false),
new Vector2(252, 16),
new Rectangle(303, 242, 16, 15),
new Rectangle(303, 242, 16, 15))
{
Visible = false,
};
_questSwitcher.OnClick += (_, _) => ToggleSwitcherState();
_questSwitcher.OnClick += (_, _) => ClickSoundEffect?.Invoke(this, EventArgs.Empty);
_questSwitcher.SetParentControl(this);
}

public override void Initialize()
{
_questSwitcher.Initialize();
base.Initialize();
}

protected override void OnUpdateControl(GameTime gameTime)
Expand All @@ -59,14 +89,28 @@ protected override void OnUpdateControl(GameTime gameTime)
base.OnUpdateControl(gameTime);
}

private void ToggleSwitcherState()
{
_state = _state == State.TalkToNpc ? State.SwitchQuest : State.TalkToNpc;
_cachedData.MatchSome(UpdateDialogControls);
}

private void UpdateCachedDataIfNeeded(Option<QuestDialogData> cachedData, QuestDialogData repoData)
{
cachedData.Match(
some: cached =>
{
_cachedData = Option.Some(repoData);
if (!cached.Equals(repoData))
{
if (_state == State.SwitchQuest)
{
// New data received after switching quests
ToggleSwitcherState();
}

UpdateDialogControls(repoData);
}
},
none: () =>
{
Expand All @@ -80,92 +124,141 @@ private void UpdateDialogControls(QuestDialogData repoData)
_pageIndex = 0;

UpdateTitle(repoData);
UpdateQuestSwitcherButton(repoData);
UpdateDialogDisplayText(repoData);
UpdateButtons(repoData);
}

private void UpdateTitle(QuestDialogData repoData)
{
if (_questDataProvider.RequestedNPC != null)
{
var npcName = _enfFileProvider.ENFFile[_questDataProvider.RequestedNPC.ID].Name;
var titleText = npcName;
if (!repoData.DialogTitles.ContainsKey(repoData.VendorID) && repoData.DialogTitles.Count == 1)
titleText += $" - {repoData.DialogTitles.Single().Value}";
else if (repoData.DialogTitles.ContainsKey(repoData.VendorID))
titleText += $" - {repoData.DialogTitles[repoData.VendorID]}";

_titleText.Text = titleText;
_titleText.ResizeBasedOnText();
}
else
switch (_state)
{
_titleText.Text = string.Empty;
case State.TalkToNpc:
if (_questDataProvider.RequestedNPC != null)
{
var npcName = _enfFileProvider.ENFFile[_questDataProvider.RequestedNPC.ID].Name;
var titleText = npcName;
if (!repoData.DialogTitles.ContainsKey(repoData.VendorID) && repoData.DialogTitles.Count == 1)
titleText += $" - {repoData.DialogTitles.Single().Value}";
else if (repoData.DialogTitles.ContainsKey(repoData.VendorID))
titleText += $" - {repoData.DialogTitles[repoData.VendorID]}";

_titleText.Text = titleText;
_titleText.ResizeBasedOnText();
}
else
{
_titleText.Text = string.Empty;
}
break;
case State.SwitchQuest:
_titleText.Text = _localizedStringFinder.GetString(EOResourceID.SELECT_A_QUEST);
break;
}
}

private void UpdateQuestSwitcherButton(QuestDialogData repoData)
{
_questSwitcher.Visible = repoData.DialogTitles.Count > 1;
}

private void UpdateDialogDisplayText(QuestDialogData repoData)
{
ClearItemList();

var rows = new List<string>();
switch (_state)
{
case State.TalkToNpc:
{
var rows = new List<string>();

var ts = new TextSplitter(repoData.PageText[_pageIndex], _contentProvider.Fonts[Constants.FontSize09]);
if (!ts.NeedsProcessing)
rows.Add(repoData.PageText[_pageIndex]);
else
rows.AddRange(ts.SplitIntoLines());
var ts = new TextSplitter(repoData.PageText[_pageIndex], _contentProvider.Fonts[Constants.FontSize09]);
if (!ts.NeedsProcessing)
rows.Add(repoData.PageText[_pageIndex]);
else
rows.AddRange(ts.SplitIntoLines());

int index = 0;
foreach (var row in rows)
{
var rowItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++)
{
PrimaryText = row,
};
int index = 0;
foreach (var row in rows)
{
var rowItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++)
{
PrimaryText = row,
};

AddItemToList(rowItem, sortList: false);
}
AddItemToList(rowItem, sortList: false);
}

// The links are only shown on the last page of the quest dialog
if (_pageIndex < repoData.PageText.Count - 1)
return;
// The links are only shown on the last page of the quest dialog
if (_pageIndex < repoData.PageText.Count - 1)
return;

var item = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++) { PrimaryText = " " };
AddItemToList(item, sortList: false);
var item = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++) { PrimaryText = " " };
AddItemToList(item, sortList: false);

foreach (var action in repoData.Actions)
{
var actionItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++)
{
PrimaryText = action.DisplayText
};
foreach (var action in repoData.Actions)
{
var actionItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++)
{
PrimaryText = action.DisplayText
};

var linkIndex = action.ActionID;
actionItem.SetPrimaryClickAction((_, _) =>
{
_questActions.RespondToQuestDialog(DialogReply.Link, linkIndex);
LinkClickAction?.Invoke(this, EventArgs.Empty);
Close(XNADialogResult.Cancel);
});
var linkIndex = action.ActionID;
actionItem.SetPrimaryClickAction((_, _) =>
{
_questActions.RespondToQuestDialog(DialogReply.Link, linkIndex);
ClickSoundEffect?.Invoke(this, EventArgs.Empty);
Close(XNADialogResult.Cancel);
});

AddItemToList(actionItem, sortList: false);
}
}
break;
case State.SwitchQuest:
{
var index = 0;
foreach (var title in repoData.DialogTitles)
{
var actionItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Small, index++)
{
PrimaryText = title.Value
};

AddItemToList(actionItem, sortList: false);
actionItem.SetPrimaryClickAction((_, _) =>
{
_questActions.RequestQuest(_questDataProvider.RequestedNPC.Index, title.Key);
ClickSoundEffect?.Invoke(this, EventArgs.Empty);
});

AddItemToList(actionItem, sortList: false);
}
}
break;
}
}

private void UpdateButtons(QuestDialogData repoData)
{
bool morePages = _pageIndex < repoData.PageText.Count - 1;
bool firstPage = _pageIndex == 0;

if (firstPage && morePages)
Buttons = ScrollingListDialogButtons.CancelNext;
else if (!firstPage && morePages)
Buttons = ScrollingListDialogButtons.BackNext;
else if (firstPage)
Buttons = ScrollingListDialogButtons.CancelOk;
else
Buttons = ScrollingListDialogButtons.BackOk;
switch (_state)
{
case State.TalkToNpc:
bool morePages = _pageIndex < repoData.PageText.Count - 1;
bool firstPage = _pageIndex == 0;

if (firstPage && morePages)
Buttons = ScrollingListDialogButtons.CancelNext;
else if (!firstPage && morePages)
Buttons = ScrollingListDialogButtons.BackNext;
else if (firstPage)
Buttons = ScrollingListDialogButtons.CancelOk;
else
Buttons = ScrollingListDialogButtons.BackOk;
break;
case State.SwitchQuest:
Buttons = ScrollingListDialogButtons.OffsetCancel;
break;
}
}

private void NextPage(object sender, EventArgs e)
Expand Down

0 comments on commit 87445f7

Please sign in to comment.