package crazypants.enderio.machine.spawner; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EnumCreatureType; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import crazypants.enderio.EnderIO; import crazypants.enderio.ModObject; import crazypants.enderio.config.Config; import crazypants.enderio.machine.AbstractPoweredTaskEntity; import crazypants.enderio.machine.IMachineRecipe; import crazypants.enderio.machine.IPoweredTask; import crazypants.enderio.machine.PoweredTask; import crazypants.enderio.machine.SlotDefinition; import crazypants.enderio.power.BasicCapacitor; import crazypants.enderio.power.Capacitors; import crazypants.enderio.power.ICapacitor; public class TilePoweredSpawner extends AbstractPoweredTaskEntity { public static final int MIN_SPAWN_DELAY_BASE = Config.poweredSpawnerMinDelayTicks; public static final int MAX_SPAWN_DELAY_BASE = Config.poweredSpawnerMaxDelayTicks; public static final int POWER_PER_TICK_ONE = Config.poweredSpawnerLevelOnePowerPerTickRF; private static final BasicCapacitor CAP_ONE = new BasicCapacitor((int) (POWER_PER_TICK_ONE * 1.25), Capacitors.BASIC_CAPACITOR.capacitor.getMaxEnergyStored()); public static final int POWER_PER_TICK_TWO = Config.poweredSpawnerLevelTwoPowerPerTickRF; private static final BasicCapacitor CAP_TWO = new BasicCapacitor((int) (POWER_PER_TICK_TWO * 1.25), Capacitors.ACTIVATED_CAPACITOR.capacitor.getMaxEnergyStored()); public static final int POWER_PER_TICK_THREE = Config.poweredSpawnerLevelThreePowerPerTickRF; private static final BasicCapacitor CAP_THREE = new BasicCapacitor((int) (POWER_PER_TICK_THREE * 1.25), Capacitors.ENDER_CAPACITOR.capacitor.getMaxEnergyStored()); public static final int MIN_PLAYER_DISTANCE = Config.poweredSpawnerMaxPlayerDistance; public static final boolean USE_VANILLA_SPAWN_CHECKS = Config.poweredSpawnerUseVanillaSpawChecks; private static final String NULL_ENTITY_NAME = "None"; private String entityTypeName; private boolean isSpawnMode = true; private int powerUsePerTick; private int remainingSpawnTries; public TilePoweredSpawner() { super(new SlotDefinition(1, 1, 1)); entityTypeName = NULL_ENTITY_NAME; } public boolean isSpawnMode() { return isSpawnMode; } public void setSpawnMode(boolean isSpawnMode) { if(isSpawnMode != this.isSpawnMode) { currentTask = null; } this.isSpawnMode = isSpawnMode; } @Override protected void taskComplete() { super.taskComplete(); if(isSpawnMode) { remainingSpawnTries = Config.poweredSpawnerSpawnCount + Config.poweredSpawnerMaxSpawnTries; for (int i = 0; i < Config.poweredSpawnerSpawnCount && remainingSpawnTries > 0; ++i) { if(!trySpawnEntity()) { break; } } } else { if(getStackInSlot(0) == null || getStackInSlot(1) != null || !hasEntityName()) { return; } ItemStack res = EnderIO.itemSoulVessel.createVesselWithEntityStub(getEntityName()); decrStackSize(0, 1); setInventorySlotContents(1, res); } } @Override public void onCapacitorTypeChange() { ICapacitor refCap; int basePowerUse; switch (getCapacitorType()) { default: case BASIC_CAPACITOR: refCap = CAP_ONE; basePowerUse = POWER_PER_TICK_ONE; break; case ACTIVATED_CAPACITOR: refCap = CAP_TWO; basePowerUse = POWER_PER_TICK_TWO; break; case ENDER_CAPACITOR: refCap = CAP_THREE; basePowerUse = POWER_PER_TICK_THREE; break; } double multiplier = PoweredSpawnerConfig.getInstance().getCostMultiplierFor(getEntityName()); setCapacitor(new BasicCapacitor((int) (refCap.getMaxEnergyExtracted() * multiplier), refCap.getMaxEnergyStored())); powerUsePerTick = (int) Math.ceil(basePowerUse * multiplier); forceClientUpdate = true; } @Override public String getMachineName() { return ModObject.blockPoweredSpawner.unlocalisedName; } @Override protected boolean isMachineItemValidForSlot(int i, ItemStack itemstack) { if(itemstack == null || isSpawnMode) { return false; } if(slotDefinition.isInputSlot(i)) { return itemstack.getItem() == EnderIO.itemSoulVessel && !EnderIO.itemSoulVessel.containsSoul(itemstack); } return false; } @Override protected IMachineRecipe canStartNextTask(float chance) { if(!hasEntityName()) { return null; } if(isSpawnMode) { if(MIN_PLAYER_DISTANCE > 0) { if(worldObj.getClosestPlayer(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, MIN_PLAYER_DISTANCE) == null) { return null; } } } else { if(getStackInSlot(0) == null || getStackInSlot(1) != null) { return null; } } return new DummyRecipe(); } @Override protected boolean startNextTask(IMachineRecipe nextRecipe, float chance) { return super.startNextTask(nextRecipe, chance); } @Override public int getPowerUsePerTick() { return powerUsePerTick; } @Override protected boolean hasInputStacks() { return true; } @Override protected boolean canInsertResult(float chance, IMachineRecipe nextRecipe) { return true; } @Override public void readCommon(NBTTagCompound nbtRoot) { //Must read the mob type first so we know the multiplier to be used when calculating input/output power String mobType = BlockPoweredSpawner.readMobTypeFromNBT(nbtRoot); if(mobType == null) { mobType = NULL_ENTITY_NAME; } entityTypeName = mobType; if(!nbtRoot.hasKey("isSpawnMode")) { isSpawnMode = true; } else { isSpawnMode = nbtRoot.getBoolean("isSpawnMode"); } super.readCommon(nbtRoot); } @Override public void writeCommon(NBTTagCompound nbtRoot) { if(hasEntityName()) { BlockPoweredSpawner.writeMobTypeToNBT(nbtRoot, getEntityName()); } else { BlockPoweredSpawner.writeMobTypeToNBT(nbtRoot, null); } nbtRoot.setBoolean("isSpawnMode", isSpawnMode); super.writeCommon(nbtRoot); } @Override protected void updateEntityClient() { if(isActive()) { double x = xCoord + worldObj.rand.nextFloat(); double y = yCoord + worldObj.rand.nextFloat(); double z = zCoord + worldObj.rand.nextFloat(); worldObj.spawnParticle("smoke", x, y, z, 0.0D, 0.0D, 0.0D); worldObj.spawnParticle("flame", x, y, z, 0.0D, 0.0D, 0.0D); } super.updateEntityClient(); } @Override protected IPoweredTask createTask(IMachineRecipe nextRecipe, float chance) { PoweredTask res = new PoweredTask(nextRecipe, chance, getRecipeInputs()); int ticksDelay; if(isSpawnMode) { ticksDelay = TilePoweredSpawner.MIN_SPAWN_DELAY_BASE + (int) Math.round((TilePoweredSpawner.MAX_SPAWN_DELAY_BASE - TilePoweredSpawner.MIN_SPAWN_DELAY_BASE) * Math.random()); } else { ticksDelay = TilePoweredSpawner.MAX_SPAWN_DELAY_BASE - ((TilePoweredSpawner.MAX_SPAWN_DELAY_BASE - TilePoweredSpawner.MIN_SPAWN_DELAY_BASE) / 2); } if(getCapacitorType().ordinal() == 1) { ticksDelay /= 2; } else if(getCapacitorType().ordinal() == 2) { ticksDelay /= 4; } int powerPerTick = getPowerUsePerTick(); res.setRequiredEnergy(powerPerTick * ticksDelay); return res; } protected boolean canSpawnEntity(EntityLiving entityliving) { boolean spaceClear = worldObj.checkNoEntityCollision(entityliving.boundingBox) && worldObj.getCollidingBoundingBoxes(entityliving, entityliving.boundingBox).isEmpty() && (!worldObj.isAnyLiquid(entityliving.boundingBox) || entityliving.isCreatureType(EnumCreatureType.waterCreature, false)); if(spaceClear && USE_VANILLA_SPAWN_CHECKS) { //Full checks for lighting, dimension etc spaceClear = entityliving.getCanSpawnHere(); } return spaceClear; } Entity createEntity(boolean forceAlive) { Entity ent = EntityList.createEntityByName(getEntityName(), worldObj); if(forceAlive && MIN_PLAYER_DISTANCE <= 0 && Config.poweredSpawnerDespawnTimeSeconds > 0 && ent instanceof EntityLiving) { ent.getEntityData().setLong(BlockPoweredSpawner.KEY_SPAWNED_BY_POWERED_SPAWNER, worldObj.getTotalWorldTime()); ((EntityLiving) ent).func_110163_bv(); } return ent; } protected boolean trySpawnEntity() { Entity entity = createEntity(true); if(!(entity instanceof EntityLiving)) { return false; } EntityLiving entityliving = (EntityLiving) entity; int spawnRange = Config.poweredSpawnerSpawnRange; if(Config.poweredSpawnerMaxNearbyEntities > 0) { int nearbyEntities = worldObj.getEntitiesWithinAABB( entity.getClass(), AxisAlignedBB.getBoundingBox( xCoord - spawnRange*2, yCoord - 4, zCoord - spawnRange*2, xCoord + spawnRange*2, yCoord + 4, zCoord + spawnRange*2)).size(); if(nearbyEntities >= Config.poweredSpawnerMaxNearbyEntities) { return false; } } while(remainingSpawnTries-- > 0) { double x = xCoord + (worldObj.rand.nextDouble() - worldObj.rand.nextDouble()) * spawnRange; double y = yCoord + worldObj.rand.nextInt(3) - 1; double z = zCoord + (worldObj.rand.nextDouble() - worldObj.rand.nextDouble()) * spawnRange; entity.setLocationAndAngles(x, y, z, worldObj.rand.nextFloat() * 360.0F, 0.0F); if(canSpawnEntity(entityliving)) { entityliving.onSpawnWithEgg(null); worldObj.spawnEntityInWorld(entityliving); worldObj.playAuxSFX(2004, xCoord, yCoord, zCoord, 0); entityliving.spawnExplosionParticle(); return true; } } return false; } public String getEntityName() { return entityTypeName; } public boolean hasEntityName() { return !NULL_ENTITY_NAME.equals(entityTypeName); } }