mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Cancel stomps when moving upwards
This commit is contained in:
parent
e6ec2083ef
commit
04298eefcf
3 changed files with 145 additions and 79 deletions
|
@ -6,9 +6,11 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.AwaitTickQueue;
|
import com.minelittlepony.unicopia.AwaitTickQueue;
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
|
import com.minelittlepony.unicopia.USounds;
|
||||||
import com.minelittlepony.unicopia.UTags;
|
import com.minelittlepony.unicopia.UTags;
|
||||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
||||||
|
import com.minelittlepony.unicopia.entity.LandingEventHandler;
|
||||||
import com.minelittlepony.unicopia.entity.Living;
|
import com.minelittlepony.unicopia.entity.Living;
|
||||||
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
@ -20,7 +22,6 @@ import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
|
||||||
import com.minelittlepony.unicopia.util.PosHelper;
|
import com.minelittlepony.unicopia.util.PosHelper;
|
||||||
import com.minelittlepony.unicopia.util.VecHelper;
|
import com.minelittlepony.unicopia.util.VecHelper;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.enchantment.EnchantmentHelper;
|
import net.minecraft.enchantment.EnchantmentHelper;
|
||||||
|
@ -105,74 +106,89 @@ public class EarthPonyStompAbility implements Ability<Hit> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Pony iplayer, Hit data) {
|
public boolean apply(Pony iplayer, Hit data) {
|
||||||
PlayerEntity player = iplayer.asEntity();
|
final PlayerEntity player = iplayer.asEntity();
|
||||||
|
final double initialY = player.getY() + 5;
|
||||||
|
|
||||||
Float2FloatFunction r = fallDistance -> {
|
var r = new LandingEventHandler.Callback() {
|
||||||
player.fallDistance = 0;
|
@Override
|
||||||
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum());
|
public float dispatch(float fallDistance) {
|
||||||
|
// fail if landing above the starting position
|
||||||
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
|
if (player.getY() > initialY) {
|
||||||
|
return fallDistance;
|
||||||
iplayer.asWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> {
|
|
||||||
double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos()));
|
|
||||||
|
|
||||||
if (dist <= rad + 3) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
i.damage(iplayer.damageOf(UDamageTypes.SMASH, iplayer), (float)amount);
|
|
||||||
Living.updateVelocity(i);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
double radius = rad + heavyness * 0.3;
|
player.fallDistance = 0;
|
||||||
|
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum());
|
||||||
|
|
||||||
spawnEffectAround(player, center, radius, rad);
|
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
|
||||||
|
|
||||||
ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0);
|
iplayer.asWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> {
|
||||||
BlockState steppingState = player.getSteppingBlockState();
|
double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos()));
|
||||||
if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) {
|
|
||||||
ParticleUtils.spawnParticle(player.getWorld(), new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), player.getBlockPos().down().toCenterPos(), Vec3d.ZERO);
|
if (dist <= rad + 3) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.damage(iplayer.damageOf(UDamageTypes.SMASH, iplayer), (float)amount);
|
||||||
|
Living.updateVelocity(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
double radius = rad + heavyness * 0.3;
|
||||||
|
|
||||||
|
spawnEffectAround(player, center, radius, rad);
|
||||||
|
|
||||||
|
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.Blocks.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);
|
||||||
|
return 0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
iplayer.subtractEnergyCost(rad);
|
@Override
|
||||||
iplayer.asEntity().addExhaustion(3);
|
public void onCancelled() {
|
||||||
return 0F;
|
System.out.println("Cancel Stomp");
|
||||||
|
iplayer.playSound(USounds.GUI_ABILITY_FAIL, 1F);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (iplayer.asEntity().isOnGround()) {
|
if (iplayer.asEntity().isOnGround()) {
|
||||||
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
|
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
|
||||||
iplayer.asEntity().jump();
|
iplayer.asEntity().jump();
|
||||||
iplayer.updateVelocity();
|
iplayer.updateVelocity();
|
||||||
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.get(0F), 5);
|
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.dispatch(0F), 5);
|
||||||
} else {
|
} else {
|
||||||
thrustDownwards(iplayer);
|
thrustDownwards(iplayer);
|
||||||
iplayer.waitForFall(r);
|
iplayer.waitForFall(r);
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.util.Tickable;
|
||||||
|
|
||||||
|
public class LandingEventHandler implements Tickable {
|
||||||
|
|
||||||
|
private final Living<?> living;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final AtomicReference<Callback> callback = new AtomicReference<>();
|
||||||
|
private double prevY;
|
||||||
|
private float prevFallDistance;
|
||||||
|
|
||||||
|
public LandingEventHandler(Living<?> living) {
|
||||||
|
this.living = living;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallback(LandingEventHandler.Callback callback) {
|
||||||
|
if (living.asEntity().isOnGround()) {
|
||||||
|
callback.dispatch(0F);
|
||||||
|
} else {
|
||||||
|
updateCallback(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beforeTick() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (living.asEntity().getY() > prevY) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
prevY = living.asEntity().getY();
|
||||||
|
|
||||||
|
if (living.asEntity().isOnGround() && living.landedChanged()) {
|
||||||
|
fire(prevFallDistance);
|
||||||
|
}
|
||||||
|
prevFallDistance = living.asEntity().fallDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fire(float fallDistance) {
|
||||||
|
var event = callback.getAndSet(null);
|
||||||
|
return event == null ? fallDistance : event.dispatch(fallDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void discard() {
|
||||||
|
updateCallback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCallback(@Nullable Callback callback) {
|
||||||
|
var event = this.callback.getAndSet(callback);
|
||||||
|
if (event != null) {
|
||||||
|
event.onCancelled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Callback {
|
||||||
|
float dispatch(float fallDistance);
|
||||||
|
|
||||||
|
void onCancelled();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package com.minelittlepony.unicopia.entity;
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
@ -39,7 +38,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
|
||||||
import com.minelittlepony.unicopia.server.world.DragonBreathStore;
|
import com.minelittlepony.unicopia.server.world.DragonBreathStore;
|
||||||
import com.minelittlepony.unicopia.util.*;
|
import com.minelittlepony.unicopia.util.*;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
|
|
||||||
import it.unimi.dsi.fastutil.floats.Float2ObjectFunction;
|
import it.unimi.dsi.fastutil.floats.Float2ObjectFunction;
|
||||||
import net.fabricmc.fabric.api.util.TriState;
|
import net.fabricmc.fabric.api.util.TriState;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -84,10 +82,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
private final Interactable landedHeuristic;
|
private final Interactable landedHeuristic;
|
||||||
private final Interactable jumpingHeuristic;
|
private final Interactable jumpingHeuristic;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private final AtomicReference<Float2FloatFunction> landEvent = new AtomicReference<>();
|
|
||||||
private float prevFallDistance;
|
|
||||||
|
|
||||||
private boolean invisible = false;
|
private boolean invisible = false;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -101,6 +95,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
|
|
||||||
private final List<Tickable> tickers = new ArrayList<>();
|
private final List<Tickable> tickers = new ArrayList<>();
|
||||||
|
|
||||||
|
private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this));
|
||||||
private final Enchantments enchants = addTicker(new Enchantments(this));
|
private final Enchantments enchants = addTicker(new Enchantments(this));
|
||||||
private final ItemTracker armour = addTicker(new ItemTracker(this));
|
private final ItemTracker armour = addTicker(new ItemTracker(this));
|
||||||
//private final Transportation<T> transportation = new Transportation<>(this);
|
//private final Transportation<T> transportation = new Transportation<>(this);
|
||||||
|
@ -134,12 +129,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
this.invisible = invisible;
|
this.invisible = invisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForFall(Float2FloatFunction action) {
|
public void waitForFall(LandingEventHandler.Callback callback) {
|
||||||
if (entity.isOnGround()) {
|
landEvent.setCallback(callback);
|
||||||
action.get(0F);
|
|
||||||
} else {
|
|
||||||
landEvent.set(action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean sneakingChanged() {
|
public boolean sneakingChanged() {
|
||||||
|
@ -209,7 +200,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean beforeUpdate() {
|
public boolean beforeUpdate() {
|
||||||
prevFallDistance = entity.fallDistance;
|
landEvent.beforeTick();
|
||||||
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
|
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
|
||||||
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
|
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
|
||||||
updateVelocity();
|
updateVelocity();
|
||||||
|
@ -240,10 +231,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
invinsibilityTicks--;
|
invinsibilityTicks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.isOnGround() && landedChanged()) {
|
|
||||||
onLanded(prevFallDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) {
|
if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) {
|
||||||
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
|
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
|
||||||
updateVelocity();
|
updateVelocity();
|
||||||
|
@ -264,11 +251,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
transportation.tick();
|
transportation.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float onLanded(float fallDistance) {
|
|
||||||
var event = landEvent.getAndSet(null);
|
|
||||||
return event == null ? fallDistance : event.get(fallDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {
|
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {
|
||||||
@Nullable
|
@Nullable
|
||||||
EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute);
|
EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute);
|
||||||
|
@ -474,7 +456,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
}
|
}
|
||||||
|
|
||||||
public float onImpact(float distance, float damageMultiplier, DamageSource cause) {
|
public float onImpact(float distance, float damageMultiplier, DamageSource cause) {
|
||||||
float fallDistance = onLanded(getEffectiveFallDistance(distance));
|
float fallDistance = landEvent.fire(getEffectiveFallDistance(distance));
|
||||||
|
|
||||||
getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> {
|
getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> {
|
||||||
spell.getDisguise().onImpact(this, fallDistance, damageMultiplier, cause);
|
spell.getDisguise().onImpact(this, fallDistance, damageMultiplier, cause);
|
||||||
|
|
Loading…
Reference in a new issue