From e9549fd9db0f7be01444ece5f189f261b32ecd0b Mon Sep 17 00:00:00 2001 From: WayofTime Date: Tue, 13 Sep 2016 17:20:35 -0400 Subject: [PATCH] Did a lot of work on the behaviour of the Inversion Pillar. Also added a Corrupted Zombie for later testing. --- .../entity/CorruptedZombieRenderFactory.java | 15 ++ .../render/entity/RenderCorruptedZombie.java | 102 ++++++++ .../entity/mob/EntityCorruptedZombie.java | 227 ++++++++++++++++++ .../inversion/InversionPillarHandler.java | 48 ++++ .../item/sigil/ItemSigilDivination.java | 16 +- .../bloodmagic/proxy/ClientProxy.java | 3 + .../bloodmagic/registry/ModEntities.java | 2 + .../bloodmagic/tile/TileInversionPillar.java | 124 +++++++++- .../assets/bloodmagic/lang/en_US.lang | 1 + .../textures/entities/zombie_raw.png | Bin 0 -> 7587 bytes 10 files changed, 529 insertions(+), 9 deletions(-) create mode 100644 src/main/java/WayofTime/bloodmagic/client/render/entity/CorruptedZombieRenderFactory.java create mode 100644 src/main/java/WayofTime/bloodmagic/client/render/entity/RenderCorruptedZombie.java create mode 100644 src/main/java/WayofTime/bloodmagic/entity/mob/EntityCorruptedZombie.java create mode 100644 src/main/resources/assets/bloodmagic/textures/entities/zombie_raw.png 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 0000000000000000000000000000000000000000..4e9c7723ef14c758c3399d74860ce05541637c01 GIT binary patch literal 7587 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 Bq@e%+ literal 0 HcmV?d00001