Skip to content

Commit

Permalink
Merge pull request #183 from ethanmoffat/spell_casting
Browse files Browse the repository at this point in the history
Implement selection/casting of spells by main player. Enforce SP limits.
  • Loading branch information
ethanmoffat authored Apr 19, 2022
2 parents 7aad651 + 6fd8fd0 commit 4700b28
Show file tree
Hide file tree
Showing 37 changed files with 814 additions and 266 deletions.
2 changes: 1 addition & 1 deletion EOLib.Localization/EOResourceID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public enum EOResourceID
STRING_SERVER = 118,
SERVER_MESSAGE_MAP_MUTATION = 119,
STATUS_LABEL_NOTHING_HAPPENED = 120,

YOU_CANNOT_ATTACK_THIS_NPC = 121,
DIALOG_SHOP_BUY_ITEMS = 122,
DIALOG_SHOP_SELL_ITEMS = 123,
DIALOG_SHOP_CRAFT_ITEMS = 124,
Expand Down
2 changes: 2 additions & 0 deletions EOLib/Domain/Character/Character.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class Character : ICharacter
{
public int ID { get; private set; }

public int Index => ID;

public string Name { get; private set; }

public string Title { get; private set; }
Expand Down
28 changes: 18 additions & 10 deletions EOLib/Domain/Character/CharacterActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ namespace EOLib.Domain.Character
public class CharacterActions : ICharacterActions
{
private readonly IPacketSendService _packetSendService;
private readonly ICharacterProvider _characterProvider;
private readonly ICharacterRepository _characterRepository;
private readonly IESFFileProvider _spellFileProvider;

public CharacterActions(IPacketSendService packetSendService,
ICharacterProvider characterProvider,
ICharacterRepository characterRepository,
IESFFileProvider spellFileProvider)
{
_packetSendService = packetSendService;
_characterProvider = characterProvider;
_characterRepository = characterRepository;
_spellFileProvider = spellFileProvider;
}

Expand All @@ -37,9 +37,9 @@ public void Face(EODirection direction)

public void Walk()
{
var admin = _characterProvider.MainCharacter.NoWall &&
_characterProvider.MainCharacter.AdminLevel != AdminLevel.Player;
var renderProperties = _characterProvider.MainCharacter.RenderProperties;
var admin = _characterRepository.MainCharacter.NoWall &&
_characterRepository.MainCharacter.AdminLevel != AdminLevel.Player;
var renderProperties = _characterRepository.MainCharacter.RenderProperties;

var packet = new PacketBuilder(PacketFamily.Walk, admin ? PacketAction.Admin : PacketAction.Player)
.AddChar((byte) renderProperties.Direction)
Expand All @@ -53,8 +53,12 @@ public void Walk()

public void Attack()
{
var c = _characterRepository.MainCharacter;
var sp = Math.Max(0, c.Stats[CharacterStat.SP] - 1);
_characterRepository.MainCharacter = c.WithStats(c.Stats.WithNewStat(CharacterStat.SP, sp));

var packet = new PacketBuilder(PacketFamily.Attack, PacketAction.Use)
.AddChar((byte) _characterProvider.MainCharacter.RenderProperties.Direction)
.AddChar((byte) _characterRepository.MainCharacter.RenderProperties.Direction)
.AddThree(DateTime.Now.ToEOTimeStamp())
.Build();

Expand All @@ -63,7 +67,7 @@ public void Attack()

public void ToggleSit()
{
var renderProperties = _characterProvider.MainCharacter.RenderProperties;
var renderProperties = _characterRepository.MainCharacter.RenderProperties;
var sitAction = renderProperties.SitState == SitState.Standing
? SitAction.Sit
: SitAction.Stand;
Expand All @@ -81,7 +85,7 @@ public void ToggleSit()

public void SitInChair()
{
var rp = _characterProvider.MainCharacter.RenderProperties;
var rp = _characterRepository.MainCharacter.RenderProperties;
var action = rp.SitState == SitState.Chair ? SitAction.Stand : SitAction.Sit;
var packet = new PacketBuilder(PacketFamily.Chair, PacketAction.Request)
.AddChar((byte)action)
Expand All @@ -106,6 +110,10 @@ public void CastSpell(int spellId, ISpellTargetable target)
{
var data = _spellFileProvider.ESFFile.Single(x => x.ID == spellId);

var c = _characterRepository.MainCharacter;
var sp = Math.Max(0, c.Stats[CharacterStat.SP] - data.SP);
_characterRepository.MainCharacter = c.WithStats(c.Stats.WithNewStat(CharacterStat.SP, sp));

var action = data.Target == IO.SpellTarget.Self
? PacketAction.TargetSelf
: data.Target == IO.SpellTarget.Normal
Expand Down Expand Up @@ -138,7 +146,7 @@ public void CastSpell(int spellId, ISpellTargetable target)
.AddChar(1) // unknown
.AddShort(1) // unknown
.AddShort((short)spellId)
.AddShort((short)target.ID)
.AddShort((short)target.Index)
.AddThree(DateTime.Now.ToEOTimeStamp());
}
else
Expand Down
10 changes: 7 additions & 3 deletions EOLib/Domain/Character/CharacterRenderProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class CharacterRenderProperties : ICharacterRenderProperties
public int ActualAttackFrame { get; private set; }
public int RenderAttackFrame { get; private set; }
public int EmoteFrame { get; private set; }
public int ActualSpellCastFrame { get; private set; }

public SitState SitState { get; private set; }
public Emote Emote { get; private set; }
Expand Down Expand Up @@ -179,10 +180,10 @@ public ICharacterRenderProperties WithNextEmoteFrame()

public ICharacterRenderProperties WithNextSpellCastFrame()
{
// spell cast frame ticks: 0 0 1 1 1
var props = MakeCopy(this);
props.CurrentAction = props.CurrentAction == CharacterActionState.Standing
? CharacterActionState.SpellCast
: CharacterActionState.Standing;
props.ActualSpellCastFrame = (props.ActualSpellCastFrame + 1) % MAX_NUMBER_OF_ATTACK_FRAMES;
props.CurrentAction = props.ActualSpellCastFrame == 0 ? CharacterActionState.Standing : CharacterActionState.SpellCast;
return props;
}

Expand Down Expand Up @@ -271,6 +272,7 @@ private static CharacterRenderProperties MakeCopy(ICharacterRenderProperties oth
ActualAttackFrame = other.ActualAttackFrame,
RenderAttackFrame = other.RenderAttackFrame,
EmoteFrame = other.EmoteFrame,
ActualSpellCastFrame = other.ActualSpellCastFrame,

SitState = other.SitState,
Emote = other.Emote,
Expand Down Expand Up @@ -304,6 +306,7 @@ public override bool Equals(object obj)
RenderWalkFrame == properties.RenderWalkFrame &&
RenderAttackFrame == properties.RenderAttackFrame &&
EmoteFrame == properties.EmoteFrame &&
ActualSpellCastFrame == properties.ActualSpellCastFrame &&
SitState == properties.SitState &&
Emote == properties.Emote &&
IsHidden == properties.IsHidden &&
Expand Down Expand Up @@ -333,6 +336,7 @@ public override int GetHashCode()
hashCode = hashCode * -1521134295 + ActualAttackFrame.GetHashCode();
hashCode = hashCode * -1521134295 + RenderAttackFrame.GetHashCode();
hashCode = hashCode * -1521134295 + EmoteFrame.GetHashCode();
hashCode = hashCode * -1521134295 + ActualSpellCastFrame.GetHashCode();
hashCode = hashCode * -1521134295 + SitState.GetHashCode();
hashCode = hashCode * -1521134295 + Emote.GetHashCode();
hashCode = hashCode * -1521134295 + IsHidden.GetHashCode();
Expand Down
1 change: 1 addition & 0 deletions EOLib/Domain/Character/ICharacterRenderProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public interface ICharacterRenderProperties : ICloneable
int ActualAttackFrame { get; }
int RenderAttackFrame { get; }
int EmoteFrame { get; }
int ActualSpellCastFrame { get; }

SitState SitState { get; }
Emote Emote { get; }
Expand Down
6 changes: 3 additions & 3 deletions EOLib/Domain/Interact/MapNPCActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public MapNPCActions(IPacketSendService packetSendService,
public void RequestShop(INPC npc)
{
var packet = new PacketBuilder(PacketFamily.Shop, PacketAction.Open)
.AddShort(npc.Index)
.AddShort((short)npc.Index)
.Build();

_packetSendService.SendPacket(packet);
Expand All @@ -39,7 +39,7 @@ public void RequestQuest(INPC npc)
var data = _enfFileProvider.ENFFile[npc.ID];

var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.Use)
.AddShort(npc.Index)
.AddShort((short)npc.Index)
.AddShort(data.VendorID)
.Build();

Expand All @@ -49,7 +49,7 @@ public void RequestQuest(INPC npc)
public void RequestBank(INPC npc)
{
var packet = new PacketBuilder(PacketFamily.Bank, PacketAction.Open)
.AddShort(npc.Index)
.AddShort((short)npc.Index)
.Build();

_packetSendService.SendPacket(packet);
Expand Down
2 changes: 0 additions & 2 deletions EOLib/Domain/NPC/INPC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ namespace EOLib.Domain.NPC
{
public interface INPC : ISpellTargetable
{
byte Index { get; }

byte X { get; }

byte Y { get; }
Expand Down
4 changes: 2 additions & 2 deletions EOLib/Domain/NPC/NPC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class NPC : INPC
{
public int ID { get; }

public byte Index { get; }
public int Index { get; }

public byte X { get; private set; }

Expand All @@ -19,7 +19,7 @@ public class NPC : INPC

public Option<short> OpponentID { get; private set; }

public NPC(int id, byte index)
public NPC(int id, int index)
{
ID = id;
Index = index;
Expand Down
2 changes: 2 additions & 0 deletions EOLib/Domain/Spells/ISpellTargetable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
public interface ISpellTargetable
{
int ID { get; }

int Index { get; }
}
}
83 changes: 83 additions & 0 deletions EOLib/Domain/Spells/SpellCastValidationActions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using AutomaticTypeMapper;
using EOLib.Domain.Character;
using EOLib.Domain.Map;
using EOLib.Domain.NPC;
using EOLib.IO;
using EOLib.IO.Repositories;

namespace EOLib.Domain.Spells
{
[AutoMappedType]
public class SpellCastValidationActions : ISpellCastValidationActions
{
private readonly IPubFileProvider _pubFileProvider;
private readonly ICurrentMapProvider _currentMapProvider;
private readonly ICharacterProvider _characterProvider;

public SpellCastValidationActions(IPubFileProvider pubFileProvider,
ICurrentMapProvider currentMapProvider,
ICharacterProvider characterProvider)
{
_pubFileProvider = pubFileProvider;
_currentMapProvider = currentMapProvider;
_characterProvider = characterProvider;
}

public SpellCastValidationResult ValidateSpellCast(int spellId)
{
var spellData = _pubFileProvider.ESFFile[spellId];

var stats = _characterProvider.MainCharacter.Stats;
if (stats[CharacterStat.SP] - spellData.SP < 0)
return SpellCastValidationResult.ExhaustedNoSp;
if (stats[CharacterStat.TP] - spellData.TP < 0)
return SpellCastValidationResult.ExhaustedNoTp;

return SpellCastValidationResult.Ok;
}

public SpellCastValidationResult ValidateSpellCast(int spellId, ISpellTargetable spellTarget)
{
var res = ValidateSpellCast(spellId);
if (res != SpellCastValidationResult.Ok)
return res;

var spellData = _pubFileProvider.ESFFile[spellId];

if (spellTarget is INPC)
{
if (spellData.TargetRestrict == SpellTargetRestrict.Friendly ||
spellData.Target != SpellTarget.Normal ||
spellData.Type != SpellType.Damage)
return SpellCastValidationResult.WrongTargetType;

var npcData = _pubFileProvider.ENFFile[spellTarget.ID];

if (npcData.Type != NPCType.Passive && npcData.Type != NPCType.Aggressive)
return SpellCastValidationResult.CannotAttackNPC;
}
else if (spellTarget is ICharacter)
{
if (spellData.TargetRestrict == SpellTargetRestrict.NPCOnly ||
spellData.Target != SpellTarget.Normal ||
(spellTarget == _characterProvider.MainCharacter && spellData.TargetRestrict != SpellTargetRestrict.Friendly) ||
(spellData.Type != SpellType.Heal && spellData.Type != SpellType.Damage) ||
(!_currentMapProvider.CurrentMap.Properties.PKAvailable && spellData.TargetRestrict == SpellTargetRestrict.Opponent))
return SpellCastValidationResult.WrongTargetType;
}
else
{
return SpellCastValidationResult.WrongTargetType;
}

return SpellCastValidationResult.Ok;
}
}

public interface ISpellCastValidationActions
{
SpellCastValidationResult ValidateSpellCast(int spellId);

SpellCastValidationResult ValidateSpellCast(int spellId, ISpellTargetable spellTarget);
}
}
11 changes: 11 additions & 0 deletions EOLib/Domain/Spells/SpellCastValidationResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace EOLib.Domain.Spells
{
public enum SpellCastValidationResult
{
Ok,
CannotAttackNPC,
WrongTargetType,
ExhaustedNoSp,
ExhaustedNoTp,
}
}
Loading

0 comments on commit 4700b28

Please sign in to comment.