package WayofTime.bloodmagic.ritual; import java.util.ArrayList; import java.util.List; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import WayofTime.bloodmagic.ConfigHandler; import WayofTime.bloodmagic.api.Constants; import WayofTime.bloodmagic.api.ritual.AreaDescriptor; import WayofTime.bloodmagic.api.ritual.EnumRuneType; import WayofTime.bloodmagic.api.ritual.IMasterRitualStone; import WayofTime.bloodmagic.api.ritual.Ritual; import WayofTime.bloodmagic.api.ritual.RitualComponent; import WayofTime.bloodmagic.api.saving.SoulNetwork; import WayofTime.bloodmagic.api.util.helper.NetworkHelper; import WayofTime.bloodmagic.tile.TileDemonCrystal; public class RitualForsakenSoul extends Ritual { public static final String CRYSTAL_RANGE = "crystal"; public static final String DAMAGE_RANGE = "damage"; public static final int MAX_UNIQUENESS = 10; public static final int HEALTH_THRESHOLD = 20; public double willBuffer = 0; public double crystalBuffer = 0; public List keyList = new ArrayList(); public RitualForsakenSoul() { super("ritualForsakenSoul", 0, 40000, "ritual." + Constants.Mod.MODID + ".forsakenSoulRitual"); addBlockRange(CRYSTAL_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-3, 2, -3), 7, 5, 7)); addBlockRange(DAMAGE_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-10, -10, -10), 21)); setMaximumVolumeAndDistanceOfRange(CRYSTAL_RANGE, 250, 5, 7); setMaximumVolumeAndDistanceOfRange(DAMAGE_RANGE, 0, 10, 10); } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); willBuffer = tag.getDouble("willBuffer"); crystalBuffer = tag.getDouble("crystalBuffer"); keyList.clear(); for (int i = 0; i < MAX_UNIQUENESS; i++) { String key = "uniq" + i; if (tag.hasKey(key)) { keyList.add(tag.getInteger(key)); } } } @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); tag.setDouble("willBuffer", willBuffer); tag.setDouble("crystalBuffer", crystalBuffer); for (int i = 0; i < Math.min(MAX_UNIQUENESS, keyList.size()); i++) { String key = "uniq" + i; tag.setInteger(key, keyList.get(i)); } } @Override public void performRitual(IMasterRitualStone masterRitualStone) { World world = masterRitualStone.getWorldObj(); SoulNetwork network = NetworkHelper.getSoulNetwork(masterRitualStone.getOwner()); int currentEssence = network.getCurrentEssence(); BlockPos pos = masterRitualStone.getBlockPos(); if (currentEssence < getRefreshCost()) { network.causeNausea(); return; } int maxEffects = 100; int totalEffects = 0; List crystalList = new ArrayList(); AreaDescriptor crystalRange = getBlockRange(CRYSTAL_RANGE); crystalRange.resetIterator(); while (crystalRange.hasNext()) { BlockPos nextPos = crystalRange.next().add(pos); TileEntity tile = world.getTileEntity(nextPos); if (tile instanceof TileDemonCrystal) { crystalList.add((TileDemonCrystal) tile); } } AreaDescriptor damageRange = getBlockRange(DAMAGE_RANGE); AxisAlignedBB range = damageRange.getAABB(pos); List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, range); for (EntityLivingBase entity : entities) { if (!ConfigHandler.wellOfSufferingBlacklist.contains(entity.getClass().getSimpleName())) { if (entity.isEntityAlive() && !(entity instanceof EntityPlayer)) { if (entity.attackEntityFrom(DamageSource.OUT_OF_WORLD, 1)) { if (!entity.isEntityAlive()) { int uniqueness = calculateUniqueness(entity); double modifier = 1; if (entity instanceof EntityAnimal && !entity.isCollided) { modifier = 4; } willBuffer += modifier * getWillForUniqueness(uniqueness) / HEALTH_THRESHOLD * entity.getMaxHealth(); crystalBuffer += modifier * entity.getMaxHealth() / HEALTH_THRESHOLD; totalEffects++; if (totalEffects >= maxEffects) { break; } } } } } } if (crystalList.size() > 0 && crystalBuffer > 0) { double growth = Math.min(crystalBuffer, 1); double willSyphonAmount = growth * willBuffer / crystalBuffer; TileDemonCrystal chosenCrystal = crystalList.get(world.rand.nextInt(crystalList.size())); double percentageGrowth = chosenCrystal.growCrystalWithWillAmount(growth * willBuffer / crystalBuffer, growth); if (percentageGrowth > 0) { crystalBuffer -= percentageGrowth; willBuffer -= percentageGrowth * willSyphonAmount; } } network.syphon(getRefreshCost() * totalEffects); } /** * * @param mob * @return The amount of uniqueness to the last 10 mobs killed */ public int calculateUniqueness(EntityLivingBase mob) { int key = mob.getClass().hashCode(); keyList.add(key); if (keyList.size() > MAX_UNIQUENESS) { keyList.remove(0); } List uniquenessList = new ArrayList(); for (int value : keyList) { if (!uniquenessList.contains(value)) { uniquenessList.add(value); } } return Math.min(uniquenessList.size(), MAX_UNIQUENESS); } public double getWillForUniqueness(int uniqueness) { return Math.max(50 - 15 * Math.sqrt(uniqueness), 0); } @Override public int getRefreshTime() { return 25; } @Override public int getRefreshCost() { return 2; } @Override public ArrayList getComponents() { ArrayList components = new ArrayList(); this.addCornerRunes(components, 1, 0, EnumRuneType.AIR); this.addParallelRunes(components, 1, -1, EnumRuneType.DUSK); this.addParallelRunes(components, 1, 1, EnumRuneType.FIRE); this.addParallelRunes(components, 2, 1, EnumRuneType.FIRE); this.addParallelRunes(components, 3, 1, EnumRuneType.FIRE); this.addOffsetRunes(components, 3, 1, 1, EnumRuneType.FIRE); this.addCornerRunes(components, 3, 1, EnumRuneType.EARTH); this.addCornerRunes(components, 3, 0, EnumRuneType.EARTH); this.addOffsetRunes(components, 3, 2, 0, EnumRuneType.EARTH); return components; } @Override public Ritual getNewCopy() { return new RitualForsakenSoul(); } }