-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #170 from ethanmoffat/quest_dlg
Implement NPC quest dialog and related packet handlers
- Loading branch information
Showing
29 changed files
with
880 additions
and
444 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using AutomaticTypeMapper; | ||
using EOLib.IO; | ||
|
||
namespace EOLib.Domain.Interact | ||
{ | ||
public interface INPCInteractionNotifier | ||
{ | ||
void NotifyInteractionFromNPC(NPCType npcType); | ||
} | ||
|
||
[AutoMappedType] | ||
public class NoOpNPCInteractionNotifier : INPCInteractionNotifier | ||
{ | ||
public void NotifyInteractionFromNPC(NPCType npcType) { } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace EOLib.Domain.Interact.Quest | ||
{ | ||
public enum DialogReply | ||
{ | ||
Ok = 1, | ||
Link | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using AutomaticTypeMapper; | ||
|
||
namespace EOLib.Domain.Interact.Quest | ||
{ | ||
public interface IStatusLabelNotifier | ||
{ | ||
void ShowWarning(string message); | ||
} | ||
|
||
[AutoMappedType] | ||
public class NoOpStatusLabelNotifier : IStatusLabelNotifier | ||
{ | ||
public void ShowWarning(string message) { } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using AutomaticTypeMapper; | ||
using EOLib.Net; | ||
using EOLib.Net.Communication; | ||
|
||
namespace EOLib.Domain.Interact.Quest | ||
{ | ||
[AutoMappedType] | ||
public class QuestActions : IQuestActions | ||
{ | ||
private readonly IPacketSendService _packetSendService; | ||
private readonly IQuestDataProvider _questDataProvider; | ||
|
||
public QuestActions(IPacketSendService packetSendService, | ||
IQuestDataProvider questDataProvider) | ||
{ | ||
_packetSendService = packetSendService; | ||
_questDataProvider = questDataProvider; | ||
} | ||
|
||
public void RespondToQuestDialog(DialogReply reply, byte linkId = 0) | ||
{ | ||
_questDataProvider.QuestDialogData.MatchSome(data => | ||
{ | ||
var builder = new PacketBuilder(PacketFamily.Quest, PacketAction.Accept) | ||
.AddShort(data.SessionID) // ignored by eoserv | ||
.AddShort(data.DialogID) // ignored by eoserv | ||
.AddShort(data.QuestID) | ||
.AddShort(data.VendorID) // ignored by eoserv | ||
.AddChar((byte)reply); | ||
|
||
if (reply == DialogReply.Link) | ||
builder = builder.AddChar(linkId); | ||
|
||
var packet = builder.Build(); | ||
_packetSendService.SendPacket(packet); | ||
}); | ||
} | ||
} | ||
|
||
public interface IQuestActions | ||
{ | ||
void RespondToQuestDialog(DialogReply reply, byte linkId = 0); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using AutomaticTypeMapper; | ||
using EOLib.Domain.NPC; | ||
using Optional; | ||
|
||
namespace EOLib.Domain.Interact.Quest | ||
{ | ||
public interface IQuestDataRepository : IResettable | ||
{ | ||
INPC RequestedNPC { get; set; } | ||
|
||
Option<IQuestDialogData> QuestDialogData { get; set; } | ||
} | ||
|
||
public interface IQuestDataProvider : IResettable | ||
{ | ||
INPC RequestedNPC { get; } | ||
|
||
Option<IQuestDialogData> QuestDialogData { get; } | ||
} | ||
|
||
[AutoMappedType(IsSingleton = true)] | ||
public class QuestDataRepository : IQuestDataProvider, IQuestDataRepository | ||
{ | ||
public INPC RequestedNPC { get; set; } | ||
|
||
public Option<IQuestDialogData> QuestDialogData { get; set; } | ||
|
||
public QuestDataRepository() | ||
{ | ||
ResetState(); | ||
} | ||
|
||
public void ResetState() | ||
{ | ||
QuestDialogData = Option.None<IQuestDialogData>(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace EOLib.Domain.Interact.Quest | ||
{ | ||
public class QuestDialogData : IQuestDialogData | ||
{ | ||
public short VendorID { get; private set; } | ||
|
||
public short QuestID { get; private set; } | ||
|
||
public short SessionID { get; private set; } | ||
|
||
public short DialogID { get; private set; } | ||
|
||
public IReadOnlyDictionary<short, string> DialogTitles { get; private set; } | ||
|
||
public IReadOnlyList<string> PageText { get; private set; } | ||
|
||
public IReadOnlyList<(short ActionID, string DisplayText)> Actions { get; private set; } | ||
|
||
public QuestDialogData() | ||
{ | ||
DialogTitles = new Dictionary<short, string>(); | ||
PageText = new List<string>(); | ||
Actions = new List<(short, string)>(); | ||
} | ||
|
||
private QuestDialogData(short vendorID, | ||
short questID, | ||
short sessionID, | ||
short dialogID, | ||
IReadOnlyDictionary<short, string> dialogTitles, | ||
IReadOnlyList<string> pageText, | ||
IReadOnlyList<(short, string)> actions) | ||
{ | ||
VendorID = vendorID; | ||
QuestID = questID; | ||
SessionID = sessionID; | ||
DialogID = dialogID; | ||
DialogTitles = dialogTitles; | ||
PageText = pageText; | ||
Actions = actions; | ||
} | ||
|
||
public IQuestDialogData WithVendorID(short vendorId) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.VendorID = vendorId; | ||
return copy; | ||
} | ||
|
||
public IQuestDialogData WithQuestID(short questId) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.QuestID = questId; | ||
return copy; | ||
} | ||
|
||
public IQuestDialogData WithSessionID(short sessionId) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.SessionID = sessionId; | ||
return copy; | ||
} | ||
|
||
public IQuestDialogData WithDialogID(short dialogId) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.DialogID = dialogId; | ||
return copy; | ||
} | ||
|
||
public IQuestDialogData WithDialogTitles(IReadOnlyDictionary<short, string> dialogTitles) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.DialogTitles = dialogTitles; | ||
return copy; | ||
} | ||
|
||
public IQuestDialogData WithPageText(IReadOnlyList<string> pageText) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.PageText = pageText; | ||
return copy; | ||
} | ||
|
||
public IQuestDialogData WithActions(IReadOnlyList<(short, string)> actions) | ||
{ | ||
var copy = MakeCopy(this); | ||
copy.Actions = actions; | ||
return copy; | ||
} | ||
|
||
private static QuestDialogData MakeCopy(IQuestDialogData other) | ||
{ | ||
return new QuestDialogData( | ||
other.VendorID, | ||
other.QuestID, | ||
other.SessionID, | ||
other.DialogID, | ||
other.DialogTitles.ToDictionary(k => k.Key, v => v.Value), | ||
new List<string>(other.PageText), | ||
new List<(short, string)>(other.Actions)); | ||
} | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
var other = obj as QuestDialogData; | ||
if (other == null) return false; | ||
|
||
return other.VendorID == VendorID | ||
&& other.QuestID == QuestID | ||
&& other.SessionID == SessionID | ||
&& other.DialogID == DialogID | ||
&& other.DialogTitles.SequenceEqual(DialogTitles) | ||
&& other.PageText.SequenceEqual(PageText) | ||
&& other.Actions.SequenceEqual(Actions); | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
int hashCode = 170256730; | ||
hashCode = hashCode * -1521134295 + VendorID.GetHashCode(); | ||
hashCode = hashCode * -1521134295 + QuestID.GetHashCode(); | ||
hashCode = hashCode * -1521134295 + SessionID.GetHashCode(); | ||
hashCode = hashCode * -1521134295 + DialogID.GetHashCode(); | ||
hashCode = hashCode * -1521134295 + DialogTitles.Aggregate(170256730, (a, b) => a * -1521134295 + b.GetHashCode()); | ||
hashCode = hashCode * -1521134295 + PageText.Aggregate(170256730, (a, b) => a * -1521134295 + b.GetHashCode()); | ||
hashCode = hashCode * -1521134295 + Actions.Aggregate(170256730, (a, b) => a * -1521134295 + b.GetHashCode()); | ||
return hashCode; | ||
} | ||
} | ||
|
||
public interface IQuestDialogData | ||
{ | ||
/// <summary> | ||
/// NPC Vendor ID (<see cref="EOLib.IO.Pub.ENFRecord.VendorID" />) | ||
/// </summary> | ||
short VendorID { get; } | ||
|
||
/// <summary> | ||
/// Quest ID, for the current dialog being shown (part of quest state in EO+ parser) | ||
/// </summary> | ||
short QuestID { get; } | ||
|
||
/// <summary> | ||
/// Session ID, not used by eoserv | ||
/// </summary> | ||
short SessionID { get; } | ||
|
||
/// <summary> | ||
/// Dialog ID, not used by eoserv | ||
/// </summary> | ||
short DialogID { get; } | ||
|
||
/// <summary> | ||
/// Quest dialog titles for the current character, keyed on <see cref="VendorID" />. | ||
/// </summary> | ||
IReadOnlyDictionary<short, string> DialogTitles { get; } | ||
|
||
/// <summary> | ||
/// Text for the quest dialog, one entry per page. | ||
/// </summary> | ||
IReadOnlyList<string> PageText { get; } | ||
|
||
/// <summary> | ||
/// Links for the quest dialog, only shown on the last page. | ||
/// </summary> | ||
IReadOnlyList<(short ActionID, string DisplayText)> Actions { get; } | ||
|
||
IQuestDialogData WithVendorID(short vendorId); | ||
|
||
IQuestDialogData WithQuestID(short questId); | ||
|
||
IQuestDialogData WithSessionID(short sessionId); | ||
|
||
IQuestDialogData WithDialogID(short dialogId); | ||
|
||
IQuestDialogData WithDialogTitles(IReadOnlyDictionary<short, string> dialogTitles); | ||
|
||
IQuestDialogData WithPageText(IReadOnlyList<string> pageText); | ||
|
||
IQuestDialogData WithActions(IReadOnlyList<(short, string)> actions); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.