diff --git a/core/src/com/riiablo/engine/client/OverlayManager.java b/core/src/com/riiablo/engine/client/OverlayManager.java new file mode 100644 index 00000000..94f4db56 --- /dev/null +++ b/core/src/com/riiablo/engine/client/OverlayManager.java @@ -0,0 +1,62 @@ +package com.riiablo.engine.client; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.artemis.ComponentMapper; +import com.artemis.annotations.All; +import com.artemis.systems.IteratingSystem; + +import com.badlogic.gdx.assets.AssetDescriptor; + +import com.riiablo.Riiablo; +import com.riiablo.codec.Animation; +import com.riiablo.codec.DC; +import com.riiablo.codec.excel.Overlay; +import com.riiablo.graphics.BlendMode; + +@All(com.riiablo.engine.client.component.Overlay.class) +public class OverlayManager extends IteratingSystem { + private static final Logger log = LogManager.getLogger(OverlayManager.class); + + protected ComponentMapper mOverlay; + + @Override + protected void process(int entityId) { + com.riiablo.engine.client.component.Overlay overlay = mOverlay.get(entityId); + if (!Riiablo.assets.isLoaded(overlay.assetDescriptor)) return; + + Animation animation = overlay.animation; + if (!overlay.isLoaded) { + DC dc = Riiablo.assets.get(overlay.assetDescriptor); + animation.edit() + .layer(dc, overlay.entry.Trans == 3 ? BlendMode.LUMINOSITY : BlendMode.ID) + .build(); + animation.setMode(Animation.Mode.ONCE); + // FIXME: set frame to elapsed time since creation + overlay.isLoaded = true; + log.debug("Loaded {}", overlay.assetDescriptor.fileName); + } + + if (animation.isFinished()) { + dispose(overlay); + mOverlay.remove(entityId); + } + } + + public void set(int entityId, String overlayId) { + if (mOverlay.has(entityId)) { + dispose(mOverlay.get(entityId)); + } + + Overlay.Entry overlay = Riiablo.files.Overlay.get(overlayId); + com.riiablo.engine.client.component.Overlay overlayC = mOverlay.create(entityId).set(overlay); + Riiablo.assets.load(overlayC.assetDescriptor); + } + + void dispose(com.riiablo.engine.client.component.Overlay overlay) { + AssetDescriptor assetDescriptor = overlay.assetDescriptor; + Riiablo.assets.unload(assetDescriptor.fileName); + log.debug("Unloaded {}", assetDescriptor.fileName); + } +} diff --git a/core/src/com/riiablo/engine/client/OverlayStepper.java b/core/src/com/riiablo/engine/client/OverlayStepper.java new file mode 100644 index 00000000..9cb727cf --- /dev/null +++ b/core/src/com/riiablo/engine/client/OverlayStepper.java @@ -0,0 +1,22 @@ +package com.riiablo.engine.client; + +import com.artemis.ComponentMapper; +import com.artemis.annotations.All; +import com.artemis.systems.IntervalIteratingSystem; + +import com.riiablo.codec.Animation; +import com.riiablo.engine.client.component.Overlay; + +@All(Overlay.class) +public class OverlayStepper extends IntervalIteratingSystem { + protected ComponentMapper mOverlay; + + public OverlayStepper() { + super(null, Animation.FRAME_DURATION); + } + + @Override + protected void process(int entityId) { + mOverlay.get(entityId).animation.update(Animation.FRAME_DURATION); + } +} diff --git a/core/src/com/riiablo/engine/client/component/Overlay.java b/core/src/com/riiablo/engine/client/component/Overlay.java new file mode 100644 index 00000000..325e79d1 --- /dev/null +++ b/core/src/com/riiablo/engine/client/component/Overlay.java @@ -0,0 +1,35 @@ +package com.riiablo.engine.client.component; + +import com.artemis.PooledComponent; +import com.artemis.annotations.PooledWeaver; +import com.artemis.annotations.Transient; + +import com.badlogic.gdx.assets.AssetDescriptor; + +import com.riiablo.codec.Animation; +import com.riiablo.codec.DC; +import com.riiablo.codec.DCC; + +@Transient +@PooledWeaver +public class Overlay extends PooledComponent { + public final Animation animation = Animation.newAnimation(); + public AssetDescriptor assetDescriptor; + public com.riiablo.codec.excel.Overlay.Entry entry; + public boolean isLoaded; + + public Overlay set(com.riiablo.codec.excel.Overlay.Entry overlay) { + this.entry = overlay; + this.assetDescriptor = new AssetDescriptor<>("data\\global\\overlays\\" + overlay.Filename + ".dcc", DCC.class); + this.isLoaded = false; + return this; + } + + @Override + protected void reset() { + animation.reset(); + assetDescriptor = null; + entry = null; + isLoaded = false; + } +} diff --git a/core/src/com/riiablo/engine/server/Actioneer.java b/core/src/com/riiablo/engine/server/Actioneer.java index 74d2a614..35c5adc8 100644 --- a/core/src/com/riiablo/engine/server/Actioneer.java +++ b/core/src/com/riiablo/engine/server/Actioneer.java @@ -7,6 +7,7 @@ import net.mostlyoriginal.api.system.core.PassiveSystem; import com.riiablo.Riiablo; import com.riiablo.codec.excel.Skills; +import com.riiablo.engine.client.OverlayManager; import com.riiablo.engine.server.component.Class; import com.riiablo.engine.server.component.MovementModes; import com.riiablo.engine.server.component.Sequence; @@ -15,10 +16,13 @@ import com.riiablo.log.LogManager; public class Actioneer extends PassiveSystem { private static final Logger log = LogManager.getLogger(Actioneer.class); + protected OverlayManager overlays; + protected ComponentMapper mClass; protected ComponentMapper mSequence; protected ComponentMapper mMovementModes; + // TODO: much of this should be split into different systems or events (e.g., onSpellCast) public void cast(int entityId, int skillId) { if (mSequence.has(entityId)) return; final Skills.Entry skill = Riiablo.files.skills.get(skillId); @@ -33,6 +37,12 @@ public class Actioneer extends PassiveSystem { mSequence.create(entityId).sequence(mode, mMovementModes.get(entityId).NU); + // FIXME: below uses client-side-only code -- may change to event-based model + // does server even need to care about overlays? Riiablo.audio.play(skill.stsound, true); + + if (!skill.castoverlay.isEmpty()) { + overlays.set(entityId, skill.castoverlay); + } } } diff --git a/core/src/com/riiablo/map/RenderSystem.java b/core/src/com/riiablo/map/RenderSystem.java index 54314e36..6af6f3fb 100644 --- a/core/src/com/riiablo/map/RenderSystem.java +++ b/core/src/com/riiablo/map/RenderSystem.java @@ -34,6 +34,7 @@ import com.riiablo.engine.Engine; import com.riiablo.engine.client.component.AnimationWrapper; import com.riiablo.engine.client.component.BBoxWrapper; import com.riiablo.engine.client.component.Hovered; +import com.riiablo.engine.client.component.Overlay; import com.riiablo.engine.client.component.Selectable; import com.riiablo.engine.server.component.AIWrapper; import com.riiablo.engine.server.component.Angle; @@ -103,6 +104,7 @@ public class RenderSystem extends BaseEntitySystem { }; protected ComponentMapper mAnimationWrapper; + protected ComponentMapper mOverlay; protected ComponentMapper mCofReference; protected ComponentMapper mPosition; protected ComponentMapper mObject; @@ -672,10 +674,22 @@ public class RenderSystem extends BaseEntitySystem { // CofComponent cofComponent = this.cofComponent.get(entity); // if (cofComponent != null && cofComponent.load != Dirty.NONE) return; - Animation animation = mAnimationWrapper.get(entity).animation; + + // TODO: create EntityRenderer class to encapsulate the following code: Vector2 pos = mPosition.get(entity).position; Vector2 tmp = iso.toScreen(tmpVec2.set(pos)); + + Overlay overlay = mOverlay.get(entity); + if (overlay != null && overlay.entry.PreDraw) { + overlay.animation.draw(batch, tmp.x, tmp.y); + } + + Animation animation = mAnimationWrapper.get(entity).animation; animation.draw(batch, tmp.x, tmp.y); + + if (overlay != null && !overlay.entry.PreDraw) { + overlay.animation.draw(batch, tmp.x, tmp.y); + } } } diff --git a/core/src/com/riiablo/screen/GameScreen.java b/core/src/com/riiablo/screen/GameScreen.java index ec2f92f6..748a952e 100644 --- a/core/src/com/riiablo/screen/GameScreen.java +++ b/core/src/com/riiablo/screen/GameScreen.java @@ -69,6 +69,8 @@ import com.riiablo.engine.client.MissileLoader; import com.riiablo.engine.client.MonsterLabelManager; import com.riiablo.engine.client.NetworkIdManager; import com.riiablo.engine.client.NetworkedClientItemManager; +import com.riiablo.engine.client.OverlayManager; +import com.riiablo.engine.client.OverlayStepper; import com.riiablo.engine.client.SelectableManager; import com.riiablo.engine.client.SoundEmitterHandler; import com.riiablo.engine.client.WarpSubstManager; @@ -568,7 +570,10 @@ public class GameScreen extends ScreenAdapter implements GameLoadingScreen.Loada ; if (!DEBUG_TOUCHPAD && Gdx.app.getType() == Application.ApplicationType.Desktop) { builder.with(new CursorMovementSystem()); - builder.with(new Actioneer()); + /** FIXME: below is tightly coupled with client-side-only code {@link Actioneer#cast} */ + builder.with(new Actioneer()); // TODO: move to more appropriate spot in list + builder.with(new OverlayManager()); // TODO: move to more appropriate spot in list + builder.with(new OverlayStepper()); // TODO: move to more appropriate spot in list } if (socket == null) { builder.with(new ItemGenerator());