Unicopia/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java

246 lines
9.2 KiB
Java
Raw Normal View History

package com.minelittlepony.unicopia.ability;
2018-09-12 01:29:49 +02:00
2023-08-16 00:18:41 +02:00
import java.util.Optional;
2021-08-04 15:38:03 +02:00
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.data.Hit;
2022-01-04 16:58:31 +01:00
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.Living;
2023-06-02 21:20:30 +02:00
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.player.Pony;
2021-09-02 19:11:51 +02:00
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
2023-04-30 11:46:33 +02:00
import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.block.Block;
2020-01-16 12:35:46 +01:00
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
2020-01-16 12:35:46 +01:00
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.player.PlayerEntity;
2021-09-02 19:11:51 +02:00
import net.minecraft.item.ItemStack;
import net.minecraft.particle.BlockStateParticleEffect;
2023-06-03 13:40:54 +02:00
import net.minecraft.registry.tag.BlockTags;
2021-09-02 19:11:51 +02:00
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
2023-06-02 21:20:30 +02:00
import net.minecraft.util.math.BlockBox;
2018-09-12 01:29:49 +02:00
import net.minecraft.util.math.BlockPos;
2020-01-16 12:35:46 +01:00
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
2018-09-12 01:29:49 +02:00
import net.minecraft.world.World;
import net.minecraft.world.WorldEvents;
2018-09-12 01:29:49 +02:00
/**
* Earth Pony stomping ability
*/
public class EarthPonyStompAbility implements Ability<Hit> {
2018-09-12 01:29:49 +02:00
2019-02-03 10:45:45 +01:00
private final double rad = 4;
2020-01-16 12:35:46 +01:00
private final Box areaOfEffect = new Box(
2019-02-03 10:45:45 +01:00
-rad, -rad, -rad,
rad, rad, rad
);
2018-09-12 01:29:49 +02:00
@Override
2020-04-15 18:12:00 +02:00
public int getWarmupTime(Pony player) {
2019-02-07 10:46:59 +01:00
return 3;
2018-09-12 01:29:49 +02:00
}
@Override
2020-04-15 18:12:00 +02:00
public int getCooldownTime(Pony player) {
2019-02-07 10:46:59 +01:00
return 50;
2018-09-12 01:29:49 +02:00
}
@Override
public boolean canUse(Race race) {
return race.canUseEarth();
2018-09-12 01:29:49 +02:00
}
@Override
public Identifier getIcon(Pony player) {
Identifier id = Abilities.REGISTRY.getId(this);
2024-02-12 18:29:02 +01:00
Race race = player.getObservedSpecies();
return new Identifier(id.getNamespace(), "textures/gui/ability/" + id.getPath()
2024-02-12 18:29:02 +01:00
+ "_" + (race.isHuman() ? Race.EARTH : race).getId().getPath()
+ ".png");
}
@Override
public double getCostEstimate(Pony player) {
return rad;
}
@Nullable
2018-09-12 01:29:49 +02:00
@Override
2023-08-16 00:18:41 +02:00
public Optional<Hit> prepare(Pony player) {
if (player.asEntity().getVelocity().y * player.getPhysics().getGravitySignum() < 0
&& !player.asEntity().getAbilities().flying) {
thrustDownwards(player);
return Hit.INSTANCE;
2018-09-12 01:29:49 +02:00
}
2023-08-16 00:18:41 +02:00
return Optional.empty();
2018-09-12 01:29:49 +02:00
}
@Override
public Hit.Serializer<Hit> getSerializer() {
return Hit.SERIALIZER;
2018-09-12 01:29:49 +02:00
}
private void thrustDownwards(Pony player) {
BlockPos ppos = player.getOrigin();
BlockPos pos = PosHelper.findSolidGroundAt(player.asWorld(), ppos, player.getPhysics().getGravitySignum());
double downV = Math.sqrt(ppos.getSquaredDistance(pos)) * player.getPhysics().getGravitySignum();
player.asEntity().addVelocity(0, -downV, 0);
player.updateVelocity();
}
2018-09-12 01:29:49 +02:00
@Override
2023-08-16 00:18:41 +02:00
public boolean apply(Pony iplayer, Hit data) {
PlayerEntity player = iplayer.asEntity();
Runnable r = () -> {
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum());
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
iplayer.asWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> {
double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos()));
if (dist <= rad + 3) {
2021-02-19 17:53:28 +01:00
double inertia = 2 / dist;
if (i instanceof LivingEntity) {
inertia *= 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, (LivingEntity)i);
}
inertia /= heavyness;
double liftAmount = Math.sin(Math.PI * dist / rad) * 12 * iplayer.getPhysics().getGravitySignum();
i.addVelocity(
-(player.getX() - i.getX()) / inertia,
-(player.getY() - i.getY() - liftAmount) / inertia + (dist < 1 ? dist : 0),
-(player.getZ() - i.getZ()) / inertia);
2021-02-19 17:53:28 +01:00
double amount = (1.5F * player.getAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE).getValue() + heavyness * 0.4) / (float)(dist * 1.3F);
if (i instanceof PlayerEntity) {
Race.Composite race = Pony.of((PlayerEntity)i).getCompositeRace();
if (race.canUseEarth()) {
amount /= 3;
}
if (race.canFly()) {
amount *= 4;
}
}
if (i instanceof LivingEntity) {
amount /= 1 + (EnchantmentHelper.getEquipmentLevel(UEnchantments.PADDED, (LivingEntity)i) / 6F);
}
2023-06-02 21:20:30 +02:00
i.damage(iplayer.damageOf(UDamageTypes.SMASH, iplayer), (float)amount);
Living.updateVelocity(i);
}
});
double radius = rad + heavyness * 0.3;
spawnEffectAround(player, center, radius, rad);
2023-06-03 13:40:54 +02:00
ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0);
BlockState steppingState = player.getSteppingBlockState();
if (steppingState.isIn(UTags.KICKS_UP_DUST)) {
ParticleUtils.spawnParticle(player.getWorld(), new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), player.getBlockPos().down().toCenterPos(), Vec3d.ZERO);
}
iplayer.subtractEnergyCost(rad);
iplayer.asEntity().addExhaustion(3);
};
if (iplayer.asEntity().isOnGround()) {
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
iplayer.asEntity().jump();
iplayer.updateVelocity();
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.run(), 5);
} else {
thrustDownwards(iplayer);
iplayer.waitForFall(r);
}
2023-08-16 00:18:41 +02:00
return true;
2018-09-12 01:29:49 +02:00
}
public static void spawnEffectAround(Entity source, BlockPos center, double radius, double range) {
2023-06-02 21:20:30 +02:00
BlockPos.stream(new BlockBox(center).expand(MathHelper.ceil(radius))).forEach(i -> {
2022-03-26 20:34:15 +01:00
double dist = Math.sqrt(i.getSquaredDistance(source.getX(), source.getY(), source.getZ()));
if (dist <= radius) {
2023-06-03 13:40:54 +02:00
spawnEffect(source.getWorld(), i, dist, range);
}
});
}
public static void spawnEffect(World w, BlockPos pos, double dist, double rad) {
if (w.getBlockState(pos.up()).isAir()) {
BlockState state = w.getBlockState(pos);
float hardness = state.getHardness(w, pos);
float scaledHardness = (1 - hardness / 70);
float damage = hardness < 0 ? 0 : MathHelper.clamp((int)((1 - dist / rad) * 9 * scaledHardness), 0, BlockDestructionManager.MAX_DAMAGE - 1);
stompBlock(w, pos, damage);
}
}
public static void stompBlock(World w, BlockPos pos, float damage) {
BlockState state = w.getBlockState(pos);
2021-09-02 19:11:51 +02:00
if (state.isAir() || damage <= 0) {
return;
}
if (BlockDestructionManager.of(w).damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE) {
w.breakBlock(pos, true);
if (w instanceof ServerWorld) {
2023-06-03 13:40:54 +02:00
if (state.isIn(BlockTags.BASE_STONE_OVERWORLD) && w.getRandom().nextInt(4) == 0) {
ItemStack stack = UItems.PEBBLES.getDefaultStack();
stack.setCount(1 + w.getRandom().nextInt(2));
Block.dropStack(w, pos, stack);
state.onStacksDropped((ServerWorld)w, pos, stack, true);
2021-09-02 19:11:51 +02:00
}
}
} else {
w.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state));
2018-09-12 01:29:49 +02:00
}
if (state.isIn(UTags.KICKS_UP_DUST)) {
if (w.random.nextInt(4) == 0 && w.isAir(pos.up()) && w.getFluidState(pos.up()).isEmpty()) {
ParticleUtils.spawnParticle(w, new BlockStateParticleEffect(UParticles.DUST_CLOUD, state), pos.up().toCenterPos(), VecHelper.supply(() -> w.random.nextTriangular(0, 0.1F)));
}
}
2018-09-12 01:29:49 +02:00
}
@Override
2023-08-16 00:18:41 +02:00
public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().addPercent(40);
2018-09-12 01:29:49 +02:00
}
@Override
2023-08-16 00:18:41 +02:00
public void coolDown(Pony player, AbilitySlot slot) {
2018-09-12 01:29:49 +02:00
}
}