From 0d0ea4558d4defd3da2699b23487eeecf680101d Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 8 Nov 2023 12:58:31 +0000 Subject: [PATCH] Added hippogriffs and seaponies --- .../minelittlepony/unicopia/Availability.java | 15 ++ .../unicopia/EquinePredicates.java | 1 + .../com/minelittlepony/unicopia/Race.java | 40 ++--- .../com/minelittlepony/unicopia/USounds.java | 2 + .../unicopia/ability/Abilities.java | 9 +- .../unicopia/ability/BatEeeeAbility.java | 106 +----------- .../unicopia/ability/FlyingDashAbility.java | 76 +++++++++ .../unicopia/ability/PeckAbility.java | 152 ++++++++++++++++++ .../unicopia/ability/ScreechAbility.java | 141 ++++++++++++++++ ...eAbility.java => ToggleFlightAbility.java} | 2 +- .../unicopia/client/gui/HudEffects.java | 61 +++++++ .../client/gui/TribeSelectionScreen.java | 2 +- .../client/minelittlepony/BodyPartGear.java | 3 +- .../unicopia/client/minelittlepony/Main.java | 4 +- .../client/render/ModelPartHooks.java | 4 - .../client/render/SmittenEyesRenderer.java | 5 - .../client/render/WingsFeatureRenderer.java | 3 +- .../client/render/WorldRenderDelegate.java | 37 +++++ .../unicopia/command/SpeciesCommand.java | 9 +- .../unicopia/entity/AmuletSelectors.java | 1 + .../unicopia/entity/duck/EntityDuck.java | 6 + .../entity/effect/RaceChangeStatusEffect.java | 1 + .../unicopia/entity/effect/UPotions.java | 2 + .../unicopia/entity/player/Acrobatics.java | 19 +++ .../entity/player/PlayerAttributes.java | 15 +- .../unicopia/entity/player/PlayerCamera.java | 16 ++ .../unicopia/entity/player/PlayerPhysics.java | 6 +- .../unicopia/entity/player/Pony.java | 40 +++++ .../minelittlepony/unicopia/item/UItems.java | 4 + .../unicopia/item/toxin/Toxics.java | 9 ++ .../mixin/MixinEnchantmentHelper.java | 25 +++ .../unicopia/mixin/MixinEntity.java | 8 + .../unicopia/mixin/MixinPlayerEntity.java | 17 ++ .../unicopia/mixin/MixinPufferfishEntity.java | 25 +++ .../unicopia/mixin/client/MixinCamera.java | 8 + .../unicopia/mixin/client/MixinInGameHud.java | 22 +-- .../mixin/client/MixinKeyboardInput.java | 5 + .../unicopia/mixin/client/MixinModelPart.java | 2 +- .../resources/assets/unicopia/lang/en_us.json | 33 +++- .../models/item/hippogriff_badge.json | 6 + .../unicopia/models/item/pearl_necklace.json | 6 + .../resources/assets/unicopia/sounds.json | 7 + .../unicopia/sounds/screech/screech0.ogg | Bin 0 -> 39055 bytes .../unicopia/textures/gui/ability/dash.png | Bin 0 -> 7125 bytes .../textures/gui/ability/dash_old.png | Bin 0 -> 8759 bytes .../unicopia/textures/gui/ability/peck.png | Bin 0 -> 7346 bytes .../unicopia/textures/gui/ability/screech.png | Bin 0 -> 7220 bytes .../ability/toggle_flight_land_hippogriff.png | Bin 0 -> 7240 bytes .../toggle_flight_takeoff_hippogriff.png | Bin 0 -> 8117 bytes .../unicopia/textures/gui/race/hippogriff.png | Bin 0 -> 6551 bytes .../textures/item/hippogriff_badge.png | Bin 0 -> 6551 bytes .../unicopia/textures/item/pearl_necklace.png | Bin 0 -> 6551 bytes .../trinkets/tags/items/chest/necklace.json | 3 +- src/main/resources/unicopia.mixin.json | 2 + 54 files changed, 792 insertions(+), 168 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/Availability.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java rename src/main/java/com/minelittlepony/unicopia/ability/{PegasusFlightToggleAbility.java => ToggleFlightAbility.java} (97%) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java create mode 100644 src/main/resources/assets/unicopia/models/item/hippogriff_badge.json create mode 100644 src/main/resources/assets/unicopia/models/item/pearl_necklace.json create mode 100644 src/main/resources/assets/unicopia/sounds/screech/screech0.ogg create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/dash.png create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/dash_old.png create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/peck.png create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/screech.png create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/toggle_flight_land_hippogriff.png create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/toggle_flight_takeoff_hippogriff.png create mode 100644 src/main/resources/assets/unicopia/textures/gui/race/hippogriff.png create mode 100644 src/main/resources/assets/unicopia/textures/item/hippogriff_badge.png create mode 100644 src/main/resources/assets/unicopia/textures/item/pearl_necklace.png diff --git a/src/main/java/com/minelittlepony/unicopia/Availability.java b/src/main/java/com/minelittlepony/unicopia/Availability.java new file mode 100644 index 00000000..f24497a3 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/Availability.java @@ -0,0 +1,15 @@ +package com.minelittlepony.unicopia; + +public enum Availability { + DEFAULT, + COMMANDS, + NONE; + + public boolean isSelectable() { + return this == DEFAULT; + } + + public boolean isGrantable() { + return this != NONE; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java index 0771db9d..be559b38 100644 --- a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java +++ b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java @@ -27,6 +27,7 @@ public interface EquinePredicates { Predicate PLAYER_CHANGELING = IS_PLAYER.and(ofRace(Race.CHANGELING)); Predicate PLAYER_KIRIN = IS_PLAYER.and(ofRace(Race.KIRIN)); Predicate PLAYER_PEGASUS = IS_PLAYER.and(e -> ((PlayerEntity)e).getAbilities().creativeMode || RACE_INTERACT_WITH_CLOUDS.test(e)); + Predicate PLAYER_SEAPONY = IS_PLAYER.and(raceMatches(Race::isFish)); Predicate PLAYER_CAN_USE_EARTH = IS_PLAYER.and(raceMatches(Race::canUseEarth)); Predicate IS_CASTER = e -> !e.isRemoved() && (e instanceof Caster || IS_PLAYER.test(e)); diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index e45fec10..1a214161 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -24,18 +24,18 @@ import net.minecraft.util.Identifier; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; -public record Race (Supplier compositeSupplier, boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal, boolean canHang) implements Affine { +public record Race (Supplier compositeSupplier, Availability availability, boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal, boolean canHang) implements Affine { public static final String DEFAULT_ID = "unicopia:unset"; public static final Registry REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID); public static final RegistryKey> REGISTRY_KEY = REGISTRY.getKey(); private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("race.unknown", id)); - public static Race register(String name, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { - return register(Unicopia.id(name), magic, flight, earth, nocturnal, canHang); + public static Race register(String name, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { + return register(Unicopia.id(name), availability, magic, flight, earth, nocturnal, canHang); } - public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { - return Registry.register(REGISTRY, id, new Race(Suppliers.memoize(() -> new Composite(REGISTRY.get(id), null)), magic, flight, earth, nocturnal, canHang)); + public static Race register(Identifier id, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { + return Registry.register(REGISTRY, id, new Race(Suppliers.memoize(() -> new Composite(REGISTRY.get(id), null)), availability, magic, flight, earth, nocturnal, canHang)); } public static RegistryKeyArgumentType argument() { @@ -46,15 +46,17 @@ public record Race (Supplier compositeSupplier, boolean canCast, Flig * The default, unset race. * This is used if there are no other races. */ - public static final Race UNSET = register("unset", false, FlightType.NONE, false, false, false); - public static final Race HUMAN = register("human", false, FlightType.NONE, false, false, false); - public static final Race EARTH = register("earth", false, FlightType.NONE, true, false, false); - public static final Race UNICORN = register("unicorn", true, FlightType.NONE, false, false, false); - public static final Race PEGASUS = register("pegasus", false, FlightType.AVIAN, false, false, false); - public static final Race BAT = register("bat", false, FlightType.AVIAN, false, true, true); - public static final Race ALICORN = register("alicorn", true, FlightType.AVIAN, true, false, false); - public static final Race CHANGELING = register("changeling", false, FlightType.INSECTOID, false, false, true); - public static final Race KIRIN = register("kirin", true, FlightType.NONE, false, false, false); + public static final Race UNSET = register("unset", Availability.COMMANDS, false, FlightType.NONE, false, false, false); + public static final Race HUMAN = register("human", Availability.COMMANDS, false, FlightType.NONE, false, false, false); + public static final Race EARTH = register("earth", Availability.DEFAULT, false, FlightType.NONE, true, false, false); + public static final Race UNICORN = register("unicorn", Availability.DEFAULT, true, FlightType.NONE, false, false, false); + public static final Race PEGASUS = register("pegasus", Availability.DEFAULT, false, FlightType.AVIAN, false, false, false); + public static final Race BAT = register("bat", Availability.DEFAULT, false, FlightType.AVIAN, false, true, true); + public static final Race ALICORN = register("alicorn", Availability.COMMANDS, true, FlightType.AVIAN, true, false, false); + public static final Race CHANGELING = register("changeling", Availability.DEFAULT, false, FlightType.INSECTOID, false, false, true); + public static final Race KIRIN = register("kirin", Availability.DEFAULT, true, FlightType.NONE, false, false, false); + public static final Race HIPPOGRIFF = register("hippogriff", Availability.DEFAULT, false, FlightType.AVIAN, false, false, false); + public static final Race SEAPONY = register("seapony", Availability.NONE, false, FlightType.NONE, false, false, false); public static void bootstrap() {} @@ -83,6 +85,10 @@ public record Race (Supplier compositeSupplier, boolean canCast, Flig return !isHuman(); } + public boolean isFish() { + return this == SEAPONY; + } + public boolean isHuman() { return this == UNSET || this == HUMAN; } @@ -91,16 +97,12 @@ public record Race (Supplier compositeSupplier, boolean canCast, Flig return !isNocturnal(); } - public boolean isOp() { - return this == ALICORN; - } - public boolean canFly() { return !flightType().isGrounded(); } public boolean canInteractWithClouds() { - return canFly() && this != CHANGELING && this != BAT; + return canFly() && this != CHANGELING && this != BAT && this != HIPPOGRIFF; } public Identifier getId() { diff --git a/src/main/java/com/minelittlepony/unicopia/USounds.java b/src/main/java/com/minelittlepony/unicopia/USounds.java index 34d9beff..ec580e36 100644 --- a/src/main/java/com/minelittlepony/unicopia/USounds.java +++ b/src/main/java/com/minelittlepony/unicopia/USounds.java @@ -14,6 +14,8 @@ public interface USounds { SoundEvent ENTITY_PLAYER_CORRUPTION = PARTICLE_SOUL_ESCAPE; SoundEvent ENTITY_PLAYER_BATPONY_SCREECH = register("entity.player.batpony.screech"); + SoundEvent ENTITY_PLAYER_HIPPOGRIFF_SCREECH = register("entity.player.hippogriff.screech"); + SoundEvent ENTITY_PLAYER_HIPPOGRIFF_PECK = ENTITY_CHICKEN_STEP; SoundEvent ENTITY_PLAYER_REBOUND = register("entity.player.rebound"); SoundEvent ENTITY_PLAYER_PEGASUS_WINGSFLAP = register("entity.player.pegasus.wingsflap"); SoundEvent ENTITY_PLAYER_PEGASUS_FLYING = register("entity.player.pegasus.flying"); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java index 9dd0d724..f0964765 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java @@ -42,9 +42,14 @@ public interface Abilities { Ability RAINBOOM = register(new PegasusRainboomAbility(), "rainboom", AbilitySlot.PRIMARY); Ability CAPTURE_CLOUD = register(new PegasusCaptureStormAbility(), "capture_cloud", AbilitySlot.SECONDARY); - // pegasus / bat / alicorn / changeling + // hippogriff + Ability DASH = register(new FlyingDashAbility(), "dash", AbilitySlot.PRIMARY); + Ability SCREECH = register(new ScreechAbility(), "screech", AbilitySlot.SECONDARY); + Ability PECK = register(new PeckAbility(), "peck", AbilitySlot.SECONDARY); + + // pegasus / bat / alicorn / changeling / hippogriff Ability CARRY = register(new CarryAbility(), "carry", AbilitySlot.PRIMARY); - Ability TOGGLE_FLIGHT = register(new PegasusFlightToggleAbility(), "toggle_flight", AbilitySlot.TERTIARY); + Ability TOGGLE_FLIGHT = register(new ToggleFlightAbility(), "toggle_flight", AbilitySlot.TERTIARY); // changeling Ability DISGUISE = register(new ChangelingDisguiseAbility(), "disguise", AbilitySlot.SECONDARY); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java index f2ad4e28..867f67ae 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java @@ -1,55 +1,20 @@ package com.minelittlepony.unicopia.ability; -import java.util.Optional; - import com.minelittlepony.unicopia.AwaitTickQueue; -import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; -import com.minelittlepony.unicopia.UTags; -import com.minelittlepony.unicopia.ability.data.Numeric; -import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.advancement.UCriteria; -import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; -import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.util.RegistryUtils; -import com.minelittlepony.unicopia.util.VecHelper; -import net.minecraft.entity.LivingEntity; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; +import net.minecraft.world.event.GameEvent; /** - * A magic casting ability for unicorns. - * (only shields for now) + * An ability to screeeeeeeeEeEeEeeee! */ -public class BatEeeeAbility implements Ability { +public class BatEeeeAbility extends ScreechAbility { public static final int SELF_SPOOK_PROBABILITY = 20000; - public static final int MOB_SPOOK_PROBABILITY = 1000; - - @Override - public int getWarmupTime(Pony player) { - return 30; - } - - @Override - public int getCooldownTime(Pony player) { - return 5; - } - - @Override - public double getCostEstimate(Pony player) { - return 0; - } - - @Override - public boolean activateOnEarlyRelease() { - return true; - } @Override public boolean canUse(Race race) { @@ -57,22 +22,7 @@ public class BatEeeeAbility implements Ability { } @Override - public Optional prepare(Pony player) { - return player.getAbilities().getActiveStat() - .map(stat -> (int)(stat.getWarmup() * getWarmupTime(player))) - .filter(i -> i >= 0) - .map(Numeric::new); - } - - @Override - public Numeric.Serializer getSerializer() { - return Numeric.SERIALIZER; - } - - @Override - public boolean apply(Pony player, Numeric data) { - float strength = 1 - MathHelper.clamp(data.type() / (float)getWarmupTime(player), 0, 1); - Random rng = player.asWorld().random; + protected void playSounds(Pony player, Random rng, float strength) { int count = 1 + rng.nextInt(10) + (int)(strength * 10); for (int i = 0; i < count; i++) { @@ -81,6 +31,7 @@ public class BatEeeeAbility implements Ability { 1.6F + (rng.nextFloat() - 0.5F) ); } + player.asWorld().emitGameEvent(player.asEntity(), GameEvent.ENTITY_ROAR, player.asEntity().getEyePos()); for (int j = 0; j < (int)(strength * 2); j++) { for (int k = 0; k < count; k++) { AwaitTickQueue.scheduleTask(player.asWorld(), w -> { @@ -88,59 +39,14 @@ public class BatEeeeAbility implements Ability { (0.9F + (rng.nextFloat() - 0.5F) / 2F) * strength, 1.6F + (rng.nextFloat() - 0.5F) ); + player.asWorld().emitGameEvent(player.asEntity(), GameEvent.ENTITY_ROAR, player.asEntity().getEyePos()); }, rng.nextInt(3)); } } - if (!player.getPhysics().isFlying()) { - player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE); - } - - Vec3d origin = player.getOriginVector(); - if (strength > 0.5F && rng.nextInt(SELF_SPOOK_PROBABILITY) == 0) { player.asEntity().damage(player.damageOf(UDamageTypes.BAT_SCREECH, player), 0.1F); UCriteria.SCREECH_SELF.trigger(player.asEntity()); } - - int total = player.findAllEntitiesInRange((int)Math.max(1, 8 * strength)).mapToInt(e -> { - if (e instanceof LivingEntity living && !SpellType.SHIELD.isOn(e)) { - boolean isEarthPony = EquinePredicates.PLAYER_EARTH.test(e); - e.damage(player.damageOf(UDamageTypes.BAT_SCREECH, player), isEarthPony ? 0.1F : 0.3F); - if (e.getWorld().random.nextInt(MOB_SPOOK_PROBABILITY) == 0) { - RegistryUtils.pickRandom(e.getWorld(), UTags.SPOOKED_MOB_DROPS).ifPresent(drop -> { - e.dropStack(drop.getDefaultStack()); - e.playSound(USounds.Vanilla.ENTITY_ITEM_PICKUP, 1, 0.1F); - UCriteria.SPOOK_MOB.trigger(player.asEntity()); - }); - } - - Vec3d knockVec = origin.subtract(e.getPos()).multiply(strength); - living.takeKnockback((isEarthPony ? 0.3F : 0.5F) * strength, knockVec.getX(), knockVec.getZ()); - if (!isEarthPony) { - e.addVelocity(0, 0.1 * strength, 0); - } - Living.updateVelocity(e); - return 1; - } - return 0; - }).sum(); - - if (total >= 20) { - UCriteria.SCREECH_TWENTY_MOBS.trigger(player.asEntity()); - } - - return true; - } - - @Override - public void warmUp(Pony player, AbilitySlot slot) { - } - - @Override - public void coolDown(Pony player, AbilitySlot slot) { - for (int i = 0; i < 20; i++) { - player.addParticle(ParticleTypes.BUBBLE_POP, player.getPhysics().getHeadPosition().toCenterPos(), VecHelper.supply(() -> player.asWorld().getRandom().nextGaussian() - 0.5)); - } } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java new file mode 100644 index 00000000..0a9f5f6b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java @@ -0,0 +1,76 @@ +package com.minelittlepony.unicopia.ability; + +import java.util.Optional; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.ability.data.Hit; +import com.minelittlepony.unicopia.entity.player.Pony; + +/** + * Dashing ability for flying creatures. + */ +public class FlyingDashAbility implements Ability { + + @Override + public int getWarmupTime(Pony player) { + return 19; + } + + @Override + public int getCooldownTime(Pony player) { + return 30; + } + + @Override + public boolean canUse(Race race) { + return race == Race.HIPPOGRIFF; + } + + @Nullable + @Override + public Optional prepare(Pony player) { + return Hit.of(player.getPhysics().isFlying()); + } + + @Override + public Hit.Serializer getSerializer() { + return Hit.SERIALIZER; + } + + @Override + public double getCostEstimate(Pony player) { + return 0; + } + + @Override + public boolean onQuickAction(Pony player, ActivationType type, Optional data) { + + if (type == ActivationType.TAP && !player.getMotion().isRainbooming() && player.getPhysics().isFlying() && player.getMagicalReserves().getMana().get() > 40) { + player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(2.5F, 0.3F)); + return true; + } + + return false; + } + + @Override + public boolean apply(Pony player, Hit data) { + player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(2.5F, 0.3F)); + player.subtractEnergyCost(2); + return true; + } + + @Override + public void warmUp(Pony player, AbilitySlot slot) { + player.getMagicalReserves().getExertion().addPercent(6); + } + + @Override + public void coolDown(Pony player, AbilitySlot slot) { + float velocityScale = player.getAbilities().getStat(slot).getCooldown(); + float multiplier = 1 + (0.02F * velocityScale); + player.asEntity().getVelocity().multiply(multiplier, 1, multiplier); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java new file mode 100644 index 00000000..849dbb4c --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java @@ -0,0 +1,152 @@ +package com.minelittlepony.unicopia.ability; + +import java.util.Optional; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.USounds; +import com.minelittlepony.unicopia.ability.data.Hit; +import com.minelittlepony.unicopia.ability.data.Numeric; +import com.minelittlepony.unicopia.entity.Living; +import com.minelittlepony.unicopia.entity.damage.UDamageTypes; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.util.TraceHelper; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import net.minecraft.world.WorldEvents; +import net.minecraft.world.event.GameEvent; + +/** + * Hippogriff ability to use their beak as a weapon + */ +public class PeckAbility implements Ability { + + @Override + public int getWarmupTime(Pony player) { + return 1; + } + + @Override + public int getCooldownTime(Pony player) { + return 10; + } + + @Override + public double getCostEstimate(Pony player) { + return 0; + } + + @Override + public boolean activateOnEarlyRelease() { + return true; + } + + @Override + public boolean canUse(Race race) { + return race == Race.HIPPOGRIFF; + } + + @Override + public Optional prepare(Pony player) { + return Hit.INSTANCE; + } + + @Override + public Numeric.Serializer getSerializer() { + return Hit.SERIALIZER; + } + + protected LivingEntity findTarget(PlayerEntity player, World w) { + return TraceHelper.findEntity(player, 5, 1, hit -> { + return EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(hit) && !player.isConnectedThroughVehicle(hit); + }).orElse(null); + } + + @Override + public boolean apply(Pony player, Hit hit) { + LivingEntity target = findTarget(player.asEntity(), player.asWorld()); + + playSounds(player, player.asWorld().getRandom(), 1); + + if (target != null) { + spookMob(player, target, 1); + } else { + BlockPos pos = TraceHelper.findBlock(player.asEntity(), 5, 1).orElse(BlockPos.ORIGIN); + if (pos != BlockPos.ORIGIN) { + BlockState state = player.asWorld().getBlockState(pos); + if (state.isReplaceable()) { + player.asWorld().breakBlock(pos, true); + } else if (state.isIn(BlockTags.DIRT) || player.asWorld().random.nextInt(40000) == 0) { + player.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state)); + pos = pos.up(); + World world = player.asWorld(); + + if (world instanceof ServerWorld sw) { + for (ItemStack stack : Block.getDroppedStacks(state, sw, pos, null)) { + if (Block.getBlockFromItem(stack.getItem()) == Blocks.AIR) { + Block.dropStack(world, pos, stack); + } + } + state.onStacksDropped(sw, pos, ItemStack.EMPTY, true); + + if (world.random.nextInt(20) == 0) { + world.breakBlock(pos.down(), false); + player.asEntity().sendMessage(Text.translatable("ability.unicopia.peck.block.fled"), true); + } + } + } else { + player.asEntity().sendMessage(Text.translatable("ability.unicopia.peck.block.unfased"), true); + } + } + } + + return true; + } + + protected void playSounds(Pony player, Random rng, float strength) { + player.getMagicalReserves().getExertion().addPercent(100); + player.getMagicalReserves().getEnergy().addPercent(10); + player.playSound(USounds.Vanilla.ENTITY_CHICKEN_HURT, + 1, + 0.9F + (rng.nextFloat() - 0.5F) + ); + player.asWorld().emitGameEvent(player.asEntity(), GameEvent.STEP, player.asEntity().getEyePos()); + } + + protected void spookMob(Pony player, LivingEntity living, float strength) { + boolean isEarthPony = EquinePredicates.PLAYER_EARTH.test(living); + boolean isBracing = isEarthPony && player.asEntity().isSneaking(); + + if (!isBracing) { + living.damage(player.damageOf(UDamageTypes.BAT_SCREECH, player), isEarthPony ? 0.1F : 0.3F); + } + + Vec3d knockVec = player.getOriginVector().subtract(living.getPos()).multiply(strength); + living.takeKnockback((isBracing ? 0.2F : isEarthPony ? 0.3F : 0.5F) * strength, knockVec.getX(), knockVec.getZ()); + if (!isEarthPony) { + living.addVelocity(0, 0.1 * strength, 0); + } + Living.updateVelocity(living); + } + + @Override + public void warmUp(Pony player, AbilitySlot slot) { + } + + @Override + public void coolDown(Pony player, AbilitySlot slot) { + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java new file mode 100644 index 00000000..ac244ea0 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java @@ -0,0 +1,141 @@ +package com.minelittlepony.unicopia.ability; + +import java.util.Optional; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.USounds; +import com.minelittlepony.unicopia.UTags; +import com.minelittlepony.unicopia.ability.data.Numeric; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.advancement.UCriteria; +import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; +import com.minelittlepony.unicopia.entity.Living; +import com.minelittlepony.unicopia.entity.damage.UDamageTypes; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.util.RegistryUtils; +import com.minelittlepony.unicopia.util.VecHelper; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.event.GameEvent; + +/** + * An ability to scream very loud + */ +public class ScreechAbility implements Ability { + public static final int MOB_SPOOK_PROBABILITY = 1000; + + @Override + public int getWarmupTime(Pony player) { + return 30; + } + + @Override + public int getCooldownTime(Pony player) { + return 5; + } + + @Override + public double getCostEstimate(Pony player) { + return 0; + } + + @Override + public boolean activateOnEarlyRelease() { + return true; + } + + @Override + public boolean canUse(Race race) { + return race == Race.HIPPOGRIFF; + } + + @Override + public Optional prepare(Pony player) { + return player.getAbilities().getActiveStat() + .map(stat -> (int)(stat.getWarmup() * getWarmupTime(player))) + .filter(i -> i >= 0) + .map(Numeric::new); + } + + @Override + public Numeric.Serializer getSerializer() { + return Numeric.SERIALIZER; + } + + @Override + public boolean apply(Pony player, Numeric data) { + float strength = 1 - MathHelper.clamp(data.type() / (float)getWarmupTime(player), 0, 1); + Random rng = player.asWorld().random; + + playSounds(player, rng, strength); + + if (!player.getPhysics().isFlying()) { + player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE); + } + + int total = player.findAllEntitiesInRange((int)Math.max(1, 8 * strength)).mapToInt(e -> { + if (e instanceof LivingEntity living && !SpellType.SHIELD.isOn(e)) { + spookMob(player, living, strength); + return 1; + } + return 0; + }).sum(); + + if (total >= 20) { + UCriteria.SCREECH_TWENTY_MOBS.trigger(player.asEntity()); + } + + return true; + } + + protected void playSounds(Pony player, Random rng, float strength) { + player.playSound(USounds.ENTITY_PLAYER_HIPPOGRIFF_SCREECH, + (1.2F + (rng.nextFloat() - 0.5F) / 2F) * strength, + 1.1F + (rng.nextFloat() - 0.5F) + ); + player.asWorld().emitGameEvent(player.asEntity(), GameEvent.ENTITY_ROAR, player.asEntity().getEyePos()); + } + + protected void spookMob(Pony player, LivingEntity living, float strength) { + boolean isEarthPony = EquinePredicates.PLAYER_EARTH.test(living); + boolean isBracing = isEarthPony && player.asEntity().isSneaking(); + + if (!isBracing) { + living.damage(player.damageOf(UDamageTypes.BAT_SCREECH, player), isEarthPony ? 0.1F : 0.3F); + + + if (living.getWorld().random.nextInt(MOB_SPOOK_PROBABILITY) == 0) { + RegistryUtils.pickRandom(living.getWorld(), UTags.SPOOKED_MOB_DROPS).ifPresent(drop -> { + living.dropStack(drop.getDefaultStack()); + living.playSound(USounds.Vanilla.ENTITY_ITEM_PICKUP, 1, 0.1F); + UCriteria.SPOOK_MOB.trigger(player.asEntity()); + }); + } + } + + Vec3d knockVec = player.getOriginVector().subtract(living.getPos()).multiply(strength); + living.takeKnockback((isBracing ? 0.2F : isEarthPony ? 0.3F : 0.5F) * strength, knockVec.getX(), knockVec.getZ()); + if (!isEarthPony) { + living.addVelocity(0, 0.1 * strength, 0); + } + Living.updateVelocity(living); + } + + @Override + public void warmUp(Pony player, AbilitySlot slot) { + } + + @Override + public void coolDown(Pony player, AbilitySlot slot) { + for (int i = 0; i < 20; i++) { + player.addParticle(ParticleTypes.BUBBLE_POP, player.asEntity().getEyePos(), + VecHelper.supply(() -> (player.asWorld().getRandom().nextGaussian() - 0.5) * 0.3) + ); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PegasusFlightToggleAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java similarity index 97% rename from src/main/java/com/minelittlepony/unicopia/ability/PegasusFlightToggleAbility.java rename to src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java index c0736de0..d9811e74 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/PegasusFlightToggleAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java @@ -12,7 +12,7 @@ import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.util.Identifier; -public class PegasusFlightToggleAbility implements Ability { +public class ToggleFlightAbility implements Ability { @Override public int getWarmupTime(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java b/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java new file mode 100644 index 00000000..2188245d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/HudEffects.java @@ -0,0 +1,61 @@ +package com.minelittlepony.unicopia.client.gui; + +import java.util.HashSet; +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.entity.duck.EntityDuck; +import com.minelittlepony.unicopia.entity.effect.EffectUtils; +import com.minelittlepony.unicopia.entity.effect.UEffects; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.registry.tag.FluidTags; +import net.minecraft.registry.tag.TagKey; + +public class HudEffects { + + private static boolean addedHunger; + private static Set> originalTags = null; + + public static void tryApply(@Nullable PlayerEntity player, float tickDelta, boolean on) { + if (player != null) { + apply(Pony.of(player), tickDelta, on); + } + } + + private static void apply(Pony pony, float tickDelta, boolean on) { + if (on) { + if (!pony.asEntity().hasStatusEffect(StatusEffects.HUNGER) && EffectUtils.getAmplifier(pony.asEntity(), UEffects.FOOD_POISONING) > 0) { + addedHunger = true; + pony.asEntity().addStatusEffect(new StatusEffectInstance(StatusEffects.HUNGER, 1, 1, false, false)); + } + } else { + if (addedHunger) { + addedHunger = false; + pony.asEntity().removeStatusEffect(StatusEffects.HUNGER); + } + } + + if (pony.getCompositeRace().includes(Race.SEAPONY)) { + Set> fluidTags = ((EntityDuck)pony.asEntity()).getSubmergedFluidTags(); + if (on) { + originalTags = new HashSet<>(fluidTags); + if (fluidTags.contains(FluidTags.WATER)) { + fluidTags.clear(); + } else { + fluidTags.add(FluidTags.WATER); + } + } else if (originalTags != null) { + fluidTags.clear(); + fluidTags.addAll(originalTags); + originalTags = null; + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java index 302c546d..a999236f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java @@ -54,7 +54,7 @@ public class TribeSelectionScreen extends GameGui implements HidesHud { final int itemWidth = 70 + 10; - List options = Race.REGISTRY.stream().filter(race -> !race.isHuman() && !race.isOp()).toList(); + List options = Race.REGISTRY.stream().filter(race -> race.availability().isSelectable()).toList(); int columns = Math.min(width / itemWidth, options.size()); diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java index e99a9860..3ec5d015 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java @@ -15,6 +15,7 @@ import com.minelittlepony.client.model.entity.race.UnicornModel; import com.minelittlepony.client.model.part.UnicornHorn; import com.minelittlepony.mson.api.MsonModel; import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.entity.AmuletSelectors; @@ -43,7 +44,7 @@ class BodyPartGear & MsonModel & IModel> public static final Predicate UNICORN_HORN_PREDICATE = MINE_LP_HAS_NO_HORN.and(AmuletSelectors.ALICORN_AMULET.or(EquinePredicates.raceMatches(Race::canCast))); public static final Identifier UNICORN_HORN = Unicopia.id("textures/models/horn/unicorn.png"); - public static final Predicate PEGA_WINGS_PREDICATE = MINE_LP_HAS_NO_WINGS.and(AmuletSelectors.PEGASUS_AMULET.or(EquinePredicates.raceMatches(Race::canInteractWithClouds))); + public static final Predicate PEGA_WINGS_PREDICATE = MINE_LP_HAS_NO_WINGS.and(AmuletSelectors.PEGASUS_AMULET.or(EquinePredicates.raceMatches(race -> race.flightType() == FlightType.AVIAN))); public static final Identifier PEGASUS_WINGS = Unicopia.id("textures/models/wings/pegasus_pony.png"); public static BodyPartGear pegasusWings() { diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java index 1639d96b..4757d7a3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java @@ -55,9 +55,9 @@ public class Main extends MineLPDelegate implements ClientModInitializer { registerRaceMapping(com.minelittlepony.api.pony.meta.Race.CHANGEDLING, Race.CHANGELING); registerRaceMapping(com.minelittlepony.api.pony.meta.Race.ZEBRA, Race.EARTH); registerRaceMapping(com.minelittlepony.api.pony.meta.Race.GRYPHON, Race.PEGASUS); - registerRaceMapping(com.minelittlepony.api.pony.meta.Race.HIPPOGRIFF, Race.PEGASUS); + registerRaceMapping(com.minelittlepony.api.pony.meta.Race.HIPPOGRIFF, Race.HIPPOGRIFF); registerRaceMapping(com.minelittlepony.api.pony.meta.Race.BATPONY, Race.BAT); - registerRaceMapping(com.minelittlepony.api.pony.meta.Race.SEAPONY, Race.UNICORN); + registerRaceMapping(com.minelittlepony.api.pony.meta.Race.SEAPONY, Race.SEAPONY); } private void onPonyModelPrepared(Entity entity, IModel model, ModelAttributes.Mode mode) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/ModelPartHooks.java b/src/main/java/com/minelittlepony/unicopia/client/render/ModelPartHooks.java index b892836b..21401622 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/ModelPartHooks.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/ModelPartHooks.java @@ -32,7 +32,6 @@ public class ModelPartHooks { final var bestCandidate = new EnqueudHeadRender(); - matrices.push(); part.forEachCuboid(matrices, (entry, name, index, cube) -> { float x = cube.maxX - cube.minX; float y = cube.maxY - cube.minY; @@ -47,7 +46,6 @@ public class ModelPartHooks { bestCandidate.maxSideLength = Math.max(Math.max(x, z), y); } }); - matrices.pop(); if (bestCandidate.transformation != null) { head.add(bestCandidate); @@ -75,8 +73,6 @@ public class ModelPartHooks { matrices.translate(x * PIXEL_SCALE, y * PIXEL_SCALE, z * PIXEL_SCALE); matrices.scale(scale, scale, scale); - //matrices.peek().getPositionMatrix().scaleAround(scale, x * PIXEL_SCALE, y * PIXEL_SCALE, z * PIXEL_SCALE); - //matrices.translate(cube.minX * PIXEL_SCALE, cube.minY * PIXEL_SCALE, cube.minZ * PIXEL_SCALE); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/SmittenEyesRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/SmittenEyesRenderer.java index 2459266a..9fa33446 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/SmittenEyesRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/SmittenEyesRenderer.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.client.render; import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment; @@ -20,7 +19,6 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RotationAxis; public class SmittenEyesRenderer { private static final Identifier TEXTURE = Unicopia.id("textures/entity/smitten_eyes.png"); @@ -42,9 +40,6 @@ public class SmittenEyesRenderer { ModelPartHooks.stopCollecting().forEach(head -> { matrices.push(); head.transform(matrices, 0.95F); - if (MineLPDelegate.getInstance().getRace(pony.asEntity()).isEquine()) { - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-90), 0, 1.2F, 0); - } float scale = 1F + (1.3F + MathHelper.sin(pony.asEntity().age / 3F) * 0.06F); matrices.scale(scale, scale, scale); matrices.translate(0, 0.05F, 0); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java index b9d33535..10c8ecc3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.client.render; +import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.entity.player.Pony; @@ -50,7 +51,7 @@ public class WingsFeatureRenderer implements AccessoryFe } protected boolean canRender(E entity) { - return entity instanceof PlayerEntity && Pony.of((PlayerEntity)entity).getObservedSpecies().canInteractWithClouds(); + return entity instanceof PlayerEntity && Pony.of((PlayerEntity)entity).getObservedSpecies().flightType() == FlightType.AVIAN; } protected Identifier getTexture(E entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java index 30472c2c..78ca8e93 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java @@ -4,7 +4,10 @@ import java.util.Optional; import com.minelittlepony.client.util.render.RenderLayerUtil; import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; +import com.minelittlepony.unicopia.client.render.model.SphereModel; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.ItemImpl; @@ -80,6 +83,27 @@ public class WorldRenderDelegate { smittenEyesRenderer.render(creature, matrices, immediate, light, 0); } + if (pony instanceof Pony p) { + if (p.getCompositeRace().includes(Race.SEAPONY) + && pony.asEntity().isSubmergedInWater() + && MineLPDelegate.getInstance().getPlayerPonyRace(p.asEntity()) != Race.SEAPONY) { + + for (var head : ModelPartHooks.stopCollecting()) { + matrices.push(); + head.transform(matrices, 1F); + + Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers(); + RenderLayer layer = RenderLayers.getMagicColored(); + float scale = 0.9F; + + SphereModel.SPHERE.render(matrices, immediate.getBuffer(layer), light, 0, scale, 0.5F, 0.5F, 0.5F, 0.1F); + SphereModel.SPHERE.render(matrices, immediate.getBuffer(layer), light, 0, scale + 0.2F, 0.5F, 0.5F, 0.5F, 0.1F); + + matrices.pop(); + } + } + } + if (pony instanceof ItemImpl || pony instanceof Living) { matrices.pop(); @@ -162,6 +186,13 @@ public class WorldRenderDelegate { roll -= 180; } + if (p.getAcrobatics().isFloppy()) { + matrices.translate(0, -0.5, 0); + p.asEntity().setBodyYaw(0); + p.asEntity().setYaw(0); + matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90)); + } + matrices.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw)); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll)); @@ -169,6 +200,12 @@ public class WorldRenderDelegate { matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(diveAngle)); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); + + if (p.getCompositeRace().includes(Race.SEAPONY) + && pony.asEntity().isSubmergedInWater() + && MineLPDelegate.getInstance().getPlayerPonyRace(p.asEntity()) != Race.SEAPONY) { + ModelPartHooks.startCollecting(); + } } else if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) { ModelPartHooks.startCollecting(); } diff --git a/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java b/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java index 6f93995b..1363ee96 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java @@ -8,7 +8,6 @@ import com.minelittlepony.unicopia.network.MsgTribeSelect; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.minecraft.command.argument.EntityArgumentType; -import net.minecraft.command.argument.RegistryKeyArgumentType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager.RegistrationEnvironment; @@ -32,8 +31,6 @@ class SpeciesCommand { } } - RegistryKeyArgumentType raceArgument = Race.argument(); - return builder .then(CommandManager.literal("get") .executes(context -> get(context.getSource(), context.getSource().getPlayer(), true)) @@ -41,13 +38,13 @@ class SpeciesCommand { .executes(context -> get(context.getSource(), EntityArgumentType.getPlayer(context, "target"), false)) )) .then(CommandManager.literal("set") - .then(CommandManager.argument("race", raceArgument) + .then(CommandManager.argument("race", Race.argument()) .executes(context -> set(context.getSource(), context.getSource().getPlayer(), Race.fromArgument(context, "race"), true)) .then(CommandManager.argument("target", EntityArgumentType.player()) .executes(context -> set(context.getSource(), EntityArgumentType.getPlayer(context, "target"), Race.fromArgument(context, "race"), false))) )) .then(CommandManager.literal("describe") - .then(CommandManager.argument("race", raceArgument) + .then(CommandManager.argument("race", Race.argument()) .executes(context -> describe(context.getSource().getPlayer(), Race.fromArgument(context, "race"))) )) .then(CommandManager.literal("list") @@ -101,7 +98,7 @@ class SpeciesCommand { boolean first = true; for (Race i : Race.REGISTRY) { - if (!i.isUnset() && i.isPermitted(player)) { + if (i.availability().isGrantable() && !i.isUnset() && i.isPermitted(player)) { message.append(Text.literal((!first ? "\n" : "") + " - ")); message.append(i.getDisplayName()); first = false; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/AmuletSelectors.java b/src/main/java/com/minelittlepony/unicopia/entity/AmuletSelectors.java index 96fc930b..81211527 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/AmuletSelectors.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/AmuletSelectors.java @@ -10,6 +10,7 @@ public interface AmuletSelectors { Predicate ALICORN_AMULET = UItems.ALICORN_AMULET::isApplicable; Predicate PEGASUS_AMULET = UItems.PEGASUS_AMULET::isApplicable; Predicate UNICORN_AMULET = UItems.UNICORN_AMULET::isApplicable; + Predicate PEARL_NECKLACE = UItems.PEARL_NECKLACE::isApplicable; Predicate ALICORN_AMULET_AFTER_1_DAYS = ALICORN_AMULET.and(ItemTracker.wearing(UItems.ALICORN_AMULET, ItemTracker.after(ItemTracker.DAYS))); Predicate ALICORN_AMULET_AFTER_2_DAYS = ALICORN_AMULET.and(ItemTracker.wearing(UItems.ALICORN_AMULET, ItemTracker.after(2 * ItemTracker.DAYS))); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java b/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java index 0a61652d..659a3a24 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java @@ -1,12 +1,18 @@ package com.minelittlepony.unicopia.entity.duck; +import java.util.Set; + import com.minelittlepony.unicopia.compat.pehkui.PehkuiEntityExtensions; import net.minecraft.entity.Entity; import net.minecraft.entity.Entity.RemovalReason; +import net.minecraft.fluid.Fluid; +import net.minecraft.registry.tag.TagKey; public interface EntityDuck extends LavaAffine, PehkuiEntityExtensions { + Set> getSubmergedFluidTags(); + void setRemovalReason(RemovalReason reason); void setVehicle(Entity vehicle); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java index f7168730..462936ad 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java @@ -34,6 +34,7 @@ public class RaceChangeStatusEffect extends StatusEffect { public static final StatusEffect CHANGE_RACE_BAT = register(0x0FFF00, Race.BAT); public static final StatusEffect CHANGE_RACE_CHANGELING = register(0xFFFF00, Race.CHANGELING); public static final StatusEffect CHANGE_RACE_KIRIN = register(0xFF8800, Race.KIRIN); + public static final StatusEffect CHANGE_RACE_HIPPOGRIFF = register(0x00FFFF, Race.HIPPOGRIFF); private final Race race; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java index 2ff93a59..82f5a0b3 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java @@ -18,6 +18,8 @@ public interface UPotions { Potion TRIBE_SWAP_PEGASUS = register("tribe_swap_pegasus", new Potion("unicopia.tribe_swap_pegasus", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_PEGASUS, RaceChangeStatusEffect.MAX_DURATION))); Potion TRIBE_SWAP_BAT = register("tribe_swap_bat", new Potion("unicopia.tribe_swap_bat", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_BAT, RaceChangeStatusEffect.MAX_DURATION))); Potion TRIBE_SWAP_CHANGELING = register("tribe_swap_changeling", new Potion("unicopia.tribe_swap_changeling", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_CHANGELING, RaceChangeStatusEffect.MAX_DURATION))); + Potion TRIBE_SWAP_KIRIN = register("tribe_swap_kirin", new Potion("unicopia.tribe_swap_kirin", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_KIRIN, RaceChangeStatusEffect.MAX_DURATION))); + Potion TRIBE_SWAP_HIPPOGRIFF = register("tribe_swap_hippogriff", new Potion("unicopia.tribe_swap_hippogriff", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_HIPPOGRIFF, RaceChangeStatusEffect.MAX_DURATION))); static Potion register(String name, Potion potion) { REGISTRY.add(potion); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java index 032d4f89..1607c64a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java @@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; +import com.minelittlepony.unicopia.entity.mob.StormCloudEntity; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; @@ -17,6 +18,8 @@ import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; @@ -42,6 +45,17 @@ public class Acrobatics implements Tickable, NbtSerialisable { pony.addTicker(this::checkDislodge); } + public boolean isImmobile() { + return isFloppy() && entity.isOnGround(); + } + + public boolean isFloppy() { + if (entity.isCreative() && entity.getAbilities().flying) { + return false; + } + return pony.getCompositeRace().any(Race::isFish) && !entity.isTouchingWater() && !entity.getWorld().isWater(StormCloudEntity.findSurfaceBelow(entity.getWorld(), entity.getBlockPos())); + } + @Override public void tick() { BlockPos climbingPos = entity.getClimbingPos().orElse(null); @@ -115,6 +129,11 @@ public class Acrobatics implements Tickable, NbtSerialisable { } else { ticksHanging = 0; } + + + if (pony.getCompositeRace().includes(Race.SEAPONY) && !entity.isSubmergedInWater() && pony.landedChanged()) { + entity.getWorld().playSound(null, entity.getBlockPos(), SoundEvents.ENTITY_GUARDIAN_FLOP, SoundCategory.PLAYERS, 1, 1); + } } boolean isFaceClimbable(World world, BlockPos pos, Direction direction) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java index 1b396f98..8bbccdef 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerAttributes.java @@ -36,12 +36,23 @@ public class PlayerAttributes implements Tickable { new ToggleableAttribute( new EntityAttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-9d2d-fb92ee19b4f7"), "Pegasus Speed", 0.2, Operation.MULTIPLY_TOTAL), List.of(EntityAttributes.GENERIC_MOVEMENT_SPEED, EntityAttributes.GENERIC_ATTACK_SPEED), - pony -> pony.getCompositeRace().canFly() + pony -> pony.getCompositeRace().canFly() && !pony.getCompositeRace().includes(Race.HIPPOGRIFF) ), new ToggleableAttribute( new EntityAttributeModifier(UUID.fromString("707b50a8-03e8-40f4-8553-ecf67025fd6d"), "Pegasus Reach", 1.5, Operation.ADDITION), List.of(UEntityAttributes.EXTENDED_REACH_DISTANCE), - pony -> pony.getCompositeRace().canFly() + pony -> pony.getCompositeRace().canFly() && !pony.getCompositeRace().includes(Race.HIPPOGRIFF) + ), + + new ToggleableAttribute( + new EntityAttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-92dd-bef19b92e4f7"), "Hippogriff Speed", 0.1, Operation.MULTIPLY_TOTAL), + List.of(EntityAttributes.GENERIC_MOVEMENT_SPEED, EntityAttributes.GENERIC_ATTACK_SPEED), + pony -> pony.getCompositeRace().includes(Race.HIPPOGRIFF) + ), + new ToggleableAttribute( + new EntityAttributeModifier(UUID.fromString("707b50a8-03e8-40f4-5853-fc7e0f625d6d"), "Hippogriff Reach", 1.3, Operation.ADDITION), + List.of(UEntityAttributes.EXTENDED_REACH_DISTANCE), + pony -> pony.getCompositeRace().includes(Race.HIPPOGRIFF) ), new ToggleableAttribute( diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java index bd070bd7..04b5bf22 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java @@ -3,9 +3,11 @@ package com.minelittlepony.unicopia.entity.player; import java.util.Optional; import com.minelittlepony.common.util.animation.MotionCompositor; +import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; +import net.minecraft.client.render.CameraSubmersionType; import net.minecraft.util.math.Vec3d; public class PlayerCamera extends MotionCompositor { @@ -35,6 +37,11 @@ public class PlayerCamera extends MotionCompositor { roll = player.getInterpolator().interpolate("roll", (float)roll, 15); } + + if (player.getAcrobatics().isFloppy()) { + roll += 90; + } + return (float)roll; } @@ -54,6 +61,15 @@ public class PlayerCamera extends MotionCompositor { .map(d -> distance * d); } + public Optional getSubmersionType(CameraSubmersionType original) { + if (player.getCompositeRace().includes(Race.SEAPONY)) { + if (original == CameraSubmersionType.WATER) { + return Optional.of(CameraSubmersionType.NONE); + } + } + return Optional.empty(); + } + public double calculateFieldOfView(double fov) { fov += player.getMagicalReserves().getExertion().get() / 5F; fov += getEnergyAddition(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index ca497829..bb9b68e9 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -414,7 +414,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (type.isAvian()) { if (pony.getObservedSpecies() != Race.BAT && entity.getWorld().random.nextInt(9000) == 0) { - entity.dropItem(UItems.PEGASUS_FEATHER); + entity.dropItem(pony.getObservedSpecies() == Race.HIPPOGRIFF ? UItems.GRYPHON_FEATHER : UItems.PEGASUS_FEATHER); playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1); UCriteria.SHED_FEATHER.trigger(entity); } @@ -513,7 +513,9 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (entity.getWorld().random.nextInt(110) == 1 && !pony.isClient()) { pony.getLevel().add(1); - pony.getMagicalReserves().getCharge().addPercent(4); + if (Abilities.RAINBOOM.canUse(pony.getCompositeRace())) { + pony.getMagicalReserves().getCharge().addPercent(4); + } pony.getMagicalReserves().getExertion().set(0); pony.getMagicalReserves().getExhaustion().set(0); mana.set(mana.getMax() * 100); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 2487a67c..74dfa609 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -36,7 +36,9 @@ import com.google.common.collect.Streams; import com.minelittlepony.common.util.animation.Interpolator; import com.mojang.authlib.GameProfile; +import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.damage.DamageSource; @@ -359,6 +361,7 @@ public class Pony extends Living implements Copyable, Update .orElseGet(this::getSpecies).composite( AmuletSelectors.UNICORN_AMULET.test(entity) ? Race.UNICORN : AmuletSelectors.ALICORN_AMULET.test(entity) ? Race.ALICORN + : AmuletSelectors.PEARL_NECKLACE.test(entity) ? Race.SEAPONY : null ); } @@ -428,6 +431,23 @@ public class Pony extends Living implements Copyable, Update } } + if (getCompositeRace().includes(Race.SEAPONY)) { + if (entity.isSubmergedInWater()) { + if (entity.getVelocity().lengthSquared() > 0.02) { + spawnParticles(ParticleTypes.BUBBLE, 4); + } + } else { + if (entity.getAir() == entity.getMaxAir()) { + entity.setAir(entity.getAir() - 1); + } + + if (entity.getAir() == -20) { + entity.setAir(0); + entity.damage(entity.getDamageSources().dryOut(), 2); + } + } + } + return super.beforeUpdate(); } @@ -568,6 +588,14 @@ public class Pony extends Living implements Copyable, Update if (getObservedSpecies() == Race.KIRIN) { return Optional.of(speed.multiply(0.5, 1, 0.5)); } + if (getCompositeRace().includes(Race.SEAPONY)) { + float factor = entity.isSwimming() ? 1.132F : 1.232F; + return Optional.of(new Vec3d( + speed.x * factor, + speed.y * 1.101, + speed.z * factor + )); + } return Optional.empty(); } @@ -595,6 +623,18 @@ public class Pony extends Living implements Copyable, Update return false; } + public int getImplicitEnchantmentLevel(Enchantment enchantment) { + + if ((enchantment == Enchantments.AQUA_AFFINITY + || enchantment == Enchantments.DEPTH_STRIDER + || enchantment == Enchantments.LUCK_OF_THE_SEA + || enchantment == Enchantments.LURE) && getCompositeRace().includes(Race.SEAPONY)) { + return 3; + } + + return 0; + } + public Optional modifyDamage(DamageSource cause, float amount) { if (getObservedSpecies() == Race.KIRIN) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 011bff35..282f9e3e 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -197,6 +197,9 @@ public interface UItems { .maxCount(1) .maxDamage(890) .rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS); + AmuletItem PEARL_NECKLACE = register("pearl_necklace", new AmuletItem(new FabricItemSettings() + .maxCount(1) + .rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS); GlassesItem SUNGLASSES = register("sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT); GlassesItem BROKEN_SUNGLASSES = register("broken_sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT); @@ -213,6 +216,7 @@ public interface UItems { Item BAT_BADGE = register(Race.BAT); Item CHANGELING_BADGE = register(Race.CHANGELING); Item KIRIN_BADGE = register(Race.KIRIN); + Item HIPPOGRIFF_BADGE = register(Race.HIPPOGRIFF); private static T register(String name, T item, RegistryKey group) { return ItemGroupRegistry.register(Unicopia.id(name), item, group); diff --git a/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxics.java b/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxics.java index 051b9f73..82157234 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxics.java +++ b/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxics.java @@ -22,12 +22,14 @@ public interface Toxics { Toxic EDIBLE = register("edible", new Toxic.Builder(Ailment.INNERT) .with(Race.CHANGELING, of(FAIR, LOVE_SICKNESS)) + .with(Race.SEAPONY, of(FAIR, FOOD_POISONING)) ); Toxic FORAGE_EDIBLE = register("forage_edible", new Toxic.Builder(Ailment.INNERT) .food(UFoodComponents.RANDOM_FOLIAGE) .with(Race.HUMAN, of(LETHAL, FOOD_POISONING)) .with(Race.CHANGELING, of(FAIR, LOVE_SICKNESS)) + .with(Race.SEAPONY, of(FAIR, FOOD_POISONING)) ); Toxic FORAGE_EDIBLE_FILLING = register("forage_edible_filling", new Toxic.Builder(Ailment.INNERT) @@ -59,6 +61,7 @@ public interface Toxics { Toxic FORAGE_PRICKLY = register("forage_prickly", new Toxic.Builder(of(SAFE, INSTANT_DAMAGE.withChance(30))) .food(UFoodComponents.RANDOM_FOLIAGE) .with(Race.HUMAN, of(LETHAL, FOOD_POISONING)) + .with(Race.HIPPOGRIFF, Ailment.INNERT) .with(Race.KIRIN, Ailment.INNERT) ); Toxic FORAGE_STRENGHTENING = register("forage_strengthening", new Toxic.Builder(of(SEVERE, STRENGTH.and(FOOD_POISONING))) @@ -94,6 +97,7 @@ public interface Toxics { Toxic COOKED_MEAT = register("cooked_meat", new Toxic.Builder(of(FAIR, FOOD_POISONING)) .with(Race.HUMAN, Ailment.INNERT) .with(Race.CHANGELING, Ailment.INNERT) + .with(Race.HIPPOGRIFF, of(MILD, FOOD_POISONING)) .with(Race.BAT, Ailment.INNERT) .with(Race.KIRIN, Ailment.INNERT) ); @@ -101,12 +105,16 @@ public interface Toxics { Toxic RAW_FISH = register("raw_fish", new Toxic.Builder(of(FAIR, FOOD_POISONING.and(CHANCE_OF_POISON))) .with(Race.HUMAN, Ailment.INNERT) .with(Race.PEGASUS, of(MILD, FOOD_POISONING)) + .with(Race.HIPPOGRIFF, Ailment.INNERT) + .with(Race.SEAPONY, Ailment.INNERT) .with(Race.ALICORN, Ailment.INNERT) .with(Race.CHANGELING, of(FAIR, LOVE_SICKNESS)) ); Toxic COOKED_FISH = register("cooked_fish", new Toxic.Builder(of(MILD, FOOD_POISONING)) .with(Race.HUMAN, Ailment.INNERT) .with(Race.PEGASUS, Ailment.INNERT) + .with(Race.HIPPOGRIFF, Ailment.INNERT) + .with(Race.SEAPONY, Ailment.INNERT) .with(Race.ALICORN, Ailment.INNERT) .with(Race.CHANGELING, of(FAIR, LOVE_SICKNESS)) ); @@ -129,6 +137,7 @@ public interface Toxics { Toxic PINECONE = register("pinecone", new Toxic.Builder(of(Toxicity.SAFE, Toxin.healing(1))) .with(Race.HUMAN, Ailment.INNERT) + .with(Race.HIPPOGRIFF, of(Toxicity.SAFE, Toxin.healing(3))) ); Toxic BAT_PONYS_DELIGHT = register("bat_ponys_delight", new Toxic.Builder(Ailment.INNERT) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java new file mode 100644 index 00000000..71ecc8f9 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java @@ -0,0 +1,25 @@ +package com.minelittlepony.unicopia.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.LivingEntity; + +@Mixin(EnchantmentHelper.class) +abstract class MixinEnchantmentHelper { + @Inject(method = "getEquipmentLevel", at = @At("RETURN"), cancellable = true) + private static void getEquipmentLevel(Enchantment enchantment, LivingEntity entity, CallbackInfoReturnable info) { + Pony.of(entity).ifPresent(pony -> { + int implicitLevel = pony.getImplicitEnchantmentLevel(enchantment); + if (implicitLevel > 0) { + info.setReturnValue(implicitLevel + info.getReturnValue()); + } + }); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index a522b101..90febf2d 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.mixin; +import java.util.Set; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.injection.At; @@ -17,9 +19,15 @@ import com.minelittlepony.unicopia.entity.duck.EntityDuck; import net.minecraft.entity.Entity; import net.minecraft.entity.Entity.PositionUpdater; import net.minecraft.entity.Entity.RemovalReason; +import net.minecraft.fluid.Fluid; +import net.minecraft.registry.tag.TagKey; @Mixin(Entity.class) abstract class MixinEntity implements EntityDuck { + @Override + @Accessor("submergedFluidTag") + public abstract Set> getSubmergedFluidTags(); + @Override @Accessor public abstract void setRemovalReason(RemovalReason reason); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java index 9d96e9c1..71d0907c 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java @@ -11,6 +11,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.entity.duck.PlayerEntityDuck; +import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.player.Pony; import com.mojang.datafixers.util.Either; @@ -114,4 +115,20 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe private void onGetBlockBreakingSpeed(BlockState state, CallbackInfoReturnable info) { info.setReturnValue(info.getReturnValue() * get().getBlockBreakingSpeed()); } + + @Override + protected int getNextAirUnderwater(int air) { + if (EquinePredicates.PLAYER_SEAPONY.test(this)) { + return super.getNextAirOnLand(air); + } + return super.getNextAirUnderwater(air); + } + + @Override + protected int getNextAirOnLand(int air) { + if (EquinePredicates.PLAYER_SEAPONY.test(this)) { + return super.getNextAirUnderwater(air); + } + return super.getNextAirOnLand(air); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java new file mode 100644 index 00000000..ecadb831 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPufferfishEntity.java @@ -0,0 +1,25 @@ +package com.minelittlepony.unicopia.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.passive.FishEntity; +import net.minecraft.entity.passive.PufferfishEntity; + +@Mixin(PufferfishEntity.class) +abstract class MixinPufferfishEntity extends FishEntity { + MixinPufferfishEntity() { super(null, null); } + + @Inject(method = "method_6591(Lnet/minecraft/class_1309;)Z", at = @At("HEAD"), cancellable = true) + private static void onShouldTarget(LivingEntity entity, CallbackInfoReturnable info) { + Pony.of(entity).filter(pony -> pony.getCompositeRace().includes(Race.SEAPONY)).ifPresent(pony -> { + info.setReturnValue(false); + }); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinCamera.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinCamera.java index 81f9f5da..6444e002 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinCamera.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinCamera.java @@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.client.UnicopiaClient; import net.minecraft.client.render.Camera; +import net.minecraft.client.render.CameraSubmersionType; @Mixin(Camera.class) abstract class MixinCamera { @@ -33,4 +34,11 @@ abstract class MixinCamera { private void redirectCameraDistance(double initial, CallbackInfoReturnable info) { UnicopiaClient.getCamera().flatMap(c -> c.calculateDistance(info.getReturnValueD())).ifPresent(info::setReturnValue); } + + @Inject(method = "getSubmersionType", + at = @At("RETURN"), + cancellable = true) + public void getSubmersionType(CallbackInfoReturnable info) { + UnicopiaClient.getCamera().flatMap(c -> c.getSubmersionType(info.getReturnValue())).ifPresent(info::setReturnValue); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinInGameHud.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinInGameHud.java index fa02c81d..e4306cbd 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinInGameHud.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinInGameHud.java @@ -6,43 +6,27 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import com.minelittlepony.unicopia.client.gui.HudEffects; import com.minelittlepony.unicopia.client.gui.UHud; -import com.minelittlepony.unicopia.entity.effect.EffectUtils; -import com.minelittlepony.unicopia.entity.effect.UEffects; - import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.player.PlayerEntity; @Mixin(InGameHud.class) abstract class MixinInGameHud { - private boolean addedHunger; - @Shadow abstract PlayerEntity getCameraPlayer(); @Inject(method = "render(Lnet/minecraft/client/gui/DrawContext;F)V", at = @At("HEAD")) private void onRender(DrawContext context, float tickDelta, CallbackInfo info) { - PlayerEntity player = getCameraPlayer(); - if (player != null && !player.hasStatusEffect(StatusEffects.HUNGER) && EffectUtils.getAmplifier(player, UEffects.FOOD_POISONING) > 0) { - addedHunger = true; - player.addStatusEffect(new StatusEffectInstance(StatusEffects.HUNGER, 1, 1, false, false)); - } + HudEffects.tryApply(getCameraPlayer(), tickDelta, true); UHud.INSTANCE.render((InGameHud)(Object)this, context, tickDelta); } @Inject(method = "render(Lnet/minecraft/client/gui/DrawContext;F)V", at = @At("RETURN")) private void afterRender(DrawContext context, float tickDelta, CallbackInfo info) { - if (addedHunger) { - addedHunger = false; - PlayerEntity player = getCameraPlayer(); - if (player != null) { - player.removeStatusEffect(StatusEffects.HUNGER); - } - } + HudEffects.tryApply(getCameraPlayer(), tickDelta, false); } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java index c0fd45da..7bc83f17 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java @@ -40,6 +40,11 @@ abstract class MixinKeyboardInput extends Input { movementForward = 0; jumping = false; } + + if (player.getAcrobatics().isImmobile()) { + movementSideways = 0; + movementForward = 0; + } } } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinModelPart.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinModelPart.java index 4fb5cd9a..aef4d87d 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinModelPart.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinModelPart.java @@ -39,7 +39,7 @@ abstract class MixinModelPart implements Hookable { isHeadPart = true; } - @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;IIFFFF)V", at = @At("RETURN")) + @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;IIFFFF)V", at = @At("HEAD")) public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha, CallbackInfo info) { if (visible && isHeadPart) { ModelPartHooks.onHeadRendered((ModelPart)(Object)this, matrices); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 8017b7e3..febcc802 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -52,6 +52,7 @@ "item.unicopia.changeling_badge": "Changeling Emblem", "item.unicopia.bat_badge": "Bat Pony Emblem", "item.unicopia.kirin_badge": "Kirin Emblem", + "item.unicopia.hippogriff_badge": "Hippogriff Emblem", "item.unicopia.butterfly_spawn_egg": "Butterfly Spawn Egg", "item.unicopia.butterfly": "Butterfly", @@ -141,13 +142,16 @@ "item.unicopia.alicorn_amulet": "Alicorn Amulet", "item.unicopia.alicorn_amulet.lore": "Time worn: %d", + "item.unicopia.pearl_necklace": "Pearl Necklace", + "item.unicopia.pearl_necklace.lore": "Gives underwater abilities to the wearer", + "item.unicopia.horse_shoe.accuracy": "Accuracy: %d%%", "item.unicopia.horse_shoe.speed": "Speed: %d", "item.unicopia.iron_horse_shoe": "Iron Horse Shoe", "item.unicopia.golden_horse_shoe": "Golden Horse Shoe", "item.unicopia.copper_horse_shoe": "Copper Horse Shoe", "item.unicopia.netherite_horse_shoe": "Netherite Horse Shoe", - + "item.unicopia.broken_alicorn_amulet": "Broken Alicorn Amulet", "item.unicopia.unicorn_amulet": "Unicorn Amulet", "item.unicopia.unicorn_amulet.lore": "Grants magical abilities to whoever wears it", @@ -344,6 +348,12 @@ "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_kirin": "Lingering Potion of Kirin Metamorphosis", "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_kirin": "Arrow of Kirin Metamorphosis", + "effect.unicopia.change_race_hippogriff": "Hippogriff Metamorphosis", + "item.minecraft.potion.effect.unicopia.tribe_swap_hippogriff": "Potion of Hippogriff Metamorphosis", + "item.minecraft.splash_potion.effect.unicopia.tribe_swap_hippogriff": "Splash Potion of Hippogriff Metamorphosis", + "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_hippogriff": "Lingering Potion of Hippogriff Metamorphosis", + "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_hippogriff": "Arrow of Hippogriff Metamorphosis", + "potion.potency.6": "VII", "spell.unicopia.frost": "Frost", @@ -480,6 +490,11 @@ "ability.unicopia.rainboom": "Sonic Rainboom", "ability.unicopia.rage": "Rage", "ability.unicopia.nirik_blast": "Nirik Blast", + "ability.unicopia.screech": "Screech", + "ability.unicopia.peck": "Peck/Squawk", + "ability.unicopia.peck.block.fled": "The block has fled", + "ability.unicopia.peck.block.unfased": "The block is unfazed by your threats", + "ability.unicopia.dash": "Flying Dash", "gui.unicopia.trait.label": "Element of %s", "gui.unicopia.trait.group": "\n %s", @@ -511,6 +526,7 @@ "gui.unicopia.tribe_selection.describe.unicopia.pegasus": "Join the Pegasus Tribe, soar with the Wonderbolts", "gui.unicopia.tribe_selection.describe.unicopia.bat": "Join the Bat Tribe, become the darkest night", "gui.unicopia.tribe_selection.describe.unicopia.kirin": "Join the Kirin's Village, take the vow of silence", + "gui.unicopia.tribe_selection.describe.unicopia.hippogriff": "Join Hippogriff Tibe, screech at your neighbors", "gui.unicopia.tribe_selection.describe.unicopia.changeling": "Join the Changeling Hive, your Queen demands it", "gui.unicopia.tribe_selection.confirm": "You have selected %s", @@ -551,6 +567,11 @@ "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.kirin": " - Is silent in their default state, and can move freely around the warden", "gui.unicopia.tribe_selection.confirm.goods.4.unicopia.kirin": " - Can eat fruits and vegetables, red meats, and some foraged items normally toxic to other races", + "gui.unicopia.tribe_selection.confirm.goods.1.unicopia.hippogriff": " - Flight and the ability to train to build endurance", + "gui.unicopia.tribe_selection.confirm.goods.2.unicopia.hippogriff": " - Can dash whilst flying", + "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.hippogriff": " - Has a sharp and noisy beak for screeching and pecking", + "gui.unicopia.tribe_selection.confirm.goods.4.unicopia.hippogriff": " - Loves stairs, fish, and meat, but mostly stairs", + "gui.unicopia.tribe_selection.confirm.bads": "but they...", "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.human": " - Have no magical abilities what-so-ever", @@ -586,6 +607,11 @@ "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.kirin": " - Lighter than other ponies, and might take increased knockback", "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.kirin": " - Doesn't like water", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.hippogriff": " - Weak to brute force attacks", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.hippogriff": " - Must rest between flights to regain their strength", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.hippogriff": " - Has a bird brain", + "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.hippogriff": "", + "gui.unicopia.tribe_selection.join": "Join Tribe", "gui.unicopia.tribe_selection.cancel": "Go Back", @@ -811,6 +837,10 @@ "unicopia.race.bat.alt": "Bat Ponies", "unicopia.race.kirin": "Kirin", "unicopia.race.kirin.alt": "Kirins", + "unicopia.race.hippogriff": "Hippogriff", + "unicopia.race.hippogriff.alt": "Hippogriffs", + "unicopia.race.seapony": "Sea Pony", + "unicopia.race.seapony.alt": "Sea Ponies", "death.attack.unicopia.generic.and_also": "%1$s and %2$s", "death.attack.unicopia.generic.whilst_flying": "%1$s whilst flying", @@ -932,6 +962,7 @@ "unicopia.subtitle.entity.player.kick": "Player kicks", "unicopia.subtitle.magic_aura": "Magic humming", "unicopia.subtitle.player.rebound": "Player Bounces Off Wall", + "unicopia.subtitle.screech": "Player Screeches", "unicopia.subtitle.ears_ringing": "Ears ringing", "unicopia.subtitle.heartbeat": "Heart beats", "unicopia.subtitle.entity.artefact.ambient": "Magic hums", diff --git a/src/main/resources/assets/unicopia/models/item/hippogriff_badge.json b/src/main/resources/assets/unicopia/models/item/hippogriff_badge.json new file mode 100644 index 00000000..c37d99ce --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/hippogriff_badge.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/hippogriff_badge" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/pearl_necklace.json b/src/main/resources/assets/unicopia/models/item/pearl_necklace.json new file mode 100644 index 00000000..8716891e --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/pearl_necklace.json @@ -0,0 +1,6 @@ +{ + "parent": "unicopia:item/amulet", + "textures": { + "layer0": "unicopia:item/pearl_necklace" + } +} diff --git a/src/main/resources/assets/unicopia/sounds.json b/src/main/resources/assets/unicopia/sounds.json index 86d150a5..67885c5c 100644 --- a/src/main/resources/assets/unicopia/sounds.json +++ b/src/main/resources/assets/unicopia/sounds.json @@ -29,6 +29,13 @@ } ] }, + "entity.player.hippogriff.screech": { + "category": "player", + "subtitle": "unicopia.subtitle.screech", + "sounds": [ + "unicopia:screech/screech0" + ] + }, "item.magic.aura": { "category": "player", "subtitle": "unicopia.subtitle.magic_aura", diff --git a/src/main/resources/assets/unicopia/sounds/screech/screech0.ogg b/src/main/resources/assets/unicopia/sounds/screech/screech0.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1343c5e5d1b245130979cf73b2a1d011336de62b GIT binary patch literal 39055 zcmce-dt4J|-Zwmx3}L`PXUL%gMw)~G0l_;#ph4+2kc3kM<&e;bx7%dE1M#pNl(oCt z-66y{govQ%BBD1$jUk97t=NP6>;_08+DcWRrMBH7xN2K{R@?6Gz1`jNUSPZTKKJu} zp6B!a^Ii_)TywZ)uHW@L|Gs%~>(&a00e#O- ze-N~@FLe3;x8N6-p8RK9dJ+b`kqN=yarNT=+A5e&MoI@a7;5Xbt$DFwt8hmxS-CvE zuuzyLOOwf-m8A=%<(q5vRM+m>D%9+1s%`kmuAQ5A?M_;H3mo!fjMcfSN*F@H8M#&% zpssi5AqayYqa-Qv@Rq`)GhO}CSGv0jmW~3l*6yy>08#Cb2Y=WJ(`$GTgg}%uto_v8 zLi1$SRwA*zp)aepL~&LaYA>713LE=VLiH}!1=sdnlS%Pt#D)+se@Iy%+Q%(l+L5%# zMu6RZLBoXTY;Qw&vb)a`o;D$D(WZTV`f$m*&)uim*L@+qa6NZL>V=y{TKP<6_4)t7 z+VqRY$*g<5-|xbf=OF~&lFN#&!E({1;prq-cLNye$+UzJ1*Qq*cXA88+;_c#Yd0h> zew9+j$+)prQ=u!?gSKbWOHG?UY})f-)2kc0_icRZ)eUd$+c>*#(_i+P2;2ADf4=(J zUzWDzsS9DKFD~ooLXuM)w=WCB&+%|Y|=ew_` zy!$$P`4$KUw=A{3+8)>cwr$yPbo2jxQ*N6`hLnJom+J+W>m{0U$>oNW&}9lwKwwRk z05!@}ry4R|YJBd)#^MhF zDV8Yme{Rjo`~oH-Iql<&zUDjuS6XW9U8a^&PCtrjSNPc zzyp?3P*i2^XI}WKX^-edE2fcT<*j=f)@3eK|aisn~MB#VHwpiw}(4 zJ=u6Zt6=+?kq@d?pXn+uN;>mIqQIgGYdUgR(aS<&>u$K3bQVa(zb@P($@}=K8~?Js z|5#8K6%V!>X{i-!pVRB~FE#Dl@asJvzqxPI?4Hj)eD$*r54`-e?Y}eDKP3kOLStQ) z$u80%zuenWk{kA9fq#&kdhX>;!Ie(Q3$IIxZ>C)PD*eT;({FGzW$DEgyiGTFd#3oC zD>64tWo(|(Z=Pw|{L#hD8{d3&!^Q6f=84#R_Tip?k(?zF5ofh86dXeSOLF?8?emKE zxWYq{4Tln5Il8sAXW-b$&j+00|4nkX+0S;{&(ijLbi1_mXl-kc=WXYXtLMLb=l{C> zQ*!bfBwz!QqiK-*i{$v^0u_*^*HenWelo}BZUBPr);#^M3jjgB4)zPndZes8b*4OH zraV=zd+z@%G2rS2<>;2M;)H7dN69R%h5BeKgjoSTaH>UcjsO$ zD{)qbi~b-xdo#=C=)6USA4|*K@c6kVhiLzE#EIPd5*AQ<2vi0^tU__2{D|-1p_roCEKG zp;}#@20iEkyL(-GV^6DdFiNA}+;cvBW=1^)x?e1JJuCD)eMQqT*OzIqRez{TZp4ZnCO*SidY zz9lA57C=;>e(CmWU#oAV7azV;aLDz_$$Nl&p5($M7R&~ZPwDhWYc_y!o!fdmo_B_q zP6N3E7HeCNtJNv(ae3ZZlV1F_x{O;~q2KiM_ji8r&g<;#7ne_cxM#_s_+J{(%K`<^ zc|=ZPw4QG|74~#2^#emua#|kfHiZ`@#i!eIlH$A2+=7AAU4;dyBOjzmlYqjCKXak7 z>gws!ACzxD)-_$VeF%bvnW5lsMgQ`=Vj-xdqkPF(&=e#EiN<#EX>PS6D<3bn%kTA` z>Pij}jgw_XM@UE3J?WVud9b^&s~mV1?`0JYbUEaA1wbJ#IT}DK0+%BJg4{kB68iEw zuZ87V!Xq|>L8lpzLU0+-c?!%i{<1d(5DF0G-TIVwmkDurb1k6y5*^>YxwHm=h_26< zDfq=Zx|tu3IjDljw`76~asGS9Wwm8bI!+a`)2ArqqHEKv!xMQLRlnv*en&x|ZnP zT~P$+4(NFn&|QAFciC}koLu(avhFRraKH#Ib%7;Z>H=?S=`rAxFqRm6r6x0x2uog? zBL-9kG2Yb(CKZ1qToe@UUYdm-1*EZp?@R@bA1dks6TJa$L6>IM=Gj*Yc<0OqRl8Gn zmlqWdj1Z@~#8&W~LnFiqFxx}mF)%&HnbXr%4teIiniOy|>F@%hynP5vdFWc!y?@`H zbdlJ;b297f&v(c_Fl+}V`#(0e4K0yD_DUT@6%E(hj+}mD?8e+O9o~i^2blQXA544U z8NgxS!059(c>j~tNg5r`> z{UvM9XEXA-XIUIRsMB^C#&kaUdjKU!J=!1nSFs#<{j0q!1} zF;t%m5S*d{Kt1w3@b`;z@n@z1iw6zc<-v>G^43&vbYO%qIm|-=L-mmN10V@wNBE>2 zkh?K853Ozl;~BP}f17V|+<5y)mH7a;rS0E>glYS^j3Ce+0V2*iJaRE+`?ZV@fzuX5 zpQ#3``AOrFP+L3X!Ic@A;u-62cP(d zK>nv})p-R)+LF?89Wa8RVbG5t=nzjR?m3p#9(nMo4y+SD z6m^)>#RYDf5=3iD_b4F-0|*RgOMM38Nz4w&xZIXv_NA-YZoFL3v1@U0_u@B;_ZJsm z-MV$lmTlX1?X2IjdFzg!n76V2dLQ;zeaEZ$$wdBB!VkWBP5ASTshO^s$aDPle!uvx zK^?JD>!n*YJ1;vcd4of_=A+EVJgl?WV7Zlarmf$iWf>5 z)ur71W2j>c5l4<1!zfDg$RKEjsv$?*{G;?kjBXgo_4#!SxvUW4-7p-yek7)!^|s?Y z0X=wB8uIsbf8W1t`pWrGJHy>k zlNYgabuySSz7Mh*!_Zg_WEsUEeoGu?B3ASpxNUP#u5e5(h#fPPF@&TX5=A{W{H(D> zR+PJ`|C?Kuzk9XnrYeaxV^bb;mI`T;IOKA+{_!FSI>}^Q?)Vg z-ng-)>Y;gLc~fAGkEdBkQVm z^2gKlf{5drw3j{|n7MJ@^(Vb1;52%~7JHbqaw>ArL^KqhKHae|MOWjl(ns+0BZh~S ze`_-ltUmk9d6af07->4@Xti5El^UiNLGX1ruSdoUQ&2C|X`qAZXE`d(nibR#{|l9%4K~C=D&Mw4k!c&Am)4zr>f7 z&k)+!(f208AiSf4bC2$=zk}lOMvMwY5U~#m*~?%r$kpuF77C(&xi=R*Yb5;3cw7wVu5 zDLzwKcY)fdRH9%iCM2kmu^4;B;nhNRq)oP$Mq#$n$l!-yFeKm~%o)axLKwFXi!=%u zEKSwMIOw;Hag5Z6uhlXoa~2fUR+{dn{OJGz0PWZdyV zS>lEoK^88O2Wh!+0?yj%AgWPE+=8Qn!?aPoYbBFmolHnI=Mbe$D)6{qClgMKq)~Nm z{bVad;|o@bjTJJsv14*JL)T?3SJe{Rgd+crKkF3SQdH_zZcRI;Jj;k6l%@C)AHpP* zQFue{+ys#}nZ?W%k_BqELN-S!)xAKEGSwwW0UMa)(0Kt0oIkq0o%Z7jd0sEtxi+Y% zW@m}_m5d{Y?O~QM$>?bjCWFLAKOr|NeMDT4fTCdeJmrI;7X%R6Or+TmNIAv)ZR3J2 zG2-Skf4IY1TJqj6PUn1ks`nEJEV;&CI#@MCYc%h{IvtyrQ5>2-KHTGRw%d%V)HFp^ zs@bkDQ{j4<{|kf{kX_H*e{4-upM}KRObWtb!iS9`2Hgx+niDX4+^giZ`#*i}{yL_T zt@eAw+{g=&;>zu3Pg#(L)TD`}t{g0JHy$>@r0rq~uxNYaAn?-)LZ@7&z#_YWB z`YE7}?>ud~byP~5yx~%t#chmn6Sk_I!=@F6;^P6J7Jg6yuqu-B6Zw-A=biwLPK1KZ z3PzmK*Fize9e83eOGf%T8-qk>4OJkxAsT3$e zB|(bQVC)_1tGJ(@aCr2z(Gr%Xjpx}^Q7IK(vx!QNVApCGEm9w>!khD^#4^zi>haWl37**1(c#EG_E6-df zB>RN2Blf~|uCi!u0!L1C=bY_K4=2l;3*%93T^{Pd@A?u2?V7-*VL#|cUj*lJ~mLc^7o%$czpk^ ziY?}8TN13Cxp3=Y)1^=4Z@g9N&P?MadFJx+T;j6Q-pwN+Gbo;WHRbDBPwfcdBsIMC zrS*0WXV7Htt~~yy09QX)o55zQhTJ^1epL2Qm+{`S-aaR}f51g}EbdynFrmq<`F(ns zULzkONQ+a*s%-O2toE4q$1t2EUaH)oPT{L=gwUL}=D>{`t=F~~bZV{_$JP2Dt5a=u zP1#0o#si;!xGccc@@~&yZOtg%+HB%^N9?Wrt_a4)m6{o>B2cQ#;qRBM{SDpY?)LD@ z##vfDQ(fvC-ejw-(mim`1}+RZrLF^>KxEmDb1S#fZilp{e#<}k1rNXhhD8aQoLKuwO#uR?D2+5Jlv_4Kf z8VmagW_xerd_nKHj5TI5iCHhIX*IiuovtWnlnbF`L0Ck_+dtkkVf&`!5l+s_o};0yJ*xH3Sl^%?})sWB;8R)%cM(QGLl9I$~`AZ%7kP8lO~ z-iP8CL@c1bP6E$Yqll6+Wk=e)d&LkGWFpy*vpc8P-F^8;T-F@teNN#}^>_NLL(KMD zwfh6+wr0Ioo+MN62+7bra9xXutn}Jj1Lk=ti64X4`(?l&JyNh8iDdm=v=2HsPRgJ; zbZ?4menO#Qu|dW*be=6Ya9L7&2=_5^#!)L;9LEm)0)MgeYB&F@=h-(V{>{Aq#Kk6p zWoCM;rZ?ByJ)cjPmW>zDxBceJ$(|DRIlgL(X*OmlXfU8QFBaKynGD1Dxs*b}`_(hbP3QS-wN($rv&KQ&RX%$? zyNx!mr^xCf5rZ){yXSyDg%-WR1|Bj<%0U!`wGwDcD3Ohz1Xl=ra*Bj4eW;Jg4Z-ZA zMu-*4L9xgcIR^G8%)dYSMUZn>_Ny_`ulD|EA*`|c`P&_*D%&>Atl_umBiigIc52r2bOk5{`r;6ACp9JwuP#mTDfgxzafXy|nVNx*jbp5X z`NIaWTB0;C_{HwwRb^a~O6!ru~aR=xVi+kef4j{f<@(<9&hR@}tfc&XbJV6D_w zt{k-As+y5$D^l;;^g|ab+iER=HOb05PmArzOb8P8$yhDpSlC`-l!4Bf1nfE){FF$6 zC<(R$#76c2ZW8mGA$#cpeZ~7$Z1&^dL=T_+mFC-d&ilvVpMU$(>3=&)AJ~*)Zqb~m z8nO+Tp5=uOnnvukG4s0ckiq6#J8Xf{k*HmURjai56(CNg^Kl~ISFdCQ6=@~C@^(Mk zDo5I!Pzy=R=O_mr%4iocY90?W?n)L_UC+O<*8n#jS`=OVkJRM0q|=)MyUL~t=ja*p zo(oClHw_VS!voi35mPzdW44*(H?+)Y7GS_4GO8hsQDtS`^LKFM^HzV>g1?zrR|55} zy<=sEp+~9xk7r}8kCoGBvff>EXTEIvufwL~TH~VePYm2yL4w zM8)Qe#Z(3cPJxUyR#rZDg|Z6{=75-u(~4v_Q#tq~UC)T@#pNZ?zQ=pB;rCk`m9~_} zR?mUEKl*zivF4vg?VE-P^Vt(_L$QBL+0+N;D>usZ!?WbKqhidX>NP`+o z1?dAC8Buppxzg}cvTzRUTfhV`Q0}b+msu)i#Y^H`W1=q15vt&Z!n+@L?8EPF`;WZR zO9$4(zAhURJe)$!Z{8SiHSllrOjhn2p^5tv=wdV3?kAC*F zMuTs-HA@eLzcUo$8lnv|7h?D;+g_W!WheMJukdQhNR^e3UcJsp#r$(u`x8|-ItA5=SL$AM}Oy=mU<#I z1LgeFvp(~!s-1ykTkUM^uzn}5@=gu&@SH8W2g6W2I(0Uz!6>1cn>Q@w3uP={%q~*(tr!8)RupNjP$v}@OUV()1ldEO_<0mTUy%5aF389@N{0|^K6a=&sjSP+ z5Cw$X8uhd^A|$E37ZC-@NJ!Mbxd5RY3LFM`4Ykoq`RK!3hFhoYHzpqr_Fb=2K(|FH zMLuA51n|L@dMW=YBRhN)V~_r_ab?W!Pgig3e^B;8RTYRyY_?}VpRJVsyldp>2evVM zYK_IbZdaD$~pJ&dMzG`kIIIUEi=2w=rT@Q2pe!F zhL2Q5950^HH4eKC8r`{MBX4++5W8yMG-&f1qs`%!UgNXF-7e0cMplf;BCfZKT%YPf zfG2V2^*{dYM?L4K4trcxsg+tCcW`$Il44GFZQ7g}=#i^=WjwZ5fnVaanbtmRcYSIR zW#+GJa*BnPWyI4Gf3bWrK66-|9XmFr5HyH|!rWjpryA<54`$UV=ON%sWr@<%ENwDJ zHflVy`;a9`dq~90&AnsoU7P1a2`ui;Le^XfYFn!FPPoabg?gk5B04H9@sg2l|R`3dH;X@QFbhB<{t&!eP*w;PwYu^Y0kArk^u{Fa!9dThTSv44L*bP_8BgSRy zacHngU#ws4HU`Y98M9|Vh%T-EQgdipiEK-*6v2>|&^aFk<8>@Qtf&t{OAb7xh>Bt& zN=CwgR{4>uN=b{c^cWHqC1fx}p+;YHgIdTCNBZEfXtBHo1*wfmoWiI^H5dmYL=BUj zMW&ll-|5oAgb3Mz(twJ(K1Vy^Fc}gmLaYToC8ZQP391=I#C8VS2BRz&MpP8AcgGZ_H4D3yHw$8d zyOZ}7T~3ec+|6QHlTfNqe8_mco1MU^NYbi>j!yXm_RBAx`s-KHdp+xzZ@;~B-lnm=cJ{_EUg>Hq zKG8g@+%mHH=&=sLNKckA3qrIi_DWj1Ncaz)4o8%E~rdvE6l5n{qRwQ-_D!8lUbFN`@{Q<}8a zNQB=LL5KWi^p60j}Q5;42fZ% zfe|@IdZkDEZpiZJu-%Nc1Kq-HY;C+d-QQ2Y5->az?1V!l#_Lk#I^NPJ zVwK8TqaLB1lv4(e;*ZpV!g01bPVT&pyM*EJ3lfM?Bs5|S`@_gZ8UK0v$C=+x@p(S=RbKj_vHlb<<)rZ{4&Nz7xQ-~JWFtF*qaVVg~eDhFR4dNrjX%Z){ z3wJSc;yzDLPLRW)3nFoB%Vpe%YFZ&*R#cogPe94%Ct3+PNn0VbSFu%HPynGygpD@S zG#z(OIiW}sE5+@o4@h>_QAmi4F{ybu7K`D6lOX+tDu`U67~da1FM^DMA|+&Pk^7?| zITQ@*#N#Hj821EOb;4W;s6_Y)oROb9?`!3xNeB!_=HzNB(7#vEseojlC{joE(i#&I z?}LII+JM}3)K5llod8h{2-Vhdw{&<0SLb+ifBLZOn{D50gHASnY&cr@?km4_zxIU}dTkprg*R@rXUu#}{^^L`of6hdkuUSlG$MxP@UGmXVK?*-3u*+f>CRb+k8Umx@ zY9@QsNuu3m{W$r?dO9#lx_z_7gCRMxfZaZ;T`fky&nL57Lr&=a*skZ>Ni>oiO)xiNmo{mJTs_@1alc&8 z0I%^XLO48Jp7*eXcU)vKT3TalG5kGsmj2APi@V+!SzF3GE@XIwFX(1Ggl)#Y zu4)Hi6WKI7%W&TKt}F*1GHa&Q8b8R6KfIvgF@Nx5DQayl(%uWlff_bQZU;LE**roE zS{qCJVOSW}TyLWaloJqf4;2uixJfJvV=Cv^6cH+!ggc4BSKm}F%hcU>$%flhkM>%M&YJvc8rFrEc1t5e7i3TXxW?>$L$=+B5&2f& zi#}=i3pba%4TZkonO8Eu`cwP!-kAF_Ky#c8|2*#fyx;!*abhKN6H}zos!q6zBREV| zBud*wl`1Z#9CmXu1nSi4H>g`qrp*Vh7af;+%s6l3diXgr&V(^2poYiQAt@!X92i#z$n8(BKiA}T zd+Y5$# zcDiPC+Nm2(n`vZLH~hvhnw;Pii<`PDbAL1MEckx%K$VMSlL|3I&K)(@6XMv=QOrIL z1*02E{EEa$oaRI^mBQS~Rw6AAaxmo#P+P3en^43B!>|)Y`Gi!bOlR+=M(2e}>JiG? zM??GBaCEgA@psA#)EGM<0^Vo5`8k@P#Mror+jbdLx1Un&C2YcOI-r6qVScO`Ph<%c z4Gh@mRZuN;dm)T?Q7xn{3uU-vSk1Pf!s%%iSP^+}x1TKIX!Lp>hVXd4NiTzx2a+qjF_Z=y-?gqv&z;%} z=@6yEnkP%CW-<7$tvP&Mp z&JW0B7+dG<$!zPliK$QTlKPy0PPrr1b*pr^r?O1`1LHuVxq1{2^r8HN8fXk_6=C)5 z>ZP2u=pGxmY>0#b^ofYc5VrT?`J{tdJ1-y_B)NAcN7^&9ma<3)IP71M)IuySu3lUeFD@o5Z{Rp(aWQ>yQ3wo@ zy1eM4tMUs`v56mkTQl(*N3q)9~Q8Kb=z38eFo5votzOvwhn0!RVgp;H3y{3P z`4`S5Bok6`WyMUXR)udYC~wf(QLtx40TBX3St)0vBxi1s!pu)_Pac_E5u6$isfcB(WnSPSklOxIt3Ex zi_TY00)vlNJ7|ItCkbLuR-M>Zpk`P^Mu;D*HnI6OI4hrJ^-&zKdRvvfD3PWVJ1#R* z@VrunB~bks;4xGNLF_?|kO4v#Zg@_jjAv4xk`1uCX`zC_dJ3! zuud40&k2YH1Q9e7aiFXPZxu9CBB*Yj9nA~^T@}nqLo9MEGQme6L0EiJ!C<6GAQl4n zg}~%ub)M41wn5d#>}F`;kra<7>kKqxqNVWuebJ1>c?V~~7hTQB8Sl=CYeo{B<L!)guPI z4Sq~jT$WMn-6*$u>1(9kOA!fT;~ULMd@d;Elc;S|sh0rp>#-(%B0qo7RH0wJt`ZC3 zRHPWardjn6@MJxn-J|~W2ayIg$7^7vk|}PHd96k+3mLp-ug&n23X5TPYYW+jqEe}c z&TAM*-bPLIpf=7)SOhx#5M0h3ih(?@LY?eOXw&t+#_IFF|_& z!o#r^XhD=vfg)bD9N5$5FccK3ZV$^CqB^zB*SgjQf?m=BLo{UV;DAJn52^vKEvS0QfK=NGs7FX#efc z{)F<7-=}{9$#MAbso#B;|K)pk2H!v5RJ|i+7u8KuS8jav$5VT@d^NN6rAzW~!PRq7 z0ct&h5b|WIv%VEC~J@1{If2l+Z;$g;USt% z?YVfwq1Sk;rpY%ADJ82M?X{j$CLF*hCwf)ioT4M-$fX!kK772rDMJoxE21kj!%miq zFh83La5?gjK~IHu!(|6vBSr72_Xuc(J()eB{%l24bpI&n4!GW3q}AaBl$c#tJ=Yd%Ad@V zAvP2$00ja?Vi1H}loIh1_m+S`pxCwnP2y=>+B<52q1xaTFI>?YReh}Q)SsX}F(dA` z#_vA+!^5+8-Ye?`0tG2+em%d*8ke)Z>yukJ~j+OW(%_qtYJd`G9|$c!#EE`_8_ zw9uLS=dR34?ievyRjiSS#kuaPJalLD+tozo;LO0OO%J;(wV(3Tsr)Is2%7KXy<%|b z_3|OJ{nK>0F2$_JAzkz|*=JwpG}^_LstBGM-;4})+pd*PsS#C5f-(FHF4oQnH|Gq| zpc3CEqU?s^iop4o`zVi?KUKmTSGd4$fMzau1}dlgyVLbvcOb!R(7iLj&q$5@Vw>G~ ztJr`4Z}Bb;I|FNL9k98{Tb6z)lv%U(+aDqx)YfIS_b|=~#qo$xoGU}aifq_?L2a`Q zZRsVVwz69(xO#$S;=+Xj0sNxvOb|{jD$vs9WdNI_3(x7V7@#HhC9A@+0KTg(*s+#@ z?+-At9XYhr=ae3~D%r+O#&j{{bzGJ=5f+Va1#u3h^{WszKVXD>aLq(mGmYbTns_og zZL$>(CD{Z918|rk)X2_)8)_VlV2zXgsBQ3#Mx;Ei;yWdyV2+BkV0;*28VqGXW? zpn?NGg?mxB4b&1W0b{Aakv|N;Ct0Gz5=VWFzk`Z{VHIE+E4uDTpDZk#Q&AXB3Yod2 zLjBFD~s>$|pdpEc$0dFt(=W0NoV z4&bK?n!o(r#J4+ts{2dFVAtmpQmfHKs2%YvOYKVxr5(k@|wJ}*h+1ihzww=GanacXm*e^CB0&LxQ3_I<2xcV;ff)TOKMIwl&;L| z1-Ml5pJ`WW!p?w1SQu(g98*9!vd#jB93erx1Hw!%3SpMZQNspGL_Sue#3qo#(%Ah` z(8<0->;#uMJYfJBh0A!DTI@R|<--aqokpr1%zUxX2#uM_xGD;Y3_XPwg{&)#qehk5 zbqtG5EubL<`1R(zfMN>kCh5j8@!ss%1V%SC2IUDU5nwD(qT|8@by*~}G~-n6UI7Dt zBv9mwjQ|r^qZR-tx~jzA$*C6_9h|f~?1S)LBnZ$y+=IKC&_ul?$F>hFH__p73xS91RMQ*m|Z%&%wQ zPxz3~nyo#3q3WSWO1oQ<#A#{vH_lxwAp3H;Qy*R4C_e#=p?GV0aeJ-0*^&;%ztdV0ICGm_vOo*fCP)f!27OJUr7q_vhE z-cppN5HpQHSUFMgSrI&2xJcM{x=-zvTLl0It|* zuAD5>-ZSyE1^5k>zBO zAQC>DxAnU0gmBs9vb>Ug8A+^l>lmw=Z9S>Y&xie75UY5n?5Re#)k~zBOgUuO3P0YbStB2-I$s%|mp^`7LEWWl)<2}YAReS0%{pc6lMtYj^^I`7v?sOjKMyL$& zR_%CLx`Iq@!tp83MX^hiIUR&n_eqy|2J8w(7?7Il3~`Z|Q%AW$g`s|I8vEI7fEI_4h}T&0W! z8;FBKOzmTUc!v~m_sKEbSVv^rAP$kw0xQ@HQh97byf6_4XN3xbS&V$8WS&Ujw;4rZ z{v1fMlv?R=CcqlV3=~s#5?19=y>U^Yk~<*k**ejQ-#8{YTtg-w2-B?-CIG;@(m^%O zDFw}O^)(Y9afYQuA{0TPz4I&ayGPgN$V}O1d^Yt z=c%k`MPrSw`3Zzj!Usbb^7fTmx0rvFj^s5=5`DSP4Cp0azV_10k<-w3Z+u*{k!Ih2 z^vqvIuKnf2cQ4(4Y5iCKFXu=mea@Z2`l?*Lr7Su+ni9K+%Fwg!T4MIumNnz0^66o_ z+bzAB)UZ)(+IZvGWI&=s1hjqZhD3FDNz!AWX16Ejz%u9stNse{fw-FWHI>x*bK+YL3Bwj#z>*oM3 zK{eVQ1o4$Bh~dssSx!ho$l4@?cX)RK$ozyb z&_iKbv5kr{WwYZ9*=l9IfTr*|Wr>4;>mz#`LA{w_6%q^|r&S?PUyB8nx4>zR#W8d?(wI|>HAnV|lU$qv?R(3dx z^uo*7)Qvj8GIbXQ+){D3Sw7wFPOEGSq@Uws4_HlYt+mh2gmtr$S=H-i&pGYQ{e8wa z2D>xWA%U*VF)o7_{OD%Tr!Y_AL+S|f`W9nCtML&L)UiCrrPv@^VQyu&k-&d zHQVh%qY&UWt6$Q~%68;TckJAdwH6h-x--{TR``9~6mn0ptH&0Sy2Z72OP%KKC1r2&%U=tHNtb@Zzc%pH-MV=6~k-kzqab7E)aj;d7Kr={a} zjX!w9fNE^SHPx++x#Hu9??~YgQEbaR{9^7t2eCl2Tj8y!uayA5R*?&9e9ek`5bzNM zia4X7nTba+jT01_)zGf&#o(;EJRb_9&CICKd5D@rWsn*aqt#ZW55I>{y&|Yu0CK`0 znGb-`0H-^Za9jyu zWy3g1!_Ccbci|bvs!qB{bU&RHQjowTw5%MF&94YWa)Yn}7pa6n5Kp5WbX@*CG|^FX z{eE|QG$O`wFfM8<0~kvfA(~-$zZk%BE;|j#!FZ>-i&I^o1Of$t9Pi5W;?IBm*WVd` ze|Prn*n1bFj(zdf#N^Jm?5AJ8yJ&gkc=f%X^?qDb<9Rm@m@8wc{?aweVKXF^R!{e+)ZEmf-3fY z#Fh!XAn~giN@mysYnvk^cy<_jF0xL_+YaWY!gj=pD1yPs~k zA|&V%SgDjqNW@Aj5eEoydSN^&t%Rl_U~bxbnbo~eE1Wnh}dw8Kq11bea&*#1Vzckxym~- z{uqg3_I)ToVGRp9<%~&)CS=KBNK0SGZjfy_0zOL_y6#9x;(e-HQcCRBh9nf867|LP z$tO{eF_f_!70r45(22eqpG!{k36Wg&B-+7b+AeeIr0ho+KQs=_J?)GaIgzS{6#4S+ z5Fx^!y!u?2<@ycIjYrNztaH8$SpgEYvKIypoqh7OW8cXE+xox%G*Q-8W)sO%U_EgrBUeYkLuCmSa zMt1_snII)CZiv2CGks%Mk1Zfe%}i9dW6W=?cJ;M0#+Yv48o6ti$^syh7H%i=Z9ig< z>JT~m|6%J}pqe<-zu%cm!Vm+U2_X%LHVFZe7}^AZMy2f}gsTw~2pF-KB;bvz1*IdqD;U7JUg5mbyzm$3b;Tx)TE%|Bxf+3My?0xDl9S% z>}J%&?aRe#IHVUx1VR+aiG=c`6y>3EF2*$GvFe*+DxG*I5gr~6B`evTJIZm68ZcO{ zVB^w)IEctdB;b+&l#SD>>|BgMtq^k!s4<3Bgn4Te$O4hF8Hj4)@)7$;&r-i&4=ux8 zI)!6&UP7&`$sl`|(g7+*vL_tAnN*E}YId~LrR{3zXcl03T`j3{rqPc@5zJ3;wgvU; zmml&L?SVqN%M*orh$8EdIwK~jJkYX~Y6f6AbEJp)=Qj4`ob~m{{5n|Bv+LUh$1mRf z=+4lIo;`QEf7S87os@El`a3-GbW)|8c3T9NrN_M` zO?6j;ahXtO4YewoXcCEnp1k0z8e^2PD2p>dAK*um$3Pq)bjiJb>+)hnbGkvvJfdoF z2~_%F+gmXeL;Fi6pMNdqFV~dMecW^F%;%&?`R>Z-XcO}CDSxfV%@(J#Z2b|#P1bI) zyZFCLg9gZ$5NACC_#>7<2dB{m??Yf25UJpm3bZgI7Br{&C@Zq(uO| zPn_DSF|{bu$!SqnQP6z3;F?uXSF2RIg-GTcTu9Auix5^8=patJjGF|p3l9m`f`@^E z98_!xw2&KdDmMTtS2S{DPN?A5hpPo*F@$;>>cY)&>@pE8RP(Y`0vZTDUIx7e2ra0j z05A5uMVS{{=Tse9Dz<^~7_JaHu9$>xLaL9g8}oua`6;zt8+S5BFYFV15>xGMktEV6 zR<9{kCc;h6Ytw~1QDKlUjL-H6QFj7SDP<)JL49KlKIT<}G6R&v%^!By2_dk;P%m70 z^}7WxXRY|_vv2R?UAyx`x zWK`ZEcX#;W077cWCC%n!vm!m`cKYzztydqnxr=q=P)A93T339qw%0C;085Kq+y7$_@L37R41KHj+00$&pl zzxu}0vJ}EFoMqe;svxeF+)icF9QmT95P7=Ek%#kGIVcJx+Co*}x{yZe41oqDI4EFQW6&-d6l3b|^n=`3S)9Orfnx9mj^2)*RhE0eTo( zBpoiorQC-@kwUEqh;wGaBMg*AAkU6Ja(z(hX&^GlkvR~VMMiR>21wNtA>pJqg#X6BHg0Uz69M2Acx@@R_5vf>Zm1>k+9qB_)$QW0T!4GAHw29>5uv(3czdc`(a>;H0Cpv^f^OxQ;W zBk%0`wwP&2LTU|1hA<=et33(vq8?F}Z5)cuB(vk;80yX;6c~vhvxp}LhX5TR%-BbZ zbv&fet zEp$9##21tqIrdOy4X~1eh7lD0VL(cr^_k(Pa2Fz+rvp(8m(rCwL1xf4gmK&!gP@6m zBqdiU5Q&86S^;yhC`;B?<#4D`_gU#-Kw1Ta#TA7@Ry;ROun`+yCW6qcmIA;MP;b}y zCd0W!ep74|qfwa+T}~nEJ+q*pR>)aAZ#}yNcTY?J(H(p-bO!?Wxu`)k78Z3EJVF2h zdjx?#9xTIAYZN$Nc&}zh`HjG%IhNkpoKW48CvTQv)nB=dyT07_GgC8q;#pOH>lc^* zAl#(xg$v`rY5sx=cfK_JXvxcB^PS$(>Ba+LhoVMPAuW?q=63Ib3!1io!>&vhs0~+h z>=@uv>+~F_AU|0gm`Xt+(l-SH1qPO51y!4cIp3q+}U?!&VDL0P@%QHXb;&NyQfnf z+#%PDCCzxSZnJ9rnA`f|yx=V^M#hvS+kJR5T`Lr`M?q69dBy7CblnN-l( ze`FEG95}FZMz(b40l`kV7f_iibsA@vS7V@rvqJ(lMcB5d$j6p33UK+OLR|()44NH) z5JxhZNpZfBs?9XXe zGw9gU={v7jk1qPpmzgUa=_O|b^yZGQ)5L8j4bK{fefiTDE|(nd@ORkUvQ7C(uxG#8 z2wiS{>e364UOXv1>CbOJU&vvek=fEha`T{ZAsMx9U~|*)uTrw)yfto!d=;gIs)^{~ z{p*@Gm-$MDiqj(29Vs-G@cT^|_a(MjKMLW5C}7G81qWkiWY2Ek_ZOKYT#b3^Ym3Vs z!e%v0vY42vcyZ0Zu3aK04kf7_TeeP{idRgX8a-vHD>qi{J=xOgYiE|JROFfE!z)UU z_kI+7ymxb~Yr0Z*sPx4CBmGAHg+h~wS6_PP)a0io6I3_GJ}EnrB3~MvIezh2=~}ii zo2_RIh|-&wQU3!DbU~jma@*Q@Xn^U0E284n* zsIw68b^}Za)e+4eQO*s=2zmW(>Qs3<7Q~rE8w$!`10R#(B-~+UJV7X+(YR(;e3Gtm z%AwZEGnx-{@C00vQSNc6A_@1|8s2INiZv02I8wEblasdqE5A`Lp+lM)td>L%gKJP3 zPAa95Il*g#aL=s=?)WjIbx5F4$>#0YNxcb9&a!U;wPZYP;OHF&#bMa7AYyt@=W?Ma zf3=V@1DBa5a42Dy1k{{-ZEhyyj5I^KAl}Shkn7Nmw}`HHwk$2s1<6{*c42VRYr3J< zZqKlL1+f$QMK$SAUxP`GcQtE@4vsb(?ooXzrA(Narw)Hkah&tf0{e>U1GFYI9r3 zrYoj9*Edg(oq%3+`aTnooOTRFv>f>x)(jKllv9S2(64)0P~ zHTubZUYj;W27>B%CyjYTa{#Fu?Gj`-Y`{a*LPSD$gLcsY8qDiT)he0b6F*PB$L)7z zcg1I3YFwI~+v$pjJ#JJcHHH8LDhlo8+-mu*5g~dBiGjjr0m-oBdT_X!$?XLmC}tER z-*heolIB3Ih*j_0Bsr9Sw3UWZ!z_csnJWPbx5Ww-tLJ>U8^I$-d^KV|S|fl0rbrFq zCN|xz5vODo42b{NlhVTnH&%*@$sf8ZQ$A!hya5zU%n3Ee(28!MN~b{}+(hpnm&^ zpf?n`Vo0@haCr1Yx*PHymElzRbpK^um0_rf?e@yHmS_S52PRb*4{6utwzlTVnj=e^ z*mAZTKn^YD!&5M=qv#;S<&QbtG8otb1nIk{fsvdXboX1+^rIDJ!{!Jkw$Lq}v6c<| z@^k<4g{39q$PtvDy{mJy>;tP;W@W9?J8ZaAwk#8+F13(Vv!~QtTScK<8yCa(D{-_N z8h}T=5F-cloUA0F2Z)I>&(g?oH3K^mKxGqc6NSDW3FSy4lr;((>IN48Pj|>C)oKw* zJI@hJZQt}&A>ZZU1SI<@Lcm}yRqnEbeH0DNb|8anil0?N`yXsJXd{fpDyx(Tw1shS zW7(C^g`hgE4U2P$R6-VnzMv;3CP|_jtSL?5wzmQ7?6hj3(_>s3@M9@J6AkTtmT>vgvD?!&Q@qh+U>Wp8m zP=Y7+r~5bC`s;nu0~IePMCf1r{N8LJ<{#hB(%X{~MRTFt;GSAXV_WjVpHl^L2ln*( zi;0Cn%K7a}ud$zb`^%q?1oSa)HS$y~)(7i;d-mhxx8IN{9ZYRME!?&MSSBm(tOtg* zM`Al?wpQ$@4x%N-w5=Nk-+#U&DFxq8&RleL)B$Z3?{sIA5bW^`M zXd2yc|OSaO1F$m&k}#S<2Ao>zu?BON)7H^8ULzr0ye$JwY^rY>sU(Fs8Mr z6oW2@wmfA_bz4D#ES$hrX6ZbmZBbE|ZGGza8yqzvO3}*q_I!fGw`p<&su*5Rd$1UZAXMY52g%8f6I5k8 z&ep`S8i*>hf^4w3rr*{pgEd-t95bPIb2SDf z2nJ+Nsywn`ZW9Ed^TK6S<)_S?n0zfrol?gw+vj#VJkIlyZ#jTnOM5TJn7Am)l^2#e zT08<+*?&-F7H+Vt47JuSaWb#1&ib$+Vo`i^8kxXapw2+Xht%y3Zj)%^hkNQ7Pd&x> z6@Y59e_YUUg1i6l)xN(x_SzMC=C-U9iEdF z;yt+2tmBLhx~ziF0Mgz+T*QGYQL~c62yJ)~JucdNvSP@E4=FimtB$g190#u0MBBjC z#=4Mg9xU%aaDgCya9J&y2nKVi!e@JH2FiBH;@8rqgQ>h|6>(<99}YkO#dMsw;5MJL z*buC6@3P{Y-mBZ5jLzhx#cfFser@Ws*=8b|_Ff&tJ7~N7W_qUn(J(~;XG9!GCVX(*|h45z! z63_CGhXs}D_5&bCPbYK>#iKr59CjTl*`cK!)f!}`l^F@Btg`wB$C;1sRv3KGa^U4>OhR>8|a=HCu4Rs5{EQLC&}odS__)tbZLYfdo2v^ zNDx*EA#{dr?1aU59O5+a?9k#H$s$-y8dA)vH{xe0&kpVEcuZJxfP}gg5&j5-uj<3` zjT}0@3e`z2EfWIO*s|+*T*GMDAiUEfmPXJJmKxhz#`aD0aoTz&^H?5Nlo;-l1*Wz! ziB!)PtLpP7Hq%`auNY$XxGE-LpF@Dtpl;T+xiK%Var02HV@w!B=XtpptZwKi0sAoa zujlGrwf7&reK`4z?^c<}mjCwz)d6OT4Z~)hT1tl=FVRP96eY%iM)yZ(uUZjCjIxFH z?hvBdYUE^c^u@y;V|9LUuUV&$iduQ_BM;w&(;ar}a`PE;T=8++s6D>-N@VvM&k5G8_1KO$woOOS*L*9B}tF4wravOJECN3U~8(iP8*_rU^GA_iV5 z^fx3P(rj#_Eb=;y4Pdo|!af>R1)N5KuZ0KQvvrp!iBAlJEf`S$cOxKx@Mt+yu!?d_ zZD%blm@g$yUSATwC?27HXf zp>PUbrcDo6&u4w9c;AJY9{zdt__K+x)vS3)^^eKtHhh~U@jiIr4ei${-;SPn5LTGR zEd*gn(%w?jUXrIeHUpJn$DN||0r<5RN{8+5ZZVTaX7MDEIdp(O;6L8wjJP>d97H>M z`#LIcK50}XyUdH!f?n4ZaGLG(&qR}yDR|1W8EKmK**YTS&Z4l}={YYew?>wzj$4Wu zMN_6@{A1~7hQ6@)k00tiE)v`GZrCp{hMs!x{F~WW+NvDRlrkc0pra%#jkCheJhQpk zDoBSZLaK=3Q6sc>b+}58dCQ8TⅆLBR1*I&>-Fm6Ur2vGuA7n&^A@)6;pDrYnn># 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/dash.png b/src/main/resources/assets/unicopia/textures/gui/ability/dash.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f3938a977a669cc299a3382d4bcf09e04ff01d GIT binary patch literal 7125 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/dash_old.png b/src/main/resources/assets/unicopia/textures/gui/ability/dash_old.png new file mode 100644 index 0000000000000000000000000000000000000000..029293fef9d55aa2e8e8be3baba18d4254176ce8 GIT binary patch literal 8759 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 T=2>#!d;n|-+pIG;?mhfJ?zi~Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/peck.png b/src/main/resources/assets/unicopia/textures/gui/ability/peck.png new file mode 100644 index 0000000000000000000000000000000000000000..a89a7cb325cddd35006f5a7e7ac00e4e0c3f8930 GIT binary patch literal 7346 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 bd+*!dtMARZ8+Gh8e2!+b{5%WhEnoXTINNi~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/toggle_flight_land_hippogriff.png b/src/main/resources/assets/unicopia/textures/gui/ability/toggle_flight_land_hippogriff.png new file mode 100644 index 0000000000000000000000000000000000000000..4d981f1e75d54241e5fb5c20c2fef66403e323bf GIT binary patch literal 7240 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/toggle_flight_takeoff_hippogriff.png b/src/main/resources/assets/unicopia/textures/gui/ability/toggle_flight_takeoff_hippogriff.png new file mode 100644 index 0000000000000000000000000000000000000000..46068f0d68715b369ac7e693e87711415db71cd4 GIT binary patch literal 8117 zcmeHMd011|wm;01ib_%yQ7~3P(~yBMMGys|paMpbAX6HW01-k$5@sV-MQd&yNuB{G1(0qG4+g;$U2aBpQ_!LA$3_;KWTb8T6kG=hRNENgJOF2bI4z>Xz z_k}JmrvNE{wxd8610A-3MO#iucK-qB%V+gipc~BE$O9cOClAdB_aq<$pd-Nj5)k&W znYoIAUJXQ5_Gbq)7EZgGc+QC@i>AJ36Ce?%=GX$lCc@d*ce#L{ruS@ zFceaQrl1*Y7-^0Z3_HgO*5^1`16^U(UpO+#U+BnL9p)}4KZ9upkDb*g=D`!p`99q+ z-3Be(w#9x6m8%R}ISw&e%RYgTbO-)sO9%BAH4UKur7HerDR%q+4T%oO_ zqxZF;z8>nE)jB!`rt7}J;fX||uD-dY8NmYZCcq$aYHDipH0CXxKYuAa-4$lySq@lR}pq|2NyZu59f+ zQ&%@SFdU*jWOWTAF*SWuH$HwIO-4|wlD{J(cFKJrDhW?LCwa(^U94^U&(wSnqX#aH zeD&K#{LiUkgN4+~^*;eAh>5DGitiCQ&5x>R9S@bNk1Y^)^ggNlaKOt+P(pJ;y9O*G{6Znv~dIJp-7@%;!jIYKU+?v(X6Qt z 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 W?nC(PQUmxnZclc!&9?sb(0>722C8}h literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/gui/race/hippogriff.png b/src/main/resources/assets/unicopia/textures/gui/race/hippogriff.png new file mode 100644 index 0000000000000000000000000000000000000000..057c22409e21fdc91613ef0bc6383267b36b0e52 GIT binary patch literal 6551 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/item/hippogriff_badge.png b/src/main/resources/assets/unicopia/textures/item/hippogriff_badge.png new file mode 100644 index 0000000000000000000000000000000000000000..057c22409e21fdc91613ef0bc6383267b36b0e52 GIT binary patch literal 6551 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/item/pearl_necklace.png b/src/main/resources/assets/unicopia/textures/item/pearl_necklace.png new file mode 100644 index 0000000000000000000000000000000000000000..057c22409e21fdc91613ef0bc6383267b36b0e52 GIT binary patch literal 6551 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/data/trinkets/tags/items/chest/necklace.json b/src/main/resources/data/trinkets/tags/items/chest/necklace.json index 675082d4..6b3f0e07 100644 --- a/src/main/resources/data/trinkets/tags/items/chest/necklace.json +++ b/src/main/resources/data/trinkets/tags/items/chest/necklace.json @@ -3,6 +3,7 @@ "values": [ "unicopia:alicorn_amulet", "unicopia:pegasus_amulet", - "unicopia:unicorn_amulet" + "unicopia:unicorn_amulet", + "unicopia:pearl_necklace" ] } \ No newline at end of file diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index 95738783..045db477 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -17,6 +17,7 @@ "MixinChunkBlockLightProvider", "MutableBlockLightStorage", "MixinDamageSource", + "MixinEnchantmentHelper", "MixinFallLocation", "MixinEntity", "MixinEntityShapeContext", @@ -34,6 +35,7 @@ "MixinPlayerManager", "MixinPowderSnowBlock", "MixinProjectileEntity", + "MixinPufferfishEntity", "MixinServerPlayerEntity", "MixinServerPlayNetworkHandler", "MixinServerWorld",