Skip to content

Commit

Permalink
Merge pull request #320 from ethanmoffat/inn
Browse files Browse the repository at this point in the history
Innkeeper dialog implementation. Includes citizen registration, unregister, and inn sleeping
  • Loading branch information
ethanmoffat authored May 25, 2023
2 parents 3e7e592 + b3a6564 commit eeed6fc
Show file tree
Hide file tree
Showing 29 changed files with 954 additions and 55 deletions.
23 changes: 23 additions & 0 deletions EOLib.Localization/EOResourceID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,29 @@ public enum EOResourceID
LOADING_GAME_HINT_FIRST = 368,
LOADING_GAME_HINT_LAST = 374,

INN_REGISTRATION_SERVICE = 384,
INN_CITIZEN_REGISTRATION_SERVICE = 385,
INN_SIGN_UP = 386,
INN_BECOME_A_CITIZEN = 387,
INN_UNSUBSCRIBE = 388,
INN_GIVE_UP_CITIZENSHIP = 389,
INN_BECOME_CITIZEN_TEXT_1 = 390,
INN_BECOME_CITIZEN_TEXT_2 = 391,
INN_BECOME_CITIZEN_TEXT_LINK = 392,
INN_GIVE_UP_TEXT_1 = 393,
INN_GIVE_UP_TEXT_LINK = 394,
INN_BECOME_CITIZEN_CONGRATULATIONS = 395,
INN_YOUR_ANSWERS_WERE_INCORRECT = 396,
INN_YOU_ARE_NOT_A_CITIZEN = 397,
INN_YOU_ARE_NO_LONGER_A_CITIZEN = 398,
INN_SLEEP = 399,
INN_FULL_HP_RECOVERY = 400,
INN_A_GOOD_NIGHT_REST_WILL_COST_YOU = 401,

YOUR_ATTACK_DID_NOTHING = 402, // ?

INN_YOU_ARE_ALREADY_A_CITIZEN_OF_A_TOWN = 403,

STATUS_LABEL_ITEM_EQUIP_CAN_ONLY_BE_USED_BY = 404,
QUEST_PROGRESS = 405,
QUEST_DID_NOT_START_ANY = 406,
Expand Down
81 changes: 81 additions & 0 deletions EOLib/Domain/Interact/Citizen/CitizenActions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using AutomaticTypeMapper;
using EOLib.Domain.Map;
using EOLib.Net;
using EOLib.Net.Communication;
using System.Collections.Generic;

namespace EOLib.Domain.Interact.Citizen
{
[AutoMappedType]
public class CitizenActions : ICitizenActions
{
private readonly IPacketSendService _packetSendService;
private readonly ICitizenDataProvider _citizenDataProvider;
private readonly ICurrentMapStateProvider _currentMapStateProvider;

public CitizenActions(IPacketSendService packetSendService,
ICitizenDataProvider citizenDataProvider,
ICurrentMapStateProvider currentMapStateProvider)
{
_packetSendService = packetSendService;
_citizenDataProvider = citizenDataProvider;
_currentMapStateProvider = currentMapStateProvider;
}

public void RequestSleep()
{
var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Request)
.AddShort(_currentMapStateProvider.MapWarpSession.ValueOr(0))
.AddShort(_citizenDataProvider.BehaviorID.ValueOr(0))
.Build();

_packetSendService.SendPacket(packet);

}

public void ConfirmSleep()
{
var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Accept)
.AddShort(_currentMapStateProvider.MapWarpSession.ValueOr(0))
.AddShort(_citizenDataProvider.BehaviorID.ValueOr(0))
.Build();

_packetSendService.SendPacket(packet);
}

public void SignUp(IReadOnlyList<string> answers)
{
var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Reply)
.AddShort(_currentMapStateProvider.MapWarpSession.ValueOr(0))
.AddByte(255)
.AddShort(_citizenDataProvider.BehaviorID.ValueOr(0))
.AddByte(255)
.AddBreakString(answers[0])
.AddBreakString(answers[1])
.AddString(answers[2])
.Build();

_packetSendService.SendPacket(packet);
}

public void Unsubscribe()
{
var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Remove)
.AddShort(_citizenDataProvider.BehaviorID.ValueOr(0))
.Build();

_packetSendService.SendPacket(packet);
}
}

public interface ICitizenActions
{
void RequestSleep();

void ConfirmSleep();

void SignUp(IReadOnlyList<string> answers);

void Unsubscribe();
}
}
41 changes: 41 additions & 0 deletions EOLib/Domain/Interact/Citizen/CitizenDataRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using AutomaticTypeMapper;
using Optional;
using System.Collections.Generic;

