2020-10-11 13:14:41 +02:00
|
|
|
package com.minelittlepony.unicopia.ability;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
2021-08-04 15:38:03 +02:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2020-10-11 13:14:41 +02:00
|
|
|
|
|
|
|
import com.google.common.collect.Lists;
|
2021-01-26 21:33:26 +01:00
|
|
|
import com.minelittlepony.unicopia.BlockDestructionManager;
|
2020-10-11 13:14:41 +02:00
|
|
|
import com.minelittlepony.unicopia.Race;
|
|
|
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
|
|
|
import com.minelittlepony.unicopia.ability.data.Pos;
|
2021-08-20 22:25:46 +02:00
|
|
|
import com.minelittlepony.unicopia.ability.data.tree.TreeType;
|
2022-01-04 17:00:06 +01:00
|
|
|
import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector;
|
2022-01-03 21:54:07 +01:00
|
|
|
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
2020-10-11 13:14:41 +02:00
|
|
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
2022-01-04 17:00:06 +01:00
|
|
|
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
|
|
|
import com.minelittlepony.unicopia.particle.UParticles;
|
2021-02-13 12:51:01 +01:00
|
|
|
import com.minelittlepony.unicopia.util.PosHelper;
|
2020-10-11 13:14:41 +02:00
|
|
|
import com.minelittlepony.unicopia.util.RayTraceHelper;
|
|
|
|
|
2021-02-13 12:51:01 +01:00
|
|
|
import net.minecraft.block.BeehiveBlock;
|
2021-02-13 12:50:24 +01:00
|
|
|
import net.minecraft.block.Block;
|
2021-02-13 12:51:01 +01:00
|
|
|
import net.minecraft.block.BlockState;
|
2020-10-11 13:14:41 +02:00
|
|
|
import net.minecraft.block.Blocks;
|
2021-02-13 12:51:01 +01:00
|
|
|
import net.minecraft.block.entity.BeehiveBlockEntity;
|
2020-10-11 13:14:41 +02:00
|
|
|
import net.minecraft.entity.ItemEntity;
|
2021-02-13 12:51:01 +01:00
|
|
|
import net.minecraft.entity.passive.BeeEntity;
|
2020-10-11 13:14:41 +02:00
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
2021-08-20 23:52:06 +02:00
|
|
|
import net.minecraft.item.ItemStack;
|
2020-10-11 13:14:41 +02:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
2021-02-13 12:51:01 +01:00
|
|
|
import net.minecraft.util.math.Box;
|
2020-10-11 13:14:41 +02:00
|
|
|
import net.minecraft.util.math.Vec3d;
|
2021-08-25 14:22:11 +02:00
|
|
|
import net.minecraft.world.WorldEvents;
|
2020-10-11 13:14:41 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Earth Pony kicking ability
|
|
|
|
*/
|
|
|
|
public class EarthPonyKickAbility implements Ability<Pos> {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getWarmupTime(Pony player) {
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getCooldownTime(Pony player) {
|
|
|
|
return 50;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean canUse(Race race) {
|
|
|
|
return race.canUseEarth();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double getCostEstimate(Pony player) {
|
2022-01-04 17:00:06 +01:00
|
|
|
double distance = MineLPConnector.getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6;
|
|
|
|
|
|
|
|
return RayTraceHelper.doTrace(player.getMaster(), distance, 1)
|
|
|
|
.getBlockPos()
|
|
|
|
.filter(pos -> TreeType.at(pos, player.getWorld()) != TreeType.NONE)
|
|
|
|
.isPresent() ? 3 : 1;
|
2020-10-11 13:14:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Override
|
|
|
|
public Pos tryActivate(Pony player) {
|
2022-01-04 17:00:06 +01:00
|
|
|
double distance = MineLPConnector.getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6;
|
|
|
|
|
|
|
|
return RayTraceHelper.doTrace(player.getMaster(), distance, 1)
|
|
|
|
.getBlockPos()
|
|
|
|
.filter(pos -> TreeType.at(pos, player.getWorld()) != TreeType.NONE)
|
|
|
|
.map(Pos::new)
|
|
|
|
.orElseGet(() -> getDefaultKickLocation(player));
|
|
|
|
}
|
|
|
|
|
|
|
|
private Pos getDefaultKickLocation(Pony player) {
|
|
|
|
Vec3d kickVector = player.getMaster().getRotationVector().multiply(1, 0, 1);
|
|
|
|
if (!MineLPConnector.getPlayerPonyRace(player.getMaster()).isDefault()) {
|
|
|
|
kickVector = kickVector.rotateY((float)Math.PI);
|
|
|
|
}
|
|
|
|
return new Pos(new BlockPos(player.getOriginVector().add(kickVector)));
|
2021-08-20 22:22:28 +02:00
|
|
|
}
|
2020-10-11 13:14:41 +02:00
|
|
|
|
2021-08-20 22:22:28 +02:00
|
|
|
@Override
|
|
|
|
public boolean canApply(Pony player, Pos data) {
|
|
|
|
BlockPos pos = data.pos();
|
2021-08-20 23:52:06 +02:00
|
|
|
TreeType tree = TreeType.at(pos, player.getWorld());
|
2020-10-11 13:14:41 +02:00
|
|
|
|
2022-01-04 17:00:06 +01:00
|
|
|
return tree == TreeType.NONE || tree.findBase(player.getWorld(), pos)
|
|
|
|
.map(base -> tree.countBlocks(player.getWorld(), pos) > 0)
|
|
|
|
.orElse(false);
|
2020-10-11 13:14:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Hit.Serializer<Pos> getSerializer() {
|
|
|
|
return Pos.SERIALIZER;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void apply(Pony iplayer, Pos data) {
|
2022-01-04 17:00:06 +01:00
|
|
|
BlockPos pos = data.pos();
|
|
|
|
TreeType tree = TreeType.at(pos, iplayer.getWorld());
|
2020-10-11 13:14:41 +02:00
|
|
|
|
2022-01-04 17:00:06 +01:00
|
|
|
iplayer.setAnimation(Animation.KICK);
|
|
|
|
iplayer.subtractEnergyCost(tree == TreeType.NONE ? 1 : 3);
|
2020-10-11 13:14:41 +02:00
|
|
|
|
2022-01-04 17:00:06 +01:00
|
|
|
if (tree == TreeType.NONE) {
|
2020-10-11 13:14:41 +02:00
|
|
|
return;
|
2022-01-04 17:00:06 +01:00
|
|
|
} else {
|
|
|
|
ParticleUtils.spawnParticle(iplayer.getWorld(), UParticles.GROUND_POUND, data.vec(), Vec3d.ZERO);
|
2020-10-11 13:14:41 +02:00
|
|
|
}
|
|
|
|
|
2022-01-04 17:00:06 +01:00
|
|
|
PlayerEntity player = iplayer.getMaster();
|
2022-01-03 21:54:07 +01:00
|
|
|
|
2022-01-04 17:00:06 +01:00
|
|
|
boolean harmed = player.getHealth() < player.getMaxHealth();
|
2020-10-11 13:14:41 +02:00
|
|
|
|
2021-01-26 21:33:26 +01:00
|
|
|
BlockDestructionManager destr = ((BlockDestructionManager.Source)player.world).getDestructionManager();
|
|
|
|
|
|
|
|
if (destr.getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) {
|
2020-10-11 13:14:41 +02:00
|
|
|
if (!harmed || player.world.random.nextInt(30) == 0) {
|
2022-01-04 17:00:06 +01:00
|
|
|
tree.traverse(player.world, pos, (w, state, p, recurseLevel) -> {
|
2021-02-13 12:50:24 +01:00
|
|
|
if (recurseLevel < 5) {
|
|
|
|
w.breakBlock(p, true);
|
|
|
|
} else {
|
|
|
|
Block.dropStacks(w.getBlockState(p), w, p);
|
|
|
|
w.setBlockState(p, Blocks.AIR.getDefaultState(), 3);
|
|
|
|
}
|
|
|
|
});
|
2020-10-11 13:14:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
iplayer.subtractEnergyCost(3);
|
|
|
|
} else {
|
2021-02-13 12:50:24 +01:00
|
|
|
int cost = dropApples(player, pos);
|
2020-10-11 13:14:41 +02:00
|
|
|
|
|
|
|
if (cost > 0) {
|
2022-01-04 17:00:06 +01:00
|
|
|
iplayer.subtractEnergyCost(cost / 7F);
|
2020-10-11 13:14:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void preApply(Pony player, AbilitySlot slot) {
|
|
|
|
player.getMagicalReserves().getExertion().add(40);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void postApply(Pony player, AbilitySlot slot) {
|
|
|
|
}
|
|
|
|
|
2021-02-13 12:50:24 +01:00
|
|
|
private int dropApples(PlayerEntity player, BlockPos pos) {
|
2021-08-20 23:52:06 +02:00
|
|
|
TreeType tree = TreeType.at(pos, player.world);
|
2021-01-26 21:33:26 +01:00
|
|
|
|
2021-02-13 12:50:24 +01:00
|
|
|
if (tree.countBlocks(player.world, pos) > 0) {
|
2020-10-11 13:14:41 +02:00
|
|
|
List<ItemEntity> capturedDrops = Lists.newArrayList();
|
|
|
|
|
2021-02-13 12:50:24 +01:00
|
|
|
tree.traverse(player.world, pos, (world, state, position, recurse) -> {
|
|
|
|
affectBlockChange(player, position);
|
|
|
|
}, (world, state, position, recurse) -> {
|
|
|
|
affectBlockChange(player, position);
|
|
|
|
|
|
|
|
if (world.getBlockState(position.down()).isAir()) {
|
2021-08-20 23:52:06 +02:00
|
|
|
ItemStack stack = tree.pickRandomStack(state);
|
|
|
|
if (!stack.isEmpty()) {
|
2021-08-25 14:22:11 +02:00
|
|
|
world.syncWorldEvent(WorldEvents.BLOCK_BROKEN, position, Block.getRawIdFromState(state));
|
2021-08-20 23:52:06 +02:00
|
|
|
|
|
|
|
capturedDrops.add(new ItemEntity(world,
|
2021-02-13 12:50:24 +01:00
|
|
|
position.getX() + world.random.nextFloat(),
|
|
|
|
position.getY() - 0.5,
|
|
|
|
position.getZ() + world.random.nextFloat(),
|
2021-08-20 23:52:06 +02:00
|
|
|
stack
|
2021-02-13 12:50:24 +01:00
|
|
|
));
|
2021-08-20 23:52:06 +02:00
|
|
|
}
|
2021-02-13 12:50:24 +01:00
|
|
|
}
|
|
|
|
});
|
2020-10-11 13:14:41 +02:00
|
|
|
|
|
|
|
capturedDrops.forEach(item -> {
|
|
|
|
item.setToDefaultPickupDelay();
|
2021-02-13 12:50:24 +01:00
|
|
|
player.world.spawnEntity(item);
|
2020-10-11 13:14:41 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return capturedDrops.size() / 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-13 12:50:24 +01:00
|
|
|
private void affectBlockChange(PlayerEntity player, BlockPos position) {
|
|
|
|
BlockDestructionManager destr = ((BlockDestructionManager.Source)player.world).getDestructionManager();
|
|
|
|
|
|
|
|
destr.damageBlock(position, 4);
|
2020-10-11 13:14:41 +02:00
|
|
|
|
2021-02-13 12:51:01 +01:00
|
|
|
PosHelper.all(position, p -> {
|
|
|
|
BlockState s = player.world.getBlockState(p);
|
|
|
|
|
|
|
|
if (s.getBlock() instanceof BeehiveBlock) {
|
|
|
|
BeehiveBlockEntity hive = (BeehiveBlockEntity)player.world.getBlockEntity(p);
|
|
|
|
if (hive != null) {
|
|
|
|
hive.angerBees(player, s, BeehiveBlockEntity.BeeState.BEE_RELEASED);
|
|
|
|
}
|
|
|
|
|
|
|
|
Box area = new Box(position).expand(8, 6, 8);
|
|
|
|
List<BeeEntity> nearbyBees = player.world.getNonSpectatingEntities(BeeEntity.class, area);
|
|
|
|
|
|
|
|
if (!nearbyBees.isEmpty()) {
|
|
|
|
List<PlayerEntity> nearbyPlayers = player.world.getNonSpectatingEntities(PlayerEntity.class, area);
|
|
|
|
int i = nearbyPlayers.size();
|
|
|
|
|
|
|
|
for (BeeEntity bee : nearbyBees) {
|
|
|
|
if (bee.getTarget() == null) {
|
|
|
|
bee.setTarget(nearbyPlayers.get(player.world.random.nextInt(i)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, PosHelper.HORIZONTAL);
|
2020-10-11 13:14:41 +02:00
|
|
|
}
|
|
|
|
}
|