diff --git a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java index 8662861b..ab9100e8 100644 --- a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java +++ b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java @@ -24,6 +24,7 @@ public interface EquinePredicates { Predicate PLAYER_CAN_USE_EARTH = IS_PLAYER.and(raceMatches(Race::canUseEarth)); Predicate IS_CASTER = e -> !e.isRemoved() && (e instanceof Caster || PLAYER_UNICORN.test(e)); + Predicate IS_PLACED_SPELL = e -> e instanceof Caster && !e.isRemoved(); Predicate HAS_WANT_IT_NEED_IT = e -> EnchantmentHelper.getEquipmentLevel(UEnchantments.WANT_IT_NEED_IT, e) > 0; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java index 33458017..13bd5e20 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java @@ -15,9 +15,10 @@ public interface Abilities { // unicorn / alicorn Ability CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY); + Ability SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.PRIMARY); Ability TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY); Ability GROUP_TELEPORT = register(new UnicornGroupTeleportAbility(), "teleport_group", AbilitySlot.SECONDARY); - Ability SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.TERTIARY); + Ability DISPELL = register(new UnicornDispellAbility(), "dispell", AbilitySlot.TERTIARY); // earth / alicorn Ability KICK = register(new EarthPonyKickAbility(), "kick", AbilitySlot.PRIMARY); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index c0c877f9..35069cec 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -15,7 +15,6 @@ import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.util.RayTraceHelper; import com.minelittlepony.unicopia.util.VecHelper; -import net.minecraft.entity.Entity; import net.minecraft.item.ItemStack; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java new file mode 100644 index 00000000..ee95e16d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java @@ -0,0 +1,91 @@ +package com.minelittlepony.unicopia.ability; + +import java.util.Optional; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.ability.data.Pos; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.particle.MagicParticleEffect; +import com.minelittlepony.unicopia.util.RayTraceHelper; +import com.minelittlepony.unicopia.util.VecHelper; + +/** + * Dispells an active spell + */ +public class UnicornDispellAbility implements Ability { + + @Override + public int getWarmupTime(Pony player) { + return 4; + } + + @Override + public int getCooldownTime(Pony player) { + return 0; + } + + @Override + public boolean canUse(Race race) { + return race.canCast(); + } + + @Override + public Pos.Serializer getSerializer() { + return Pos.SERIALIZER; + } + + @Override + public boolean onQuickAction(Pony player, ActivationType type) { + + if (type.getTapCount() > 1) { + player.getSpellSlot().clear(); + return true; + } + if (type == ActivationType.TAP) { + // TODO: gui to remove spells + } + + return false; + } + + @Override + public double getCostEstimate(Pony player) { + return getTarget(player) + .filter(caster -> caster.getMaster() != player.getMaster()) + .isPresent() ? 10 : 0; + } + + @Override + public Pos tryActivate(Pony player) { + return getTarget(player).map(Caster::getOrigin).map(Pos::new).orElse(null); + } + + @Override + public void apply(Pony player, Pos data) { + Caster.stream(VecHelper.findInRange(player.getEntity(), player.getWorld(), data.vec(), 2, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> { + target.getSpellSlot().clear(); + }); + } + + private Optional> getTarget(Pony player) { + int maxDistance = player.getMaster().isCreative() ? 1000 : 100; + return RayTraceHelper.doTrace(player.getMaster(), maxDistance, 1, + EquinePredicates.IS_PLACED_SPELL) + .getEntity() + .flatMap(Caster::of); + } + + + + @Override + public void preApply(Pony player, AbilitySlot slot) { + player.getMagicalReserves().getExhaustion().multiply(3.3F); + player.spawnParticles(MagicParticleEffect.UNICORN, 5); + } + + @Override + public void postApply(Pony player, AbilitySlot slot) { + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/data/Numeric.java b/src/main/java/com/minelittlepony/unicopia/ability/data/Numeric.java index 30334814..85ac2f98 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/data/Numeric.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/data/Numeric.java @@ -1,13 +1,10 @@ package com.minelittlepony.unicopia.ability.data; -import com.google.gson.annotations.Expose; - import net.minecraft.network.PacketByteBuf; public class Numeric extends Hit { public static final Serializer SERIALIZER = Numeric::new; - @Expose public int type; Numeric(PacketByteBuf buf) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/data/Pos.java b/src/main/java/com/minelittlepony/unicopia/ability/data/Pos.java index 16ad3bdb..e1fc7037 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/data/Pos.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/data/Pos.java @@ -4,6 +4,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import net.minecraft.network.PacketByteBuf; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; public class Pos extends Hit { @@ -42,6 +43,10 @@ public class Pos extends Hit { return new BlockPos(x, y, z); } + public Vec3d vec() { + return new Vec3d(x, y, z); + } + public double distanceTo(Caster caster) { return Math.sqrt(caster.getEntity().squaredDistanceTo(x, y, z)); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java index 1c710953..52fa9381 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java @@ -93,10 +93,7 @@ public interface Caster extends Owned, Levelled, Affi } static Stream> stream(Stream entities) { - return entities - .map(Caster::of) - .filter(Optional::isPresent) - .map(Optional::get); + return entities.map(Caster::of).flatMap(Optional::stream); } /** diff --git a/src/main/java/com/minelittlepony/unicopia/entity/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/CastSpellEntity.java index 0dd2b483..392c562d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/CastSpellEntity.java @@ -44,6 +44,13 @@ public class CastSpellEntity extends Entity implements Caster, Lig getDataTracker().set(SPELL, Optional.ofNullable(spell).map(Spell::getUuid)); SpellContainer.Delegate.super.put(spell); } + + @Override + public void clear() { + getDataTracker().get(SPELL).ifPresent(id -> { + delegate().removeIf(spell -> spell.getUuid().equals(id), true); + }); + } }; private final EntityReference owner = new EntityReference<>(); @@ -96,11 +103,11 @@ public class CastSpellEntity extends Entity implements Caster, Lig emitter.tick(); - if (!dataTracker.get(SPELL).filter(spellId -> { + if (dataTracker.get(SPELL).filter(spellId -> { return getSpellSlot().forEach(spell -> { return spell.getUuid().equals(spellId) ? Operation.ofBoolean(spell.tick(this, Situation.GROUND_ENTITY)) : Operation.SKIP; }, true); - }).isPresent()) { + }).isEmpty()) { discard(); } }