namespace EOLib.Domain.Interact.Citizen
{
public interface ICitizenDataRepository
{
Option<int> BehaviorID { get; set; }

Option<int> CurrentHomeID { get; set; }

List<string> Questions { get; set; }
}

public interface ICitizenDataProvider
{
Option<int> BehaviorID { get; }

Option<int> CurrentHomeID { get; }

IReadOnlyList<string> Questions { get; }
}

[AutoMappedType(IsSingleton = true)]
public class CitizenDataRepository : ICitizenDataRepository, ICitizenDataProvider
{
public Option<int> BehaviorID { get; set; }

public Option<int> CurrentHomeID { get; set; }

public List<string> Questions { get; set; }

IReadOnlyList<string> ICitizenDataProvider.Questions => Questions;

public CitizenDataRepository()
{
Questions = new List<string>();
}
}
}
8 changes: 8 additions & 0 deletions EOLib/Domain/Interact/Citizen/CitizenUnsubscribeReply.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace EOLib.Domain.Interact.Citizen
{
public enum CitizenUnsubscribeReply
{
NotACitizen = 0,
Unsubscribed = 1
}
}
17 changes: 15 additions & 2 deletions EOLib/Domain/Interact/INPCInteractionNotifier.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutomaticTypeMapper;
using EOLib.Domain.Interact.Citizen;
using EOLib.Domain.Interact.Skill;
using EOLib.IO;

Expand All @@ -10,11 +11,17 @@ public interface INPCInteractionNotifier

void NotifySkillLearnSuccess(int spellId, int characterGold);

void NotifySkillLearnFail(SkillmasterReply skillmasterReply, int classId);
void NotifySkillLearnFail(SkillmasterReply reply, int classId);

void NotifySkillForget();

void NotifyStatReset();

void NotifyCitizenUnsubscribe(CitizenUnsubscribeReply reply);

void NotifyCitizenSignUp(int questionsWrong);

void NotifyCitizenRequestSleep(int sleepCost);
}

[AutoMappedType]
Expand All @@ -24,10 +31,16 @@ public void NotifyInteractionFromNPC(NPCType npcType) { }

public void NotifySkillLearnSuccess(int spellId, int characterGold) { }

public void NotifySkillLearnFail(SkillmasterReply skillmasterReply, int classId) { }
public void NotifySkillLearnFail(SkillmasterReply reply, int classId) { }

public void NotifySkillForget() { }

public void NotifyStatReset() { }

public void NotifyCitizenUnsubscribe(CitizenUnsubscribeReply reply) { }

public void NotifyCitizenSignUp(int questionsWrong) { }

public void NotifyCitizenRequestSleep(int sleepCost) { }
}
}
11 changes: 11 additions & 0 deletions EOLib/Domain/Interact/MapNPCActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ public void RequestSkillmaster(NPC.NPC npc)

_packetSendService.SendPacket(packet);
}

public void RequestInnkeeper(NPC.NPC npc)
{
var packet = new PacketBuilder(PacketFamily.Citizen, PacketAction.Open)
.AddShort(npc.Index)
.Build();

_packetSendService.SendPacket(packet);
}
}

public interface IMapNPCActions
Expand All @@ -74,5 +83,7 @@ public interface IMapNPCActions
void RequestBank(NPC.NPC npc);

void RequestSkillmaster(NPC.NPC npc);

void RequestInnkeeper(NPC.NPC npc);
}
}
7 changes: 7 additions & 0 deletions EOLib/Domain/Map/CurrentMapStateRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public interface ICurrentMapStateRepository

Option<DateTime> MapWarpTime { get; set; }

bool IsSleepWarp { get; set; }

HashSet<int> UnknownPlayerIDs { get; set; }

HashSet<int> UnknownNPCIndexes { get; set; }
Expand Down Expand Up @@ -70,6 +72,8 @@ public interface ICurrentMapStateProvider

Option<DateTime> MapWarpTime { get; }

bool IsSleepWarp { get; }

HashSet<int> UnknownPlayerIDs { get; }

HashSet<int> UnknownNPCIndexes { get; }
Expand Down Expand Up @@ -106,6 +110,8 @@ public class CurrentMapStateRepository : ICurrentMapStateRepository, ICurrentMap

public Option<DateTime> MapWarpTime { get; set; }

public bool IsSleepWarp { get; set; }

public HashSet<int> UnknownPlayerIDs { get; set; }

public HashSet<int> UnknownNPCIndexes { get; set; }
Expand Down Expand Up @@ -145,6 +151,7 @@ public void ResetState()
MapWarpState = WarpState.None;
MapWarpSession = Option.None<int>();
MapWarpID = Option.None<int>();
IsSleepWarp = false;
}
}
}
51 changes: 51 additions & 0 deletions EOLib/PacketHandlers/Citizen/CitizenAcceptHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using AutomaticTypeMapper;
using EOLib.Domain.Character;
using EOLib.Domain.Login;
using EOLib.Domain.Map;
using EOLib.Net;
using EOLib.Net.Handlers;

namespace EOLib.PacketHandlers.Citizen
{
/// <summary>
/// Sent when the player has accepted the cost of sleeping at an inn
/// </summary>
[AutoMappedType]
public class CitizenAcceptHandler : InGameOnlyPacketHandler
{
private readonly ICharacterInventoryRepository _characterInventoryRepository;
private readonly ICurrentMapStateRepository _currentMapStateRepository;
private readonly ICharacterRepository _characterRepository;

public override PacketFamily Family => PacketFamily.Citizen;

public override PacketAction Action => PacketAction.Accept;

public CitizenAcceptHandler(IPlayerInfoProvider playerInfoProvider,
ICharacterInventoryRepository characterInventoryRepository,
ICurrentMapStateRepository currentMapStateRepository,
ICharacterRepository characterRepository)
: base(playerInfoProvider)
{
_characterInventoryRepository = characterInventoryRepository;
_currentMapStateRepository = currentMapStateRepository;
_characterRepository = characterRepository;
}

public override bool HandlePacket(IPacket packet)
{
var goldRemaining = packet.ReadInt();
_characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1);
_characterInventoryRepository.ItemInventory.Add(new InventoryItem(1, goldRemaining));

var stats = _characterRepository.MainCharacter.Stats;
stats = stats.WithNewStat(CharacterStat.HP, stats[CharacterStat.MaxHP])
.WithNewStat(CharacterStat.TP, stats[CharacterStat.MaxTP]);
_characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats);

_currentMapStateRepository.IsSleepWarp = true;

return true;
}
}
}
59 changes: 59 additions & 0 deletions EOLib/PacketHandlers/Citizen/CitizenOpenHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using AutomaticTypeMapper;
using EOLib.Domain.Interact;
using EOLib.Domain.Interact.Citizen;
using EOLib.Domain.Login;
using EOLib.Domain.Map;
using EOLib.Net;
using EOLib.Net.Handlers;
using Optional;
using System.Collections.Generic;

namespace EOLib.PacketHandlers.Citizen
{
/// <summary>
/// Sent when opening an Innkeeper dialog
/// </summary>
[AutoMappedType]
public class CitizenOpenHandler : InGameOnlyPacketHandler
{
private readonly ICitizenDataRepository _citizenDataRepository;
private readonly ICurrentMapStateRepository _currentMapStateRepository;
private readonly IEnumerable<INPCInteractionNotifier> _npcInteractionNotifiers;

public override PacketFamily Family => PacketFamily.Citizen;

public override PacketAction Action => PacketAction.Open;

public CitizenOpenHandler(IPlayerInfoProvider playerInfoProvider,
ICitizenDataRepository citizenDataRepository,
ICurrentMapStateRepository currentMapStateRepository,
IEnumerable<INPCInteractionNotifier> npcInteractionNotifiers)
: base(playerInfoProvider)
{
_citizenDataRepository = citizenDataRepository;
_currentMapStateRepository = currentMapStateRepository;
_npcInteractionNotifiers = npcInteractionNotifiers;
}

public override bool HandlePacket(IPacket packet)
{
_citizenDataRepository.BehaviorID = Option.Some(packet.ReadThree());
_citizenDataRepository.CurrentHomeID = packet.ReadChar().SomeWhen(x => x > 0);
_currentMapStateRepository.MapWarpSession = Option.Some(packet.ReadShort());

if (packet.ReadByte() != 255)
return false;

var question1 = packet.ReadBreakString();
var question2 = packet.ReadBreakString();
var question3 = packet.ReadEndString();

_citizenDataRepository.Questions = new List<string> { question1, question2, question3 };

foreach (var notifier in _npcInteractionNotifiers)
notifier.NotifyInteractionFromNPC(IO.NPCType.Inn);

return true;
}
}
}
Loading

0 comments on commit eeed6fc

Please sign in to comment.