Compare commits

...
12 Commits
Author SHA1 Message Date
UltraProdigy 8546cab959 Optimize Images & Workflow (#108) 2026-03-16 08:47:43 +00:00
Yoshy f69e39227e fix typos (#105) 2026-01-28 06:25:37 -05:00
Caedis 06def1b332 Synth Node now consumes the entire stack of essense instead of 1 (#102) 2025-11-22 11:37:31 +01:00
Aerindor of Arcane a351ef46b4 Potion ID configs Added [Issue #97] (#99) 2025-11-12 06:35:20 +00:00
koolkrafter5andRecursivePineapple 33cc4943a7 Improved Dispenser Functionality (#94)
Co-authored-by: RecursivePineapple <recursive_pineapple@proton.me>
2025-11-12 05:09:09 +00:00
Martin Robertz 5f37e3aa3d update 2025-10-25 17:28:20 +02:00
DarkShadow44 7eb409820b Fix nullpointer crash when exploding Alchemite (#100) 2025-10-25 17:03:57 +02:00
Martin Robertz ce27ffd52d update 2025-10-16 10:48:22 +02:00
551cdf4a93 Soul Beacon Event Handler Cleanup (#93)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-12 23:36:36 +02:00
Martin Robertz 5a14114583 update 2025-10-02 01:51:49 +02:00
Martin Robertz fc0cc6a074 update 2025-09-22 18:36:53 +02:00
Aerindor of Arcane 47c06267c1 Add client-side vortex sound in TileVortex (#96) 2025-09-22 11:55:29 +02:00
295 changed files with 583 additions and 201 deletions

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
name: Optimize images
on:
pull_request:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
push:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
jobs:
optimize-images:
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master
secrets: inherit
+2 -2
View File
@@ -1,9 +1,9 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:Baubles-Expanded:2.1.9-GTNH:dev')
api('com.github.GTNewHorizons:Baubles-Expanded:2.2.2-GTNH:dev')
api('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev')
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.51.368:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.69:dev') {transitive = false}
}
+5 -3
View File
@@ -45,7 +45,7 @@ enableModernJavaSyntax = true
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
enableGenericInjection = false
enableGenericInjection = true
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
@@ -96,7 +96,9 @@ usesMixinDebug = false
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
# Specify the package that contains all of your Mixins. The package must exist or
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
# it must match with this or the build will fail.
mixinsPackage =
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
@@ -151,7 +153,7 @@ modrinthProjectId = 1wDWP1tN
# type can be one of [project, version],
# and the name is the Modrinth project or version slug/id of the other mod.
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
modrinthRelations =
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.38'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.46'
}
@@ -5,6 +5,8 @@
package com.kentington.thaumichorizons.client;
import java.awt.Color;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
@@ -28,6 +30,7 @@ import net.minecraft.world.World;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.MinecraftForge;
import com.kentington.thaumichorizons.client.audio.VortexSound;
import com.kentington.thaumichorizons.client.fx.FXSonic;
import com.kentington.thaumichorizons.client.gui.GuiBloodInfuser;
import com.kentington.thaumichorizons.client.gui.GuiCase;
@@ -555,4 +558,54 @@ public class ClientProxy extends CommonProxy {
1.0f,
0.1f);
}
private final Map<TileCoord, VortexSound> activeVortexSounds = new HashMap<>();
@Override
public void playVortexSound(TileVortex tile) {
if (tile == null || tile.isInvalid() || tile.getWorldObj() == null) return;
TileCoord pos = new TileCoord(tile.xCoord, tile.yCoord, tile.zCoord);
if (activeVortexSounds.containsKey(pos)) return;
VortexSound sound = new VortexSound(tile);
Minecraft.getMinecraft().getSoundHandler().playSound(sound);
activeVortexSounds.put(pos, sound);
}
@Override
public void stopVortexSound(TileVortex tile) {
if (tile == null) return;
TileCoord pos = new TileCoord(tile.xCoord, tile.yCoord, tile.zCoord);
VortexSound sound = activeVortexSounds.remove(pos);
if (sound != null) {
sound.markDone();
}
}
// Inner class to replace BlockPos for 1.7.10
private static class TileCoord {
final int x, y, z;
TileCoord(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof TileCoord)) return false;
TileCoord other = (TileCoord) o;
return this.x == other.x && this.y == other.y && this.z == other.z;
}
@Override
public int hashCode() {
return x * 31 * 31 + y * 31 + z;
}
}
}
@@ -0,0 +1,48 @@
package com.kentington.thaumichorizons.client.audio;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.MovingSound;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
public class VortexSound extends MovingSound {
private final TileEntity tile;
public VortexSound(TileEntity tile) {
super(new ResourceLocation("thaumichorizons:vortex"));
this.tile = tile;
this.repeat = true;
this.field_147665_h = 0;
this.volume = 1.0F;
}
// Let me know if update needs to be cached or if that's a good idea or not for performance.
@Override
public void update() {
if (tile == null || tile.isInvalid() || tile.getWorldObj() == null) {
this.donePlaying = true;
return;
}
// follow tile
this.xPosF = tile.xCoord + 0.5F;
this.yPosF = tile.yCoord + 0.5F;
this.zPosF = tile.zCoord + 0.5F;
// distance-based volume
EntityPlayer p = Minecraft.getMinecraft().thePlayer;
if (p != null) {
double dist = p.getDistance(this.xPosF, this.yPosF, this.zPosF);
this.volume = Math.max(0.0F, 1.0F / (1.0F + (float) (dist / 8.0F)));
}
}
public void markDone() {
this.donePlaying = true;
}
}
@@ -29,6 +29,7 @@ import com.kentington.thaumichorizons.common.tiles.TileSoulExtractor;
import com.kentington.thaumichorizons.common.tiles.TileSoulforge;
import com.kentington.thaumichorizons.common.tiles.TileVat;
import com.kentington.thaumichorizons.common.tiles.TileVisDynamo;
import com.kentington.thaumichorizons.common.tiles.TileVortex;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.IGuiHandler;
@@ -134,4 +135,8 @@ public class CommonProxy implements IGuiHandler {
public void lightningBolt(final World worldObj, final double x, final double y, final double z,
final int boltLength) {}
public void playVortexSound(TileVortex tile) {}
public void stopVortexSound(TileVortex tile) {}
}
@@ -8,16 +8,24 @@ package com.kentington.thaumichorizons.common;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDispenser;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.dispenser.BehaviorDefaultDispenseItem;
import net.minecraft.dispenser.BehaviorProjectileDispense;
import net.minecraft.dispenser.IBlockSource;
import net.minecraft.dispenser.IPosition;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.monster.EntityBlaze;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.entity.monster.EntityGhast;
@@ -44,7 +52,9 @@ import net.minecraft.item.crafting.ShapelessRecipes;
import net.minecraft.nbt.NBTTagByte;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
@@ -57,6 +67,7 @@ import net.minecraftforge.oredict.ShapelessOreRecipe;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.collect.Sets;
import com.kentington.thaumichorizons.client.lib.RenderEventHandler;
import com.kentington.thaumichorizons.common.blocks.BlockAlchemite;
import com.kentington.thaumichorizons.common.blocks.BlockBloodInfuser;
@@ -132,6 +143,7 @@ import com.kentington.thaumichorizons.common.entities.EntitySyringe;
import com.kentington.thaumichorizons.common.entities.EntityTaintPig;
import com.kentington.thaumichorizons.common.entities.EntityVoltSlime;
import com.kentington.thaumichorizons.common.entities.ItemSpawnerEgg;
import com.kentington.thaumichorizons.common.handlers.BehaviorDispenseBoat;
import com.kentington.thaumichorizons.common.items.ItemAmuletMirror;
import com.kentington.thaumichorizons.common.items.ItemBarChocolate;
import com.kentington.thaumichorizons.common.items.ItemBoatGreatwood;
@@ -473,7 +485,7 @@ public class ThaumicHorizons {
} catch (Exception var8) {
log.error("Thaumic Horizons could not load its configuration file");
} finally {
if (config != null) {
if (config != null && config.hasChanged()) {
config.save();
}
}
@@ -752,6 +764,7 @@ public class ThaumicHorizons {
proxy.registerHandlers();
proxy.registerRenderers();
FMLCommonHandler.instance().bus().register(instance);
initPotions();
}
@EventHandler
@@ -796,7 +809,6 @@ public class ThaumicHorizons {
shapelessOreDictRecipe(
new ItemStack(ConfigItems.itemTripleMeatTreat),
new Object[] { Items.sugar, itemMeatNugget, ConfigItems.itemNuggetBeef, ConfigItems.itemNuggetFish });
initPotions();
ResearchCategories.registerCategory(
"ThaumicHorizons",
new ResourceLocation("thaumichorizons", "textures/misc/vat.png"),
@@ -3631,6 +3643,7 @@ public class ThaumicHorizons {
new ItemStack(Items.dye, 1, 0), new ItemStack(Items.dye, 1, 15) },
10));
addAspectsToAllTheThings();
registerDispenserBehavior();
}
public static CreatureInfusionRecipe getCreatureInfusion(EntityLivingBase entityContained,
@@ -3667,7 +3680,6 @@ public class ThaumicHorizons {
public static void initPotions() {
byte customPotions = 5;
int potionOffset = Potion.potionTypes.length;
boolean start = false;
int var4;
if (potionOffset < 128 - customPotions) {
Potion[] potionTypes = new Potion[potionOffset + customPotions];
@@ -3679,40 +3691,54 @@ public class ThaumicHorizons {
var4 = -1;
}
int visBoostPotionId = potionVisBoostID;
var4 = getNextPotionId(var4);
if (var4 >= 0) {
potionVisBoostID = var4;
PotionVisBoost.instance = new PotionVisBoost(potionVisBoostID, true, 6697847);
PotionVisBoost.init();
if (Potion.potionTypes[visBoostPotionId] != null) {
visBoostPotionId = getNextPotionId(visBoostPotionId);
}
potionVisBoostID = visBoostPotionId;
PotionVisBoost.instance = new PotionVisBoost(potionVisBoostID, true, 6697847);
PotionVisBoost.init();
int visRegenPotionId = potionVisRegenID;
var4 = getNextPotionId(var4);
if (Potion.potionTypes[visRegenPotionId] != null) {
visRegenPotionId = getNextPotionId(visRegenPotionId);
}
var4 = getNextPotionId(var4);
if (var4 >= 0) {
potionVisRegenID = var4;
PotionVisRegen.instance = new PotionVisRegen(potionVisRegenID, true, 5701759);
PotionVisRegen.init();
potionVisRegenID = visRegenPotionId;
PotionVisRegen.instance = new PotionVisRegen(potionVisRegenID, true, 5701759);
PotionVisRegen.init();
int vacuumPotionId = potionVacuumID;
if (Potion.potionTypes[vacuumPotionId] != null) {
vacuumPotionId = getNextPotionId(vacuumPotionId);
}
var4 = getNextPotionId(var4);
if (var4 >= 0) {
potionVacuumID = var4;
PotionVacuum.instance = new PotionVacuum(potionVacuumID, true, 4210752);
PotionVacuum.init();
potionVacuumID = vacuumPotionId;
PotionVacuum.instance = new PotionVacuum(potionVacuumID, true, 4210752);
PotionVacuum.init();
int shockPotionId = potionShockID;
if (Potion.potionTypes[shockPotionId] != null) {
shockPotionId = getNextPotionId(shockPotionId);
}
var4 = getNextPotionId(var4);
if (var4 >= 0) {
potionShockID = var4;
PotionShock.instance = new PotionShock(potionShockID, true, 11513861);
PotionShock.init();
potionShockID = shockPotionId;
PotionShock.instance = new PotionShock(potionShockID, true, 11513861);
PotionShock.init();
int synthesisPotionId = potionSynthesisID;
if (Potion.potionTypes[synthesisPotionId] != null) {
synthesisPotionId = getNextPotionId(synthesisPotionId);
}
var4 = getNextPotionId(var4);
if (var4 >= 0) {
potionSynthesisID = var4;
PotionSynthesis.instance = new PotionSynthesis(potionSynthesisID, false, 3253280);
PotionSynthesis.init();
}
potionSynthesisID = synthesisPotionId;
PotionSynthesis.instance = new PotionSynthesis(potionSynthesisID, false, 3253280);
PotionSynthesis.init();
}
static int getNextPotionId(int start) {
@@ -3889,6 +3915,96 @@ public class ThaumicHorizons {
(new AspectList()).add(Aspect.WEAPON, 3).add(Aspect.BEAST, 3));
}
private static void registerDispenserBehavior() {
BlockDispenser.dispenseBehaviorRegistry
.putObject(Item.getItemFromBlock(blockAlchemite), new BehaviorDefaultDispenseItem() {
@Override
protected ItemStack dispenseStack(IBlockSource dispenser, ItemStack dispensedItem) {
EnumFacing enumfacing = BlockDispenser.func_149937_b(dispenser.getBlockMetadata());
World world = dispenser.getWorld();
int x = dispenser.getXInt() + enumfacing.getFrontOffsetX();
int y = dispenser.getYInt() + enumfacing.getFrontOffsetY();
int z = dispenser.getZInt() + enumfacing.getFrontOffsetZ();
EntityAlchemitePrimed primedAlchemite = new EntityAlchemitePrimed(
world,
x + 0.5F,
y + 0.5F,
z + 0.5F,
null);
world.spawnEntityInWorld(primedAlchemite);
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "game.tnt.primed", 1.0F, 1.0F);
dispensedItem.stackSize--;
return dispensedItem;
}
});
BlockDispenser.dispenseBehaviorRegistry.putObject(itemSyringeInjection, new BehaviorDefaultDispenseItem() {
@Override
public ItemStack dispenseStack(IBlockSource dispenser, ItemStack stack) {
if (!(stack.getItem() instanceof ItemSyringeInjection)) {
return super.dispenseStack(dispenser, stack);
}
World world = dispenser.getWorld();
EnumFacing facing = BlockDispenser.func_149937_b(dispenser.getBlockMetadata());
double spawnX = dispenser.getX() + facing.getFrontOffsetX();
double spawnY = dispenser.getY() + facing.getFrontOffsetY();
double spawnZ = dispenser.getZ() + facing.getFrontOffsetZ();
IProjectile projectile = createProjectile(
(ItemSyringeInjection) stack.getItem(),
stack,
world,
spawnX,
spawnY,
spawnZ);
projectile.setThrowableHeading(
facing.getFrontOffsetX(),
facing.getFrontOffsetY() + 0.1F,
facing.getFrontOffsetZ(),
1.1F, // velocity
6F // inaccuracy
);
world.spawnEntityInWorld((Entity) projectile);
stack.stackSize--;
return stack;
}
private IProjectile createProjectile(ItemSyringeInjection item, ItemStack stack, World world, double x,
double y, double z) {
if (item.isPhial(stack.getItemDamage())) {
return new EntityBlastPhial(world, x, y, z, stack);
} else {
return new EntitySyringe(world, x, y, z, stack.stackTagCompound);
}
}
@Override
protected void playDispenseSound(IBlockSource source) {
source.getWorld().playAuxSFX(1002, source.getXInt(), source.getYInt(), source.getZInt(), 0);
}
});
BlockDispenser.dispenseBehaviorRegistry.putObject(itemEggIncubated, new BehaviorProjectileDispense() {
protected IProjectile getProjectileEntity(World worldIn, IPosition position) {
return new EntityEggIncubated(worldIn, position.getX(), position.getY(), position.getZ());
}
});
BlockDispenser.dispenseBehaviorRegistry.putObject(
itemBoatGreatwood,
new BehaviorDispenseBoat(Collections.singleton(Material.water), EntityBoatGreatwood::new));
BlockDispenser.dispenseBehaviorRegistry.putObject(
itemBoatThaumium,
new BehaviorDispenseBoat(Sets.newHashSet(Material.water, Material.lava), EntityBoatThaumium::new));
}
static IRecipe shapelessOreDictRecipe(ItemStack res, Object[] params) {
ShapelessOreRecipe rec = new ShapelessOreRecipe(res, params);
CraftingManager.getInstance().getRecipeList().add(rec);
@@ -3916,6 +4032,32 @@ public class ThaumicHorizons {
warpedTumorValueProperty.comment = "Points of warp held by warped tumor.";
warpedTumorValueProperty.setRequiresMcRestart(true);
warpedTumorValue = warpedTumorValueProperty.getInt();
Property visboostPotionProperty = config.get("potions", "visboostPotionID", 24);
visboostPotionProperty.comment = "Potion ID for the VisBoost Potion";
visboostPotionProperty.setRequiresMcRestart(true);
potionVisBoostID = visboostPotionProperty.getInt();
Property visregenPotionProperty = config.get("potions", "visregenPotionID", 25);
visregenPotionProperty.comment = "Potion ID for the VisRegen Potion";
visregenPotionProperty.setRequiresMcRestart(true);
potionVisRegenID = visregenPotionProperty.getInt();
Property vacuumPotionProperty = config.get("potions", "vacuumPotionID", 26);
vacuumPotionProperty.comment = "Potion ID for the Vacuum";
vacuumPotionProperty.setRequiresMcRestart(true);
potionVacuumID = vacuumPotionProperty.getInt();
Property shockPotionProperty = config.get("potions", "shockPotionID", 27);
shockPotionProperty.comment = "Potion ID for the Shock Potion";
shockPotionProperty.setRequiresMcRestart(true);
potionShockID = shockPotionProperty.getInt();
Property synthesisPotionProperty = config.get("potions", "synthesisPotionID", 28);
synthesisPotionProperty.comment = "Potion ID for the Sythesis Potion";
synthesisPotionProperty.setRequiresMcRestart(true);
potionSynthesisID = synthesisPotionProperty.getInt();
config.save();
}
@@ -29,6 +29,7 @@ public class BlockAlchemite extends BlockTNT {
this.setBlockName("ThaumicHorizons_alchemite");
this.setBlockTextureName("ThaumicHorizons:alchemite");
this.setCreativeTab(ThaumicHorizons.tabTH);
this.setStepSound(soundTypeGrass); // same place/break sound as TNT
}
public void onBlockDestroyedByExplosion(final World p_149723_1_, final int p_149723_2_, final int p_149723_3_,
@@ -12,23 +12,27 @@ import net.minecraft.world.World;
public class EntityBlastPhial extends EntityPotion {
public EntityBlastPhial(final World p_i1790_1_) {
super(p_i1790_1_);
public EntityBlastPhial(final World world) {
super(world);
}
public EntityBlastPhial(final World p_i1790_1_, final EntityLivingBase p_i1790_2_, final float power,
final ItemStack p_i1790_3_) {
super(p_i1790_1_, p_i1790_2_, p_i1790_3_);
public EntityBlastPhial(final World world, final double x, final double y, final double z, final ItemStack stack) {
super(world, x, y, z, stack);
}
public EntityBlastPhial(final World world, final EntityLivingBase thrower, final float power,
final ItemStack stack) {
super(world, thrower, stack);
this.setSize(0.25f, 0.25f);
this.setSize(0.5f, 0.5f);
this.setLocationAndAngles(
p_i1790_2_.posX,
p_i1790_2_.posY + p_i1790_2_.getEyeHeight(),
p_i1790_2_.posZ,
p_i1790_2_.rotationYaw,
p_i1790_2_.rotationPitch);
thrower.posX,
thrower.posY + thrower.getEyeHeight(),
thrower.posZ,
thrower.rotationYaw,
thrower.rotationPitch);
this.posX -= MathHelper.cos(this.rotationYaw / 180.0f * (float) Math.PI) * 0.16f;
this.posY -= 0.10000000149011612;
this.posY -= 0.1;
this.posZ -= MathHelper.sin(this.rotationYaw / 180.0f * (float) Math.PI) * 0.16f;
this.setPosition(this.posX, this.posY, this.posZ);
this.yOffset = 0.0f;
@@ -39,6 +39,7 @@ import io.netty.buffer.ByteBuf;
public class EntitySyringe extends Entity implements IProjectile, IEntityAdditionalSpawnData {
public int color;
public int canBePickedUp;
public NBTTagCompound effects;
private boolean inGround;
private int field_145791_d;
@@ -50,7 +51,6 @@ public class EntitySyringe extends Entity implements IProjectile, IEntityAdditio
private int ticksInAir;
private int knockbackStrength;
private EntityLivingBase shootingEntity;
private int canBePickedUp;
private byte arrowShake;
private double damage;
@@ -146,6 +146,13 @@ public class EntitySyringe extends Entity implements IProjectile, IEntityAdditio
this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, p_i1756_3_ * 1.5f, 1.0f);
}
public EntitySyringe(World world, double x, double y, double z, NBTTagCompound effects) {
this(world, x, y, z);
this.effects = effects;
this.color = this.effects.getInteger("color");
this.canBePickedUp = 1;
}
public void writeEntityToNBT(final NBTTagCompound p_70014_1_) {
p_70014_1_.setTag("effects", this.effects);
p_70014_1_.setShort("xTile", (short) this.field_145791_d);
@@ -31,7 +31,7 @@ public class EntityAIHurtByTargetTH extends EntityAITargetTH {
this.field_142052_b = this.taskOwner.func_142015_aE();
if (this.entityCallsForHelp) {
final double d0 = this.getTargetDistance();
final List<EntityLiving> list = this.taskOwner.worldObj.getEntitiesWithinAABB(
final List<? extends EntityLiving> list = this.taskOwner.worldObj.getEntitiesWithinAABB(
this.taskOwner.getClass(),
AxisAlignedBB.getBoundingBox(
this.taskOwner.posX,
@@ -0,0 +1,66 @@
package com.kentington.thaumichorizons.common.handlers;
import java.util.Set;
import net.minecraft.block.BlockDispenser;
import net.minecraft.block.material.Material;
import net.minecraft.dispenser.BehaviorDefaultDispenseItem;
import net.minecraft.dispenser.IBlockSource;
import net.minecraft.entity.item.EntityBoat;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
public class BehaviorDispenseBoat extends BehaviorDefaultDispenseItem {
public interface BoatFactory {
EntityBoat create(World world, double x, double y, double z);
}
private final Set<Material> validMaterials;
private final BoatFactory boatFactory;
public BehaviorDispenseBoat(Set<Material> validMaterials, BoatFactory boatFactory) {
this.validMaterials = validMaterials;
this.boatFactory = boatFactory;
}
@Override
protected ItemStack dispenseStack(IBlockSource dispenser, ItemStack stack) {
EnumFacing facing = BlockDispenser.func_149937_b(dispenser.getBlockMetadata());
World world = dispenser.getWorld();
// Calculate spawn position slightly in front of the dispenser
double spawnX = dispenser.getX() + (facing.getFrontOffsetX() * 1.25F);
double spawnY = dispenser.getY() + (facing.getFrontOffsetY() * 1.125F) - 0.5F;
double spawnZ = dispenser.getZ() + (facing.getFrontOffsetZ() * 1.25F);
// Block coordinates in front of the dispenser
int targetX = dispenser.getXInt() + facing.getFrontOffsetX();
int targetY = dispenser.getYInt() + facing.getFrontOffsetY();
int targetZ = dispenser.getZInt() + facing.getFrontOffsetZ();
Material frontMaterial = world.getBlock(targetX, targetY, targetZ).getMaterial();
if (validMaterials.contains(frontMaterial)) {
spawnY++;
} else if (!Material.air.equals(frontMaterial)) {
return stack;
}
EntityBoat boat = boatFactory.create(world, spawnX, spawnY, spawnZ);
boat.rotationYaw = switch (facing) {
case NORTH -> 90.0F;
case WEST -> 180.0F;
case EAST -> 0.0F;
default -> -90.0F; // SOUTH or other
};
world.spawnEntityInWorld(boat);
stack.stackSize--;
return stack;
}
}
@@ -5,7 +5,6 @@
package com.kentington.thaumichorizons.common.lib;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -25,7 +24,6 @@ import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
@@ -69,7 +67,8 @@ import com.kentington.thaumichorizons.common.lib.networking.PacketPlayerInfusion
import com.kentington.thaumichorizons.common.tiles.TileSoulBeacon;
import com.kentington.thaumichorizons.common.tiles.TileVat;
import baubles.api.BaublesApi;
import baubles.common.container.InventoryBaubles;
import baubles.common.lib.PlayerHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.relauncher.Side;
@@ -82,6 +81,7 @@ import thaumcraft.common.config.ConfigBlocks;
import thaumcraft.common.config.ConfigItems;
import thaumcraft.common.entities.EntityAspectOrb;
import thaumcraft.common.entities.EntityFollowingItem;
import thaumcraft.common.entities.EntityPermanentItem;
import thaumcraft.common.items.relics.ItemHandMirror;
import thaumcraft.common.lib.network.fx.PacketFXShield;
import thaumcraft.common.lib.utils.EntityUtils;
@@ -678,6 +678,7 @@ public class EventHandlerEntity {
}
if (!event.entity.worldObj.isRemote && event.entity instanceof final EntityPlayer player
&& event.entityLiving.getHealth() - event.ammount <= 0.0f) {
// Clear player infusions
if (prop.tumorWarpPermanent > 0 || prop.tumorWarp > 0 || prop.tumorWarpTemp > 0) {
Thaumcraft.proxy.getPlayerKnowledge()
.addWarpPerm(event.entity.getCommandSenderName(), prop.tumorWarpPermanent);
@@ -687,150 +688,136 @@ public class EventHandlerEntity {
.addWarpTemp(event.entity.getCommandSenderName(), prop.tumorWarpTemp);
}
prop.resetPlayerInfusions();
final IInventory baubles = BaublesApi.getBaubles(player);
for (int a = 0; a < 4; ++a) {
final ItemStack amulet = baubles.getStackInSlot(a);
if (amulet != null) {
if (amulet.getItem() instanceof ItemAmuletMirror) {
boolean transportedSomething = false;
for (int i = 0; i < player.inventory.armorInventory.length; ++i) {
final ItemStack item = player.inventory.armorInventory[i];
if (item != null && ItemHandMirror.transport(amulet, item, player, player.worldObj)) {
transportedSomething = true;
player.inventory.armorInventory[i] = null;
}
}
for (int i = 0; i < player.inventory.mainInventory.length; ++i) {
final ItemStack item = player.inventory.mainInventory[i];
if (item != null && ItemHandMirror.transport(amulet, item, player, player.worldObj)) {
transportedSomething = true;
player.inventory.mainInventory[i] = null;
}
}
for (int b = 0; b < 4; ++b) {
if (a != b && baubles.getStackInSlot(b) != null
&& ItemHandMirror
.transport(amulet, baubles.getStackInSlot(b), player, player.worldObj)) {
transportedSomething = true;
baubles.setInventorySlotContents(b, null);
}
}
if (transportedSomething) {
PacketHandler.INSTANCE.sendToAllAround(
new PacketFXContainment(
player.posX,
player.posY + player.getEyeHeight(),
player.posZ),
new NetworkRegistry.TargetPoint(
player.worldObj.provider.dimensionId,
player.posX,
player.posY,
player.posZ,
32.0));
player.worldObj.playSoundEffect(
// Mirrored Amulet returning items
ItemStack amulet = null;
for (ItemStack bauble : PlayerHandler.getPlayerBaubles(player).stackList) {
if (bauble != null && bauble.getItem() instanceof ItemAmuletMirror) {
amulet = bauble;
break;
}
}
if (amulet != null) {
boolean transportedSomething = false;
for (int i = 0; i < player.inventory.armorInventory.length; ++i) {
final ItemStack item = player.inventory.armorInventory[i];
if (item != null && ItemHandMirror.transport(amulet, item, player, player.worldObj)) {
transportedSomething = true;
player.inventory.armorInventory[i] = null;
}
}
for (int i = 0; i < player.inventory.mainInventory.length; ++i) {
final ItemStack item = player.inventory.mainInventory[i];
if (item != null && ItemHandMirror.transport(amulet, item, player, player.worldObj)) {
transportedSomething = true;
player.inventory.mainInventory[i] = null;
}
}
InventoryBaubles baubles = PlayerHandler.getPlayerBaubles(player);
int amuletIndex = 0;
for (int i = 0; i < baubles.stackList.length; ++i) {
final ItemStack item = baubles.stackList[i];
if (item == amulet) {
amuletIndex = i;
} else if (item != null && ItemHandMirror.transport(amulet, item, player, player.worldObj)) {
transportedSomething = true;
baubles.stackList[i] = null;
}
}
PlayerHandler.setPlayerBaubles(player, baubles);
if (transportedSomething) {
baubles.stackList[amuletIndex] = null;
PlayerHandler.setPlayerBaubles(player, baubles);
PacketHandler.INSTANCE.sendToAllAround(
new PacketFXContainment(
player.posX,
player.posY + player.getEyeHeight(),
player.posZ,
"thaumcraft:craftfail",
1.0f,
1.0f);
baubles.setInventorySlotContents(a, null);
player.inventory.markDirty();
baubles.markDirty();
final ItemStack droppedPearl = new ItemStack(ConfigItems.itemEldritchObject, 1, 3);
final EntityItem drop = new EntityItem(
player.worldObj,
player.posZ),
new NetworkRegistry.TargetPoint(
player.worldObj.provider.dimensionId,
player.posX,
player.posY,
player.posZ,
droppedPearl);
player.worldObj.spawnEntityInWorld(drop);
break;
}
break;
}
32.0));
player.worldObj.playSoundEffect(
player.posX,
player.posY + player.getEyeHeight(),
player.posZ,
"thaumcraft:craftfail",
1.0f,
1.0f);
player.inventory.markDirty();
final ItemStack droppedPearl = new ItemStack(ConfigItems.itemEldritchObject, 1, 3);
final EntityPermanentItem drop = new EntityPermanentItem(
player.worldObj,
player.posX,
player.posY,
player.posZ,
droppedPearl);
player.worldObj.spawnEntityInWorld(drop);
}
}
}
if (!event.entity.worldObj.isRemote && event.entityLiving instanceof EntityPlayer
&& event.entityLiving.getHealth() - event.ammount <= 0.0f
&& event.entityLiving.getEntityData().getBoolean("soulBeacon")) {
final EntityPlayer player = (EntityPlayer) event.entity;
final int dim = player.getEntityData().getInteger("soulBeaconDim");
final World world = MinecraftServer.getServer().worldServerForDimension(dim);
final int x = player.getEntityData().getIntArray("soulBeaconCoords")[0];
final int y = player.getEntityData().getIntArray("soulBeaconCoords")[1];
final int z = player.getEntityData().getIntArray("soulBeaconCoords")[2];
if (world.getTileEntity(x, y, z) instanceof TileSoulBeacon
&& world.getTileEntity(x, y - 1, z) instanceof TileVat
&& ((TileVat) world.getTileEntity(x, y - 1, z)).mode == 4) {
event.setCanceled(true);
if (!world.isRemote) {
world.createExplosion(
// Return to Soul Beacon before death
if (player.getEntityData().getBoolean("soulBeacon")) {
final int dim = player.getEntityData().getInteger("soulBeaconDim");
final World beaconWorld = MinecraftServer.getServer().worldServerForDimension(dim);
final World playerWorld = player.worldObj;
final int x = player.getEntityData().getIntArray("soulBeaconCoords")[0];
final int y = player.getEntityData().getIntArray("soulBeaconCoords")[1];
final int z = player.getEntityData().getIntArray("soulBeaconCoords")[2];
if (beaconWorld.getTileEntity(x, y, z) instanceof TileSoulBeacon
&& beaconWorld.getTileEntity(x, y - 1, z) instanceof TileVat vat
&& vat.mode == 4) {
event.setCanceled(true);
event.ammount = 0.0f;
playerWorld.createExplosion(
null,
player.posX,
player.posY + player.getEyeHeight(),
player.posZ,
0.0f,
false);
for (int a2 = 0; a2 < 25; ++a2) {
final int xx = (int) player.posX + world.rand.nextInt(8) - world.rand.nextInt(8);
final int yy = (int) player.posY + world.rand.nextInt(8) - world.rand.nextInt(8);
final int zz = (int) player.posZ + world.rand.nextInt(8) - world.rand.nextInt(8);
if (world.isAirBlock(xx, yy, zz)) {
for (int i = 0; i < 25; ++i) {
final int xx = (int) player.posX + playerWorld.rand.nextInt(8) - playerWorld.rand.nextInt(8);
final int yy = (int) player.posY + playerWorld.rand.nextInt(8) - playerWorld.rand.nextInt(8);
final int zz = (int) player.posZ + playerWorld.rand.nextInt(8) - playerWorld.rand.nextInt(8);
if (playerWorld.isAirBlock(xx, yy, zz)) {
if (yy <= (int) player.posY + 1) {
world.setBlock(xx, yy, zz, ConfigBlocks.blockFluxGoo, 8, 3);
playerWorld.setBlock(xx, yy, zz, ConfigBlocks.blockFluxGoo, 8, 3);
} else {
world.setBlock(xx, yy, zz, ConfigBlocks.blockFluxGas, 8, 3);
playerWorld.setBlock(xx, yy, zz, ConfigBlocks.blockFluxGas, 8, 3);
}
}
}
}
player.inventory.dropAllItems();
final IInventory baubles2 = BaublesApi.getBaubles(player);
for (int j = 0; j < 4; ++j) {
if (baubles2.getStackInSlot(j) != null) {
final EntityItem bauble = new EntityItem(
world,
player.posX,
player.posY,
player.posZ,
baubles2.getStackInSlot(j));
world.spawnEntityInWorld(bauble);
baubles2.setInventorySlotContents(j, null);
player.inventory.dropAllItems();
for (ItemStack bauble : PlayerHandler.getPlayerBaubles(player).stackList) {
if (bauble == null) {
continue;
}
player.func_146097_a(bauble, true, false);
}
PlayerHandler.clearPlayerBaubles(player);
player.inventory.markDirty();
PacketHandler.INSTANCE.sendTo(new PacketNoMoreItems(), (EntityPlayerMP) player);
player.curePotionEffects(new ItemStack(Items.milk_bucket));
player.heal(Float.MAX_VALUE);
if (dim != player.worldObj.provider.dimensionId) {
player.travelToDimension(dim);
}
player.setPositionAndUpdate(x + 0.5, y - 2.5, z + 0.5);
Thaumcraft.proxy.blockSparkle(beaconWorld, x, y - 2, z, 16777215, 20);
Thaumcraft.proxy.blockSparkle(beaconWorld, x, y - 3, z, 16777215, 20);
beaconWorld.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "thaumcraft:whispers", 1.0f, beaconWorld.rand.nextFloat());
this.applyPlayerInfusions(player, vat);
vat.selfInfusions = new int[12];
vat.mode = 0;
vat.setEntityContained(player);
beaconWorld.getTileEntity(x, y - 1, z).markDirty();
player.worldObj.markBlockForUpdate(x, y - 1, z);
}
baubles2.markDirty();
player.inventory.markDirty();
PacketHandler.INSTANCE.sendTo(new PacketNoMoreItems(), (EntityPlayerMP) player);
player.curePotionEffects(new ItemStack(Items.milk_bucket));
player.heal(999.0f);
if (dim != player.worldObj.provider.dimensionId) {
player.travelToDimension(dim);
}
player.setPositionAndUpdate(x + 0.5, y - 2.5, z + 0.5);
Thaumcraft.proxy.blockSparkle(world, x, y - 2, z, 16777215, 20);
Thaumcraft.proxy.blockSparkle(world, x, y - 3, z, 16777215, 20);
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "thaumcraft:whispers", 1.0f, world.rand.nextFloat());
this.applyPlayerInfusions(player, (TileVat) world.getTileEntity(x, y - 1, z));
((TileVat) world.getTileEntity(x, y - 1, z)).selfInfusions = new int[12];
((TileVat) world.getTileEntity(x, y - 1, z)).mode = 0;
((TileVat) world.getTileEntity(x, y - 1, z)).setEntityContained(player);
world.getTileEntity(x, y - 1, z).markDirty();
player.worldObj.markBlockForUpdate(x, y - 1, z);
}
} else if (event.entity.worldObj.isRemote && event.entityLiving instanceof EntityPlayer
&& event.entityLiving.getHealth() - event.ammount <= 0.0f
&& event.entityLiving.getEntityData().getBoolean("soulBeacon")) {
final EntityPlayer player = (EntityPlayer) event.entity;
Arrays.fill(player.inventory.mainInventory, null);
Arrays.fill(player.inventory.armorInventory, null);
final IInventory baubles3 = BaublesApi.getBaubles(player);
baubles3.setInventorySlotContents(0, null);
baubles3.setInventorySlotContents(1, null);
baubles3.setInventorySlotContents(2, null);
baubles3.setInventorySlotContents(3, null);
}
}
}
void applyPlayerInfusions(final EntityPlayer player, final TileVat tile) {
@@ -222,8 +222,16 @@ public class ExplosionAlchemite extends Explosion {
if (block.getMaterial() == Material.air) {
continue;
}
final AspectList aspects = this
.getAspects(Item.getItemFromBlock(block), this.worldObj.getBlockMetadata(i, j, k));
Item item = Item.getItemFromBlock(block);
int meta = worldObj.getBlockMetadata(i, j, k);
if (item == null) {
item = block.getItemDropped(meta, worldObj.rand, 0);
}
if (item == null) {
continue;
}
final AspectList aspects = this.getAspects(item, meta);
if (aspects != null && aspects.size() > 0) {
for (final Aspect asp2 : aspects.getAspects()) {
final ItemStack stack = new ItemStack(
@@ -5,9 +5,9 @@
package com.kentington.thaumichorizons.common.lib.networking;
import net.minecraft.client.Minecraft;
import net.minecraft.inventory.IInventory;
import net.minecraft.client.entity.EntityClientPlayerMP;
import baubles.api.BaublesApi;
import baubles.common.lib.PlayerHandler;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
@@ -19,12 +19,9 @@ public class PacketNoMoreItems implements IMessage, IMessageHandler<PacketNoMore
@SideOnly(Side.CLIENT)
public IMessage onMessage(final PacketNoMoreItems message, final MessageContext ctx) {
Minecraft.getMinecraft().thePlayer.inventory.clearInventory(null, -1);
final IInventory baubles = BaublesApi.getBaubles(Minecraft.getMinecraft().thePlayer);
baubles.setInventorySlotContents(0, null);
baubles.setInventorySlotContents(1, null);
baubles.setInventorySlotContents(2, null);
baubles.setInventorySlotContents(3, null);
EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer;
player.inventory.clearInventory(null, -1);
PlayerHandler.clearPlayerBaubles(player);
return null;
}
@@ -9,7 +9,6 @@ import java.util.ArrayList;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
@@ -435,16 +434,22 @@ public class TileSyntheticNode extends TileVisNode implements INode, IWandable {
}
public void addEssence(final EntityPlayer player) {
final Item essence = player.getHeldItem().getItem();
if (essence == ConfigItems.itemWispEssence
&& ((ItemWispEssence) essence).getAspects(player.getHeldItem()) != null
&& ((ItemWispEssence) essence).getAspects(player.getHeldItem()).getAspects().length > 0) {
final Aspect asp = ((ItemWispEssence) essence).getAspects(player.getHeldItem()).getAspects()[0];
this.aspectsMax.add(asp, 4);
final ItemStack heldItem = player.getHeldItem();
// just in case
if (heldItem == null) return;
if (heldItem.stackSize == 0) return;
if (heldItem.getItem() instanceof ItemWispEssence essence && essence == ConfigItems.itemWispEssence) {
if (essence.getAspects(heldItem) == null) return;
var aspectList = essence.getAspects(heldItem).getAspects();
if (aspectList == null || aspectList.length == 0) return;
final Aspect asp = aspectList[0];
this.aspectsMax.add(asp, 4 * heldItem.stackSize);
this.aspects.add(asp, 0);
this.fractionalAspects.add(asp, 0);
final ItemStack heldItem = player.getHeldItem();
--heldItem.stackSize;
heldItem.stackSize = 0;
this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord);
this.markDirty();
}
@@ -231,7 +231,7 @@ public class TileTransductionAmplifier extends TileThaumcraft {
}
}
if (transducers > 1 && this.count % 50 == 0) {
final List<Entity> targets = (List<Entity>) this.worldObj.getEntitiesWithinAABB(
final List<EntityLivingBase> targets = this.worldObj.getEntitiesWithinAABB(
EntityLivingBase.class,
AxisAlignedBB.getBoundingBox(
this.xCoord,
@@ -240,7 +240,7 @@ public class TileTransductionAmplifier extends TileThaumcraft {
this.xCoord + 1,
this.yCoord + 1,
this.zCoord + 1).expand(10.0, 10.0, 10.0));
if (targets != null && targets.size() > 0) {
if (targets != null && !targets.isEmpty()) {
for (final Entity target : targets) {
PacketHandler.INSTANCE.sendToAllAround(
new PacketFXBlockZap(
@@ -1048,7 +1048,7 @@ public class TileVat extends TileThaumcraft implements IAspectContainer, IEssent
}
private void inEvZap(final boolean all) {
final List<Entity> targets = (List<Entity>) this.worldObj.getEntitiesWithinAABB(
final List<EntityLivingBase> targets = this.worldObj.getEntitiesWithinAABB(
EntityLivingBase.class,
AxisAlignedBB.getBoundingBox(
this.xCoord,
@@ -1057,7 +1057,7 @@ public class TileVat extends TileThaumcraft implements IAspectContainer, IEssent
this.xCoord + 1,
this.yCoord + 1,
this.zCoord + 1).expand(10.0, 10.0, 10.0));
if (targets != null && targets.size() > 0) {
if (targets != null && !targets.isEmpty()) {
for (final Entity target : targets) {
thaumcraft.common.lib.network.PacketHandler.INSTANCE.sendToAllAround(
new PacketFXBlockZap(
@@ -62,6 +62,7 @@ public class TileVortex extends TileThaumcraft implements IWandable, IAspectCont
public boolean cheat;
public ArrayList<ItemStack> items;
Thread ppThread;
private boolean soundStarted = false;
public TileVortex() {
this.aspects = new AspectList();
@@ -77,6 +78,11 @@ public class TileVortex extends TileThaumcraft implements IWandable, IAspectCont
public void updateEntity() {
super.updateEntity();
if (this.worldObj != null && this.worldObj.isRemote && !soundStarted) {
ThaumicHorizons.proxy.playVortexSound(this);
soundStarted = true;
}
if (this.generating) {
this.worldObj.createExplosion(
null,
@@ -572,4 +578,23 @@ public class TileVortex extends TileThaumcraft implements IWandable, IAspectCont
public int containerContains(final Aspect tag) {
return 0;
}
@Override
public void invalidate() {
super.invalidate();
stopSound();
}
@Override
public void onChunkUnload() {
super.onChunkUnload();
stopSound();
}
private void stopSound() {
if (this.worldObj != null && this.worldObj.isRemote) {
ThaumicHorizons.proxy.stopVortexSound(this);
}
soundStarted = false;
}
}
@@ -296,7 +296,7 @@ healingVatContainment= §nContainment Focus Unlocked§r<IMG>thaumichorizons:
tc.research_name.infusionVat=Creature Infusion
tc.research_text.infusionVat=Harder, faster, stronger
infusionVat1=To infuse a living creature would be an unprecedented feat: thaumaturgic texts are filled with cautionary tales of grotesque deformities as the creature's body rejects the foreign magic. Your curative vats may finally allow this procedure to succeed by suspending the organism's vital functions while the infusion is applied.<BR>You must first install a modified runic matrix atop the vat. This is more difficult than it sounds, as attempting to infuse a runic matrix produces considerable magical feedback between the two matrices. The prudent thaumaturge would ensure that her altar is well-prepared.
infusionVat2=Once the infusion vat has been set up, its operation is almost identical to the standard infusion altar, although essentia must be piped in directly.<BR>The process is somewhat riskier than infusing inanimate matter, however. In addition to the usual effects, accumulated instability will damage the subject. Worse, the process cannot be aborted; it will end in either success or death.<BR>Less hardy creatures may not survive complex infusions without outside help. Your experiments have shown that providing a combination of §3Aqua§0, §7Ordo§0, and §2Terra§0 centivis can slow the rate of injury.
infusionVat2=Once the infusion vat has been set up, its operation is almost identical to that of the standard infusion altar, although essentia must be piped in directly.<BR>The process is somewhat riskier than infusing inanimate matter, however. In addition to the usual effects, accumulated instability will damage the subject. Worse, the process cannot be aborted; it will end in either success or death.<BR>Less hardy creatures may not survive complex infusions without outside help. Your experiments have shown that providing a combination of §3Aqua§0, §7Ordo§0, and §2Terra§0 centivis can slow the rate of injury.
infusionVat3=The infusion vat has a few limitations. Chief among them is the fact that humans (and other sentient beings) cannot be infused, as the human soul actively interferes with the addition of magical energy. Likewise, creatures of an already magical nature such as undead and golems will not be affected.<BR>Also, while a given creature can have any number of general infusions, it may possess only one species-specific infusion.<BR>Unfortunately, infused creatures do not pass on their infusions to offspring.
infusionVatClone= §nIncarnation Unlocked§r<BR>Your incarnation procedure can clone infused creatures. This requires additional essentia; you will need to supply the sum of every aspect from each infusion that the creature was subjected to.<BR>Curiously, the blood sample provides such a complete pattern for the developing organism that no instability is generated and no physical objects are required, making cloning a very efficient way of propagating your creations.
tc.research_name.generalInfusion=General Infusions
@@ -483,15 +483,15 @@ tc.research_text.chameleonSkin=Now you see me...
chameleonSkin1=Whether sneaking into a rival's laboratory or taking notes on the life cycle of the eldritch crab, there are times when you'd like to remain unobserved. Perhaps you can come up with a more permanent solution than chugging invisibility potions?<BR>The §5Chameleon Skin§0 infusion implants magical pigments and microscopic eyes into your skin, reflexively altering its color to match objects on the opposite side. The effect is much like constant invisibility, including its inability to hide armor.<BR>This effect can be toggled using the X key.
tc.research_name.tumorOops=Eldritch Apotheosis
tc.research_text.tumorOops=All is the Pattern
tumorOops1=You believed you had mastered your world and everything upon it. You fool.<BR>It is finally clear. The Eldritch are not beings in the ordinary sense, not crude things of meat and blood and bone like yourself. They are a pattern written in the stars, in the currents and eddies of magic, encoded deep in the structure of life itself.<BR>But the Pattern is fragmented, sundered and spread throughout the cosmos by some primordial catacylsm which can only be guessed at. It has sought to reassemble itself since the dawn of time, and now you have played your role in its life cycle.
tumorOops2=All of your studies, your creations, your journeys have served the Pattern. Learning the laws of magic invited it into your mind. Crafting forbidden artifacts allowed it to replicate itself into physical matter. And once you survived the trials of the Outer Lands, the Pattern judged you to have accumulated enough of itself.<BR>Enough to craft into a greater being. The next stage of its life cycle.<BR>But you still live. Perhaps it is not too late. Perhaps you can understand more of the Pattern- perhaps you can still stop it-<BR>Or incubate more. So many more.
tumorOops1=You believed you had mastered your world and everything upon it. You fool.<BR>It is finally clear. The Eldritch are not beings in the ordinary sense, not crude things of meat and blood and bone like yourself. They are a pattern written in the stars, in the currents and eddies of magic, encoded deep in the structure of life itself.<BR>But the Pattern is fragmented, sundered and spread throughout the cosmos by some primordial cataclysm which can only be guessed at. It has sought to reassemble itself since the dawn of time, and now you have played your role in its life cycle.
tumorOops2=All of your studies, your creations, your journeys have served the Pattern. Learning the laws of magic invited it into your mind. Crafting forbidden artifacts allowed it to replicate itself into physical matter. And once you survived the trials of the Outer Lands, the Pattern judged you to have accumulated enough of itself.<BR>Enough to craft into a greater being. The next stage of its life cycle.<BR>But you still live. Perhaps it is not too late. Perhaps you can understand more of the Pattern - perhaps you can still stop it-<BR>Or incubate more. So many more.
tc.research_name.construction=Arcane Construction
tc.research_text.construction=Don't tell the golems' union
construction1=TODO
tc.research_name.planarTheory=Planar Theory
tc.research_text.planarTheory=Deeper and deeper
planarTheory1=The cosmos is vaster and more varied than you could have imagined, but certain patterns are starting to emerge. Most importantly, you finally understand what lies between the planes.<BR>It is not a void in the traditional sense, for even the emptiest places are subject to the laws of space and time. Rather, the interplanar substance could be described as frozen possibility - infinite potential with nothing to act upon. Only when it leaks through an aura node in the form of vis, into a world with established natural law, can this potential be actualized.<BR>Such is the root of all magic.
planarTheory2=Of course, understanding this from an academic perspective is very different from being able to put it into practice. So far, all of your attempts to develop synthetic aura nodes have met with failure. Something is still missing...<BR>One offshoot of this research may warrant further study, however. By shattering an ender pearl, filling the resulting tesseract with ethereal essence, and encasing the structure in voidmetal you have created a remarkably stable device capable of manipulating rips in spacetime.<BR>Perhaps you will find some use for it.
planarTheory2=Of course, understanding this from an academic perspective is very different from being able to put it into practice. So far, all of your attempts to develop synthetic aura nodes have met with failure. Something is still missing...<BR>One offshoot of this research may warrant further study, however. By shattering an ender pearl, filling the resulting tesseract with ethereal essence, and encasing the structure in voidmetal, you have created a remarkably stable device capable of manipulating rips in spacetime.<BR>Perhaps you will find some use for it.
tc.research_name.transductionAmplifier=Transduction Amplifier
tc.research_text.transductionAmplifier=Full power!
transductionAmplifier1=Without outside interference, an aura node accumulates vis in short spurts as its dimensional breach fluctuates in size. Your node transducers can hold a node open at its largest natural diameter, but actually expanding the breach was not possible until recent advances in planar theory.<BR>You have developed a device which creates spatial turbulence, allowing microscopic rips to merge with an existing energized node. Attaching a transduction amplifier to one's side and applying a redstone signal can increase its centivis output as though the original node had ten additional vis per aspect.
@@ -515,7 +515,7 @@ planarRift2=This is unfortunate - an extremely high-vis node might have containe
planarRift3=And what then? Passing matter into the void would immerse it in a sea of endless vis, without grinding it down to its base aspects like an ordinary hungry node. Who can imagine what staggering works of thaumaturgy could be accomplished with this resource at hand?<BR>You imagine there will be severe limitations - most materials will still not survive immersion - but you already understand the basic nature of the process. By right-clicking a rift with your wand, you can tug on ethereal currents and retrieve any surviving objects.<BR>It is now time to determine what can be crafted in this manner...
tc.research_name.wispSpawn=Wisp Propagation
tc.research_text.wispSpawn=Kicking the hornet's nest
wispSpawn1=Casting a pile of salis mundus into a stabilized rift has a curious result: the salt grains absorb enough vis to resonate with one another and clump together into a quasi-living being.<BR>These artificially generated wisps are almost identical to the ones which naturally grow in magical environs. Note that the wisps' aspects will depend on which aspects were present in the parent node.<BR>The number of wisps generated is highly variable, and an incautious thamaturge can find himself quickly overwhelmed.
wispSpawn1=Casting a pile of salis mundus into a stabilized rift has a curious result: the salt grains absorb enough vis to resonate with one another and clump together into a quasi-living being.<BR>These artificially generated wisps are almost identical to the ones which naturally grow in magical environs. Note that the wisps' aspects will depend on which aspects were present in the parent node.<BR>The number of wisps generated is highly variable, and an incautious thaumaturge can find himself quickly overwhelmed.
tc.research_name.crystalWand=Crystalline Wand
tc.research_text.crystalWand=Disposable magic
crystalWand1=All advanced wands incorporate shards into their design, but only for the purpose of amplifying another material's ability to store vis. On their own, shards are wholly incapable of absorbing additional magic and so cannot drain an aura node - but what if you were to take them straight to the source?<BR>By constructing a wandlike arrangement of crystals and passing it into the void, you have created a curious device - a wand with tremendous vis capacity but no ability to ever recharge itself. Perhaps it could be used to craft objects unattainable with traditional wands.
@@ -0,0 +1,15 @@
{
"vortex": {
"category": "ambient",
"sounds": [
{ "name": "thaumichorizons:vortex", "stream": true }
]
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 849 B

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 B

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 B

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 B

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 726 B

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 971 B

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 B

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 579 B

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 638 B

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 B

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 681 B

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 B

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 B

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 990 B

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 765 B

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 585 B

Loaded 100 of 295 files, more files were not shown because too many files have changed in this diff. Show more