Added gemstones, feathers, and Wings of Icarus

This commit is contained in:
Sollace 2021-02-27 12:24:09 +02:00
parent 42670af93b
commit 59c2f400d0
24 changed files with 480 additions and 59 deletions

View file

@ -18,5 +18,5 @@ org.gradle.daemon=false
# Dependencies
modmenu_version=1.14.+
minelp_version=4.2.1-1.16.2-SNAPSHOT
minelp_version=4.2.1-1.16.5
kirin_version=1.7.1-1.16.2-SNAPSHOT

View file

@ -2,16 +2,27 @@ package com.minelittlepony.unicopia;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.sound.SoundEvent;
public enum FlightType {
NONE,
CREATIVE,
AVIAN,
INSECTOID;
INSECTOID,
ARTIFICIAL;
public boolean isGrounded() {
return this == NONE;
}
public boolean isAvian() {
return this == AVIAN || isArtifical();
}
public boolean isArtifical() {
return this == ARTIFICIAL;
}
public boolean canFly() {
return !isGrounded();
}
@ -24,6 +35,10 @@ public enum FlightType {
return canFly() && !canFlyCreative();
}
public SoundEvent getWingFlapSound() {
return this == INSECTOID ? USounds.ENTITY_PLAYER_CHANGELING_BUZZ : USounds.ENTITY_PLAYER_PEGASUS_WINGSFLAP;
}
/**
* Predicate for abilities to control whether a player can fly.
*

View file

@ -1,5 +1,11 @@
package com.minelittlepony.unicopia.ability;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import javax.annotation.Nullable;
import com.google.common.collect.Streams;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit;
@ -7,8 +13,17 @@ import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.ShieldSpell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import net.minecraft.item.ItemStack;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Hand;
import net.minecraft.util.Pair;
import net.minecraft.util.math.Vec3d;
/**
* A magic casting ability for unicorns.
* (only shields for now)
@ -31,8 +46,10 @@ public class UnicornCastingAbility implements Ability<Hit> {
}
@Override
@Nullable
public Hit tryActivate(Pony player) {
return Hit.INSTANCE;
System.out.println(getCostEstimate(player) + " " + player.getMagicalReserves().getMana().get());
return getCostEstimate(player) <= player.getMagicalReserves().getMana().get() ? Hit.INSTANCE : null;
}
@Override
@ -42,50 +59,81 @@ public class UnicornCastingAbility implements Ability<Hit> {
@Override
public double getCostEstimate(Pony player) {
if (player.hasSpell()) {
String current = player.getSpell(true).getName();
Spell replaced = Streams.stream(player.getMaster().getItemsHand())
.map(SpellRegistry::getKeyFromStack)
.filter(i -> i != null && !current.equals(i))
.map(SpellRegistry.instance()::getSpellFromName)
.filter(i -> i != null)
.findFirst()
.orElse(null);
return replaced == null ? 2 : 4;
}
return 4;
return getAmulet(player)
.map(pair -> Math.min(player.getMagicalReserves().getMana().get(), pair.getLeft().getChargeRemainder(pair.getRight())))
.orElseGet(() -> player.hasSpell() && getNewSpell(player).isPresent() ? 4F : 2F);
}
@Override
public void apply(Pony player, Hit data) {
getAmulet(player).filter(pair -> {
float amount = -Math.min(player.getMagicalReserves().getMana().get(), pair.getLeft().getChargeRemainder(pair.getRight()));
if (amount < 0) {
AmuletItem.consumeEnergy(pair.getRight(), amount);
player.getMagicalReserves().getMana().add(amount * player.getMagicalReserves().getMana().getMax());
player.getWorld().playSoundFromEntity(null, player.getMaster(), SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.PLAYERS, 1, 1);
}
return true;
}).orElseGet(() -> {
Optional<Spell> newSpell = getNewSpell(player);
@Nullable
Spell spell = player.hasSpell() ? newSpell.orElse(null) : newSpell.orElseGet(ShieldSpell::new);
if (player.hasSpell()) {
String current = player.getSpell(true).getName();
Spell spell = Streams.stream(player.getMaster().getItemsHand())
.map(SpellRegistry::getKeyFromStack)
.filter(i -> i != null && !current.equals(i))
.map(SpellRegistry.instance()::getSpellFromName)
.filter(i -> i != null)
.findFirst()
.orElse(null);
player.subtractEnergyCost(spell == null ? 2 : 4);
player.setSpell(spell);
} else {
player.subtractEnergyCost(4);
player.setSpell(Streams.stream(player.getMaster().getItemsHand())
.map(SpellRegistry.instance()::getSpellFrom)
.filter(i -> i != null)
.findFirst()
.orElseGet(ShieldSpell::new));
return null;
});
}
private Optional<Pair<AmuletItem, ItemStack>> getAmulet(Pony player) {
ItemStack stack = player.getMaster().getStackInHand(Hand.MAIN_HAND);
if (stack.getItem() instanceof AmuletItem) {
AmuletItem amulet = (AmuletItem)stack.getItem();
if (amulet.canCharge(stack)) {
return Optional.of(new Pair<>(amulet, stack));
}
}
return Optional.empty();
}
private Optional<Spell> getNewSpell(Pony player) {
final String current = player.hasSpell() ? player.getSpell(true).getName() : null;
return Streams.stream(player.getMaster().getItemsHand())
.map(SpellRegistry::getKeyFromStack)
.filter(i -> !Objects.equals(i, current))
.map(SpellRegistry.instance()::getSpellFromName)
.filter(Objects::nonNull)
.findFirst();
}
@Override
public void preApply(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getEnergy().multiply(3.3F);
if (getAmulet(player).isPresent()) {
Vec3d eyes = player.getMaster().getCameraPosVec(1);
float i = player.getAbilities().getStat(slot).getFillProgress();
Random rng = player.getWorld().random;
player.getWorld().addParticle(i > 0.5F ? ParticleTypes.LARGE_SMOKE : ParticleTypes.CLOUD, eyes.x, eyes.y, eyes.z,
(rng.nextGaussian() - 0.5) / 10,
(rng.nextGaussian() - 0.5) / 10,
(rng.nextGaussian() - 0.5) / 10
);
player.getWorld().playSound(player.getEntity().getX(), player.getEntity().getY(), player.getEntity().getZ(), SoundEvents.ENTITY_GUARDIAN_ATTACK, SoundCategory.PLAYERS, 1, i / 20, true);
} else {
player.spawnParticles(MagicParticleEffect.UNICORN, 5);
}
}
@Override
public void postApply(Pony player, AbilitySlot slot) {

View file

@ -8,6 +8,8 @@ import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.Jumper;
import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
import com.minelittlepony.unicopia.util.NbtSerialisable;
@ -19,13 +21,14 @@ import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LightningEntity;
import net.minecraft.entity.attribute.EntityAttributeInstance;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Tickable;
import net.minecraft.util.math.BlockPos;
@ -38,6 +41,8 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
private float thrustScale = 0;
private FlightType lastFlightType;
public boolean isFlyingEither = false;
public boolean isFlyingSurvival = false;
@ -89,6 +94,9 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
if (!creative) {
entity.abilities.flying |= (type.canFly() || entity.abilities.allowFlying) && isFlyingEither;
if (!type.canFly() && (type != lastFlightType)) {
entity.abilities.flying = false;
}
if ((entity.isOnGround() && entity.isSneaking())
|| entity.isTouchingWater()
@ -109,6 +117,8 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
}
}
lastFlightType = type;
isFlyingSurvival = entity.abilities.flying && !creative;
isFlyingEither = isFlyingSurvival || (creative && entity.abilities.flying);
@ -137,9 +147,38 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
}
}
ticksInAir++;
if (type.isArtifical()) {
if (ticksInAir % 10 == 0 && !entity.world.isClient) {
ItemStack stack = entity.getEquippedStack(EquipmentSlot.CHEST);
float energyConsumed = 2 + (float)getHorizontalMotion(entity) / 10F;
if (entity.world.hasRain(entity.getBlockPos())) {
energyConsumed *= 3;
}
AmuletItem.consumeEnergy(stack, energyConsumed);
if (AmuletItem.getEnergy(stack) < 9) {
entity.world.playSoundFromEntity(null, entity, SoundEvents.BLOCK_CHAIN_STEP, SoundCategory.PLAYERS, 0.13F, 0.5F);
}
if (entity.world.random.nextInt(50) == 0) {
stack.damage(1, entity, e -> e.sendEquipmentBreakStatus(EquipmentSlot.CHEST));
}
if (!getFlightType().canFly()) {
entity.world.playSoundFromEntity(null, entity, SoundEvents.ITEM_SHIELD_BREAK, SoundCategory.PLAYERS, 1, 2);
entity.abilities.flying = false;
isFlyingEither = false;
isFlyingSurvival = false;
}
}
} else {
int level = pony.getLevel().get() + 1;
if (ticksInAir++ > (level * 100)) {
if (ticksInAir > (level * 100)) {
Bar mana = pony.getMagicalReserves().getMana();
float cost = (float)-getHorizontalMotion(entity) * 20F / level;
@ -163,9 +202,10 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
}
}
}
}
entity.fallDistance = 0;
if (type == FlightType.AVIAN) {
if (type.isAvian()) {
applyThrust(entity, velocity);
}
moveFlying(entity, velocity);
@ -173,9 +213,9 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
applyTurbulance(entity, velocity);
}
if (type == FlightType.AVIAN) {
if (type.isAvian()) {
if (entity.world.isClient && ticksInAir % 20 == 0 && entity.getVelocity().length() < 0.29) {
entity.playSound(getWingSound(), 0.5F, 1);
entity.playSound(getFlightType().getWingFlapSound(), 0.5F, 1);
thrustScale = 1;
}
velocity.y -= 0.02 * getGravitySignum();
@ -185,7 +225,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
} else {
ticksInAir = 0;
if (!creative && type == FlightType.AVIAN) {
if (!creative && type.isAvian()) {
double horMotion = getHorizontalMotion(entity);
double motion = entity.getPos().subtract(lastPos).lengthSquared();
@ -222,10 +262,6 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
entity.setVelocity(velocity.toImmutable());
}
private SoundEvent getWingSound() {
return pony.getSpecies() == Race.CHANGELING ? USounds.ENTITY_PLAYER_CHANGELING_BUZZ : USounds.ENTITY_PLAYER_PEGASUS_WINGSFLAP;
}
protected void handleWallCollission(PlayerEntity player, MutableVector velocity) {
if (wallHitCooldown > 0) {
@ -276,7 +312,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
protected void applyThrust(PlayerEntity player, MutableVector velocity) {
if (pony.sneakingChanged() && player.isSneaking()) {
thrustScale = 1;
player.playSound(getWingSound(), 0.5F, 1);
player.playSound(getFlightType().getWingFlapSound(), 0.5F, 1);
} else {
thrustScale *= 0.1889F;
}
@ -350,6 +386,10 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
return FlightType.CREATIVE;
}
if (UItems.PEGASUS_AMULET.isApplicable(pony.getMaster())) {
return FlightType.ARTIFICIAL;
}
if (pony.hasSpell()) {
Spell effect = pony.getSpell(true);
if (!effect.isDead() && effect instanceof FlightType.Provider) {

View file

@ -0,0 +1,192 @@
package com.minelittlepony.unicopia.item;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ArmorMaterial;
import net.minecraft.item.ArmorMaterials;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.StringVisitable;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import net.minecraft.world.World;
public class AmuletItem extends ArmorItem {
private final int maxEnergy;
private final float drain;
private final ImmutableMultimap<EntityAttribute, EntityAttributeModifier> modifiers;
public AmuletItem(Item.Settings settings, int maxEnergy, int drainRate) {
this(settings, maxEnergy, drainRate, ImmutableMultimap.builder());
}
public AmuletItem(Item.Settings settings, int maxEnergy, int drainRate, ImmutableMultimap.Builder<EntityAttribute, EntityAttributeModifier> modifiers) {
super((Settings)settings, EquipmentSlot.CHEST, settings);
this.maxEnergy = maxEnergy;
drain = ((float)drainRate / (float)maxEnergy) / 10;
this.modifiers = modifiers.build();
}
@Override
public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) {
if (isChargable() && entity instanceof LivingEntity && ((LivingEntity) entity).getEquippedStack(getSlotType()) == stack) {
consumeEnergy(stack, drain);
}
}
@Override
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> list, TooltipContext tooltipContext) {
for (StringVisitable line : MinecraftClient.getInstance().textRenderer.getTextHandler().wrapLines(
new TranslatableText(getTranslationKey(stack) + ".lore"), 150, Style.EMPTY)) {
MutableText compiled = new LiteralText("").formatted(Formatting.ITALIC, Formatting.GRAY);
line.visit(s -> {
compiled.append(s);
return Optional.empty();
});
list.add(compiled);
}
if (isChargable()) {
list.add(new TranslatableText("item.unicopia.amulet.energy", (int)Math.floor(getEnergy(stack)), maxEnergy));
}
}
@Override
public boolean hasGlint(ItemStack stack) {
return !isChargable() || stack.hasEnchantments() || getEnergy(stack) > 0;
}
@Override
public Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(EquipmentSlot slot) {
return slot == getSlotType() ? modifiers : ImmutableMultimap.of();
}
public boolean isApplicable(ItemStack stack) {
return stack.getItem() == this && getEnergy(stack) > 0;
}
public boolean isApplicable(LivingEntity entity) {
return isApplicable(entity.getEquippedStack(getSlotType()));
}
public boolean isChargable() {
return maxEnergy > 0;
}
public boolean canCharge(ItemStack stack) {
return isChargable() && getEnergy(stack) < maxEnergy;
}
public float getChargeRemainder(ItemStack stack) {
return Math.max(0, maxEnergy - getEnergy(stack));
}
public static void consumeEnergy(ItemStack stack, float amount) {
setEnergy(stack, getEnergy(stack) - amount);
}
public static float getEnergy(ItemStack stack) {
return stack.hasTag() && stack.getTag().contains("energy") ? stack.getTag().getFloat("energy") : 0;
}
public static void setEnergy(ItemStack stack, float energy) {
if (energy <= 0) {
stack.removeSubTag("energy");
} else {
stack.getOrCreateTag().putFloat("energy", energy);
}
}
public static class Settings extends FabricItemSettings implements ArmorMaterial {
private final String name;
private int protection;
private float toughness;
private float resistance;
public Settings(String name) {
this.name = name;
}
public Settings protection(int protection) {
this.protection = protection;
return this;
}
public Settings toughness(int toughness) {
this.toughness = toughness;
return this;
}
public Settings resistance(int resistance) {
this.resistance = resistance;
return this;
}
@Override
public int getDurability(EquipmentSlot slot) {
return ArmorMaterials.LEATHER.getDurability(slot);
}
@Override
public int getProtectionAmount(EquipmentSlot slot) {
return protection;
}
@Override
public int getEnchantability() {
return 0;
}
@Override
public SoundEvent getEquipSound() {
return SoundEvents.ITEM_ARMOR_EQUIP_DIAMOND;
}
@Override
public Ingredient getRepairIngredient() {
return Ingredient.EMPTY;
}
@Override
public String getName() {
return name;
}
@Override
public float getToughness() {
return toughness;
}
@Override
public float getKnockbackResistance() {
return resistance;
}
}
}

View file

@ -58,6 +58,22 @@ public interface UItems {
Item CRYSTAL_HEART = register("crystal_heart", new CrystalHeartItem(new Item.Settings().group(ItemGroup.DECORATIONS).maxCount(1)));
Item CRYSTAL_SHARD = register("crystal_shard", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item GEMSTONE = register("gemstone", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item PEGASUS_FEATHER = register("pegasus_feather", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item GRYPHON_FEATHER = register("gryphon_feather", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item GOLDEN_FEATHER = register("golden_feather", new Item(new Item.Settings().rarity(Rarity.UNCOMMON).group(ItemGroup.MATERIALS)));
Item GOLDEN_WING = register("golden_wing", new Item(new Item.Settings().rarity(Rarity.UNCOMMON).group(ItemGroup.MATERIALS)));
AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new AmuletItem(new AmuletItem.Settings("pegasus_amulet")
.maxDamage(890)
.rarity(Rarity.UNCOMMON)
.group(ItemGroup.DECORATIONS), 900, 10));
/*AmuletItem ALICORN_AMULET = register("alicorn_amulet", new AmuletItem(new AmuletItem.Settings("alicorn_amulet")
.toughness(900000000)
.resistance(90000000)
.group(ItemGroup.DECORATIONS), 0, 0));*/
static <T extends Item> T register(String name, T item) {
ITEMS.add(item);

View file

@ -30,6 +30,16 @@
"item.unicopia.crystal_heart": "Crystal Heart",
"item.unicopia.crystal_shard": "Crystal Shard",
"item.unicopia.gemstone": "Gemstone",
"item.unicopia.pegasus_feather": "Pegasus Feather",
"item.unicopia.gryphon_feather": "Gryphon Feather",
"item.unicopia.golden_feather": "Golden Feather",
"item.unicopia.golden_wing": "Golden Wing",
"item.unicopia.pegasus_amulet": "Wings of Icarus",
"item.unicopia.pegasus_amulet.lore": "Grants temporary flight to whoever wears it",
"item.unicopia.amulet.energy": "Energy: %d / %d",
"item.unicopia.music_disc_pet": "Music Disc",
"item.unicopia.music_disc_pet.desc": "Danial Ingram - pet",

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/gemstone"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/golden_feather"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/golden_wing"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/gryphon_feather"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/pegasus_amulet"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/pegasus_feather"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,15 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"**",
"**"
],
"key": {
"*": {
"item": "unicopia:crystal_shard"
}
},
"result": {
"item": "unicopia:gemstone"
}
}

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"***",
"*#*",
"***"
],
"key": {
"#": [
{ "item": "unicopia:pegasus_feather" },
{ "item": "unicopia:gryphon_feather" }
],
"*": {
"item": "minecraft:gold_nugget"
}
},
"result": {
"item": "unicopia:golden_feather"
}
}

View file

@ -0,0 +1,16 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"***",
"***",
"***"
],
"key": {
"*": {
"item": "unicopia:golden_feather"
}
},
"result": {
"item": "unicopia:golden_wing"
}
}

View file

@ -0,0 +1,13 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"*#*"
],
"key": {
"#": { "item": "unicopia:gemstone" },
"*": { "item": "unicopia:golden_wing" }
},
"result": {
"item": "unicopia:pegasus_amulet"
}
}