diff --git a/build.gradle b/build.gradle
index 5a4790ad..ee2094e8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -59,6 +59,8 @@ minecraft {
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
+
+ def argsz = ['--username', 'WinDanesz', '--user', 'WinDanesz', '--uuid', '7faee354-8c60-4f5c-9862-fc0ce5f7f575']
runs {
client {
workingDirectory project.file('run')
@@ -68,6 +70,7 @@ minecraft {
// Recommended logging level for the console
property 'forge.logging.console.level', 'info'
+ args argsz
}
server {
diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java
index 0b715922..ccf01dec 100644
--- a/src/main/java/electroblob/wizardry/Settings.java
+++ b/src/main/java/electroblob/wizardry/Settings.java
@@ -138,6 +138,12 @@ public final class Settings {
new ResourceLocation(Wizardry.MODID, "shrine_5"),
new ResourceLocation(Wizardry.MODID, "shrine_6"),
new ResourceLocation(Wizardry.MODID, "shrine_7")};
+ /** [Server-only] Whether conquered shrines should regenerate after a period of time. */
+ public boolean shrineRegenerationEnabled = true;
+ /** [Server-only] Time in minutes for a conquered shrine to regenerate. */
+ public int shrineRegenerationTime = 1;
+ /** [Server-only] Whether players can loot shrines multiple times. If false, each player can only loot each shrine once. */
+ public boolean shrineAllowMultipleLoot = false;
/** [Server-only] List of dimension ids in which to generate library ruins. */
public int[] libraryDimensions = {0};
/** [Server-only] The rarity of library ruins, used by the world generator. Larger numbers are rarer. */
@@ -1124,6 +1130,22 @@ public final class Settings {
shrineFiles = getResourceLocationList(property);
propOrder.add(property.getName());
+ property = config.get(WORLDGEN_CATEGORY, "shrineRegenerationEnabled", true, "Whether conquered shrines should regenerate after a period of time. When disabled, shrines remain conquered permanently.");
+ property.setLanguageKey("config." + Wizardry.MODID + ".shrine_regeneration_enabled");
+ shrineRegenerationEnabled = property.getBoolean();
+ propOrder.add(property.getName());
+
+ property = config.get(WORLDGEN_CATEGORY, "shrineRegenerationTime", 1, "Time in minutes for a conquered shrine to regenerate. Minimum 1 minute, maximum 1440 minutes (24 hours).", 1, 1440);
+ property.setLanguageKey("config." + Wizardry.MODID + ".shrine_regeneration_time");
+ Wizardry.proxy.setToNumberSliderEntry(property);
+ shrineRegenerationTime = property.getInt();
+ propOrder.add(property.getName());
+
+ property = config.get(WORLDGEN_CATEGORY, "shrineAllowMultipleLoot", false, "Whether players can loot shrines multiple times. If false, each player can only loot each shrine once until it regenerates.");
+ property.setLanguageKey("config." + Wizardry.MODID + ".shrine_allow_multiple_loot");
+ shrineAllowMultipleLoot = property.getBoolean();
+ propOrder.add(property.getName());
+
property = config.get(WORLDGEN_CATEGORY, "libraryDimensions", new int[]{0}, "List of dimension ids in which library ruins will generate. Remove all dimensions to disable library ruins completely.");
property.setLanguageKey("config." + Wizardry.MODID + ".library_dimensions");
property.setRequiresWorldRestart(true);
diff --git a/src/main/java/electroblob/wizardry/block/BlockPedestal.java b/src/main/java/electroblob/wizardry/block/BlockPedestal.java
index 53bb1bb4..a6177b2d 100644
--- a/src/main/java/electroblob/wizardry/block/BlockPedestal.java
+++ b/src/main/java/electroblob/wizardry/block/BlockPedestal.java
@@ -1,5 +1,6 @@
package electroblob.wizardry.block;
+import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.tileentity.TileEntityShrineCore;
@@ -81,11 +82,25 @@ public class BlockPedestal extends Block implements ITileEntityProvider {
@Override
public float getBlockHardness(IBlockState state, World world, BlockPos pos){
+ // If shrine regeneration is enabled, make pedestal blocks with shrine cores unbreakable to prevent exploitation
+ if(!world.isRemote && Wizardry.settings != null && Wizardry.settings.shrineRegenerationEnabled){
+ TileEntity tileEntity = world.getTileEntity(pos);
+ if(tileEntity instanceof TileEntityShrineCore){
+ return -1; // Unbreakable if it has a shrine core
+ }
+ }
return state.getValue(NATURAL) ? -1 : super.getBlockHardness(state, world, pos);
}
@Override
public float getExplosionResistance(World world, BlockPos pos, @Nullable Entity exploder, Explosion explosion){
+ // If shrine regeneration is enabled, make pedestal blocks with shrine cores unbreakable to prevent exploitation
+ if(!world.isRemote && Wizardry.settings != null && Wizardry.settings.shrineRegenerationEnabled){
+ TileEntity tileEntity = world.getTileEntity(pos);
+ if(tileEntity instanceof TileEntityShrineCore){
+ return 6000000.0F; // Unbreakable if it has a shrine core
+ }
+ }
return world.getBlockState(pos).getValue(NATURAL) ? 6000000.0F : super.getExplosionResistance(world, pos, exploder, explosion);
}
diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneLock.java b/src/main/java/electroblob/wizardry/spell/ArcaneLock.java
index 7c532079..60816844 100644
--- a/src/main/java/electroblob/wizardry/spell/ArcaneLock.java
+++ b/src/main/java/electroblob/wizardry/spell/ArcaneLock.java
@@ -13,14 +13,18 @@ import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
+import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingDestroyBlockEvent;
+
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.ExplosionEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+
@Mod.EventBusSubscriber
public class ArcaneLock extends SpellRay {
@@ -167,4 +171,8 @@ public class ArcaneLock extends SpellRay {
&& event.getWorld().getTileEntity(pos).getTileData().hasUniqueId(NBT_KEY));
}
+
+
+
+
}
diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java
index 6bde7079..bf9e3feb 100644
--- a/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java
+++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java
@@ -2,6 +2,7 @@ package electroblob.wizardry.tileentity;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockPedestal;
+import electroblob.wizardry.constants.Element;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.packet.PacketConquerShrine;
@@ -13,87 +14,120 @@ import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.ArcaneLock;
import electroblob.wizardry.util.*;
import electroblob.wizardry.util.ParticleBuilder.Type;
+import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
+import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.util.ITickable;
+import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
+import net.minecraft.util.text.TextComponentTranslation;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.network.NetworkRegistry;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
+import java.util.*;
public class TileEntityShrineCore extends TileEntity implements ITickable {
private static final double ACTIVATION_RADIUS = 5;
private boolean activated = false;
+ private boolean conquered = false;
+ private long regenerationTime = 0;
+ private long lastRegenerationTime = 0;
+ private Element shrineElement;
private AxisAlignedBB containmentField;
private final UUID[] linkedWizards = new UUID[3];
private TileEntity linkedContainer;
private BlockPos linkedContainerPos; // Temporary stores the container position read from NBT until the world is set
+ private final Set lootedPlayers = new HashSet<>();
@Override
- public void setPos(BlockPos pos){
+ public void setPos(BlockPos pos) {
super.setPos(pos);
initContainmentField(pos);
}
- private void initContainmentField(BlockPos pos){
+ private void initContainmentField(BlockPos pos) {
float r = PotionContainment.getContainmentDistance(0);
this.containmentField = new AxisAlignedBB(-r, -r, -r, r, r, r).offset(GeometryUtils.getCentre(pos));
}
- public void linkContainer(TileEntity container){
+ public void linkContainer(TileEntity container) {
this.linkedContainer = container;
}
- @Override
- public void update(){
+ public void setShrineElement(Element element) {
+ this.shrineElement = element;
+ }
- if(this.linkedContainer == null && this.linkedContainerPos != null){
+ public boolean canPlayerLoot(EntityPlayer player) {
+ if (Wizardry.settings.shrineAllowMultipleLoot) {
+ return true; // Allow multiple looting if enabled
+ }
+ return !lootedPlayers.contains(player.getUniqueID());
+ }
+
+ public void recordPlayerLoot(EntityPlayer player) {
+ if (!Wizardry.settings.shrineAllowMultipleLoot) {
+ lootedPlayers.add(player.getUniqueID());
+ this.markDirty();
+ }
+ }
+
+ @Override
+ public void update() {
+
+ if (this.linkedContainer == null && this.linkedContainerPos != null) {
this.linkContainer(world.getTileEntity(this.linkedContainerPos));
}
+ // Handle shrine regeneration
+ if (conquered && Wizardry.settings.shrineRegenerationEnabled && regenerationTime > 0) {
+ if (world.getTotalWorldTime() >= regenerationTime) {
+ regenerate();
+ return; // Don't process other logic during regeneration
+ }
+ }
+
double x = this.pos.getX() + 0.5;
double y = this.pos.getY() + 0.5;
double z = this.pos.getZ() + 0.5;
- if(!activated && world.getClosestPlayer(x, y, z, ACTIVATION_RADIUS, false) != null){
+ if (!activated && !conquered && world.getClosestPlayer(x, y, z, ACTIVATION_RADIUS, false) != null && (lastRegenerationTime == 0 || world.getTotalWorldTime() - lastRegenerationTime > 100)) { // 5 second delay after regeneration
this.activated = true;
- if(world.isRemote){
+ if (world.isRemote) {
ParticleBuilder.create(Type.SPHERE).pos(x, y + 1, z).clr(0xf06495).scale(5).time(12).spawn(world);
}
- world.playSound(x, y, z,
- WizardrySounds.BLOCK_PEDESTAL_ACTIVATE, SoundCategory.BLOCKS, 1.5f, 1, false);
+ world.playSound(x, y, z, WizardrySounds.BLOCK_PEDESTAL_ACTIVATE, SoundCategory.BLOCKS, 1.5f, 1, false);
- if(!world.isRemote){
+ if (!world.isRemote) {
EntityEvilWizard[] wizards = new EntityEvilWizard[linkedWizards.length];
- for(int i = 0; i < linkedWizards.length; i++){
+ for (int i = 0; i < linkedWizards.length; i++) {
EntityEvilWizard wizard = new EntityEvilWizard(world);
- float angle = world.rand.nextFloat() * 2 * (float)Math.PI;
+ float angle = world.rand.nextFloat() * 2 * (float) Math.PI;
double x1 = this.pos.getX() + 0.5 + 5 * MathHelper.sin(angle);
double z1 = this.pos.getZ() + 0.5 + 5 * MathHelper.cos(angle);
Integer y1 = BlockUtils.getNearestFloor(world, new BlockPos(x1, this.pos.getY(), z1), 8);
- if(y1 == null){
+ if (y1 == null) {
// Fallback to the position of the shrine core if it failed to find a position (unlikely)
x1 = this.pos.getX() + 1; // Offset it so the wizard isn't inside the block
y1 = this.pos.getY();
@@ -110,110 +144,279 @@ public class TileEntityShrineCore extends TileEntity implements ITickable {
linkedWizards[i] = wizard.getUniqueID();
}
- for(EntityEvilWizard wizard : wizards) wizard.groupUUIDs.addAll(Arrays.asList(linkedWizards));
+ for (EntityEvilWizard wizard : wizards) wizard.groupUUIDs.addAll(Arrays.asList(linkedWizards));
}
containNearbyTargets();
}
- if(activated && world.getTotalWorldTime() % 20L == 0) containNearbyTargets();
+ if (!areWizardsDead() && activated && world.getTotalWorldTime() % 20L == 0) containNearbyTargets();
- if(activated && areWizardsDead() && !world.isRemote){
+ if (activated && areWizardsDead() && !world.isRemote) {
conquer();
}
}
- private boolean areWizardsDead(){
+ private boolean areWizardsDead() {
- for(UUID uuid : linkedWizards){
+ for (UUID uuid : linkedWizards) {
Entity entity = EntityUtils.getEntityByUUID(world, uuid);
- if(entity instanceof EntityEvilWizard && entity.isEntityAlive()) return false;
+ if (entity instanceof EntityEvilWizard && entity.isEntityAlive()) return false;
}
return true;
}
- public void conquer(){
+ public void conquer() {
double x = this.pos.getX() + 0.5;
double y = this.pos.getY() + 0.5;
double z = this.pos.getZ() + 0.5;
- if(!world.isRemote){
+ if (!world.isRemote) {
- WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos),
- new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64));
+ WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos), new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64));
- if(world.getBlockState(pos).getBlock() == WizardryBlocks.runestone_pedestal){
- world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState()
- .withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT)));
- }else{
- Wizardry.logger.warn("What's going on?! A shrine core is being conquered but the block at its position is not a runestone pedestal!");
+ // Remove containment effects from nearby targets when shrine is conquered
+ removeContainmentFromNearbyTargets();
+
+ // If regeneration is enabled, schedule regeneration instead of removing the tile entity
+ if (Wizardry.settings.shrineRegenerationEnabled) {
+ this.conquered = true;
+ this.regenerationTime = world.getTotalWorldTime() + (Wizardry.settings.shrineRegenerationTime * 1200L); // Convert minutes to ticks (20 ticks per second * 60 seconds)
+ this.activated = false;
+ Arrays.fill(this.linkedWizards, null); // Clear wizard references
+ // Keep lootedPlayers list - it's permanent tracking for this shrine instance
+
+ // Handle chest breaking and loot dropping
+ handleChestLootDrop();
+
+ // Mark the tile entity for update
+ this.markDirty();
+
+ if (world.getBlockState(pos).getBlock() == WizardryBlocks.runestone_pedestal) {
+ // Keep the block state the same, just mark as conquered
+ this.shrineElement = world.getBlockState(pos).getValue(BlockPedestal.ELEMENT);
+ } else {
+ Wizardry.logger.warn("What's going on?! A shrine core is being conquered but the block at its position is not a runestone pedestal!");
+ }
+ } else {
+ // Original behavior: remove the tile entity
+ BlockPos chestPos = this.pos.up();
+ TileEntity chestTileEntity = world.getTileEntity(chestPos);
+ if (chestTileEntity instanceof TileEntityChest) {
+ TileEntityChest chest = (TileEntityChest) chestTileEntity;
+ NBTExtras.removeUniqueId(chest.getTileData(), ArcaneLock.NBT_KEY);
+ chest.markDirty();
+ world.markAndNotifyBlock(pos, null, world.getBlockState(pos), world.getBlockState(pos), 3);
+ }
+ if (world.getBlockState(pos).getBlock() == WizardryBlocks.runestone_pedestal) {
+ world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState().withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT)));
+ } else {
+ Wizardry.logger.warn("What's going on?! A shrine core is being conquered but the block at its position is not a runestone pedestal!");
+ }
+ world.markTileEntityForRemoval(this);
}
}
- world.markTileEntityForRemoval(this);
-
- if(!world.isRemote){
- if(linkedContainer != null) NBTExtras.removeUniqueId(linkedContainer.getTileData(), ArcaneLock.NBT_KEY);
- }else{
- TileEntity tileEntity = world.getTileEntity(this.pos.up());
- if(tileEntity != null){ // Bit of a dirty fix but it's only visual, so meh
- NBTExtras.removeUniqueId(tileEntity.getTileData(), ArcaneLock.NBT_KEY);
- }
+ if (linkedContainer == null) {
+ linkedContainer = world.getTileEntity(pos.up());
}
+ if (linkedContainer != null) {
+ NBTExtras.removeUniqueId(linkedContainer.getTileData(), ArcaneLock.NBT_KEY);
+ //linkedContainer.getTileData().removeTag("arcaneLockOwnerMost");
+ //linkedContainer.getTileData().removeTag("arcaneLockOwnerLeast");
+ }
world.playSound(x, y, z, WizardrySounds.BLOCK_PEDESTAL_CONQUER, SoundCategory.BLOCKS, 1, 1, false);
- if(world.isRemote){
+ if (world.isRemote) {
ParticleBuilder.create(Type.SPHERE).scale(5).pos(x, y + 1, z).clr(0xf06495).time(12).spawn(world);
- for(int i=0; i<5; i++){
+ for (int i = 0; i < 5; i++) {
float brightness = 0.8f + world.rand.nextFloat() * 0.2f;
- ParticleBuilder.create(Type.SPARKLE, world.rand, x, y + 1, z, 1, true)
- .clr(1, brightness, brightness).spawn(world);
+ ParticleBuilder.create(Type.SPARKLE, world.rand, x, y + 1, z, 1, true).clr(1, brightness, brightness).spawn(world);
}
}
}
- private void containNearbyTargets(){
+ private void regenerate() {
- List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, containmentField,
- e -> e instanceof EntityPlayer || e instanceof EntityWizard || e instanceof EntityEvilWizard);
+ if (world.isRemote) return;
- for(EntityLivingBase entity : entities){
+ // Remove containment effects from nearby targets when shrine regenerates
+ removeContainmentFromNearbyTargets();
+
+ // Reset shrine state
+ this.conquered = false;
+ this.regenerationTime = 0;
+ this.activated = false;
+ Arrays.fill(this.linkedWizards, null);
+ // Keep lootedPlayers list - it's permanent for this shrine instance
+
+ // Force a short delay before allowing reactivation to prevent immediate re-activation
+ this.lastRegenerationTime = world.getTotalWorldTime();
+
+ // Forcibly replace whatever block is above the altar with a fresh chest
+ BlockPos chestPos = this.pos.up();
+
+ // Always replace the block above with a fresh chest during regeneration
+ world.setBlockState(chestPos, Blocks.CHEST.getDefaultState());
+
+ // Set up the loot table for the shrine chest
+ TileEntity chestTileEntity = world.getTileEntity(chestPos);
+ if (chestTileEntity instanceof TileEntityChest) {
+ TileEntityChest chest = (TileEntityChest) chestTileEntity;
+ chest.setLootTable(new ResourceLocation(Wizardry.MODID, "chests/shrine"), world.rand.nextLong());
+ }
+
+ // Link and apply arcane lock to the container
+ if (chestTileEntity != null) {
+ this.linkContainer(chestTileEntity);
+ chestTileEntity.getTileData().setUniqueId(ArcaneLock.NBT_KEY, new UUID(0, 0)); // Nil UUID for shrine lock
+ chestTileEntity.markDirty(); // Mark tile entity as dirty for client sync
+
+ // Trigger visual update for arcane lock effect
+ IBlockState blockState = world.getBlockState(chestPos);
+ world.markAndNotifyBlock(chestPos, null, blockState, blockState, 3);
+ world.notifyBlockUpdate(chestPos, blockState, blockState, 3); // Additional client sync
+ }
+
+ // Visual and audio effects for regeneration
+ double x = this.pos.getX() + 0.5;
+ double y = this.pos.getY() + 0.5;
+ double z = this.pos.getZ() + 0.5;
+
+ // WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos), new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64));
+
+ if (world.isRemote) {
+ ParticleBuilder.create(Type.SPHERE).pos(x, y + 1, z).clr(0xf06495).scale(5).time(12).spawn(world);
+ }
+
+ world.playSound(x, y, z, WizardrySounds.BLOCK_PEDESTAL_ACTIVATE, SoundCategory.BLOCKS, 1.5f, 1, false);
+
+ this.markDirty();
+ }
+
+ private void handleChestLootDrop() {
+ BlockPos chestPos = this.pos.up();
+
+ // Check if there's a chest at the expected position
+ if (world.getBlockState(chestPos).getBlock() == Blocks.CHEST) {
+ TileEntity chestTileEntity = world.getTileEntity(chestPos);
+
+ if (chestTileEntity instanceof TileEntityChest) {
+ TileEntityChest chest = (TileEntityChest) chestTileEntity;
+
+ // Find the player who conquered the shrine (closest player)
+ EntityPlayer conqueringPlayer = world.getClosestPlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 20.0, false);
+
+ if (conqueringPlayer != null && !canPlayerLoot(conqueringPlayer)) {
+ // Send message to player that they've already looted this shrine
+ if (!world.isRemote) {
+ conqueringPlayer.sendMessage(new TextComponentTranslation("wizardry.shrine_already_looted"));
+ }
+ chest.setLootTable(null, world.rand.nextLong());
+ if (world.getBlockState(chestPos).getBlock() == Blocks.CHEST) {
+ world.setBlockToAir(chestPos);
+ }
+ return;
+ }
+
+ if (conqueringPlayer != null && canPlayerLoot(conqueringPlayer)) {
+ // Record that this player has looted the shrine
+ recordPlayerLoot(conqueringPlayer);
+ }
+ // If player has already looted, don't drop anything
+ }
+ }
+
+ // Break the chest regardless
+ if (world.getBlockState(chestPos).getBlock() == Blocks.CHEST) {
+ world.setBlockToAir(chestPos);
+ }
+ }
+
+ private void containNearbyTargets() {
+ List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, containmentField, e -> e instanceof EntityPlayer || e instanceof EntityWizard || e instanceof EntityEvilWizard);
+
+ for (EntityLivingBase entity : entities) {
entity.addPotionEffect(new PotionEffect(WizardryPotions.containment, 219));
NBTExtras.storeTagSafely(entity.getEntityData(), PotionContainment.ENTITY_TAG, NBTUtil.createPosTag(this.pos));
}
}
+ private void removeContainmentFromNearbyTargets() {
+// List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, containmentField,
+// e -> e instanceof EntityPlayer || e instanceof EntityWizard || e instanceof EntityEvilWizard);
+//
+// for(EntityLivingBase entity : entities){
+// // Remove the containment potion effect
+// if(entity.isPotionActive(WizardryPotions.containment)){
+// entity.removePotionEffect(WizardryPotions.containment);
+// }
+// // Also remove the containment position tag
+// if(entity.getEntityData().hasKey(PotionContainment.ENTITY_TAG)){
+// BlockPos containmentPos = NBTUtil.getPosFromTag(entity.getEntityData().getCompoundTag(PotionContainment.ENTITY_TAG));
+// // Only remove if the containment position matches this shrine
+// if(containmentPos.equals(this.pos)){
+// entity.getEntityData().removeTag(PotionContainment.ENTITY_TAG);
+// }
+// }
+// }
+ }
+
@Override
- public NBTTagCompound writeToNBT(NBTTagCompound compound){
+ public NBTTagCompound writeToNBT(NBTTagCompound compound) {
compound.setBoolean("activated", this.activated);
- if(linkedContainer != null) NBTExtras.storeTagSafely(compound, "linkedContainerPos", NBTUtil.createPosTag(linkedContainer.getPos()));
+ compound.setBoolean("conquered", this.conquered);
+ compound.setLong("regenerationTime", this.regenerationTime);
+ compound.setLong("lastRegenerationTime", this.lastRegenerationTime);
+ if (shrineElement != null) compound.setInteger("shrineElement", this.shrineElement.ordinal());
+ if (linkedContainer != null)
+ NBTExtras.storeTagSafely(compound, "linkedContainerPos", NBTUtil.createPosTag(linkedContainer.getPos()));
- NBTTagList tagList = new NBTTagList();
- for(UUID uuid : linkedWizards){
- if(uuid != null) tagList.appendTag(NBTUtil.createUUIDTag(uuid));
+ NBTTagList wizardTagList = new NBTTagList();
+ for (UUID uuid : linkedWizards) {
+ if (uuid != null) wizardTagList.appendTag(NBTUtil.createUUIDTag(uuid));
}
- NBTExtras.storeTagSafely(compound, "wizards", tagList);
+ NBTExtras.storeTagSafely(compound, "wizards", wizardTagList);
+
+ NBTTagList playerTagList = new NBTTagList();
+ for (UUID uuid : lootedPlayers) {
+ playerTagList.appendTag(NBTUtil.createUUIDTag(uuid));
+ }
+ NBTExtras.storeTagSafely(compound, "lootedPlayers", playerTagList);
return super.writeToNBT(compound);
}
@Override
- public void readFromNBT(NBTTagCompound compound){
+ public void readFromNBT(NBTTagCompound compound) {
this.activated = compound.getBoolean("activated");
+ this.conquered = compound.getBoolean("conquered");
+ this.regenerationTime = compound.getLong("regenerationTime");
+ this.lastRegenerationTime = compound.getLong("lastRegenerationTime");
+ if (compound.hasKey("shrineElement"))
+ this.shrineElement = Element.values()[compound.getInteger("shrineElement")];
this.linkedContainerPos = NBTUtil.getPosFromTag(compound.getCompoundTag("linkedContainerPos"));
- NBTTagList tagList = compound.getTagList("wizards", Constants.NBT.TAG_COMPOUND);
+ NBTTagList wizardTagList = compound.getTagList("wizards", Constants.NBT.TAG_COMPOUND);
int i = 0;
- for(NBTBase tag : tagList){
- if(tag instanceof NBTTagCompound) linkedWizards[i++] = NBTUtil.getUUIDFromTag((NBTTagCompound)tag);
+ for (NBTBase tag : wizardTagList) {
+ if (tag instanceof NBTTagCompound) linkedWizards[i++] = NBTUtil.getUUIDFromTag((NBTTagCompound) tag);
else Wizardry.logger.warn("Unexpected tag type in NBT tag list of compound tags!");
}
+ this.lootedPlayers.clear();
+ if (compound.hasKey("lootedPlayers")) {
+ NBTTagList playerTagList = compound.getTagList("lootedPlayers", Constants.NBT.TAG_COMPOUND);
+ for (NBTBase tag : playerTagList) {
+ if (tag instanceof NBTTagCompound) lootedPlayers.add(NBTUtil.getUUIDFromTag((NBTTagCompound) tag));
+ }
+ }
+
super.readFromNBT(compound);
// Must be after super
initContainmentField(this.pos);
diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java
index 7e9b4d5d..2a735446 100644
--- a/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java
+++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java
@@ -74,13 +74,27 @@ public class WorldGenShrine extends WorldGenSurfaceStructure {
if(container != null){
container.getTileData().setUniqueId(ArcaneLock.NBT_KEY, new UUID(0, 0)); // Nil UUID
+ container.markDirty(); // Mark tile entity as dirty for client sync
- if(core instanceof TileEntityShrineCore){
- ((TileEntityShrineCore)core).linkContainer(container);
- }else{
- Wizardry.logger.info("What?!");
+ // Trigger visual update for arcane lock effect
+ BlockPos chestPos = entry.getKey().up();
+ net.minecraft.block.state.IBlockState blockState = world.getBlockState(chestPos);
+ world.markAndNotifyBlock(chestPos, null, blockState, blockState, 3);
+ world.notifyBlockUpdate(chestPos, blockState, blockState, 3); // Additional client sync
+
+ // Set up the loot table for the shrine chest
+ if(container instanceof net.minecraft.tileentity.TileEntityChest){
+ net.minecraft.tileentity.TileEntityChest chest = (net.minecraft.tileentity.TileEntityChest) container;
+ chest.setLootTable(new net.minecraft.util.ResourceLocation(Wizardry.MODID, "chests/shrine"), world.rand.nextLong());
}
+ if(core instanceof TileEntityShrineCore){
+ ((TileEntityShrineCore)core).linkContainer(container);
+ ((TileEntityShrineCore)core).setShrineElement(element);
+ }else{
+ Wizardry.logger.info("What?!");
+ }
+
}else{
Wizardry.logger.info("Expected chest or other container at {} in structure {}, found no tile entity", entry.getKey(), structureFile);
}
diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang
index 412aabcc..34f6d9bd 100644
--- a/src/main/resources/assets/ebwizardry/lang/en_us.lang
+++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang
@@ -1832,3 +1832,5 @@ spell.ebwizardry\:invigorating_presence_festive=Invigorating Presents
spell.ebwizardry\:empowering_presence_festive=Empowering Presents
wizard.debug=%1$s, %2$s, %3$s
+
+wizardry.shrine_already_looted=You have already looted this shrine!
\ No newline at end of file