Skip to content

Commit

Permalink
Implement EFFECT_AGREE handler for rendering an effect at given coord…
Browse files Browse the repository at this point in the history
…inates
  • Loading branch information
ethanmoffat committed Sep 7, 2022
1 parent 4be483c commit c9bb922
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 7 deletions.
10 changes: 10 additions & 0 deletions EOLib/Domain/Notifiers/IEffectNotifier.cs
Expand Up @@ -7,17 +7,27 @@ namespace EOLib.Domain.Notifiers
public interface IEffectNotifier
{
void NotifyWarpLeaveEffect(short characterId, WarpAnimation anim);

void NotifyWarpEnterEffect(short characterId, WarpAnimation anim);

void NotifyPotionEffect(short playerId, int effectId);

void NotifyMapEffect(MapEffect effect, byte strength = 0);

void NotifyEffectAtLocation(byte x, byte y, short effectId);
}

[AutoMappedType]
public class NoOpEffectNotifier : IEffectNotifier
{
public void NotifyWarpLeaveEffect(short characterId, WarpAnimation anim) { }

public void NotifyWarpEnterEffect(short characterId, WarpAnimation anim) { }

public void NotifyPotionEffect(short playerId, int effectId) { }

public void NotifyMapEffect(MapEffect effect, byte strength = 0) { }

public void NotifyEffectAtLocation(byte x, byte y, short effectId) { }
}
}
37 changes: 37 additions & 0 deletions EOLib/PacketHandlers/Effects/EffectAgreeHandler.cs
@@ -0,0 +1,37 @@
using AutomaticTypeMapper;
using EOLib.Domain.Login;
using EOLib.Domain.Notifiers;
using EOLib.Net;
using EOLib.Net.Handlers;
using System.Collections.Generic;

namespace EOLib.PacketHandlers.Effects
{
[AutoMappedType]
public class EffectAgreeHandler : InGameOnlyPacketHandler
{
private readonly IEnumerable<IEffectNotifier> _effectNotifiers;

public override PacketFamily Family => PacketFamily.Effect;
public override PacketAction Action => PacketAction.Agree;

public EffectAgreeHandler(IPlayerInfoProvider playerInfoProvider,
IEnumerable<IEffectNotifier> effectNotifiers)
: base(playerInfoProvider)
{
_effectNotifiers = effectNotifiers;
}

public override bool HandlePacket(IPacket packet)
{
var x = packet.ReadChar();
var y = packet.ReadChar();
var effectId = packet.ReadShort();

foreach (var notifier in _effectNotifiers)
notifier.NotifyEffectAtLocation(x, y, effectId);

return true;
}
}
}
Expand Up @@ -306,6 +306,15 @@ public void MakeMainPlayerDrunk()
_statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_ITEM_USE_DRUNK);
}

public void NotifyEffectAtLocation(byte x, byte y, short effectId)
{
if (_hudControlProvider.IsInGame)
{
_hudControlProvider.GetComponent<IMapRenderer>(HudControlIdentifier.MapRenderer)
.RenderEffect(x, y, effectId);
}
}

private void ShowWaterSplashiesIfNeeded(CharacterActionState action, int characterID)
{
var character = characterID == _characterRepository.MainCharacter.ID
Expand Down
21 changes: 21 additions & 0 deletions EndlessClient/Rendering/Effects/CustomEffectSpriteInfo.cs
@@ -0,0 +1,21 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace EndlessClient.Rendering.Effects
{
public class CustomEffectSpriteInfo : EffectSpriteInfo
{
public CustomEffectSpriteInfo(int numberOfFrames, int repeats, bool onTopOfCharacter, int alpha, Texture2D graphic)
: base(numberOfFrames, repeats, onTopOfCharacter, alpha, graphic)
{
}

protected override Vector2 GetDrawLocation(Rectangle textureSourceRectangle, Rectangle targetActorRectangle)
{
var targetX = targetActorRectangle.X + (targetActorRectangle.Width - textureSourceRectangle.Width) / 2 - targetActorRectangle.Width / 2;
var targetY = targetActorRectangle.Y - textureSourceRectangle.Height;

return new Vector2(targetX, targetY);
}
}
}
13 changes: 11 additions & 2 deletions EndlessClient/Rendering/Effects/EffectSpriteManager.cs
Expand Up @@ -80,8 +80,17 @@ private IList<IEffectSpriteInfo> ResolveSpellEffect(HardCodedSpellGraphic effect
return new List<IEffectSpriteInfo>(retList);
}

//not implemented spell graphics will just not render anything
return new IEffectSpriteInfo[] { };
// not implemented spell graphics have a default rendering set
// spell effects seem to start at GFX 128 and go in sets of 3, indexed on (spellGraphic - 10)
// first gfx is behind character, other 2 are in front
// 255 alpha assumed until proven otherwise
// 4 frames assumed until proven otherwise
return new List<IEffectSpriteInfo>
{
new CustomEffectSpriteInfo(4, 1, false, 255, GetGraphic(((int)effect - 9)*3 + 128)),
new CustomEffectSpriteInfo(4, 1, true, 255, GetGraphic(((int)effect - 9)*3 + 129)),
new CustomEffectSpriteInfo(4, 1, true, 255, GetGraphic(((int)effect - 9)*3 + 130))
};
}

