mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-07 22:16:44 +01:00
Earth ponies can now kick things other than trees
This commit is contained in:
parent
a1f84872f2
commit
e994b5e837
8 changed files with 104 additions and 51 deletions
|
@ -15,8 +15,7 @@ import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
|||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.PosHelper;
|
||||
import com.minelittlepony.unicopia.util.RayTraceHelper;
|
||||
import com.minelittlepony.unicopia.util.*;
|
||||
|
||||
import net.minecraft.block.BeehiveBlock;
|
||||
import net.minecraft.block.Block;
|
||||
|
@ -24,12 +23,15 @@ import net.minecraft.block.BlockState;
|
|||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.passive.BeeEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldEvents;
|
||||
|
||||
/**
|
||||
|
@ -62,18 +64,52 @@ public class EarthPonyKickAbility implements Ability<Pos> {
|
|||
.isPresent() ? 3 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQuickAction(Pony player, ActivationType type) {
|
||||
if (type == ActivationType.TAP) {
|
||||
|
||||
if (!player.isClient()) {
|
||||
Vec3d origin = player.getOriginVector();
|
||||
|
||||
Pos kickLocation = getDefaultKickLocation(player);
|
||||
World w = player.getReferenceWorld();
|
||||
|
||||
for (var e : VecHelper.findInRange(player.getEntity(), w, kickLocation.vec(), 2, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR)) {
|
||||
if (e instanceof LivingEntity entity) {
|
||||
float calculatedStrength = 0.5F * (1 + player.getLevel().getScaled(9));
|
||||
entity.damage(MagicalDamageSource.KICK, player.getReferenceWorld().random.nextBetween(2, 10) + calculatedStrength);
|
||||
entity.takeKnockback(calculatedStrength, origin.x - entity.getX(), origin.z - entity.getZ());
|
||||
player.subtractEnergyCost(3);
|
||||
player.setAnimation(Animation.KICK);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BlockPos pos = kickLocation.pos();
|
||||
EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.getMaster(), w, pos));
|
||||
player.setAnimation(Animation.KICK);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Pos tryActivate(Pony player) {
|
||||
double distance = MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6;
|
||||
|
||||
return RayTraceHelper.doTrace(player.getMaster(), distance, 1)
|
||||
return RayTraceHelper.doTrace(player.getMaster(), 6 * getKickDirection(player), 1)
|
||||
.getBlockPos()
|
||||
.filter(pos -> TreeType.at(pos, player.getReferenceWorld()) != TreeType.NONE)
|
||||
.map(Pos::new)
|
||||
.orElseGet(() -> getDefaultKickLocation(player));
|
||||
}
|
||||
|
||||
private int getKickDirection(Pony player) {
|
||||
return MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault() ? 1 : -1;
|
||||
}
|
||||
|
||||
private Pos getDefaultKickLocation(Pony player) {
|
||||
Vec3d kickVector = player.getMaster().getRotationVector().multiply(1, 0, 1);
|
||||
if (!MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault()) {
|
||||
|
@ -115,9 +151,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
|
|||
|
||||
boolean harmed = player.getHealth() < player.getMaxHealth();
|
||||
|
||||
BlockDestructionManager destr = ((BlockDestructionManager.Source)player.world).getDestructionManager();
|
||||
|
||||
if (destr.getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) {
|
||||
if (BlockDestructionManager.of(player.world).getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) {
|
||||
if (!harmed || player.world.random.nextInt(30) == 0) {
|
||||
tree.traverse(player.world, pos, (w, state, p, recurseLevel) -> {
|
||||
if (recurseLevel < 5) {
|
||||
|
@ -186,9 +220,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
|
|||
}
|
||||
|
||||
private void affectBlockChange(PlayerEntity player, BlockPos position) {
|
||||
BlockDestructionManager destr = ((BlockDestructionManager.Source)player.world).getDestructionManager();
|
||||
|
||||
destr.damageBlock(position, 4);
|
||||
BlockDestructionManager.of(player.world).damageBlock(position, 4);
|
||||
|
||||
PosHelper.all(position, p -> {
|
||||
BlockState s = player.world.getBlockState(p);
|
||||
|
|
|
@ -163,31 +163,37 @@ public class EarthPonyStompAbility implements Ability<Hit> {
|
|||
}
|
||||
|
||||
public static void spawnEffect(World w, BlockPos pos, double dist, double rad) {
|
||||
BlockState state = w.getBlockState(pos);
|
||||
BlockDestructionManager destr = ((BlockDestructionManager.Source)w).getDestructionManager();
|
||||
if (w.getBlockState(pos.up()).isAir()) {
|
||||
BlockState state = w.getBlockState(pos);
|
||||
|
||||
if (!state.isAir() && w.getBlockState(pos.up()).isAir()) {
|
||||
|
||||
double amount = (1 - dist / rad) * 9;
|
||||
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);
|
||||
|
||||
int damage = hardness < 0 ? 0 : MathHelper.clamp((int)(amount * scaledHardness), 2, 9);
|
||||
stompBlock(w, pos, damage);
|
||||
}
|
||||
}
|
||||
|
||||
if (destr.damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE) {
|
||||
w.breakBlock(pos, true);
|
||||
public static void stompBlock(World w, BlockPos pos, float damage) {
|
||||
BlockState state = w.getBlockState(pos);
|
||||
|
||||
if (w instanceof ServerWorld) {
|
||||
if (state.getMaterial() == Material.STONE && 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);
|
||||
}
|
||||
if (state.isAir() || damage <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BlockDestructionManager.of(w).damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE) {
|
||||
w.breakBlock(pos, true);
|
||||
|
||||
if (w instanceof ServerWorld) {
|
||||
if (state.getMaterial() == Material.STONE && 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);
|
||||
}
|
||||
} else {
|
||||
w.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state));
|
||||
}
|
||||
} else {
|
||||
w.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,21 +30,25 @@ public class BlockDestructionManager {
|
|||
return Suppliers.memoize(() -> new BlockDestructionManager(world));
|
||||
}
|
||||
|
||||
public static BlockDestructionManager of(World world) {
|
||||
return ((BlockDestructionManager.Source)world).getDestructionManager();
|
||||
}
|
||||
|
||||
private BlockDestructionManager(World world) {
|
||||
this.chunks = WorldOverlay.getOverlay(world, ID, w -> new WorldOverlay<>(world, Destruction::new, this::sendUpdates));
|
||||
}
|
||||
|
||||
public int getBlockDestruction(BlockPos pos) {
|
||||
public float getBlockDestruction(BlockPos pos) {
|
||||
Destruction destr = chunks.getState(pos);
|
||||
return destr == null ? UNSET_DAMAGE : destr.amount;
|
||||
}
|
||||
|
||||
public void setBlockDestruction(BlockPos pos, int amount) {
|
||||
public void setBlockDestruction(BlockPos pos, float amount) {
|
||||
chunks.getOrCreateState(pos).set(amount);
|
||||
chunks.markDirty();
|
||||
}
|
||||
|
||||
public int damageBlock(BlockPos pos, int amount) {
|
||||
public float damageBlock(BlockPos pos, float amount) {
|
||||
if (amount == 0) {
|
||||
return getBlockDestruction(pos);
|
||||
}
|
||||
|
@ -64,12 +68,12 @@ public class BlockDestructionManager {
|
|||
}
|
||||
|
||||
private void sendUpdates(Long2ObjectMap<Destruction> destructions, List<ServerPlayerEntity> players) {
|
||||
Long2ObjectOpenHashMap<Integer> values = new Long2ObjectOpenHashMap<>();
|
||||
Long2ObjectOpenHashMap<Float> values = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
destructions.forEach((blockPos, item) -> {
|
||||
if (item.dirty) {
|
||||
item.dirty = false;
|
||||
values.put(blockPos.longValue(), (Integer)item.amount);
|
||||
values.put(blockPos.longValue(), (Float)item.amount);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -78,7 +82,7 @@ public class BlockDestructionManager {
|
|||
if (msg.toBuffer().writerIndex() > 1048576) {
|
||||
throw new IllegalStateException("Payload may not be larger than 1048576 bytes. Here's what we were trying to send: ["
|
||||
+ values.size() + "]\n"
|
||||
+ Arrays.toString(values.values().stream().mapToInt(Integer::intValue).toArray()));
|
||||
+ Arrays.toString(values.values().stream().mapToDouble(Float::doubleValue).toArray()));
|
||||
}
|
||||
|
||||
players.forEach(player -> {
|
||||
|
@ -89,7 +93,7 @@ public class BlockDestructionManager {
|
|||
}
|
||||
|
||||
private class Destruction implements WorldOverlay.State {
|
||||
int amount = UNSET_DAMAGE;
|
||||
float amount = UNSET_DAMAGE;
|
||||
int age = DESTRUCTION_COOLDOWN;
|
||||
boolean dirty;
|
||||
|
||||
|
@ -105,7 +109,7 @@ public class BlockDestructionManager {
|
|||
return amount < 0 || age-- <= 0;
|
||||
}
|
||||
|
||||
void set(int amount) {
|
||||
void set(float amount) {
|
||||
this.age = DESTRUCTION_COOLDOWN;
|
||||
this.amount = amount >= 0 && amount < MAX_DAMAGE ? amount : UNSET_DAMAGE;
|
||||
this.dirty = true;
|
||||
|
@ -113,13 +117,13 @@ public class BlockDestructionManager {
|
|||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
compound.putInt("destruction", amount);
|
||||
compound.putFloat("destruction", amount);
|
||||
compound.putInt("age", age);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
amount = compound.getInt("destruction");
|
||||
amount = compound.getFloat("destruction");
|
||||
age = compound.getInt("age");
|
||||
dirty = true;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public class ClientBlockDestructionManager {
|
|||
|
||||
private final Object locker = new Object();
|
||||
|
||||
public void setBlockDestruction(long pos, int amount) {
|
||||
public void setBlockDestruction(long pos, float amount) {
|
||||
synchronized (locker) {
|
||||
if (amount <= 0 || amount > BlockDestructionManager.MAX_DAMAGE) {
|
||||
destructions.remove(pos);
|
||||
|
@ -70,9 +70,9 @@ public class ClientBlockDestructionManager {
|
|||
return amount < 0 || age-- <= 0;
|
||||
}
|
||||
|
||||
void set(int amount) {
|
||||
void set(float amount) {
|
||||
this.age = 50;
|
||||
info.setStage(amount >= 0 && amount < BlockDestructionManager.MAX_DAMAGE ? amount : BlockDestructionManager.UNSET_DAMAGE);
|
||||
info.setStage(amount >= 0 && amount < BlockDestructionManager.MAX_DAMAGE ? (int)amount : BlockDestructionManager.UNSET_DAMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,21 +13,21 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||
*/
|
||||
public class MsgBlockDestruction implements Packet<PlayerEntity> {
|
||||
|
||||
private final Long2ObjectMap<Integer> destructions;
|
||||
private final Long2ObjectMap<Float> destructions;
|
||||
|
||||
MsgBlockDestruction(PacketByteBuf buffer) {
|
||||
destructions = new Long2ObjectOpenHashMap<>();
|
||||
int size = buffer.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
destructions.put(buffer.readLong(), (Integer)buffer.readInt());
|
||||
destructions.put(buffer.readLong(), (Float)buffer.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
public MsgBlockDestruction(Long2ObjectMap<Integer> destructions) {
|
||||
public MsgBlockDestruction(Long2ObjectMap<Float> destructions) {
|
||||
this.destructions = destructions;
|
||||
}
|
||||
|
||||
public Long2ObjectMap<Integer> getDestructions() {
|
||||
public Long2ObjectMap<Float> getDestructions() {
|
||||
return destructions;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ public class MsgBlockDestruction implements Packet<PlayerEntity> {
|
|||
buffer.writeInt(destructions.size());
|
||||
destructions.forEach((p, i) -> {
|
||||
buffer.writeLong(p);
|
||||
buffer.writeInt(i);
|
||||
buffer.writeFloat(i);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ public class MagicalDamageSource extends EntityDamageSource {
|
|||
public static final DamageSource FOOD_POISONING = mundane("food_poisoning");
|
||||
public static final DamageSource TRIBE_SWAP = mundane("tribe_swap");
|
||||
public static final DamageSource ZAP_APPLE = create("zap");
|
||||
public static final DamageSource KICK = create("kick");
|
||||
|
||||
public static DamageSource mundane(String type) {
|
||||
return new DamageSource(type) {};
|
||||
|
|
|
@ -50,12 +50,12 @@ public class RayTraceHelper {
|
|||
* @return A Trace describing what was found.
|
||||
*/
|
||||
public static Trace doTrace(Entity e, double distance, float tickDelta, Predicate<Entity> predicate) {
|
||||
final Vec3d ray = e.getRotationVec(tickDelta).multiply(distance);
|
||||
final Vec3d orientation = e.getRotationVec(tickDelta);
|
||||
final Vec3d start = e.getCameraPosVec(tickDelta);
|
||||
|
||||
final Box box = e.getBoundingBox().stretch(ray).expand(1);
|
||||
final Box box = e.getBoundingBox().stretch(orientation.multiply(Math.abs(distance))).expand(10);
|
||||
|
||||
EntityHitResult pointedEntity = ProjectileUtil.raycast(e, start, start.add(ray), box, predicate, distance);
|
||||
EntityHitResult pointedEntity = ProjectileUtil.raycast(e, start, start.add(orientation.multiply(distance)), box, predicate, Math.abs(distance));
|
||||
|
||||
if (pointedEntity != null) {
|
||||
return new Trace(pointedEntity);
|
||||
|
@ -85,6 +85,14 @@ public class RayTraceHelper {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity> Optional<T> getEntity(Predicate<T> predicate) {
|
||||
if (result != null && result.getType() == HitResult.Type.ENTITY) {
|
||||
return Optional.of((T)((EntityHitResult)result).getEntity()).filter(predicate);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<BlockPos> getBlockPos() {
|
||||
if (result != null && result.getType() == HitResult.Type.BLOCK) {
|
||||
return Optional.of(((BlockHitResult)result).getBlockPos());
|
||||
|
|
|
@ -455,8 +455,10 @@
|
|||
"death.attack.paradox": "%1$s imploded",
|
||||
"death.attack.food_poisoning": "%1$s died of food poisoning",
|
||||
"death.attack.food_poisoning.attacker": "%2$s poisoned %1$s to death",
|
||||
"death.attack.back_hole": "%1$s was sucked into a black hole",
|
||||
"death.attack.back_hole.attacker": "%1$s got sucked into %2$s's black hole",
|
||||
"death.attack.black_hole": "%1$s was sucked into a black hole",
|
||||
"death.attack.black_hole.attacker": "%1$s got sucked into %2$s's black hole",
|
||||
"death.attack.kick": "%1$s was kicked really hard",
|
||||
"death.attack.kick.attacker": "%2$s kicked %1$s really hard",
|
||||
|
||||
"unicopia.subtitle.flap_wings": "Wing flaps",
|
||||
"unicopia.subtitle.wind_rush": "Wind gusts",
|
||||
|
|
Loading…
Reference in a new issue