From 3c065ac0978036fd74e204de19848730b038207d Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 26 Dec 2022 23:46:37 +0100 Subject: [PATCH] Added bubble spell --- .../magic/spell/effect/BubbleSpell.java | 173 ++++++++++++++++++ .../ability/magic/spell/effect/SpellType.java | 1 + .../resources/assets/unicopia/lang/en_us.json | 2 + 3 files changed, 176 insertions(+) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java new file mode 100644 index 00000000..80bde7b8 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -0,0 +1,173 @@ +package com.minelittlepony.unicopia.ability.magic.spell.effect; + +import java.util.Map; +import java.util.UUID; + +import com.minelittlepony.unicopia.USounds; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.*; +import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; +import com.minelittlepony.unicopia.entity.*; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.particle.ParticleHandle; +import com.minelittlepony.unicopia.particle.SphereParticleEffect; +import com.minelittlepony.unicopia.particle.UParticles; +import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.*; +import net.minecraft.entity.attribute.EntityAttributeModifier.Operation; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class BubbleSpell extends AbstractSpell implements TimedSpell, + ProjectileDelegate.EntityHitListener { + private static final EntityAttributeModifier GRAVITY_MODIFIER = + new EntityAttributeModifier(UUID.fromString("9dc7818b-927b-46e0-acbe-48d31a28128f"), "Bubble Floating", 0.02D - 1D, Operation.MULTIPLY_TOTAL); + private static final EntityAttributeModifier SPEED_MODIFIER = + new EntityAttributeModifier(UUID.fromString("9dc7818b-927b-46e0-acbe-48d31a28128f"), "Bubble Floating", 0.01D - 1D, Operation.MULTIPLY_TOTAL); + + private static final Map MODIFIERS = Map.of( + UEntityAttributes.ENTITY_GRAVTY_MODIFIER, GRAVITY_MODIFIER, + UEntityAttributes.EXTENDED_REACH_DISTANCE, GRAVITY_MODIFIER, + UEntityAttributes.EXTENDED_ATTACK_DISTANCE, GRAVITY_MODIFIER, + EntityAttributes.GENERIC_MOVEMENT_SPEED, SPEED_MODIFIER, + EntityAttributes.GENERIC_FLYING_SPEED, SPEED_MODIFIER + ); + + public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() + .with(Trait.FOCUS, 6) + .with(Trait.POWER, 1) + .build(); + + protected final ParticleHandle particlEffect = new ParticleHandle(); + + private final Timer timer; + + private int struggles; + private float radius; + + protected BubbleSpell(CustomisedSpellType type) { + super(type); + timer = new Timer((120 + (int)(getTraits().get(Trait.FOCUS, 0, 160) * 19)) * 20); + struggles = (int)(getTraits().get(Trait.POWER) * 2); + } + + @Override + public Timer getTimer() { + return timer; + } + + @Override + public boolean apply(Caster source) { + + if (getType().isOn(source)) { + source.getSpellSlot().removeWhere(getType(), true); + return false; + } + + Entity entity = source.asEntity(); + + if (entity instanceof LivingEntity l) { + MODIFIERS.forEach((attribute, modifier) -> { + if (l.getAttributes().hasAttribute(attribute)) { + l.getAttributeInstance(attribute).addPersistentModifier(modifier); + } + }); + } + radius = Math.max(entity.getHeight(), entity.getWidth()) * 1.2F; + source.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1); + entity.addVelocity(0, 0.2F * source.getPhysics().getGravitySignum(), 0); + Living.updateVelocity(entity); + + return super.apply(source); + } + + @Override + public boolean tick(Caster source, Situation situation) { + + if (situation == Situation.PROJECTILE) { + return true; + } + + timer.tick(); + + if (timer.getTicksRemaining() <= 0) { + return false; + } + + setDirty(); + + source.asEntity().addVelocity( + MathHelper.sin(source.asEntity().age / 6F) / 50F, + MathHelper.sin(source.asEntity().age / 6F) / 50F, + MathHelper.sin(source.asEntity().age / 6F) / 50F + ); + + source.asEntity().fallDistance = 0; + + Vec3d origin = source.getOriginVector(); + + if (source instanceof Pony pony && pony.sneakingChanged() && pony.asEntity().isSneaking()) { + setDirty(); + radius += 0.5F; + source.playSound(SoundEvents.BLOCK_HONEY_BLOCK_STEP, 1); + if (struggles-- <= 0) { + setDead(); + return false; + } + } + + particlEffect.update(getUuid(), source, spawner -> { + spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, 0xFFFFFF, 0.3F, 0, new Vec3d(0, radius / 2F, 0)), origin, Vec3d.ZERO); + }).ifPresent(p -> { + p.setAttribute(Attachment.ATTR_RADIUS, radius); + }); + + return !isDead(); + } + + @Override + public void onDestroyed(Caster source) { + particlEffect.destroy(); + if (source.asEntity() instanceof LivingEntity l) { + MODIFIERS.forEach((attribute, modifier) -> { + if (l.getAttributes().hasAttribute(attribute)) { + l.getAttributeInstance(attribute).removeModifier(modifier); + } + }); + } + source.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1); + } + + + @Override + public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { + Caster.of(hit.getEntity()).ifPresent(caster -> { + getTypeAndTraits().apply(caster); + }); + } + + @Override + public void toNBT(NbtCompound compound) { + super.toNBT(compound); + compound.putInt("struggles", struggles); + compound.putFloat("radius", radius); + timer.toNBT(compound); + } + + @Override + public void fromNBT(NbtCompound compound) { + super.fromNBT(compound); + struggles = compound.getInt("struggles"); + radius = compound.getFloat("radius"); + timer.fromNBT(compound); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index d457fc53..93e1823a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -65,6 +65,7 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType MIMIC = register("mimic", Affinity.GOOD, 0xFFFF00, true, SpellTraits.EMPTY, MimicSpell::new); public static final SpellType MIND_SWAP = register("mind_swap", Affinity.BAD, 0xF9FF99, true, SpellTraits.EMPTY, MindSwapSpell::new); public static final SpellType HYDROPHOBIC = register("hydrophobic", Affinity.NEUTRAL, 0xF999FF, true, SpellTraits.EMPTY, s -> new HydrophobicSpell(s, FluidTags.WATER)); + public static final SpellType BUBBLE = register("bubble", Affinity.NEUTRAL, 0xF999FF, true, BubbleSpell.DEFAULT_TRAITS, BubbleSpell::new); public static void bootstrap() {} diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 3725d5b8..1bc1ab4d 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -204,6 +204,8 @@ "spell.unicopia.fire_bolt.lore": "Produces several burning projectiles", "spell.unicopia.shield": "Protection", "spell.unicopia.shield.lore": "Casts a protective shield around the user", + "spell.unicopia.bubble": "Bubble", + "spell.unicopia.bubble.lore": "Traps any creature it hits in a soap bubble", "spell.unicopia.arcane_protection": "Arcane Protections", "spell.unicopia.arcane_protection.lore": "Creates a protective shroud over an area in which no other spells can be cast", "spell.unicopia.vortex": "Arcane Attraction",