Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 01cea3df06 | |||
| 591cfb5857 | |||
| bc2037f74e | |||
| 6aa3b21190 | |||
| b262b6edc0 | |||
| b7be05669b | |||
| 071e299d48 | |||
| 1e885d70c3 | |||
| e04a43e56d | |||
| 378796cdda | |||
| 48c37d1c17 | |||
| fe8f9fc5cd | |||
| ced6ab7e8d | |||
| 378e02eb6c | |||
| 4677d9ff30 | |||
| 0541b2171b | |||
| dc59a14e82 | |||
| 1a13afb6e3 | |||
| 03dd76c18a | |||
| 9426a96df3 | |||
| 382faf59c9 | |||
| cab68e23ac | |||
| 60a6c5124e | |||
| 028b753be6 | |||
| d020668e0c | |||
| 656a78962e | |||
| 5a2f5aa295 | |||
| 5e37a2322c | |||
| 3ca9f200fd | |||
| 37e3a842f5 | |||
| 4e8e2c951b | |||
| 43b66df22a | |||
| b192a431d7 | |||
| 3be98ab612 | |||
| ed950322ff |
@@ -23,6 +23,7 @@ run
|
|||||||
logs
|
logs
|
||||||
/misc
|
/misc
|
||||||
/libs
|
/libs
|
||||||
|
libs_src
|
||||||
libsfordeobf
|
libsfordeobf
|
||||||
generated
|
generated
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
Electroblob's Wizardry
|
Electroblob's Wizardry
|
||||||
Version 4.1.4
|
Version 4.2.3
|
||||||
For Minecraft 1.12.2
|
For Minecraft 1.12.2
|
||||||
|
|
||||||
Designed, coded and textured by Electroblob
|
Designed, coded and textured by Electroblob
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/relations/dependents) [](https://discord.gg/MTmMzMv)
|
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://discord.gg/MTmMzMv)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
|
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
|
||||||
|
|
||||||
Please read the [guide for contributing](guide_for_contributing.md) before submitting an issue or a PR.
|
Please read the [guide for contributing](CONTRIBUTING.md) before submitting an issue or a PR.
|
||||||
|
|
||||||
<b>Links</b>
|
<b>Links</b>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
|
|||||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||||
|
|
||||||
|
|
||||||
version = "4.2.2" // There, it matches semver, happy now?
|
version = "4.2.5" // There, it matches semver, happy now?
|
||||||
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
archivesBaseName = "ElectroblobsWizardry"
|
archivesBaseName = "ElectroblobsWizardry"
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
|||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -364,7 +365,7 @@ public final class Settings {
|
|||||||
*/
|
*/
|
||||||
void initConfig(FMLPreInitializationEvent event){
|
void initConfig(FMLPreInitializationEvent event){
|
||||||
|
|
||||||
config = new Configuration(event.getSuggestedConfigurationFile());
|
config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg"));
|
||||||
config.load();
|
config.load();
|
||||||
|
|
||||||
Wizardry.logger.info("Setting up main config");
|
Wizardry.logger.info("Setting up main config");
|
||||||
@@ -700,7 +701,7 @@ public final class Settings {
|
|||||||
fastWorldgen = property.getBoolean();
|
fastWorldgen = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate.");
|
property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_dimensions");
|
property.setLanguageKey("config." + Wizardry.MODID + ".tower_dimensions");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
towerDimensions = property.getIntList();
|
towerDimensions = property.getIntList();
|
||||||
@@ -725,20 +726,20 @@ public final class Settings {
|
|||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "towerFiles", new String[]{Wizardry.MODID + ":wizard_tower_0", Wizardry.MODID + ":wizard_tower_1", Wizardry.MODID + ":wizard_tower_2", Wizardry.MODID + ":wizard_tower_3"},
|
property = config.get(WORLDGEN_CATEGORY, "towerFiles", new String[]{Wizardry.MODID + ":wizard_tower_0", Wizardry.MODID + ":wizard_tower_1", Wizardry.MODID + ":wizard_tower_2", Wizardry.MODID + ":wizard_tower_3"},
|
||||||
"List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
"List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_files");
|
property.setLanguageKey("config." + Wizardry.MODID + ".tower_files");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
towerFiles = getResourceLocationList(property);
|
towerFiles = getResourceLocationList(property);
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "towerWithChestFiles", new String[]{Wizardry.MODID + ":wizard_tower_chest_0", Wizardry.MODID + ":wizard_tower_chest_1", Wizardry.MODID + ":wizard_tower_chest_2", Wizardry.MODID + ":wizard_tower_chest_3"},
|
property = config.get(WORLDGEN_CATEGORY, "towerWithChestFiles", new String[]{Wizardry.MODID + ":wizard_tower_chest_0", Wizardry.MODID + ":wizard_tower_chest_1", Wizardry.MODID + ":wizard_tower_chest_2", Wizardry.MODID + ":wizard_tower_chest_3"},
|
||||||
"List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
"List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_with_chest_files");
|
property.setLanguageKey("config." + Wizardry.MODID + ".tower_with_chest_files");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
towerWithChestFiles = getResourceLocationList(property);
|
towerWithChestFiles = getResourceLocationList(property);
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate.");
|
property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate. Remove all dimensions to disable obelisks completely.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_dimensions");
|
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_dimensions");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
obeliskDimensions = property.getIntList();
|
obeliskDimensions = property.getIntList();
|
||||||
@@ -752,13 +753,13 @@ public final class Settings {
|
|||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "obeliskFiles", new String[]{Wizardry.MODID + ":obelisk_0", Wizardry.MODID + ":obelisk_1", Wizardry.MODID + ":obelisk_2", Wizardry.MODID + ":obelisk_3", Wizardry.MODID + ":obelisk_4"},
|
property = config.get(WORLDGEN_CATEGORY, "obeliskFiles", new String[]{Wizardry.MODID + ":obelisk_0", Wizardry.MODID + ":obelisk_1", Wizardry.MODID + ":obelisk_2", Wizardry.MODID + ":obelisk_3", Wizardry.MODID + ":obelisk_4"},
|
||||||
"List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
"List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable obelisks, use the obelisk dimensions setting.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_files");
|
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_files");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
obeliskFiles = getResourceLocationList(property);
|
obeliskFiles = getResourceLocationList(property);
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate.");
|
property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate. Remove all dimensions to disable shrines completely.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_dimensions");
|
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_dimensions");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
shrineDimensions = property.getIntList();
|
shrineDimensions = property.getIntList();
|
||||||
@@ -772,7 +773,7 @@ public final class Settings {
|
|||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "shrineFiles", new String[]{Wizardry.MODID + ":shrine_0", Wizardry.MODID + ":shrine_1", Wizardry.MODID + ":shrine_2", Wizardry.MODID + ":shrine_3", Wizardry.MODID + ":shrine_4", Wizardry.MODID + ":shrine_5", Wizardry.MODID + ":shrine_6", Wizardry.MODID + ":shrine_7"},
|
property = config.get(WORLDGEN_CATEGORY, "shrineFiles", new String[]{Wizardry.MODID + ":shrine_0", Wizardry.MODID + ":shrine_1", Wizardry.MODID + ":shrine_2", Wizardry.MODID + ":shrine_3", Wizardry.MODID + ":shrine_4", Wizardry.MODID + ":shrine_5", Wizardry.MODID + ":shrine_6", Wizardry.MODID + ":shrine_7"},
|
||||||
"List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
"List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable shrines, use the shrine dimensions setting.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_files");
|
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_files");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
shrineFiles = getResourceLocationList(property);
|
shrineFiles = getResourceLocationList(property);
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import electroblob.wizardry.misc.Forfeit;
|
|||||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.*;
|
import electroblob.wizardry.registry.*;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.CustomSoundCategory;
|
|
||||||
import electroblob.wizardry.util.SpellProperties;
|
import electroblob.wizardry.util.SpellProperties;
|
||||||
import electroblob.wizardry.worldgen.*;
|
import electroblob.wizardry.worldgen.*;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.util.SoundCategory;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.RegistryEvent;
|
import net.minecraftforge.event.RegistryEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
@@ -31,6 +31,8 @@ import net.minecraftforge.fml.common.network.NetworkRegistry;
|
|||||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <i>"Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as
|
* <i>"Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as
|
||||||
* possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
|
* possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
|
||||||
@@ -61,7 +63,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.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.
|
* 1.11.x versions, and so on.
|
||||||
*/
|
*/
|
||||||
public static final String VERSION = "4.2.2";
|
public static final String VERSION = "4.2.5";
|
||||||
|
|
||||||
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
||||||
// IDEA: Abstract the vanilla particles behind the particle builder
|
// IDEA: Abstract the vanilla particles behind the particle builder
|
||||||
@@ -82,6 +84,10 @@ public class Wizardry {
|
|||||||
* - <b>INFO</b>: Anything that might happen during normal mod operation that the user needs to know about. */
|
* - <b>INFO</b>: Anything that might happen during normal mod operation that the user needs to know about. */
|
||||||
public static Logger logger;
|
public static Logger logger;
|
||||||
|
|
||||||
|
/** A {@link File} object representing wizardry's config folder, {@code config/ebwizardry}). As of wizardry 4.2.4,
|
||||||
|
* this folder contains the main config file and the global spell properties folder, if used. */
|
||||||
|
public static File configDirectory;
|
||||||
|
|
||||||
// The instance of wizardry that Forge uses.
|
// The instance of wizardry that Forge uses.
|
||||||
@Instance(Wizardry.MODID)
|
@Instance(Wizardry.MODID)
|
||||||
public static Wizardry instance;
|
public static Wizardry instance;
|
||||||
@@ -97,6 +103,7 @@ public class Wizardry {
|
|||||||
|
|
||||||
proxy.registerResourceReloadListeners();
|
proxy.registerResourceReloadListeners();
|
||||||
|
|
||||||
|
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
|
||||||
settings.initConfig(event);
|
settings.initConfig(event);
|
||||||
|
|
||||||
// Capabilities
|
// Capabilities
|
||||||
@@ -113,7 +120,8 @@ public class Wizardry {
|
|||||||
proxy.registerRenderers();
|
proxy.registerRenderers();
|
||||||
proxy.registerKeyBindings();
|
proxy.registerKeyBindings();
|
||||||
|
|
||||||
WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + "_spells");
|
// Commented out for 4.2.3 to get rid of the sound bug, reinstate once a fix is found.
|
||||||
|
WizardrySounds.SPELLS = SoundCategory.PLAYERS;//CustomSoundCategory.add(Wizardry.MODID + "_spells");
|
||||||
|
|
||||||
WizardryBaublesIntegration.init();
|
WizardryBaublesIntegration.init();
|
||||||
WizardryAntiqueAtlasIntegration.init();
|
WizardryAntiqueAtlasIntegration.init();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package electroblob.wizardry;
|
|||||||
|
|
||||||
import electroblob.wizardry.item.ItemSpellBook;
|
import electroblob.wizardry.item.ItemSpellBook;
|
||||||
import electroblob.wizardry.item.ItemWizardHandbook;
|
import electroblob.wizardry.item.ItemWizardHandbook;
|
||||||
import electroblob.wizardry.spell.Spell;
|
|
||||||
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
|
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
|
||||||
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
|
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
|
||||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||||
@@ -48,9 +47,9 @@ public class WizardryGuiHandler implements IGuiHandler {
|
|||||||
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
|
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
|
||||||
}else if(id == SPELL_BOOK){
|
}else if(id == SPELL_BOOK){
|
||||||
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
|
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
|
||||||
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemMainhand().getItemDamage()));
|
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemMainhand());
|
||||||
}else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
|
}else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
|
||||||
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemOffhand().getItemDamage()));
|
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemOffhand());
|
||||||
}
|
}
|
||||||
}else if(id == PORTABLE_CRAFTING){
|
}else if(id == PORTABLE_CRAFTING){
|
||||||
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
|
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package electroblob.wizardry.client.gui;
|
package electroblob.wizardry.client.gui;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.client.DrawingUtils;
|
import electroblob.wizardry.client.DrawingUtils;
|
||||||
import electroblob.wizardry.constants.Tier;
|
import electroblob.wizardry.constants.Tier;
|
||||||
import electroblob.wizardry.data.SpellGlyphData;
|
import electroblob.wizardry.data.SpellGlyphData;
|
||||||
import electroblob.wizardry.data.WizardData;
|
import electroblob.wizardry.data.WizardData;
|
||||||
|
import electroblob.wizardry.item.ItemSpellBook;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
@@ -14,27 +14,22 @@ import net.minecraft.client.audio.PositionedSoundRecord;
|
|||||||
import net.minecraft.client.gui.GuiScreen;
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.item.ItemStack;
|
||||||
import org.lwjgl.input.Keyboard;
|
import org.lwjgl.input.Keyboard;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class GuiSpellBook extends GuiScreen {
|
public class GuiSpellBook extends GuiScreen {
|
||||||
|
|
||||||
private int xSize, ySize;
|
private int xSize, ySize;
|
||||||
|
private ItemSpellBook book;
|
||||||
private Spell spell;
|
private Spell spell;
|
||||||
|
|
||||||
private static final Map<Tier, ResourceLocation> textures = ImmutableMap.of(
|
public GuiSpellBook(ItemStack stack){
|
||||||
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
|
||||||
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
|
||||||
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
|
||||||
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
|
||||||
|
|
||||||
public GuiSpellBook(Spell spell){
|
|
||||||
super();
|
super();
|
||||||
xSize = 288;
|
xSize = 288;
|
||||||
ySize = 180;
|
ySize = 180;
|
||||||
this.spell = spell;
|
if(!(stack.getItem() instanceof ItemSpellBook)) throw new ClassCastException("Cannot create spell book GUI for item that does not extend ItemSpellBook!");
|
||||||
|
this.book = (ItemSpellBook)stack.getItem();
|
||||||
|
this.spell = Spell.byMetadata(stack.getItemDamage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,7 +54,7 @@ public class GuiSpellBook extends GuiScreen {
|
|||||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
||||||
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128);
|
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128);
|
||||||
|
|
||||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.getTier()));
|
Minecraft.getMinecraft().renderEngine.bindTexture(book.getGuiTexture(spell));
|
||||||
DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
|
DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
|
||||||
|
|
||||||
super.drawScreen(par1, par2, par3);
|
super.drawScreen(par1, par2, par3);
|
||||||
@@ -77,7 +72,7 @@ public class GuiSpellBook extends GuiScreen {
|
|||||||
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
||||||
|
|
||||||
if(spell.getTier() == Tier.NOVICE){
|
if(spell.getTier() == Tier.NOVICE){
|
||||||
// Basic is usually white but this doesn't show up.
|
// Novice is usually white but this doesn't show up.
|
||||||
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
|
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
|
||||||
}else{
|
}else{
|
||||||
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemCrystal;
|
|||||||
import electroblob.wizardry.registry.WizardryBlocks;
|
import electroblob.wizardry.registry.WizardryBlocks;
|
||||||
import electroblob.wizardry.registry.WizardryItems;
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||||
|
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||||
import net.minecraft.client.renderer.block.statemap.StateMap;
|
import net.minecraft.client.renderer.block.statemap.StateMap;
|
||||||
import net.minecraft.creativetab.CreativeTabs;
|
import net.minecraft.creativetab.CreativeTabs;
|
||||||
@@ -294,24 +295,13 @@ public final class WizardryModels {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers an item model, using the item's registry name as the model name (this convention makes it easier to
|
* Registers an item model, using the item's registry name as the model name (this convention makes it easier to
|
||||||
* keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus
|
* keep track of everything). Variant defaults to "normal". Registers the model for all metadata values.
|
||||||
* all the other metadata values that the item can take, as defined in
|
|
||||||
* {@link Item#getSubItems(CreativeTabs, NonNullList)}. The creative tab supplied
|
|
||||||
* to the aforementioned method will be whichever one the item is in.
|
|
||||||
*/
|
*/
|
||||||
private static void registerItemModel(Item item){
|
private static void registerItemModel(Item item){
|
||||||
|
|
||||||
if(item.getHasSubtypes()){
|
|
||||||
NonNullList<ItemStack> items = NonNullList.create();
|
|
||||||
item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK.
|
|
||||||
for(ItemStack stack : items){
|
|
||||||
ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(),
|
|
||||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
||||||
ModelLoader.setCustomModelResourceLocation(item, 0,
|
ModelBakery.registerItemVariants(item, new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
// Assigns the model for all metadata values
|
||||||
|
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import java.util.Random;
|
|||||||
public enum Tier {
|
public enum Tier {
|
||||||
|
|
||||||
NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"),
|
NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"),
|
||||||
APPRENTICE(1000, 5, 5, 4000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
APPRENTICE(1000, 5, 5, 2000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||||
ADVANCED(1500, 7, 2, 6000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
ADVANCED(1500, 7, 2, 3500, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||||
MASTER(2500, 9, 1, 10000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
MASTER(2500, 9, 1, 6000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
||||||
|
|
||||||
/** Maximum mana a wand of this tier can store. */
|
/** Maximum mana a wand of this tier can store. */
|
||||||
public final int maxCharge;
|
public final int maxCharge;
|
||||||
|
|||||||
@@ -35,11 +35,17 @@ import net.minecraft.world.DifficultyInstance;
|
|||||||
import net.minecraft.world.EnumDifficulty;
|
import net.minecraft.world.EnumDifficulty;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.util.Constants.NBT;
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@Mod.EventBusSubscriber
|
||||||
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
|
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
|
||||||
|
|
||||||
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
|
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
|
||||||
@@ -283,16 +289,6 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
|||||||
public int getMaxSpawnedInChunk(){
|
public int getMaxSpawnedInChunk(){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getCanSpawnHere(){
|
|
||||||
// Evil wizards can only spawn in the specified dimensions
|
|
||||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
|
||||||
if(this.dimension == id) return super.getCanSpawnHere();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canDespawn(){
|
protected boolean canDespawn(){
|
||||||
@@ -393,4 +389,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
|||||||
textureIndex = data.readInt();
|
textureIndex = data.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
|
||||||
|
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
|
||||||
|
if(event.getEntityLiving() instanceof EntityEvilWizard && !event.isSpawner()){
|
||||||
|
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
|
||||||
|
event.setResult(Event.Result.DENY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ import net.minecraft.util.EnumHand;
|
|||||||
import net.minecraft.util.EnumParticleTypes;
|
import net.minecraft.util.EnumParticleTypes;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
@Mod.EventBusSubscriber
|
||||||
public class EntityIceWraith extends EntityBlazeMinion {
|
public class EntityIceWraith extends EntityBlazeMinion {
|
||||||
|
|
||||||
/** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */
|
/** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */
|
||||||
@@ -185,12 +191,16 @@ public class EntityIceWraith extends EntityBlazeMinion {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getCanSpawnHere(){
|
public boolean getCanSpawnHere(){
|
||||||
// Only spawns in the specified dimensions
|
return super.getCanSpawnHere() && this.isValidLightLevel();
|
||||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
}
|
||||||
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
@SubscribeEvent
|
||||||
|
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
|
||||||
|
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
|
||||||
|
if(event.getEntityLiving() instanceof EntityLightningWraith && !event.isSpawner()){
|
||||||
|
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
|
||||||
|
event.setResult(Event.Result.DENY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,7 +13,16 @@ import net.minecraft.init.MobEffects;
|
|||||||
import net.minecraft.util.DamageSource;
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.IntPredicate;
|
||||||
|
|
||||||
|
@Mod.EventBusSubscriber
|
||||||
public class EntityLightningWraith extends EntityBlazeMinion {
|
public class EntityLightningWraith extends EntityBlazeMinion {
|
||||||
|
|
||||||
public EntityLightningWraith(World world){
|
public EntityLightningWraith(World world){
|
||||||
@@ -74,14 +83,17 @@ public class EntityLightningWraith extends EntityBlazeMinion {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getCanSpawnHere(){
|
public boolean getCanSpawnHere(){
|
||||||
// Only spawns in the specified dimensions, during thunderstorms
|
return super.getCanSpawnHere() && this.isValidLightLevel();
|
||||||
if(!world.isThundering()) return false;
|
}
|
||||||
|
|
||||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
@SubscribeEvent
|
||||||
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel();
|
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
|
||||||
|
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
|
||||||
|
if(event.getEntityLiving() instanceof EntityLightningWraith && !event.isSpawner()){
|
||||||
|
if(!event.getWorld().isThundering()) event.setResult(Event.Result.DENY);
|
||||||
|
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
|
||||||
|
event.setResult(Event.Result.DENY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -780,6 +780,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
Tier maxTier = Tier.NOVICE;
|
Tier maxTier = Tier.NOVICE;
|
||||||
|
|
||||||
List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells);
|
List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells);
|
||||||
|
npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book));
|
||||||
|
|
||||||
for(int i = 0; i < n; i++){
|
for(int i = 0; i < n; i++){
|
||||||
|
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ public class ItemArtefact extends Item {
|
|||||||
|
|
||||||
if(artefact == WizardryItems.ring_condensing){
|
if(artefact == WizardryItems.ring_condensing){
|
||||||
|
|
||||||
if(world.isRemote && player.ticksExisted % 150 == 0){
|
if(player.ticksExisted % 150 == 0){
|
||||||
for(ItemStack stack : WizardryUtilities.getHotbar(player)){
|
for(ItemStack stack : WizardryUtilities.getHotbar(player)){
|
||||||
// Needs to be both of these interfaces because this ring only recharges wands
|
// Needs to be both of these interfaces because this ring only recharges wands
|
||||||
// (or more accurately, chargeable spellcasting items)
|
// (or more accurately, chargeable spellcasting items)
|
||||||
@@ -276,7 +276,7 @@ public class ItemArtefact extends Item {
|
|||||||
|
|
||||||
}else if(artefact == WizardryItems.amulet_arcane_defence){
|
}else if(artefact == WizardryItems.amulet_arcane_defence){
|
||||||
|
|
||||||
if(world.isRemote && player.ticksExisted % 300 == 0){
|
if(player.ticksExisted % 300 == 0){
|
||||||
for(ItemStack stack : player.getArmorInventoryList()){
|
for(ItemStack stack : player.getArmorInventoryList()){
|
||||||
// IManaStoringItem is sufficient, since anything in the armour slots is probably armour
|
// IManaStoringItem is sufficient, since anything in the armour slots is probably armour
|
||||||
if(stack.getItem() instanceof IManaStoringItem)
|
if(stack.getItem() instanceof IManaStoringItem)
|
||||||
@@ -601,7 +601,7 @@ public class ItemArtefact extends Item {
|
|||||||
|
|
||||||
}else if(artefact == WizardryItems.amulet_transience){
|
}else if(artefact == WizardryItems.amulet_transience){
|
||||||
|
|
||||||
if(player.getHealth() <= 2 && player.world.rand.nextFloat() < 0.25f){
|
if(player.getHealth() <= 6 && player.world.rand.nextFloat() < 0.25f){
|
||||||
player.addPotionEffect(new PotionEffect(WizardryPotions.transience, 300));
|
player.addPotionEffect(new PotionEffect(WizardryPotions.transience, 300));
|
||||||
player.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 300, 0, false, false));
|
player.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 300, 0, false, false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,13 +51,14 @@ public class ItemScroll extends Item implements ISpellCastingItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
||||||
|
|
||||||
if(tab == WizardryTabs.SPELLS){
|
if(tab == WizardryTabs.SPELLS){
|
||||||
// In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance
|
|
||||||
// is not required, only the metadata.
|
List<Spell> spells = Spell.getSpells(Spell.allSpells);
|
||||||
for(int i = 0; i < Spell.getTotalSpellCount(); i++){
|
spells.removeIf(s -> !s.applicableForItem(this));
|
||||||
// i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata
|
|
||||||
// 0 and since this is not used as a spell book the metadata starts at 1.
|
for(Spell spell : spells){
|
||||||
list.add(new ItemStack(this, 1, i + 1));
|
list.add(new ItemStack(this, 1, spell.metadata()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.WizardryGuiHandler;
|
import electroblob.wizardry.WizardryGuiHandler;
|
||||||
|
import electroblob.wizardry.constants.Tier;
|
||||||
import electroblob.wizardry.data.SpellGlyphData;
|
import electroblob.wizardry.data.SpellGlyphData;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
@@ -9,19 +11,23 @@ import net.minecraft.creativetab.CreativeTabs;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.*;
|
||||||
import net.minecraft.util.EnumActionResult;
|
|
||||||
import net.minecraft.util.EnumHand;
|
|
||||||
import net.minecraft.util.NonNullList;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import net.minecraftforge.oredict.OreDictionary;
|
import net.minecraftforge.oredict.OreDictionary;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ItemSpellBook extends Item {
|
public class ItemSpellBook extends Item {
|
||||||
|
|
||||||
|
private static final Map<Tier, ResourceLocation> guiTextures = ImmutableMap.of(
|
||||||
|
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
||||||
|
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
||||||
|
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
||||||
|
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
||||||
|
|
||||||
public ItemSpellBook(){
|
public ItemSpellBook(){
|
||||||
super();
|
super();
|
||||||
setHasSubtypes(true);
|
setHasSubtypes(true);
|
||||||
@@ -31,13 +37,14 @@ public class ItemSpellBook extends Item {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
||||||
|
|
||||||
if(tab == WizardryTabs.SPELLS){
|
if(tab == WizardryTabs.SPELLS){
|
||||||
// In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance
|
|
||||||
// is not required, only the metadata.
|
List<Spell> spells = Spell.getSpells(Spell.allSpells);
|
||||||
for(int i = 0; i < Spell.getTotalSpellCount(); i++){
|
spells.removeIf(s -> !s.applicableForItem(this));
|
||||||
// i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata
|
|
||||||
// 0 and since this is not used as a spell book the metadata starts at 1.
|
for(Spell spell : spells){
|
||||||
list.add(new ItemStack(this, 1, i + 1));
|
list.add(new ItemStack(this, 1, spell.metadata()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,4 +86,12 @@ public class ItemSpellBook extends Item {
|
|||||||
return Wizardry.proxy.getFontRenderer(stack);
|
return Wizardry.proxy.getFontRenderer(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the GUI texture to be used when this spell book is opened.
|
||||||
|
* @param spell The spell for the book being opened.
|
||||||
|
*/
|
||||||
|
public ResourceLocation getGuiTexture(Spell spell){
|
||||||
|
return guiTextures.get(spell.getTier());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,10 +108,14 @@ public class RandomSpell extends LootFunction {
|
|||||||
// element = null;
|
// element = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpellProperties.Context spellContext = context.getLootedEntity() == null ? SpellProperties.Context.TREASURE
|
||||||
|
: SpellProperties.Context.LOOTING;
|
||||||
|
|
||||||
// Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting
|
// Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting
|
||||||
// the spell randomiser use any element) change the overall outcome at all?
|
// the spell randomiser use any element) change the overall outcome at all?
|
||||||
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.TREASURE));
|
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, spellContext));
|
||||||
|
|
||||||
|
spellsList.removeIf(s -> !s.applicableForItem(stack.getItem()));
|
||||||
if(stack.getItem() instanceof ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
|
if(stack.getItem() instanceof ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
|
||||||
if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK));
|
if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK));
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.gson.JsonSerializationContext;
|
import com.google.gson.JsonSerializationContext;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.entity.living.ISpellCaster;
|
import electroblob.wizardry.entity.living.ISpellCaster;
|
||||||
|
import electroblob.wizardry.item.ItemScroll;
|
||||||
import electroblob.wizardry.item.ItemSpellBook;
|
import electroblob.wizardry.item.ItemSpellBook;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
@@ -33,13 +34,18 @@ public class WizardSpell extends LootFunction {
|
|||||||
@Override
|
@Override
|
||||||
public ItemStack apply(ItemStack stack, Random random, LootContext context){
|
public ItemStack apply(ItemStack stack, Random random, LootContext context){
|
||||||
|
|
||||||
if(!(stack.getItem() instanceof ItemSpellBook)) Wizardry.logger
|
if(!(stack.getItem() instanceof ItemSpellBook) && !(stack.getItem() instanceof ItemScroll)) Wizardry.logger
|
||||||
.warn("Applying the wizard_spell loot function to an item that isn't a spell book or scroll.");
|
.warn("Applying the wizard_spell loot function to an item that isn't a spell book or scroll.");
|
||||||
|
|
||||||
if(context.getLootedEntity() instanceof ISpellCaster){
|
if(context.getLootedEntity() instanceof ISpellCaster){
|
||||||
List<Spell> spells = ((ISpellCaster)context.getLootedEntity()).getSpells();
|
List<Spell> spells = ((ISpellCaster)context.getLootedEntity()).getSpells();
|
||||||
spells.remove(Spells.magic_missile); // Can't drop magic missile
|
spells.remove(Spells.magic_missile); // Can't drop magic missile
|
||||||
stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata());
|
spells.removeIf(s -> !s.applicableForItem(stack.getItem()));
|
||||||
|
if(spells.isEmpty()){
|
||||||
|
Wizardry.logger.warn("Tried to apply the wizard_spell loot function to an item, but none of the looted entity's spells were applicable for that item. This is probably a bug!");
|
||||||
|
}else{
|
||||||
|
stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata());
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster.");
|
Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public abstract class Forfeit {
|
|||||||
|
|
||||||
event.setCanceled(true);
|
event.setCanceled(true);
|
||||||
|
|
||||||
Forfeit forfeit = getRandomForfeit(event.getWorld().rand, event.getSpell().getTier(), event.getSpell().getElement());
|
Forfeit forfeit = getRandomForfeit(data.synchronisedRandom, event.getSpell().getTier(), event.getSpell().getElement());
|
||||||
|
|
||||||
if(forfeit == null){ // Should never happen, but just in case...
|
if(forfeit == null){ // Should never happen, but just in case...
|
||||||
if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing"));
|
if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing"));
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
|||||||
import net.minecraftforge.oredict.OreDictionary;
|
import net.minecraftforge.oredict.OreDictionary;
|
||||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a dynamic crafting recipe for recharging items with mana flasks.
|
* Implements a dynamic crafting recipe for recharging items with mana flasks.
|
||||||
*
|
*
|
||||||
@@ -42,16 +40,17 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
|||||||
this.flask = flask;
|
this.flask = flask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
// Commented out for now because JEI spams the log with errors about the recipe having no output
|
||||||
@Override
|
// @Nonnull
|
||||||
public ItemStack getRecipeOutput(){
|
// @Override
|
||||||
return ItemStack.EMPTY; // According to the javadoc, dynamic recipes are supposed to return an empty stack here
|
// public ItemStack getRecipeOutput(){
|
||||||
}
|
// return ItemStack.EMPTY; // According to the javadoc, dynamic recipes are supposed to return an empty stack here
|
||||||
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getCraftingResult(InventoryCrafting inv){
|
public ItemStack getCraftingResult(InventoryCrafting inv){
|
||||||
ItemStack result = super.getCraftingResult(inv);
|
ItemStack result = super.getCraftingResult(inv);
|
||||||
rechargeItem(result, inv);
|
rechargeItemAndCopyNBT(result, inv);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,11 +61,12 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
|||||||
return super.matches(inv, world);
|
return super.matches(inv, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rechargeItem(ItemStack toCharge, InventoryCrafting inv){
|
private void rechargeItemAndCopyNBT(ItemStack toCharge, InventoryCrafting inv){
|
||||||
if(toCharge.getItem() == chargeable){
|
if(toCharge.getItem() == chargeable){
|
||||||
ItemStack stack = findItemToCharge(inv);
|
ItemStack stack = findItemToCharge(inv);
|
||||||
if(!stack.isEmpty()) chargeable.setMana(toCharge, chargeable.getMana(stack));
|
if(!stack.isEmpty()) chargeable.setMana(toCharge, chargeable.getMana(stack));
|
||||||
chargeable.rechargeMana(toCharge, flask.size.capacity);
|
chargeable.rechargeMana(toCharge, flask.size.capacity);
|
||||||
|
toCharge.setTagCompound(stack.getTagCompound()); // Copy NBT to new stack
|
||||||
}else{
|
}else{
|
||||||
Wizardry.logger.warn("Tried to recharge item {} with mana flask, but it did not match the recipe result {}!", toCharge.getItem(), chargeable);
|
Wizardry.logger.warn("Tried to recharge item {} with mana flask, but it did not match the recipe result {}!", toCharge.getItem(), chargeable);
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
|||||||
if(recipe instanceof RecipeRechargeWithFlask
|
if(recipe instanceof RecipeRechargeWithFlask
|
||||||
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
|
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
|
||||||
// Have to modify the itemstack in the actual event, it cannot be replaced
|
// Have to modify the itemstack in the actual event, it cannot be replaced
|
||||||
((RecipeRechargeWithFlask)recipe).rechargeItem(event.crafting, (InventoryCrafting)event.craftMatrix);
|
((RecipeRechargeWithFlask)recipe).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package electroblob.wizardry.spell;
|
package electroblob.wizardry.spell;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
import electroblob.wizardry.registry.WizardryItems;
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
import electroblob.wizardry.registry.WizardryPotions;
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
@@ -18,12 +19,21 @@ import net.minecraft.util.math.Vec3d;
|
|||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.event.entity.living.LivingEvent;
|
import net.minecraftforge.event.entity.living.LivingEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||||
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
public class ArcaneJammer extends SpellRay {
|
public class ArcaneJammer extends SpellRay {
|
||||||
|
|
||||||
|
private static final Field spellTicks;
|
||||||
|
|
||||||
|
static { // Yay more reflection
|
||||||
|
spellTicks = ObfuscationReflectionHelper.findField(EntitySpellcasterIllager.class, "field_193087_b");
|
||||||
|
}
|
||||||
|
|
||||||
public ArcaneJammer(){
|
public ArcaneJammer(){
|
||||||
super("arcane_jammer", false, EnumAction.NONE);
|
super("arcane_jammer", false, EnumAction.NONE);
|
||||||
this.soundValues(0.7f, 1, 0.4f);
|
this.soundValues(0.7f, 1, 0.4f);
|
||||||
@@ -68,9 +78,17 @@ public class ArcaneJammer extends SpellRay {
|
|||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){
|
public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){
|
||||||
|
|
||||||
if(event.getEntity() instanceof EntitySpellcasterIllager
|
if(event.getEntity() instanceof EntitySpellcasterIllager
|
||||||
&& event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){
|
&& event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){
|
||||||
|
|
||||||
((EntitySpellcasterIllager)event.getEntity()).setSpellType(EntitySpellcasterIllager.SpellType.NONE);
|
((EntitySpellcasterIllager)event.getEntity()).setSpellType(EntitySpellcasterIllager.SpellType.NONE);
|
||||||
|
|
||||||
|
try{
|
||||||
|
spellTicks.set(event.getEntity(), 10);
|
||||||
|
}catch(IllegalAccessException e){
|
||||||
|
Wizardry.logger.error("Error setting evoker spell timer:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemSpellBook;
|
|||||||
import electroblob.wizardry.packet.PacketSpellProperties;
|
import electroblob.wizardry.packet.PacketSpellProperties;
|
||||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.util.SpellModifiers;
|
import electroblob.wizardry.util.SpellModifiers;
|
||||||
import electroblob.wizardry.util.SpellProperties;
|
import electroblob.wizardry.util.SpellProperties;
|
||||||
@@ -18,6 +19,7 @@ import net.minecraft.entity.EntityLivingBase;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
import net.minecraft.item.EnumAction;
|
import net.minecraft.item.EnumAction;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
@@ -27,6 +29,10 @@ import net.minecraft.util.text.ITextComponent;
|
|||||||
import net.minecraft.util.text.TextComponentTranslation;
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.event.RegistryEvent;
|
import net.minecraftforge.event.RegistryEvent;
|
||||||
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import net.minecraftforge.registries.ForgeRegistry;
|
import net.minecraftforge.registries.ForgeRegistry;
|
||||||
@@ -82,6 +88,7 @@ import java.util.stream.Collectors;
|
|||||||
* @see ItemScroll ItemScroll
|
* @see ItemScroll ItemScroll
|
||||||
* @see Spells
|
* @see Spells
|
||||||
*/
|
*/
|
||||||
|
@Mod.EventBusSubscriber
|
||||||
public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements Comparable<Spell> {
|
public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements Comparable<Spell> {
|
||||||
|
|
||||||
// Spell checklist:
|
// Spell checklist:
|
||||||
@@ -115,6 +122,8 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
|||||||
private final String unlocalisedName;
|
private final String unlocalisedName;
|
||||||
/** This spell's associated SpellProperties object. */
|
/** This spell's associated SpellProperties object. */
|
||||||
private SpellProperties properties;
|
private SpellProperties properties;
|
||||||
|
/** A reference to the global spell properties for this spell, so they are only loaded once. */
|
||||||
|
private SpellProperties globalProperties;
|
||||||
/** Used in initialisation. */
|
/** Used in initialisation. */
|
||||||
private Set<String> propertyKeys = new HashSet<>();
|
private Set<String> propertyKeys = new HashSet<>();
|
||||||
|
|
||||||
@@ -248,6 +257,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
|||||||
|
|
||||||
if(!arePropertiesInitialised()){
|
if(!arePropertiesInitialised()){
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
if(this.globalProperties == null) this.globalProperties = properties;
|
||||||
}else{
|
}else{
|
||||||
Wizardry.logger.info("A mod attempted to set a spell's properties, but they were already initialised.");
|
Wizardry.logger.info("A mod attempted to set a spell's properties, but they were already initialised.");
|
||||||
}
|
}
|
||||||
@@ -264,9 +274,14 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
|||||||
.map(s -> s.properties).toArray(SpellProperties[]::new)));
|
.map(s -> s.properties).toArray(SpellProperties[]::new)));
|
||||||
}else{
|
}else{
|
||||||
// On the client side, wipe the spell properties so the new ones can be set
|
// On the client side, wipe the spell properties so the new ones can be set
|
||||||
for(Spell spell : registry){
|
// TESTME: Can we guarantee this happens before the packet arrives?
|
||||||
spell.properties = null; // TESTME: Can we guarantee this happens before the packet arrives?
|
clearProperties();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void clearProperties(){
|
||||||
|
for(Spell spell : registry){
|
||||||
|
spell.properties = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,6 +574,13 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
|||||||
this.enabled = isEnabled;
|
this.enabled = isEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns true if the given item has a variant for this spell. By default, returns true if the given item is
|
||||||
|
* either {@link WizardryItems#spell_book} or {@link WizardryItems#scroll}. Override to give the spell a special
|
||||||
|
* type of book or scroll. */
|
||||||
|
public boolean applicableForItem(Item item){
|
||||||
|
return item == WizardryItems.spell_book || item == WizardryItems.scroll;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". <b>This should
|
* Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". <b>This should
|
||||||
* only be used for translation purposes.</b>
|
* only be used for translation purposes.</b>
|
||||||
@@ -862,4 +884,32 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
|||||||
&& (this.element == null || spell.getElement() == this.element);
|
&& (this.element == null || spell.getElement() == this.element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================ Event handlers ==============================================
|
||||||
|
|
||||||
|
// Not ideal but it solves the reloading of spell properties without breaking encapsulation
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onWorldLoadEvent(WorldEvent.Load event){
|
||||||
|
if(!event.getWorld().isRemote){
|
||||||
|
if(event.getWorld().provider.getDimension() != 0) return; // Only do it once per save file
|
||||||
|
clearProperties();
|
||||||
|
SpellProperties.loadWorldSpecificSpellProperties(event.getWorld());
|
||||||
|
for(Spell spell : Spell.registry){
|
||||||
|
if(!spell.arePropertiesInitialised()) spell.setProperties(spell.globalProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onClientDisconnectEvent(FMLNetworkEvent.ClientDisconnectionFromServerEvent event){
|
||||||
|
// Why does the world UNLOAD event happen during world LOADING? How does that even work?!
|
||||||
|
clearProperties();
|
||||||
|
for(Spell spell : Spell.registry){
|
||||||
|
// If someone wants to access them from the menu, they'll get the global ones (not sure why you'd want to)
|
||||||
|
// No need to sync here since the server is about to shut down anyway
|
||||||
|
spell.setProperties(spell.globalProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,16 @@ import electroblob.wizardry.spell.Spell;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.util.JsonUtils;
|
import net.minecraft.util.JsonUtils;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.crafting.CraftingHelper;
|
import net.minecraftforge.common.crafting.CraftingHelper;
|
||||||
import net.minecraftforge.fml.common.Loader;
|
import net.minecraftforge.fml.common.Loader;
|
||||||
import net.minecraftforge.fml.common.ModContainer;
|
import net.minecraftforge.fml.common.ModContainer;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -40,9 +43,6 @@ import java.util.stream.Collectors;
|
|||||||
* @author Electroblob
|
* @author Electroblob
|
||||||
* @since Wizardry 4.2
|
* @since Wizardry 4.2
|
||||||
*/
|
*/
|
||||||
// There is not a particular semantic reason to separate this from the Spell class itself. However, doing so means that
|
|
||||||
// everything related to the JSON spell system is kept in one place and doesn't clutter the (already long) Spell class.
|
|
||||||
// Additionally, it allows SpellProperties objects to be passed around during loading and syncing.
|
|
||||||
public final class SpellProperties {
|
public final class SpellProperties {
|
||||||
|
|
||||||
private static final Gson gson = new Gson();
|
private static final Gson gson = new Gson();
|
||||||
@@ -245,32 +245,57 @@ public final class SpellProperties {
|
|||||||
// things don't work as expected then that may be why - pretty sure it's fine though since the properties get
|
// things don't work as expected then that may be why - pretty sure it's fine though since the properties get
|
||||||
// wiped client-side on each login anyway.
|
// wiped client-side on each login anyway.
|
||||||
public static void init(){
|
public static void init(){
|
||||||
|
|
||||||
// Collecting to a set should give us one of each mod ID
|
// Collecting to a set should give us one of each mod ID
|
||||||
Set<String> modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet());
|
Set<String> modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet());
|
||||||
|
|
||||||
boolean flag = true;
|
boolean flag = loadConfigSpellProperties();
|
||||||
|
|
||||||
for(String modID : modIDs){
|
for(String modID : modIDs){
|
||||||
flag &= loadSpellProperties(modID); // Don't short-circuit, or mods later on won't get loaded!
|
flag &= loadBuiltInSpellProperties(modID); // Don't short-circuit, or mods later on won't get loaded!
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!flag) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!");
|
if(!flag) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sooooooo I just realised that resource packs - you know, that famously client-side thing - can now define
|
// There are now three 'layers' of spell properties - in order of priority, these are:
|
||||||
// stuff that should be specified by the server. No wonder it all got moved to data packs in 1.13...
|
// 1. World-specific properties, stored in saves/[world]/data/spells
|
||||||
// Anyway, for the time being we're in 1.12 so we're gonna have to do this instead.
|
// 2. Global overrides, stored in config/ebwizardry/spells
|
||||||
|
// 3. Built-in properties, stored in mods/[mod jar]/assets/spells
|
||||||
|
// There's a method for loading each of these below, because that makes sense to me!
|
||||||
|
|
||||||
|
public static void loadWorldSpecificSpellProperties(World world){
|
||||||
|
|
||||||
|
Wizardry.logger.info("Loading custom spell properties for world {}", world.getWorldInfo().getWorldName());
|
||||||
|
|
||||||
|
File spellJSONDir = new File(new File(world.getSaveHandler().getWorldDirectory(), "data"), "spells");
|
||||||
|
|
||||||
|
if(spellJSONDir.mkdirs()) return; // If it just got created it can't possibly have anything inside
|
||||||
|
|
||||||
|
if(!loadSpellPropertiesFromDir(spellJSONDir)) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean loadConfigSpellProperties(){
|
||||||
|
|
||||||
|
Wizardry.logger.info("Loading spell properties from config folder");
|
||||||
|
|
||||||
|
File spellJSONDir = new File(Wizardry.configDirectory, "spells");
|
||||||
|
|
||||||
|
if(!spellJSONDir.exists()) return true; // If there's no global spell properties folder, do nothing
|
||||||
|
|
||||||
|
return loadSpellPropertiesFromDir(spellJSONDir);
|
||||||
|
}
|
||||||
|
|
||||||
// For crafting recipes, Forge does some stuff behind the scenes to load recipe JSON files from mods' namespaces.
|
// For crafting recipes, Forge does some stuff behind the scenes to load recipe JSON files from mods' namespaces.
|
||||||
// This leverages the same methods.
|
// This leverages the same methods.
|
||||||
|
|
||||||
private static boolean loadSpellProperties(String modID){
|
private static boolean loadBuiltInSpellProperties(String modID){
|
||||||
|
|
||||||
// Yes, I know you're not supposed to do orElse(null). But... meh.
|
// Yes, I know you're not supposed to do orElse(null). But... meh.
|
||||||
ModContainer mod = Loader.instance().getModList().stream().filter(m -> m.getModId().equals(modID)).findFirst().orElse(null);
|
ModContainer mod = Loader.instance().getModList().stream().filter(m -> m.getModId().equals(modID)).findFirst().orElse(null);
|
||||||
|
|
||||||
if(mod == null){
|
if(mod == null){
|
||||||
Wizardry.logger.warn("Tried to load spell properties for mod with ID '" + modID + "', but no such mod was loaded");
|
Wizardry.logger.warn("Tried to load built-in spell properties for mod with ID '" + modID + "', but no such mod was loaded");
|
||||||
return false; // Failed!
|
return false; // Failed!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +304,7 @@ public final class SpellProperties {
|
|||||||
List<Spell> spells = Spell.getSpells(s -> s.getRegistryName().getNamespace().equals(modID));
|
List<Spell> spells = Spell.getSpells(s -> s.getRegistryName().getNamespace().equals(modID));
|
||||||
if(modID.equals(Wizardry.MODID)) spells.add(Spells.none); // In this particular case we do need the none spell
|
if(modID.equals(Wizardry.MODID)) spells.add(Spells.none); // In this particular case we do need the none spell
|
||||||
|
|
||||||
Wizardry.logger.info("Loading spell properties for " + spells.size() + " spells in mod " + modID);
|
Wizardry.logger.info("Loading built-in spell properties for " + spells.size() + " spells in mod " + modID);
|
||||||
|
|
||||||
// This method is used by Forge to load mod recipes and advancements, so it's a fair bet it's the right one
|
// This method is used by Forge to load mod recipes and advancements, so it's a fair bet it's the right one
|
||||||
// In the absence of Javadoc, here's what the non-obvious parameters do:
|
// In the absence of Javadoc, here's what the non-obvious parameters do:
|
||||||
@@ -307,12 +332,16 @@ public final class SpellProperties {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedReader reader = null;
|
|
||||||
|
|
||||||
// We want to do this regardless of whether the JSON file got read properly, because that prints its
|
// We want to do this regardless of whether the JSON file got read properly, because that prints its
|
||||||
// own separate warning
|
// own separate warning
|
||||||
if(!spells.remove(spell)) Wizardry.logger.warn("What's going on?!");
|
if(!spells.remove(spell)) Wizardry.logger.warn("What's going on?!");
|
||||||
|
|
||||||
|
// Ignore spells overridden in the config folder
|
||||||
|
// This needs to be done AFTER the above line or it'll think there are missing spell properties files
|
||||||
|
if(spell.arePropertiesInitialised()) return true;
|
||||||
|
|
||||||
|
BufferedReader reader = null;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
reader = Files.newBufferedReader(file);
|
reader = Files.newBufferedReader(file);
|
||||||
@@ -348,6 +377,54 @@ public final class SpellProperties {
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean loadSpellPropertiesFromDir(File dir){
|
||||||
|
|
||||||
|
boolean success = true;
|
||||||
|
|
||||||
|
for(File file : FileUtils.listFiles(dir, new String[]{"json"}, true)){
|
||||||
|
|
||||||
|
// The structure in world and config folders is subtly different in that the "spells" and mod id directories
|
||||||
|
// are in the opposite order, i.e. it's spells/modid/whatever.json instead of modid/spells/whatever.json
|
||||||
|
String relative = dir.toPath().relativize(file.toPath()).toString(); // modid\whatever.json
|
||||||
|
String nameAndModID = FilenameUtils.removeExtension(relative).replaceAll("\\\\", "/"); // modid/whatever
|
||||||
|
String modID = nameAndModID.split("/")[0]; // modid
|
||||||
|
String name = nameAndModID.substring(nameAndModID.indexOf('/') + 1); // whatever
|
||||||
|
|
||||||
|
ResourceLocation key = new ResourceLocation(modID, name);
|
||||||
|
|
||||||
|
Spell spell = Spell.registry.getValue(key);
|
||||||
|
|
||||||
|
// If no spell matches a particular file, log it and just ignore the file
|
||||||
|
if(spell == null){
|
||||||
|
Wizardry.logger.info("Spell properties file " + nameAndModID + ".json does not match any registered spells; ensure the filename is spelled correctly.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedReader reader = null;
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
reader = Files.newBufferedReader(file.toPath());
|
||||||
|
|
||||||
|
JsonObject json = JsonUtils.fromJson(gson, reader, JsonObject.class);
|
||||||
|
SpellProperties properties = new SpellProperties(json, spell);
|
||||||
|
spell.setProperties(properties);
|
||||||
|
|
||||||
|
}catch(JsonParseException jsonparseexception){
|
||||||
|
Wizardry.logger.error("Parsing error loading spell property file for " + key, jsonparseexception);
|
||||||
|
success = false;
|
||||||
|
}catch(IOException ioexception){
|
||||||
|
Wizardry.logger.error("Couldn't read spell property file for " + key, ioexception);
|
||||||
|
success = false;
|
||||||
|
}finally{
|
||||||
|
IOUtils.closeQuietly(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We probably could have used the attribute system for all of this, but I am reluctant to do so for a number of
|
// We probably could have used the attribute system for all of this, but I am reluctant to do so for a number of
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ public final class WizardryUtilities {
|
|||||||
|
|
||||||
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side and
|
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side and
|
||||||
* a block that is replaceable. This means the surface can be built on. */
|
* a block that is replaceable. This means the surface can be built on. */
|
||||||
SurfaceCriteria BUILDABLE = (world, pos, side) -> world.isSideSolid(pos, side) && world.getBlockState(pos.offset(side)).getBlock().isReplaceable(world, pos);
|
SurfaceCriteria BUILDABLE = (world, pos, side) -> world.isSideSolid(pos, side) && world.getBlockState(pos.offset(side)).getBlock().isReplaceable(world, pos.offset(side));
|
||||||
|
|
||||||
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side
|
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side
|
||||||
* or a liquid, and an air block. Used for freezing water and placing snow. */
|
* or a liquid, and an air block. Used for freezing water and placing snow. */
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import net.minecraft.world.gen.structure.MapGenStructureData;
|
|||||||
import net.minecraft.world.gen.structure.StructureBoundingBox;
|
import net.minecraft.world.gen.structure.StructureBoundingBox;
|
||||||
import net.minecraft.world.gen.structure.template.PlacementSettings;
|
import net.minecraft.world.gen.structure.template.PlacementSettings;
|
||||||
import net.minecraft.world.gen.structure.template.Template;
|
import net.minecraft.world.gen.structure.template.Template;
|
||||||
import net.minecraftforge.common.BiomeDictionary;
|
|
||||||
import net.minecraftforge.common.util.Constants;
|
import net.minecraftforge.common.util.Constants;
|
||||||
import net.minecraftforge.fml.common.IWorldGenerator;
|
import net.minecraftforge.fml.common.IWorldGenerator;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
@@ -120,6 +119,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
* @param world The world in which to spawn the structure
|
* @param world The world in which to spawn the structure
|
||||||
* @param chunkX The x-coordinate of the chunk being populated
|
* @param chunkX The x-coordinate of the chunk being populated
|
||||||
* @param chunkZ The z-coordinate of the chunk being populated
|
* @param chunkZ The z-coordinate of the chunk being populated
|
||||||
|
* @param structureFile The name of the structure file, used for error messages.
|
||||||
* @return The coordinates of the position found, or null if no suitable position was found. The returned
|
* @return The coordinates of the position found, or null if no suitable position was found. The returned
|
||||||
* {@code BlockPos} is <b>always</b> the northwest corner of the structure, and the y-coordinate is that of the
|
* {@code BlockPos} is <b>always</b> the northwest corner of the structure, and the y-coordinate is that of the
|
||||||
* uppermost block at those (x, z) coordinates. If the structure is being rotated this needs to be altered using
|
* uppermost block at those (x, z) coordinates. If the structure is being rotated this needs to be altered using
|
||||||
@@ -128,7 +128,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BlockPos findValidPosition(Template template, PlacementSettings settings, Random random, World world,
|
protected BlockPos findValidPosition(Template template, PlacementSettings settings, Random random, World world,
|
||||||
int chunkX, int chunkZ){
|
int chunkX, int chunkZ, String structureFile){
|
||||||
|
|
||||||
// Offset by (8, 8) to minimise cascading worldgen lag
|
// Offset by (8, 8) to minimise cascading worldgen lag
|
||||||
// See https://www.reddit.com/r/feedthebeast/cowmments/5x0twz/investigating_extreme_worldgen_lag/?ref=share&ref_source=embed&utm_content=title&utm_medium=post_embed&utm_name=c07cbb545f74487793783012794733d8&utm_source=embedly&utm_term=5x0twz
|
// See https://www.reddit.com/r/feedthebeast/cowmments/5x0twz/investigating_extreme_worldgen_lag/?ref=share&ref_source=embed&utm_content=title&utm_medium=post_embed&utm_name=c07cbb545f74487793783012794733d8&utm_source=embedly&utm_term=5x0twz
|
||||||
@@ -136,6 +136,11 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16));
|
BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16));
|
||||||
|
|
||||||
BlockPos size = template.transformedSize(settings.getRotation());
|
BlockPos size = template.transformedSize(settings.getRotation());
|
||||||
|
|
||||||
|
if(size.getX() == 0 || size.getY() == 0 || size.getZ() == 0){
|
||||||
|
Wizardry.logger.warn("Structure template file {} is missing or empty! If you're trying to disable structure spawning, pointing to a non-existent location is NOT the correct way to do so; use the structure dimension lists instead.", structureFile);
|
||||||
|
}
|
||||||
|
|
||||||
// Estimate a starting height for searching for the floor
|
// Estimate a starting height for searching for the floor
|
||||||
BlockPos centre = world.getTopSolidOrLiquidBlock(new BlockPos(origin.add(size.getX()/2, 0, size.getZ()/2)));
|
BlockPos centre = world.getTopSolidOrLiquidBlock(new BlockPos(origin.add(size.getX()/2, 0, size.getZ()/2)));
|
||||||
Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true,
|
Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true,
|
||||||
@@ -145,8 +150,8 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
|
|
||||||
if(Wizardry.settings.fastWorldgen){
|
if(Wizardry.settings.fastWorldgen){
|
||||||
BlockPos result = origin.up(startingHeight);
|
BlockPos result = origin.up(startingHeight);
|
||||||
// Fast worldgen doesn't check for water, instead it checks the biome like vanilla, which is crude but fast
|
// Fast worldgen only checks the central position for water, which isn't perfect but it is faster
|
||||||
return BiomeDictionary.hasType(world.getBiome(result), BiomeDictionary.Type.WATER) ? null : result;
|
return world.getBlockState(new BlockPos(centre.getX(), startingHeight + 1, centre.getZ())).getMaterial().isLiquid() ? null : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] floorHeights = new int[size.getX() * size.getZ()];
|
int[] floorHeights = new int[size.getX() * size.getZ()];
|
||||||
@@ -212,7 +217,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
BlockPos origin;
|
BlockPos origin;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
origin = findValidPosition(template, settings, random, world, chunkX, chunkZ);
|
origin = findValidPosition(template, settings, random, world, chunkX, chunkZ, structureFile.toString());
|
||||||
triesLeft--;
|
triesLeft--;
|
||||||
}while(triesLeft > 0 && origin != null);
|
}while(triesLeft > 0 && origin != null);
|
||||||
|
|
||||||
@@ -244,7 +249,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
|
|
||||||
spawnStructure(random, world, origin, template, settings, structureFile);
|
spawnStructure(random, world, origin, template, settings, structureFile);
|
||||||
|
|
||||||
if(!Wizardry.settings.fastWorldgen) removeFloatingTrees(world, box);
|
if(!Wizardry.settings.fastWorldgen) removeFloatingTrees(world, box, random);
|
||||||
|
|
||||||
structureMap.put(ChunkPos.asLong(origin.getX() >> 4, origin.getZ() >> 4), settings.getBoundingBox());
|
structureMap.put(ChunkPos.asLong(origin.getX() >> 4, origin.getZ() >> 4), settings.getBoundingBox());
|
||||||
|
|
||||||
@@ -306,7 +311,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Finds and removes any floating bits of tree in and above the given structure bounding box. */
|
/** Finds and removes any floating bits of tree in and above the given structure bounding box. */
|
||||||
protected static void removeFloatingTrees(World world, StructureBoundingBox boundingBox){
|
protected static void removeFloatingTrees(World world, StructureBoundingBox boundingBox, Random random){
|
||||||
|
|
||||||
boolean changed = true;
|
boolean changed = true;
|
||||||
int y = boundingBox.minY;
|
int y = boundingBox.minY;
|
||||||
@@ -354,7 +359,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int i=0; i<16; i++){
|
for(int i=0; i<16; i++){
|
||||||
leaves.forEach(p -> world.getBlockState(p).getBlock().updateTick(world, p, world.getBlockState(p), null));
|
leaves.forEach(p -> world.getBlockState(p).getBlock().updateTick(world, p, world.getBlockState(p), random));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, remove all the items that were dropped as a result of leaf decay
|
// Finally, remove all the items that were dropped as a result of leaf decay
|
||||||
|
|||||||
@@ -1164,27 +1164,27 @@ config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses f
|
|||||||
config.ebwizardry.fast_worldgen.true=Fast
|
config.ebwizardry.fast_worldgen.true=Fast
|
||||||
config.ebwizardry.fast_worldgen.false=Fancy
|
config.ebwizardry.fast_worldgen.false=Fancy
|
||||||
config.ebwizardry.tower_dimensions=Tower Dimensions
|
config.ebwizardry.tower_dimensions=Tower Dimensions
|
||||||
config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate.
|
config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.
|
||||||
config.ebwizardry.tower_rarity=Tower Rarity
|
config.ebwizardry.tower_rarity=Tower Rarity
|
||||||
config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.
|
config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.
|
||||||
config.ebwizardry.evil_wizard_chance=Evil Wizard Chance
|
config.ebwizardry.evil_wizard_chance=Evil Wizard Chance
|
||||||
config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.
|
config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.
|
||||||
config.ebwizardry.tower_files=Tower Structure Files
|
config.ebwizardry.tower_files=Tower Structure Files
|
||||||
config.ebwizardry.tower_files.tooltip=List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.tower_files.tooltip=List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.
|
||||||
config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files
|
config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files
|
||||||
config.ebwizardry.tower_with_chest_files.tooltip=List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.tower_with_chest_files.tooltip=List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.
|
||||||
config.ebwizardry.obelisk_dimensions=Obelisk Dimensions
|
config.ebwizardry.obelisk_dimensions=Obelisk Dimensions
|
||||||
config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate.
|
config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. Remove all dimensions to disable obelisks completely.
|
||||||
config.ebwizardry.obelisk_rarity=Obelisk Rarity
|
config.ebwizardry.obelisk_rarity=Obelisk Rarity
|
||||||
config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.
|
config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.
|
||||||
config.ebwizardry.obelisk_files=Obelisk Structure Files
|
config.ebwizardry.obelisk_files=Obelisk Structure Files
|
||||||
config.ebwizardry.obelisk_files.tooltip=List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.obelisk_files.tooltip=List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable obelisks, use the obelisk dimensions setting.
|
||||||
config.ebwizardry.shrine_dimensions=Shrine Dimensions
|
config.ebwizardry.shrine_dimensions=Shrine Dimensions
|
||||||
config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate.
|
config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. Remove all dimensions to disable shrines completely.
|
||||||
config.ebwizardry.shrine_rarity=Shrine Rarity
|
config.ebwizardry.shrine_rarity=Shrine Rarity
|
||||||
config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.
|
config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.
|
||||||
config.ebwizardry.shrine_files=Shrine Structure Files
|
config.ebwizardry.shrine_files=Shrine Structure Files
|
||||||
config.ebwizardry.shrine_files.tooltip=List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.shrine_files.tooltip=List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable shrines, use the shrine dimensions setting.
|
||||||
config.ebwizardry.tree_blocks=Tree Blocks
|
config.ebwizardry.tree_blocks=Tree Blocks
|
||||||
config.ebwizardry.tree_blocks.tooltip=List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).
|
config.ebwizardry.tree_blocks.tooltip=List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).
|
||||||
config.ebwizardry.ore_dimensions=Ore Dimensions
|
config.ebwizardry.ore_dimensions=Ore Dimensions
|
||||||
|
|||||||
@@ -1164,27 +1164,27 @@ config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses f
|
|||||||
config.ebwizardry.fast_worldgen.true=Fast
|
config.ebwizardry.fast_worldgen.true=Fast
|
||||||
config.ebwizardry.fast_worldgen.false=Fancy
|
config.ebwizardry.fast_worldgen.false=Fancy
|
||||||
config.ebwizardry.tower_dimensions=Tower Dimensions
|
config.ebwizardry.tower_dimensions=Tower Dimensions
|
||||||
config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate.
|
config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.
|
||||||
config.ebwizardry.tower_rarity=Tower Rarity
|
config.ebwizardry.tower_rarity=Tower Rarity
|
||||||
config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.
|
config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.
|
||||||
config.ebwizardry.evil_wizard_chance=Evil Wizard Chance
|
config.ebwizardry.evil_wizard_chance=Evil Wizard Chance
|
||||||
config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.
|
config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.
|
||||||
config.ebwizardry.tower_files=Tower Structure Files
|
config.ebwizardry.tower_files=Tower Structure Files
|
||||||
config.ebwizardry.tower_files.tooltip=List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.tower_files.tooltip=List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.
|
||||||
config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files
|
config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files
|
||||||
config.ebwizardry.tower_with_chest_files.tooltip=List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.tower_with_chest_files.tooltip=List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.
|
||||||
config.ebwizardry.obelisk_dimensions=Obelisk Dimensions
|
config.ebwizardry.obelisk_dimensions=Obelisk Dimensions
|
||||||
config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate.
|
config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. Remove all dimensions to disable obelisks completely.
|
||||||
config.ebwizardry.obelisk_rarity=Obelisk Rarity
|
config.ebwizardry.obelisk_rarity=Obelisk Rarity
|
||||||
config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.
|
config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.
|
||||||
config.ebwizardry.obelisk_files=Obelisk Structure Files
|
config.ebwizardry.obelisk_files=Obelisk Structure Files
|
||||||
config.ebwizardry.obelisk_files.tooltip=List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.obelisk_files.tooltip=List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable obelisks, use the obelisk dimensions setting.
|
||||||
config.ebwizardry.shrine_dimensions=Shrine Dimensions
|
config.ebwizardry.shrine_dimensions=Shrine Dimensions
|
||||||
config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate.
|
config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. Remove all dimensions to disable shrines completely.
|
||||||
config.ebwizardry.shrine_rarity=Shrine Rarity
|
config.ebwizardry.shrine_rarity=Shrine Rarity
|
||||||
config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.
|
config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.
|
||||||
config.ebwizardry.shrine_files=Shrine Structure Files
|
config.ebwizardry.shrine_files=Shrine Structure Files
|
||||||
config.ebwizardry.shrine_files.tooltip=List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.
|
config.ebwizardry.shrine_files.tooltip=List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable shrines, use the shrine dimensions setting.
|
||||||
config.ebwizardry.tree_blocks=Tree Blocks
|
config.ebwizardry.tree_blocks=Tree Blocks
|
||||||
config.ebwizardry.tree_blocks.tooltip=List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).
|
config.ebwizardry.tree_blocks.tooltip=List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).
|
||||||
config.ebwizardry.ore_dimensions=Ore Dimensions
|
config.ebwizardry.ore_dimensions=Ore Dimensions
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"item.wand.levelup": {"category": "player", "sounds": ["random/levelup"]},
|
"item.wand.levelup": {"category": "player", "sounds": ["random/levelup"]},
|
||||||
"item.wand.melee": {"category": "player", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]},
|
"item.wand.melee": {"category": "player", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]},
|
||||||
"item.armour.equip_silk": {"category": "player", "sounds": ["item/armor/equip_leather1", "item/armor/equip_leather2", "item/armor/equip_leather3", "item/armor/equip_leather4", "item/armor/equip_leather5", "item/armor/equip_leather6"]},
|
"item.armour.equip_silk": {"category": "player", "sounds": ["item/armor/equip_leather1", "item/armor/equip_leather2", "item/armor/equip_leather3", "item/armor/equip_leather4", "item/armor/equip_leather5", "item/armor/equip_leather6"]},
|
||||||
"item.purifying_elixir.drink": {"category": "player", "sounds": ["ebwizardry:spellbind"]},
|
"item.purifying_elixir.drink": {"category": "player", "sounds": ["ebwizardry:buff_large"]},
|
||||||
|
|
||||||
"entity.black_hole.ambient": {"category": "spells", "sounds": ["portal/portal"]},
|
"entity.black_hole.ambient": {"category": "spells", "sounds": ["portal/portal"]},
|
||||||
"entity.black_hole.vanish": {"category": "spells", "sounds": ["portal/trigger"]},
|
"entity.black_hole.vanish": {"category": "spells", "sounds": ["portal/trigger"]},
|
||||||
@@ -158,8 +158,8 @@
|
|||||||
"spell.flaming_axe": {"category": "spells", "sounds": ["ebwizardry:buff"]},
|
"spell.flaming_axe": {"category": "spells", "sounds": ["ebwizardry:buff"]},
|
||||||
"spell.flaming_weapon": {"category": "spells", "sounds": ["ebwizardry:buff"]},
|
"spell.flaming_weapon": {"category": "spells", "sounds": ["ebwizardry:buff"]},
|
||||||
"spell.flight": {"category": "spells", "sounds": ["mob/enderdragon/wings1", "mob/enderdragon/wings2", "mob/enderdragon/wings3", "mob/enderdragon/wings4", "mob/enderdragon/wings5", "mob/enderdragon/wings6"]},
|
"spell.flight": {"category": "spells", "sounds": ["mob/enderdragon/wings1", "mob/enderdragon/wings2", "mob/enderdragon/wings3", "mob/enderdragon/wings4", "mob/enderdragon/wings5", "mob/enderdragon/wings6"]},
|
||||||
"spell.font_of_mana": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.font_of_mana": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.font_of_vitality": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.font_of_vitality": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.force_arrow": {"category": "spells", "sounds": ["ebwizardry:force"]},
|
"spell.force_arrow": {"category": "spells", "sounds": ["ebwizardry:force"]},
|
||||||
"spell.forcefield": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]},
|
"spell.forcefield": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]},
|
||||||
"spell.force_orb": {"category": "spells", "sounds": ["random/bow"]},
|
"spell.force_orb": {"category": "spells", "sounds": ["random/bow"]},
|
||||||
@@ -179,11 +179,11 @@
|
|||||||
"spell.grapple.pull": {"category": "spells", "sounds": ["ebwizardry:pull1", "ebwizardry:pull2"]},
|
"spell.grapple.pull": {"category": "spells", "sounds": ["ebwizardry:pull1", "ebwizardry:pull2"]},
|
||||||
"spell.grapple.release": {"category": "spells", "sounds": ["random/bowhit1", "random/bowhit2", "random/bowhit3"]},
|
"spell.grapple.release": {"category": "spells", "sounds": ["random/bowhit1", "random/bowhit2", "random/bowhit3"]},
|
||||||
"spell.greater_fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]},
|
"spell.greater_fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]},
|
||||||
"spell.greater_heal": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.greater_heal": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.greater_telekinesis.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]},
|
"spell.greater_telekinesis.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]},
|
||||||
"spell.greater_telekinesis.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]},
|
"spell.greater_telekinesis.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]},
|
||||||
"spell.greater_telekinesis.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]},
|
"spell.greater_telekinesis.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]},
|
||||||
"spell.greater_ward": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.greater_ward": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.group_heal": {"category": "spells", "sounds": ["ebwizardry:heal"]},
|
"spell.group_heal": {"category": "spells", "sounds": ["ebwizardry:heal"]},
|
||||||
"spell.growth_aura": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]},
|
"spell.growth_aura": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]},
|
||||||
"spell.hailstorm": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]},
|
"spell.hailstorm": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]},
|
||||||
@@ -250,12 +250,12 @@
|
|||||||
"spell.ray_of_purification.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]},
|
"spell.ray_of_purification.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]},
|
||||||
"spell.ray_of_purification.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]},
|
"spell.ray_of_purification.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]},
|
||||||
"spell.ray_of_purification.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]},
|
"spell.ray_of_purification.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]},
|
||||||
"spell.remove_curse": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.remove_curse": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.replenish_hunger": {"category": "spells", "sounds": ["ebwizardry:heal"]},
|
"spell.replenish_hunger": {"category": "spells", "sounds": ["ebwizardry:heal"]},
|
||||||
"spell.resurrection": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.resurrection": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.reversal": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]},
|
"spell.reversal": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]},
|
||||||
"spell.ring_of_fire": {"category": "spells", "sounds": ["mob/ghast/fireball4"]},
|
"spell.ring_of_fire": {"category": "spells", "sounds": ["mob/ghast/fireball4"]},
|
||||||
"spell.satiety": {"category": "spells", "sounds": ["ebwizardry:spellbind"]},
|
"spell.satiety": {"category": "spells", "sounds": ["ebwizardry:buff_large"]},
|
||||||
"spell.shadow_ward.start": {"category": "spells", "sounds": ["ebwizardry:dark_aura_start"]},
|
"spell.shadow_ward.start": {"category": "spells", "sounds": ["ebwizardry:dark_aura_start"]},
|
||||||
"spell.shadow_ward.loop": {"category": "spells", "sounds": ["ebwizardry:dark_aura_loop"]},
|
"spell.shadow_ward.loop": {"category": "spells", "sounds": ["ebwizardry:dark_aura_loop"]},
|
||||||
"spell.shadow_ward.end": {"category": "spells", "sounds": ["ebwizardry:dark_aura_end"]},
|
"spell.shadow_ward.end": {"category": "spells", "sounds": ["ebwizardry:dark_aura_end"]},
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 151 KiB |
@@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"modid" : "ebwizardry",
|
"modid" : "ebwizardry",
|
||||||
"name" : "Electroblob's Wizardry",
|
"name" : "Electroblob's Wizardry",
|
||||||
"version" : "4.2.2",
|
"version" : "4.2.5",
|
||||||
"mcversion" : "1.12.2",
|
"mcversion" : "1.12.2",
|
||||||
"url" : "https://minecraft.curseforge.com/projects/electroblobs-wizardry",
|
"url" : "https://minecraft.curseforge.com/projects/electroblobs-wizardry",
|
||||||
"credits" : "\nDesigned, coded and textured by Electroblob.\nCode contributed by: Corail31, 12foo, Shadows-of-Fire, Tora-B, Avatair, Aeronica.\nTranslators: MadWrist (Spanish, Mexican Spanish), VilagVil & kellixon (Russian), Hahdrim (French), lorrampi (Brazilian Portuguese), ZHENGLOC & dragon-evol (Chinese), shejery & rewi_wire (Korean), Trozuu (Polish).",
|
"credits" : "\nDesigned, coded and textured by Electroblob.\nCode contributed by: Corail31, 12foo, Shadows-of-Fire, Tora-B, Avatair, Aeronica.\nTranslators: MadWrist (Spanish, Mexican Spanish), VilagVil & kellixon (Russian), Hahdrim (French), lorrampi (Brazilian Portuguese), ZHENGLOC & dragon-evol (Chinese), shejery & rewi_wire (Korean), Trozuu (Polish).",
|
||||||
|
|||||||
Reference in New Issue
Block a user