mirror of
https://github.com/Ellpeck/NaturesAura.git
synced 2024-11-22 19:58:34 +01:00
add the ability to see passive effects to the ocular
This commit is contained in:
parent
ea54997ae5
commit
9aa2e498d2
14 changed files with 398 additions and 163 deletions
|
@ -3,6 +3,7 @@ package de.ellpeck.naturesaura;
|
|||
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
|
||||
import de.ellpeck.naturesaura.api.aura.item.IAuraRecharge;
|
||||
import de.ellpeck.naturesaura.blocks.tiles.TileEntityImpl;
|
||||
import de.ellpeck.naturesaura.chunk.AuraChunk;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
|
@ -28,6 +29,7 @@ import net.minecraft.util.SoundCategory;
|
|||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import net.minecraft.world.gen.ChunkProviderServer;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
|
@ -41,25 +43,46 @@ import org.lwjgl.opengl.GL11;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class Helper {
|
||||
|
||||
public static boolean getTileEntitiesInArea(World world, BlockPos pos, int radius, Function<TileEntity, Boolean> consumer) {
|
||||
world.profiler.func_194340_a(() -> NaturesAura.MOD_ID + ":getAuraChunksInArea");
|
||||
for (int x = (pos.getX() - radius) >> 4; x <= (pos.getX() + radius) >> 4; x++) {
|
||||
for (int z = (pos.getZ() - radius) >> 4; z <= (pos.getZ() + radius) >> 4; z++) {
|
||||
if (isChunkLoaded(world, x, z)) {
|
||||
for (TileEntity tile : world.getChunk(x, z).getTileEntityMap().values()) {
|
||||
if (tile.getPos().distanceSq(pos) <= radius * radius)
|
||||
if (consumer.apply(tile))
|
||||
if (consumer.apply(tile)) {
|
||||
world.profiler.endSection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
world.profiler.endSection();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void getAuraChunksInArea(World world, BlockPos pos, int radius, Consumer<AuraChunk> consumer) {
|
||||
world.profiler.func_194340_a(() -> NaturesAura.MOD_ID + ":getAuraChunksInArea");
|
||||
for (int x = (pos.getX() - radius) >> 4; x <= (pos.getX() + radius) >> 4; x++) {
|
||||
for (int z = (pos.getZ() - radius) >> 4; z <= (pos.getZ() + radius) >> 4; z++) {
|
||||
if (Helper.isChunkLoaded(world, x, z)) {
|
||||
Chunk chunk = world.getChunk(x, z);
|
||||
if (chunk.hasCapability(NaturesAuraAPI.capAuraChunk, null)) {
|
||||
AuraChunk auraChunk = (AuraChunk) chunk.getCapability(NaturesAuraAPI.capAuraChunk, null);
|
||||
consumer.accept(auraChunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
world.profiler.endSection();
|
||||
}
|
||||
|
||||
public static List<EntityItemFrame> getAttachedItemFrames(World world, BlockPos pos) {
|
||||
List<EntityItemFrame> frames = world.getEntitiesWithinAABB(EntityItemFrame.class, new AxisAlignedBB(pos).grow(0.25));
|
||||
for (int i = frames.size() - 1; i >= 0; i--) {
|
||||
|
|
|
@ -15,7 +15,6 @@ import net.minecraft.util.math.AxisAlignedBB;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import org.apache.commons.lang3.mutable.MutableFloat;
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
@ -114,17 +113,7 @@ public class InternalHooks implements NaturesAuraAPI.IInternalHooks {
|
|||
@Override
|
||||
public void getAuraSpotsInArea(World world, BlockPos pos, int radius, BiConsumer<BlockPos, Integer> consumer) {
|
||||
world.profiler.func_194340_a(() -> NaturesAura.MOD_ID + ":getSpotsInArea");
|
||||
for (int x = (pos.getX() - radius) >> 4; x <= (pos.getX() + radius) >> 4; x++) {
|
||||
for (int z = (pos.getZ() - radius) >> 4; z <= (pos.getZ() + radius) >> 4; z++) {
|
||||
if (Helper.isChunkLoaded(world, x, z)) {
|
||||
Chunk chunk = world.getChunk(x, z);
|
||||
if (chunk.hasCapability(NaturesAuraAPI.capAuraChunk, null)) {
|
||||
IAuraChunk auraChunk = chunk.getCapability(NaturesAuraAPI.capAuraChunk, null);
|
||||
auraChunk.getSpotsInArea(pos, radius, consumer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Helper.getAuraChunksInArea(world, pos, radius, chunk -> chunk.getSpotsInArea(pos, radius, consumer));
|
||||
world.profiler.endSection();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,11 +46,6 @@ public interface IAuraChunk extends ICapabilityProvider, INBTSerializable<NBTTag
|
|||
* This method uses the supplied consumer to iterate over all the drain
|
||||
* spots, represented as a position and the number of Aura in them, in any
|
||||
* given area.
|
||||
* <p>
|
||||
* Notice that this is different from {@link #getSpotsInArea(BlockPos, int,
|
||||
* BiConsumer)} because this method iterates over several chunks while the
|
||||
* former only uses the current aura chunk instance. Most of the time, you
|
||||
* will want to use this method.
|
||||
*
|
||||
* @param world The world
|
||||
* @param pos The center position
|
||||
|
@ -133,11 +128,6 @@ public interface IAuraChunk extends ICapabilityProvider, INBTSerializable<NBTTag
|
|||
return NaturesAuraAPI.instance().getHighestAuraDrainSpot(world, pos, radius, defaultSpot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getSpotsInArea(World, BlockPos, int, BiConsumer)
|
||||
*/
|
||||
void getSpotsInArea(BlockPos pos, int radius, BiConsumer<BlockPos, Integer> consumer);
|
||||
|
||||
/**
|
||||
* Drains the given amount of Aura from the given position. Returns the
|
||||
* amount of Aura that was drained.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package de.ellpeck.naturesaura.api.aura.chunk;
|
||||
|
||||
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -13,4 +15,12 @@ public interface IDrainSpotEffect {
|
|||
boolean appliesHere(Chunk chunk, IAuraChunk auraChunk, IAuraType type);
|
||||
|
||||
ResourceLocation getName();
|
||||
|
||||
default int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
default ItemStack getDisplayIcon() {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,14 @@ import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect;
|
|||
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
||||
import de.ellpeck.naturesaura.packet.PacketAuraChunk;
|
||||
import de.ellpeck.naturesaura.packet.PacketHandler;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
@ -45,16 +49,6 @@ public class AuraChunk implements IAuraChunk {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSpotsInArea(BlockPos pos, int radius, BiConsumer<BlockPos, Integer> consumer) {
|
||||
for (Map.Entry<BlockPos, MutableInt> entry : this.drainSpots.entrySet()) {
|
||||
BlockPos drainPos = entry.getKey();
|
||||
if (drainPos.distanceSq(pos) <= radius * radius) {
|
||||
consumer.accept(drainPos, entry.getValue().intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drainAura(BlockPos pos, int amount, boolean aimForZero, boolean simulate) {
|
||||
if (amount <= 0)
|
||||
|
@ -174,6 +168,34 @@ public class AuraChunk implements IAuraChunk {
|
|||
return new PacketAuraChunk(this.chunk.x, this.chunk.z, this.drainSpots);
|
||||
}
|
||||
|
||||
public void getSpotsInArea(BlockPos pos, int radius, BiConsumer<BlockPos, Integer> consumer) {
|
||||
for (Map.Entry<BlockPos, MutableInt> entry : this.drainSpots.entrySet()) {
|
||||
BlockPos drainPos = entry.getKey();
|
||||
if (drainPos.distanceSq(pos) <= radius * radius) {
|
||||
consumer.accept(drainPos, entry.getValue().intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void getActiveEffectIcons(EntityPlayer player, Map<ResourceLocation, Tuple<ItemStack, Boolean>> icons) {
|
||||
for (IDrainSpotEffect effect : this.effects) {
|
||||
Tuple<ItemStack, Boolean> alreadyThere = icons.get(effect.getName());
|
||||
if (alreadyThere != null && alreadyThere.getSecond())
|
||||
continue;
|
||||
for (Map.Entry<BlockPos, MutableInt> entry : this.drainSpots.entrySet()) {
|
||||
BlockPos pos = entry.getKey();
|
||||
MutableInt amount = entry.getValue();
|
||||
int state = effect.isActiveHere(player, this.chunk, this, pos, amount.intValue());
|
||||
if (state < 0)
|
||||
continue;
|
||||
ItemStack stack = effect.getDisplayIcon();
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
icons.put(effect.getName(), new Tuple<>(stack, state == 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
|
||||
return capability == NaturesAuraAPI.capAuraChunk;
|
||||
|
|
|
@ -9,6 +9,8 @@ import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
|||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.passive.EntityAnimal;
|
||||
import net.minecraft.entity.passive.EntityChicken;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemEgg;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
|
@ -28,25 +30,50 @@ public class AnimalEffect implements IDrainSpotEffect {
|
|||
|
||||
public static final ResourceLocation NAME = new ResourceLocation(NaturesAura.MOD_ID, "animal");
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
private int chance;
|
||||
private AxisAlignedBB bb;
|
||||
|
||||
private boolean calcValues(World world, BlockPos pos, Integer spot) {
|
||||
if (spot <= 0)
|
||||
return;
|
||||
return false;
|
||||
int aura = IAuraChunk.getAuraInArea(world, pos, 30);
|
||||
if (aura < 1500000)
|
||||
return;
|
||||
int chance = Math.min(50, Math.abs(aura) / 500000);
|
||||
if (chance <= 0)
|
||||
return;
|
||||
return false;
|
||||
this.chance = Math.min(50, Math.abs(aura) / 500000);
|
||||
if (this.chance <= 0)
|
||||
return false;
|
||||
int dist = MathHelper.clamp(Math.abs(aura) / 150000, 5, 35);
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos).grow(dist);
|
||||
this.bb = new AxisAlignedBB(pos).grow(dist);
|
||||
return true;
|
||||
}
|
||||
|
||||
List<EntityAnimal> animals = world.getEntitiesWithinAABB(EntityAnimal.class, bb);
|
||||
@Override
|
||||
public int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(player.world, pos, spot))
|
||||
return -1;
|
||||
if (!this.bb.contains(player.getPositionVector()))
|
||||
return -1;
|
||||
if (NaturesAuraAPI.instance().isEffectPowderActive(player.world, player.getPosition(), NAME))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayIcon() {
|
||||
return new ItemStack(Items.EGG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(world, pos, spot))
|
||||
return;
|
||||
|
||||
List<EntityAnimal> animals = world.getEntitiesWithinAABB(EntityAnimal.class, this.bb);
|
||||
if (animals.size() >= 200)
|
||||
return;
|
||||
|
||||
if (world.getTotalWorldTime() % 200 == 0) {
|
||||
List<EntityItem> items = world.getEntitiesWithinAABB(EntityItem.class, bb);
|
||||
List<EntityItem> items = world.getEntitiesWithinAABB(EntityItem.class, this.bb);
|
||||
for (EntityItem item : items) {
|
||||
if (item.isDead)
|
||||
continue;
|
||||
|
@ -78,7 +105,7 @@ public class AnimalEffect implements IDrainSpotEffect {
|
|||
}
|
||||
}
|
||||
|
||||
if (world.rand.nextInt(200) <= chance) {
|
||||
if (world.rand.nextInt(200) <= this.chance) {
|
||||
if (animals.size() < 2)
|
||||
return;
|
||||
EntityAnimal first = animals.get(world.rand.nextInt(animals.size()));
|
||||
|
|
|
@ -2,11 +2,15 @@ package de.ellpeck.naturesaura.chunk.effect;
|
|||
|
||||
import de.ellpeck.naturesaura.ModConfig;
|
||||
import de.ellpeck.naturesaura.NaturesAura;
|
||||
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
|
||||
import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk;
|
||||
import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect;
|
||||
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
||||
import de.ellpeck.naturesaura.potion.ModPotions;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
@ -21,22 +25,46 @@ public class BreathlessEffect implements IDrainSpotEffect {
|
|||
|
||||
public static final ResourceLocation NAME = new ResourceLocation(NaturesAura.MOD_ID, "breathless");
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (spot >= 0 || world.getTotalWorldTime() % 100 != 0)
|
||||
return;
|
||||
private int amp;
|
||||
private AxisAlignedBB bb;
|
||||
|
||||
private boolean calcValues(World world, BlockPos pos, Integer spot) {
|
||||
if (spot >= 0)
|
||||
return false;
|
||||
int aura = IAuraChunk.getAuraInArea(world, pos, 50);
|
||||
if (aura > 0)
|
||||
return;
|
||||
return false;
|
||||
int dist = Math.min(Math.abs(aura) / 50000, 75);
|
||||
if (dist < 10)
|
||||
return;
|
||||
int amp = Math.min(MathHelper.floor(Math.abs(aura) / 2500000F), 3);
|
||||
return false;
|
||||
this.amp = Math.min(MathHelper.floor(Math.abs(aura) / 2500000F), 3);
|
||||
this.bb = new AxisAlignedBB(pos).grow(dist);
|
||||
return true;
|
||||
}
|
||||
|
||||
List<EntityLivingBase> entities = world.getEntitiesWithinAABB(EntityLivingBase.class,
|
||||
new AxisAlignedBB(pos).grow(dist));
|
||||
@Override
|
||||
public int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(player.world, pos, spot))
|
||||
return -1;
|
||||
if (!this.bb.contains(player.getPositionVector()))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayIcon() {
|
||||
return new ItemStack(Blocks.WOOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (world.getTotalWorldTime() % 100 != 0)
|
||||
return;
|
||||
if (!this.calcValues(world, pos, spot))
|
||||
return;
|
||||
List<EntityLivingBase> entities = world.getEntitiesWithinAABB(EntityLivingBase.class, this.bb);
|
||||
for (EntityLivingBase entity : entities)
|
||||
entity.addPotionEffect(new PotionEffect(ModPotions.BREATHLESS, 300, amp));
|
||||
entity.addPotionEffect(new PotionEffect(ModPotions.BREATHLESS, 300, this.amp));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,7 +6,9 @@ import de.ellpeck.naturesaura.api.NaturesAuraAPI;
|
|||
import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk;
|
||||
import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect;
|
||||
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
||||
import de.ellpeck.naturesaura.items.ModItems;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -20,23 +22,48 @@ public class CacheRechargeEffect implements IDrainSpotEffect {
|
|||
|
||||
public static final ResourceLocation NAME = new ResourceLocation(NaturesAura.MOD_ID, "cache_recharge");
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
private int amount;
|
||||
private AxisAlignedBB bb;
|
||||
|
||||
private boolean calcValues(World world, BlockPos pos, Integer spot) {
|
||||
if (spot < 100000)
|
||||
return;
|
||||
return false;
|
||||
int aura = IAuraChunk.getAuraInArea(world, pos, 20);
|
||||
if (aura < 1500000)
|
||||
return;
|
||||
if (NaturesAuraAPI.instance().isEffectPowderActive(world, pos, NAME))
|
||||
return;
|
||||
return false;
|
||||
int dist = MathHelper.clamp(aura / 3500, 3, 15);
|
||||
int amount = aura / 250000 - 2;
|
||||
this.bb = new AxisAlignedBB(pos).grow(dist);
|
||||
this.amount = aura / 250000 - 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
List<EntityPlayer> players = world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(pos).grow(dist));
|
||||
@Override
|
||||
public int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(player.world, pos, spot))
|
||||
return -1;
|
||||
if (!this.bb.contains(player.getPositionVector()))
|
||||
return -1;
|
||||
if (NaturesAuraAPI.instance().isEffectPowderActive(player.world, player.getPosition(), NAME))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayIcon() {
|
||||
return new ItemStack(ModItems.AURA_CACHE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(world, pos, spot))
|
||||
return;
|
||||
List<EntityPlayer> players = world.getEntitiesWithinAABB(EntityPlayer.class, this.bb);
|
||||
for (EntityPlayer player : players) {
|
||||
if (NaturesAuraAPI.instance().insertAuraIntoPlayer(player, amount, true)) {
|
||||
NaturesAuraAPI.instance().insertAuraIntoPlayer(player, amount, false);
|
||||
auraChunk.drainAura(pos, amount);
|
||||
if (NaturesAuraAPI.instance().isEffectPowderActive(world, player.getPosition(), NAME))
|
||||
continue;
|
||||
if (NaturesAuraAPI.instance().insertAuraIntoPlayer(player, this.amount, true)) {
|
||||
NaturesAuraAPI.instance().insertAuraIntoPlayer(player, this.amount, false);
|
||||
auraChunk.drainAura(pos, this.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import de.ellpeck.naturesaura.NaturesAura;
|
|||
import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk;
|
||||
import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect;
|
||||
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
@ -15,28 +18,54 @@ public class ExplosionEffect implements IDrainSpotEffect {
|
|||
|
||||
public static final ResourceLocation NAME = new ResourceLocation(NaturesAura.MOD_ID, "explosions");
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (spot >= 0 || world.getTotalWorldTime() % 40 != 0)
|
||||
return;
|
||||
private int chance;
|
||||
private float strength;
|
||||
private int dist;
|
||||
|
||||
private boolean calcValues(World world, BlockPos pos, Integer spot){
|
||||
if (spot >= 0)
|
||||
return false;
|
||||
int aura = IAuraChunk.getAuraInArea(world, pos, 85);
|
||||
if (aura > -5000000)
|
||||
return;
|
||||
int chance = 140 - Math.abs(aura) / 200000;
|
||||
if (chance > 1 && world.rand.nextInt(chance) != 0)
|
||||
return;
|
||||
float strength = Math.min(Math.abs(aura) / 5000000F, 5F);
|
||||
if (strength <= 0)
|
||||
return;
|
||||
int dist = MathHelper.clamp(Math.abs(aura) / 200000, 25, 100);
|
||||
return false;
|
||||
this.chance = 140 - Math.abs(aura) / 200000;
|
||||
if (this.chance > 1 && world.rand.nextInt(this.chance) != 0)
|
||||
return false;
|
||||
this.strength = Math.min(Math.abs(aura) / 5000000F, 5F);
|
||||
if (this.strength <= 0)
|
||||
return false;
|
||||
this.dist = MathHelper.clamp(Math.abs(aura) / 200000, 25, 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
int x = MathHelper.floor(pos.getX() + world.rand.nextGaussian() * dist);
|
||||
int z = MathHelper.floor(pos.getZ() + world.rand.nextGaussian() * dist);
|
||||
@Override
|
||||
public int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(player.world, pos, spot))
|
||||
return -1;
|
||||
if (player.getDistanceSq(pos) > this.dist * this.dist)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayIcon() {
|
||||
return new ItemStack(Blocks.TNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if(world.getTotalWorldTime() % 40 != 0)
|
||||
return;
|
||||
if(!this.calcValues(world, pos, spot))
|
||||
return;
|
||||
|
||||
int x = MathHelper.floor(pos.getX() + world.rand.nextGaussian() * this.dist);
|
||||
int z = MathHelper.floor(pos.getZ() + world.rand.nextGaussian() * this.dist);
|
||||
BlockPos chosenPos = new BlockPos(x, world.getHeight(x, z), z);
|
||||
if (chosenPos.distanceSq(pos) <= dist * dist && world.isBlockLoaded(chosenPos)) {
|
||||
if (chosenPos.distanceSq(pos) <= this.dist * this.dist && world.isBlockLoaded(chosenPos)) {
|
||||
world.newExplosion(null,
|
||||
chosenPos.getX() + 0.5, chosenPos.getY() + 0.5, chosenPos.getZ() + 0.5,
|
||||
strength, false, true);
|
||||
this.strength, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ import de.ellpeck.naturesaura.api.aura.type.IAuraType;
|
|||
import de.ellpeck.naturesaura.blocks.ModBlocks;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
@ -20,21 +22,48 @@ public class GrassDieEffect implements IDrainSpotEffect {
|
|||
|
||||
public static final ResourceLocation NAME = new ResourceLocation(NaturesAura.MOD_ID, "grass_die");
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
private int amount;
|
||||
private int dist;
|
||||
|
||||
private boolean calcValues(World world, BlockPos pos, Integer spot) {
|
||||
if (spot < 0) {
|
||||
int aura = IAuraChunk.getAuraInArea(world, pos, 50);
|
||||
if (aura < 0) {
|
||||
int amount = Math.min(300, Math.abs(aura) / 100000);
|
||||
if (amount > 1) {
|
||||
int dist = MathHelper.clamp(Math.abs(aura) / 75000, 5, 75);
|
||||
for (int i = amount / 2 + world.rand.nextInt(amount / 2); i >= 0; i--) {
|
||||
this.amount = Math.min(300, Math.abs(aura) / 100000);
|
||||
if (this.amount > 1) {
|
||||
this.dist = MathHelper.clamp(Math.abs(aura) / 75000, 5, 75);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(player.world, pos, spot))
|
||||
return -1;
|
||||
if (player.getDistanceSq(pos) > this.dist * this.dist)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayIcon() {
|
||||
return new ItemStack(ModBlocks.DECAYED_LEAVES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(world, pos, spot))
|
||||
return;
|
||||
for (int i = this.amount / 2 + world.rand.nextInt(this.amount / 2); i >= 0; i--) {
|
||||
BlockPos grassPos = new BlockPos(
|
||||
pos.getX() + world.rand.nextGaussian() * dist,
|
||||
pos.getY() + world.rand.nextGaussian() * dist,
|
||||
pos.getZ() + world.rand.nextGaussian() * dist
|
||||
pos.getX() + world.rand.nextGaussian() * this.dist,
|
||||
pos.getY() + world.rand.nextGaussian() * this.dist,
|
||||
pos.getZ() + world.rand.nextGaussian() * this.dist
|
||||
);
|
||||
if (grassPos.distanceSq(pos) <= dist * dist && world.isBlockLoaded(grassPos)) {
|
||||
if (grassPos.distanceSq(pos) <= this.dist * this.dist && world.isBlockLoaded(grassPos)) {
|
||||
IBlockState state = world.getBlockState(grassPos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
|
@ -51,9 +80,6 @@ public class GrassDieEffect implements IDrainSpotEffect {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesHere(Chunk chunk, IAuraChunk auraChunk, IAuraType type) {
|
||||
|
|
|
@ -11,7 +11,10 @@ import de.ellpeck.naturesaura.packet.PacketParticles;
|
|||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.IGrowable;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
@ -22,23 +25,47 @@ public class PlantBoostEffect implements IDrainSpotEffect {
|
|||
|
||||
public static final ResourceLocation NAME = new ResourceLocation(NaturesAura.MOD_ID, "plant_boost");
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
private int amount;
|
||||
private int dist;
|
||||
|
||||
private boolean calcValues(World world, BlockPos pos, Integer spot) {
|
||||
if (spot <= 0)
|
||||
return;
|
||||
return false;
|
||||
int aura = IAuraChunk.getAuraInArea(world, pos, 30);
|
||||
if (aura < 1500000)
|
||||
return;
|
||||
int amount = Math.min(45, Math.abs(aura) / 100000);
|
||||
if (amount <= 1)
|
||||
return;
|
||||
int dist = MathHelper.clamp(Math.abs(aura) / 150000, 5, 35);
|
||||
return false;
|
||||
this.amount = Math.min(45, Math.abs(aura) / 100000);
|
||||
if (this.amount <= 1)
|
||||
return false;
|
||||
this.dist = MathHelper.clamp(Math.abs(aura) / 150000, 5, 35);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = amount / 2 + world.rand.nextInt(amount / 2); i >= 0; i--) {
|
||||
int x = MathHelper.floor(pos.getX() + world.rand.nextGaussian() * dist);
|
||||
int z = MathHelper.floor(pos.getZ() + world.rand.nextGaussian() * dist);
|
||||
@Override
|
||||
public int isActiveHere(EntityPlayer player, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(player.world, pos, spot))
|
||||
return -1;
|
||||
if (player.getDistanceSq(pos) > this.dist * this.dist)
|
||||
return -1;
|
||||
if (NaturesAuraAPI.instance().isEffectPowderActive(player.world, player.getPosition(), NAME))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayIcon() {
|
||||
return new ItemStack(Items.WHEAT_SEEDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(World world, Chunk chunk, IAuraChunk auraChunk, BlockPos pos, Integer spot) {
|
||||
if (!this.calcValues(world, pos, spot))
|
||||
return;
|
||||
for (int i = this.amount / 2 + world.rand.nextInt(this.amount / 2); i >= 0; i--) {
|
||||
int x = MathHelper.floor(pos.getX() + world.rand.nextGaussian() * this.dist);
|
||||
int z = MathHelper.floor(pos.getZ() + world.rand.nextGaussian() * this.dist);
|
||||
BlockPos plantPos = new BlockPos(x, world.getHeight(x, z), z);
|
||||
if (plantPos.distanceSq(pos) <= dist * dist && world.isBlockLoaded(plantPos)) {
|
||||
if (plantPos.distanceSq(pos) <= this.dist * this.dist && world.isBlockLoaded(plantPos)) {
|
||||
if (NaturesAuraAPI.instance().isEffectPowderActive(world, plantPos, NAME))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
@ -58,6 +59,10 @@ import java.util.Map;
|
|||
public class ClientEvents {
|
||||
|
||||
public static final ResourceLocation OVERLAYS = new ResourceLocation(NaturesAura.MOD_ID, "textures/gui/overlays.png");
|
||||
private static final Map<ResourceLocation, Tuple<ItemStack, Boolean>> SHOWING_EFFECTS = new HashMap<>();
|
||||
private static ItemStack heldCache = ItemStack.EMPTY;
|
||||
private static ItemStack heldEye = ItemStack.EMPTY;
|
||||
private static ItemStack heldOcular = ItemStack.EMPTY;
|
||||
|
||||
@SubscribeEvent
|
||||
public void onDebugRender(RenderGameOverlayEvent.Text event) {
|
||||
|
@ -95,6 +100,10 @@ public class ClientEvents {
|
|||
@SubscribeEvent
|
||||
public void onClientTick(ClientTickEvent event) {
|
||||
if (event.phase == Phase.END) {
|
||||
heldCache = ItemStack.EMPTY;
|
||||
heldEye = ItemStack.EMPTY;
|
||||
heldOcular = ItemStack.EMPTY;
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
if (mc.world == null) {
|
||||
ParticleHandler.clearParticles();
|
||||
|
@ -138,6 +147,41 @@ public class ClientEvents {
|
|||
if (!mc.isGamePaused())
|
||||
ParticleHandler.updateParticles();
|
||||
mc.profiler.endSection();
|
||||
|
||||
if (mc.player != null) {
|
||||
if (Compat.baubles) {
|
||||
IItemHandler baubles = BaublesApi.getBaublesHandler(mc.player);
|
||||
for (int i = 0; i < baubles.getSlots(); i++) {
|
||||
ItemStack slot = baubles.getStackInSlot(i);
|
||||
if (!slot.isEmpty()) {
|
||||
if (slot.getItem() == ModItems.AURA_CACHE)
|
||||
heldCache = slot;
|
||||
else if (slot.getItem() == ModItems.EYE)
|
||||
heldEye = slot;
|
||||
else if (slot.getItem() == ModItems.EYE_IMPROVED)
|
||||
heldOcular = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mc.player.inventory.getSizeInventory(); i++) {
|
||||
ItemStack slot = mc.player.inventory.getStackInSlot(i);
|
||||
if (!slot.isEmpty()) {
|
||||
if (slot.getItem() == ModItems.AURA_CACHE)
|
||||
heldCache = slot;
|
||||
else if (slot.getItem() == ModItems.EYE && i <= 8)
|
||||
heldEye = slot;
|
||||
else if (slot.getItem() == ModItems.EYE_IMPROVED)
|
||||
heldOcular = slot;
|
||||
}
|
||||
}
|
||||
|
||||
if (!heldOcular.isEmpty() && mc.world.getTotalWorldTime() % 20 == 0) {
|
||||
SHOWING_EFFECTS.clear();
|
||||
Helper.getAuraChunksInArea(mc.world, mc.player.getPosition(), 100,
|
||||
chunk -> chunk.getActiveEffectIcons(mc.player, SHOWING_EFFECTS));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -237,39 +281,8 @@ public class ClientEvents {
|
|||
if (event.getType() == ElementType.ALL) {
|
||||
ScaledResolution res = event.getResolution();
|
||||
if (mc.player != null) {
|
||||
ItemStack cache = ItemStack.EMPTY;
|
||||
ItemStack eye = ItemStack.EMPTY;
|
||||
ItemStack eyeImproved = ItemStack.EMPTY;
|
||||
|
||||
if (Compat.baubles) {
|
||||
IItemHandler baubles = BaublesApi.getBaublesHandler(mc.player);
|
||||
for (int i = 0; i < baubles.getSlots(); i++) {
|
||||
ItemStack slot = baubles.getStackInSlot(i);
|
||||
if (!slot.isEmpty()) {
|
||||
if (slot.getItem() == ModItems.AURA_CACHE)
|
||||
cache = slot;
|
||||
else if (slot.getItem() == ModItems.EYE)
|
||||
eye = slot;
|
||||
else if (slot.getItem() == ModItems.EYE_IMPROVED)
|
||||
eyeImproved = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mc.player.inventory.getSizeInventory(); i++) {
|
||||
ItemStack slot = mc.player.inventory.getStackInSlot(i);
|
||||
if (!slot.isEmpty()) {
|
||||
if (slot.getItem() == ModItems.AURA_CACHE)
|
||||
cache = slot;
|
||||
else if (slot.getItem() == ModItems.EYE && i <= 8)
|
||||
eye = slot;
|
||||
else if (slot.getItem() == ModItems.EYE_IMPROVED)
|
||||
eyeImproved = slot;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cache.isEmpty()) {
|
||||
IAuraContainer container = cache.getCapability(NaturesAuraAPI.capAuraContainer, null);
|
||||
if (!heldCache.isEmpty()) {
|
||||
IAuraContainer container = heldCache.getCapability(NaturesAuraAPI.capAuraContainer, null);
|
||||
int width = MathHelper.ceil(container.getStoredAura() / (float) container.getMaxAura() * 80);
|
||||
int x = res.getScaledWidth() / 2 - 173 - (mc.player.getHeldItemOffhand().isEmpty() ? 0 : 29);
|
||||
int y = res.getScaledHeight() - 8;
|
||||
|
@ -286,14 +299,14 @@ public class ClientEvents {
|
|||
|
||||
float scale = 0.75F;
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
String s = cache.getDisplayName();
|
||||
String s = heldCache.getDisplayName();
|
||||
mc.fontRenderer.drawString(s, (x + 80) / scale - mc.fontRenderer.getStringWidth(s), (y - 7) / scale, color, true);
|
||||
|
||||
GlStateManager.color(1F, 1F, 1F);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
if (!eye.isEmpty() || !eyeImproved.isEmpty()) {
|
||||
if (!heldEye.isEmpty() || !heldOcular.isEmpty()) {
|
||||
GlStateManager.pushMatrix();
|
||||
mc.getTextureManager().bindTexture(OVERLAYS);
|
||||
|
||||
|
@ -307,19 +320,19 @@ public class ClientEvents {
|
|||
float textScale = 0.75F;
|
||||
|
||||
int startX = conf % 2 == 0 ? 3 : res.getScaledWidth() - 3 - 6;
|
||||
int startY = conf < 2 ? 10 : (!eyeImproved.isEmpty() && (totalPercentage > 1F || totalPercentage < 0) ? -26 : 0) + res.getScaledHeight() - 60;
|
||||
int startY = conf < 2 ? 10 : (!heldOcular.isEmpty() && (totalPercentage > 1F || totalPercentage < 0) ? -26 : 0) + res.getScaledHeight() - 60;
|
||||
float plusOffX = conf % 2 == 0 ? 7 : -1 - 6;
|
||||
float textX = conf % 2 == 0 ? 3 : res.getScaledWidth() - 3 - mc.fontRenderer.getStringWidth(text) * textScale;
|
||||
float textY = conf < 2 ? 3 : res.getScaledHeight() - 3 - 6;
|
||||
|
||||
int tHeight = MathHelper.ceil(MathHelper.clamp(totalPercentage, 0F, 1F) * 50);
|
||||
int y = !eyeImproved.isEmpty() && totalPercentage > 1F ? startY + 26 : startY;
|
||||
int y = !heldOcular.isEmpty() && totalPercentage > 1F ? startY + 26 : startY;
|
||||
if (tHeight < 50)
|
||||
Gui.drawModalRectWithCustomSizedTexture(startX, y, 6, 12, 6, 50 - tHeight, 256, 256);
|
||||
if (tHeight > 0)
|
||||
Gui.drawModalRectWithCustomSizedTexture(startX, y + 50 - tHeight, 0, 12 + 50 - tHeight, 6, tHeight, 256, 256);
|
||||
|
||||
if (!eyeImproved.isEmpty()) {
|
||||
if (!heldOcular.isEmpty()) {
|
||||
GlStateManager.color(160 / 255F, 83 / 255F, 8 / 255F);
|
||||
|
||||
int topHeight = MathHelper.ceil(MathHelper.clamp((totalPercentage - 1F) * 2F, 0F, 1F) * 25);
|
||||
|
@ -336,16 +349,37 @@ public class ClientEvents {
|
|||
}
|
||||
}
|
||||
|
||||
int color = eyeImproved.isEmpty() ? 0x53a008 : 0xa05308;
|
||||
if (totalPercentage > (eyeImproved.isEmpty() ? 1F : 1.5F))
|
||||
int color = heldOcular.isEmpty() ? 0x53a008 : 0xa05308;
|
||||
if (totalPercentage > (heldOcular.isEmpty() ? 1F : 1.5F))
|
||||
mc.fontRenderer.drawString("+", startX + plusOffX, startY - 0.5F, color, true);
|
||||
if (totalPercentage < (eyeImproved.isEmpty() ? 0F : -0.5F))
|
||||
mc.fontRenderer.drawString("-", startX + plusOffX, startY - 0.5F + (eyeImproved.isEmpty() ? 44 : 70), color, true);
|
||||
if (totalPercentage < (heldOcular.isEmpty() ? 0F : -0.5F))
|
||||
mc.fontRenderer.drawString("-", startX + plusOffX, startY - 0.5F + (heldOcular.isEmpty() ? 44 : 70), color, true);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.scale(textScale, textScale, textScale);
|
||||
mc.fontRenderer.drawString(text, textX / textScale, textY / textScale, 0x53a008, true);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
if (!heldOcular.isEmpty()) {
|
||||
float scale = 0.75F;
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
int stackY = 15;
|
||||
for (Tuple<ItemStack, Boolean> effect : SHOWING_EFFECTS.values()) {
|
||||
int theX = (int) (10 / scale);
|
||||
int theY = (int) (stackY / scale);
|
||||
ItemStack stack = effect.getFirst();
|
||||
Helper.renderItemInGui(stack, theX, theY, 1F);
|
||||
if (effect.getSecond()) {
|
||||
GlStateManager.disableDepth();
|
||||
mc.getTextureManager().bindTexture(OVERLAYS);
|
||||
Gui.drawModalRectWithCustomSizedTexture(theX, theY, 240, 0, 16, 16, 256, 256);
|
||||
GlStateManager.enableDepth();
|
||||
}
|
||||
stackY += 8;
|
||||
}
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
if (mc.objectMouseOver != null) {
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "It needs be noted that the extended bar only shows if $(aura) levels are high or low enough.$(br)An additional perk is that, while the $(item)Environmental Eye$() needs to be held in the hotbar, the $(item)Environmental Ocular$() can be anywhere in the user's inventory to work.$(p)All other properties of the $(item)Environmental Eye$() carry over to the $(item)Environmental Ocular$() as expected."
|
||||
"text": "It needs be noted that the extended bar only shows if $(aura) levels are high or low enough.$(p)Secondly, the $(item)Environmental Ocular$() has the ability to display all $(thing)Aura Imbalance$() effects that are currently occuring in the place the user is standing. The icons it displays are the same as the ones depicted for each effect in the $(thing)Aura Imbalance$() section of this book."
|
||||
},{
|
||||
"type": "text",
|
||||
"text": "An additional perk is that, while the $(item)Environmental Eye$() needs to be held in the hotbar, the $(item)Environmental Ocular$() can be anywhere in the user's inventory to work.$(p)All other properties of the $(item)Environmental Eye$() carry over to the $(item)Environmental Ocular$() as expected."
|
||||
},
|
||||
{
|
||||
"type": "naturesaura:tree_ritual",
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.1 KiB |
Loading…
Reference in a new issue