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

282 lines
9.5 KiB
Java
Raw Normal View History

package com.minelittlepony.unicopia.ability;
2018-09-12 01:29:49 +02:00
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
2019-02-07 14:47:33 +01:00
import com.google.common.collect.Lists;
2020-04-15 19:06:45 +02:00
import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.TreeTraverser;
2020-04-22 20:23:54 +02:00
import com.minelittlepony.unicopia.TreeType;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Multi;
2020-04-15 18:12:00 +02:00
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.VecHelper;
import com.minelittlepony.unicopia.util.WorldEvent;
2020-04-15 18:12:00 +02:00
import com.minelittlepony.unicopia.util.shape.Shape;
import com.minelittlepony.unicopia.util.shape.Sphere;
2018-09-12 01:29:49 +02:00
import net.minecraft.block.Block;
2020-01-16 12:35:46 +01:00
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.LogBlock;
import net.minecraft.entity.EntityContext;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.BlockStateParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
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.Direction;
2018-09-12 01:29:49 +02:00
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
2018-09-12 01:29:49 +02:00
import net.minecraft.world.World;
/**
* Earth Pony stomping ability
*/
public class EarthPonyStompAbility implements Ability<Multi> {
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 playerSpecies) {
return playerSpecies.canUseEarth();
}
@Nullable
2018-09-12 01:29:49 +02:00
@Override
public Multi tryActivate(Pony player) {
2020-01-16 12:35:46 +01:00
HitResult mop = VecHelper.getObjectMouseOver(player.getOwner(), 6, 1);
if (mop instanceof BlockHitResult && mop.getType() == HitResult.Type.BLOCK) {
BlockPos pos = ((BlockHitResult)mop).getBlockPos();
BlockState state = player.getWorld().getBlockState(pos);
2019-02-07 10:46:59 +01:00
2020-01-16 12:35:46 +01:00
if (state.getBlock() instanceof LogBlock) {
pos = TreeTraverser.descendTree(player.getWorld(), state, pos).get();
if (TreeTraverser.measureTree(player.getWorld(), state, pos) > 0) {
return new Multi(pos, 1);
2018-09-12 01:29:49 +02:00
}
}
}
2020-01-16 12:35:46 +01:00
if (!player.getOwner().onGround && !player.getOwner().abilities.flying) {
2019-02-03 10:45:45 +01:00
player.getOwner().addVelocity(0, -6, 0);
return new Multi(Vec3i.ZERO, 0);
2018-09-12 01:29:49 +02:00
}
2018-09-12 01:29:49 +02:00
return null;
}
2018-09-12 01:29:49 +02:00
@Override
public Hit.Serializer<Multi> getSerializer() {
return Multi.SERIALIZER;
2018-09-12 01:29:49 +02:00
}
2018-09-12 01:29:49 +02:00
@Override
public void apply(Pony iplayer, Multi data) {
2020-01-16 12:35:46 +01:00
PlayerEntity player = iplayer.getOwner();
2018-09-12 01:29:49 +02:00
if (data.hitType == 0) {
2020-01-16 12:35:46 +01:00
BlockPos ppos = player.getBlockPos();
BlockPos pos = getSolidBlockBelow(ppos, player.getEntityWorld());
2020-01-16 12:35:46 +01:00
player.addVelocity(0, -(ppos.getSquaredDistance(pos)), 0);
2020-01-16 12:35:46 +01:00
iplayer.getWorld().getEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> {
double dist = Math.sqrt(pos.getSquaredDistance(i.getBlockPos()));
2018-09-12 01:29:49 +02:00
if (dist <= rad + 3) {
double force = dist / 5;
i.addVelocity(
2020-04-22 16:28:20 +02:00
-(player.getX() - i.getX()) / force,
-(player.getY() - i.getY() - 2) / force + (dist < 1 ? dist : 0),
-(player.getZ() - i.getZ()) / force);
2018-09-12 01:29:49 +02:00
DamageSource damage = MagicalDamageSource.causePlayerDamage("smash", player);
2020-01-16 12:35:46 +01:00
double amount = (4 * player.getAttributeInstance(EntityAttributes.ATTACK_DAMAGE).getValue()) / (float)dist;
2020-01-16 12:35:46 +01:00
if (i instanceof PlayerEntity) {
2020-04-15 18:12:00 +02:00
Race race = Pony.of((PlayerEntity)i).getSpecies();
if (race.canUseEarth()) {
amount /= 3;
}
if (race.canFly()) {
amount *= 4;
}
2018-09-12 01:29:49 +02:00
}
2020-01-16 12:35:46 +01:00
i.damage(damage, (float)amount);
2018-09-12 01:29:49 +02:00
}
2019-02-03 10:45:45 +01:00
});
2020-01-16 12:35:46 +01:00
BlockPos.iterate(pos.add(-rad, -rad, -rad), pos.add(rad, rad, rad)).forEach(i -> {
2020-04-22 16:28:20 +02:00
if (i.getSquaredDistance(player.getX(), player.getY(), player.getZ(), true) <= rad*rad) {
2018-09-12 01:29:49 +02:00
spawnEffect(player.world, i);
}
2019-02-03 10:45:45 +01:00
});
2018-09-12 01:29:49 +02:00
for (int i = 1; i < 202; i+= 2) {
spawnParticleRing(player, i, 0);
2018-09-12 01:29:49 +02:00
}
iplayer.subtractEnergyCost(rad);
2018-09-12 01:29:49 +02:00
} else if (data.hitType == 1) {
2020-04-22 16:28:20 +02:00
boolean harmed = player.getHealth() < player.getMaximumHealth();
2020-01-16 12:35:46 +01:00
if (harmed && player.world.random.nextInt(30) == 0) {
iplayer.subtractEnergyCost(3);
return;
}
2020-01-16 12:35:46 +01:00
if (harmed || player.world.random.nextInt(5) == 0) {
2020-01-16 12:35:46 +01:00
if (!harmed || player.world.random.nextInt(30) == 0) {
AwaitTickQueue.enqueueTask(w -> TreeTraverser.removeTree(w, data.pos()));
}
iplayer.subtractEnergyCost(3);
} else {
int cost = dropApples(player.world, data.pos());
if (cost > 0) {
iplayer.subtractEnergyCost(cost * 3);
}
}
2018-09-12 01:29:49 +02:00
}
}
private void spawnEffect(World w, BlockPos pos) {
2020-01-16 12:35:46 +01:00
BlockState state = w.getBlockState(pos);
2018-09-12 01:29:49 +02:00
2020-01-16 12:35:46 +01:00
if (!state.isAir() && w.getBlockState(pos.up()).isAir()) {
WorldEvent.DESTROY_BLOCK.play(w, pos, state);
2018-09-12 01:29:49 +02:00
}
}
@Override
2020-04-15 18:12:00 +02:00
public void preApply(Pony player) {
player.getMagicalReserves().addExertion(40);
2020-01-16 12:35:46 +01:00
player.getOwner().attemptSprintingParticles();
2018-09-12 01:29:49 +02:00
}
@Override
2020-04-15 18:12:00 +02:00
public void postApply(Pony player) {
2020-05-06 15:55:25 +02:00
int timeDiff = getCooldownTime(player) - player.getAbilities().getStat(player.getAbilities().getActiveSlot()).getRemainingCooldown();
2018-09-12 01:29:49 +02:00
2020-01-16 12:35:46 +01:00
if (player.getOwner().getEntityWorld().getTime() % 1 == 0 || timeDiff == 0) {
spawnParticleRing(player.getOwner(), timeDiff, 1);
2018-09-12 01:29:49 +02:00
}
}
2020-01-16 12:35:46 +01:00
private void spawnParticleRing(PlayerEntity player, int timeDiff, double yVel) {
int animationTicks = timeDiff / 10;
2018-09-12 01:29:49 +02:00
if (animationTicks < 6) {
2020-04-15 18:12:00 +02:00
Shape shape = new Sphere(true, animationTicks, 1, 0, 1);
2018-09-12 01:29:49 +02:00
double y = 0.5 + (Math.sin(animationTicks) * 1.5);
yVel *= y * 5;
for (int i = 0; i < shape.getVolumeOfSpawnableSpace(); i++) {
2020-04-22 16:28:20 +02:00
Vec3d point = shape.computePoint(player.getEntityWorld().random).add(player.getPos());
2020-01-16 12:35:46 +01:00
player.world.addParticle(new BlockStateParticleEffect(ParticleTypes.BLOCK, Blocks.DIRT.getDefaultState()),
2020-04-22 16:28:20 +02:00
point.x,
point.y + y,
point.z,
2020-01-16 12:35:46 +01:00
0, yVel, 0
);
2018-09-12 01:29:49 +02:00
}
}
}
private int dropApples(World w, BlockPos pos) {
2020-01-16 12:35:46 +01:00
BlockState log = w.getBlockState(pos);
int size = TreeTraverser.measureTree(w, log, pos);
2018-09-12 01:29:49 +02:00
if (size > 0) {
2019-02-07 14:47:33 +01:00
2020-01-16 12:35:46 +01:00
List<ItemEntity> capturedDrops = Lists.newArrayList();
2019-02-07 14:47:33 +01:00
dropApplesPart(capturedDrops, new ArrayList<BlockPos>(), w, log, pos, 0);
2020-04-15 12:37:14 +02:00
AwaitTickQueue.enqueueTask(wo -> {
capturedDrops.forEach(item -> {
2020-01-16 12:35:46 +01:00
item.setToDefaultPickupDelay();
wo.spawnEntity(item);
});
});
return capturedDrops.size() / 3;
2018-09-12 01:29:49 +02:00
}
return 0;
2018-09-12 01:29:49 +02:00
}
private static void dropApplesPart(List<ItemEntity> drops, List<BlockPos> done, World w, BlockState log, BlockPos pos, int level) {
2018-09-12 01:29:49 +02:00
if (!done.contains(pos)) {
done.add(pos);
pos = TreeTraverser.ascendTree(w, log, pos, false);
if (level < 10 && TreeTraverser.isWoodOrLeaf(w, log, pos)) {
2020-01-16 12:35:46 +01:00
BlockState state = w.getBlockState(pos);
2019-02-03 10:45:45 +01:00
2020-01-16 12:35:46 +01:00
if (state.getBlock() instanceof LeavesBlock && w.getBlockState(pos.down()).isAir()) {
2019-02-07 12:38:42 +01:00
WorldEvent.DESTROY_BLOCK.play(w, pos, state);
drops.add(new ItemEntity(w,
pos.getX() + w.random.nextFloat(),
pos.getY() - 0.5,
pos.getZ() + w.random.nextFloat(),
TreeType.get(log).pickRandomStack()
));
2018-09-12 01:29:49 +02:00
}
PosHelper.all(pos, p -> {
2019-02-07 14:47:33 +01:00
dropApplesPart(drops, done, w, log, p, level + 1);
2020-01-16 12:35:46 +01:00
}, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST);
2018-09-12 01:29:49 +02:00
}
}
}
private static BlockPos getSolidBlockBelow(BlockPos pos, World w) {
while (World.isValid(pos)) {
2018-09-12 01:29:49 +02:00
pos = pos.down();
if (Block.isFaceFullSquare(w.getBlockState(pos).getCollisionShape(w, pos, EntityContext.absent()), Direction.UP)) {
return pos;
}
2018-09-12 01:29:49 +02:00
}
return pos;
}
}