private IList<IEffectSpriteInfo> GetWarpEffect(EffectType warpEffect)
Expand Down
53 changes: 53 additions & 0 deletions EndlessClient/Rendering/Factories/MapGridEffectTargetFactory.cs
@@ -0,0 +1,53 @@
using AutomaticTypeMapper;
using EndlessClient.Audio;
using EndlessClient.Rendering.Character;
using EndlessClient.Rendering.Effects;
using EndlessClient.Rendering.Map;
using EOLib.Domain.Character;
using EOLib.Domain.Map;
using EOLib.Graphics;

namespace EndlessClient.Rendering.Factories
{
[AutoMappedType]
public class MapGridEffectTargetFactory : IMapGridEffectTargetFactory
{
private readonly INativeGraphicsManager _nativeGraphicsManager;
private readonly ISfxPlayer _sfxPlayer;
private readonly IRenderOffsetCalculator _renderOffsetCalculator;
private readonly ICharacterRendererProvider _characterRendererProvider;
private readonly ICharacterTextures _characterTextures;

public MapGridEffectTargetFactory(INativeGraphicsManager nativeGraphicsManager,
ISfxPlayer sfxPlayer,
IRenderOffsetCalculator renderOffsetCalculator,
ICharacterRendererProvider characterRendererProvider,
ICharacterTextures characterTextures)
{
_nativeGraphicsManager = nativeGraphicsManager;
_sfxPlayer = sfxPlayer;
_renderOffsetCalculator = renderOffsetCalculator;
_characterRendererProvider = characterRendererProvider;
_characterTextures = characterTextures;
}

public IMapGridEffectTarget Create(byte x, byte y)
{
if (_characterTextures.Skin == null)
_characterTextures.Refresh(new CharacterRenderProperties.Builder().ToImmutable());

return new MapGridEffectTarget(
_nativeGraphicsManager,
_sfxPlayer,
_renderOffsetCalculator,
_characterRendererProvider,
_characterTextures,
new MapCoordinate(x, y));
}
}

public interface IMapGridEffectTargetFactory
{
IMapGridEffectTarget Create(byte x, byte y);
}
}
8 changes: 6 additions & 2 deletions EndlessClient/Rendering/Factories/MapRendererFactory.cs
Expand Up @@ -24,6 +24,7 @@ public class MapRendererFactory : IMapRendererFactory
private readonly IConfigurationProvider _configurationProvider;
private readonly IMouseCursorRendererFactory _mouseCursorRendererFactory;
private readonly IRenderOffsetCalculator _renderOffsetCalculator;
private readonly IMapGridEffectTargetFactory _mapGridEffectTargetFactory;
private readonly INPCRendererUpdater _npcRendererUpdater;
private readonly IDynamicMapObjectUpdater _dynamicMapObjectUpdater;

Expand All @@ -38,7 +39,8 @@ public class MapRendererFactory : IMapRendererFactory
IDynamicMapObjectUpdater dynamicMapObjectUpdater,
IConfigurationProvider configurationProvider,
IMouseCursorRendererFactory mouseCursorRendererFactory,
IRenderOffsetCalculator renderOffsetCalculator)
IRenderOffsetCalculator renderOffsetCalculator,
IMapGridEffectTargetFactory mapGridEffectTargetFactory)
{
_endlessGameProvider = endlessGameProvider;
_renderTargetFactory = renderTargetFactory;
Expand All @@ -52,6 +54,7 @@ public class MapRendererFactory : IMapRendererFactory
_configurationProvider = configurationProvider;
_mouseCursorRendererFactory = mouseCursorRendererFactory;
_renderOffsetCalculator = renderOffsetCalculator;
_mapGridEffectTargetFactory = mapGridEffectTargetFactory;
}

