Improved animations when casting or dispelling spells and added animations when using magic staffs. #151

This commit is contained in:
Sollace 2023-08-05 15:45:36 +01:00
parent 3dec711b78
commit b337709f78
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
20 changed files with 304 additions and 168 deletions

View file

@ -76,7 +76,7 @@ public class BatEeeeAbility implements Ability<Hit> {
}, rng.nextInt(10)); }, rng.nextInt(10));
if (!player.getPhysics().isFlying()) { if (!player.getPhysics().isFlying()) {
player.setAnimation(Animation.SPREAD_WINGS); player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE);
} }
Vec3d origin = player.getOriginVector(); Vec3d origin = player.getOriginVector();

View file

@ -88,14 +88,14 @@ public class EarthPonyKickAbility implements Ability<Pos> {
entity.takeKnockback(calculatedStrength, origin.x - entity.getX(), origin.z - entity.getZ()); entity.takeKnockback(calculatedStrength, origin.x - entity.getX(), origin.z - entity.getZ());
Living.updateVelocity(entity); Living.updateVelocity(entity);
player.subtractEnergyCost(3); player.subtractEnergyCost(3);
player.setAnimation(Animation.KICK); player.setAnimation(Animation.KICK, Animation.Recipient.ANYONE);
return; return;
} }
} }
BlockPos pos = kickLocation.pos(); BlockPos pos = kickLocation.pos();
EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.asEntity(), w, pos)); EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.asEntity(), w, pos));
player.setAnimation(Animation.KICK); player.setAnimation(Animation.KICK, Animation.Recipient.ANYONE);
}); });
} }
@ -153,7 +153,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
BlockPos pos = data.pos(); BlockPos pos = data.pos();
TreeType tree = TreeType.at(pos, iplayer.asWorld()); TreeType tree = TreeType.at(pos, iplayer.asWorld());
iplayer.setAnimation(Animation.KICK); iplayer.setAnimation(Animation.KICK, Animation.Recipient.ANYONE);
iplayer.subtractEnergyCost(tree == TreeType.NONE ? 1 : 3); iplayer.subtractEnergyCost(tree == TreeType.NONE ? 1 : 3);
if (tree == TreeType.NONE) { if (tree == TreeType.NONE) {

View file

@ -95,7 +95,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
public void apply(Pony iplayer, Hit data) { public void apply(Pony iplayer, Hit data) {
PlayerEntity player = iplayer.asEntity(); PlayerEntity player = iplayer.asEntity();
iplayer.setAnimation(Animation.STOMP, 10); iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
thrustDownwards(iplayer); thrustDownwards(iplayer);

View file

@ -68,7 +68,7 @@ public class PegasusFlightToggleAbility implements Ability<Hit> {
player.getPhysics().cancelFlight(true); player.getPhysics().cancelFlight(true);
} }
player.setDirty(); player.setDirty();
player.setAnimation(Animation.SPREAD_WINGS); player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE);
} }
@Override @Override

View file

@ -111,14 +111,14 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility {
player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6); player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6);
player.playSound(USounds.SPELL_CAST_FAIL, 1, 0.5F); player.playSound(USounds.SPELL_CAST_FAIL, 1, 0.5F);
} else { } else {
player.setAnimation(Animation.ARMS_UP); player.setAnimation(Animation.ARMS_UP, Animation.Recipient.HUMAN);
if (s instanceof HomingSpell homer) { if (s instanceof HomingSpell homer) {
TraceHelper.findEntity(player.asEntity(), homer.getRange(player), 1, EntityPredicates.VALID_ENTITY).ifPresent(homer::setTarget); TraceHelper.findEntity(player.asEntity(), homer.getRange(player), 1, EntityPredicates.VALID_ENTITY).ifPresent(homer::setTarget);
} }
player.playSound(USounds.SPELL_CAST_SUCCESS, 0.05F, 2.2F); player.playSound(USounds.SPELL_CAST_SUCCESS, 0.05F, 2.2F);
} }
} else { } else {
player.setAnimation(Animation.WOLOLO); player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE);
} }
} }
} }

View file

