diff --git a/src/main/java/WayofTime/bloodmagic/client/render/entity/CorruptedZombieRenderFactory.java b/src/main/java/WayofTime/bloodmagic/client/render/entity/CorruptedZombieRenderFactory.java new file mode 100644 index 00000000..9626ee9a --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/client/render/entity/CorruptedZombieRenderFactory.java @@ -0,0 +1,15 @@ +package WayofTime.bloodmagic.client.render.entity; + +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraftforge.fml.client.registry.IRenderFactory; +import WayofTime.bloodmagic.entity.mob.EntityCorruptedZombie; + +public class CorruptedZombieRenderFactory implements IRenderFactory +{ + @Override + public Render createRenderFor(RenderManager manager) + { + return new RenderCorruptedZombie(manager); + } +} diff --git a/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderCorruptedZombie.java b/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderCorruptedZombie.java new file mode 100644 index 00000000..8c0dfd38 --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderCorruptedZombie.java @@ -0,0 +1,102 @@ +package WayofTime.bloodmagic.client.render.entity; + +import java.util.List; + +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.model.ModelZombie; +import net.minecraft.client.model.ModelZombieVillager; +import net.minecraft.client.renderer.entity.RenderBiped; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; +import net.minecraft.client.renderer.entity.layers.LayerCustomHead; +import net.minecraft.client.renderer.entity.layers.LayerHeldItem; +import net.minecraft.client.renderer.entity.layers.LayerRenderer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import WayofTime.bloodmagic.entity.mob.EntityCorruptedZombie; + +import com.google.common.collect.Lists; + +@SideOnly(Side.CLIENT) +public class RenderCorruptedZombie extends RenderBiped +{ + private static final ResourceLocation ZOMBIE_TEXTURES = new ResourceLocation("bloodmagic", "textures/entities/zombie_raw.png"); + private final ModelBiped defaultModel; + private final ModelZombieVillager zombieVillagerModel; + private final List> defaultLayers; + + public RenderCorruptedZombie(RenderManager renderManagerIn) + { + super(renderManagerIn, new ModelZombie(), 0.5F, 1.0F); + LayerRenderer layerrenderer = (LayerRenderer) this.layerRenderers.get(0); + this.defaultModel = this.modelBipedMain; + this.zombieVillagerModel = new ModelZombieVillager(); + this.addLayer(new LayerHeldItem(this)); + LayerBipedArmor layerbipedarmor = new LayerBipedArmor(this) + { + protected void initArmor() + { + this.modelLeggings = new ModelZombie(0.5F, true); + this.modelArmor = new ModelZombie(1.0F, true); + } + }; + this.addLayer(layerbipedarmor); + this.defaultLayers = Lists.newArrayList(this.layerRenderers); + + if (layerrenderer instanceof LayerCustomHead) + { + this.removeLayer(layerrenderer); + this.addLayer(new LayerCustomHead(this.zombieVillagerModel.bipedHead)); + } + + this.removeLayer(layerbipedarmor); + } + + /** + * Allows the render to do state modifications necessary before the model is + * rendered. + */ + protected void preRenderCallback(EntityCorruptedZombie entitylivingbaseIn, float partialTickTime) + { + super.preRenderCallback(entitylivingbaseIn, partialTickTime); + } + + /** + * Renders the desired {@code T} type Entity. + */ + public void doRender(EntityCorruptedZombie entity, double x, double y, double z, float entityYaw, float partialTicks) + { + this.swapArmor(entity); + super.doRender(entity, x, y, z, entityYaw, partialTicks); + } + + /** + * Returns the location of an entity's texture. Doesn't seem to be called + * unless you call Render.bindEntityTexture. + */ + protected ResourceLocation getEntityTexture(EntityCorruptedZombie entity) + { + + { + return ZOMBIE_TEXTURES; + } + } + + private void swapArmor(EntityCorruptedZombie zombie) + { + + { + this.mainModel = this.defaultModel; + this.layerRenderers = this.defaultLayers; + } + + this.modelBipedMain = (ModelBiped) this.mainModel; + } + + protected void rotateCorpse(EntityCorruptedZombie entityLiving, float p_77043_2_, float p_77043_3_, float partialTicks) + { + + super.rotateCorpse(entityLiving, p_77043_2_, p_77043_3_, partialTicks); + } +} \ No newline at end of file diff --git a/src/main/java/WayofTime/bloodmagic/entity/mob/EntityCorruptedZombie.java b/src/main/java/WayofTime/bloodmagic/entity/mob/EntityCorruptedZombie.java new file mode 100644 index 00000000..cafed0d6 --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/entity/mob/EntityCorruptedZombie.java @@ -0,0 +1,227 @@ +package WayofTime.bloodmagic.entity.mob; + +import lombok.Getter; +import lombok.Setter; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.entity.monster.EntityGhast; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.World; +import WayofTime.bloodmagic.api.Constants; +import WayofTime.bloodmagic.api.soul.EnumDemonWillType; +import WayofTime.bloodmagic.demonAura.WorldDemonWillHandler; +import WayofTime.bloodmagic.entity.ai.EntityAIAttackRangedBow; + +public class EntityCorruptedZombie extends EntityDemonBase +{ + @Getter + @Setter + protected EnumDemonWillType type = EnumDemonWillType.DEFAULT; + + private final EntityAIAttackRangedBow aiArrowAttack = new EntityAIAttackRangedBow(this, 1.0D, 20, 15.0F); + private final EntityAIAttackMelee aiAttackOnCollide = new EntityAIAttackMelee(this, 1.0D, false); + + private final int attackPriority = 3; + + public EntityCorruptedZombie(World worldIn) + { + super(worldIn); + this.setSize(0.6F, 1.95F); +// ((PathNavigateGround) getNavigator()).setCanSwim(false); + + this.setCombatTask(); +// this.targetTasks.addTask(8, new EntityAINearestAttackableTarget(this, EntityMob.class, 10, true, false, new TargetPredicate(this))); + } + + @Override + protected void applyEntityAttributes() + { + super.applyEntityAttributes(); + getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(40.0D); + getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6.0D); + getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.27D); + } + + @Override + public void setCombatTask() + { + if (this.worldObj != null && !this.worldObj.isRemote) + { + this.tasks.removeTask(this.aiAttackOnCollide); + this.tasks.removeTask(this.aiArrowAttack); + ItemStack itemstack = this.getHeldItemMainhand(); + + if (itemstack != null && itemstack.getItem() instanceof ItemBow) + { + int i = 20; + + if (this.worldObj.getDifficulty() != EnumDifficulty.HARD) + { + i = 40; + } + + this.aiArrowAttack.setAttackCooldown(i); + this.tasks.addTask(attackPriority, this.aiArrowAttack); + } else + { + this.tasks.addTask(attackPriority, this.aiAttackOnCollide); + } + } + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount) + { + return this.isEntityInvulnerable(source) ? false : super.attackEntityFrom(source, amount); + } + + /** + * Redone from EntityMob to prevent despawning on peaceful. + */ + @Override + public boolean attackEntityAsMob(Entity attackedEntity) + { + boolean flag = super.attackEntityAsMob(attackedEntity); + + if (flag) + { + //EMPTY + + return true; + } else + { + return false; + } + } + + /** + * @param toHeal + * @return Amount of Will consumed from the Aura to heal + */ + public double absorbWillFromAuraToHeal(double toHeal) + { + if (worldObj.isRemote) + { + return 0; + } + + double healthMissing = this.getMaxHealth() - this.getHealth(); + if (healthMissing <= 0) + { + return 0; + } + + double will = WorldDemonWillHandler.getCurrentWill(worldObj, getPosition(), getType()); + + toHeal = Math.min(healthMissing, Math.min(toHeal, will / getWillToHealth())); + if (toHeal > 0) + { + this.heal((float) toHeal); + return WorldDemonWillHandler.drainWill(worldObj, getPosition(), getType(), toHeal * getWillToHealth(), true); + } + + return 0; + } + + public double getWillToHealth() + { + return 2; + } + + @Override + protected boolean canDespawn() + { + return !this.isTamed() && super.canDespawn(); + } + + public void onUpdate() + { + if (!this.worldObj.isRemote && this.ticksExisted % 20 == 0) + { + absorbWillFromAuraToHeal(2); + } + + super.onUpdate(); + } + + @Override + public void writeEntityToNBT(NBTTagCompound tag) + { + super.writeEntityToNBT(tag); + + tag.setString(Constants.NBT.WILL_TYPE, type.toString()); + } + + @Override + public void readEntityFromNBT(NBTTagCompound tag) + { + super.readEntityFromNBT(tag); + + if (!tag.hasKey(Constants.NBT.WILL_TYPE)) + { + type = EnumDemonWillType.DEFAULT; + } else + { + type = EnumDemonWillType.valueOf(tag.getString(Constants.NBT.WILL_TYPE)); + } + + this.setCombatTask(); + } + + //TODO: Change to fit the given AI + @Override + public boolean shouldAttackEntity(EntityLivingBase attacker, EntityLivingBase owner) + { + if (!(attacker instanceof EntityCreeper) && !(attacker instanceof EntityGhast)) + { + return super.shouldAttackEntity(attacker, owner); + } else + { + return false; + } + } + + @Override + protected SoundEvent getAmbientSound() + { + return SoundEvents.ENTITY_COW_AMBIENT; + } + + @Override + protected SoundEvent getHurtSound() + { + return SoundEvents.ENTITY_COW_HURT; + } + + @Override + protected SoundEvent getDeathSound() + { + return SoundEvents.ENTITY_COW_DEATH; + } + + @Override + protected void playStepSound(BlockPos pos, Block block) + { + this.playSound(SoundEvents.ENTITY_COW_STEP, 0.15F, 1.0F); + } + + /** + * Returns the volume for the sounds this mob makes. + */ + @Override + protected float getSoundVolume() + { + return 0.4F; + } +} \ No newline at end of file diff --git a/src/main/java/WayofTime/bloodmagic/inversion/InversionPillarHandler.java b/src/main/java/WayofTime/bloodmagic/inversion/InversionPillarHandler.java index d9217231..512cb8cb 100644 --- a/src/main/java/WayofTime/bloodmagic/inversion/InversionPillarHandler.java +++ b/src/main/java/WayofTime/bloodmagic/inversion/InversionPillarHandler.java @@ -198,4 +198,52 @@ public class InversionPillarHandler return new ArrayList(); } + + public static List getAllConnectedPillars(World world, EnumDemonWillType type, BlockPos pos) + { + List checkedPosList = new ArrayList(); + List uncheckedPosList = new ArrayList(); //Positions where we did not check their connections. + + uncheckedPosList.add(pos); + + int dim = world.provider.getDimension(); + if (nearPillarMap.containsKey(dim)) + { + Map>> willMap = nearPillarMap.get(dim); + if (willMap.containsKey(type)) + { + Map> posMap = willMap.get(type); + // This is where the magic happens. + + while (!uncheckedPosList.isEmpty()) + { + //Positions that are new this iteration and need to be dumped into uncheckedPosList next iteration. + List newPosList = new ArrayList(); + + Iterator itr = uncheckedPosList.iterator(); + while (itr.hasNext()) + { + BlockPos checkPos = itr.next(); + List posList = posMap.get(checkPos); + if (posList != null) + { + for (BlockPos testPos : posList) + { + //Check if the position has already been checked, is scheduled to be checked, or is already found it needs to be checked. + if (!checkedPosList.contains(testPos) && !uncheckedPosList.contains(testPos) && !newPosList.contains(testPos)) + { + newPosList.add(testPos); + } + } + } + } + + checkedPosList.addAll(uncheckedPosList); + uncheckedPosList = newPosList; + } + } + } + + return checkedPosList; + } } diff --git a/src/main/java/WayofTime/bloodmagic/item/sigil/ItemSigilDivination.java b/src/main/java/WayofTime/bloodmagic/item/sigil/ItemSigilDivination.java index 8dbe5b5f..c45d9882 100644 --- a/src/main/java/WayofTime/bloodmagic/item/sigil/ItemSigilDivination.java +++ b/src/main/java/WayofTime/bloodmagic/item/sigil/ItemSigilDivination.java @@ -12,13 +12,12 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; import WayofTime.bloodmagic.api.altar.IBloodAltar; import WayofTime.bloodmagic.api.iface.IAltarReader; import WayofTime.bloodmagic.api.util.helper.NetworkHelper; import WayofTime.bloodmagic.api.util.helper.PlayerHelper; -import WayofTime.bloodmagic.structures.DungeonTester; import WayofTime.bloodmagic.tile.TileIncenseAltar; +import WayofTime.bloodmagic.tile.TileInversionPillar; import WayofTime.bloodmagic.util.ChatUtil; import WayofTime.bloodmagic.util.helper.NumeralHelper; @@ -38,6 +37,13 @@ public class ItemSigilDivination extends ItemSigilBase implements IAltarReader //// BuildTestStructure s = new BuildTestStructure(); //// s.placeStructureAtPosition(new Random(), Rotation.CLOCKWISE_180, (WorldServer) world, player.getPosition(), 0); // DungeonTester.testDungeonElementWithOutput((WorldServer) world, player.getPosition()); +// } + +// if (!world.isRemote) +// { +// EntityCorruptedZombie fred = new EntityCorruptedZombie(world); +// fred.setPosition(player.posX, player.posY, player.posZ); +// world.spawnEntityInWorld(fred); // } if (!world.isRemote) @@ -74,7 +80,13 @@ public class ItemSigilDivination extends ItemSigilBase implements IAltarReader altar.recheckConstruction(); double tranquility = altar.tranquility; ChatUtil.sendNoSpam(player, new TextComponentTranslation(tooltipBase + "currentTranquility", (int) ((100D * (int) (100 * tranquility)) / 100d)), new TextComponentTranslation(tooltipBase + "currentBonus", (int) (100 * altar.incenseAddition))); + } else if (tile != null && tile instanceof TileInversionPillar) + { + TileInversionPillar pillar = (TileInversionPillar) tile; + double inversion = pillar.getCurrentInversion(); + ChatUtil.sendNoSpam(player, new TextComponentTranslation(tooltipBase + "currentInversion", ((int) (10 * inversion)) / 10d)); } else + { int currentEssence = NetworkHelper.getSoulNetwork(getOwnerUUID(stack)).getCurrentEssence(); ChatUtil.sendNoSpam(player, new TextComponentTranslation(tooltipBase + "currentEssence", currentEssence)); diff --git a/src/main/java/WayofTime/bloodmagic/proxy/ClientProxy.java b/src/main/java/WayofTime/bloodmagic/proxy/ClientProxy.java index ecb19f46..1a8f50d8 100644 --- a/src/main/java/WayofTime/bloodmagic/proxy/ClientProxy.java +++ b/src/main/java/WayofTime/bloodmagic/proxy/ClientProxy.java @@ -35,11 +35,13 @@ import WayofTime.bloodmagic.client.render.RenderDemonCrucible; import WayofTime.bloodmagic.client.render.RenderItemRoutingNode; import WayofTime.bloodmagic.client.render.block.RenderMimic; import WayofTime.bloodmagic.client.render.entity.BloodLightRenderFactory; +import WayofTime.bloodmagic.client.render.entity.CorruptedZombieRenderFactory; import WayofTime.bloodmagic.client.render.entity.MeteorRenderFactory; import WayofTime.bloodmagic.client.render.entity.MimicRenderFactory; import WayofTime.bloodmagic.client.render.entity.SentientArrowRenderFactory; import WayofTime.bloodmagic.client.render.entity.SentientSpecterRenderFactory; import WayofTime.bloodmagic.client.render.entity.SoulSnareRenderFactory; +import WayofTime.bloodmagic.entity.mob.EntityCorruptedZombie; import WayofTime.bloodmagic.entity.mob.EntityMimic; import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.projectile.EntityBloodLight; @@ -104,6 +106,7 @@ public class ClientProxy extends CommonProxy RenderingRegistry.registerEntityRenderingHandler(EntityMeteor.class, new MeteorRenderFactory()); RenderingRegistry.registerEntityRenderingHandler(EntitySentientSpecter.class, new SentientSpecterRenderFactory()); RenderingRegistry.registerEntityRenderingHandler(EntityMimic.class, new MimicRenderFactory()); + RenderingRegistry.registerEntityRenderingHandler(EntityCorruptedZombie.class, new CorruptedZombieRenderFactory()); ShaderHelper.init(); } diff --git a/src/main/java/WayofTime/bloodmagic/registry/ModEntities.java b/src/main/java/WayofTime/bloodmagic/registry/ModEntities.java index e9336e05..e20eb6e1 100644 --- a/src/main/java/WayofTime/bloodmagic/registry/ModEntities.java +++ b/src/main/java/WayofTime/bloodmagic/registry/ModEntities.java @@ -2,6 +2,7 @@ package WayofTime.bloodmagic.registry; import net.minecraftforge.fml.common.registry.EntityRegistry; import WayofTime.bloodmagic.BloodMagic; +import WayofTime.bloodmagic.entity.mob.EntityCorruptedZombie; import WayofTime.bloodmagic.entity.mob.EntityMimic; import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.projectile.EntityBloodLight; @@ -21,5 +22,6 @@ public class ModEntities EntityRegistry.registerModEntity(EntityMeteor.class, "Meteor", id++, BloodMagic.instance, 64, 1, true); EntityRegistry.registerModEntity(EntitySentientSpecter.class, "SentientSpecter", id++, BloodMagic.instance, 64, 1, true); EntityRegistry.registerModEntity(EntityMimic.class, "Mimic", id++, BloodMagic.instance, 64, 1, true); + EntityRegistry.registerModEntity(EntityCorruptedZombie.class, "CorruptedZombie", id++, BloodMagic.instance, 64, 1, true); } } diff --git a/src/main/java/WayofTime/bloodmagic/tile/TileInversionPillar.java b/src/main/java/WayofTime/bloodmagic/tile/TileInversionPillar.java index 5d128c79..b1c32306 100644 --- a/src/main/java/WayofTime/bloodmagic/tile/TileInversionPillar.java +++ b/src/main/java/WayofTime/bloodmagic/tile/TileInversionPillar.java @@ -1,5 +1,6 @@ package WayofTime.bloodmagic.tile; +import java.util.Collections; import java.util.List; import lombok.Getter; @@ -8,7 +9,10 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import WayofTime.bloodmagic.api.Constants; import WayofTime.bloodmagic.api.soul.EnumDemonWillType; import WayofTime.bloodmagic.demonAura.WorldDemonWillHandler; @@ -25,10 +29,15 @@ public class TileInversionPillar extends TileTicking public static double inversionToIncreaseRadius = 100; public static double inversionToAddPillar = 200; public static double operationThreshold = 20; + public static double inversionToSpreadWill = 200; + public static double willPushRate = 3; + public static double inversionCostPerWillSpread = 4; + public static double minimumWillForChunkWhenSpreading = 100; public EnumDemonWillType type; public double currentInversion = 0; public int consecutiveFailedChecks = 0; //If you fail enough checks, increase the radius. + public int consecutiveFailedAirChecks = 0; public int currentInfectionRadius = 1; public int counter = 0; @@ -76,9 +85,19 @@ public class TileInversionPillar extends TileTicking if (pollute == 1) { consecutiveFailedChecks++; + } else if (pollute == 3) + { + consecutiveFailedAirChecks++; } else if (pollute == 0) { + //We successfully found a block to replace! consecutiveFailedChecks = 0; + consecutiveFailedAirChecks = 0; + } + + if (currentInversion >= inversionToSpreadWill) + { + spreadWillToSurroundingChunks(); } if (consecutiveFailedChecks > 5 * currentInfectionRadius && currentInversion >= inversionToIncreaseRadius) @@ -91,7 +110,97 @@ public class TileInversionPillar extends TileTicking if (currentInfectionRadius >= 10 && currentInversion >= inversionToAddPillar) { - //TODO: Spawn pillar + //TODO: Improve algorithm + List allConnectedPos = InversionPillarHandler.getAllConnectedPillars(worldObj, type, pos); + BlockPos candidatePos = findCandidatePositionForPillar(worldObj, type, pos, allConnectedPos, 5, 10); + if (!candidatePos.equals(BlockPos.ORIGIN)) + { + currentInversion -= inversionToAddPillar; + IBlockState pillarState = ModBlocks.INVERSION_PILLAR.getStateFromMeta(type.ordinal()); + IBlockState bottomState = ModBlocks.INVERSION_PILLAR_END.getStateFromMeta(type.ordinal() * 2); + IBlockState topState = ModBlocks.INVERSION_PILLAR_END.getStateFromMeta(type.ordinal() * 2 + 1); + worldObj.setBlockState(candidatePos, pillarState); + worldObj.setBlockState(candidatePos.down(), bottomState); + worldObj.setBlockState(candidatePos.up(), topState); + } + } + } + } + + public static BlockPos findCandidatePositionForPillar(World world, EnumDemonWillType type, BlockPos pos, List posList, double tooCloseDistance, double wantedAverageDistance) + { + int maxIterations = 100; + int heightCheckRange = 3; + + for (int i = 0; i < maxIterations; i++) + { + Collections.shuffle(posList); + BlockPos pillarPos = posList.get(0); + + Vec3d vec = new Vec3d(world.rand.nextDouble() * 2 - 1, world.rand.nextDouble() * 2 - 1, world.rand.nextDouble() * 2 - 1).normalize().scale(wantedAverageDistance); + + BlockPos centralPos = pillarPos.add(vec.xCoord, vec.yCoord, vec.zCoord); + BlockPos testPos = null; + candidateTest: for (int h = 0; h <= heightCheckRange; h++) + { + for (int sig = -1; sig <= 1; sig += (h > 0 ? 2 : 3)) + { + BlockPos candidatePos = centralPos.add(0, sig * h, 0); + IBlockState candidateState = world.getBlockState(candidatePos); + if (world.isAirBlock(candidatePos) && world.isAirBlock(candidatePos.up()) && world.isAirBlock(candidatePos.down()) && !world.isAirBlock(candidatePos.down(2))) + { + testPos = candidatePos; + break candidateTest; + } + } + } + + if (testPos != null) + { + boolean isValid = true; + for (BlockPos pillarTestPos : posList) + { + if (pillarTestPos.distanceSq(testPos) <= tooCloseDistance * tooCloseDistance) + { + isValid = false; + break; + } + } + + if (isValid) + { + return testPos; + } + } + } + + return BlockPos.ORIGIN; + } + + public void spreadWillToSurroundingChunks() + { + double currentAmount = WorldDemonWillHandler.getCurrentWill(worldObj, pos, type); + if (currentAmount <= minimumWillForChunkWhenSpreading) + { + return; + } + + for (EnumFacing side : EnumFacing.HORIZONTALS) + { + BlockPos offsetPos = pos.offset(side, 16); + double sideAmount = WorldDemonWillHandler.getCurrentWill(worldObj, offsetPos, type); + if (currentAmount > sideAmount) + { + double drainAmount = Math.min((currentAmount - sideAmount) / 2, willPushRate); + if (drainAmount < willPushRate / 2) + { + continue; + } + + double drain = WorldDemonWillHandler.drainWill(worldObj, pos, type, drainAmount, true); + drain = WorldDemonWillHandler.fillWillToMaximum(worldObj, offsetPos, type, drain, maxWillForChunk, true); + + currentInversion -= drain * inversionCostPerWillSpread; } } } @@ -176,14 +285,15 @@ public class TileInversionPillar extends TileTicking * @param currentWillInChunk * @return 0 if the block is successfully placed, 1 if the block is not * placed due to the selected place being invalid, 2 if the block is - * not placed due to there not being enough Will or Inversion + * not placed due to there not being enough Will or Inversion, 3 if + * the block is not placed due to the selected block being air. */ public int polluteNearbyBlocks(double currentWillInChunk) { // System.out.println("Hai! :D Current Inversion: " + currentInversion + ", Current Will: " + currentWillInChunk); if (currentWillInChunk < operationThreshold || currentInversion < inversionPerOperation) { - return 2; + return 2; //Not enough Will or Inversion available } double xOff = worldObj.rand.nextGaussian() * currentInfectionRadius; @@ -202,7 +312,7 @@ public class TileInversionPillar extends TileTicking BlockPos offsetPos = pos.add(xOff + 0.5, yOff + 0.5, zOff + 0.5); if (offsetPos.equals(pos)) { - return 1; + return 1; //Invalid block (itself!) } IBlockState state = worldObj.getBlockState(offsetPos); @@ -218,13 +328,13 @@ public class TileInversionPillar extends TileTicking WorldDemonWillHandler.drainWill(worldObj, pos, type, willPerOperation, true); currentInversion -= inversionPerOperation; - return 0; + return 0; //Successfully placed } } - return 1; + return 1; //Invalid block } - return 1; + return 3; //The block was air } } diff --git a/src/main/resources/assets/bloodmagic/lang/en_US.lang b/src/main/resources/assets/bloodmagic/lang/en_US.lang index b1f568f4..0ef4763e 100644 --- a/src/main/resources/assets/bloodmagic/lang/en_US.lang +++ b/src/main/resources/assets/bloodmagic/lang/en_US.lang @@ -383,6 +383,7 @@ tooltip.BloodMagic.sigil.divination.currentAltarTier=Current Tier: %d tooltip.BloodMagic.sigil.divination.currentEssence=Current Essence: %d LP tooltip.BloodMagic.sigil.divination.currentAltarCapacity=Current Capacity: %d LP tooltip.BloodMagic.sigil.divination.currentTranquility=Current Tranquility: %d +tooltip.BloodMagic.sigil.divination.currentInversion=Current Inversion: %d tooltip.BloodMagic.sigil.divination.currentBonus=Current Bonus: +%d%% tooltip.BloodMagic.sigil.water.desc=&oInfinite water, anyone? tooltip.BloodMagic.sigil.lava.desc=&oHOT! DO NOT EAT diff --git a/src/main/resources/assets/bloodmagic/textures/entities/zombie_raw.png b/src/main/resources/assets/bloodmagic/textures/entities/zombie_raw.png new file mode 100644 index 00000000..4e9c7723 Binary files /dev/null and b/src/main/resources/assets/bloodmagic/textures/entities/zombie_raw.png differ