diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java index d4fc9a3d..30091d60 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java @@ -55,6 +55,7 @@ public interface Abilities { // kirin Ability RAGE = register(new KirinRageAbility(), "rage", AbilitySlot.PRIMARY); + Ability NIRIK_BLAST = register(new NirikBlastAbility(), "nirik_blast", AbilitySlot.SECONDARY); Ability KIRIN_CAST = register(new KirinCastingAbility(), "kirin_cast", AbilitySlot.SECONDARY); static > T register(T power, String name, AbilitySlot slot) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java new file mode 100644 index 00000000..05fd3d74 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java @@ -0,0 +1,104 @@ +package com.minelittlepony.unicopia.ability; + +import java.util.Optional; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.ability.data.Hit; +import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; +import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; +import com.minelittlepony.unicopia.entity.player.Pony; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageTypes; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.BlockView; +import net.minecraft.world.World.ExplosionSourceType; +import net.minecraft.world.explosion.Explosion; +import net.minecraft.world.explosion.ExplosionBehavior; + +/** + * Kirin ability to transform into a nirik + */ +public class NirikBlastAbility implements Ability { + @Override + public int getWarmupTime(Pony player) { + return 10; + } + + @Override + public int getCooldownTime(Pony player) { + return 3; + } + + @Override + public boolean canUse(Race race) { + return race == Race.KIRIN; + } + + @Nullable + @Override + public Optional prepare(Pony player) { + return Hit.of(EquinePredicates.RAGING.test(player.asEntity())); + } + + @Override + public Hit.Serializer getSerializer() { + return Hit.SERIALIZER; + } + + @Override + public double getCostEstimate(Pony player) { + return 0; + } + + @Override + public boolean apply(Pony player, Hit data) { + + player.asWorld().createExplosion(player.asEntity(), player.damageOf(DamageTypes.FIREBALL), new ExplosionBehavior(){ + @Override + public boolean canDestroyBlock(Explosion explosion, BlockView world, BlockPos pos, BlockState state, float power) { + return false; + } + }, player.getOriginVector(), 5, true, ExplosionSourceType.MOB); + player.setInvulnerabilityTicks(5); + + player.setAnimation(Animation.ARMS_UP, Recipient.ANYONE, 12); + player.playSound(SoundEvents.ENTITY_POLAR_BEAR_WARNING, 2F, 0.1F); + player.subtractEnergyCost(25); + + coolDown(player, AbilitySlot.NONE); + + for (Entity e : player.findAllEntitiesInRange(5, EntityPredicates.VALID_LIVING_ENTITY.and(EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR)).toList()) { + Vec3d offset = player.getOriginVector().subtract(e.getPos()); + ((LivingEntity)e).takeKnockback(1, offset.x, offset.z); + } + + return true; + } + + @Override + public void warmUp(Pony player, AbilitySlot slot) { + } + + @Override + public void coolDown(Pony player, AbilitySlot slot) { + Random rng = player.asWorld().random; + + for (int i = 0; i < 26; i++) { + Vec3d pos = player.getOriginVector().add(rng.nextGaussian(), 0, rng.nextGaussian()); + player.addParticle(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE, pos, new Vec3d(rng.nextGaussian(), 0.3, rng.nextGaussian())); + player.addParticle(ParticleTypes.FLAME, pos, new Vec3d(rng.nextGaussian(), 0.8, rng.nextGaussian())); + player.addParticle(ParticleTypes.LAVA, pos, new Vec3d(rng.nextGaussian(), 0.8, rng.nextGaussian())); + } + + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java index 10ca83e2..3edec65a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RageAbilitySpell.java @@ -64,7 +64,7 @@ public class RageAbilitySpell extends AbstractSpell { public boolean canDestroyBlock(Explosion explosion, BlockView world, BlockPos pos, BlockState state, float power) { return false; } - }, source.getOriginVector(), 0, true, ExplosionSourceType.MOB); + }, source.getOriginVector(), 3, true, ExplosionSourceType.MOB); if (source instanceof Pony pony) { pony.setAnimation(Animation.ARMS_UP, Recipient.ANYONE, 12); @@ -87,7 +87,9 @@ public class RageAbilitySpell extends AbstractSpell { } else { if (age % 5 == 0) { source.spawnParticles(ParticleTypes.LAVA, 4); - source.subtractEnergyCost(Math.min(12, 3 + source.asEntity().getVelocity().length() * 0.1)); + if (source instanceof Pony pony && !pony.asEntity().handSwinging) { + source.subtractEnergyCost(Math.min(12, 3 + source.asEntity().getVelocity().length() * 0.1)); + } } } 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 d41347bb..8cde15c2 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -136,7 +136,7 @@ public class UHud { slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta)); - boolean canCast = Abilities.CAST.canUse(pony.getCompositeRace()); + boolean canCast = Abilities.CAST.canUse(pony.getCompositeRace()) || Abilities.KIRIN_CAST.canUse(pony.getCompositeRace()); if (canCast) { Ability ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index bfd22bb3..706eb512 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -105,6 +105,8 @@ public class Pony extends Living implements Copyable, Update private float magicExhaustion = 0; + private int ticksInvulnerable; + private int ticksInSun; private boolean hasShades; private int ticksSunImmunity = INITIAL_SUN_IMMUNITY; @@ -275,6 +277,10 @@ public class Pony extends Living implements Copyable, Update return ticksSunImmunity > 0; } + public void setInvulnerabilityTicks(int ticks) { + this.ticksInvulnerable = Math.max(0, ticks); + } + @Override public Affinity getAffinity() { return getSpecies().getAffinity(); @@ -354,6 +360,10 @@ public class Pony extends Living implements Copyable, Update ); } + if (ticksInvulnerable > 0) { + entity.setInvulnerable(--ticksInvulnerable > 0); + } + if (isClient()) { if (entity.hasVehicle() && entity.isSneaking()) { @@ -850,6 +860,7 @@ public class Pony extends Living implements Copyable, Update compound.put("mana", mana.toNBT()); compound.putInt("levels", levels.get()); compound.putInt("corruption", corruption.get()); + compound.putInt("ticksInvulnerable", ticksInvulnerable); NbtCompound progress = new NbtCompound(); advancementProgress.forEach((key, count) -> { @@ -872,6 +883,7 @@ public class Pony extends Living implements Copyable, Update magicExhaustion = compound.getFloat("magicExhaustion"); ticksHanging = compound.getInt("ticksHanging"); + ticksInvulnerable = compound.getInt("ticksInvulnerable"); entity.getDataTracker().set(HANGING_POSITION, NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); ticksInSun = compound.getInt("ticksInSun"); hasShades = compound.getBoolean("hasShades"); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index cda863e5..65be0c75 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -404,6 +404,7 @@ "ability.unicopia.disguise": "Change Form", "ability.unicopia.rainboom": "Sonic Rainboom", "ability.unicopia.rage": "Rage", + "ability.unicopia.nirik_blast": "Nirik Blast", "gui.unicopia.trait.label": "Element of %s", "gui.unicopia.trait.group": "\n %s", diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/nirik_blast.png b/src/main/resources/assets/unicopia/textures/gui/ability/nirik_blast.png new file mode 100644 index 00000000..7144e5b8 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/gui/ability/nirik_blast.png differ