@ -58,7 +58,7 @@ public class UnicornDispellAbility implements Ability<Pos> {
if (player.getSpecies() != Race.CHANGELING) { if (player.getSpecies() != Race.CHANGELING) {
if (type.getTapCount() > 1) { if (type.getTapCount() > 1) {
player.setAnimation(Animation.WOLOLO, 10); player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE, 10);
if (player.getSpellSlot().clear()) { if (player.getSpellSlot().clear()) {
player.asEntity().sendMessage(Text.translatable("gui.unicopia.action.spells_cleared"), true); player.asEntity().sendMessage(Text.translatable("gui.unicopia.action.spells_cleared"), true);
} else { } else {
@ -90,7 +90,7 @@ public class UnicornDispellAbility implements Ability<Pos> {
@Override @Override
public void apply(Pony player, Pos data) { public void apply(Pony player, Pos data) {
player.setAnimation(Animation.WOLOLO); player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE);
Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> { Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
target.getSpellSlot().clear(); target.getSpellSlot().clear();
}); });

View file

@ -43,7 +43,7 @@ public class UnicornProjectileAbility extends AbstractSpellCastingAbility {
if (thrown.getResult() != ActionResult.FAIL) { if (thrown.getResult() != ActionResult.FAIL) {
thrown.getValue().create().toThrowable().throwProjectile(player).ifPresent(projectile -> { thrown.getValue().create().toThrowable().throwProjectile(player).ifPresent(projectile -> {
player.subtractEnergyCost(getCostEstimate(player)); player.subtractEnergyCost(getCostEstimate(player));
player.setAnimation(Animation.ARMS_FORWARD, 2); player.setAnimation(Animation.ARMS_FORWARD, Animation.Recipient.ANYONE, 2);
}); });
} }
} }
@ -62,7 +62,7 @@ public class UnicornProjectileAbility extends AbstractSpellCastingAbility {
spell.toThrowable().throwProjectile(player).ifPresent(projectile -> { spell.toThrowable().throwProjectile(player).ifPresent(projectile -> {
player.subtractEnergyCost(getCostEstimate(player)); player.subtractEnergyCost(getCostEstimate(player));
player.setAnimation(Animation.ARMS_FORWARD); player.setAnimation(Animation.ARMS_FORWARD, Animation.Recipient.ANYONE);
projectile.setHydrophobic(); projectile.setHydrophobic();
if (spell instanceof HomingSpell) { if (spell instanceof HomingSpell) {

View file

@ -6,6 +6,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.command.CommandArgumentEnum;
import net.minecraft.command.argument.EnumArgumentType; import net.minecraft.command.argument.EnumArgumentType;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@ -17,7 +18,7 @@ import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.StringIdentifiable; import net.minecraft.util.StringIdentifiable;
public enum Trait implements StringIdentifiable { public enum Trait implements CommandArgumentEnum<Trait> {
/** /**
* Imparts physical strength or enhances endurance. * Imparts physical strength or enhances endurance.
* Spells with more of the strength trait hit harder and last longer. * Spells with more of the strength trait hit harder and last longer.

View file

@ -51,7 +51,7 @@ public class Main extends MineLPDelegate implements ClientModInitializer {
model.getAttributes().isGoingFast |= pony.getMotion().isRainbooming(); model.getAttributes().isGoingFast |= pony.getMotion().isRainbooming();
model.getAttributes().isGoingFast &= !pony.getEntityInArms().isPresent(); model.getAttributes().isGoingFast &= !pony.getEntityInArms().isPresent();
if (pony.getAnimation() == Animation.SPREAD_WINGS) { if (pony.getAnimation().isOf(Animation.SPREAD_WINGS)) {
model.getAttributes().wingAngle = -AnimationUtil.seeSitSaw(pony.getAnimationProgress(1), 1.5F) * (float)Math.PI / 1.2F; model.getAttributes().wingAngle = -AnimationUtil.seeSitSaw(pony.getAnimationProgress(1), 1.5F) * (float)Math.PI / 1.2F;
model.getAttributes().isFlying = true; model.getAttributes().isFlying = true;
} }

View file

@ -2,8 +2,10 @@ package com.minelittlepony.unicopia.client.render;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
import com.minelittlepony.unicopia.command.CommandArgumentEnum;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.GlassesItem; import com.minelittlepony.unicopia.item.GlassesItem;
import com.minelittlepony.unicopia.util.AnimationUtil; import com.minelittlepony.unicopia.util.AnimationUtil;
@ -30,8 +32,12 @@ public class PlayerPoser {
public void applyPosing(MatrixStack matrices, PlayerEntity player, BipedEntityModel<?> model, Context context) { public void applyPosing(MatrixStack matrices, PlayerEntity player, BipedEntityModel<?> model, Context context) {
Pony pony = Pony.of(player); Pony pony = Pony.of(player);
float progress = pony.getAnimationProgress(MinecraftClient.getInstance().getTickDelta()); float progress = pony.getAnimationProgress(MinecraftClient.getInstance().getTickDelta());
Animation animation = pony.getAnimation(); AnimationInstance animation = pony.getAnimation();
boolean isPony = MineLPDelegate.getInstance().getPlayerPonyRace(player).isEquine(); Race ponyRace = MineLPDelegate.getInstance().getPlayerPonyRace(player);
Arm mainArm = player.getMainArm();
boolean liftLeftArm = mainArm == Arm.LEFT || !ponyRace.isEquine();
boolean liftRightArm = mainArm == Arm.RIGHT || !ponyRace.isEquine();
ItemStack glasses = GlassesItem.getForEntity(player); ItemStack glasses = GlassesItem.getForEntity(player);
@ -43,7 +49,7 @@ public class PlayerPoser {
float beat30 = bop / 30F; float beat30 = bop / 30F;
if (isPony) { if (ponyRace.isEquine()) {
float beat50 = bop / 50F; float beat50 = bop / 50F;
float beat20 = bop / 20F; float beat20 = bop / 20F;
@ -60,7 +66,8 @@ public class PlayerPoser {
} }
} }
switch (animation) { if (animation.canPlay(ponyRace.isEquine())) {
switch (animation.animation()) {
case NECK_SNAP: { case NECK_SNAP: {
head.yaw += 3F; head.yaw += 3F;
head.pitch *= -1; head.pitch *= -1;
@ -70,70 +77,82 @@ public class PlayerPoser {
float roll = MathHelper.sin(player.age / 10F); float roll = MathHelper.sin(player.age / 10F);
float yaw = MathHelper.cos(player.age / 10F); float yaw = MathHelper.cos(player.age / 10F);
model.leftArm.pitch += -1; if (liftLeftArm) {
model.rightArm.pitch += -1; rotateArm(model.leftArm, 1, yaw, -roll);
}
model.leftArm.roll = -roll; if (liftRightArm) {
model.rightArm.roll = roll; rotateArm(model.leftArm, 1, yaw, roll);
}
model.leftArm.yaw = yaw;
model.rightArm.yaw = yaw;
break; break;
} }
case ARMS_FORWARD: { case ARMS_FORWARD: {
float roll = (progress + 1) / 2F; float roll = (progress + 1) / 2F;
float pitch = 1.5F * roll; float pitch = 1.5F * roll;
float yaw = 0.5F * roll; float yaw = -0.5F * roll;
model.leftArm.pitch -= pitch; if (liftLeftArm) {
model.rightArm.pitch -= pitch; rotateArm(model.leftArm, pitch, -yaw, 0);
}
model.leftArm.roll = 0; if (liftRightArm) {
model.rightArm.roll = 0; rotateArm(model.rightArm, pitch, yaw, 0);
}
model.leftArm.yaw = yaw;
model.rightArm.yaw = -yaw;
break; break;
} }
case ARMS_UP: { case ARMS_UP: {
float roll = (progress + 1) / 2F; float saw = AnimationUtil.seesaw(progress);
float pitch = 3F * roll; float pitch = 3F * saw;
float yaw = 0.5F * roll; float yaw = 0.5F * saw;
float roll = saw;
model.leftArm.pitch -= pitch; if (ponyRace.isEquine()) {
model.rightArm.pitch -= pitch; rearUp(matrices, model, saw);
pitch = roll * 2F;
model.head.pitch += saw * 0.5F;
}
model.leftArm.roll = 0; if (liftLeftArm) {
model.rightArm.roll = 0; rotateArm(model.leftArm, pitch, -yaw, yaw);
} else if (ponyRace.isEquine()) {
model.leftArm.pitch += saw / 4F;
model.leftArm.roll -= saw / 4F;
}
if (liftRightArm) {
rotateArm(model.rightArm, pitch, yaw, -yaw);
} else if (ponyRace.isEquine()) {
model.rightArm.pitch += saw / 4F;
model.rightArm.roll += saw / 4F;
}
model.leftArm.yaw = yaw;
model.rightArm.yaw = -yaw;
break; break;
} }
case WAVE_ONE: case WAVE_ONE:
case WAVE_TWO: { case WAVE_TWO: {
progress = AnimationUtil.seesaw(progress); progress = AnimationUtil.seesaw(progress);
if (animation == Animation.WAVE_TWO && isPony) { if (animation.isOf(Animation.WAVE_TWO) && ponyRace.isEquine()) {
rearUp(matrices, model, progress); rearUp(matrices, model, progress);
model.head.pitch += progress; model.head.pitch += progress * 0.5F;
model.hat.pitch += progress;
} }
float wave = 2.5F + progress * MathHelper.sin(player.age / 3F); float wave = 2.5F + progress * MathHelper.sin(player.age / 3F);
if (animation == Animation.WAVE_TWO || player.getMainArm() == Arm.LEFT) { if (animation.isOf(Animation.WAVE_TWO) || mainArm == Arm.LEFT) {
model.leftArm.roll = -wave; model.leftArm.roll = -wave;
} }
if (animation == Animation.WAVE_TWO || player.getMainArm() == Arm.RIGHT) { if (animation.isOf(Animation.WAVE_TWO) || mainArm == Arm.RIGHT) {
model.rightArm.roll = wave; model.rightArm.roll = wave;
} }
break; break;
} }
case KICK: { case KICK: {
if (isPony) { if (ponyRace.isEquine()) {
float roll = (progress + 1) / 2F; float roll = (progress + 1) / 2F;
model.rightLeg.pitch = roll * 1.5F; model.rightLeg.pitch = roll * 1.5F;
@ -143,9 +162,9 @@ public class PlayerPoser {
model.leftLeg.yaw = roll / 7F; model.leftLeg.yaw = roll / 7F;
model.leftArm.pitch = 0; model.leftArm.pitch = 0;
model.leftArm.roll = -roll / 7F; model.leftArm.roll = MathHelper.lerp(progress, model.leftArm.roll, 0);
model.rightArm.pitch = 0; model.rightArm.pitch = 0;
model.rightArm.roll = roll / 7F; model.rightArm.roll = MathHelper.lerp(progress, model.rightArm.roll, 0);
break; break;
} }
@ -167,8 +186,8 @@ public class PlayerPoser {
case STOMP: { case STOMP: {
progress = AnimationUtil.seesaw(progress); progress = AnimationUtil.seesaw(progress);
if (!isPony) { if (!ponyRace.isEquine()) {
if (player.getMainArm() == Arm.LEFT) { if (mainArm == Arm.LEFT) {
model.rightLeg.roll = -progress / 9F; model.rightLeg.roll = -progress / 9F;
model.rightLeg.pivotY -= progress * 5; model.rightLeg.pivotY -= progress * 5;
} else { } else {
@ -179,10 +198,13 @@ public class PlayerPoser {
} }
rearUp(matrices, model, progress); rearUp(matrices, model, progress);
model.head.pitch += progress * 0.5F;
model.leftArm.pitch += progress / 2F;
model.rightArm.pitch += progress / 2F;
break; break;
} }
case WIGGLE_NOSE: { case WIGGLE_NOSE: {
if (!isPony) { if (!ponyRace.isEquine()) {
break; break;
} }
@ -194,9 +216,10 @@ public class PlayerPoser {
} }
default: default:
} }
}
if (pony.getEntityInArms().isPresent()) { if (pony.getEntityInArms().isPresent()) {
if (isPony && pony.getPhysics().isFlying()) { if (ponyRace.isEquine() && pony.getPhysics().isFlying()) {
model.leftLeg.pitch = 1; model.leftLeg.pitch = 1;
model.rightLeg.pitch = 1; model.rightLeg.pitch = 1;
model.leftLeg.yaw = 0.3F; model.leftLeg.yaw = 0.3F;
@ -220,6 +243,12 @@ public class PlayerPoser {
model.hat.copyTransform(model.head); model.hat.copyTransform(model.head);
} }
private void rotateArm(ModelPart arm, float pitch, float yaw, float roll) {
arm.pitch -= pitch;
arm.roll = roll;
arm.yaw = yaw;
}
private void rearUp(MatrixStack matrices, BipedEntityModel<?> model, float progress) { private void rearUp(MatrixStack matrices, BipedEntityModel<?> model, float progress) {
matrices.translate(0, 0, 0.5); matrices.translate(0, 0, 0.5);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-45 * progress)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-45 * progress));
@ -234,7 +263,19 @@ public class PlayerPoser {
model.leftLeg.yaw = roll / 7F; model.leftLeg.yaw = roll / 7F;
} }
public enum Animation implements StringIdentifiable { public record AnimationInstance(Animation animation, Animation.Recipient recipient) {
public static final AnimationInstance NONE = new AnimationInstance(Animation.NONE, Animation.Recipient.ANYONE);
public boolean isOf(Animation animation) {
return animation() == animation;
}
public boolean canPlay(boolean isPony) {
return !isOf(Animation.NONE) && (recipient == Animation.Recipient.ANYONE || isPony == (recipient == Animation.Recipient.PONY));
}
}
public enum Animation implements CommandArgumentEnum<Animation> {
NONE(0), NONE(0),
WOLOLO(USounds.ENTITY_PLAYER_WOLOLO, 40), WOLOLO(USounds.ENTITY_PLAYER_WOLOLO, 40),
ARMS_FORWARD(5), ARMS_FORWARD(5),
@ -268,11 +309,6 @@ public class PlayerPoser {
return sound; return sound;
} }
@Override
public String asString() {
return name();
}
public static EnumArgumentType<Animation> argument() { public static EnumArgumentType<Animation> argument() {
return new ArgumentType(); return new ArgumentType();
} }
@ -286,6 +322,24 @@ public class PlayerPoser {
} }
} }
public enum Recipient implements CommandArgumentEnum<Recipient> {
HUMAN,
PONY,
ANYONE;
public static EnumArgumentType<Recipient> argument() {
return new ArgumentType();
}
public static final class ArgumentType extends EnumArgumentType<Recipient> {
@SuppressWarnings("deprecation")
static final Codec<Recipient> CODEC = StringIdentifiable.createCodec(Recipient::values);
protected ArgumentType() {
super(CODEC, Recipient::values);
}
}
}
} }
public enum Context { public enum Context {

View file

@ -0,0 +1,16 @@
package com.minelittlepony.unicopia.command;
import net.minecraft.util.StringIdentifiable;
public interface CommandArgumentEnum<T extends Enum<T> & CommandArgumentEnum<T>> extends StringIdentifiable {
@SuppressWarnings("unchecked")
default T asSelf() {
return (T)this;
}
@Override
default String asString() {
return asSelf().name();
}
}

View file

@ -16,6 +16,7 @@ public class Commands {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void bootstrap() { public static void bootstrap() {
ArgumentTypeRegistry.registerArgumentType(Unicopia.id("animation"), Animation.ArgumentType.class, ConstantArgumentSerializer.of(Animation::argument)); ArgumentTypeRegistry.registerArgumentType(Unicopia.id("animation"), Animation.ArgumentType.class, ConstantArgumentSerializer.of(Animation::argument));
ArgumentTypeRegistry.registerArgumentType(Unicopia.id("animation_recipient"), Animation.Recipient.ArgumentType.class, ConstantArgumentSerializer.of(Animation.Recipient::argument));
ArgumentTypeRegistry.registerArgumentType(Unicopia.id("mana_type"), ManaType.ArgumentType.class, ConstantArgumentSerializer.of(ManaType::argument)); ArgumentTypeRegistry.registerArgumentType(Unicopia.id("mana_type"), ManaType.ArgumentType.class, ConstantArgumentSerializer.of(ManaType::argument));
ArgumentTypeRegistry.registerArgumentType(Unicopia.id("trait_type"), Trait.ArgumentType.class, ConstantArgumentSerializer.of(Trait::argument)); ArgumentTypeRegistry.registerArgumentType(Unicopia.id("trait_type"), Trait.ArgumentType.class, ConstantArgumentSerializer.of(Trait::argument));
ArgumentTypeRegistry.registerArgumentType(Unicopia.id("spell_traits"), TraitsArgumentType.class, ConstantArgumentSerializer.of(TraitsArgumentType::traits)); ArgumentTypeRegistry.registerArgumentType(Unicopia.id("spell_traits"), TraitsArgumentType.class, ConstantArgumentSerializer.of(TraitsArgumentType::traits));

View file

@ -15,23 +15,31 @@ public class EmoteCommand {
.literal("emote") .literal("emote")
.then(CommandManager.argument("animation", Animation.argument()).executes(source -> apply( .then(CommandManager.argument("animation", Animation.argument()).executes(source -> apply(
source.getSource(), source.getSource(),
source.getArgument("animation", Animation.class) source.getArgument("animation", Animation.class),
Animation.Recipient.ANYONE
) )
).then(CommandManager.argument("duration", IntegerArgumentType.integer(1, 99)).executes(source -> apply( ).then(CommandManager.argument("duration", IntegerArgumentType.integer(1, 99)).executes(source -> apply(
source.getSource(), source.getSource(),
source.getArgument("animation", Animation.class), source.getArgument("animation", Animation.class),
source.getArgument("duration", Integer.class) Animation.Recipient.ANYONE,
IntegerArgumentType.getInteger(source, "duration")
) )
).then(CommandManager.argument("recipient_type", Animation.Recipient.argument()).executes(source -> apply(
source.getSource(),
source.getArgument("animation", Animation.class),
source.getArgument("recipient_type", Animation.Recipient.class),
IntegerArgumentType.getInteger(source, "duration")
) )
))
))); )));
} }
static int apply(ServerCommandSource source, Animation animation) throws CommandSyntaxException { static int apply(ServerCommandSource source, Animation animation, Animation.Recipient recipient) throws CommandSyntaxException {
return apply(source, animation, animation.getDuration()); return apply(source, animation, recipient, animation.getDuration());
} }
static int apply(ServerCommandSource source, Animation animation, int duration) throws CommandSyntaxException { static int apply(ServerCommandSource source, Animation animation, Animation.Recipient recipient, int duration) throws CommandSyntaxException {
Pony.of(source.getPlayer()).setAnimation(animation, duration); Pony.of(source.getPlayer()).setAnimation(animation, recipient, duration);
return 0; return 0;
} }
} }

View file

@ -44,7 +44,7 @@ public class ManaCommand {
); );
} }
enum ManaType implements StringIdentifiable { enum ManaType implements CommandArgumentEnum<ManaType> {
EXERTION(MagicReserves::getExertion), EXERTION(MagicReserves::getExertion),
EXHAUSTION(MagicReserves::getExhaustion), EXHAUSTION(MagicReserves::getExhaustion),
ENERGY(MagicReserves::getEnergy), ENERGY(MagicReserves::getEnergy),
@ -61,11 +61,6 @@ public class ManaCommand {
return getter.apply(reserves); return getter.apply(reserves);
} }
@Override
public String asString() {
return name();
}
public static EnumArgumentType<ManaType> argument() { public static EnumArgumentType<ManaType> argument() {
return new ArgumentType(); return new ArgumentType();
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.entity.player; package com.minelittlepony.unicopia.entity.player;
import java.util.function.Supplier;
import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
@ -120,7 +122,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
@Override @Override
public float getWingAngle() { public float getWingAngle() {
if (pony.getAnimation() == Animation.SPREAD_WINGS) { if (pony.getAnimation().isOf(Animation.SPREAD_WINGS)) {
return AnimationUtil.seeSitSaw(pony.getAnimationProgress(1), 1.5F); return AnimationUtil.seeSitSaw(pony.getAnimationProgress(1), 1.5F);
} }
@ -485,6 +487,14 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
isFlyingSurvival = true; isFlyingSurvival = true;
thrustScale = 0; thrustScale = 0;
entity.calculateDimensions(); entity.calculateDimensions();
if (entity.isOnGround() || !force) {
Supplier<Vec3d> vec = VecHelper.sphere(pony.asWorld().getRandom(), 0.5D);
pony.spawnParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, vec, vec, 5);
pony.spawnParticles(ParticleTypes.CLOUD, vec, vec, 5);
}
} }
private void handleWallCollission(MutableVector velocity) { private void handleWallCollission(MutableVector velocity) {

View file

@ -6,6 +6,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.client.render.PlayerPoser.AnimationInstance;
import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.*; import com.minelittlepony.unicopia.ability.*;
import com.minelittlepony.unicopia.ability.magic.*; import com.minelittlepony.unicopia.ability.magic.*;
@ -100,7 +101,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
private boolean hasShades; private boolean hasShades;
private int ticksSunImmunity = INITIAL_SUN_IMMUNITY; private int ticksSunImmunity = INITIAL_SUN_IMMUNITY;
private Animation animation = Animation.NONE; private AnimationInstance animation = new AnimationInstance(Animation.NONE, Animation.Recipient.ANYONE);
private int animationMaxDuration; private int animationMaxDuration;
private int animationDuration; private int animationDuration;
@ -124,34 +125,53 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
builder.add(UEntityAttributes.ENTITY_GRAVTY_MODIFIER); builder.add(UEntityAttributes.ENTITY_GRAVTY_MODIFIER);
} }
@Deprecated
public void setAnimation(Animation animation) { public void setAnimation(Animation animation) {
setAnimation(animation, animation.getDuration()); setAnimation(new AnimationInstance(animation, Animation.Recipient.ANYONE));
} }
@Deprecated
public void setAnimation(Animation animation, int duration) { public void setAnimation(Animation animation, int duration) {
if (animation != this.animation && duration != animationDuration) { setAnimation(new AnimationInstance(animation, Animation.Recipient.ANYONE));
}
public void setAnimation(Animation animation, Animation.Recipient recipient) {
setAnimation(new AnimationInstance(animation, recipient), animation.getDuration());
}
public void setAnimation(Animation animation, Animation.Recipient recipient, int duration) {
setAnimation(new AnimationInstance(animation, recipient), duration);
}
public void setAnimation(AnimationInstance animation) {
setAnimation(animation, animation.animation().getDuration());
}
public void setAnimation(AnimationInstance animation, int duration) {
if (!animation.equals(this.animation) || duration != animationDuration) {
this.animation = animation; this.animation = animation;
this.animationDuration = animation == Animation.NONE ? 0 : Math.max(0, duration); this.animationDuration = animation.isOf(Animation.NONE) ? 0 : Math.max(0, duration);
this.animationMaxDuration = animationDuration; this.animationMaxDuration = animationDuration;
if (!isClient()) { if (!isClient()) {
Channel.SERVER_PLAYER_ANIMATION_CHANGE.sendToAllPlayers(new MsgPlayerAnimationChange(this, animation, animationDuration), asWorld()); Channel.SERVER_PLAYER_ANIMATION_CHANGE.sendToAllPlayers(new MsgPlayerAnimationChange(this, animation, animationDuration), asWorld());
} }
animation.getSound().ifPresent(sound -> { animation.animation().getSound().ifPresent(sound -> {
playSound(sound, sound == USounds.ENTITY_PLAYER_WOLOLO ? 0.1F : 0.9F, 1); playSound(sound, sound == USounds.ENTITY_PLAYER_WOLOLO ? 0.1F : 0.9F, 1);
}); });
} }
} }
public Animation getAnimation() { public AnimationInstance getAnimation() {
return animation; return animation;
} }
public float getAnimationProgress(float delta) { public float getAnimationProgress(float delta) {
if (animation == Animation.NONE) { if (animation.isOf(Animation.NONE)) {
return 0; return 0;
} }
System.out.println(animationMaxDuration);
return 1 - (((float)animationDuration) / animationMaxDuration); return 1 - (((float)animationDuration) / animationMaxDuration);
} }
@ -378,8 +398,8 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
} }
private void updateAnimations() { private void updateAnimations() {
if (animationDuration >= 0 && --animationDuration <= 0) { if (animationDuration > 0 && --animationDuration <= 0) {
setAnimation(Animation.NONE); setAnimation(AnimationInstance.NONE);
} }
} }

View file

@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.CastSpellEntity; import com.minelittlepony.unicopia.entity.CastSpellEntity;
import com.minelittlepony.unicopia.entity.UEntities; import com.minelittlepony.unicopia.entity.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -131,6 +132,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch
pony.subtractEnergyCost(4); pony.subtractEnergyCost(4);
stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND)); stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND));
getSpellEffect(stack).create().toThrowable().throwProjectile(pony); getSpellEffect(stack).create().toThrowable().throwProjectile(pony);
pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10);
}); });
ChargeableItem.consumeEnergy(stack, 1); ChargeableItem.consumeEnergy(stack, 1);
} else if (i > 5) { } else if (i > 5) {
@ -138,6 +140,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch
pony.subtractEnergyCost(4); pony.subtractEnergyCost(4);
stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND)); stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND));
getSpellEffect(stack).create().toThrowable().throwProjectile(pony); getSpellEffect(stack).create().toThrowable().throwProjectile(pony);
pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10);
}); });
ChargeableItem.consumeEnergy(stack, 1); ChargeableItem.consumeEnergy(stack, 1);
} }

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.network;
import java.util.UUID; import java.util.UUID;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.client.render.PlayerPoser.AnimationInstance;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.sollace.fabwork.api.packets.HandledPacket; import com.sollace.fabwork.api.packets.HandledPacket;
@ -15,22 +16,23 @@ import net.minecraft.network.PacketByteBuf;
*/ */
public record MsgPlayerAnimationChange ( public record MsgPlayerAnimationChange (
UUID playerId, UUID playerId,
Animation animation, AnimationInstance animation,
int duration int duration
) implements HandledPacket<PlayerEntity> { ) implements HandledPacket<PlayerEntity> {
MsgPlayerAnimationChange(PacketByteBuf buffer) { MsgPlayerAnimationChange(PacketByteBuf buffer) {
this(buffer.readUuid(), buffer.readEnumConstant(Animation.class), buffer.readInt()); this(buffer.readUuid(), new AnimationInstance(buffer.readEnumConstant(Animation.class), buffer.readEnumConstant(Animation.Recipient.class)), buffer.readInt());
} }
public MsgPlayerAnimationChange(Pony player, Animation animation, int duration) { public MsgPlayerAnimationChange(Pony player, AnimationInstance animation, int duration) {
this(player.asEntity().getUuid(), animation, duration); this(player.asEntity().getUuid(), animation, duration);
} }
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeUuid(playerId); buffer.writeUuid(playerId);
buffer.writeEnumConstant(animation); buffer.writeEnumConstant(animation.animation());
buffer.writeEnumConstant(animation.recipient());
buffer.writeInt(duration); buffer.writeInt(duration);
} }

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.particle; package com.minelittlepony.unicopia.particle;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import com.minelittlepony.unicopia.EntityConvertable; import com.minelittlepony.unicopia.EntityConvertable;
import com.minelittlepony.unicopia.util.shape.PointGenerator; import com.minelittlepony.unicopia.util.shape.PointGenerator;
@ -11,6 +12,16 @@ import net.minecraft.util.math.Vec3d;
public interface ParticleSource<E extends Entity> extends ParticleSpawner, EntityConvertable<E> { public interface ParticleSource<E extends Entity> extends ParticleSpawner, EntityConvertable<E> {
default void spawnParticles(ParticleEffect particleId, Supplier<Vec3d> posSupplier, Supplier<Vec3d> velSupplier, int count) {
for (int i = 0; i < count; i++) {
spawnParticle(particleId, posSupplier, velSupplier);
}
}
default void spawnParticle(ParticleEffect particleId, Supplier<Vec3d> posSupplier, Supplier<Vec3d> velSupplier) {
addParticle(particleId, getOriginVector().add(posSupplier.get()), velSupplier.get());
}
default void spawnParticles(ParticleEffect particleId, int count) { default void spawnParticles(ParticleEffect particleId, int count) {
ParticleUtils.spawnParticles(particleId, asEntity(), count); ParticleUtils.spawnParticles(particleId, asEntity(), count);
} }

View file

@ -3,11 +3,14 @@ package com.minelittlepony.unicopia.util;
import java.util.List; import java.util.List;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.Box; import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.EntityView; import net.minecraft.world.EntityView;
public interface VecHelper { public interface VecHelper {
@ -20,6 +23,18 @@ public interface VecHelper {
return new Vec3d(rng.getAsDouble(), rng.getAsDouble(), rng.getAsDouble()); return new Vec3d(rng.getAsDouble(), rng.getAsDouble(), rng.getAsDouble());
} }
static Supplier<Vec3d> supplier(DoubleSupplier rng) {
return () -> supply(rng);
}
static Supplier<Vec3d> sphere(Random rng) {
return sphere(rng, 1);
}
static Supplier<Vec3d> sphere(Random rng, double radius) {
return supplier(() -> (rng.nextGaussian() - 0.5) * radius);
}
static Predicate<Entity> inRange(Vec3d center, double range) { static Predicate<Entity> inRange(Vec3d center, double range) {
double rad = Math.pow(range, 2); double rad = Math.pow(range, 2);
return e -> { return e -> {