package dev.tilera.auracore.aura; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityWitch; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.ChatComponentText; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import dev.tilera.auracore.AuraCore; import dev.tilera.auracore.api.Aspects; import dev.tilera.auracore.api.AuraNode; import dev.tilera.auracore.api.EnumNodeType; import dev.tilera.auracore.helper.Utils; import dev.tilera.auracore.network.AuraDeletePacket; import dev.tilera.auracore.network.AuraPacket; import dev.tilera.auracore.network.AuraTransferFXPacket; import dev.tilera.auracore.network.NodeZapPacket; import thaumcraft.api.aspects.Aspect; import thaumcraft.api.aspects.AspectList; import thaumcraft.common.entities.monster.EntityBrainyZombie; import thaumcraft.common.entities.monster.EntityFireBat; import thaumcraft.common.entities.monster.EntityGiantBrainyZombie; import thaumcraft.common.entities.monster.EntityWisp; import thaumcraft.common.lib.world.biomes.BiomeHandler; public class AuraManager { public static ConcurrentHashMap auraNodes = new ConcurrentHashMap<>(); public static ConcurrentHashMap> auraUpdateList = new ConcurrentHashMap<>(); public static volatile ConcurrentHashMap> nodeNeighbours = new ConcurrentHashMap<>(); public static volatile ConcurrentHashMap, List> nodeChunks = new ConcurrentHashMap<>(); public static volatile ConcurrentHashMap markedForTransmission = new ConcurrentHashMap<>(); public static volatile ArrayList> fluxEventList = new ArrayList<>(); public static LinkedBlockingQueue> auraCalcQueue = new LinkedBlockingQueue<>(); public static LinkedBlockingQueue auraDeleteQueue = new LinkedBlockingQueue<>(); public static LinkedBlockingQueue auraUpdateQueue = new LinkedBlockingQueue<>(); public static Object saveLock = new Object(); public static NodeIdStorage nodeIdStore = null; public static void invalidate() { auraNodes.clear();; auraUpdateList.clear(); nodeNeighbours.clear();; nodeChunks.clear(); markedForTransmission.clear();; fluxEventList.clear(); auraCalcQueue.clear(); auraDeleteQueue.clear(); auraUpdateQueue.clear(); } public static int registerAuraNode(World world, short lvl, EnumNodeType type, int dim, int x, int y, int z) { return registerAuraNode(world, lvl, type, dim, x, y, z, false); } public static int registerAuraNode(World world, short lvl, EnumNodeType type, int dim, int x, int y, int z, boolean virtual) { if (nodeIdStore == null) { nodeIdStore = new NodeIdStorage(world.getSaveHandler()); } int key = nodeIdStore.getUniqueDataId("tcnode"); AuraNode node = new AuraNode(key, lvl, type, dim, x, y, z); if (virtual) { node.isVirtual = true; } auraNodes.put(node.key, node); LinkedList temp = (LinkedList)auraUpdateList.get(dim); if (temp == null) { temp = new LinkedList(); auraUpdateList.put(dim, temp); } temp.add(node.key); return key; } public static List getNodeNeighbours(int nkey) { ArrayList neighbours = new ArrayList<>(); if (nodeNeighbours.get(nkey) != null) { neighbours.addAll(nodeNeighbours.get(nkey)); } return neighbours; } public static List getNodeNeighboursNeighbours(int nkey) { List neighbours = AuraManager.getNodeNeighbours(nkey); if (neighbours != null && neighbours.size() > 0) { ArrayList neighboursNeighbours = new ArrayList(); neighboursNeighbours.addAll(neighbours); for (Integer key : neighbours) { try { for (Integer key2 : AuraManager.getNodeNeighbours(key)) { if (neighboursNeighbours.contains(key2)) continue; neighboursNeighbours.add(key2); } } catch (Exception e) { } } return neighboursNeighbours; } return null; } public static synchronized void addToAuraUpdateList(AuraNode node) { LinkedList temp = (LinkedList)auraUpdateList.get(node.dimension); if (temp == null) { temp = new LinkedList(); auraUpdateList.put(node.dimension, temp); } if (!temp.contains(node.key)) { temp.add(node.key); } auraUpdateList.put(node.dimension, temp); } public static void generateNodeNeighbours(AuraNode node) { int dim = node.dimension; synchronized (saveLock) { Integer[] updateList = AuraManager.getUpdateList(dim); ArrayList neighbours = new ArrayList(); for (int a = 0; a < updateList.length && a < updateList.length; ++a) { double zd; double yd; double xd; double distSq; float influence; int nk; AuraNode targetNode; if (updateList[a] == null || updateList[a] == node.key || (targetNode = AuraManager.copyNode(AuraManager.getNode(nk = updateList[a].intValue()))) == null || !((double)((influence = Math.max((float)node.baseLevel / 4.0f, (float)targetNode.baseLevel / 4.0f)) * influence) >= (distSq = (xd = node.xPos - targetNode.xPos) * xd + (yd = node.yPos - targetNode.yPos) * yd + (zd = node.zPos - targetNode.zPos) * zd))) continue; neighbours.add(targetNode.key); } nodeNeighbours.put(node.key, neighbours); int cx = MathHelper.floor_double((double)node.xPos) / 16; int cz = MathHelper.floor_double((double)node.zPos) / 16; if (nodeChunks.get(Arrays.asList(dim, cx, cz)) != null) { ArrayList nds = (ArrayList)nodeChunks.get(Arrays.asList(dim, cx, cz)); if (!nds.contains(node.key) && nds.size() > 0) { nds.add(node.key); nodeChunks.put(Arrays.asList(dim, cx, cz), nds); } } else { ArrayList temp = new ArrayList(); temp.add(node.key); nodeChunks.put(Arrays.asList(dim, cx, cz), temp); } } } public static void updateNodeNeighbours(AuraNode node) { int dim = node.dimension; List updateList = AuraManager.getNodeNeighboursNeighbours(node.key); ArrayList newNeighbours = new ArrayList(); ArrayList deadNodes = new ArrayList(); if (updateList != null && updateList.size() > 0) { for (Integer key : updateList) { List nlist; double zd; double yd; double xd; double distSq; AuraNode targetNode = AuraManager.copyNode(AuraManager.getNode(key)); if (targetNode == null || key == node.key) continue; float influence = Math.max((float)node.baseLevel / 4.0f, (float)targetNode.baseLevel / 4.0f); if ((double)(influence * influence) >= (distSq = (xd = node.xPos - targetNode.xPos) * xd + (yd = node.yPos - targetNode.yPos) * yd + (zd = node.zPos - targetNode.zPos) * zd)) { newNeighbours.add(targetNode.key); nlist = AuraManager.getNodeNeighbours(targetNode.key); if (nlist.contains(node.key)) continue; nlist.add(node.key); nodeNeighbours.put(targetNode.key, nlist); continue; } nlist = AuraManager.getNodeNeighbours(targetNode.key); int index = nlist.indexOf(node.key); if (index <= -1) continue; nlist.remove(index); nodeNeighbours.put(targetNode.key, nlist); } nodeNeighbours.put(node.key, newNeighbours); } else { AuraManager.generateNodeNeighbours(node); } } public static int getClosestAuraWithinRange(World world, double x, double y, double z, double range) { int dim = world.provider.dimensionId; int cx = MathHelper.floor_double((double)x) / 16; int cz = MathHelper.floor_double((double)z) / 16; if (world.isRemote) { return -1; } int size = 5; int closest = -1; double clRange = Double.MAX_VALUE; synchronized (saveLock) { for (int xx = -size; xx <= size; ++xx) { for (int zz = -size; zz <= size; ++zz) { List nc = nodeChunks.get(Arrays.asList(dim, cx + xx, cz + zz)); if (nc == null || nc.size() <= 0) continue; for (Integer key : nc) { try { double zd; double yd; double xd; double distSq; AuraNode node = AuraManager.copyNode(AuraManager.getNode(key)); if (node == null || node.locked || !Utils.isChunkLoaded(world, MathHelper.floor_double((double)node.xPos), MathHelper.floor_double((double)node.zPos)) || !(range * range >= (distSq = (xd = node.xPos - x) * xd + (yd = node.yPos - y) * yd + (zd = node.zPos - z) * zd)) || !(distSq < clRange)) continue; closest = key; clRange = distSq; } catch (Exception e) {} } } } } return closest; } public static int getClosestAuraWithinRange(World world, double x, double z, double range) { int dim = world.provider.dimensionId; int cx = MathHelper.floor_double((double)x) / 16; int cz = MathHelper.floor_double((double)z) / 16; if (world.isRemote) { return -1; } int size = 5; int closest = -1; double clRange = Double.MAX_VALUE; synchronized (saveLock) { for (int xx = -size; xx <= size; ++xx) { for (int zz = -size; zz <= size; ++zz) { List nc = nodeChunks.get(Arrays.asList(dim, cx + xx, cz + zz)); if (nc == null || nc.size() <= 0) continue; for (Integer key : nc) { try { double zd; double xd; double distSq; AuraNode node = AuraManager.copyNode(AuraManager.getNode(key)); if (node == null || node.locked || !Utils.isChunkLoaded(world, MathHelper.floor_double((double)node.xPos), MathHelper.floor_double((double)node.zPos)) || !(range * range >= (distSq = (xd = node.xPos - x) * xd + (zd = node.zPos - z) * zd)) || !(distSq < clRange)) continue; closest = key; clRange = distSq; } catch (Exception e) {} } } } } return closest; } public static ArrayList getAurasWithin(World world, double x, double y, double z) { int dim = world.provider.dimensionId; int cx = MathHelper.floor_double((double)x) / 16; int cz = MathHelper.floor_double((double)z) / 16; ArrayList ret = new ArrayList(); if (world.isRemote) { return ret; } synchronized (saveLock) { for (int xx = -16; xx <= 16; ++xx) { for (int zz = -16; zz <= 16; ++zz) { List nc = nodeChunks.get(Arrays.asList(dim, cx + xx, cz + zz)); if (nc == null || nc.size() <= 0) continue; for (Integer key : nc) { try { double zd; double yd; double xd; double distSq; float influence; AuraNode node = AuraManager.copyNode(AuraManager.getNode(key)); if (node == null || !Utils.isChunkLoaded(world, MathHelper.floor_double((double)node.xPos), MathHelper.floor_double((double)node.zPos)) || !((double)((influence = (float)node.baseLevel) * influence) >= (distSq = (xd = node.xPos - x) * xd + (yd = node.yPos - y) * yd + (zd = node.zPos - z) * zd))) continue; ret.add(key); } catch (Exception e) {} } } } } return ret; } public static boolean decreaseClosestAura(World world, double x, double y, double z, int amount) { if (amount == 0) { return true; } return AuraManager.decreaseClosestAura(world, x, y, z, amount, true); } public static boolean decreaseClosestAura(World world, double x, double y, double z, int amount, boolean doit) { AuraNode node; if (world.isRemote) { return false; } int dim = world.provider.dimensionId; ArrayList nodes = AuraManager.getAurasWithin(world, x, y, z); int total = 0; ArrayList> sortednodes = new ArrayList>(); ArrayList> depnodes = new ArrayList>(); for (Integer n : nodes) { int a; double zd; double yd; double xd; double distSq; float influence; node = AuraManager.getNode(n); if (node == null || node.level <= 0 || !((double)((influence = (float)node.baseLevel / 4.0f) * influence) >= (distSq = (xd = node.xPos - x) * xd + (yd = node.yPos - y) * yd + (zd = node.zPos - z) * zd))) continue; if (sortednodes.size() == 0) { sortednodes.add(Arrays.asList(distSq, node.key)); continue; } for (a = 0; !(a > sortednodes.size() || a < sortednodes.size() && (Double)((List)sortednodes.get(a)).get(0) > distSq); ++a) { } if (a < sortednodes.size()) { sortednodes.add(a, Arrays.asList(distSq, node.key)); continue; } sortednodes.add(Arrays.asList(distSq, node.key)); } if (sortednodes.size() == 0) { return false; } for (List list : sortednodes) { node = AuraManager.getNode((Integer)list.get(1)); if (node != null && node.level > 0) { if (node.level >= amount - total) { depnodes.add(Arrays.asList(amount - total, node.key)); total += amount - total; break; } depnodes.add(Arrays.asList((int)node.level, node.key)); total += node.level; } if (amount - total != 0) continue; break; } if (total == amount) { for (List list : depnodes) { int amt = (Integer)list.get(0); AuraNode node2 = AuraManager.getNode((Integer)list.get(1)); if (node2 == null || !doit) continue; AuraManager.queueNodeChanges(node2.key, -amt, 0, false, null, 0.0f, 0.0f, 0.0f); } return true; } return false; } public static boolean increaseLowestAura(World world, double x, double y, double z, int amount) { if (world.isRemote) { return false; } int dim = world.provider.dimensionId; ArrayList nodes = AuraManager.getAurasWithin(world, x, y, z); int n = Integer.MAX_VALUE; AuraNode lowest = null; for (Integer nk : nodes) { double zd; double yd; double xd; double distSq; float influence; short s = Short.MAX_VALUE; AuraNode node = AuraManager.getNode(nk); if (node == null || node.level >= s || !((double)((influence = (float)node.baseLevel / 4.0f) * influence) >= (distSq = (xd = node.xPos - x) * xd + (yd = node.yPos - y) * yd + (zd = node.zPos - z) * zd))) continue; lowest = node; s = node.level; } if (lowest != null) { AuraNode node = AuraManager.getNode(lowest.key); if (node != null) { AuraManager.queueNodeChanges(node.key, amount, 0, false, null, 0.0f, 0.0f, 0.0f); } return true; } return false; } public static boolean increaseLowestAuraWithLimit(World world, double x, double y, double z, int amount, float limit) { if (world.isRemote) { return false; } int dim = world.provider.dimensionId; ArrayList nodes = AuraManager.getAurasWithin(world, x, y, z); int n = Integer.MAX_VALUE; AuraNode lowest = null; for (Integer nk : nodes) { double zd; double yd; double xd; double distSq; float influence; short s = Short.MAX_VALUE; AuraNode node = AuraManager.getNode(nk); if (node == null || node.level >= s || !((float)node.level < (float)node.baseLevel * limit) || !((double)((influence = (float)node.baseLevel / 4.0f) * influence) >= (distSq = (xd = node.xPos - x) * xd + (yd = node.yPos - y) * yd + (zd = node.zPos - z) * zd))) continue; lowest = node; s = node.level; } if (lowest != null) { AuraNode node = AuraManager.getNode(lowest.key); if (node != null) { AuraManager.queueNodeChanges(node.key, amount, 0, false, null, 0.0f, 0.0f, 0.0f); } return true; } return false; } public static boolean auraNearby(int dim, int x, int y, int z, int range) { Collection col = auraNodes.values(); for (AuraNode an : col) { float pz; double zd; float py; double yd; float px; double xd; double distSq; if (dim != an.dimension || !((distSq = (xd = (double)((px = (float)an.xPos) - (float)x + 0.5f)) * xd + (yd = (double)((py = (float)an.yPos) - (float)y + 0.5f)) * yd + (zd = (double)((pz = (float)an.zPos) - (float)z + 0.5f)) * zd) < (double)(range * range))) continue; return true; } return false; } public static boolean specificAuraTypeNearby(int dim, int x, int y, int z, EnumNodeType type, int range) { Collection col = auraNodes.values(); for (AuraNode an : col) { float pz; double zd; float py; double yd; float px; double xd; double distSq; if (dim != an.dimension || an.type != type || !((distSq = (xd = (double)((px = (float)an.xPos) - (float)x + 0.5f)) * xd + (yd = (double)((py = (float)an.yPos) - (float)y + 0.5f)) * yd + (zd = (double)((pz = (float)an.zPos) - (float)z + 0.5f)) * zd) < (double)(range * range))) continue; return true; } return false; } public static void sendNodePacket(AuraNode node) { AuraCore.CHANNEL.sendToAllAround(new AuraPacket(node), new TargetPoint(node.dimension, node.xPos, node.yPos, node.zPos, Math.max(32.0f, (float)node.baseLevel / 4.0f))); } public static void sendNodeTransferFXPacket(AuraNode node, AuraNode tnode, double distance) { double xx = (node.xPos + tnode.xPos) / 2.0; double yy = (node.yPos + tnode.yPos) / 2.0; double zz = (node.zPos + tnode.zPos) / 2.0; AuraCore.CHANNEL.sendToAllAround(new AuraTransferFXPacket(node, tnode), new TargetPoint(node.dimension, xx, yy, zz, MathHelper.sqrt_double((double)distance) + 32.0f)); } public static void sendNodeDeletionPacket(AuraNode node) { AuraCore.CHANNEL.sendToAll(new AuraDeletePacket(node)); } public static void addFluxToClosest(World world, float x, float y, float z, AspectList tags) { if (world.isRemote) { return; } int dim = world.provider.dimensionId; ArrayList nodes = AuraManager.getAurasWithin(world, x, y, z); if (nodes == null || nodes.size() == 0) { return; } boolean total = false; double cDist = Double.MAX_VALUE; int cKey = -1; for (Integer nk : nodes) { double zd; double yd; double xd; double distSq; float influence; AuraNode node = AuraManager.getNode(nk); if (node == null || !((double)((influence = (float)node.baseLevel / 4.0f) * influence) >= (distSq = (xd = node.xPos - (double)x) * xd + (yd = node.yPos - (double)y) * yd + (zd = node.zPos - (double)z) * zd)) || !(distSq < cDist)) continue; cDist = distSq; cKey = nk; } if (cKey < 0) { return; } AuraNode node = AuraManager.getNode(cKey); if (node != null) { AspectList flux = new AspectList(); for (Aspect tag : tags.getAspects()) { if (tags.getAmount(tag) <= 0) continue; flux.add(tag, tags.getAmount(tag)); } if (flux.size() > 0) { AuraManager.queueNodeChanges(node.key, 0, 0, false, flux, 0.0f, 0.0f, 0.0f); } } } public static void removeRandomFlux(World world, AuraNode node, int amount) { AspectList flux = new AspectList(); for (int a = 0; a < amount; ++a) { int i$ = 0; Aspect[] arr$ = node.flux.getAspects(); int len$ = arr$.length; if (i$ >= len$) continue; Aspect tg = arr$[i$]; if (world.rand.nextInt(5) != 0 || -flux.getAmount(tg) >= node.flux.getAmount(tg)) continue; flux.add(tg, -1); } if (flux.size() > 0) { AuraManager.queueNodeChanges(node.key, 0, 0, false, flux, 0.0f, 0.0f, 0.0f); } } public static void addRandomFlux(World world, AuraNode node, int amount) { AspectList flux = new AspectList(); block20: for (int a = 0; a < amount; ++a) { if (world.rand.nextInt(5) != 0) continue; switch (world.rand.nextInt(3)) { case 0: { int biome = world.getBiomeGenForCoords((int)((int)node.xPos), (int)((int)node.zPos)).biomeID; flux.add(BiomeHandler.getRandomBiomeTag(biome, world.rand), 1); continue block20; } case 1: { switch (world.rand.nextInt(20)) { case 0: case 1: { flux.add(Aspect.AIR, 1); continue block20; } case 2: { flux.add(Aspect.MOTION, 1); continue block20; } case 3: case 4: { flux.add(Aspect.FIRE, 1); continue block20; } case 5: { flux.add(Aspect.ENERGY, 1); continue block20; } case 6: case 7: { flux.add(Aspect.WATER, 1); continue block20; } case 8: { flux.add(Aspect.COLD, 1); continue block20; } case 9: case 10: { flux.add(Aspect.EARTH, 1); continue block20; } case 11: { flux.add(Aspects.ROCK, 1); continue block20; } case 12: { flux.add(Aspect.POISON, 1); continue block20; } case 13: { flux.add(Aspect.PLANT, 1); continue block20; } case 14: { flux.add(Aspect.TREE, 1); continue block20; } case 15: case 16: { flux.add(Aspect.MAGIC, 1); continue block20; } case 17: { flux.add(Aspect.BEAST, 1); continue block20; } case 18: { flux.add(Aspect.DEATH, 1); continue block20; } } flux.add(Aspect.WEATHER, 1); continue block20; } default: { flux.add(Aspects.FLUX, 1); } } } if (flux.size() > 0) { AuraManager.queueNodeChanges(node.key, 0, 0, false, flux, 0.0f, 0.0f, 0.0f); } } public static void deleteNode(AuraNode node) { auraDeleteQueue.add(node.key); sendNodeDeletionPacket(node); } public static boolean spawnMajorFluxEvent(World world, AuraNode node, Aspect fluxTag) { boolean success = false; if (fluxTag == Aspects.PURE) { success = true; } if (success) { AuraManager.queueNodeChanges(node.key, 0, 0, false, new AspectList().add(fluxTag, -50), 0.0f, 0.0f, 0.0f); } return success; } public static boolean spawnModerateFluxEvent(World world, AuraNode node, Aspect fluxTag) { boolean success = false; if (fluxTag == Aspects.PURE) { success = true; } else if (fluxTag == Aspect.DEATH) { success = AuraManager.spawnGiant(world, node); } if (success) { AuraManager.queueNodeChanges(node.key, 0, 0, false, new AspectList().add(fluxTag, -25), 0.0f, 0.0f, 0.0f); } return success; } public static boolean spawnMinorFluxEvent(World world, AuraNode node, Aspect fluxTag) { boolean success = false; if (world.rand.nextInt(3) == 0) { success = AuraManager.spawnWisp(world, node, fluxTag); } else { if (fluxTag == Aspect.ENERGY || fluxTag == Aspects.DESTRUCTION) { success = AuraManager.spawnLightning(world, node); } else if (fluxTag == Aspect.POISON || fluxTag == Aspects.INSECT) { success = AuraManager.poisonCreature(world, node, Potion.poison.id); } else if (fluxTag == Aspect.DARKNESS || fluxTag == Aspect.VOID) { success = AuraManager.poisonCreature(world, node, Potion.blindness.id); } else if (fluxTag == Aspect.ARMOR) { success = AuraManager.poisonCreature(world, node, Potion.resistance.id); } else if (fluxTag == Aspect.MOTION) { success = AuraManager.poisonCreature(world, node, Potion.moveSpeed.id); } else if (fluxTag == Aspect.FLIGHT) { success = AuraManager.poisonCreature(world, node, Potion.jump.id); } else if (fluxTag == Aspect.TOOL) { success = AuraManager.poisonCreature(world, node, Potion.digSpeed.id); } else if (fluxTag == Aspects.ROCK) { success = AuraManager.poisonCreature(world, node, Potion.digSlowdown.id); } else if (fluxTag == Aspect.COLD) { success = AuraManager.poisonCreature(world, node, Potion.moveSlowdown.id); } else if (fluxTag == Aspects.SOUND || fluxTag == Aspect.MIND || fluxTag == Aspects.FUNGUS) { success = AuraManager.poisonCreature(world, node, Potion.confusion.id); } else if (fluxTag == Aspects.EVIL) { success = AuraManager.spawnEvil(world, node); } else if (fluxTag == Aspect.DEATH) { success = AuraManager.spawnDeath(world, node); } else if (fluxTag == Aspect.FIRE) { success = AuraManager.spawnFire(world, node); } else if (fluxTag == Aspect.CROP || fluxTag == Aspect.PLANT || fluxTag == Aspect.TREE) { success = AuraManager.promoteGrowth(world, node); } else if (fluxTag == Aspects.PURE) { success = true; } } if (success) { AuraManager.queueNodeChanges(node.key, 0, 0, false, new AspectList().add(fluxTag, -10), 0.0f, 0.0f, 0.0f); } return success; } private static boolean promoteGrowth(World world, AuraNode node) { int fuzz = (int)((float)node.baseLevel / 8.0f); double xx = node.xPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double zz = node.zPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double yy = Utils.getFirstUncoveredBlockHeight(world, (int)xx, (int)zz); if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)xx), MathHelper.floor_double((double)zz))) { return false; } return Utils.useBonemealAtLoc(world, (int)xx, (int)yy, (int)zz); } private static boolean poisonCreature(World world, AuraNode node, int type) { boolean did = false; List ents = world.getEntitiesWithinAABB(EntityLivingBase.class, AxisAlignedBB.getBoundingBox(node.xPos - 1.0, node.yPos - 1.0, node.zPos - 1.0, node.xPos + 1.0, node.yPos + 1.0, node.zPos + 1.0).expand((double)((float)node.baseLevel / 4.0f), (double)((float)node.baseLevel / 4.0f), (double)((float)node.baseLevel / 4.0f))); if (ents.size() > 0) { for (int a = 0; a < 3 && ents.size() >= 1; ++a) { int q = world.rand.nextInt(ents.size()); EntityLivingBase el = ents.get(q); if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)el.posX), MathHelper.floor_double((double)el.posZ))) continue; el.addPotionEffect(new PotionEffect(type, 100 + world.rand.nextInt(200), 0)); if (el instanceof EntityPlayer) { ((EntityPlayer)el).addChatMessage(new ChatComponentText("\u00a72\u00a7oThe air around you suddenly becomes suffused with strange energies.")); } did = true; ents.remove(q); } } return did; } private static boolean spawnLightning(World world, AuraNode node) { List ents = world.getEntitiesWithinAABB(EntityLivingBase.class, AxisAlignedBB.getBoundingBox(node.xPos - 1.0, node.yPos - 1.0, node.zPos - 1.0, node.xPos + 1.0, node.yPos + 1.0, node.zPos + 1.0).expand((double)((float)node.baseLevel / 4.0f / 2.0f), (double)((float)node.baseLevel / 4.0f / 2.0f), (double)((float)node.baseLevel / 4.0f / 2.0f))); if (ents.size() > 0) { for (EntityLivingBase ent : ents) { if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)ent.posX), MathHelper.floor_double((double)ent.posZ))) continue; AuraCore.CHANNEL.sendToAllAround(new NodeZapPacket(node.xPos, node.yPos, node.zPos, ent), new TargetPoint(ent.dimension, ent.posX, ent.posY, ent.posZ, 64.0)); world.playSoundEffect(node.xPos, node.yPos, node.zPos, "thaumcraft.zap", 1.0f, 1.1f); ent.attackEntityFrom(DamageSource.magic, 5); return true; } } return false; } private static boolean spawnGiant(World world, AuraNode node) { boolean spawn; int fuzz = (int)((float)node.baseLevel / 4.0f) / 3; double xx = node.xPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double zz = node.zPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double yy = world.getHeightValue((int)xx, (int)zz) + 5; if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)xx), MathHelper.floor_double((double)zz))) { return false; } EntityGiantBrainyZombie zombie = new EntityGiantBrainyZombie(world); zombie.setLocationAndAngles(xx, yy, zz, world.rand.nextFloat() * 360.0f, 0.0f); boolean bl = spawn = zombie.getCanSpawnHere() && world.spawnEntityInWorld((Entity)zombie); if (spawn) { Utils.sendChatNearby(world, xx, yy, zz, 64.0, "\u00a75\u00a7oA nearby node spews forth something foul."); } return spawn; } private static boolean spawnFire(World world, AuraNode node) { int fuzz = (int)((float)node.baseLevel / 4.0f) / 3; double xx = node.xPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double yy = node.yPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double zz = node.zPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)xx), MathHelper.floor_double((double)zz))) { return false; } EntityFireBat firebat = new EntityFireBat(world); firebat.setLocationAndAngles(xx, yy, zz, world.rand.nextFloat() * 360.0f, 0.0f); firebat.addPotionEffect(new PotionEffect(Potion.damageBoost.id, 32000, 0)); boolean spawn = firebat.getCanSpawnHere() && world.spawnEntityInWorld((Entity)firebat); return spawn; } private static boolean spawnDeath(World world, AuraNode node) { double yy; int fuzz = (int)((float)node.baseLevel / 4.0f) / 3; double xx = node.xPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double zz = node.zPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)xx), MathHelper.floor_double((double)zz))) { return false; } EntityBrainyZombie zombie = new EntityBrainyZombie(world); for (yy = node.yPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); world.isAirBlock((int)xx, (int)yy - 2, (int)zz) && yy > 10.0; yy -= 1.0) { } zombie.setLocationAndAngles(xx, yy, zz, world.rand.nextFloat() * 360.0f, 0.0f); zombie.addPotionEffect(new PotionEffect(Potion.damageBoost.id, 32000, 0)); boolean spawn = zombie.getCanSpawnHere() && world.spawnEntityInWorld((Entity)zombie); return spawn; } private static boolean spawnEvil(World world, AuraNode node) { double yy; int fuzz = (int)((float)node.baseLevel / 4.0f) / 3; double xx = node.xPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); double zz = node.zPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)xx), MathHelper.floor_double((double)zz))) { return false; } EntityWitch witch = new EntityWitch(world); for (yy = node.yPos + (double)world.rand.nextInt(fuzz) - (double)world.rand.nextInt(fuzz); world.isAirBlock((int)xx, (int)yy - 2, (int)zz) && yy > 10.0; yy -= 1.0) { } witch.setLocationAndAngles(xx, yy + 0.5, zz, world.rand.nextFloat() * 360.0f, 0.0f); boolean spawn = witch.getCanSpawnHere() && world.spawnEntityInWorld((Entity)witch); return spawn; } private static boolean spawnWisp(World world, AuraNode node, Aspect type) { if (!Utils.isChunkLoaded(world, MathHelper.floor_double((double)node.xPos), MathHelper.floor_double((double)node.zPos))) { return false; } EntityWisp wisp = new EntityWisp(world); wisp.setLocationAndAngles(node.xPos, node.yPos, node.zPos, world.rand.nextFloat() * 360.0f, 0.0f); //wisp.type = type; wisp.playLivingSound(); return wisp.getCanSpawnHere() && world.spawnEntityInWorld((Entity)wisp); } public static synchronized AuraNode getNode(int key) { return (AuraNode)auraNodes.get(key); } public static synchronized AuraNode getNodeCopy(int key) { return AuraManager.copyNode((AuraNode)auraNodes.get(key)); } public static synchronized Integer[] getUpdateList(int dim) { int count = 0; while (auraUpdateList.get(dim) != null && count < 10) { try { ++count; return ((List)auraUpdateList.get(dim)).toArray(new Integer[]{0}); } catch (Exception exception) { } } return null; } public static void queueNodeChanges(int key, int levelMod, int baseMod, boolean toggleLock, AspectList flx, float x, float y, float z) { NodeChanges nc = new NodeChanges(key, levelMod, baseMod, 0, toggleLock, flx, x, y, z); auraUpdateQueue.add(nc); } public static void queueNodeChanges(int key, int levelMod, int baseMod, int taint, boolean toggleLock, AspectList flx, float x, float y, float z) { NodeChanges nc = new NodeChanges(key, levelMod, baseMod, taint, toggleLock, flx, x, y, z); auraUpdateQueue.add(nc); } public static void addTaintToClosest(World world, int x, int y, int z, int taint) { int key = getClosestAuraWithinRange(world, x, y, z, 64); if (key < 0) { key = registerAuraNode(world, (short)(world.rand.nextInt(50) + 50), EnumNodeType.DARK, world.provider.dimensionId, x, y, z); } queueNodeChanges(key, 0, 0, taint, false, null, 0, 0, 0); } public static AuraNode copyNode(AuraNode in) { try { AuraNode out = new AuraNode(); out.key = in.key; out.level = in.level; out.baseLevel = in.baseLevel; out.taint = in.taint; out.type = in.type; AspectList outflux = new AspectList(); for (Aspect tag : in.flux.getAspects()) { outflux.add(tag, in.flux.getAmount(tag)); } out.flux = outflux; out.dimension = in.dimension; out.xPos = in.xPos; out.yPos = in.yPos; out.zPos = in.zPos; out.locked = in.locked; out.isVirtual = in.isVirtual; return out; } catch (NullPointerException e) { return null; } } public static void replaceNode(AuraNode in, AuraNode out) { out.key = in.key; out.level = in.level; out.baseLevel = in.baseLevel; out.taint = in.taint; out.type = in.type; out.flux = in.flux; out.dimension = in.dimension; out.xPos = in.xPos; out.yPos = in.yPos; out.zPos = in.zPos; out.locked = in.locked; out.isVirtual = in.isVirtual; } public static class NodeChanges { int key = 0; int levelMod = 0; int baseMod = 0; int taintMod = 0; boolean lock = false; AspectList flux = null; float motionX; float motionY; float motionZ; NodeChanges(int k, int l, int b, int t, boolean lo, AspectList ot, float x, float y, float z) { this.key = k; this.levelMod = l; this.baseMod = b; this.taintMod = t; this.lock = lo; this.flux = ot; this.motionX = x; this.motionY = y; this.motionZ = z; } } }