mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-08 06:26:43 +01:00
Implement enchantment effects
This commit is contained in:
parent
b033d1dc7a
commit
1601c14d95
30 changed files with 409 additions and 350 deletions
|
@ -6,8 +6,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
|
|||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||
import com.minelittlepony.unicopia.entity.Equine;
|
||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.decoration.AbstractDecorationEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
@ -44,7 +43,7 @@ public interface EquinePredicates {
|
|||
Predicate<Entity> EXCEPT_MAGIC_IMMUNE = IS_MAGIC_IMMUNE.negate();
|
||||
Predicate<Entity> VALID_LIVING_AND_NOT_MAGIC_IMMUNE = EntityPredicates.VALID_LIVING_ENTITY.and(EXCEPT_MAGIC_IMMUNE);
|
||||
|
||||
Predicate<LivingEntity> LIVING_HAS_WANT_IT_NEED_IT = e -> WantItNeedItEnchantment.getLevel(e) > 0;
|
||||
Predicate<LivingEntity> LIVING_HAS_WANT_IT_NEED_IT = e -> EnchantmentUtil.getWantItNeedItLevel(e) > 0;
|
||||
Predicate<Entity> VALID_FOR_DISGUISE = EntityPredicates.EXCEPT_SPECTATOR.and(e -> !(e instanceof LightningEntity || e instanceof AbstractDecorationEntity));
|
||||
|
||||
static Predicate<Entity> ofRace(Race race) {
|
||||
|
|
|
@ -29,6 +29,7 @@ public class InteractionManager {
|
|||
public static final int SOUND_MAGIC_BEAM = 5;
|
||||
public static final int SOUND_HEART_BEAT = 6;
|
||||
public static final int SOUND_KIRIN_RAGE = 7;
|
||||
public static final int SOUND_GEM_FINDING_MAGIC_HUM = 8;
|
||||
|
||||
public static final int SCREEN_DISPELL_ABILITY = 0;
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ public enum Trait implements CommandArgumentEnum<Trait> {
|
|||
|
||||
private static final Trait[] VALUES = values();
|
||||
private static final Map<Identifier, Trait> IDS = Arrays.stream(values()).collect(Collectors.toMap(Trait::getId, Function.identity()));
|
||||
@SuppressWarnings("deprecation")
|
||||
private static final EnumCodec<Trait> NAME_CODEC = StringIdentifiable.createCodec(Trait::values, n -> n.toLowerCase(Locale.ROOT));
|
||||
public static final Codec<Trait> CODEC = Identifier.CODEC.xmap(id -> IDS.get(id), Trait::getId);
|
||||
public static final Codec<Set<Trait>> SET_CODEC = CODEC.listOf().xmap(
|
||||
|
|
|
@ -101,7 +101,7 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
|
||||
protected BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
|
||||
if (state.get(CONSUMING)) {
|
||||
return state;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||
protected void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||
if (state.get(CONSUMING) || !state.get(AWAKE)) {
|
||||
return;
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {
|
||||
protected ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {
|
||||
if (EquineContext.of(player).getCompositeRace().includes(Race.CHANGELING)) {
|
||||
world.setBlockState(pos, state.with(CONSUMING, true));
|
||||
if (!world.isClient) {
|
||||
|
@ -171,15 +171,13 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
super.neighborUpdate(state, world, pos, sourceBlock, sourcePos, notify);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||
protected VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||
return EquineContext.of(context).getSpecies() == Race.CHANGELING ? VoxelShapes.empty() : super.getCollisionShape(state, world, pos, context);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
|
||||
protected float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
|
||||
float delta = super.calcBlockBreakingDelta(state, player, world, pos);
|
||||
delta *= Pony.of(player).getSpecies() == Race.CHANGELING ? 2 : 1;
|
||||
return delta;
|
||||
|
@ -213,6 +211,7 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
listener = new Listener(pos);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void readNbt(NbtCompound nbt, WrapperLookup lookup) {
|
||||
opening = nbt.getBoolean("opening");
|
||||
|
@ -225,6 +224,7 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected void writeNbt(NbtCompound nbt, WrapperLookup lookup) {
|
||||
nbt.putBoolean("opening", opening);
|
||||
|
@ -312,14 +312,15 @@ public class HiveBlock extends ConnectingBlock implements BlockEntityProvider {
|
|||
}
|
||||
|
||||
record Entry (BlockPos pos, BlockState state, @Nullable BlockEntity data) {
|
||||
@SuppressWarnings("deprecation")
|
||||
public static final Serializer<NbtCompound, Entry> SERIALIZER = Serializer.of((compound, lookup) -> new Entry(
|
||||
NbtSerialisable.BLOCK_POS.read(compound.getCompound("pos"), lookup),
|
||||
NbtSerialisable.decode(BlockPos.CODEC, compound.getCompound("pos")).orElse(BlockPos.ORIGIN),
|
||||
NbtSerialisable.decode(BlockState.CODEC, compound.get("state")).orElse(Blocks.AIR.getDefaultState()),
|
||||
compound.getCompound("data"),
|
||||
lookup
|
||||
), (entry, lookup) -> {
|
||||
NbtCompound compound = new NbtCompound();
|
||||
compound.put("pos", NbtSerialisable.BLOCK_POS.write(entry.pos(), lookup));
|
||||
compound.put("pos", NbtSerialisable.encode(BlockPos.CODEC, entry.pos()));
|
||||
compound.put("state", NbtSerialisable.encode(BlockState.CODEC, entry.state()));
|
||||
if (entry.data() != null) {
|
||||
compound.put("data", entry.data().createNbtWithId(lookup));
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.block.jar;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
|
@ -12,6 +11,7 @@ import com.minelittlepony.unicopia.item.UItems;
|
|||
import com.minelittlepony.unicopia.mixin.MixinEntityBucketItem;
|
||||
import com.minelittlepony.unicopia.util.FluidHelper;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.block.Block;
|
||||
|
@ -20,7 +20,6 @@ import net.minecraft.inventory.SidedInventory;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Pair;
|
||||
|
@ -33,15 +32,14 @@ public record ItemsJarContents (
|
|||
) implements JarContents, SidedInventory {
|
||||
private static final int MAX_SIZE = 16;
|
||||
private static final int[] SLOTS = IntStream.range(0, MAX_SIZE).toArray();
|
||||
private static final Codec<List<ItemStack>> STACKS_CODEC = ItemStack.CODEC.listOf(0, MAX_SIZE);
|
||||
|
||||
public ItemsJarContents(TileData tile) {
|
||||
this(tile, new ArrayList<>(MAX_SIZE));
|
||||
}
|
||||
|
||||
public ItemsJarContents(TileData tile, NbtCompound compound, WrapperLookup lookup) {
|
||||
this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE), lookup)
|
||||
.limit(MAX_SIZE)
|
||||
.collect(Collectors.toList()));
|
||||
this(tile, new ArrayList<>(NbtSerialisable.decode(STACKS_CODEC, compound.get("items")).orElse(List.of())));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -199,7 +197,7 @@ public record ItemsJarContents (
|
|||
|
||||
@Override
|
||||
public NbtCompound toNBT(NbtCompound compound, WrapperLookup lookup) {
|
||||
compound.put("items", NbtSerialisable.ITEM_STACK.writeAll(stacks, lookup));
|
||||
compound.put("items", NbtSerialisable.encode(STACKS_CODEC, stacks));
|
||||
return compound;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.minelittlepony.unicopia.client;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -18,6 +20,7 @@ import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
|
|||
import com.minelittlepony.unicopia.client.particle.ClientBoundParticleSpawner;
|
||||
import com.minelittlepony.unicopia.client.sound.*;
|
||||
import com.minelittlepony.unicopia.container.SpellbookChapter;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.entity.player.PlayerPhysics;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity;
|
||||
|
@ -47,10 +50,10 @@ import net.minecraft.util.math.random.Random;
|
|||
import net.minecraft.world.World;
|
||||
|
||||
public class ClientInteractionManager extends InteractionManager {
|
||||
|
||||
private final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
private final Int2ObjectMap<WeakReference<TickableSoundInstance>> playingSounds = new Int2ObjectOpenHashMap<>();
|
||||
private final Map<UUID, Int2ObjectMap<WeakReference<TickableSoundInstance>>> entitySounds = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public SpellbookChapter readChapter(PacketByteBuf buffer) {
|
||||
|
@ -99,11 +102,23 @@ public class ClientInteractionManager extends InteractionManager {
|
|||
return EquinePredicates.RAGING.test(source);
|
||||
}
|
||||
});
|
||||
} else if (type == SOUND_GEM_FINDING_MAGIC_HUM) {
|
||||
play(source.getUuid(), type, () -> {
|
||||
return new MagicAuraSoundInstance(source.getSoundCategory(), Living.living(source), source.getWorld().getRandom());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void play(UUID sourceId, int type, Supplier<TickableSoundInstance> soundSupplier) {
|
||||
play(entitySounds.computeIfAbsent(sourceId, id -> new Int2ObjectOpenHashMap<>()), type, soundSupplier);
|
||||
}
|
||||
|
||||
private void play(int type, Supplier<TickableSoundInstance> soundSupplier) {
|
||||
play(playingSounds, type, soundSupplier);
|
||||
}
|
||||
|
||||
private void play(Int2ObjectMap<WeakReference<TickableSoundInstance>> playingSounds, int type, Supplier<TickableSoundInstance> soundSupplier) {
|
||||
WeakReference<TickableSoundInstance> activeSound = playingSounds.get(type);
|
||||
TickableSoundInstance existing;
|
||||
if (activeSound == null || (existing = activeSound.get()) == null || existing.isDone()) {
|
||||
|
|
|
@ -2,8 +2,7 @@ package com.minelittlepony.unicopia.client.render;
|
|||
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.model.Dilation;
|
||||
import net.minecraft.client.model.ModelData;
|
||||
|
@ -57,6 +56,6 @@ public class SmittenEyesRenderer {
|
|||
}
|
||||
|
||||
public boolean isSmitten(Creature pony) {
|
||||
return pony.isSmitten() || WantItNeedItEnchantment.getLevel(pony.asEntity()) > 0;
|
||||
return pony.isSmitten() || EnchantmentUtil.getWantItNeedItLevel(pony.asEntity()) > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package com.minelittlepony.unicopia.client.sound;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.UTags;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
public class MagicAuraSoundInstance extends FadeOutSoundInstance {
|
||||
|
@ -12,7 +15,7 @@ public class MagicAuraSoundInstance extends FadeOutSoundInstance {
|
|||
private final Living<?> living;
|
||||
|
||||
public MagicAuraSoundInstance(SoundCategory category, Living<?> living, Random random) {
|
||||
super(USounds.ITEM_MAGIC_AURA, category, 1, random);
|
||||
super(USounds.ITEM_MAGIC_AURA, category, 0.1F, random);
|
||||
this.relative = false;
|
||||
this.living = living;
|
||||
setPosition(living.getOriginVector());
|
||||
|
@ -20,18 +23,32 @@ public class MagicAuraSoundInstance extends FadeOutSoundInstance {
|
|||
|
||||
@Override
|
||||
protected boolean shouldKeepPlaying() {
|
||||
var data = living.getEnchants().getOrEmpty(UEnchantments.GEM_FINDER);
|
||||
int level = EnchantmentUtil.getLevel(UEnchantments.GEM_FINDER, living.asEntity());
|
||||
|
||||
setPosition(living.getOriginVector());
|
||||
|
||||
if (!living.asEntity().isRemoved() && data.isPresent()) {
|
||||
float level = data.get().level;
|
||||
if (level != targetVolume) {
|
||||
setTargetVolume(level);
|
||||
}
|
||||
return true;
|
||||
if (level <= 0 || living.asEntity().isRemoved()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
float volume = computeTargetVolume(level);
|
||||
if (volume != targetVolume) {
|
||||
setTargetVolume(volume);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private float computeTargetVolume(int level) {
|
||||
int radius = 2 + (level * 2);
|
||||
|
||||
BlockPos origin = living.getOrigin();
|
||||
|
||||
double volume = BlockPos.findClosest(origin, radius, radius, p -> living.asWorld().getBlockState(p).isIn(UTags.Blocks.INTERESTING))
|
||||
.map(p -> living.getOriginVector().squaredDistanceTo(p.getX(), p.getY(), p.getZ()))
|
||||
.map(find -> (1 - (Math.sqrt(find) / radius)))
|
||||
.orElse(-1D);
|
||||
|
||||
volume = Math.max(volume, 0.04F);
|
||||
|
||||
return (float)volume * (1.3F + level);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
package com.minelittlepony.unicopia.entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.minelittlepony.unicopia.util.Tickable;
|
||||
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.nbt.NbtList;
|
||||
import net.minecraft.nbt.NbtString;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
|
||||
// TODO: Use a EnchantmentLocationBasedEffect for this instead
|
||||
@Deprecated
|
||||
public class Enchantments implements NbtSerialisable, Tickable {
|
||||
|
||||
private final Living<?> entity;
|
||||
|
||||
private final Set<RegistryKey<Enchantment>> equippedEnchantments = new HashSet<>();
|
||||
|
||||
private final Map<RegistryKey<Enchantment>, Data> data = new HashMap<>();
|
||||
|
||||
Enchantments(Living<?> entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Data> Optional<T> getOrEmpty(RegistryKey<Enchantment> enchantment) {
|
||||
return Optional.ofNullable((T)data.get(enchantment));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Data> T computeIfAbsent(RegistryKey<Enchantment> enchantment, Supplier<T> factory) {
|
||||
return (T)data.computeIfAbsent(enchantment, e -> factory.get());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Data> T remove(RegistryKey<Enchantment> enchantment) {
|
||||
return (T)data.remove(enchantment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
UEnchantments.REGISTRY.forEach(key -> {
|
||||
var ench = entity.entryFor(key);
|
||||
int level = EnchantmentHelper.getEquipmentLevel(ench, entity.asEntity());
|
||||
|
||||
boolean active = level > 0;
|
||||
|
||||
if (active != equippedEnchantments.contains(key)) {
|
||||
if (active) {
|
||||
equippedEnchantments.add(key);
|
||||
ench.value().applyLocationBasedEffects((ServerWorld)entity.asWorld(), level, null, entity.asEntity());
|
||||
} else {
|
||||
equippedEnchantments.remove(key);
|
||||
ench.value().removeLocationBasedEffects(level, null, entity.asEntity());
|
||||
}
|
||||
}
|
||||
|
||||
if (active) {
|
||||
ench.value().onTick((ServerWorld)entity.asWorld(), level, null, entity.asEntity());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound, WrapperLookup lookup) {
|
||||
NbtList list = new NbtList();
|
||||
equippedEnchantments.forEach(key -> {
|
||||
list.add(NbtString.of(key.getValue().toString()));
|
||||
});
|
||||
compound.put("enchants", list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound, WrapperLookup lookup) {
|
||||
equippedEnchantments.clear();
|
||||
if (compound.contains("enchants")) {
|
||||
compound.getList("enchants", NbtElement.STRING_TYPE).forEach(tag -> {
|
||||
equippedEnchantments.add(RegistryKey.of(RegistryKeys.ENCHANTMENT, Identifier.of(tag.asString())));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class Data {
|
||||
public float level;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import java.util.List;
|
|||
import com.minelittlepony.unicopia.*;
|
||||
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
import com.minelittlepony.unicopia.network.track.DataTracker;
|
||||
import com.minelittlepony.unicopia.network.track.DataTrackerManager;
|
||||
import com.minelittlepony.unicopia.network.track.Trackable;
|
||||
|
@ -56,7 +55,7 @@ public class ItemImpl implements Equine<ItemEntity> {
|
|||
public boolean beforeUpdate() {
|
||||
|
||||
if (!entity.getWorld().isClient) {
|
||||
if (WantItNeedItEnchantment.getLevel(entity) > 0) {
|
||||
if (EnchantmentUtil.getWantItNeedItLevel(entity) > 0) {
|
||||
var random = entity.getWorld().random;
|
||||
|
||||
if (random.nextInt(15) == 0) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.stream.StreamSupport;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.InteractionManager;
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.UTags;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
|
@ -40,6 +41,8 @@ import com.minelittlepony.unicopia.particle.ParticleUtils;
|
|||
import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
|
||||
import com.minelittlepony.unicopia.server.world.DragonBreathStore;
|
||||
import com.minelittlepony.unicopia.util.*;
|
||||
import com.minelittlepony.unicopia.util.serialization.NbtMap;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -67,6 +70,7 @@ import net.minecraft.server.world.ServerWorld;
|
|||
import net.minecraft.sound.BlockSoundGroup;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -97,7 +101,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
private final List<Tickable> tickers = new ArrayList<>();
|
||||
|
||||
private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this));
|
||||
private final Enchantments enchants = addTicker(new Enchantments(this));
|
||||
private final NbtMap<Identifier, Float> enchants = NbtMap.of(Identifier.CODEC, Codec.FLOAT);
|
||||
private final ItemTracker armour = addTicker(new ItemTracker(this));
|
||||
private final Transportation<T> transportation = new Transportation<>(this);
|
||||
|
||||
|
@ -152,7 +156,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
return spells.getSlots();
|
||||
}
|
||||
|
||||
public Enchantments getEnchants() {
|
||||
public NbtMap<Identifier, Float> getEnchants() {
|
||||
return enchants;
|
||||
}
|
||||
|
||||
|
@ -251,6 +255,10 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
|
||||
updateDragonBreath();
|
||||
|
||||
if (EnchantmentUtil.getLevel(UEnchantments.GEM_FINDER, entity) > 0) {
|
||||
InteractionManager.getInstance().playLoopingSound(entity, InteractionManager.SOUND_GEM_FINDING_MAGIC_HUM, 0);
|
||||
}
|
||||
|
||||
transportation.tick();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.minelittlepony.unicopia.EquinePredicates;
|
|||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
|
@ -40,7 +39,7 @@ public class WantItTakeItGoal extends BreakHeartGoal {
|
|||
protected boolean canTarget(Entity e) {
|
||||
return e != null && !e.isRemoved() && (
|
||||
(e instanceof LivingEntity l && predicate.test(mob, l)
|
||||
|| (e instanceof ItemEntity i && WantItNeedItEnchantment.getLevel(i) > 0)
|
||||
|| (e instanceof ItemEntity i && EnchantmentUtil.getWantItNeedItLevel(i) > 0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.util.RegistryUtils;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentEffectContext;
|
||||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
public record AmbientSoundsEnchantmentEffect (
|
||||
Identifier id,
|
||||
TagKey<SoundEvent> sounds
|
||||
) implements EnchantmentEntityEffect {
|
||||
public static final MapCodec<AmbientSoundsEnchantmentEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Identifier.CODEC.fieldOf("id").forGetter(AmbientSoundsEnchantmentEffect::id),
|
||||
TagKey.codec(RegistryKeys.SOUND_EVENT).fieldOf("sounds").forGetter(AmbientSoundsEnchantmentEffect::sounds)
|
||||
).apply(instance, AmbientSoundsEnchantmentEffect::new));
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends EnchantmentEntityEffect> getCodec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity entity, Vec3d pos) {
|
||||
Living.getOrEmpty(entity).ifPresent(user -> {
|
||||
user.getEnchants().compute(id, (id, data) -> {
|
||||
if (data == null) {
|
||||
data = 0F;
|
||||
}
|
||||
Random rng = world.getRandom();
|
||||
data -= rng.nextFloat() * 0.8F;
|
||||
int light = world.getLightLevel(entity.getRootVehicle().getBlockPos());
|
||||
if (rng.nextInt(Math.max(1, (light * 9) + data.intValue())) == 0) {
|
||||
data = (float)rng.nextInt(5000);
|
||||
|
||||
RegistryUtils.pickRandom(world, sounds).ifPresent(event -> {
|
||||
user.asWorld().playSoundFromEntity(
|
||||
null,
|
||||
user.asEntity(),
|
||||
event, SoundCategory.HOSTILE,
|
||||
0.5F + rng.nextFloat() * 0.5F,
|
||||
0.5F + rng.nextFloat() * 0.5F
|
||||
);
|
||||
});
|
||||
}
|
||||
return data;
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.entity.Enchantments;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
|
||||
|
||||
public class CollaboratorEnchantment {
|
||||
private static final Identifier TEAM_STRENGTH_ID = Unicopia.id("team_strength");
|
||||
|
||||
protected CollaboratorEnchantment() {
|
||||
//addModifier(EntityAttributes.GENERIC_ATTACK_DAMAGE, this::getModifier);
|
||||
}
|
||||
|
||||
protected boolean shouldChangeModifiers(Living<?> user, int level) {
|
||||
return false;//super.shouldChangeModifiers(user, getTeamCollectiveLevel(user, 2 + (level * 2)));
|
||||
}
|
||||
|
||||
private EntityAttributeModifier getModifier(Living<?> user, int level) {
|
||||
return new EntityAttributeModifier(TEAM_STRENGTH_ID, user.getEnchants().computeIfAbsent(UEnchantments.HERDS, Enchantments.Data::new).level / 2, Operation.ADD_VALUE);
|
||||
}
|
||||
|
||||
private static int getTeamCollectiveLevel(Living<?> user, int radius) {
|
||||
return user.findAllEntitiesInRange(radius, e -> e instanceof LivingEntity)
|
||||
.mapToInt(e -> EnchantmentUtil.getLevel(UEnchantments.HERDS, (LivingEntity)e))
|
||||
.reduce((a, b) -> a + b)
|
||||
.orElse(0);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ import net.minecraft.sound.SoundCategory;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ConsumptionEnchantment {
|
||||
public class ConsumptionEnchantmentUtil {
|
||||
public static boolean applyConsumption(World w, BlockState state, BlockPos pos, @Nullable BlockEntity blockEntity, Entity entity, ItemStack tool) {
|
||||
|
||||
if (!(w instanceof ServerWorld world)) {
|
|
@ -0,0 +1,47 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentEffectContext;
|
||||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.mob.HostileEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class DangerSensingEnchantmentEffect implements EnchantmentEntityEffect {
|
||||
public static final DangerSensingEnchantmentEffect INSTANCE = new DangerSensingEnchantmentEffect();
|
||||
public static final MapCodec<DangerSensingEnchantmentEffect> CODEC = MapCodec.unit(INSTANCE);
|
||||
|
||||
@Override
|
||||
public MapCodec<DangerSensingEnchantmentEffect> getCodec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity entity, Vec3d pos) {
|
||||
Pony.of(entity).ifPresent(pony -> {
|
||||
if (pony.asEntity().age % 10 == 0) {
|
||||
int range = (level + 1) * 3;
|
||||
if (pony.asWorld().getEntitiesByClass(HostileEntity.class, pony.asEntity().getBoundingBox().expand(range, 0, range), enemy -> {
|
||||
return enemy != null
|
||||
&& enemy.canTarget(pony.asEntity())
|
||||
&& enemy.canSee(pony.asEntity())
|
||||
&& enemy.getTarget() == pony.asEntity();
|
||||
}).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bar bar = pony.getMagicalReserves().getEnergy();
|
||||
float targetPercent = (level / (float)pony.entryFor(UEnchantments.STRESSED).value().definition().maxLevel()) * 0.05125F;
|
||||
float increase = 1F + (level * level)/100F;
|
||||
if (bar.getPercentFill() < targetPercent) {
|
||||
bar.add(increase);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@ import net.minecraft.component.type.ItemEnchantmentsComponent;
|
|||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.enchantment.Enchantments;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.effect.StatusEffect;
|
||||
import net.minecraft.entity.effect.StatusEffects;
|
||||
|
@ -40,6 +42,27 @@ public interface EnchantmentUtil {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
static boolean prefersEquipment(ItemStack newStack, ItemStack oldStack) {
|
||||
int newLevel = EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, newStack);
|
||||
int oldLevel = EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, oldStack);
|
||||
return newLevel > oldLevel;
|
||||
}
|
||||
|
||||
static int getWantItNeedItLevel(Entity entity) {
|
||||
return entity instanceof LivingEntity l ? getWantItNeedItLevel(l)
|
||||
: entity instanceof ItemEntity i ? getWantItNeedItLevel(i)
|
||||
: 0;
|
||||
}
|
||||
|
||||
static int getWantItNeedItLevel(ItemEntity entity) {
|
||||
return getLevel(UEnchantments.WANT_IT_NEED_IT, entity.getStack());
|
||||
}
|
||||
|
||||
static int getWantItNeedItLevel(LivingEntity entity) {
|
||||
return getLevel(UEnchantments.WANT_IT_NEED_IT, entity);
|
||||
}
|
||||
|
||||
static int getLuck(int baseline, LivingEntity entity) {
|
||||
boolean naturallyLucky = Living.getOrEmpty(entity).filter(c -> c.getCompositeRace().canUseEarth()).isPresent();
|
||||
if (naturallyLucky) {
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.UTags;
|
||||
import com.minelittlepony.unicopia.client.sound.MagicAuraSoundInstance;
|
||||
import com.minelittlepony.unicopia.entity.Enchantments;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class GemFindingEnchantment {
|
||||
|
||||
public void onUserTick(Living<?> user, int level) {
|
||||
int radius = 2 + (level * 2);
|
||||
|
||||
BlockPos origin = user.getOrigin();
|
||||
|
||||
double volume = BlockPos.findClosest(origin, radius, radius, pos -> user.asWorld().getBlockState(pos).isIn(UTags.Blocks.INTERESTING))
|
||||
.map(p -> user.getOriginVector().squaredDistanceTo(p.getX(), p.getY(), p.getZ()))
|
||||
.map(find -> (1 - (Math.sqrt(find) / radius)))
|
||||
.orElse(-1D);
|
||||
|
||||
volume = Math.max(volume, 0.04F);
|
||||
|
||||
user.getEnchants().computeIfAbsent(UEnchantments.GEM_FINDER, Enchantments.Data::new).level = (float)volume * (1.3F + level);
|
||||
}
|
||||
|
||||
public void onEquipped(Living<?> user) {
|
||||
if (user.isClient()) {
|
||||
MinecraftClient.getInstance().getSoundManager().play(new MagicAuraSoundInstance(user.asEntity().getSoundCategory(), user, user.asWorld().getRandom()));
|
||||
}
|
||||
}
|
||||
|
||||
public void onUnequipped(Living<?> user) {
|
||||
user.getEnchants().remove(UEnchantments.GEM_FINDER).level = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentEffectContext;
|
||||
import net.minecraft.enchantment.EnchantmentLevelBasedValue;
|
||||
import net.minecraft.enchantment.effect.AttributeEnchantmentEffect;
|
||||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
|
||||
public record GroupBasedAttributeEnchantmentEffect (
|
||||
AttributeEnchantmentEffect attribute,
|
||||
EnchantmentLevelBasedValue range
|
||||
) implements EnchantmentEntityEffect {
|
||||
public static final MapCodec<GroupBasedAttributeEnchantmentEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
AttributeEnchantmentEffect.CODEC.fieldOf("attribute").forGetter(GroupBasedAttributeEnchantmentEffect::attribute),
|
||||
EnchantmentLevelBasedValue.CODEC.fieldOf("range").forGetter(GroupBasedAttributeEnchantmentEffect::range)
|
||||
).apply(instance, GroupBasedAttributeEnchantmentEffect::new));
|
||||
|
||||
@Override
|
||||
public MapCodec<GroupBasedAttributeEnchantmentEffect> getCodec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity user, Vec3d pos) {
|
||||
Living.getOrEmpty(user).ifPresent(living -> {
|
||||
int collectiveLevels = living.findAllEntitiesInRange(range.getValue(level), e -> e instanceof LivingEntity)
|
||||
.mapToInt(e -> EnchantmentUtil.getLevel(UEnchantments.HERDS, (LivingEntity)e))
|
||||
.reduce(Integer::sum)
|
||||
.orElse(0);
|
||||
|
||||
living.updateAttributeModifier(attribute.id(), attribute.attribute(), attribute.amount().getValue(collectiveLevels), value -> {
|
||||
return new EntityAttributeModifier(attribute.id(), value, attribute.operation());
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(EnchantmentEffectContext context, Entity user, Vec3d pos, int level) {
|
||||
Living.getOrEmpty(user).ifPresent(living -> {
|
||||
living.updateAttributeModifier(attribute.id(), attribute.attribute(), 0, value -> {
|
||||
return new EntityAttributeModifier(attribute.id(), value, attribute.operation());
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.particle.WeakTarget;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentEffectContext;
|
||||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public record ParticleTrailEnchantmentEntityEffect(
|
||||
Optional<ParticleEffect> particle,
|
||||
float followSpeed,
|
||||
int density,
|
||||
int probability
|
||||
) implements EnchantmentEntityEffect {
|
||||
public static final MapCodec<ParticleTrailEnchantmentEntityEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ParticleTypes.TYPE_CODEC.optionalFieldOf("particle").forGetter(ParticleTrailEnchantmentEntityEffect::particle),
|
||||
Codec.FLOAT.fieldOf("followSpeed").forGetter(ParticleTrailEnchantmentEntityEffect::followSpeed),
|
||||
Codec.INT.fieldOf("density").forGetter(ParticleTrailEnchantmentEntityEffect::density),
|
||||
Codec.INT.fieldOf("probability").forGetter(ParticleTrailEnchantmentEntityEffect::probability)
|
||||
).apply(instance, ParticleTrailEnchantmentEntityEffect::new));
|
||||
|
||||
@Override
|
||||
public MapCodec<ParticleTrailEnchantmentEntityEffect> getCodec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity entity, Vec3d pos) {
|
||||
if (probability <= 0 || world.random.nextInt(probability) == 0) {
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(
|
||||
UParticles.HEALTH_DRAIN,
|
||||
new WeakTarget(entity.getCameraPosVec(1), entity), followSpeed, particle
|
||||
), entity, density);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.UTags;
|
||||
import com.minelittlepony.unicopia.entity.Enchantments;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.util.RegistryUtils;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
public class PoisonedJokeEnchantment {
|
||||
|
||||
public void onUserTick(Living<?> user, int level) {
|
||||
if (user.asWorld().isClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
int light = user.asWorld().getLightLevel(user.asEntity().getRootVehicle().getBlockPos());
|
||||
Random rng = user.asWorld().random;
|
||||
Enchantments.Data data = user.getEnchants().computeIfAbsent(UEnchantments.POISONED_JOKE, Enchantments.Data::new);
|
||||
|
||||
data.level -= rng.nextFloat() * 0.8F;
|
||||
if (rng.nextInt(Math.max(1, (light * 9) + (int)data.level)) == 0) {
|
||||
data.level = rng.nextInt(5000);
|
||||
|
||||
RegistryUtils.pickRandom(user.asWorld(), UTags.Sounds.POISON_JOKE_EVENTS).ifPresent(event -> {
|
||||
user.asWorld().playSoundFromEntity(
|
||||
null,
|
||||
user.asEntity(),
|
||||
event, SoundCategory.HOSTILE,
|
||||
0.5F + rng.nextFloat() * 0.5F,
|
||||
0.5F + rng.nextFloat() * 0.5F
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
||||
import net.minecraft.entity.mob.HostileEntity;
|
||||
|
||||
public class StressfulEnchantment {
|
||||
|
||||
public void onUserTick(Living<?> user, int level) {
|
||||
if (user instanceof Pony pony && pony.asEntity().age % 10 == 0) {
|
||||
int range = (level + 1) * 3;
|
||||
if (pony.asWorld().getEntitiesByClass(HostileEntity.class, user.asEntity().getBoundingBox().expand(range, 0, range), enemy -> {
|
||||
return enemy != null
|
||||
&& enemy.canTarget(user.asEntity())
|
||||
&& enemy.canSee(user.asEntity())
|
||||
&& enemy.getTarget() == user.asEntity();
|
||||
}).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bar bar = pony.getMagicalReserves().getEnergy();
|
||||
float targetPercent = (level / (float)user.entryFor(UEnchantments.STRESSED).value().definition().maxLevel()) * 0.05125F;
|
||||
float increase = 1F + (level * level)/100F;
|
||||
if (bar.getPercentFill() < targetPercent) {
|
||||
bar.add(increase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
|
||||
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
|
||||
public interface UEnchantmentEffects {
|
||||
static void bootstrap() {
|
||||
register("group_based_attribute", GroupBasedAttributeEnchantmentEffect.CODEC);
|
||||
register("poisoned_joke_sound", AmbientSoundsEnchantmentEffect.CODEC);
|
||||
register("danger_sensor", DangerSensingEnchantmentEffect.CODEC);
|
||||
register("particle_trail", ParticleTrailEnchantmentEntityEffect.CODEC);
|
||||
}
|
||||
|
||||
private static void register(String name, MapCodec<? extends EnchantmentEntityEffect> codec) {
|
||||
Registry.register(Registries.ENCHANTMENT_ENTITY_EFFECT_TYPE, Unicopia.id("name"), codec);
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
|
||||
public interface UEnchantmentValidSlots {
|
||||
EquipmentSlot[] ANY = EquipmentSlot.values();
|
||||
EquipmentSlot[] ARMOR = { EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET };
|
||||
EquipmentSlot[] HANDS = { EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND };
|
||||
}
|
|
@ -2,6 +2,9 @@ package com.minelittlepony.unicopia.item.enchantment;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.UTags;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
|
||||
import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
|
||||
|
@ -12,6 +15,7 @@ import net.minecraft.enchantment.EnchantmentLevelBasedValue;
|
|||
import net.minecraft.enchantment.effect.AttributeEnchantmentEffect;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
|
@ -137,6 +141,7 @@ public interface UEnchantments {
|
|||
}
|
||||
|
||||
static void bootstrap() {
|
||||
UEnchantmentEffects.bootstrap();
|
||||
// Options.table -> EnchantmentTags.IN_ENCHANTING_TABLE
|
||||
// Optiona.curse -> EnchantmentTags.CURSE
|
||||
// Options.traded -> EnchantmentTags.TRADEABLE
|
||||
|
@ -153,7 +158,6 @@ public interface UEnchantments {
|
|||
4,
|
||||
AttributeModifierSlot.HAND
|
||||
)));
|
||||
// TODO: gem finder effect
|
||||
|
||||
register(registry, PADDED, Enchantment.builder(Enchantment.definition(
|
||||
items.getEntryList(ItemTags.HEAD_ARMOR_ENCHANTABLE).orElseThrow(),
|
||||
|
@ -197,8 +201,12 @@ public interface UEnchantments {
|
|||
1,
|
||||
AttributeModifierSlot.MAINHAND
|
||||
)
|
||||
));
|
||||
// TODO: Herding effect
|
||||
).addEffect(EnchantmentEffectComponentTypes.TICK, new GroupBasedAttributeEnchantmentEffect(new AttributeEnchantmentEffect(
|
||||
Unicopia.id("team_strength"),
|
||||
EntityAttributes.GENERIC_ATTACK_DAMAGE,
|
||||
EnchantmentLevelBasedValue.linear(0, 1),
|
||||
Operation.ADD_VALUE
|
||||
), EnchantmentLevelBasedValue.linear(2, 2))));
|
||||
|
||||
register(registry, REPULSION, Enchantment.builder(
|
||||
Enchantment.definition(
|
||||
|
@ -225,8 +233,8 @@ public interface UEnchantments {
|
|||
Enchantment.constantCost(2), Enchantment.constantCost(10),
|
||||
4,
|
||||
AttributeModifierSlot.ANY
|
||||
)));
|
||||
// TODO: Want it need it effect
|
||||
)).addEffect(EnchantmentEffectComponentTypes.TICK, new ParticleTrailEnchantmentEntityEffect(Optional.empty(), 0.2F, 1, 10)));
|
||||
|
||||
register(registry, POISONED_JOKE, Enchantment.builder(Enchantment.definition(
|
||||
items.getEntryList(ItemTags.VANISHING_ENCHANTABLE).orElseThrow(),
|
||||
Rarity.VERY_RARE,
|
||||
|
@ -234,8 +242,7 @@ public interface UEnchantments {
|
|||
Enchantment.constantCost(2), Enchantment.constantCost(10),
|
||||
4,
|
||||
AttributeModifierSlot.ANY
|
||||
)));
|
||||
// TODO: Poisoned joke effect
|
||||
)).addEffect(EnchantmentEffectComponentTypes.TICK, new AmbientSoundsEnchantmentEffect(Unicopia.id("poisoned_joke_level"), UTags.Sounds.POISON_JOKE_EVENTS)));
|
||||
|
||||
register(registry, CLINGY, Enchantment.builder(Enchantment.definition(
|
||||
items.getEntryList(ItemTags.VANISHING_ENCHANTABLE).orElseThrow(),
|
||||
|
@ -244,8 +251,7 @@ public interface UEnchantments {
|
|||
Enchantment.constantCost(2), Enchantment.constantCost(12),
|
||||
4,
|
||||
AttributeModifierSlot.ANY
|
||||
)));
|
||||
// TODO: Stressful effect
|
||||
)).addEffect(EnchantmentEffectComponentTypes.TICK, DangerSensingEnchantmentEffect.INSTANCE));
|
||||
|
||||
register(registry, CLINGY, Enchantment.builder(Enchantment.definition(
|
||||
items.getEntryList(ItemTags.EQUIPPABLE_ENCHANTABLE).orElseThrow(),
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
package com.minelittlepony.unicopia.item.enchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class WantItNeedItEnchantment {
|
||||
|
||||
public void onUserTick(Living<?> user, int level) {
|
||||
if (user instanceof Creature && user.asWorld().random.nextInt(10) == 0) {
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, user.asEntity(), 0.2F), user.asEntity(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean prefersEquipment(ItemStack newStack, ItemStack oldStack) {
|
||||
int newLevel = EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, newStack);
|
||||
int oldLevel = EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, oldStack);
|
||||
return newLevel > oldLevel;
|
||||
}
|
||||
|
||||
public static int getLevel(Entity entity) {
|
||||
return entity instanceof LivingEntity l ? getLevel(l)
|
||||
: entity instanceof ItemEntity i ? getLevel(i)
|
||||
: 0;
|
||||
}
|
||||
|
||||
public static int getLevel(ItemEntity entity) {
|
||||
return EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, entity.getStack());
|
||||
}
|
||||
|
||||
public static int getLevel(LivingEntity entity) {
|
||||
return EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, entity)
|
||||
+ EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, entity.getOffHandStack())
|
||||
+ EnchantmentUtil.getLevel(UEnchantments.WANT_IT_NEED_IT, entity.getMainHandStack());
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.minelittlepony.unicopia.item.enchantment.ConsumptionEnchantment;
|
||||
import com.minelittlepony.unicopia.item.enchantment.ConsumptionEnchantmentUtil;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -24,7 +24,7 @@ abstract class MixinBlock {
|
|||
cancellable = true
|
||||
)
|
||||
private static void dropStacks(BlockState state, World world, BlockPos pos, @Nullable BlockEntity blockEntity, Entity entity, ItemStack stack, CallbackInfo info) {
|
||||
if (ConsumptionEnchantment.applyConsumption(world, state, pos, blockEntity, entity, stack)) {
|
||||
if (ConsumptionEnchantmentUtil.applyConsumption(world, state, pos, blockEntity, entity, stack)) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.*;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
|
||||
import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.goal.GoalSelector;
|
||||
|
@ -35,7 +34,7 @@ abstract class MixinMobEntity extends LivingEntity implements Equine.Container<C
|
|||
@Inject(method = "prefersNewEquipment(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)Z",
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private void onPrefersNewEquipment(ItemStack newStack, ItemStack oldStack, CallbackInfoReturnable<Boolean> info) {
|
||||
if (WantItNeedItEnchantment.prefersEquipment(newStack, oldStack)) {
|
||||
if (EnchantmentUtil.prefersEquipment(newStack, oldStack)) {
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.stream.Stream;
|
|||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -17,8 +16,6 @@ import net.minecraft.util.math.Vec3d;
|
|||
public interface NbtSerialisable {
|
||||
@Deprecated
|
||||
Serializer<NbtElement, BlockPos> BLOCK_POS = Serializer.ofCodec(BlockPos.CODEC);
|
||||
@Deprecated
|
||||
Serializer<NbtElement, ItemStack> ITEM_STACK = Serializer.ofCodec(ItemStack.CODEC);
|
||||
|
||||
/**
|
||||
* Called to save this to nbt to persist state on file or to transmit over the network
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package com.minelittlepony.unicopia.util.serialization;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
|
||||
|
||||
public class NbtMap<K, V> implements NbtSerialisable {
|
||||
public static <K, V> NbtMap<K, V> of(Codec<K> keyCodec, Codec<V> valueCodec) {
|
||||
return new NbtMap<>(Codec.unboundedMap(keyCodec, valueCodec));
|
||||
}
|
||||
|
||||
private final Codec<Map<K, V>> codec;
|
||||
private final Map<K, V> data = new HashMap<>();
|
||||
|
||||
public NbtMap(Codec<Map<K, V>> codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
public Optional<V> getOrEmpty(K key) {
|
||||
return Optional.ofNullable(data.get(key));
|
||||
}
|
||||
|
||||
public V computeIfAbsent(K key, Supplier<V> factory) {
|
||||
return data.computeIfAbsent(key, e -> factory.get());
|
||||
}
|
||||
|
||||
public V put(K key, V value) {
|
||||
return data.put(key, value);
|
||||
}
|
||||
|
||||
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> function) {
|
||||
return data.compute(key, function);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public V remove(K key) {
|
||||
return data.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound, WrapperLookup lookup) {
|
||||
compound.put("data", NbtSerialisable.encode(codec, data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound, WrapperLookup lookup) {
|
||||
data.clear();
|
||||
NbtSerialisable.decode(codec, compound.get("data")).ifPresent(data::putAll);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue