/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Jul 23, 2014, 5:32:11 PM (GMT)]
*/
package vazkii.botania.common.block.tile;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.MobSpawnerBaseLogic;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedSpawnerEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
import vazkii.botania.api.mana.IManaReceiver;
import vazkii.botania.common.Botania;
import vazkii.botania.common.core.handler.MethodHandles;
public class TileSpawnerClaw extends TileMod implements IManaReceiver {
private static final String TAG_MANA = "mana";
int mana = 0;
@Override
public void update() {
TileEntity tileBelow = world.getTileEntity(pos.down());
if(mana >= 5 && tileBelow instanceof TileEntityMobSpawner) {
TileEntityMobSpawner spawner = (TileEntityMobSpawner) tileBelow;
MobSpawnerBaseLogic logic = spawner.getSpawnerBaseLogic();
try {
// Directly drawn from MobSpawnerBaseLogic, with inverted isActivated check and mana consumption
if(!((boolean) MethodHandles.isActivated.invokeExact(logic))) {
if(!world.isRemote)
mana -= 6;
if(logic.getSpawnerWorld().isRemote) {
int delay = (int) MethodHandles.spawnDelay_getter.invokeExact(logic);
if(delay > 0)
MethodHandles.spawnDelay_setter.invokeExact(logic, delay - 1);
if(Math.random() > 0.5)
Botania.proxy.wispFX(getPos().getX() + 0.3 + Math.random() * 0.5, getPos().getY() - 0.3 + Math.random() * 0.25, getPos().getZ() + Math.random(), 0.6F - (float) Math.random() * 0.3F, 0.1F, 0.6F - (float) Math.random() * 0.3F, (float) Math.random() / 3F, -0.025F - 0.005F * (float) Math.random(), 2F);
MethodHandles.prevMobRotation_setter.invokeExact(logic, logic.getMobRotation());
MethodHandles.mobRotation_setter.invokeExact(logic, (logic.getMobRotation() + 1000.0F / ((int) MethodHandles.spawnDelay_getter.invokeExact(logic) + 200.0F)) % 360.0D);
} else {
if((int) MethodHandles.spawnDelay_getter.invokeExact(logic) == -1)
resetTimer(logic);
int delay = (int) MethodHandles.spawnDelay_getter.invokeExact(logic);
if(delay > 0) {
MethodHandles.spawnDelay_setter.invokeExact(logic, delay - 1);
return;
}
if(logic.getSpawnerWorld().isRemote)
return;
boolean flag = false;
int spawnCount = (int) MethodHandles.spawnCount_getter.invokeExact(logic);
int spawnRange = (int) MethodHandles.spawnRange_getter.invokeExact(logic);
int maxNearbyEntities = (int) MethodHandles.maxNearbyEntities_getter.invokeExact(logic);
WeightedSpawnerEntity randomEntity = (WeightedSpawnerEntity) MethodHandles.randomEntity_getter.invokeExact(logic);
BlockPos blockpos = logic.getSpawnerPosition();
for(int i = 0; i < spawnCount; ++i) {
NBTTagCompound nbttagcompound = randomEntity.getNbt();
NBTTagList nbttaglist = nbttagcompound.getTagList("Pos", 6);
World world = logic.getSpawnerWorld();
int j = nbttaglist.tagCount();
double d0 = j >= 1 ? nbttaglist.getDoubleAt(0) : blockpos.getX() + (world.rand.nextDouble() - world.rand.nextDouble()) * spawnRange + 0.5D;
double d1 = j >= 2 ? nbttaglist.getDoubleAt(1) : (double)(blockpos.getY() + world.rand.nextInt(3) - 1);
double d2 = j >= 3 ? nbttaglist.getDoubleAt(2) : blockpos.getZ() + (world.rand.nextDouble() - world.rand.nextDouble()) * spawnRange + 0.5D;
Entity entity = AnvilChunkLoader.readWorldEntityPos(nbttagcompound, world, d0, d1, d2, false);
if (entity == null)
{
return;
}
int k = world.getEntitiesWithinAABB(entity.getClass(), new AxisAlignedBB(blockpos.getX(), blockpos.getY(), blockpos.getZ(), blockpos.getX() + 1, blockpos.getY() + 1, blockpos.getZ() + 1).expandXyz(spawnRange)).size();
if (k >= maxNearbyEntities)
{
resetTimer(logic);
return;
}
EntityLiving entityliving = entity instanceof EntityLiving ? (EntityLiving)entity : null;
entity.setLocationAndAngles(entity.posX, entity.posY, entity.posZ, world.rand.nextFloat() * 360.0F, 0.0F);
if (entityliving == null || net.minecraftforge.event.ForgeEventFactory.canEntitySpawnSpawner(entityliving, logic.getSpawnerWorld(), (float)entity.posX, (float)entity.posY, (float)entity.posZ))
{
if (randomEntity.getNbt().getSize() == 1 && randomEntity.getNbt().hasKey("id", 8) && entity instanceof EntityLiving)
{
if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(entityliving, logic.getSpawnerWorld(), (float)entity.posX, (float)entity.posY, (float)entity.posZ))
((EntityLiving)entity).onInitialSpawn(world.getDifficultyForLocation(new BlockPos(entity)), null);
}
AnvilChunkLoader.spawnEntity(entity, world);
world.playEvent(2004, blockpos, 0);
if (entityliving != null)
{
entityliving.spawnExplosionParticle();
}
flag = true;
}
}
if (flag)
resetTimer(logic);
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
// Direct copy of MobSpawnerBaseLogic.resetTimer()
private void resetTimer(MobSpawnerBaseLogic logic) throws Throwable {
int maxSpawnDelay = (int) MethodHandles.maxSpawnDelay_getter.invokeExact(logic);
int minSpawnDelay = (int) MethodHandles.minSpawnDelay_getter.invokeExact(logic);
List potentialEntitySpawns = (List) MethodHandles.potentialSpawns_getter.invokeExact(logic);
if(maxSpawnDelay <= minSpawnDelay)
MethodHandles.spawnDelay_setter.invokeExact(logic, minSpawnDelay);
else {
int i = maxSpawnDelay - minSpawnDelay;
MethodHandles.spawnDelay_setter.invokeExact(logic, minSpawnDelay + logic.getSpawnerWorld().rand.nextInt(i));
}
if(potentialEntitySpawns != null && potentialEntitySpawns.size() > 0)
logic.setNextSpawnData((WeightedSpawnerEntity)WeightedRandom.getRandomItem(logic.getSpawnerWorld().rand, potentialEntitySpawns));
logic.broadcastEvent(1);
}
@Override
public void writePacketNBT(NBTTagCompound cmp) {
cmp.setInteger(TAG_MANA, mana);
}
@Override
public void readPacketNBT(NBTTagCompound cmp) {
mana = cmp.getInteger(TAG_MANA);
}
@Override
public int getCurrentMana() {
return mana;
}
@Override
public boolean isFull() {
return mana >= 160;
}
@Override
public void recieveMana(int mana) {
this.mana = Math.min(160, this.mana + mana);
}
@Override
public boolean canRecieveManaFromBursts() {
return true;
}
}