mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38:00 +01:00
For spells with a timer, display the timer progress to the user
This commit is contained in:
parent
082e5e37f2
commit
638a136d6d
8 changed files with 158 additions and 59 deletions
|
@ -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<T extends Spell> extends Predicate<Spell> {
|
|||
SpellPredicate<ProjectileSpell> HAS_PROJECTILE_EVENTS = s -> s instanceof ProjectileSpell;
|
||||
SpellPredicate<AbstractDisguiseSpell> IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell;
|
||||
SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell;
|
||||
SpellPredicate<TimedSpell> IS_TIMED = spell -> spell instanceof TimedSpell;
|
||||
|
||||
default SpellPredicate<T> and(SpellPredicate<T> predicate) {
|
||||
default <Q extends Spell> SpellPredicate<Q> and(SpellPredicate<Q> predicate) {
|
||||
SpellPredicate<T> self = this;
|
||||
return s -> {
|
||||
return self.test(s) && predicate.test(s);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Entity> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Entity> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<EntityReference<FairyEntity>> 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 -> {
|
||||
|
|
|
@ -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<Text> 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<Text> 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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue