Compare commits

..

3 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 91e75ee7f1 Clarify that singleUseSpellBooks config does not affect scrolls
Co-authored-by: WinDanesz <31292708+WinDanesz@users.noreply.github.com>
2025-11-02 00:10:00 +00:00
copilot-swe-agent[bot] 1d80c5a447 Initial analysis of spell book consumption feature
Co-authored-by: WinDanesz <31292708+WinDanesz@users.noreply.github.com>
2025-11-02 00:08:10 +00:00
copilot-swe-agent[bot] 9906b3e154 Initial plan 2025-11-02 00:04:59 +00:00
41 changed files with 172 additions and 478 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/electroblobs-wizardry",
"promos": {
"1.12.2-latest": "4.3.16",
"1.12.2-recommended": "4.3.16"
"1.12.2-latest": "4.3.15",
"1.12.2-recommended": "4.3.15"
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ apply plugin: org.ajoberstar.grgit.gradle.GrgitPlugin
apply plugin: 'wtf.gofancy.fancygradle'
version = "4.3.16"
version = "4.3.15"
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "ElectroblobsWizardry"
Vendored Regular → Executable
View File
@@ -43,10 +43,6 @@ public class CommonProxy {
public void registerRenderers(){}
public void registerItemColorHandlers(){}
public void registerModelProperties(){}
public void initialiseLayers(){}
public void initialiseAnimations(){}
@@ -179,8 +175,6 @@ public class CommonProxy {
public void handleConquerShrinePacket(PacketConquerShrine.Message message){}
public void handleBombExplosionPacket(PacketBombExplosion.Message message){}
// SECTION Misc
// ===============================================================================================================
@@ -207,7 +207,7 @@ public final class Settings {
/** <b>[Server-only]</b> Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like
* necromancy_indirect_wizardry_magic, necromancy_wizardry_magic*/
public boolean damageTypePerElement = false;
/** <b>[Server-only]</b> Whether spell books are consumed when they are bound to a wand.*/
/** <b>[Server-only]</b> Whether spell books are consumed when they are bound to a wand. Does not affect scrolls.*/
public boolean singleUseSpellBooks = false;
/** <b>[Server-only]</b> Whether to prevent binding the same spell to a wand multiple times*/
public boolean preventBindingSameSpellTwiceToWands = false;
@@ -355,8 +355,6 @@ public final class Settings {
* velocity-based one.
*/
public boolean replaceVanillaFallDamage = true;
/** <b>[Synchronised]</b> Whether spell book colors are only shown when the player has the Archivist's Eyeglass equipped. */
public boolean spellBookColorsRequireArchivistsEyeglass = false;
/** <b>[Synchronised]</b> Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */
public double forfeitChance = 0.2;
/** <b>[Synchronised]</b> Progression requirements for upgrading a wand to each tier. */
@@ -463,8 +461,6 @@ public final class Settings {
public static final String DEFAULT_HUD_SKIN_KEY = "default"; // Defined here so it's not in a client-only class.
/** <b>[Client-only]</b> The string identifier of the skin used for the spell HUD. */
public String spellHUDSkin = DEFAULT_HUD_SKIN_KEY;
/** <b>[Client-only]</b> Whether to show elemental colors on spell books for discovered spells. */
public boolean spellBookColors = true;
/** Set of constants for each of the eight positions that the spell HUD can be in. */
public enum GuiPosition {
@@ -727,7 +723,7 @@ public final class Settings {
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "singleUseSpellBooks", false,
"Whether spell books are consumed when they are bound to a wand.");
"Whether spell books are consumed when they are bound to a wand. This does not affect scrolls, which cannot be placed in the arcane workbench.");
property.setLanguageKey("config." + Wizardry.MODID + ".single_use_spell_books");
Wizardry.proxy.setToNamedBooleanEntry(property);
singleUseSpellBooks = property.getBoolean();
@@ -1107,13 +1103,6 @@ public final class Settings {
replaceVanillaFallDamage = property.getBoolean();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "spellBookColorsRequireArchivistsEyeglass", false,
"If true, spell book colors are only shown when the player has the charm of spell discovery equipped.");
property.setLanguageKey("config." + Wizardry.MODID + ".spell_book_colors_require_charm");
Wizardry.proxy.setToNamedBooleanEntry(property);
spellBookColorsRequireArchivistsEyeglass = property.getBoolean();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "blindnessTweak", true,
"Whether to tweak the blindness effect to reduce follow distance when used on non-players. This automatically disables itself in favour of Potion Core's implementation if installed.");
property.setLanguageKey("config." + Wizardry.MODID + ".blindness_tweak");
@@ -1224,7 +1213,7 @@ public final class Settings {
bookshelfSearchRadius = property.getInt();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "currencyItems", new String[]{"gold_ingot 3", "emerald 6"}, "List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade. To specify metadata, use the format 'modid:item:meta value'. For example, 'minecraft:wool:1 5'. If no metadata is given, any metadata will be accepted.",
property = config.get(TWEAKS_CATEGORY, "currencyItems", new String[]{"gold_ingot 3", "emerald 6"}, "List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade.",
Pattern.compile("[A-Za-z0-9:_]+ [0-9]+"));
property.setLanguageKey("config." + Wizardry.MODID + ".currency_items");
propOrder.add(property.getName());
@@ -1498,14 +1487,6 @@ public final class Settings {
Wizardry.proxy.setToNamedBooleanEntry(property);
showChargeMeter = property.getBoolean();
propOrder.add(property.getName());
property = config.get(CLIENT_CATEGORY, "spellBookColors", true, "Whether to show elemental colors on spell books for discovered spells.");
property.setLanguageKey("config." + Wizardry.MODID + ".spell_book_colors");
property.setRequiresWorldRestart(false);
Wizardry.proxy.setToNamedBooleanEntry(property);
spellBookColors = property.getBoolean();
propOrder.add(property.getName());
property = config.get(CLIENT_CATEGORY, "loadHandbook", true, "Whether to initialise the in-game handbook. Setting this to false will brick the in-game handbook, but it might help if you have startup crashes.");
property.setLanguageKey("config." + Wizardry.MODID + ".load_handbook");
property.setRequiresWorldRestart(false);
@@ -1836,46 +1817,16 @@ public final class Settings {
string = string.toLowerCase(Locale.ROOT).trim();
String[] itemArgs = string.split(":");
String item;
short meta;
int lastColon = string.lastIndexOf(':');
if (lastColon > -1 && lastColon < string.length() - 1) { // if there is a colon and it's not the last char
String metaString = string.substring(lastColon + 1);
try {
short parsedMeta = Short.parseShort(metaString);
String itemString = string.substring(0, lastColon);
// If itemString has no colon, it could be 'item:meta' or 'namespace:numeric_path'.
// e.g., 'wool:1' vs 'mod:123'. We want to support 'wool:1' as item 'wool' with meta 1.
// We can't reliably distinguish the two cases without knowing all namespaces, so we have to use
// a heuristic. The original code favoured the 'item:meta' interpretation, let's stick with that.
// The issue was with 'namespace:numeric_path' which this logic now handles.
if (itemString.indexOf(':') == -1) {
item = itemString;
meta = parsedMeta;
} else {
// Disambiguate things like 'mod:123:4' (item 'mod:123' with meta 4) vs 'mod:item:123' (item 'mod:item' with meta 123)
// If the bit before the last colon is a valid resource location, it's probably item:meta
try {
new ResourceLocation(itemString);
item = itemString;
meta = parsedMeta;
} catch (Exception e) {
item = string;
meta = OreDictionary.WILDCARD_VALUE;
}
}
} catch (NumberFormatException e) {
// The part after colon is not a number, so it's part of the name
item = string;
meta = OreDictionary.WILDCARD_VALUE;
}
} else {
item = string;
try {
meta = Short.parseShort(itemArgs[itemArgs.length-1]);
item = String.join(":", Arrays.copyOfRange(itemArgs, 0, itemArgs.length-1));
}catch(NumberFormatException e){ // If no metadata is specified
meta = OreDictionary.WILDCARD_VALUE;
item = string;
}
return Pair.of(new ResourceLocation(item), meta);
@@ -82,7 +82,7 @@ public class Wizardry {
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
* 1.11.x versions, and so on.
*/
public static final String VERSION = "4.3.16";
public static final String VERSION = "4.3.15";
/**
* Json file used by Forge's built-in <a href="https://mcforge.readthedocs.io/en/1.12.x/gettingstarted/autoupdate/">update checker</a>.
@@ -198,8 +198,6 @@ public class Wizardry {
// Client-side stuff (via proxies)
proxy.initGuiBits();
proxy.registerParticles();
proxy.registerItemColorHandlers();
proxy.registerModelProperties();
proxy.registerSoundEventListener();
}
@@ -1,6 +1,7 @@
package electroblob.wizardry.client;
import electroblob.wizardry.CommonProxy;
import electroblob.wizardry.Settings;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockBookshelf;
import electroblob.wizardry.client.animation.ActionAnimation;
@@ -18,8 +19,6 @@ import electroblob.wizardry.client.model.ModelRobeArmour;
import electroblob.wizardry.client.model.ModelSageArmour;
import electroblob.wizardry.client.model.ModelWizardArmour;
import electroblob.wizardry.client.particle.*;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory;
import electroblob.wizardry.client.renderer.RenderSpectralGolem;
import electroblob.wizardry.client.renderer.entity.*;
@@ -39,7 +38,6 @@ import electroblob.wizardry.entity.projectile.*;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.item.ItemScroll;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWand;
@@ -717,65 +715,6 @@ public class ClientProxy extends CommonProxy {
}else Wizardry.logger.warn("Received a PacketConquerShrine, but there was no shrine core at the position sent");
}
@Override
public void handleBombExplosionPacket(PacketBombExplosion.Message message){
net.minecraft.world.World world = Minecraft.getMinecraft().world;
double x = message.x, y = message.y, z = message.z;
float blastMultiplier = message.blastMultiplier;
switch(message.bombType){
case PacketBombExplosion.FIREBOMB:
ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier).clr(1, 0.6f, 0).spawn(world);
for(int i = 0; i < 60 * blastMultiplier; i++){
ParticleBuilder.create(Type.MAGIC_FIRE, world.rand, x, y, z, 2 * blastMultiplier, false)
.time(10 + world.rand.nextInt(4)).scale(2 + world.rand.nextFloat()).spawn(world);
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false)
.clr(1.0f, 0.2f + world.rand.nextFloat() * 0.4f, 0.0f).spawn(world);
}
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0);
break;
case PacketBombExplosion.POISON_BOMB:
ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier)
.clr(0.2f + world.rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
for(int i = 0; i < 60 * blastMultiplier; i++){
ParticleBuilder.create(Type.SPARKLE, world.rand, x, y, z, 2 * blastMultiplier, false).time(35)
.scale(2).clr(0.2f + world.rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false)
.clr(0.2f + world.rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world);
}
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0);
break;
case PacketBombExplosion.SMOKE_BOMB:
ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world);
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0);
for(int i = 0; i < 60 * blastMultiplier; i++){
float brightness = world.rand.nextFloat() * 0.1f + 0.1f;
ParticleBuilder.create(Type.CLOUD, world.rand, x, y, z, 2 * blastMultiplier, false)
.clr(brightness, brightness, brightness).time(80 + world.rand.nextInt(12)).shaded(true).spawn(world);
brightness = world.rand.nextFloat() * 0.3f;
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false)
.clr(brightness, brightness, brightness).spawn(world);
}
break;
case PacketBombExplosion.SPARK_BOMB:
ParticleBuilder.spawnShockParticles(world, x, y, z);
for(int id : message.secondaryTargetIDs){
net.minecraft.entity.Entity target = world.getEntityByID(id);
if(target instanceof net.minecraft.entity.EntityLivingBase){
ParticleBuilder.create(Type.LIGHTNING).pos(x, y, z).target(target).spawn(world);
ParticleBuilder.spawnShockParticles(world, target.posX,
target.posY + target.height / 2, target.posZ);
}
}
break;
}
}
// Rendering
// ===============================================================================================================
@@ -938,51 +877,4 @@ public class ClientProxy extends CommonProxy {
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityImbuementAltar.class, new RenderImbuementAltar());
}
public void registerItemColorHandlers() {
// Spell book overlay textures are now per-element, so no runtime tinting is needed.
}
public void registerModelProperties() {
Item spellBook = WizardryItems.spell_book;
spellBook.addPropertyOverride(new ResourceLocation(Wizardry.MODID, "discovered"), (stack, world, entity) -> {
if (!Wizardry.settings.spellBookColors) return 0.0f;
boolean discovered = shouldDisplayDiscovered(Spell.byMetadata(stack.getMetadata()), stack);
if(discovered && Wizardry.settings.spellBookColorsRequireArchivistsEyeglass){
// Entity can be null so we have to check
if(entity instanceof EntityPlayer){
return ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.charm_spell_discovery) ? 1.0f : 0.0f;
}
// If there's no entity, there's no charm, so no colour
return 0.0f;
}
return discovered ? 1.0f : 0.0f;
});
// Returns ordinal+1 for each element (1=MAGIC through 8=HEALING), or 0 if not yet discovered.
// Drives per-element bookmark texture selection via model overrides in spell_book.json.
spellBook.addPropertyOverride(new ResourceLocation(Wizardry.MODID, "element"), (stack, world, entity) -> {
if (!Wizardry.settings.spellBookColors) return 0.0f;
Spell spell = Spell.byMetadata(stack.getMetadata());
boolean discovered = shouldDisplayDiscovered(spell, stack);
if(!discovered) return 0.0f;
if(Wizardry.settings.spellBookColorsRequireArchivistsEyeglass){
if(entity instanceof EntityPlayer){
if(!ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.charm_spell_discovery)) return 0.0f;
} else {
return 0.0f;
}
}
Element element = spell.getElement();
return element == null ? 0.0f : (float)(element.ordinal() + 1);
});
}
}
@@ -1,6 +1,5 @@
package electroblob.wizardry.client;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
import electroblob.wizardry.data.DispenserCastingData;
import electroblob.wizardry.data.SpellEmitterData;
@@ -14,6 +13,7 @@ import electroblob.wizardry.spell.SixthSense;
import electroblob.wizardry.spell.SlowTime;
import electroblob.wizardry.spell.Transience;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.BufferBuilder;
@@ -31,9 +31,6 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
@@ -199,15 +196,6 @@ public final class WizardryClientEventHandler {
}
}
@SubscribeEvent
public static void onItemTooltip(ItemTooltipEvent event) {
if (event.getItemStack().getItem() == WizardryItems.charm_spell_discovery) {
if (Wizardry.settings.spellBookColorsRequireArchivistsEyeglass) {
event.getToolTip().add(TextFormatting.GRAY + I18n.format("item.ebwizardry:charm_spell_discovery.desc.color"));
}
}
}
/**
* Renders an overlay across the entire screen.
* @param resolution The screen resolution
@@ -515,13 +515,12 @@ public class GuiArcaneWorkbench extends GuiContainer {
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
if(this.searchNeedsClearing){
this.searchNeedsClearing = false;
if(this.searchNeedsClearing){
this.searchNeedsClearing = false;
this.searchField.setText("");
}
// Allow exiting the GUI by pressing the inventory button. Does not work if bookshelves are present by default
if(this.searchField.getVisible() && this.searchField.textboxKeyTyped(typedChar, keyCode)){
if(this.searchField.textboxKeyTyped(typedChar, keyCode)){
arcaneWorkbenchContainer.setSearchText(searchField.getText().toLowerCase(Locale.ROOT));
}else{
super.keyTyped(typedChar, keyCode);
@@ -1063,4 +1062,4 @@ public class GuiArcaneWorkbench extends GuiContainer {
}
}
}
}
@@ -7,6 +7,7 @@ import electroblob.wizardry.enchantment.Imbuement;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.WizardryPacketHandler;
@@ -355,20 +356,20 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
// For each item in the player's inventory
for(ItemStack stack : player.inventory.mainInventory){
updateImbuedItem(stack, activeImbuements);
updateImbutedItem(stack, activeImbuements);
}
for(ItemStack stack : player.inventory.armorInventory){
updateImbuedItem(stack, activeImbuements);
updateImbutedItem(stack, activeImbuements);
}
for(ItemStack stack : player.inventory.offHandInventory){
updateImbuedItem(stack, activeImbuements);
updateImbutedItem(stack, activeImbuements);
}
// Removes all imbuements from the map that are no longer active
this.imbuementDurations.keySet().retainAll(activeImbuements);
}
private void updateImbuedItem(ItemStack stack, Set<Imbuement> activeImbuements){
private void updateImbutedItem(ItemStack stack, Set<Imbuement> activeImbuements){
if(stack.isItemEnchanted()){
@@ -465,7 +466,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
if(this.castCommandSpell != null && this.castCommandSpell.isContinuous){
if(castCommandTick > castCommandDuration){
if(castCommandTick >= castCommandDuration){
this.stopCastingContinuousSpell();
return;
}
@@ -1,18 +1,18 @@
package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.packet.PacketBombExplosion;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import java.util.List;
@@ -29,27 +29,40 @@ public class EntityFirebomb extends EntityBomb {
@Override
protected void onImpact(RayTraceResult rayTrace){
Entity entityHit = rayTrace.entityHit;
if(!this.world.isRemote){
if(entityHit != null){
// This is if the firebomb gets a direct hit
float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
Entity entityHit = rayTrace.entityHit;
entityHit.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(),
damage);
if(entityHit != null){
// This is if the firebomb gets a direct hit
float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit))
entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
}
entityHit.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(),
damage);
// Particle effect
if(world.isRemote){
ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(1, 0.6f, 0)
.spawn(world);
if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit))
entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
for(int i = 0; i < 60 * blastMultiplier; i++){
ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false)
.time(10 + rand.nextInt(4)).scale(2 + rand.nextFloat()).spawn(world);
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
.clr(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world);
}
// Notify clients to play the explosion effect
WizardryPacketHandler.net.sendToAllAround(
new PacketBombExplosion.Message(PacketBombExplosion.FIREBOMB, posX, posY, posZ, blastMultiplier),
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
}
if(!this.world.isRemote){
this.playSound(WizardrySounds.ENTITY_FIREBOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
this.playSound(WizardrySounds.ENTITY_FIREBOMB_FIRE, 1, 1);
@@ -69,9 +82,9 @@ public class EntityFirebomb extends EntityBomb {
target.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
}
}
}
this.setDead();
this.setDead();
}
}
}
@@ -1,20 +1,20 @@
package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.packet.PacketBombExplosion;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.MobEffects;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import java.util.List;
@@ -31,30 +31,44 @@ public class EntityPoisonBomb extends EntityBomb {
@Override
protected void onImpact(RayTraceResult rayTrace){
Entity entityHit = rayTrace.entityHit;
if(entityHit != null){
// This is if the poison bomb gets a direct hit
float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
entityHit.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON).setProjectile(),
damage);
if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.POISON, entityHit))
((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON,
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(),
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue()));
}
// Particle effect
if(world.isRemote){
ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier)
.clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
for(int i = 0; i < 60 * blastMultiplier; i++){
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).time(35)
.scale(2).clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
.clr(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world);
}
// Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it
// works pretty well.
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
}
if(!this.world.isRemote){
Entity entityHit = rayTrace.entityHit;
if(entityHit != null){
// This is if the poison bomb gets a direct hit
float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
entityHit.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON).setProjectile(),
damage);
if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.POISON, entityHit))
((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON,
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(),
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue()));
}
// Notify clients to play the explosion effect
WizardryPacketHandler.net.sendToAllAround(
new PacketBombExplosion.Message(PacketBombExplosion.POISON_BOMB, posX, posY, posZ, blastMultiplier),
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
this.playSound(WizardrySounds.ENTITY_POISON_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
this.playSound(WizardrySounds.ENTITY_POISON_BOMB_POISON, 1.2F, 1.0f);
@@ -74,8 +88,8 @@ public class EntityPoisonBomb extends EntityBomb {
Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue()));
}
}
}
this.setDead();
this.setDead();
}
}
}
@@ -1,17 +1,17 @@
package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.packet.PacketBombExplosion;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.MobEffects;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import java.util.List;
@@ -29,12 +29,26 @@ public class EntitySmokeBomb extends EntityBomb {
@Override
protected void onImpact(RayTraceResult rayTrace){
if(!this.world.isRemote){
// Particle effect
if(world.isRemote){
ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world);
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
for(int i = 0; i < 60 * blastMultiplier; i++){
// Notify clients to play the explosion effect
WizardryPacketHandler.net.sendToAllAround(
new PacketBombExplosion.Message(PacketBombExplosion.SMOKE_BOMB, posX, posY, posZ, blastMultiplier),
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
float brightness = rand.nextFloat() * 0.1f + 0.1f;
ParticleBuilder.create(Type.CLOUD, rand, posX, posY, posZ, 2*blastMultiplier, false)
.clr(brightness, brightness, brightness).time(80 + this.rand.nextInt(12)).shaded(true).spawn(world);
brightness = rand.nextFloat() * 0.3f;
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
.clr(brightness, brightness, brightness).spawn(world);
}
}
if(!this.world.isRemote){
this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMOKE, 1.2F, 1.0f);
@@ -51,8 +65,8 @@ public class EntitySmokeBomb extends EntityBomb {
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
}
}
}
this.setDead();
this.setDead();
}
}
}
@@ -1,7 +1,5 @@
package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.packet.PacketBombExplosion;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
@@ -15,9 +13,7 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import java.util.ArrayList;
import java.util.List;
public class EntitySparkBomb extends EntityBomb {
@@ -35,37 +31,47 @@ public class EntitySparkBomb extends EntityBomb {
@Override
protected void onImpact(RayTraceResult rayTrace){
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f);
if(!this.world.isRemote){
Entity entityHit = rayTrace.entityHit;
Entity entityHit = rayTrace.entityHit;
if(entityHit != null){
// This is if the spark bomb gets a direct hit
float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
if(entityHit != null){
// This is if the spark bomb gets a direct hit
float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
entityHit.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(),
damage);
entityHit.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(),
damage);
}
}
double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier;
// Particle effect
if(world.isRemote){
ParticleBuilder.spawnShockParticles(world, posX, posY + height/2, posZ);
}
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(seekerRange, this.posX, this.posY,
this.posZ, this.world);
double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier;
List<Integer> secondaryTargetIDs = new ArrayList<>();
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(seekerRange, this.posX, this.posY,
this.posZ, this.world);
for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){
for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){
boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower()
&& !(targets.get(i) instanceof EntityPlayer
&& ((EntityPlayer)targets.get(i)).isCreative());
boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower()
&& !(targets.get(i) instanceof EntityPlayer
&& ((EntityPlayer)targets.get(i)).isCreative());
if(flag){
EntityLivingBase target = targets.get(i);
// Detects (client side) if target is the thrower, to stop particles being spawned around them.
//if(flag && world.isRemote && targets.get(i).getEntityId() == this.playerID) flag = false;
if(flag){
EntityLivingBase target = targets.get(i);
if(!this.world.isRemote){
target.playSound(WizardrySounds.ENTITY_SPARK_BOMB_CHAIN, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
@@ -73,18 +79,11 @@ public class EntitySparkBomb extends EntityBomb {
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK),
Spells.spark_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier);
secondaryTargetIDs.add(target.getEntityId());
}else{
ParticleBuilder.create(Type.LIGHTNING).pos(this.getPositionVector()).target(target).spawn(world);
ParticleBuilder.spawnShockParticles(world, target.posX, target.posY + target.height/2, target.posZ);
}
}
// Notify clients to play the explosion effect, including lightning arcs to secondary targets
int[] idArray = secondaryTargetIDs.stream().mapToInt(Integer::intValue).toArray();
WizardryPacketHandler.net.sendToAllAround(
new PacketBombExplosion.Message(PacketBombExplosion.SPARK_BOMB, posX, posY + height / 2, posZ,
blastMultiplier, idArray),
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f);
}
this.setDead();
@@ -160,21 +160,12 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
Spell spell = Spell.byMetadata(stack.getItemDamage());
// By default, scrolls have no modifiers - but with the event system, they could be added.
SpellModifiers modifiers;
if(WizardData.get(player) != null){
modifiers = WizardData.get(player).itemCastingModifiers;
}else{
modifiers = new SpellModifiers();
}
SpellModifiers modifiers = new SpellModifiers();
int castingTick = stack.getMaxItemUseDuration() - count;
// Continuous spells (these must check if they can be cast each tick since the mana changes)
// In theory the spell is always continuous here but just in case it isn't...
// Do not check canCast() on tick 0 as it is already done in onItemRightClick() and would duplicate modifiers
if(spell.isContinuous && (castingTick == 0 || canCast(stack, spell, player, player.getActiveHand(), castingTick, modifiers))){
if(spell.isContinuous && canCast(stack, spell, player, player.getActiveHand(), castingTick, modifiers)){
cast(stack, spell, player, player.getActiveHand(), castingTick, modifiers);
}else{
// Scrolls normally work on the max use duration so this isn't ever reached by wizardry, but if the
@@ -1,79 +0,0 @@
package electroblob.wizardry.packet;
import electroblob.wizardry.Wizardry;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
/**
* <b>[Server -> Client]</b> This packet is sent when a bomb entity impacts something. It is used to guarantee that the
* client always sees the explosion effect, even in singleplayer where the server may remove the entity before the
* client's own simulation can call {@code onImpact()}.
*/
public class PacketBombExplosion implements IMessageHandler<PacketBombExplosion.Message, IMessage> {
/** Bomb type constants, matching the order bombs are handled in {@link electroblob.wizardry.CommonProxy}. */
public static final int FIREBOMB = 0;
public static final int POISON_BOMB = 1;
public static final int SMOKE_BOMB = 2;
public static final int SPARK_BOMB = 3;
@Override
public IMessage onMessage(Message message, MessageContext ctx){
if(ctx.side.isClient()){
net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(
() -> Wizardry.proxy.handleBombExplosionPacket(message));
}
return null;
}
public static class Message implements IMessage {
/** One of the bomb type constants defined in {@link PacketBombExplosion}. */
public int bombType;
public double x, y, z;
public float blastMultiplier;
/** Entity IDs of secondary targets struck by the spark bomb chain. Empty for other bomb types. */
public int[] secondaryTargetIDs;
// Required no-arg constructor
public Message(){}
public Message(int bombType, double x, double y, double z, float blastMultiplier){
this(bombType, x, y, z, blastMultiplier, new int[0]);
}
public Message(int bombType, double x, double y, double z, float blastMultiplier, int[] secondaryTargetIDs){
this.bombType = bombType;
this.x = x;
this.y = y;
this.z = z;
this.blastMultiplier = blastMultiplier;
this.secondaryTargetIDs = secondaryTargetIDs;
}
@Override
public void fromBytes(ByteBuf buf){
bombType = buf.readInt();
x = buf.readDouble();
y = buf.readDouble();
z = buf.readDouble();
blastMultiplier = buf.readFloat();
int count = buf.readInt();
secondaryTargetIDs = new int[count];
for(int i = 0; i < count; i++) secondaryTargetIDs[i] = buf.readInt();
}
@Override
public void toBytes(ByteBuf buf){
buf.writeInt(bombType);
buf.writeDouble(x);
buf.writeDouble(y);
buf.writeDouble(z);
buf.writeFloat(blastMultiplier);
buf.writeInt(secondaryTargetIDs.length);
for(int id : secondaryTargetIDs) buf.writeInt(id);
}
}
}
@@ -35,7 +35,6 @@ public class WizardryPacketHandler {
registerMessage(PacketSpellQuickAccess.class, PacketSpellQuickAccess.Message.class);
registerMessage(PacketRequestDonationPerks.class, PacketRequestDonationPerks.Message.class);
registerMessage(PacketSyncDonationPerks.class, PacketSyncDonationPerks.Message.class);
registerMessage(PacketBombExplosion.class, PacketBombExplosion.Message.class);
}
private static int nextPacketId = 0;
@@ -907,7 +907,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
* its JSON file using a resource pack. If called with no arguments, defaults to any context, i.e. only returns
* false if the spell is completely disabled in all contexts. */
public final boolean isEnabled(SpellProperties.Context... contexts){
return enabled && (contexts.length == 0 || (arePropertiesInitialised() && properties.isEnabled(contexts)));
return enabled && (contexts.length == 0 || properties.isEnabled(contexts));
}
/** Sets whether the spell is enabled or not. */
@@ -235,11 +235,12 @@ public class TileEntityImbuementAltar extends TileEntity implements ITickable {
*/
public static ItemStack getImbuementResult(ItemStack input, Element[] receptacleElements, boolean fullLootGen, World world, EntityPlayer lastUser){
ImbuementActivateEvent event = new ImbuementActivateEvent(input, receptacleElements, world, lastUser, ItemStack.EMPTY);
ItemStack eventResult = ItemStack.EMPTY;
if (world != null && MinecraftForge.EVENT_BUS.post(event)) {
// Event was cancelled; return whatever result the handler set (may be empty to suppress all recipes).
return event.result;
if (world != null && MinecraftForge.EVENT_BUS.post(new ImbuementActivateEvent(input, receptacleElements, world, lastUser, eventResult))) {
// return the stack if something changes the result from an empty stack.
//noinspection ConstantConditions
if (eventResult != ItemStack.EMPTY) return eventResult;
}
if(input.getItem() instanceof ItemWizardArmour && ((ItemWizardArmour)input.getItem()).element == null){
@@ -117,9 +117,6 @@ public final class AllyDesignationSystem {
// Always return true if the attacker is null - this must be after the target null check!
if(attacker == null) return true;
// Teammates are allies
if(attacker.isOnSameTeam(target)) return false;
// Tests whether the target is the attacker
if(target == attacker) return false;
@@ -223,10 +220,6 @@ public final class AllyDesignationSystem {
if(allyOf instanceof EntityPlayer && isOwnerAlly((EntityPlayer)allyOf, pet)) return true;
}
if(possibleAlly.isOnSameTeam(allyOf)) {
return true;
}
// Check if the possibleAlly is mind controlled by the allyOf entity
if(possibleAlly instanceof EntityLiving && possibleAlly.isPotionActive(WizardryPotions.mind_control)){
NBTTagCompound entityNBT = possibleAlly.getEntityData();
@@ -524,7 +524,6 @@ item.ebwizardry\:charm_move_speed.name=Icarus Medallion
item.ebwizardry\:charm_move_speed.desc=Move at near-full speed when casting spells
item.ebwizardry\:charm_spell_discovery.name=Archivist's Eyeglass
item.ebwizardry\:charm_spell_discovery.desc=Spell books found in chests are much more likely to be ones you have not yet discovered
item.ebwizardry\:charm_spell_discovery.desc.color=When equipped, you can see the element of a known spell book by the color of its bookmark
item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark
item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar
item.ebwizardry\:charm_lava_walking.name=Nether Ice Core
@@ -1693,10 +1692,6 @@ config.ebwizardry.replace_vanilla_fall_damage=Replace Vanilla Fall Damage
config.ebwizardry.replace_vanilla_fall_damage.tooltip=Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, velocity-based one. This is done such that mobs in freefall will take exactly the same damage as normal, so it will not break falling-based mob farms. Disable this if you experience falling-related weirdness! If this is disabled, some spells revert to a more simplistic method of resetting the player's fall damage in certain cases.
config.ebwizardry.replace_vanilla_fall_damage.true=Yes - it's parkour time
config.ebwizardry.replace_vanilla_fall_damage.false=No - break my legs normally
config.ebwizardry.spell_book_colors_require_charm=Spell Book Colors Require Archivist's Eyeglass
config.ebwizardry.spell_book_colors_require_charm.tooltip=Whether to require the Archivist's Eyeglass charm artifact to see colored spell book bookmarks.
config.ebwizardry.spell_book_colors_require_charm.true=Yes - I want to see the colours only if the charm is worn
config.ebwizardry.spell_book_colors_require_charm.false=No - I want to see the colours all the time
config.ebwizardry.blindness_tweak=Blindness Tweak
config.ebwizardry.blindness_tweak.tooltip=Whether to tweak the blindness effect to reduce follow distance when used on non-players. This automatically disables itself in favour of Potion Core's implementation if installed.
config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist
@@ -1,14 +1,14 @@
{
"parent": "ebwizardry:item/spell_book_undiscovered",
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book"
},
"overrides": [
{"predicate": {"ebwizardry:element": 1}, "model": "ebwizardry:item/spell_book_discovered_magic"},
{"predicate": {"ebwizardry:element": 2}, "model": "ebwizardry:item/spell_book_discovered_fire"},
{"predicate": {"ebwizardry:element": 3}, "model": "ebwizardry:item/spell_book_discovered_ice"},
{"predicate": {"ebwizardry:element": 4}, "model": "ebwizardry:item/spell_book_discovered_lightning"},
{"predicate": {"ebwizardry:element": 5}, "model": "ebwizardry:item/spell_book_discovered_necromancy"},
{"predicate": {"ebwizardry:element": 6}, "model": "ebwizardry:item/spell_book_discovered_earth"},
{"predicate": {"ebwizardry:element": 7}, "model": "ebwizardry:item/spell_book_discovered_sorcery"},
{"predicate": {"ebwizardry:element": 8}, "model": "ebwizardry:item/spell_book_discovered_healing"},
{"predicate": {"festive": 1}, "model": "ebwizardry:item/festive_spell_book"}
{
"predicate": {
"festive": 1
},
"model": "ebwizardry:item/festive_spell_book"
}
]
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_earth"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_fire"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_healing"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_ice"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_lightning"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_magic"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_necromancy"
}
}
@@ -1,7 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book",
"layer1": "ebwizardry:items/spell_book_overlay_sorcery"
}
}
@@ -1,6 +0,0 @@
{
"parent": "item/generated",
"textures": {
"layer0": "ebwizardry:items/spell_book"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B