From 03182de7d2fc0009db39f4e25bbc08ad628e1259 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 17 Dec 2023 21:30:42 -0800 Subject: [PATCH 1/4] Add weapon metadata load - Add WeaponMetadataProvider and WeaponMetadata types. - Add mapping to GFXMetadataLoader for types. - Update SoundEffectID previous unknown value to Alternate attack. --- EndlessClient/Audio/SoundEffectID.cs | 2 +- .../Rendering/Metadata/GFXMetadataLoader.cs | 3 +- .../Metadata/Models/WeaponMetadata.cs | 8 ++ .../Metadata/WeaponMetadataProvider.cs | 105 ++++++++++++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 EndlessClient/Rendering/Metadata/Models/WeaponMetadata.cs create mode 100644 EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs diff --git a/EndlessClient/Audio/SoundEffectID.cs b/EndlessClient/Audio/SoundEffectID.cs index 2d7ad9fb4..ffbbfa286 100644 --- a/EndlessClient/Audio/SoundEffectID.cs +++ b/EndlessClient/Audio/SoundEffectID.cs @@ -41,7 +41,7 @@ public enum SoundEffectID Craft, UnknownBuzzSound = 28, AdminChatReceived, - UnknownAttackLikeSound, + AlternateMeleeAttack, PotionOfFlamesEffect, AdminWarp = 32, NoWallWalk, diff --git a/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs b/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs index 1f33b87b8..2330f666c 100644 --- a/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs +++ b/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs @@ -25,7 +25,8 @@ static GFXMetadataLoader() { typeof(EffectMetadata), GFXTypes.Spells }, { typeof(NPCMetadata), GFXTypes.NPC }, { typeof(ShieldMetadata), GFXTypes.MaleBack }, - { typeof(HatMetadata), GFXTypes.MaleHat } + { typeof(HatMetadata), GFXTypes.MaleHat }, + { typeof(WeaponMetadata), GFXTypes.MaleWeapons } }; } diff --git a/EndlessClient/Rendering/Metadata/Models/WeaponMetadata.cs b/EndlessClient/Rendering/Metadata/Models/WeaponMetadata.cs new file mode 100644 index 000000000..7e55ed2ed --- /dev/null +++ b/EndlessClient/Rendering/Metadata/Models/WeaponMetadata.cs @@ -0,0 +1,8 @@ +using EndlessClient.Audio; + +namespace EndlessClient.Rendering.Metadata.Models; + +public record WeaponMetadata(int? Slash, SoundEffectID[] SFX, bool Ranged) : IGFXMetadata +{ + public static WeaponMetadata Default { get; } = new WeaponMetadata(Slash: null, SFX: new[] { SoundEffectID.PunchAttack }, Ranged: false); +} diff --git a/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs b/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs new file mode 100644 index 000000000..470ada40d --- /dev/null +++ b/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs @@ -0,0 +1,105 @@ +using AutomaticTypeMapper; +using EndlessClient.Audio; +using EndlessClient.Rendering.Metadata.Models; +using System.Collections.Generic; + +namespace EndlessClient.Rendering.Metadata +{ + [AutoMappedType(IsSingleton = true)] + public class WeaponMetadataProvider : IMetadataProvider + { + public IReadOnlyDictionary DefaultMetadata => _metadata; + + private readonly Dictionary _metadata; + private readonly IGFXMetadataLoader _metadataLoader; + + public WeaponMetadataProvider(IGFXMetadataLoader metadataLoader) + { + _metadata = new Dictionary + { + { 0, new WeaponMetadata( null, new[] { SoundEffectID.PunchAttack }, false) }, // fist + { 1, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // wood axe + { 2, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // sai + { 3, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dragon blade + { 4, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dagger + { 5, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // spear + { 6, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // saber + { 7, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // staff + { 8, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // book + { 9, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // mace + { 10, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // spirit star + { 11, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // throw axe + { 12, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dark katana + { 13, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // short sword + { 14, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // broadsword + { 15, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // broom + { 16, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ninchackus + { 17, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ancient star + { 18, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle axe + { 19, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ancient sword + { 20, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // luna staff + { 21, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lance + { 22, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // aura staff + { 23, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // forest staff + { 24, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // normal sword + { 25, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // jewel staff + { 26, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // thor's hammer + { 27, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // light katana + { 28, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // polearm + { 29, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // sickle + { 30, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // trident + { 31, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // warlock sword + { 32, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // whip + { 33, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ultima + { 34, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ice blade + { 35, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gold defender + { 36, new WeaponMetadata( 4, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lotus sword + { 37, new WeaponMetadata( 4, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // cristal sword + { 38, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // killing edge + { 39, new WeaponMetadata( 7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // dark blade + { 40, new WeaponMetadata( 7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // reaper scyth + { 41, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // crescent staff + { 42, new WeaponMetadata( 0, new[] { SoundEffectID.AttackBow }, true) }, // bow + { 43, new WeaponMetadata( 0, new[] { SoundEffectID.AttackBow }, true) }, // xbow + { 44, new WeaponMetadata( 8, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // reaper + { 45, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // hockey stick + { 46, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // twin blades + { 47, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lefor mace + { 48, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // cava staff + { 49, new WeaponMetadata( 0, new[] { SoundEffectID.Harp1,SoundEffectID.Harp2,SoundEffectID.Harp3}, true) }, // harp + { 50, new WeaponMetadata( 0, new[] { SoundEffectID.Guitar1,SoundEffectID.Guitar2, SoundEffectID.Guitar3 }, true) }, // guitar + { 51, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle spear + { 52, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // flail + { 53, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // war axe + { 54, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gastro + { 55, new WeaponMetadata( 7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // ablo staff + { 56, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fluon sword + { 57, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // rapier + { 58, new WeaponMetadata( 0, new[] { SoundEffectID.Gun }, true) }, // gun + { 59, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // knob staff + { 60, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fladdat staff + { 61, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gabrasto + { 62, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle spear 2 + { 63, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lens of truth + { 64, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // chopper + { 65, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // adger + { 66, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // chains + { 67, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // mitova + { 68, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // merhawk + { 69, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // kontra + { 70, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // jack spear + { 71, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // bazar staff + { 72, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // saw blade + { 73, new WeaponMetadata( 0, new[] { SoundEffectID.AttackBow }, true) }, // scav bow + { 74, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fan + }; + _metadataLoader = metadataLoader; + } + + public WeaponMetadata GetValueOrDefault(int graphic) + { + return _metadataLoader.GetMetadata(graphic) + .ValueOr(DefaultMetadata.TryGetValue(graphic, out var ret) ? ret : WeaponMetadata.Default); + } + } +} From 8d7188cbc1486c0a2d2dd9e7d549a7ff2bbe1d7c Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 18 Dec 2023 11:07:12 -0800 Subject: [PATCH 2/4] Load and use weapon metadata - Remove IsRanged from CharacterRenderProperties - Remove manual determination of weapon SFX --- BatchMap/Program.cs | 2 +- EOLib.IO/Actions/IPubFileLoadActions.cs | 4 +- EOLib.IO/Actions/PubFileLoadActions.cs | 22 ++---- EOLib.IO/Extensions/EIFFileExtensions.cs | 14 ---- .../Character/AttackValidationActions.cs | 9 ++- .../Character/CharacterRenderProperties.cs | 2 - .../Domain/Extensions/CharacterExtensions.cs | 3 +- .../CharacterRenderPropertiesExtensions.cs | 4 +- .../Spells/SpellCastValidationActions.cs | 5 +- .../CharacterDisplayPacketTranslator.cs | 9 +-- .../Translators/CharacterFromPacketFactory.cs | 6 +- .../Avatar/AvatarAgreeHandler.cs | 9 +-- .../PacketHandlers/Items/ItemReplyHandler.cs | 2 +- .../MapInfo/MapInfoReplyHandler.cs | 4 +- .../Players/PlayersAgreeHandler.cs | 7 +- EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs | 3 +- EOLib/misc.cs | 6 +- EndlessClient/GameExecution/EndlessGame.cs | 2 +- .../HUD/Controls/HudControlsFactory.cs | 13 +++- .../Character/CharacterAnimationActions.cs | 73 +++++++------------ .../Rendering/Character/CharacterAnimator.cs | 14 ++-- .../Rendering/Character/CharacterRenderer.cs | 7 +- .../CharacterProperties/ArmorRenderer.cs | 13 ++-- .../BaseCharacterPropertyRenderer.cs | 5 +- .../CharacterProperties/BootsRenderer.cs | 11 +-- .../CharacterProperties/EmoteRenderer.cs | 8 +- .../CharacterProperties/FaceRenderer.cs | 7 +- .../HairRenderLocationCalculator.cs | 4 +- .../CharacterProperties/HairRenderer.cs | 7 +- .../CharacterProperties/HatRenderer.cs | 7 +- .../ICharacterPropertyRenderer.cs | 5 +- .../CharacterProperties/ShieldRenderer.cs | 11 +-- .../SkinRenderLocationCalculator.cs | 4 +- .../CharacterProperties/SkinRenderer.cs | 9 +-- .../CharacterProperties/WeaponRenderer.cs | 13 ++-- .../Factories/CharacterRendererFactory.cs | 6 +- .../Rendering/Metadata/GFXMetadataLoader.cs | 2 +- .../Sprites/CharacterSpriteCalculator.cs | 21 ++---- EndlessClient/Test/CharacterStateTest.cs | 30 +++++--- EndlessClient/Test/TestModeLauncher.cs | 12 ++- 40 files changed, 179 insertions(+), 216 deletions(-) delete mode 100644 EOLib.IO/Extensions/EIFFileExtensions.cs diff --git a/BatchMap/Program.cs b/BatchMap/Program.cs index b2db35c26..785b6ca18 100644 --- a/BatchMap/Program.cs +++ b/BatchMap/Program.cs @@ -103,7 +103,7 @@ private static void Main(string[] args) { var actions = _typeRegistry.Resolve(); - actions.LoadItemFileByName(Path.Combine(pubFilePath, "dat001.eif"), rangedWeaponIds: Constants.RangedWeaponIDs.Concat(Constants.InstrumentIDs)); + actions.LoadItemFileByName(Path.Combine(pubFilePath, "dat001.eif")); actions.LoadNPCFileByName(Path.Combine(pubFilePath, "dtn001.enf")); } catch diff --git a/EOLib.IO/Actions/IPubFileLoadActions.cs b/EOLib.IO/Actions/IPubFileLoadActions.cs index 15af14a08..d633276fc 100644 --- a/EOLib.IO/Actions/IPubFileLoadActions.cs +++ b/EOLib.IO/Actions/IPubFileLoadActions.cs @@ -4,9 +4,9 @@ namespace EOLib.IO.Actions { public interface IPubFileLoadActions { - void LoadItemFile(IEnumerable rangedWeaponIds); + void LoadItemFile(); - void LoadItemFileByName(string fileName, IEnumerable rangedWeaponIds); + void LoadItemFileByName(string fileName); void LoadNPCFile(); diff --git a/EOLib.IO/Actions/PubFileLoadActions.cs b/EOLib.IO/Actions/PubFileLoadActions.cs index 519b63707..ccecea1e2 100644 --- a/EOLib.IO/Actions/PubFileLoadActions.cs +++ b/EOLib.IO/Actions/PubFileLoadActions.cs @@ -3,13 +3,12 @@ using EOLib.IO.Pub; using EOLib.IO.Repositories; using EOLib.IO.Services; -using System.Collections.Generic; using System.IO; using System.Linq; namespace EOLib.IO.Actions { - [MappedType(BaseType = typeof(IPubFileLoadActions))] + [AutoMappedType] public class PubFileLoadActions : IPubFileLoadActions { private readonly IPubFileRepository _pubFileRepository; @@ -31,18 +30,18 @@ public PubFileLoadActions(IPubFileRepository pubFileRepository, _classFileLoadService = classFileLoadService; } - public void LoadItemFile(IEnumerable rangedWeaponIds) + public void LoadItemFile() { var itemFiles = _itemFileLoadService.LoadPubFromDefaultFile(); _pubFileRepository.EIFFiles = itemFiles.ToList(); - _pubFileRepository.EIFFile = OverrideRangedWeapons(PubFileExtensions.Merge(_pubFileRepository.EIFFiles), rangedWeaponIds); + _pubFileRepository.EIFFile = PubFileExtensions.Merge(_pubFileRepository.EIFFiles); } - public void LoadItemFileByName(string fileName, IEnumerable rangedWeaponIds) + public void LoadItemFileByName(string fileName) { var itemFiles = _itemFileLoadService.LoadPubFromExplicitFile(Path.GetDirectoryName(fileName), Path.GetFileName(fileName)); _pubFileRepository.EIFFiles = itemFiles.ToList(); - _pubFileRepository.EIFFile = OverrideRangedWeapons(PubFileExtensions.Merge(_pubFileRepository.EIFFiles), rangedWeaponIds); + _pubFileRepository.EIFFile = PubFileExtensions.Merge(_pubFileRepository.EIFFiles); } public void LoadNPCFile() @@ -86,16 +85,5 @@ public void LoadClassFileByName(string fileName) _pubFileRepository.ECFFiles = classFiles.ToList(); _pubFileRepository.ECFFile = PubFileExtensions.Merge(_pubFileRepository.ECFFiles); } - - private static IPubFile OverrideRangedWeapons(IPubFile inputFile, IEnumerable rangedWeaponIds) - { - var rangedItemOverrides = inputFile.Where(x => x.Type == ItemType.Weapon && rangedWeaponIds.Contains(x.ID)).ToList(); - - var retFile = inputFile; - foreach (var item in rangedItemOverrides) - retFile = retFile.WithUpdatedRecord((EIFRecord)item.WithProperty(PubRecordProperty.ItemSubType, (int)ItemSubType.Ranged)); - - return retFile; - } } } \ No newline at end of file diff --git a/EOLib.IO/Extensions/EIFFileExtensions.cs b/EOLib.IO/Extensions/EIFFileExtensions.cs deleted file mode 100644 index 03ccd8c4f..000000000 --- a/EOLib.IO/Extensions/EIFFileExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using EOLib.IO.Pub; -using System.Linq; - -namespace EOLib.IO.Extensions -{ - public static class EIFFileExtensions - { - public static bool IsRangedWeapon(this IPubFile itemFile, int graphic) - { - var weaponInfo = itemFile?.FirstOrDefault(x => x.Type == ItemType.Weapon && x.DollGraphic == graphic); - return weaponInfo?.SubType == ItemSubType.Ranged; - } - } -} diff --git a/EOLib/Domain/Character/AttackValidationActions.cs b/EOLib/Domain/Character/AttackValidationActions.cs index 50420fce0..adc5a921b 100644 --- a/EOLib/Domain/Character/AttackValidationActions.cs +++ b/EOLib/Domain/Character/AttackValidationActions.cs @@ -35,7 +35,14 @@ public AttackValidationError ValidateCharacterStateBeforeAttacking() var rp = _characterProvider.MainCharacter.RenderProperties; - if (rp.IsRangedWeapon && (rp.ShieldGraphic == 0 || !_eifFileProvider.EIFFile.Any(x => x.DollGraphic == rp.ShieldGraphic && x.SubType == IO.ItemSubType.Arrows))) + var isRangedWeapon = _eifFileProvider.EIFFile + .Where(x => x.Type == IO.ItemType.Weapon && x.SubType == IO.ItemSubType.Ranged) + .Any(x => x.Graphic == rp.WeaponGraphic); + var isArrows = _eifFileProvider.EIFFile + .Where(x => x.Type == IO.ItemType.Shield && x.SubType == IO.ItemSubType.Arrows) + .Any(x => x.Graphic == rp.ShieldGraphic); + + if (isRangedWeapon && (rp.ShieldGraphic == 0 || !isArrows)) return AttackValidationError.MissingArrows; return _mapCellStateProvider diff --git a/EOLib/Domain/Character/CharacterRenderProperties.cs b/EOLib/Domain/Character/CharacterRenderProperties.cs index 4e1cb2522..419ad3ff6 100644 --- a/EOLib/Domain/Character/CharacterRenderProperties.cs +++ b/EOLib/Domain/Character/CharacterRenderProperties.cs @@ -40,7 +40,5 @@ public sealed partial class CharacterRenderProperties public bool IsHidden { get; } public bool IsDead { get; } public bool IsDrunk { get; } - - public bool IsRangedWeapon { get; } } } diff --git a/EOLib/Domain/Extensions/CharacterExtensions.cs b/EOLib/Domain/Extensions/CharacterExtensions.cs index 36fce6e97..fc5b251d0 100644 --- a/EOLib/Domain/Extensions/CharacterExtensions.cs +++ b/EOLib/Domain/Extensions/CharacterExtensions.cs @@ -5,7 +5,7 @@ namespace EOLib.Domain.Extensions { public static class CharacterExtensions { - public static Character.Character WithAppliedData(this Character.Character original, Character.Character updatedData, bool isRangedWeapon) + public static Character.Character WithAppliedData(this Character.Character original, Character.Character updatedData) { var existingRenderProps = original.RenderProperties; var newRenderProps = updatedData.RenderProperties.ToBuilder(); @@ -14,7 +14,6 @@ public static Character.Character WithAppliedData(this Character.Character origi ? CharacterActionState.Standing : CharacterActionState.Sitting; newRenderProps.IsDead = existingRenderProps.IsDead; - newRenderProps.IsRangedWeapon = isRangedWeapon; newRenderProps.IsDrunk = existingRenderProps.IsDrunk; newRenderProps.IsHidden = existingRenderProps.IsHidden; diff --git a/EOLib/Domain/Extensions/CharacterRenderPropertiesExtensions.cs b/EOLib/Domain/Extensions/CharacterRenderPropertiesExtensions.cs index 8ea46ba4e..ff2e51838 100644 --- a/EOLib/Domain/Extensions/CharacterRenderPropertiesExtensions.cs +++ b/EOLib/Domain/Extensions/CharacterRenderPropertiesExtensions.cs @@ -60,13 +60,13 @@ public static CharacterRenderProperties WithNextWalkFrame(this CharacterRenderPr return props.ToImmutable(); } - public static CharacterRenderProperties WithNextAttackFrame(this CharacterRenderProperties rp) + public static CharacterRenderProperties WithNextAttackFrame(this CharacterRenderProperties rp, bool isRangedWeapon) { var props = rp.ToBuilder(); props.ActualAttackFrame = (props.ActualAttackFrame + 1) % CharacterRenderProperties.MAX_NUMBER_OF_WALK_FRAMES; props.RenderAttackFrame = props.ActualAttackFrame; - if (props.IsRangedWeapon) + if (isRangedWeapon) { // ranged attack ticks: 0 0 1 1 1 props.RenderAttackFrame /= CharacterRenderProperties.MAX_NUMBER_OF_RANGED_ATTACK_FRAMES; diff --git a/EOLib/Domain/Spells/SpellCastValidationActions.cs b/EOLib/Domain/Spells/SpellCastValidationActions.cs index b95ecf8d3..2382a869e 100644 --- a/EOLib/Domain/Spells/SpellCastValidationActions.cs +++ b/EOLib/Domain/Spells/SpellCastValidationActions.cs @@ -1,10 +1,8 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; using EOLib.Domain.Map; -using EOLib.Domain.NPC; using EOLib.IO; using EOLib.IO.Repositories; -using Optional.Collections; using System.Linq; namespace EOLib.Domain.Spells @@ -78,8 +76,7 @@ public SpellCastValidationResult ValidateSpellCast(int spellId, ISpellTargetable public bool ValidateBard() { var weapon = _characterProvider.MainCharacter.RenderProperties.WeaponGraphic; - return _pubFileProvider.EIFFile.SingleOrNone(x => x.DollGraphic == weapon && x.Type == ItemType.Weapon) - .Match(some => Constants.InstrumentIDs.Any(x => x == some.ID), () => false); + return Constants.Instruments.Any(x => x == weapon); } } diff --git a/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs b/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs index c318e77aa..1f9e20aa4 100644 --- a/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs +++ b/EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs @@ -1,8 +1,6 @@ -using System.Collections.Generic; -using System.IO; -using EOLib.Domain.Character; -using EOLib.IO.Extensions; +using EOLib.Domain.Character; using EOLib.IO.Repositories; +using System.Collections.Generic; namespace EOLib.Net.Translators { @@ -69,8 +67,7 @@ private Character GetNextCharacter(IPacket packet) ArmorGraphic = armor, HatGraphic = hat, ShieldGraphic = shield, - WeaponGraphic = weapon, - IsRangedWeapon = _eifFileProvider.EIFFile.IsRangedWeapon(weapon), + WeaponGraphic = weapon }; character.Stats = stats; diff --git a/EOLib/Net/Translators/CharacterFromPacketFactory.cs b/EOLib/Net/Translators/CharacterFromPacketFactory.cs index b3fba825d..4bd9e6a9b 100644 --- a/EOLib/Net/Translators/CharacterFromPacketFactory.cs +++ b/EOLib/Net/Translators/CharacterFromPacketFactory.cs @@ -1,8 +1,7 @@ -using System.IO; -using AutomaticTypeMapper; +using AutomaticTypeMapper; using EOLib.Domain.Character; -using EOLib.IO.Extensions; using EOLib.IO.Repositories; +using System.IO; namespace EOLib.Net.Translators { @@ -71,7 +70,6 @@ public Character CreateCharacter(IPacket packet) HatGraphic = hat, ShieldGraphic = shield, WeaponGraphic = weapon, - IsRangedWeapon = _eifFileProvider.EIFFile.IsRangedWeapon(weapon), SitState = sitState, CurrentAction = sitState == SitState.Standing ? CharacterActionState.Standing : CharacterActionState.Sitting, IsHidden = hidden, diff --git a/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs b/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs index 2ecf05864..a89efd44e 100644 --- a/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs +++ b/EOLib/PacketHandlers/Avatar/AvatarAgreeHandler.cs @@ -2,7 +2,6 @@ using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.IO.Extensions; using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Handlers; @@ -61,12 +60,8 @@ public override bool HandlePacket(IPacket packet) currentRenderProps = currentRenderProps .WithBootsGraphic(packet.ReadShort()) .WithArmorGraphic(packet.ReadShort()) - .WithHatGraphic(packet.ReadShort()); - - var weaponGraphic = packet.ReadShort(); - currentRenderProps = currentRenderProps - .WithWeaponGraphic(weaponGraphic) - .WithIsRangedWeapon(_eifFileProvider.EIFFile.IsRangedWeapon(weaponGraphic)) + .WithHatGraphic(packet.ReadShort()) + .WithWeaponGraphic(packet.ReadShort()) .WithShieldGraphic(packet.ReadShort()); break; diff --git a/EOLib/PacketHandlers/Items/ItemReplyHandler.cs b/EOLib/PacketHandlers/Items/ItemReplyHandler.cs index f52552444..6a754897a 100644 --- a/EOLib/PacketHandlers/Items/ItemReplyHandler.cs +++ b/EOLib/PacketHandlers/Items/ItemReplyHandler.cs @@ -135,7 +135,7 @@ public override bool HandlePacket(IPacket packet) else if (loc == EquipLocation.Hat) renderProps = renderProps.WithHatGraphic(0); else if (loc == EquipLocation.Weapon) - renderProps = renderProps.WithWeaponGraphic(0).WithIsRangedWeapon(false); + renderProps = renderProps.WithWeaponGraphic(0); else if (loc == EquipLocation.Shield) renderProps = renderProps.WithShieldGraphic(0); } diff --git a/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs b/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs index ae4a85635..2b40b3b83 100644 --- a/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs +++ b/EOLib/PacketHandlers/MapInfo/MapInfoReplyHandler.cs @@ -2,7 +2,6 @@ using EOLib.Domain.Extensions; using EOLib.Domain.Login; using EOLib.Domain.Map; -using EOLib.IO.Extensions; using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Handlers; @@ -47,8 +46,7 @@ public override bool HandlePacket(IPacket packet) var character = _characterFromPacketFactory.CreateCharacter(packet); if (_currentMapStateRepository.Characters.TryGetValue(character.ID, out var existingCharacter)) { - var isRangedWeapon = _eifFileProvider.EIFFile.IsRangedWeapon(character.RenderProperties.WeaponGraphic); - character = existingCharacter.WithAppliedData(character, isRangedWeapon); + character = existingCharacter.WithAppliedData(character); } _currentMapStateRepository.Characters.Update(existingCharacter, character); diff --git a/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs b/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs index b901c4867..9852d8c9b 100644 --- a/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs +++ b/EOLib/PacketHandlers/Players/PlayersAgreeHandler.cs @@ -4,7 +4,6 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.IO.Extensions; using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Handlers; @@ -69,14 +68,12 @@ public override bool HandlePacket(IPacket packet) if (_characterRepository.MainCharacter.ID == character.ID) { var existingCharacter = _characterRepository.MainCharacter; - var isRangedWeapon = _eifFileProvider.EIFFile.IsRangedWeapon(character.RenderProperties.WeaponGraphic); - _characterRepository.MainCharacter = existingCharacter.WithAppliedData(character, isRangedWeapon); + _characterRepository.MainCharacter = existingCharacter.WithAppliedData(character); _characterRepository.HasAvatar = true; } else if (_mapStateRepository.Characters.TryGetValue(character.ID, out var existingCharacter)) { - var isRangedWeapon = _eifFileProvider.EIFFile.IsRangedWeapon(character.RenderProperties.WeaponGraphic); - _mapStateRepository.Characters.Update(existingCharacter, existingCharacter.WithAppliedData(character, isRangedWeapon)); + _mapStateRepository.Characters.Update(existingCharacter, existingCharacter.WithAppliedData(character)); } else { diff --git a/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs b/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs index adda26679..51b3ac34c 100644 --- a/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs +++ b/EOLib/PacketHandlers/Warp/WarpAgreeHandler.cs @@ -4,7 +4,6 @@ using EOLib.Domain.Login; using EOLib.Domain.Map; using EOLib.Domain.Notifiers; -using EOLib.IO.Extensions; using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Handlers; @@ -68,7 +67,7 @@ public override bool HandlePacket(IPacket packet) var bringBackToLife = _characterRepository.MainCharacter.RenderProperties.WithIsDead(false); _characterRepository.MainCharacter = _characterRepository.MainCharacter .WithRenderProperties(bringBackToLife) - .WithAppliedData(updatedMainCharacter, _eifFileProvider.EIFFile.IsRangedWeapon(updatedMainCharacter.RenderProperties.WeaponGraphic)); + .WithAppliedData(updatedMainCharacter); var withoutMainCharacter = warpAgreePacketData.Characters.Where(x => !MainCharacterIDMatches(x)); warpAgreePacketData = warpAgreePacketData.WithCharacters(withoutMainCharacter.ToList()); diff --git a/EOLib/misc.cs b/EOLib/misc.cs index f13eb81d1..b42ab79a0 100644 --- a/EOLib/misc.cs +++ b/EOLib/misc.cs @@ -48,10 +48,8 @@ public static class Constants //not a config option because this shouldn't be exposed at the user level public static readonly int[] TrapSpikeGFXObjectIDs = { 449, 450, 451, 452 }; - // Item IDs of instruments (there is no pub flag for this) - public static readonly int[] InstrumentIDs = { 349, 350 }; - // Item IDs of ranged weapons (overrides pub value) - public static readonly int[] RangedWeaponIDs = { 365 }; + // Weapon graphics of instruments (there is no pub flag for this) + public static readonly int[] Instruments = { 49, 50 }; public const string FontSize07 = @"BitmapFonts/sans_09px"; public const string FontSize08 = @"BitmapFonts/sans_11px"; public const string FontSize08pt5 = @"BitmapFonts/sans_11px_103pct"; diff --git a/EndlessClient/GameExecution/EndlessGame.cs b/EndlessClient/GameExecution/EndlessGame.cs index 5e0e79a73..c3c837b8c 100644 --- a/EndlessClient/GameExecution/EndlessGame.cs +++ b/EndlessClient/GameExecution/EndlessGame.cs @@ -248,7 +248,7 @@ private void AttemptToLoadPubFiles() try { - _pubFileLoadActions.LoadItemFile(rangedWeaponIds: Constants.RangedWeaponIDs.Concat(Constants.InstrumentIDs)); + _pubFileLoadActions.LoadItemFile(); } catch (Exception ex) when (ex is IOException || ex is ArgumentException) { diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index 30f6219f0..eba4263c0 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -14,6 +14,8 @@ using EndlessClient.Rendering.Character; using EndlessClient.Rendering.Factories; using EndlessClient.Rendering.Map; +using EndlessClient.Rendering.Metadata; +using EndlessClient.Rendering.Metadata.Models; using EndlessClient.Rendering.NPC; using EndlessClient.UIControls; using EOLib; @@ -67,6 +69,7 @@ public class HudControlsFactory : IHudControlsFactory private readonly INewsProvider _newsProvider; private readonly IFixedTimeStepRepository _fixedTimeStepRepository; private readonly IClickDispatcherFactory _clickDispatcherFactory; + private readonly IMetadataProvider _weaponMetadataProvider; private IChatController _chatController; private IMainButtonController _mainButtonController; @@ -99,7 +102,8 @@ public HudControlsFactory(IHudButtonController hudButtonController, IMiniMapRendererFactory miniMapRendererFactory, INewsProvider newsProvider, IFixedTimeStepRepository fixedTimeStepRepository, - IClickDispatcherFactory clickDispatcherFactory) + IClickDispatcherFactory clickDispatcherFactory, + IMetadataProvider weaponMetadataProvider) { _hudButtonController = hudButtonController; _hudPanelFactory = hudPanelFactory; @@ -130,6 +134,7 @@ public HudControlsFactory(IHudButtonController hudButtonController, _newsProvider = newsProvider; _fixedTimeStepRepository = fixedTimeStepRepository; _clickDispatcherFactory = clickDispatcherFactory; + _weaponMetadataProvider = weaponMetadataProvider; } public void InjectChatController(IChatController chatController, @@ -561,7 +566,11 @@ private IUserInputHandler CreateUserInputHandler() private ICharacterAnimator CreateCharacterAnimator() { - return new CharacterAnimator(_endlessGameProvider, _characterRepository, _currentMapStateRepository, _currentMapProvider, _spellSlotDataRepository, _characterActions, _walkValidationActions, _pathFinder, _fixedTimeStepRepository); + return new CharacterAnimator( + _endlessGameProvider, _characterRepository, _currentMapStateRepository, + _currentMapProvider, _spellSlotDataRepository, _characterActions, + _walkValidationActions, _pathFinder, _fixedTimeStepRepository, + _weaponMetadataProvider); } private INPCAnimator CreateNPCAnimator() diff --git a/EndlessClient/Rendering/Character/CharacterAnimationActions.cs b/EndlessClient/Rendering/Character/CharacterAnimationActions.cs index 230411859..ea44d41bf 100644 --- a/EndlessClient/Rendering/Character/CharacterAnimationActions.cs +++ b/EndlessClient/Rendering/Character/CharacterAnimationActions.cs @@ -5,6 +5,8 @@ using EndlessClient.HUD.Controls; using EndlessClient.Rendering.Effects; using EndlessClient.Rendering.Map; +using EndlessClient.Rendering.Metadata; +using EndlessClient.Rendering.Metadata.Models; using EOLib; using EOLib.Config; using EOLib.Domain.Character; @@ -36,7 +38,8 @@ public class CharacterAnimationActions : ICharacterAnimationActions, IOtherChara private readonly IPubFileProvider _pubFileProvider; private readonly IStatusLabelSetter _statusLabelSetter; private readonly ISfxPlayer _sfxPlayer; - + private readonly IMetadataProvider _weaponMetadataProvider; + private readonly Random _random; public CharacterAnimationActions(IHudControlProvider hudControlProvider, @@ -47,7 +50,8 @@ public CharacterAnimationActions(IHudControlProvider hudControlProvider, ISpikeTrapActions spikeTrapActions, IPubFileProvider pubFileProvider, IStatusLabelSetter statusLabelSetter, - ISfxPlayer sfxPlayer) + ISfxPlayer sfxPlayer, + IMetadataProvider weaponMetadataProvider) { _hudControlProvider = hudControlProvider; _characterRepository = characterRepository; @@ -58,7 +62,7 @@ public CharacterAnimationActions(IHudControlProvider hudControlProvider, _pubFileProvider = pubFileProvider; _statusLabelSetter = statusLabelSetter; _sfxPlayer = sfxPlayer; - + _weaponMetadataProvider = weaponMetadataProvider; _random = new Random(); } @@ -383,57 +387,30 @@ private void PlayMainCharacterWalkSfx() private void PlayWeaponSound(EOLib.Domain.Character.Character character, int noteIndex = -1) { - if (character.RenderProperties.WeaponGraphic == 0) - { - _sfxPlayer.PlaySfx(SoundEffectID.PunchAttack); - return; - } + var weaponMetadata = _weaponMetadataProvider.GetValueOrDefault(character.RenderProperties.WeaponGraphic); - _pubFileProvider.EIFFile.FirstOrNone(x => x.Type == ItemType.Weapon && x.DollGraphic == character.RenderProperties.WeaponGraphic) - .MatchSome(x => + if (noteIndex >= 0 && noteIndex < 36) + { + var firstSfx = weaponMetadata.SFX.FirstOrDefault(); + if (firstSfx == SoundEffectID.Harp1) { - var instrumentIndex = Constants.InstrumentIDs.ToList().FindIndex(y => y == x.ID); - switch (instrumentIndex) - { - case 0: - { - if (noteIndex < 0 || noteIndex >= 36) - _sfxPlayer.PlaySfx(SoundEffectID.Harp1 + _random.Next(0, 3)); - else - _sfxPlayer.PlayHarpNote(noteIndex); - } - break; - case 1: - { - if (noteIndex < 0 || noteIndex >= 36) - _sfxPlayer.PlaySfx(SoundEffectID.Guitar1 + _random.Next(0, 3)); - else - _sfxPlayer.PlayGuitarNote(noteIndex); - } - break; - default: - switch (x.SubType) - { - case ItemSubType.Ranged: - if (x.ID == 365 && string.Equals(x.Name, "gun", System.StringComparison.OrdinalIgnoreCase)) - _sfxPlayer.PlaySfx(SoundEffectID.Gun); - else - _sfxPlayer.PlaySfx(SoundEffectID.AttackBow); - break; - default: - _sfxPlayer.PlaySfx(SoundEffectID.MeleeWeaponAttack); - break; - } - break; - } - }); + _sfxPlayer.PlayHarpNote(noteIndex); + } + else if (firstSfx == SoundEffectID.Guitar1) + { + _sfxPlayer.PlayGuitarNote(noteIndex); + } + } + else + { + var index = _random.Next(0, weaponMetadata.SFX.Length); + _sfxPlayer.PlaySfx(weaponMetadata.SFX[index]); + } } private bool IsInstrumentWeapon(int weaponGraphic) { - return _pubFileProvider.EIFFile - .SingleOrNone(x => x.Type == ItemType.Weapon && x.DollGraphic == weaponGraphic) - .Match(some: x => Constants.InstrumentIDs.ToList().FindIndex(y => y == x.ID) >= 0, none: () => false); + return Constants.Instruments.Any(x => x == weaponGraphic); } private bool IsSteppingStone(CharacterRenderProperties renderProps) diff --git a/EndlessClient/Rendering/Character/CharacterAnimator.cs b/EndlessClient/Rendering/Character/CharacterAnimator.cs index 074e1bb8c..0d54091b5 100644 --- a/EndlessClient/Rendering/Character/CharacterAnimator.cs +++ b/EndlessClient/Rendering/Character/CharacterAnimator.cs @@ -1,6 +1,8 @@ using EndlessClient.GameExecution; using EndlessClient.HUD; using EndlessClient.HUD.Spells; +using EndlessClient.Rendering.Metadata; +using EndlessClient.Rendering.Metadata.Models; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -31,6 +33,7 @@ public class CharacterAnimator : GameComponent, ICharacterAnimator private readonly IWalkValidationActions _walkValidationActions; private readonly IPathFinder _pathFinder; private readonly IFixedTimeStepRepository _fixedTimeStepRepository; + private readonly IMetadataProvider _weaponMetadataProvider; // todo: this state should really be managed better private readonly Dictionary _queuedDirections; @@ -55,7 +58,8 @@ public CharacterAnimator(IEndlessGameProvider gameProvider, ICharacterActions characterActions, IWalkValidationActions walkValidationActions, IPathFinder pathFinder, - IFixedTimeStepRepository fixedTimeStepRepository) + IFixedTimeStepRepository fixedTimeStepRepository, + IMetadataProvider weaponMetadataProvider) : base((Game) gameProvider.Game) { _characterRepository = characterRepository; @@ -66,7 +70,7 @@ public CharacterAnimator(IEndlessGameProvider gameProvider, _walkValidationActions = walkValidationActions; _pathFinder = pathFinder; _fixedTimeStepRepository = fixedTimeStepRepository; - + _weaponMetadataProvider = weaponMetadataProvider; _queuedDirections = new Dictionary(); _queuedPositions = new Dictionary(); _otherPlayerStartWalkingTimes = new Dictionary(); @@ -441,7 +445,8 @@ private void AnimateCharacterAttacking() some: currentCharacter => { var renderProperties = currentCharacter.RenderProperties; - var nextFrameRenderProperties = renderProperties.WithNextAttackFrame(); + var isRanged = _weaponMetadataProvider.GetValueOrDefault(renderProperties.WeaponGraphic).Ranged; + var nextFrameRenderProperties = renderProperties.WithNextAttackFrame(isRanged); if (nextFrameRenderProperties.ActualAttackFrame == 2) pair.SoundEffect(); @@ -451,8 +456,7 @@ private void AnimateCharacterAttacking() { if (pair.Replay) { - nextFrameRenderProperties = renderProperties.ResetAnimationFrames() - .WithNextAttackFrame(); + nextFrameRenderProperties = renderProperties.ResetAnimationFrames().WithNextAttackFrame(isRanged); pair.ClearReplay(); } else diff --git a/EndlessClient/Rendering/Character/CharacterRenderer.cs b/EndlessClient/Rendering/Character/CharacterRenderer.cs index bd301f9e8..897d7f222 100644 --- a/EndlessClient/Rendering/Character/CharacterRenderer.cs +++ b/EndlessClient/Rendering/Character/CharacterRenderer.cs @@ -39,6 +39,7 @@ public class CharacterRenderer : DrawableGameComponent, ICharacterRenderer private readonly ICurrentMapProvider _currentMapProvider; private readonly IUserInputProvider _userInputProvider; private readonly IMetadataProvider _hatMetadataProvider; + private readonly IMetadataProvider _weaponMetadataProvider; private readonly ISfxPlayer _sfxPlayer; private readonly IClientWindowSizeRepository _clientWindowSizeRepository; private readonly IEffectRenderer _effectRenderer; @@ -99,6 +100,7 @@ public CharacterRenderer(Game game, IUserInputProvider userInputProvider, IEffectRendererFactory effectRendererFactory, IMetadataProvider hatMetadataProvider, + IMetadataProvider weaponMetadataProvider, ISfxPlayer sfxPlayer, IClientWindowSizeRepository clientWindowSizeRepository) : base(game) @@ -115,6 +117,7 @@ public CharacterRenderer(Game game, _currentMapProvider = currentMapProvider; _userInputProvider = userInputProvider; _hatMetadataProvider = hatMetadataProvider; + _weaponMetadataProvider = weaponMetadataProvider; _effectRenderer = effectRendererFactory.Create(); _sfxPlayer = sfxPlayer; _clientWindowSizeRepository = clientWindowSizeRepository; @@ -282,6 +285,8 @@ public void DrawToSpriteBatch(SpriteBatch spriteBatch) private void DrawToRenderTarget() { + var weaponMetadata = _weaponMetadataProvider.GetValueOrDefault(Character.RenderProperties.WeaponGraphic); + lock (_rt_locker_) { GraphicsDevice.SetRenderTarget(_charRenderTarget); @@ -292,7 +297,7 @@ private void DrawToRenderTarget() .BuildList(_characterTextures, _character.RenderProperties) .Where(x => x.CanRender); foreach (var renderer in characterPropertyRenderers) - renderer.Render(_sb, DrawArea); + renderer.Render(_sb, DrawArea, weaponMetadata); if (_gameStateProvider.CurrentState == GameStates.None) { diff --git a/EndlessClient/Rendering/CharacterProperties/ArmorRenderer.cs b/EndlessClient/Rendering/CharacterProperties/ArmorRenderer.cs index 65e73b37f..423cf75be 100644 --- a/EndlessClient/Rendering/CharacterProperties/ArmorRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/ArmorRenderer.cs @@ -1,4 +1,5 @@ using System; +using EndlessClient.Rendering.Metadata.Models; using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; @@ -21,24 +22,24 @@ public ArmorRenderer(CharacterRenderProperties renderProperties, _armorSheet = armorSheet; } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { - var offsets = GetOffsets(parentCharacterDrawArea.Size.ToVector2()); + var offsets = GetOffsets(parentCharacterDrawArea.Size.ToVector2(), weaponMetadata.Ranged); var drawLoc = new Vector2(parentCharacterDrawArea.X - 2 + offsets.X, parentCharacterDrawArea.Y + offsets.Y); Render(spriteBatch, _armorSheet, drawLoc); } - private Vector2 GetOffsets(Vector2 parentCharacterSize) + private Vector2 GetOffsets(Vector2 parentCharacterSize, bool ranged) { var resX = -(float)Math.Floor(Math.Abs(_armorSheet.SourceRectangle.Width - parentCharacterSize.X) / 2); var resY = -(float)Math.Floor(Math.Abs(_armorSheet.SourceRectangle.Height - parentCharacterSize.Y) / 2); - if ((_renderProperties.RenderAttackFrame == 2 && !_renderProperties.IsRangedWeapon) || - (_renderProperties.RenderAttackFrame == 1 && _renderProperties.IsRangedWeapon)) + if ((_renderProperties.RenderAttackFrame == 2 && !ranged) || + (_renderProperties.RenderAttackFrame == 1 && ranged)) { resX += _renderProperties.IsFacing(EODirection.Up, EODirection.Right) ? 4 : 0; - if (_renderProperties.IsRangedWeapon) + if (ranged) { var factor = _renderProperties.IsFacing(EODirection.Down, EODirection.Left) ? -1 : 1; resX += _renderProperties.IsFacing(EODirection.Left, EODirection.Up) diff --git a/EndlessClient/Rendering/CharacterProperties/BaseCharacterPropertyRenderer.cs b/EndlessClient/Rendering/CharacterProperties/BaseCharacterPropertyRenderer.cs index beb5f907b..18978c99d 100644 --- a/EndlessClient/Rendering/CharacterProperties/BaseCharacterPropertyRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/BaseCharacterPropertyRenderer.cs @@ -1,4 +1,5 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -23,7 +24,7 @@ protected BaseCharacterPropertyRenderer(CharacterRenderProperties renderProperti LayerDepth = 1.0f; } - public abstract void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea); + public abstract void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata); protected virtual void Render(SpriteBatch spriteBatch, ISpriteSheet sheet, Vector2 drawLoc, int alpha = 255) { diff --git a/EndlessClient/Rendering/CharacterProperties/BootsRenderer.cs b/EndlessClient/Rendering/CharacterProperties/BootsRenderer.cs index 713264aaa..3b0af0f47 100644 --- a/EndlessClient/Rendering/CharacterProperties/BootsRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/BootsRenderer.cs @@ -1,4 +1,5 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -21,16 +22,16 @@ public BootsRenderer(CharacterRenderProperties renderProperties, _bootsSheet = bootsSheet; } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { - var offsets = GetOffsets(parentCharacterDrawArea); + var offsets = GetOffsets(parentCharacterDrawArea, weaponMetadata.Ranged); var drawLoc = new Vector2(parentCharacterDrawArea.X + offsets.X, // Center the Y coordinate over the bottom half of the character sprite parentCharacterDrawArea.Y + offsets.Y); Render(spriteBatch, _bootsSheet, drawLoc); } - private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) + private Vector2 GetOffsets(Rectangle parentCharacterDrawArea, bool ranged) { var resX = -(float)Math.Floor(Math.Abs((float)_bootsSheet.SourceRectangle.Width - parentCharacterDrawArea.Width) / 2); var resY = (int)Math.Floor(parentCharacterDrawArea.Height / 3f) * 2 - 1 - _renderProperties.Gender; @@ -51,7 +52,7 @@ private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) resX += 2 * factor; resY += 1 * factor - extra; } - else if (_renderProperties.RenderAttackFrame == 1 && _renderProperties.IsRangedWeapon) + else if (_renderProperties.RenderAttackFrame == 1 && ranged) { var isDownOrLeft = _renderProperties.IsFacing(EODirection.Down, EODirection.Left); var isDownOrRight = _renderProperties.IsFacing(EODirection.Down, EODirection.Right); diff --git a/EndlessClient/Rendering/CharacterProperties/EmoteRenderer.cs b/EndlessClient/Rendering/CharacterProperties/EmoteRenderer.cs index a1229803e..5031b7749 100644 --- a/EndlessClient/Rendering/CharacterProperties/EmoteRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/EmoteRenderer.cs @@ -1,6 +1,6 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib.Domain.Character; -using EOLib.Domain.Extensions; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -26,12 +26,12 @@ public EmoteRenderer(CharacterRenderProperties renderProperties, _skinRenderLocationCalculator = new SkinRenderLocationCalculator(_renderProperties); } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { if (_emoteSheet is EmptySpriteSheet) return; - var skinLoc = _skinRenderLocationCalculator.CalculateDrawLocationOfCharacterSkin(_skinSheet.SourceRectangle, parentCharacterDrawArea); + var skinLoc = _skinRenderLocationCalculator.CalculateDrawLocationOfCharacterSkin(_skinSheet.SourceRectangle, parentCharacterDrawArea, weaponMetadata.Ranged); var emotePos = new Vector2(skinLoc.X - 15, parentCharacterDrawArea.Y - _emoteSheet.SheetTexture.Height); Render(spriteBatch, _emoteSheet, emotePos, 128); } diff --git a/EndlessClient/Rendering/CharacterProperties/FaceRenderer.cs b/EndlessClient/Rendering/CharacterProperties/FaceRenderer.cs index 5392a2cec..83e37046b 100644 --- a/EndlessClient/Rendering/CharacterProperties/FaceRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/FaceRenderer.cs @@ -1,4 +1,5 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -29,12 +30,12 @@ public FaceRenderer(CharacterRenderProperties renderProperties, _skinRenderLocationCalculator = new SkinRenderLocationCalculator(_renderProperties); } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { if (!_renderProperties.IsFacing(EODirection.Down, EODirection.Right)) return; - var skinLoc = _skinRenderLocationCalculator.CalculateDrawLocationOfCharacterSkin(_skinSheet.SourceRectangle, parentCharacterDrawArea); + var skinLoc = _skinRenderLocationCalculator.CalculateDrawLocationOfCharacterSkin(_skinSheet.SourceRectangle, parentCharacterDrawArea, weaponMetadata.Ranged); var adjustX = _renderProperties.IsFacing(EODirection.Down) ? _renderProperties.SitState == SitState.Standing ? 2 : 8 diff --git a/EndlessClient/Rendering/CharacterProperties/HairRenderLocationCalculator.cs b/EndlessClient/Rendering/CharacterProperties/HairRenderLocationCalculator.cs index 772919588..239b90e48 100644 --- a/EndlessClient/Rendering/CharacterProperties/HairRenderLocationCalculator.cs +++ b/EndlessClient/Rendering/CharacterProperties/HairRenderLocationCalculator.cs @@ -15,14 +15,14 @@ public HairRenderLocationCalculator(CharacterRenderProperties renderProperties) _renderProperties = renderProperties; } - public Vector2 CalculateDrawLocationOfCharacterHair(Rectangle hairRectangle, Rectangle parentCharacterDrawArea) + public Vector2 CalculateDrawLocationOfCharacterHair(Rectangle hairRectangle, Rectangle parentCharacterDrawArea, bool ranged) { var resX = -(float)Math.Floor(Math.Abs((float)hairRectangle.Width - parentCharacterDrawArea.Width) / 2) - 1; var resY = -(float)Math.Floor(Math.Abs(hairRectangle.Height - (parentCharacterDrawArea.Height / 2f)) / 2) - _renderProperties.Gender; var isFlipped = _renderProperties.IsFacing(EODirection.Up, EODirection.Right); - if (_renderProperties.IsRangedWeapon && _renderProperties.RenderAttackFrame == 1) + if (ranged && _renderProperties.RenderAttackFrame == 1) { var rangedXOff = _renderProperties.Gender == 0 ? 1 : 3; resX += rangedXOff * (isFlipped ? 1 : -1); diff --git a/EndlessClient/Rendering/CharacterProperties/HairRenderer.cs b/EndlessClient/Rendering/CharacterProperties/HairRenderer.cs index 4bae8d260..6f7dd9066 100644 --- a/EndlessClient/Rendering/CharacterProperties/HairRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/HairRenderer.cs @@ -1,4 +1,5 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib.Domain.Character; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -20,9 +21,9 @@ public HairRenderer(CharacterRenderProperties renderProperties, _hairRenderLocationCalculator = new HairRenderLocationCalculator(_renderProperties); } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { - var drawLoc = _hairRenderLocationCalculator.CalculateDrawLocationOfCharacterHair(_hairSheet.SourceRectangle, parentCharacterDrawArea); + var drawLoc = _hairRenderLocationCalculator.CalculateDrawLocationOfCharacterHair(_hairSheet.SourceRectangle, parentCharacterDrawArea, weaponMetadata.Ranged); Render(spriteBatch, _hairSheet, drawLoc); } } diff --git a/EndlessClient/Rendering/CharacterProperties/HatRenderer.cs b/EndlessClient/Rendering/CharacterProperties/HatRenderer.cs index 462cef484..30e78b456 100644 --- a/EndlessClient/Rendering/CharacterProperties/HatRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/HatRenderer.cs @@ -1,4 +1,5 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -26,9 +27,9 @@ public HatRenderer(CharacterRenderProperties renderProperties, _hairRenderLocationCalculator = new HairRenderLocationCalculator(_renderProperties); } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { - var hairDrawLoc = _hairRenderLocationCalculator.CalculateDrawLocationOfCharacterHair(_hairSheet.SourceRectangle, parentCharacterDrawArea); + var hairDrawLoc = _hairRenderLocationCalculator.CalculateDrawLocationOfCharacterHair(_hairSheet.SourceRectangle, parentCharacterDrawArea, weaponMetadata.Ranged); var offsets = GetOffsets(); Render(spriteBatch, _hatSheet, hairDrawLoc + offsets); diff --git a/EndlessClient/Rendering/CharacterProperties/ICharacterPropertyRenderer.cs b/EndlessClient/Rendering/CharacterProperties/ICharacterPropertyRenderer.cs index 92ee2b0b6..9d5bb6c96 100644 --- a/EndlessClient/Rendering/CharacterProperties/ICharacterPropertyRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/ICharacterPropertyRenderer.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using EndlessClient.Rendering.Metadata.Models; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace EndlessClient.Rendering.CharacterProperties @@ -9,6 +10,6 @@ public interface ICharacterPropertyRenderer float LayerDepth { get; set; } - void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea); + void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata); } } diff --git a/EndlessClient/Rendering/CharacterProperties/ShieldRenderer.cs b/EndlessClient/Rendering/CharacterProperties/ShieldRenderer.cs index eda25b30e..0fb203e7a 100644 --- a/EndlessClient/Rendering/CharacterProperties/ShieldRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/ShieldRenderer.cs @@ -1,4 +1,5 @@ -using EndlessClient.Rendering.Sprites; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; @@ -30,14 +31,14 @@ public ShieldRenderer(CharacterRenderProperties renderProperties, _isShieldOnBack = isShieldOnBack; } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { - var offsets = GetOffsets(parentCharacterDrawArea); + var offsets = GetOffsets(parentCharacterDrawArea, weaponMetadata.Ranged); var drawLoc = new Vector2(parentCharacterDrawArea.X + offsets.X, parentCharacterDrawArea.Y + offsets.Y); Render(spriteBatch, _shieldSheet, drawLoc); } - private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) + private Vector2 GetOffsets(Rectangle parentCharacterDrawArea, bool ranged) { float resX, resY; @@ -48,7 +49,7 @@ private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) if (_renderProperties.RenderAttackFrame == 2) resX += _renderProperties.IsFacing(EODirection.Up, EODirection.Right) ? 2 : -2; - else if (_renderProperties.IsRangedWeapon && _renderProperties.RenderAttackFrame == 1) + else if (ranged && _renderProperties.RenderAttackFrame == 1) { // This currently does *not* match up perfectly with the original client. The original client doesn't keep // the arrows aligned on the attack frame, so they look like they are sliding across the back of the character. diff --git a/EndlessClient/Rendering/CharacterProperties/SkinRenderLocationCalculator.cs b/EndlessClient/Rendering/CharacterProperties/SkinRenderLocationCalculator.cs index 7d3f8f399..5689254d0 100644 --- a/EndlessClient/Rendering/CharacterProperties/SkinRenderLocationCalculator.cs +++ b/EndlessClient/Rendering/CharacterProperties/SkinRenderLocationCalculator.cs @@ -15,13 +15,13 @@ public SkinRenderLocationCalculator(CharacterRenderProperties renderProperties) _renderProperties = renderProperties; } - public Vector2 CalculateDrawLocationOfCharacterSkin(Rectangle skinRectangle, Rectangle parentCharacterDrawArea) + public Vector2 CalculateDrawLocationOfCharacterSkin(Rectangle skinRectangle, Rectangle parentCharacterDrawArea, bool ranged) { float resX, resY; // Ranged weapon attack frame is offset based on the Left or Right border of the parent character draw area // Ranged weapon graphics do not use the centering approach - if (_renderProperties.IsRangedWeapon && _renderProperties.RenderAttackFrame == 1) + if (ranged && _renderProperties.RenderAttackFrame == 1) { var isFlipped = _renderProperties.IsFacing(EODirection.Right, EODirection.Up); var needsExtraOffset = _renderProperties.IsFacing(EODirection.Right, EODirection.Down); diff --git a/EndlessClient/Rendering/CharacterProperties/SkinRenderer.cs b/EndlessClient/Rendering/CharacterProperties/SkinRenderer.cs index 5325fe240..3ee22f3b6 100644 --- a/EndlessClient/Rendering/CharacterProperties/SkinRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/SkinRenderer.cs @@ -1,7 +1,6 @@ -using EndlessClient.Rendering.Sprites; -using EOLib; +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; using EOLib.Domain.Character; -using EOLib.Domain.Extensions; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -23,9 +22,9 @@ public SkinRenderer(CharacterRenderProperties renderProperties, _skinRenderLocationCalculator = new SkinRenderLocationCalculator(_renderProperties); } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { - var drawLoc = _skinRenderLocationCalculator.CalculateDrawLocationOfCharacterSkin(_skinSheet.SourceRectangle, parentCharacterDrawArea); + var drawLoc = _skinRenderLocationCalculator.CalculateDrawLocationOfCharacterSkin(_skinSheet.SourceRectangle, parentCharacterDrawArea, weaponMetadata.Ranged); Render(spriteBatch, _skinSheet, drawLoc); } } diff --git a/EndlessClient/Rendering/CharacterProperties/WeaponRenderer.cs b/EndlessClient/Rendering/CharacterProperties/WeaponRenderer.cs index f201c0871..30d521aef 100644 --- a/EndlessClient/Rendering/CharacterProperties/WeaponRenderer.cs +++ b/EndlessClient/Rendering/CharacterProperties/WeaponRenderer.cs @@ -1,10 +1,11 @@ -using System; +using EndlessClient.Rendering.Metadata.Models; using EndlessClient.Rendering.Sprites; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using System; namespace EndlessClient.Rendering.CharacterProperties { @@ -21,18 +22,18 @@ public WeaponRenderer(CharacterRenderProperties renderProperties, _weaponSheet = weaponSheet; } - public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea) + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) { if (_renderProperties.IsActing(CharacterActionState.Sitting, CharacterActionState.SpellCast) || (_renderProperties.CurrentAction == CharacterActionState.Emote && _renderProperties.SitState != SitState.Standing)) return; - var offsets = GetOffsets(parentCharacterDrawArea); + var offsets = GetOffsets(parentCharacterDrawArea, weaponMetadata.Ranged); var drawLoc = new Vector2(parentCharacterDrawArea.X + offsets.X, parentCharacterDrawArea.Y + offsets.Y); Render(spriteBatch, _weaponSheet, drawLoc); } - private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) + private Vector2 GetOffsets(Rectangle parentCharacterDrawArea, bool ranged) { float resX, resY; @@ -45,13 +46,13 @@ private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) resX += (parentCharacterDrawArea.Width / 1.5f - 3) * factor; if (_renderProperties.RenderAttackFrame == 2) resX += 2 * factor; - else if (_renderProperties.RenderAttackFrame == 1 && _renderProperties.IsRangedWeapon) + else if (_renderProperties.RenderAttackFrame == 1 && ranged) resX += (isDownOrRight ? 6 : 4) * factor; resY -= 1 + _renderProperties.Gender; if (_renderProperties.IsActing(CharacterActionState.Walking)) resY -= 1; - else if (_renderProperties.RenderAttackFrame == 1 && _renderProperties.IsRangedWeapon) + else if (_renderProperties.RenderAttackFrame == 1 && ranged) resY += isDownOrRight ? 1 : 0; return new Vector2(resX, resY); diff --git a/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs b/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs index fc7d1a211..7f99c0ecf 100644 --- a/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs +++ b/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs @@ -1,6 +1,5 @@ using AutomaticTypeMapper; using EndlessClient.Audio; -using EndlessClient.Controllers; using EndlessClient.GameExecution; using EndlessClient.Input; using EndlessClient.Rendering.Character; @@ -9,7 +8,6 @@ using EndlessClient.Rendering.Effects; using EndlessClient.Rendering.Metadata; using EndlessClient.Rendering.Metadata.Models; -using EndlessClient.Rendering.Sprites; using EOLib.Domain.Character; using EOLib.Domain.Map; using Microsoft.Xna.Framework; @@ -32,6 +30,7 @@ public class CharacterRendererFactory : ICharacterRendererFactory private readonly IUserInputProvider _userInputProvider; private readonly IEffectRendererFactory _effectRendererFactory; private readonly IMetadataProvider _hatMetadataProvider; + private readonly IMetadataProvider _weaponMetadataProvider; private readonly ISfxPlayer _sfxPlayer; private readonly IClientWindowSizeRepository _clientWindowSizeRepository; @@ -48,6 +47,7 @@ public CharacterRendererFactory(IEndlessGameProvider gameProvider, IUserInputProvider userInputProvider, IEffectRendererFactory effectRendererFactory, IMetadataProvider hatMetadataProvider, + IMetadataProvider weaponMetadataProvider, ISfxPlayer sfxPlayer, IClientWindowSizeRepository clientWindowSizeRepository) { @@ -64,6 +64,7 @@ public CharacterRendererFactory(IEndlessGameProvider gameProvider, _userInputProvider = userInputProvider; _effectRendererFactory = effectRendererFactory; _hatMetadataProvider = hatMetadataProvider; + _weaponMetadataProvider = weaponMetadataProvider; _sfxPlayer = sfxPlayer; _clientWindowSizeRepository = clientWindowSizeRepository; } @@ -85,6 +86,7 @@ public ICharacterRenderer CreateCharacterRenderer(EOLib.Domain.Character.Charact _userInputProvider, _effectRendererFactory, _hatMetadataProvider, + _weaponMetadataProvider, _sfxPlayer, _clientWindowSizeRepository); } diff --git a/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs b/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs index 2330f666c..a89107ada 100644 --- a/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs +++ b/EndlessClient/Rendering/Metadata/GFXMetadataLoader.cs @@ -39,7 +39,7 @@ public GFXMetadataLoader(IPEFileCollection peFileCollection) public Option GetMetadata(int graphic) where TMetadata : class, IGFXMetadata { - if (!_mapper.TryGetValue(typeof(TMetadata), out var gfxType)) + if (graphic == 0 || !_mapper.TryGetValue(typeof(TMetadata), out var gfxType)) return Option.None(); if (!_cache.ContainsKey(gfxType)) diff --git a/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs b/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs index 9a839116c..1b33285f7 100644 --- a/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs +++ b/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs @@ -5,9 +5,6 @@ using EOLib.Domain.Character; using EOLib.Domain.Extensions; using EOLib.Graphics; -using EOLib.IO; -using EOLib.IO.Pub; -using EOLib.IO.Repositories; using Microsoft.Xna.Framework; using System; using System.Linq; @@ -18,19 +15,19 @@ namespace EndlessClient.Rendering.Sprites public class CharacterSpriteCalculator : ICharacterSpriteCalculator { private readonly INativeGraphicsManager _gfxManager; - private readonly IEIFFileProvider _eifFileProvider; private readonly IMetadataProvider _shieldMetadataProvider; private readonly IMetadataProvider _hatMetadataProvider; + private readonly IMetadataProvider _weaponMetadataProvider; public CharacterSpriteCalculator(INativeGraphicsManager gfxManager, - IEIFFileProvider eifFileProvider, IMetadataProvider shieldMetadataProvider, - IMetadataProvider hatMetadataProvider) + IMetadataProvider hatMetadataProvider, + IMetadataProvider weaponMetadataProvider) { _gfxManager = gfxManager; - _eifFileProvider = eifFileProvider; _shieldMetadataProvider = shieldMetadataProvider; _hatMetadataProvider = hatMetadataProvider; + _weaponMetadataProvider = weaponMetadataProvider; } public ISpriteSheet GetBootsTexture(CharacterRenderProperties characterRenderProperties) @@ -516,15 +513,7 @@ private int GetOffsetBasedOnState(WeaponSpriteType type) private bool BowIsEquipped(CharacterRenderProperties characterRenderProperties) { - if (EIFFile == null) - return false; - - var weaponInfo = EIFFile.FirstOrDefault(x => x.Type == ItemType.Weapon && - x.DollGraphic == characterRenderProperties.WeaponGraphic); - - return weaponInfo != null && weaponInfo.SubType == ItemSubType.Ranged; + return _weaponMetadataProvider.GetValueOrDefault(characterRenderProperties.WeaponGraphic).Ranged; } - - private IPubFile EIFFile => _eifFileProvider.EIFFile; } } diff --git a/EndlessClient/Test/CharacterStateTest.cs b/EndlessClient/Test/CharacterStateTest.cs index d1f3f37c0..ef96f552d 100644 --- a/EndlessClient/Test/CharacterStateTest.cs +++ b/EndlessClient/Test/CharacterStateTest.cs @@ -1,18 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using EndlessClient.GameExecution; +using EndlessClient.GameExecution; using EndlessClient.Rendering.Character; using EndlessClient.Rendering.Factories; +using EndlessClient.Rendering.Metadata; +using EndlessClient.Rendering.Metadata.Models; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Extensions; using EOLib.IO; -using EOLib.IO.Extensions; using EOLib.IO.Pub; using EOLib.IO.Repositories; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; +using System; +using System.Collections.Generic; +using System.Linq; namespace EndlessClient.Test { @@ -43,6 +44,7 @@ static CharacterStateTest() private readonly ICharacterRendererFactory _characterRendererFactory; private readonly IEIFFileProvider _eifFileProvider; + private readonly IMetadataProvider _weaponMetadataProvider; private CharacterRenderProperties _baseProperties; private readonly Dictionary _itemIndices; @@ -57,11 +59,13 @@ static CharacterStateTest() public CharacterStateTest(IEndlessGame baseGame, ICharacterRendererFactory characterRendererFactory, - IEIFFileProvider eifFileProvider) + IEIFFileProvider eifFileProvider, + IMetadataProvider weaponMetadataProvider) : base((Game)baseGame) { _characterRendererFactory = characterRendererFactory; _eifFileProvider = eifFileProvider; + _weaponMetadataProvider = weaponMetadataProvider; _itemIndices = ((ItemType[])Enum.GetValues(typeof(ItemType))).ToDictionary(k => k, v => 0); _renderersForDifferentStates = new List(12); @@ -153,7 +157,7 @@ public override void Update(GameTime gameTime) else if (KeyPressed(Keys.D6) && !_isBowEquipped) { var nextGraphic = GetNextItemGraphicMatching(ItemType.Weapon, _baseProperties.WeaponGraphic); - _baseProperties = _baseProperties.WithWeaponGraphic(nextGraphic).WithIsRangedWeapon(EIFFile.IsRangedWeapon(nextGraphic)); + _baseProperties = _baseProperties.WithWeaponGraphic(nextGraphic); update = true; } else if (KeyPressed(Keys.D7)) @@ -173,11 +177,11 @@ public override void Update(GameTime gameTime) { _lastGraphic = _baseProperties.WeaponGraphic; var firstBowWeapon = EIFFile.First(x => x.Type == ItemType.Weapon && x.SubType == ItemSubType.Ranged); - _baseProperties = _baseProperties.WithWeaponGraphic(firstBowWeapon.DollGraphic).WithIsRangedWeapon(true); + _baseProperties = _baseProperties.WithWeaponGraphic(firstBowWeapon.DollGraphic); } else { - _baseProperties = _baseProperties.WithWeaponGraphic(_lastGraphic).WithIsRangedWeapon(EIFFile.IsRangedWeapon(_lastGraphic)); + _baseProperties = _baseProperties.WithWeaponGraphic(_lastGraphic); } _isBowEquipped = !_isBowEquipped; @@ -200,7 +204,8 @@ public override void Update(GameTime gameTime) if ((now - _lastAttack).TotalMilliseconds > 500) { var rend = _renderersForDifferentStates[(int)DisplayState.AttackingAnimation]; - rend.Character = rend.Character.WithRenderProperties(rend.Character.RenderProperties.WithNextAttackFrame()); + var isRanged = _weaponMetadataProvider.GetValueOrDefault(rend.Character.RenderProperties.WeaponGraphic).Ranged; + rend.Character = rend.Character.WithRenderProperties(rend.Character.RenderProperties.WithNextAttackFrame(isRanged)); _lastAttack = now; } @@ -223,6 +228,7 @@ public override void Draw(GameTime gameTime) private CharacterRenderProperties GetRenderPropertiesForState(DisplayState displayState) { + var isRanged = _weaponMetadataProvider.GetValueOrDefault(_baseProperties.WeaponGraphic).Ranged; switch (displayState) { case DisplayState.Standing: @@ -232,9 +238,9 @@ private CharacterRenderProperties GetRenderPropertiesForState(DisplayState displ case DisplayState.SitFloor: return _baseProperties.WithSitState(SitState.Floor); case DisplayState.Attack1: - return _baseProperties.WithNextAttackFrame(); + return _baseProperties.WithNextAttackFrame(isRanged); case DisplayState.Attack2: - return _baseProperties.WithNextAttackFrame().WithNextAttackFrame(); + return _baseProperties.WithNextAttackFrame(isRanged).WithNextAttackFrame(isRanged); case DisplayState.Walk1: return _baseProperties.WithNextWalkFrame(); case DisplayState.Walk2: diff --git a/EndlessClient/Test/TestModeLauncher.cs b/EndlessClient/Test/TestModeLauncher.cs index 2d85e4643..0e0f5cbd3 100644 --- a/EndlessClient/Test/TestModeLauncher.cs +++ b/EndlessClient/Test/TestModeLauncher.cs @@ -1,27 +1,32 @@ using AutomaticTypeMapper; using EndlessClient.GameExecution; using EndlessClient.Rendering.Factories; +using EndlessClient.Rendering.Metadata; +using EndlessClient.Rendering.Metadata.Models; using EOLib.IO.Repositories; namespace EndlessClient.Test { - [MappedType(BaseType = typeof(ITestModeLauncher))] + [AutoMappedType] public class TestModeLauncher : ITestModeLauncher { private readonly IEndlessGameProvider _endlessGameProvider; private readonly ICharacterRendererFactory _characterRendererFactory; private readonly IEIFFileProvider _eifFileProvider; private readonly IGameStateProvider _gameStateProvider; + private readonly IMetadataProvider _weaponMetadataProvider; public TestModeLauncher(IEndlessGameProvider endlessGameProvider, ICharacterRendererFactory characterRendererFactory, IEIFFileProvider eifFileProvider, - IGameStateProvider gameStateProvider) + IGameStateProvider gameStateProvider, + IMetadataProvider weaponMetadataProvider) { _endlessGameProvider = endlessGameProvider; _characterRendererFactory = characterRendererFactory; _eifFileProvider = eifFileProvider; _gameStateProvider = gameStateProvider; + _weaponMetadataProvider = weaponMetadataProvider; } public void LaunchTestMode() @@ -32,7 +37,8 @@ public void LaunchTestMode() var testMode = new CharacterStateTest( _endlessGameProvider.Game, _characterRendererFactory, - _eifFileProvider); + _eifFileProvider, + _weaponMetadataProvider); _endlessGameProvider.Game.Components.Clear(); _endlessGameProvider.Game.Components.Add(testMode); From cb22a81393c4ba1527d566b0931739b7a682a54f Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 18 Dec 2023 13:06:41 -0800 Subject: [PATCH 3/4] Add weapon slash rendering --- .../Rendering/Character/CharacterTextures.cs | 3 + .../Rendering/Character/ICharacterTextures.cs | 1 + .../CharacterPropertyRendererBuilder.cs | 2 + .../WeaponSlashRenderer.cs | 46 ++++++ .../Metadata/WeaponMetadataProvider.cs | 150 +++++++++--------- .../Sprites/CharacterSpriteCalculator.cs | 16 ++ .../Sprites/ICharacterSpriteCalculator.cs | 19 +-- 7 files changed, 153 insertions(+), 84 deletions(-) create mode 100644 EndlessClient/Rendering/CharacterProperties/WeaponSlashRenderer.cs diff --git a/EndlessClient/Rendering/Character/CharacterTextures.cs b/EndlessClient/Rendering/Character/CharacterTextures.cs index 91cde3d69..961c6c61c 100644 --- a/EndlessClient/Rendering/Character/CharacterTextures.cs +++ b/EndlessClient/Rendering/Character/CharacterTextures.cs @@ -15,6 +15,7 @@ public class CharacterTextures : ICharacterTextures public ISpriteSheet Shield { get; private set; } public ISpriteSheet Weapon { get; private set; } public ISpriteSheet WeaponExtra { get; private set; } + public ISpriteSheet WeaponSlash{ get; private set; } public ISpriteSheet Hair { get; private set; } public ISpriteSheet Skin { get; private set; } @@ -38,6 +39,8 @@ public void Refresh(CharacterRenderProperties characterRenderProperties) Weapon = weaponTextures[0]; WeaponExtra = weaponTextures[1]; + WeaponSlash = _characterSpriteCalculator.GetWeaponSlash(characterRenderProperties); + Hair = _characterSpriteCalculator.GetHairTexture(characterRenderProperties); Skin = _characterSpriteCalculator.GetSkinTexture(characterRenderProperties); Emote = _characterSpriteCalculator.GetEmoteTexture(characterRenderProperties); diff --git a/EndlessClient/Rendering/Character/ICharacterTextures.cs b/EndlessClient/Rendering/Character/ICharacterTextures.cs index 4d9f06358..9869d503a 100644 --- a/EndlessClient/Rendering/Character/ICharacterTextures.cs +++ b/EndlessClient/Rendering/Character/ICharacterTextures.cs @@ -12,6 +12,7 @@ public interface ICharacterTextures ISpriteSheet Shield { get; } ISpriteSheet Weapon { get; } ISpriteSheet WeaponExtra { get; } + ISpriteSheet WeaponSlash { get; } ISpriteSheet Hair { get; } ISpriteSheet Skin { get; } diff --git a/EndlessClient/Rendering/CharacterProperties/CharacterPropertyRendererBuilder.cs b/EndlessClient/Rendering/CharacterProperties/CharacterPropertyRendererBuilder.cs index ae88af764..d269f11bc 100644 --- a/EndlessClient/Rendering/CharacterProperties/CharacterPropertyRendererBuilder.cs +++ b/EndlessClient/Rendering/CharacterProperties/CharacterPropertyRendererBuilder.cs @@ -63,6 +63,8 @@ public IEnumerable BuildList(ICharacterTextures text { LayerDepth = BaseLayer * (hatMaskType == HatMaskType.FaceMask ? 11 : 10) }; + + yield return new WeaponSlashRenderer(renderProperties, textures.WeaponSlash) { LayerDepth = BaseLayer * 14 }; } private bool IsShieldBehindCharacter(CharacterRenderProperties renderProperties) diff --git a/EndlessClient/Rendering/CharacterProperties/WeaponSlashRenderer.cs b/EndlessClient/Rendering/CharacterProperties/WeaponSlashRenderer.cs new file mode 100644 index 000000000..328aa6613 --- /dev/null +++ b/EndlessClient/Rendering/CharacterProperties/WeaponSlashRenderer.cs @@ -0,0 +1,46 @@ +using EndlessClient.Rendering.Metadata.Models; +using EndlessClient.Rendering.Sprites; +using EOLib; +using EOLib.Domain.Character; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace EndlessClient.Rendering.CharacterProperties +{ + public class WeaponSlashRenderer : BaseCharacterPropertyRenderer + { + private readonly ISpriteSheet _slashSheet; + + public override bool CanRender => _slashSheet.HasTexture && _renderProperties.WeaponGraphic != 0 && _renderProperties.RenderAttackFrame == 2; + + protected override bool ShouldFlip => false; + + public WeaponSlashRenderer(CharacterRenderProperties renderProperties, + ISpriteSheet slashSheet) + : base(renderProperties) + { + _slashSheet = slashSheet; + } + + public override void Render(SpriteBatch spriteBatch, Rectangle parentCharacterDrawArea, WeaponMetadata weaponMetadata) + { + if (weaponMetadata.Slash == null || weaponMetadata.Ranged) + return; + + var offsets = GetOffsets(parentCharacterDrawArea) - new Vector2(0, _renderProperties.Gender); + Render(spriteBatch, _slashSheet, parentCharacterDrawArea.Location.ToVector2() + offsets, 96); + } + + private Vector2 GetOffsets(Rectangle parentCharacterDrawArea) + { + return _renderProperties.Direction switch + { + EODirection.Down => new Vector2(-30, 4), + EODirection.Left => new Vector2(-34, -9), + EODirection.Up => new Vector2(-6, -9), + EODirection.Right => new Vector2(-10, 4), + _ => Vector2.Zero + }; + } + } +} diff --git a/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs b/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs index 470ada40d..95f2830a9 100644 --- a/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs +++ b/EndlessClient/Rendering/Metadata/WeaponMetadataProvider.cs @@ -17,81 +17,81 @@ public WeaponMetadataProvider(IGFXMetadataLoader metadataLoader) { _metadata = new Dictionary { - { 0, new WeaponMetadata( null, new[] { SoundEffectID.PunchAttack }, false) }, // fist - { 1, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // wood axe - { 2, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // sai - { 3, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dragon blade - { 4, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dagger - { 5, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // spear - { 6, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // saber - { 7, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // staff - { 8, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // book - { 9, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // mace - { 10, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // spirit star - { 11, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // throw axe - { 12, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dark katana - { 13, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // short sword - { 14, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // broadsword - { 15, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // broom - { 16, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ninchackus - { 17, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ancient star - { 18, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle axe - { 19, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ancient sword - { 20, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // luna staff - { 21, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lance - { 22, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // aura staff - { 23, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // forest staff - { 24, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // normal sword - { 25, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // jewel staff - { 26, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // thor's hammer - { 27, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // light katana - { 28, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // polearm - { 29, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // sickle - { 30, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // trident - { 31, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // warlock sword - { 32, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // whip - { 33, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ultima - { 34, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ice blade - { 35, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gold defender - { 36, new WeaponMetadata( 4, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lotus sword - { 37, new WeaponMetadata( 4, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // cristal sword - { 38, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // killing edge - { 39, new WeaponMetadata( 7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // dark blade - { 40, new WeaponMetadata( 7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // reaper scyth - { 41, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // crescent staff - { 42, new WeaponMetadata( 0, new[] { SoundEffectID.AttackBow }, true) }, // bow - { 43, new WeaponMetadata( 0, new[] { SoundEffectID.AttackBow }, true) }, // xbow - { 44, new WeaponMetadata( 8, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // reaper - { 45, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // hockey stick - { 46, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // twin blades - { 47, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lefor mace - { 48, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // cava staff - { 49, new WeaponMetadata( 0, new[] { SoundEffectID.Harp1,SoundEffectID.Harp2,SoundEffectID.Harp3}, true) }, // harp - { 50, new WeaponMetadata( 0, new[] { SoundEffectID.Guitar1,SoundEffectID.Guitar2, SoundEffectID.Guitar3 }, true) }, // guitar - { 51, new WeaponMetadata( 5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle spear - { 52, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // flail - { 53, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // war axe - { 54, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gastro - { 55, new WeaponMetadata( 7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // ablo staff - { 56, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fluon sword - { 57, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // rapier - { 58, new WeaponMetadata( 0, new[] { SoundEffectID.Gun }, true) }, // gun - { 59, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // knob staff - { 60, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fladdat staff - { 61, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gabrasto - { 62, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle spear 2 - { 63, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lens of truth - { 64, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // chopper - { 65, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // adger - { 66, new WeaponMetadata( 1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // chains - { 67, new WeaponMetadata( 2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // mitova - { 68, new WeaponMetadata( 3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // merhawk - { 69, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // kontra - { 70, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // jack spear - { 71, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // bazar staff - { 72, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // saw blade - { 73, new WeaponMetadata( 0, new[] { SoundEffectID.AttackBow }, true) }, // scav bow - { 74, new WeaponMetadata( 0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fan + { 0, new WeaponMetadata(null, new[] { SoundEffectID.PunchAttack }, false) }, // fist + { 1, new WeaponMetadata(3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // wood axe + { 2, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // sai + { 3, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dragon blade + { 4, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dagger + { 5, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // spear + { 6, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // saber + { 7, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // staff + { 8, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // book + { 9, new WeaponMetadata(3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // mace + { 10, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // spirit star + { 11, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // throw axe + { 12, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // dark katana + { 13, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // short sword + { 14, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // broadsword + { 15, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // broom + { 16, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ninchackus + { 17, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ancient star + { 18, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle axe + { 19, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ancient sword + { 20, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // luna staff + { 21, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lance + { 22, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // aura staff + { 23, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // forest staff + { 24, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // normal sword + { 25, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // jewel staff + { 26, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // thor's hammer + { 27, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // light katana + { 28, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // polearm + { 29, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // sickle + { 30, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // trident + { 31, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // warlock sword + { 32, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // whip + { 33, new WeaponMetadata(5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ultima + { 34, new WeaponMetadata(5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // ice blade + { 35, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gold defender + { 36, new WeaponMetadata(4, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lotus sword + { 37, new WeaponMetadata(4, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // cristal sword + { 38, new WeaponMetadata(5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // killing edge + { 39, new WeaponMetadata(7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // dark blade + { 40, new WeaponMetadata(7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // reaper scyth + { 41, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // crescent staff + { 42, new WeaponMetadata(0, new[] { SoundEffectID.AttackBow }, true) }, // bow + { 43, new WeaponMetadata(0, new[] { SoundEffectID.AttackBow }, true) }, // xbow + { 44, new WeaponMetadata(8, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // reaper + { 45, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // hockey stick + { 46, new WeaponMetadata(5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // twin blades + { 47, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lefor mace + { 48, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // cava staff + { 49, new WeaponMetadata(0, new[] { SoundEffectID.Harp1,SoundEffectID.Harp2,SoundEffectID.Harp3}, true) }, // harp + { 50, new WeaponMetadata(0, new[] { SoundEffectID.Guitar1,SoundEffectID.Guitar2, SoundEffectID.Guitar3 }, true) }, // guitar + { 51, new WeaponMetadata(5, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle spear + { 52, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // flail + { 53, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // war axe + { 54, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gastro + { 55, new WeaponMetadata(7, new[] { SoundEffectID.AlternateMeleeAttack }, false) }, // ablo staff + { 56, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fluon sword + { 57, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // rapier + { 58, new WeaponMetadata(0, new[] { SoundEffectID.Gun }, true) }, // gun + { 59, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // knob staff + { 60, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fladdat staff + { 61, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // gabrasto + { 62, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // battle spear 2 + { 63, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // lens of truth + { 64, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // chopper + { 65, new WeaponMetadata(3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // adger + { 66, new WeaponMetadata(1, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // chains + { 67, new WeaponMetadata(2, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // mitova + { 68, new WeaponMetadata(3, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // merhawk + { 69, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // kontra + { 70, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // jack spear + { 71, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // bazar staff + { 72, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // saw blade + { 73, new WeaponMetadata(0, new[] { SoundEffectID.AttackBow }, true) }, // scav bow + { 74, new WeaponMetadata(0, new[] { SoundEffectID.MeleeWeaponAttack }, false) }, // fan }; _metadataLoader = metadataLoader; } diff --git a/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs b/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs index 1b33285f7..7da2d8533 100644 --- a/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs +++ b/EndlessClient/Rendering/Sprites/CharacterSpriteCalculator.cs @@ -287,6 +287,22 @@ public ISpriteSheet[] GetWeaponTextures(CharacterRenderProperties characterRende return retTextures; } + public ISpriteSheet GetWeaponSlash(CharacterRenderProperties characterRenderProperties) + { + const int NUM_SLASHES = 9; + + var metadata = _weaponMetadataProvider.GetValueOrDefault(characterRenderProperties.WeaponGraphic); + if (!metadata.Slash.HasValue || metadata.Ranged || characterRenderProperties.RenderAttackFrame != 2) + return new EmptySpriteSheet(); + + var sheet = _gfxManager.TextureFromResource(GFXTypes.PostLoginUI, 40, transparent: true); + return new SpriteSheet(sheet, + new Rectangle(sheet.Width / 4 * (int)characterRenderProperties.Direction, + sheet.Height / NUM_SLASHES * metadata.Slash.Value, + sheet.Width / 4, + sheet.Height / NUM_SLASHES)); + } + public ISpriteSheet GetSkinTexture(CharacterRenderProperties characterRenderProperties) { const int SheetRows = 7; diff --git a/EndlessClient/Rendering/Sprites/ICharacterSpriteCalculator.cs b/EndlessClient/Rendering/Sprites/ICharacterSpriteCalculator.cs index 70275c6c1..1fe5818ba 100644 --- a/EndlessClient/Rendering/Sprites/ICharacterSpriteCalculator.cs +++ b/EndlessClient/Rendering/Sprites/ICharacterSpriteCalculator.cs @@ -4,15 +4,16 @@ namespace EndlessClient.Rendering.Sprites { public interface ICharacterSpriteCalculator { - ISpriteSheet GetBootsTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet GetArmorTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet GetHatTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet GetShieldTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet[] GetWeaponTextures(CharacterRenderProperties _characterRenderProperties); + ISpriteSheet GetBootsTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetArmorTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetHatTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetShieldTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet[] GetWeaponTextures(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetWeaponSlash(CharacterRenderProperties characterRenderProperties); - ISpriteSheet GetSkinTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet GetHairTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet GetFaceTexture(CharacterRenderProperties _characterRenderProperties); - ISpriteSheet GetEmoteTexture(CharacterRenderProperties _characterRenderProperties); + ISpriteSheet GetSkinTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetHairTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetFaceTexture(CharacterRenderProperties characterRenderProperties); + ISpriteSheet GetEmoteTexture(CharacterRenderProperties characterRenderProperties); } } From 5eda2e9de181383a36e54d2f3537af2745b1df52 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 18 Dec 2023 13:06:59 -0800 Subject: [PATCH 4/4] Update EndlessClient.Binaries to version with embedded weapon metadata --- EndlessClient/EndlessClient.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EndlessClient/EndlessClient.csproj b/EndlessClient/EndlessClient.csproj index 5163d32c5..d615482f8 100644 --- a/EndlessClient/EndlessClient.csproj +++ b/EndlessClient/EndlessClient.csproj @@ -77,7 +77,7 @@ - +