From 638a136d6db96c15f805de73297a627e7d382853 Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 16 Sep 2022 12:47:32 +0200 Subject: [PATCH] For spells with a timer, display the timer progress to the user --- .../ability/magic/SpellPredicate.java | 8 ++- .../ability/magic/spell/TimedSpell.java | 49 +++++++++++++++++++ .../magic/spell/effect/AttractiveSpell.java | 28 +++++------ .../magic/spell/effect/AwkwardSpell.java | 33 ++++++++++++- .../magic/spell/effect/FeatherFallSpell.java | 23 ++++++--- .../magic/spell/effect/LightSpell.java | 29 +++++------ .../client/gui/DismissSpellScreen.java | 42 +++++++++------- .../unicopia/client/gui/UHud.java | 5 ++ 8 files changed, 158 insertions(+), 59 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java index 6adb2b04..5904ac9f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java @@ -2,10 +2,7 @@ package com.minelittlepony.unicopia.ability.magic; import java.util.function.Predicate; -import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; -import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; -import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.ShieldSpell; import net.minecraft.entity.Entity; @@ -16,8 +13,9 @@ public interface SpellPredicate extends Predicate { SpellPredicate HAS_PROJECTILE_EVENTS = s -> s instanceof ProjectileSpell; SpellPredicate IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell; SpellPredicate IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell; + SpellPredicate IS_TIMED = spell -> spell instanceof TimedSpell; - default SpellPredicate and(SpellPredicate predicate) { + default SpellPredicate and(SpellPredicate predicate) { SpellPredicate self = this; return s -> { return self.test(s) && predicate.test(s); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java new file mode 100644 index 00000000..03a10cba --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java @@ -0,0 +1,49 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import com.minelittlepony.unicopia.util.NbtSerialisable; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.math.MathHelper; + +/** + * A magic effect with a set duration capable of reporting how long it has until it runs out. + */ +public interface TimedSpell extends Spell { + Timer getTimer(); + + class Timer implements NbtSerialisable { + public int maxDuration; + public int duration; + public int prevDuration; + + public Timer(int initial) { + maxDuration = initial; + duration = initial; + } + + public void tick() { + prevDuration = duration; + duration--; + } + + public float getPercentTimeRemaining(float tickDelta) { + return MathHelper.lerp(tickDelta, prevDuration, duration) / maxDuration; + } + + public int getTicksRemaining() { + return duration; + } + + @Override + public void toNBT(NbtCompound compound) { + compound.putInt("duration", duration); + compound.putInt("maxDuration", maxDuration); + } + + @Override + public void fromNBT(NbtCompound compound) { + duration = compound.getInt("duration"); + maxDuration = compound.getInt("maxDuration"); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index ccaf9863..e8aef920 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -17,30 +17,32 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -public class AttractiveSpell extends ShieldSpell implements ProjectileSpell, HomingSpell { +public class AttractiveSpell extends ShieldSpell implements ProjectileSpell, HomingSpell, TimedSpell { private final EntityReference target = new EntityReference<>(); - private int age; - private int duration; + private final Timer timer; protected AttractiveSpell(CustomisedSpellType type) { super(type); - duration = 120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19); + timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + } + + @Override + public Timer getTimer() { + return timer; } @Override public boolean tick(Caster caster, Situation situation) { - age++; + timer.tick(); - if (age % 20 == 0) { - duration--; - } - - if (duration <= 0) { + if (timer.duration <= 0) { return false; } + setDirty(); + Vec3d pos = caster.getOriginVector(); if (target.isPresent(caster.getReferenceWorld()) && target.get(caster.getReferenceWorld()).distanceTo(caster.getEntity()) > getDrawDropOffRange(caster)) { target.get(caster.getReferenceWorld()).requestTeleport(pos.x, pos.y, pos.z); @@ -147,15 +149,13 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell, Hom public void toNBT(NbtCompound compound) { super.toNBT(compound); compound.put("target", target.toNBT()); - compound.putInt("age", age); - compound.putInt("duration", duration); + timer.toNBT(compound); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); target.fromNBT(compound.getCompound("target")); - age = compound.getInt("age"); - duration = compound.getInt("duration"); + timer.fromNBT(compound); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java index 6bba451e..629d0bb1 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java @@ -5,8 +5,10 @@ import java.util.List; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.util.shape.Sphere; +import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleType; import net.minecraft.particle.ParticleTypes; @@ -15,14 +17,31 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; -public class AwkwardSpell extends AbstractSpell { +public class AwkwardSpell extends AbstractSpell implements TimedSpell { + + private final Timer timer; protected AwkwardSpell(CustomisedSpellType type) { super(type); + timer = new Timer(20); + } + + @Override + public Timer getTimer() { + return timer; } @Override public boolean tick(Caster source, Situation situation) { + + if (situation != Situation.PROJECTILE) { + timer.tick(); + + if (timer.duration <= 0) { + return false; + } + } + if (source.isClient()) { source.spawnParticles(new Sphere(false, (1 + source.getLevel().getScaled(8)) * 8), 10, pos -> { @@ -49,4 +68,16 @@ public class AwkwardSpell extends AbstractSpell { && type != ParticleTypes.EXPLOSION_EMITTER && type != ParticleTypes.AMBIENT_ENTITY_EFFECT; } + + @Override + public void toNBT(NbtCompound compound) { + super.toNBT(compound); + timer.toNBT(compound); + } + + @Override + public void fromNBT(NbtCompound compound) { + super.fromNBT(compound); + timer.fromNBT(compound); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java index 412c3505..3b3a609b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java @@ -5,6 +5,7 @@ import java.util.stream.Stream; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.item.FriendshipBraceletItem; @@ -17,7 +18,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -public class FeatherFallSpell extends AbstractSpell { +public class FeatherFallSpell extends AbstractSpell implements TimedSpell { private static final int MIN_RANGE = 1; private static final int MAX_RANGE = 20; private static final int MIN_TARGETS = 1; @@ -35,20 +36,28 @@ public class FeatherFallSpell extends AbstractSpell { .with(Trait.ORDER, 15) .build(); - private int duration; + private final Timer timer; protected FeatherFallSpell(CustomisedSpellType type) { super(type); - duration = (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19); + timer = new Timer(10 + (int)(getTraits().get(Trait.FOCUS, 0, 160))); + } + + @Override + public Timer getTimer() { + return timer; } @Override public boolean tick(Caster caster, Situation situation) { + timer.tick(); - if (duration-- <= 0) { + if (timer.duration <= 0) { return false; } + setDirty(); + List targets = getTargets(caster).toList(); if (targets.isEmpty()) { @@ -82,7 +91,7 @@ public class FeatherFallSpell extends AbstractSpell { ParticleUtils.spawnParticles(new MagicParticleEffect(getType().getColor()), target, 7); }); - return caster.subtractEnergyCost(duration % 50 == 0 ? getCostPerEntity() * targets.size() : 0); + return caster.subtractEnergyCost(timer.duration % 50 == 0 ? getCostPerEntity() * targets.size() : 0); } protected double getCostPerEntity() { @@ -117,12 +126,12 @@ public class FeatherFallSpell extends AbstractSpell { @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.putInt("duration", duration); + timer.toNBT(compound); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - duration = compound.getInt("duration"); + timer.fromNBT(compound); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index f0f7b4fe..621cf3a5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -5,6 +5,7 @@ import java.util.List; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Situation; +import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; @@ -16,7 +17,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; -public class LightSpell extends AbstractSpell { +public class LightSpell extends AbstractSpell implements TimedSpell { public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() .with(Trait.LIFE, 10) .with(Trait.AIR, 0.3F) @@ -24,14 +25,18 @@ public class LightSpell extends AbstractSpell { .with(Trait.ORDER, 25) .build(); - private int age; - private int duration; + private final Timer timer; private final List> lights = new ArrayList<>(); protected LightSpell(CustomisedSpellType type) { super(type); - duration = 120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19); + timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + } + + @Override + public Timer getTimer() { + return timer; } @Override @@ -41,16 +46,14 @@ public class LightSpell extends AbstractSpell { return false; } - age++; + timer.tick(); - if (age % 20 == 0) { - duration--; - } - - if (duration <= 0) { + if (timer.duration <= 0) { return false; } + setDirty(); + if (!caster.isClient()) { if (lights.isEmpty()) { int size = 2 + caster.getReferenceWorld().random.nextInt(2) + (int)(getTraits().get(Trait.LIFE, 10, 20) - 10)/10; @@ -93,8 +96,7 @@ public class LightSpell extends AbstractSpell { @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.putInt("age", age); - compound.putInt("duration", duration); + timer.toNBT(compound); if (!lights.isEmpty()) { NbtList list = new NbtList(); lights.forEach(light -> { @@ -107,8 +109,7 @@ public class LightSpell extends AbstractSpell { @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - age = compound.getInt("age"); - duration = compound.getInt("duration"); + timer.fromNBT(compound); lights.clear(); if (compound.contains("lights", NbtElement.LIST_TYPE)) { compound.getList("lights", NbtElement.COMPOUND_TYPE).forEach(nbt -> { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java index 62b18829..25b96666 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/DismissSpellScreen.java @@ -4,11 +4,11 @@ import java.util.ArrayList; import java.util.List; import com.minelittlepony.common.client.gui.GameGui; -import com.minelittlepony.unicopia.ability.magic.spell.AbstractDelegatingSpell; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.client.FlowingText; import com.minelittlepony.unicopia.client.particle.SphereModel; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.MsgRemoveSpell; @@ -23,6 +23,7 @@ import net.minecraft.screen.ScreenTexts; import net.minecraft.sound.SoundEvents; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.util.StringHelper; import net.minecraft.util.math.Vector4f; public class DismissSpellScreen extends GameGui { @@ -88,8 +89,6 @@ public class DismissSpellScreen extends GameGui { class Entry extends Vector4f implements Element, Drawable, Selectable { - private final List tooltip = new ArrayList<>(); - private final Spell spell; private final Spell actualSpell; @@ -103,19 +102,6 @@ public class DismissSpellScreen extends GameGui { SphereModel.convertToCartesianCoord(this, radius, azimuth, azimuth); add(0, -(float)radius / 2F, 0, 0); - - MutableText name = actualSpell.getType().getName().copy(); - int color = actualSpell.getType().getColor(); - name.setStyle(name.getStyle().withColor(color == 0 ? 0xFFAAAAAA : color)); - - tooltip.add(Text.translatable("Spell Type: %s", name)); - actualSpell.getType().getTraits().appendTooltip(tooltip); - tooltip.add(ScreenTexts.EMPTY); - tooltip.add(Text.translatable("Affinity: %s", actualSpell.getAffinity().name()).formatted(actualSpell.getAffinity().getColor())); - tooltip.add(ScreenTexts.EMPTY); - tooltip.addAll(FlowingText.wrap(Text.translatable(actualSpell.getType().getTranslationKey() + ".lore").formatted(actualSpell.getAffinity().getColor()), 180).toList()); - tooltip.add(ScreenTexts.EMPTY); - tooltip.add(Text.translatable("[Click to Discard]")); } private Spell getActualSpell() { @@ -147,7 +133,9 @@ public class DismissSpellScreen extends GameGui { copy.set(getX(), getY(), getZ(), getW()); copy.transform(matrices.peek().getPositionMatrix()); - DrawableUtil.renderItemIcon(actualSpell.getType().getDefualtStack(), + var type = actualSpell.getType().withTraits(actualSpell.getTraits()); + + DrawableUtil.renderItemIcon(actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(), copy.getX() - 8 + (copy.getX() - mouseX - 5) / 60D, copy.getY() - 8 + (copy.getY() - mouseY - 5) / 60D, 1 @@ -162,6 +150,24 @@ public class DismissSpellScreen extends GameGui { if (isMouseOver(relativeMouseX, relativeMouseY)) { DrawableUtil.drawArc(matrices, 0, 8, 0, DrawableUtil.TAU, color | 0x000000FF, false); + + List tooltip = new ArrayList<>(); + + MutableText name = actualSpell.getType().getName().copy(); + color = actualSpell.getType().getColor(); + name.setStyle(name.getStyle().withColor(color == 0 ? 0xFFAAAAAA : color)); + tooltip.add(Text.translatable("Spell Type: %s", name)); + actualSpell.getType().getTraits().appendTooltip(tooltip); + tooltip.add(ScreenTexts.EMPTY); + tooltip.add(Text.translatable("Affinity: %s", actualSpell.getAffinity().name()).formatted(actualSpell.getAffinity().getColor())); + tooltip.add(ScreenTexts.EMPTY); + tooltip.addAll(FlowingText.wrap(Text.translatable(actualSpell.getType().getTranslationKey() + ".lore").formatted(actualSpell.getAffinity().getColor()), 180).toList()); + if (spell instanceof TimedSpell timed) { + tooltip.add(ScreenTexts.EMPTY); + tooltip.add(Text.translatable("Time Left: %s", StringHelper.formatTicks(timed.getTimer().getTicksRemaining()))); + } + tooltip.add(ScreenTexts.EMPTY); + tooltip.add(Text.translatable("[Click to Discard]")); renderTooltip(matrices, tooltip, 0, 0); if (!lastMouseOver) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index 9abcb44a..02bac686 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -7,7 +7,9 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilitySlot; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.KeyBindingsHandler; @@ -168,6 +170,9 @@ public class UHud extends DrawableHelper { DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU, color & 0xFFFFFF2F, false); DrawableUtil.drawArc(modelStack, radius + 3, radius + 4, 0, DrawableUtil.TAU, color & 0xFFFFFFAF, false); + pony.getSpellSlot().get(spell.and(SpellPredicate.IS_TIMED), false).map(TimedSpell::getTimer).ifPresent(timer -> { + DrawableUtil.drawArc(modelStack, radius, radius + 3, 0, DrawableUtil.TAU * timer.getPercentTimeRemaining(client.getTickDelta()), 0xFFFFFFFF, false); + }); modelStack.pop(); }