public IMapRenderer CreateMapRenderer()
Expand All @@ -67,7 +70,8 @@ public IMapRenderer CreateMapRenderer()
_dynamicMapObjectUpdater,
_configurationProvider,
_mouseCursorRendererFactory.Create(),
_renderOffsetCalculator);
_renderOffsetCalculator,
_mapGridEffectTargetFactory);
}
}
}
4 changes: 4 additions & 0 deletions EndlessClient/Rendering/Map/IMapRenderer.cs
Expand Up @@ -14,5 +14,9 @@ public interface IMapRenderer : IGameComponent
void StartEarthquake(byte strength);

void RedrawGroundLayer();

void RenderEffect(byte x, byte y, short effectId);

void ClearTransientRenderables();
}
}
4 changes: 3 additions & 1 deletion EndlessClient/Rendering/Map/MapChangedActions.cs
Expand Up @@ -153,9 +153,11 @@ private void ShowMapNameIfAvailable(bool differentMapID)

private void ShowMapTransition(bool showMapTransition)
{
var mapRenderer = _hudControlProvider.GetComponent<IMapRenderer>(HudControlIdentifier.MapRenderer);
mapRenderer.ClearTransientRenderables();

if (showMapTransition)
{
var mapRenderer = _hudControlProvider.GetComponent<IMapRenderer>(HudControlIdentifier.MapRenderer);
mapRenderer.StartMapTransition();
}
}
Expand Down
86 changes: 86 additions & 0 deletions EndlessClient/Rendering/Map/MapGridEffectTarget.cs
@@ -0,0 +1,86 @@
using EndlessClient.Audio;
using EndlessClient.Rendering.Character;
using EndlessClient.Rendering.Effects;
using EOLib.Domain.Map;
using EOLib.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace EndlessClient.Rendering.Map
{
public class MapGridEffectTarget : IMapGridEffectTarget
{
private IEffectRenderer _renderer;
private readonly IRenderOffsetCalculator _renderOffsetCalculator;
private readonly ICharacterRendererProvider _characterRendererProvider;
private readonly ICharacterTextures _characterTextures;
private readonly MapCoordinate _location;

public Rectangle EffectTargetArea { get; private set; }

public MapGridEffectTarget(INativeGraphicsManager nativeGraphicsManager,
ISfxPlayer sfxPlayer,
IRenderOffsetCalculator renderOffsetCalculator,
ICharacterRendererProvider characterRendererProvider,
ICharacterTextures characterTextures,
MapCoordinate location)
{
_renderer = new EffectRenderer(nativeGraphicsManager, sfxPlayer, this);
_renderOffsetCalculator = renderOffsetCalculator;
_characterRendererProvider = characterRendererProvider;
_characterTextures = characterTextures;
_location = location;
}

public bool EffectIsPlaying() => _renderer.State == EffectState.Playing;

public void ShowPotionAnimation(int potionId) { }

public void ShowSpellAnimation(int spellGraphic)
{
_renderer.PlayEffect(EffectType.Spell, spellGraphic);
}

public void ShowWarpArrive() { }

public void ShowWarpLeave() { }

public void ShowWaterSplashies() { }

public void Update()
{
EffectTargetArea = _characterRendererProvider.MainCharacterRenderer
.Match(
some: mainRenderer =>
{
var offsetX = _renderOffsetCalculator.CalculateOffsetX(_location);
var offsetY = _renderOffsetCalculator.CalculateOffsetY(_location);
var mainOffsetX = _renderOffsetCalculator.CalculateOffsetX(mainRenderer.Character.RenderProperties);
var mainOffsetY = _renderOffsetCalculator.CalculateOffsetY(mainRenderer.Character.RenderProperties);
return new Rectangle(
offsetX + 320 - mainOffsetX,
offsetY + 168 - mainOffsetY,
_characterTextures.Skin.SourceRectangle.Width,
_characterTextures.Skin.SourceRectangle.Height);
},
none: () => new Rectangle(0, 0, 1, 1));

_renderer.Update();
}

public void Draw(SpriteBatch sb, bool beginHasBeenCalled = true)
{
_renderer.DrawBehindTarget(sb, beginHasBeenCalled);
_renderer.DrawInFrontOfTarget(sb, beginHasBeenCalled);
}
}

public interface IMapGridEffectTarget : IEffectTarget
{
void Update();

void Draw(SpriteBatch sb, bool beginHasBeenCalled = true);
}
}

0 comments on commit c9bb922

Please sign in to comment.