Merge branch 'master' into fix/manipulator

This commit is contained in:
Martin Robertz authored and GitHub committed 2026-11-11 18:46:53 +01:00
commit 02b59e392d
340 files changed
+394 -184

No files matched your search

+2 -2
View File
@@ -3,9 +3,9 @@ name: Build and test
on:
pull_request:
branches: [ master, main ]
branches: [ master, main, release/** ]
push:
branches: [ master, main ]
branches: [ master, main, release/** ]
jobs:
build-and-test:
+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
+8 -5
View File
@@ -1,13 +1,16 @@
// Add your dependencies here
dependencies {
api("com.github.GTNewHorizons:GTNHLib:0.9.47:dev")
api('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev')
api('com.github.GTNewHorizons:DummyCore:1.20.0:dev')
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.95:dev') {transitive=false}
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.341:dev') {transitive=false}
compileOnly('curse.maven:automagy-222153:2285272')
compileOnly('com.github.GTNewHorizons:EnderIO:2.10.21:dev')
runtimeOnly("com.github.GTNewHorizons:NotEnoughItems:2.8.26-GTNH:dev")
runtimeOnly("com.github.GTNewHorizons:waila:1.9.7:dev")
runtimeOnly('com.github.GTNewHorizons:Baubles:1.0.4:dev')
runtimeOnly('com.github.GTNewHorizons:CodeChickenCore:1.4.7:dev') // Required to allow dummycore to run in dev
runtimeOnly("com.github.GTNewHorizons:NotEnoughItems:2.8.73-GTNH:dev")
runtimeOnly("com.github.GTNewHorizons:waila:1.19.22:dev")
runtimeOnly('com.github.GTNewHorizons:Baubles-Expanded:2.2.9-GTNH:dev')
runtimeOnly('com.github.GTNewHorizons:CodeChickenCore:1.4.11:dev') // Required to allow dummycore to run in dev
}
+35 -3
View File
@@ -39,9 +39,33 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
enableModernJavaSyntax = true
# Enables modern Java syntax support. Valid values:
# - false: No modern syntax, Java 8 only
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
# - modern: Native modern Java bytecode, no downgrading
enableModernJavaSyntax = jabel
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
# and should *not* be used in most situations. -1 disables this.
# forceToolchainVersion = -1
# Target JVM version for JVM Downgrader bytecode downgrading.
# Only used when enableModernJavaSyntax = jvmDowngrader
# downgradeTargetVersion = 8
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
# Classes will be available in META-INF/versions/N/ for each version N in this list.
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
# jvmDowngraderMultiReleaseVersions = 21,25
# Specifies how JVM Downgrader API stubs are provided. Options:
# - shade: Shade minimized stubs into the jar
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
# - external: Another dependency provides stubs (no constraint, no warning)
# - (empty): Warning reminding you to configure stubs
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
# jvmDowngraderStubsProvider =
# 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.
@@ -162,6 +186,11 @@ modrinthRelations =
# Leave this empty if you don't want to publish on CurseForge.
curseForgeProjectId =
# Comma-separated supported CurseForge environments: client, server (case-insensitive).
# Use client or server for mods that only support one environment. Defaults to client,server.
# These tags describe where the mod can run, not whether installation is required on both sides.
curseForgeEnvironments = client,server
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
# Syntax: type1:name1;type2:name2;...
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
@@ -209,3 +238,6 @@ customArchiveBaseName = Thaumic-Based
# This is meant to be set in $HOME/.gradle/gradle.properties.
# ideaCheckSpotlessOnBuild = true
# Non-GTNH properties
org.gradle.configuration-cache = true
org.gradle.parallel = true
+12
View File
@@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9064f22734b42ac03e85df04b632e167/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/4d0277c49991306ac78048580fe34bcf/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a9fa3b809e484a1e1ac4308a5dda661a/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/aa99913fa6d767d899ffc96082da01ca/redirect
toolchainVersion=25
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+2 -5
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
Vendored
+1 -2
View File
@@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.48'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.34'
}
@@ -22,6 +22,7 @@ import org.lwjgl.opengl.GL11;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import tb.common.inventory.ContainerThaumicAnvil;
import tb.utils.TBConfig;
@SideOnly(Side.CLIENT)
public class GuiThaumicAnvil extends GuiContainer implements ICrafting {
@@ -79,6 +80,10 @@ public class GuiThaumicAnvil extends GuiContainer implements ICrafting {
GL11.glDisable(GL11.GL_BLEND);
this.fontRendererObj.drawString(I18n.format("container.repair", new Object[0]), 60, 6, 4210752);
if (TBConfig.modernAnvilGui) {
this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 94, 0x404040);
}
if (this.field_147092_v.maximumCost > 0) {
int k = 8453920;
boolean flag = true;
@@ -96,7 +101,11 @@ public class GuiThaumicAnvil extends GuiContainer implements ICrafting {
k = 16736352;
}
if (flag) {
if (flag && TBConfig.modernAnvilGui) {
int x = this.xSize - 10 - this.fontRendererObj.getStringWidth(s);
drawRect(x - 2, 67, this.xSize - 8, 79, 0x4F000000);
this.fontRendererObj.drawStringWithShadow(s, x, 69, k);
} else if (flag) {
int l = -16777216 | (k & 16579836) >> 2 | k & -16777216;
int i1 = this.xSize - 8 - this.fontRendererObj.getStringWidth(s);
byte b0 = 67;
+10 -1
View File
@@ -22,6 +22,7 @@ import org.lwjgl.opengl.GL11;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import tb.common.inventory.ContainerVoidAnvil;
import tb.utils.TBConfig;
@SideOnly(Side.CLIENT)
public class GuiVoidAnvil extends GuiContainer implements ICrafting {
@@ -78,6 +79,10 @@ public class GuiVoidAnvil extends GuiContainer implements ICrafting {
GL11.glDisable(GL11.GL_BLEND);
this.fontRendererObj.drawString(I18n.format("container.repair", new Object[0]), 60, 6, 4210752);
if (TBConfig.modernAnvilGui) {
this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 94, 0x404040);
}
if (this.field_147092_v.maximumCost > 0) {
int k = 8453920;
boolean flag = true;
@@ -95,7 +100,11 @@ public class GuiVoidAnvil extends GuiContainer implements ICrafting {
k = 16736352;
}
if (flag) {
if (flag && TBConfig.modernAnvilGui) {
int x = this.xSize - 10 - this.fontRendererObj.getStringWidth(s);
drawRect(x - 2, 67, this.xSize - 8, 79, 0x4F000000);
this.fontRendererObj.drawStringWithShadow(s, x, 69, k);
} else if (flag) {
int l = -16777216 | (k & 16579836) >> 2 | k & -16777216;
int i1 = this.xSize - 8 - this.fontRendererObj.getStringWidth(s);
byte b0 = 67;
@@ -53,6 +53,24 @@ public class BlockOverchanter extends BlockContainer {
return new TileOverchanter();
}
@Override
public void onNeighborBlockChange(World worldIn, int x, int y, int z, Block neighbor) {
boolean powered = worldIn.isBlockIndirectlyGettingPowered(x, y, z)
|| worldIn.isBlockIndirectlyGettingPowered(x, y - 1, z);
int meta = worldIn.getBlockMetadata(x, y, z);
boolean metaUnpowered = (meta & 8) == 0;
if (powered && metaUnpowered) {
if (worldIn.getTileEntity(x, y, z) instanceof TileOverchanter teo) {
teo.tryStartEnchanting();
}
worldIn.setBlockMetadataWithNotify(x, y, z, meta | 8, 4);
return;
}
if (powered || metaUnpowered) return;
worldIn.setBlockMetadataWithNotify(x, y, z, meta & -9, 4);
}
public void breakBlock(World w, int x, int y, int z, Block b, int meta) {
MiscUtils.dropItemsOnBlockBreak(w, x, y, z, b, meta);
}
@@ -18,7 +18,6 @@ import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import DummyCore.Utils.MathUtils;
import DummyCore.Utils.MiscUtils;
import tb.utils.TBUtils;
import thaumcraft.api.damagesource.DamageSourceThaumcraft;
import thaumcraft.api.entities.ITaintedMob;
@@ -32,6 +31,7 @@ import thaumcraft.common.config.ConfigItems;
import thaumcraft.common.lib.network.PacketHandler;
import thaumcraft.common.lib.network.playerdata.PacketResearchComplete;
import thaumcraft.common.lib.research.ResearchManager;
import thaumcraft.common.lib.utils.Utils;
import thaumcraft.common.lib.world.ThaumcraftWorldGenerator;
public class ItemConcentratedTaint extends Item {
@@ -55,7 +55,7 @@ public class ItemConcentratedTaint extends Item {
int dX = x + MathHelper.floor_double(MathUtils.randomDouble(w.rand) * 16);
int dZ = z + MathHelper.floor_double(MathUtils.randomDouble(w.rand) * 16);
int dY = y + w.rand.nextInt(2) - w.rand.nextInt(2);
MiscUtils.changeBiome(w, ThaumcraftWorldGenerator.biomeTaint, dX, dZ);
Utils.setBiomeAt(w, dX, dZ, ThaumcraftWorldGenerator.biomeTaint);
if (w.isBlockNormalCubeDefault(dX, dY - 1, dZ, false) && w.getBlock(dX, dY, dZ)
.isReplaceable(w, dX, dY, dZ)) {
w.setBlock(dX, dY, dZ, ConfigBlocks.blockTaintFibres, 0, 3);
@@ -100,14 +100,14 @@ public class TileNodeLinker extends TileEntity implements IWandable {
(float) eZ);
if (syncTimer % 10 == 0 && !this.worldObj.isRemote) {
TileNode reciever = (TileNode) this.worldObj.getTileEntity(xCoord, yCoord - 1, zCoord);
TileNode receiver = (TileNode) this.worldObj.getTileEntity(xCoord, yCoord - 1, zCoord);
TileNode transmitter = (TileNode) this.worldObj.getTileEntity(x, y - 1, z);
boolean isPushPerm = this.worldObj.rand.nextDouble() < 0.3D ? true
: transmitter.getAspects()
.visSize() > 0 ? false : true;
AspectList pullFrom = isPushPerm ? transmitter.getAspectsBase()
: transmitter.getAspects();
AspectList pushTo = isPushPerm ? reciever.getAspectsBase() : reciever.getAspects();
AspectList pushTo = isPushPerm ? receiver.getAspectsBase() : receiver.getAspects();
if (pullFrom.visSize() <= 0) {
this.worldObj.setBlockToAir(x, y - 1, z);
return;
@@ -118,7 +118,7 @@ public class TileNodeLinker extends TileEntity implements IWandable {
if (this.worldObj.rand.nextDouble() <= 0.7D) {
if (instabilityCheck()) {
pushTo.add(randomAspect, 1);
reciever.getAspects()
receiver.getAspects()
.add(randomAspect, 1);
}
pullFrom.reduce(randomAspect, 1);
@@ -128,7 +128,7 @@ public class TileNodeLinker extends TileEntity implements IWandable {
++instability;
} else {
if (pushTo.getAmount(randomAspect) > 0
&& pushTo.getAmount(randomAspect) <= reciever.getAspectsBase()
&& pushTo.getAmount(randomAspect) <= receiver.getAspectsBase()
.getAmount(randomAspect)) {
if (instabilityCheck()) pushTo.add(randomAspect, 1);
@@ -140,7 +140,7 @@ public class TileNodeLinker extends TileEntity implements IWandable {
}
transmitter.markDirty();
reciever.markDirty();
receiver.markDirty();
this.worldObj.markBlockForUpdate(x, y - 1, z);
this.worldObj.markBlockForUpdate(xCoord, yCoord - 1, zCoord);
}
@@ -364,7 +364,7 @@ public class TileNodeLinker extends TileEntity implements IWandable {
paramItemStack.getTagCompound()
.removeTag("linkCoordZ");
if (paramWorld.isRemote) paramEntityPlayer
.addChatMessage(new ChatComponentText(StatCollector.translateToLocal("tb.txt.linkEstabilished")));
.addChatMessage(new ChatComponentText(StatCollector.translateToLocal("tb.txt.linkEstablished")));
return paramItemStack;
}
+230 -137
View File
@@ -1,13 +1,14 @@
package tb.common.tile;
import java.util.Iterator;
import java.util.LinkedHashMap;
import static tb.core.TBCore.isAutomagyLoaded;
import static tb.core.TBCore.isEioLoaded;
import java.util.List;
import java.util.Set;
import java.util.Map;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
@@ -16,25 +17,32 @@ import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import com.gtnewhorizon.gtnhlib.geometry.CubeIterator;
import DummyCore.Utils.MathUtils;
import DummyCore.Utils.MiscUtils;
import crazypants.enderio.machine.obelisk.xp.TileExperienceObelisk;
import crazypants.enderio.xp.ExperienceContainer;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.wands.IWandable;
import thaumcraft.common.lib.events.EssentiaHandler;
import tuhljin.automagy.tiles.TileEntityJarXP;
public class TileOverchanter extends TileEntity implements IInventory, IWandable {
public class TileOverchanter extends TileEntity implements ISidedInventory, IWandable {
public ItemStack inventory;
public int enchantingTime;
public boolean xpAbsorbed;
public int enchantingTicks;
public int xpToAbsorb;
public boolean isEnchantingStarted;
public int syncTimer;
// public Lightning renderedLightning;
public static final int xp30lv = 825;
public static final String overchantsNbtTag = "overchants";
public static final int nbtIntArrayType = 11;
@Override
public int getSizeInventory() {
@@ -42,146 +50,133 @@ public class TileOverchanter extends TileEntity implements IInventory, IWandable
}
@Override
@SuppressWarnings("unchecked")
public void updateEntity() {
if (!worldObj.isRemote) {
if (syncTimer <= 0) {
syncTimer = 100;
NBTTagCompound tg = new NBTTagCompound();
tg.setInteger("0", enchantingTime);
tg.setBoolean("1", xpAbsorbed);
tg.setBoolean("2", isEnchantingStarted);
tg.setInteger("x", xCoord);
tg.setInteger("y", yCoord);
tg.setInteger("z", zCoord);
MiscUtils.syncTileEntity(tg, 0);
} else--syncTimer;
if (worldObj.isRemote) {
return;
}
if (this.inventory == null) {
isEnchantingStarted = false;
xpAbsorbed = false;
enchantingTime = 0;
// renderedLightning = null;
} else {
if (this.isEnchantingStarted) {
if (this.worldObj.getTotalWorldTime() % 20 == 0) {
// renderedLightning = new Lightning(this.worldObj.rand, new Coord3D(0,0,0), new
// Coord3D(MathUtils.randomDouble(this.worldObj.rand)/50,MathUtils.randomDouble(this.worldObj.rand)/50,MathUtils.randomDouble(this.worldObj.rand)/50),
// 0.3F, 1,0,1);
this.worldObj
.playSoundEffect(this.xCoord, this.yCoord, this.zCoord, "thaumcraft:infuserstart", 1F, 1.0F);
if (EssentiaHandler.drainEssentia(this, Aspect.MAGIC, ForgeDirection.UNKNOWN, 8, false)) {
++enchantingTime;
if (enchantingTime >= 16 && !this.xpAbsorbed) {
List<EntityPlayer> players = this.worldObj.getEntitiesWithinAABB(
EntityPlayer.class,
AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord + 1, yCoord + 1, zCoord + 1)
.expand(6, 3, 6));
if (!players.isEmpty()) {
for (int i = 0; i < players.size(); ++i) {
EntityPlayer p = players.get(i);
if (p.experienceLevel >= 30) {
p.attackEntityFrom(DamageSource.magic, 8);
this.worldObj
.playSoundEffect(p.posX, p.posY, p.posZ, "thaumcraft:zap", 1F, 1.0F);
p.experienceLevel -= 30;
xpAbsorbed = true;
break;
}
}
}
}
if (xpAbsorbed && enchantingTime >= 32) {
xpToAbsorb = xp30lv; // 30 levels
enchantingTicks = 0;
return;
}
if (this.isEnchantingStarted) {
if (enchantingTicks % 20 == 0) {
this.worldObj
.playSoundEffect(this.xCoord, this.yCoord, this.zCoord, "thaumcraft:infuserstart", 1F, 1.0F);
if (EssentiaHandler.drainEssentia(this, Aspect.MAGIC, ForgeDirection.UNKNOWN, 8, false)) {
// +1 is needed to exactly mimic original timings and not use extra 1 essentia (should be 32 in
// perfect conditions)
int enchantingSeconds = enchantingTicks / 20 + 1;
// the values being checked against are the second milestones in the enchanting process
if (enchantingSeconds >= 16) {
if (xpToAbsorb != 0) absorbXP();
if (enchantingSeconds >= 32 && xpToAbsorb == 0) {
int enchId = this.findEnchantment(inventory);
NBTTagList nbttaglist = this.inventory.getEnchantmentTagList();
for (int i = 0; i < nbttaglist.tagCount(); ++i) {
NBTTagCompound tag = nbttaglist.getCompoundTagAt(i);
if (tag != null && Integer.valueOf(tag.getShort("id")) == enchId) {
tag.setShort("lvl", (short) (Integer.valueOf(tag.getShort("lvl")) + 1));
NBTTagCompound stackTag = MiscUtils.getStackTag(inventory);
if (!stackTag.hasKey("overchants")) {
stackTag.setIntArray("overchants", new int[] { enchId });
} else {
int[] arrayInt = stackTag.getIntArray("overchants");
int[] newArrayInt = new int[arrayInt.length + 1];
for (int j = 0; j < arrayInt.length; ++j) {
newArrayInt[j] = arrayInt[j];
}
newArrayInt[newArrayInt.length - 1] = enchId;
stackTag.setIntArray("overchants", newArrayInt);
}
break;
}
}
increaseEnchantmentLevel(enchId);
addOverchantId(enchId);
isEnchantingStarted = false;
xpAbsorbed = false;
enchantingTime = 0;
// renderedLightning = null;
xpToAbsorb = xp30lv;
enchantingTicks = 0;
this.worldObj
.playSoundEffect(this.xCoord, this.yCoord, this.zCoord, "thaumcraft:wand", 1F, 1F);
return;
}
} else {
--enchantingTime;
}
} else {
enchantingTicks -= 20;
}
}
enchantingTicks += 1;
}
}
public boolean canStartEnchanting() {
if (!this.isEnchantingStarted) if (this.inventory != null) {
if (this.inventory.getEnchantmentTagList() != null && this.inventory.getEnchantmentTagList()
.tagCount() > 0) {
if (findEnchantment(inventory) != -1) {
return true;
}
}
private void increaseEnchantmentLevel(int enchantmentId) {
Map<Integer, Integer> enchantments = EnchantmentHelper.getEnchantments(this.inventory);
int newLevel = MathHelper.clamp_int(enchantments.get(enchantmentId) + 1, 1, Short.MAX_VALUE);
enchantments.put(enchantmentId, newLevel);
EnchantmentHelper.setEnchantments(enchantments, this.inventory);
}
private void addOverchantId(int enchantmentId) {
NBTTagCompound stackTag = MiscUtils.getStackTag(inventory);
if (!stackTag.hasKey(overchantsNbtTag)) {
stackTag.setIntArray(overchantsNbtTag, new int[] { enchantmentId });
} else {
int[] arrayInt = stackTag.getIntArray(overchantsNbtTag);
int[] newArrayInt = new int[arrayInt.length + 1];
System.arraycopy(arrayInt, 0, newArrayInt, 0, arrayInt.length);
newArrayInt[newArrayInt.length - 1] = enchantmentId;
stackTag.setIntArray(overchantsNbtTag, newArrayInt);
}
}
public boolean tryStartEnchanting() {
if (canStartEnchanting()) {
this.isEnchantingStarted = true;
this.worldObj.playSoundEffect(this.xCoord, this.yCoord, this.zCoord, "thaumcraft:craftstart", 0.5F, 1.0F);
return true;
}
return false;
}
@SuppressWarnings("unchecked")
public boolean canStartEnchanting() {
if (this.isEnchantingStarted || this.inventory == null) {
return false;
}
NBTTagList enchantmentTagList = this.inventory.getEnchantmentTagList();
if (enchantmentTagList == null || enchantmentTagList.tagCount() < 1) {
return false;
}
return findEnchantment(inventory) != -1;
}
public int findEnchantment(ItemStack enchanted) {
NBTTagCompound stackTag = MiscUtils.getStackTag(inventory);
LinkedHashMap<Integer, Integer> ench = (LinkedHashMap<Integer, Integer>) EnchantmentHelper
.getEnchantments(enchanted);
Set<Integer> keys = ench.keySet();
Iterator<Integer> $i = keys.iterator();
Map<Integer, Integer> enchantments = EnchantmentHelper.getEnchantments(enchanted);
if (enchantments.isEmpty()) {
return -1;
}
while ($i.hasNext()) {
int i = $i.next();
if (!stackTag.hasKey("overchants")) {
return i;
} else {
int[] overchants = stackTag.getIntArray("overchants");
if (MathUtils.arrayContains(overchants, i)) continue;
NBTTagCompound stackTag = MiscUtils.getStackTag(enchanted);
if (!stackTag.hasKey(overchantsNbtTag)) {
return enchantments.keySet()
.iterator()
.next();
}
if (!stackTag.hasKey(overchantsNbtTag, nbtIntArrayType)) {
return -1;
}
int[] overchants = stackTag.getIntArray(overchantsNbtTag);
return i;
for (int id : enchantments.keySet()) {
if (!MathUtils.arrayContains(overchants, id)) {
return id;
}
}
return -1;
}
public void syncToClients() {
if (worldObj.isRemote) {
return;
}
NBTTagCompound tag = new NBTTagCompound();
writeToNBT(tag);
MiscUtils.syncTileEntity(tag, 0);
}
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
enchantingTime = pkt.func_148857_g()
.getInteger("0");
xpAbsorbed = pkt.func_148857_g()
.getBoolean("1");
isEnchantingStarted = pkt.func_148857_g()
.getBoolean("2");
readFromNBT(pkt.func_148857_g());
}
@Override
public void markDirty() {
super.markDirty();
if (!worldObj.isRemote && !isEnchantingStarted) {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
if (!worldObj.isRemote) {
syncToClients();
}
}
@@ -194,31 +189,21 @@ public class TileOverchanter extends TileEntity implements IInventory, IWandable
public ItemStack decrStackSize(int slot, int num) {
if (this.inventory != null) {
ItemStack itemstack;
if (this.inventory.stackSize <= num) {
itemstack = this.inventory;
this.inventory = null;
this.markDirty();
return itemstack;
} else {
itemstack = this.inventory.splitStack(num);
if (this.inventory.stackSize == 0) {
this.inventory = null;
}
this.markDirty();
return itemstack;
}
this.markDirty();
return itemstack;
} else {
return null;
}
}
/*
* @Override public ItemStack decrStackSize(int i, int j) { if (inventory != null) { ItemStack stackAt; if
* (inventory.stackSize <= j) { stackAt = inventory; inventory = null; return stackAt; } else { stackAt =
* inventory.splitStack(j); if (inventory.stackSize == 0) inventory = null; return stackAt; } } return null; }
*/
@Override
public ItemStack getStackInSlotOnClosing(int slot) {
@@ -259,25 +244,46 @@ public class TileOverchanter extends TileEntity implements IInventory, IWandable
@Override
public boolean isItemValidForSlot(int slot, ItemStack stk) {
// return stk.hasTagCompound() && stk.getEnchantmentTagList() != null;
return false;
return stk.hasTagCompound() && stk.getEnchantmentTagList() != null
&& stk.getEnchantmentTagList()
.tagCount() > 0
&& findEnchantment(stk) != -1;
}
@Override
public boolean canExtractItem(int slot, ItemStack item, int side) {
return !isItemValidForSlot(0, item);
}
@Override
public boolean canInsertItem(int slot, ItemStack item, int side) {
return isItemValidForSlot(0, item);
}
@Override
public int[] getAccessibleSlotsFromSide(int side) {
return new int[] { 0 };
}
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
enchantingTime = tag.getInteger("enchTime");
xpAbsorbed = tag.getBoolean("xpAbsorbed");
enchantingTicks = tag.getInteger("enchTime");
xpToAbsorb = tag.hasKey("xpToAbsorb") ? tag.getInteger("xpToAbsorb") : xp30lv;
isEnchantingStarted = tag.getBoolean("enchStarted");
if (tag.hasKey("itm")) inventory = ItemStack.loadItemStackFromNBT(tag.getCompoundTag("itm"));
if (tag.hasKey("itm")) {
inventory = ItemStack.loadItemStackFromNBT(tag.getCompoundTag("itm"));
} else {
inventory = null;
}
}
public void writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
tag.setInteger("enchTime", enchantingTime);
tag.setBoolean("xpAbsorbed", xpAbsorbed);
tag.setInteger("enchTime", enchantingTicks);
tag.setInteger("xpToAbsorb", xpToAbsorb);
tag.setBoolean("enchStarted", isEnchantingStarted);
if (inventory != null) {
@@ -290,11 +296,8 @@ public class TileOverchanter extends TileEntity implements IInventory, IWandable
@Override
public int onWandRightClick(World world, ItemStack wandstack, EntityPlayer player, int x, int y, int z, int side,
int md) {
if (canStartEnchanting()) {
isEnchantingStarted = true;
if (!world.isRemote && tryStartEnchanting()) {
player.swingItem();
syncTimer = 0;
this.worldObj.playSoundEffect(this.xCoord, this.yCoord, this.zCoord, "thaumcraft:craftstart", 0.5F, 1.0F);
return 1;
}
return -1;
@@ -310,4 +313,94 @@ public class TileOverchanter extends TileEntity implements IInventory, IWandable
@Override
public void onWandStoppedUsing(ItemStack wandstack, World world, EntityPlayer player, int count) {}
public void absorbXP() {
// Note that the drain functions shouldn't be in a non-remote test because of player damage fallback
if (isAutomagyLoaded) {
// This scans a 17x17x17 cube centered around the TE, prioritizing the closest sources
this.xpToAbsorb = this.drainXPJarsInRange(this.xpToAbsorb, 8);
if (xpToAbsorb == 0) return;
}
if (isEioLoaded) {
this.xpToAbsorb = this.drainEIOObelisksInRange(this.xpToAbsorb, 8);
if (xpToAbsorb == 0) return;
}
List<EntityPlayer> players = this.worldObj.getEntitiesWithinAABB(
EntityPlayer.class,
AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord + 1, yCoord + 1, zCoord + 1)
.expand(6, 3, 6));
if (!players.isEmpty()) {
// See https://minecraft.wiki/w/Experience#Values_from_Java_Edition_1.3.1_to_1.8_(14w02a) for XP math
// Uses a double in the second branch so that float division is used
int lvlsleft = (int) Math
.round(xpToAbsorb > 255 ? (59 + Math.sqrt(24 * xpToAbsorb - 5159)) / 6 : xpToAbsorb / 17d);
for (EntityPlayer p : players) {
if (p.experienceLevel >= lvlsleft) {
p.attackEntityFrom(DamageSource.magic, 8);
this.worldObj.playSoundEffect(p.posX, p.posY, p.posZ, "thaumcraft:zap", 1F, 1.0F);
p.experienceLevel -= lvlsleft;
this.xpToAbsorb = 0;
// If anyone else wants to implement the exact formula for experience draining, you can
return;
}
}
}
}
public int drainXPJarsInRange(int xp, int range) {
if (xp <= 0) return xp;
CubeIterator cubeIter = new CubeIterator(range);
int jarxp;
while (cubeIter.hasNext()) {
cubeIter.next();
if (this.worldObj.getTileEntity(
cubeIter.n + this.xCoord,
cubeIter.l + this.yCoord,
cubeIter.m + this.zCoord) instanceof TileEntityJarXP jar) {
jarxp = jar.getXP();
if (jarxp < xp) {
if (!worldObj.isRemote) jar.setXP(0);
xp -= jarxp;
continue;
}
if (!worldObj.isRemote) jar.setXP(jarxp - xp);
return 0;
}
}
return xp;
// This algorithm drains each jar it comes across sequentially without regard to how full they are. If you would
// rather it prioritize emptying barely filled jars within a certain radius, and then emptying non-full jars,
// then instead have a counter sinceLastPrioJar that starts at 0 and increments each iteration, and cache the
// most recent "priority" jar (lowest non-full jar with jarxp > xp argument); reset that counter per each jar
// with jarxp under xp argument, and drain each jar with jarxp under xp argument, stopping once the counter
// reaches an arbitrary count of blocks searched without draining a jar, and then drain the cached lowest-filled
// jar. The TC EssentiaHandler would be so much better if it worked that way as well.
}
// EIO version (separated so that it prioritizes the magic jars, feel free to switch this to being in sync instead)
public int drainEIOObelisksInRange(int xp, int range) {
if (xp <= 0) return xp;
CubeIterator cubeIter = new CubeIterator(range);
int jarxp;
while (cubeIter.hasNext()) {
cubeIter.next();
if (this.worldObj.getTileEntity(
cubeIter.n + this.xCoord,
cubeIter.l + this.yCoord,
cubeIter.m + this.zCoord) instanceof TileExperienceObelisk obelisk) {
ExperienceContainer cont = obelisk.getContainer();
jarxp = cont.getExperienceTotal();
// goddamn private fields with no good setters
if (!worldObj.isRemote) {
cont.drain(null, Integer.MAX_VALUE, true);
cont.addExperience(Math.max(0, jarxp - xp));
}
// if this causes desyncs, remove the !worldObj.isRemote test or add an additional multiplayer test
xp -= jarxp;
if (xp <= 0) return 0;
}
}
return xp;
}
}
+4 -1
View File
@@ -44,10 +44,13 @@ public class TBCore {
public static final String name = "Thaumic Bases";
public static final String serverProxy = "tb.network.proxy.TBServer";
public static final String clientProxy = "tb.network.proxy.TBClient";
public static final String dependencies = "required-after:Thaumcraft@[4.2.3.5,);required-after:Baubles@[1.0.1.10,);required-after:DummyCore@[1.6,);";
public static final String dependencies = "required-after:Thaumcraft@[4.2.3.5,);required-after:Baubles@[1.0.1.10,);required-after:DummyCore@[1.6,);required-after:gtnhlib@[0.9.47,);";
public static final TBConfig cfg = new TBConfig();
public static final boolean isAutomagyLoaded = cpw.mods.fml.common.Loader.isModLoaded("Automagy");
public static final boolean isEioLoaded = cpw.mods.fml.common.Loader.isModLoaded("EnderIO");
@SidedProxy(serverSide = serverProxy, clientSide = clientProxy)
public static TBServer proxy;
+1 -1
View File
@@ -63,7 +63,7 @@ public class TBBlocks {
public static Block quicksilverBlock = new TBBlockDeco(Material.iron, false).setBlockName("quicksilverBlock")
.setBlockTextureName("thaumicbases:quicksilverBlock")
.setHardness(1F);
public static Block quicksilverBrick = new TBBlockDeco(Material.rock, true).setBlockName("quicksilverBrick")
public static Block quicksilverBrick = new TBBlockDeco(Material.rock, false).setBlockName("quicksilverBrick")
.setBlockTextureName("thaumicbases:quicksilverBrick")
.setHardness(1F);
public static Block crystalBlock = new BlockCrystalBlock().setBlockName("crystalBlock")
+4 -1
View File
@@ -1261,7 +1261,9 @@ public class TBThaumonomicon {
new ResearchItem(
"TB.Tainted",
catName,
new AspectList().add(Aspect.TAINT, 16),
new AspectList().add(Aspect.TAINT, 16)
.add(Aspect.MAGIC, 8)
.add(Aspect.WEAPON, 8),
-3,
9,
1,
@@ -1394,6 +1396,7 @@ public class TBThaumonomicon {
new ResearchPage("tb.rec.overchanter.page.0"),
new ResearchPage("tb.rec.overchanter.page.1"),
new ResearchPage("tb.rec.overchanter.page.2"),
new ResearchPage("tb.rec.overchanter.page.3"),
new ResearchPage(overchanterRec))
.registerResearchItem();
+1
View File
@@ -22,4 +22,5 @@ public class TBTiles {
GameRegistry.registerTileEntity(TileCampfire.class, "tb.campfire");
GameRegistry.registerTileEntity(TileBrazier.class, "tb.brazier");
}
}
+10 -1
View File
@@ -40,6 +40,8 @@ public class TBConfig implements IDummyConfig {
public static int speedMultiplierForFurnace;
public static boolean makeRequireAlumentum;
public static boolean modernAnvilGui;
@Override
public void load(Configuration config) {
cfg = config;
@@ -93,7 +95,7 @@ public class TBConfig implements IDummyConfig {
"Allow the mod to register it's enchantments in the Thaumic Tinkerer's enchanter? Set to false if Thaumic Tinkerer is crashing you.");
shardsFromOre = cfg
.getInt("shardsFromOre", "General", 8, 1, 64, "Amount of shards recieved from crucible ore processing");
.getInt("shardsFromOre", "General", 8, 1, 64, "Amount of shards received from crucible ore processing");
brightFociRequiresPrimordialPearl = cfg.getBoolean(
"brightFociRequiresPrimordialPearl",
@@ -142,5 +144,12 @@ public class TBConfig implements IDummyConfig {
.getInt("minBlazePowderFromPyrofluid", "Pyrofluid", 5, 0, Integer.MAX_VALUE, "");
maxBlazePowderFromPyrofluid = cfg
.getInt("maxBlazePowderFromPyrofluid", "Pyrofluid", 5 + 32, 0, Integer.MAX_VALUE, "");
// client
modernAnvilGui = cfg.getBoolean(
"modernAnvilGui",
"Client",
false,
"If set to true the Void Anvil and Thaumic Anvil GUIs use the modern vanilla anvil style (Inventory label and a translucent box behind the repair cost)");
}
}
@@ -46,6 +46,9 @@ tile.spike.name=Spikes
tile.spikeiron.name=Iron Spikes
tile.spikethaumic.name=Thaumic Spikes
tile.spikevoid.name=Void Spikes
tile.spikeiron_bloody.name=Bloodstained Iron Spikes
tile.spikethaumic_bloody.name=Bloodstained Thaumic Spikes
tile.spikevoid_bloody.name=Bloodstained Void Spikes
tile.goldenOakSapling.name=Golden Oak Sapling
tile.goldenOakLeaves.name=Golden Oak Leaves
tile.cryingObsidian.name=Crying Obsidian
@@ -261,7 +264,7 @@ tb.rec.capthauminite.page.0=A thaumaturge always seeks for the best possible res
tc.research_name.TB.Pyrofluid=Incendium
tc.research_text.TB.Pyrofluid=Just a quick nether trip
tb.rec.pyrofluid.page.0=Sometmies a thaumaturge just wants some of that nether essence, the Blaze Powder. However, it is hot and dangerous in the nether, and some thaumaturges might not want to go there. You have discovered a way to get blaze powder without venturing to the nether - infusing a bucket of lava with some Ignis and Praecantatio creates a liquid, that has lost it's ability to spread. It will slowly crystallise while in the world. Once fully crystallised it can then be harvested by bare hands, dropping a random amount of blaze powder. Note, that the liquid is still as dangerous as lava, and you should not swim in it...
tb.rec.pyrofluid.page.0=Sometimes a thaumaturge just wants some of that nether essence, the Blaze Powder. However, it is hot and dangerous in the nether, and some thaumaturges might not want to go there. You have discovered a way to get blaze powder without venturing to the nether - infusing a bucket of lava with some Ignis and Praecantatio creates a liquid, that has lost it's ability to spread. It will slowly crystallise while in the world. Once fully crystallised it can then be harvested by bare hands, dropping a random amount of blaze powder. Note, that the liquid is still as dangerous as lava, and you should not swim in it...
tc.research_name.ROD_tbthaumium=Thaumic Wand Rod
tc.research_text.ROD_tbthaumium=Where magic meets more magic!
@@ -282,17 +285,17 @@ tb.rec.basicPlants.page.0=Thaumaturhy is rich in directions it affects. Alchemy,
tc.research_name.TB.Knose=Rosa Mysteria
tc.research_text.TB.Knose=A forgotten plant from a lost world...
tb.rec.knose.page.0=A wise thaumaturge keeps their knowledge in books and papers - that's why there are so many of those Knowledge Fragments scattered around the world. However, every living being has it's sort of memory - animals and humans use their brains, zombies use other's brains... What about plants? They do have a memory too, don't they? Well, what happens should you infuse a plant in a lot of cognitio essentia? Well, the results... are interesting for sure. Only one plant was able to survive the infusion - the Rose. You've tried planting it and letting it grow. No success... almost.
tb.rec.knose.page.1=A newborn Rosa Mysteria seems too weak for the regular soil - it dies of without any aspects supporting it's growth. You've tried putting it on top of Salis Mundus - does not do the job. However, those Aspect Blocks serve like a descent enough base for the plant to grow. While growing it will accumulate aspects from the block underneath it. Once grown a Knowledge Fragment of sorts can be harvested. It will be attuned to certain aspects based on the block the Rose was growing on. The fragment can be washed-up in a crucible to remove it's attunement, but it looses much in the process. Growing the rose on top of a mixed block yields a Mixed Fragment. it is up to you to discover what would happen should you grow the rose on a Tained Block, but you have a feeling that nothing good will happen...
tb.rec.knose.page.1=A newborn Rosa Mysteria seems too weak for the regular soil - it dies of without any aspects supporting it's growth. You've tried putting it on top of Salis Mundus - does not do the job. However, those Aspect Blocks serve like a decent enough base for the plant to grow. While growing it will accumulate aspects from the block underneath it. Once grown a Knowledge Fragment of sorts can be harvested. It will be attuned to certain aspects based on the block the Rose was growing on. The fragment can be washed-up in a crucible to remove it's attunement, but it looses much in the process. Growing the rose on top of a mixed block yields a Mixed Fragment. it is up to you to discover what would happen should you grow the rose on a Tained Block, but you have a feeling that nothing good will happen...
tc.research_name.TB.Lazullia=Lazullia
tc.research_text.TB.Lazullia=Magic meets beauty
tb.rec.lazullia.page.0_ec3=Sometimes a thaumaturge needs some lapis for his... thaumaturgy. And sometimes a thaumaturge is just too lazy to venture down into caves just to spend a good 5 hours searching for that blue ore. You have once again used plants to aid you with this nonsense. Lazullia will slowly grow and once fully grown can be harvested. Upon harvesting a thaumaturge will recieve some Lapis Lazuli alongside with a seed. <LINE> Funny enough the crop also follows the mythical "Enderstar Pulses", which you may or may not know of, and, therefore, will also crystallise mythriline, if the pre-requisites are correct.
tb.rec.lazullia.page.0_ec3=Sometimes a thaumaturge needs some lapis for his... thaumaturgy. And sometimes a thaumaturge is just too lazy to venture down into caves just to spend a good 5 hours searching for that blue ore. You have once again used plants to aid you with this nonsense. Lazullia will slowly grow and once fully grown can be harvested. Upon harvesting a thaumaturge will receive some Lapis Lazuli alongside with a seed. <LINE> Funny enough the crop also follows the mythical "Enderstar Pulses", which you may or may not know of, and, therefore, will also crystallise mythriline, if the pre-requisites are correct.
tb.rec.lazullia.page.0=Sometimes a thaumaturge needs some lapis for his... thaumaturgy. And sometimes a thaumaturge is just too lazy to venture down into caves just to spend a good 5 hours searching for that blue ore. You have once again used plants to aid you with this nonsense. Lazullia will slowly grow and once fully grown can be harvested. Upon harvesting a thaumaturge will receive some Lapis Lazuli alongside with a seed.
tc.research_name.TB.RainbowCacti=Rainbow Cacti
tc.research_text.TB.RainbowCacti=Grow the rainbow, taste the rainbow!
tb.rec.rainCacti.page.0=Magic is not always strict and logical - it is magic, after all. The same goes to life - it can take various shapes, sometimes shocking, sometimes funny. Well, you have managed to create a plant, that, pretty much, is a definition of the word 'funny'. This plant functions just like the regular cacti - must be placed on sand and grows up to 3 blocks. However, once broken it will only drop itself it it is the last cacti block left. Otherwise it will drop all kinds of dyes. however, cacti can't create certain dye types, like bonemeal and Lapis. It is also more likely to drop green dye than other dyes.
tb.rec.rainCacti.page.0.gt=Magic is not always strict and logical - it is magic, after all. The same goes to life - it can take various shapes, sometimes shocking, sometimes funny. Well, you have managed to create a plant, that, pretty much, is a definition of the word 'funny'. This plant functions just like the regular cacti - must be placed on sand and grows up to 3 blocks. However, once broken it will only drop itself it it is the last cacti block left. Otherwise it will drop all kinds of dyes.
tb.rec.rainCacti.page.0=Magic is not always strict and logical - it is magic, after all. The same goes for life - it can take various shapes: sometimes shocking, sometimes funny. Well, you have managed to create a plant, that, pretty much, is a definition of the word 'funny'. This plant functions just like a regular cactus - it must be placed on sand and it grows up to 3 blocks. However, when broken, it will only drop itself if it is the last cactus block left. Otherwise, it drops all kinds of dyes. However, these cacti can't create certain dye types, like Bone Meal and Lapis Lazuli. It is also more likely to drop green dye than other dyes.
tb.rec.rainCacti.page.0.gt=Magic is not always strict and logical - it is magic, after all. The same goes for life - it can take various shapes: sometimes shocking, sometimes funny. Well, you have managed to create a plant, that, pretty much, is a definition of the word 'funny'. This plant functions just like a regular cactus - it must be placed on sand and it grows up to 3 blocks. However, when broken, it will only drop itself if it is the last cactus block left. Otherwise, it drops all kinds of dyes.
tc.research_name.TB.Metalleat=Metalleat
tc.research_text.TB.Metalleat=Iron is good for your health
@@ -424,8 +427,9 @@ tb.rec.cryingObs.page.0=Should a thaumaturge die he will reappear next to the be
tc.research_name.TB.Overchanter=Overchanting
tc.research_text.TB.Overchanter=Pushing the limits
tb.rec.overchanter.page.0=Thaumaturges often use their magic to infuse regular mundane items with magical force, making them better. This process is called enchanting. Thaumaturges have also discovered a way to do the same with an Infusion Altar, using it to make items stronger. However, there always seems to be a limit to the magic infused into the item... You have managed to push that limit a little bit further. You have managed to create an Overchanting table, which is able to increase the level of enchantments on the item by one. Not only could it get items closer to the desired level, it can do more - it can increase the level beyond maximum, allowing enchantments like Fortune IV, or Sharpness VI.
tb.rec.overchanter.page.1=The device will improve the first enchantment on the item. The order is the same as displayed in the item's description. Previously buffed enchantments will be skipped - the device is not quite powerful enough to do thinks like Sharpness VII. It does not take the enchantment into account, so thinks like Silk Touch II are possible, yet useless. To infuse the item just put it in the only slot available and start the overchanting process by using your wand on the table twice. Then the Praecantatio essentia will be drawn from nearby jars into the table - you will need 32 Praecantatio in total. The table also requires a player nearby, since in the middle of the process it will use 30 levels from the player in range of 6 blocks!
tb.rec.overchanter.page.1=The device will improve the first enchantment on the item. The order is the same as displayed in the item's description. Previously buffed enchantments will be skipped - the device is not quite powerful enough to do things like Sharpness VII. It does not take the enchantment into account, so things like Silk Touch II are possible, yet useless. To infuse the item just put it in the only slot available and start the overchanting process by using your wand on the table twice. Then the Praecantatio essentia will be drawn from nearby jars into the table - you will need 32 Praecantatio in total. The table also requires a player nearby, since in the middle of the process it will use 30 levels from the player in range of 6 blocks!
tb.rec.overchanter.page.2=Overchanting can be stopped in any time just by taking the item from the table, but the levels and the essentia will be wasted then. The table will draw Praecantatio from the range of 8 blocks, mirrors will also do the job just fine. Upon sapping experience the table will skip players with level before 30, so having multiple people with total level of 30 will not work. Any item with enchantments can be overchanted. Putting a non-enchanted item in the Overchanting table does nothing.
tb.rec.overchanter.page.3=You can also automate the Overchanter with redstone, hoppers, and an XP container from the mods Automagy and EnderIO. Redstone input to the table will start overchanting, and overchanted items can be inserted and non-overchanted items extracted via hopper. It will only be able to extract fully overchanted items, so there is no need to lock hoppers! XP can be sourced from Automagy XP jars (first priority) or EnderIO XP obelisks (second priority) within a 17x17x17 cube centered on the table, prioritizing closer sources. If XP is left over, it will consume the rest from nearby players.
tc.research_name.TB.EntityDec=Entity Deconstructor
tc.research_text.TB.EntityDec=Lively knowledge
@@ -460,7 +464,7 @@ tc.research_text.TB.NodeFoci.Efficiency=Waste nothing
tb.rec.foci.efficiency.page.0=Efficiency foci will affect the node in a very spectacular way. If any aspect is drained from the node affected with this foci there is a 50% chance that the aspect will be used, but will not be drained. Works with everything - wands, recharge pedestals, different constructs...
tc.research_name.TB.NodeFoci.Bright=Manipulator Foci: Brightness
tc.research_text.TB.NodeFoci.Bright=Making things brigher
tc.research_text.TB.NodeFoci.Bright=Making things brighter
tb.rec.foci.bright.page.0=Brightness foci will make the Manipulator extremely slowly turn the node into a Bright Node. Will only work with normal nodes. Takes 20 minutes to finish.
tc.research_name.TB.NodeFoci.Destr=Manipulator Foci: Destruction
@@ -473,7 +477,7 @@ tb.rec.foci.hunger.page.0=Hunger foci will make the Manipulator slowly turn the
tc.research_name.TB.NodeFoci.Purity=Manipulator Foci: Purity
tc.research_text.TB.NodeFoci.Purity=Node purification
tb.rec.foci.pure.page.0=Purity foci will make the Manipulator slowly turn a Tainted node into normal and a normal node into Pure Node. Will only work with normal or tainted nodes. Takes 3 minutes to finish with a normal node or 33 minutes with a tainted node. Note that the node will not recieve aspects that pure nodes usually have in them, but will still turn the biome around to Magical Forest.
tb.rec.foci.pure.page.0=Purity foci will make the Manipulator slowly turn a Tainted node into normal and a normal node into Pure Node. Will only work with normal or tainted nodes. Takes 3 minutes to finish with a normal node or 33 minutes with a tainted node. Note that the node will not receive aspects that pure nodes usually have in them, but will still turn the biome around to Magical Forest.
tc.research_name.TB.NodeFoci.Stability=Manipulator Foci: Stability
tc.research_text.TB.NodeFoci.Stability=Saving the dying nodes
@@ -481,7 +485,7 @@ tb.rec.foci.stability.page.0=Stability foci will make the Manipulator slowly res
tc.research_name.TB.NodeFoci.Taint=Manipulator Foci: Taint
tc.research_text.TB.NodeFoci.Taint=Why make everything worse?
tb.rec.foci.taint.page.0=Taint foci will make the Manipulator slowly turn the node into a tainted node. Will only work with normal nodes. Takes 6 minutes to finish. Note that the node will not recieve aspects that tainted nodes usually have in them, but will still turn the biome around to tainted Lands.
tb.rec.foci.taint.page.0=Taint foci will make the Manipulator slowly turn the node into a tainted node. Will only work with normal nodes. Takes 6 minutes to finish. Note that the node will not receive aspects that tainted nodes usually have in them, but will still turn the biome around to tainted Lands.
tc.research_name.TB.Enchantments=New Enchantments!
tc.research_text.TB.Enchantments=Magic reborn!
@@ -600,7 +604,7 @@ revolverUpgrade.BANE_OF_ATROPODS.name=Bane of Arthropods
revolverUpgrade.BANE_OF_ELDRITCH.name=Bane of Eldritch
revolverUpgrade.PIERCING.name=Piercing
revolverUpgrade.DUELING.name=Dueling
revolverUpgrade.TAINTED.name=tainted
revolverUpgrade.TAINTED.name=Tainted
revolverUpgrade.PRIMAL.name=Primal
revolverUpgrade.SPEED.name=Speed
revolverUpgrade.EFFICIENCY.name=Efficiency
@@ -738,7 +742,7 @@ tb.rec.bracelet.quartz.page.0=You have created a bracelet that shares the same f
tc.research_name.TB.Bracelet.Bone=Bone Bracelets
tc.research_text.TB.Bracelet.Bone=The undead bracelet!
tb.rec.bracelet.bone.page.0=You have created a bracelet that shares the same functionality as the bone wand core - it will slowly regenerate perdidio vis inside it.
tb.rec.bracelet.bone.page.0=You have created a bracelet that shares the same functionality as the bone wand core - it will slowly regenerate perditio vis inside it.
tc.research_name.TB.Bracelet.Primal=Primal Bracelets
tc.research_text.TB.Bracelet.Primal=The ultimate way
@@ -748,4 +752,4 @@ tb.rec.bracelet.primal.page.0=Using your knowledge of the Staff core of the Prim
#Chat notifications
tb.txt.linkStarted=Link Started
tb.txt.linkEstabilished=Link Established
tb.txt.linkEstablished=Link Established
@@ -794,4 +794,4 @@ tc.research_text.TB.ROD_primal_staff=Силы элементов в комбин
#Chat notifications
tb.txt.linkStarted=Акцептор Назначен
tb.txt.linkEstabilished=Соединение установлено
tb.txt.linkEstablished=Соединение установлено
@@ -418,6 +418,7 @@ tc.research_text.TB.Overchanter=挑战极限
tb.rec.overchanter.page.0=神秘使通常会向普通物品注入魔法力量来改进它们.这个过程被称为附魔.神秘使也找到了一个方法用注魔祭坛办到同样的事情.然而,给物品注入魔力总是有极限的...但是你成功将这个极限变得了更极限了一些.你成功创造了这个超吟附魔台.它能够将附魔等级上限提升一级.不仅仅是是将物品的附魔向理想状态提升一级,它甚至可以超过极限,使得时运IV或者锋利VI这种附魔得以实现.
tb.rec.overchanter.page.1=这个设备会提升物品上的第一个附魔.这个顺序和物品中附魔描述的顺序相同.之前的强化后的附魔将会被忽略——这个设备还没有制作出锋利VII那样强力的能力.它并没有考虑这个附魔本身的特性,因此例如精准采集II这样的附魔是会出现的,虽然这并没有什么卵用.如果想给物品注入魔力只需要把它放进超吟附魔台中唯一的栏位然后用法杖点击附魔台2次.然后附魔台会从附近吸收总共32点的Praecantatio源质.这个附魔台也需要有一个玩家在附近,由于这个附魔过程中会从玩家身上抽取30级经验!
tb.rec.overchanter.page.2=超吟附魔台可以在任何时候停止它的工作,但是吸收的经验与源质就会被浪费掉了.附魔台会在8格范围内吸收Praecantatio源质,范围之内的源质之镜也能很好的工作.附魔台会忽略等级没有达到30级的玩家,因此即便是多人的等级和超过30附魔台也不会工作.任何物品只要具有附魔就可以使用超吟附魔台,但是没有附魔的物品放上去并不会产生什么卵用.
tb.rec.overchanter.page.3=超吟附魔台也可以通过赤石末实现自动化。激活后,附魔台还能从Automagy的罐子以及EnderIO的方尖碑中吸收经验。附魔台会在8格范围内搜索罐装附魔精华液和经验交换方尖碑。罐子的优先级高于方尖碑,剩余部分则由玩家供应。漏斗可用于把物品传入和移出。它们仅在工艺流程做成后才会进行移出,因此无需加锁。
tc.research_name.TB.EntityDec=实体粉碎机
tc.research_text.TB.EntityDec=活生生的知识
@@ -742,5 +743,5 @@ tb.rec.bracelet.primal.page.0=使用始源杖芯的知识你制作出了一个
#Chat notifications
tb.txt.linkStarted=连接开始
tb.txt.linkEstabilished=连接已建立
tb.txt.linkEstablished=连接已建立
Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 B

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 B

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 B

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 B

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 601 B

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 B

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 B

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 B

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 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: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 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: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 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: 518 B

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 B

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 B

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 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: 602 B

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 638 B

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 B

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 824 B

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

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