auracore/src/main/java/dev/tilera/auracore/aura/AuraManager.java

951 lines
42 KiB
Java

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<Integer, AuraNode> auraNodes = new ConcurrentHashMap<>();
public static ConcurrentHashMap<Integer, List<Integer>> auraUpdateList = new ConcurrentHashMap<>();
public static volatile ConcurrentHashMap<Integer, Collection<Integer>> nodeNeighbours = new ConcurrentHashMap<>();
public static volatile ConcurrentHashMap<List<Integer>, List<Integer>> nodeChunks = new ConcurrentHashMap<>();
public static volatile ConcurrentHashMap<Integer, Long> markedForTransmission = new ConcurrentHashMap<>();
public static volatile ArrayList<List<Object>> fluxEventList = new ArrayList<>();
public static LinkedBlockingQueue<List<Object>> auraCalcQueue = new LinkedBlockingQueue<>();
public static LinkedBlockingQueue<Integer> auraDeleteQueue = new LinkedBlockingQueue<>();
public static LinkedBlockingQueue<NodeChanges> 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<Integer> temp = (LinkedList<Integer>)auraUpdateList.get(dim);
if (temp == null) {
temp = new LinkedList<Integer>();
auraUpdateList.put(dim, temp);
}
temp.add(node.key);
return key;
}
public static List<Integer> getNodeNeighbours(int nkey) {
ArrayList<Integer> neighbours = new ArrayList<>();
if (nodeNeighbours.get(nkey) != null) {
neighbours.addAll(nodeNeighbours.get(nkey));
}
return neighbours;
}
public static List<Integer> getNodeNeighboursNeighbours(int nkey) {
List<Integer> neighbours = AuraManager.getNodeNeighbours(nkey);
if (neighbours != null && neighbours.size() > 0) {
ArrayList<Integer> neighboursNeighbours = new ArrayList<Integer>();
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<Integer> temp = (LinkedList<Integer>)auraUpdateList.get(node.dimension);
if (temp == null) {
temp = new LinkedList<Integer>();
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<Integer> neighbours = new ArrayList<Integer>();
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<Integer> temp = new ArrayList<Integer>();
temp.add(node.key);
nodeChunks.put(Arrays.asList(dim, cx, cz), temp);
}
}
}
public static void updateNodeNeighbours(AuraNode node) {
int dim = node.dimension;
List<Integer> updateList = AuraManager.getNodeNeighboursNeighbours(node.key);
ArrayList<Integer> newNeighbours = new ArrayList<Integer>();
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<Integer> 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<Integer> 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<Integer> 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<Integer> ret = new ArrayList<Integer>();
if (world.isRemote) {
return ret;
}
synchronized (saveLock) {
for (int xx = -16; xx <= 16; ++xx) {
for (int zz = -16; zz <= 16; ++zz) {
List<Integer> 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<Integer> nodes = AuraManager.getAurasWithin(world, x, y, z);
int total = 0;
ArrayList<List<Number>> sortednodes = new ArrayList<List<Number>>();
ArrayList<List<Integer>> depnodes = new ArrayList<List<Integer>>();
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<Number> 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<Integer> 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<Integer> 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<Integer> 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<AuraNode> 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<AuraNode> 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<Integer> 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<EntityLivingBase> 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<EntityLivingBase> 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<Integer>)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, null, 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, null, x, y, z);
auraUpdateQueue.add(nc);
}
public static void queueNodeChanges(int key, int levelMod, int baseMod, int taint, boolean toggleLock, AspectList flx, AspectList stasis, float x, float y, float z) {
NodeChanges nc = new NodeChanges(key, levelMod, baseMod, taint, toggleLock, flx, stasis, 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 void addGoodVibes(World world, int x, int y, int z, int amount) {
int key = getClosestAuraWithinRange(world, x, y, z, 64);
if (key < 0) return;
queueNodeChanges(key, 0, 0, 0, false, null, new AspectList().add(Aspect.MAGIC, amount), 0, 0, 0);
}
public static void addBadVibes(World world, int x, int y, int z, int amount) {
int key = getClosestAuraWithinRange(world, x, y, z, 64);
if (key < 0) return;
queueNodeChanges(key, 0, 0, 0, false, new AspectList().add(Aspect.TAINT, amount), null, 0, 0, 0);
}
public static void addBoost(World world, int x, int y, int z, int amount) {
int key = getClosestAuraWithinRange(world, x, y, z, 64);
if (key < 0) return;
queueNodeChanges(key, 0, 0, 0, false, null, new AspectList().add(Aspects.TIME, amount), 0, 0, 0);
}
public static int getBoost(World world, int x, int y, int z) {
int key = getClosestAuraWithinRange(world, x, y, z, 64);
if (key < 0) return 0;
AuraNode node = getNode(key);
return node.stasis.getAmount(Aspects.TIME);
}
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;
AspectList outstasis = new AspectList();
for (Aspect tag : in.stasis.getAspects()) {
outstasis.add(tag, in.stasis.getAmount(tag));
}
out.stasis = outstasis;
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.stasis = in.stasis;
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;
AspectList stasis = null;
float motionX;
float motionY;
float motionZ;
NodeChanges(int k, int l, int b, int t, boolean lo, AspectList flux, AspectList stasis, float x, float y, float z) {
this.key = k;
this.levelMod = l;
this.baseMod = b;
this.taintMod = t;
this.lock = lo;
this.flux = flux;
this.stasis = stasis;
this.motionX = x;
this.motionY = y;
this.motionZ = z;
}
}
}