From 7787ca68b58eaf9bbff4a0be289369ea164e5e87 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 27 Aug 2023 14:56:18 +0100 Subject: [PATCH] Add a time change ability for the unicorn amulet --- .../unicopia/ability/Abilities.java | 3 +- .../unicopia/ability/Ability.java | 8 ++ .../unicopia/ability/AbilityDispatcher.java | 2 +- .../unicopia/ability/TimeChangeAbility.java | 69 ++++++++++++++++++ .../magic/spell/TimeControlAbilitySpell.java | 69 ++++++++++++++++++ .../ability/magic/spell/effect/SpellType.java | 2 + .../unicopia/client/gui/UHud.java | 6 +- .../unicopia/entity/Living.java | 2 +- .../unicopia/entity/player/PlayerPhysics.java | 2 +- .../unicopia/entity/player/Pony.java | 3 + .../minelittlepony/unicopia/item/UItems.java | 2 +- .../textures/gui/ability/time_control.png | Bin 0 -> 984 bytes .../unicopia/textures/item/unicorn_amulet.png | Bin 4578 -> 4805 bytes .../textures/models/armor/alicorn_amulet.png | Bin 565 -> 4674 bytes .../textures/models/armor/unicorn_amulet.png | Bin 0 -> 4679 bytes 15 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimeControlAbilitySpell.java create mode 100644 src/main/resources/assets/unicopia/textures/gui/ability/time_control.png create mode 100644 src/main/resources/assets/unicopia/textures/models/armor/unicorn_amulet.png diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java index 94134e78..bbd82471 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java @@ -20,13 +20,14 @@ public interface Abilities { BiFunction>> BY_SLOT_AND_COMPOSITE_RACE = Util.memoize((slot, race) -> { return BY_SLOT.computeIfAbsent(slot, s -> new LinkedHashSet<>()) .stream() - .filter(a -> race.any(a::canUse)) + .filter(a -> a.canUse(race)) .toList(); }); // unicorn / alicorn Ability CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY); Ability SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.PRIMARY); + Ability TIME = register(new TimeChangeAbility(), "time_control", AbilitySlot.SECONDARY); Ability TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY); Ability GROUP_TELEPORT = register(new UnicornGroupTeleportAbility(), "teleport_group", AbilitySlot.SECONDARY); Ability DISPELL = register(new UnicornDispellAbility(), "dispell", AbilitySlot.TERTIARY); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Ability.java b/src/main/java/com/minelittlepony/unicopia/ability/Ability.java index 014c2125..979d7f97 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/Ability.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/Ability.java @@ -56,6 +56,14 @@ public interface Ability { return false; } + /** + * Checks if the given race is permitted to use this ability + * @param race The player's species + */ + default boolean canUse(Race.Composite race) { + return race.any(this::canUse); + } + /** * Checks if the given race is permitted to use this ability * @param playerSpecies The player's species diff --git a/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java b/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java index 232fcfbf..6ae10a9f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java @@ -262,7 +262,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable { public synchronized Optional> getActiveAbility() { return activeAbility.filter(ability -> { - return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && player.getCompositeRace().any(ability::canUse)); + return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && ability.canUse(player.getCompositeRace())); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java new file mode 100644 index 00000000..d79ce12b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java @@ -0,0 +1,69 @@ +package com.minelittlepony.unicopia.ability; + +import java.util.Optional; + +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.ability.data.Hit; +import com.minelittlepony.unicopia.ability.data.Hit.Serializer; +import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.entity.player.Pony; + +public class TimeChangeAbility implements Ability { + + @Override + public boolean canUse(Race race) { + return race == Race.ALICORN; + } + + @Override + public boolean canUse(Race.Composite race) { + return race.physical() != race.pseudo() && race.pseudo() == Race.UNICORN; + } + + @Override + public int getCooldownTime(Pony player) { + return 2; + } + + @Override + public int getWarmupTime(Pony player) { + return 20; + } + + @Override + public double getCostEstimate(Pony player) { + return 400; + } + + @Override + public Serializer getSerializer() { + return Hit.SERIALIZER; + } + + @Override + public Optional prepare(Pony player) { + return Hit.INSTANCE; + } + + @Override + public boolean apply(Pony player, Hit data) { + + if (player.getSpellSlot().contains(SpellType.TIME_CONTROL)) { + player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL, true); + } else { + SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE); + } + + return true; + } + + @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/magic/spell/TimeControlAbilitySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimeControlAbilitySpell.java new file mode 100644 index 00000000..a8712113 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimeControlAbilitySpell.java @@ -0,0 +1,69 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import com.minelittlepony.unicopia.ability.Abilities; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.*; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +/** + * Internal. + *

+ * Used by the Rainboom ability. + */ +public class TimeControlAbilitySpell extends AbstractSpell { + + private Vec3d prevRotation = null; + + public TimeControlAbilitySpell(CustomisedSpellType type) { + super(type); + } + + @Override + public boolean tick(Caster source, Situation situation) { + + if (situation != Situation.BODY) { + return false; + } + + if (!(source instanceof Pony pony) || !Abilities.TIME.canUse(pony.getCompositeRace())) { + return false; + } + + if (source.asWorld() instanceof ServerWorld sw) { + + float yaw = MathHelper.wrapDegrees(source.asEntity().getHeadYaw()); + float pitch = MathHelper.wrapDegrees(source.asEntity().getPitch(1)) / 90F; + + if (yaw > 0) { + pitch += 90; + } + + Vec3d rotation = new Vec3d(pitch, 0, 1); + + if (prevRotation != null) { + pitch = (float)MathHelper.lerp(0.05, pitch, rotation.x); + + sw.setTimeOfDay((long)(pitch * 6000)); + } + + prevRotation = new Vec3d(pitch, 0, 1); + } + + return source.subtractEnergyCost(2); + } + + @Override + public void toNBT(NbtCompound compound) { + super.toNBT(compound); + } + + @Override + public void fromNBT(NbtCompound compound) { + super.fromNBT(compound); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 53dfc899..d5607e7d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; +import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.util.RegistryUtils; @@ -48,6 +49,7 @@ public final class SpellType implements Affine, SpellPredicate< public static final SpellType CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new); public static final SpellType RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new); + public static final SpellType TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new); public static final SpellType FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, IceSpell.DEFAULT_TRAITS, IceSpell::new); public static final SpellType CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index a46f23cd..2794bdbd 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -137,7 +137,9 @@ public class UHud { slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta)); - if (pony.getObservedSpecies().canCast()) { + boolean canCast = Abilities.CAST.canUse(pony.getCompositeRace()); + + if (canCast) { Ability ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) .getAbility(Unicopia.getConfig().hudPage.get()) .orElse(null); @@ -168,7 +170,7 @@ public class UHud { matrices.pop(); - if (pony.getObservedSpecies().canCast()) { + if (canCast) { renderSpell(context, pony.getCharms().getEquippedSpell(Hand.MAIN_HAND), hudX + 10 - xDirection * 13, hudY + 2); renderSpell(context, pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 8 - xDirection * 2, hudY - 6); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index c6321016..2a668fdc 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -312,7 +312,7 @@ public abstract class Living implements Equine, Caste if (isBeingCarried()) { Pony carrier = Pony.of(entity.getVehicle()).orElse(null); - if (!carrier.getCompositeRace().any(Abilities.CARRY::canUse)) { + if (!Abilities.CARRY.canUse(carrier.getCompositeRace())) { entity.stopRiding(); entity.refreshPositionAfterTeleport(carrier.getOriginVector()); Living.transmitPassengers(carrier.asEntity()); 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 b10ee952..0f607c6d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -336,7 +336,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab double horizontalSpeed = this.getHorizontalMotion(); double verticalSpeed = velocity.y; - if (Abilities.RAINBOOM.canUse(pony.getActualSpecies()) && horizontalSpeed != 0 && verticalSpeed < -0.3F && (verticalSpeed / horizontalSpeed) < -0.3F) { + if (Abilities.RAINBOOM.canUse(pony.getCompositeRace()) && horizontalSpeed != 0 && verticalSpeed < -0.3F && (verticalSpeed / horizontalSpeed) < -0.3F) { ticksDiving++; } else { ticksDiving = 0; 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 71594222..779d4e61 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -199,6 +199,9 @@ public class Pony extends Living implements Copyable, Update if (AmuletSelectors.ALICORN_AMULET.test(entity)) { return Race.ALICORN; } + if (AmuletSelectors.UNICORN_AMULET.test(entity)) { + return Race.UNICORN; + } return getObservedSpecies(); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 111fd4a1..0c72f71c 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -146,7 +146,7 @@ public interface UItems { AmuletItem UNICORN_AMULET = register("unicorn_amulet", new AmuletItem(new FabricItemSettings() .maxCount(1) .maxDamage(890) - .rarity(Rarity.UNCOMMON), 900), ItemGroups.TOOLS); + .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); diff --git a/src/main/resources/assets/unicopia/textures/gui/ability/time_control.png b/src/main/resources/assets/unicopia/textures/gui/ability/time_control.png new file mode 100644 index 0000000000000000000000000000000000000000..e6f52cdc02532c11718764bb2870f08a2a747060 GIT binary patch literal 984 zcmV;}11J26P) zUr1Yb6vsd3CNs55O;Te=gi>WMqY4%g#WA)ix(87<7#r*%qN9D7Y%rL(hf)~G2DG; zpI+JZpUwwREh3^t%OyJ4s{;-GOfVGDK&6kXGoR7g*=6USswk}l&IeGf*82-x-9!fq ziY?HZBBZS4?E$Zdq@y=}du(Z84k##JJo*jU+$PUXy~bjEgZldCm~Nio%pb3F>DHR1 z9#36M#ZY+C5RpvD4yfv|h@^v|h<|BeE?d*sO2=_G7rYk%c=F37aMCbyaAi;jzS?#cE; zEO@`BBiqikwe4GSH@ELw0;}##z5-W=VK81kLG5M@C;mLa%`=y%-K^mj(2;H5W`A_B zSBgD!NJKVDo`kA;t&R-af&(c0PN z7-;b4Rn-uYd`Trx)nN4-d?-BW9qsSA z`^e4$pUa3XEzC7871yhUiS}XSo#5j@H82a@7LnVk>JpLkBR!1bvH8X=%MV8Sy2nK1 zmytfL7LmLEa4u8og~Zrx2qjihv5~&+uYfjBT}v789cOLt;q2j#0)H3_OACWaCJMdx=F&~t^Pxii`Q74*_jV2$ zVKdXdsxbI&KkK8V`Rvo`r2E=V60Qt|M^e)yiziKK%dfo~tbR4NC;jL5zmd#Y2a_Be zRQwF;4{zx-??^YxZT@Um*fKSB>W?`UmzHn~*%!rr{Lx!{GPNw?1Wx)1h0Y@=6O*w#N)ZJq4!zWZ@a4|DBqht&@) z?jP^FY{l4g{=n3GAFt0k@J9V*Z=aYg6WjL2?$>?G-Y`zLKJa0(;_OY@teKogl|IzD z-JinVme=^tG(Ycc@f)Fmw5;*jwk1_sUUGT&tVf}oP3HcM#aR$BsJC2 zC{5SWz%WhM#Ms+c+}JG9G||Y&EP1jQyEn4t`RsWdEJbssSWOlbFyfGA Qv{2i!*7M6|Z-MEI0064^H~;_u delta 593 zcmX@A`bc>~Gb7W)7DEpY1_lO3AcoQIp1uJJMtX(@dd4OU3`Pb<##ROvRz_wD21Zsu zwvi!FHRA$iupW>;5b$$0_MiAyv3{xRD!#G_mlT~#H+6SeT+-DB)`|eP7@$^{P7*@v*>_@I1^}OinwMSobOUK7Uk89_YpMSXbH^aiv)LA#D zGnm{pGFrK0#_9E4jo~bUjr`6Xr_QW7?-?XD?`x_5+>r9Zc~9?tPv>35I+@XKqQ$}b zS8c9)9BnpdUbTEL+#VSj)_J~DooAQAN9F6H)9+hMml3N-yKy4zS?A#+Nh{l@%B7_` zE6-EwTRF?`r_;IAsh`Et*WOB)Tm4DAjqBGbqwATj6Avj(Q*dl)V$)i2$Z1a5ToGYO zEB~q=%6;)l)1B6FNmz;nG_&3O*!=(C`*a5k z{bu=K&m3NLJwBUp^ZX^|yQAK4NZe!7Teo}GCia+j42%6sZ%&Xs>F=!}*7)7{*D@P} zB5s~FJBwe>dHjX(#HBTt%nuw?G>BXDrnJADz54mLeE;-1`{CK<~MZkzd Sicws2;ob6AoAm^zGXelU9^`}o diff --git a/src/main/resources/assets/unicopia/textures/models/armor/alicorn_amulet.png b/src/main/resources/assets/unicopia/textures/models/armor/alicorn_amulet.png index 1ef9b9ae738775621b876db1783fb4e55000ee40..e8c32632242ffc47b78381918940e6a12cfb62f1 100644 GIT binary patch literal 4674 zcmeHKdsI}%8NUk%f+3~U0Fg#FE2;Rn`?&kQvIqjgDhmV%55?5`+U3IT-evc~u5VC4 ztbztqP6;u!@uXOe$w{jv5$mH!NmZgIQcN2H!4N_f!B{JSL_7ELZgSegIn96U?(BSb z<~P6j<~QGbyR$bbA=cMtfe!>hzWTW6WKb7^5;4~ke1G`YojXBwoyyP~_4;MdT<`#p z0uM+4tU^!(V|E0v-30ECJE%)R@dq}C;mQKR9KPNU?BFr`5U@kXFmAw>3EUuGP}hQj z0DC^De+vq|XLPP}z~)|a`F9+!IOg#>R&PiWB4U|TELVW>QbdkQH7KGMN)c44L=gm_ z1;3i~h+|6E-;@ECVmc}+Ngov@wAmRWZKfc|RlEHaU0hSr{F20!X3;ZVE6Y%_E}`It zsN%FwOr2j&N!oMqFAsYe7F5m;jJSM_-3^3_2xP~IiV_^hMyP${#$BV|e3#{H(R zAAOtYo^uh8hzLoLHl5n5E;FetyB~z-6(6P!57oLpJU-8Vm3`y=p>oGxs3Oyvt7hX- z&FU3L&SdoAX)0y6CNH&(y&Py?SYO+q$!$Y(JFCu1v#zHfc`qUNsiiA$Z~y4fx;J($ zGhfPX*S~Y{*n{H-c3yh8?(^jLUlJ^Cam%?bY}_%pYDl-CUZd-Ip`1?U^2o>zQcH!`+_uFeO++EUFUJ;;k^K2;EccVd1=^Fqw)CJ+CzW5_uyXAqfZ|9)7J*PhCZ-=;vTs6 zZ4iSlIyHmMFvOz-V-aH{gHvLc#l~$I6t>D`!-!mp72=eMw(3L!jps!|n$(HXl?JK7 z7DZ*#aa-(E%9eywVoNTeB}J>keZpKQAh1v@CUjZMRtM_RiFjTV*j%$jB;+A%u1=Hz z;wXx-Q$mGUA(p~1F1i2_h5HD@?4%J*j$SiH0iJZCY?ig55{c946g%Z&#%_|xv|6o1 zibxOy1_;=(*~(%r*y>o!QH*j#Qx3vT+gO^h3OP;;XYyH{NCf(YHnP;wDCL5}0Uegh8|x# z4+bcM0gYyee9k?6v`)m$kCF^QlPGU$6e?1#Rg$n$iD+R3rc}b1T5W_W1&QD|rj(JC zdJ2`^>R>S|L2*=oTucKVl|qUW1fhaKMZyY&R0-p1xdxWYwQ@PGRZ-e$6p3~kL?vdP z>J>*t0xD81LkJb7f-y`<04kXl#x)oY8!?mNCI8M*ew{?PTGQ*D2dH# z;yXCO(a0pdPK1c1lPyVRj5UG*I#E1r&38?9q|z2Dg~d2EWh$*)CY8w%M1g34F$qee z><$o#94DVU`5tatP_P&vEXKttAmH1}(L~mr=r(}kL}Dx!jj<-4rIx#yHX#zR|tw4D4zfi(ZexsI7M?14AZWn-Huv7yh>i-l> zGPYm|movs!947gWCSg2aN|FKNM%zI00=ZB!kqpN)I#_!`@bA8-ahJv+&a^qrM! zR<0Q-FeC76bj`{&BL!vzo{g^mn_NDV*D1;h{slR~Whph~-Gktw<%zG0jfOsgz^pzofFK!49uIlUUbGBCBJYOnY zvpT}^5*WUbL~I%fVy%_CS>by`Y&Ssb)aJC z)VTyz^~f6oir)ynEWxs_)(w4}RngSn-&y)*VCg-Zznd*dEYCUJ?YFJ*?B~D!IONqU zdCsjPSGo_Zho8PoIW^t_=-uE0f}zS*yMO74ZGN^J=09U)UlfLh+}QF$SAd_deIPM0 zbH(9XKhG#z^5oiX0aJaX``BRDfIq(?xulZroegP=AE;dYt; delta 518 zcmV+h0{Q*IB((&PBYy$>Nkl+48vP@_aOQ2 z&(4@HmF|kYGhSm-002j8Ysu*De=<4A=FScuDiwl4;kFpIuCGmg77CynMQIU)VVKO9 zN(6-h+qK$V1p|A}AENI6uEN`B&|B8mIr)<3Ihe z8$~>?R{0bJJb!C8b72@Jd#x4#-wqF%FO@h70)PbIqThFQv(N#W&1P=U1+Lod^k6tR z`F}h)NsC}}YAOL3-u;7kjrlcj^sfJUeVvU)gUN*jZaN*_%*^~2Zt1-^=J@y+fVV3v0PNQ5RLW%llb_`dFxm-TE-t3uz8)O#qth|@ z51{}?$HD38smXr`hrrQs@CuTNi3yW0lMoUc97&QSNz&i@1-@p#Me#8oDgXcg07*qo IM6N<$g8!iSw*UYD diff --git a/src/main/resources/assets/unicopia/textures/models/armor/unicorn_amulet.png b/src/main/resources/assets/unicopia/textures/models/armor/unicorn_amulet.png new file mode 100644 index 0000000000000000000000000000000000000000..405ba2a7f256267f9738d0fda3503e39481cbebb GIT binary patch literal 4679 zcmeHLdsGzH8J`6OB$5)N(Ws5XYKmfJcW3rJusj!Kg+&6$qe7C|*}KcgzStRHAu5Ui zO`=8-!5Z2$iHTN9Jhk{}eSjxYTMn)7YKRf6TAD-!VhJJ!duMpJIqmVB=09f7-TTeG zzwdYN{oU_=aQDrm#H9iLv;7eS2{6RzlVQCMmPkJz_@MX4WvQTe^_M9QR650!gFkaBcMP5h%tZQH) zpgkSd`(a@=4vuva+Wg}ueBz+RGY{8G4aOvtkl-?jTmk)Mgq)OVNJ5Ru2vVse1E4Pn#41FLpPD;eTfC< z#aj>g$LY|rSQ>N(` z?)$Jb#CAI8is3ig-oL-+os!c%@wbxyxI#4ljMu7j=&`k35f5}LYc;ytFP80y?0oy? z>doG3jz!kq(6pV|dXW^Bo^9NDz5B}U#yi1ZZrS>r&dcY>`nSK{`tco6b!cPPj-YoB zE}qOxX%cs>UD8(RTkcptpmaL!vNhpI=I#{_eKeX$KUr3J;@z52sz&D*ZhvQtNR9aYAC@GXnoNlWW z*J`y=86hPI3?eYL$iYz_%)!p*DF!+8fTi7xi({M)l;@;O&U{WM7Q=pYcz$-5(Ktfy zV24zIdPqH#ONvWmQoCI`)`R6@3n0nRgud5Tf8M{mHf?|(Da*SnEtZ{SWdxYhTod|Rv;T?w_ zUb_H>D5H_oJL!CWdIr5t%#Tl+oit-61ye(rDS(@3jL<4*OrgMOj8Z8y7$G+Ug+-+z zG?ZlwmBGPsl!FF56(pB1kO$xj6OF3~OliU8n8IRGVOpHVF&f}9K$w&!$TNmwxtoDe zN!iBEil;I|Dg{tlfI_LoR4SzmQxIA?rlDvPCdUa}Lzqm2N~sa3%rv>g>9$jFI~hA= z1yYy8Ds=FIlTk?qotTiwMq83>6lZ}BI&lKy$oGtPq%wAp!cn}MxJoO>Ww>0f#c`Qh zO^kxlfSZMp$a4z0Q|RHhg@lWN!cu&kLIR;3u7!+o1B!FHQ=LwmPCSxzN4kyhIGHJq z(o-COq$7DabvO?%mf@sqaQZx*(P?HZMgI%UA09Le;^CIZF)SRvNN5^7Q7IsA@NMwb z#t26VMTJ8_QuN>wSgHV+g?U1*!7e(7a##V(9z)?e+|GPoC|Jz2TBX)ta==HEmQrCR z870SnT1lwkPHHqb7|+f+EnFex22ob1Bh(6pr|=gFT_|kSqVed$9Ki1a6bzHW7*+qf zVA7!lOZl8Jyy7tFe`pdW0LCO4=r`B~lNZc|(vf61q#2)fe!ypFFMhxgAoau`Po(dJ zToZCVkpfQyo`|jqxt>UYCjw7I*Z)l}|IzCdaKQh93gKnx@S&`$@S^2oieIWnE+X(g zcAMB!3tOhR;xbtTdFoldh>+bivtXkyXE4V4cKFQ^se| zskvvmm#?i~%G>y9S)1MM{lXJ?me))jXr3W z%qjgUdO-&oY$)ce;W5>TRd-^gwtH8vewLlR=~7!x?ys^Q?frHa@@}ZbQO9&xAHN)- z`0YaNK>gIChdzF0-IT{(aTQy-9eQ!l;p>PH(NvwaPT%{P+vFWb5N^`EZpLvQwHf8P3ZMMrl@ zC#q{go%epu#ANRJ;6+r@zwDzT!-avK;~#WYb0vxL z;Is3tOAHmIjq%_5Y%33GH>*N@wUgHe8$udZrhOv6lt88J?^X1#?Q3b5_owVX|4mEp zG0StGK>-TyvIl3j_h%n2+lx)=?!Ne=S&x_i(T0eopx3(ipH=?bbF{K8FFjy#;IFx6 P9%hJ5)PEBFTIs(4<;8SE literal 0 HcmV?d00001