diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java index 99dda711..d965f9da 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java @@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.player.Pony; @@ -92,7 +93,11 @@ public class UnicornDispellAbility implements Ability { public boolean apply(Pony player, Pos data) { player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE); Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> { - target.getSpellSlot().clear(); + target.getSpellSlot().forEach(spell -> { + spell.setDead(); + spell.tickDying(target); + return Operation.ofBoolean(!spell.isDead()); + }, true); }); return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index f6219d62..68a006ed 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -69,11 +69,20 @@ public abstract class AbstractDelegatingSpell implements Spell, getDelegates().forEach(Spell::setDead); } + @Override + public void tickDying(Caster caster) { + } + @Override public boolean isDead() { return getDelegates().isEmpty() || getDelegates().stream().allMatch(Spell::isDead); } + @Override + public boolean isDying() { + return false; + } + @Override public boolean isDirty() { return dirty || getDelegates().stream().anyMatch(Spell::isDirty); @@ -110,7 +119,13 @@ public abstract class AbstractDelegatingSpell implements Spell, @Override public boolean tick(Caster source, Situation situation) { - return execute(getDelegates().stream(), a -> a.tick(source, situation)); + return execute(getDelegates().stream(), a -> { + if (a.isDying()) { + a.tickDying(source); + return !a.isDead(); + } + return a.tick(source, situation); + }); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index bba345b4..ed03506d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -59,6 +59,10 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS private int prevAge; private int age; + private boolean dead; + private int prevDeathTicks; + private int deathTicks; + private Optional position = Optional.empty(); public PlaceableSpell(CustomisedSpellType type) { @@ -74,6 +78,29 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS return MathHelper.lerp(tickDelta, prevAge, age); } + public float getScale(float tickDelta) { + float add = MathHelper.clamp(getAge(tickDelta) / 25F, 0, 1); + float subtract = dead ? 1 - (MathHelper.lerp(tickDelta, prevDeathTicks, deathTicks) / 20F) : 0; + return MathHelper.clamp(add - subtract, 0, 1); + } + + @Override + public boolean isDying() { + return dead && deathTicks > 0; + } + + @Override + public void setDead() { + super.setDead(); + dead = true; + deathTicks = 20; + } + + @Override + public boolean isDead() { + return dead && deathTicks <= 0; + } + @Override public Collection getDelegates() { return List.of(spell); @@ -119,6 +146,12 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS return !isDead(); } + @Override + public void tickDying(Caster caster) { + prevDeathTicks = deathTicks; + deathTicks--; + } + private void checkDetachment(Caster source, EntityValues target) { if (getWorld(source).map(Ether::get).map(ether -> ether.get(getType(), target, placedSpellId)).isEmpty()) { setDead(); @@ -198,6 +231,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); + compound.putBoolean("dead", dead); + compound.putInt("deathTicks", deathTicks); compound.putInt("age", age); compound.putFloat("pitch", pitch); compound.putFloat("yaw", yaw); @@ -217,6 +252,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); + dead = compound.getBoolean("dead"); + deathTicks = compound.getInt("deathTicks"); age = compound.getInt("age"); pitch = compound.getFloat("pitch"); yaw = compound.getFloat("yaw"); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index d6bb1ccf..55a5f3bf 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -61,6 +61,8 @@ public interface Spell extends NbtSerialisable, Affine { */ boolean isDead(); + boolean isDying(); + /** * Returns true if this effect has changes that need to be sent to the client. */ @@ -68,6 +70,7 @@ public interface Spell extends NbtSerialisable, Affine { /** * Applies this spell to the supplied caster. + * @param caster The caster to apply the spell to */ default boolean apply(Caster caster) { caster.getSpellSlot().put(this); @@ -76,7 +79,7 @@ public interface Spell extends NbtSerialisable, Affine { /** * Gets the default form of this spell used to apply to a caster. - * @param caster + * @param caster The caster currently fueling this spell */ default Spell prepareForCast(Caster caster, CastingMethod method) { return this; @@ -89,6 +92,12 @@ public interface Spell extends NbtSerialisable, Affine { */ boolean tick(Caster caster, Situation situation); + /** + * Called on spells that are actively dying to update any post-death animations before removal. + * @param caster The caster currently fueling this spell + */ + void tickDying(Caster caster); + /** * Marks this effect as dirty. */ diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java index a8c1b706..8b64d9c3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java @@ -12,6 +12,7 @@ import net.minecraft.nbt.NbtCompound; public abstract class AbstractSpell implements Spell { private boolean dead; + private boolean dying; private boolean dirty; private boolean hidden; private boolean destroyed; @@ -45,7 +46,7 @@ public abstract class AbstractSpell implements Spell { @Override public final void setDead() { - dead = true; + dying = true; setDirty(); } @@ -54,6 +55,11 @@ public abstract class AbstractSpell implements Spell { return dead; } + @Override + public final boolean isDying() { + return dying; + } + @Override public final boolean isDirty() { return dirty; @@ -82,6 +88,11 @@ public abstract class AbstractSpell implements Spell { protected void onDestroyed(Caster caster) { } + @Override + public void tickDying(Caster caster) { + dead = true; + } + @Override public final void destroy(Caster caster) { if (destroyed) { @@ -94,6 +105,7 @@ public abstract class AbstractSpell implements Spell { @Override public void toNBT(NbtCompound compound) { + compound.putBoolean("dying", dying); compound.putBoolean("dead", dead); compound.putBoolean("hidden", hidden); compound.putUuid("uuid", uuid); @@ -106,6 +118,7 @@ public abstract class AbstractSpell implements Spell { if (compound.contains("uuid")) { uuid = compound.getUuid("uuid"); } + dying = compound.getBoolean("dying"); dead = compound.getBoolean("dead"); hidden = compound.getBoolean("hidden"); if (compound.contains("traits")) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java index 698375c9..7c4d09c3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java @@ -57,7 +57,7 @@ public class PlacedSpellRenderer extends SpellRenderer { matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); - float scale = (spell.getAge(tickDelta) / 25F) * 3; + float scale = spell.getScale(tickDelta) * 3; matrices.scale(scale, scale, scale); float angle = (animationProgress / 9F) % 360; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 16a4100b..9677a123 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -72,6 +72,10 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster getMasterReference() { return owner; diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java index 2a4568e9..b2cad93c 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java +++ b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java @@ -44,7 +44,13 @@ public class EffectSync implements SpellContainer, NbtSerialisable { } public boolean tick(Situation situation) { - return tick(spell -> Operation.ofBoolean(spell.tick(owner, situation))); + return tick(spell -> { + if (spell.isDying()) { + spell.tickDying(owner); + return Operation.ofBoolean(!spell.isDead()); + } + return Operation.ofBoolean(spell.tick(owner, situation)); + }); } public boolean tick(Function tickAction) {