diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 13746ff1..182b1c1a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,10 +7,10 @@ assignees: '' --- -Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting. +Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting. Minecraft version: 1.12.2 [change as necessary] -Wizardry version: 4.2.2 [change as necessary] +Wizardry version: 4.2.10 [change as necessary] Environment: Singleplayer/LAN game/Server [delete as necessary] Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.] diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index e78ff6a4..f1e2fecf 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,7 +7,7 @@ assignees: '' --- -Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting. +Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting. Minecraft versions: [if this suggestion only applies to some versions, list them here] diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index d338f061..ff92dd20 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -7,10 +7,10 @@ assignees: '' --- -Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting. +Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting. Minecraft version: 1.12.2 [change as necessary] -Wizardry version: 4.2.2 [change as necessary] +Wizardry version: 4.2.10 [change as necessary] Question details: [explain your question here] diff --git a/.gitignore b/.gitignore index d45b2340..1c0ee64d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ run logs /misc /libs +libs_src libsfordeobf generated Thumbs.db \ No newline at end of file diff --git a/CREDITS.md b/CREDITS.md index e1823a54..fdbc9f24 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,7 +1,7 @@ # Credits Electroblob's Wizardry -Version 4.2.3 +Version 4.2.10 For Minecraft 1.12.2 Designed, coded and textured by Electroblob @@ -21,15 +21,21 @@ In addition, I'd like to thank the following individuals for their contributions - Tora-B - Avatair - Aeronica +- UltraHex +- Azim-Palmer +- raoulvdberge #### Translations -- Spanish and Mexican Spanish: MadWrist -- Russian: VilagVil, kellixon -- French: Hahdrim -- Brazilian Portuguese: lorrampi -- Chinese: ZHENGLOC, dragon-evol -- Korean: shejery, rewi_wire +- Spanish: MadWrist, Alsentar +- Mexican Spanish: MadWrist +- Russian: VilagVil, kellixon, bigenergy +- French: Hahdrim +- Brazilian Portuguese: lorrampi +- Chinese: ZHENGLOC, dragon-evol, Hokorizero, TUsama +- Korean: shejery, rewi_wire - Polish: Trozuu +- German: BirdyDragon +- Taiwanese: chesterccj305 Lightning ray sound effect from OhhWowProductions diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index c1c9cc05..3c47b45d 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,7 +1,7 @@ Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting. Minecraft version: 1.12.2 [change as necessary] -Wizardry version: 4.1.4 [change as necessary] +Wizardry version: 4.2.10 [change as necessary] Environment: Singleplayer/LAN game/Server [delete as necessary] Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.] diff --git a/build.gradle b/build.gradle index a27baec4..7aadf522 100644 --- a/build.gradle +++ b/build.gradle @@ -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. -version = "4.2.3" // There, it matches semver, happy now? +version = "4.2.10" // There, it matches semver, happy now? group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "ElectroblobsWizardry" @@ -31,15 +31,10 @@ repositories { name = "ModMaven" url = "modmaven.k-4u.nl" } - flatDir { - // evErYthINg hAS tO Be a mAVeN rEPoSiTOrY... (to use deobfProvided, for some reason) - // The lack of documentation is actually quite impressive, see the following threads: - // http://www.minecraftforge.net/forum/topic/44262-solved-how-to-build-mod-with-dependencies/ - // https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2866817-setting-up-dependencies-in-minecraft-forge-with - // http://www.minecraftforge.net/forum/topic/44534-adding-dependencies-to-a-forge-project/ - dirs "libsfordeobf" // Don't put src jars in libs or forge will think you have duplicate mods + maven { + name = "Curseforge Maven" + url = "https://minecraft.curseforge.com/api/maven/" } - } minecraft { @@ -56,37 +51,14 @@ minecraft { } dependencies { - // you may put jars on which you depend on in ./libs - // or you may define them like so.. - //compile "some.group:artifact:version:classifier" - //compile "some.group:artifact:version" - // compile against the JEI API but do not include it at runtime + // Compile against the JEI API but do not include it at runtime deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api" - // at runtime, use the full JEI jar + // At runtime, use the full JEI jar runtime "mezz.jei:jei_${mc_version}:${jei_version}" - //deobfProvided "baubles:baubles-1.12:1.5.2:api" // #ihavenoideawhatimdoing #itjustworks - //runtime "baubles:baubles-1.12:1.5.2" // If in doubt, copy what already works - - //deobfProvided "antiqueatlas:antiqueatlas-1.12.2:4.5.1:src" - //runtime "antiqueatlas:antiqueatlas-1.12.2:4.5.1" - - // real examples - //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env - //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env - - // the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. - //provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' - - // the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided, - // except that these dependencies get remapped to your current MCP mappings - //deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev' - //deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev' - - // for more info... - // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html - // http://www.gradle.org/docs/current/userguide/dependency_management.html + deobfCompile "baubles:Baubles:${mc_version_short}:${baubles_version}" + deobfCompile "antique-atlas:antiqueatlas:${mc_version}:${antique_atlas_version}" } diff --git a/gradle.properties b/gradle.properties index b4ec0fb3..a4e7eb14 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,7 @@ # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G mc_version=1.12.2 -jei_version=4.13.1.225 \ No newline at end of file +mc_version_short=1.12 +jei_version=4.13.1.225 +baubles_version=1.5.2 +antique_atlas_version=4.6.3 \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 71165cc2..63cf5ede 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -7,6 +7,7 @@ import electroblob.wizardry.spell.Spell; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; @@ -99,9 +100,9 @@ public class CommonProxy { return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack); } - /** Like {@link CommonProxy#addMultiLineDescription(List, String, Style)}, but style defaults to light grey. */ - public void addMultiLineDescription(List tooltip, String key){ - this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY)); + /** Like {@link CommonProxy#addMultiLineDescription(List, String, Style, Object...)}, but style defaults to light grey. */ + public void addMultiLineDescription(List tooltip, String key, Object... args){ + this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY), args); } /** @@ -112,7 +113,7 @@ public class CommonProxy { * @param key The translation key for the description * @param style A style to apply */ - public void addMultiLineDescription(List tooltip, String key, Style style){} + public void addMultiLineDescription(List tooltip, String key, Style style, Object... args){} // SECTION Packet Handlers // =============================================================================================================== @@ -139,8 +140,6 @@ public class CommonProxy { public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){} - public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){} - public void handleResurrectionPacket(PacketResurrection.Message message){} public void handlePossessionPacket(PacketPossession.Message message){} @@ -238,6 +237,16 @@ public class CommonProxy { + "of sound events, but the given array contained less than 3 sound events!"); playSpellSoundLoop(world, x, y, z, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch, duration); } + + /** Starts the first-person blink overlay effect for the specified player. */ + public void playBlinkEffect(EntityPlayer player){} + + /** + * Starts the client-side screen shake effect for the specified player. + * @param player The player whose screen is to be shaken + * @param intensity The amplitude of the shaking (around 10 looks about right) + */ + public void shakeScreen(EntityPlayer player, float intensity){} /** * Gets the client side world using Minecraft.getMinecraft().world. Only to be called client side! Returns diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index 52546851..bafabf8f 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -6,8 +6,10 @@ import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.AllyDesignationSystem.FriendlyFire; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityList; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.translation.I18n; import net.minecraftforge.common.config.ConfigCategory; @@ -16,7 +18,10 @@ import net.minecraftforge.common.config.Property; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.oredict.OreDictionary; +import org.apache.commons.lang3.tuple.Pair; +import java.io.File; import java.util.*; import java.util.regex.Pattern; @@ -89,7 +94,7 @@ public final class Settings { /** [Server-only] List of dimension ids in which to generate wizard towers. */ public int[] towerDimensions = {0}; /** [Server-only] The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */ - public int towerRarity = 900; + public int towerRarity = 700; /** [Server-only] List of structure file locations for wizard towers without loot chests. */ public ResourceLocation[] towerFiles = {new ResourceLocation(Wizardry.MODID, "wizard_tower_0"), new ResourceLocation(Wizardry.MODID, "wizard_tower_1"), @@ -103,7 +108,7 @@ public final class Settings { /** [Server-only] List of dimension ids in which to generate obelisks. */ public int[] obeliskDimensions = {0, -1}; /** [Server-only] The rarity of obelisks, used by the world generator. Larger numbers are rarer. */ - public int obeliskRarity = 800; + public int obeliskRarity = 600; /** [Server-only] List of structure file locations for obelisks. */ public ResourceLocation[] obeliskFiles = {new ResourceLocation(Wizardry.MODID, "obelisk_0"), new ResourceLocation(Wizardry.MODID, "obelisk_1"), @@ -113,7 +118,7 @@ public final class Settings { /** [Server-only] List of dimension ids in which to generate shrines. */ public int[] shrineDimensions = {0, -1}; /** [Server-only] The rarity of shrines, used by the world generator. Larger numbers are rarer. */ - public int shrineRarity = 1500; + public int shrineRarity = 1100; /** [Server-only] List of structure file locations for shrines. */ public ResourceLocation[] shrineFiles = {new ResourceLocation(Wizardry.MODID, "shrine_0"), new ResourceLocation(Wizardry.MODID, "shrine_1"), @@ -124,7 +129,7 @@ public final class Settings { new ResourceLocation(Wizardry.MODID, "shrine_6"), new ResourceLocation(Wizardry.MODID, "shrine_7")}; /** [Server-only] List of solid blocks (usually trees) which are ignored by the structure generators. */ - public ResourceLocation[] treeBlocks = toResourceLocations(DEFAULT_TREE_BLOCKS); + public Pair[] treeBlocks = parseItemMetaStrings(DEFAULT_TREE_BLOCKS); /** [Server-only] The chance for wizard towers to generate with an evil wizard and chest inside. */ public double evilWizardChance = 0.2; /** [Server-only] List of dimension ids in which to generate crystal ore. */ @@ -163,11 +168,11 @@ public final class Settings { public boolean playerBlockDamage = true; /** [Server-only] Whether to revert to the old wand upgrade system, which only requires tomes of arcana. */ public boolean legacyWandLevelling = false; - /** [Server-only] Whether to replace Minecraft's own fireballs with wizardry fireballs. */ - public boolean replaceVanillaFireballs = true; /** [Server-only] Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, * velocity-based one. */ public boolean replaceVanillaFallDamage = true; + /** [Server-only] Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */ + public boolean bonemealGrowsCrystalFlowers = true; /** * [Server-only] List of registry names of entities which summoned creatures are allowed to attack, in addition * to the defaults. @@ -187,15 +192,15 @@ public final class Settings { * [Server-only] List of registry names of items which cannot be smelted by the pocket furnace spell, in * addition to armour, tools and weapons. */ - public ResourceLocation[] pocketFurnaceItemBlacklist = toResourceLocations("cobblestone", "netherrack"); + public Pair[] pocketFurnaceItemBlacklist = parseItemMetaStrings("cobblestone", "netherrack"); /** [Server-only] List of registry names of blocks which can be detected by the divination spell. */ - public ResourceLocation[] divinationOreWhitelist = {}; + public Pair[] divinationOreWhitelist = parseItemMetaStrings(); // That works I guess /** [Server-only] List of registry names of items which count as swords for imbuement spells. */ - public ResourceLocation[] swordItemWhitelist = {}; + public Pair[] swordItemWhitelist = parseItemMetaStrings(); /** [Server-only] List of registry names of items which count as bows for imbuement spells. */ - public ResourceLocation[] bowItemWhitelist = {}; + public Pair[] bowItemWhitelist = parseItemMetaStrings(); /** [Server-only] Map of items to values which wizard trades may use as currency. */ - public Map currencyItems = new HashMap<>(); + public Map, Integer> currencyItems = new HashMap<>(); /** [Server-only] Global damage scaling factor for all player magic damage. */ public double playerDamageScale = 1.0; /** [Server-only] Global damage scaling factor for all npc magic damage. */ @@ -265,7 +270,9 @@ public final class Settings { * effect. */ public boolean slowTimeAffectsPlayers = true; - /** [Synchronised] Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */ + /** [Synchronised] Whether to replace Minecraft's own fireballs with wizardry fireballs. */ + public boolean replaceVanillaFireballs = true; + /** [Synchronised] Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */ public double forfeitChance = 0.2; // Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys @@ -364,7 +371,7 @@ public final class Settings { */ void initConfig(FMLPreInitializationEvent event){ - config = new Configuration(event.getSuggestedConfigurationFile()); + config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg")); config.load(); Wizardry.logger.info("Setting up main config"); @@ -430,7 +437,7 @@ public final class Settings { Property property; - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + for(Spell spell : Spell.getAllSpells()){ property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true, I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc")); // Uses the same config key as the spell name, because - well, that's what it's called! @@ -541,6 +548,13 @@ public final class Settings { slowTimeAffectsPlayers = property.getBoolean(); propOrder.add(property.getName()); + property = config.get(GAMEPLAY_CATEGORY, "bonemealGrowsCrystalFlowers", true, + "Whether using bonemeal on grass blocks has a chance to grow crystal flowers."); + property.setLanguageKey("config." + Wizardry.MODID + ".bonemeal_grows_crystal_flowers"); + Wizardry.proxy.setToNamedBooleanEntry(property); + bonemealGrowsCrystalFlowers = property.getBoolean(); + propOrder.add(property.getName()); + property = config.get(GAMEPLAY_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them."); property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist"); property.setRequiresMcRestart(true); @@ -642,41 +656,42 @@ public final class Settings { "List of registry names of blocks or items which cannot be smelted by the pocket furnace spell, in addition to armour, tools and weapons. Block/item names are not case sensitive. For mod items, prefix with the mod ID (e.g. " + Wizardry.MODID + ":crystal_ore)."); property.setLanguageKey("config." + Wizardry.MODID + ".pocket_furnace_item_blacklist"); property.setRequiresWorldRestart(true); - pocketFurnaceItemBlacklist = getResourceLocationList(property); + pocketFurnaceItemBlacklist = parseItemMetaStrings(property.getStringList()); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "divinationOreWhitelist", new String[0], "List of registry names of ore blocks which can be detected by the divination spell. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. " + Wizardry.MODID + ":crystal_ore)."); property.setLanguageKey("config." + Wizardry.MODID + ".divination_ore_whitelist"); property.setRequiresWorldRestart(true); - divinationOreWhitelist = getResourceLocationList(property); + divinationOreWhitelist = parseItemMetaStrings(property.getStringList()); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "swordItemWhitelist", new String[0], "List of registry names of items which should count as swords for imbuement spells. Most swords should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:broadsword)."); property.setLanguageKey("config." + Wizardry.MODID + ".sword_item_whitelist"); property.setRequiresWorldRestart(true); - swordItemWhitelist = getResourceLocationList(property); + swordItemWhitelist = parseItemMetaStrings(property.getStringList()); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "bowItemWhitelist", new String[0], "List of registry names of items which should count as bows for imbuement spells. Most bows should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:shortbow)."); property.setLanguageKey("config." + Wizardry.MODID + ".bow_item_whitelist"); property.setRequiresWorldRestart(true); - bowItemWhitelist = getResourceLocationList(property); + bowItemWhitelist = parseItemMetaStrings(property.getStringList()); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "currencyItems", new String[]{"gold_ingot 3", "emerald 6"}, "List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade.", - Pattern.compile("[A-Za-z:_]+ [0-9]+")); + Pattern.compile("[A-Za-z0-9:_]+ [0-9]+")); property.setLanguageKey("config." + Wizardry.MODID + ".currency_items"); property.setRequiresWorldRestart(true); propOrder.add(property.getName()); currencyItems = new HashMap<>(); for(String string : property.getStringList()){ + string = string.toLowerCase(Locale.ROOT).trim(); String[] args = string.split(" "); if(args.length != 2){ Wizardry.logger.warn("Invalid entry in currency items: {}", string); continue; // Ignore invalid entries, the pattern above should ensure this never happens } try { - currencyItems.put(new ResourceLocation(args[0]), Integer.parseInt(args[1])); + currencyItems.put(parseItemMetaString(args[0]), Integer.parseInt(args[1])); }catch(NumberFormatException e){ Wizardry.logger.warn("Invalid integer in currency items: {}", args[1]); } @@ -700,7 +715,7 @@ public final class Settings { fastWorldgen = property.getBoolean(); 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.setRequiresWorldRestart(true); towerDimensions = property.getIntList(); @@ -725,20 +740,20 @@ public final class Settings { 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"}, - "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.setRequiresWorldRestart(true); towerFiles = getResourceLocationList(property); 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"}, - "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.setRequiresWorldRestart(true); towerWithChestFiles = getResourceLocationList(property); 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.setRequiresWorldRestart(true); obeliskDimensions = property.getIntList(); @@ -752,13 +767,13 @@ public final class Settings { 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"}, - "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.setRequiresWorldRestart(true); obeliskFiles = getResourceLocationList(property); 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.setRequiresWorldRestart(true); shrineDimensions = property.getIntList(); @@ -772,7 +787,7 @@ public final class Settings { 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"}, - "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.setRequiresWorldRestart(true); shrineFiles = getResourceLocationList(property); @@ -781,7 +796,7 @@ public final class Settings { property = config.get(GAMEPLAY_CATEGORY, "treeBlocks", DEFAULT_TREE_BLOCKS, "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)."); property.setLanguageKey("config." + Wizardry.MODID + ".tree_blocks"); property.setRequiresWorldRestart(true); - treeBlocks = getResourceLocationList(property); + treeBlocks = parseItemMetaStrings(property.getStringList()); propOrder.add(property.getName()); property = config.get(WORLDGEN_CATEGORY, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!"); @@ -1072,4 +1087,45 @@ public final class Settings { public static ResourceLocation[] toResourceLocations(String... strings){ return Arrays.stream(strings).map(s -> new ResourceLocation(s.toLowerCase(Locale.ROOT).trim())).toArray(ResourceLocation[]::new); } + + /** Applies {@link Settings#parseItemMetaString(String)} to each input string and returns and array of the resulting + * {@link Pair}s. */ + @SuppressWarnings("unchecked") // Shut up java + public static Pair[] parseItemMetaStrings(String... strings){ + return Arrays.stream(strings).map(Settings::parseItemMetaString).toArray(Pair[]::new); + } + + /** Parses the given input string as an item of the form {@code id:metadata} and returns the resulting + * {@link ResourceLocation} ID and metadata value as a {@link Pair} object. */ + public static Pair parseItemMetaString(String string){ + + string = string.toLowerCase(Locale.ROOT).trim(); + + String[] itemArgs = string.split(":"); + String item; + short meta; + + try { + meta = Short.parseShort(itemArgs[itemArgs.length-1]); + item = String.join(":", Arrays.copyOfRange(itemArgs, 0, itemArgs.length-1)); + }catch(NumberFormatException e){ // If no metadata is specified + meta = OreDictionary.WILDCARD_VALUE; + item = string; + } + + return Pair.of(new ResourceLocation(item), meta); + } + + public static boolean containsMetaBlock(Pair[] array, IBlockState block){ + return containsMetaThing(array, block.getBlock().getRegistryName(), (short)block.getBlock().getMetaFromState(block)); + } + + public static boolean containsMetaItem(Pair[] array, ItemStack stack){ + return containsMetaThing(array, stack.getItem().getRegistryName(), (short)stack.getMetadata()); + } + + public static boolean containsMetaThing(Pair[] array, ResourceLocation id, short metadata){ + return Arrays.asList(array).contains(Pair.of(id, metadata)) || Arrays.asList(array).contains(Pair.of(id, OreDictionary.WILDCARD_VALUE)); + } + } diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index f73b173d..091ee65a 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -31,6 +31,9 @@ import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; import org.apache.logging.log4j.Logger; +import java.io.File; +import java.util.Calendar; + /** * "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 @@ -43,7 +46,7 @@ import org.apache.logging.log4j.Logger; */ @Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]", - guiFactory = "electroblob.wizardry.WizardryGuiFactory", dependencies = "required-after:forge@[14.23.5.2814,)") + guiFactory = "electroblob.wizardry.WizardryGuiFactory", dependencies = "required-after:forge@[14.23.5.2814,);after:antiqueatlas@[4.6,)") public class Wizardry { @@ -61,7 +64,7 @@ public class Wizardry { * 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft * 1.11.x versions, and so on. */ - public static final String VERSION = "4.2.3"; + public static final String VERSION = "4.2.10"; // IDEA: Triggering of inbuilt Forge events in relevant places? // IDEA: Abstract the vanilla particles behind the particle builder @@ -82,6 +85,12 @@ public class Wizardry { * - INFO: Anything that might happen during normal mod operation that the user needs to know about. */ 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; + + public static boolean tisTheSeason; + // The instance of wizardry that Forge uses. @Instance(Wizardry.MODID) public static Wizardry instance; @@ -97,8 +106,13 @@ public class Wizardry { proxy.registerResourceReloadListeners(); + configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID); settings.initConfig(event); + Calendar calendar = Calendar.getInstance(); + tisTheSeason = calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DAY_OF_MONTH) >= 24 + && calendar.get(Calendar.DAY_OF_MONTH) <= 26; + // Capabilities WizardData.register(); DispenserCastingData.register(); diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java index 08cb5ac9..bdac3b8b 100644 --- a/src/main/java/electroblob/wizardry/WizardryEventHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -33,6 +33,9 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.LootTable; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.entity.PlaySoundAtEntityEvent; @@ -46,6 +49,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; import java.util.ArrayList; +import java.util.List; /** * General-purpose event handler for things that don't fit anywhere else or groups of related behaviours that are better @@ -286,7 +290,7 @@ public final class WizardryEventHandler { EntityLivingBase attacker = (EntityLivingBase)event.getSource().getTrueSource(); // Players can only ever attack with their main hand, so this is the right method to use here. - if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand().getItem())){ + if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand())){ int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, attacker.getHeldItemMainhand()); @@ -343,18 +347,21 @@ public final class WizardryEventHandler { Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell(); SpellModifiers modifiers = ((ISpellCaster)event.getEntity()).getModifiers(); + int count = ((ISpellCaster)event.getEntity()).getSpellCounter(); if(spell != null && spell != Spells.none){ // IntelliJ is wrong, do NOT remove the null check! if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(SpellCastEvent.Source.NPC, spell, event.getEntityLiving(), - modifiers, 0))){ + modifiers, count))){ - spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0, + spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, count, // TODO: This implementation of modifiers relies on them being accessible client-side. // Right now that doesn't matter because NPCs don't use modifiers, but they might in future ((EntityLiving)event.getEntity()).getAttackTarget(), modifiers); } } + + ((ISpellCaster)event.getEntity()).setSpellCounter(count + 1); } } } @@ -366,6 +373,22 @@ public final class WizardryEventHandler { EntityPlayer player = (EntityPlayer)event.getSource().getTrueSource(); + // Compatibility with "Lycanites Mobs" -it uses custom loot drop logic which can't be hooked, given the + // number of mobs that spawn as Lycanites when this mod is active it would massively nerf the wizard drops + // if we didn't handle this + if(event.getEntity().getClass().getCanonicalName().contains("lycanitesmobs")) + { + WorldServer world = (WorldServer)event.getEntity().getEntityWorld(); + LootTable table = world.getLootTableManager().getLootTableFromLocation(new ResourceLocation(Wizardry.MODID, "entities/mob_additions")); + + LootContext ctx = new LootContext.Builder(world).withPlayer(player).build(); + List stacks = table.generateLootForPools(world.rand, ctx); + + for(ItemStack stack : stacks) { + event.getEntity().entityDropItem(stack, 0f); + } + } + for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){ if(stack.getItem() instanceof IManaStoringItem && !((IManaStoringItem)stack.getItem()).isManaFull(stack) @@ -397,7 +420,7 @@ public final class WizardryEventHandler { @SubscribeEvent // Priority doesn't matter here, we're only setting event fields so if it's cancelled it won't matter public static void onLivingFallEvent(LivingFallEvent event){ // Why is fall damage based on distance fallen? Why? Who on earth came up with that? It makes no sense whatsoever! - if(Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){ + if(!event.getEntity().world.isRemote && Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){ // We want to keep the fall damage EXACTLY THE SAME for free, uninterrupted falls, but fix the weirdness // caused when something else changes the entity's velocity // All living entities have a gravity of 0.08b/t^2 @@ -444,7 +467,8 @@ public final class WizardryEventHandler { // Wizardry.logger.info("Replaced fall distance {} with effective distance {} based on entity velocity", event.getDistance(), y); // } - event.setDistance((float)y); + // Don't let it increase fall damage beyond vanilla values + if(y < event.getDistance()) event.setDistance((float)y); } } } diff --git a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java index 140ed107..69ffe1ab 100644 --- a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java @@ -2,7 +2,6 @@ package electroblob.wizardry; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemWizardHandbook; -import electroblob.wizardry.spell.Spell; import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; import electroblob.wizardry.tileentity.ContainerPortableWorkbench; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; @@ -48,9 +47,9 @@ public class WizardryGuiHandler implements IGuiHandler { return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook(); }else if(id == SPELL_BOOK){ 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){ - 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){ return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z)); diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java index ed9a09d3..3babff08 100644 --- a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java @@ -1,5 +1,6 @@ package electroblob.wizardry.block; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -56,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush { @SubscribeEvent public static void onBonemealEvent(BonemealEvent event){ // Grows crystal flowers when bonemeal is used on grass - if(event.getBlock().getBlock() == Blocks.GRASS){ + if(Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){ BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8), event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4), diff --git a/src/main/java/electroblob/wizardry/block/BlockSnare.java b/src/main/java/electroblob/wizardry/block/BlockSnare.java index a10df677..807425c0 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSnare.java +++ b/src/main/java/electroblob/wizardry/block/BlockSnare.java @@ -18,6 +18,7 @@ import net.minecraft.item.Item; import net.minecraft.potion.PotionEffect; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.DamageSource; import net.minecraft.util.EnumBlockRenderType; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; @@ -54,21 +55,24 @@ public class BlockSnare extends Block implements ITileEntityProvider { @Override public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){ - if(!world.isRemote && entity instanceof EntityLivingBase){ + if(entity instanceof EntityLivingBase){ + if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){ TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos); if(AllyDesignationSystem.isValidTarget(tileentity.getCaster(), entity)){ - entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), - Spells.snare.getProperty(Spell.DAMAGE).floatValue()); + DamageSource source = tileentity.getCaster() == null ? DamageSource.CACTUS + : MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC); + + entity.attackEntityFrom(source, Spells.snare.getProperty(Spell.DAMAGE).floatValue()); ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, Spells.snare.getProperty(Spell.EFFECT_DURATION).intValue(), Spells.snare.getProperty(Spell.EFFECT_STRENGTH).intValue())); - world.destroyBlock(pos, false); + if(!world.isRemote) world.destroyBlock(pos, false); } } } diff --git a/src/main/java/electroblob/wizardry/block/BlockThorns.java b/src/main/java/electroblob/wizardry/block/BlockThorns.java index 0ceb6035..8e22c841 100644 --- a/src/main/java/electroblob/wizardry/block/BlockThorns.java +++ b/src/main/java/electroblob/wizardry/block/BlockThorns.java @@ -137,9 +137,11 @@ public class BlockThorns extends BlockBush implements ITileEntityProvider { TileEntity tileentity = world.getTileEntity(pos); if(tileentity instanceof TileEntityPlayerSaveTimed){ - if(AllyDesignationSystem.isValidTarget(((TileEntityPlayerSaveTimed)tileentity).getCaster(), target)){ - source = MagicDamage.causeDirectMagicDamage(((TileEntityPlayerSaveTimed)tileentity).getCaster(), - MagicDamage.DamageType.MAGIC); + + EntityLivingBase caster = ((TileEntityPlayerSaveTimed)tileentity).getCaster(); + + if(caster != null && AllyDesignationSystem.isValidTarget(caster, target)){ + source = MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.MAGIC); }else{ return false; // Don't attack or slow allies of the caster } diff --git a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java index 945cd597..163f043e 100644 --- a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java +++ b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java @@ -141,7 +141,8 @@ public class BlockTransportationStone extends Block { if(locations.isEmpty()) locations.add(here); else{ locations.remove(here); // Prevents duplicates - locations.set(Math.max(locations.size() - 1, 0), here); + if(locations.isEmpty()) locations.add(here); + else locations.set(Math.max(locations.size() - 1, 0), here); } if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()), true); } diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index b5d75afb..7b4f2e6e 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -29,7 +29,6 @@ import electroblob.wizardry.item.ItemScroll; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.packet.*; -import electroblob.wizardry.potion.PotionSlowTime; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.*; @@ -107,7 +106,7 @@ public class ClientProxy extends CommonProxy { // Armour Model public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f); - /** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style)}). */ + /** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style, Object...)}). */ private static final int TOOLTIP_WRAP_WIDTH = 140; // SECTION Registry @@ -190,6 +189,16 @@ public class ClientProxy extends CommonProxy { } } + @Override + public void playBlinkEffect(EntityPlayer player){ + if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.playBlinkEffect(); + } + + @Override + public void shakeScreen(EntityPlayer player, float intensity){ + if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.shakeScreen(intensity); + } + @Override public Set getSpellHUDSkins(){ return GuiSpellDisplay.getSkinKeys(); @@ -282,8 +291,8 @@ public class ClientProxy extends CommonProxy { } @Override - public void addMultiLineDescription(List tooltip, String key, Style style){ - String description = style.getFormattingCode() + I18n.format(key); + public void addMultiLineDescription(List tooltip, String key, Style style, Object... args){ + String description = style.getFormattingCode() + I18n.format(key, args); tooltip.addAll(Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(description, TOOLTIP_WRAP_WIDTH)); } @@ -429,6 +438,7 @@ public class ClientProxy extends CommonProxy { if(caster instanceof ISpellCaster){ if(spell.isContinuous || spell instanceof None){ ((ISpellCaster)caster).setContinuousSpell(spell); + ((ISpellCaster)caster).setSpellCounter(spell instanceof None ? 0 : 1); ((EntityLiving)caster).setAttackTarget((EntityLivingBase)target); } } @@ -542,7 +552,7 @@ public class ClientProxy extends CommonProxy { data.randomNames = new HashMap<>(); data.randomDescriptions = new HashMap<>(); - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + for(Spell spell : Spell.getAllSpells()){ // -1 because the none spell isn't included // This is a case where we must use the network ID, not the metadata data.randomNames.put(spell, message.names.get(spell.networkID() - 1)); @@ -569,13 +579,6 @@ public class ClientProxy extends CommonProxy { GuiWizardHandbook.updateUnlockStatus(message.showToasts, message.completedAdvancements); } - @Override - public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){ - Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.hostID); - if(entity instanceof EntityLivingBase) PotionSlowTime.unblockNearbyEntities((EntityLivingBase)entity); - else Wizardry.logger.warn("Received a PacketEndSlowTime, but the entity ID did not match any living entity"); - } - @Override public void handleResurrectionPacket(PacketResurrection.Message message){ Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.playerID); diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index a024f95e..4a5586da 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -9,6 +9,7 @@ import electroblob.wizardry.data.WizardData; import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.item.ItemArtefact; import electroblob.wizardry.item.ItemSpectralBow; +import electroblob.wizardry.potion.PotionSlowTime; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; @@ -23,11 +24,8 @@ import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.item.EntityArmorStand; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; @@ -35,18 +33,17 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.village.MerchantRecipe; import net.minecraft.world.World; import net.minecraftforge.client.event.*; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.relauncher.Side; import org.lwjgl.opengl.GL11; -import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; /** * Event handler responsible for client-side only events, mostly rendering. @@ -72,24 +69,34 @@ public final class WizardryClientEventHandler { /** The number of ticks the blink effect lasts for. */ private static final int BLINK_EFFECT_DURATION = 8; - private static final Method unpressKey; - - static { - unpressKey = ObfuscationReflectionHelper.findMethod(KeyBinding.class, "func_74505_d", void.class); - } + /** The remaining time for which the screen shake effect will be active. */ + private static int screenShakeCounter = 0; + private static final float SHAKINESS = 0.5f; - /** Starts the first person blink overlay effect. */ + /** Starts the first-person blink overlay effect. */ public static void playBlinkEffect(){ blinkEffectTimer = BLINK_EFFECT_DURATION; } + + /** Starts the client-side screen shake effect. */ + public static void shakeScreen(float intensity){ + screenShakeCounter = (int)(intensity / SHAKINESS); + Minecraft.getMinecraft().player.rotationPitch -= intensity * 0.5f; // Start halfway down + } @SubscribeEvent public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){ - if(event.player == Minecraft.getMinecraft().player){ + if(event.player == Minecraft.getMinecraft().player && event.phase == TickEvent.Phase.END){ if(blinkEffectTimer > 0) blinkEffectTimer--; + if(screenShakeCounter > 0){ + float magnitude = screenShakeCounter * SHAKINESS; + Minecraft.getMinecraft().player.rotationPitch += screenShakeCounter % 2 == 0 ? magnitude : -magnitude; + screenShakeCounter--; + } + // Only seems to work here... // EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player); // if(victim != null && victim.getHeldItemMainhand().isEmpty()){ @@ -151,7 +158,10 @@ public final class WizardryClientEventHandler { if(world == null) return; - for(TileEntity tileentity : world.loadedTileEntityList){ + // Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list + List tileEntities = new ArrayList<>(world.loadedTileEntityList); + + for(TileEntity tileentity : tileEntities){ if(tileentity instanceof TileEntityDispenser){ if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){ DispenserCastingData.get((TileEntityDispenser)tileentity).update(); @@ -160,6 +170,7 @@ public final class WizardryClientEventHandler { } SpellEmitterData.update(world); + PotionSlowTime.cleanUpEntities(world); } } diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java index 56d8b1cc..b4cf57a4 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java @@ -31,7 +31,6 @@ import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.fml.common.Mod; diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java index 306abffb..3e26c194 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java @@ -1,11 +1,11 @@ package electroblob.wizardry.client.gui; -import com.google.common.collect.ImmutableMap; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; @@ -13,33 +13,27 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.ResourceLocation; +import net.minecraft.item.ItemStack; import org.lwjgl.input.Keyboard; -import java.util.Map; - public class GuiSpellBook extends GuiScreen { private int xSize, ySize; + private ItemSpellBook book; private Spell spell; - private static final Map textures = 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 GuiSpellBook(Spell spell){ + public GuiSpellBook(ItemStack stack){ super(); xSize = 288; 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()); } - /** - * Draws the screen and all the components in it. - */ + @Override public void drawScreen(int par1, int par2, float par3){ int xPos = this.width / 2 - xSize / 2; @@ -59,7 +53,7 @@ public class GuiSpellBook extends GuiScreen { Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); 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); super.drawScreen(par1, par2, par3); @@ -74,22 +68,18 @@ public class GuiSpellBook extends GuiScreen { 0x777777); } - //this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0); + // Novice is usually white but this doesn't show up + String tier = I18n.format("gui.ebwizardry:spell_book.tier", spell.getTier() == Tier.NOVICE ? + "\u00A77" + spell.getTier().getDisplayName() : spell.getTier().getDisplayNameWithFormatting()); + this.fontRenderer.drawString(tier, xPos + 17, yPos + 45, 0); - if(spell.getTier() == Tier.NOVICE){ - // Basic is usually white but this doesn't show up. - this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0); - }else{ - this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0); - } - - String element = "Element: " + spell.getElement().getFormattingCode() + spell.getElement().getDisplayName(); - if(!discovered) element = "Element: ?"; + String element = I18n.format("gui.ebwizardry:spell_book.element", spell.getElement().getFormattingCode() + spell.getElement().getDisplayName()); + if(!discovered) element = I18n.format("gui.ebwizardry:spell_book.element_undiscovered"); this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0); - String manaCost = "Mana Cost: " + spell.getCost(); - if(spell.isContinuous) manaCost = "Mana Cost: " + spell.getCost() + "/second"; - if(!discovered) manaCost = "Mana Cost: ?"; + String manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost", spell.getCost()); + if(spell.isContinuous) manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost_continuous", spell.getCost()); + if(!discovered) manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost_undiscovered"); this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0); if(discovered){ @@ -100,6 +90,7 @@ public class GuiSpellBook extends GuiScreen { } } + @Override public void initGui(){ super.initGui(); Keyboard.enableRepeatEvents(true); @@ -108,6 +99,7 @@ public class GuiSpellBook extends GuiScreen { this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1)); } + @Override public void onGuiClosed(){ super.onGuiClosed(); Keyboard.enableRepeatEvents(false); diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java index 2bebd9c0..4a55d5ef 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java @@ -1,5 +1,6 @@ package electroblob.wizardry.client.model; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.block.BlockStatue; import net.minecraft.client.model.ModelRenderer; import net.minecraft.entity.Entity; @@ -13,6 +14,7 @@ public class ModelWizardArmour extends ModelArmourFixer { ModelRenderer hatSegment4; ModelRenderer hatSegment5; ModelRenderer hatSegment6; + ModelRenderer hatBobble; ModelRenderer robe; public ModelWizardArmour(float delta){ @@ -75,6 +77,13 @@ public class ModelWizardArmour extends ModelArmourFixer { hatSegment6.mirror = true; setRotation(hatSegment6, -0.5585054F, 0F, 0F); + hatBobble = new ModelRenderer(this, 52, 47); + hatBobble.addBox(0F, 0F, 0F, 3, 3, 3); + hatBobble.setRotationPoint(-1.5F, -15.1F, 4F); + hatBobble.setTextureSize(64, 64); + hatBobble.mirror = true; + setRotation(hatBobble, -0.65F, 0F, 0F); + bipedBody = new ModelRenderer(this, 16, 16); bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta); bipedBody.setRotationPoint(0F, 0F, 0F); @@ -97,6 +106,7 @@ public class ModelWizardArmour extends ModelArmourFixer { bipedHead.addChild(hatSegment4); bipedHead.addChild(hatSegment5); bipedHead.addChild(hatSegment6); + bipedHead.addChild(hatBobble); } public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){ @@ -129,6 +139,8 @@ public class ModelWizardArmour extends ModelArmourFixer { this.robe.rotateAngleX = (this.bipedLeftLeg.rotateAngleX + this.bipedRightLeg.rotateAngleX) / 2f; this.robe.rotateAngleY = this.bipedBody.rotateAngleY; this.robe.rotateAngleZ = (this.bipedLeftLeg.rotateAngleZ + this.bipedRightLeg.rotateAngleZ) / 2f; + + this.hatBobble.showModel = Wizardry.tisTheSeason; } } diff --git a/src/main/java/electroblob/wizardry/client/model/WizardryModels.java b/src/main/java/electroblob/wizardry/client/model/WizardryModels.java index b6066c31..05a6ccc0 100644 --- a/src/main/java/electroblob/wizardry/client/model/WizardryModels.java +++ b/src/main/java/electroblob/wizardry/client/model/WizardryModels.java @@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemCrystal; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; 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.statemap.StateMap; import net.minecraft.creativetab.CreativeTabs; @@ -66,10 +67,10 @@ public final class WizardryModels { registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal); - registerItemModel(WizardryItems.magic_wand); - registerItemModel(WizardryItems.apprentice_wand); - registerItemModel(WizardryItems.advanced_wand); - registerItemModel(WizardryItems.master_wand); + registerWandModel(WizardryItems.magic_wand); + registerWandModel(WizardryItems.apprentice_wand); + registerWandModel(WizardryItems.advanced_wand); + registerWandModel(WizardryItems.master_wand); registerItemModel(WizardryItems.spell_book); // Wildcard registered for wizard trades. @@ -77,37 +78,37 @@ public final class WizardryModels { registerItemModel(WizardryItems.arcane_tome); registerItemModel(WizardryItems.wizard_handbook); - registerItemModel(WizardryItems.novice_fire_wand); - registerItemModel(WizardryItems.novice_ice_wand); - registerItemModel(WizardryItems.novice_lightning_wand); - registerItemModel(WizardryItems.novice_necromancy_wand); - registerItemModel(WizardryItems.novice_earth_wand); - registerItemModel(WizardryItems.novice_sorcery_wand); - registerItemModel(WizardryItems.novice_healing_wand); + registerWandModel(WizardryItems.novice_fire_wand); + registerWandModel(WizardryItems.novice_ice_wand); + registerWandModel(WizardryItems.novice_lightning_wand); + registerWandModel(WizardryItems.novice_necromancy_wand); + registerWandModel(WizardryItems.novice_earth_wand); + registerWandModel(WizardryItems.novice_sorcery_wand); + registerWandModel(WizardryItems.novice_healing_wand); - registerItemModel(WizardryItems.apprentice_fire_wand); - registerItemModel(WizardryItems.apprentice_ice_wand); - registerItemModel(WizardryItems.apprentice_lightning_wand); - registerItemModel(WizardryItems.apprentice_necromancy_wand); - registerItemModel(WizardryItems.apprentice_earth_wand); - registerItemModel(WizardryItems.apprentice_sorcery_wand); - registerItemModel(WizardryItems.apprentice_healing_wand); + registerWandModel(WizardryItems.apprentice_fire_wand); + registerWandModel(WizardryItems.apprentice_ice_wand); + registerWandModel(WizardryItems.apprentice_lightning_wand); + registerWandModel(WizardryItems.apprentice_necromancy_wand); + registerWandModel(WizardryItems.apprentice_earth_wand); + registerWandModel(WizardryItems.apprentice_sorcery_wand); + registerWandModel(WizardryItems.apprentice_healing_wand); - registerItemModel(WizardryItems.advanced_fire_wand); - registerItemModel(WizardryItems.advanced_ice_wand); - registerItemModel(WizardryItems.advanced_lightning_wand); - registerItemModel(WizardryItems.advanced_necromancy_wand); - registerItemModel(WizardryItems.advanced_earth_wand); - registerItemModel(WizardryItems.advanced_sorcery_wand); - registerItemModel(WizardryItems.advanced_healing_wand); + registerWandModel(WizardryItems.advanced_fire_wand); + registerWandModel(WizardryItems.advanced_ice_wand); + registerWandModel(WizardryItems.advanced_lightning_wand); + registerWandModel(WizardryItems.advanced_necromancy_wand); + registerWandModel(WizardryItems.advanced_earth_wand); + registerWandModel(WizardryItems.advanced_sorcery_wand); + registerWandModel(WizardryItems.advanced_healing_wand); - registerItemModel(WizardryItems.master_fire_wand); - registerItemModel(WizardryItems.master_ice_wand); - registerItemModel(WizardryItems.master_lightning_wand); - registerItemModel(WizardryItems.master_necromancy_wand); - registerItemModel(WizardryItems.master_earth_wand); - registerItemModel(WizardryItems.master_sorcery_wand); - registerItemModel(WizardryItems.master_healing_wand); + registerWandModel(WizardryItems.master_fire_wand); + registerWandModel(WizardryItems.master_ice_wand); + registerWandModel(WizardryItems.master_lightning_wand); + registerWandModel(WizardryItems.master_necromancy_wand); + registerWandModel(WizardryItems.master_earth_wand); + registerWandModel(WizardryItems.master_sorcery_wand); + registerWandModel(WizardryItems.master_healing_wand); registerItemModel(WizardryItems.spectral_sword); registerItemModel(WizardryItems.spectral_pickaxe); @@ -294,24 +295,30 @@ public final class WizardryModels { /** * 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 - * 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. + * keep track of everything). Variant defaults to "normal". Registers the model for all metadata values. */ private static void registerItemModel(Item item){ - - if(item.getHasSubtypes()){ - NonNullList 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! - ModelLoader.setCustomModelResourceLocation(item, 0, - new ModelResourceLocation(item.getRegistryName(), "inventory")); + ModelBakery.registerItemVariants(item, new ModelResourceLocation(item.getRegistryName(), "inventory")); + // Assigns the model for all metadata values + ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation(item.getRegistryName(), "inventory")); + } + + /** + * Registers a wand model, using the item's registry name as the model name (this convention makes it easier to + * keep track of everything). + */ + private static void registerWandModel(Item item){ + + if(Wizardry.tisTheSeason){ + // Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why! + ModelBakery.registerItemVariants(item, new ModelResourceLocation("ebwizardry:festive_wand", "inventory")); + // Assigns the model for all metadata values + ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation("ebwizardry:festive_wand", "inventory")); + }else{ + registerItemModel(item); + } + } /** diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java index 1172bb34..1b91c6aa 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java @@ -525,30 +525,42 @@ public abstract class ParticleWizardry extends Particle { // =============================================== Helper Methods =============================================== - + + /** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int)} which uses wizardry's mod + * ID automatically. */ + public static ResourceLocation[] generateTextures(String stem, int n){ + return generateTextures(Wizardry.MODID, stem, n); + } + /** Static helper method that generates an array of n ResourceLocations using the particle file naming convention, * which is the given stem plus an underscore plus the integer index. */ - public static ResourceLocation[] generateTextures(String stem, int n){ + public static ResourceLocation[] generateTextures(String modID, String stem, int n){ ResourceLocation[] textures = new ResourceLocation[n]; for(int i=0; i { double scaleX = 1, scaleY = 1; // It's more logical to use the model's texture size, but some classes don't bother setting it properly // (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead. - if(model.boxList != null && model.boxList.get(0) != null){ + if(model.boxList != null && model.boxList.size() >= 1 && model.boxList.get(0) != null){ scaleX = (double)model.boxList.get(0).textureWidth / 16d; scaleY = (double)model.boxList.get(0).textureHeight / 16d; }else{ // Fallback to model fields; should never be needed @@ -121,11 +121,26 @@ public class LayerFrost implements LayerRenderer { } GlStateManager.scale(scaleX, scaleY, 1); GlStateManager.matrixMode(GL11.GL_MODELVIEW); - + + boolean headWearHidden = false; + boolean bodyWearHidden = false; + boolean leftArmWearHidden = false; + boolean rightArmWearHidden = false; + boolean leftLegWearHidden = false; + boolean rightLegWearHidden = false; + // Hides the hat layer for bipeds - if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = true; + if(this.model instanceof ModelBiped){ + headWearHidden = ((ModelBiped)this.model).bipedHeadwear.isHidden; + ((ModelBiped)this.model).bipedHeadwear.isHidden = true; + } if(this.model instanceof ModelPlayer){ + bodyWearHidden = ((ModelPlayer)this.model).bipedBodyWear.isHidden; + leftArmWearHidden = ((ModelPlayer)this.model).bipedLeftArmwear.isHidden; + rightArmWearHidden = ((ModelPlayer)this.model).bipedRightArmwear.isHidden; + leftLegWearHidden = ((ModelPlayer)this.model).bipedLeftLegwear.isHidden; + rightLegWearHidden = ((ModelPlayer)this.model).bipedRightLegwear.isHidden; ((ModelPlayer)this.model).bipedBodyWear.isHidden = true; ((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true; ((ModelPlayer)this.model).bipedRightArmwear.isHidden = true; @@ -136,7 +151,15 @@ public class LayerFrost implements LayerRenderer { this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks); this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); - if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = false; + if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = headWearHidden; + + if(this.model instanceof ModelPlayer){ + ((ModelPlayer)this.model).bipedBodyWear.isHidden = bodyWearHidden; + ((ModelPlayer)this.model).bipedLeftArmwear.isHidden = leftArmWearHidden; + ((ModelPlayer)this.model).bipedRightArmwear.isHidden = rightArmWearHidden; + ((ModelPlayer)this.model).bipedLeftLegwear.isHidden = leftLegWearHidden; + ((ModelPlayer)this.model).bipedRightLegwear.isHidden = rightLegWearHidden; + } // Undoes the texture scaling GlStateManager.matrixMode(GL11.GL_TEXTURE); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java index abab6a76..a9f36d1e 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java @@ -42,6 +42,7 @@ public class RenderArcaneLock { GlStateManager.pushMatrix(); GlStateManager.enableBlend(); + boolean lighting = GL11.glIsEnabled(GL11.GL_LIGHTING); GlStateManager.disableLighting(); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); @@ -62,6 +63,8 @@ public class RenderArcaneLock { List tileentities = new ArrayList<>(world.loadedTileEntityList); for(TileEntity tileentity : tileentities){ + + if(tileentity == null) continue; // What the heck VoxelMap if(tileentity.getDistanceSq(origin.x, origin.y, origin.z) <= tileentity.getMaxRenderDistanceSquared() && tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){ @@ -82,7 +85,9 @@ public class RenderArcaneLock { GlStateManager.disableBlend(); GlStateManager.enableTexture2D(); - GlStateManager.enableLighting(); + if (lighting) { + GlStateManager.enableLighting(); + } GlStateManager.disableRescaleNormal(); GlStateManager.popMatrix(); } diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java b/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java index 26177fa0..cbde5ed2 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderBlackHole.java @@ -53,9 +53,8 @@ public class RenderBlackHole extends Render { (float)blackhole.ticksExisted / 10); } if(blackhole.ticksExisted > blackhole.lifetime - 10){ - GlStateManager.scale((float)(blackhole.lifetime - blackhole.ticksExisted) / 10, - (float)(blackhole.lifetime - blackhole.ticksExisted) / 10, - (float)(blackhole.lifetime - blackhole.ticksExisted) / 10); + float scale = Math.max(0, (float)(blackhole.lifetime - blackhole.ticksExisted) / 10); + GlStateManager.scale(scale, scale, scale); } this.bindTexture(texture); diff --git a/src/main/java/electroblob/wizardry/command/CommandCastSpell.java b/src/main/java/electroblob/wizardry/command/CommandCastSpell.java index c71e9e29..e460be1b 100644 --- a/src/main/java/electroblob/wizardry/command/CommandCastSpell.java +++ b/src/main/java/electroblob/wizardry/command/CommandCastSpell.java @@ -190,7 +190,8 @@ public class CommandCastSpell extends CommandBase { } if(spell.isContinuous){ - + // We need not query Spell#canBeCastByDispensers since with commands there's no difference between + // a spell that can't be cast positionally and one that can be cast positionally but fails if(spell.cast(world, origin.x, origin.y, origin.z, direction, 0, duration, modifiers)){ MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, world, origin.x, origin.y, origin.z, direction, modifiers)); diff --git a/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java b/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java index 84733924..3bb209ee 100644 --- a/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java +++ b/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java @@ -113,7 +113,7 @@ public class CommandDiscoverSpell extends CommandBase { if(server.sendCommandFeedback()) sender.sendMessage( new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.clear", player.getName())); }else if(all){ - data.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells)); + data.spellsDiscovered.addAll(Spell.getAllSpells()); if(server.sendCommandFeedback()) sender.sendMessage( new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.all", player.getName())); }else{ diff --git a/src/main/java/electroblob/wizardry/command/SpellEmitter.java b/src/main/java/electroblob/wizardry/command/SpellEmitter.java index 7a09e6b0..b60659fc 100644 --- a/src/main/java/electroblob/wizardry/command/SpellEmitter.java +++ b/src/main/java/electroblob/wizardry/command/SpellEmitter.java @@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.data.SpellEmitterData; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import io.netty.buffer.ByteBuf; import net.minecraft.nbt.NBTTagCompound; @@ -129,7 +130,7 @@ public class SpellEmitter implements ITickable { nbt.setDouble("z", z); nbt.setInteger("direction", direction.getIndex()); nbt.setInteger("duration", duration); - nbt.setTag("modifiers", modifiers.toNBT()); + NBTExtras.storeTagSafely(nbt, "modifiers", modifiers.toNBT()); nbt.setInteger("castingTick", castingTick); return nbt; diff --git a/src/main/java/electroblob/wizardry/constants/Tier.java b/src/main/java/electroblob/wizardry/constants/Tier.java index b814beee..49b23619 100644 --- a/src/main/java/electroblob/wizardry/constants/Tier.java +++ b/src/main/java/electroblob/wizardry/constants/Tier.java @@ -12,9 +12,9 @@ import java.util.Random; public enum Tier { NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"), - APPRENTICE(1000, 5, 5, 4000, new Style().setColor(TextFormatting.AQUA), "apprentice"), - ADVANCED(1500, 7, 2, 6000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), - MASTER(2500, 9, 1, 10000, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); + APPRENTICE(1000, 5, 5, 2000, new Style().setColor(TextFormatting.AQUA), "apprentice"), + ADVANCED(1500, 7, 2, 3500, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), + MASTER(2500, 9, 1, 6000, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); /** Maximum mana a wand of this tier can store. */ public final int maxCharge; diff --git a/src/main/java/electroblob/wizardry/data/BlockCastingData.java b/src/main/java/electroblob/wizardry/data/BlockCastingData.java index a02d2de7..05f80bcf 100644 --- a/src/main/java/electroblob/wizardry/data/BlockCastingData.java +++ b/src/main/java/electroblob/wizardry/data/BlockCastingData.java @@ -7,6 +7,7 @@ import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.None; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -141,7 +142,7 @@ public abstract class BlockCastingData implements INBTSeri nbt.setInteger("spell", spell.metadata()); nbt.setInteger("castingTick", castingTick); - nbt.setTag("modifiers", modifiers.toNBT()); + NBTExtras.storeTagSafely(nbt, "modifiers", modifiers.toNBT()); return nbt; } diff --git a/src/main/java/electroblob/wizardry/data/DispenserCastingData.java b/src/main/java/electroblob/wizardry/data/DispenserCastingData.java index 28d0fe56..226c4abc 100644 --- a/src/main/java/electroblob/wizardry/data/DispenserCastingData.java +++ b/src/main/java/electroblob/wizardry/data/DispenserCastingData.java @@ -166,7 +166,10 @@ public class DispenserCastingData extends BlockCastingData // This will fire once for each dimension, but since we want dispenser-casting to work in all dimensions, // this is correct (the loaded tile entity list will of course be different in each case. - for(TileEntity tileentity : event.world.loadedTileEntityList){ + // Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list + List tileEntities = new ArrayList<>(event.world.loadedTileEntityList); + + for(TileEntity tileentity : tileEntities){ if(tileentity instanceof TileEntityDispenser){ if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){ DispenserCastingData.get((TileEntityDispenser)tileentity).update(); diff --git a/src/main/java/electroblob/wizardry/data/IStoredVariable.java b/src/main/java/electroblob/wizardry/data/IStoredVariable.java index f6594f57..ea7d1a0d 100644 --- a/src/main/java/electroblob/wizardry/data/IStoredVariable.java +++ b/src/main/java/electroblob/wizardry/data/IStoredVariable.java @@ -1,5 +1,6 @@ package electroblob.wizardry.data; +import electroblob.wizardry.util.NBTExtras; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -89,7 +90,7 @@ public interface IStoredVariable extends IVariable { @Override public void write(NBTTagCompound nbt, T value){ - if(value != null) nbt.setTag(key, serialiser.apply(value)); + if(value != null) NBTExtras.storeTagSafely(nbt, key, serialiser.apply(value)); } @Override diff --git a/src/main/java/electroblob/wizardry/data/SpellEmitterData.java b/src/main/java/electroblob/wizardry/data/SpellEmitterData.java index a3178303..8b53f510 100644 --- a/src/main/java/electroblob/wizardry/data/SpellEmitterData.java +++ b/src/main/java/electroblob/wizardry/data/SpellEmitterData.java @@ -91,7 +91,7 @@ public class SpellEmitterData extends WorldSavedData { @Override public NBTTagCompound writeToNBT(NBTTagCompound compound){ - compound.setTag("emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT)); + NBTExtras.storeTagSafely(compound, "emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT)); return compound; } diff --git a/src/main/java/electroblob/wizardry/data/SpellGlyphData.java b/src/main/java/electroblob/wizardry/data/SpellGlyphData.java index 03fc3f89..55ba24fe 100644 --- a/src/main/java/electroblob/wizardry/data/SpellGlyphData.java +++ b/src/main/java/electroblob/wizardry/data/SpellGlyphData.java @@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.packet.PacketGlyphData; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.NBTExtras; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -43,11 +44,11 @@ public class SpellGlyphData extends WorldSavedData { /** Generates random names and descriptions for any spells which don't already have them. */ public void generateGlyphNames(World world){ - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + for(Spell spell : Spell.getAllSpells()){ if(!randomNames.containsKey(spell)) randomNames.put(spell, generateRandomName(world.rand)); } - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + for(Spell spell : Spell.getAllSpells()){ if(!randomDescriptions.containsKey(spell)) randomDescriptions.put(spell, generateRandomDescription(world.rand)); } @@ -161,7 +162,7 @@ public class SpellGlyphData extends WorldSavedData { NBTTagList tagList = new NBTTagList(); - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + for(Spell spell : Spell.getAllSpells()){ // Much like the enchantments tag for items, this stores a list of spell-id-to-name tag pairs // The description is now also included; there's no point in making a second compound tag! NBTTagCompound tag = new NBTTagCompound(); @@ -171,7 +172,7 @@ public class SpellGlyphData extends WorldSavedData { tagList.appendTag(tag); } - nbt.setTag("spellGlyphData", tagList); + NBTExtras.storeTagSafely(nbt, "spellGlyphData", tagList); return nbt; } diff --git a/src/main/java/electroblob/wizardry/data/WizardData.java b/src/main/java/electroblob/wizardry/data/WizardData.java index 0511d67c..7e70b21d 100644 --- a/src/main/java/electroblob/wizardry/data/WizardData.java +++ b/src/main/java/electroblob/wizardry/data/WizardData.java @@ -515,12 +515,12 @@ public class WizardData implements INBTSerializable { NBTTagCompound properties = new NBTTagCompound(); - properties.setTag("imbuements", NBTExtras.mapToNBT(this.imbuementDurations, + NBTExtras.storeTagSafely(properties, "imbuements", NBTExtras.mapToNBT(this.imbuementDurations, imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new)); // Mmmmmm Java 8.... - properties.setTag("allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag)); - properties.setTag("allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new)); + NBTExtras.storeTagSafely(properties, "allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag)); + NBTExtras.storeTagSafely(properties, "allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new)); // Might be worth converting this over to WizardryUtilities.listToNBT. int[] spells = new int[this.spellsDiscovered.size()]; @@ -531,7 +531,7 @@ public class WizardData implements INBTSerializable { } properties.setIntArray("discoveredSpells", spells); - properties.setTag("recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata()))); + NBTExtras.storeTagSafely(properties, "recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata()))); storedVariables.forEach(k -> k.write(properties, this.spellData.get(k))); diff --git a/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java b/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java index c397d37b..12222480 100644 --- a/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java +++ b/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java @@ -68,7 +68,7 @@ public class EnchantmentMagicProtection extends Enchantment { public enum Type { - MAGIC("magic", 1, 5, 8, s -> s instanceof IElementalDamage), + MAGIC("magic", 1, 5, 8, s -> s instanceof IElementalDamage || s.isMagicDamage()), FROST("frost", 2, 10, 8, s -> s instanceof IElementalDamage && ((IElementalDamage)s).getType() == MagicDamage.DamageType.FROST), SHOCK("shock", 2, 10, 8, s -> s instanceof IElementalDamage && ((IElementalDamage)s).getType() == MagicDamage.DamageType.SHOCK); // Fire already exists, and the other types aren't used enough to be worth having diff --git a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java index 53906427..7487ca3d 100644 --- a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java +++ b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java @@ -120,9 +120,9 @@ public interface Imbuement { ItemStack bow = archer.getHeldItemMainhand(); - if(!ImbueWeapon.isBow(bow.getItem())){ + if(!ImbueWeapon.isBow(bow)){ bow = archer.getHeldItemOffhand(); - if(!ImbueWeapon.isBow(bow.getItem())) return; + if(!ImbueWeapon.isBow(bow)) return; } // Taken directly from ItemBow, so it works exactly the same as the power enchantment. diff --git a/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java b/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java index 84305760..72b67202 100644 --- a/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java +++ b/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java @@ -5,6 +5,7 @@ import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; @@ -183,7 +184,7 @@ public class EntityLevitatingBlock extends EntityFallingBlock implements IEntity NBTBase nbtbase = this.tileEntityData.getTag(s); if(!"x".equals(s) && !"y".equals(s) && !"z".equals(s)){ - nbttagcompound.setTag(s, nbtbase.copy()); + NBTExtras.storeTagSafely(nbttagcompound, s, nbtbase.copy()); } } diff --git a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java index f41d63ad..938e5c16 100644 --- a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java +++ b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java @@ -5,9 +5,11 @@ import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Meteor; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.MoverType; import net.minecraft.entity.item.EntityFallingBlock; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.SoundCategory; import net.minecraft.world.World; @@ -61,9 +63,9 @@ public class EntityMeteor extends EntityFallingBlock { this.motionY *= 0.9800000190734863D; this.motionZ *= 0.9800000190734863D; - if(!this.world.isRemote){ + if(this.onGround){ - if(this.onGround){ + if(!this.world.isRemote){ this.motionX *= 0.699999988079071D; this.motionZ *= 0.699999988079071D; @@ -72,8 +74,13 @@ public class EntityMeteor extends EntityFallingBlock { Spells.meteor.getProperty(Meteor.BLAST_STRENGTH).floatValue() * blastMultiplier, damageBlocks, damageBlocks); this.setDead(); + + }else{ + WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class) + .forEach(p -> Wizardry.proxy.shakeScreen(p, 10)); } } + } @Override diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java index e494c610..08a59b14 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java @@ -65,7 +65,7 @@ public class EntityBubble extends EntityMagicConstruct { if(isDarkOrb){ if(WizardryUtilities.getRider(this) != null - && this.ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){ + && WizardryUtilities.getRider(this).ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){ if(this.getCaster() != null){ WizardryUtilities.getRider(this).attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java b/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java index 45494990..1077cdd3 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java @@ -1,6 +1,5 @@ package electroblob.wizardry.entity.construct; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.WizardryUtilities; diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java index 2a6f455a..19dd083c 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java @@ -7,7 +7,6 @@ import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityFallingBlock; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.MobEffects; import net.minecraft.network.play.server.SPacketEntityVelocity; @@ -97,18 +96,6 @@ public class EntityEarthquake extends EntityMagicConstruct { } } } - - if(!world.isRemote){ - // Constant 15 blocks for now - List targets2 = WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class); - - float magnitude = 10f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime; - - // Makes the screen shake - for(EntityPlayer target : targets2){ - target.rotationPitch += this.ticksExisted % 2 == 0 ? magnitude : -magnitude; - } - } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java index 8a56a293..328a4077 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java @@ -80,8 +80,8 @@ public class EntityHammer extends EntityMagicConstruct { if(this.world.isRemote && this.ticksExisted % 3 == 0){ ParticleBuilder.create(Type.SPARK) - .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble()) - .spawn(world); + .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble()) + .spawn(world); } this.prevPosX = this.posX; @@ -103,39 +103,37 @@ public class EntityHammer extends EntityMagicConstruct { this.rotationPitch = 0; this.spin = false; - if(this.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){ + double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue(); - double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue(); + List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, + this.posY + 1, this.posZ, world); - List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, - this.posY + 1, this.posZ, world); + int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue(); + while(targets.size() > maxTargets) targets.remove(targets.size() - 1); - int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue(); - while(targets.size() > maxTargets) targets.remove(targets.size() - 1); + for(EntityLivingBase target : targets){ - for(EntityLivingBase target : targets){ + if(WizardryUtilities.isLiving(target) && this.isValidTarget(target) + && target.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){ - if(WizardryUtilities.isLiving(target) && this.isValidTarget(target)){ + if(world.isRemote){ - if(world.isRemote){ + ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world); - ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world); + ParticleBuilder.spawnShockParticles(world, target.posX, + target.getEntityBoundingBox().minY + target.height, target.posZ); + } - ParticleBuilder.spawnShockParticles(world, target.posX, - target.getEntityBoundingBox().minY + target.height, target.posZ); - } + target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); - target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); + float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier; - float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier; - - if(this.getCaster() != null){ - WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage( - this, getCaster(), DamageType.SHOCK), damage); - WizardryUtilities.applyStandardKnockback(this, target); - }else{ - target.attackEntityFrom(DamageSource.MAGIC, damage); - } + if(this.getCaster() != null){ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage( + this, getCaster(), DamageType.SHOCK), damage); + WizardryUtilities.applyStandardKnockback(this, target); + }else{ + target.attackEntityFrom(DamageSource.MAGIC, damage); } } } @@ -171,6 +169,7 @@ public class EntityHammer extends EntityMagicConstruct { public void fall(float distance, float damageMultiplier){ if(world.isRemote){ + for(int i = 0; i < 40; i++){ double particleX = this.posX - 1.0d + 2 * rand.nextDouble(); double particleZ = this.posZ - 1.0d + 2 * rand.nextDouble(); @@ -182,6 +181,12 @@ public class EntityHammer extends EntityMagicConstruct { particleX - this.posX, 0, particleZ - this.posZ, Block.getStateId(block)); } } + + if(this.fallDistance > 10){ + WizardryUtilities.getEntitiesWithinRadius(10, posX, posY, posZ, world, EntityPlayer.class) + .forEach(p -> Wizardry.proxy.shakeScreen(p, 6)); + } + }else{ // Just to check the hammer has actually fallen from the sky, rather than the block under it being broken. if(this.fallDistance > 10){ diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java index df3dd462..dc32d17b 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java @@ -62,7 +62,7 @@ public class EntityHealAura extends EntityMagicConstruct { target.motionZ = velZ; } - }else if(target.getHealth() < target.getMaxHealth() && this.ticksExisted % 5 == 0){ + }else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){ target.heal(Spells.healing_aura.getProperty(Spell.HEALTH).floatValue() * damageMultiplier); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java index 75a83bc4..d79ac809 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java @@ -10,6 +10,7 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.Vec3d; @@ -29,9 +30,9 @@ public class EntityIceSpike extends EntityMagicConstruct { this.setRotation(-facing.getHorizontalAngle(), WizardryUtilities.getPitch(facing)); float yaw = (-facing.getHorizontalAngle()) * (float)Math.PI/180; float pitch = (WizardryUtilities.getPitch(facing) - 90) * (float)Math.PI/180; - Vec3d min = new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw); - Vec3d max = new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw); - this.setEntityBoundingBox(new AxisAlignedBB(this.getPositionVector().add(min), this.getPositionVector().add(max))); + Vec3d min = this.getPositionVector().add(new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw)); + Vec3d max = this.getPositionVector().add(new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw)); + this.setEntityBoundingBox(new AxisAlignedBB(min.x, min.y, min.z, max.x, max.y, max.z)); } public EnumFacing getFacing(){ @@ -61,10 +62,9 @@ public class EntityIceSpike extends EntityMagicConstruct { if(!this.world.isRemote){ for(Object entity : this.world.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox())){ if(entity instanceof EntityLivingBase && this.isValidTarget((EntityLivingBase)entity)){ + DamageSource source = this.getCaster() == null ? DamageSource.MAGIC : MagicDamage.causeDirectMagicDamage(this.getCaster(), DamageType.FROST); // Potion effect only gets added if the damage succeeded. - if(((EntityLivingBase)entity).attackEntityFrom( - MagicDamage.causeDirectMagicDamage(this.getCaster(), DamageType.FROST), - Spells.ice_spikes.getProperty(Spell.DAMAGE).floatValue() * this.damageMultiplier)) + if(((EntityLivingBase)entity).attackEntityFrom(source, Spells.ice_spikes.getProperty(Spell.DAMAGE).floatValue() * this.damageMultiplier)) ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost, Spells.ice_spikes.getProperty(Spell.EFFECT_DURATION).intValue(), Spells.ice_spikes.getProperty(Spell.EFFECT_STRENGTH).intValue())); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java index d0cd4c93..21cf3471 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java @@ -213,6 +213,7 @@ public class EntityAIAttackSpell extends return false; } + // This is only called when spell casting starts so ticksInUse is always zero if(spell.cast(attacker.world, attacker, EnumHand.MAIN_HAND, 0, target, modifiers)){ if(spell.isContinuous){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index 4a9c8755..ca20dd61 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -35,11 +35,17 @@ import net.minecraft.world.DifficultyInstance; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; 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 org.apache.commons.lang3.ArrayUtils; import javax.annotation.Nullable; import java.util.*; +@Mod.EventBusSubscriber public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData { private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50); @@ -68,6 +74,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // Field implementations private List spells = new ArrayList(4); private Spell continuousSpell; + private int spellCounter; public EntityEvilWizard(World world){ @@ -169,6 +176,16 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity public Spell getContinuousSpell(){ return this.continuousSpell; } + + @Override + public void setSpellCounter(int count){ + spellCounter = count; + } + + @Override + public int getSpellCounter(){ + return spellCounter; + } @Override public int getAimingError(EnumDifficulty difficulty){ @@ -246,7 +263,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // When right-clicked with a spell book in creative, sets one of the spells to that spell if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){ Spell spell = Spell.byMetadata(stack.getItemDamage()); - if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){ + if(this.spells.size() >= 4 && spell.canBeCastBy(this, true)){ // The set(...) method returns the element that was replaced - neat! player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard", this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(), @@ -263,9 +280,9 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity super.writeEntityToNBT(nbt); nbt.setInteger("element", this.getElement().ordinal()); nbt.setInteger("skin", this.textureIndex); - nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata()))); + NBTExtras.storeTagSafely(nbt, "spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata()))); nbt.setBoolean("hasStructure", this.hasStructure); - nbt.setTag("groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag)); + NBTExtras.storeTagSafely(nbt, "groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag)); } @Override @@ -283,16 +300,6 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity public int getMaxSpawnedInChunk(){ 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 protected boolean canDespawn(){ @@ -373,7 +380,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // All wizards know magic missile, even if it is disabled. spells.add(Spells.magic_missile); - Tier maxTier = EntityWizard.populateSpells(spells, element, hasStructure, 3, rand); + Tier maxTier = EntityWizard.populateSpells(this, spells, element, hasStructure, 3, rand); // Now done after the spells so it can take the tier into account. For evil wizards this is slightly different; // it picks a random wand which is at least a high enough tier for the spells the wizard has. @@ -393,4 +400,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity 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); + } + } + } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java index c3b118e7..b964ac3e 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java @@ -52,7 +52,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F)); this.tasks.addTask(7, new EntityAILookIdle(this)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java index 467fc3ad..8e4e55b4 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java @@ -16,7 +16,13 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.MathHelper; 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 { /** 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 public boolean getCanSpawnHere(){ - // Only spawns in the specified dimensions - for(int id : Wizardry.settings.mobSpawnDimensions){ - if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel(); - } + 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); + } } /** diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java index d396735f..e0dd58be 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java @@ -13,7 +13,13 @@ import net.minecraft.init.MobEffects; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; 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 EntityLightningWraith extends EntityBlazeMinion { public EntityLightningWraith(World world){ @@ -74,14 +80,17 @@ public class EntityLightningWraith extends EntityBlazeMinion { @Override public boolean getCanSpawnHere(){ - // Only spawns in the specified dimensions, during thunderstorms - if(!world.isThundering()) return false; + return super.getCanSpawnHere() && this.isValidLightLevel(); + } - for(int id : Wizardry.settings.mobSpawnDimensions){ - if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel(); + @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(!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; } /** diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java index e04428b0..23e11730 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java @@ -30,6 +30,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell<>(this, AISpeed, 15f, 60, 140); private Spell continuousSpell; + private int spellCounter; private static final List attack = Collections.singletonList(Spells.flame_ray); @@ -50,7 +51,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste this.tasks.addTask(3, new EntityAILookIdle(this)); // this.targetTasks.addTask(0, new EntityAIMoveTowardsTarget(this, 1, 10)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); this.setAIMoveSpeed((float)AISpeed); @@ -76,6 +77,16 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste continuousSpell = spell; } + @Override + public void setSpellCounter(int count){ + spellCounter = count; + } + + @Override + public int getSpellCounter(){ + return spellCounter; + } + @Override public boolean hasRangedAttack(){ return true; diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java index 55963b90..1ebd82ba 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -45,7 +45,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell this.tasks.addTask(2, new EntityAIWander(this, AISpeed)); this.tasks.addTask(3, new EntityAILookIdle(this)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); this.setAIMoveSpeed((float)AISpeed); @@ -61,21 +61,6 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell return attack; } - @Override - public SpellModifiers getModifiers(){ - return new SpellModifiers(); - } - - @Override - public Spell getContinuousSpell(){ - return Spells.none; - } - - @Override - public void setContinuousSpell(Spell spell){ - // Doesn't use continuous spells. - } - @Override protected void applyEntityAttributes(){ super.applyEntityAttributes(); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java index ce87a216..ef6c3aee 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -59,21 +59,6 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe return attack; } - @Override - public SpellModifiers getModifiers(){ - return new SpellModifiers(); - } - - @Override - public Spell getContinuousSpell(){ - return Spells.none; - } - - @Override - public void setContinuousSpell(Spell spell){ - // Doesn't use continuous spells. - } - @Override protected void applyEntityAttributes(){ super.applyEntityAttributes(); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 2d5ac7b0..c5737951 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -50,6 +50,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.oredict.OreDictionary; +import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nullable; import java.util.*; @@ -83,6 +84,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Field implementations private List spells = new ArrayList(4); private Spell continuousSpell; + private int spellCounter; /** A set of the positions of the blocks that are part of this wizard's tower. */ private Set towerBlocks; @@ -187,7 +189,17 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp public Spell getContinuousSpell(){ return this.continuousSpell; } - + + @Override + public void setSpellCounter(int count){ + spellCounter = count; + } + + @Override + public int getSpellCounter(){ + return spellCounter; + } + @Override public int getAimingError(EnumDifficulty difficulty){ // Being more intelligent than skeletons, wizards are a little more accurate. @@ -218,7 +230,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Copied from EntityVillager if(!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20){ this.livingSoundTime = -this.getTalkInterval(); - this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : WizardrySounds.ENTITY_WIZARD_YES, this.getSoundVolume(), this.getSoundPitch()); + SoundEvent yes = Wizardry.tisTheSeason ? WizardrySounds.ENTITY_WIZARD_HOHOHO : WizardrySounds.ENTITY_WIZARD_YES; + this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : yes, this.getSoundVolume(), this.getSoundPitch()); } } @@ -256,6 +269,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp @Override protected SoundEvent getAmbientSound(){ + if(Wizardry.tisTheSeason) return WizardrySounds.ENTITY_WIZARD_HOHOHO; return this.isTrading() ? WizardrySounds.ENTITY_WIZARD_TRADING : WizardrySounds.ENTITY_WIZARD_AMBIENT; } @@ -357,7 +371,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // When right-clicked with a spell book in creative, sets one of the spells to that spell if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){ Spell spell = Spell.byMetadata(stack.getItemDamage()); - if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){ + if(this.spells.size() >= 4 && spell.canBeCastBy(this, true)){ // The set(...) method returns the element that was replaced - neat! player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard", this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(), @@ -387,15 +401,15 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp super.writeEntityToNBT(nbt); if(this.trades != null){ - nbt.setTag("trades", this.trades.getRecipiesAsTags()); + NBTExtras.storeTagSafely(nbt, "trades", this.trades.getRecipiesAsTags()); } nbt.setInteger("element", this.getElement().ordinal()); nbt.setInteger("skin", this.textureIndex); - nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata()))); + NBTExtras.storeTagSafely(nbt, "spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata()))); if(this.towerBlocks != null && this.towerBlocks.size() > 0){ - nbt.setTag("towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag)); + NBTExtras.storeTagSafely(nbt, "towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag)); } } @@ -414,7 +428,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.spells = (List)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), (NBTTagInt tag) -> Spell.byMetadata(tag.getInt())); - NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_LONG); + NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_COMPOUND); if(!tagList.isEmpty()){ this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(tagList, NBTUtil::getPosFromTag)); }else{ @@ -489,7 +503,6 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp ItemStack anySpellBook = new ItemStack(WizardryItems.spell_book, 1, OreDictionary.WILDCARD_VALUE); ItemStack crystalStack = new ItemStack(WizardryItems.magic_crystal, 5); - // NOTE: For wizardry 1.2, increase the number of uses of this trade. The default is 7, for reference. this.trades.add(new MerchantRecipe(anySpellBook, crystalStack)); this.addRandomRecipes(3); @@ -574,12 +587,14 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // TODO: Switch all of this over to some kind of loot pool system? + @SuppressWarnings("unchecked") private ItemStack getRandomPrice(Tier tier){ - Map map = Wizardry.settings.currencyItems; + Map, Integer> map = Wizardry.settings.currencyItems; // This isn't that efficient but it's not called very often really so it doesn't matter - ResourceLocation itemName = map.keySet().toArray(new ResourceLocation[0])[rand.nextInt(map.size())]; - Item item = Item.REGISTRY.getObject(itemName); + Pair itemName = map.keySet().toArray(new Pair[0])[rand.nextInt(map.size())]; + Item item = Item.REGISTRY.getObject(itemName.getLeft()); + short meta = itemName.getRight(); int value; if(item == null){ @@ -593,7 +608,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // ((tier.ordinal() + 1) * 16 + rand.nextInt(6)) gives a 'value' for the item being bought // This is then divided by the value of the currency item to give a price // The absolute maximum stack size that can result from this calculation (with value = 1) is 64. - return new ItemStack(item, (8 + tier.ordinal() * 16 + rand.nextInt(9)) / value); + return new ItemStack(item, (8 + tier.ordinal() * 16 + rand.nextInt(9)) / value, meta); } private ItemStack getRandomItemOfTier(Tier tier){ @@ -750,7 +765,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // All wizards know magic missile, even if it is disabled. spells.add(Spells.magic_missile); - Tier maxTier = populateSpells(spells, element, false, 3, rand); + Tier maxTier = populateSpells(this, spells, element, false, 3, rand); // Now done after the spells so it can take the tier into account. ItemStack wand = new ItemStack(WizardryItems.getWand(maxTier, element)); @@ -767,19 +782,22 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp /** * Adds n random spells to the given list. The spells will be of the given element if possible. Extracted as a * separate function since it was the same in both EntityWizard and EntityEvilWizard. - * + * + * @param wizard The wizard whose spells are to be populated. * @param spells The spell list to be populated. * @param e The element that the spells should belong to, or {@link Element#MAGIC} for a random element each time. + * @param master Whether to include master spells. * @param n The number of spells to add. * @param random A random number generator to use. * @return The tier of the highest-tier spell that was added to the list. */ - static Tier populateSpells(List spells, Element e, boolean master, int n, Random random){ + static Tier populateSpells(final EntityLiving wizard, List spells, Element e, boolean master, int n, Random random){ // This is the tier of the highest tier spell added. Tier maxTier = Tier.NOVICE; - List npcSpells = Spell.getSpells(Spell.npcSpells); + List npcSpells = Spell.getSpells(s -> s.canBeCastBy(wizard, false)); + npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book)); for(int i = 0; i < n; i++){ diff --git a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java index 6b336783..af70b1d1 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java @@ -19,7 +19,9 @@ import java.util.List; * packets) is handled by that class, and all the implementor needs to do is decide which spell(s) to select. *

* This class also allows Wizardry to do all the syncing necessary for continuous spell casting. All the implementor - * needs to do is store the actual fields involved. + * needs to do is store the actual fields involved, by implementing {@link ISpellCaster#setContinuousSpell(Spell)}, + * {@link ISpellCaster#getContinuousSpell()}, {@link ISpellCaster#setSpellCounter(int)}, {@link ISpellCaster#getSpellCounter()} + * and {@link ISpellCaster#getModifiers()}. */ /* Perhaps this should be a capability? Though I can't help thinking they're mainly for attaching data to vanilla * classes, rather than custom ones. For now, the main purpose of this is to centralise code within wizardry itself, and @@ -36,10 +38,10 @@ public interface ISpellCaster { * * @return A list of {@link Spell} instances. A random spell from this list will be cast when the entity attacks. * The list will not be modified by the AI class and can therefore be an immutable list. The spells in the - * list must be castable by NPCs (i.e. {@link Spell#canBeCastByNPCs()} returns true). + * list must be castable by NPCs (i.e. {@link Spell#canBeCastBy(net.minecraft.entity.EntityLiving, boolean)} returns true). */ @Nonnull - public List getSpells(); + List getSpells(); /** * Called each time the entity attacks to get the modifiers to apply to the spell. @@ -48,31 +50,47 @@ public interface ISpellCaster { * required, pass in an empty {@code SpellModifiers} object. */ @Nonnull - public SpellModifiers getModifiers(); + default SpellModifiers getModifiers(){ + return new SpellModifiers(); // May seem wasteful but this should never be called so it doesn't matter + } /** * Returns the continuous spell that is currently being cast, or the None spell if there is none. Implementors * should simply store this as a private field and return it here. Will be synced by the AI class, but whether it is - * saved to NBT is up to you. If the implementing class does not deal with continuous spells, just return - * {@link Spells#none}. If the implementing class only ever uses one continuous spell, do not just return - * that spell; the field must still be stored. + * saved to NBT is up to you. If the implementing class only ever uses one continuous spell, do not just + * return that spell; the field must still be stored. */ @Nonnull - public Spell getContinuousSpell(); + default Spell getContinuousSpell(){ + return Spells.none; + } /** * Sets the continuous spell that is currently being cast, or the None spell if there is none. Implementors should * simply store this as a private field and assign it here. Will be synced by the AI class, but whether it is saved * to NBT is up to you. If the implementing class does not deal with continuous spells, leave this method blank. */ - public void setContinuousSpell(Spell spell); + default void setContinuousSpell(Spell spell){ + // Do nothing + } + + /** Returns the number of ticks the current spell has been cast for. Implementors should simply store this as a + * private field and return it here. This is only used client-side. */ + default int getSpellCounter(){ + return 0; + } + + /** Sets the number of ticks the current spell has been cast for. Implementors should simply store this as a + * private field and assign it here. This is only used client-side. */ + default void setSpellCounter(int count){ + // Do nothing + } /** - * Returns the aiming arror for the given difficulty, used in projectile spells. Defaults to the values used by + * Returns the aiming error for the given difficulty, used in projectile spells. Defaults to the values used by * skeletons, which are: Easy - 10, Normal - 6, Hard - 2, Peaceful - 10 (rarely used). */ - // This is what default methods are actually intended for! - public default int getAimingError(EnumDifficulty difficulty) { + default int getAimingError(EnumDifficulty difficulty) { return WizardryUtilities.getDefaultAimingError(difficulty); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index 5b9e06da..c4639338 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -221,7 +221,8 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData, IEntityOw * possible for implementors to override this in order to do something special when selecting a target. */ default Predicate getTargetSelector(){ - return entity -> getCaster() == null ? entity instanceof EntityPlayer : !entity.isInvisible() && isValidTarget(entity); + return entity -> !entity.isInvisible() && (getCaster() == null ? entity instanceof EntityPlayer && + !((EntityPlayer)entity).isCreative() : isValidTarget(entity)); } /** diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java index 7a34b09d..f3989ffa 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java @@ -9,7 +9,6 @@ import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import net.minecraft.potion.PotionEffect; @@ -48,13 +47,7 @@ public class EntityIceball extends EntityMagicProjectile { }else{ - boolean flag = true; - - if(this.getThrower() != null && this.getThrower() instanceof EntityLiving){ - flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.getThrower()); - } - - if(flag){ + if(this.getThrower() == null || WizardryUtilities.canDamageBlocks(this.getThrower(), world)){ BlockPos pos = rayTrace.getBlockPos(); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java index e78574a4..4a4d9b43 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java @@ -3,6 +3,7 @@ package electroblob.wizardry.entity.projectile; import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.projectile.EntityLargeFireball; import net.minecraft.nbt.NBTTagCompound; @@ -50,7 +51,7 @@ public class EntityLargeMagicFireball extends EntityMagicFireball { protected void onImpact(RayTraceResult rayTrace){ if(!world.isRemote){ - boolean flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.thrower); + boolean flag = this.getThrower() == null || WizardryUtilities.canDamageBlocks(this.getThrower(), world); this.world.newExplosion(null, this.posX, this.posY, this.posZ, getExplosionPower() * blastMultiplier, flag, flag); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java index 0089966a..96d98607 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java @@ -6,14 +6,18 @@ import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.projectile.EntitySmallFireball; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.fml.common.Mod; @@ -80,13 +84,7 @@ public class EntityMagicFireball extends EntityMagicProjectile { }else{ - boolean flag = true; - - if(this.getThrower() != null && this.getThrower() instanceof EntityLiving){ - flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.getThrower()); - } - - if(flag){ + if(this.getThrower() == null || WizardryUtilities.canDamageBlocks(this.getThrower(), world)){ BlockPos blockpos = rayTrace.getBlockPos().offset(rayTrace.sideHit); @@ -131,6 +129,54 @@ public class EntityMagicFireball extends EntityMagicProjectile { } } + @Override + public boolean canBeCollidedWith(){ + return true; + } + + @Override + public float getCollisionBorderSize(){ + return 1.0F; + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount){ + + if(this.isEntityInvulnerable(source)){ + return false; + + }else{ + + this.markVelocityChanged(); + + if(source.getTrueSource() != null){ + + Vec3d vec3d = source.getTrueSource().getLookVec(); + + if(vec3d != null){ + + double speed = MathHelper.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); + + this.motionX = vec3d.x * speed; + this.motionY = vec3d.y * speed; + this.motionZ = vec3d.z * speed; + + this.lifetime = 160; + + } + + if(source.getTrueSource() instanceof EntityLivingBase){ + this.setCaster((EntityLivingBase)source.getTrueSource()); + } + + return true; + + }else{ + return false; + } + } + } + public void setLifetime(int lifetime){ this.lifetime = lifetime; } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index 9649b84a..c6565669 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -1,5 +1,6 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; @@ -44,15 +45,34 @@ public class EntityMagicMissile extends EntityMagicArrow { public void tickInAir(){ if(this.world.isRemote){ - ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) - .time(20 + rand.nextInt(10)).spawn(world); - - if(this.ticksExisted > 1){ // Don't spawn particles behind where it started! - double x = posX - motionX/2; - double y = posY - motionY/2; - double z = posZ - motionZ/2; - ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) - .time(20 + rand.nextInt(10)).spawn(world); + + if(Wizardry.tisTheSeason){ + + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(0.8f, 0.15f, 0.15f) + .time(20 + rand.nextInt(10)).spawn(world); + + ParticleBuilder.create(Type.SNOW).pos(posX, posY, posZ).spawn(world); + + if(this.ticksExisted > 1){ // Don't spawn particles behind where it started! + double x = posX - motionX / 2; + double y = posY - motionY / 2; + double z = posZ - motionZ / 2; + ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(0.15f, 0.7f, 0.15f) + .time(20 + rand.nextInt(10)).spawn(world); + } + + }else{ + + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) + .time(20 + rand.nextInt(10)).spawn(world); + + if(this.ticksExisted > 1){ // Don't spawn particles behind where it started! + double x = posX - motionX / 2; + double y = posY - motionY / 2; + double z = posZ - motionZ / 2; + ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) + .time(20 + rand.nextInt(10)).spawn(world); + } } } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java index 3246d818..fa94a473 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java @@ -71,7 +71,7 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I double dy = !this.hasNoGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY : target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY; double dz = target.posZ - caster.posZ; - double horizontalDistance = (double)MathHelper.sqrt(dx * dx + dz * dz); + double horizontalDistance = MathHelper.sqrt(dx * dx + dz * dz); if(horizontalDistance >= 1.0E-7D){ diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java index cbdb5315..1339c929 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -9,7 +9,6 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumParticleTypes; @@ -66,12 +65,11 @@ public class EntitySmokeBomb extends EntityBomb { for(EntityLivingBase target : targets){ if(target != this.getThrower()){ - // Gives the target blindness if it is a player, mind trick otherwise (since this has the desired + // Gives the target blindness, and mind trick if it's not a player (since this has the desired // effect of preventing targeting) - if(target instanceof EntityPlayer){ - target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0)); - }else if(target instanceof EntityLiving){ - // New AI + target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0)); + + if(target instanceof EntityLiving){ ((EntityLiving)target).setAttackTarget(null); target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, duration, 0)); } diff --git a/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java b/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java index 8fb48157..5eabb205 100644 --- a/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java +++ b/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java @@ -1,11 +1,17 @@ package electroblob.wizardry.integration.antiqueatlas; import electroblob.wizardry.Wizardry; +import hunternif.mc.atlas.AntiqueAtlasMod; import hunternif.mc.atlas.api.AtlasAPI; +import hunternif.mc.atlas.marker.GlobalMarkersData; +import hunternif.mc.atlas.marker.Marker; import hunternif.mc.atlas.registry.MarkerType; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; /** * This class handles all of wizardry's integration with the Antique Atlas mod. This class contains only the code @@ -15,6 +21,7 @@ import net.minecraftforge.fml.common.Loader; * @since Wizardry 4.2 * @author Electroblob */ +@Mod.EventBusSubscriber public class WizardryAntiqueAtlasIntegration { public static final String ANTIQUE_ATLAS_MOD_ID = "antiqueatlas"; @@ -38,7 +45,7 @@ public class WizardryAntiqueAtlasIntegration { * {@link electroblob.wizardry.Settings#autoTowerMarkers} is enabled. Server side only! */ public static void markTower(World world, int x, int z){ if(enabled() && Wizardry.settings.autoTowerMarkers){ - AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, TOWER_MARKER.toString(), "integration.antiqueatlas.marker." + TOWER_MARKER.toString(), x, z); + AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, TOWER_MARKER.toString(), "integration.antiqueatlas.marker." + TOWER_MARKER.toString().replace(':', '.'), x, z); } } @@ -46,7 +53,7 @@ public class WizardryAntiqueAtlasIntegration { * {@link electroblob.wizardry.Settings#autoObeliskMarkers} is enabled. Server side only! */ public static void markObelisk(World world, int x, int z){ if(enabled() && Wizardry.settings.autoObeliskMarkers){ - AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, OBELISK_MARKER.toString(), "integration.antiqueatlas.marker." + OBELISK_MARKER.toString(), x, z); + AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, OBELISK_MARKER.toString(), "integration.antiqueatlas.marker." + OBELISK_MARKER.toString().replace(':', '.'), x, z); } } @@ -54,7 +61,7 @@ public class WizardryAntiqueAtlasIntegration { * {@link electroblob.wizardry.Settings#autoShrineMarkers} is enabled. Server side only! */ public static void markShrine(World world, int x, int z){ if(enabled() && Wizardry.settings.autoShrineMarkers){ - AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, SHRINE_MARKER.toString(), "integration.antiqueatlas.marker." + SHRINE_MARKER.toString(), x, z); + AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, SHRINE_MARKER.toString(), "integration.antiqueatlas.marker." + SHRINE_MARKER.toString().replace(':', '.'), x, z); } } @@ -68,4 +75,21 @@ public class WizardryAntiqueAtlasIntegration { AtlasAPI.getMarkerAPI().registerMarker(new MarkerType(OBELISK_MARKER, new ResourceLocation(Wizardry.MODID, "textures/integration/antiqueatlas/obelisk.png"))); } + @SubscribeEvent + public static void onWorldLoadEvent(WorldEvent.Load event){ + + if(!enabled()) return; + + // Backwards compatibility for existing markers using the old translation key format (with colons) + GlobalMarkersData data = AntiqueAtlasMod.globalMarkersData.getData(); + for(Marker marker : data.getMarkersInDimension(event.getWorld().provider.getDimension())){ + if(marker.getLabel().contains(":")){ + // Remove old-format markers and replace them with new ones + data.removeMarker(marker.getId()); + AtlasAPI.getMarkerAPI().putGlobalMarker(event.getWorld(), marker.isVisibleAhead(), marker.getType(), + marker.getLabel().replace(':', '.'), marker.getX(), marker.getZ()); + } + } + } + } diff --git a/src/main/java/electroblob/wizardry/item/IConjuredItem.java b/src/main/java/electroblob/wizardry/item/IConjuredItem.java index eadfe591..ea2dfb71 100644 --- a/src/main/java/electroblob/wizardry/item/IConjuredItem.java +++ b/src/main/java/electroblob/wizardry/item/IConjuredItem.java @@ -58,6 +58,8 @@ public interface IConjuredItem { */ default int getMaxDamageFromNBT(ItemStack stack, Spell spell){ + if(!spell.arePropertiesInitialised()) return 600; // Failsafe, some edge-cases call this during preInit + float baseDuration = spell.getProperty(SpellConjuration.ITEM_LIFETIME).floatValue(); if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){ diff --git a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java index 3e40abd8..c710e5d0 100644 --- a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java +++ b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java @@ -61,11 +61,10 @@ public class ItemArcaneTome extends Item { Tier tier = Tier.values()[stack.getItemDamage()]; Tier tier2 = Tier.values()[stack.getItemDamage() - 1]; + tooltip.add(tier.getDisplayNameWithFormatting()); - tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":arcane_tome.desc1", - tier2.getDisplayNameWithFormatting())); - tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":arcane_tome.desc2", - tier.getDisplayNameWithFormatting() + "\u00A77")); + Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc", + tier2.getDisplayNameWithFormatting() + "\u00A77", tier.getDisplayNameWithFormatting() + "\u00A77"); } } diff --git a/src/main/java/electroblob/wizardry/item/ItemArtefact.java b/src/main/java/electroblob/wizardry/item/ItemArtefact.java index be1e987c..68b51e6e 100644 --- a/src/main/java/electroblob/wizardry/item/ItemArtefact.java +++ b/src/main/java/electroblob/wizardry/item/ItemArtefact.java @@ -265,7 +265,7 @@ public class ItemArtefact extends Item { if(artefact == WizardryItems.ring_condensing){ - if(world.isRemote && player.ticksExisted % 150 == 0){ + if(player.ticksExisted % 150 == 0){ for(ItemStack stack : WizardryUtilities.getHotbar(player)){ // Needs to be both of these interfaces because this ring only recharges wands // (or more accurately, chargeable spellcasting items) @@ -276,7 +276,7 @@ public class ItemArtefact extends Item { }else if(artefact == WizardryItems.amulet_arcane_defence){ - if(world.isRemote && player.ticksExisted % 300 == 0){ + if(player.ticksExisted % 300 == 0){ for(ItemStack stack : player.getArmorInventoryList()){ // IManaStoringItem is sufficient, since anything in the armour slots is probably armour if(stack.getItem() instanceof IManaStoringItem) @@ -375,7 +375,7 @@ public class ItemArtefact extends Item { if(artefact == WizardryItems.ring_battlemage){ if(player.getHeldItemOffhand().getItem() instanceof ISpellCastingItem - && ImbueWeapon.isSword(player.getHeldItemMainhand().getItem())){ + && ImbueWeapon.isSword(player.getHeldItemMainhand())){ modifiers.set(SpellModifiers.POTENCY, 1.1f * potency, false); } @@ -601,7 +601,7 @@ public class ItemArtefact extends Item { }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(MobEffects.INVISIBILITY, 300, 0, false, false)); } @@ -639,6 +639,7 @@ public class ItemArtefact extends Item { WizardryUtilities.getEntitiesWithinRadius(3, player.posX, player.posY, player.posZ, world).stream() .filter(WizardryUtilities::isLiving) + .filter(e -> e != player) .min(Comparator.comparingDouble(player::getDistanceSq)) .ifPresent(target -> { diff --git a/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java b/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java index dc15754e..068e78c8 100644 --- a/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java @@ -1,5 +1,6 @@ package electroblob.wizardry.item; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.data.WizardData; import electroblob.wizardry.registry.Spells; @@ -11,11 +12,13 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; public class ItemBlankScroll extends Item implements IWorkbenchItem { public ItemBlankScroll(){ this.setCreativeTab(WizardryTabs.WIZARDRY); + this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0); } @Override @@ -45,10 +48,14 @@ public class ItemBlankScroll extends Item implements IWorkbenchItem { int cost = spell.getCost() * centre.getStack().getCount(); // Continuous spell scrolls require enough mana to cast them for the duration defined in ItemScroll. if(spell.isContinuous) cost *= ItemScroll.CASTING_TIME / 20; + + int manaPerItem = Constants.MANA_PER_CRYSTAL; + if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD; + if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA; - if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL > cost){ + if(crystals.getStack().getCount() * manaPerItem > cost){ // Rounds up to the nearest whole crystal - crystals.decrStackSize(cost / Constants.MANA_PER_CRYSTAL + 1); + crystals.decrStackSize(cost / manaPerItem + 1); centre.putStack(new ItemStack(WizardryItems.scroll, centre.getStack().getCount(), spell.metadata())); return true; } diff --git a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java index cca0d046..a7f3fffc 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java @@ -3,6 +3,7 @@ package electroblob.wizardry.item; import com.google.common.collect.Multimap; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; @@ -81,6 +82,12 @@ public class ItemFrostAxe extends ItemAxe implements IConjuredItem { stack.setItemDamage(damage + 1); } + @Override + public Multimap getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot){ + attackDamage = Spells.frost_axe.getProperty(Spell.DAMAGE).floatValue(); + return super.getItemAttributeModifiers(equipmentSlot); + } + @Override public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){ if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) diff --git a/src/main/java/electroblob/wizardry/item/ItemScroll.java b/src/main/java/electroblob/wizardry/item/ItemScroll.java index c4584cdd..c1947d35 100644 --- a/src/main/java/electroblob/wizardry/item/ItemScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemScroll.java @@ -1,7 +1,6 @@ package electroblob.wizardry.item; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.packet.PacketCastSpell; @@ -14,16 +13,12 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.ActionResult; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; +import net.minecraft.util.*; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -import net.minecraftforge.oredict.OreDictionary; import java.util.List; @@ -37,6 +32,7 @@ public class ItemScroll extends Item implements ISpellCastingItem { setHasSubtypes(true); setMaxStackSize(16); setCreativeTab(WizardryTabs.SPELLS); + this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0); } @Override @@ -51,13 +47,14 @@ public class ItemScroll extends Item implements ISpellCastingItem { @Override public void getSubItems(CreativeTabs tab, NonNullList list){ + 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. - for(int i = 0; i < Spell.getTotalSpellCount(); i++){ - // 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. - list.add(new ItemStack(this, 1, i + 1)); + + List spells = Spell.getAllSpells(); + spells.removeIf(s -> !s.applicableForItem(this)); + + for(Spell spell : spells){ + list.add(new ItemStack(this, 1, spell.metadata())); } } } diff --git a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java index 428420ac..5db1eb9a 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java @@ -1,7 +1,9 @@ package electroblob.wizardry.item; +import com.google.common.collect.ImmutableMap; import electroblob.wizardry.Wizardry; import electroblob.wizardry.WizardryGuiHandler; +import electroblob.wizardry.constants.Tier; import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.spell.Spell; @@ -9,35 +11,41 @@ import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.ActionResult; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; +import net.minecraft.util.*; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.oredict.OreDictionary; import java.util.List; +import java.util.Map; public class ItemSpellBook extends Item { + private static final Map 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(){ super(); setHasSubtypes(true); setMaxStackSize(16); setCreativeTab(WizardryTabs.SPELLS); + this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0); } @Override public void getSubItems(CreativeTabs tab, NonNullList list){ + 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. - for(int i = 0; i < Spell.getTotalSpellCount(); i++){ - // 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. - list.add(new ItemStack(this, 1, i + 1)); + + List spells = Spell.getAllSpells(); + spells.removeIf(s -> !s.applicableForItem(this)); + + for(Spell spell : spells){ + list.add(new ItemStack(this, 1, spell.metadata())); } } } @@ -79,4 +87,12 @@ public class ItemSpellBook extends Item { 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()); + } + } diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index f77a80b4..f87e9e10 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -400,7 +400,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.WAND, spell, caster, modifiers, castingTick))) return false; } - int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST)); + int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding // As of wizardry 4.2 mana cost is only divided over two intervals each second if(spell.isContinuous) cost = getDistributedCost(cost, castingTick); @@ -436,7 +436,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, caster.setActiveHand(hand); // Mana cost - int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST)); + int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding // As of wizardry 4.2 mana cost is only divided over two intervals each second if(spell.isContinuous) cost = getDistributedCost(cost, castingTick); @@ -497,7 +497,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, int castingTick = stack.getMaxItemUseDuration() - timeLeft; // Might as well include this - int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST)), castingTick); + int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f), castingTick); // Still need to check there's enough mana or the spell will finish twice, since running out of mana is // handled separately. diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java index 1e7c2708..023b328b 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java @@ -57,12 +57,12 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana } /** Should only be used by vanilla's armour damage calculations; use {@link ItemWizardArmour#setMana(ItemStack, int)} - * to modify wand mana from elsewhere. */ + * to modify armour mana from elsewhere. */ @Override public void setDamage(ItemStack stack, int damage){ // Overridden to stop repair things from 'repairing' the mana in wizard armour // This being armour, it's much easier to let its damage increase normally, but block it from being decreased - if(stack.getItemDamage() < damage) super.setDamage(stack, damage); + if(stack.getItemDamage() < damage) super.setDamage(stack, Math.min(damage, stack.getMaxDamage())); } @Override @@ -178,9 +178,14 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana String s = "wizard_armour"; - if(this.element != null) s = s + "_" + this.element.getName(); + if(Wizardry.tisTheSeason){ + s = s + "_festive"; + }else{ + if(this.element != null) s = s + "_" + this.element.getName(); + if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s; + } + if(slot == EntityEquipmentSlot.LEGS) s = s + "_legs"; - if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s; return "ebwizardry:textures/armour/" + s + ".png"; } @@ -325,7 +330,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana IAttributeInstance attribute = event.getEntityLiving().getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE); double followRange = attribute == null ? 16 : attribute.getAttributeValue(); if(event.getTarget().isSneaking()) followRange *= 0.8; - float f = armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size(); + float f = (float)armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size(); if(f < 0.1F) f = 0.1F; followRange *= (double)(0.7F * f); // Don't need to worry about the isSuitableTarget check since it must already have been checked to get this far diff --git a/src/main/java/electroblob/wizardry/loot/RandomSpell.java b/src/main/java/electroblob/wizardry/loot/RandomSpell.java index 7b9848c0..9db7972c 100644 --- a/src/main/java/electroblob/wizardry/loot/RandomSpell.java +++ b/src/main/java/electroblob/wizardry/loot/RandomSpell.java @@ -7,6 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.data.WizardData; import electroblob.wizardry.item.ItemScroll; import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellProperties; import net.minecraft.entity.player.EntityPlayer; @@ -16,9 +17,9 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.LootContext; import net.minecraft.world.storage.loot.conditions.LootCondition; import net.minecraft.world.storage.loot.functions.LootFunction; -import org.apache.commons.lang3.ArrayUtils; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Random; @@ -76,85 +77,94 @@ public class RandomSpell extends LootFunction { if(!(stack.getItem() instanceof ItemSpellBook) && !(stack.getItem() instanceof ItemScroll)) Wizardry.logger .warn("Applying the random_spell loot function to an item that isn't a spell book or scroll."); - Tier tier; - Element element; - - if(ignoreWeighting){ - if(tiers == null || tiers.isEmpty()){ - tier = Tier.values()[random.nextInt(Tier.values().length)]; - }else{ - tier = tiers.get(random.nextInt(tiers.size())); - } - }else{ - if(tiers == null || tiers.isEmpty()){ - tier = Tier.getWeightedRandomTier(random); - }else{ - tier = Tier.getWeightedRandomTier(random, tiers.toArray(new Tier[0])); - } - } - - // Elements aren't weighted - if(elements == null || elements.isEmpty()){ - // Element can only be MAGIC if tier is NOVICE - if(tier == Tier.NOVICE){ - element = Element.values()[random.nextInt(Element.values().length)]; - }else{ - Element[] elements = ArrayUtils.removeElement(Element.values(), Element.MAGIC); - element = elements[random.nextInt(elements.length)]; - } - }else{ - // In theory, swapping this line to the commented one should make absolutely no difference. - element = elements.get(random.nextInt(elements.size())); - // element = null; - } - - // 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? - List spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.TREASURE)); - - 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)); - - // Ensures the tier chosen actually has spells in it, and if not uses NOVICE instead. NOVICE always has at least - // the NONE spell since this spell cannot be disabled. - // Commented out for now because it will interfere with the ability to specify tiers and elements. - // To be honest, I may as well just say that if you disable enough spells to make this important, you deserve - // less loot! - /* if(spells.isEmpty()){ spellsList = Spell.getSpells(new Spell.TierElementFilter(EnumTier.NOVICE, null)); - * if(stack.getItem() instanceof ItemScroll) spellsList.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); - * } */ - - if(spells != null && !spells.isEmpty()){ - spellsList.retainAll(spells); - } + SpellProperties.Context spellContext = context.getLootedEntity() == null ? SpellProperties.Context.TREASURE + : SpellProperties.Context.LOOTING; // This method is badly-named, loot chests pass a player through too, not just mobs // (And WHY does it only return an entity?! The underlying field is always a player so I'm casting it anyway) EntityPlayer player = (EntityPlayer)context.getKillerPlayer(); + Spell spell = pickRandomSpell(stack, random, spellContext, player); + + if(spell == Spells.none) Wizardry.logger.warn("Tried to apply the random_spell loot function to an item, but no" + + " enabled spells matched the criteria specified. Substituting placeholder (metadata 0) item."); + + stack.setItemDamage(spell.metadata()); + + return stack; + } + + private Spell pickRandomSpell(ItemStack stack, Random random, SpellProperties.Context spellContext, EntityPlayer player){ + + // We're now doing this first because we need to know which spells we have to play with before selecting a tier and element + List possibleSpells = Spell.getSpells(s -> s.isEnabled(spellContext) && s.applicableForItem(stack.getItem()) + // Remove excluded tiers/elements immediately (mainly because empty tier checks should account for excluded elements) + && (tiers == null || tiers.contains(s.getTier())) && (elements == null || elements.contains(s.getElement()))); + + if(spells != null && !spells.isEmpty()){ + possibleSpells.retainAll(spells); // Normally you wouldn't specify a spells list AND tiers/elements... but you could! + } + + if(stack.getItem() instanceof ItemScroll) possibleSpells.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL)); + if(stack.getItem() instanceof ItemSpellBook) possibleSpells.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK)); + + // Select a tier... + + List possibleTiers = new ArrayList<>(); + + if(tiers == null || tiers.isEmpty()){ + possibleTiers.addAll(Arrays.asList(Tier.values())); + }else{ + possibleTiers.addAll(tiers); + } + // Remove all empty tiers + possibleTiers.removeIf(t -> possibleSpells.stream().noneMatch(s -> s.getTier() == t)); // Lambdaception! + + if(possibleTiers.isEmpty()) return Spells.none; // Gotta disable a lot of spells for this to happen + + Tier tier = ignoreWeighting ? possibleTiers.get(random.nextInt(possibleTiers.size())) + : Tier.getWeightedRandomTier(random, possibleTiers.toArray(new Tier[0])); + + // Remove all spells that aren't of the selected tier + possibleSpells.removeIf(s -> s.getTier() != tier); + if(possibleSpells.isEmpty()) return Spells.none; // Should be caught by the no-elements check but we might as well + + // Select an element... + + List possibleElements = new ArrayList<>(); + + // Elements aren't weighted + if(elements == null || elements.isEmpty()){ + possibleElements.addAll(Arrays.asList(Element.values())); + }else{ + possibleElements.addAll(elements); + } + // Remove all empty elements + possibleElements.removeIf(e -> possibleSpells.stream().noneMatch(s -> s.getElement() == e)); + + if(possibleElements.isEmpty()) return Spells.none; // A bit more likely I guess, but still pretty unlikely + + Element element = possibleElements.get(random.nextInt(possibleElements.size())); + + // Remove all spells that aren't of the selected tier + possibleSpells.removeIf(s -> s.getElement() != element); + if(possibleSpells.isEmpty()) return Spells.none; // If it fails anywhere, it'll most likely be here + // Remove either the undiscovered spells or the discovered ones, depending on the bias if(undiscoveredBias > 0 && player != null){ WizardData data = WizardData.get(player); - int discoveredCount = (int)spellsList.stream().filter(data::hasSpellBeenDiscovered).count(); + int discoveredCount = (int)possibleSpells.stream().filter(data::hasSpellBeenDiscovered).count(); // If none have been discovered or they've all been discovered, don't bother! - if(discoveredCount > 0 && discoveredCount < spellsList.size()){ + if(discoveredCount > 0 && discoveredCount < possibleSpells.size()){ // Kinda unintuitive but it's very neat! boolean keepDiscovered = random.nextFloat() < 0.5f + 0.5f * undiscoveredBias; - spellsList.removeIf(s -> keepDiscovered != data.hasSpellBeenDiscovered(s)); + possibleSpells.removeIf(s -> keepDiscovered != data.hasSpellBeenDiscovered(s)); } } - if(spellsList.isEmpty()){ - Wizardry.logger.warn("Tried to apply the random_spell loot function to an item, but no enabled spells" - + "matched the criteria specified. Substituting placeholder (metadata 0) item."); - stack.setItemDamage(0); - }else{ - stack.setItemDamage(spellsList.get(random.nextInt(spellsList.size())).metadata()); - } - - return stack; + return possibleSpells.get(random.nextInt(possibleSpells.size())); // Finally pick a spell } public static class Serializer extends LootFunction.Serializer { diff --git a/src/main/java/electroblob/wizardry/loot/WizardSpell.java b/src/main/java/electroblob/wizardry/loot/WizardSpell.java index 72c6d35a..81ec74bd 100644 --- a/src/main/java/electroblob/wizardry/loot/WizardSpell.java +++ b/src/main/java/electroblob/wizardry/loot/WizardSpell.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.living.ISpellCaster; +import electroblob.wizardry.item.ItemScroll; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; @@ -33,13 +34,18 @@ public class WizardSpell extends LootFunction { @Override 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."); if(context.getLootedEntity() instanceof ISpellCaster){ List spells = ((ISpellCaster)context.getLootedEntity()).getSpells(); 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{ Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster."); } diff --git a/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java b/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java index cf75f72b..c314e84e 100644 --- a/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java +++ b/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java @@ -62,7 +62,7 @@ public class BehaviourSpellDispense extends BehaviorDispenseOptional { if(world.isSideSolid(source.getBlockPos().offset(direction), direction.getOpposite())) return stack; // If the scroll can never be cast by a dispenser, it should be dispensed as an item. - if(!spell.canBeCastByDispensers()) return super.dispenseStack(source, stack); + if(!spell.canBeCastBy(source.getBlockTileEntity())) return super.dispenseStack(source, stack); SpellModifiers modifiers = new SpellModifiers(); diff --git a/src/main/java/electroblob/wizardry/misc/Forfeit.java b/src/main/java/electroblob/wizardry/misc/Forfeit.java index ac58c343..46e9bb07 100644 --- a/src/main/java/electroblob/wizardry/misc/Forfeit.java +++ b/src/main/java/electroblob/wizardry/misc/Forfeit.java @@ -162,7 +162,7 @@ public abstract class Forfeit { 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(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing")); diff --git a/src/main/java/electroblob/wizardry/misc/WildcardTradeList.java b/src/main/java/electroblob/wizardry/misc/WildcardTradeList.java index 0917bcfa..991a99fd 100644 --- a/src/main/java/electroblob/wizardry/misc/WildcardTradeList.java +++ b/src/main/java/electroblob/wizardry/misc/WildcardTradeList.java @@ -1,8 +1,10 @@ package electroblob.wizardry.misc; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTUtil; +import net.minecraft.network.PacketBuffer; import net.minecraft.village.MerchantRecipe; import net.minecraft.village.MerchantRecipeList; import net.minecraftforge.oredict.OreDictionary; @@ -46,12 +48,42 @@ public class WildcardTradeList extends MerchantRecipeList { } private boolean areItemStacksExactlyEqual(ItemStack stack1, ItemStack stack2){ - // Added to allow wildcards; this line is the only actual change. + // Added to allow wildcards if((stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE || stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE) // Can't use ItemStack.areItemsEqualIgnoreDurability because that only works for items with durability, not subtypes. && stack1.getItem() == stack2.getItem()) return true; return ItemStack.areItemsEqual(stack1, stack2) && (!stack2.hasTagCompound() || stack1.hasTagCompound() && NBTUtil.areNBTEquals(stack2.getTagCompound(), stack1.getTagCompound(), false)); } + + @Override + public void writeToBuf(PacketBuffer buffer){ + + buffer.writeByte((byte)(this.size() & 255)); + + // Trick the client into thinking this is a normal item + for(MerchantRecipe merchantrecipe : this){ + + ItemStack itemToBuy = merchantrecipe.getItemToBuy(); + if(itemToBuy.getMetadata() == OreDictionary.WILDCARD_VALUE) itemToBuy = WizardryUtilities.copyWithMeta(itemToBuy, 0); + buffer.writeItemStack(itemToBuy); + + ItemStack itemToSell = merchantrecipe.getItemToSell(); + if(itemToSell.getMetadata() == OreDictionary.WILDCARD_VALUE) itemToSell = WizardryUtilities.copyWithMeta(itemToSell, 0); + buffer.writeItemStack(itemToSell); + + ItemStack secondItemToBuy = merchantrecipe.getSecondItemToBuy(); + buffer.writeBoolean(!secondItemToBuy.isEmpty()); + + if(!secondItemToBuy.isEmpty()){ + if(secondItemToBuy.getMetadata() == OreDictionary.WILDCARD_VALUE) secondItemToBuy = WizardryUtilities.copyWithMeta(secondItemToBuy, 0); + buffer.writeItemStack(secondItemToBuy); + } + + buffer.writeBoolean(merchantrecipe.isRecipeDisabled()); + buffer.writeInt(merchantrecipe.getToolUses()); + buffer.writeInt(merchantrecipe.getMaxTradeUses()); + } + } } diff --git a/src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java b/src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java deleted file mode 100644 index e4d276f8..00000000 --- a/src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java +++ /dev/null @@ -1,47 +0,0 @@ -package electroblob.wizardry.packet; - -import electroblob.wizardry.Wizardry; -import io.netty.buffer.ByteBuf; -import net.minecraft.entity.Entity; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; -import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; -import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; - -/** [Server -> Client] This packet is sent when the slow time potion effect expires or is removed from an - * entity to unblock all nearby entities' updates. */ -public class PacketEndSlowTime implements IMessageHandler { - - @Override - public IMessage onMessage(Message message, MessageContext ctx){ - - // Just to make sure that the side is correct - if(ctx.side.isClient()){ - net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleEndSlowTimePacket(message)); - } - - return null; - } - - public static class Message implements IMessage { - - public int hostID; - - // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) - public Message(){ - } - - public Message(Entity host){ - this.hostID = host.getEntityId(); - } - - @Override - public void fromBytes(ByteBuf buf){ - this.hostID = buf.readInt(); - } - - @Override - public void toBytes(ByteBuf buf){ - buf.writeInt(hostID); - } - } -} diff --git a/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java b/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java index 9fc16ac5..6a408b81 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java +++ b/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java @@ -56,6 +56,7 @@ public class PacketSyncSettings implements IMessageHandler { settings.discoveryMode = buf.readBoolean(); settings.creativeBypassesArcaneLock = buf.readBoolean(); settings.slowTimeAffectsPlayers = buf.readBoolean(); + settings.replaceVanillaFireballs = buf.readBoolean(); settings.forfeitChance = buf.readFloat(); } @@ -64,6 +65,7 @@ public class PacketSyncSettings implements IMessageHandler { buf.writeBoolean(settings.discoveryMode); buf.writeBoolean(settings.creativeBypassesArcaneLock); buf.writeBoolean(settings.slowTimeAffectsPlayers); + buf.writeBoolean(settings.replaceVanillaFireballs); buf.writeFloat((float)settings.forfeitChance); // Configs don't have floats but this can only be 0-1 anyway } } diff --git a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java index 41d12d0d..045205bf 100644 --- a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java +++ b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java @@ -26,7 +26,6 @@ public class WizardryPacketHandler { registerMessage(PacketSpellProperties.class, PacketSpellProperties.Message.class); registerMessage(PacketSyncAdvancements.class, PacketSyncAdvancements.Message.class); registerMessage(PacketRequestAdvancementSync.class, PacketRequestAdvancementSync.Message.class); - registerMessage(PacketEndSlowTime.class, PacketEndSlowTime.Message.class); registerMessage(PacketResurrection.class, PacketResurrection.Message.class); registerMessage(PacketCastSpellAtPos.class, PacketCastSpellAtPos.Message.class); registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class); diff --git a/src/main/java/electroblob/wizardry/potion/PotionContainment.java b/src/main/java/electroblob/wizardry/potion/PotionContainment.java index 672d6ba6..ec8d269d 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionContainment.java +++ b/src/main/java/electroblob/wizardry/potion/PotionContainment.java @@ -2,6 +2,7 @@ package electroblob.wizardry.potion; import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayerMP; @@ -40,7 +41,7 @@ public class PotionContainment extends PotionMagicEffect { // Initialise the containment position to the entity's position if it wasn't set already if(!target.getEntityData().hasKey(ENTITY_TAG)){ - target.getEntityData().setTag(ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5)))); + NBTExtras.storeTagSafely(target.getEntityData(), ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5)))); } Vec3d origin = WizardryUtilities.getCentre(NBTUtil.getPosFromTag(target.getEntityData().getCompoundTag(ENTITY_TAG))); diff --git a/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java b/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java index b6e1f51d..e849de0c 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java +++ b/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java @@ -2,8 +2,6 @@ package electroblob.wizardry.potion; import electroblob.wizardry.Wizardry; import electroblob.wizardry.item.ItemArtefact; -import electroblob.wizardry.packet.PacketEndSlowTime; -import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; @@ -17,11 +15,15 @@ import net.minecraft.entity.IProjectile; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.event.entity.living.PotionEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import java.util.ArrayList; import java.util.List; @Mod.EventBusSubscriber @@ -29,6 +31,8 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion { // FIXME: Minecarts with entities in them (and, I suspect, any other ridden entities) go crazy when time-slowed + public static final String NBT_KEY = "time_slowed"; + public PotionSlowTime(boolean isBadEffect, int liquidColour){ super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_slow_time.png")); this.setPotionName("potion." + Wizardry.MODID + ":slow_time"); @@ -61,6 +65,8 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion { for(Entity entity : targetsInRange){ + entity.getEntityData().setBoolean(NBT_KEY, true); + // If time is stopped, block all updates; otherwise block all updates except every [interval] ticks entity.updateBlocked = stopTime || host.ticksExisted % interval != 0; @@ -130,6 +136,29 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion { } + /** + * Goes through every entity in the given world and does the following:
+ * 1. Checks if they have the slow time NBT tag
+ * 2. If so, scans the area nearby for players or NPCs with the slow time effect
+ * 3. If none are found, removes the slow time NBT tag and unblocks the entity's updates + */ + public static void cleanUpEntities(World world){ + // Had trouble with accessing loadedTileEntityList from tick events causing random CMEs so I'm making a + // copy of this too just in case + List loadedEntityList = new ArrayList<>(world.loadedEntityList); + + for(Entity entity : loadedEntityList){ + if(entity.getEntityData().getBoolean(NBT_KEY)){ + // Currently only players can cast slow time, but you could apply the effect to NPCs with commands + List nearby = WizardryUtilities.getEntitiesWithinRadius(getEffectRadius(), entity.posX, entity.posY, entity.posZ, entity.world, EntityLivingBase.class); + if(nearby.stream().noneMatch(e -> e.isPotionActive(WizardryPotions.slow_time))){ + entity.getEntityData().removeTag(NBT_KEY); + entity.updateBlocked = false; + } + } + } + } + @SubscribeEvent public static void onLivingUpdateEvent(LivingUpdateEvent event){ @@ -150,23 +179,16 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion { } @SubscribeEvent - public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){ - if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() == WizardryPotions.slow_time){ - unblockNearbyEntities(event.getEntityLiving()); - if(!event.getEntity().world.isRemote){ - WizardryPacketHandler.net.sendToDimension(new PacketEndSlowTime.Message(event.getEntityLiving()), event.getEntity().dimension); - } - } + public static void tick(TickEvent.WorldTickEvent event){ + if(!event.world.isRemote && event.phase == TickEvent.Phase.END) cleanUpEntities(event.world); } + // We still need this as well as tick events because the player hasn't moved anywhere, they just logged out + // In fact, it won't really matter since the tick event fixes it on login anyway, but if the mod is uninstalled or + // something else weird happens... @SubscribeEvent - public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){ - if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() == WizardryPotions.slow_time){ - unblockNearbyEntities(event.getEntityLiving()); - if(!event.getEntity().world.isRemote){ - WizardryPacketHandler.net.sendToDimension(new PacketEndSlowTime.Message(event.getEntityLiving()), event.getEntity().dimension); - } - } + public static void onPlayerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event){ + if(event.player.updateBlocked) event.player.updateBlocked = false; } } diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java index 5398da75..85ee05a1 100644 --- a/src/main/java/electroblob/wizardry/registry/Spells.java +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -5,6 +5,7 @@ import electroblob.wizardry.entity.construct.*; import electroblob.wizardry.entity.living.*; import electroblob.wizardry.entity.projectile.*; import electroblob.wizardry.spell.*; +import net.minecraft.entity.projectile.EntitySnowball; import net.minecraft.init.MobEffects; import net.minecraft.item.EnumAction; import net.minecraft.util.ResourceLocation; @@ -243,10 +244,15 @@ public final class Spells { IForgeRegistry registry = event.getRegistry(); registry.register(new None()); - registry.register(new SpellArrow<>("magic_missile", EntityMagicMissile::new).addProperties(Spell.DAMAGE).soundValues(1, 1.4f, 0.4f)); + registry.register(new SpellArrow("magic_missile", EntityMagicMissile::new){ + @Override + protected String getTranslationKey(){ + return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey(); + } + }.addProperties(Spell.DAMAGE).soundValues(1, 1.4f, 0.4f)); registry.register(new Ignite()); registry.register(new Freeze()); - registry.register(new Snowball()); + registry.register(new SpellThrowable<>("snowball", EntitySnowball::new).npcSelector((e, o) -> o).soundValues(0.5f, 0.4f, 0.2f)); // Let's spare wizards the pain of the snowball spell registry.register(new Arc()); registry.register(new SpellProjectile<>("thunderbolt", EntityThunderbolt::new).addProperties(Spell.DAMAGE, EntityThunderbolt.KNOCKBACK_STRENGTH).soundValues(0.8f, 0.9f, 0.2f)); registry.register(new SummonZombie()); @@ -316,7 +322,7 @@ public final class Spells { registry.register(new SpellProjectile<>("darkness_orb", EntityDarknessOrb::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new ShadowWard()); registry.register(new Decay()); - registry.register(new SpellBuff("water_breathing", 0.3f, 0.3f, 1, () -> MobEffects.WATER_BREATHING){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("water_breathing", 0.3f, 0.3f, 1, () -> MobEffects.WATER_BREATHING).npcSelector((e, o) -> false).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Tornado()); registry.register(new Glide()); registry.register(new SummonSpiritHorse()); @@ -367,7 +373,7 @@ public final class Spells { registry.register(new Intimidate()); registry.register(new Banish()); registry.register(new SixthSense()); - registry.register(new SpellBuff("darkvision", 0, 0.4f, 0.7f, () -> MobEffects.NIGHT_VISION){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("darkvision", 0, 0.4f, 0.7f, () -> MobEffects.NIGHT_VISION).npcSelector((e, o) -> false).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Clairvoyance()); registry.register(new PocketWorkbench()); registry.register(new ImbueWeapon()); diff --git a/src/main/java/electroblob/wizardry/registry/WizardryLoot.java b/src/main/java/electroblob/wizardry/registry/WizardryLoot.java index 551e11e0..f8bdca33 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryLoot.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryLoot.java @@ -5,7 +5,6 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.loot.RandomSpell; import electroblob.wizardry.loot.WizardSpell; import electroblob.wizardry.spell.Spell; -import net.minecraft.entity.EntityList; import net.minecraft.entity.EnumCreatureType; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.*; diff --git a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java index 97f9f25e..f5a9b447 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java +++ b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java @@ -88,6 +88,7 @@ public final class WizardrySounds { public static final SoundEvent ENTITY_WIZARD_TRADING = createSound("entity.wizard.trading"); public static final SoundEvent ENTITY_WIZARD_HURT = createSound("entity.wizard.hurt"); public static final SoundEvent ENTITY_WIZARD_DEATH = createSound("entity.wizard.death"); + public static final SoundEvent ENTITY_WIZARD_HOHOHO = createSound("entity.wizard.hohoho"); public static final SoundEvent ENTITY_DARKNESS_ORB_HIT = createSound("entity.darkness_orb.hit"); public static final SoundEvent ENTITY_DART_HIT = createSound("entity.dart.hit"); @@ -132,10 +133,17 @@ public final class WizardrySounds { public static final SoundEvent MISC_PAGE_TURN = createSound("misc.page_turn"); public static final SoundEvent MISC_FREEZE = createSound("misc.freeze"); - /** Trick borrowed from the Twilight Forest, makes things neater. */ + // Trick borrowed from the Twilight Forest, makes things neater. + + /** Overload for {@link WizardrySounds#createSound(String, String)} which assigns wizardry's mod ID automatically. */ public static SoundEvent createSound(String name){ + return createSound(Wizardry.MODID, name); + } + + /** Creates a sound with the given name, to be read from {@code assets/[modID]/sounds.json}. */ + public static SoundEvent createSound(String modID, String name){ // All the setRegistryName methods delegate to this one, it doesn't matter which you use. - return new SoundEvent(new ResourceLocation(Wizardry.MODID, name)).setRegistryName(name); + return new SoundEvent(new ResourceLocation(modID, name)).setRegistryName(name); } // For some reason, sound events seem to work even when they aren't registered, without even so much as a warning. @@ -250,7 +258,7 @@ public final class WizardrySounds { event.getRegistry().register(MISC_PAGE_TURN); event.getRegistry().register(MISC_FREEZE); - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + for(Spell spell : Spell.getAllSpells()){ event.getRegistry().registerAll(spell.getSounds()); } diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java index 7f4be44a..cbf02353 100644 --- a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java +++ b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; @@ -18,12 +19,21 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingEvent; 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.SubscribeEvent; +import java.lang.reflect.Field; + @Mod.EventBusSubscriber public class ArcaneJammer extends SpellRay { + private static final Field spellTicks; + + static { // Yay more reflection + spellTicks = ObfuscationReflectionHelper.findField(EntitySpellcasterIllager.class, "field_193087_b"); + } + public ArcaneJammer(){ super("arcane_jammer", false, EnumAction.NONE); this.soundValues(0.7f, 1, 0.4f); @@ -68,9 +78,17 @@ public class ArcaneJammer extends SpellRay { @SubscribeEvent public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){ + if(event.getEntity() instanceof EntitySpellcasterIllager && event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){ + ((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); + } } } diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneLock.java b/src/main/java/electroblob/wizardry/spell/ArcaneLock.java index 38930604..b2c88f5a 100644 --- a/src/main/java/electroblob/wizardry/spell/ArcaneLock.java +++ b/src/main/java/electroblob/wizardry/spell/ArcaneLock.java @@ -6,11 +6,13 @@ import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -32,9 +34,9 @@ public class ArcaneLock extends SpellRay { @Override public boolean requiresPacket(){ return true; } - @Override public boolean canBeCastByDispensers(){ return false; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser){ return false; } - @Override public boolean canBeCastByNPCs(){ return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return false; } @Override protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java index 9777892f..e12fe1ff 100644 --- a/src/main/java/electroblob/wizardry/spell/Banish.java +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -7,6 +8,7 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; @@ -78,9 +80,7 @@ public class Banish extends SpellRay { world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } - // Can't be bothered to route this through the proxies! - if(entity == net.minecraft.client.Minecraft.getMinecraft().player) - electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + if(entity instanceof EntityPlayer) Wizardry.proxy.playBlinkEffect((EntityPlayer)entity); } if(y != null){ diff --git a/src/main/java/electroblob/wizardry/spell/Blink.java b/src/main/java/electroblob/wizardry/spell/Blink.java index f6adf784..fcc4975e 100644 --- a/src/main/java/electroblob/wizardry/spell/Blink.java +++ b/src/main/java/electroblob/wizardry/spell/Blink.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.SpellModifiers; @@ -41,9 +42,8 @@ public class Blink extends Spell { world.spawnParticle(EnumParticleTypes.PORTAL, dx, dy, dz, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } - - // Can't be bothered to route this through the proxies! - electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + + Wizardry.proxy.playBlinkEffect(caster); } if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ @@ -136,7 +136,7 @@ public class Blink extends Spell { } @Override - public boolean canBeCastByNPCs(){ + public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java index 0e638ceb..c5ffba8b 100644 --- a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java +++ b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java @@ -12,6 +12,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.player.EntityPlayer; @@ -21,6 +22,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.pathfinding.Path; import net.minecraft.pathfinding.PathNodeType; import net.minecraft.pathfinding.PathPoint; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; @@ -44,8 +46,8 @@ public class Clairvoyance extends Spell { WizardData.registerStoredVariables(LOCATION_KEY, DIMENSION_KEY); } - @Override public boolean canBeCastByNPCs() { return false; } - @Override public boolean canBeCastByDispensers() { return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java index ff2294a2..bc62c719 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java +++ b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java @@ -3,6 +3,7 @@ package electroblob.wizardry.spell; import com.google.common.collect.ImmutableMap; import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; @@ -40,7 +41,7 @@ public class ConjureArmour extends SpellConjuration { armour = new ItemStack(SPECTRAL_ARMOUR_MAP.get(slot)); IConjuredItem.setDurationMultiplier(armour, modifiers.get(WizardryItems.duration_upgrade)); // Sets a blank "ench" tag to trick the renderer into showing the enchantment effect on the armour model - armour.getTagCompound().setTag("ench", new NBTTagList()); + NBTExtras.storeTagSafely(armour.getTagCompound(), "ench", new NBTTagList()); caster.setItemStackToSlot(slot, armour); flag = true; } diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java index c7721ba5..e47b7865 100644 --- a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java +++ b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java @@ -9,12 +9,14 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.*; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTUtil; import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; @@ -45,9 +47,9 @@ public class CurseOfSoulbinding extends SpellRay { WizardData.registerStoredVariables(TARGETS_KEY); } - @Override public boolean canBeCastByNPCs() { return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; } // You can't damage a dispenser so this would be nonsense! - @Override public boolean canBeCastByDispensers() { return false; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; } @Override protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/Decoy.java b/src/main/java/electroblob/wizardry/spell/Decoy.java index 42eab5ab..46f21c4e 100644 --- a/src/main/java/electroblob/wizardry/spell/Decoy.java +++ b/src/main/java/electroblob/wizardry/spell/Decoy.java @@ -21,7 +21,7 @@ public class Decoy extends Spell { addProperties(DECOY_LIFETIME, MOB_TRICK_CHANCE); } - @Override public boolean canBeCastByNPCs(){ return true; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/Divination.java b/src/main/java/electroblob/wizardry/spell/Divination.java index f4ed42b6..61d6a6f2 100644 --- a/src/main/java/electroblob/wizardry/spell/Divination.java +++ b/src/main/java/electroblob/wizardry/spell/Divination.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Settings; import electroblob.wizardry.Wizardry; import electroblob.wizardry.block.BlockCrystalOre; import electroblob.wizardry.registry.WizardryItems; @@ -21,6 +22,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import org.apache.commons.lang3.tuple.Pair; import java.util.Arrays; import java.util.Comparator; @@ -65,11 +67,13 @@ public class Divination extends Spell { List sphere = WizardryUtilities.getBlockSphere(caster.getPosition(), range); - sphere.removeIf(b -> !(world.getBlockState(b).getBlock() instanceof BlockOre - || world.getBlockState(b).getBlock() instanceof BlockRedstoneOre - || world.getBlockState(b).getBlock() instanceof BlockCrystalOre - || Arrays.asList(Wizardry.settings.divinationOreWhitelist) - .contains(world.getBlockState(b).getBlock().getRegistryName()))); + sphere.removeIf(b -> { + Block block = world.getBlockState(b).getBlock(); + return !(block instanceof BlockOre + || block instanceof BlockRedstoneOre + || block instanceof BlockCrystalOre + || Settings.containsMetaBlock(Wizardry.settings.divinationOreWhitelist, world.getBlockState(b))); + }); Strength strength = Strength.NOTHING; diff --git a/src/main/java/electroblob/wizardry/spell/DragonFireball.java b/src/main/java/electroblob/wizardry/spell/DragonFireball.java index 037b7cd3..c1323866 100644 --- a/src/main/java/electroblob/wizardry/spell/DragonFireball.java +++ b/src/main/java/electroblob/wizardry/spell/DragonFireball.java @@ -85,7 +85,7 @@ public class DragonFireball extends Spell { } @Override - public boolean canBeCastByNPCs(){ + public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Earthquake.java b/src/main/java/electroblob/wizardry/spell/Earthquake.java index 946358be..2c9ae2b8 100644 --- a/src/main/java/electroblob/wizardry/spell/Earthquake.java +++ b/src/main/java/electroblob/wizardry/spell/Earthquake.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; + import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.construct.EntityEarthquake; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; @@ -7,6 +8,7 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; + import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; @@ -53,6 +55,10 @@ world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, y, particleZ, particleX - x, 0, particleZ - z, Block.getStateId(block)); } + + WizardryUtilities.getEntitiesWithinRadius(15, x, y, z, world, EntityPlayer.class) + .forEach(p -> Wizardry.proxy.shakeScreen(p, 12)); + } return super.spawnConstruct(world, x, y, z, side, caster, modifiers); diff --git a/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java b/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java index ad42d9c3..7fcbaf18 100644 --- a/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java +++ b/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.registry.WizardryItems; @@ -66,10 +67,16 @@ public class EmpoweringPresence extends Spell { return true; } + @Override + protected String getTranslationKey(){ + return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey(); + } + @SubscribeEvent(priority = EventPriority.LOW) // Doesn't really matter but there's no point processing it if casting is blocked public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ // Empowerment stacks extra potency on top of the existing potency. - if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.empowerment)){ + if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.empowerment) + && !(event.getSpell() instanceof EmpoweringPresence)){ // Prevent exponential empowerment stacking! float potency = 1 + Constants.EMPOWERMENT_POTENCY_PER_LEVEL * (event.getCaster().getActivePotionEffect(WizardryPotions.empowerment).getAmplifier() + 1); @@ -78,4 +85,5 @@ public class EmpoweringPresence extends Spell { event.getModifiers().get(SpellModifiers.POTENCY) * potency, true); } } + } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java index bb1c3611..b77f4e9a 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java @@ -31,7 +31,7 @@ public class FlamingWeapon extends Spell { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ - if((ImbueWeapon.isSword(stack.getItem()) || ImbueWeapon.isBow(stack.getItem())) + if((ImbueWeapon.isSword(stack) || ImbueWeapon.isBow(stack)) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.flaming_weapon)){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. diff --git a/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java b/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java index 93860407..9a8a6e49 100644 --- a/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java +++ b/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java @@ -11,6 +11,7 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -29,8 +30,8 @@ public class ForestOfThorns extends Spell { } @Override public boolean requiresPacket(){ return false; } - @Override public boolean canBeCastByNPCs(){ return true; } - @Override public boolean canBeCastByDispensers(){ return true; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser){ return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java index 1c798319..46cc6111 100644 --- a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java @@ -37,7 +37,7 @@ public class FreezingWeapon extends Spell { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ - if((ImbueWeapon.isSword(stack.getItem()) || ImbueWeapon.isBow(stack.getItem())) + if((ImbueWeapon.isSword(stack) || ImbueWeapon.isBow(stack)) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.freezing_weapon)){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. diff --git a/src/main/java/electroblob/wizardry/spell/FrostAxe.java b/src/main/java/electroblob/wizardry/spell/FrostAxe.java index 31c104db..054b77f7 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostAxe.java +++ b/src/main/java/electroblob/wizardry/spell/FrostAxe.java @@ -11,6 +11,7 @@ public class FrostAxe extends SpellConjuration { public FrostAxe(){ super("frost_axe", WizardryItems.frost_axe); + addProperties(DAMAGE); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Glide.java b/src/main/java/electroblob/wizardry/spell/Glide.java index c1c465ad..8239f676 100644 --- a/src/main/java/electroblob/wizardry/spell/Glide.java +++ b/src/main/java/electroblob/wizardry/spell/Glide.java @@ -9,7 +9,6 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; import net.minecraft.world.World; public class Glide extends Spell { diff --git a/src/main/java/electroblob/wizardry/spell/Grapple.java b/src/main/java/electroblob/wizardry/spell/Grapple.java index 6ee73cab..e30ecdbc 100644 --- a/src/main/java/electroblob/wizardry/spell/Grapple.java +++ b/src/main/java/electroblob/wizardry/spell/Grapple.java @@ -19,6 +19,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumAction; import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.SoundEvent; @@ -58,12 +59,12 @@ public class Grapple extends Spell { } @Override - public boolean canBeCastByNPCs(){ - return super.canBeCastByNPCs(); + public boolean canBeCastBy(EntityLiving npc, boolean override){ + return true; } @Override - public boolean canBeCastByDispensers(){ + public boolean canBeCastBy(TileEntityDispenser dispenser){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java b/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java index 3929d8d2..b5f90f81 100644 --- a/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java +++ b/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java @@ -9,12 +9,14 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityTNTPrimed; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumAction; import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; @@ -41,8 +43,8 @@ public class GreaterTelekinesis extends SpellRay { this.soundValues(0.8f, 1, 0.2f); } - @Override public boolean canBeCastByNPCs() { return false; } - @Override public boolean canBeCastByDispensers() { return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; } @Override protected SoundEvent[] createSounds(){ diff --git a/src/main/java/electroblob/wizardry/spell/HealAlly.java b/src/main/java/electroblob/wizardry/spell/HealAlly.java index ffcbf274..2a31ad2e 100644 --- a/src/main/java/electroblob/wizardry/spell/HealAlly.java +++ b/src/main/java/electroblob/wizardry/spell/HealAlly.java @@ -4,6 +4,7 @@ import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; @@ -19,6 +20,11 @@ public class HealAlly extends SpellRay { addProperties(HEALTH); } + @Override + public boolean canBeCastBy(EntityLiving npc, boolean override){ + return false; + } + @Override protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java index a41cd34b..631b9222 100644 --- a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Settings; import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.data.WizardData; @@ -11,9 +12,13 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.*; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; import net.minecraft.util.EnumHand; import net.minecraft.world.World; +import org.apache.commons.lang3.tuple.Pair; import java.util.Arrays; @@ -32,7 +37,7 @@ public class ImbueWeapon extends Spell { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ - if(isSword(stack.getItem()) + if(isSword(stack) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.magic_sword) && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_sword) <= 0){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that @@ -44,7 +49,7 @@ public class ImbueWeapon extends Spell { WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_sword, (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); - }else if(isBow(stack.getItem()) + }else if(isBow(stack) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.magic_bow) && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_bow) <= 0){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that @@ -77,13 +82,13 @@ public class ImbueWeapon extends Spell { } /** Returns true if the given item counts as a sword, i.e. it extends {@link ItemSword} or is in the whitelist. */ - public static boolean isSword(Item item){ - return item instanceof ItemSword || Arrays.asList(Wizardry.settings.swordItemWhitelist).contains(item.getRegistryName()); + public static boolean isSword(ItemStack stack){ + return stack.getItem() instanceof ItemSword || Settings.containsMetaItem(Wizardry.settings.swordItemWhitelist, stack); } /** Returns true if the given item counts as a bow, i.e. it extends {@link ItemBow} or is in the whitelist. */ - public static boolean isBow(Item item){ - return item instanceof ItemBow || Arrays.asList(Wizardry.settings.bowItemWhitelist).contains(item.getRegistryName()); + public static boolean isBow(ItemStack stack){ + return stack.getItem() instanceof ItemBow || Settings.containsMetaItem(Wizardry.settings.bowItemWhitelist, stack); } } diff --git a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java index c6c473b8..a90b7a44 100644 --- a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java +++ b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.ParticleBuilder; @@ -62,4 +63,9 @@ public class InvigoratingPresence extends Spell { return true; } + @Override + protected String getTranslationKey(){ + return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey(); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java index 77f4fbee..2270da29 100644 --- a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java +++ b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java @@ -10,6 +10,7 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.*; import net.minecraft.entity.passive.*; @@ -52,7 +53,7 @@ public class Metamorphosis extends SpellRay { this.soundValues(0.5f, 1f, 0); } - @Override public boolean canBeCastByNPCs() { return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; } @Override protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java index caa03f9d..039b642c 100644 --- a/src/main/java/electroblob/wizardry/spell/MindControl.java +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -19,6 +19,7 @@ import net.minecraft.item.EnumAction; import net.minecraft.item.EnumDyeColor; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -43,8 +44,8 @@ public class MindControl extends SpellRay { addProperties(EFFECT_DURATION); } - @Override public boolean canBeCastByNPCs() { return false; } - @Override public boolean canBeCastByDispensers() { return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; } @Override protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/PhaseStep.java b/src/main/java/electroblob/wizardry/spell/PhaseStep.java index 18926341..9f21eac8 100644 --- a/src/main/java/electroblob/wizardry/spell/PhaseStep.java +++ b/src/main/java/electroblob/wizardry/spell/PhaseStep.java @@ -43,8 +43,7 @@ public class PhaseStep extends Spell { world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } - // Can't be bothered to route this through the proxies! - electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + Wizardry.proxy.playBlinkEffect(caster); } if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ diff --git a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java index 4b9afbc1..29a2bdb8 100644 --- a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java +++ b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Settings; import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; @@ -10,8 +11,6 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; -import java.util.Arrays; - public class PocketFurnace extends Spell { public static final String ITEMS_SMELTED = "items_smelted"; @@ -37,9 +36,9 @@ public class PocketFurnace extends Spell { result = FurnaceRecipes.instance().getSmeltingResult(stack); - if(!result.isEmpty() && !(result.getItem() instanceof ItemTool) && !(result.getItem() instanceof ItemSword) - && !(result.getItem() instanceof ItemArmor) - && !Arrays.asList(Wizardry.settings.pocketFurnaceItemBlacklist).contains(result.getItem().getRegistryName())){ + if(!result.isEmpty() && !(stack.getItem() instanceof ItemTool) && !(stack.getItem() instanceof ItemSword) + && !(stack.getItem() instanceof ItemArmor) + && !Settings.containsMetaItem(Wizardry.settings.pocketFurnaceItemBlacklist, stack)){ if(stack.getCount() <= usesLeft){ ItemStack stack2 = new ItemStack(result.getItem(), stack.getCount(), result.getItemDamage()); diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java index 5cf6a5f9..0e747f0f 100644 --- a/src/main/java/electroblob/wizardry/spell/Poison.java +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -8,6 +8,7 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -28,7 +29,7 @@ public class Poison extends SpellRay { } @Override - public boolean canBeCastByNPCs(){ + public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Possession.java b/src/main/java/electroblob/wizardry/spell/Possession.java index cd7e8bde..e464b173 100644 --- a/src/main/java/electroblob/wizardry/spell/Possession.java +++ b/src/main/java/electroblob/wizardry/spell/Possession.java @@ -16,6 +16,7 @@ import electroblob.wizardry.packet.PacketPossession; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -43,6 +44,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagList; import net.minecraft.potion.PotionEffect; import net.minecraft.potion.PotionUtils; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.*; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -123,8 +125,8 @@ public class Possession extends SpellRay { addProperties(EFFECT_DURATION, CRITICAL_HEALTH); } - @Override public boolean canBeCastByNPCs() { return false; } - @Override public boolean canBeCastByDispensers() { return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; } @Override public boolean requiresPacket(){ @@ -199,6 +201,8 @@ public class Possession extends SpellRay { */ public boolean possess(EntityPlayer possessor, EntityLiving target, int duration){ + if(possessor.isSneaking()) return false; + if(WizardData.get(possessor) != null){ WizardData.get(possessor).setVariable(POSSESSEE_KEY, target); @@ -267,7 +271,7 @@ public class Possession extends SpellRay { // Inventory and items if(possessor.getEntityData() != null){ - possessor.getEntityData().setTag(INVENTORY_NBT_KEY, possessor.inventory.writeToNBT(new NBTTagList())); + NBTExtras.storeTagSafely(possessor.getEntityData(), INVENTORY_NBT_KEY, possessor.inventory.writeToNBT(new NBTTagList())); } possessor.inventory.clear(); @@ -681,11 +685,13 @@ public class Possession extends SpellRay { if(possessee != null){ - if(possessee.canPickUpLoot() && possessee.getHeldItemMainhand().isEmpty()){ - possessee.setHeldItem(EnumHand.MAIN_HAND, event.getItem().getItem()); - }else{ - event.setCanceled(true); - } + event.setCanceled(true); + +// if(possessee.canPickUpLoot() && possessee.getHeldItemMainhand().isEmpty()){ +// possessee.setHeldItem(EnumHand.MAIN_HAND, event.getItem().getItem()); +// }else{ +// event.setCanceled(true); +// } } } diff --git a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java index f2ec06c2..df819477 100644 --- a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java +++ b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java @@ -1,6 +1,7 @@ package electroblob.wizardry.spell; import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumHand; @@ -17,7 +18,7 @@ public class ReplenishHunger extends SpellBuff { addProperties(HUNGER_POINTS, SATURATION_MODIFIER); } - @Override public boolean canBeCastByNPCs(){ return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return false; } @Override protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/Resurrection.java b/src/main/java/electroblob/wizardry/spell/Resurrection.java index 1809e07b..a28d0fe9 100644 --- a/src/main/java/electroblob/wizardry/spell/Resurrection.java +++ b/src/main/java/electroblob/wizardry/spell/Resurrection.java @@ -25,6 +25,8 @@ public class Resurrection extends Spell { public static final String WAIT_TIME = "wait_time"; + private static final String POTION_CORE_FIX_NBT_KEY = "Potion Core - Health Fix"; + public Resurrection(){ super("resurrection", EnumAction.NONE, false); addProperties(EFFECT_RADIUS, WAIT_TIME); @@ -90,6 +92,8 @@ public class Resurrection extends Spell { player.experience = 0; player.experienceLevel = 0; player.experienceTotal = 0; + // Not sure what potion core is 'fixing' but it breaks my resurrection, so let's unfix it! + player.getEntityData().removeTag(POTION_CORE_FIX_NBT_KEY); if(player.world.isRemote){ ParticleBuilder.spawnHealParticles(player.world, player); diff --git a/src/main/java/electroblob/wizardry/spell/Reversal.java b/src/main/java/electroblob/wizardry/spell/Reversal.java index f8c79376..c763fe91 100644 --- a/src/main/java/electroblob/wizardry/spell/Reversal.java +++ b/src/main/java/electroblob/wizardry/spell/Reversal.java @@ -8,6 +8,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -28,7 +29,7 @@ public class Reversal extends SpellRay { } @Override - public boolean canBeCastByDispensers(){ + public boolean canBeCastBy(TileEntityDispenser dispenser){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Satiety.java b/src/main/java/electroblob/wizardry/spell/Satiety.java index 8f3ce6e4..c8cb84db 100644 --- a/src/main/java/electroblob/wizardry/spell/Satiety.java +++ b/src/main/java/electroblob/wizardry/spell/Satiety.java @@ -1,6 +1,7 @@ package electroblob.wizardry.spell; import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumHand; @@ -17,7 +18,7 @@ public class Satiety extends SpellBuff { addProperties(HUNGER_POINTS, SATURATION_MODIFIER); } - @Override public boolean canBeCastByNPCs(){ return false; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return false; } @Override protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/Shockwave.java b/src/main/java/electroblob/wizardry/spell/Shockwave.java index abfd6767..2d3d89c7 100644 --- a/src/main/java/electroblob/wizardry/spell/Shockwave.java +++ b/src/main/java/electroblob/wizardry/spell/Shockwave.java @@ -41,12 +41,17 @@ public class Shockwave extends Spell { for(EntityLivingBase target : targets){ - if(target instanceof EntityPlayer && (!Wizardry.settings.playersMoveEachOther - || ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring))){ + if(target instanceof EntityPlayer){ - if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell.resist", - target.getName(), this.getNameForTranslationFormatted()), true); - return false; + Wizardry.proxy.shakeScreen((EntityPlayer)target, 10); + + if(!Wizardry.settings.playersMoveEachOther) continue; + + if(ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring)){ + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell.resist", + target.getName(), this.getNameForTranslationFormatted()), true); + continue; + } } if(AllyDesignationSystem.isValidTarget(caster, target)){ diff --git a/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java b/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java index 8b59fdf4..7998a426 100644 --- a/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java +++ b/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java @@ -1,6 +1,7 @@ package electroblob.wizardry.spell; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; @@ -12,6 +13,7 @@ import net.minecraft.entity.projectile.EntityShulkerBullet; import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTUtil; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -29,9 +31,9 @@ public class ShulkerBullet extends Spell { addProperties(RANGE); } - @Override public boolean canBeCastByNPCs(){ return true; } + @Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } - @Override public boolean canBeCastByDispensers(){ return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser){ return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ @@ -89,7 +91,7 @@ public class ShulkerBullet extends Spell { targetTag.setInteger("X", pos.getX()); targetTag.setInteger("Y", pos.getY()); targetTag.setInteger("Z", pos.getZ()); - nbt.setTag("Target", targetTag); + NBTExtras.storeTagSafely(nbt, "Target", targetTag); bullet.readFromNBT(nbt); // LOL I just modified private fields without reflection world.spawnEntity(bullet); diff --git a/src/main/java/electroblob/wizardry/spell/SlowTime.java b/src/main/java/electroblob/wizardry/spell/SlowTime.java index 04ce8150..2d00a81f 100644 --- a/src/main/java/electroblob/wizardry/spell/SlowTime.java +++ b/src/main/java/electroblob/wizardry/spell/SlowTime.java @@ -3,7 +3,9 @@ package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; @@ -35,12 +37,12 @@ public class SlowTime extends SpellBuff { } @Override - public boolean canBeCastByDispensers(){ + public boolean canBeCastBy(TileEntityDispenser dispenser){ return false; } @Override - public boolean canBeCastByNPCs(){ + public boolean canBeCastBy(EntityLiving npc, boolean override){ return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/Snowball.java b/src/main/java/electroblob/wizardry/spell/Snowball.java deleted file mode 100644 index 500488fd..00000000 --- a/src/main/java/electroblob/wizardry/spell/Snowball.java +++ /dev/null @@ -1,45 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.projectile.EntitySnowball; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.World; - -public class Snowball extends Spell { - - public Snowball(){ - super("snowball", EnumAction.NONE, false); - addProperties(RANGE); - soundValues(0.5f, 0.4f, 0.2f); - } - - @Override - public boolean requiresPacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - // Trajectory calculation - see SpellProjectile for a more detailed explanation - float g = 0.03f; - float launchHeight = caster.getEyeHeight(); - float range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); - float velocity = MathHelper.sqrt(MathHelper.sqrt(g*g * (launchHeight*launchHeight + range*range)) - g*launchHeight); - - EntitySnowball snowball = new EntitySnowball(world, caster); - snowball.shoot(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, velocity, 1.0f); - world.spawnEntity(snowball); - } - - this.playSound(world, caster, ticksInUse, -1, modifiers); - caster.swingArm(hand); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Spell.java b/src/main/java/electroblob/wizardry/spell/Spell.java index 3a264eac..863bd31c 100644 --- a/src/main/java/electroblob/wizardry/spell/Spell.java +++ b/src/main/java/electroblob/wizardry/spell/Spell.java @@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.packet.PacketSpellProperties; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.SpellProperties; @@ -18,6 +19,8 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; @@ -27,6 +30,10 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; 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.SideOnly; import net.minecraftforge.registries.ForgeRegistry; @@ -36,6 +43,7 @@ import net.minecraftforge.registries.IForgeRegistryEntry; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.function.BiPredicate; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -82,6 +90,7 @@ import java.util.stream.Collectors; * @see ItemScroll ItemScroll * @see Spells */ +@Mod.EventBusSubscriber public abstract class Spell extends IForgeRegistryEntry.Impl implements Comparable { // Spell checklist: @@ -115,6 +124,8 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C private final String unlocalisedName; /** This spell's associated SpellProperties object. */ 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. */ private Set propertyKeys = new HashSet<>(); @@ -140,6 +151,17 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ protected float pitchVariation = 0; + // The following two fields are supposed to eliminate the need for boilerplate classes in spell packs. + // As an example, spells in the twilight forest spell pack only appear on custom spell book and scroll items and + // NPCs can only cast them if they spawned in the twilight forest. Without these convenience fields, spells that + // would not otherwise require their own classes have to have one just so they can override those two behaviours. + + /** List of items for which this spell is applicable (used by default behaviour of {@link Spell#applicableForItem(Item)}). */ + protected Item[] applicableItems; + /** Predicate that specifies a condition that NPCs must satisfy in order to spawn with this spell equipped (used by + * default behaviour of {@link Spell#canBeCastBy(EntityLiving, boolean)}). */ + protected BiPredicate npcSelector; // Kinda ugly but it's better than boilerplate classes + private static int nextSpellId = 0; /** The spell's integer ID, mainly used for networking. */ // This was added after I learnt the hard way why you can't assume Forge's registry IDs are sequential... @@ -177,6 +199,8 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C this.icon = new ResourceLocation(modID, "textures/spells/" + name + ".png"); this.sounds = createSounds(); this.id = nextSpellId++; + this.items(WizardryItems.spell_book, WizardryItems.scroll); + this.npcSelector((e, o) -> canBeCastByNPCs()); // Fallback to old behaviour until we remove it entirely } // ========================================= Initialisation methods =========================================== @@ -195,7 +219,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * @see Spell#playSound(World, double, double, double, int, int, SpellModifiers, String...) */ protected SoundEvent[] createSounds(){ - return new SoundEvent[]{WizardrySounds.createSound("spell." + this.getRegistryName().getPath())}; + return new SoundEvent[]{WizardrySounds.createSound(this.getRegistryName().getNamespace(), "spell." + this.getRegistryName().getPath())}; } // Note 1: The aim here is conciseness. Keeping the identifiers in the spell classes means we don't usually have to @@ -248,6 +272,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C if(!arePropertiesInitialised()){ this.properties = properties; + if(this.globalProperties == null) this.globalProperties = properties; }else{ Wizardry.logger.info("A mod attempted to set a spell's properties, but they were already initialised."); } @@ -264,9 +289,14 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C .map(s -> s.properties).toArray(SpellProperties[]::new))); }else{ // On the client side, wipe the spell properties so the new ones can be set - for(Spell spell : registry){ - spell.properties = null; // TESTME: Can we guarantee this happens before the packet arrives? - } + // TESTME: Can we guarantee this happens before the packet arrives? + clearProperties(); + } + } + + private static void clearProperties(){ + for(Spell spell : registry){ + spell.properties = null; } } @@ -279,7 +309,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * @see Spell#createSoundsWithSuffixes(String[]) */ public final SoundEvent createSoundWithSuffix(String suffix){ - return WizardrySounds.createSound("spell." + this.getRegistryName().getPath() + "." + suffix); + return WizardrySounds.createSound(this.getRegistryName().getNamespace(), "spell." + this.getRegistryName().getPath() + "." + suffix); } /** @@ -339,7 +369,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * work if the caster is on full health). *

* This method is intended for use by NPCs (see {@link EntityWizard}) so that they can cast spells. Override it if - * you want a spell to be cast by wizards. Note that you must also override {@link Spell#canBeCastByNPCs()} to + * you want a spell to be cast by wizards. Note that you must also override {@link Spell#canBeCastBy(EntityLiving, boolean)} to * return true to allow wizards to select the spell. For some spells, this method may well be exactly the same as * the regular cast method; for others it won't be - for example, projectile-based spells are normally done using * the player's look vector, but NPCs need to use a target-based method instead. @@ -375,7 +405,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * won't work if the caster is on full health). *

* This method is intended for use by dispensers and command blocks so that they can cast spells. Override it if - * you want a spell to be cast by dispensers. Note that you must also override {@link Spell#canBeCastByDispensers()} to + * you want a spell to be cast by dispensers. Note that you must also override {@link Spell#canBeCastBy(TileEntityDispenser)} to * return true to allow dispensers to select the spell. For some spells, this method may well be exactly the same as * the regular cast method; for others it won't be - for example, projectile-based spells are normally done using * the player's look vector, but dispensers need to use a facing-based method instead. @@ -431,20 +461,50 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C public void finishCasting(World world, @Nullable EntityLivingBase caster, double x, double y, double z, @Nullable EnumFacing direction, int duration, SpellModifiers modifiers){} + /** + * Whether the given entity can cast this spell. If you have overridden + * {@link Spell#cast(World, EntityLiving, EnumHand, int, EntityLivingBase, SpellModifiers)}, you should override + * this to return true (either always or under certain circumstances), or alternatively assign an NPC selector via + * {@link Spell#npcSelector(BiPredicate)} (recommended for general spell classes). + * @param npc The entity to query. + * @param override True if a player in creative mode is assigning this spell to the given entity, false otherwise. + * Usually this means situational conditions should be ignored. + */ + // We could make this final and force everyone to move over to the predicate system, but for particularly complex + // behaviour (i.e. several lines of code) it gets too ugly, and then you end up moving the contents of the predicate + // to a static method anyway and referring to it via method reference... so we may as well leave people the option. + public boolean canBeCastBy(EntityLiving npc, boolean override){ + return npcSelector.test(npc, override); + } + /** * Whether NPCs such as wizards can cast this spell. If you have overridden * {@link Spell#cast(World, EntityLiving, EnumHand, int, EntityLivingBase, SpellModifiers)}, you should override * this to return true. + * @deprecated Use the entity-sensitive version {@link Spell#canBeCastBy(EntityLiving, boolean)}. */ + @Deprecated public boolean canBeCastByNPCs(){ return false; } + /** + * Whether the given dispenser can cast this spell. If you have overridden + * {@link Spell#cast(World, double, double, double, EnumFacing, int, int, SpellModifiers)}, you should override this + * to return true (either always or under certain circumstances). + * @param dispenser The dispenser to query. + */ + public boolean canBeCastBy(TileEntityDispenser dispenser){ + return canBeCastByDispensers(); + } + /** * Whether dispensers can cast this spell. If you have overridden * {@link Spell#cast(World, double, double, double, EnumFacing, int, int, SpellModifiers)}, you should override this * to return true. + * @deprecated Use the tileentity-sensitive version {@link Spell#canBeCastBy(TileEntityDispenser)}. */ + @Deprecated public boolean canBeCastByDispensers(){ return false; } @@ -546,19 +606,6 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return properties.getBaseValue(identifier); } - /** Returns whether the spell is enabled in any of the given {@link electroblob.wizardry.util.SpellProperties.Context Context}s. - * A spell may be disabled globally in the config, or it may be disabled for one or more specific contexts in - * its JSON file using a resource pack. If called with no arguments, defaults to any context, i.e. only returns - * false if the spell is completely disabled in all contexts. */ - public final boolean isEnabled(SpellProperties.Context... contexts){ - return enabled && (contexts.length == 0 || properties.isEnabled(contexts)); - } - - /** Sets whether the spell is enabled or not. */ - public final void setEnabled(boolean isEnabled){ - this.enabled = isEnabled; - } - /** * Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". This should * only be used for translation purposes. @@ -575,13 +622,23 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * translating it. If, for whatever reason, you need to supply an ITextComponent but don't want it translated * (perhaps a name?), you can use TextComponentString, which will simply keep the raw string it is given. */ + /** Returns the translation key for this spell. */ + protected String getTranslationKey(){ + return "spell." + unlocalisedName; + } + + /** Returns the translation key for this spell's description. */ + protected String getDescriptionTranslationKey(){ + return "spell." + unlocalisedName + ".desc"; + } + /** * Returns the translated display name of the spell, without formatting (i.e. not coloured). Client-side * only! On the server side, use {@link TextComponentTranslation} (see {@link Spell#getNameForTranslation()}). */ @SideOnly(Side.CLIENT) public String getDisplayName(){ - return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); + return net.minecraft.client.resources.I18n.format(getTranslationKey()); } /** @@ -589,7 +646,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * formatting (i.e. not coloured). */ public ITextComponent getNameForTranslation(){ - return new TextComponentTranslation("spell." + unlocalisedName); + return new TextComponentTranslation(getTranslationKey()); } /** @@ -598,7 +655,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C */ @SideOnly(Side.CLIENT) public String getDisplayNameWithFormatting(){ - return this.getElement().getFormattingCode() + net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); + return this.getElement().getFormattingCode() + net.minecraft.client.resources.I18n.format(getTranslationKey()); } /** @@ -606,7 +663,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * formatting (i.e. coloured). */ public ITextComponent getNameForTranslationFormatted(){ - return new TextComponentTranslation("spell." + unlocalisedName).setStyle(this.getElement().getColour()); + return new TextComponentTranslation(getTranslationKey()).setStyle(this.getElement().getColour()); } /** @@ -615,7 +672,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C */ @SideOnly(Side.CLIENT) public String getDescription(){ - return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName + ".desc"); + return net.minecraft.client.resources.I18n.format(getDescriptionTranslationKey()); } // ============================================ Sound methods ============================================== @@ -735,6 +792,51 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C } } + // ============================================= Misc methods =============================================== + + /** Returns whether the spell is enabled in any of the given {@link electroblob.wizardry.util.SpellProperties.Context Context}s. + * A spell may be disabled globally in the config, or it may be disabled for one or more specific contexts in + * its JSON file using a resource pack. If called with no arguments, defaults to any context, i.e. only returns + * false if the spell is completely disabled in all contexts. */ + public final boolean isEnabled(SpellProperties.Context... contexts){ + return enabled && (contexts.length == 0 || properties.isEnabled(contexts)); + } + + /** Sets whether the spell is enabled or not. */ + public final void setEnabled(boolean 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 + * in this spell's {@link Spell#applicableItems} list (set using {@link Spell#items(Item...)}). Override to do + * something more complex. */ + public boolean applicableForItem(Item item){ + return Arrays.asList(applicableItems).contains(item); + } + + /** + * Sets which items this spell can appear on (these default to the regular spell book and scroll). + * @param applicableItems The items this spell should naturally appear on (or no items at all). + * @return The spell instance, allowing this method to be chained onto the constructor. Note that since this method + * only returns a {@code Spell}, if you are chaining multiple methods onto the constructor this should be called last. + */ + public Spell items(Item... applicableItems){ + this.applicableItems = applicableItems; + return this; + } + + /** + * Specifies a condition that NPCs must satisfy in order to spawn with this spell equipped (this defaults to always + * true). + * @param selector A condition that NPCs must satisfy in order to spawn with this spell equipped. + * @return The spell instance, allowing this method to be chained onto the constructor. Note that since this method + * only returns a {@code Spell}, if you are chaining multiple methods onto the constructor this should be called last. + */ + public Spell npcSelector(BiPredicate selector){ + this.npcSelector = selector; + return this; + } + // Spells are sorted according to tier and element. Where several spells have the same tier and element, // they will remain in the order they were registered. @Override @@ -753,7 +855,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** * Returns the total number of registered spells, excluding the 'None' spell. Returns the same number that would be - * returned by {@code Spell.getSpells(Spell.allSpells).size()}, but this method is more efficient. + * returned by {@code Spell.getAllSpells().size()}, but this method is more efficient. */ public static int getTotalSpellCount(){ return registry.getValuesCollection().size() - 1; @@ -801,31 +903,37 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** * Returns a list containing all spells matching the given {@link Predicate}. The returned list is separate from the * internal spells list; any changes you make to the returned list will have no effect on wizardry since the - * returned list is local to this method. Never includes the {@link None} spell. For convenience, there are some - * predefined predicates in the Spell class (some of these really aren't shortcuts any more): - *

- * {@link Spell#allSpells} will allow all spells to be returned
- * {@link Spell#npcSpells} will only allow enabled spells that can be cast by NPCs (see - * {@link Spell#canBeCastByNPCs()})
- * {@link Spell#nonContinuousSpells} will filter out continuous spells but not disabled spells
- * {@link TierElementFilter} will only allow enabled spells of the specified tier and element + * returned list is local to this method. Never includes the {@link None} spell. * * @param filter A Predicate<Spell> that the returned spells must satisfy. * * @return A local, modifiable list of spells matching the given predicate. Note that this list may be * empty. + * + * @see TierElementFilter */ public static List getSpells(Predicate filter){ return registry.getValuesCollection().stream().filter(filter.and(s -> s != Spells.none)).collect(Collectors.toList()); } - /** Predicate which allows all spells. */ + /** Returns all registered spells, except the {@link None} spell. */ + public static List getAllSpells(){ + return getSpells(s -> true); + } + + /** Predicate which allows all spells. + * @deprecated Use {@link Spell#getAllSpells()}. */ + @Deprecated public static Predicate allSpells = s -> true; - /** Predicate which allows all non-continuous spells, even those that have been disabled. */ + /** Predicate which allows all non-continuous spells, even those that have been disabled. + * @deprecated Nobody ever uses this now we have continuous scrolls, if you really need it just use a lambda. */ + @Deprecated public static Predicate nonContinuousSpells = s -> !s.isContinuous; - /** Predicate which allows all enabled spells for which {@link Spell#canBeCastByNPCs()} returns true. */ + /** Predicate which allows all enabled spells for which {@link Spell#canBeCastBy(EntityLiving, boolean)} returns true. + * @deprecated in favour of entity-sensitive version, use a lambda expression directly. */ + @Deprecated public static Predicate npcSpells = s -> s.isEnabled(SpellProperties.Context.NPCS) && s.canBeCastByNPCs(); /** @@ -862,4 +970,32 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C && (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); + } + } + } diff --git a/src/main/java/electroblob/wizardry/spell/SpellArrow.java b/src/main/java/electroblob/wizardry/spell/SpellArrow.java index bc0af987..ca26c045 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellArrow.java +++ b/src/main/java/electroblob/wizardry/spell/SpellArrow.java @@ -11,6 +11,7 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.MathHelper; @@ -29,9 +30,9 @@ import java.util.function.Function; *

* Properties added by this type of spell: {@link Spell#RANGE} *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * @@ -58,13 +59,12 @@ public class SpellArrow extends Spell { super(modID, name, EnumAction.NONE, false); this.arrowFactory = arrowFactory; this.addProperties(RANGE); + this.npcSelector((e, o) -> true); } @Override public boolean requiresPacket(){ return false; } - @Override public boolean canBeCastByNPCs(){ return true; } - - @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } /** Computes the velocity the projectile should be launched at to achieve the required range. */ // Long story short, it doesn't make much sense to me to have the JSON file specify the velocity - even less so if diff --git a/src/main/java/electroblob/wizardry/spell/SpellBuff.java b/src/main/java/electroblob/wizardry/spell/SpellBuff.java index 5a7273a5..2e3faec2 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellBuff.java +++ b/src/main/java/electroblob/wizardry/spell/SpellBuff.java @@ -11,6 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; @@ -32,9 +33,9 @@ import java.util.stream.Collectors; *

* Properties added by this type of spell: {@link SpellBuff#getDurationKey(Potion)}, {@link SpellBuff#getStrengthKey(Potion)} *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()} * @@ -67,6 +68,7 @@ public class SpellBuff extends Spell { this.r = r; this.g = g; this.b = b; + this.npcSelector((e, o) -> true); } @Override @@ -103,9 +105,7 @@ public class SpellBuff extends Spell { return this; } - @Override public boolean canBeCastByNPCs(){ return true; } - - @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java index b982f9ea..1d86c527 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java @@ -24,9 +24,9 @@ import net.minecraft.world.World; *

* Properties added by this type of spell: {@link SpellConjuration#ITEM_LIFETIME} *

- * By default, this type of spell cannot be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell cannot be cast by NPCs. {@link Spell#canBeCastBy(net.minecraft.entity.EntityLiving, boolean)} *

- * By default, this type of spell cannot be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell cannot be cast by dispensers. {@link Spell#canBeCastBy(net.minecraft.tileentity.TileEntityDispenser)} *

* By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()} * diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java index 4428aed8..4ff0fed7 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java @@ -9,6 +9,7 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -29,9 +30,9 @@ import java.util.function.Function; *

* Properties added by this type of spell: {@link Spell#DURATION} (if the construct is not permanent) *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * @@ -58,14 +59,13 @@ public class SpellConstruct extends Spell { super(modID, name, action, false); this.constructFactory = constructFactory; this.permanent = permanent; + this.npcSelector((e, o) -> true); if(!permanent) this.addProperties(DURATION); } @Override public boolean requiresPacket(){ return false; } - - @Override public boolean canBeCastByNPCs(){ return true; } - @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } /** * Sets whether the construct must be spawned on the ground. diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java b/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java index 05d1b618..b48a28ac 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java @@ -10,6 +10,7 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -30,9 +31,9 @@ import java.util.function.Function; * Properties added by this type of spell: {@link Spell#RANGE}, {@link Spell#DURATION} (if the construct is not * permanent) *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * @@ -54,6 +55,7 @@ public class SpellConstructRanged extends SpellC public SpellConstructRanged(String modID, String name, Function constructFactory, boolean permanent){ super(modID, name, EnumAction.NONE, constructFactory, permanent); this.addProperties(RANGE); + this.npcSelector((e, o) -> true); } /** @@ -79,10 +81,8 @@ public class SpellConstructRanged extends SpellC } @Override public boolean requiresPacket(){ return false; } - - @Override public boolean canBeCastByNPCs(){ return true; } - @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/SpellMinion.java b/src/main/java/electroblob/wizardry/spell/SpellMinion.java index f492b07a..21dcf505 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellMinion.java +++ b/src/main/java/electroblob/wizardry/spell/SpellMinion.java @@ -14,6 +14,7 @@ import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -32,9 +33,9 @@ import java.util.function.Function; *

* Properties added by this type of spell: {@link SpellMinion#MINION_LIFETIME} *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * @@ -66,6 +67,7 @@ public class SpellMinion extends Spe super(modID, name, EnumAction.BOW, false); this.minionFactory = minionFactory; addProperties(MINION_LIFETIME, MINION_COUNT, SUMMON_RADIUS); + this.npcSelector((e, o) -> true); } /** @@ -80,9 +82,7 @@ public class SpellMinion extends Spe @Override public boolean requiresPacket(){ return false; } - @Override public boolean canBeCastByNPCs(){ return true; } - - @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/SpellProjectile.java b/src/main/java/electroblob/wizardry/spell/SpellProjectile.java index 1e8562e0..21624770 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellProjectile.java +++ b/src/main/java/electroblob/wizardry/spell/SpellProjectile.java @@ -11,6 +11,7 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.MathHelper; @@ -29,9 +30,9 @@ import java.util.function.Function; *

* Properties added by this type of spell: {@link Spell#RANGE} *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * @@ -58,13 +59,12 @@ public class SpellProjectile extends Spell { super(modID, name, EnumAction.NONE, false); this.projectileFactory = projectileFactory; addProperties(RANGE); + this.npcSelector((e, o) -> true); } @Override public boolean requiresPacket(){ return false; } - @Override public boolean canBeCastByNPCs(){ return true; } - - @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } /** Computes the velocity the projectile should be launched at to achieve the required range. */ // Long story short, it doesn't make much sense to me to have the JSON file specify the velocity - even less so if diff --git a/src/main/java/electroblob/wizardry/spell/SpellRay.java b/src/main/java/electroblob/wizardry/spell/SpellRay.java index 1dc46232..25271427 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellRay.java +++ b/src/main/java/electroblob/wizardry/spell/SpellRay.java @@ -10,6 +10,7 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -22,7 +23,7 @@ import javax.annotation.Nullable; /** * Generic superclass for all spells which use a raytrace to do something and (optionally) spawn particles along that - * trajectory. This is for both continuous ('stream') spells and non-continuous ('bolt') spells This allows all the + * trajectory. This is for both continuous ('stream') spells and non-continuous ('bolt') spells. This allows all the * relevant code to be centralised. This class differs from most other spell superclasses in that it is abstract and as * such must be subclassed to define what the spell actually does. This is because ray-like spells do a wider variety of * different things, so it does not make sense to define more specific functions in this class since they would be @@ -34,9 +35,9 @@ import javax.annotation.Nullable; *

* Properties added by this type of spell: {@link Spell#RANGE} *

- * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} *

- * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} *

* By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()} * @@ -72,6 +73,7 @@ public abstract class SpellRay extends Spell { public SpellRay(String modID, String name, boolean isContinuous, EnumAction action){ super(modID, name, action, isContinuous); this.addProperties(RANGE); + this.npcSelector((e, o) -> true); } // Although this class is abstract, someone might instantiate one of its subclasses more than once to make two @@ -150,10 +152,8 @@ public abstract class SpellRay extends Spell { this.aimAssist = aimAssist; return this; } - - @Override public boolean canBeCastByNPCs(){ return true; } - - @Override public boolean canBeCastByDispensers() { return true; } + + @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } // Finally everything in here is standardised and written in a form that's actually readable - it was long overdue! @Override diff --git a/src/main/java/electroblob/wizardry/spell/SpellThrowable.java b/src/main/java/electroblob/wizardry/spell/SpellThrowable.java new file mode 100644 index 00000000..d3145dd6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellThrowable.java @@ -0,0 +1,142 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.living.ISpellCaster; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityThrowable; +import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +import java.util.function.BiFunction; + +/** + * Similar to {@link electroblob.wizardry.spell.SpellProjectile}, but for any {@link EntityThrowable}. + * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple + * instantiation of this class is sufficient to create a projectile spell; if something extra needs to be done, such as + * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. + *

+ * N.B. It is advised that this class is only used where the projectile to be launched belongs to vanilla Minecraft + * or another mod; no guarantees are made as to the behaviour of such projectiles! + *

+ * Properties added by this type of spell: {@link Spell#RANGE} + *

+ * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)} + *

+ * By default, this type of spell cannot be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)} + *

+ * By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} + * + * @author Electroblob + * @since Wizardry 4.2.8 + */ +// TODO: Use events to make these projectiles seek targets when the caster is wearing a ring of attraction (is this possible?) +public class SpellThrowable extends Spell { + + private static final float LAUNCH_Y_OFFSET = 0.1f; + + protected final BiFunction projectileFactory; + + public SpellThrowable(String name, BiFunction projectileFactory){ + this(Wizardry.MODID, name, projectileFactory); + } + + public SpellThrowable(String modID, String name, BiFunction projectileFactory){ + super(modID, name, EnumAction.NONE, false); + this.projectileFactory = projectileFactory; + addProperties(RANGE); + this.npcSelector((e, o) -> true); + } + + @Override + public boolean requiresPacket(){ + return false; + } + + /** Trajectory calculation - see {@link SpellProjectile} for a more detailed explanation */ + protected float calculateVelocity(SpellModifiers modifiers, float launchHeight){ + float g = 0.03f; + float range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + return range / MathHelper.sqrt(2 * launchHeight/g); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(!world.isRemote){ + float velocity = calculateVelocity(modifiers, caster.getEyeHeight() - LAUNCH_Y_OFFSET); + T projectile = projectileFactory.apply(world, caster); + projectile.shoot(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, velocity, 1.0f); + addProjectileExtras(projectile, caster, modifiers); + world.spawnEntity(projectile); + } + + this.playSound(world, caster, ticksInUse, -1, modifiers); + caster.swingArm(hand); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + float velocity = calculateVelocity(modifiers, caster.getEyeHeight() - LAUNCH_Y_OFFSET); + T projectile = projectileFactory.apply(world, caster); + int aimingError = caster instanceof ISpellCaster ? ((ISpellCaster)caster).getAimingError(world.getDifficulty()) + : WizardryUtilities.getDefaultAimingError(world.getDifficulty()); + aim(projectile, caster, target, velocity, aimingError); + addProjectileExtras(projectile, caster, modifiers); + world.spawnEntity(projectile); + } + + this.playSound(world, caster, ticksInUse, -1, modifiers); + caster.swingArm(hand); + return true; + } + + return false; + } + + // Copied from EntityMagicProjectile (ugh what a mess) + private void aim(T throwable, EntityLivingBase caster, Entity target, float speed, float aimingError){ + + throwable.ignoreEntity = caster; + + throwable.posY = caster.getEntityBoundingBox().minY + (double)caster.getEyeHeight() - LAUNCH_Y_OFFSET; + double dx = target.posX - caster.posX; + double dy = !throwable.hasNoGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - throwable.posY + : target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - throwable.posY; + double dz = target.posZ - caster.posZ; + double horizontalDistance = MathHelper.sqrt(dx * dx + dz * dz); + + if(horizontalDistance >= 1.0E-7D){ + + double dxNormalised = dx / horizontalDistance; + double dzNormalised = dz / horizontalDistance; + throwable.setPosition(caster.posX + dxNormalised, throwable.posY, caster.posZ + dzNormalised); + + // Depends on the horizontal distance between the two entities and accounts for bullet drop, + // but of course if gravity is ignored throwable should be 0 since there is no bullet drop. + float bulletDropCompensation = !throwable.hasNoGravity() ? (float)horizontalDistance * 0.2f : 0; + // It turns out that throwable method normalises the input (x, y, z) anyway + throwable.shoot(dx, dy + (double)bulletDropCompensation, dz, speed, aimingError); + } + } + + /** + * Does nothing by default, but can be overridden to call extra methods or set additional fields on the launched + * projectile. + */ + protected void addProjectileExtras(T projectile, EntityLivingBase caster, SpellModifiers modifiers){} + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java index 2f77947c..8e7c9476 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java @@ -1,5 +1,6 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -45,4 +46,8 @@ public class SummonSnowGolem extends Spell { return true; } + @Override + protected String getTranslationKey(){ + return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey(); + } } diff --git a/src/main/java/electroblob/wizardry/spell/Tornado.java b/src/main/java/electroblob/wizardry/spell/Tornado.java index 3cd3d9ea..b79d3f0b 100644 --- a/src/main/java/electroblob/wizardry/spell/Tornado.java +++ b/src/main/java/electroblob/wizardry/spell/Tornado.java @@ -6,9 +6,6 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - -import javax.annotation.Nullable; public class Tornado extends SpellConstruct { diff --git a/src/main/java/electroblob/wizardry/spell/WitherSkull.java b/src/main/java/electroblob/wizardry/spell/WitherSkull.java index 8370ad26..c71af6ec 100644 --- a/src/main/java/electroblob/wizardry/spell/WitherSkull.java +++ b/src/main/java/electroblob/wizardry/spell/WitherSkull.java @@ -33,7 +33,7 @@ public class WitherSkull extends Spell { } @Override - public boolean canBeCastByNPCs(){ + public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; } diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java index 991098b7..cfc6dc09 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java @@ -7,6 +7,7 @@ import electroblob.wizardry.item.ItemCrystal; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.WandHelper; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; @@ -205,7 +206,7 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, } } - tagCompound.setTag("Inventory", itemList); + NBTExtras.storeTagSafely(tagCompound, "Inventory", itemList); return tagCompound; } diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java index b03f23be..f34a834b 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java @@ -184,7 +184,7 @@ public class TileEntityShrineCore extends TileEntity implements ITickable { for(EntityLivingBase entity : entities){ entity.addPotionEffect(new PotionEffect(WizardryPotions.containment, 219)); - entity.getEntityData().setTag(PotionContainment.ENTITY_TAG, NBTUtil.createPosTag(this.pos)); + NBTExtras.storeTagSafely(entity.getEntityData(), PotionContainment.ENTITY_TAG, NBTUtil.createPosTag(this.pos)); } } @@ -192,13 +192,13 @@ public class TileEntityShrineCore extends TileEntity implements ITickable { public NBTTagCompound writeToNBT(NBTTagCompound compound){ compound.setBoolean("activated", this.activated); - if(linkedContainer != null) compound.setTag("linkedContainerPos", NBTUtil.createPosTag(linkedContainer.getPos())); + if(linkedContainer != null) NBTExtras.storeTagSafely(compound, "linkedContainerPos", NBTUtil.createPosTag(linkedContainer.getPos())); NBTTagList tagList = new NBTTagList(); for(UUID uuid : linkedWizards){ if(uuid != null) tagList.appendTag(NBTUtil.createUUIDTag(uuid)); } - compound.setTag("wizards", tagList); + NBTExtras.storeTagSafely(compound, "wizards", tagList); return super.writeToNBT(compound); } diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java index ab999d7d..4f07e8e1 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java @@ -1,5 +1,6 @@ package electroblob.wizardry.tileentity; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.entity.EntityList; @@ -152,7 +153,7 @@ public class TileEntityStatue extends TileEntity implements ITickable { tagCompound.setFloat("entityYawHead", creature.rotationYawHead); tagCompound.setFloat("entityYawOffset", creature.renderYawOffset); } - tagCompound.setTag("entity", entityCompound); + NBTExtras.storeTagSafely(tagCompound, "entity", entityCompound); tagCompound.setInteger("timer", timer); tagCompound.setInteger("lifetime", lifetime); tagCompound.setBoolean("isIce", isIce); diff --git a/src/main/java/electroblob/wizardry/util/MagicDamage.java b/src/main/java/electroblob/wizardry/util/MagicDamage.java index 23ce536e..8c0429c2 100644 --- a/src/main/java/electroblob/wizardry/util/MagicDamage.java +++ b/src/main/java/electroblob/wizardry/util/MagicDamage.java @@ -8,7 +8,10 @@ import net.minecraft.entity.monster.*; import net.minecraft.util.DamageSource; import net.minecraft.util.EntityDamageSource; -import java.util.*; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; // A note on the use of the vanilla damagesources: // When using indirect damage sources, the SECOND argument is the original entity (i.e. the caster), and the diff --git a/src/main/java/electroblob/wizardry/util/NBTExtras.java b/src/main/java/electroblob/wizardry/util/NBTExtras.java index 309fa217..eac5464d 100644 --- a/src/main/java/electroblob/wizardry/util/NBTExtras.java +++ b/src/main/java/electroblob/wizardry/util/NBTExtras.java @@ -51,8 +51,8 @@ public final class NBTExtras { for(Map.Entry entry : map.entrySet()){ NBTTagCompound mapping = new NBTTagCompound(); - mapping.setTag(keyTagName, keyFunction.apply(entry.getKey())); - mapping.setTag(valueTagName, valueFunction.apply(entry.getValue())); + NBTExtras.storeTagSafely(mapping, keyTagName, keyFunction.apply(entry.getKey())); + NBTExtras.storeTagSafely(mapping, valueTagName, valueFunction.apply(entry.getValue())); tagList.appendTag(mapping); } @@ -205,6 +205,51 @@ public final class NBTExtras { tag.removeTag(key + "Least"); } + /** + * Stores the given NBT tag inside the given NBT tag compound using the given key. Under normal circumstances, this + * is equivalent to {@link NBTTagCompound#setTag(String, NBTBase)}, but this method performs safety checks to + * prevent circular references. If storing the given tag would cause a circular reference, the tag is not stored + * and an error is printed to the console. + * @param compound The {@link NBTTagCompound} in which to store the tag. + * @param key The key to store the tag under. + * @param tag The tag to store. + */ + // This is a catch-all fix for issue #299. + public static void storeTagSafely(NBTTagCompound compound, String key, NBTBase tag){ + + if(compound == tag || deepContains(tag, compound)){ + Wizardry.logger.error("Cannot store tag of type {} under key '{}' as it would result in a circular reference! Please report this (including your full log) to wizardry's issue tracker.", + NBTBase.getTypeName(tag.getId()), key); + }else{ + compound.setTag(key, tag); + } + } + + /** + * Recursively searches within the first NBT tag for the second NBT tag. This handles both compound and list tags. + * @param toSearch The NBT tag to search inside. If this is not a compound or list tag, this method will always + * return false. + * @param searchFor The NBT tag to search for. + * @return True if the second tag appears anywhere within the NBT tree contained within the first tag, false if not. + */ + public static boolean deepContains(NBTBase toSearch, NBTBase searchFor){ + + if(toSearch instanceof NBTTagCompound){ + + for(String subKey : ((NBTTagCompound)toSearch).getKeySet()){ + NBTBase subTag = ((NBTTagCompound)toSearch).getTag(subKey); + if(subTag == searchFor || deepContains(subTag, searchFor)) return true; + } + + }else if(toSearch instanceof NBTTagList){ + for(NBTBase subTag : (NBTTagList)toSearch){ + if(subTag == searchFor || deepContains(subTag, searchFor)) return true; + } + } + + return false; + } + /** * Returns an NBTTagCompound which contains only the given UUID, stored using * {@link NBTTagCompound#setUniqueId(String, UUID)}. Allows for neater storage to NBTTagLists. diff --git a/src/main/java/electroblob/wizardry/util/SpellProperties.java b/src/main/java/electroblob/wizardry/util/SpellProperties.java index 55e7d00b..de12eb52 100644 --- a/src/main/java/electroblob/wizardry/util/SpellProperties.java +++ b/src/main/java/electroblob/wizardry/util/SpellProperties.java @@ -13,13 +13,16 @@ import electroblob.wizardry.spell.Spell; import io.netty.buffer.ByteBuf; import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.*; @@ -40,9 +43,6 @@ import java.util.stream.Collectors; * @author Electroblob * @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 { 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 // wiped client-side on each login anyway. public static void init(){ - // Collecting to a set should give us one of each mod ID - Set modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet()); - boolean flag = true; + // Collecting to a set should give us one of each mod ID + Set modIDs = Spell.getAllSpells().stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet()); + + boolean flag = loadConfigSpellProperties(); 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!"); } - // Sooooooo I just realised that resource packs - you know, that famously client-side thing - can now define - // stuff that should be specified by the server. No wonder it all got moved to data packs in 1.13... - // Anyway, for the time being we're in 1.12 so we're gonna have to do this instead. + // There are now three 'layers' of spell properties - in order of priority, these are: + // 1. World-specific properties, stored in saves/[world]/data/spells + // 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. // 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. ModContainer mod = Loader.instance().getModList().stream().filter(m -> m.getModId().equals(modID)).findFirst().orElse(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! } @@ -279,7 +304,7 @@ public final class SpellProperties { List 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 - 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 // In the absence of Javadoc, here's what the non-obvious parameters do: @@ -307,12 +332,16 @@ public final class SpellProperties { return true; } - BufferedReader reader = null; - // We want to do this regardless of whether the JSON file got read properly, because that prints its // own separate warning 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{ reader = Files.newBufferedReader(file); @@ -348,6 +377,54 @@ public final class SpellProperties { 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 diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java index 7651abfb..677761a3 100644 --- a/src/main/java/electroblob/wizardry/util/WandHelper.java +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -398,7 +398,7 @@ public final class WandHelper { if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); if(!wand.getTagCompound().hasKey(UPGRADES_KEY)) - wand.getTagCompound().setTag(UPGRADES_KEY, new NBTTagCompound()); + NBTExtras.storeTagSafely(wand.getTagCompound(), UPGRADES_KEY, new NBTTagCompound()); NBTTagCompound upgrades = wand.getTagCompound().getCompoundTag(UPGRADES_KEY); @@ -406,7 +406,7 @@ public final class WandHelper { if(key != null) upgrades.setInteger(key, upgrades.getInteger(key) + 1); - wand.getTagCompound().setTag(UPGRADES_KEY, upgrades); + NBTExtras.storeTagSafely(wand.getTagCompound(), UPGRADES_KEY, upgrades); } /** Returns true if the given item is a valid special wand upgrade. */ diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index cbb0ee05..6e019a5e 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -1,6 +1,7 @@ package electroblob.wizardry.util; import electroblob.wizardry.CommonProxy; +import electroblob.wizardry.Settings; import electroblob.wizardry.Wizardry; import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.living.ISpellCaster; @@ -23,6 +24,7 @@ import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.EntityEquipmentSlot.Type; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.server.MinecraftServer; import net.minecraft.util.*; @@ -270,7 +272,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 * 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 * or a liquid, and an air block. Used for freezing water and placing snow. */ @@ -298,11 +300,10 @@ public final class WizardryUtilities { * @return True if the given block is a tree block, false if not. */ public static boolean isTreeBlock(World world, BlockPos pos){ - return world.getBlockState(pos).getBlock() instanceof BlockLog - || world.getBlockState(pos).getBlock() instanceof BlockCactus - || world.getBlockState(pos).getBlock().isLeaves(world.getBlockState(pos), world, pos) - || world.getBlockState(pos).getBlock().isFoliage(world, pos) - || Arrays.asList(Wizardry.settings.treeBlocks).contains(world.getBlockState(pos).getBlock().getRegistryName()); + Block block = world.getBlockState(pos).getBlock(); + return block instanceof BlockLog || block instanceof BlockCactus + || block.isLeaves(world.getBlockState(pos), world, pos) || block.isFoliage(world, pos) + || Settings.containsMetaBlock(Wizardry.settings.treeBlocks, world.getBlockState(pos)); } /** @@ -795,6 +796,20 @@ public final class WizardryUtilities { return false; } + /** + * Returns a new {@link ItemStack} that is identical to the supplied one, except with the metadata changed to the + * new value given. + * @param toCopy The stack to copy + * @param newMetadata The new metadata value + * @return The resulting {@link ItemStack} + */ + public static ItemStack copyWithMeta(ItemStack toCopy, int newMetadata){ + ItemStack copy = new ItemStack(toCopy.getItem(), toCopy.getCount(), newMetadata); + NBTTagCompound compound = toCopy.getTagCompound(); + if(compound != null) copy.setTagCompound(compound.copy()); + return copy; + } + /** * Checks if the given player is opped on the given server. If the server is a singleplayer or LAN server, this * means they have cheats enabled. diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java index c55ba7c4..5af256f9 100644 --- a/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java @@ -3,6 +3,7 @@ package electroblob.wizardry.worldgen; import com.google.common.math.Quantiles; import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.WizardryUtilities; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -27,7 +28,6 @@ import net.minecraft.world.gen.structure.MapGenStructureData; import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.template.PlacementSettings; import net.minecraft.world.gen.structure.template.Template; -import net.minecraftforge.common.BiomeDictionary; import net.minecraftforge.common.util.Constants; import net.minecraftforge.fml.common.IWorldGenerator; import net.minecraftforge.fml.common.Mod; @@ -120,6 +120,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { * @param world The world in which to spawn the structure * @param chunkX The x-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 * {@code BlockPos} is always 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 @@ -128,7 +129,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { */ @Nullable 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 // 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,8 +137,16 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16)); 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 BlockPos centre = world.getTopSolidOrLiquidBlock(new BlockPos(origin.add(size.getX()/2, 0, size.getZ()/2))); + // Check if we're at the top of the world, and if so just randomise the y pos (accounts for 'cavern' dimensions) + if(centre.getY() >= world.getActualHeight()) centre = new BlockPos(centre.getX(), random.nextInt(world.getActualHeight()), centre.getZ()); + Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true, WizardryUtilities.SurfaceCriteria.COLLIDABLE_IGNORING_TREES); @@ -145,8 +154,8 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { if(Wizardry.settings.fastWorldgen){ BlockPos result = origin.up(startingHeight); - // Fast worldgen doesn't check for water, instead it checks the biome like vanilla, which is crude but fast - return BiomeDictionary.hasType(world.getBiome(result), BiomeDictionary.Type.WATER) ? null : result; + // Fast worldgen only checks the central position for water, which isn't perfect but it is faster + return world.getBlockState(new BlockPos(centre.getX(), startingHeight + 1, centre.getZ())).getMaterial().isLiquid() ? null : result; } int[] floorHeights = new int[size.getX() * size.getZ()]; @@ -212,7 +221,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { BlockPos origin; do { - origin = findValidPosition(template, settings, random, world, chunkX, chunkZ); + origin = findValidPosition(template, settings, random, world, chunkX, chunkZ, structureFile.toString()); triesLeft--; }while(triesLeft > 0 && origin != null); @@ -244,14 +253,14 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { 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()); NBTTagCompound tag = new NBTTagCompound(); tag.setInteger("ChunkX", chunkX); tag.setInteger("ChunkZ", chunkZ); - tag.setTag("BB", settings.getBoundingBox().toNBTTagIntArray()); + NBTExtras.storeTagSafely(tag, "BB", settings.getBoundingBox().toNBTTagIntArray()); structureData.writeInstance(tag, chunkX, chunkZ); structureData.markDirty(); } @@ -306,7 +315,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { } /** 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; int y = boundingBox.minY; @@ -354,7 +363,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator { } 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 diff --git a/src/main/resources/assets/ebwizardry/lang/de_de.lang b/src/main/resources/assets/ebwizardry/lang/de_de.lang new file mode 100644 index 00000000..a205ec43 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/lang/de_de.lang @@ -0,0 +1,1296 @@ +#PARSE_ESCAPES +tile.ebwizardry\:arcane_workbench.name=Arkane Werkbank +tile.ebwizardry\:crystal_ore.name=Kristallerz +tile.ebwizardry\:petrified_stone.name=Versteinertes Gestein +tile.ebwizardry\:ice_statue.name=Eis-Statue +tile.ebwizardry\:crystal_flower.name=Kristallblume +tile.ebwizardry\:snare.name=Anwurzeln +tile.ebwizardry\:transportation_stone.name=Stein der Teleportation +tile.ebwizardry\:transportation_stone.confirm=Sie werden hier nach wirken des Zaubers zurückkehren %1$s +tile.ebwizardry\:transportation_stone.remember=Position %s, %s, %s in der dimension %s gespeichert +tile.ebwizardry\:transportation_stone.forget=Position %s, %s, %s in der dimension %s vergessen +tile.ebwizardry\:transportation_stone.invalid=Du musst zuerst einen Kreis mit 8 Teleportsteinen bilden! +tile.ebwizardry\:spectral_block.name=Spektralblock +tile.ebwizardry\:runestone.name=Runenstein +tile.ebwizardry\:runestone_pedestal.name=Runenstein Sockel +tile.ebwizardry\:thorns.name=Dornen +tile.ebwizardry\:obsidian_crust.name=Obsidian Kruste +tile.ebwizardry\:dry_frosted_ice.name=Gefrohrenes Trockeneis + +tile.ebwizardry\:magic_crystal_block.name=Kristallblock +tile.ebwizardry\:fire_crystal_block.name=Block aus feurigem Kristall +tile.ebwizardry\:ice_crystal_block.name=Block aus eisigem Kristall +tile.ebwizardry\:lightning_crystal_block.name=Block aus stürmischem Kristall +tile.ebwizardry\:necromancy_crystal_block.name=Block aus verbotenem Kristall +tile.ebwizardry\:earth_crystal_block.name=Block aus erdgebundenem Kristall +tile.ebwizardry\:sorcery_crystal_block.name=Block des mystischen Kristall +tile.ebwizardry\:healing_crystal_block.name=Block aus strahlendem Kristall + +item.ebwizardry\:crystal_magic.name=Magischer Kristall +item.ebwizardry\:crystal_fire.name=Feuriger Kristall +item.ebwizardry\:crystal_ice.name=Eisiger Kristall +item.ebwizardry\:crystal_lightning.name=Stürmischer Kristall +item.ebwizardry\:crystal_necromancy.name=Dunkler Kristall +item.ebwizardry\:crystal_earth.name=Erdgebundener Kristall +item.ebwizardry\:crystal_sorcery.name=Mystischer Kristall +item.ebwizardry\:crystal_healing.name=Strahlender Kristall + +item.ebwizardry\:magic_wand.name=Magischer Zauberstab +item.ebwizardry\:apprentice_wand.name=Lehrlingszauberstab +item.ebwizardry\:advanced_wand.name=Höherer Zauberstab +item.ebwizardry\:master_wand.name=Meisterhafter Zauberstab +item.ebwizardry\:spell_book.name=Zauberbuch + +item.ebwizardry\:spell_book.apply_to_wizard=%1$s Zauber mit %2$s und %3$s ersetzt. + +item.ebwizardry\:arcane_tome.name=Leitfaden der Arkanen Künste +item.ebwizardry\:arcane_tome.desc=Verbessert jeden %1$s Zauberstab mit ausreichender Verbesserung auf %2$s Stufe + +item.ebwizardry\:wizard_handbook.name=Handbuch eines Magiers +item.ebwizardry\:wizard_handbook.desc=Von %1$s + +item.ebwizardry\:wand.generic=Zauberstab + +item.ebwizardry\:wand.buff=+%1$s %2$s Wirkung +item.ebwizardry\:wand.spell=Derzeitiger Zauber\: %1$s +item.ebwizardry\:wand.mana=Mana\: %1$s/%2$s +item.ebwizardry\:wand.progression=Verbesserung\: %1$s/%2$s + +item.ebwizardry\:wand.levelup=%1$s ist bereit, auf die Stufe %2$s aufzusteigen + +item.ebwizardry\:wand.addally=%1$s wurde zu der Liste der Verbündeten hinzugefügt +item.ebwizardry\:wand.removeally=%1$s wurde von der Liste der Verbündeten gestrichen + +item.ebwizardry\:novice_fire_wand.name=Zauberstab der Glut +item.ebwizardry\:novice_ice_wand.name=Zauberstab des Fröstelns +item.ebwizardry\:novice_lightning_wand.name=Zauberstab des Funkens +item.ebwizardry\:novice_necromancy_wand.name=Zauberstab des Verbotenen +item.ebwizardry\:novice_earth_wand.name=Zauberstab des Erdgebundenen +item.ebwizardry\:novice_sorcery_wand.name=Zauberstab der Mystik +item.ebwizardry\:novice_healing_wand.name=Zauberstab der Heilung + +item.ebwizardry\:apprentice_fire_wand.name=Lehrlingszauberstab des Feuers +item.ebwizardry\:apprentice_ice_wand.name=Lehrlingszauberstab des Frosts +item.ebwizardry\:apprentice_lightning_wand.name=Lehrlingszauberstab des Funkens +item.ebwizardry\:apprentice_necromancy_wand.name=Lehrlingszauberstab der verbotenen Magie +item.ebwizardry\:apprentice_earth_wand.name=Lehrlingszauberstab des Erdgebundenen +item.ebwizardry\:apprentice_sorcery_wand.name=Lehrlingszauberstab der Mystik +item.ebwizardry\:apprentice_healing_wand.name=Lehrlingszauberstab der Heilung + +item.ebwizardry\:advanced_fire_wand.name=Höherer Zauberstab des Infernos +item.ebwizardry\:advanced_ice_wand.name=Höherer Zauberstab des tötlichen Eises +item.ebwizardry\:advanced_lightning_wand.name=Höherer Zauberstab des Blitzes +item.ebwizardry\:advanced_necromancy_wand.name=Höherer Zauberstab der verbotenen Magie +item.ebwizardry\:advanced_earth_wand.name=Höherer Zauberstab der Erdmagie +item.ebwizardry\:advanced_sorcery_wand.name=Höherer Zauberstab der Mystik +item.ebwizardry\:advanced_healing_wand.name=Höherer Zauberstab der Wiederherstellung + +item.ebwizardry\:master_fire_wand.name=Meisterzauberstab des Infernos +item.ebwizardry\:master_ice_wand.name=Meisterzauberstab der Frost +item.ebwizardry\:master_lightning_wand.name=Meisterzauberstab des Blitzgewitters +item.ebwizardry\:master_necromancy_wand.name=Meisterzauberstab der Verbotenen Künste +item.ebwizardry\:master_earth_wand.name=Meisterzauberstab des Erdgebundenen +item.ebwizardry\:master_sorcery_wand.name=Meisterzauberstab der Mystik +item.ebwizardry\:master_healing_wand.name=Meisterzauberstab der Wiederherstellung + +item.ebwizardry\:spectral_sword.name=Spektralschwert +item.ebwizardry\:spectral_pickaxe.name=Spektralspitzhacke +item.ebwizardry\:spectral_bow.name=Spektralbogen + +item.ebwizardry\:spectral_sword_upgraded.name=Spektralschwert +item.ebwizardry\:spectral_pickaxe_upgraded.name=Spektralspitzhacke + +item.ebwizardry\:small_mana_flask.name=Kleines Manafläschchen +item.ebwizardry\:medium_mana_flask.name=Manaflasche +item.ebwizardry\:large_mana_flask.name=Große Manaflasche + +item.ebwizardry\:grand_crystal.name=Großer magischer Kristall +item.ebwizardry\:crystal_shard.name=Magische Kristallscherbe + +item.ebwizardry\:astral_diamond.name=Astral-Diamant + +item.ebwizardry\:purifying_elixir.name=Reinigendes Elixier +item.ebwizardry\:purifying_elixir.desc=Entfernt Flüche beim Konsumieren + +item.ebwizardry\:storage_upgrade.name=Aufwertung des Manaspeichers +item.ebwizardry\:siphon_upgrade.name=Aufwertung Blut - in - Mana +item.ebwizardry\:condenser_upgrade.name=Aufwertung des regenerativen Mana +item.ebwizardry\:range_upgrade.name=Aufwertung der Zauberreichweite +item.ebwizardry\:duration_upgrade.name=Aufwertung der Effektdauer +item.ebwizardry\:cooldown_upgrade.name=Aufwertung der Abklingzeiten +item.ebwizardry\:blast_upgrade.name=Aufwertung der Wirkungsbereichgröße +item.ebwizardry\:attunement_upgrade.name=Aufwertung der Zauber-Slots +item.ebwizardry\:melee_upgrade.name=Aufwertung des Nahkampfes + +item.ebwizardry\:storage_upgrade.desc=Erhöht die maximale Mana - Anzahl +item.ebwizardry\:siphon_upgrade.desc=Entzieht getöteten Lebewesen Mana das den Stab aufläd +item.ebwizardry\:condenser_upgrade.desc=Generiert langsarm Mana +item.ebwizardry\:range_upgrade.desc=Erhöht die Reichweite von Projektilzaubern und Beschwörungen +item.ebwizardry\:duration_upgrade.desc=Verlängert Effekte von Zaubern +item.ebwizardry\:cooldown_upgrade.desc=Verringert die Wartezeit zwischen Zaubern +item.ebwizardry\:blast_upgrade.desc=Erhöht den Wirkungsbereich von Flächendeckenden Zaubern +item.ebwizardry\:attunement_upgrade.desc=Erhöht die Anzahl an Zaubern die an einen Stab gebunden werden können +item.ebwizardry\:melee_upgrade.desc=Entzieht pro Schlag Mana um erhöhten Nahkampfschaden mit dem Stab zu machen + +item.ebwizardry\:flaming_axe.name=Feurige Axt +item.ebwizardry\:frost_axe.name=Eisige Axt + +item.ebwizardry\:flaming_axe_upgraded.name=Feurige Axt +item.ebwizardry\:frost_axe_upgraded.name=Eisige Axt + +item.ebwizardry\:firebomb.name=Feuerbombe +item.ebwizardry\:poison_bomb.name=Giftbombe +item.ebwizardry\:smoke_bomb.name=Rauchbombe +item.ebwizardry\:spark_bomb.name=Blitzbombe + +item.ebwizardry\:blank_scroll.name=Leere Schriftrolle +item.ebwizardry\:scroll.generic=Schriftrolle +item.ebwizardry\:scroll.name=Schriftrolle %1$s +item.ebwizardry\:scroll.undiscovered.name=Schriftrolle "%1$s" +item.ebwizardry\:identification_scroll.name=Schriftrolle der Enthüllung +item.ebwizardry\:identification_scroll.desc=Erkennt ein unbekanntes Zauberbuch oder eine unbekannte Schriftrolle +item.ebwizardry\:identification_scroll.nothing_to_identify=Nichts zu enthüllen! + +item.ebwizardry\:armour_upgrade.name=Arkanes Schutzsiegel +item.ebwizardry\:armour_upgrade.desc1=%1$sVerbessert jede Magierrüstung +item.ebwizardry\:armour_upgrade.desc2=%1$sum sie %2$slegendär zu machen + +item.ebwizardry\:magic_silk.name=Magische Seide + +item.ebwizardry\:wizard_armour.legendary=Legendär +item.ebwizardry\:wizard_armour.buff=-%1$s %2$s Kosten +item.ebwizardry\:wizard_armour.mana=Mana\: %1$s/%2$s + +item.ebwizardry\:wizard_hat.name=Zauberer-Hut +item.ebwizardry\:wizard_robe.name=Zauberer-Robe +item.ebwizardry\:wizard_leggings.name=Zauberer-Hose +item.ebwizardry\:wizard_boots.name=Zauberer-Schuhe + +item.ebwizardry\:wizard_hat_fire.name=Pyromantiker-Hut +item.ebwizardry\:wizard_robe_fire.name=Pyromantiker-Robe +item.ebwizardry\:wizard_leggings_fire.name=Pyromantiker-Hose +item.ebwizardry\:wizard_boots_fire.name=Pyromantiker-Schuhe + +item.ebwizardry\:wizard_hat_ice.name=Eismagier-Hut +item.ebwizardry\:wizard_robe_ice.name=Eismagier-Robe +item.ebwizardry\:wizard_leggings_ice.name=Eismagier-Hose +item.ebwizardry\:wizard_boots_ice.name=Eismagier-Schuhe + +item.ebwizardry\:wizard_hat_lightning.name=Blitzmagier-Hut +item.ebwizardry\:wizard_robe_lightning.name=Blitzmagier-Robe +item.ebwizardry\:wizard_leggings_lightning.name=Blitzmagier-Hose +item.ebwizardry\:wizard_boots_lightning.name=Blitzmagier-Schuhe + +item.ebwizardry\:wizard_hat_necromancy.name=Verbotenenmager-Hut +item.ebwizardry\:wizard_robe_necromancy.name=Verbotenenmager-Robe +item.ebwizardry\:wizard_leggings_necromancy.name=Verbotenenmager-Hose +item.ebwizardry\:wizard_boots_necromancy.name=Verbotenenmager-Schuhe + +item.ebwizardry\:wizard_hat_earth.name=Erdmagier-Hut +item.ebwizardry\:wizard_robe_earth.name=Erdmagier-Robe +item.ebwizardry\:wizard_leggings_earth.name=Erdmagier-Hose +item.ebwizardry\:wizard_boots_earth.name=Erdmagier-Schuhe + +item.ebwizardry\:wizard_hat_sorcery.name=Magier-Hut +item.ebwizardry\:wizard_robe_sorcery.name=Magier-Robe +item.ebwizardry\:wizard_leggings_sorcery.name=Magier-Hose +item.ebwizardry\:wizard_boots_sorcery.name=Magier-Schuhe + +item.ebwizardry\:wizard_hat_healing.name=Heilmagier-Hut +item.ebwizardry\:wizard_robe_healing.name=Heilmagier-Robe +item.ebwizardry\:wizard_leggings_healing.name=Heilmagier-Hose +item.ebwizardry\:wizard_boots_healing.name=Heilmagier-Schuhe + +item.ebwizardry\:spawn_wizard.name=Erschaffe Zauberer +item.ebwizardry\:spawn_evil_wizard.name=Erschaffe Böser Zauberer + +item.ebwizardry\:spectral_helmet.name=Spektralhelm +item.ebwizardry\:spectral_chestplate.name=Spektralbrustplatte +item.ebwizardry\:spectral_leggings.name=Spektralbeinlinge +item.ebwizardry\:spectral_boots.name=Spektralschuhe + +item.ebwizardry\:lightning_hammer.name=Blitzhammer + +item.ebwizardry\:ring_condensing.name=Ring der Managenerierung +item.ebwizardry\:ring_condensing.desc=Regeneriert langsam Mana für alle Zauberstäbe in der Hotbar +item.ebwizardry\:ring_siphoning.name=Ring der Konvertierung +item.ebwizardry\:ring_siphoning.desc=Erhöht das Mana von getöteten Lebewesen um 30%% +item.ebwizardry\:ring_battlemage.name=Ring des Kampfmagiers +item.ebwizardry\:ring_battlemage.desc=Halte einen Zauberstab in der linken und ein Schwert in der rechten Hand für 10%% mehr Magieschaden +item.ebwizardry\:ring_combustion.name=Ring der Infernohüllen +item.ebwizardry\:ring_combustion.desc=Mit Feuer getötete Lebewesen explodieren beim tod +item.ebwizardry\:ring_fire_melee.name=Ring der feurigen Hand +item.ebwizardry\:ring_fire_melee.desc=Schlage eine Kreatur mit dem Zauberstab um sie anzuzünden +item.ebwizardry\:ring_fire_biome.name=Ring der starken Sonne +item.ebwizardry\:ring_fire_biome.desc=Feuerzauber sind 30%% stärker in warmen biomen +item.ebwizardry\:ring_disintegration.name=Ring der versengenden Glut +item.ebwizardry\:ring_disintegration.desc=Alle Feuerangriffszauber bewirken das sich ihre Opfer auflösen +item.ebwizardry\:ring_ice_melee.name=Ring des Frostbisses +item.ebwizardry\:ring_ice_melee.desc=Schlage eine Kreatur mit dem Zauberstab um ihr Frostbiss zu geben +item.ebwizardry\:ring_ice_biome.name=Ring der Eisstürme +item.ebwizardry\:ring_ice_biome.desc=Eiszauber sind 30%% stärker in Schneebiomen +item.ebwizardry\:ring_arcane_frost.name=Ring des arkanen Frostes +item.ebwizardry\:ring_arcane_frost.desc=Mit Eis getötete Lebewesen explodieren in Eissplitter +item.ebwizardry\:ring_shattering.name=Ring der Zerbrechlichkeit +item.ebwizardry\:ring_shattering.desc=Schlage Kreaturen die gerade Frostbiss haben, zersplittern manchmal direkt +item.ebwizardry\:ring_lightning_melee.name=Ring der Lichtkette +item.ebwizardry\:ring_lightning_melee.desc=Schlage eine Kreatur um nahe Kreaturen mit Blitzen abzuschießen +item.ebwizardry\:ring_storm.name=Ring des aufziehenden Sturms +item.ebwizardry\:ring_storm.desc=Während eines gewitters haben Blitzzauber kaum mehr Abklingzeit +item.ebwizardry\:ring_seeking.name=Ring der Anziehung +item.ebwizardry\:ring_seeking.desc=Alle Projektile verfolgen das Ziel +item.ebwizardry\:ring_hammer.name=Ring von Thalek dem Allmächtigen +item.ebwizardry\:ring_hammer.desc=Blitzhammer können aufgehoben und geworfen werden +item.ebwizardry\:ring_soulbinding.name=Ring der Seelenwanderer +item.ebwizardry\:ring_soulbinding.desc=Kreaturen die du mit verbotenen Künsten angreifst sind an dich Seelengebunden +item.ebwizardry\:ring_leeching.name=Ring des Blutsaugers +item.ebwizardry\:ring_leeching.desc=Alle Zauber der verbotenen Kunst haben eine 30%% chance, Leben zu absorbieren +item.ebwizardry\:ring_necromancy_melee.name=Ring der verbotenen Berührung +item.ebwizardry\:ring_necromancy_melee.desc=Schlae eine Kreatur mit dem Zauberstab, um sie zu verdorren +item.ebwizardry\:ring_mind_control.name=Ring der Massenpsyche +item.ebwizardry\:ring_mind_control.desc=Kreaturen unter Gedankenkontrolle haben die chance, andere Kreaturen in der Umgebung auch damit anzustecken +item.ebwizardry\:ring_poison.name=Ring der Giftschlange +item.ebwizardry\:ring_poison.desc=Alle Erdgebundenen-Zauber vergiften das Ziel zusätzlich +item.ebwizardry\:ring_earth_melee.name=Ring der giftigen Berührung +item.ebwizardry\:ring_earth_melee.desc=Schlage eine Kreatur um sie zu vergiften +item.ebwizardry\:ring_earth_biome.name=Ring des Dyraden +item.ebwizardry\:ring_earth_biome.desc=Erdgebundenenzauber sind 30%% wirkungsvoller in Wäldern +item.ebwizardry\:ring_full_moon.name=Ring des heulenden Wolfs +item.ebwizardry\:ring_full_moon.desc=Bei Vollmond haben Erdgebundenenzauber stark reduzierte Abklingzeiten +item.ebwizardry\:ring_extraction.name=Ring der Extraktion +item.ebwizardry\:ring_extraction.desc=Das Töten von Kreaturen mit mystischen Zaubern extrahiert mehr Mana +item.ebwizardry\:ring_mana_return.name=Ring des Perfektionisten +item.ebwizardry\:ring_mana_return.desc=Gibt das Mana von Pfeilen wieder in den Stab zurück, falls das Ziel nicht getroffen wird +item.ebwizardry\:ring_blockwrangler.name=Ring der kräftigen Blöcke +item.ebwizardry\:ring_blockwrangler.desc=Geworfene Blöcke verursachen viel mehr Schaden +item.ebwizardry\:ring_conjurer.name=Ring des Beschwörers +item.ebwizardry\:ring_conjurer.desc=Beschworene Gegenstände halten doppelt so lang +item.ebwizardry\:ring_defender.name=Ring des Schützenden +item.ebwizardry\:ring_defender.desc=Deine Projektile fliegen durch die Kraftfelder verbündeter hindurch +item.ebwizardry\:ring_paladin.name=Ring des Paladin +item.ebwizardry\:ring_paladin.desc=Wenn du dich selbst oder andere heilst, heilen sich alle in der Nähe auch ein bischen +item.ebwizardry\:ring_interdiction.name=Ring der blutenden Versuchung +item.ebwizardry\:ring_interdiction.desc=Dein Kraftfeld verletzt Kreaturen die es Berühren + +item.ebwizardry\:amulet_arcane_defence.name=Amulett der arkarnen Verteidigung +item.ebwizardry\:amulet_arcane_defence.desc=Regeneriert das Mana der Magier-Rüstung langsarm +item.ebwizardry\:amulet_warding.name=Amulett des Schildes +item.ebwizardry\:amulet_warding.desc=Reduziert allen magischen Schaden um 10%% +item.ebwizardry\:amulet_wisdom.name=Amulett der Weisheit +item.ebwizardry\:amulet_wisdom.desc=Verringert die chance auf negative Effekte beim aufdecken neuer Zauber drastisch +item.ebwizardry\:amulet_fire_protection.name=Amulett der gezähmten Flammen +item.ebwizardry\:amulet_fire_protection.desc=Reduziert Feuerschaden den du bekommst um 30%% +item.ebwizardry\:amulet_fire_cloaking.name=Amulett des Flammenmantels +item.ebwizardry\:amulet_fire_cloaking.desc=Reduziert 75%% des Schadens den du erhälst, während du in einem Feuerring stehst, der dir oder einem Verbündeten gehört +item.ebwizardry\:amulet_ice_immunity.name=Amulett des unendlichen Eises +item.ebwizardry\:amulet_ice_immunity.desc=Vollständige Immunität gegen Frostbiss +item.ebwizardry\:amulet_ice_protection.name=Amulett des Eisgebundenen +item.ebwizardry\:amulet_ice_protection.desc=Reduziert Frostschaden den du bekommst um 30%% +item.ebwizardry\:amulet_potential.name=Amulett der Ausgleichsspannung +item.ebwizardry\:amulet_potential.desc=Gibt eine 15%% chance einen Blitz auf eine dich angreifende Kreatur zu schießen +item.ebwizardry\:amulet_channeling.name=Amulett der Erdung +item.ebwizardry\:amulet_channeling.desc=Gewährt eine 30%% Chance, eingehende Schockschäden zu negieren +item.ebwizardry\:amulet_lich.name=Amulett des Lichs +item.ebwizardry\:amulet_lich.desc=Gewährt eine 15%% Chance, dass der eingehende Schaden auf eine andere Kreatur in der nähe geht +item.ebwizardry\:amulet_wither_immunity.name=Amulett der Verdorrenden Perlen +item.ebwizardry\:amulet_wither_immunity.desc=Vollständige Immunität gegen Withereffekte +item.ebwizardry\:amulet_glide.name=Amulett der gewürfelten Feder +item.ebwizardry\:amulet_glide.desc=Weiter als 3 Blöcke zu fallen gibt eine 50%% Chance auf einen Gleit-Effekt +item.ebwizardry\:amulet_banishing.name=Amulett des Endgebundenen +item.ebwizardry\:amulet_banishing.desc=Kreaturen die dich angreifen haben eine 15%% Chance sich zufällig in die nähe von dir zu teleportieren +item.ebwizardry\:amulet_anchoring.name=Amulett des magischen Ankers +item.ebwizardry\:amulet_anchoring.desc=Gewährt Immunität gegen Zauber die dich wegstoßen +item.ebwizardry\:amulet_recovery.name=Amulett der Lebenswiederherstellung +item.ebwizardry\:amulet_recovery.desc=Wenn du weniger als die Hälfte deiner Leben hast, regenerierst du deine Leben durch Mana deiner Magier-Rüstung langsarm wieder +item.ebwizardry\:amulet_transience.name=Amulett der Vergänglichkeit +item.ebwizardry\:amulet_transience.desc=Gewährt eine 25%% Chance, die Vergangenheit hervorzurufen, wenn es sich um eine kritische Verletzung handelt +item.ebwizardry\:amulet_resurrection.name=Amulett des Unsterblichen +item.ebwizardry\:amulet_resurrection.desc=Der Totenbeschwören - Zauber kann von jenseits des Grabes an einem selbst angewendet werden +item.ebwizardry\:amulet_auto_shield.name=Amulett von Hyeleth +item.ebwizardry\:amulet_auto_shield.desc=Gewährt eine 25%% Chance, den Schild-Zauber für einige Sekunden auszulösen, wenn er an einen Zauberstab an Ihrem Hotbar gebunden ist + +item.ebwizardry\:charm_haggler.name=Zeichen des Wortgewandten +item.ebwizardry\:charm_haggler.desc=Die Zauberer bieten garantiert jedes Mal ein neues Angebot an, wenn du mit ihnen handelst +item.ebwizardry\:charm_experience_tome.name=Leitfaden des Fleißigen +item.ebwizardry\:charm_experience_tome.desc=Erhöht die Geschwindigkeit, mit der Zauberstäbe Fortschritte erlangen, um 50%% +item.ebwizardry\:charm_auto_smelt.name=Das Zeichen des Metallurgen +item.ebwizardry\:charm_auto_smelt.desc=Der Taschenofen löst sich automatisch aus, wenn er an einen Stab auf Ihrem Hotbar gebunden wird +item.ebwizardry\:charm_lava_walking.name=Eisiges Nether-Herz +item.ebwizardry\:charm_lava_walking.desc=Schritte erstarren Lava zu einer Obsidiankruste +item.ebwizardry\:charm_storm.name=Gewitterwolke in der Flasche +item.ebwizardry\:charm_storm.desc=Beschwört einen aufziehenden Sturm +item.ebwizardry\:charm_minion_health.name=Zombiekopf aus Obsidian +item.ebwizardry\:charm_minion_health.desc=Beschwörungen sind 25%% stärker +item.ebwizardry\:charm_minion_variants.name=Talisman der Transformation +item.ebwizardry\:charm_minion_variants.desc=Beschworene Zombies und Skelette werden zu einer stärkeren Variante +item.ebwizardry\:charm_flight.name=Käferflügel aus Smaragt +item.ebwizardry\:charm_flight.desc=Fliegen und Gleiten sind um 50%% schneller +item.ebwizardry\:charm_growth.name=Neid der Kristallblume +item.ebwizardry\:charm_growth.desc=Die Wachstumsaura hat eine 35%% Chance, dass die Pflanzen sofort ausgewachsen sind +item.ebwizardry\:charm_abseiling.name=Verzaubertes Seil +item.ebwizardry\:charm_abseiling.desc=Drücke Shift während des Greifens um das Seil langsarm auszufahren +item.ebwizardry\:charm_silk_touch.name=Mondsteinkugel +item.ebwizardry\:charm_silk_touch.desc=Blöcke, die mit dem Minenzauber abgebaut werden, werden Behutsam als sich selbst gedroppt +item.ebwizardry\:charm_stop_time.name=Seltsame Taschenuhr +item.ebwizardry\:charm_stop_time.desc=Der Zauber "Zeit Verlangsamen" lässt die Zeit stillstehen +item.ebwizardry\:charm_light.name=Der immerbrennende Stern von Elevinia +item.ebwizardry\:charm_light.desc=Beschworene Lichtquellen bleiben für immer und können mit einem Rechtsklick mit dem Stab entfehrnt werden +item.ebwizardry\:charm_transportation.name=Antiker Kompass +item.ebwizardry\:charm_transportation.desc=Bis zu vier Steinkreise können bei der Benutzung von Steinen der Teleportation gespeichert und ausgewählt werden +item.ebwizardry\:charm_feeding.name=Bodenlose Vorräte +item.ebwizardry\:charm_feeding.desc=Hunger wiederherstellen wird sofort gewirkt, wenn der Stab sich mit dem Zauber in der Hotbar befindet + +item.charge_status.full=Voll +item.charge_status.almost_full=Fast Voll +item.charge_status.mostly_full=Größtenteils Voll +item.charge_status.half_full=Halb Voll +item.charge_status.mostly_empty=Bald Leer +item.charge_status.almost_empty=Fast Leer +item.charge_status.empty=Leer + +entity.ebwizardry\:summonedcreature.nameplate=%1$s von %2$s +entity.ebwizardry\:summonedcreature.nameplate_fallback=Erscheinung von %1$s + +entity.ebwizardry\:wizard.greeting_0=Guten Tag, Weggefährte. +entity.ebwizardry\:wizard.greeting_1=Sei gegrüßt, Reisender. Was führt dich hierher? +entity.ebwizardry\:wizard.greeting_2=Ah, schön hier eine Person zu sehen. +entity.ebwizardry\:wizard.speech_0=Dürfte ich dich vielleicht für ein paar Zaubersprüche interessieren? +entity.ebwizardry\:wizard.speech_1=Magie ist überall, wenn man weiß, wo man suchen muss. +entity.ebwizardry\:wizard.speech_2=Es gibt für uns alle noch viel über die arkanen Künste zu lernen, Abenteurer. +entity.ebwizardry\:wizard.speech_3=Vielleicht hast du etwas gelernt, das du teilen möchten? +entity.ebwizardry\:wizard.speech_4=Arkane Künste zu studieren ist sehr faszinierend, findest du nicht auch? +entity.ebwizardry\:wizard.farewell_0=Viel Glück auf deiner Suche, Abenteurer. +entity.ebwizardry\:wizard.farewell_1=Ich vertraue darauf, dass wir uns bald wieder sehen werden, mein Freund. +entity.ebwizardry\:wizard.farewell_2=Dann auf Wiedersehen, Reisender. +entity.ebwizardry\:wizard.combat_0=Verschwindet, ihr widerlichen Kreaturen! +entity.ebwizardry\:wizard.combat_1=Lasst mich in Ruhe, ihr Schädlinge! +entity.ebwizardry\:wizard.combat_2=Untote Wesen sind hier nicht willkommen, husch! +entity.ebwizardry\:wizard.combat_3=Away with you, creatures of darkness! +entity.ebwizardry\:wizard.combat_4=Fort mit euch, Geschöpfe der Finsternis! +entity.ebwizardry\:wizard.combat_5=Kehrt in die Höhlen zurück, aus denen ihr gekommen seid, böse Kreaturen! +entity.ebwizardry\:wizard.player_combat_0=Du wirst diese Entscheidung bereuen, Reisender! +entity.ebwizardry\:wizard.player_combat_1=Was glaubst du, was du da tust?! +entity.ebwizardry\:wizard.player_combat_2=Nur ein Narr wagt es, einen Zauberer zu verärgern! +entity.ebwizardry\:wizard.player_combat_3=Du wirst für deine Unachtsamkeit bezahlen, Abenteurer! +entity.ebwizardry\:wizard.player_combat_4=Sei bereit, dich zu verteidigen, Feind! +entity.ebwizardry\:wizard.player_combat_5=Bereite dich darauf vor, meinen Zorn zu spüren! + +entity.ebwizardry\:zombie_minion.name=Zombie +entity.ebwizardry\:husk_minion.name=Wüstenzombie +entity.ebwizardry\:skeleton_minion.name=Skeleton +entity.ebwizardry\:stray_minion.name=Eiswanderer +entity.ebwizardry\:spider_minion.name=Spinne +entity.ebwizardry\:blaze_minion.name=Lohe +entity.ebwizardry\:wither_skeleton_minion.name=Witherskelett +entity.ebwizardry\:ice_wraith.name=Eis-Geist +entity.ebwizardry\:lightning_wraith.name=Donner-Geist +entity.ebwizardry\:shadow_wraith.name=Verbotener-Geist +entity.ebwizardry\:spirit_wolf.name=Geisterwolf +entity.ebwizardry\:spirit_horse.name=Gersterpferd +entity.ebwizardry\:ice_giant.name=Eis-Gigant +entity.ebwizardry\:phoenix.name=Phönix +entity.ebwizardry\:wizard.name=Zauberer +entity.ebwizardry\:magic_slime.name=Magischer Schleim +entity.ebwizardry\:silverfish_minion.name=Silberfischchen +entity.ebwizardry\:storm_elemental.name=Sturm-Elementar +entity.ebwizardry\:evil_wizard.name=Zauberer +entity.ebwizardry\:decoy.name=Trugbild +entity.ebwizardry\:vex_minion.name=Vex + +entity.ebwizardry\:magic_missile.name=Magie +entity.ebwizardry\:arc.name=Magie +entity.ebwizardry\:spark_bomb.name=Magie +entity.ebwizardry\:ice_shard.name=Magie +entity.ebwizardry\:firebomb.name=Magie +entity.ebwizardry\:poison_bomb.name=Magie +entity.ebwizardry\:force_orb.name=Magie +entity.ebwizardry\:spark.name=Magie +entity.ebwizardry\:darkness_orb.name=Magie +entity.ebwizardry\:fire_sigil.name=Magie +entity.ebwizardry\:frost_sigil.name=Magie +entity.ebwizardry\:lightning_sigil.name=Magie +entity.ebwizardry\:lightning_arrow.name=Magie +entity.ebwizardry\:firebolt.name=Magie +entity.ebwizardry\:ice_charge.name=Magie +entity.ebwizardry\:force_arrow.name=Magie +entity.ebwizardry\:dart.name=Magie +entity.ebwizardry\:lightning_disc.name=Magie +entity.ebwizardry\:thunderbolt.name=Magie +entity.ebwizardry\:decay.name=Magie +entity.ebwizardry\:ice_lance.name=Magie +entity.ebwizardry\:smoke_bomb.name=Magie +entity.ebwizardry\:ice_spike.name=Magie +entity.ebwizardry\:combustion_rune.name=Magie + +entity.ebwizardry\:black_hole.name=Schwarzes Loch +entity.ebwizardry\:shield.name=Schild +entity.ebwizardry\:meteor.name=Meteor +entity.ebwizardry\:blizzard.name=Froststurm +entity.ebwizardry\:bubble.name=Luftblase +entity.ebwizardry\:tornado.name=Tornado +entity.ebwizardry\:lightning_hammer.name=Blitzhammer +entity.ebwizardry\:arrow_rain.name=Pfeilhagel +entity.ebwizardry\:healing_aura.name=Heilende Aura +entity.ebwizardry\:forcefield.name=Kraftfeld +entity.ebwizardry\:ring_of_fire.name=Feuerring +entity.ebwizardry\:earthquake.name=Erdbeben +entity.ebwizardry\:hailstorm.name=Hagelsturm +entity.ebwizardry\:lightning_pulse.name=Schockimpuls + +itemGroup.ebwizardry=Zauberei +itemGroup.ebwizardryspells=Zauber +itemGroup.ebwizardrygear=Magie-Ausrüstung + +advancement.ebwizardry\:root=Zauberei +advancement.ebwizardry\:root.desc=Die Reise eines Zauberers zur Beherrschung des Arkanen +advancement.ebwizardry\:crystal=Ein seltsamer Kristall... +advancement.ebwizardry\:crystal.desc=Baue einen magischen Kristall ab +advancement.ebwizardry\:arcane_initiate=Arkaner Eingeweihter +advancement.ebwizardry\:arcane_initiate.desc=Fertigen Sie einen Zauberstab mit einem Goldnugget, einem Stock und einem magischen Kristall + +advancement.ebwizardry\:apprentice=Zauberlehrling +advancement.ebwizardry\:apprentice.desc=Nutze einen Leitfaden des Arkanen um deinen Stab aufzuwerten +advancement.ebwizardry\:special_upgrade=Arkarnes Zauberhandwerk +advancement.ebwizardry\:special_upgrade.desc=Wende eine Aufwertung auf einen Stab an +advancement.ebwizardry\:advanced=Fortschrittliches Zauberhandwerk +advancement.ebwizardry\:advanced.desc=Werte einen Stab zu einem hohen Stab auf +advancement.ebwizardry\:master=Arkarner Meister +advancement.ebwizardry\:master.desc=Beschaffe einen Meisterzauberstab +advancement.ebwizardry\:max_out_wand=Voll Ausgerüstet +advancement.ebwizardry\:max_out_wand.desc=Stoße an die Grenze von Aufwertungen auf einen Stab +advancement.ebwizardry\:all_spells=Ein Magier für aller Art +advancement.ebwizardry\:all_spells.desc=Jeden einzelnen Zauberspruch im Spiel nutzen + +advancement.ebwizardry\:wizard_tower=Wer wohnt hier? +advancement.ebwizardry\:wizard_tower.desc=Besuche einen Magierturm +advancement.ebwizardry\:wizard_trade=Magischer Handel +advancement.ebwizardry\:wizard_trade.desc=Kaufe ein Angebot eines Zauberers +advancement.ebwizardry\:anger_wizard=Du wirst es bereuen +advancement.ebwizardry\:anger_wizard.desc=Mache einen Magier zornig +advancement.ebwizardry\:defeat_evil_wizard=Rechtschaffend +advancement.ebwizardry\:defeat_evil_wizard.desc=Bezwinge einen bösen Magier +advancement.ebwizardry\:buy_master_spell=Wissen ist Macht +advancement.ebwizardry\:buy_master_spell.desc=Kaufe einen Zauber von einem Magier + +advancement.ebwizardry\:discover_spell=So lange bis es klappt +advancement.ebwizardry\:discover_spell.desc=Enthülle einen unbekannten Zauberspruch, indem du ihn wirkst und siehst, was passiert +advancement.ebwizardry\:identify_spell=Arkane Wertschätzung +advancement.ebwizardry\:identify_spell.desc=Finden Sie eine zuverlässigere Methode zur Definition von Zaubersprüchen +advancement.ebwizardry\:spell_failure=Das ist nach hinten losgegangen +advancement.ebwizardry\:spell_failure.desc=Finde auf die harte Tour heraus, wie Zaubersprüche schief gehen können +advancement.ebwizardry\:discover_master_spell=Die Gefahr auswürfeln +advancement.ebwizardry\:discover_master_spell.desc=Erfolgreiche enthüllung eines Meisterzaubers durch probieren + +advancement.ebwizardry\:visit_shrine=Erweckt +advancement.ebwizardry\:visit_shrine.desc=Betreten Sie einen Schrein und erwecken Sie seine alte Magie +advancement.ebwizardry\:artefact=Ein vergessenes Relikt +advancement.ebwizardry\:artefact.desc=Heben Sie die schützenden Verzauberungen von einem Schrein auf und beanspruchen Sie die Schätze darin +advancement.ebwizardry\:all_artefacts=Ein wahres Museum +advancement.ebwizardry\:all_artefacts.desc=Sammeln Sie alle Ringe, Amulette und Talismane + +advancement.ebwizardry\:armour_set=Jetzt bist du ein wahrer Magier! +advancement.ebwizardry\:armour_set.desc=Fertigen und rüsten Sie einen vollständigen Satz Zauberer-Rüstungen! +advancement.ebwizardry\:legendary=Legendär! +advancement.ebwizardry\:legendary.desc=Erhalten Sie ein Stück der legendären Zauberer-Rüstung + +advancement.ebwizardry\:enchant_scroll=Abpausen auf Pergament +advancement.ebwizardry\:enchant_scroll.desc=Fertigen Sie eine leere Schriftrolle an und verzaubern Sie sie mit einem Zauberspruch an einer arkanen Werkbank + +handbook.toast.title=Neuer Abschnitt des Handbuchs freigeschaltet! + +container.ebwizardry\:arcane_workbench=Arkane Werkbank +container.ebwizardry\:arcane_workbench.apply=Fertigen +container.ebwizardry\:arcane_workbench.mana=Mana\: +container.ebwizardry\:arcane_workbench.upgrades=Bestehende Aufwertungen\: + +tier.novice=Novize +tier.apprentice=Lehrling +tier.advanced=Höherer +tier.master=Meister + +element.magic=Keines +element.fire=Feuer +element.ice=Eis +element.lightning=Blitz +element.necromancy=Verboten +element.earth=Erdgebunden +element.sorcery=Mystisch +element.healing=Heilend + +element.magic.wizard=Zauberer +element.fire.wizard=Pyromant +element.ice.wizard=Eismagier +element.lightning.wizard=Blitzmagier +element.necromancy.wizard=Magier des Verbotenen +element.earth.wizard=Erdgebundener Magier +element.sorcery.wizard=Mystischer Magier +element.healing.wizard=Heiler + +spelltype.attack=Offensiv +spelltype.defence=Deffensiv +spelltype.utility=Werkzeug +spelltype.minion=Erscheinung +spelltype.buff=Effekt +spelltype.construct=Gebilde +spelltype.projectile=Projektil +spelltype.alteration=Veränderung + +spell.disabled=%1$s wurde in der Konfiguration deaktiviert +spell.resist=%1$s hat %2$s wiederstanden! +spell.discover=Zauber %1$s enthüllt! + +spell.ebwizardry\:agility=Beweglichkeit +spell.ebwizardry\:arc=Lichtbogen +spell.ebwizardry\:arcane_jammer=Magie Unterdrücken +spell.ebwizardry\:arcane_lock=Arkarnes Schloss +spell.ebwizardry\:arrow_rain=Pfeilhagel +spell.ebwizardry\:banish=Bannen +spell.ebwizardry\:black_hole=Schwarzes Loch +spell.ebwizardry\:blink=Augenzwinker +spell.ebwizardry\:blizzard=Eissturm +spell.ebwizardry\:bubble=Luftblase +spell.ebwizardry\:chain_lightning=Kettenblitz +spell.ebwizardry\:charge=Statisch Voranstürmen +spell.ebwizardry\:clairvoyance=Echo der Vergangenheit +spell.ebwizardry\:cobwebs=Spinnenweben +spell.ebwizardry\:combustion_rune=Flammende Rune +spell.ebwizardry\:conjure_armour=Rüstung Beschwören +spell.ebwizardry\:conjure_block=Block Beschwören +spell.ebwizardry\:conjure_bow=Bogen Beschwören +spell.ebwizardry\:conjure_pickaxe=Spitzhacke Beschwören +spell.ebwizardry\:conjure_sword=Schwert Beschwören +spell.ebwizardry\:containment=Bewahrung +spell.ebwizardry\:cure_effects=Reinigung der Effekte +spell.ebwizardry\:curse_of_enfeeblement=Fluch der Entkräftung +spell.ebwizardry\:curse_of_soulbinding=Fluch des Seelengebundenen +spell.ebwizardry\:curse_of_undeath=Fluch der Untoten +spell.ebwizardry\:darkness_orb=Sphere des Verbotenen +spell.ebwizardry\:darkvision=Nachtsicht +spell.ebwizardry\:dart=Dart +spell.ebwizardry\:decay=Verderben +spell.ebwizardry\:decoy=Trugbild +spell.ebwizardry\:detonate=Explosion +spell.ebwizardry\:diamondflesh=Diamanthaut +spell.ebwizardry\:disintegration=Auflösung +spell.ebwizardry\:divination=Vorahnung +spell.ebwizardry\:dragon_fireball=Drachenfeuerball +spell.ebwizardry\:earthquake=Erdbeben +spell.ebwizardry\:empowering_presence=Magisch-Ermächtigende Präsenz +spell.ebwizardry\:entrapment=Sphere des verbotenen Aufstiegs +spell.ebwizardry\:evade=Umgehen +spell.ebwizardry\:fireball=Feuerball +spell.ebwizardry\:firebolt=Feuerbolzen +spell.ebwizardry\:firebomb=Feuerbombe +spell.ebwizardry\:fire_resistance=Feuerresistenz +spell.ebwizardry\:fire_sigil=Feuriges Siegel +spell.ebwizardry\:fireskin=Feuerhaut +spell.ebwizardry\:fire_breath=Flammender Atem +spell.ebwizardry\:flame_ray=Flammenstrahl +spell.ebwizardry\:flaming_axe=Brennende Axt +spell.ebwizardry\:flaming_weapon=Brennende Waffe +spell.ebwizardry\:flight=Fliegen +spell.ebwizardry\:font_of_mana=Das Wesen des Mana +spell.ebwizardry\:font_of_vitality=Das Wesen der Vitalität +spell.ebwizardry\:force_arrow=Kraftfeldpfeil +spell.ebwizardry\:forcefield=Kraftfeld +spell.ebwizardry\:force_orb=Kraftfeldkugel +spell.ebwizardry\:forests_curse=Wälderfluch +spell.ebwizardry\:forest_of_thorns=Wald aus Dornen +spell.ebwizardry\:freeze=Erfrieren +spell.ebwizardry\:freezing_weapon=Eisige Waffe +spell.ebwizardry\:frost_axe=Eisige Axt +spell.ebwizardry\:frost_ray=Eisstrahl +spell.ebwizardry\:frost_sigil=Eisiges Siegel +spell.ebwizardry\:frost_step=Frostschritte +spell.ebwizardry\:glide=Gleiten +spell.ebwizardry\:grapple=Kletterrankengreifhaken +spell.ebwizardry\:greater_fireball=Größerer Feuerball +spell.ebwizardry\:greater_heal=Große Heilung +spell.ebwizardry\:greater_telekinesis=Mächtige Telekinese +spell.ebwizardry\:greater_ward=Mächtiges Kraftschild +spell.ebwizardry\:group_heal=Gruppenheilung +spell.ebwizardry\:growth_aura=Wachstumsaura +spell.ebwizardry\:hailstorm=Hagelsturm +spell.ebwizardry\:heal=Heilen +spell.ebwizardry\:heal_ally=Verbündeten Heilen +spell.ebwizardry\:healing_aura=Heilende Aura +spell.ebwizardry\:homing_spark=Zielender Funke +spell.ebwizardry\:iceball=Eisball +spell.ebwizardry\:ice_age=Eiszeit +spell.ebwizardry\:ice_charge=Aufgeladenes Eis +spell.ebwizardry\:ice_lance=Eis Lanze +spell.ebwizardry\:ice_shard=Eis Splitter +spell.ebwizardry\:ice_shroud=Eisige Haut +spell.ebwizardry\:ice_spikes=Eisstachel +spell.ebwizardry\:ice_statue=Eisblock +spell.ebwizardry\:ignite=Entzünden +spell.ebwizardry\:imbue_weapon=Perfekter Schliff der Waffe +spell.ebwizardry\:intimidate=Einschüchtern +spell.ebwizardry\:invigorating_presence=Ermächtigende Präsenz +spell.ebwizardry\:invisibility=Unsichtbarkeit +spell.ebwizardry\:invoke_weather=Sturm Heraufziehen +spell.ebwizardry\:ironflesh=Eisenhaut +spell.ebwizardry\:leap=Sprung +spell.ebwizardry\:levitation=Aufsteigende Winde +spell.ebwizardry\:life_drain=Blut Saugen +spell.ebwizardry\:light=Lichtkugel +spell.ebwizardry\:lightning_arrow=Blitzpfeil +spell.ebwizardry\:lightning_bolt=Blitzeinschlag +spell.ebwizardry\:lightning_disc=Lichtscheibe +spell.ebwizardry\:lightning_hammer=Blitzhammer +spell.ebwizardry\:lightning_pulse=Blitzimpuls +spell.ebwizardry\:lightning_ray=Lichtbogenstrahl +spell.ebwizardry\:lightning_sigil=Zappendes Siegel +spell.ebwizardry\:lightning_web=Blitzvernetzung +spell.ebwizardry\:magic_missile=Magisches Geschoss +spell.ebwizardry\:metamorphosis=Metamorphose +spell.ebwizardry\:meteor=Meteor +spell.ebwizardry\:mind_control=Gedankenkontrolle +spell.ebwizardry\:mind_trick=Gedanken-Nebel +spell.ebwizardry\:mine=Zerbrechlichkeit von Materie +spell.ebwizardry\:muffle=Leise Schritte +spell.ebwizardry\:none=[Leerer Platz] +spell.ebwizardry\:oakflesh=Eichenhaut +spell.ebwizardry\:paralysis=Lähmung +spell.ebwizardry\:petrify=Versteinern +spell.ebwizardry\:phase_step=Geister-Gänge +spell.ebwizardry\:plague_of_darkness=Pest der Dunkelheit +spell.ebwizardry\:pocket_furnace=Taschenofen +spell.ebwizardry\:pocket_workbench=Taschenwerkbank +spell.ebwizardry\:poison=Gift +spell.ebwizardry\:poison_bomb=Giftbombe +spell.ebwizardry\:possession=Besitz +spell.ebwizardry\:ray_of_purification=Strahl der Läuterung +spell.ebwizardry\:remove_curse=Fluch entfernen +spell.ebwizardry\:replenish_hunger=Kleinen Hunger stillen +spell.ebwizardry\:resurrection=Wiederbelebung +spell.ebwizardry\:reversal=Umkehrung +spell.ebwizardry\:ring_of_fire=Feuerring +spell.ebwizardry\:satiety=Sättigung +spell.ebwizardry\:shadow_ward=Verbotener Schild-Zauber +spell.ebwizardry\:shield=Schild-Zauber +spell.ebwizardry\:shockwave=Schockwelle +spell.ebwizardry\:shulker_bullet=Shulker-Schuss +spell.ebwizardry\:silverfish_swarm=Silberfisch-Schwarm +spell.ebwizardry\:sixth_sense=Sechster Sinn +spell.ebwizardry\:slime=Schleim +spell.ebwizardry\:slow_time=Zeit Verlangsamen +spell.ebwizardry\:smoke_bomb=Rauchbombe +spell.ebwizardry\:snare=Anwurzeln +spell.ebwizardry\:snowball=Schneeball +spell.ebwizardry\:spark_bomb=Blitzbombe +spell.ebwizardry\:spectral_pathway=Spektraler Pfad +spell.ebwizardry\:speed_time=Zeit verschnellern +spell.ebwizardry\:spider_swarm=Spinnen-Schwarm +spell.ebwizardry\:static_aura=Statisch geladene Aura +spell.ebwizardry\:summon_blaze=Beschwöre Lohe +spell.ebwizardry\:summon_ice_giant=Beschwöre Eis-Gigant +spell.ebwizardry\:summon_ice_wraith=Beschwöre Eis-Geist +spell.ebwizardry\:summon_iron_golem=Beschwöre Eisen Golem +spell.ebwizardry\:summon_lightning_wraith=Beschwöre Blitz-Geist +spell.ebwizardry\:summon_phoenix=Beschwöre Phönix +spell.ebwizardry\:summon_shadow_wraith=Beschwöre Verbotenen-Geist +spell.ebwizardry\:summon_skeleton=Beschwöre Skelett +spell.ebwizardry\:summon_skeleton_legion=Beschwöre Skelett-Legion +spell.ebwizardry\:summon_snow_golem=Beschwöre Schneemann +spell.ebwizardry\:summon_spirit_horse=Beschwöre Gersterpferd +spell.ebwizardry\:summon_spirit_wolf=Beschwöre Geisterwolf +spell.ebwizardry\:summon_storm_elemental=Beschwöre Sturm-Elementar +spell.ebwizardry\:summon_wither_skeleton=Beschwöre Witherskelett +spell.ebwizardry\:summon_zombie=Beschwöre Zombie +spell.ebwizardry\:telekinesis=Telekinese +spell.ebwizardry\:thunderbolt=Blitzeinschlag +spell.ebwizardry\:thunderstorm=Mächtige Blitz-Adern +spell.ebwizardry\:tornado=Tornado +spell.ebwizardry\:transience=Vergangenheit +spell.ebwizardry\:transportation=Transportation +spell.ebwizardry\:vanishing_box=Fluktuirender Endspeicher +spell.ebwizardry\:vex_swarm=Vex Schwarm +spell.ebwizardry\:wall_of_frost=Wand des Eises +spell.ebwizardry\:ward=Schutz +spell.ebwizardry\:water_breathing=Wasseratmung +spell.ebwizardry\:whirlwind=Wirbelwind +spell.ebwizardry\:wither=Wither +spell.ebwizardry\:wither_skull=Wither Schädel + +spell.ebwizardry\:agility.desc=Gewährt dem Magier eine höhere Bewegungsgeschwindigkeit und eine größere Sprunghöhe für 30 Sekunden. +spell.ebwizardry\:arc.desc=Feuert einen Blitzfunken auf das Ziel ab. +spell.ebwizardry\:arcane_jammer.desc=Verhindert, dass das Ziel 15 Sekunden lang Magie benutzt. +spell.ebwizardry\:arcane_lock.desc=Erzeugt eine undurchdringliche Kraftbarriere um einen Behälter, die ihn vor dem Öffnen oder der Zerstörung schützt. Der Magier und seine Verbündeten können ihn jedoch immer noch öffnen. +spell.ebwizardry\:arrow_rain.desc="Schützen, Feuert!" +spell.ebwizardry\:banish.desc=Teleportiert das Ziel gegen seinen Willen an einen zufälligen Ort innerhalb einer bestimmten Reichweite. +spell.ebwizardry\:black_hole.desc=Zerreißen Sie die Realität. +spell.ebwizardry\:blink.desc=Teleportiert den Magier über eine kurze Distanz dorthin, wohin er gerade zeigt. +spell.ebwizardry\:blizzard.desc=Schafft eine Zone mit wirbelndem eisigen Wind, der alles, was sich darin verfängt, verlangsamt und ständig beschädigt. Der Magier ist gegen den Schaden immun, wird aber dennoch verlangsamt. +spell.ebwizardry\:bubble.desc=Feuert einen Blasenstrahl ab, der alles, was er trifft, hilflos nach oben schweben lässt. Das Ziel fällt nach einer bestimmten Zeit oder wenn es beschädigt ist. +spell.ebwizardry\:chain_lightning.desc=Feuert einen Blitzfunken auf das Ziel ab, das sich dann bis zu zweimal an weitere Ziele kettet. +spell.ebwizardry\:charge.desc=Veranlasst den Magier, schnell in die Richtung geschleudert, in die er schaut, wobei er alles, was sich ihm in den Weg stellt, beschädigt und zurückwirft. +spell.ebwizardry\:clairvoyance.desc=Enthüllt den Weg zu einem gespeicherten Ort. Wenn dieser Zauberspruch ausgewählt ist, klicken Sie mit der rechten Maustaste auf einen Block, um den Ort festzulegen. Sprechen Sie diesen Zauber normal, um den Pfad aufzudecken. Der Pfad wird nach 90 Sekunden verblassen. +spell.ebwizardry\:cobwebs.desc=Erzeugt Spinnennetze, auf die Sie zeigen, die die Bewegung der Kreaturen, die sich unter ihnen befinden, stark behindern. Die Spinnennetze verschwinden nach 20 Sekunden oder wenn sie gebrochen sind. +spell.ebwizardry\:combustion_rune.desc=Platziert eine magische Landmine auf dem Boden, auf den Sie zeigen, die beim Betreten explodiert. +spell.ebwizardry\:conjure_armour.desc=Erzeugt eine spektrale Rüstung um den Zaubernden, die den gleichen Schutz wie eine eiserne Rüstung bietet. Die Panzerung hält 60 Sekunden lang an. Der Zaubernde darf keine Rüstung anhaben. +spell.ebwizardry\:conjure_block.desc=Beschwört einen spektralen Block, auf den Ihr zeigt. Der Spektralblock verschwindet nach 45 Sekunden, oder man kann ihn durch erneutes Zaubern mit diesem Zauberspruch aufheben. +spell.ebwizardry\:conjure_bow.desc=Erstellt einen Spektralbogen mit unbegrenzten Pfeilen, der 30 Sekunden lang hält. +spell.ebwizardry\:conjure_pickaxe.desc=Erstellt eine Spektralspitzhacke von gleicher Stärke wie eine Eisenspitzhacke, die 30 Sekunden lang hält. +spell.ebwizardry\:conjure_sword.desc=Erstellt ein Spektralschwert von gleicher Stärke wie ein Eisenschwert, das 30 Sekunden lang hält. +spell.ebwizardry\:containment.desc=Wurzelt das Ziel für 20 Sekunden an. +spell.ebwizardry\:cure_effects.desc=Entfernt alle Effekte, die den Zaubernden derzeit beeinflussen, ob gut oder schlecht. +spell.ebwizardry\:curse_of_enfeeblement.desc="Er war plötzlich geschwächt, als ob ihm das Leben aus seinem Inneren gerissen worden wäre. - Zeugnis der einzigen Person, von der bekannt ist, dass sie einem Mitglied des Seelenwandererkults begegnet ist und überlebt hat. +spell.ebwizardry\:curse_of_soulbinding.desc=Verursacht, dass die Seele des Ziels untrennbar mit der des Magiers verbunden ist, was bedeutet, dass der gesamte dem Magier zugefügte Schaden auch dem Opfer zugefügt wird. Dauert so lange, bis entweder das Opfer oder der Magier stirbt. +spell.ebwizardry\:curse_of_undeath.desc=Verflucht das Ziel mit Untotsein, was dazu führt, dass es im Sonnenlicht verbrennt, wie Zombies und Skelette. Dauert, bis das Opfer stirbt. Hat keine Wirkung auf Untote. +spell.ebwizardry\:darkness_orb.desc=Feuert sich langsam bewegende dunkle Energie in die Richtung, in die Sie zeigen, die verdorrt, was immer sie trifft. +spell.ebwizardry\:darkvision.desc=Erlaubt dem Magier eine Nachtsicht für 45 Sekunden. +spell.ebwizardry\:dart.desc=Feuert einen Dart in die Richtung, in die Sie zeigen, was sein Ziel beschädigt und schwächt. +spell.ebwizardry\:decay.desc=Erzeugt am Boden einen Zerfallsfleck, der jedes Lebewesen, das ihn berührt, infiziert, wodurch im Laufe der Zeit Schaden verursacht werden und sich der Zerfall überall, wo es läuft, weiter ausbreitet. +spell.ebwizardry\:decoy.desc=Erstellt einen illusionären Klon des Magiers, der Mobs dazu bringt, ihn stattdessen anzugreifen. Der Köder wird nach 30 Sekunden verschwinden. +spell.ebwizardry\:detonate.desc=Verursacht eine Explosion an der Stelle, auf die Sie zeigen, und schädigt alle Lebewesen in der Nähe - einschließlich des Magiers, wenn sie zu nah sind. +spell.ebwizardry\:diamondflesh.desc="Deine Pfeile sind kein Hinderniss für mich!" +spell.ebwizardry\:disintegration.desc=Schießt einen kräftigen Flammenstoß aus kurzer Entfernung vor sich her, der die Ziele beim Töten in brennende Glut explodieren lässt. Geschöpfe, die auf die Glut treten, werden in Brand gesetzt. +spell.ebwizardry\:divination.desc=Führt den Magier zu nahe gelegenen Erzen und Ressourcen. Die Wirksamkeit erhöht die Chance, wertvollere Erze zu finden. +spell.ebwizardry\:dragon_fireball.desc=Wirft einen Enderdrachen-Feuerball in die von Ihnen angegebene Richtung ab, der beim Aufprall verweilende Giftwolken freisetzt. +spell.ebwizardry\:earthquake.desc=Ein wahrer Meister der Erdmagie kann Berge versetzen. +spell.ebwizardry\:empowering_presence.desc=Gewährt dem Zaubernden und Verbündeten in der Nähe 30 Sekunden lang erhöhten magischen Schaden. +spell.ebwizardry\:entrapment.desc=Fängt das Ziel in einer Sphäre der Dunkelheit ein, die es hilflos nach oben zieht und es ständig schadet. +spell.ebwizardry\:evade.desc=Veranlasst den Magier, schnell zur Seite zu springen, um eingehenden Angriffen auszuweichen. +spell.ebwizardry\:fireball.desc=Schießt einen Feuerball in die von Ihnen angegebene Richtung ab. +spell.ebwizardry\:firebolt.desc=Schießt einen Feuerstrahl kurzer Entfernung vor sich her. +spell.ebwizardry\:firebomb.desc=Lässt eine Feuerbombe in die Richtung, in die Sie zeigen, die beim Aufprall explodiert und dabei Ziele in Brand setzt los. +spell.ebwizardry\:fire_resistance.desc=Gewährt dem Magier Feuerresistenz für 30 Sekunden. +spell.ebwizardry\:fire_sigil.desc=Stellt eine magische Feuerfalle auf den Boden, die die Kreatur, die sie auslöst, schadet und in Brand setzt. +spell.ebwizardry\:fireskin.desc=Verhüllt den Magier für 30 Sekunden in Flammen und lässt alles, was ihn angreift, in Flammen aufgehen. +spell.ebwizardry\:fire_breath.desc="Ich bin der Drache." +spell.ebwizardry\:flame_ray.desc=Erzeugt einen Flammenstrom in die Richtung, in die Sie zeigen, der ein Feuer entfacht und kontinuierlich Ziele schadet. +spell.ebwizardry\:flaming_axe.desc=Erstellt eine flammende Axt, die den Feind beim Treffer in Brand setzt. Hält 30 Sekunden lang an. +spell.ebwizardry\:flaming_weapon.desc=Er verleiht der ersten Waffe auf dem Hotbar des Magiers vorübergehend die Kraft der Flamme, wodurch sie ihre Opfer in Brand setzt. Die Magie lässt nach 45 Sekunden nach. +spell.ebwizardry\:flight.desc=Aufsteigen wie ein Adler. +spell.ebwizardry\:font_of_mana.desc="Wir sind von einer intensiven magischen Energie erfüllt, die aus dem Zentrum des..." - Auszug aus dem Tagebuch eines vergessenen Magiers; der Rest der Seite ist weggebrannt. +spell.ebwizardry\:font_of_vitality.desc=Es fühlt sich wunderbar an! +spell.ebwizardry\:force_arrow.desc=Schießt einen Kraftpfeil in die Richtung, in die Sie zeigen. +spell.ebwizardry\:forcefield.desc=Erzeugt ein Kraftfeld um den Magier, das Kreaturen abstößt und Geschosse ablenkt. +spell.ebwizardry\:force_orb.desc=Erzeugt ein Kraftfeld, das beim Aufprall nahegelegene Lebewesen schädigt und abstößt. +spell.ebwizardry\:forests_curse.desc="Wie könnt ihr es wagen, meinen Wald zu betreten?" +spell.ebwizardry\:forest_of_thorns.desc=Inmitten des Waldes liegt eine verborgene Lichtung,\nIn der Lichtung vollführt ein Zauberer,\nMagical Künste einer unerzählten Ordnung,\nDeep im Dornenwald. +spell.ebwizardry\:freeze.desc=Friert das Ziel für 10 Sekunden ein. Es friert auch Wasser ein und erzeugt Schnee auf dem Boden. +spell.ebwizardry\:freezing_weapon.desc=Er verleiht der ersten Waffe auf der Hotbar des Magiers vorübergehend die Kraft des Frostes, wodurch sie ihre Opfer einfrieren lässt. Die Magie lässt nach 45 Sekunden nach. +spell.ebwizardry\:frost_axe.desc=Erstellt eine eingefrorene Axt, die Feinde beim Schlagen einfriert. Hält 30 Sekunden lang an. +spell.ebwizardry\:frost_ray.desc=Erzeugt einen Froststrahl in die Richtung, in die Sie zeigen, der die Ziele verlangsamt und kontinuierlich schadet. +spell.ebwizardry\:frost_sigil.desc=Stellt eine magische Eisfalle auf den Boden, die das Wesen, das sie auslöst, schädigt und einfriert. +spell.ebwizardry\:frost_step.desc=Erlaubt es dem Magier, das Wasser beim Gehen 30 Sekunden lang einzufrieren. +spell.ebwizardry\:grapple.desc=Schießt eine magische Ranke, die es dem Magier erlaubt, sich an Blöcken festzuhalten oder Wesen einzuholen. Lassen Sie rechte Maustaste los, um den Block oder das Objekt loszulassen. +spell.ebwizardry\:glide.desc=Erlaubt es dem Magier, nach unten zu gleiten, während er sich in der Luft befindet und den Stab gedrückt hält. +spell.ebwizardry\:greater_fireball.desc=Schießt einen großen Feuerball in die von Ihnen angegebene Richtung ab, der beim Aufprall explodiert. +spell.ebwizardry\:greater_heal.desc=Heilt den Magier um 4 Herzen. +spell.ebwizardry\:greater_telekinesis.desc=Erlaubt es dem Magier, einen Block oder eine Kreatur aufzuheben und sie in der Luft zu halten, solange die Taste gedrückt wird. Schleichen, während man einen Block oder eine Kreatur hält, wirft ihn eine kurze Distanz. +spell.ebwizardry\:greater_ward.desc=Gewährt dem Zaubernden eine starke Abschirmwirkung, die den einfallenden magischen Schaden 30 Sekunden lang stark reduziert. +spell.ebwizardry\:group_heal.desc=Heilt den Zaubernden und alle in der Nähe befindlichen Verbündeten und beschworenen Kreaturen um 3 Herzen. +spell.ebwizardry\:growth_aura.desc=Pflanzen werden in der Nähe des Magiers erzeugt. Wächst auch hohes Gras und Blumen auf Gras. +spell.ebwizardry\:hailstorm.desc=Es war während des großen Winters des dritten Zeitalters, als die Eismagier ihre wahre Macht entdeckten. +spell.ebwizardry\:heal.desc=Heilt den Magier um 2 Herzen. +spell.ebwizardry\:heal_ally.desc=Heilt as Ziel um 2 und ein halbes Herzen. +spell.ebwizardry\:healing_aura.desc=Schafft eine Zone der heilenden Energie, die die Gesundheit jedes Verbündeten in ihrem Inneren regeneriert. Jeder Untote innerhalb der heilenden Aura wird Schaden nehmen. +spell.ebwizardry\:homing_spark.desc=Erzeugt einen schwebenden Funken, der sich auf die Feinde zubewegt. +spell.ebwizardry\:iceball.desc=Startet einen Eisball in die von Ihnen angegebene Richtung. +spell.ebwizardry\:ice_age.desc="Du sollst für die Ewigkeit eingefroren sein!" +spell.ebwizardry\:ice_charge.desc=Schießt eine Eisladung ab, die beim Aufprall explodiert, wobei nahe stehende Lebewesen eingefroren werden und Scherben in alle Richtungen freigesetzt werden. +spell.ebwizardry\:ice_lance.desc=Feuert einen großen Eisspeer in die Richtung, in die Sie zeigen, der übermäßig in die Ziele eindringt und sie dabei schadet und einfriert. +spell.ebwizardry\:ice_shard.desc=Feuert einen Eissplitter in die Richtung, in die Sie zeigen, was die Ziele beim Treffer beschädigt und verlangsamt. +spell.ebwizardry\:ice_shroud.desc=Erzeugt 30 Sekunden lang einen Kälteschleier um den Magier, wodurch alles, was ihn angreift, eingefroren wird. +spell.ebwizardry\:ice_spikes.desc=Verursacht rasiermesserscharfe Eisspitzen, die an der Stelle, auf die Sie zeigen, vom Boden aufsteigen und alle Kreaturen aufspießen, die dort sind. +spell.ebwizardry\:ice_statue.desc=Friert das Ziel für 20 Sekunden oder bis zum Ausbruch ein. Das Ziel kann sich im gefrorenen Zustand nicht bewegen oder etwas tun, ist aber auch gegen jeglichen Schaden unempfindlich. +spell.ebwizardry\:ignite.desc=Setzt das Ziel 10 Sekunden lang in Brand. Funktioniert auch wie ein Feuerstein und Stahl. +spell.ebwizardry\:imbue_weapon.desc=Verzaubert vorübergehend die erste Waffe auf dem Hotbar des Magiers mit Magie, wodurch sie stärker wird. Die Magie lässt nach 45 Sekunden nach. +spell.ebwizardry\:intimidate.desc=Emittiert ein einschüchterndes Brüllen, das nahegelegene Kreaturen in Angst weglaufen lässt. Von Angst befallene Kreaturen erholen sich nach 30 Sekunden. +spell.ebwizardry\:invigorating_presence.desc=Gewährt dem Magier und allen Verbündeten in der Nähe 45 Sekunden lang erhöhte Stärke. +spell.ebwizardry\:invisibility.desc=Macht den Magier 30 Sekunden lang unsichtbar. +spell.ebwizardry\:invoke_weather.desc=Verändert das Wetter in der Welt. +spell.ebwizardry\:ironflesh.desc=Verbessert die Schadensresistenz des Magiers für 30 Sekunden erheblich. +spell.ebwizardry\:leap.desc=Veranlasst den Magier, mehrere Blöcke nach oben und leicht vorwärts zu springen. +spell.ebwizardry\:levitation.desc=Gedrückt halten, um zu Schweben. Kurz vor aufprall drücken, um Fallschaden zu negieren. +spell.ebwizardry\:life_drain.desc=Erzeugt einen Strahl Energie in die von Ihnen angegebene Richtung, der dem Ziel das Leben entzieht und es zur allmählichen Regeneration Ihrer Gesundheit nutzt. +spell.ebwizardry\:light.desc=Erzeugt einen magischen Lichtpunkt, der die Umgebung beleuchtet. Hält 30 Sekunden lang an. +spell.ebwizardry\:lightning_arrow.desc=Schießt einen Blitzpfeil in die Richtung, in die Sie zeigen. +spell.ebwizardry\:lightning_bolt.desc=Verursacht einen Blitz, der dort einschlägt, wo Sie hinzielen. +spell.ebwizardry\:lightning_disc.desc=Sendet eine Blitzscheibe, die in die Richtung fliegt, in die Sie zeigen, und die Ziele sucht. +spell.ebwizardry\:lightning_hammer.desc="Ich zerschlage euch mit dem Zorn des Himmels!" +spell.ebwizardry\:lightning_pulse.desc=Lädt den Boden um den Magier herum mit Blitzen auf, wodurch nahe stehende Lebewesen schaden nehmen und abgestoßen werden. +spell.ebwizardry\:lightning_ray.desc=Erzeugt einen Blitzstrom in die Richtung, in die Sie zeigen, der ständig Ziele beschädigt. +spell.ebwizardry\:lightning_sigil.desc=Stellt eine magische Blitzfalle auf den Boden, die die auslösende Kreatur schädigt und kettet Blitze an andere Kreaturen in der Nähe. +spell.ebwizardry\:lightning_web.desc="Fokus. Lenken Sie den Sturm in Ihrem Geist durch Ihren Zauberstab und entfesseln Sie seine Wut." +spell.ebwizardry\:magic_missile.desc=Feuert magische Energie in die Richtung, in die Sie zeigen. +spell.ebwizardry\:metamorphosis.desc=Ändert das Ziel in eine andere Form. Funktioniert nur bei einigen Kreaturen wie zum Beispiel einem Schwein. +spell.ebwizardry\:meteor.desc=Manche Zauberer wollen die Welt einfach nur brennen sehen... +spell.ebwizardry\:mind_control.desc=Übernimmt 30 Sekunden lang die Kontrolle über den Verstand des Ziels, so dass es die Seite wechselt und stattdessen für den Magier kämpft. Wirkt nicht auf Kreaturen, die zu willensstark sind. +spell.ebwizardry\:mind_trick.desc=Verwirrt und desorientiert das Ziel 15 Sekunden lang, so dass es nicht mehr in der Lage ist, effektiv anzugreifen. Der Effekt wird beendet, wenn das Ziel Schaden nimmt. +spell.ebwizardry\:mine.desc=Zerbricht den Block, auf den der Magier schaut. Hohe stufen erlauben es, härtere Blöcke zu brechen. +spell.ebwizardry\:muffle.desc=Dämpft 30 Sekunden lang alle Geräusche, die der Magier macht. Wenn sie gedämpft sind, können die Mobs Sie nur erkennen, wenn sie auf Sie schauen. +spell.ebwizardry\:none.desc=Um ein Zauberbuch mit dem /give command zu bekommen, nutze id\: /give [player] ebwizardry\:spell_book 1 [spell id] (Wenn Sie dieses Buch in einer Truhe gefunden haben, hat irgendein anderer Mod die Sache versaut). +spell.ebwizardry\:oakflesh.desc=Verbessert die Schadensresistenz des Magiers für 30 Sekunden. +spell.ebwizardry\:paralysis.desc=Erzeugt einen starken Blitz, der Ziele für 5 Sekunden lahmlegt. Gelähmte Kreaturen können sich nicht bewegen und werden trotzdem Schaden nehmen - aber zu viel wird die Kreatur aus der Lähmung reißen. +spell.ebwizardry\:petrify.desc=Verwandelt das Ziel in Stein, bis es ausgebrochen wird, mit der Chance, dass es ausbricht, wenn es dunkel ist. Das Ziel kann sich nicht bewegen oder etwas tun, wenn es versteinert ist, aber es ist auch unempfindlich gegen jeglichen Schaden. +spell.ebwizardry\:phase_step.desc=Teleportiert den Magier eine kurze Strecke vor sich her, auch durch Wände hindurch. Reichweiten-Upgrades erhöhen die Wandstärke, durch die Sie teleportieren können. +spell.ebwizardry\:plague_of_darkness.desc=Die Dunkelheit wird sie alle verzehren... +spell.ebwizardry\:pocket_furnace.desc=Schmelzt bis zu 5 schmelzbare Gegenstände aus dem Inventar. Die Gegenstände auf der Hotbar werden zuerst eingeschmolzen. +spell.ebwizardry\:pocket_workbench.desc=Erlaubt dem Magier, Gegenstände wie an einer Werkbank herzustellen. +spell.ebwizardry\:poison.desc=Feuert Gift in die von Ihnen angegebene Richtung. +spell.ebwizardry\:poison_bomb.desc=Schießt eine Giftbombe in die Richtung, in die Sie zeigen, die beim Aufprall explodiert und nahegelegene Lebewesen vergiftet. +spell.ebwizardry\:possession.desc="Werde dein Feind." +spell.ebwizardry\:ray_of_purification.desc=Sendet einen blendenden Lichtstrahl aus, der seine Ziele verletzt und blendet. Untote Kreaturen erleiden doppelten Schaden und werden in Brand gesteckt. +spell.ebwizardry\:remove_curse.desc=Entfernt alle Flüche, die den Magier derzeit betreffen. +spell.ebwizardry\:replenish_hunger.desc=Füllt den Hungerbalken des Magiers um 4 Hungerpunkte auf. +spell.ebwizardry\:resurrection.desc=Mit einem Meisterheiler an Ihrer Seite, ist tot zu sein... optional. +spell.ebwizardry\:reversal.desc=Entfernt einen zufälligen negativen Trankeffekt und fügt ihn dem Ziel zu, das diesen Effekt für die verbleibende Dauer erleiden wird. Die Stufe erhöht die Anzahl der Effekte, die umgekehrt werden. +spell.ebwizardry\:ring_of_fire.desc=Erzeugt einen Feuerring um den Magier, der alle Feinde in der Nähe schädigt und sie in Brand setzt. +spell.ebwizardry\:satiety.desc=Füllt den Hungerbalken des Magiers um 8 Hungerpunkte auf. +spell.ebwizardry\:shadow_ward.desc=Erzeugt eine Wand der Dunkelheit vor dem Magier, die bewirkt, dass die Hälfte aller eintreffenden Schäden stattdessen dem Angreifer zugefügt wird. +spell.ebwizardry\:shield.desc=Schafft eine schützende Kraftbarriere, die Geschosse und Magie blockiert. Gewährt dem Magier auch einen schwachen Widerstandseffekt. +spell.ebwizardry\:shockwave.desc=Boom. +spell.ebwizardry\:shulker_bullet.desc=Schießt ein Shulker-Geschoss, das nach Zielen sucht und diese beim Treffer zum Schweben bringt. +spell.ebwizardry\:silverfish_swarm.desc="Ahhhh! Sie vermengen sich!" +spell.ebwizardry\:sixth_sense.desc=Erlaubt es dem Magier, für 20 Sekunden die Positionen von nahegelegenen Kreaturen zu erspüren, sogar durch Wände hindurch. +spell.ebwizardry\:slime.desc=Verschlingt das Ziel in Schleim, der es verlangsamt und kontinuierlich schädigt. Der Schleim zerplatzt nach 10 Sekunden. +spell.ebwizardry\:slow_time.desc=Chronomantik ist die Kunst, die Zeit selbst zu manipulieren, um sie den eigenen Bedürfnissen anzupassen. Man glaubte, sie sei in der Vergangenheit verloren gegangen... bis heute. +spell.ebwizardry\:smoke_bomb.desc=Schießt eine Rauchbombe in die von Ihnen angegebene Richtung ab, die beim Aufprall explodiert und dabei Rauch freisetzt und nahe stehende Lebewesen für kurze Zeit blendet. +spell.ebwizardry\:snare.desc=Stellt eine Falle auf den Boden, die die auslösende Kreatur beschädigt und kurzzeitig verlangsamt. +spell.ebwizardry\:snowball.desc=Wirft einen Schneeball in die von Ihnen angegebene Richtung. +spell.ebwizardry\:spark_bomb.desc=Schießt eine Schockladung in die von Ihnen angegebene Richtung ab, die beim Aufprall Funken auf nahegelegene Feinde auslöst. +spell.ebwizardry\:spectral_pathway.desc=Erschafft vor Ihnen eine unzerstörbare magische Brücke, die sich über 15 Blöcke erstreckt. Die Brücke verschwindet nach 60 Sekunden. +spell.ebwizardry\:speed_time.desc=...Tag, Nacht, Morgen- und Abenddämmerung, Sonnenauf- und -untergang\: So ist der Lauf der Zeit, der uns in einem endlosen Zyklus von... +spell.ebwizardry\:spider_swarm.desc=Beschwört einen Schwarm giftiger Spinnen, um für Sie zu kämpfen. Die Spinnen verschwinden nach 30 Sekunden oder wenn sie getötet werden. +spell.ebwizardry\:static_aura.desc=Umgibt den Magier 30 Sekunden lang mit einem Blitz und feuert einen Blitzfunken auf alles, was ihn trifft. +spell.ebwizardry\:summon_blaze.desc=Beschwört ein Lohe, um für Sie zu kämpfen. Der Lohe verschwindet nach 30 Sekunden oder wenn es getötet wird. +spell.ebwizardry\:summon_ice_giant.desc="Zerschmettern Sie sie!" +spell.ebwizardry\:summon_ice_wraith.desc=Ruft einen Eis-Geist herbei, das für Sie kämpft. der Eis-Geist verschwindet nach 30 Sekunden oder wenn es getötet wird. +spell.ebwizardry\:summon_iron_golem.desc=Automatischer autonomer Automat. +spell.ebwizardry\:summon_lightning_wraith.desc=Beschwört ein Geist des Blitzes, um für Sie zu kämpfen. Das Blitz-Gespenst verschwindet nach 30 Sekunden oder wenn es getötet wird. +spell.ebwizardry\:summon_phoenix.desc=Von den Aschen auferstanden... +spell.ebwizardry\:summon_shadow_wraith.desc=Beschwört einen Schatten-Geist, um für Sie zu kämpfen. +spell.ebwizardry\:summon_skeleton.desc=Beschwört ein Skelett, um für Sie zu kämpfen. Das Skelett verschwindet nach 30 Sekunden oder wenn es getötet wird. +spell.ebwizardry\:summon_skeleton_legion.desc="Erhebt euch, untote Armee!" +spell.ebwizardry\:summon_snow_golem.desc=Erstellt einen Schnee-Golem, der für Sie kämpft. Dauert, bis der Schnee-Golem stirbt. +spell.ebwizardry\:summon_spirit_horse.desc=Beschwört ein Geistpferd für Sie zum Reiten. Das Geisterpferd verschwindet kurz nach dem Absteigen, oder Sie können es durch einen Shift-Rechtsklick mit einem beliebigen Zauberstab "verschwinden lassen". +spell.ebwizardry\:summon_spirit_wolf.desc=Beschwört einen Geisterwolf-Gefährten, der für Sie kämpft. Der Geisterwolf wird nur verschwinden, wenn er getötet wird, oder Sie können ihn durch Umschalt-Rechtsklick mit einem beliebigen Zauberstab "verschwinden lassen". +spell.ebwizardry\:summon_storm_elemental.desc="Sturm-Elementar\: Eine uralte Manifestation der Elemente, sie kann die rohe Kraft, die in ihr brodelt, kaum eindämmen." - Der Leitfaden des Zauberers für arkane Wesen, Band II +spell.ebwizardry\:summon_wither_skeleton.desc=Beschwört ein Witherskelett, um für Sie zu kämpfen. Das Witherskelett verschwindet nach 30 Sekunden oder wenn es getötet wird. +spell.ebwizardry\:summon_zombie.desc=Ruft einen Zombie herbei, der für Sie kämpft. Der Zombie verschwindet nach 30 Sekunden oder wenn er getötet wird. +spell.ebwizardry\:telekinesis.desc=Bewegt ein Element oder ein anderes kleines Objekt auf Sie zu oder klickt mit der rechten Maustaste auf das betrachtete Objekt um es auszulösen (Hebel). Kann auch zum Entwaffnen von Spielern verwendet werden. +spell.ebwizardry\:thunderbolt.desc=Schießt einen Donnerkeil ab, der Ziele zurückwirft. +spell.ebwizardry\:thunderstorm.desc="Mwahahahahahaha!" +spell.ebwizardry\:tornado.desc=Entfesselt einen Tornado in die von Ihnen angegebene Richtung, der alles, was ihm in den Weg kommt, in den Himmel schleudert. +spell.ebwizardry\:transience.desc=Macht den Magier für 20 Sekunden nicht mehr Ansprechbar. Der Magier ist immun gegen alle Schäden, die er während der Transiente erleidet, aber er kann nicht brechen, Blöcke platzieren oder Schaden verursachen. +spell.ebwizardry\:transportation.desc=Bringt die Magier zu ihrem gespeicherten Steinkreis. Um diesen Zauberspruch anzuwenden, machen Sie einen Kreis aus Transportsteinen und klicken Sie dann mit einem Zauberstab mit der rechten Maustaste darauf. +spell.ebwizardry\:vanishing_box.desc=Gewährt dem Magier Zugang zu seinem Endtruhenspeicher. +spell.ebwizardry\:vex_swarm.desc=Beschwört einen Schwarm von fliegenden Vex, um für Sie zu kämpfen. Die Vex verschwinden nach 30 Sekunden oder wenn sie getötet werden. +spell.ebwizardry\:wall_of_frost.desc=Der Winter liegt Ihnen zu Füßen. +spell.ebwizardry\:ward.desc=Gewährt dem Zaubernden einen Abschirmungseffekt, der eingehenden magischen Schaden 30 Sekunden lang reduziert. +spell.ebwizardry\:water_breathing.desc=Erlaubt dem Magier, 60 Sekunden lang unter Wasser zu atmen. +spell.ebwizardry\:whirlwind.desc=Verursacht, dass das Ziel mit hoher Geschwindigkeit nach oben und von Ihnen weggeblasen wird. +spell.ebwizardry\:wither.desc=Feuert einen Strahl der Dunkelheit ab, der alles verdorrt, was er berührt. +spell.ebwizardry\:wither_skull.desc=Feuert einen Wither Schädel in die Richtung, in die Sie zeigen. + +spell.ebwizardry\:invoke_weather.sun=Der Regen hört allmählich auf... +spell.ebwizardry\:invoke_weather.rain=Der Himmel öffnet sich... +spell.ebwizardry\:transportation.missing=Der Steinkreis fehlt oder ist versperrt... +spell.ebwizardry\:transportation.undefined=Sie müssen sich zuerst an die Lage eines Steinkreises erinnern! +spell.ebwizardry\:transportation.wrongdimension=Kein gespeicherter Steinkreis in dieser Dimension... +spell.ebwizardry\:clairvoyance.searching=Suchen... +spell.ebwizardry\:clairvoyance.confirm=Der Weg, der sich beim deuten von %1$s offenbart hat, führt nun zurück zu diesem Punkt +spell.ebwizardry\:clairvoyance.outofrange=Ihr gespeicherter Standort ist zu weit entfernt oder unzugänglich... +spell.ebwizardry\:clairvoyance.undefined=Sie müssen sich zuerst einen Ort merken! +spell.ebwizardry\:clairvoyance.wrongdimension=Ihr erinnerter Ort ist in einer anderen Dimension... +spell.ebwizardry\:possession.insufficienthealth=Sie haben nicht genug Herzen, um %1$s zu besitzen! +spell.ebwizardry\:possession.success=Drücke %s, um den Besitz abzutreten. +spell.ebwizardry\:divination.nothing=Nichts passiert. +spell.ebwizardry\:divination.weak=Man spürt lediglich das Zucken des Zauberstabs %s. +spell.ebwizardry\:divination.moderate=Sie spüren, wie Ihr Zauberstab %s gezerrt wird. +spell.ebwizardry\:divination.strong=Ihr Zauberstab zieht stark %s. +spell.ebwizardry\:divination.very_strong=Ihr Zauberstab schwankt sehr stark %s. +spell.ebwizardry\:divination.down=nach unten +spell.ebwizardry\:divination.up=nach oben +spell.ebwizardry\:divination.front=nach vorne +spell.ebwizardry\:divination.back=nach hinten +spell.ebwizardry\:divination.left=nach links +spell.ebwizardry\:divination.right=nach rechts +spell.ebwizardry\:resurrection.resurrect_ally=%s wurde wiederbelebt von %s +spell.ebwizardry\:resurrection.resurrect_self=%s kam zurück ins Leben +spell.ebwizardry\:resurrection.button_wait=Wiederbelebung in (%ss) +spell.ebwizardry\:resurrection.button_ready=Wiederbeben! + +forfeit.ebwizardry\:do_nothing=Nichts passierte. + +forfeit.ebwizardry\:burn_self=Das %s geht in Ihrer Hand in Flammen auf! +forfeit.ebwizardry\:fireball=Ein Feuerball materialisiert sich vor Ihren Augen! +forfeit.ebwizardry\:firebomb=Eine Feuerbombe erscheint direkt über Ihnen! +forfeit.ebwizardry\:explode=Eine plötzliche Explosion wirft Sie zu Boden! +forfeit.ebwizardry\:blazes=Plötzlich materialisieren sich um Sie herum feindliche Lohen! +forfeit.ebwizardry\:burn_surroundings=Das Gebiet um Sie herum ist in Flammen gesetzt! +forfeit.ebwizardry\:meteors=Feuriges Harmagedon regnet vom Himmel! + +forfeit.ebwizardry\:freeze_self=Sie spüren eine eisige Kälte, die Sie durchströmt! +forfeit.ebwizardry\:freeze_self_2=Von den %s geht eine Kälte aus, die so intensiv ist, dass sie einen festwurzelt! +forfeit.ebwizardry\:ice_spikes=Eisstacheln steigen unter Ihren Füßen vom Boden auf! +forfeit.ebwizardry\:blizzard=Sie sind plötzlich von einem wütenden Schneesturm umgeben! +forfeit.ebwizardry\:ice_wraiths=Plötzlich materialisieren sich feindliche Eisgespenster um Sie herum! +forfeit.ebwizardry\:hailstorm=Rasiermesserscharfes Eis beginnt auf Sie zu regnen! +forfeit.ebwizardry\:ice_giant=Ein feindlicher Eisriese materialisiert sich vor Ihnen! + +forfeit.ebwizardry\:thunder=Die Schriftrolle gibt einen ohrenbetäubenden Lärm ab, der Sie zu Boden schlägt! +forfeit.ebwizardry\:storm=Sieht aus, als würde ein Sturm aufziehen! +forfeit.ebwizardry\:lightning_sigils=Passen Sie auf, wo Sie hintreten! +forfeit.ebwizardry\:lightning=Sie sind vom Blitz getroffen! +forfeit.ebwizardry\:paralyse_self=Sie sind gelähmt! +forfeit.ebwizardry\:lightning_wraiths=Plötzlich materialisieren sich feindliche Blitzgeister um Sie herum! +forfeit.ebwizardry\:storm_elementals=Feindliche Sturm-Elementarwesen materialisieren sich auf allen Seiten! + +forfeit.ebwizardry\:nausea=...hm? Was ist gerade passiert? Wo bin ich hier? +forfeit.ebwizardry\:zombie_horde=Um Sie herum erhebt sich eine Horde von Zombies aus dem Boden! +forfeit.ebwizardry\:wither_self=Die Dunkelheit verdorrt Ihre Seele! +forfeit.ebwizardry\:cripple_self=Das %s strahlt ein tödliches Heulen aus, und Sie sind bis auf einen Zentimeter Ihres Lebens verkrüppelt! +forfeit.ebwizardry\:shadow_wraiths=Feindliche Schattengespenster materialisieren sich auf allen Seiten! + +forfeit.ebwizardry\:snares=Es ist eine Falle! +forfeit.ebwizardry\:squid=Tintenfisch! +forfeit.ebwizardry\:uproot_plants=Alle Pflanzen in der Nähe sind plötzlich entwurzelt! +forfeit.ebwizardry\:poison_self=Sie sind vergiftet! +forfeit.ebwizardry\:flood=Wasser materialisiert sich um Sie herum! +forfeit.ebwizardry\:bury_self=Der Boden bricht unter Ihnen zusammen! + +forfeit.ebwizardry\:spill_inventory=Ihre Gegenstände fallen von selbst überall hin! +forfeit.ebwizardry\:teleport_self=Sie werden sofort irgendwo hin teleportiert! +forfeit.ebwizardry\:levitate_self=Sie beginnen hilflos nach oben zu schweben! +forfeit.ebwizardry\:vex_horde=Eine Horde von Vex materialisiert sich um Sie herum! +forfeit.ebwizardry\:black_hole=Ein wirbelnder Vortex erscheint vor Ihnen! +forfeit.ebwizardry\:arrow_rain=Ein Sperrfeuer von Pfeilen beginnt auf Sie zu regnen! + +forfeit.ebwizardry\:damage_self=Aua! +forfeit.ebwizardry\:spill_armour=Deine ganze Rüstung fällt herunter! +forfeit.ebwizardry\:hunger=Sie sind plötzlich sehr hungrig! +forfeit.ebwizardry\:blind_self=Sie sind geblendet! +forfeit.ebwizardry\:weaken_self=Sie sind stark geschwächt! +forfeit.ebwizardry\:jam_self=Ihre Magie ist nun nutzlos! +forfeit.ebwizardry\:curse_self=Sie sind mit dem Untod verflucht! + +potion.ebwizardry\:frost=Frostbiss +potion.ebwizardry\:fireskin=Feuerhaut +potion.ebwizardry\:ice_shroud=Eiswolke +potion.ebwizardry\:static_aura=Statische Aura +potion.ebwizardry\:transience=Weisheit +potion.ebwizardry\:decay=Verfall +potion.ebwizardry\:sixth_sense=Sechster Sinn +potion.ebwizardry\:arcane_jammer=Magieblock +potion.ebwizardry\:mind_trick=Gedanken-Nebel +potion.ebwizardry\:mind_control=Gedankenkontrolle +potion.ebwizardry\:font_of_mana=Das Wesen des Mana +potion.ebwizardry\:fear=Angst +potion.ebwizardry\:curse_of_soulbinding=Fluch des Seelengebundenen +potion.ebwizardry\:paralysis=Lähmung +potion.ebwizardry\:muffle=Leise Schritte +potion.ebwizardry\:ward=Schild +potion.ebwizardry\:slow_time=Zeit Verlangsamen +potion.ebwizardry\:empowerment=Starke Magie +potion.ebwizardry\:curse_of_enfeeblement=Ableben +potion.ebwizardry\:curse_of_undeath=Fluch des Untotsein +potion.ebwizardry\:containment=Aufbewahrung +potion.ebwizardry\:frost_step=Frostschritt + +enchantment.ebwizardry\:magic_sword=Verstärkt +enchantment.ebwizardry\:magic_bow=Verstärkt +enchantment.ebwizardry\:flaming_weapon=Feuer-Verstärkt +enchantment.ebwizardry\:freezing_weapon=Frost-Verstärkt +enchantment.ebwizardry\:shocking_weapon=Blitz-Verstärkt + +enchantment.ebwizardry\:magic_protection=Magischer Schutz +enchantment.ebwizardry\:frost_protection=Frostschutz +enchantment.ebwizardry\:shock_protection=Schockschutz + +enchantment.ebwizardry.magic_sword.desc=Teil des Zaubers " Unruhige Waffe "; im Überlebensmodus unerreichbar (das Buch wird nicht funktionieren). +enchantment.ebwizardry.magic_bow.desc=Teil des Zaubers " Unruhige Waffe "; im Überlebensmodus unerreichbar (das Buch wird nicht funktionieren). +enchantment.ebwizardry.flaming_weapon.desc=Teil des Zaubers "Flammenwaffe"; im Überlebensmodus unerreichbar (das Buch wird nicht funktionieren). +enchantment.ebwizardry.freezing_weapon.desc=Teil des Zaubers "Gefrohrene Waffe"; im Überlebensmodus unerreichbar (das Buch wird nicht funktionieren). +enchantment.ebwizardry.shocking_weapon.desc=Teil des Zaubers "Schockwaffe"; im Überlebensmodus unerreichbar (das Buch wird nicht funktionieren). + +enchantment.ebwizardry.magic_protection.desc=Zeduziert magischen Schaden jeder Art. +enchantment.ebwizardry.frost_protection.desc=Zeduziert magischen Frostschaden. +enchantment.ebwizardry.shock_protection.desc=Zeduziert magischen Schockschaden. + +key.categories.ebwizardry=Zauberei + +key.ebwizardry.next_spell=Nächster Zauber +key.ebwizardry.previous_spell=Vorheriger Zauber + +death.attack.wizardry_magic=%1$s wurde von %2$s mit Magie getötet +death.attack.indirect_wizardry_magic=%1$s wurde von %2$s mit Magie getötet + +soundCategory.ebwizardry_spells=Spells + +commands.ebwizardry\:cast.usage=/%1$s [spieler | x y z richtung] [dauer] [modifiers] +commands.ebwizardry\:cast.success=Erfolgreich %s gezaubert +commands.ebwizardry\:cast.success_continuous=Erfolgreich %s für %s Sekunden gezaubert +commands.ebwizardry\:cast.success_remote=Successfully cast %s as %s +commands.ebwizardry\:cast.success_remote_continuous=Erfolgreich %s als %s für %s Sekunden gezaubert +commands.ebwizardry\:cast.success_position=Erfolgreich %s at %s, %s, %s gezaubert +commands.ebwizardry\:cast.success_position_continuous=Erfolgreich %s at %s, %s, %s für %s Sekunden gezaubert +commands.ebwizardry\:cast.fail=Fehlgeschlag %1$s zu zaubern. +commands.ebwizardry\:cast.not_found=Kein Zauber mit der ID %1$s gefunden +commands.ebwizardry\:cast.invalid_direction=Falsche Richtung: %1$s (Gültige Richtungen sind: up, down, north, south, east, west) +commands.ebwizardry\:cast.tag_error=Data tag parsing fehlgeschlagen\: %s +commands.ebwizardry\:cast.origin_not_specified=Sie müssen einen Spieler oder einen Ort angeben, von dem aus Sie den Zauberspruch wirken wollen +commands.ebwizardry\:cast.duration_not_specified=Sie müssen eine Dauer für diesen Zauberspruch angeben + +commands.ebwizardry\:ally.usage=/%1$s [spieler] +commands.ebwizardry\:ally.addally=%1$s wurde zu der Liste der Verbündeten von %2$s hinzugefügt +commands.ebwizardry\:ally.removeally=%1$s wurde von der Liste der Verbündeten von %2$s entfehrnt +commands.ebwizardry\:ally.self=Spieler können nicht mit sich selbst Verbündet sein +commands.ebwizardry\:ally.permission=Du hast nicht die benötigte Berechtigung Listen zu bearbeiten + +commands.ebwizardry\:allies.usage=/%1$s [spieler] +commands.ebwizardry\:allies.list=Mit dir verbündete Spieler\: %1$s +commands.ebwizardry\:allies.list_other=Verbündete Spieler mit %1$s\: %2$s +commands.ebwizardry\:allies.permission=Du hast nicht die benötigte Berechtigung Listen anderer Spieler anzusehen +commands.ebwizardry\:allies.none=Keine Verbündeten + +commands.ebwizardry\:discoverspell.usage=/%1$s [spieler] +commands.ebwizardry\:discoverspell.not_found=Kein Zauber mit der ID %1$s gefunden +commands.ebwizardry\:discoverspell.clear=Alle Zauber für %1$s unkenntlich gemacht +commands.ebwizardry\:discoverspell.all=Alle Zauber für %1$s enthüllt +commands.ebwizardry\:discoverspell.addspell=Zauber %1$s von %2$s's Zauberentülldaten hinzugefügt. +commands.ebwizardry\:discoverspell.removespell=Zauber %1$s von %2$s's Zauberentülldaten entfehrnt. + +config.ebwizardry.title.general=Mod Optionen + +config.ebwizardry.generic.true=An +config.ebwizardry.generic.false=Aus + +config.ebwizardry.category.spells=Zauberkonfiguration +config.ebwizardry.category.spells.tooltip=Wählen Sie aus, welche Zaubersprüche aktiviert sind +config.ebwizardry.title.spells=Konfiguration der Zaubersprüche +config.ebwizardry.subtitle.spells=Die globale Deaktivierung eines Zaubers hier überschreibt die feineren Einstellungen in der JSON-Datei + +config.ebwizardry.category.gameplay=Gameplay-Einstellungen +config.ebwizardry.category.gameplay.tooltip=Allgemeine Gameplayeinstellungen der Zauberei +config.ebwizardry.title.gameplay=Gameplay-Einstellungen +config.ebwizardry.subtitle.gameplay=Globale Einstellungen, die sich auf die Spielmechanik auswirken. + +config.ebwizardry.discovery_mode=Enthüllmodus +config.ebwizardry.discovery_mode.tooltip=Für diejenigen, die einen Sinn für das Geheimnisvolle mögen! Wenn Sie diese Option aktivieren, sind Zaubersprüche, die Sie noch nicht gewirkt haben, erst dann lesbar, wenn Sie sie (Für jede Welt einzeln) gewirkt haben. Im kreativen Modus hat sie keine Wirkung. Enthüllungszauber sind im Überlebensmodus nicht erreichbar, wenn dieser deaktiviert ist. +config.ebwizardry.legacy_wand_levelling=Altes Zauberstab-Aufwertungssystem +config.ebwizardry.legacy_wand_levelling.tooltip=Steuert, ob die Zauberstäbe vor dem Aufsteigen in die nächste Stufe Zeit brauchen. Aktivieren Sie diese Option, um zum System vor 4.2 zurückzukehren, das nur Leitfäden der Arkanen Künste benötigt. Die Zauberstäbe werden auch dann noch Fortschritte machen, wenn diese Option aktiviert ist, so dass Sie bei der Rückkehr zum neuen System keinen Fortschritt verlieren. +config.ebwizardry.legacy_wand_levelling.true=Ja - es hat mir gefallen, wie es war! +config.ebwizardry.legacy_wand_levelling.false=Nein, ich will Leveln! +config.ebwizardry.friendly_fire=Friendly Fire +config.ebwizardry.friendly_fire.tooltip=Kontrolliert, welche Kreaturen durch Ihre Magie beschädigt werden können, wenn sie mit Ihnen verbündet sind. Eure Zauber werden unabhängig von dieser Einstellung nicht auf Eure Verbündeten oder die von ihnen beschworenen/besessenen Kreaturen abzielen, aber diese Einstellung macht sie völlig immun, wenn sie deaktiviert wird. +config.ebwizardry.minion_revenge_targeting=Beschwörungen haben Rache +config.ebwizardry.minion_revenge_targeting.tooltip=Ob beschworene Kreaturen Rache nehmen können - Spieler oder Kreaturen, die sie sonst nicht angreifen könnten. +config.ebwizardry.minion_revenge_targeting.true=Ja - ich würde ihnen nie wehtun! +config.ebwizardry.minion_revenge_targeting.false=Nein - sie müssen mir immer gehorchen! +config.ebwizardry.players_move_each_other=Spieler bewegen sich gegenseitig +config.ebwizardry.players_move_each_other.tooltip=Den Spielern erlauben, andere Spieler mit Hilfe von Magie zu bewegen. +config.ebwizardry.players_move_each_other.true=Ja - lasst die Spiele beginnen! +config.ebwizardry.players_move_each_other.false=Nein - ich lasse mich nicht herumschubsen +config.ebwizardry.player_block_damage=Spieler Block-Schaden +config.ebwizardry.player_block_damage.tooltip=Ob Zaubersprüche, die von Spielern gewirkt werden, Blöcke in der Welt zerstören können. Deaktivieren Sie dies, um Griefen zu verhindern. Um zu verhindern, dass NPC´s Blöcke mit Magie zerstören können, verwenden Sie die mobGriefing-Gamerule. +config.ebwizardry.player_block_damage.true=Ja - kaboom! +config.ebwizardry.player_block_damage.false=Nein - AntiGrief (TM) aktivieren +config.ebwizardry.telekinetic_disarmament=Telekinetische Entwaffnung +config.ebwizardry.telekinetic_disarmament.tooltip=Ob man den Spielern erlaubt, andere Spieler mit dem Telekinese-Spruch zu entwaffnen. Deaktivieren, um das Stehlen von Gegenständen zu verhindern. +config.ebwizardry.telekinetic_disarmament.true=Ja - Leute Dinge stehlen lassen! +config.ebwizardry.telekinetic_disarmament.false=Nein - das ist Schummeln! +config.ebwizardry.teleport_through_unbreakable_blocks=Teleportieren durch unzerbrechliche Blöcke +config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Ob es den Spielern erlaubt ist, sich mit dem Geisterwand Zauber durch unzerbrechliche Blöcke (z.B. Grundgestein) zu teleportieren. +config.ebwizardry.teleport_through_unbreakable_blocks.true=Ja - ich möchte die Leere sehen! +config.ebwizardry.teleport_through_unbreakable_blocks.false=Nein - Grundgestein ist undurchdringlich +config.ebwizardry.world_time_manipulation=Weltzeitmanipulation +config.ebwizardry.world_time_manipulation.tooltip=Ob es den Spielern erlaubt ist, die Weltzeit mit den Zeit-Zaubersprüchen zu verändern. Wenn er deaktiviert ist, ändert der Zeit-Zaubern die Weltzeit nicht, aber er beschleunigt trotzdem die Ticks der nahegelegenen Blöcke, Kreaturen und Kachel-Kreaturen-Ticks.. +config.ebwizardry.world_time_manipulation.true=Ja - Jederzeit... +config.ebwizardry.world_time_manipulation.false=Nein - ich brauche meinen Schlaf! +config.ebwizardry.replace_vanilla_fireballs=Vanilla-Feuerkugeln ersetzen +config.ebwizardry.replace_vanilla_fireballs.tooltip=Ob die eigenen Feuerkugeln von Minecraft durch Zauberei-Feuerkugeln ersetzt werden sollen. Wenn dies deaktiviert ist, werden nur Zaubersprüche der Zauberei die eigenen Feuerkugeln verwenden. +config.ebwizardry.replace_vanilla_fireballs.true=Ja - gebt mir FEUER! +config.ebwizardry.replace_vanilla_fireballs.false=Nein - Lohen sind gemein genug +config.ebwizardry.replace_vanilla_fall_damage=Sturzschäden durch Vanilla ersetzen +config.ebwizardry.replace_vanilla_fall_damage.tooltip=Ob die auf der Entfernung basierende Berechnung des Fallschadens von Meincraft durch eine gleichwertige, auf der Geschwindigkeit basierende Berechnung von Zauberei ersetzt werden soll. Dies wird so gemacht, dass Mobs im freien Fall genau den gleichen Schaden wie normal nehmen, damit Mobfarmen noch funktionieren. Deaktivieren Sie diese Funktion, wenn Sie seltsamen Fallschaden erleben! Wenn dies deaktiviert wird, greifen einige Zauber auf eine einfachere Methode zurück, um den Sturzschaden des Spielers in bestimmten Fällen zurückzusetzen. +config.ebwizardry.replace_vanilla_fall_damage.true=Ja - es ist Parkourzeit +config.ebwizardry.replace_vanilla_fall_damage.false=Nein - Auf normaler Art und Weise die Beine brechen +config.ebwizardry.creative_bypasses_arcane_lock=Umgehung der Arkanen Sperre +config.ebwizardry.creative_bypasses_arcane_lock.tooltip=Bestimmt, welche Spieler arkane Sperren umgehen können. +config.ebwizardry.creative_bypasses_arcane_lock.true=Jeder im kreativen Modus +config.ebwizardry.creative_bypasses_arcane_lock.false=Nur Operationen im kreativen Modus +config.ebwizardry.slow_time_affects_players=Langsame Zeit beeinflusst die Spieler +config.ebwizardry.slow_time_affects_players.tooltip=Ob die Spieler verlangsamt werden, wenn ein anderer Spieler in der Nähe den Zeit-Zauber benutzt. Wenn dieser deaktiviert ist, sind Mobs und Geschosse immer noch betroffen, aber die Spieler bewegen sich mit normaler Geschwindigkeit. +config.ebwizardry.bonemeal_grows_crystal_flowers=Knochenmehl züchtet Kristallblumen +config.ebwizardry.bonemeal_grows_crystal_flowers.tooltip=Ob die Verwendung von Knochenmehl auf Grasblöcken eine Chance hat, Kristallblumen wachsen zu lassen. +config.ebwizardry.mob_loot_table_whitelist=Whitelist für die Beute der Mobs +config.ebwizardry.mob_loot_table_whitelist.tooltip=Whitelist für Beute-Tabellen, in die zusätzliche Mob-Drops (wie in loot_tables/entities/mob_additions.json angegeben) injiziert werden können. Zauberei rät am besten, welche Beute-Tabellen zu feindlichen Mobs gehören, aber das ist nicht immer korrekt oder angemessen; fügen Sie die Orte der Beute-Tabellen (nicht Entitäts-IDs) zu dieser Liste hinzu, um sie manuell aufzunehmen. +config.ebwizardry.mob_loot_table_blacklist=Blacklist für die Beute der Mobs +config.ebwizardry.mob_loot_table_blacklist.tooltip=Blacklist für Beute-Tabellen, in die zusätzliche Mob-Drops (wie in loot_tables/entities/mob_additions.json angegeben) injiziert werden können. Zauberei rät am besten, welche Beute-Tabellen zu feindlichen Mobs gehören, aber das ist nicht immer korrekt oder angemessen; fügen Sie die Orte der Beute-Tabellen (nicht Entitäts-IDs) zu dieser Liste hinzu, um sie manuell aufzunehmen. +config.ebwizardry.mob_spawn_dimensions=Dimensionen des Mob-Spawnings +config.ebwizardry.mob_spawn_dimensions.tooltip=Liste von IDs von Dimensionen, in denen feindliche Mobs der Zauberei brüten können. +config.ebwizardry.mob_spawn_biome_blacklist=Biom Blacklist für Mobs +config.ebwizardry.mob_spawn_biome_blaclist.tooltip=Liste mit Namen von Biomen, in denen die feindlichen Mobs der Zauberei nicht spawnen können. Bei den Namen von Biomen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Biomen wird der Mod-ID ein Präfix vorangestellt (z.B. biomesoplenty\:mystic_grove). +config.ebwizardry.evil_wizard_spawn_rate=Böser Zauberer Spawn-Rate +config.ebwizardry.evil_wizard_spawn_rate.tooltip=Spawnrate für natürlich gespawnte böse Zauberer; höhere Zahlen bedeuten, dass mehr böse Zauberer spawnen werden. 5 entspricht Hexen, 100 entspricht Zombies, Skeletten und Kriechtieren. Setzen Sie den Wert 0, um das spawnen böser Zauberer vollständig zu deaktivieren. +config.ebwizardry.ice_wraith_spawn_rate=Eis-Geist Spawn Rate +config.ebwizardry.ice_wraith_spawn_rate.tooltip=Spawnrate für natürlich gespawnte Eis-Geister; höhere Zahlen bedeuten, dass mehr Eis-Geister spawnen werden. 5 entspricht Hexen, 100 entspricht Zombies, Skeletten und Kriechtieren. Setzen Sie den Wert 0, um das spawnen von Eis-Geistern vollständig zu deaktivieren. +config.ebwizardry.lightning_wraith_spawn_rate=Blitz-Geist +config.ebwizardry.lightning_wraith_spawn_rate.tooltip=Spawnrate für natürlich gespawnte Blitz-Geister; höhere Zahlen bedeuten, dass mehr Blitz-Geister spawnen werden. 5 entspricht Hexen, 100 entspricht Zombies, Skeletten und Kriechtieren. Setzen Sie den Wert 0, um das spawnen von Blitz-Geistern vollständig zu deaktivieren. +config.ebwizardry.forfeit_chance=Chance verpassen +config.ebwizardry.forfeit_chance.tooltip=Die Chance, einen unentdeckten Zauberspruch "falsch zu lesen" und stattdessen eine Strafe auszulösen. Wenn Sie diesen Wert auf 0 setzen, wird die Strafe deaktiviert. Hat keine Auswirkung, wenn der Entdeckungsmodus deaktiviert ist. +config.ebwizardry.player_damage_scaling=Skalierungsfaktor für Spielerschäden +config.ebwizardry.player_damage_scaling.tooltip=Globaler Schadensskalierungsfaktor für den von den Zaubernden verursachten Schaden, relativ zu 1. +config.ebwizardry.npc_damage_scaling=NPC-Schadensskalierungsfaktor +config.ebwizardry.npc_damage_scaling.tooltip=Globaler Schadensskalierungsfaktor für den von NSCs verursachten Schaden, relativ zu 1. +config.ebwizardry.summoned_creature_targets_whitelist=Whitelist der beschworenen Kreatur +config.ebwizardry.summoned_creature_targets_whitelist.tooltip=Liste mit den Namen der Einheiten, die Kreaturen und Zauberer beschwören, die angreifen dürfen. Fügen Sie Mod-Kreaturen zu dieser Liste hinzu, wenn Sie möchten, dass beschworene Kreaturen sie angreifen, und sie dies nicht bereits tun. Bei den Namen von Entitäten wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Kreaturen ist der Mod-ID ein Präfix voranzustellen (z.B. ebwizardry\:wizard). +config.ebwizardry.summoned_creature_targets_blacklist=Blacklist der beschworenen Kreatur +config.ebwizardry.summoned_creature_targets_blacklist.tooltip=Liste mit den Namen der Wesen, die Kreaturen und Zauberer beschworen haben, die ausdrücklich nicht angreifen dürfen, wobei die Vorgaben und die Whitelist außer Kraft gesetzt werden. Fügen Sie Kreaturen zu dieser Liste hinzu, wenn das Zulassen eines Angriffs Probleme verursacht oder zu zerstörerisch ist (das Entfernen von Creepern aus dieser Liste erfolgt auf eigene Gefahr!). Bei den Namen der Entitäten wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Entitäten ist die Mod-ID voranzustellen (z.B. ebwizardry\:wizard). +config.ebwizardry.mind_control_targets_blacklist=Blacklist von Gedankenkontrolle-Zielen +config.ebwizardry.mind_control_targets_blacklist.tooltip=Liste der Namen von Entitäten, die nicht durch den Verstand kontrolliert werden können, zusätzlich zu den Standardeinstellungen. Fügen Sie dieser Liste Geschöpfe hinzu, wenn die Möglichkeit, sie gedankenkontrolliert zu lassen, Probleme verursacht oder ausgenutzt werden könnte. Bei den Namen von Entitäten wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Entitäten wird die Mod-ID vorangestellt (z.B. ebwizardry\:wizard). +config.ebwizardry.pocket_furnace_item_blacklist=Blacklist für Taschenöfen +config.ebwizardry.pocket_furnace_item_blacklist.tooltip=Liste der Registernamen von Blöcken oder Gegenständen, die durch den Taschenofenzauber nicht geschmolzen werden können, zusätzlich zu Rüstungen, Werkzeugen und Waffen. Bei den Namen von Blöcken/Gegenständen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Gegenständen ist die Mod-ID voranzustellen (z.B. ebwizardry\:crystal_ore). +config.ebwizardry.divination_ore_whitelist=Wahrsagerei-Erz-Whiteliste +config.ebwizardry.divination_ore_whitelist.tooltip=Liste der Registernamen von Erzblöcken, die durch den Weissagungszauber erkannt werden können. Bei den Blocknamen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Blöcken wird die Mod-ID vorangestellt (z.B. ebwizardry\:crystal_ore). +config.ebwizardry.sword_item_whitelist=Schwert Item Whitelist +config.ebwizardry.sword_item_whitelist.tooltip=Liste der Registrierungsnamen von Gegenständen, die als Schwerter für Schwert-Buff-Zauber gelten sollen. Die meisten Schwerter sollten automatisch funktionieren, aber diejenigen, die das nicht tun, können hier manuell hinzugefügt werden. Bei den Namen von Gegenständen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Elementen ist der Mod-ID ein Präfix voranzustellen (z.B. tconstruct:broadsword). +config.ebwizardry.bow_item_whitelist=Whitelist für Bögenartige Gegenstände +config.ebwizardry.bow_item_whitelist.tooltip=Liste der Registernamen von Gegenständen, die als Bogen für Bogenbuffende Zaubersprüche zählen sollten. Die meisten Bögen sollten automatisch funktionieren, aber diejenigen, die das nicht tun, können hier manuell hinzugefügt werden. Bei den Namen von Gegenständen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Elementen ist der Mod-ID ein Präfix voranzustellen (z.B. tconstruct:shortbow). +config.ebwizardry.currency_items=Gegenstände als Geldwährung +config.ebwizardry.currency_items.tooltip=Liste der Registrierungsnamen von Objekten, die vom Zauberer als Währung verwendet werden können (im ersten Slot; der zweite Slot ist davon nicht betroffen). Jeder Eintrag in dieser Liste sollte aus einem Namen des Registers bestehen, gefolgt von einem einzelnen Leerzeichen, dann einer ganzen Zahl, die den "Wert" des Artikels definiert. Höhere Werte bedeuten, dass für einen bestimmten Handel weniger dieser Währungsposten benötigt werden. + +config.ebwizardry.category.worldgen=Einstellungen der Weltgeneration +config.ebwizardry.category.worldgen.tooltip=Konfigurieren Sie die Weltgenerationsfunktionen der Zauberei +config.ebwizardry.title.worldgen=Einstellungen der Weltgeneration +config.ebwizardry.subtitle.worldgen=Einstellungen, die die Welterzeugung beeinflussen. + +config.ebwizardry.fast_worldgen=Struktur-Generierung +config.ebwizardry.fast_worldgen.tooltip=Steuert, welche Algorithmus Zauberei für die Strukturerzeugung verwendet werden. Fancy worldgen verhindert Strukturen auf Klippen, in Höhlen und beim Überschneiden anderer Strukturen und räumt nach der Generierung schwimmende Bäume auf. Fast worldgen verzichtet auf diese Verbesserungen, was möglicherweise zu einer schnelleren Weltgenerierung führt. Die Leistungsverbesserung hängt von Ihrem Setup ab. Diese Option wirkt sich auf die Randomisierung aus; bei einem bestimmten Seed sind die Strukturen nicht die gleichen wie beim Ausschalten. +config.ebwizardry.fast_worldgen.true=Schnell +config.ebwizardry.fast_worldgen.false=Schön +config.ebwizardry.tower_dimensions=Dimensionen von Zauberer-Türmen +config.ebwizardry.tower_dimensions.tooltip=Liste der IDs der Dimensionen, in denen Zauberer-Türme generiert werden. Entfernen Sie alle Dimensionen, um die Zauberer-Türme vollständig zu deaktivieren. +config.ebwizardry.tower_rarity=Turm-Wahrscheinlichkeit +config.ebwizardry.tower_rarity.tooltip=Seltenheit der Zaubertürme. 1 wird machen, dass Chunks viele Zaubertürme enthalten, was bedeutet, dass sie bei höheren Zahlen seltener sind. +config.ebwizardry.evil_wizard_chance=Böse Zauberer Wahrscheinlichkeit +config.ebwizardry.evil_wizard_chance.tooltip=Die Chance für Zaubertürme mit einem bösen Zauberer und einer Truhe im Inneren statt eines freundlichen Zauberers zu generieren. +config.ebwizardry.tower_files=Dateien zur Turmstruktur +config.ebwizardry.tower_files.tooltip=Liste der Strukturdateistellen für Zaubertürme ohne Lootkisten. Eine dieser Dateien wird jedes Mal, wenn ein Wizard-Turm generiert wird, zufällig ausgewählt. Die Dateispeicherorte haben das Format [mod id]\:[filename], das sich auf die Datei assets/[mod id]/structures/[filename].nbt bezieht. Doppelte Einträge sind erlaubt, was eine einfache Gewichtung ermöglicht, ohne die Strukturdateien selbst zu duplizieren. Diese Liste sollte nicht leer sein; um die Wizard-Türme zu deaktivieren, verwenden Sie die Einstellung in der Sie Türmegeneration deaktivieren. +config.ebwizardry.tower_with_chest_files=Turm mit Truhenstrukturdateien +config.ebwizardry.tower_with_chest_files.tooltip=Liste der Strukturdateistellen für Zaubertürme ohne Lootkisten. Eine dieser Dateien wird jedes Mal, wenn ein Wizard-Turm generiert wird, zufällig ausgewählt. Die Dateispeicherorte haben das Format [mod id]\:[filename], das sich auf die Datei assets/[mod id]/structures/[filename].nbt bezieht. Doppelte Einträge sind erlaubt, was eine einfache Gewichtung ermöglicht, ohne die Strukturdateien selbst zu duplizieren. Diese Liste sollte nicht leer sein; um die Wizard-Türme zu deaktivieren, verwenden Sie die Einstellung in der Sie Türmegeneration deaktivieren. +config.ebwizardry.obelisk_dimensions=Obelisk - Dimensionen +config.ebwizardry.obelisk_dimensions.tooltip=Liste der ids der Dimensionen, in denen Obelisken generiert werden. Entfernen Sie alle Dimensionen, um die Obelisken vollständig zu deaktivieren. +config.ebwizardry.obelisk_rarity=Obelisk Wahrscheinlichkeit +config.ebwizardry.obelisk_rarity.tooltip=Seltenheit der Obelisken. 1 wird in vielen Chunks einen Obelisken enthalten, mit höheren Zahlen werden sie seltener. +config.ebwizardry.obelisk_files=Obelisk-Struktur-Dateien +config.ebwizardry.obelisk_files.tooltip=Liste der Speicherorte von Strukturdateien für Obelisken. Eine dieser Dateien wird bei jeder Generierung eines Obelisken nach dem Zufallsprinzip ausgewählt. Die Speicherorte der Dateien haben das Format [mod id]\:[filename], das sich auf die Datei assets/[mod id]/structures/[filename].nbt bezieht. Doppelte Einträge sind erlaubt, was eine einfache Gewichtung ermöglicht, ohne die Strukturdateien selbst zu duplizieren. Diese Liste sollte nicht leer sein; um Obelisken zu deaktivieren, verwenden Sie die Obelisken-Generations-Einstellung. +config.ebwizardry.shrine_dimensions=Schrein - Dimensionen +config.ebwizardry.shrine_dimensions.tooltip=Liste der ids der Dimensionen, in denen Schreine entstehen werden. Entfernen Sie alle Dimensionen, um Schreine vollständig zu deaktivieren. +config.ebwizardry.shrine_rarity=Schrein Wahrscheinlichkeit +config.ebwizardry.shrine_rarity.tooltip=Seltenheit der Schreine. 1 wird in vielen Chunks einen Schrein enthalten, mit höheren Zahlen werden sie seltener. +config.ebwizardry.shrine_files=Schrein-Struktur-Dateien +config.ebwizardry.shrine_files.tooltip=Liste der Strukturdateistellen für Schrein-Lootkisten. Eine dieser Dateien wird jedes Mal, wenn ein Schrein generiert wird, in der liste geladen. Eine dieser Dateien wird bei jeder Generierung eines Schreins nach dem Zufallsprinzip ausgewählt. Die Speicherorte der Dateien haben das Format [mod id]\:[filename], das sich auf die Datei assets/[mod id]/structures/[filename].nbt bezieht. Doppelte Einträge sind erlaubt, was eine einfache Gewichtung ermöglicht, ohne die Strukturdateien selbst zu duplizieren. Diese Liste sollte nicht leer sein; um Schreine zu deaktivieren, verwenden Sie die Einstellung für die Abmessungen von Schreinen. +config.ebwizardry.tree_blocks=Baumblöcke +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).Liste der Registrierungsnamen von Blöcken, die von den Strukturgeneratoren von Wizardry überschrieben werden können, was sowohl die schnelle als auch die schöne Strukturerzeugung beeinflusst. Die meisten Baumblöcke und anderes Laub sollten automatisch funktionieren, aber die, die es nicht tun, können hier manuell hinzugefügt werden. Bei Blocknamen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Blöcken ist der Mod-ID ein Präfix voranzustellen (z.B. dynamictrees:oakbranch). +config.ebwizardry.ore_dimensions=Erz-Dimensionen +config.ebwizardry.ore_dimensions.tooltip=Liste von ids der Dimensionen, in denen das Kristallerz erzeugt wird. Beachten Sie, dass das Entfernen der normalen Welt (id 0) aus dieser Liste das Spielen der Mod SEHR schwierig macht! +config.ebwizardry.flower_dimensions=Flora Dimensionen +config.ebwizardry.flower_dimensions.tooltip=Liste von ids der Dimensionen, in denen Kristallblumen erzeugt werden. +config.ebwizardry.loot_injection_locations=Beute-Schnittstellen +config.ebwizardry.loot_injection_locations.tooltip=Liste der Beute-Tabellen, in die die Beute der Mod (wie in loot_tables/chests/dungeon_additions.json angegeben) injiziert werden soll. + +config.ebwizardry.category.client=Client-Einstellungen +config.ebwizardry.category.client.tooltip=Konfigurieren Sie die Anzeige und Bedienelemente der Wizardry Mod +config.ebwizardry.title.client=Client-Einstellungen +config.ebwizardry.subtitle.client=Client-seitige Einstellungen, die nur das lokale Minecraft betreffen. + +config.ebwizardry.shift_scrolling=Mit Shift scrollen +config.ebwizardry.shift_scrolling.tooltip=Ob Sie zwischen den Zaubern auf einem Zauberstab wechseln können, indem Sie beim Schleichen mit dem Mausrad scrollen. Beachten Sie, dass dies nur Sie betrifft; andere Spieler, die mit demselben Server verbunden sind, haben ihren eigenen Einstellungen. +config.ebwizardry.reverse_scroll_direction=Scroll Direction +config.ebwizardry.reverse_scroll_direction.tooltip=The scroll direction used to switch between spells on a wand while sneaking. +config.ebwizardry.reverse_scroll_direction.true=Umgekehrt +config.ebwizardry.reverse_scroll_direction.false=Normal +config.ebwizardry.spell_hud_position=HUD - Position der Zauber +config.ebwizardry.spell_hud_position.tooltip=Die Position des Zauber HUD´s. +config.ebwizardry.spell_hud_skin=Zauber - HUD Aussehen +config.ebwizardry.spell_hud_skin.tooltip=Ändern Sie das Aussehen des Zaubers HUD... +config.ebwizardry.spell_hud_skin.preview=Vorschau +config.ebwizardry.handbook_progression=Handbuch Fortschritt +config.ebwizardry.handbook_progression.tooltip=Wenn diese Option aktiviert ist, um die Spieler durch den Mod zu führen, werden Abschnitte des Handbuchs von Wizardry freigeschaltet, wenn ein Spieler den Fortschritt erzielt, der ihn auslöst, und andernfalls ausgeblendet. Wenn diese Option deaktiviert ist, ist das gesamte Handbuch unabhängig vom Aufstiegsfortschritt lesbar. Das gesamte Handbuch ist immer im Kreativmodus lesbar. +config.ebwizardry.handbook_progression.true=Ja - teach me, Sensei! +config.ebwizardry.handbook_progression.false=Nein - Ich weiß, was ich tue. +config.ebwizardry.books_pause_game=Bücher pausieren das Spiel +config.ebwizardry.books_pause_game.tooltip=Ob das Öffnen eines der Bücher der Zauberei das Spiel im Einzelspieler-Modus unterbricht. Hat keine Auswirkungen auf Server oder LAN-Welten. +config.ebwizardry.books_pause_game.true=Ja - ich will keine Störungen! +config.ebwizardry.books_pause_game.false=Nein - Ich lese, um mir die Zeit zu vertreiben +config.ebwizardry.summoned_creature_names=Namen von beschworenen Kreaturen +config.ebwizardry.summoned_creature_names.tooltip=Steuert, ob die Namen und Besitzer der beschworenen Kreaturen über ihren Köpfen angezeigt werden. +config.ebwizardry.summoned_creature_names.true=Angezeigt +config.ebwizardry.summoned_creature_names.false=Versteckt +config.ebwizardry.use_shaders=Benutzerdefinierte Shader verwenden +config.ebwizardry.use_shaders.tooltip=Ob für bestimmte Zaubersprüche benutzerdefinierte Shader verwendet werden sollen. Diese verwenden das Vanilla-Schattierungssystem (wie Mob-Schatten) und sollten in den meisten Fällen keine großen Auswirkungen auf die Leistung haben, aber sie können mit anderen Shadern in Konflikt geraten. +config.ebwizardry.use_shaders.true=Ja - gib mir die hübschen Shader! +config.ebwizardry.use_shaders.false=Nein - das Spiel läuft auf einer Kartoffel. + +config.ebwizardry.category.commands=Befehl Einstellungen +config.ebwizardry.category.commands.tooltip=Konfigurieren Sie die Befehle von Wizardry +config.ebwizardry.title.commands=Befehl Einstellungen +config.ebwizardry.subtitle.commands=Einstellungen für die durch Wizardry hinzugefügten Befehle. + +config.ebwizardry.cast_command_multiplier_limit=Cast Befehl Multiplikationsgrenze +config.ebwizardry.cast_command_multiplier_limit.tooltip=Obergrenze für die Multiplikatoren, die in den Befehl /cast übergeben werden. Damit soll verhindert werden, dass Spieler versehentlich einen World/Server zerstören. Große Explosions - Vielfachen können extreme lags verursachen - Sie wurden gewarnt! +config.ebwizardry.cast_command_name=Name des Befehls "Cast" +config.ebwizardry.cast_command_name.tooltip=Der Name des Befehls /cast. Diesen tippen Sie direkt nach dem /; wenn dieser z.B. auf 'magic' gesetzt wäre, würden Sie statt /cast /magic tippen. +config.ebwizardry.discoverspell_command_name=Name des Befehls der "Enthüllung" +config.ebwizardry.discoverspell_command_name.tooltip=Der Name des Befehls "/discoverspell". Diesen tippen Sie direkt nach dem /; wenn dieser z.B. auf 'magic' gesetzt wäre, würden Sie statt /discoverspell /magic tippen. +config.ebwizardry.ally_command_name="Ally" Befehlsnamen festlegen +config.ebwizardry.ally_command_name.tooltip=Der Name des Befehls /ally. Diesen tippen Sie direkt nach dem /; wenn dieser z.B. auf 'magic' gesetzt wäre, würden Sie statt /ally /magic tippen. +config.ebwizardry.allies_command_name=Befehlsname des Befehls"Ally" anzeigen +config.ebwizardry.allies_command_name.tooltip=Der Name des Befehls /allies. Diesen tippen Sie direkt nach dem /; wenn dieser beispielsweise auf "magic" gesetzt wäre, würden Sie statt /allies /magic tippen. + +config.ebwizardry.category.resistances=Resistenz-Konfiguration +config.ebwizardry.category.resistances.tooltip=Konfigurieren Sie, welche Mobs gegen verschiedene Arten von Magie immun sind +config.ebwizardry.title.resistances=Resistenz-Konfiguration +config.ebwizardry.subtitle.resistances=Einstellungen, die es ermöglichen, Wesen gegen bestimmte Arten von Magie immun zu machen. + +config.ebwizardry.mobs_immune_to_fire=Feuerwiderstandsfähige Mobs +config.ebwizardry.mobs_immune_to_fire.tooltip=Liste mit den Namen der Einheiten, die gegen Feuer immun sind, zusätzlich zu den Standardeinstellungen. Fügen Sie dieser Liste Mod-Kreaturen hinzu, wenn Sie möchten, dass sie gegen Feuermagie immun sind, und sie es nicht bereits sind. Bei den Namen von Wesen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Kreaturen wird die Mod-ID vorangestellt (z.B. ebwizardry\:wizard). +config.ebwizardry.mobs_immune_to_ice=Mobs, die gegen Kälte immun sind +config.ebwizardry.mobs_immune_to_ice.tooltip=Liste mit den Namen der Entitäten, die gegen Eis immun sind, zusätzlich zu den Standardeinstellungen. Fügen Sie dieser Liste Mod-Kreaturen hinzu, wenn Sie möchten, dass diese gegen Eismagie immun sind. Bei den Namen der Wesen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Kreaturen wird die Mod-ID vorangestellt (z.B. ebwizardry\:wizard). +config.ebwizardry.mobs_immune_to_lightning=Gegen Blitze immune Mobs +config.ebwizardry.mobs_immune_to_lightning.tooltip=Liste mit den Namen der Kreaturen, die gegen Blitzschlag immun sind, zusätzlich zu den Standardeinstellungen. Fügen Sie dieser Liste Mod-Kreaturen hinzu, wenn Sie möchten, dass sie gegen Blitzmagie immun sind, und sie es nicht bereits sind. Bei den Namen der Wesen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Kreaturen wird die Mod-ID vorangestellt (z.B. ebwizardry\:wizard). +config.ebwizardry.mobs_immune_to_wither=Wither - Resistente Mobs +config.ebwizardry.mobs_immune_to_wither.tooltip=Liste der Namen von Entitäten, die zusätzlich zu den Standardeinstellungen gegen Withereffekte immun sind. Fügen Sie dieser Liste Mod-Kreaturen hinzu, wenn Sie möchten, dass sie gegen Wither Magie immun sind. Bei den Namen der Wesen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Kreaturen wird die Mod-ID vorangestellt (z.B. ebwizardry\:wizard). +config.ebwizardry.mobs_immune_to_poison=Mobs, die gegen Gift immun sind +config.ebwizardry.mobs_immune_to_poison.tooltip=Liste mit den Namen der Entitäten, die gegen Gift immun sind, zusätzlich zu den Standardwerten. Fügen Sie dieser Liste Mod-Kreaturen hinzu, wenn Sie möchten, dass sie gegen Giftmagie immun sind, und sie es nicht bereits sind. Bei den Namen der Wesen wird nicht zwischen Groß- und Kleinschreibung unterschieden. Bei Mod-Kreaturen wird die Mod-ID vorangestellt (z.B. ebwizardry\:wizard). + +config.ebwizardry.category.compatibility=Mod-Kompatibilitätseinstellungen +config.ebwizardry.category.compatibility.tooltip=Konfigurieren Sie, wie die Wizardry Mod mit anderen Mods interagieren +config.ebwizardry.title.compatibility=Mod-Kompatibilitätseinstellungen +config.ebwizardry.subtitle.compatibility=Einstellungen, die beeinflussen, wie die Wizardry Mod mit anderen Mods interagiert. + +config.ebwizardry.damage_source_blacklist=Schadensquellen Liste +config.ebwizardry.damage_source_blacklist.tooltip=Liste der Identifikatoren von Schadensursachen-Strings, die bei der erneuten Anwendung von Schäden zu ignorieren sind. Groß- und Kleinschreibung wird berücksichtigt. Eine Meldung wird protokolliert, wenn Wizardry eine Schadensquelle entdeckt, die zu dieser Liste hinzugefügt werden sollte. Andernfalls ändern Sie sie nicht, es sei denn, Sie werden dazu aufgefordert. +config.ebwizardry.compatibility_warnings=Kompatibilitäts-Warnungen +config.ebwizardry.compatibility_warnings.tooltip=Ob Kompatibilitätswarnungen über die Konsole erstellt werden sollen. Setzen Sie die Option auf false, wenn übermäßige Meldungen gespammt werden. +config.ebwizardry.baubles_integration=Integration von Baubles +config.ebwizardry.baubles_integration.tooltip=Wenn Baubles installiert ist, wird gesteuert, ob die Integrationsfunktionen von Baubles aktiviert sind. Wenn dies deaktiviert ist, verhält sich Wizardry immer so, als ob Baubles nicht installiert wäre. +config.ebwizardry.jei_integration=JEI-Integration +config.ebwizardry.jei_integration.tooltip=Wenn JEI (Just Enough Items) installiert ist, wird gesteuert, ob JEI-Integrationsfunktionen aktiviert sind. Wenn dies deaktiviert ist, verhält sich der Wizardry immer so, als ob JEI nicht installiert wäre. +config.ebwizardry.antique_atlas_integration=Integration von Antique Atlas +config.ebwizardry.antique_atlas_integration.tooltip=Wenn Antique Atlas installiert ist, wird gesteuert, ob die Integrationsfunktionen des Antique Atlas aktiviert sind. Wenn dies deaktiviert ist, verhält sich Wizardry immer so, als ob Antique Atlas nicht installiert wäre. +config.ebwizardry.auto_place_tower_markers=Automatisches Setzen von Turmmarkierungen +config.ebwizardry.auto_place_tower_markers.tooltip=Steuert, ob die Zauberei automatisch Atlasmarker an den Standorten der Zaubertürme platziert. +config.ebwizardry.auto_place_obelisk_markers=Obelisken-Markierungen automatisch platzieren +config.ebwizardry.auto_place_obelisk_markers.tooltip=Steuert, ob Wizardry automatisch Atlasmarkierungen an den Stellen der Obelisken platziert. +config.ebwizardry.auto_place_shrine_markers=Schrein-Markierungen automatisch platzieren +config.ebwizardry.auto_place_shrine_markers.tooltip=Steuert, ob Wizardry automatisch Atlasmarkierungen an den Stellen der Schreine platziert. + +integration.jei.category.ebwizardry\:arcane_workbench=Akarner Zaubertisch + +integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Zaubererturm +integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk +integration.antiqueatlas.marker.ebwizardry\:shrine=Schrein + +spell.ebwizardry\:magic_missile_festive=Magisches - Raketenfest +spell.ebwizardry\:summon_snow_golem_festive=Erschaffe Frosty The Snowman +spell.ebwizardry\:invigorating_presence_festive=Ermächtigende Präsenz +spell.ebwizardry\:empowering_presence_festive=Magisch-Ermächtigende Präsenz + +wizard.debug=%1$s, %2$s, %3$s \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index eb8431d8..bf38dfc9 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -1,4 +1,4 @@ -#PARSE_ESCAPES +# PARSE_ESCAPES tile.ebwizardry\:arcane_workbench.name=Arcane Workbench tile.ebwizardry\:crystal_ore.name=Crystal Ore tile.ebwizardry\:petrified_stone.name=Petrified Stone @@ -44,8 +44,7 @@ item.ebwizardry\:spell_book.name=Spell Book item.ebwizardry\:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s item.ebwizardry\:arcane_tome.name=Tome of Arcana -item.ebwizardry\:arcane_tome.desc1=Upgrades any %1$s -item.ebwizardry\:arcane_tome.desc2=wand to %1$s tier +item.ebwizardry\:arcane_tome.desc=Upgrades any %1$s wand with sufficient progression to %2$s tier item.ebwizardry\:wizard_handbook.name=The Wizard's Handbook item.ebwizardry\:wizard_handbook.desc=by %1$s @@ -499,6 +498,13 @@ advancement.ebwizardry\:enchant_scroll.desc=Craft a blank scroll and enchant it handbook.toast.title=New Handbook Section Unlocked! +gui.ebwizardry\:spell_book.tier=Tier: %s +gui.ebwizardry\:spell_book.element=Element: %s +gui.ebwizardry\:spell_book.element_undiscovered=Element: ? +gui.ebwizardry\:spell_book.mana_cost=Mana Cost: %s +gui.ebwizardry\:spell_book.mana_cost_continuous=Mana Cost: %s/second +gui.ebwizardry\:spell_book.mana_cost_undiscovered=Mana Cost: ? + container.ebwizardry\:arcane_workbench=Arcane Workbench container.ebwizardry\:arcane_workbench.apply=Apply container.ebwizardry\:arcane_workbench.mana=Mana\: @@ -1117,6 +1123,8 @@ config.ebwizardry.creative_bypasses_arcane_lock.true=Anyone in creative mode config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode config.ebwizardry.slow_time_affects_players=Slow Time Affects Players config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed. +config.ebwizardry.bonemeal_grows_crystal_flowers=Bonemeal Grows Crystal Flowers +config.ebwizardry.bonemeal_grows_crystal_flowers.tooltip=Whether using bonemeal on grass blocks has a chance to grow crystal flowers. config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist config.ebwizardry.mob_loot_table_whitelist.tooltip=Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them. config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist @@ -1164,27 +1172,27 @@ config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses f config.ebwizardry.fast_worldgen.true=Fast config.ebwizardry.fast_worldgen.false=Fancy 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.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.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.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.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.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.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.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.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.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.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.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 @@ -1283,8 +1291,13 @@ config.ebwizardry.auto_place_shrine_markers.tooltip=Controls whether wizardry au integration.jei.category.ebwizardry\:arcane_workbench=Arcane Workbench -integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wizard Tower -integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk -integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine +integration.antiqueatlas.marker.ebwizardry.wizard_tower=Wizard Tower +integration.antiqueatlas.marker.ebwizardry.obelisk=Obelisk +integration.antiqueatlas.marker.ebwizardry.shrine=Shrine + +spell.ebwizardry\:magic_missile_festive=Magic Mistletoe +spell.ebwizardry\:summon_snow_golem_festive=Summon Frosty The Snowman +spell.ebwizardry\:invigorating_presence_festive=Invigorating Presents +spell.ebwizardry\:empowering_presence_festive=Empowering Presents wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index f5c08bbf..0a7269e9 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -44,8 +44,7 @@ item.ebwizardry\:spell_book.name=Spell Book item.ebwizardry\:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s item.ebwizardry\:arcane_tome.name=Tome of Arcana -item.ebwizardry\:arcane_tome.desc1=Upgrades any %1$s -item.ebwizardry\:arcane_tome.desc2=wand to %1$s tier +item.ebwizardry\:arcane_tome.desc=Upgrades any %1$s wand with sufficient progression to %2$s tier item.ebwizardry\:wizard_handbook.name=The Wizard's Handbook item.ebwizardry\:wizard_handbook.desc=by %1$s @@ -499,6 +498,13 @@ advancement.ebwizardry\:enchant_scroll.desc=Craft a blank scroll and enchant it handbook.toast.title=New Handbook Section Unlocked! +gui.ebwizardry\:spell_book.tier=Tier: %s +gui.ebwizardry\:spell_book.element=Element: %s +gui.ebwizardry\:spell_book.element_undiscovered=Element: ? +gui.ebwizardry\:spell_book.mana_cost=Mana Cost: %s +gui.ebwizardry\:spell_book.mana_cost_continuous=Mana Cost: %s/second +gui.ebwizardry\:spell_book.mana_cost_undiscovered=Mana Cost: ? + container.ebwizardry\:arcane_workbench=Arcane Workbench container.ebwizardry\:arcane_workbench.apply=Apply container.ebwizardry\:arcane_workbench.mana=Mana\: @@ -1117,6 +1123,8 @@ config.ebwizardry.creative_bypasses_arcane_lock.true=Anyone in creative mode config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode config.ebwizardry.slow_time_affects_players=Slow Time Affects Players config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed. +config.ebwizardry.bonemeal_grows_crystal_flowers=Bonemeal Grows Crystal Flowers +config.ebwizardry.bonemeal_grows_crystal_flowers.tooltip=Whether using bonemeal on grass blocks has a chance to grow crystal flowers. config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist config.ebwizardry.mob_loot_table_whitelist.tooltip=Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them. config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist @@ -1164,27 +1172,27 @@ config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses f config.ebwizardry.fast_worldgen.true=Fast config.ebwizardry.fast_worldgen.false=Fancy 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.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.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.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.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.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.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.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.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.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.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.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 @@ -1283,8 +1291,13 @@ config.ebwizardry.auto_place_shrine_markers.tooltip=Controls whether wizardry au integration.jei.category.ebwizardry\:arcane_workbench=Arcane Workbench -integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wizard Tower -integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk -integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine +integration.antiqueatlas.marker.ebwizardry.wizard_tower=Wizard Tower +integration.antiqueatlas.marker.ebwizardry.obelisk=Obelisk +integration.antiqueatlas.marker.ebwizardry.shrine=Shrine + +spell.ebwizardry\:magic_missile_festive=Magic Mistletoe +spell.ebwizardry\:summon_snow_golem_festive=Summon Frosty The Snowman +spell.ebwizardry\:invigorating_presence_festive=Invigorating Presents +spell.ebwizardry\:empowering_presence_festive=Empowering Presents wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/pl_pl.lang b/src/main/resources/assets/ebwizardry/lang/pl_pl.lang index d993dd91..d474ae3a 100644 --- a/src/main/resources/assets/ebwizardry/lang/pl_pl.lang +++ b/src/main/resources/assets/ebwizardry/lang/pl_pl.lang @@ -1272,8 +1272,8 @@ config.ebwizardry.auto_place_shrine_markers.tooltip=Kontroluje, czy Wizardry aut integration.jei.category.ebwizardry\:arcane_workbench=Tajmniczny Stół -integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wieża Czarodzieja -integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk -integration.antiqueatlas.marker.ebwizardry\:shrine=Świątynia +integration.antiqueatlas.marker.ebwizardry.wizard_tower=Wieża Czarodzieja +integration.antiqueatlas.marker.ebwizardry.obelisk=Obelisk +integration.antiqueatlas.marker.ebwizardry.shrine=Świątynia wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/ru_ru.lang b/src/main/resources/assets/ebwizardry/lang/ru_ru.lang index 0a5fdac1..cd4822de 100644 --- a/src/main/resources/assets/ebwizardry/lang/ru_ru.lang +++ b/src/main/resources/assets/ebwizardry/lang/ru_ru.lang @@ -7,8 +7,30 @@ tile.ebwizardry:snare.name=Ловушка tile.ebwizardry:transportation_stone.name=Камень Транспортировки tile.ebwizardry:spectral_block.name=Спектральный Блок tile.ebwizardry:crystal_block.name=Кристальный Блок +tile.ebwizardry:runestone.name=Рунический камень +tile.ebwizardry:runestone_pedestal.name=Пьедестал рунического камня +tile.ebwizardry:thorns.name=Колючки +tile.ebwizardry:obsidian_crust.name=Обсидиановая кора +tile.ebwizardry:dry_frosted_ice.name=Сухой матовый лед + +tile.ebwizardry:magic_crystal_block.name=Блок кристалла +tile.ebwizardry:fire_crystal_block.name=Блок огненного кристалла +tile.ebwizardry:ice_crystal_block.name=Блок ледяного кристалла +tile.ebwizardry:lightning_crystal_block.name=Блок грозового кристалла +tile.ebwizardry:necromancy_crystal_block.name=Блок темного кристалла +tile.ebwizardry:earth_crystal_block.name=Блок зеленого кристалла +tile.ebwizardry:sorcery_crystal_block.name=Блок мистического кристалла +tile.ebwizardry:healing_crystal_block.name=Блок сияющего кристалла + +item.ebwizardry:crystal_magic.name=Магический Кристалл +item.ebwizardry:crystal_fire.name=Огненный кристалл +item.ebwizardry:crystal_ice.name=Ледяной кристалл +item.ebwizardry:crystal_lightning.name=Грозовой кристалл +item.ebwizardry:crystal_necromancy.name=Темный кристалл +item.ebwizardry:crystal_earth.name=Зелёный кристалл +item.ebwizardry:crystal_sorcery.name=Мистический кристалл +item.ebwizardry:crystal_healing.name=Сияющий кристалл -item.ebwizardry:magic_crystal.name=Магический Кристалл item.ebwizardry:magic_wand.name=Волшебный Жезл item.ebwizardry:apprentice_wand.name=Жезл Ученика item.ebwizardry:advanced_wand.name=Продвинутый Жезл @@ -62,7 +84,21 @@ item.ebwizardry:spectral_sword.name=Спектральный Меч item.ebwizardry:spectral_pickaxe.name=Спектральная Кирка item.ebwizardry:spectral_bow.name=Спектральный Лук -item.ebwizardry:mana_flask.name=Бутылка Маны +item.ebwizardry:spectral_sword_upgraded.name=Спектральный Меч +item.ebwizardry:spectral_pickaxe_upgraded.name=Спектральная Кирка + +item.ebwizardry:small_mana_flask.name=Маленькая Бутылка Маны +item.ebwizardry:medium_mana_flask.name=Средняя Бутылка Маны +item.ebwizardry:large_mana_flask.name=Большая Бутылка Маны + +item.ebwizardry:grand_crystal.name=Большой Магический Кристалл +item.ebwizardry:crystal_shard.name=Осколок Магического Кристалла + +item.ebwizardry:astral_diamond.name=Звёздный Алмаз + +item.ebwizardry:purifying_elixir.name=Очищающий Эликсир +item.ebwizardry:purifying_elixir.desc=Снимает проклятия при употреблении + item.ebwizardry:storage_upgrade.name=Улучшение Хранилища Маны Жезла item.ebwizardry:siphon_upgrade.name=Улучшение Сифона Жезла item.ebwizardry:condenser_upgrade.name=Улучшение Конденсатора Жезла @@ -75,9 +111,13 @@ item.ebwizardry:attunement_upgrade.name=Улучшение Хранилища З item.ebwizardry:flaming_axe.name=Огненный Топор item.ebwizardry:frost_axe.name=Ледяной Топор +item.ebwizardry:flaming_axe_upgraded.name=Огненный Топор +item.ebwizardry:frost_axe_upgraded.name=Ледяной Топор + item.ebwizardry:firebomb.name=Огненная Бомба item.ebwizardry:poison_bomb.name=Ядовитая Бомба item.ebwizardry:smoke_bomb.name=Дымовая Бомба +item.ebwizardry:spark_bomb.name=Бомба Искр item.ebwizardry:blank_scroll.name=Пустой Свиток item.ebwizardry:scroll.name=Свиток %1$s @@ -137,6 +177,75 @@ item.ebwizardry:wizard_leggings_healing.name=Поножи Целителя item.ebwizardry:wizard_boots_healing.name=Ботинки Целителя item.ebwizardry:spawn_wizard.name=Спаун Волшебника +item.ebwizardry:spawn_evil_wizard.name=Спаун Злого Волшебника + +item.ebwizardry:spectral_helmet.name=Призрачный шлем +item.ebwizardry:spectral_chestplate.name=Призрачный нагрудник +item.ebwizardry:spectral_leggings.name=Призрачные поножи +item.ebwizardry:spectral_boots.name=Призрачные ботинки + +item.ebwizardry:lightning_hammer.name=Молот Шторма + +item.ebwizardry:ring_condensing.name=Кольцо Конденсации +item.ebwizardry:ring_condensing.desc=Медленно восстанавливает ману для всех жезлов на вашем хотбаре +item.ebwizardry:ring_siphoning.name=Кольцо Сифонинга +item.ebwizardry:ring_siphoning.desc=Увеличивает сифоновую ману на 30 %% +item.ebwizardry:ring_battlemage.name=Кольцо Боевого Мага +item.ebwizardry:ring_battlemage.desc=Держа палочку в руке и меч в основной руке, вы получаете 10 %% дополнительного магического урона +item.ebwizardry:ring_combustion.name=Кольцо Горения +item.ebwizardry:ring_combustion.desc=Существа, убитые огненными заклинаниями, взрываются +item.ebwizardry:ring_fire_melee.name=Кольцо Огненного Прикосновения +item.ebwizardry:ring_fire_melee.desc=Удар по существу огненной палочкой поджигает его +item.ebwizardry:ring_fire_biome.name=Кольцо Пустынного Солнца +item.ebwizardry:ring_fire_biome.desc=Огненные заклинания на 30% более сильны в горячих биомах +item.ebwizardry:ring_disintegration.name=Кольцо Раскаленных Углей +item.ebwizardry:ring_disintegration.desc=Все заклинания огненной атаки разрушают их жертв +item.ebwizardry:ring_ice_melee.name=Кольцо Ледяного Прикосновения +item.ebwizardry:ring_ice_melee.desc=Удар по существу ледяной палочкой дает эффект обморожения +item.ebwizardry:ring_ice_biome.name=Кольцо Оледенения +item.ebwizardry:ring_ice_biome.desc=Заклинания льда в снежных биомах на 30% более мощные +item.ebwizardry:ring_arcane_frost.name=Кольцо Чародейского Мороза +item.ebwizardry:ring_arcane_frost.desc=Существа, убитые ледяными заклинаниями, выпускают осколки льда во всех направлениях +item.ebwizardry:ring_shattering.name=Кольцо Разрушителя +item.ebwizardry:ring_shattering.desc=Атаки ближнего боя на мобов с эффектом обморожения могут разбить их на ледяные осколки +item.ebwizardry:ring_lightning_melee.name=Кольцо Цепи +item.ebwizardry:ring_lightning_melee.desc=Удар молнии о существо выстреливает молнией в другого находящегося поблизости существа +item.ebwizardry:ring_storm.name=Кольцо Собирающейся Бури +item.ebwizardry:ring_storm.desc=Во время грозы заклинания молнии резко сокращают время восстановления +item.ebwizardry:ring_seeking.name=Кольцо Притяжения +item.ebwizardry:ring_seeking.desc=Все снарядовые заклинания ищут свои цели +item.ebwizardry:ring_hammer.name=Кольцо Талека Всемогущего +item.ebwizardry:ring_hammer.desc=Молнии могут быть подняты и брошены +item.ebwizardry:ring_soulbinding.name=Кольцо Странника Душ +item.ebwizardry:ring_soulbinding.desc=Существа, поврежденные заклинаниями некромантии, становятся привязанными к вам +item.ebwizardry:ring_leeching.name=Кольцо Пиявки +item.ebwizardry:ring_leeching.desc=Все атаки некромантии с вероятностью 30% могут вызвать эффект истощения жизни +item.ebwizardry:ring_necromancy_melee.name=Кольцо Некротического Прикосновения +item.ebwizardry:ring_necromancy_melee.desc=Удар по существу с помощью палочки некромантии дает ему эффект увядания +item.ebwizardry:ring_mind_control.name=Кольцо Экстрасенса +item.ebwizardry:ring_mind_control.desc=Контролируемые разумом существа могут контролировать свои близлежащие существа +item.ebwizardry:ring_poison.name=Кольцо Змеи +item.ebwizardry:ring_poison.desc=Все заклинания земли отравляют свою цель +item.ebwizardry:ring_earth_melee.name=Кольцо ядовитого прикосновения +item.ebwizardry:ring_earth_melee.desc=Удар по существу земной палочкой отравляет его +item.ebwizardry:ring_earth_biome.name=Кольцо Дриады +item.ebwizardry:ring_earth_biome.desc=Заклинания земли сильнее на 30% в лесах и крытых лесах +item.ebwizardry:ring_full_moon.name=Кольцо Воющего Волка +item.ebwizardry:ring_full_moon.desc=Земные заклинания резко сократили время восстановления при полной луне +item.ebwizardry:ring_extraction.name=Кольцо Извлечения +item.ebwizardry:ring_extraction.desc=Убийства заклинаниями магии дают бонус маны +item.ebwizardry:ring_mana_return.name=Кольцо Перфекциониста +item.ebwizardry:ring_mana_return.desc=Силовые стрелы, которые не попадают в цель, возвращают ману, которую они использовали к вашей палочке +item.ebwizardry:ring_blockwrangler.name=Кольцо Странника +item.ebwizardry:ring_blockwrangler.desc=Брошенные блоки наносят в два раза больше обычного урона +item.ebwizardry:ring_conjurer.name=Кольцо фокусника +item.ebwizardry:ring_conjurer.desc=Колдовские вещи длятся в два раза дольше +item.ebwizardry:ring_defender.name=Кольцо Защитника +item.ebwizardry:ring_defender.desc=Ваши снаряды проходят через силовые поля, принадлежащие вам или союзнику +item.ebwizardry:ring_paladin.name=Кольцо Паладина +item.ebwizardry:ring_paladin.desc=Когда вы исцеляете себя или союзника, близлежащие союзники также получают немного здоровья +item.ebwizardry:ring_interdiction.name=Кольцо Запрета +item.ebwizardry:ring_interdiction.desc=Ваше силовое поле наносит урон существам, которые его касаются entity.ebwizardry:zombie_minion.name=Зомби entity.ebwizardry:skeleton_minion.name=Скелет @@ -609,4 +718,4 @@ config.ebwizardry.show_summoned_creature_names=Show Summoned Creature Names config.ebwizardry.spell_hud_position=Spell HUD Position config.ebwizardry.category.spells=Configure Spells -config.ebwizardry.category.spells.tooltip=Select which spells are enabled. \ No newline at end of file +config.ebwizardry.category.spells.tooltip=Select which spells are enabled. diff --git a/src/main/resources/assets/ebwizardry/lang/zh_cn.lang b/src/main/resources/assets/ebwizardry/lang/zh_cn.lang index 8580edc9..7c623ab8 100644 --- a/src/main/resources/assets/ebwizardry/lang/zh_cn.lang +++ b/src/main/resources/assets/ebwizardry/lang/zh_cn.lang @@ -1277,12 +1277,14 @@ config.ebwizardry.jei_integration.tooltip=若已下载 JEI,控制是否接受 config.ebwizardry.antique_atlas_integration=古式地图 联动 config.ebwizardry.antique_atlas_integration.tooltip=若已下载 古式地图,控制是否接受 古式地图 的特性。若关闭,则本模组视 古式地图 为不存在。 config.ebwizardry.auto_place_tower_markers=自动标记巫师塔 + config.ebwizardry.auto_place_tower_markers.tooltip=控制古式地图是否自动标记巫师塔。 config.ebwizardry.auto_place_obelisk_markers=自动标记方尖碑 config.ebwizardry.auto_place_obelisk_markers.tooltip=控制古式地图是否自动标记方尖碑。 config.ebwizardry.auto_place_shrine_markers=自动标记圣祠 config.ebwizardry.auto_place_shrine_markers.tooltip=控制古式地图是否自动标记圣祠。 + integration.jei.category.ebwizardry\:arcane_workbench=奥术工作台 integration.antiqueatlas.marker.ebwizardry.wizard_tower=巫师塔 diff --git a/src/main/resources/assets/ebwizardry/lang/zh_tw.lang b/src/main/resources/assets/ebwizardry/lang/zh_tw.lang new file mode 100644 index 00000000..095177d7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/lang/zh_tw.lang @@ -0,0 +1,1290 @@ +#PARSE_ESCAPES +tile.ebwizardry\:arcane_workbench.name=法術工作台 +tile.ebwizardry\:crystal_ore.name=水晶礦 +tile.ebwizardry\:petrified_stone.name=石化石頭 +tile.ebwizardry\:ice_statue.name=冰雕 +tile.ebwizardry\:crystal_flower.name=水晶花 +tile.ebwizardry\:snare.name=陷阱 +tile.ebwizardry\:transportation_stone.name=傳送石 +tile.ebwizardry\:transportation_stone.confirm=現在你施展%1$s法術後將返回這裡 +tile.ebwizardry\:transportation_stone.remember=記憶座標位置 %s, %s, %s 於世界: %s +tile.ebwizardry\:transportation_stone.forget=消除記憶座標位置 %s, %s, %s 於世界: %s +tile.ebwizardry\:transportation_stone.invalid=你必須先用8個傳送石圍成一圈! +tile.ebwizardry\:spectral_block.name=具現化方塊 +tile.ebwizardry\:runestone.name=符文石 +tile.ebwizardry\:runestone_pedestal.name=符文石座 +tile.ebwizardry\:thorns.name=荊棘 +tile.ebwizardry\:obsidian_crust.name=黑曜石殼 +tile.ebwizardry\:dry_frosted_ice.name=乾的結凍冰 + +tile.ebwizardry\:magic_crystal_block.name=魔法水晶方塊 +tile.ebwizardry\:fire_crystal_block.name=火焰水晶方塊 +tile.ebwizardry\:ice_crystal_block.name=寒冰水晶方塊 +tile.ebwizardry\:lightning_crystal_block.name=雷電水晶方塊 +tile.ebwizardry\:necromancy_crystal_block.name=黑暗水晶方塊 +tile.ebwizardry\:earth_crystal_block.name=碧綠水晶方塊 +tile.ebwizardry\:sorcery_crystal_block.name=神秘水晶方塊 +tile.ebwizardry\:healing_crystal_block.name=聖光水晶方塊 + +item.ebwizardry\:crystal_magic.name=魔法水晶 +item.ebwizardry\:crystal_fire.name=火焰水晶 +item.ebwizardry\:crystal_ice.name=寒冰水晶 +item.ebwizardry\:crystal_lightning.name=雷電水晶 +item.ebwizardry\:crystal_necromancy.name=黑暗水晶 +item.ebwizardry\:crystal_earth.name=碧綠水晶 +item.ebwizardry\:crystal_sorcery.name=神秘水晶 +item.ebwizardry\:crystal_healing.name=聖光水晶 + +item.ebwizardry\:magic_wand.name=基礎法杖 +item.ebwizardry\:apprentice_wand.name=學徒法杖 +item.ebwizardry\:advanced_wand.name=進階法杖 +item.ebwizardry\:master_wand.name=大師法杖 +item.ebwizardry\:spell_book.name=法術書 + +item.ebwizardry\:spell_book.apply_to_wizard=將%1$s的法術 %2$s換成%3$s + +item.ebwizardry\:arcane_tome.name=法術寶典 +item.ebwizardry\:arcane_tome.desc1=升級%1$s法杖 +item.ebwizardry\:arcane_tome.desc2=成為%1$s法杖 + +item.ebwizardry\:wizard_handbook.name=法師手冊 +item.ebwizardry\:wizard_handbook.desc=作者: %1$s + +item.ebwizardry\:wand.generic=法杖 + +item.ebwizardry\:wand.buff=+%1$s %2$s系潛能 +item.ebwizardry\:wand.spell=目前法術\: %1$s +item.ebwizardry\:wand.mana=法力\: %1$s/%2$s +item.ebwizardry\:wand.progression=成長度\: %1$s/%2$s + +item.ebwizardry\:wand.levelup=%1$s已準備好升級至%2$s等級 + +item.ebwizardry\:wand.addally=%1$s 已加入你的同伴名單 +item.ebwizardry\:wand.removeally=%1$s 已從你的同伴名單中刪除 + +item.ebwizardry\:novice_fire_wand.name=基礎火苗法杖 +item.ebwizardry\:novice_ice_wand.name=基礎冷凍法杖 +item.ebwizardry\:novice_lightning_wand.name=基礎電光法杖 +item.ebwizardry\:novice_necromancy_wand.name=基礎暗影法杖 +item.ebwizardry\:novice_earth_wand.name=基礎森林法杖 +item.ebwizardry\:novice_sorcery_wand.name=基礎神秘法杖 +item.ebwizardry\:novice_healing_wand.name=基礎治療法杖 + +item.ebwizardry\:apprentice_fire_wand.name=學徒烈焰法杖 +item.ebwizardry\:apprentice_ice_wand.name=學徒寒冰法杖 +item.ebwizardry\:apprentice_lightning_wand.name=學徒雷電法杖 +item.ebwizardry\:apprentice_necromancy_wand.name=學徒死靈法杖 +item.ebwizardry\:apprentice_earth_wand.name=學徒大地法杖 +item.ebwizardry\:apprentice_sorcery_wand.name=學徒秘術法杖 +item.ebwizardry\:apprentice_healing_wand.name=學徒治療法杖 + +item.ebwizardry\:advanced_fire_wand.name=進階烈焰法杖 +item.ebwizardry\:advanced_ice_wand.name=進階寒冰法杖 +item.ebwizardry\:advanced_lightning_wand.name=進階雷電法杖 +item.ebwizardry\:advanced_necromancy_wand.name=進階死靈法杖 +item.ebwizardry\:advanced_earth_wand.name=進階大地法杖 +item.ebwizardry\:advanced_sorcery_wand.name=進階秘術法杖 +item.ebwizardry\:advanced_healing_wand.name=進階治療法杖 + +item.ebwizardry\:master_fire_wand.name=大師烈焰法杖 +item.ebwizardry\:master_ice_wand.name=大師寒冰法杖 +item.ebwizardry\:master_lightning_wand.name=大師雷電法杖 +item.ebwizardry\:master_necromancy_wand.name=大師死靈法杖 +item.ebwizardry\:master_earth_wand.name=大師大地法杖 +item.ebwizardry\:master_sorcery_wand.name=大師秘術法杖 +item.ebwizardry\:master_healing_wand.name=大師治療法杖 + +item.ebwizardry\:spectral_sword.name=具現化劍 +item.ebwizardry\:spectral_pickaxe.name=具現化鎬 +item.ebwizardry\:spectral_bow.name=具現化弓 + +item.ebwizardry\:spectral_sword_upgraded.name=具現化劍 +item.ebwizardry\:spectral_pickaxe_upgraded.name=具現化鎬 + +item.ebwizardry\:small_mana_flask.name=小法力瓶 +item.ebwizardry\:medium_mana_flask.name=中法力瓶 +item.ebwizardry\:large_mana_flask.name=大法力瓶 + +item.ebwizardry\:grand_crystal.name=大魔法水晶 +item.ebwizardry\:crystal_shard.name=魔法水晶碎片 + +item.ebwizardry\:astral_diamond.name=星鑽 + +item.ebwizardry\:purifying_elixir.name=淨化藥水 +item.ebwizardry\:purifying_elixir.desc=喝下後可驅除詛咒 + +item.ebwizardry\:storage_upgrade.name=法杖儲存升級 +item.ebwizardry\:siphon_upgrade.name=法杖吸取升級 +item.ebwizardry\:condenser_upgrade.name=法杖恢復升級 +item.ebwizardry\:range_upgrade.name=法杖距離升級 +item.ebwizardry\:duration_upgrade.name=法杖持久升級 +item.ebwizardry\:cooldown_upgrade.name=法杖冷卻升級 +item.ebwizardry\:blast_upgrade.name=法杖範圍升級 +item.ebwizardry\:attunement_upgrade.name=法杖協調升級 +item.ebwizardry\:melee_upgrade.name=法杖戰鬥升級 + +item.ebwizardry\:storage_upgrade.desc=升級法杖儲存法力的容量 +item.ebwizardry\:siphon_upgrade.desc=升級法杖從被殺死生物中吸取的法力 +item.ebwizardry\:condenser_upgrade.desc=升級法杖緩慢恢復法力的時間 +item.ebwizardry\:range_upgrade.desc=升級法杖施展法術的有效距離 +item.ebwizardry\:duration_upgrade.desc=升級法杖施法後的持續時間 +item.ebwizardry\:cooldown_upgrade.desc=升級法杖施法後的冷卻速度 +item.ebwizardry\:blast_upgrade.desc=升級法杖施展法術的有效範圍 +item.ebwizardry\:attunement_upgrade.desc=升級法杖可存入法術的數量 +item.ebwizardry\:melee_upgrade.desc=升級法杖在打擊生物時用法力來造成更大的傷害 + +item.ebwizardry\:flaming_axe.name=燃燒之斧 +item.ebwizardry\:frost_axe.name=冰凍之斧 + +item.ebwizardry\:flaming_axe_upgraded.name=燃燒之斧 +item.ebwizardry\:frost_axe_upgraded.name=冰凍之斧 + +item.ebwizardry\:firebomb.name=火焰彈 +item.ebwizardry\:poison_bomb.name=毒液彈 +item.ebwizardry\:smoke_bomb.name=煙霧彈 +item.ebwizardry\:spark_bomb.name=電擊彈 + +item.ebwizardry\:blank_scroll.name=空白卷軸 +item.ebwizardry\:scroll.generic=卷軸 +item.ebwizardry\:scroll.name=%1$s的卷軸 +item.ebwizardry\:scroll.undiscovered.name=卷軸《%1$s》 +item.ebwizardry\:identification_scroll.name=鑑定卷軸 +item.ebwizardry\:identification_scroll.desc=鑑定未知的法術書或卷軸 +item.ebwizardry\:identification_scroll.nothing_to_identify=沒有東西可鑑定! + +item.ebwizardry\:armour_upgrade.name=防護法術印記 +item.ebwizardry\:armour_upgrade.desc1=%1$s升級任何法師護具 +item.ebwizardry\:armour_upgrade.desc2=%1$s使其變成%2$s傳奇等級 + +item.ebwizardry\:magic_silk.name=魔法絲綢 + +item.ebwizardry\:wizard_armour.legendary=傳奇 +item.ebwizardry\:wizard_armour.buff=-%1$s %2$s系消耗 +item.ebwizardry\:wizard_armour.mana=法力\: %1$s/%2$s + +item.ebwizardry\:wizard_hat.name=法師帽 +item.ebwizardry\:wizard_robe.name=法師袍 +item.ebwizardry\:wizard_leggings.name=法師褲 +item.ebwizardry\:wizard_boots.name=法師鞋 + +item.ebwizardry\:wizard_hat_fire.name=烈焰法師帽 +item.ebwizardry\:wizard_robe_fire.name=烈焰法師袍 +item.ebwizardry\:wizard_leggings_fire.name=烈焰法師褲 +item.ebwizardry\:wizard_boots_fire.name=烈焰法師鞋 + +item.ebwizardry\:wizard_hat_ice.name=寒冰法師帽 +item.ebwizardry\:wizard_robe_ice.name=寒冰法師袍 +item.ebwizardry\:wizard_leggings_ice.name=寒冰法師褲 +item.ebwizardry\:wizard_boots_ice.name=寒冰法師鞋 + +item.ebwizardry\:wizard_hat_lightning.name=雷電法師帽 +item.ebwizardry\:wizard_robe_lightning.name=雷電法師袍 +item.ebwizardry\:wizard_leggings_lightning.name=雷電法師褲 +item.ebwizardry\:wizard_boots_lightning.name=雷電法師鞋 + +item.ebwizardry\:wizard_hat_necromancy.name=死靈法師帽 +item.ebwizardry\:wizard_robe_necromancy.name=死靈法師袍 +item.ebwizardry\:wizard_leggings_necromancy.name=死靈法師褲 +item.ebwizardry\:wizard_boots_necromancy.name=死靈法師鞋 + +item.ebwizardry\:wizard_hat_earth.name=大地法師帽 +item.ebwizardry\:wizard_robe_earth.name=大地法師袍 +item.ebwizardry\:wizard_leggings_earth.name=大地法師褲 +item.ebwizardry\:wizard_boots_earth.name=大地法師鞋 + +item.ebwizardry\:wizard_hat_sorcery.name=秘術法師帽 +item.ebwizardry\:wizard_robe_sorcery.name=秘術法師袍 +item.ebwizardry\:wizard_leggings_sorcery.name=秘術法師褲 +item.ebwizardry\:wizard_boots_sorcery.name=秘術法師鞋 + +item.ebwizardry\:wizard_hat_healing.name=治療法師帽 +item.ebwizardry\:wizard_robe_healing.name=治療法師袍 +item.ebwizardry\:wizard_leggings_healing.name=治療法師褲 +item.ebwizardry\:wizard_boots_healing.name=治療法師鞋 + +item.ebwizardry\:spawn_wizard.name=生成法師 +item.ebwizardry\:spawn_evil_wizard.name=生成邪惡法師 + +item.ebwizardry\:spectral_helmet.name=具現化頭盔 +item.ebwizardry\:spectral_chestplate.name=具現化胸甲 +item.ebwizardry\:spectral_leggings.name=具現化護腿 +item.ebwizardry\:spectral_boots.name=具現化靴子 + +item.ebwizardry\:lightning_hammer.name=雷神之鎚 + +item.ebwizardry\:ring_condensing.name=法力之戒 +item.ebwizardry\:ring_condensing.desc=緩慢恢復快捷欄中所有法杖的法力 +item.ebwizardry\:ring_siphoning.name=吸星之戒 +item.ebwizardry\:ring_siphoning.desc=增加30%%的法力吸取能力 +item.ebwizardry\:ring_battlemage.name=戰鬥之戒 +item.ebwizardry\:ring_battlemage.desc=當你用慣用手持劍並用副手握著你的法杖時,可增加10%%的額外魔法傷害 +item.ebwizardry\:ring_combustion.name=燃爆之戒 +item.ebwizardry\:ring_combustion.desc=使被火系法術殺死的生物發生爆炸 +item.ebwizardry\:ring_fire_melee.name=燃燒之戒 +item.ebwizardry\:ring_fire_melee.desc=使火系法杖打到的生物著火 +item.ebwizardry\:ring_fire_biome.name=烈陽之戒 +item.ebwizardry\:ring_fire_biome.desc=使火系法術於熱帶地區可提高30%%的效力 +item.ebwizardry\:ring_disintegration.name=灰燼之戒 +item.ebwizardry\:ring_disintegration.desc=所有的火系法術都能使敵人灰飛煙滅 +item.ebwizardry\:ring_ice_melee.name=冰觸之戒 +item.ebwizardry\:ring_ice_melee.desc=使冰系法杖打到的生物被冰凍 +item.ebwizardry\:ring_ice_biome.name=冰川之戒 +item.ebwizardry\:ring_ice_biome.desc=使冰系法術於寒帶地區可提高30%%的效力 +item.ebwizardry\:ring_arcane_frost.name=冰爆之戒 +item.ebwizardry\:ring_arcane_frost.desc=使被冰系法術殺死的生物會朝四面八方射出碎冰 +item.ebwizardry\:ring_shattering.name=粉碎之戒 +item.ebwizardry\:ring_shattering.desc=有機會粉碎近戰攻擊時被冰凍的生物 +item.ebwizardry\:ring_lightning_melee.name=連鎖之戒 +item.ebwizardry\:ring_lightning_melee.desc=使被電系法杖打到的生物再電擊附近其它生物 +item.ebwizardry\:ring_storm.name=暴風之戒 +item.ebwizardry\:ring_storm.desc=使電系法術在暴風雨間可大幅減少冷卻時間 +item.ebwizardry\:ring_seeking.name=吸引之戒 +item.ebwizardry\:ring_seeking.desc=所有發射類的法術都會自動追蹤目標 +item.ebwizardry\:ring_hammer.name=雷神之戒 +item.ebwizardry\:ring_hammer.desc=可以撿起並丟出雷神之鎚 +item.ebwizardry\:ring_soulbinding.name=靈魂之戒 +item.ebwizardry\:ring_soulbinding.desc=將被死靈法術傷害的生物靈魂綁定於你 +item.ebwizardry\:ring_leeching.name=吸血之戒 +item.ebwizardry\:ring_leeching.desc=所有的死靈攻擊都有30%%的機會造成生命吸取的效果 +item.ebwizardry\:ring_necromancy_melee.name=凋零之戒 +item.ebwizardry\:ring_necromancy_melee.desc=使被死靈法杖打到的生物凋零 +item.ebwizardry\:ring_mind_control.name=精神之戒 +item.ebwizardry\:ring_mind_control.desc=受到精神控制的生物有機會再控制其它附近的生物 +item.ebwizardry\:ring_poison.name=毒蛇之戒 +item.ebwizardry\:ring_poison.desc=所有大地法術都會使目標中毒 +item.ebwizardry\:ring_earth_melee.name=毒液之戒 +item.ebwizardry\:ring_earth_melee.desc=使被大地法杖接觸的生物中毒 +item.ebwizardry\:ring_earth_biome.name=森林之戒 +item.ebwizardry\:ring_earth_biome.desc=使大地法術在森林或黑森林地區可提高30%%的效力 +item.ebwizardry\:ring_full_moon.name=狼嚎之戒 +item.ebwizardry\:ring_full_moon.desc=使大地法術在滿月時可大幅減少冷卻時間 +item.ebwizardry\:ring_extraction.name=提取之戒 +item.ebwizardry\:ring_extraction.desc=以秘術進行殺戮可獲得額外法力 +item.ebwizardry\:ring_mana_return.name=完美主義之戒 +item.ebwizardry\:ring_mana_return.desc=當能量箭沒有擊中目標時會返還其使用的法力至你的法杖 +item.ebwizardry\:ring_blockwrangler.name=方塊達人之戒 +item.ebwizardry\:ring_blockwrangler.desc=丟出的方塊會造成兩倍的傷害 +item.ebwizardry\:ring_conjurer.name=具現化之戒 +item.ebwizardry\:ring_conjurer.desc=將具現化物品的維持時間延長一倍 +item.ebwizardry\:ring_defender.name=後衛之戒 +item.ebwizardry\:ring_defender.desc=你的發射物會穿越你或同伴的力場 +item.ebwizardry\:ring_paladin.name=聖騎士之戒 +item.ebwizardry\:ring_paladin.desc=當你在治療自己或同伴時,身邊的同伴也會獲得部分治療 +item.ebwizardry\:ring_interdiction.name=阻截之戒 +item.ebwizardry\:ring_interdiction.desc=你的力場會傷害觸碰到的生物 + +item.ebwizardry\:amulet_arcane_defence.name=法力恢復項鍊 +item.ebwizardry\:amulet_arcane_defence.desc=緩慢恢復所有穿在身上法師服的法力 +item.ebwizardry\:amulet_warding.name=防禦項鍊 +item.ebwizardry\:amulet_warding.desc=使所有受到的魔法傷害降低10%% +item.ebwizardry\:amulet_wisdom.name=智慧項鍊 +item.ebwizardry\:amulet_wisdom.desc=大幅度降低試用未知法術時受到負面效果的機率 +item.ebwizardry\:amulet_fire_protection.name=防火項鍊 +item.ebwizardry\:amulet_fire_protection.desc=減少30%%的火焰傷害 +item.ebwizardry\:amulet_fire_cloaking.name=火焰遮罩項鍊 +item.ebwizardry\:amulet_fire_cloaking.desc=站在你或同伴的火焰環中可使受到的火焰傷害降低75%% +item.ebwizardry\:amulet_ice_immunity.name=永凍土項鍊 +item.ebwizardry\:amulet_ice_immunity.desc=使你對於冰凍效果完全免疫 +item.ebwizardry\:amulet_ice_protection.name=防凍項鍊 +item.ebwizardry\:amulet_ice_protection.desc=減少30%%的冰凍傷害 +item.ebwizardry\:amulet_potential.name=潛能項鍊 +item.ebwizardry\:amulet_potential.desc=使你有15%%的機會對近身攻擊你的生物發射電擊 +item.ebwizardry\:amulet_channeling.name=導引項鍊 +item.ebwizardry\:amulet_channeling.desc=使你有30%%的機會抵銷受到的衝擊傷害 +item.ebwizardry\:amulet_lich.name=巫妖項鍊 +item.ebwizardry\:amulet_lich.desc=使你有15%%的機會將受到的傷害轉移至身邊的召喚生物 +item.ebwizardry\:amulet_wither_immunity.name=凋零珍珠項鍊 +item.ebwizardry\:amulet_wither_immunity.desc=使你對於凋零效果完全免疫 +item.ebwizardry\:amulet_glide.name=飄羽項鍊 +item.ebwizardry\:amulet_glide.desc=使你在掉落超過三個方塊時,有50%%的機會啟動滑翔效果 +item.ebwizardry\:amulet_banishing.name=終界項鍊 +item.ebwizardry\:amulet_banishing.desc=有15%%的機會將近身攻擊你的生物傳送至附近隨機地點 +item.ebwizardry\:amulet_anchoring.name=定身項鍊 +item.ebwizardry\:amulet_anchoring.desc=使你不受魔法的移動位置所影響 +item.ebwizardry\:amulet_recovery.name=恢復項鍊 +item.ebwizardry\:amulet_recovery.desc=當生命值低於50%%時,會隨時用護甲的法力來對你治療 +item.ebwizardry\:amulet_transience.name=無敵項鍊 +item.ebwizardry\:amulet_transience.desc=使你在嚴重受傷時,有25%%的機會啟動無敵效果 +item.ebwizardry\:amulet_resurrection.name=不死項鍊 +item.ebwizardry\:amulet_resurrection.desc=使你可以在死後對自己施展復活術 +item.ebwizardry\:amulet_auto_shield.name=防護項鍊 +item.ebwizardry\:amulet_auto_shield.desc=讓你有25%%的機率會啟動快捷欄上法杖中的護盾術,維持幾秒 + +item.ebwizardry\:charm_haggler.name=議價者招牌 +item.ebwizardry\:charm_haggler.desc=使法師們保證每次都會為你提供新的交易 +item.ebwizardry\:charm_experience_tome.name=勤奮寶典 +item.ebwizardry\:charm_experience_tome.desc=使法杖成長的速度提高50%% +item.ebwizardry\:charm_auto_smelt.name=煉金者的印記 +item.ebwizardry\:charm_auto_smelt.desc=讓你自動啟動快捷欄上法杖中的隨身熔煉術 +item.ebwizardry\:charm_lava_walking.name=地獄冰凍核心 +item.ebwizardry\:charm_lava_walking.desc=使足凍術可將腳下的岩漿凍結成黑曜石 +item.ebwizardry\:charm_storm.name=雷雲瓶 +item.ebwizardry\:charm_storm.desc=使天氣變換術召喚的雨天為暴風雨 +item.ebwizardry\:charm_minion_health.name=黑曜石殭屍頭 +item.ebwizardry\:charm_minion_health.desc=使召喚出的生物增強25%% +item.ebwizardry\:charm_minion_variants.name=轉變符 +item.ebwizardry\:charm_minion_variants.desc=將召喚的殭屍變為屍殼,骷髏變為流髑 +item.ebwizardry\:charm_flight.name=綠寶石甲蟲之翼 +item.ebwizardry\:charm_flight.desc=使飛行及滑行的速度加快50%% +item.ebwizardry\:charm_growth.name=水晶花護身符 +item.ebwizardry\:charm_growth.desc=施展生長術時,有35%%的機會使作物立即成熟 +item.ebwizardry\:charm_abseiling.name=附魔繩 +item.ebwizardry\:charm_abseiling.desc=在向上施展抓取術時可按住潛行鍵來逐漸放長藤蔓讓你降下 +item.ebwizardry\:charm_silk_touch.name=月亮寶石 +item.ebwizardry\:charm_silk_touch.desc=施展挖掘術時,以絲綢之觸的方式破壞方塊 +item.ebwizardry\:charm_stop_time.name=神奇懷錶 +item.ebwizardry\:charm_stop_time.desc=使緩時術可讓時間完全停止 +item.ebwizardry\:charm_light.name=永恆之燈 +item.ebwizardry\:charm_light.desc=使照明術產生的光源永久存在,用法杖對光源點擊滑鼠右鍵以解除 +item.ebwizardry\:charm_transportation.name=古代羅盤 +item.ebwizardry\:charm_transportation.desc=傳送時最多可記憶及選擇四個石陣 +item.ebwizardry\:charm_feeding.name=餵食袋 +item.ebwizardry\:charm_feeding.desc=讓你自動啟動快捷欄上法杖中的充飢術 + +item.charge_status.full=完全滿 +item.charge_status.almost_full=幾乎滿 +item.charge_status.mostly_full=有點滿 +item.charge_status.half_full=一半滿 +item.charge_status.mostly_empty=有點空 +item.charge_status.almost_empty=幾乎空 +item.charge_status.empty=完全空 + +entity.ebwizardry\:summonedcreature.nameplate=%1$s的%2$s +entity.ebwizardry\:summonedcreature.nameplate_fallback=某人的%1$s + +entity.ebwizardry\:wizard.greeting_0=你好啊,流浪漢。 +entity.ebwizardry\:wizard.greeting_1=嗨! 旅行者,什麼風把你吹來的啊? +entity.ebwizardry\:wizard.greeting_2=哇! 真高興在這附近還能看到別人。 +entity.ebwizardry\:wizard.speech_0=我可以推薦個法術給你嗎? +entity.ebwizardry\:wizard.speech_1=勇於嘗試,魔法無所不在。 +entity.ebwizardry\:wizard.speech_2=神秘的魔法還有太多要學習的,冒險家。 +entity.ebwizardry\:wizard.speech_3=有什麼你自己學到的想要分享嗎? +entity.ebwizardry\:wizard.speech_4=你是不是也覺得研究魔法超有趣? +entity.ebwizardry\:wizard.farewell_0=祝你任務順利,冒險家。 +entity.ebwizardry\:wizard.farewell_1=相信我們很快又會見面的,朋友。 +entity.ebwizardry\:wizard.farewell_2=再見了,旅行者。 +entity.ebwizardry\:wizard.combat_0=走開,骯髒的生物! +entity.ebwizardry\:wizard.combat_1=離我遠一點,你這隻害蟲! +entity.ebwizardry\:wizard.combat_2=這裡不歡迎不死生物,呿! +entity.ebwizardry\:wizard.combat_3=請你離開,黑暗的生物! +entity.ebwizardry\:wizard.combat_4=我要的就是你滾出這裡,怪物! +entity.ebwizardry\:wizard.combat_5=滾回你的洞穴,邪惡的生物! +entity.ebwizardry\:wizard.player_combat_0=你會後悔這麼做的,旅行者! +entity.ebwizardry\:wizard.player_combat_1=你覺得你在做什麼?! +entity.ebwizardry\:wizard.player_combat_2=只有笨蛋才敢激怒法師! +entity.ebwizardry\:wizard.player_combat_3=你會為你的疏忽而付出代價,冒險者! +entity.ebwizardry\:wizard.player_combat_4=準備好防禦你自己吧,小人! +entity.ebwizardry\:wizard.player_combat_5=準備好嚐嚐我的憤怒! + +entity.ebwizardry\:zombie_minion.name=殭屍 +entity.ebwizardry\:husk_minion.name=屍殼 +entity.ebwizardry\:skeleton_minion.name=骷髏 +entity.ebwizardry\:stray_minion.name=流髑 +entity.ebwizardry\:spider_minion.name=蜘蛛 +entity.ebwizardry\:blaze_minion.name=烈焰使者 +entity.ebwizardry\:wither_skeleton_minion.name=凋零骷髏 +entity.ebwizardry\:ice_wraith.name=寒冰幽靈 +entity.ebwizardry\:lightning_wraith.name=雷電幽靈 +entity.ebwizardry\:shadow_wraith.name=暗影幽靈 +entity.ebwizardry\:spirit_wolf.name=狼靈 +entity.ebwizardry\:spirit_horse.name=馬靈 +entity.ebwizardry\:ice_giant.name=寒冰巨人 +entity.ebwizardry\:phoenix.name=鳳凰 +entity.ebwizardry\:wizard.name=法師 +entity.ebwizardry\:magic_slime.name=魔法史萊姆 +entity.ebwizardry\:silverfish_minion.name=蠹蟲 +entity.ebwizardry\:storm_elemental.name=風暴元素 +entity.ebwizardry\:evil_wizard.name=法師 +entity.ebwizardry\:decoy.name=替身 +entity.ebwizardry\:vex_minion.name=惱鬼 + +entity.ebwizardry\:magic_missile.name=魔法 +entity.ebwizardry\:arc.name=魔法 +entity.ebwizardry\:spark_bomb.name=魔法 +entity.ebwizardry\:ice_shard.name=魔法 +entity.ebwizardry\:firebomb.name=魔法 +entity.ebwizardry\:poison_bomb.name=魔法 +entity.ebwizardry\:force_orb.name=魔法 +entity.ebwizardry\:spark.name=魔法 +entity.ebwizardry\:darkness_orb.name=魔法 +entity.ebwizardry\:fire_sigil.name=魔法 +entity.ebwizardry\:frost_sigil.name=魔法 +entity.ebwizardry\:lightning_sigil.name=魔法 +entity.ebwizardry\:lightning_arrow.name=魔法 +entity.ebwizardry\:firebolt.name=魔法 +entity.ebwizardry\:ice_charge.name=魔法 +entity.ebwizardry\:force_arrow.name=魔法 +entity.ebwizardry\:dart.name=魔法 +entity.ebwizardry\:lightning_disc.name=魔法 +entity.ebwizardry\:thunderbolt.name=魔法 +entity.ebwizardry\:decay.name=魔法 +entity.ebwizardry\:ice_lance.name=魔法 +entity.ebwizardry\:smoke_bomb.name=魔法 +entity.ebwizardry\:ice_spike.name=魔法 +entity.ebwizardry\:combustion_rune.name=魔法 + +entity.ebwizardry\:black_hole.name=黑洞 +entity.ebwizardry\:shield.name=護盾 +entity.ebwizardry\:meteor.name=隕石 +entity.ebwizardry\:blizzard.name=寒冰暴風圈 +entity.ebwizardry\:bubble.name=泡泡 +entity.ebwizardry\:tornado.name=龍捲風 +entity.ebwizardry\:lightning_hammer.name=雷神之鎚 +entity.ebwizardry\:arrow_rain.name=箭雨 +entity.ebwizardry\:healing_aura.name=治療氣場 +entity.ebwizardry\:forcefield.name=力場 +entity.ebwizardry\:ring_of_fire.name=烈焰之環 +entity.ebwizardry\:earthquake.name=地震 +entity.ebwizardry\:hailstorm.name=雹暴 +entity.ebwizardry\:lightning_pulse.name=雷擊 + +itemGroup.ebwizardry=法術模組 +itemGroup.ebwizardryspells=法術 +itemGroup.ebwizardrygear=法師裝備 + +advancement.ebwizardry\:root=法術模組 +advancement.ebwizardry\:root.desc=一個法師學習掌握法術的旅程 +advancement.ebwizardry\:crystal=神奇的水晶..... +advancement.ebwizardry\:crystal.desc=挖掘一個魔法水晶 +advancement.ebwizardry\:arcane_initiate=法術開端 +advancement.ebwizardry\:arcane_initiate.desc=用魔法水晶、木棍和金粒製作一根法杖 + +advancement.ebwizardry\:apprentice=法師的學徒 +advancement.ebwizardry\:apprentice.desc=使用法術寶典來升級你的法杖 +advancement.ebwizardry\:special_upgrade=魔法改造 +advancement.ebwizardry\:special_upgrade.desc=將法杖進行特殊升級 +advancement.ebwizardry\:advanced=急速進展 +advancement.ebwizardry\:advanced.desc=將你的法杖升級至進階等級 +advancement.ebwizardry\:master=魔法大師 +advancement.ebwizardry\:master.desc=得到大師法杖 +advancement.ebwizardry\:max_out_wand=全副武裝 +advancement.ebwizardry\:max_out_wand.desc=將大師級法杖進行最大數量的升級 +advancement.ebwizardry\:all_spells=博學法師 +advancement.ebwizardry\:all_spells.desc=在遊戲中施展每一個法術 + +advancement.ebwizardry\:wizard_tower=誰住在這? +advancement.ebwizardry\:wizard_tower.desc=拜訪一座法師塔 +advancement.ebwizardry\:wizard_trade=魔法交易 +advancement.ebwizardry\:wizard_trade.desc=從法師那購買物品 +advancement.ebwizardry\:anger_wizard=你會後悔的 +advancement.ebwizardry\:anger_wizard.desc=激怒一個法師 +advancement.ebwizardry\:defeat_evil_wizard=正義使者 +advancement.ebwizardry\:defeat_evil_wizard.desc=打敗一個邪惡法師 +advancement.ebwizardry\:buy_master_spell=知識就是力量 +advancement.ebwizardry\:buy_master_spell.desc=從法師那購買大師級法術 + +advancement.ebwizardry\:discover_spell=嘗試錯誤 +advancement.ebwizardry\:discover_spell.desc=藉由施展看看來鑑定一個未知的法術 +advancement.ebwizardry\:identify_spell=法術鑑定 +advancement.ebwizardry\:identify_spell.desc=發現更可靠的方法來鑑定法術 +advancement.ebwizardry\:spell_failure=事與願違 +advancement.ebwizardry\:spell_failure.desc=以痛苦的方式來發現法術是會出錯的 +advancement.ebwizardry\:discover_master_spell=搏命演出 +advancement.ebwizardry\:discover_master_spell.desc=藉由嘗試錯誤來成功鑑定一個大師級法術 + +advancement.ebwizardry\:visit_shrine=參拜 +advancement.ebwizardry\:visit_shrine.desc=進入一座神殿並喚醒其古老的魔法 +advancement.ebwizardry\:artefact=遺物 +advancement.ebwizardry\:artefact.desc=解除神殿的防衛魔法並獲得其中的寶物 +advancement.ebwizardry\:all_artefacts=博物館 +advancement.ebwizardry\:all_artefacts.desc=收集所有的戒指、項鍊及神器 + +advancement.ebwizardry\:armour_set=現在你完全是個法師了 +advancement.ebwizardry\:armour_set.desc=製作並穿上整套法師服 +advancement.ebwizardry\:legendary=傳奇 +advancement.ebwizardry\:legendary.desc=獲得一件傳奇的法師服 + +advancement.ebwizardry\:enchant_scroll=法術卷軸 +advancement.ebwizardry\:enchant_scroll.desc=製作一個空白卷軸,並在法術工作台中存入法術 + +handbook.toast.title=已解鎖新的手冊章節! + +container.ebwizardry\:arcane_workbench=法術工作台 +container.ebwizardry\:arcane_workbench.apply=存入 +container.ebwizardry\:arcane_workbench.mana=法力\: +container.ebwizardry\:arcane_workbench.upgrades=已進行的升級\: + +tier.novice=基礎 +tier.apprentice=學徒 +tier.advanced=進階 +tier.master=大師 + +element.magic=無 +element.fire=火 +element.ice=冰 +element.lightning=電 +element.necromancy=死靈 +element.earth=大地 +element.sorcery=秘術 +element.healing=治療 + +element.magic.wizard=法師 +element.fire.wizard=烈焰法師 +element.ice.wizard=冰凍法師 +element.lightning.wizard=雷電法師 +element.necromancy.wizard=死靈法師 +element.earth.wizard=大地法師 +element.sorcery.wizard=秘術法師 +element.healing.wizard=治療法師 + +spelltype.attack=攻擊 +spelltype.defence=防禦 +spelltype.utility=應用 +spelltype.minion=召喚 +spelltype.buff=作用 +spelltype.construct=建構 +spelltype.projectile=投射 +spelltype.alteration=改變 + +spell.disabled=《%1$s》已在設定檔中被禁用 +spell.resist=《%1$s》抵制了《%2$s》 +spell.discover=發現法術《%1$s》! + +spell.ebwizardry\:agility=敏捷術 +spell.ebwizardry\:arc=電擊術 +spell.ebwizardry\:arcane_jammer=法術干擾 +spell.ebwizardry\:arcane_lock=法術鎖 +spell.ebwizardry\:arrow_rain=箭雨術 +spell.ebwizardry\:banish=驅逐術 +spell.ebwizardry\:black_hole=黑洞術 +spell.ebwizardry\:blink=瞬移術 +spell.ebwizardry\:blizzard=冰暴術 +spell.ebwizardry\:bubble=泡泡術 +spell.ebwizardry\:chain_lightning=連鎖電擊術 +spell.ebwizardry\:charge=衝擊術 +spell.ebwizardry\:clairvoyance=尋路術 +spell.ebwizardry\:cobwebs=蛛網術 +spell.ebwizardry\:combustion_rune=燃爆符文 +spell.ebwizardry\:conjure_armour=具現化護甲 +spell.ebwizardry\:conjure_block=具現化方塊 +spell.ebwizardry\:conjure_bow=具現化弓 +spell.ebwizardry\:conjure_pickaxe=具現化鎬 +spell.ebwizardry\:conjure_sword=具現化劍 +spell.ebwizardry\:containment=封鎖術 +spell.ebwizardry\:cure_effects=藥效消除術 +spell.ebwizardry\:curse_of_enfeeblement=虛弱詛咒 +spell.ebwizardry\:curse_of_soulbinding=靈魂詛咒 +spell.ebwizardry\:curse_of_undeath=不死詛咒 +spell.ebwizardry\:darkness_orb=黑暗球 +spell.ebwizardry\:darkvision=夜視術 +spell.ebwizardry\:dart=飛箭 +spell.ebwizardry\:decay=腐蝕術 +spell.ebwizardry\:decoy=替身術 +spell.ebwizardry\:detonate=引爆術 +spell.ebwizardry\:diamondflesh=鑽石護體 +spell.ebwizardry\:disintegration=燃爆術 +spell.ebwizardry\:divination=探索術 +spell.ebwizardry\:dragon_fireball=龍之火球術 +spell.ebwizardry\:earthquake=地震術 +spell.ebwizardry\:empowering_presence=魔力提升術 +spell.ebwizardry\:entrapment=黑暗束縛術 +spell.ebwizardry\:evade=閃避術 +spell.ebwizardry\:fireball=火球術 +spell.ebwizardry\:firebolt=噴火術 +spell.ebwizardry\:firebomb=火焰彈 +spell.ebwizardry\:fire_resistance=抗火術 +spell.ebwizardry\:fire_sigil=火焰印記 +spell.ebwizardry\:fireskin=火焰護體 +spell.ebwizardry\:fire_breath=火焰風暴 +spell.ebwizardry\:flame_ray=烈焰射線 +spell.ebwizardry\:flaming_axe=燃燒之斧 +spell.ebwizardry\:flaming_weapon=燃燒武器 +spell.ebwizardry\:flight=飛行術 +spell.ebwizardry\:font_of_mana=法力字符 +spell.ebwizardry\:font_of_vitality=活力字符 +spell.ebwizardry\:force_arrow=能量箭 +spell.ebwizardry\:forcefield=力場 +spell.ebwizardry\:force_orb=衝擊球 +spell.ebwizardry\:forests_curse=森林詛咒 +spell.ebwizardry\:forest_of_thorns=荊棘森林 +spell.ebwizardry\:freeze=冰凍術 +spell.ebwizardry\:freezing_weapon=寒冰武器 +spell.ebwizardry\:frost_axe=冰凍之斧 +spell.ebwizardry\:frost_ray=冷凍射線 +spell.ebwizardry\:frost_sigil=冰凍印記 +spell.ebwizardry\:frost_step=足凍術 +spell.ebwizardry\:glide=滑翔術 +spell.ebwizardry\:grapple=抓取術 +spell.ebwizardry\:greater_fireball=大火球術 +spell.ebwizardry\:greater_heal=強力治療術 +spell.ebwizardry\:greater_telekinesis=加強念力 +spell.ebwizardry\:greater_ward=強力屏障術 +spell.ebwizardry\:group_heal=群體治療術 +spell.ebwizardry\:growth_aura=生長術 +spell.ebwizardry\:hailstorm=雹暴術 +spell.ebwizardry\:heal=治療術 +spell.ebwizardry\:heal_ally=目標治療術 +spell.ebwizardry\:healing_aura=治療氣場 +spell.ebwizardry\:homing_spark=電球術 +spell.ebwizardry\:iceball=冰球術 +spell.ebwizardry\:ice_age=強力凍結術 +spell.ebwizardry\:ice_charge=冰爆彈 +spell.ebwizardry\:ice_lance=冰矛術 +spell.ebwizardry\:ice_shard=冰礫術 +spell.ebwizardry\:ice_shroud=冰凍護體 +spell.ebwizardry\:ice_spikes=冰尖刺 +spell.ebwizardry\:ice_statue=凍結術 +spell.ebwizardry\:ignite=點燃術 +spell.ebwizardry\:imbue_weapon=武器注魔 +spell.ebwizardry\:intimidate=威嚇術 +spell.ebwizardry\:invigorating_presence=力量提升術 +spell.ebwizardry\:invisibility=隱身術 +spell.ebwizardry\:invoke_weather=天氣變換術 +spell.ebwizardry\:ironflesh=鐵皮術 +spell.ebwizardry\:leap=跳躍術 +spell.ebwizardry\:levitation=飄浮術 +spell.ebwizardry\:life_drain=生命吸取術 +spell.ebwizardry\:light=照明術 +spell.ebwizardry\:lightning_arrow=閃電箭 +spell.ebwizardry\:lightning_bolt=落雷術 +spell.ebwizardry\:lightning_disc=電氣斬 +spell.ebwizardry\:lightning_hammer=雷神之鎚 +spell.ebwizardry\:lightning_pulse=雷擊術 +spell.ebwizardry\:lightning_ray=電擊射線 +spell.ebwizardry\:lightning_sigil=電擊印記 +spell.ebwizardry\:lightning_web=電擊網 +spell.ebwizardry\:magic_missile=魔法彈 +spell.ebwizardry\:metamorphosis=生物轉換術 +spell.ebwizardry\:meteor=隕石術 +spell.ebwizardry\:mind_control=心靈控制術 +spell.ebwizardry\:mind_trick=心智擾亂術 +spell.ebwizardry\:mine=挖掘術 +spell.ebwizardry\:muffle=靜音術 +spell.ebwizardry\:none=[空] +spell.ebwizardry\:oakflesh=銅皮術 +spell.ebwizardry\:paralysis=麻痺術 +spell.ebwizardry\:petrify=石化術 +spell.ebwizardry\:phase_step=穿越術 +spell.ebwizardry\:plague_of_darkness=黑暗瘟疫 +spell.ebwizardry\:pocket_furnace=隨身熔煉術 +spell.ebwizardry\:pocket_workbench=隨身工作台 +spell.ebwizardry\:poison=毒液術 +spell.ebwizardry\:poison_bomb=毒液彈 +spell.ebwizardry\:possession=附身術 +spell.ebwizardry\:ray_of_purification=陽光射線 +spell.ebwizardry\:remove_curse=驅除詛咒 +spell.ebwizardry\:replenish_hunger=充飢術 +spell.ebwizardry\:resurrection=復活術 +spell.ebwizardry\:reversal=逆轉術 +spell.ebwizardry\:ring_of_fire=烈焰之環 +spell.ebwizardry\:satiety=果腹術 +spell.ebwizardry\:shadow_ward=暗影屏障術 +spell.ebwizardry\:shield=護盾術 +spell.ebwizardry\:shockwave=震波術 +spell.ebwizardry\:shulker_bullet=界伏彈 +spell.ebwizardry\:silverfish_swarm=召喚蠹蟲群 +spell.ebwizardry\:sixth_sense=感應術 +spell.ebwizardry\:slime=史萊姆術 +spell.ebwizardry\:slow_time=緩時術 +spell.ebwizardry\:smoke_bomb=煙霧彈 +spell.ebwizardry\:snare=陷阱術 +spell.ebwizardry\:snowball=雪球術 +spell.ebwizardry\:spark_bomb=電擊彈 +spell.ebwizardry\:spectral_pathway=具現化道路 +spell.ebwizardry\:speed_time=時間加快術 +spell.ebwizardry\:spider_swarm=召喚蜘蛛群 +spell.ebwizardry\:static_aura=電氣護體 +spell.ebwizardry\:summon_blaze=召喚烈焰使者 +spell.ebwizardry\:summon_ice_giant=召喚寒冰巨人 +spell.ebwizardry\:summon_ice_wraith=召喚寒冰幽靈 +spell.ebwizardry\:summon_iron_golem=召喚鐵巨人 +spell.ebwizardry\:summon_lightning_wraith=召喚雷電幽靈 +spell.ebwizardry\:summon_phoenix=召喚鳳凰 +spell.ebwizardry\:summon_shadow_wraith=召喚暗影幽靈 +spell.ebwizardry\:summon_skeleton=召喚骷髏 +spell.ebwizardry\:summon_skeleton_legion=召喚骷髏軍團 +spell.ebwizardry\:summon_snow_golem=召喚雪人 +spell.ebwizardry\:summon_spirit_horse=召喚馬靈 +spell.ebwizardry\:summon_spirit_wolf=召喚狼靈 +spell.ebwizardry\:summon_storm_elemental=召喚風暴元素 +spell.ebwizardry\:summon_wither_skeleton=召喚凋零骷髏 +spell.ebwizardry\:summon_zombie=召喚殭屍 +spell.ebwizardry\:telekinesis=念力 +spell.ebwizardry\:thunderbolt=電擊彈 +spell.ebwizardry\:thunderstorm=雷暴術 +spell.ebwizardry\:tornado=龍捲術 +spell.ebwizardry\:transience=無敵術 +spell.ebwizardry\:transportation=傳送術 +spell.ebwizardry\:vanishing_box=終界箱存取術 +spell.ebwizardry\:vex_swarm=召喚惱鬼群 +spell.ebwizardry\:wall_of_frost=冰牆術 +spell.ebwizardry\:ward=屏障術 +spell.ebwizardry\:water_breathing=水中呼吸術 +spell.ebwizardry\:whirlwind=強風術 +spell.ebwizardry\:wither=凋零術 +spell.ebwizardry\:wither_skull=凋零頭顱術 + +spell.ebwizardry\:agility.desc=使施法者獲得更快的速度及更高的跳躍力,維持30秒。 +spell.ebwizardry\:arc.desc=對目標發射電光火花。 +spell.ebwizardry\:arcane_jammer.desc=使目標在15秒內無法使用魔法。 +spell.ebwizardry\:arcane_lock.desc=在容器的周圍包覆無法穿透的力場屏障,以防被施法者及他的同伴以外的人打開或破壞。 +spell.ebwizardry\:arrow_rain.desc=『弓箭手們, 射擊!』 +spell.ebwizardry\:banish.desc=將目標傳送到一定範圍內的隨機地點。 +spell.ebwizardry\:black_hole.desc=撕裂現實空間。 +spell.ebwizardry\:blink.desc=讓施法者瞬間移動到所指的位置。 +spell.ebwizardry\:blizzard.desc=製造一個寒冰暴風圈,使困在裡面的任何生物速度減緩並持續受到傷害,施法者不會受到傷害,但仍會減慢速度。 +spell.ebwizardry\:bubble.desc=發射一陣泡泡,使任何碰到的東西不由自主的向上漂浮,直到過一段時間或泡泡被打破後才會掉下來。 +spell.ebwizardry\:chain_lightning.desc=對目標發射電擊,並連鎖傳導至額外的目標最多兩次。 +spell.ebwizardry\:charge.desc=使施法者迅速朝他們所看的方向猛衝過去,傷害並撞飛所有東西。 +spell.ebwizardry\:clairvoyance.desc=顯示前往記錄地點的路線。 拿著法杖並切換到這個法術,於潛行時對著方塊點擊滑鼠右鍵以記錄位置。 之後以一般的方式施展這個法術就會顯示出前往記錄地點的路線,顯示的路線會在90秒後消失。 +spell.ebwizardry\:cobwebs.desc=在你所指的位置創造出蜘蛛網來嚴重妨礙任何被其困住的生物的行動。這些蜘蛛網會在受到破壞或20秒後消失。 +spell.ebwizardry\:combustion_rune.desc=在你所站的位置放置一個被踩到就會爆炸的魔法地雷。 +spell.ebwizardry\:conjure_armour.desc=在施法者身上具現化出防護力與鐵裝相等的護甲。這個護甲可維持60秒。施法者必須有空的護甲槽。 +spell.ebwizardry\:conjure_block.desc=在你所指的地方具現化一個特殊的方塊,這個方塊會在45秒後消失,你也可以對這個方塊再施展一次法術來讓它消失。 +spell.ebwizardry\:conjure_bow.desc=具現化一把具有無限箭矢的弓,維持30秒。 +spell.ebwizardry\:conjure_pickaxe.desc=具現化一把強度相當於鐵鎬的鎬,維持30秒。 +spell.ebwizardry\:conjure_sword.desc=具現化一把強度相當於鐵劍的劍,維持30秒。 +spell.ebwizardry\:containment.desc=將目標封鎖在其目前位置的短距離範圍內20秒。 +spell.ebwizardry\:cure_effects.desc=清除施法者身上不論好壞的所有藥水效果。 +spell.ebwizardry\:curse_of_enfeeblement.desc=『他忽然就變得很虛弱,好像生了場大病。』 - 已知唯一遭遇死靈邪教成員而倖免於難的人的證詞。 +spell.ebwizardry\:curse_of_soulbinding.desc=將目標的靈魂與施法者緊密的綁定在一起,表示當施法者受到傷害時,綁定的對象也會受到相同的傷害,直到其中一方死亡為止。 +spell.ebwizardry\:curse_of_undeath.desc=不死生物詛咒,使目標會像殭屍及骷髏一樣在陽光下自燃,直到死亡為止。對不死生物無效。 +spell.ebwizardry\:darkness_orb.desc=朝你所指的方向發射一顆緩慢移動的黑暗能量,無論擊中什麼都會使其凋零。 +spell.ebwizardry\:darkvision.desc=賦予施法者45秒的夜視能力。 +spell.ebwizardry\:dart.desc=朝你所指的方向發射一支飛箭,傷害被擊中的目標並使其虛弱。 +spell.ebwizardry\:decay.desc=在地面上創造出一片腐爛之地並感染任何接觸到的生物,隨著時間持續造成傷害並擴散感染其走過的地方。 +spell.ebwizardry\:decoy.desc=創造一個虛幻的施法者分身,以誘騙怪物的攻擊。這個替身會在30秒之後消失。 +spell.ebwizardry\:detonate.desc=在你所指的地方製造一場爆炸,傷害附近所有生物。如果施法者靠太近的話,本身也會受到傷害。 +spell.ebwizardry\:diamondflesh.desc=『你的箭刺不穿我啦!』 +spell.ebwizardry\:disintegration.desc=朝前方射出一股短距離的高溫射線,殺死目標並使其炸裂成燃燒的灰燼。踩到這些灰燼的生物也會燒起來。 +spell.ebwizardry\:divination.desc=指引到附近的礦物及資源。潛能可增加尋找更有價值礦物的機會。 +spell.ebwizardry\:dragon_fireball.desc=朝你所指的方向發射一顆終界龍的火球,且在撞擊時釋放出揮之不去的毒雲。 +spell.ebwizardry\:earthquake.desc=一個真正的大地魔法大師可移動山脈。 +spell.ebwizardry\:empowering_presence.desc=提高施法者及附近同伴的魔法傷害力30秒。 +spell.ebwizardry\:entrapment.desc=將目標捕捉至黑暗領域中,使其無助地被向上拉動並不斷受到傷害。 +spell.ebwizardry\:evade.desc=使施法者快速的跳到旁邊以閃避攻擊。 +spell.ebwizardry\:fireball.desc=朝你所指的方向發射一顆火球。 +spell.ebwizardry\:firebolt.desc=朝你面前噴射出短距離的火焰。 +spell.ebwizardry\:firebomb.desc=朝你所指的方向發射一顆火焰炸彈。炸彈會在撞擊時爆炸,使附近的目標著火。 +spell.ebwizardry\:fire_resistance.desc=使施法者獲得30秒的火焰抗性。 +spell.ebwizardry\:fire_sigil.desc=在地上放置一個魔法火焰陷阱,使觸動陷阱的生物受到傷害並著火。 +spell.ebwizardry\:fireskin.desc=在施法者身上包覆火焰30秒,使任何攻擊他的對象都會著火。 +spell.ebwizardry\:fire_breath.desc=『我是噴火龍!』 +spell.ebwizardry\:flame_ray.desc=朝你所指的方向產生一串火焰,使目標著火並不斷地受到傷害。 +spell.ebwizardry\:flaming_axe.desc=創造一把維持30秒的燃燒之斧,可使打到的敵人著火。 +spell.ebwizardry\:flaming_weapon.desc=暫時將燃燒的能力附加到施法者快捷欄的第一把武器上,可使其攻擊的對象著火。這個魔法會在45秒後消失。 +spell.ebwizardry\:flight.desc=像鷹一樣翱翔。 +spell.ebwizardry\:font_of_mana.desc=『我們充滿了強烈的魔法能量,這股能量的中心似乎發自於...』──摘錄自被遺忘的法師日記,剩餘的頁面已被燒掉了。 +spell.ebwizardry\:font_of_vitality.desc=這個感覺太棒了。 +spell.ebwizardry\:force_arrow.desc=朝你所指的方向發射能量箭。 +spell.ebwizardry\:forcefield.desc=在施法者的周圍創造一個力場以擊退生物並反彈投射物。 +spell.ebwizardry\:force_orb.desc=射出一顆衝擊球,於碰撞時衝擊並傷害附近的生物。 +spell.ebwizardry\:forests_curse.desc=『你竟敢進入我的森林!』 +spell.ebwizardry\:forest_of_thorns.desc=樹木之間的隱密空地,\n空地之內的法師表演,\n無法言喻的魔法藝術,\n濃密深沉的荊棘森林。 +spell.ebwizardry\:freeze.desc=使目標被冰凍10秒鐘, 也可讓水結冰或在地面產生積雪。 +spell.ebwizardry\:freezing_weapon.desc=暫時將冰凍的能力附加到施法者快捷欄的第一把武器上,可冰凍受到攻擊的對象。這個魔法會在45秒後消失。 +spell.ebwizardry\:frost_axe.desc=創造一把維持30秒的冰凍之斧,可冰凍被打到的敵人。 +spell.ebwizardry\:frost_ray.desc=朝你所指的方向噴射一連串冷凍光束,使目標減緩速度並持續受到傷害。 +spell.ebwizardry\:frost_sigil.desc=在地上放置一個魔法冰凍陷阱,使觸動陷阱的生物受到傷害並結凍。 +spell.ebwizardry\:frost_step.desc=使施法者可暫時凍結腳下的水面30秒。 +spell.ebwizardry\:grapple.desc=射出一條魔法藤蔓讓施法者抓住前方的方塊或纏住物體。放開滑鼠右鍵就會放開抓住的方塊或物體。 +spell.ebwizardry\:glide.desc=在空中按住按鍵持續施展法術,可讓施法者向下滑行。 +spell.ebwizardry\:greater_fireball.desc=朝你所指的方向發射一顆大火球,並在撞擊時爆炸。 +spell.ebwizardry\:greater_heal.desc=治療施法者,使其恢復4顆心的生命值。 +spell.ebwizardry\:greater_telekinesis.desc=讓施法者能將方塊或生物抓到半空中,直到放開滑鼠右鍵。在抓住時按下潛行鍵可將方塊或生物向前丟一點距離。 +spell.ebwizardry\:greater_ward.desc=讓施法者獲得強力的屏障保護,可在30秒內大幅度降低受到的魔法傷害。 +spell.ebwizardry\:group_heal.desc=治療施法者及附近的同伴與召喚生物,使其恢復3顆心的生命值。 +spell.ebwizardry\:growth_aura.desc=加速所有在施法者附近的作物生長,也會使草地長出花和草。 +spell.ebwizardry\:hailstorm.desc=於第三世紀寒冷的冬天,冰系法師才發現它們真正的力量。 +spell.ebwizardry\:heal.desc=治療施法者,使其恢復2顆心的生命值。 +spell.ebwizardry\:heal_ally.desc=治療目標,使其恢復2.5顆心的生命值。 +spell.ebwizardry\:healing_aura.desc=創造一個治療能量區,恢復區域內任何同伴的生命值。 治療區中的不死生物則會緩慢受到傷害。 +spell.ebwizardry\:homing_spark.desc=創造一個一直朝向敵人飄去的電球。 +spell.ebwizardry\:iceball.desc=朝你所指的方向丟出一顆冰球。 +spell.ebwizardry\:ice_age.desc=『你將被永遠凍結!』 +spell.ebwizardry\:ice_charge.desc=發射一顆冰爆彈,在擊中爆開後會使附近的生物結凍,並朝四面八方射出碎冰。 +spell.ebwizardry\:ice_lance.desc=朝你所指的方向射出大冰矛來刺穿目標,使其遭到冰凍並受到傷害。 +spell.ebwizardry\:ice_shard.desc=朝你所指的方向發射碎冰,被擊中的目標會受到傷害並減速。 +spell.ebwizardry\:ice_shroud.desc=在施法者身上包覆冰凍能量30秒,冰凍任何攻擊他的對象。 +spell.ebwizardry\:ice_spikes.desc=在你所指的地面升起鋒利的冰尖刺,刺穿困於其中的生物。 +spell.ebwizardry\:ice_statue.desc=將目標凍結成冰塊,維持20秒或直到冰塊被打破。 目標結冰時無法移動或做任何事,但也不會受到任何傷害。 +spell.ebwizardry\:ignite.desc=使目標著火10秒鐘, 也可用於像打火石的作用。 +spell.ebwizardry\:imbue_weapon.desc=暫時將魔法注入施法者快捷欄的第一把武器上,加強其威力。這個魔法會在45秒後消失。 +spell.ebwizardry\:intimidate.desc=發出令人畏懼的吼叫聲,使附近的生物恐懼而逃跑。 心生恐懼的生物會在30秒後恢復。 +spell.ebwizardry\:invigorating_presence.desc=提高施法者與附近所有同伴的力量45秒。 +spell.ebwizardry\:invisibility.desc=讓施法者隱形30秒。 +spell.ebwizardry\:invoke_weather.desc=改變目前的天氣。 +spell.ebwizardry\:ironflesh.desc=更大的提高施法者對傷害的抗性30秒。 +spell.ebwizardry\:leap.desc=使施法者稍微向前並向上跳躍幾個方塊高。 +spell.ebwizardry\:levitation.desc=按住按鍵持續施展這個法術可讓施法者不斷向上飄浮。 在掉落地面前施展,也能減少掉落傷害。 +spell.ebwizardry\:life_drain.desc=朝你所指的方向創造一股凋零能量,吸取目標的生命並用來補充自己的生命。 +spell.ebwizardry\:light.desc=製造一個可持續30秒照亮周圍的魔法光點。 +spell.ebwizardry\:lightning_arrow.desc=朝你所指的方向射出閃電箭。 +spell.ebwizardry\:lightning_bolt.desc=讓雷電擊中你所指的地方。 +spell.ebwizardry\:lightning_disc.desc=射出一個電氣飛盤,朝你所指的方向飛去並電擊遇到的目標。 +spell.ebwizardry\:lightning_hammer.desc=『我讓天譴來懲罰你!』 +spell.ebwizardry\:lightning_pulse.desc=在施法者周圍的地面通電,以傷害並擊退身旁的生物。 +spell.ebwizardry\:lightning_ray.desc=朝你所指的方向產生一串電擊射線,使目標持續受到傷害。 +spell.ebwizardry\:lightning_sigil.desc=在地上放置一個魔法電擊陷阱,使觸動陷阱的生物受到傷害,並連鎖電擊附近其它生物。 +spell.ebwizardry\:lightning_web.desc=『集中精神,經由法杖來引導你腦海中的風暴,然後釋放它的怒火。』 +spell.ebwizardry\:magic_missile.desc=朝你所指的方向發射一顆魔法能量彈。 +spell.ebwizardry\:metamorphosis.desc=使目標轉換成另一種形態,只能用於某些生物。 +spell.ebwizardry\:meteor.desc=有些法師就是想看到燃燒的世界... +spell.ebwizardry\:mind_control.desc=控制目標的心靈30秒鐘,使其改變陣營為施法者戰鬥。 無法控制太強大的生物。 +spell.ebwizardry\:mind_trick.desc=擾亂目標,使其15秒內無法進行有效的攻擊。如果目標受到傷害,法術的效果就會提前中斷。 +spell.ebwizardry\:mine.desc=破壞施法者所指的方塊。潛能可提高能夠破壞的方塊硬度。 +spell.ebwizardry\:muffle.desc=在30秒內抑制任何施法者所發出的聲音。當施展靜音術時,生物只有在直接看到你才會發現你。 +spell.ebwizardry\:none.desc=使用 /give 指令來取得法術書的方式,執行 id\: /give [玩家名稱] ebwizardry\:spell_book 1 [法術id] (如果你在箱子中找到這本書,表示被某個其它模組搞亂了)。 +spell.ebwizardry\:oakflesh.desc=暫時提高施法者對傷害的抗性30秒。 +spell.ebwizardry\:paralysis.desc=射出強力的電擊使目標短暫麻痺5秒鐘。被麻痺的生物無法移動,且仍然會受到傷害,但太多次反而會讓生物不再麻痺。 +spell.ebwizardry\:petrify.desc=將目標石化直到石化遭到破壞,天黑後有機會破石而出。 被石化後無法移動或做任何事,但也不會受到任何傷害。 +spell.ebwizardry\:phase_step.desc=將施法者向前傳送一小段距離,即便前面是牆壁。 法杖範圍升級可增加能傳送穿越的牆壁厚度。 +spell.ebwizardry\:plague_of_darkness.desc=黑暗的力量將榨乾它們... +spell.ebwizardry\:pocket_furnace.desc=燒製施法者身上物品欄中可燒製的物品,從快捷欄開始燒製最多5個。 +spell.ebwizardry\:pocket_workbench.desc=讓施法者能像在工作台一樣合成物品。 +spell.ebwizardry\:poison.desc=朝你所指的方向發射毒液。 +spell.ebwizardry\:poison_bomb.desc=朝你所指的方向發射一顆毒液炸彈。炸彈會在撞擊時爆炸,使附近的生物中毒。 +spell.ebwizardry\:possession.desc=『變成敵人!』 +spell.ebwizardry\:ray_of_purification.desc=射出一道刺眼的陽光,傷害目標並使其暫時失明。不死生物會受到兩倍的傷害且著火。 +spell.ebwizardry\:remove_curse.desc=驅除施法者身上所有的詛咒。 +spell.ebwizardry\:replenish_hunger.desc=為施法者補充4點(2支雞腿)的飽食度。 +spell.ebwizardry\:resurrection.desc=身邊有個治療大師,就算死了...也沒關係。 +spell.ebwizardry\:reversal.desc=隨機移除一種負面的藥水效果,將其加諸在目標身上,持續原本剩餘的效果時間。潛能可增加逆轉的效果數量。 +spell.ebwizardry\:ring_of_fire.desc=在施法者四周製造一個火焰圈,傷害所有靠近的敵人並使它們著火。 +spell.ebwizardry\:satiety.desc=為施法者補充8點(4支雞腿)的飽食度。 +spell.ebwizardry\:shadow_ward.desc=在施法者面前形成一塊黑暗屏障,將所有受到傷害的一半施加予攻擊者。 +spell.ebwizardry\:shield.desc=創造一個可以阻擋投射物與魔法的屏障護盾,同時賦予施法者一個弱的抗性效果。 +spell.ebwizardry\:shockwave.desc=蹦! +spell.ebwizardry\:shulker_bullet.desc=發射一顆界伏彈,自動追蹤目標並使其在被擊中後懸浮。 +spell.ebwizardry\:silverfish_swarm.desc=『啊啊啊啊啊!它們全都一起來!』 +spell.ebwizardry\:sixth_sense.desc=讓施法者在20秒的時間內能穿透牆壁感知附近生物的位置。 +spell.ebwizardry\:slime.desc=用史萊姆來吞沒敵人,使其減緩速度並持續受到傷害。 史萊姆會在10秒鐘後破裂。 +spell.ebwizardry\:slow_time.desc=時間操控術是一門控制時間來配合自身需求的藝術。過去人們普遍認為已被遺忘...直到現在。 +spell.ebwizardry\:smoke_bomb.desc=朝你所指的方向發射一顆煙霧彈,煙霧彈會在擊中時爆炸,並產生煙霧使附近的生物短時間內看不見。 +spell.ebwizardry\:snare.desc=在地面設置一個會傷害生物並使其暫時減速的陷阱。 +spell.ebwizardry\:snowball.desc=朝你所指的方向丟出一顆雪球。 +spell.ebwizardry\:spark_bomb.desc=朝你所指的方向發射一顆電擊彈,其釋放的電擊會衝擊附近的敵人。 +spell.ebwizardry\:spectral_pathway.desc=在你面前創造一條無法破壞的具現化道路,其延伸至15個方塊遠,並於60秒後消失。 +spell.ebwizardry\:speed_time.desc=...白天、夜晚、清晨、黃昏、日出以及日落\: 這些時光的流逝將我們困在永無止盡的循環當中... +spell.ebwizardry\:spider_swarm.desc=召喚毒蜘蛛群來為你戰鬥, 蜘蛛群會在被殺死或30秒後消失。 +spell.ebwizardry\:static_aura.desc=使施法者身上圍繞著電荷30秒,任何攻擊他的對象都會遭到電擊。 +spell.ebwizardry\:summon_blaze.desc=召喚烈焰使者來為你戰鬥, 烈焰使者會在被殺死或30秒後消失。 +spell.ebwizardry\:summon_ice_giant.desc=『粉碎他們!』 +spell.ebwizardry\:summon_ice_wraith.desc=召喚寒冰幽靈來為你戰鬥, 寒冰幽靈會在被殺死或30秒後消失。 +spell.ebwizardry\:summon_iron_golem.desc=自動化自主性自動機器人。 +spell.ebwizardry\:summon_lightning_wraith.desc=召喚雷電幽靈來為你戰鬥, 雷電幽靈會在被殺死或30秒後消失。 +spell.ebwizardry\:summon_phoenix.desc=來自於灰燼當中... +spell.ebwizardry\:summon_shadow_wraith.desc=召喚暗影幽靈來為你戰鬥。 +spell.ebwizardry\:summon_skeleton.desc=召喚骷髏來為你戰鬥, 骷髏會在被殺死或30秒後消失。 +spell.ebwizardry\:summon_skeleton_legion.desc=『起來吧,不死軍團!』 +spell.ebwizardry\:summon_snow_golem.desc=召喚雪人來為你戰鬥, 雪人會持續到被殺死為止。 +spell.ebwizardry\:summon_spirit_horse.desc=召喚一隻馬靈來成為你的坐騎。 馬靈會在下馬一段時間後消失,或你也可以拿著法杖於潛行時對牠點擊滑鼠右鍵來解除牠。 +spell.ebwizardry\:summon_spirit_wolf.desc=召喚一隻狼靈同伴來為你戰鬥。 狼靈只會在被殺死後消失,或你也可以拿著法杖於潛行時對牠點擊滑鼠右鍵來解除牠。 +spell.ebwizardry\:summon_storm_elemental.desc=『風暴元素:古老的元素展現形式,它幾乎無法控制其中的原始攪動力量。』──法師指南之法術本質第二冊 +spell.ebwizardry\:summon_wither_skeleton.desc=召喚凋零骷髏來為你戰鬥, 凋零骷髏會在被殺死或30秒後消失。 +spell.ebwizardry\:summon_zombie.desc=召喚殭屍來為你戰鬥。 殭屍會在被殺死或30秒後消失。 +spell.ebwizardry\:telekinesis.desc=使物品或其它小物件朝自己移動,或對遠方游標所指的方塊點擊滑鼠右鍵。也能用來卸除玩家武裝。 +spell.ebwizardry\:thunderbolt.desc=射出電擊彈以擊退目標。 +spell.ebwizardry\:thunderstorm.desc=『哇哈哈哈哈哈!』 +spell.ebwizardry\:tornado.desc=朝你所指的方向釋放龍捲風,將路過的任何東西都捲到空中。 +spell.ebwizardry\:transience.desc=使施法者暫時不會受到任何傷害20秒,但同時不能造成任何傷害,也不能破壞或放置方塊。 +spell.ebwizardry\:transportation.desc=將施法者傳送回他們所記錄的石陣。 要使用這個法術,必須先用傳送石放在地上圍成一圈,然後拿著法杖對其點擊滑鼠右鍵以記錄位置。 +spell.ebwizardry\:vanishing_box.desc=讓施法者可存取他們的終界箱。 +spell.ebwizardry\:vex_swarm.desc=召喚成群的飛行腦鬼來為你戰鬥。 腦鬼會在被殺死或30秒後消失。 +spell.ebwizardry\:wall_of_frost.desc=寒冬觸手可及。 +spell.ebwizardry\:ward.desc=讓施法者獲得屏障保護,可在30秒內降低受到的魔法傷害。 +spell.ebwizardry\:water_breathing.desc=讓施法者能在水中呼吸60秒。 +spell.ebwizardry\:whirlwind.desc=使目標被高速向上吹離你面前。 +spell.ebwizardry\:wither.desc=發射黑暗射線使接觸到的任何東西凋零。 +spell.ebwizardry\:wither_skull.desc=朝你所指的方向發射一顆凋零骷髏頭。 + +spell.ebwizardry\:invoke_weather.sun=雨(雪)停了... +spell.ebwizardry\:invoke_weather.rain=開始下雨(雪)了... +spell.ebwizardry\:transportation.missing=傳送石陣已消失或被擋住了... +spell.ebwizardry\:transportation.undefined=你必須先以傳送石陣來記錄位置! +spell.ebwizardry\:transportation.wrongdimension=這個世界沒有記錄的傳送石陣... +spell.ebwizardry\:clairvoyance.searching=搜尋中... +spell.ebwizardry\:clairvoyance.confirm=施展%1$s法術將顯示出帶你回到這個地點的路線 +spell.ebwizardry\:clairvoyance.outofrange=你記錄的位置過於遙遠或無法前往... +spell.ebwizardry\:clairvoyance.undefined=你必須先記錄位置! +spell.ebwizardry\:clairvoyance.wrongdimension=你記錄的位置在另一個世界... +spell.ebwizardry\:possession.insufficienthealth=你的生命值不足以附身 %1$s! +spell.ebwizardry\:possession.success=按下 %s 鍵以停止附身 +spell.ebwizardry\:divination.nothing=沒有發生任何事 +spell.ebwizardry\:divination.weak=你感覺到法杖%s抽動 +spell.ebwizardry\:divination.moderate=你覺得法杖被用力拉%s +spell.ebwizardry\:divination.strong=你的法杖被強力的%s拉 +spell.ebwizardry\:divination.very_strong=你的法杖突然%s傾斜 +spell.ebwizardry\:divination.down=向下 +spell.ebwizardry\:divination.up=向上 +spell.ebwizardry\:divination.front=向前 +spell.ebwizardry\:divination.back=向後 +spell.ebwizardry\:divination.left=到左邊 +spell.ebwizardry\:divination.right=到右邊 +spell.ebwizardry\:resurrection.resurrect_ally=%s 被 %s 救活了 +spell.ebwizardry\:resurrection.resurrect_self=%s 重新活了起來 +spell.ebwizardry\:resurrection.button_wait=復活 (%s秒) +spell.ebwizardry\:resurrection.button_ready=復活 + +forfeit.ebwizardry\:do_nothing=沒有事情發生。 + +forfeit.ebwizardry\:burn_self=%s在你手中炸成火花! +forfeit.ebwizardry\:fireball=一顆火球在你面前形成! +forfeit.ebwizardry\:firebomb=在你頭上出現一顆火焰彈! +forfeit.ebwizardry\:explode=忽然發生的爆炸將你震倒在地! +forfeit.ebwizardry\:blazes=忽然間敵人的火焰出現在你四周! +forfeit.ebwizardry\:burn_surroundings=你的周圍地區燒了起來! +forfeit.ebwizardry\:meteors=火熱的地獄之雨從天而降! + +forfeit.ebwizardry\:freeze_self=你感到冰冷的寒意迎面撲來! +forfeit.ebwizardry\:freeze_self_2=來自%s發出如此強烈的寒氣,使你動彈不得! +forfeit.ebwizardry\:ice_spikes=冰尖刺從你腳下的地面升上來! +forfeit.ebwizardry\:blizzard=你突然被劇烈的寒冰暴風圈所包圍! +forfeit.ebwizardry\:ice_wraiths=你的周圍突然間出現充滿敵意的寒冰幽靈! +forfeit.ebwizardry\:hailstorm=你的上方開始降下尖銳的冰刀雨! +forfeit.ebwizardry\:ice_giant=一個充滿敵意的寒冰巨人出現在你面前! + +forfeit.ebwizardry\:thunder=卷軸發出了震耳欲聾的聲音,將你震倒在地上! +forfeit.ebwizardry\:storm=看起來快要暴風雨了! +forfeit.ebwizardry\:lightning_sigils=注意你的腳下! +forfeit.ebwizardry\:lightning=你被閃電擊中了! +forfeit.ebwizardry\:paralyse_self=你麻掉了! +forfeit.ebwizardry\:lightning_wraiths=你的周圍突然間出現充滿敵意的雷電幽靈! +forfeit.ebwizardry\:storm_elementals=充滿敵意的風暴元素出現在四面八方! + +forfeit.ebwizardry\:nausea=...嗯? 剛剛發生什麼事? 我在哪裡? +forfeit.ebwizardry\:zombie_horde=一大群殭屍從你周圍的地面鑽出來! +forfeit.ebwizardry\:wither_self=黑暗的力量使你的靈魂開始凋零! +forfeit.ebwizardry\:cripple_self=%s發出致命的吼叫聲,使你癱瘓到幾乎沒命! +forfeit.ebwizardry\:shadow_wraiths=充滿敵意的暗影幽靈出現在四面八方! + +forfeit.ebwizardry\:snares=這是陷阱! +forfeit.ebwizardry\:squid=烏賊! +forfeit.ebwizardry\:uproot_plants=附近的所有植物都突然被連根拔起了! +forfeit.ebwizardry\:poison_self=你中毒了! +forfeit.ebwizardry\:flood=你的周圍突然出現水! +forfeit.ebwizardry\:bury_self=你腳下的地面崩塌了! + +forfeit.ebwizardry\:spill_inventory=你的東西散落得到處都是! +forfeit.ebwizardry\:teleport_self=你被傳送到某個地方! +forfeit.ebwizardry\:levitate_self=你開始不由自主的向上漂浮! +forfeit.ebwizardry\:vex_horde=一群腦鬼忽然出現在你的周圍! +forfeit.ebwizardry\:black_hole=你的面前出現一個旋轉的渦流! +forfeit.ebwizardry\:arrow_rain=你的上方開始降下一陣密集的箭雨! + +forfeit.ebwizardry\:damage_self=哎喲! +forfeit.ebwizardry\:spill_armour=你的護甲都脫落了! +forfeit.ebwizardry\:hunger=你突然覺得超餓! +forfeit.ebwizardry\:blind_self=你瞎掉了! +forfeit.ebwizardry\:weaken_self=你變得超虛弱! +forfeit.ebwizardry\:jam_self=你的魔法變得毫無用處! +forfeit.ebwizardry\:curse_self=你受到了不死生物的詛咒! + +potion.ebwizardry\:frost=冰凍 +potion.ebwizardry\:fireskin=火焰護體 +potion.ebwizardry\:ice_shroud=冰凍護體 +potion.ebwizardry\:static_aura=電氣護體 +potion.ebwizardry\:transience=無敵 +potion.ebwizardry\:decay=腐蝕 +potion.ebwizardry\:sixth_sense=感應 +potion.ebwizardry\:arcane_jammer=法術干擾 +potion.ebwizardry\:mind_trick=心智擾亂 +potion.ebwizardry\:mind_control=心靈控制 +potion.ebwizardry\:font_of_mana=法力字符 +potion.ebwizardry\:fear=恐懼 +potion.ebwizardry\:curse_of_soulbinding=靈魂詛咒 +potion.ebwizardry\:paralysis=麻痺 +potion.ebwizardry\:muffle=靜音 +potion.ebwizardry\:ward=屏障 +potion.ebwizardry\:slow_time=緩時 +potion.ebwizardry\:empowerment=魔力提升 +potion.ebwizardry\:curse_of_enfeeblement=虛弱詛咒 +potion.ebwizardry\:curse_of_undeath=不死詛咒 +potion.ebwizardry\:containment=封鎖 +potion.ebwizardry\:frost_step=足凍 + +enchantment.ebwizardry\:magic_sword=注魔 +enchantment.ebwizardry\:magic_bow=注魔 +enchantment.ebwizardry\:flaming_weapon=燃燒 +enchantment.ebwizardry\:freezing_weapon=冰凍 +enchantment.ebwizardry\:shocking_weapon=雷電 + +enchantment.ebwizardry\:magic_protection=魔法防護 +enchantment.ebwizardry\:frost_protection=冰凍防護 +enchantment.ebwizardry\:shock_protection=衝擊防護 + +enchantment.ebwizardry.magic_sword.desc=部分武器注魔法術,無法於生存模式中取得(書本無作用) +enchantment.ebwizardry.magic_bow.desc=部分武器注魔法術,無法於生存模式中取得(書本無作用) +enchantment.ebwizardry.flaming_weapon.desc=部分燃燒武器法術,無法於生存模式中取得(書本無作用) +enchantment.ebwizardry.freezing_weapon.desc=部分寒冰武器法術,無法於生存模式中取得(書本無作用) +enchantment.ebwizardry.shocking_weapon.desc=部分衝擊武器法術,無法於生存模式中取得(書本無作用) + +enchantment.ebwizardry.magic_protection.desc=降低所有魔法傷害 +enchantment.ebwizardry.frost_protection.desc=降低冰凍傷害 +enchantment.ebwizardry.shock_protection.desc=降低衝擊傷害 + +key.categories.ebwizardry=法術模組 + +key.ebwizardry.next_spell=下個法術 +key.ebwizardry.previous_spell=上個法術 + +death.attack.wizardry_magic=%1$s 被 %2$s 施展的魔法殺死了 +death.attack.indirect_wizardry_magic=%1$s 被 %2$s 施展的魔法殺死了 + +soundCategory.ebwizardry_spells=法術 + +commands.ebwizardry\:cast.usage=/%1$s [player | x y z direction] [duration] [modifiers] +commands.ebwizardry\:cast.success=成功施展 %s +commands.ebwizardry\:cast.success_continuous=成功施展 %s 持續 %s 秒 +commands.ebwizardry\:cast.success_remote=成功施展 %s 作為 %s +commands.ebwizardry\:cast.success_remote_continuous=成功施展 %s 作為 %s 持續 %s 秒 +commands.ebwizardry\:cast.success_position=成功施展 %s 位於 %s, %s, %s +commands.ebwizardry\:cast.success_position_continuous=成功施展 %s 位於 %s, %s, %s 持續 %s 秒 +commands.ebwizardry\:cast.fail=無法施展《%1$s》 +commands.ebwizardry\:cast.not_found=沒有 ID 為 %1$s 的法術 +commands.ebwizardry\:cast.invalid_direction=無效的方向: %1$s (可指定方向為: up, down, north, south, east, west) +commands.ebwizardry\:cast.tag_error=資料標籤解析失敗\: %s +commands.ebwizardry\:cast.origin_not_specified=你必須指定施展這個法術的玩家或位置 +commands.ebwizardry\:cast.duration_not_specified=這個法術必須指定持續時間 + +commands.ebwizardry\:ally.usage=/%1$s <玩家> [玩家] +commands.ebwizardry\:ally.addally=%1$s 已加入至 %2$s 的同伴名單 +commands.ebwizardry\:ally.removeally=%1$s 已從 %2$s 的同伴名單中刪除 +commands.ebwizardry\:ally.self=玩家無法成為他們自己的同伴 +commands.ebwizardry\:ally.permission=你沒有改變其他玩家同伴的權限 + +commands.ebwizardry\:allies.usage=/%1$s [玩家] +commands.ebwizardry\:allies.list=玩家與你成為同伴\: %1$s +commands.ebwizardry\:allies.list_other=玩家與 %1$s 成為同伴\: %2$s +commands.ebwizardry\:allies.permission=你沒有觀看其他玩家同伴的權限 +commands.ebwizardry\:allies.none=無 + +commands.ebwizardry\:discoverspell.usage=/%1$s <法術/all/clear> [玩家] +commands.ebwizardry\:discoverspell.not_found=沒有 ID 為 %1$s 的法術 +commands.ebwizardry\:discoverspell.clear=清除 %1$s 的所有法術探索資料 +commands.ebwizardry\:discoverspell.all=將所有法術加入 %1$s 的法術探索資料 +commands.ebwizardry\:discoverspell.addspell=加入《%1$s》至 %1$s 的法術探索資料 +commands.ebwizardry\:discoverspell.removespell=從 %2$s 的法術探索資料中移除《%1$s》 + +config.ebwizardry.title.general=模組選項 + +config.ebwizardry.generic.true=開啟 +config.ebwizardry.generic.false=關閉 + +config.ebwizardry.category.spells=法術設定 +config.ebwizardry.category.spells.tooltip=選擇要啟用的法術 +config.ebwizardry.title.spells=法術設定 +config.ebwizardry.subtitle.spells=此處全面性的法術停用將覆蓋法術JSON檔中的細部設定。 + +config.ebwizardry.category.gameplay=遊玩設定 +config.ebwizardry.category.gameplay.tooltip=法師模組的一般遊玩設定 +config.ebwizardry.title.gameplay=遊玩設定 +config.ebwizardry.subtitle.gameplay=影響遊戲機制的全域設定 + +config.ebwizardry.discovery_mode=探索模式 +config.ebwizardry.discovery_mode.tooltip=給喜歡神秘感的玩家使用! 當開啟時,你無法讀取沒施展過的法術資料(基於各別的世界)。創造模式下這個沒有效果。若關閉的話,生存模式下無法獲得鑑定卷軸。 +config.ebwizardry.legacy_wand_levelling=傳統的法杖升級系統 +config.ebwizardry.legacy_wand_levelling.tooltip=設定法杖是否需要獲得成長才能升級至下個等級。開啟這個選項以恢復使用4.2版之前的系統,只要用法術寶典就能升級。此時法杖仍會默默的獲得成長,因此若你之後決定改回新的系統,並不會損失任何成長度。 +config.ebwizardry.legacy_wand_levelling.true=是 - 我喜歡原來的方式! +config.ebwizardry.legacy_wand_levelling.false=不 - 讓我升級吧! +config.ebwizardry.friendly_fire=友善攻擊 +config.ebwizardry.friendly_fire.tooltip=控制你的法術會傷害哪些與你友好的生物。無論這個設定為何,你的法術都無法瞄準你的同伴或其召喚/擁有的生物,但若這個設定關閉的話,可使他們完全免於受到傷害。 +config.ebwizardry.minion_revenge_targeting=召喚生物報復目標 +config.ebwizardry.minion_revenge_targeting.tooltip=被召喚的生物是否會報復性攻擊原本其不能攻擊的玩家或生物。 +config.ebwizardry.minion_revenge_targeting.true=是 - 我永遠不會傷害他們! +config.ebwizardry.minion_revenge_targeting.false=不 - 他們永遠都要服從我! +config.ebwizardry.players_move_each_other=玩家可互相移動 +config.ebwizardry.players_move_each_other.tooltip=是否允許玩家以魔法移動周圍的玩家。 +config.ebwizardry.players_move_each_other.true=是 - 開始遊戲吧! +config.ebwizardry.players_move_each_other.false=不 - 不要逼我移動! +config.ebwizardry.player_block_damage=玩家可破壞方塊 +config.ebwizardry.player_block_damage.tooltip=玩家施展的法術是否會破壞到方塊,關閉這個選項可防止災難發生。若要防止非玩家的法術去破壞到方塊,就用指令 /gamerule 設定 mobGriefing。 +config.ebwizardry.player_block_damage.true=是 - 爆破吧! +config.ebwizardry.player_block_damage.false=不 - 啟動反災難裝置! +config.ebwizardry.telekinetic_disarmament=念力解除武裝 +config.ebwizardry.telekinetic_disarmament.tooltip=玩家是否能用念力法術來解除其他玩家的武裝。 關閉以防止竊取物品的行為。 +config.ebwizardry.telekinetic_disarmament.true=是 - 讓大家可以偷東西! +config.ebwizardry.telekinetic_disarmament.false=不 - 那是作弊的行為! +config.ebwizardry.teleport_through_unbreakable_blocks=傳送穿越不可破壞的方塊 +config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=使用穿牆術時是否能穿越不可破壞的方塊(例如基岩)。 +config.ebwizardry.teleport_through_unbreakable_blocks.true=是 - 我想見識一下虛空! +config.ebwizardry.teleport_through_unbreakable_blocks.false=不 - 基岩就是不可穿越的! +config.ebwizardry.world_time_manipulation=世界時間的操縱 +config.ebwizardry.world_time_manipulation.tooltip=玩家是否能用時間加快術來改變世界的時間。關閉的話,時間加快術只會加快附近方塊及實體的運作速度,不會改變到整個世界的時間。 +config.ebwizardry.world_time_manipulation.true=是 - 白天、晚上... +config.ebwizardry.world_time_manipulation.false=不 - 我需要睡覺! +config.ebwizardry.replace_vanilla_fireballs=取代原版火球 +config.ebwizardry.replace_vanilla_fireballs.tooltip=是否用法術模組的火球來取代 Minecraft 中原本的火球。如果關閉的話,只有施展法術時才會使用模組的火球。 +config.ebwizardry.replace_vanilla_fireballs.true=是 - 給我燒吧! +config.ebwizardry.replace_vanilla_fireballs.false=不 - 這樣的燒法已經夠了! +config.ebwizardry.replace_vanilla_fall_damage=取代原版墜落傷害 +config.ebwizardry.replace_vanilla_fall_damage.tooltip=對於墜落傷害,是否以基於速度的等效計算方式來取代 Minecraft 中原本基於距離的計算方式。這麼做是為了使自由落體中的生物受到與正常情況下完全相同的傷害,因此並不會破壞到以墜落來設計的怪物農場。如果遇到與墜落相關的怪異狀況,請關閉這個選項。如果關閉的話,某些法術會在某些情況下恢復為更簡單的方法來重新計算玩家的墜落傷害。 +config.ebwizardry.replace_vanilla_fall_damage.true=是 - 來跑酷吧! +config.ebwizardry.replace_vanilla_fall_damage.false=不 - 我的腿會摔斷! +config.ebwizardry.creative_bypasses_arcane_lock=忽略法術鎖 +config.ebwizardry.creative_bypasses_arcane_lock.tooltip=決定誰可以忽略法術鎖 +config.ebwizardry.creative_bypasses_arcane_lock.true=任何在創造模式的人 +config.ebwizardry.creative_bypasses_arcane_lock.false=只有在創造模式的管理者 +config.ebwizardry.slow_time_affects_players=緩時術影響玩家 +config.ebwizardry.slow_time_affects_players.tooltip=玩家是否會受到附近其他玩家施展的緩時術影響。如果這個選項關閉的話,只會影響生物及投擲物,而玩家能以正常的速度移動。 +config.ebwizardry.mob_loot_table_whitelist=怪物戰利品檔白名單 +config.ebwizardry.mob_loot_table_whitelist.tooltip=白名單中列的是用來匯入以增加怪物掉落的戰利品檔(格式請參考 loot_tables/entities/mob_additions.json) 。 法術模組會盡量判斷哪些戰利品檔是屬於敵對生物的,但並不保證一定正確或合適。請加入戰利品檔的位置(非實體ID)到這個清單以手動將它們包含進來。 +config.ebwizardry.mob_loot_table_blacklist=怪物戰利品檔黑名單 +config.ebwizardry.mob_loot_table_blacklist.tooltip=黑名單中列的是用來匯入以增加怪物掉落的戰利品檔(格式請參考檔案 loot_tables/entities/mob_additions.json) 。 法術模組會盡量判斷哪些戰利品檔是屬於敵對的生物,但並不保證一定正確或合適。請加入戰利品檔的位置(非實體ID)到這個清單以手動將它們排除。 +config.ebwizardry.mob_spawn_dimensions=怪物生成世界 +config.ebwizardry.mob_spawn_dimensions.tooltip=列出會生成法術模組敵對生物的世界ID。 +config.ebwizardry.mob_spawn_biome_blacklist=怪物生成生態域黑名單 +config.ebwizardry.mob_spawn_biome_blaclist.tooltip=列出無法生成法術模組敵對生物的生態域名稱(不區分大小寫)。對於模組的生態域,前面要加上模組ID(例如 biomesoplenty\:mystic_grove)。 +config.ebwizardry.evil_wizard_spawn_rate=邪惡法師生成率 +config.ebwizardry.evil_wizard_spawn_rate.tooltip=自然生成邪惡法師的機率,愈大的數值表示會生成愈多邪惡法師。設定為5等同於女巫的生成率,100等同於殭屍、骷髏和苦力怕的生成率。設成0則完全不會生成邪惡法師。 +config.ebwizardry.ice_wraith_spawn_rate=寒冰幽靈生成率 +config.ebwizardry.ice_wraith_spawn_rate.tooltip=自然生成寒冰幽靈的機率,愈大的數值表示會生成愈多寒冰幽靈。設定為5等同於女巫的生成率,100等同於殭屍、骷髏和苦力怕的生成率。設成0則完全不會生成寒冰幽靈。 +config.ebwizardry.lightning_wraith_spawn_rate=雷電幽靈生成率 +config.ebwizardry.lightning_wraith_spawn_rate.tooltip=自然生成雷電幽靈的機率,愈大的數值表示會生成愈多雷電幽靈。設定為5等同於女巫的生成率,100等同於殭屍、骷髏和苦力怕的生成率。設成0則完全不會生成雷電幽靈。 +config.ebwizardry.forfeit_chance=懲罰機率 +config.ebwizardry.forfeit_chance.tooltip=誤試未鑑定的法術而遭受懲罰的機率。此值設定為0則停用懲罰機制。若關閉探索模式,則這個設定無效。 +config.ebwizardry.player_damage_scaling=玩家傷害係數 +config.ebwizardry.player_damage_scaling.tooltip=玩家施展法術造成傷害的全域性傷害倍數,基本為1。 +config.ebwizardry.npc_damage_scaling=非玩家角色傷害係數 +config.ebwizardry.npc_damage_scaling.tooltip=非玩家角色施展法術造成傷害的全域性傷害倍數,基本為1。 +config.ebwizardry.summoned_creature_targets_whitelist=召喚生物攻擊白名單 +config.ebwizardry.summoned_creature_targets_whitelist.tooltip=除了預設值以外,召喚生物及法師會攻擊的實體名稱列表。若你召喚的生物不會攻擊某個模組生物,就將其加到這個名單中。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.summoned_creature_targets_blacklist=召喚生物攻擊黑名單 +config.ebwizardry.summoned_creature_targets_blacklist.tooltip=列出召喚生物及法師不會攻擊的實體名稱,優先權比預設值和白名單高。若是某個生物遭到攻擊會導致發生問題,或某個生物破壞性太強(若從名單中移除苦力怕後果自負!),就將其加到這個名單中。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.mind_control_targets_blacklist=心靈控制目標黑名單 +config.ebwizardry.mind_control_targets_blacklist.tooltip=除了預設以外,無法受到心靈控制的生物名單。將受到心靈控制後會導致問題或會被濫用的生物加入名單。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.pocket_furnace_item_blacklist=隨身熔煉物品黑名單 +config.ebwizardry.pocket_furnace_item_blacklist.tooltip=列出除了護甲、工具及武器以外,隨身熔煉術不可熔煉的方塊或物品註冊名稱(不分大小寫)。對於模組的物品,須在名稱前加上模組ID(例如ebwizardry\:crystal_ore)。 +config.ebwizardry.divination_ore_whitelist=探索術礦物白名單 +config.ebwizardry.divination_ore_whitelist.tooltip=列出探索術可偵測的方塊或物品註冊名稱(不分大小寫)。對於模組的物品,須在名稱前加上模組ID(例如ebwizardry\:crystal_ore)。 +config.ebwizardry.sword_item_whitelist=劍的白名單 +config.ebwizardry.sword_item_whitelist.tooltip=列出注魔術可將其認為是劍而作用的物品註冊名稱(不分大小寫)。大部分的劍應該都能自動作用,將那些不能的手動增加於此。對於模組的物品,須在名稱前加上模組ID(例如tconstruct:broadsword)。 +config.ebwizardry.bow_item_whitelist=弓的白名單 +config.ebwizardry.bow_item_whitelist.tooltip=列出注魔術可將其認為是弓而作用的物品註冊名稱(不分大小寫)。大部分的弓應該都能自動作用,將那些不能的手動增加於此。對於模組的物品,須在名稱前加上模組ID(例如tconstruct:shortbow)。 +config.ebwizardry.currency_items=貨幣物品 +config.ebwizardry.currency_items.tooltip=列出可以當成貨幣(放入第一個槽,第二個槽不受影響),用來和法師交易的物品註冊名稱(不分大小寫)。列表中每個條目應包括物品的註冊名稱,加一個空白,再加上代表物品價值的整數值。愈高價值的貨幣物品,表示在交易時所需的數量愈少。 + +config.ebwizardry.category.worldgen=世界生成設定 +config.ebwizardry.category.worldgen.tooltip=法師模組的世界生成設定 +config.ebwizardry.title.worldgen=世界生成設定 +config.ebwizardry.subtitle.worldgen=影響世界生成的設定 + +config.ebwizardry.fast_worldgen=結構生成 +config.ebwizardry.fast_worldgen.tooltip=設定法術模組用於結構生成的計算方式。講究的世界生成會防止結構位於峭壁上及洞穴中,以及與其它結構交叉重疊,並會在生成後清除浮在半空中的樹木。快速的世界生成則犧牲了這些改良,來加快世界生成的速度。這個選項的影響是隨機的,對於輸入種子碼的世界,結構也不會都一樣。 +config.ebwizardry.fast_worldgen.true=快速 +config.ebwizardry.fast_worldgen.false=講究 +config.ebwizardry.tower_dimensions=出現塔的世界 +config.ebwizardry.tower_dimensions.tooltip=列出會生成法師塔的世界ID。移除所有的世界ID就完全不會生成法師塔了。 +config.ebwizardry.tower_rarity=塔的出現率 +config.ebwizardry.tower_rarity.tooltip=法師塔的出現機率,設定每多少區塊中會出現一座法師塔,這個意思就是數值愈大機率愈低。 +config.ebwizardry.evil_wizard_chance=邪惡法師機率 +config.ebwizardry.evil_wizard_chance.tooltip=生成的法師塔中住著邪惡法師及寶箱的機率。 +config.ebwizardry.tower_files=無寶箱塔的結構檔 +config.ebwizardry.tower_files.tooltip=列出無戰利品寶箱的法師塔結構檔位置。每次生成法師塔時會在這些檔案中隨機挑選一個。檔案位置的格式為[模組ID]\:[檔案名稱],其指向檔案 assets/[模組ID]/structures/[檔案名稱].nbt。清單中允許重複的檔案,如此可以簡單的提高某個結構的出現率,而不用實際去複製增加那個結構的檔案。這個清單請勿完全空白,若要停用法師塔,請在塔的生成世界中設定。 +config.ebwizardry.tower_with_chest_files=有寶箱塔的結構檔 +config.ebwizardry.tower_with_chest_files.tooltip=列出有戰利品寶箱的法師塔結構檔位置。每次生成法師塔時會在這些檔案中隨機挑選一個。檔案位置的格式為[模組ID]\:[檔案名稱],其指向檔案 assets/[模組ID]/structures/[檔案名稱].nbt。清單中允許重複的檔案,如此可以簡單的提高某個結構的出現率,而不用實際去複製增加那個結構的檔案。這個清單請勿完全空白,若要停用法師塔,請在塔的生成世界中設定。 +config.ebwizardry.obelisk_dimensions=出現方尖碑的世界 +config.ebwizardry.obelisk_dimensions.tooltip=列出會生成方尖碑的世界ID。移除所有的世界ID就完全不會生成方尖碑了。 +config.ebwizardry.obelisk_rarity=方尖碑的出現率 +config.ebwizardry.obelisk_rarity.tooltip=方尖碑的出現機率,設定每多少區塊中會出現一座方尖碑,這個意思就是數值愈大機率愈低。 +config.ebwizardry.obelisk_files=方尖碑結構檔 +config.ebwizardry.obelisk_files.tooltip=列出方尖碑結構檔的位置。每次生成方尖碑時會在這些檔案中隨機挑選一個。檔案位置的格式為[模組ID]\:[檔案名稱],其指向檔案 assets/[模組ID]/structures/[檔案名稱].nbt。清單中允許重複的檔案,如此可以簡單的提高某個結構的出現率,而不用實際去複製增加那個結構的檔案。這個清單請勿完全空白,若要停用方尖碑,請在方尖碑的生成世界中設定。 +config.ebwizardry.shrine_dimensions=出現神殿的世界 +config.ebwizardry.shrine_dimensions.tooltip=列出會生成神殿的世界ID。移除所有的世界ID就完全不會生成神殿了。 +config.ebwizardry.shrine_rarity=神殿的出現率 +config.ebwizardry.shrine_rarity.tooltip=神殿的出現機率,設定每多少區塊中會出現一座神殿,這個意思就是數值愈大機率愈低。 +config.ebwizardry.shrine_files=神殿結構檔 +config.ebwizardry.shrine_files.tooltip=列出神殿結構檔的位置。每次生成神殿時會在這些檔案中隨機挑選一個。檔案位置的格式為[模組ID]\:[檔案名稱],其指向檔案 assets/[模組ID]/structures/[檔案名稱].nbt。清單中允許重複的檔案,如此可以簡單的提高某個結構的出現率,而不用實際去複製增加那個結構的檔案。這個清單請勿完全空白,若要停用神殿,請在神殿的生成世界中設定。 +config.ebwizardry.tree_blocks=樹木方塊 +config.ebwizardry.tree_blocks.tooltip=列出法術模組在生成結構時(快速及講究模式都是),可被覆蓋的方塊註冊名稱(不分大小寫)。大部分的樹木方塊及其它樹葉應該都能自動作用,將那些不能的手動增加於此。對於模組的方塊,須在名稱前加上模組ID(例如dynamictrees:oakbranch)。 +config.ebwizardry.ore_dimensions=出現礦物的世界 +config.ebwizardry.ore_dimensions.tooltip=列出會生成水晶礦的世界ID。請注意,如果將主世界(id=0)從名單中移除,會使這個模組玩起來變得非常困難! +config.ebwizardry.flower_dimensions=出現花的世界 +config.ebwizardry.flower_dimensions.tooltip=列出會生成水晶花的世界ID。 +config.ebwizardry.loot_injection_locations=戰利品匯入檔位置 +config.ebwizardry.loot_injection_locations.tooltip=列出用來匯入的法術模組戰利品檔(格式請參考 loot_tables/chests/dungeon_additions.json) 。 + +config.ebwizardry.category.client=客戶端設定 +config.ebwizardry.category.client.tooltip=法術模組的顯示及控制設定 +config.ebwizardry.title.client=客戶端設定 +config.ebwizardry.subtitle.client=客戶端的設定只會影響到那台Minecraft遊戲 + +config.ebwizardry.shift_scrolling=潛行+滑鼠滾輪 +config.ebwizardry.shift_scrolling.tooltip=是否能在潛行時使用滑鼠滾輪來切換法杖中的法術。請注意,這個設定只會用於你,其他連線到相同伺服器的玩家,用的是他們自己的設定。 +config.ebwizardry.reverse_scroll_direction=滑鼠滾輪方向 +config.ebwizardry.reverse_scroll_direction.tooltip=潛行時用來選擇法杖中法術的滑鼠滾輪切換方向。 +config.ebwizardry.reverse_scroll_direction.true=相反 +config.ebwizardry.reverse_scroll_direction.false=一般 +config.ebwizardry.spell_hud_position=法術顯示窗位置 +config.ebwizardry.spell_hud_position.tooltip=法術顯示窗的位置。 +config.ebwizardry.spell_hud_skin=法術顯示窗的外觀 +config.ebwizardry.spell_hud_skin.tooltip=變更法術顯示窗看起來的樣子。 +config.ebwizardry.spell_hud_skin.preview=預覽 +config.ebwizardry.handbook_progression=漸進式手冊 +config.ebwizardry.handbook_progression.tooltip=開啟時,為了指引玩家進入這個模組,玩家必須完成進度,才會解鎖法師手冊中的章節,否則都是隱藏的。 關閉的話,不論進度如何,整本手冊都可閱讀。創造模式下也可直接閱讀整本手冊。 +config.ebwizardry.handbook_progression.true=是 - 老師請教我! +config.ebwizardry.handbook_progression.false=不 - 我知道在幹什麼! +config.ebwizardry.books_pause_game=看書時暫停 +config.ebwizardry.books_pause_game.tooltip=是否在單人遊戲中開啟任何法術模組的書本時暫停遊戲。於伺服器或網路的世界無效。 +config.ebwizardry.books_pause_game.true=是 - 我需要專心看書! +config.ebwizardry.books_pause_game.false=不 - 我都看書來打發時間! +config.ebwizardry.summoned_creature_names=召喚的生物名稱 +config.ebwizardry.summoned_creature_names.tooltip=設定是否將生物的名稱及擁有者顯示在牠們頭上。 +config.ebwizardry.summoned_creature_names.true=顯示 +config.ebwizardry.summoned_creature_names.false=隱藏 +config.ebwizardry.use_shaders=使用自訂著色器 +config.ebwizardry.use_shaders.tooltip=是否對某些法術使用自訂的著色器。這些使用一般的著色系統(像是模組旁觀著色器),在大部分的情況下應該不會對效能產生太大影響,但可能會與其它的著色器發生衝突。 +config.ebwizardry.use_shaders.true=是 - 我要這些很讚的著色器! +config.ebwizardry.use_shaders.false=不 - 我在龜速的電腦上執行! + +config.ebwizardry.category.commands=指令設定 +config.ebwizardry.category.commands.tooltip=法術模組的指令設定 +config.ebwizardry.title.commands=指令設定 +config.ebwizardry.subtitle.commands=法術模組增加的指令設定 + +config.ebwizardry.cast_command_multiplier_limit=多重施法命令限制 +config.ebwizardry.cast_command_multiplier_limit.tooltip=多重透過/case指令施法的上限。這個限制是為了阻止世界或伺服器遭到玩家破壞的意外發生。多重大規模的爆炸會導致系統嚴重的延遲──已警告你了! +config.ebwizardry.cast_command_name=施法指令名稱 +config.ebwizardry.cast_command_name.tooltip=執行/cast命令的名稱,這是你要在斜線(/)後直接輸入的指令,舉例來說,如果將這個值設定為'magic',那原本輸入/cast的指令就要改成輸入/magic。 +config.ebwizardry.discoverspell_command_name=探索法術指令名稱 +config.ebwizardry.discoverspell_command_name.tooltip=執行/discoverspell命令的名稱,這是你要在斜線(/)後直接輸入的指令,舉例來說,如果將這個值設定為'magic',那原本輸入/discoverspell的指令就要改成輸入/magic。 +config.ebwizardry.ally_command_name=設定同伴指令名稱 +config.ebwizardry.ally_command_name.tooltip=執行/ally命令的名稱,這是你要在斜線(/)後直接輸入的指令,舉例來說,如果將這個值設定為'magic',那原本輸入/ally的指令就要改成輸入/magic。 +config.ebwizardry.allies_command_name=檢視同伴指令名稱 +config.ebwizardry.allies_command_name.tooltip=執行/allies命令的名稱,這是你要在斜線(/)後直接輸入的指令,舉例來說,如果將這個值設定為'magic',那原本輸入/allies的指令就要改成輸入/magic。 + +config.ebwizardry.category.resistances=免疫設定 +config.ebwizardry.category.resistances.tooltip=設定對各類魔法免疫的生物 +config.ebwizardry.title.resistances=免疫設定 +config.ebwizardry.subtitle.resistances=設定對該類魔法免疫的實體名稱 + +config.ebwizardry.mobs_immune_to_fire=對火焰免疫的生物 +config.ebwizardry.mobs_immune_to_fire.tooltip=除了預設值以外,對火焰免疫的實體名稱列表。將想要使其對火系魔法免疫的生物加入這個名單。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.mobs_immune_to_ice=對冰凍免疫的生物 +config.ebwizardry.mobs_immune_to_ice.tooltip=除了預設值以外,對冰凍免疫的實體名稱列表。將想要使其對冰系魔法免疫的生物加入這個名單。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.mobs_immune_to_lightning=對雷電免疫的生物 +config.ebwizardry.mobs_immune_to_lightning.tooltip=除了預設值以外,對雷電免疫的實體名稱列表。將想要使其對電系魔法免疫的生物加入這個名單。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.mobs_immune_to_wither=對凋零免疫的生物 +config.ebwizardry.mobs_immune_to_wither.tooltip=除了預設值以外,對凋零免疫的實體名稱列表。將想要使其對凋零魔法免疫的生物加入這個名單。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 +config.ebwizardry.mobs_immune_to_poison=對毒性免疫的生物 +config.ebwizardry.mobs_immune_to_poison.tooltip=除了預設值以外,對毒性免疫的實體名稱列表。將想要使其對毒性魔法免疫的生物加入這個名單。名單中的實體名稱不分英文大小寫,若要加入模組的生物,須在名稱開頭加上模組ID(例如ebwizardry\:wizard)。 + +config.ebwizardry.category.compatibility=模組相容性設定 +config.ebwizardry.category.compatibility.tooltip=設定法術模組如何與其它模組互動 +config.ebwizardry.title.compatibility=模組相容性設定 +config.ebwizardry.subtitle.compatibility=設定法術模組與其它模組如何互相影響 + +config.ebwizardry.damage_source_blacklist=傷害來源黑名單 +config.ebwizardry.damage_source_blacklist.tooltip=列出要忽略的重複傷害來源識別字串(區分大小寫)。如果法術模組偵測到應該加入清單的傷害來源,會輸出訊息到紀錄檔。 +config.ebwizardry.compatibility_warnings=相容性警告 +config.ebwizardry.compatibility_warnings.tooltip=是否將相容性警告訊息輸出至監控畫面。 如果輸出的訊息太多就關掉。 +config.ebwizardry.baubles_integration=飾品欄(Baubles)模組的整合 +config.ebwizardry.baubles_integration.tooltip=當安裝了飾品欄(Baubles)模組時,控制是否開啟整合飾品欄模組的功能。如果關閉這個設定,法術模組就會當成沒有安裝飾品欄模組。 +config.ebwizardry.jei_integration=JEI模組的整合 +config.ebwizardry.jei_integration.tooltip=當安裝了JEI(Just Enough Items)模組時,控制是否開啟整合JEI模組的功能。如果關閉這個設定,法術模組就會當成沒有安裝JEI模組。 +config.ebwizardry.antique_atlas_integration=古代地圖(Antique Atlas)模組的整合 +config.ebwizardry.antique_atlas_integration.tooltip=當安裝了古代地圖(Antique Atlas)模組時,控制是否開啟整合古代地圖模組的功能。如果關閉這個設定,法術模組就會當成沒有安裝古代地圖模組。 +config.ebwizardry.auto_place_tower_markers=自動標記法師塔 +config.ebwizardry.auto_place_tower_markers.tooltip=設定法術模組是否在古代地圖中自動放置法師塔位置的記號。 +config.ebwizardry.auto_place_obelisk_markers=自動標記方尖塔 +config.ebwizardry.auto_place_obelisk_markers.tooltip=設定法術模組是否在古代地圖中自動放置方尖塔位置的記號。 +config.ebwizardry.auto_place_shrine_markers=自動標記神殿 +config.ebwizardry.auto_place_shrine_markers.tooltip=設定法術模組是否在古代地圖中自動放置神殿位置的記號。 + +integration.jei.category.ebwizardry\:arcane_workbench=法術工作台 + +integration.antiqueatlas.marker.ebwizardry\:wizard_tower=法師塔 +integration.antiqueatlas.marker.ebwizardry\:obelisk=方尖碑 +integration.antiqueatlas.marker.ebwizardry\:shrine=神殿 + +wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json index db383025..70959e51 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json @@ -103,7 +103,7 @@ { "type": "item", "name": "ebwizardry:astral_diamond", - "weight": 1 + "weight": 2 }, { "type": "item", @@ -113,7 +113,7 @@ { "type": "item", "name": "ebwizardry:grand_crystal", - "weight": 1 + "weight": 2 } ] } diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json index 7a0a73a4..481b9c33 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json @@ -10,7 +10,7 @@ { "type": "loot_table", "name": "ebwizardry:subsets/arcane_tomes", - "weight": 3 + "weight": 4 }, { "type": "loot_table", diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json index 76af240f..933e15ff 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json @@ -31,7 +31,7 @@ { "type": "loot_table", "name": "ebwizardry:subsets/arcane_tomes", - "weight": 6 + "weight": 8 }, { "type": "loot_table", @@ -108,7 +108,7 @@ { "type": "item", "name": "ebwizardry:astral_diamond", - "weight": 1 + "weight": 2 }, { "type": "item", @@ -118,7 +118,7 @@ { "type": "item", "name": "ebwizardry:grand_crystal", - "weight": 1 + "weight": 2 } ] }, diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json index 4bb9c235..a003824c 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json @@ -20,7 +20,7 @@ { "type": "loot_table", "name": "ebwizardry:subsets/arcane_tomes", - "weight": 4 + "weight": 5 }, { "type": "loot_table", diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/arcane_tomes.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/arcane_tomes.json index 404f7402..c9629c35 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/subsets/arcane_tomes.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/subsets/arcane_tomes.json @@ -8,7 +8,7 @@ "type": "item", "entryName": "apprentice_tome", "name": "ebwizardry:arcane_tome", - "weight": 3, + "weight": 4, "functions": [ { "function": "set_data", diff --git a/src/main/resources/assets/ebwizardry/models/item/blank_scroll.json b/src/main/resources/assets/ebwizardry/models/item/blank_scroll.json index 14f38c44..bcbf8838 100644 --- a/src/main/resources/assets/ebwizardry/models/item/blank_scroll.json +++ b/src/main/resources/assets/ebwizardry/models/item/blank_scroll.json @@ -2,5 +2,13 @@ "parent": "item/generated", "textures": { "layer0": "ebwizardry:items/scroll" - } + }, + "overrides": [ + { + "predicate": { + "festive": 1 + }, + "model": "ebwizardry:item/festive_scroll" + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/festive_scroll.json b/src/main/resources/assets/ebwizardry/models/item/festive_scroll.json new file mode 100644 index 00000000..18e8a816 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/festive_scroll.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/scroll_festive" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/festive_spell_book.json b/src/main/resources/assets/ebwizardry/models/item/festive_spell_book.json new file mode 100644 index 00000000..98e8e12e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/festive_spell_book.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/spell_book_festive" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/festive_wand.json b/src/main/resources/assets/ebwizardry/models/item/festive_wand.json new file mode 100644 index 00000000..b31af7dd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/festive_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/wand_festive" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/scroll.json b/src/main/resources/assets/ebwizardry/models/item/scroll.json index 14f38c44..bcbf8838 100644 --- a/src/main/resources/assets/ebwizardry/models/item/scroll.json +++ b/src/main/resources/assets/ebwizardry/models/item/scroll.json @@ -2,5 +2,13 @@ "parent": "item/generated", "textures": { "layer0": "ebwizardry:items/scroll" - } + }, + "overrides": [ + { + "predicate": { + "festive": 1 + }, + "model": "ebwizardry:item/festive_scroll" + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/spell_book.json b/src/main/resources/assets/ebwizardry/models/item/spell_book.json index e47489da..b5941b77 100644 --- a/src/main/resources/assets/ebwizardry/models/item/spell_book.json +++ b/src/main/resources/assets/ebwizardry/models/item/spell_book.json @@ -2,5 +2,13 @@ "parent": "item/generated", "textures": { "layer0": "ebwizardry:items/spell_book" - } + }, + "overrides": [ + { + "predicate": { + "festive": 1 + }, + "model": "ebwizardry:item/festive_spell_book" + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/magic_silk.json b/src/main/resources/assets/ebwizardry/recipes/magic_silk.json index 033a85e4..0e759257 100644 --- a/src/main/resources/assets/ebwizardry/recipes/magic_silk.json +++ b/src/main/resources/assets/ebwizardry/recipes/magic_silk.json @@ -7,7 +7,8 @@ ], "key": { "x": { - "item": "minecraft:string" + "type": "forge:ore_dict", + "ore": "string" }, "y": [ { @@ -48,4 +49,4 @@ "item": "ebwizardry:magic_silk", "count": 2 } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/ebwizardry/sounds.json b/src/main/resources/assets/ebwizardry/sounds.json index 9ed093b0..75efd3a7 100644 --- a/src/main/resources/assets/ebwizardry/sounds.json +++ b/src/main/resources/assets/ebwizardry/sounds.json @@ -7,7 +7,7 @@ "item.wand.levelup": {"category": "player", "sounds": ["random/levelup"]}, "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.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.vanish": {"category": "spells", "sounds": ["portal/trigger"]}, @@ -62,7 +62,8 @@ "entity.wizard.no": {"category": "neutral", "sounds": ["mob/villager/no1", "mob/villager/no2", "mob/villager/no3"]}, "entity.wizard.hurt": {"category": "neutral", "sounds": ["mob/villager/hit1", "mob/villager/hit2", "mob/villager/hit3", "mob/villager/hit4"]}, "entity.wizard.death": {"category": "neutral", "sounds": ["mob/villager/death"]}, - + "entity.wizard.hohoho": {"category": "neutral", "sounds": ["ebwizardry:hohoho"]}, + "entity.darkness_orb.hit": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]}, "entity.dart.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, "entity.dart.hit_block": {"category": "spells", "sounds": ["random/bowhit1", "random/bowhit2", "random/bowhit3"]}, @@ -158,8 +159,8 @@ "spell.flaming_axe": {"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.font_of_mana": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, - "spell.font_of_vitality": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.font_of_mana": {"category": "spells", "sounds": ["ebwizardry:buff_large"]}, + "spell.font_of_vitality": {"category": "spells", "sounds": ["ebwizardry:buff_large"]}, "spell.force_arrow": {"category": "spells", "sounds": ["ebwizardry:force"]}, "spell.forcefield": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, "spell.force_orb": {"category": "spells", "sounds": ["random/bow"]}, @@ -179,11 +180,11 @@ "spell.grapple.pull": {"category": "spells", "sounds": ["ebwizardry:pull1", "ebwizardry:pull2"]}, "spell.grapple.release": {"category": "spells", "sounds": ["random/bowhit1", "random/bowhit2", "random/bowhit3"]}, "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.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]}, "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.growth_aura": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, "spell.hailstorm": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, @@ -250,12 +251,12 @@ "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.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.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.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.loop": {"category": "spells", "sounds": ["ebwizardry:dark_aura_loop"]}, "spell.shadow_ward.end": {"category": "spells", "sounds": ["ebwizardry:dark_aura_end"]}, diff --git a/src/main/resources/assets/ebwizardry/sounds/arc1.ogg b/src/main/resources/assets/ebwizardry/sounds/arc1.ogg index f5d3c72f..83f70350 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/arc1.ogg and b/src/main/resources/assets/ebwizardry/sounds/arc1.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/arc2.ogg b/src/main/resources/assets/ebwizardry/sounds/arc2.ogg index 53a04e5d..380bf733 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/arc2.ogg and b/src/main/resources/assets/ebwizardry/sounds/arc2.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/arc3.ogg b/src/main/resources/assets/ebwizardry/sounds/arc3.ogg index b2ee55d9..4ff58041 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/arc3.ogg and b/src/main/resources/assets/ebwizardry/sounds/arc3.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/aura_end.ogg b/src/main/resources/assets/ebwizardry/sounds/aura_end.ogg index 89170073..c8c25c91 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/aura_end.ogg and b/src/main/resources/assets/ebwizardry/sounds/aura_end.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg index 616ed77c..5d6d3b3e 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg and b/src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/aura_start.ogg b/src/main/resources/assets/ebwizardry/sounds/aura_start.ogg index 1736c3bb..385d9b72 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/aura_start.ogg and b/src/main/resources/assets/ebwizardry/sounds/aura_start.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/buff.ogg b/src/main/resources/assets/ebwizardry/sounds/buff.ogg index 4ac23bd7..d65e74c8 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/buff.ogg and b/src/main/resources/assets/ebwizardry/sounds/buff.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/buff_large.ogg b/src/main/resources/assets/ebwizardry/sounds/buff_large.ogg new file mode 100644 index 00000000..5fd15705 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/sounds/buff_large.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/conjure.ogg b/src/main/resources/assets/ebwizardry/sounds/conjure.ogg index d48bdffc..14bae7a8 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/conjure.ogg and b/src/main/resources/assets/ebwizardry/sounds/conjure.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/conjure_large.ogg b/src/main/resources/assets/ebwizardry/sounds/conjure_large.ogg index c9caa43f..7a2e02da 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/conjure_large.ogg and b/src/main/resources/assets/ebwizardry/sounds/conjure_large.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/crackle.ogg b/src/main/resources/assets/ebwizardry/sounds/crackle.ogg index cc81620e..44a499bf 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/crackle.ogg and b/src/main/resources/assets/ebwizardry/sounds/crackle.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg b/src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg index 3e3093c1..5f0a204e 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg and b/src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/dark_aura_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/dark_aura_loop.ogg index 2268fe1d..9b9e5ed8 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/dark_aura_loop.ogg and b/src/main/resources/assets/ebwizardry/sounds/dark_aura_loop.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg b/src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg index 04fd8be5..dd134c6e 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg and b/src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/effect1.ogg b/src/main/resources/assets/ebwizardry/sounds/effect1.ogg index dc9a4760..8dab3fcf 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/effect1.ogg and b/src/main/resources/assets/ebwizardry/sounds/effect1.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/effect2.ogg b/src/main/resources/assets/ebwizardry/sounds/effect2.ogg index c2c9a62d..f428ae96 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/effect2.ogg and b/src/main/resources/assets/ebwizardry/sounds/effect2.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/firebolt.ogg b/src/main/resources/assets/ebwizardry/sounds/firebolt.ogg index 84babd4e..2fb6c994 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/firebolt.ogg and b/src/main/resources/assets/ebwizardry/sounds/firebolt.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/flames_end.ogg b/src/main/resources/assets/ebwizardry/sounds/flames_end.ogg index b3488b59..1b50d105 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/flames_end.ogg and b/src/main/resources/assets/ebwizardry/sounds/flames_end.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg index 634727f6..acf52a10 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg and b/src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/flames_start.ogg b/src/main/resources/assets/ebwizardry/sounds/flames_start.ogg index 40108d2c..326400f4 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/flames_start.ogg and b/src/main/resources/assets/ebwizardry/sounds/flames_start.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/force.ogg b/src/main/resources/assets/ebwizardry/sounds/force.ogg index 0da336b2..e62e7deb 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/force.ogg and b/src/main/resources/assets/ebwizardry/sounds/force.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/freeze.ogg b/src/main/resources/assets/ebwizardry/sounds/freeze.ogg index 014dc1e4..bfe80996 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/freeze.ogg and b/src/main/resources/assets/ebwizardry/sounds/freeze.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/frostray.ogg b/src/main/resources/assets/ebwizardry/sounds/frostray.ogg index 0567212e..4117e4e6 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/frostray.ogg and b/src/main/resources/assets/ebwizardry/sounds/frostray.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/grow.ogg b/src/main/resources/assets/ebwizardry/sounds/grow.ogg index bf48758b..5fd63112 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/grow.ogg and b/src/main/resources/assets/ebwizardry/sounds/grow.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/heal.ogg b/src/main/resources/assets/ebwizardry/sounds/heal.ogg index a58b11f6..bb6a6705 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/heal.ogg and b/src/main/resources/assets/ebwizardry/sounds/heal.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/hohoho.ogg b/src/main/resources/assets/ebwizardry/sounds/hohoho.ogg new file mode 100644 index 00000000..ee09f4df Binary files /dev/null and b/src/main/resources/assets/ebwizardry/sounds/hohoho.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/ice.ogg b/src/main/resources/assets/ebwizardry/sounds/ice.ogg index 9879c888..0f0a8f4c 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/ice.ogg and b/src/main/resources/assets/ebwizardry/sounds/ice.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_end.ogg b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_end.ogg index b8eb148c..6b98488b 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_end.ogg and b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_end.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg index 041658ec..732d522d 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg and b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_start.ogg b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_start.ogg index 898bb0b3..3edda40e 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_start.ogg and b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_start.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/magic1.ogg b/src/main/resources/assets/ebwizardry/sounds/magic1.ogg index 94b13b16..65f745cc 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/magic1.ogg and b/src/main/resources/assets/ebwizardry/sounds/magic1.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/magic2.ogg b/src/main/resources/assets/ebwizardry/sounds/magic2.ogg index cf4f5a79..8f51fb1b 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/magic2.ogg and b/src/main/resources/assets/ebwizardry/sounds/magic2.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/magic3.ogg b/src/main/resources/assets/ebwizardry/sounds/magic3.ogg index f65f2ad4..a8048bae 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/magic3.ogg and b/src/main/resources/assets/ebwizardry/sounds/magic3.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/magic4.ogg b/src/main/resources/assets/ebwizardry/sounds/magic4.ogg index 1793567a..ff88573a 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/magic4.ogg and b/src/main/resources/assets/ebwizardry/sounds/magic4.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/pull1.ogg b/src/main/resources/assets/ebwizardry/sounds/pull1.ogg index 4ce3730c..a6c453b9 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/pull1.ogg and b/src/main/resources/assets/ebwizardry/sounds/pull1.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/pull2.ogg b/src/main/resources/assets/ebwizardry/sounds/pull2.ogg index 737809f4..3e87e9ca 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/pull2.ogg and b/src/main/resources/assets/ebwizardry/sounds/pull2.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/rumble.ogg b/src/main/resources/assets/ebwizardry/sounds/rumble.ogg index b9d208b1..a8318bb6 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/rumble.ogg and b/src/main/resources/assets/ebwizardry/sounds/rumble.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/shockwave.ogg b/src/main/resources/assets/ebwizardry/sounds/shockwave.ogg index 3af866c0..059f8f30 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/shockwave.ogg and b/src/main/resources/assets/ebwizardry/sounds/shockwave.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg b/src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg index 9010c3d5..f94d6ed5 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg and b/src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg index 77c76ac2..a81f8dd9 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg and b/src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg b/src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg index 9004f213..5421bdff 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg and b/src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/sparkle.ogg b/src/main/resources/assets/ebwizardry/sounds/sparkle.ogg index e6899fee..f7e169d1 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/sparkle.ogg and b/src/main/resources/assets/ebwizardry/sounds/sparkle.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/summon1.ogg b/src/main/resources/assets/ebwizardry/sounds/summon1.ogg index 81b556fd..34b51215 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/summon1.ogg and b/src/main/resources/assets/ebwizardry/sounds/summon1.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/summon2.ogg b/src/main/resources/assets/ebwizardry/sounds/summon2.ogg index df471a0d..f9624fbe 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/summon2.ogg and b/src/main/resources/assets/ebwizardry/sounds/summon2.ogg differ diff --git a/src/main/resources/assets/ebwizardry/sounds/wind.ogg b/src/main/resources/assets/ebwizardry/sounds/wind.ogg index 1b824691..50170537 100644 Binary files a/src/main/resources/assets/ebwizardry/sounds/wind.ogg and b/src/main/resources/assets/ebwizardry/sounds/wind.ogg differ diff --git a/src/main/resources/assets/ebwizardry/spells/frost_axe.json b/src/main/resources/assets/ebwizardry/spells/frost_axe.json index b76cbfdf..e0d8912f 100644 --- a/src/main/resources/assets/ebwizardry/spells/frost_axe.json +++ b/src/main/resources/assets/ebwizardry/spells/frost_axe.json @@ -17,6 +17,7 @@ "chargeup": 0, "cooldown": 50, "base_properties": { - "item_lifetime": 1200 + "item_lifetime": 1200, + "damage": 8 } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json index d8b193a0..a040b1c2 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json +++ b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json @@ -736,7 +736,7 @@ "Translations:", - "- Spanish and Mexican Spanish: MadWrist \n- Russian: VilagVil, kellixon \n- French: Hahdrim \n- Brazilian Portuguese: lorrampi \n- Chinese: ZHENGLOC, dragon-evol \n- Korean: shejery, rewi_wire \n- Polish: Trozuu", + "- Spanish: MadWrist, Alsentar \n- Mexican Spanish: MadWrist \n- Russian: VilagVil, kellixon, bigenergy \n- French: Hahdrim \n- Brazilian Portuguese: lorrampi \n- Chinese: ZHENGLOC, dragon-evol, Hokorizero, TUsama \n- Korean: shejery, rewi_wire \n- Polish: Trozuu \n-German: BirdyDragon", "Lightning ray sound effect from OhhWowProductions", diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json index 0fd729f5..45d60db3 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json +++ b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json @@ -736,7 +736,7 @@ "Translations:", - "- Spanish and Mexican Spanish: MadWrist \n- Russian: VilagVil, kellixon \n- French: Hahdrim \n- Brazilian Portuguese: lorrampi \n- Chinese: ZHENGLOC, dragon-evol \n- Korean: shejery, rewi_wire \n- Polish: Trozuu", + "- Spanish: MadWrist, Alsentar \n- Mexican Spanish: MadWrist \n- Russian: VilagVil, kellixon, bigenergy \n- French: Hahdrim \n- Brazilian Portuguese: lorrampi \n- Chinese: ZHENGLOC, dragon-evol, Hokorizero, TUsama \n- Korean: shejery, rewi_wire \n- Polish: Trozuu \n-German: BirdyDragon", "Lightning ray sound effect from OhhWowProductions", diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_es_es.json b/src/main/resources/assets/ebwizardry/texts/handbook_es_es.json new file mode 100644 index 00000000..a8b933ab --- /dev/null +++ b/src/main/resources/assets/ebwizardry/texts/handbook_es_es.json @@ -0,0 +1,750 @@ +{ + "bookmark_start_section": "introduction", + + "colours": { + "text": "#000000", + "caption": "#666666", + "hyperlink": "#601ba0", + "highlight": "#dd4c1d", + "new_section": "#ee88f7" + }, + + "images": { + "workbench": { + "location": "ebwizardry:textures/gui/arcane_workbench_picture.png", + "caption": "Mesa Arcana", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "crystal_ore": { + "location": "ebwizardry:textures/gui/ore_picture.png", + "caption": "Mena de Cristal Mágico", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "magic_crystal": { + "location": "ebwizardry:textures/items/crystal_magic.png", + "caption": "Cristal Mágico", + "u": 6, + "v": 6, + "width": 36, + "height": 33, + "texture_width": 48, + "texture_height": 48, + "border": false + }, + "magic_wand": { + "location": "ebwizardry:textures/items/wand_novice.png", + "caption": "Varita Mágica", + "u": 0, + "v": 0, + "width": 64, + "height": 64, + "border": false + }, + "crystal_flower": { + "location": "ebwizardry:textures/gui/flower_picture.png", + "caption": "Flor de Cristal", + "u": 0, + "v": 0, + "width": 48, + "height": 48 + }, + "wizard_tower": { + "location": "ebwizardry:textures/gui/tower_picture.png", + "caption": "Torre de mago", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "wizard_armour": { + "location": "ebwizardry:textures/gui/armour_picture.png", + "caption": "Conjunto de Armadura de mago", + "u": 0, + "v": 0, + "width": 90, + "height": 90 + }, + "obelisk": { + "location": "ebwizardry:textures/gui/obelisk_picture.png", + "caption": "Obelisco", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "shrine": { + "location": "ebwizardry:textures/gui/shrine_picture.png", + "caption": "Santuario de la tierra", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "tiers": { + "location": "ebwizardry:textures/gui/tiers_picture.png", + "caption": "Los 4 niveles en las Varitas", + "u": 0, + "v": 0, + "width": 96, + "height": 24, + "border": false + }, + "elements": { + "location": "ebwizardry:textures/gui/elements_picture.png", + "caption": "Los 7 elementos Arcanos", + "u": 0, + "v": 0, + "width": 106, + "height": 20, + "border": false + } + }, + + "recipes": { + "arcane_workbench": { + "locations": [ "ebwizardry:arcane_workbench" ] + }, + "magic_wand": { + "locations": [ "ebwizardry:magic_wand" ] + }, + "novice_wands": { + "locations": [ + "ebwizardry:magic_wand", + "ebwizardry:wand_fire", + "ebwizardry:wand_ice", + "ebwizardry:wand_lightning", + "ebwizardry:wand_necromancy", + "ebwizardry:wand_earth", + "ebwizardry:wand_sorcery", + "ebwizardry:wand_healing" + ] + }, + "magic_missile_spell_book": { + "locations": [ "ebwizardry:magic_missile_spell_book" ] + }, + "wizard_handbook": { + "locations": [ "ebwizardry:wizard_handbook" ] + }, + "crystal_flower_to_crystals": { + "locations": [ "ebwizardry:crystal_flower_to_crystals" ] + }, + "crystal_blocks": { + "locations": [ + "ebwizardry:crystal_block", + "ebwizardry:crystal_block_fire", + "ebwizardry:crystal_block_ice", + "ebwizardry:crystal_block_lightning", + "ebwizardry:crystal_block_necromancy", + "ebwizardry:crystal_block_earth", + "ebwizardry:crystal_block_sorcery", + "ebwizardry:crystal_block_healing" + ] + }, + "crystal_blocks_to_crystals": { + "locations": [ + "ebwizardry:crystal_block_to_crystals", + "ebwizardry:crystal_block_to_crystals_fire", + "ebwizardry:crystal_block_to_crystals_ice", + "ebwizardry:crystal_block_to_crystals_lightning", + "ebwizardry:crystal_block_to_crystals_necromancy", + "ebwizardry:crystal_block_to_crystals_earth", + "ebwizardry:crystal_block_to_crystals_sorcery", + "ebwizardry:crystal_block_to_crystals_healing" + ] + }, + "crystal_shard": { + "locations": [ "ebwizardry:crystal_shard" ] + }, + "small_mana_flask": { + "locations": [ "ebwizardry:small_mana_flask" ] + }, + "medium_mana_flask": { + "locations": [ "ebwizardry:medium_mana_flask" ] + }, + "large_mana_flask": { + "locations": [ "ebwizardry:large_mana_flask" ] + }, + "runestone": { + "locations": [ + "ebwizardry:runestone_fire", + "ebwizardry:runestone_ice", + "ebwizardry:runestone_lightning", + "ebwizardry:runestone_necromancy", + "ebwizardry:runestone_earth", + "ebwizardry:runestone_sorcery", + "ebwizardry:runestone_healing" + ] + }, + "runestone_pedestal": { + "locations": [ + "ebwizardry:runestone_pedestal_fire", + "ebwizardry:runestone_pedestal_ice", + "ebwizardry:runestone_pedestal_lightning", + "ebwizardry:runestone_pedestal_necromancy", + "ebwizardry:runestone_pedestal_earth", + "ebwizardry:runestone_pedestal_sorcery", + "ebwizardry:runestone_pedestal_healing" + ] + }, + "transportation_stone": { + "locations": [ "ebwizardry:transportation_stone" ] + }, + "magic_silk": { + "locations": [ "ebwizardry:magic_silk" ] + }, + "wizard_hat": { + "locations": [ "ebwizardry:wizard_hat" ] + }, + "wizard_robe": { + "locations": [ "ebwizardry:wizard_robe" ] + }, + "wizard_leggings": { + "locations": [ "ebwizardry:wizard_leggings" ] + }, + "wizard_boots": { + "locations": [ "ebwizardry:wizard_boots" ] + }, + "blank_scroll": { + "locations": [ "ebwizardry:blank_scroll" ] + }, + "firebomb": { + "locations": [ "ebwizardry:firebomb" ] + }, + "poison_bomb": { + "locations": [ "ebwizardry:poison_bomb" ] + }, + "smoke_bomb": { + "locations": [ "ebwizardry:smoke_bomb" ] + }, + "spark_bomb": { + "locations": [ "ebwizardry:spark_bomb" ] + } + }, + + "sections": { + + "inside_cover": { + "centre": { + "x": true, + "y": true + }, + "text": [ + + "El Manual del Mago", + + "Por Electroblob" + ] + }, + + "introduction": { + "title": "Introduccion", + "text": [ + + "¡Saludos Mago! Este libro te mostrara los secretos de las artes arcanas, y de cómo usarlas. Este no es un libro común y corriente, ya que su conocimiento y sus páginas aumentarán a medida que descubres más y más sobre mundo mágico.", + + "Utiliza los botones en forma de flecha para pasar la página, y los botones de doble flecha para pasar de una sección a otra. Usa el botón de menú central para regresar al índice.", + + "Haz clic en cualquier palabra en color purpura para ir directamente al tema en cuestión. Haz clic derecho al marcador rojo para moverlo a la página actual, y clic izquierdo para saltar a la página marcada." + ] + }, + + "main_contents": { + "title": "Índice", + "contents": { + "id": "main_contents", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + } + }, + + "setting_up": { + "title": "Iniciación", + "include_in_contents": "main_contents", + "text": [ + + "Para comenzar como mago, necesitarás conseguir lo siguiente:", + + "- Una Varita mágica, hecha de la siguiente forma:", + + "#recipe magic_wand", + + "- Una @arcane_workbench Mesa Arcana@, hecha de a siguiente forma:", + + "#recipe arcane_workbench", + + "- Un @spells Libro de hechizos@. Estos se pueden encontrar en cofres, recompensas por matar monstruos, y comprado a otros magos. Puedes crear el hechizo Misil Mágico, un hechizo de bajo nivel, de la siguiente forma:", + + "#recipe magic_missile_spell_book", + + "También necesitaras bastantes Cristales Mágicos para suplir tu varita de @mana@." + ] + }, + + "mana": { + "title": "Maná", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:crystal" + ], + "text": [ + + "El Maná es la energía mística que concede a los magos sus habilidades. Mucho más que una sustancia física, el Maná es un aura que impregna la realidad de forma omnipresente. En nuestro mundo, suele acumularse hasta formar cristales sólidos, los cuales pueden ser hallados incrustados en piedra en el subsuelo. Las @wands Varitas@ almacenan Maná dentro de ellas, y este Maná es canalizado hacia fuera al conjurar un @spells Hechizo@. Diferentes Hechizos requieren diferentes cantidades de Maná, dependiendo de que tan poderosos sean y de cuanto duren sus efectos.", + + "#image crystal_ore", + + "#image magic_crystal", + + "Al ser energía pura, el Maná no puede ser creado ni destruido. Cuando se conjura un hechizo, El Maná canalizado simplemente se disipa en el ambiente. Ciertamente, la mayoría de Maná se encuentra esparcido en pequeñas cantidades a través de todo el Cosmos. Sin embargo, para poder ser usado, el Maná debe de estar concentrado. Esto se puede lograr de forma natural a través de miles de años, como pasa con los cristales mágicos, o de forma artificial, un método avanzado no abordado en este libro. También existen diferentes formas de que el Maná sea mejor administrado al conjurar hechizos, y de recuperar una parte del Maná disipado en el ambiente." + ] + }, + + "wands": { + "title": "Varitas", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "La varita es el arma y herramienta principal de un mago. Con ella, podrás conjurar cualquier @spells hechizo@ que la varita pueda canalizar (véase @tiers Niveles@). Las varitas vienen en diferentes variedades, pero es muy probable que empieces con una varita básica.", + + "#image magic_wand", + + "La mayoria de varitas comienzan como una estructura simple de un cristal mágico unido a un palo de madera, con una pepita de oro unido en el otro extremo. El cristal es, claro está, la fuente de poder de la varita, ya que provee el foco necesario para canalizar @spells hechizos@. El resto de la varita es importante también, ya que no solo provee un medio para sostener la varita, sino también un circuito interno por el cual el @mana maná@ puede ser canalizado y dirigido.", + + "A medida que se conjuren hechizos con la varita, esta se volverá más efectiva en canalizar dichos @spells hechizos@, y eventualmente, en conjurar hechizos mas poderosos. Esto se puede notar debido a ciertos cambios en la varita misma: Mientras mas poderosa se vuelva una varita, su cristal mágico se volverá más brillante, su color puede llegar a cambiar dependiendo de su @elements elemento@, y después de un tiempo, la madera de la que esta hecha comenzara a crecer por si sola y a retorcerse en figuras mas complejas.", + + "Mientras sostienes una varita, un pequeño recuadro aparecerá en la esquina de tu pantalla. Este recuadro muestra el hechizo seleccionado actualmente, además de una imagen para representar tal hechizo, si el hechizo ya fue conjurado, y una barra de cooldown indicando el tiempo restante para poder conjurar el hechizo otra vez. Tambien muestra los nombres del hechizo anterior y el hechizo siguiente vinculados a la varita. Para cambiar de hechizo, utiliza las teclas #next_spell_key and #previous_spell_key (Estas pueden ser modificadas en Opciones > Controles). Tambien puedes cambiar de hechizo utilizando la rueda del mouse mientras estas agachado.", + + "Cuando veas tu inventario, si pones el mouse sobre la varita, veras cuanto @mana mana@ le queda, junto con el @spells hechizo@ seleccionado actualmente y otras habilidades que tenga. Puedes visualizar más información sobre la varita colocándola en una @arcane_workbench mesa arcana@." + ] + }, + + "spells": { + "title": "Hechizos", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/spells" + ], + "text": [ + + "Sin hechizos para conjurar y lanzar, una @wands varita@ es prácticamente inútil. Los hechizos son grabados en dos formas: en libros, los cual los hace permanentes, y en pergaminos, los cuales son temporales.", + + "Los libros de hechizos son inútiles por si mismos, por lo que son usados para vincular el hechizo que contienen a las @wands varitas@. Los libros de hechizos se encuentran pueden ser hallados a través de todo el planeta, y no tomara mucho tiempo encontrarte con uno. Cuando lo encuentres, puedes colocar el mouse sobre el libro de hechizo para ver información básica sobre el hechizo que contiene. También puedes darle clic derecho mientras lo sostienes para leer mas acerca de él.", + + "Por otro lado, los pergaminos sirven otro propósito: Haciendo click derecho mientras sostienes uno conjurará el hechizo escrito en el, consumiendo el pergamino. Al igual que los libros de hechizos, los pergaminos pueden ser hallados en muchas partes del mundo, pero también puedes crearlos tu mismo(a) (véase @enchanting_scrolls Encantando Pergaminos@).", + + "Los pergaminos son bastante utiles cuando necesitas utilizar un hechizo una o dos veces en una misión específica, y no quieres que tome espacio innecesario en tu @wands varita@. De todas formas, cabe destacar que no son tan efectivas para conjurar hechizos en comparación con las varitas.", + + "Desde la perspectiva de alguien común y corriente, los símbolos y runas en los cuales están escritos los hechizos son solo garabatos ilegibles. Pero tú no eres alguien común. ¡Eres un mago, joder! Y como tal, poco a poco iras aprendiendo a descifrar este lenguaje. Para identificar un hechizo podrías, claro está, simplemente conjurarlo y ver que pasa. Pero ten en cuenta que al hacerlo puede haber efectos no deseados, además de que muchos hechizos necesitan ciertas condiciones para funcionar. Además de eso, para novatos es probable leer el hechizo de forma errónea y pueden llegar a haber consecuencias peligrosas dependiendo de que tan poderoso sea el hechizo. Una opción más segura es utilizar un pergamino de identificación, los cuales pueden ser encontrados en cofres o comprados a otros magos. Al hacer click derecho mientras se sostiene uno, se identificará el primer hechizo desconocido en tu inventario, consumiendo el pergamino de identificación." + ] + }, + + "arcane_workbench": { + "title": "Mesa Arcana", + "include_in_contents": "main_contents", + "contents": { + "id": "arcane_workbench_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "La mesa arcana es un bloque similar a la mesa de encantamientos, donde podrás recargar, mejorar, y vincular @spells hechizos@ a tu @wands varita@. Puedes crearla de la siguiente forma:", + + "#recipe arcane_workbench", + + "Las siguientes paginas explicaran las acciones que puedes hacer en una mesa arcana.", + + "#image workbench" + ], + "sections": { + "binding_spells": { + "title": "Vinculando Hechizos", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "Para vincular un @spells hechizo@ a tu @wands varita@, solo tienes que colocar la varita en la ranura central de la mesa arcana, luego colocar el libro de hechizo que desees en las ranuras alrededor y presionar “Aplicar”. Como habrás de notar, el acto de vincular un hechizo no afecta al libro, esto es porque al vincular un hechizo, la mesa arcana no “toma” el hechizo del libro, sino que de cierta forma “copia” de forma resumida el hechizo en la varita. De esta forma, puedes cambiar los hechizos vinculados a tu varita tantas veces como quieras con solo repetir el proceso. Puedes vincular hasta cinco hechizos diferentes a una sola varita cada vez, aunque este numero puede aumentar con mejoras de vinculación." + ] + }, + "charging_wands": { + "title": "Recargando Varitas", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "Para recargar tu @wands varita@, coloca la varita en la ranura central de la mesa arcana, coloca algunos cristales mágicos en la ranura inferior izquierda y luego presiona “Aplicar”. Cada cristal vale #mana_per_crystal @mana maná@, y la varita solo tomara lo que necesita, por lo que puedes dejar una provision de cristales en la mesa arcana para cuando la necesites. Sin embargo, ten en cuenta que la varita solo puede tomar números de cristales enteros, así que si por ejemplo, la varita necesita 30 mas de maná, #example_charging_loss de maná se perderán al cargarla." + ] + }, + "upgrading_wands": { + "title": "Mejorando Varitas", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], + "text": [ + + "Para mejorar tu @wands varita@, necesitaras un Tomo de Arcana del @tiers nivel@ adecuado, o también, una mejora especial para tu varita. Los Tomos de Arcana y las mejoras especiales pueden ser hallados en cofres o comprados a otros magos. Para mejorar tu varita, colocala en la ranura central, y coloca el objeto de mejora en la ranura superior derecha, luego presiona “Aplicar”.", + + "Mejoras especiales para la varita cambian el aspecto de la varita. Cada tipo de mejora se puede acumular tres veces, y el total de mejoras que una varita puede tomar depende de su nivel. Solo recuerda que las mejoras no pueden ser removidas." + ] + }, + "enchanting_scrolls": { + "title": "Encantando Pergaminos", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/scrolls" + ], + "text": [ + + "La mesa Arcana tambien puede ser usada para encantar @spells hechizos@ en pergaminos. Para hacerlo, necesitaras un pergamino en blanco, creado con papel y un poco de cuerda, un libro de hechizo de tu preferencia, y suficientes cristales mágicos para proveer @mana maná@ para conjurar.", + + "#recipe blank_scroll", + + "Coloca los cristales en la ranura inferior izquierda, el pergamino en blanco en la ranura central, y el libro de hechizos en la sola ranura encima, luego presiona confirmar par encantar le pergamino." + ] + } + } + }, + + "wizard_armour": { + "title": "Armadura de Mago", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "Como el legendario y poderoso mago que eres, necesitaras algo para protegerte de las criaturas y monstruos que obviamente vencerás. Las armaduras normales son buenas, sí… pero checa eso: Sombrero, túnica, pantalones y botas. A diferencia de las armaduras normales, la armadura de mago no se rompe, ya que utiliza maná para endurecer su tela al punto de simular el metal, y proteger al usuario. Estas armaduras deben de ser recargadas con cristales mágicos, como las varitas. Afortunadamente, estas ropas no consumen mucho @mana maná@. Recárgalas como lo harías con una varita en la @arcane_workbench mesa arcana@ o con @mana_flasks frascos de mana@. Pero ten cuidado, si se le acaba el maná, lo único que te protegerá de aquellos monstruos será simple tela.", + + "#image wizard_armour", + + "Puedes crear una armadura de mago a partir de tela mágica:", + + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + + "Puedes encantar una armadura de mago usando una mesa de encantamientos común, y debido a las propiedades de la tela mágica, es bastante efectiva en retener encantamientos. Los encantamientos de Protección contra Magia, Hielo y Electricidad son de particular utilidad para magos como tú, especialmente en defensa contra otros magos.", + + "Aquellos magos que se dedican a la práctica de un elemento particular suelen llevar ropas especiales que les proporcionan efectos adicionales para dominar tal elemento. Conjuntos enteros de aquellas ropas son muy buscadas por los magos y no son fáciles de encontrar.", + + "Leyendas hablan sobre un sello arcano usado por los magos y brujas mas poderosos. Dicen que aquel sello volverá la armadura de cualquier mago tan resistente como su contraparte mundana…" + ] + }, + + "magical_world": { + "title": "Magia en el Mundo", + "include_in_contents": "main_contents", + "contents": { + "id": "magical_world_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/on_subsection_unlock" + ], + "text": [ + + "No puedes dominar las artes arcanas quedándote encerrado en tu cuarto ¿o sí? ¡Hay un mundo entero de magia allá afuera para explorar! Ruinas Antiguas, reliquias y seres misteriosos benévolos y malévolos esperan ser descubiertos – si sabes donde buscar. Los más grandes magos también son los más curiosos, y mucho de su conocimiento y poder lo encontraron explorando el mundo que los rodea, y experimentando con lo que encuentran.", + + "Aunque un mago pasa la mayoría de su tiempo solo, compartir conocimiento es vital para aprender las artes arcanas. Busca a otros practicantes de la magia y aprende todo lo que puedas de ellos. La comunicación es uno de los poderes mas grandes que puedas tener." + ], + "sections": { + "crystal_flowers": { + "title": "Flores de Cristal", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/crystal_flowers" + ], + "text": [ + + "Durante tu travesía, es probable que te encuentre una curiosa y colorida flor que emite luz. Estas interesantes flores se les conoce como flores de cristal, y son altamente concentradas en @mana maná@. Nade sabe el porque de esto, lo que si sabemos es que sus pétalos están hechos de cristales de mana, haciendo de estas flores una fuente útil de mana en la superficie. La cantidad de maná obtenida de esta forma es limitada debido al pequeño tamaño de las flores, y que suelen crecer en grupos pequeños.", + + "#image crystal_flower", + "#recipe crystal_flower_to_crystals" + ] + }, + "wizard_towers": { + "title": "Torres de mago", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:wizard_tower" + ], + "text": [ + + "No temas, no eres el único practicante de magia en este mundo. En tus viajes, puede que te encuentres con una o dos altas torres con techos puntiagudos. Esta es la residencia de un mago. A veces una vida de soledad puede volver a los magos un poco gruñones, pero usualmente son personas amigables que están dispuestos a compartir su conocimiento contigo, por un precio. No te sorprendas si debes pagar raros y preciosos metales y gemas, ya que a cambio recibirás grandes maravillas arcanas.", + + "En el caso de que fuese un hechizo de nivel @tiers maestro@ lo que buscas, necesitaras hablar con un especialista.", + + "#image wizard_tower", + + "Desafortunadamente, existen algunos magos en cuyas puertas los visitantes no son bienvenidos. Estos magos suelen ser marginados, y son hostiles hacia todo aquel que se cruce en su camino. Ten cuidado con estos individuos. Si los encuentras, prepárate para defenderte contra magia poderosa. Véncelos, y su conocimiento será tuyo.", + + "Cabe destacar que los magos no toman de buena forma el ser atacados o robados, y siendo ese el caso, no dudarán en tomar la justicia por sus propias manos." + ] + }, + "obelisks": { + "title": "Obeliscos", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/obelisks" + ], + "text": [ + + "Vestigios de antiguas civilizaciones yacen esparcidas por todo el mundo. Los mas notables son estructuras de piedra tallada con símbolos y runas. Estas ruinas son todo lo que queda de lo que parece ser alguna clase de civilización antigua. Quien sea, o lo que sea que las haya construido, claramente tenían amplios conocimientos sobre magia, conocimientos que uso para conjurar encantamientos protectores que aun hoy día permanecen en aquellos lugares.", + + "Estas estructuras suelen ser de dos tipos. El primero, y el mas común, son los Obeliscos: altas construcciones puntiagudas hechas de piedras rúnicas, con una estructura inferior abierta que contiene reliquias arcanas menores, ya olvidadas en el pasado.", + + "#image obelisk", + + "Estas estructuras suelen estar protegidas por un encantamiento que invoca @creatures criaturas@ del Caos Elemental cuando un humano se acerca demasiado. Vence a estas criaturas, destruye su invocador, y las reliquias serán tuyas." + ] + }, + "shrines": { + "title": "Santuarios", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:visit_shrine" + ], + "text": [ + + "El Segundo tipo es mucho mas raro, y son conocidos como santuarios. Estas estructuras consisten en un circulo de pilares de piedras rúnicas rodeando un pedestal central, en el cualse encuentra un cofre que contiene @artefacts artefactos@. Este cofre suele estar protegido por un encantamiento de Cerradura Arcana, impidiendo que cualquiera excepto el dueño lo abra. La estructura completa también esta protegida por un campo de contención, el cual impide el escape de cualquier cosa que se acerque demasiado.", + + "#image shrine", + + "Debido al gran poder e importancia arcana, sin mencionar las riquezas que contiene, estas estructuras son particularmente atractivas para cualquier mago aspirante. Pero ten cuidado, ha habido reportes de magos quedando atrapados en en el campo de contención y lentamente perdiendo la cordura a medida que pasa el tiempo. Algunos otros, creen que aquellas ocurrencias es un deliberado esfuerzo de la magia protectora del santuario, y que aquellos magos atrapados son controlados para proteger la estructura. Una perspectiva escalofriante sin duda para todo aquel que se atreva a aventurarse cerca…." + ] + }, + "creatures": { + "title": "Criaturas Magicas", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/magical_creatures" + ], + "text": [ + + "Además de magos, una gran cantidad de criaturas utilizan magia. Muchas de estas criaturas son de origen arcano, y la mayoría pueden ser invocadas desde el Caos Elemental usando @spells hechizos@. Es posible encontrarse con estas criaturas protegiendo un obelisco o a un poderoso mago invocador. Seres arcanos menores pueden ser encontrados casualmente en la naturaleza." + ] + }, + "artefacts": { + "title": "Artefactos", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:artefact" + ], + "text": [ + + "Al explorar un @shrines santuario@, puedes ser lo bastante afortunado(a) como para encontrar alguna clase de artefacto mágico antiguo, un objeto capaz de concederle a su portador poderes y habilidades únicas y poderosas. Tres tipos de artefactos se han encontrado son: anillos, lo cuales conceden efectos especiales a hechizos, amuletos, los cuales mejoran habilidades defensivas y talismanes, que conceden efectos de utilidad. Estos artefactos parecen funcionar solo si se llevan de forma apropiada, el simple hecho de tenerla en su persona es insuficiente." + ] + } + } + }, + + "tiers": { + "title": "Niveles", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], + "text":[ + + "Las @wands varitas@ y @spells hechizos@ vienen en cuatro niveles: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Cada nivel es mas poderoso que el anterior.", + + "#image tiers", + + "#colour_noviceNovice #colour_resetwands son las que pueden ser creadas. Pueden almacenar hasta #novice_max_charge maná, y solo pueden conjurar hechizos de nivel novato. Hechizos de nivel novato son lo bastante simples para ser conjurados por cualquiera y no suelen usar mucho maná. Esto no significa que son inútiles en niveles mas altos, ya que su bajo costo los hace bastante útiles incluso al tener acceso a hechizos de nivel maestro.", + + "#colour_apprenticeApprentice #colour_resetwands son el siguiente nivel de varitas después del nivel novato. Pueden almacenar hasta #apprentice_max_charge maná y puede conjurar hechizos de novato y hechizos de aprendiz. Los hechizos de aprendiz son mas impresionantes que los hechizos de novato, pero suelen costar más.", + + "#colour_advancedAdvanced #colour_resetwands son mas raras y ponderosas. Pueden conjurar todos los hechizos excepto hechizos de nivel maestro, y almacenan hasta #advanced_max_charge maná. Hechizos de nivel avanzado pueden conceder poderes y habilidades super humanas como inivisibilidad y causar estragos en enemigos.", + + "#colour_masterMaster #colour_resetwands son las varitas más poderosas que existen. Almacenan hasta #master_max_charge maná y pueden conjurar cualquier hechizo. Libros de hechizo de nivel maestro son muy raros, y ciertos hechizos pueden causar una terrible devastación no solo a enemigos, sino al mundo mismo. Usar con precaución.", + + "Para poder ser mejorada a un nivel mayor, la varita debe de volverse lo suficientemente poderosa como para canalizar hechizos de ese nivel. Las varitas ganan poder a medida de que hechizos son conjurados con ellas. Variedad, poder, efectos elementales y otros fatores externos pueden tener efecto en que tan rápido una varita gana este poder.", + + "Una vez que una varita es lo suficientemente poderosa, un tomo de arcana proveerá el catalizador final para elevar a la varita al siguiente nivel (véase @upgrading_wands Mejorando varitas@), una vez que esto pasa, el proceso de maduración para la varita comienza de nuevo." + ] + }, + + "elements": { + "title": "Elementos", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/elements" + ], + "text": [ + + "Los @spells hechizos@ pertenecen a diferentes elementos, los cuales determinan la naturaleza del hechizo y conceden ventajas al ser conjurados por ciertas @wands varitas@.", + + "#image elements", + + "#colour_fireFire#colour_reset \n Talvez el elemento mas destructivo. El fuego se trata sobre quemar, consumir, lava y explosiones. Un Pirómano poderoso desatará el infierno ante sus enemigos y probablemente incendie el mundo en el proceso. La mayoría de hechizos de fuego envuelven a los enemigos en llamas, causando Daño adicional con el tiempo. Sin embargo, ten en cuenta que los hechizos de fuego no tienen efecto sobre las criaturas provenientes del Nether.", + + "#colour_iceIce#colour_reset \n El elemento de hielo contiene todo lo que es frio. Los hechizos gélidos suelen ralentizar a los enemigos o congelarlos completamente, y son especialmente efectivos en criaturas de fuego. Los hechizos de hielo suelen también ser útiles fuera de combate, como por ejemplo, congelar el agua para cruzar un rio.", + + "#colour_lightningLightning#colour_reset \n Este es el element que concierne los relámpagos, truenos y rayos, tormentas, lluvias y el clima. Un poderoso mago de la tormenta es una fuerza a temer, y algunos poseen la habilidad de comandar a los rayos a voluntad. Los hechizos de tormenta suelen dañar múltiples enemigos al mismo tiempo e incluso siguen a sus objetivos, haciendo de estos un ataque efectivo contra cualquier enemigo…..pero ten cuidado con los creepers.", + + "#colour_necromancyNecromancy#colour_reset \n La necromancia es el elemento de la oscuridad, caos y de la no-muerte. Los necromagos son misteriosos, y suelen considerarse malvados, aunque este no suele ser el caso. Los hechizos de necromancia suelen ser usados para invocar @creatures criaturas@ para pelear por ti o incluso doblegar la voluntad de tus enemigos.", + + "#colour_earthEarth#colour_reset \n El elemento de la tierra se enfoca en el mundo natural: animales, plantas, el viento, y cosas por el estilo. Los hechizos de tierra son diversos y toman una gran variedad de formas, desde envenenar enemigos hasta desencadenar la furia del clima terrenal. Los hechizos de tierra suelen ser una mezcla de ataque, defensa y utilidad.", + + "#colour_sorcerySorcery#colour_reset \n La hechicería es el elemento del cambio y la fuerza. Los hechiceros manipulan la luz, la gravedad e incluso la realidad misma para que se ajuste a sus necesidades. Los hechizos de hechicería pueden ser usados, entre muchas otras cosas, para darle al mago poderes especiales o mover objetos a voluntad.", + + "#colour_healingHealing#colour_reset \n El elemento de curación es un elemento perfectamente válido, ¿verdad? ¡¿Verdad?! Este elemento se trata sobre defensa y regeneración. Los curanderos buscan protegerse a ellos mismos y a sus aliados en los mas posible y por eso suelen ser oponentes formidables. Aunque no suele ser usado de forma ofensiva, la luz purificadora de algunos hechizos de curación hará un Daño considerable a los no-muertos. Los hechizos de curación son indispensables en combate", + + "Los límites entre diferentes elementos no son siempre diferentes, y algunos hechizos suelen tener semejanza a otros elementos diferentes al suyo.", + + "Si tienes suerte, podrás encontrar un cristal elemental. Los cristales elementales son cristales mágicos que absorbieron propiedades elementales mientras se formaban. Estos cristales pueden ser usados para crear varitas elementales, las cuales potencian los hechizos de tal elemento." + ] + }, + + "miscellaneous": { + "title": "Miscelaneo", + "include_in_contents": "main_contents", + "contents": { + "id": "miscellaneous_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:on_subsection_unlock" + ], + "sections": { + "mana_flasks": { + "title": "Frascos de mana", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/mana_flasks" + ], + "text": [ + + "Provisiones Arcanas de Arkendur inc. – ¡Objetos mágicos para todas tus necesidades!", + + "¿Necesitas recargar tu @wands varita@ de forma rápida? ¡No hay problema! El @mana mana@ ya puede ser embotellado. Simplemente creas un frasco de mana con una botella y ocho cristales mágicos. Cuando quieras usarlo, solo colócalo en la mesa de crafteo con tu varita y cargara cierta parte. *", + + "#recipe medium_mana_flask", + + "¡NUEVO! Aquí llegaron los nuevos frascos de mana de tamaños pequeños y grandes – ¡ahora puedes seleccionar un frasco que satisface tus necesidades!", + + "#recipe small_mana_flask", + "#recipe large_mana_flask", + + "* Este proceso destruirá la botella. Cierto nivel de mana se pierde durante el embotellamiento." + ] + }, + "throwable_items": { + "title": "Objetos Arrojables", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/throwables" + ], + "text": [ + + "Algunos @spells hechizos@ conjuran objetos físicos, algunos de estos pueden ser creados directamente. Bombas de fuego, Bombas de veneno, Bombas de chispas y Bombas de humo pueden todas ser creadas:", + + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" + ] + }, + "automated_casting": { + "title": "Conjuracion Automatica", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:enchant_scroll" + ], + "text": [ + + "Experimentación reciente ha revelado que es posible automatizar la conjuración de @spells hechizos@, hasta cierto punto, usando nada mas que un dispensador simple. Nadie sabe porque, pero parece que las extrañas propiedades de la piedra roja se extienden hasta la conjuración de un pergamino de hechizo. Poniendo un par de estos en un dispensador y dándole poder serviría como una buena trampa…." + ] + } + } + }, + + "crafting_recipes": { + "title": "Recetas para crafteos", + "include_in_contents": "main_contents", + "text": [ + + "#recipe arcane_workbench", + "#recipe novice_wands", + "#recipe magic_missile_spell_book", + "#recipe wizard_handbook", + "#recipe crystal_flower_to_crystals", + "#recipe crystal_blocks", + "#recipe crystal_blocks_to_crystals", + "#recipe crystal_shard", + "#recipe small_mana_flask", + "#recipe medium_mana_flask", + "#recipe large_mana_flask", + "#recipe runestone", + "#recipe runestone_pedestal", + "#recipe transportation_stone", + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + "#recipe blank_scroll", + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" + ] + }, + + "credits": { + "title": "Creditos", + "include_in_contents": "main_contents", + "text": [ + + "Electroblob's Wizardry \nVersion #version \nPara Minecraft #mcversion", + + "Diseñado, programado y texturizado por Electroblob", + + "Gracias a Minecraft Forge y MCP, cuya presencia hizo posible este mod.", + + "¡Gracias también a la Comunidad de Mods de Minecraft, que siempre tiene una respuesta para mis preguntas!", + + "Adicionalmente, me gustaría agradecer a los siguientes individuos por sus contribuciones al mod:", + + "Codigo:", + + "- Corail31 \n- 12foo \n- Shadows-of-Fire \n- HellFirePvP \n- Tora-B \n- Avatair \n- Aeronica", + + "Traducciones:", + + "- Español: MadWrist, Alsentar \n- Español de Mexico: MadWrist \n- Ruso: VilagVil, kellixon, bigenergy \n- Frances: Hahdrim \n- Portuges Brasileño: lorrampi \n- Chino: ZHENGLOC, dragon-evol, Hokorizero, TUsama \n- Koreano: shejery, rewi_wire \n- Polaco: Trozuu, \nAlemán: BirdyDragon", + + "Efecto de sonido para los relámpagos por OhhWowProductions", + + "Para mas informacion, revisa nuestra @https://github.com/Electroblob77/Wizardry/wiki wiki@.", + + "¿Te encanta este mod? ¡unete al @https://discord.gg/MTmMzMv servidor de Discord@ para las ultimas noticias,discusiones y extras!" + ] + } + + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_zh_cn.json b/src/main/resources/assets/ebwizardry/texts/handbook_zh_cn.json index a0dbb35e..f63424da 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_zh_cn.json +++ b/src/main/resources/assets/ebwizardry/texts/handbook_zh_cn.json @@ -1,751 +1,751 @@ -{ - "bookmark_start_section": "introduction", - - "colours": { - "text": "#000000", - "caption": "#666666", - "hyperlink": "#601ba0", - "highlight": "#dd4c1d", - "new_section": "#ee88f7" - }, - - "images": { - "workbench": { - "location": "ebwizardry:textures/gui/arcane_workbench_picture.png", - "caption": "奥术工作台", - "u": 0, - "v": 0, - "width": 110, - "height": 110 - }, - "crystal_ore": { - "location": "ebwizardry:textures/gui/ore_picture.png", - "caption": "水晶矿石", - "u": 0, - "v": 0, - "width": 64, - "height": 64 - }, - "magic_crystal": { - "location": "ebwizardry:textures/items/crystal_magic.png", - "caption": "魔法水晶", - "u": 6, - "v": 6, - "width": 36, - "height": 33, - "texture_width": 48, - "texture_height": 48, - "border": false - }, - "magic_wand": { - "location": "ebwizardry:textures/items/wand_novice.png", - "caption": "魔杖", - "u": 0, - "v": 0, - "width": 64, - "height": 64, - "border": false - }, - "crystal_flower": { - "location": "ebwizardry:textures/gui/flower_picture.png", - "caption": "水晶花", - "u": 0, - "v": 0, - "width": 48, - "height": 48 - }, - "wizard_tower": { - "location": "ebwizardry:textures/gui/tower_picture.png", - "caption": "巫师塔", - "u": 0, - "v": 0, - "width": 110, - "height": 110 - }, - "wizard_armour": { - "location": "ebwizardry:textures/gui/armour_picture.png", - "caption": "一整套巫师护具", - "u": 0, - "v": 0, - "width": 90, - "height": 90 - }, - "obelisk": { - "location": "ebwizardry:textures/gui/obelisk_picture.png", - "caption": "方尖碑", - "u": 0, - "v": 0, - "width": 110, - "height": 67 - }, - "shrine": { - "location": "ebwizardry:textures/gui/shrine_picture.png", - "caption": "大地圣祠", - "u": 0, - "v": 0, - "width": 110, - "height": 67 - }, - "tiers": { - "location": "ebwizardry:textures/gui/tiers_picture.png", - "caption": "宗师级魔杖", - "u": 0, - "v": 0, - "width": 96, - "height": 24, - "border": false - }, - "elements": { - "location": "ebwizardry:textures/gui/elements_picture.png", - "caption": "七种魔法元素", - "u": 0, - "v": 0, - "width": 106, - "height": 20, - "border": false - } - }, - - "recipes": { - "arcane_workbench": { - "locations": [ "ebwizardry:arcane_workbench" ] - }, - "magic_wand": { - "locations": [ "ebwizardry:magic_wand" ] - }, - "novice_wands": { - "locations": [ - "ebwizardry:magic_wand", - "ebwizardry:wand_fire", - "ebwizardry:wand_ice", - "ebwizardry:wand_lightning", - "ebwizardry:wand_necromancy", - "ebwizardry:wand_earth", - "ebwizardry:wand_sorcery", - "ebwizardry:wand_healing" - ] - }, - "magic_missile_spell_book": { - "locations": [ "ebwizardry:magic_missile_spell_book" ] - }, - "wizard_handbook": { - "locations": [ "ebwizardry:wizard_handbook" ] - }, - "crystal_flower_to_crystals": { - "locations": [ "ebwizardry:crystal_flower_to_crystals" ] - }, - "crystal_blocks": { - "locations": [ - "ebwizardry:crystal_block", - "ebwizardry:crystal_block_fire", - "ebwizardry:crystal_block_ice", - "ebwizardry:crystal_block_lightning", - "ebwizardry:crystal_block_necromancy", - "ebwizardry:crystal_block_earth", - "ebwizardry:crystal_block_sorcery", - "ebwizardry:crystal_block_healing" - ] - }, - "crystal_blocks_to_crystals": { - "locations": [ - "ebwizardry:crystal_block_to_crystals", - "ebwizardry:crystal_block_to_crystals_fire", - "ebwizardry:crystal_block_to_crystals_ice", - "ebwizardry:crystal_block_to_crystals_lightning", - "ebwizardry:crystal_block_to_crystals_necromancy", - "ebwizardry:crystal_block_to_crystals_earth", - "ebwizardry:crystal_block_to_crystals_sorcery", - "ebwizardry:crystal_block_to_crystals_healing" - ] - }, - "crystal_shard": { - "locations": [ "ebwizardry:crystal_shard" ] - }, - "small_mana_flask": { - "locations": [ "ebwizardry:small_mana_flask" ] - }, - "medium_mana_flask": { - "locations": [ "ebwizardry:medium_mana_flask" ] - }, - "large_mana_flask": { - "locations": [ "ebwizardry:large_mana_flask" ] - }, - "runestone": { - "locations": [ - "ebwizardry:runestone_fire", - "ebwizardry:runestone_ice", - "ebwizardry:runestone_lightning", - "ebwizardry:runestone_necromancy", - "ebwizardry:runestone_earth", - "ebwizardry:runestone_sorcery", - "ebwizardry:runestone_healing" - ] - }, - "runestone_pedestal": { - "locations": [ - "ebwizardry:runestone_pedestal_fire", - "ebwizardry:runestone_pedestal_ice", - "ebwizardry:runestone_pedestal_lightning", - "ebwizardry:runestone_pedestal_necromancy", - "ebwizardry:runestone_pedestal_earth", - "ebwizardry:runestone_pedestal_sorcery", - "ebwizardry:runestone_pedestal_healing" - ] - }, - "transportation_stone": { - "locations": [ "ebwizardry:transportation_stone" ] - }, - "magic_silk": { - "locations": [ "ebwizardry:magic_silk" ] - }, - "wizard_hat": { - "locations": [ "ebwizardry:wizard_hat" ] - }, - "wizard_robe": { - "locations": [ "ebwizardry:wizard_robe" ] - }, - "wizard_leggings": { - "locations": [ "ebwizardry:wizard_leggings" ] - }, - "wizard_boots": { - "locations": [ "ebwizardry:wizard_boots" ] - }, - "blank_scroll": { - "locations": [ "ebwizardry:blank_scroll" ] - }, - "firebomb": { - "locations": [ "ebwizardry:firebomb" ] - }, - "poison_bomb": { - "locations": [ "ebwizardry:poison_bomb" ] - }, - "smoke_bomb": { - "locations": [ "ebwizardry:smoke_bomb" ] - }, - "spark_bomb": { - "locations": [ "ebwizardry:spark_bomb" ] - } - }, - - "sections": { - - "inside_cover": { - "centre": { - "x": true, - "y": true - }, - "text": [ - - "巫师手札", - - "By Electroblob" - ] - }, - - "introduction": { - "title": "介绍", - "text": [ - - "向你致以敬意, 巫师! 这本书介绍了数种魔法类别以及操纵这些元素的方法。 我必须提醒你,这本书并不只是像现在这样,看起来十分普通 —— 当你在探索这个世界时,书中新的内容会不断地具现出来。", - - "点击单箭头按钮可以切换页数, 点击双箭头按钮可以在章节之间切换. 点击中心按钮可以返回目录。", - - "点击紫色的链接将会直接跳转到相关页面, 右键书签将会把书签移动到当前页面, 左键书签将会返回标记页面。" - ] - }, - - "main_contents": { - "title": "内容", - "contents": { - "id": "main_contents", - "hyperlinks": true, - "page_numbers": true, - "separator": "." - } - }, - - "setting_up": { - "title": "在最开始", - "include_in_contents": "main_contents", - "text": [ - - "想要开始你的巫术之旅,你需要:", - - "- 一把魔杖, 合成如下所示:", - - "#recipe magic_wand", - - "- 一个 @arcane_workbench 奥术工作台@ , 合成如下所示:", - - "#recipe arcane_workbench", - - "- 一本 @spells 法术@ 书. 你可以在战利品箱发现法术书, 它也会以掉落物形式出现,你也可以与其他巫师交易。当然你也可以制作一本初始的法术书, 魔法飞弹, 如下所示:", - - "#recipe magic_missile_spell_book", - - "你还要准备大量的魔法水晶,为你的魔杖注入 @mana 魔力@ ." - ] - }, - - "mana": { - "title": "魔力", - "include_in_contents": "main_contents", - "triggers": [ - "ebwizardry:crystal" - ], - "text": [ - - "魔力作为一种魔法能量,是巫师力量的来源。 它自身并不是某种物质; 它是无处不在的场域,充塞于世界上的一切之中. 特殊的情况下,它会以水晶的形式在自然中出现, 而这种水晶通常会镶嵌于地底的石头中. @wands 魔杖@ 可以储存魔力, 这些魔力会被你引导到你所释放的 @spells 法术@ 中。不同的法术需要的魔力各不一样, 魔力损耗取决于法术威力以及时长。", - - "#image crystal_ore", - - "#image magic_crystal", - - "人们普遍认为魔力无法被创生或毁灭, 当释放法术时, 法术所引导的魔力会消散到周围环境。这确实是魔力最广泛地存在形式 - 散布于世界的各个角落。然而, 一旦需要利用这些魔力, 你必须, 就像历经几千年而形成的地底水晶一样,将其凝合起来。又或者通过人工的方式将其聚合为固体形态 - 但这一精深的课题已经超出了本书的范围了. 当然,也存在着一些方法,能够提高你的魔力使用效率,或者在施法过程中恢复一些魔力消耗。" - ] - }, - - "wands": { - "title": "魔杖", - "include_in_contents": "main_contents", - "triggers": [ - "ebwizardry:arcane_initiate" - ], - "text": [ - - "魔杖是巫师的工具。你能够释放任何你当前的魔杖等阶能够释放的@spells 法术@ ,(参见 @tiers 等阶@ ). 魔杖有许多种类型 ,但可以肯定的是,你需要从一把基础魔杖来开启你的巫师之旅。", - - "#image magic_wand", - - "大多数魔杖的制作,在最开始时相当简单,将一块魔法水晶固定在木棍的一端,而另一端镶嵌一粒金粒,一根简单的魔杖就制作好了。魔法水晶是魔杖力量的来源, 它提供了必要的,用来引导 @spells 法术@ 的核心. 魔杖的其它部分也很重要, 它不仅能让你方便的手持魔杖进行施法, 而且还充当了引导和定向 @mana 魔力@ 流动的通路。", - - "随着魔杖释放的法术越多, 它引导 @spells 法术@ 的效率会越来越高, 因此可以可以用它来施放更强大的魔法。这种能力的变化可以从魔杖本身的形状和外观上的细微变化中看出: 随着魔杖变得越来越强大, 它顶端的魔法水晶将会变得更有活力, 水晶的颜色也会变化,变化的颜色取决于它所引导的 @elements 元素@ , 制作它的木材将会生长和扭曲,形成更复杂的形状。", - - "手持魔杖的时候, 屏幕的角落会出现一个显示框。 上面会显示当前选中的法术及其图标,如果当前法术被施放,其上的冷却条将会指示该法术可以再次施放的时间间隔。 显示框还能显示与魔杖当前使用的法术相连的上一个和下一个法术的名称. 如要在法术间切换, 你可以使用 #next_spell_key 和 #previous_spell_key 键 (这些都可以在 选项 -> 控制 中修改). 也可以在潜行时通过滚动鼠标滚轮来切换法术。", - - "查看物品栏时, 将鼠标悬停在一根魔杖上,就会显示出还有多少 @mana 魔力@ 储存在其中, 以及当前所应用于魔杖的 @spells 法术@ 以及任何特殊的能力. 想要查询魔杖的更详细的信息,可将其放置在 @arcane_workbench 奥术工作台@ ." - ] - }, - - "spells": { - "title": "法术", - "include_in_contents": "main_contents", - "triggers": [ - "ebwizardry:handbook/spells" - ], - "text": [ - - "一把 @wands 魔杖@ ,如果没有法术,那你就无法使用它. 法术有两种记录的形式: 永久性的写在法术书中,或者写在一次性的法术卷轴上", - - "法术书本身没什么用;但它们可以将其所包含的法术绑定到 @wands 魔杖@ 上. 世界中的很多地方都藏有法术书,你很快就能找到一本. 当你找到法术书时,将鼠标悬停在在法术书上就能看到法术的基本信息。你也可以在拿着一本法术书右键来阅读更多关于它的内容。", - - "卷轴有不同的用途: 右键将会施放与之绑定的法术, 在此过程中卷轴会销毁。像法术书一样,卷轴可以在世界各地找到,但你也可以自己制作(参见 @enchanting_scrolls 附魔卷轴@ ).", - - "当你需要在一些特定的情形下中使用少量特殊的法术,但又不想占用你的 @wands 魔杖@ 法术位时,卷轴将会发挥巨大的作用。然而,我必须提醒你,与使用魔杖相比,使用卷轴是一种效率低下的施法方法。", - - "对不了解该法术的人而言, 那些用于书写法术书的魔法符文实在是令人头疼。为了鉴定一个法术,你可以尝试施放该法术,看看会发生什么 - 尽管这样做可能会产生副作用, 而且许多法术需要一定的条件才能生效。更重要的是,在施放一个你不了解的法术时,总会有误读该法术的可能, 而那些由误读而带来的潜在的危险的强度则取决于该法术的威力.一个更安全、更可靠的选择是使用鉴定卷轴,你可以在箱子里找到或者从巫师那里买到. 手持鉴定卷轴右键,将会识别第一个你所不知道的法术,该过程先将快捷栏的右边开始,然后向左依次检索, 鉴定完毕会消耗鉴定卷轴。" - ] - }, - - "arcane_workbench": { - "title": "奥术工作台", - "include_in_contents": "main_contents", - "contents": { - "id": "arcane_workbench_subsections", - "hyperlinks": true, - "page_numbers": true, - "separator": "." - }, - "triggers": [ - "ebwizardry:handbook/arcane_workbench" - ], - "text": [ - - "奥术工作台外观上与附魔台很相似,它可以用来为你的魔杖充能、升级 ,以及绑定 @spells 法术@ 到你的 @wands 魔杖@ 。制作方法如下所示:", - - "#recipe arcane_workbench", - - "以下内容展示了在奥术工作台中可以执行的操作。", - - "#image workbench" - ], - "sections": { - "binding_spells": { - "title": "绑定法术", - "include_in_contents": "arcane_workbench_subsections", - "triggers": [ - "ebwizardry:handbook/arcane_workbench" - ], - "text": [ - - "想要绑定@spells 法术@到你的@wands 魔杖@, 只需将你的魔杖放在工作台中间的凹槽里,然后把法术书放在周围的一个槽里,然后点击“应用”按钮即可. 你会注意到法术书在这个过程中并没有发生变化 - 这是因为法术绑定行为不会从法术书中“取走”法术; 相反,它使魔杖与法术相协调。你可以通过简单地重复法术绑定过程来改变你魔杖上的法术,以及你也可以一次性在一根魔杖上绑定五种法术, 而一次性绑定法术上限的个数会随着魔杖协调升级而增加" - ] - }, - "charging_wands": { - "title": "魔杖充能", - "include_in_contents": "arcane_workbench_subsections", - "triggers": [ - "ebwizardry:handbook/arcane_workbench" - ], - "text": [ - - "想要充能你的 @wands 魔杖@ , 你需要把魔杖放在奥术工作台的中央凹槽里,然后把一些魔法水晶放在左下角的凹槽里, 最后点击“应用”按钮即可。每个水晶含有#mana_per_crystal @mana 魔力@, 充能时魔杖不会过量吸收魔力, 所以你可以在工作台中常备一些水晶,以便不时之需。不过要记住,魔杖只能吸收一整个水晶中的魔力, 例如,增加30点魔力, #example_charging_loss 魔力将会损失。." - ] - }, - "upgrading_wands": { - "title": "升级魔杖", - "include_in_contents": "arcane_workbench_subsections", - "triggers": [ - "ebwizardry:handbook/tome_of_arcana" - ], - "text": [ - - "为了升级你的 @wands 魔杖@ , 你需要一本适当 @tiers 等阶@ 的奥法宝典 或者一些特殊的魔杖升级. 两者都可以作为战利品或者从巫师那里购买. 想要升级你的魔杖, 你需要把它放在奥术工作台的中央凹槽,然后将升级物品放置在右上角凹槽,最后点击应用。", - - "特殊的魔杖升级可以改善魔杖某个方面的能力。每种类型的升级最多可以叠加三次,一根魔杖可以升级的总数取决于它的等级。魔杖的升级不能被移除。" - ] - }, - "enchanting_scrolls": { - "title": "附魔卷轴", - "include_in_contents": "arcane_workbench_subsections", - "triggers": [ - "ebwizardry:handbook/scrolls" - ], - "text": [ - - "奥术工作台也可以用来附魔 @spells 法术@ 卷轴。首先,你需要一个空白卷轴, 空白卷轴由线和纸组成, 以及一本法术书, 还要足够的 @mana 魔力@ ,这样才能够成功使法术拓印在空白卷轴上。", - - "#recipe blank_scroll", - - "将魔法水晶放在左下的凹槽, 空白卷轴放置在中央凹槽, 将一本法术书放置在周围凹槽, 点击应用来附魔该卷轴。" - ] - } - } - }, - - "wizard_armour": { - "title": "巫师护具", - "include_in_contents": "main_contents", - "triggers": [ - "ebwizardry:arcane_initiate" - ], - "text": [ - - "作为一名巫师, 你需要一些东西在战斗时保护你不受过高的伤害,普通的盔甲可无法承此重任。为了能够在提供保护时还能让你最高效率地使用的魔力, 你需要一套巫师护具: 包括帽子、长袍、裤子和靴子。 与普通盔甲不同的是,它们耐久归零之后不会消失。而且,蕴藏在其中的奥术能量将会保护穿戴者。当然,这意味着它们必须使用水晶充能, 这一点和魔杖很相似。幸运的是, 这些护具不太消耗@mana 魔力@. 你可以像和魔杖那样,将其放置在 @arcane_workbench 奥术工作台@ ,或者使用 @mana_flasks 魔力瓶@ 为其充能, 但是要小心-如果护具们耗尽了魔力,它们将不再提供任何保护。", - - "#image wizard_armour", - - "你可以用魔法绸缎制造巫师护具:", - - "#recipe magic_silk", - "#recipe wizard_hat", - "#recipe wizard_robe", - "#recipe wizard_leggings", - "#recipe wizard_boots", - - "你可以用附魔台为巫师护具附魔,而因为魔法绸缎的固有属性, 它们倾向于被附魔上能够使它们留存的更久的附魔. 对巫师具有特殊的实用价值为魔法,冰霜,雷电保护附魔, 这些附魔可以有效抵御其它巫师的进攻。", - - "那些沉迷于练习单系魔法的巫师,有时会穿上可以给予额外魔法增益的服装。全套这样的服装在巫师群体中很受欢迎,所以并不容易找到。", - - "在传说中,最强大的巫师使用一种神秘的封印来提高他们护甲的能力。" - ] - }, - - "magical_world": { - "title": "魔法世界", - "include_in_contents": "main_contents", - "contents": { - "id": "magical_world_subsections", - "hyperlinks": true, - "page_numbers": true, - "separator": "." - }, - "triggers": [ - "ebwizardry:handbook/on_subsection_unlock" - ], - "text": [ - - "一个人仅仅呆在家里是无法掌握奥术之力的 - 这个充塞着魔力的世界等待着你的探索! 古代遗迹,还有那些神秘的,抱着善意或者恶意的生物等待着你发现 - 如果你知道它们在哪。最伟大的巫师往往有着强烈的好奇心, 他们通过对周围环境的探索获得大量的知识和力量, 然后通过实验去验证他们所发现的。", - - "巫师的大部分时间都是一个人度过的, 然而对学习奥术而言,与他人分享彼此的知识很重要。你应该去寻找那些先行者,尽可能多地向他们学习:交流可以说是最强大的力量了。" - ], - "sections": { - "crystal_flowers": { - "title": "魔法水晶花", - "include_in_contents": "magical_world_subsections", - "triggers": [ - "ebwizardry:handbook/crystal_flowers" - ], - "text": [ - - "在你的旅行中,你可能在野外会不时地遇到一种奇怪的,发光的花. 这些独特的花朵被称为水晶花,它们能够高效的聚集 @mana 魔力@ - 直到今天,还没有人能确定它高效聚集魔力的原因。但是我们知道,它们可以被收集和制作成魔法水晶,使得它们成为相当有用的地上的魔力来源。然而,因为花的尺寸很小,而且它们无法密集生长,所以通过这种方式收获的魔力并不是很多,", - - "#image crystal_flower", - "#recipe crystal_flower_to_crystals" - ] - }, - "wizard_towers": { - "title": "巫师塔", - "include_in_contents": "magical_world_subsections", - "triggers": [ - "ebwizardry:wizard_tower" - ], - "text": [ - - "不要害怕 —— 你不是这个世界上唯一一个使用魔法的人。 在旅行途中,你很可能会遇到一两个有着独特尖顶的高塔。这是其它巫师的住所。孤独的生活有时会让巫师有点暴躁,但他们通常都很友好,而且愿意与你分享他们的知识 —— 尽管是有代价的。你可以用贵重金属和宝石来与他们交换珍贵的奥术知识。", - - "然而,如果你寻找的是 @tiers 宗师@ 法术, 你需要去找那些专业人士。", - - "#image wizard_tower", - - "不幸的是,有一些巫师不欢迎访客的到来。这些巫师早已被逐出巫师群体, 他们对任何路过此地的人都抱有敌意. 与这些人打交道要格外谨慎, 并做好防御强大魔法的准备。打败他们,他们的知识就是你的了。", - - "还应该指出的是,没有哪个巫师会乐意被攻击或被偷 - 他们更喜欢按他们的规矩来。" - ] - }, - "obelisks": { - "title": "方尖碑", - "include_in_contents": "magical_world_subsections", - "triggers": [ - "ebwizardry:handbook/obelisks" - ], - "text": [ - - "古代魔法遗迹散布在世界各地, 其中最著名的是雕刻着许多符号和符文的石头建筑. 这些遗迹似乎是某种古代文明的遗迹。不管是谁,或者是什么东西建造了它们,它们显然拥有相当丰富的魔法知识, 并使用这些知识在这些地方设置了保护魔法,这些魔法直到今天还在生效。", - - "这些结构大致可分为两类. 第一个,也是最常见的,是方尖碑: 符文石制成的尖顶, 底部有一个开放的结构,其中为次级魔法遗迹,你在上面还能感受到残存着的气息,那是来自被遗忘的过去。", - - "#image obelisk", - - "这些建筑通常受到魔法的保护,一旦有人离得太近,就会召唤敌对 @creatures 生物@ 。击退这些生物并摧毁它们的源头,那么这个遗迹的财富就是你的了。" - ] - }, - "shrines": { - "title": "圣祠", - "include_in_contents": "magical_world_subsections", - "triggers": [ - "ebwizardry:visit_shrine" - ], - "text": [ - - "第二种,也是比较少见的一种,被称为圣祠。这些结构由围绕着中心基座的一圈符文石柱组成, 基座上放置着一个箱子,里面装满了古代的 @artefacts 圣遗物@ . 这个箱子通常被一个奥术锁保护着, 除了箱子的主人,其它人都无法打开。整个结构也被一个控制场域保护着, 防止任何离得太近的东西逃跑。", - - "#image shrine", - - "只要你意识到圣祠所包含的强大魔力和其重要性, 箱子里所存放的东西的珍贵毋庸置疑, 这些结构对任何有抱负的巫师都特别有吸引力 - 但是要谨慎。有很多关于巫师被困在封闭空间里,慢慢被逼疯的报道,这也许是因为幽闭恐惧症。 然而,越来越多的人相信这种情况的发生也是圣祠的保护魔法的一部分, 被困在里面的巫师实际上是被控制来保护该结构的。 对于任何胆敢靠近的人来说,这无疑令人不寒而栗....." - ] - }, - "creatures": { - "title": "魔法生物", - "include_in_contents": "magical_world_subsections", - "triggers": [ - "ebwizardry:handbook/magical_creatures" - ], - "text": [ - - "除了巫师,许多其他生物也可以使用魔法。而在其中有很多从出生开始就拥有魔力,而且它们大部分都可以施放 @spells 法术@ . 其中一种你可能会在守卫 @obelisks 方尖碑@ 的生物中看到,他们可能是由更强大的召唤师召唤而来。偶尔你还能够在野外中被发现魔法能力不强的生物。" - ] - }, - "artefacts": { - "title": "圣遗物", - "include_in_contents": "magical_world_subsections", - "triggers": [ - "ebwizardry:artefact" - ], - "text": [ - - "当你在探索圣祠时,你可能会幸运地发现一些古老的魔法制品 —— 一些能赋予穿戴者独特而强大的魔法和特殊能力的物品。已发现三种类型: 戒指,给予法术增幅和额外效果,护身符,提高防御能力,还有符咒,能产生特殊效用。这些魔法制物似乎只有在正确佩戴时才能发挥作用; 仅仅是把它们放在身上无法发挥它们的效果。" - ] - } - } - }, - - "tiers": { - "title": "等阶", - "include_in_contents": "main_contents", - "triggers": [ - "ebwizardry:handbook/tome_of_arcana" - ], - "text":[ - - "@wands 魔杖@ 和 @spells 法术@ 分成四阶: #colour_novice新手#colour_reset, #colour_apprentice学徒#colour_reset, #colour_advanced进阶 #colour_reset 和 #colour_master宗师#colour_reset.每一阶都比上一阶更强大。", - - "#image tiers", - - "#colour_novice新手 #colour_reset魔杖 魔杖可以手工制作. 它们可以容纳 #novice_max_charge 魔力, 且只可以释放基础法术. 基础法术很简单,任何人都可以使用,而且通常情况下不会消耗很多魔力。然而,这并不一定意味着在你步入更高等阶后,它们就没有用处了; 即便你已经可以使用宗师级魔法,基础法术低廉的魔力消耗依然使得它们备受青睐。", - - "#colour_apprentice学徒 #colour_reset魔杖 是新手的下一等阶. 学徒级魔杖可容纳 #apprentice_max_charge 魔力 ,可以施放基础和学徒法术。学徒法术比新手法术更令人眼前一亮,但通常魔力消耗更多。", - - "#colour_advanced进阶 #colour_reset魔杖 魔杖是相当罕见的,而且更强大. 他们可以使用除宗师法术以外的所有法术,并能够容纳 #advanced_max_charge 魔力. 进阶法术能够带来超越人类极限的能力,譬如隐形,以及为你的敌人带来浩劫。", - - "#colour_master宗师 #colour_reset魔杖 魔杖是世界上最强大的魔杖. 他们能够容纳 #master_max_charge 魔力, 并且能够随意施展任何法术.宗师等阶的法术书是非常罕见的,这些法术不仅可以对敌人造成彻底的破坏,甚至可以对世界本身造成破坏。请务必谨慎使用。", - - "要升级到更高的等级,一根魔杖首先要有足够的力量来引导该等级的法术。魔杖在施法时会增进自身。法术种类、法术强度、元素效果和其他外部因素都会影响魔杖的成熟速度。", - - "一旦一根魔杖足够强大,一本奥法宝典就是魔杖提升到下一层所需的最后催化剂 (参见 @upgrading_wands 升级魔杖@ ), 升级过后,魔杖又可以继续成长到下一等阶。" - ] - }, - - "elements": { - "title": "元素", - "include_in_contents": "main_contents", - "triggers": [ - "ebwizardry:handbook/elements" - ], - "text": [ - - "@spells 法术@ 分属于不同的元素 , 元素决定了法术的本质并且决定了它会被何种 @wands 魔杖@ 增幅。", - - "#image elements", - - "#colour_fire火焰#colour_reset \n 它或许是最具破坏性的元素, 火与燃烧、熔岩和爆炸有关。 一位强大的舞焰师能够释放出地狱烈焰灼烧他的敌人,并可能在这个过程中点燃整个世界。大多数攻击型火焰法术都会点燃目标,造成持续的伤害。然而,要注意火系法术可能对下界生物没有效果。", - - "#colour_ice冰霜#colour_reset \nThe 冰元素囊括了所有与寒冷有关的事物,冰霜法术通常会让敌人减速或者完全冻结,同时对火焰生物能造成额外伤害。冰霜魔法在战斗之外也同样有用,比如冻住河流,让你方便的过河。", - - "#colour_lightning雷电#colour_reset \n 这种元素与闪电,风暴和天气有关。绝不可忽视的一位强大的驯雷师的力量,他们能够使雷电屈从于他们的意志。雷电法术通常能够一次性伤害多个敌人,并且能够自动寻找目标,这使得它们能有效地攻击任何生物…… 但是要小心爬行者。", - - "#colour_necromancy死灵#colour_reset \n 死灵元素与黑暗, 混乱与亡灵相关. 操纵死灵元素的巫师是神秘的,而且通常被认为是邪恶的,但实际上往往并不是这样。死灵法术通常能够召唤 @creatures 魔法生物@ 为你而战,亦可以扭曲你的敌人的意志。", - - "#colour_earth大地#colour_reset \nThe 大地元素与自然相关: 动物,植物,风,以及与这些相似的。大地魔法种类繁多,形式多样,既可以毒害敌人,亦可展现天气狂暴的一面。大地法术集合了攻击、防御和功能类法术。", - - "#colour_sorcery秘法#colour_reset \n 秘法元素与力场与变化有关. 秘术师可以操纵光、重力甚至是现实本身来满足他们的需要。此外,秘法系法术可以赋予施法者奇特的魔法能力,或者可以帮助施法者移动他所希望移动的目标。", - - "#colour_healing治愈#colour_reset \n 治愈元素侧重于防御和再生,治疗师尽可能多地保护他们自己和他们的盟友,因此在特殊情况下会非常难对付。虽然一般不用于攻击,但某些治疗法术的净化之光会对亡灵造成相当大的伤害。治疗法术在战斗中是必不可少的。", - - "不同元素之间的界限并不总是泾渭分明的,有些法术反而具有其它元素的特征。", - - "如果幸运的话,你可能会找到元素水晶。元素水晶是一种魔法水晶,它在生长过程中吸收了元素属性 - 尽管这种情况发生的条件和机制仍然是一个谜。 然而,我们确实知道,这些水晶可以用来制造单元素魔杖,这种魔杖会增幅与其相对应元素的法术的法术强度。" - ] - }, - - "miscellaneous": { - "title": "杂项", - "include_in_contents": "main_contents", - "contents": { - "id": "miscellaneous_subsections", - "hyperlinks": true, - "page_numbers": true, - "separator": "." - }, - "triggers": [ - "ebwizardry:on_subsection_unlock" - ], - "sections": { - "mana_flasks": { - "title": "魔力瓶", - "include_in_contents": "miscellaneous_subsections", - "triggers": [ - "ebwizardry:handbook/mana_flasks" - ], - "text": [ - - "Arkendur的魔法物品供应 - 我们有你所想要的魔法物品!", - - "想要在旅途中充能你的 @wands 魔杖@ ? 没问题! @mana 魔力@ 现在可以装瓶了。将八颗魔法水晶放入玻璃瓶中,魔法瓶的制作就这样简简单单。 当你想使用它时, 将它与你的魔杖合成一下,它将会为你的魔杖恢复一些魔力。", - - "#recipe medium_mana_flask", - - "新品!让我们为你介绍崭新的小型魔力瓶和大型魔力瓶 - 现在你可以根据你的需要来挑选适合大小的魔力瓶!", - - "#recipe small_mana_flask", - "#recipe large_mana_flask", - - "* 这个过程会破坏瓶子。装瓶过程中会不可避免的损失一些魔力。" - ] - }, - "throwable_items": { - "title": "投掷物", - "include_in_contents": "miscellaneous_subsections", - "triggers": [ - "ebwizardry:handbook/throwables" - ], - "text": [ - - "有许多 @spells 法术@ 召唤出物理实体的投掷物, 有些还可以直接制作。燃烧弹, 毒气弹, 电击弹, 烟雾弹都可以制造:", - - "#recipe firebomb", - "#recipe poison_bomb", - "#recipe smoke_bomb", - "#recipe spark_bomb" - ] - }, - "automated_casting": { - "title": "施法自动化", - "include_in_contents": "miscellaneous_subsections", - "triggers": [ - "ebwizardry:enchant_scroll" - ], - "text": [ - - "最近的实验表明,自动化释放 @spells 法术@ 是可能的, 只用一个简单的发射器就可以办到了。 没有人确切知道其中的原理, 但似乎红石的奇怪属性能够激活法术卷轴。在发射器里放一些法术卷轴,然后给它通上红石信号就可以了。" - ] - } - } - }, - - "crafting_recipes": { - "title": "合成配方", - "include_in_contents": "main_contents", - "text": [ - - "#recipe arcane_workbench", - "#recipe novice_wands", - "#recipe magic_missile_spell_book", - "#recipe wizard_handbook", - "#recipe crystal_flower_to_crystals", - "#recipe crystal_blocks", - "#recipe crystal_blocks_to_crystals", - "#recipe crystal_shard", - "#recipe small_mana_flask", - "#recipe medium_mana_flask", - "#recipe large_mana_flask", - "#recipe runestone", - "#recipe runestone_pedestal", - "#recipe transportation_stone", - "#recipe magic_silk", - "#recipe wizard_hat", - "#recipe wizard_robe", - "#recipe wizard_leggings", - "#recipe wizard_boots", - "#recipe blank_scroll", - "#recipe firebomb", - "#recipe poison_bomb", - "#recipe smoke_bomb", - "#recipe spark_bomb" - ] - }, - - "credits": { - "title": "鸣谢", - "include_in_contents": "main_contents", - "text": [ - - "Electroblob's Wizardry \n版本 #version \nFor Minecraft #mcversion", - - "设计, 代码和材质 by Electroblob", - - "感谢Minecraft Forge 以及 MCP, 没有它们, 这个mod就不可能得以实现。", - - "同时也感谢Minecraft modding community, 他们总会在我遇到mod难题时帮助我!", - - "此外, 我还要感谢以下人员对本mod的贡献:", - - "代码:", - - "- Corail31 \n- 12foo \n- Shadows-of-Fire \n- HellFirePvP \n- Tora-B \n- Avatair \n- Aeronica", - - "翻译:", - - "- 西班牙语 : MadWrist \n- 俄语: VilagVil, kellixon \n- 法语: Hahdrim \n- 葡萄牙语: lorrampi \n- 中文: ZHENGLOC, dragon-evol \n- 韩语: shejery, rewi_wire \n- 波兰语: Trozuu \n- 德语: BirdyDragon", - - "雷电效果音: OhhWowProductions", - - "想要获得更多信息, 请参看 @https://github.com/Electroblob77/Wizardry/wiki wiki@.", - - "觉得不过瘾? 加入 @https://discord.gg/MTmMzMv Discord server@ 获得第一手资讯,还可以一起探讨新内容!" - - ] - } - - } -} +{ + "bookmark_start_section": "introduction", + + "colours": { + "text": "#000000", + "caption": "#666666", + "hyperlink": "#601ba0", + "highlight": "#dd4c1d", + "new_section": "#ee88f7" + }, + + "images": { + "workbench": { + "location": "ebwizardry:textures/gui/arcane_workbench_picture.png", + "caption": "奥术工作台", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "crystal_ore": { + "location": "ebwizardry:textures/gui/ore_picture.png", + "caption": "水晶矿石", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "magic_crystal": { + "location": "ebwizardry:textures/items/crystal_magic.png", + "caption": "魔法水晶", + "u": 6, + "v": 6, + "width": 36, + "height": 33, + "texture_width": 48, + "texture_height": 48, + "border": false + }, + "magic_wand": { + "location": "ebwizardry:textures/items/wand_novice.png", + "caption": "魔杖", + "u": 0, + "v": 0, + "width": 64, + "height": 64, + "border": false + }, + "crystal_flower": { + "location": "ebwizardry:textures/gui/flower_picture.png", + "caption": "水晶花", + "u": 0, + "v": 0, + "width": 48, + "height": 48 + }, + "wizard_tower": { + "location": "ebwizardry:textures/gui/tower_picture.png", + "caption": "巫师塔", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "wizard_armour": { + "location": "ebwizardry:textures/gui/armour_picture.png", + "caption": "一整套巫师护具", + "u": 0, + "v": 0, + "width": 90, + "height": 90 + }, + "obelisk": { + "location": "ebwizardry:textures/gui/obelisk_picture.png", + "caption": "方尖碑", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "shrine": { + "location": "ebwizardry:textures/gui/shrine_picture.png", + "caption": "大地圣祠", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "tiers": { + "location": "ebwizardry:textures/gui/tiers_picture.png", + "caption": "宗师级魔杖", + "u": 0, + "v": 0, + "width": 96, + "height": 24, + "border": false + }, + "elements": { + "location": "ebwizardry:textures/gui/elements_picture.png", + "caption": "七种魔法元素", + "u": 0, + "v": 0, + "width": 106, + "height": 20, + "border": false + } + }, + + "recipes": { + "arcane_workbench": { + "locations": [ "ebwizardry:arcane_workbench" ] + }, + "magic_wand": { + "locations": [ "ebwizardry:magic_wand" ] + }, + "novice_wands": { + "locations": [ + "ebwizardry:magic_wand", + "ebwizardry:wand_fire", + "ebwizardry:wand_ice", + "ebwizardry:wand_lightning", + "ebwizardry:wand_necromancy", + "ebwizardry:wand_earth", + "ebwizardry:wand_sorcery", + "ebwizardry:wand_healing" + ] + }, + "magic_missile_spell_book": { + "locations": [ "ebwizardry:magic_missile_spell_book" ] + }, + "wizard_handbook": { + "locations": [ "ebwizardry:wizard_handbook" ] + }, + "crystal_flower_to_crystals": { + "locations": [ "ebwizardry:crystal_flower_to_crystals" ] + }, + "crystal_blocks": { + "locations": [ + "ebwizardry:crystal_block", + "ebwizardry:crystal_block_fire", + "ebwizardry:crystal_block_ice", + "ebwizardry:crystal_block_lightning", + "ebwizardry:crystal_block_necromancy", + "ebwizardry:crystal_block_earth", + "ebwizardry:crystal_block_sorcery", + "ebwizardry:crystal_block_healing" + ] + }, + "crystal_blocks_to_crystals": { + "locations": [ + "ebwizardry:crystal_block_to_crystals", + "ebwizardry:crystal_block_to_crystals_fire", + "ebwizardry:crystal_block_to_crystals_ice", + "ebwizardry:crystal_block_to_crystals_lightning", + "ebwizardry:crystal_block_to_crystals_necromancy", + "ebwizardry:crystal_block_to_crystals_earth", + "ebwizardry:crystal_block_to_crystals_sorcery", + "ebwizardry:crystal_block_to_crystals_healing" + ] + }, + "crystal_shard": { + "locations": [ "ebwizardry:crystal_shard" ] + }, + "small_mana_flask": { + "locations": [ "ebwizardry:small_mana_flask" ] + }, + "medium_mana_flask": { + "locations": [ "ebwizardry:medium_mana_flask" ] + }, + "large_mana_flask": { + "locations": [ "ebwizardry:large_mana_flask" ] + }, + "runestone": { + "locations": [ + "ebwizardry:runestone_fire", + "ebwizardry:runestone_ice", + "ebwizardry:runestone_lightning", + "ebwizardry:runestone_necromancy", + "ebwizardry:runestone_earth", + "ebwizardry:runestone_sorcery", + "ebwizardry:runestone_healing" + ] + }, + "runestone_pedestal": { + "locations": [ + "ebwizardry:runestone_pedestal_fire", + "ebwizardry:runestone_pedestal_ice", + "ebwizardry:runestone_pedestal_lightning", + "ebwizardry:runestone_pedestal_necromancy", + "ebwizardry:runestone_pedestal_earth", + "ebwizardry:runestone_pedestal_sorcery", + "ebwizardry:runestone_pedestal_healing" + ] + }, + "transportation_stone": { + "locations": [ "ebwizardry:transportation_stone" ] + }, + "magic_silk": { + "locations": [ "ebwizardry:magic_silk" ] + }, + "wizard_hat": { + "locations": [ "ebwizardry:wizard_hat" ] + }, + "wizard_robe": { + "locations": [ "ebwizardry:wizard_robe" ] + }, + "wizard_leggings": { + "locations": [ "ebwizardry:wizard_leggings" ] + }, + "wizard_boots": { + "locations": [ "ebwizardry:wizard_boots" ] + }, + "blank_scroll": { + "locations": [ "ebwizardry:blank_scroll" ] + }, + "firebomb": { + "locations": [ "ebwizardry:firebomb" ] + }, + "poison_bomb": { + "locations": [ "ebwizardry:poison_bomb" ] + }, + "smoke_bomb": { + "locations": [ "ebwizardry:smoke_bomb" ] + }, + "spark_bomb": { + "locations": [ "ebwizardry:spark_bomb" ] + } + }, + + "sections": { + + "inside_cover": { + "centre": { + "x": true, + "y": true + }, + "text": [ + + "巫师手札", + + "By Electroblob" + ] + }, + + "introduction": { + "title": "介绍", + "text": [ + + "向你致以敬意, 巫师! 这本书介绍了数种魔法类别以及操纵这些元素的方法。 我必须提醒你,这本书并不只是像现在这样,看起来十分普通 —— 当你在探索这个世界时,书中新的内容会不断地具现出来。", + + "点击单箭头按钮可以切换页数, 点击双箭头按钮可以在章节之间切换. 点击中心按钮可以返回目录。", + + "点击紫色的链接将会直接跳转到相关页面, 右键书签将会把书签移动到当前页面, 左键书签将会返回标记页面。" + ] + }, + + "main_contents": { + "title": "内容", + "contents": { + "id": "main_contents", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + } + }, + + "setting_up": { + "title": "在最开始", + "include_in_contents": "main_contents", + "text": [ + + "想要开始你的巫术之旅,你需要:", + + "- 一把魔杖, 合成如下所示:", + + "#recipe magic_wand", + + "- 一个 @arcane_workbench 奥术工作台@ , 合成如下所示:", + + "#recipe arcane_workbench", + + "- 一本 @spells 法术@ 书. 你可以在战利品箱发现法术书, 它也会以掉落物形式出现,你也可以与其他巫师交易。当然你也可以制作一本初始的法术书, 魔法飞弹, 如下所示:", + + "#recipe magic_missile_spell_book", + + "你还要准备大量的魔法水晶,为你的魔杖注入 @mana 魔力@ ." + ] + }, + + "mana": { + "title": "魔力", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:crystal" + ], + "text": [ + + "魔力作为一种魔法能量,是巫师力量的来源。 它自身并不是某种物质; 它是无处不在的场域,充塞于世界上的一切之中. 特殊的情况下,它会以水晶的形式在自然中出现, 而这种水晶通常会镶嵌于地底的石头中. @wands 魔杖@ 可以储存魔力, 这些魔力会被你引导到你所释放的 @spells 法术@ 中。不同的法术需要的魔力各不一样, 魔力损耗取决于法术威力以及时长。", + + "#image crystal_ore", + + "#image magic_crystal", + + "人们普遍认为魔力无法被创生或毁灭, 当释放法术时, 法术所引导的魔力会消散到周围环境。这确实是魔力最广泛地存在形式 - 散布于世界的各个角落。然而, 一旦需要利用这些魔力, 你必须, 就像历经几千年而形成的地底水晶一样,将其凝合起来。又或者通过人工的方式将其聚合为固体形态 - 但这一精深的课题已经超出了本书的范围了. 当然,也存在着一些方法,能够提高你的魔力使用效率,或者在施法过程中恢复一些魔力消耗。" + ] + }, + + "wands": { + "title": "魔杖", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "魔杖是巫师的工具。你能够释放任何你当前的魔杖等阶能够释放的@spells 法术@ ,(参见 @tiers 等阶@ ). 魔杖有许多种类型 ,但可以肯定的是,你需要从一把基础魔杖来开启你的巫师之旅。", + + "#image magic_wand", + + "大多数魔杖的制作,在最开始时相当简单,将一块魔法水晶固定在木棍的一端,而另一端镶嵌一粒金粒,一根简单的魔杖就制作好了。魔法水晶是魔杖力量的来源, 它提供了必要的,用来引导 @spells 法术@ 的核心. 魔杖的其它部分也很重要, 它不仅能让你方便的手持魔杖进行施法, 而且还充当了引导和定向 @mana 魔力@ 流动的通路。", + + "随着魔杖释放的法术越多, 它引导 @spells 法术@ 的效率会越来越高, 因此可以可以用它来施放更强大的魔法。这种能力的变化可以从魔杖本身的形状和外观上的细微变化中看出: 随着魔杖变得越来越强大, 它顶端的魔法水晶将会变得更有活力, 水晶的颜色也会变化,变化的颜色取决于它所引导的 @elements 元素@ , 制作它的木材将会生长和扭曲,形成更复杂的形状。", + + "手持魔杖的时候, 屏幕的角落会出现一个显示框。 上面会显示当前选中的法术及其图标,如果当前法术被施放,其上的冷却条将会指示该法术可以再次施放的时间间隔。 显示框还能显示与魔杖当前使用的法术相连的上一个和下一个法术的名称. 如要在法术间切换, 你可以使用 #next_spell_key 和 #previous_spell_key 键 (这些都可以在 选项 -> 控制 中修改). 也可以在潜行时通过滚动鼠标滚轮来切换法术。", + + "查看物品栏时, 将鼠标悬停在一根魔杖上,就会显示出还有多少 @mana 魔力@ 储存在其中, 以及当前所应用于魔杖的 @spells 法术@ 以及任何特殊的能力. 想要查询魔杖的更详细的信息,可将其放置在 @arcane_workbench 奥术工作台@ ." + ] + }, + + "spells": { + "title": "法术", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/spells" + ], + "text": [ + + "一把 @wands 魔杖@ ,如果没有法术,那你就无法使用它. 法术有两种记录的形式: 永久性的写在法术书中,或者写在一次性的法术卷轴上", + + "法术书本身没什么用;但它们可以将其所包含的法术绑定到 @wands 魔杖@ 上. 世界中的很多地方都藏有法术书,你很快就能找到一本. 当你找到法术书时,将鼠标悬停在在法术书上就能看到法术的基本信息。你也可以在拿着一本法术书右键来阅读更多关于它的内容。", + + "卷轴有不同的用途: 右键将会施放与之绑定的法术, 在此过程中卷轴会销毁。像法术书一样,卷轴可以在世界各地找到,但你也可以自己制作(参见 @enchanting_scrolls 附魔卷轴@ ).", + + "当你需要在一些特定的情形下中使用少量特殊的法术,但又不想占用你的 @wands 魔杖@ 法术位时,卷轴将会发挥巨大的作用。然而,我必须提醒你,与使用魔杖相比,使用卷轴是一种效率低下的施法方法。", + + "对不了解该法术的人而言, 那些用于书写法术书的魔法符文实在是令人头疼。为了鉴定一个法术,你可以尝试施放该法术,看看会发生什么 - 尽管这样做可能会产生副作用, 而且许多法术需要一定的条件才能生效。更重要的是,在施放一个你不了解的法术时,总会有误读该法术的可能, 而那些由误读而带来的潜在的危险的强度则取决于该法术的威力.一个更安全、更可靠的选择是使用鉴定卷轴,你可以在箱子里找到或者从巫师那里买到. 手持鉴定卷轴右键,将会识别第一个你所不知道的法术,该过程先将快捷栏的右边开始,然后向左依次检索, 鉴定完毕会消耗鉴定卷轴。" + ] + }, + + "arcane_workbench": { + "title": "奥术工作台", + "include_in_contents": "main_contents", + "contents": { + "id": "arcane_workbench_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "奥术工作台外观上与附魔台很相似,它可以用来为你的魔杖充能、升级 ,以及绑定 @spells 法术@ 到你的 @wands 魔杖@ 。制作方法如下所示:", + + "#recipe arcane_workbench", + + "以下内容展示了在奥术工作台中可以执行的操作。", + + "#image workbench" + ], + "sections": { + "binding_spells": { + "title": "绑定法术", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "想要绑定@spells 法术@到你的@wands 魔杖@, 只需将你的魔杖放在工作台中间的凹槽里,然后把法术书放在周围的一个槽里,然后点击“应用”按钮即可. 你会注意到法术书在这个过程中并没有发生变化 - 这是因为法术绑定行为不会从法术书中“取走”法术; 相反,它使魔杖与法术相协调。你可以通过简单地重复法术绑定过程来改变你魔杖上的法术,以及你也可以一次性在一根魔杖上绑定五种法术, 而一次性绑定法术上限的个数会随着魔杖协调升级而增加" + ] + }, + "charging_wands": { + "title": "魔杖充能", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "想要充能你的 @wands 魔杖@ , 你需要把魔杖放在奥术工作台的中央凹槽里,然后把一些魔法水晶放在左下角的凹槽里, 最后点击“应用”按钮即可。每个水晶含有#mana_per_crystal @mana 魔力@, 充能时魔杖不会过量吸收魔力, 所以你可以在工作台中常备一些水晶,以便不时之需。不过要记住,魔杖只能吸收一整个水晶中的魔力, 例如,增加30点魔力, #example_charging_loss 魔力将会损失。." + ] + }, + "upgrading_wands": { + "title": "升级魔杖", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], + "text": [ + + "为了升级你的 @wands 魔杖@ , 你需要一本适当 @tiers 等阶@ 的奥法宝典 或者一些特殊的魔杖升级. 两者都可以作为战利品或者从巫师那里购买. 想要升级你的魔杖, 你需要把它放在奥术工作台的中央凹槽,然后将升级物品放置在右上角凹槽,最后点击应用。", + + "特殊的魔杖升级可以改善魔杖某个方面的能力。每种类型的升级最多可以叠加三次,一根魔杖可以升级的总数取决于它的等级。魔杖的升级不能被移除。" + ] + }, + "enchanting_scrolls": { + "title": "附魔卷轴", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/scrolls" + ], + "text": [ + + "奥术工作台也可以用来附魔 @spells 法术@ 卷轴。首先,你需要一个空白卷轴, 空白卷轴由线和纸组成, 以及一本法术书, 还要足够的 @mana 魔力@ ,这样才能够成功使法术拓印在空白卷轴上。", + + "#recipe blank_scroll", + + "将魔法水晶放在左下的凹槽, 空白卷轴放置在中央凹槽, 将一本法术书放置在周围凹槽, 点击应用来附魔该卷轴。" + ] + } + } + }, + + "wizard_armour": { + "title": "巫师护具", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "作为一名巫师, 你需要一些东西在战斗时保护你不受过高的伤害,普通的盔甲可无法承此重任。为了能够在提供保护时还能让你最高效率地使用的魔力, 你需要一套巫师护具: 包括帽子、长袍、裤子和靴子。 与普通盔甲不同的是,它们耐久归零之后不会消失。而且,蕴藏在其中的奥术能量将会保护穿戴者。当然,这意味着它们必须使用水晶充能, 这一点和魔杖很相似。幸运的是, 这些护具不太消耗@mana 魔力@. 你可以像和魔杖那样,将其放置在 @arcane_workbench 奥术工作台@ ,或者使用 @mana_flasks 魔力瓶@ 为其充能, 但是要小心-如果护具们耗尽了魔力,它们将不再提供任何保护。", + + "#image wizard_armour", + + "你可以用魔法绸缎制造巫师护具:", + + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + + "你可以用附魔台为巫师护具附魔,而因为魔法绸缎的固有属性, 它们倾向于被附魔上能够使它们留存的更久的附魔. 对巫师具有特殊的实用价值为魔法,冰霜,雷电保护附魔, 这些附魔可以有效抵御其它巫师的进攻。", + + "那些沉迷于练习单系魔法的巫师,有时会穿上可以给予额外魔法增益的服装。全套这样的服装在巫师群体中很受欢迎,所以并不容易找到。", + + "在传说中,最强大的巫师使用一种神秘的封印来提高他们护甲的能力。" + ] + }, + + "magical_world": { + "title": "魔法世界", + "include_in_contents": "main_contents", + "contents": { + "id": "magical_world_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/on_subsection_unlock" + ], + "text": [ + + "一个人仅仅呆在家里是无法掌握奥术之力的 - 这个充塞着魔力的世界等待着你的探索! 古代遗迹,还有那些神秘的,抱着善意或者恶意的生物等待着你发现 - 如果你知道它们在哪。最伟大的巫师往往有着强烈的好奇心, 他们通过对周围环境的探索获得大量的知识和力量, 然后通过实验去验证他们所发现的。", + + "巫师的大部分时间都是一个人度过的, 然而对学习奥术而言,与他人分享彼此的知识很重要。你应该去寻找那些先行者,尽可能多地向他们学习:交流可以说是最强大的力量了。" + ], + "sections": { + "crystal_flowers": { + "title": "魔法水晶花", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/crystal_flowers" + ], + "text": [ + + "在你的旅行中,你可能在野外会不时地遇到一种奇怪的,发光的花. 这些独特的花朵被称为水晶花,它们能够高效的聚集 @mana 魔力@ - 直到今天,还没有人能确定它高效聚集魔力的原因。但是我们知道,它们可以被收集和制作成魔法水晶,使得它们成为相当有用的地上的魔力来源。然而,因为花的尺寸很小,而且它们无法密集生长,所以通过这种方式收获的魔力并不是很多,", + + "#image crystal_flower", + "#recipe crystal_flower_to_crystals" + ] + }, + "wizard_towers": { + "title": "巫师塔", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:wizard_tower" + ], + "text": [ + + "不要害怕 —— 你不是这个世界上唯一一个使用魔法的人。 在旅行途中,你很可能会遇到一两个有着独特尖顶的高塔。这是其它巫师的住所。孤独的生活有时会让巫师有点暴躁,但他们通常都很友好,而且愿意与你分享他们的知识 —— 尽管是有代价的。你可以用贵重金属和宝石来与他们交换珍贵的奥术知识。", + + "然而,如果你寻找的是 @tiers 宗师@ 法术, 你需要去找那些专业人士。", + + "#image wizard_tower", + + "不幸的是,有一些巫师不欢迎访客的到来。这些巫师早已被逐出巫师群体, 他们对任何路过此地的人都抱有敌意. 与这些人打交道要格外谨慎, 并做好防御强大魔法的准备。打败他们,他们的知识就是你的了。", + + "还应该指出的是,没有哪个巫师会乐意被攻击或被偷 - 他们更喜欢按他们的规矩来。" + ] + }, + "obelisks": { + "title": "方尖碑", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/obelisks" + ], + "text": [ + + "古代魔法遗迹散布在世界各地, 其中最著名的是雕刻着许多符号和符文的石头建筑. 这些遗迹似乎是某种古代文明的遗迹。不管是谁,或者是什么东西建造了它们,它们显然拥有相当丰富的魔法知识, 并使用这些知识在这些地方设置了保护魔法,这些魔法直到今天还在生效。", + + "这些结构大致可分为两类. 第一个,也是最常见的,是方尖碑: 符文石制成的尖顶, 底部有一个开放的结构,其中为次级魔法遗迹,你在上面还能感受到残存着的气息,那是来自被遗忘的过去。", + + "#image obelisk", + + "这些建筑通常受到魔法的保护,一旦有人离得太近,就会召唤敌对 @creatures 生物@ 。击退这些生物并摧毁它们的源头,那么这个遗迹的财富就是你的了。" + ] + }, + "shrines": { + "title": "圣祠", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:visit_shrine" + ], + "text": [ + + "第二种,也是比较少见的一种,被称为圣祠。这些结构由围绕着中心基座的一圈符文石柱组成, 基座上放置着一个箱子,里面装满了古代的 @artefacts 圣遗物@ . 这个箱子通常被一个奥术锁保护着, 除了箱子的主人,其它人都无法打开。整个结构也被一个控制场域保护着, 防止任何离得太近的东西逃跑。", + + "#image shrine", + + "只要你意识到圣祠所包含的强大魔力和其重要性, 箱子里所存放的东西的珍贵毋庸置疑, 这些结构对任何有抱负的巫师都特别有吸引力 - 但是要谨慎。有很多关于巫师被困在封闭空间里,慢慢被逼疯的报道,这也许是因为幽闭恐惧症。 然而,越来越多的人相信这种情况的发生也是圣祠的保护魔法的一部分, 被困在里面的巫师实际上是被控制来保护该结构的。 对于任何胆敢靠近的人来说,这无疑令人不寒而栗....." + ] + }, + "creatures": { + "title": "魔法生物", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/magical_creatures" + ], + "text": [ + + "除了巫师,许多其他生物也可以使用魔法。而在其中有很多从出生开始就拥有魔力,而且它们大部分都可以施放 @spells 法术@ . 其中一种你可能会在守卫 @obelisks 方尖碑@ 的生物中看到,他们可能是由更强大的召唤师召唤而来。偶尔你还能够在野外中被发现魔法能力不强的生物。" + ] + }, + "artefacts": { + "title": "圣遗物", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:artefact" + ], + "text": [ + + "当你在探索圣祠时,你可能会幸运地发现一些古老的魔法制品 —— 一些能赋予穿戴者独特而强大的魔法和特殊能力的物品。已发现三种类型: 戒指,给予法术增幅和额外效果,护身符,提高防御能力,还有符咒,能产生特殊效用。这些魔法制物似乎只有在正确佩戴时才能发挥作用; 仅仅是把它们放在身上无法发挥它们的效果。" + ] + } + } + }, + + "tiers": { + "title": "等阶", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], + "text":[ + + "@wands 魔杖@ 和 @spells 法术@ 分成四阶: #colour_novice新手#colour_reset, #colour_apprentice学徒#colour_reset, #colour_advanced进阶 #colour_reset 和 #colour_master宗师#colour_reset.每一阶都比上一阶更强大。", + + "#image tiers", + + "#colour_novice新手 #colour_reset魔杖 魔杖可以手工制作. 它们可以容纳 #novice_max_charge 魔力, 且只可以释放基础法术. 基础法术很简单,任何人都可以使用,而且通常情况下不会消耗很多魔力。然而,这并不一定意味着在你步入更高等阶后,它们就没有用处了; 即便你已经可以使用宗师级魔法,基础法术低廉的魔力消耗依然使得它们备受青睐。", + + "#colour_apprentice学徒 #colour_reset魔杖 是新手的下一等阶. 学徒级魔杖可容纳 #apprentice_max_charge 魔力 ,可以施放基础和学徒法术。学徒法术比新手法术更令人眼前一亮,但通常魔力消耗更多。", + + "#colour_advanced进阶 #colour_reset魔杖 魔杖是相当罕见的,而且更强大. 他们可以使用除宗师法术以外的所有法术,并能够容纳 #advanced_max_charge 魔力. 进阶法术能够带来超越人类极限的能力,譬如隐形,以及为你的敌人带来浩劫。", + + "#colour_master宗师 #colour_reset魔杖 魔杖是世界上最强大的魔杖. 他们能够容纳 #master_max_charge 魔力, 并且能够随意施展任何法术.宗师等阶的法术书是非常罕见的,这些法术不仅可以对敌人造成彻底的破坏,甚至可以对世界本身造成破坏。请务必谨慎使用。", + + "要升级到更高的等级,一根魔杖首先要有足够的力量来引导该等级的法术。魔杖在施法时会增进自身。法术种类、法术强度、元素效果和其他外部因素都会影响魔杖的成熟速度。", + + "一旦一根魔杖足够强大,一本奥法宝典就是魔杖提升到下一层所需的最后催化剂 (参见 @upgrading_wands 升级魔杖@ ), 升级过后,魔杖又可以继续成长到下一等阶。" + ] + }, + + "elements": { + "title": "元素", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/elements" + ], + "text": [ + + "@spells 法术@ 分属于不同的元素 , 元素决定了法术的本质并且决定了它会被何种 @wands 魔杖@ 增幅。", + + "#image elements", + + "#colour_fire火焰#colour_reset \n 它或许是最具破坏性的元素, 火与燃烧、熔岩和爆炸有关。 一位强大的舞焰师能够释放出地狱烈焰灼烧他的敌人,并可能在这个过程中点燃整个世界。大多数攻击型火焰法术都会点燃目标,造成持续的伤害。然而,要注意火系法术可能对下界生物没有效果。", + + "#colour_ice冰霜#colour_reset \nThe 冰元素囊括了所有与寒冷有关的事物,冰霜法术通常会让敌人减速或者完全冻结,同时对火焰生物能造成额外伤害。冰霜魔法在战斗之外也同样有用,比如冻住河流,让你方便的过河。", + + "#colour_lightning雷电#colour_reset \n 这种元素与闪电,风暴和天气有关。绝不可忽视的一位强大的驯雷师的力量,他们能够使雷电屈从于他们的意志。雷电法术通常能够一次性伤害多个敌人,并且能够自动寻找目标,这使得它们能有效地攻击任何生物…… 但是要小心爬行者。", + + "#colour_necromancy死灵#colour_reset \n 死灵元素与黑暗, 混乱与亡灵相关. 操纵死灵元素的巫师是神秘的,而且通常被认为是邪恶的,但实际上往往并不是这样。死灵法术通常能够召唤 @creatures 魔法生物@ 为你而战,亦可以扭曲你的敌人的意志。", + + "#colour_earth大地#colour_reset \nThe 大地元素与自然相关: 动物,植物,风,以及与这些相似的。大地魔法种类繁多,形式多样,既可以毒害敌人,亦可展现天气狂暴的一面。大地法术集合了攻击、防御和功能类法术。", + + "#colour_sorcery秘法#colour_reset \n 秘法元素与力场与变化有关. 秘术师可以操纵光、重力甚至是现实本身来满足他们的需要。此外,秘法系法术可以赋予施法者奇特的魔法能力,或者可以帮助施法者移动他所希望移动的目标。", + + "#colour_healing治愈#colour_reset \n 治愈元素侧重于防御和再生,治疗师尽可能多地保护他们自己和他们的盟友,因此在特殊情况下会非常难对付。虽然一般不用于攻击,但某些治疗法术的净化之光会对亡灵造成相当大的伤害。治疗法术在战斗中是必不可少的。", + + "不同元素之间的界限并不总是泾渭分明的,有些法术反而具有其它元素的特征。", + + "如果幸运的话,你可能会找到元素水晶。元素水晶是一种魔法水晶,它在生长过程中吸收了元素属性 - 尽管这种情况发生的条件和机制仍然是一个谜。 然而,我们确实知道,这些水晶可以用来制造单元素魔杖,这种魔杖会增幅与其相对应元素的法术的法术强度。" + ] + }, + + "miscellaneous": { + "title": "杂项", + "include_in_contents": "main_contents", + "contents": { + "id": "miscellaneous_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:on_subsection_unlock" + ], + "sections": { + "mana_flasks": { + "title": "魔力瓶", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/mana_flasks" + ], + "text": [ + + "Arkendur的魔法物品供应 - 我们有你所想要的魔法物品!", + + "想要在旅途中充能你的 @wands 魔杖@ ? 没问题! @mana 魔力@ 现在可以装瓶了。将八颗魔法水晶放入玻璃瓶中,魔法瓶的制作就这样简简单单。 当你想使用它时, 将它与你的魔杖合成一下,它将会为你的魔杖恢复一些魔力。", + + "#recipe medium_mana_flask", + + "新品!让我们为你介绍崭新的小型魔力瓶和大型魔力瓶 - 现在你可以根据你的需要来挑选适合大小的魔力瓶!", + + "#recipe small_mana_flask", + "#recipe large_mana_flask", + + "* 这个过程会破坏瓶子。装瓶过程中会不可避免的损失一些魔力。" + ] + }, + "throwable_items": { + "title": "投掷物", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/throwables" + ], + "text": [ + + "有许多 @spells 法术@ 召唤出物理实体的投掷物, 有些还可以直接制作。燃烧弹, 毒气弹, 电击弹, 烟雾弹都可以制造:", + + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" + ] + }, + "automated_casting": { + "title": "施法自动化", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:enchant_scroll" + ], + "text": [ + + "最近的实验表明,自动化释放 @spells 法术@ 是可能的, 只用一个简单的发射器就可以办到了。 没有人确切知道其中的原理, 但似乎红石的奇怪属性能够激活法术卷轴。在发射器里放一些法术卷轴,然后给它通上红石信号就可以了。" + ] + } + } + }, + + "crafting_recipes": { + "title": "合成配方", + "include_in_contents": "main_contents", + "text": [ + + "#recipe arcane_workbench", + "#recipe novice_wands", + "#recipe magic_missile_spell_book", + "#recipe wizard_handbook", + "#recipe crystal_flower_to_crystals", + "#recipe crystal_blocks", + "#recipe crystal_blocks_to_crystals", + "#recipe crystal_shard", + "#recipe small_mana_flask", + "#recipe medium_mana_flask", + "#recipe large_mana_flask", + "#recipe runestone", + "#recipe runestone_pedestal", + "#recipe transportation_stone", + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + "#recipe blank_scroll", + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" + ] + }, + + "credits": { + "title": "鸣谢", + "include_in_contents": "main_contents", + "text": [ + + "Electroblob's Wizardry \n版本 #version \nFor Minecraft #mcversion", + + "设计, 代码和材质 by Electroblob", + + "感谢Minecraft Forge 以及 MCP, 没有它们, 这个mod就不可能得以实现。", + + "同时也感谢Minecraft modding community, 他们总会在我遇到mod难题时帮助我!", + + "此外, 我还要感谢以下人员对本mod的贡献:", + + "代码:", + + "- Corail31 \n- 12foo \n- Shadows-of-Fire \n- HellFirePvP \n- Tora-B \n- Avatair \n- Aeronica", + + "翻译:", + + "- 西班牙语 : MadWrist \n- 俄语: VilagVil, kellixon \n- 法语: Hahdrim \n- 葡萄牙语: lorrampi \n- 中文: ZHENGLOC, dragon-evol \n- 韩语: shejery, rewi_wire \n- 波兰语: Trozuu \n- 德语: BirdyDragon", + + "雷电效果音: OhhWowProductions", + + "想要获得更多信息, 请参看 @https://github.com/Electroblob77/Wizardry/wiki wiki@.", + + "觉得不过瘾? 加入 @https://discord.gg/MTmMzMv Discord server@ 获得第一手资讯,还可以一起探讨新内容!" + + ] + } + + } +} diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_zh_tw.json b/src/main/resources/assets/ebwizardry/texts/handbook_zh_tw.json new file mode 100644 index 00000000..7158605b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/texts/handbook_zh_tw.json @@ -0,0 +1,750 @@ +{ + "bookmark_start_section": "introduction", + + "colours": { + "text": "#000000", + "caption": "#666666", + "hyperlink": "#601ba0", + "highlight": "#dd4c1d", + "new_section": "#ee88f7" + }, + + "images": { + "workbench": { + "location": "ebwizardry:textures/gui/arcane_workbench_picture.png", + "caption": "法術工作台", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "crystal_ore": { + "location": "ebwizardry:textures/gui/ore_picture.png", + "caption": "水晶礦", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "magic_crystal": { + "location": "ebwizardry:textures/items/crystal_magic.png", + "caption": "魔法水晶", + "u": 6, + "v": 6, + "width": 36, + "height": 33, + "texture_width": 48, + "texture_height": 48, + "border": false + }, + "magic_wand": { + "location": "ebwizardry:textures/items/wand_novice.png", + "caption": "法杖", + "u": 0, + "v": 0, + "width": 64, + "height": 64, + "border": false + }, + "crystal_flower": { + "location": "ebwizardry:textures/gui/flower_picture.png", + "caption": "水晶花", + "u": 0, + "v": 0, + "width": 48, + "height": 48 + }, + "wizard_tower": { + "location": "ebwizardry:textures/gui/tower_picture.png", + "caption": "法師塔", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "wizard_armour": { + "location": "ebwizardry:textures/gui/armour_picture.png", + "caption": "法師服", + "u": 0, + "v": 0, + "width": 90, + "height": 90 + }, + "obelisk": { + "location": "ebwizardry:textures/gui/obelisk_picture.png", + "caption": "方尖碑", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "shrine": { + "location": "ebwizardry:textures/gui/shrine_picture.png", + "caption": "神殿", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "tiers": { + "location": "ebwizardry:textures/gui/tiers_picture.png", + "caption": "四種等級的法杖", + "u": 0, + "v": 0, + "width": 96, + "height": 24, + "border": false + }, + "elements": { + "location": "ebwizardry:textures/gui/elements_picture.png", + "caption": "七種法術元素", + "u": 0, + "v": 0, + "width": 106, + "height": 20, + "border": false + } + }, + + "recipes": { + "arcane_workbench": { + "locations": [ "ebwizardry:arcane_workbench" ] + }, + "magic_wand": { + "locations": [ "ebwizardry:magic_wand" ] + }, + "novice_wands": { + "locations": [ + "ebwizardry:magic_wand", + "ebwizardry:wand_fire", + "ebwizardry:wand_ice", + "ebwizardry:wand_lightning", + "ebwizardry:wand_necromancy", + "ebwizardry:wand_earth", + "ebwizardry:wand_sorcery", + "ebwizardry:wand_healing" + ] + }, + "magic_missile_spell_book": { + "locations": [ "ebwizardry:magic_missile_spell_book" ] + }, + "wizard_handbook": { + "locations": [ "ebwizardry:wizard_handbook" ] + }, + "crystal_flower_to_crystals": { + "locations": [ "ebwizardry:crystal_flower_to_crystals" ] + }, + "crystal_blocks": { + "locations": [ + "ebwizardry:crystal_block", + "ebwizardry:crystal_block_fire", + "ebwizardry:crystal_block_ice", + "ebwizardry:crystal_block_lightning", + "ebwizardry:crystal_block_necromancy", + "ebwizardry:crystal_block_earth", + "ebwizardry:crystal_block_sorcery", + "ebwizardry:crystal_block_healing" + ] + }, + "crystal_blocks_to_crystals": { + "locations": [ + "ebwizardry:crystal_block_to_crystals", + "ebwizardry:crystal_block_to_crystals_fire", + "ebwizardry:crystal_block_to_crystals_ice", + "ebwizardry:crystal_block_to_crystals_lightning", + "ebwizardry:crystal_block_to_crystals_necromancy", + "ebwizardry:crystal_block_to_crystals_earth", + "ebwizardry:crystal_block_to_crystals_sorcery", + "ebwizardry:crystal_block_to_crystals_healing" + ] + }, + "crystal_shard": { + "locations": [ "ebwizardry:crystal_shard" ] + }, + "small_mana_flask": { + "locations": [ "ebwizardry:small_mana_flask" ] + }, + "medium_mana_flask": { + "locations": [ "ebwizardry:medium_mana_flask" ] + }, + "large_mana_flask": { + "locations": [ "ebwizardry:large_mana_flask" ] + }, + "runestone": { + "locations": [ + "ebwizardry:runestone_fire", + "ebwizardry:runestone_ice", + "ebwizardry:runestone_lightning", + "ebwizardry:runestone_necromancy", + "ebwizardry:runestone_earth", + "ebwizardry:runestone_sorcery", + "ebwizardry:runestone_healing" + ] + }, + "runestone_pedestal": { + "locations": [ + "ebwizardry:runestone_pedestal_fire", + "ebwizardry:runestone_pedestal_ice", + "ebwizardry:runestone_pedestal_lightning", + "ebwizardry:runestone_pedestal_necromancy", + "ebwizardry:runestone_pedestal_earth", + "ebwizardry:runestone_pedestal_sorcery", + "ebwizardry:runestone_pedestal_healing" + ] + }, + "transportation_stone": { + "locations": [ "ebwizardry:transportation_stone" ] + }, + "magic_silk": { + "locations": [ "ebwizardry:magic_silk" ] + }, + "wizard_hat": { + "locations": [ "ebwizardry:wizard_hat" ] + }, + "wizard_robe": { + "locations": [ "ebwizardry:wizard_robe" ] + }, + "wizard_leggings": { + "locations": [ "ebwizardry:wizard_leggings" ] + }, + "wizard_boots": { + "locations": [ "ebwizardry:wizard_boots" ] + }, + "blank_scroll": { + "locations": [ "ebwizardry:blank_scroll" ] + }, + "firebomb": { + "locations": [ "ebwizardry:firebomb" ] + }, + "poison_bomb": { + "locations": [ "ebwizardry:poison_bomb" ] + }, + "smoke_bomb": { + "locations": [ "ebwizardry:smoke_bomb" ] + }, + "spark_bomb": { + "locations": [ "ebwizardry:spark_bomb" ] + } + }, + + "sections": { + + "inside_cover": { + "centre": { + "x": true, + "y": true + }, + "text": [ + + "法師手冊", + + "作者: Electroblob\n\n翻譯: Grant" + ] + }, + + "introduction": { + "title": "前言", + "text": [ + + "你好啊,法師!\n\n本書介紹許多法術相關事物及使用方式。 這不是一本普通的書,其內容會隨著你在魔法世界的探索而逐漸呈現。", + + "使用箭頭按鈕來翻頁,按下雙箭頭按鈕則可快速的切換章節,而中間的選單按鈕則是翻回主目錄頁面。", + + "點擊任何紫色連結文字直接跳至相關頁面。對書籤點擊滑鼠右鍵可將書籤移到目前這頁,對書籤點擊滑鼠左鍵則可翻回書籤那頁。" + ] + }, + + "main_contents": { + "title": "目錄", + "contents": { + "id": "main_contents", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + } + }, + + "setting_up": { + "title": "準備", + "include_in_contents": "main_contents", + "text": [ + + "要開始使用法術,你需要準備:", + + "》法杖, 請依圖示合成:", + + "#recipe magic_wand", + + "\n\n》@arcane_workbench 法術工作台@, 合成方式如圖:", + + "#recipe arcane_workbench", + + "》@spells 法術書@\n這個可以在箱子裡找到,或從怪物身上掉落,或向法師購買。\n\n\n\n不然你也可以自己合成一個\n初學者法術【魔法彈】,\n如圖所示:", + + "#recipe magic_missile_spell_book", + + "你還需要準備一大堆魔法水晶\n來為法杖供應@mana 法力@。" + ] + }, + + "mana": { + "title": "法力", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:crystal" + ], + "text": [ + + "法力是賦予法師力量的魔法能量,其本身並非實體的物質,反而是可滲入於萬物之中的永恆能量。特別的是,法力蘊藏在於地下岩石中所找到的天然水晶內。\n@wands 法杖@可儲存法力,並在施法時\n將法力引導到@spells 法術@上。\n不同的法術會依其力量強度及持續時間消耗不同的法力值。", + + "#image crystal_ore", + + "#image magic_crystal", + + "人們普遍認為法力無法被創造或消滅,每當施展法術時,其引導的法力就會散失到周圍環境中。事實上這就是大量的法力散布於世界各處的原因。總之無論要如何使用法力,必須從地底下的天然千年水晶中,或本書未涵蓋的高級人工方式將其收集。還有各種方法使法術更有效的使用法力,以及回收在施法過程中逸散的部分法力。" + ] + }, + + "wands": { + "title": "法杖", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "法杖是法師首選的器具。\n你能用它來施展任何法杖能力\n所及的@spells 法術@(請參閱@tiers 等級@章節)\n。\n法杖的種類很多,不過當然都得從基礎法杖開始。", + + "#image magic_wand", + + "大多數的法杖都誕生於一個簡單的製作方式。\n準備一顆某種類型的魔法水晶,\n將水晶裝在木棒的一端,\n再於另一端黏上一顆金粒。\n水晶自然是法杖力量的源頭,\n因為它提供了引導@spells 法術@所需的\n焦點。而其餘的部分也很重要,不只是因為提供了握住法杖的地方,更是指引@mana 法力@前進的路徑\n。", + + "隨著法杖施展了愈多法術,\n其變得愈能駕馭@spells 法術@,\n因此也能施展更強大的法術。\n這樣的成長可以從法杖外觀上的細微變化中發現,隨著法杖愈來愈強,水晶會變得更加明亮,\n顏色也可能會根據其@elements 元素@而\n產生變化。過了一段時間之後,法杖本身的木材也會開始扭曲生長成各種複雜的形狀。", + + "當你拿著法杖時,畫面的角落會顯示出目前法杖所選的法術及其圖示,而在施放法術之後,還會顯示冷卻條來表示直到下次施展所需等待的時間,它還會顯示法杖中的前一個和下一個法術名稱。按下《#next_spell_key 鍵》及《#previous_spell_key 鍵》可切換法術(這些都可在【選項】->【按鍵設定】中變更),你也可以在潛行時使用滑鼠滾輪來切換法術。", + + "當你將游標停留在物品欄的法杖上時,會顯示法杖中儲存的\n@mana 法力@,伴隨目前所選的@spells 法術@及其\n特殊能力。\n將法杖放入@arcane_workbench 法術工作台@則可\n看見更詳細的資訊。" + ] + }, + + "spells": { + "title": "法術", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/spells" + ], + "text": [ + + "沒有法術的@wands 法杖@沒有作用。\n法術的記錄形式有兩種:\n一種是永久性的書本,\n一種是暫時性的卷軸。", + + "法術書本身無法使用,而是用於將書中記載的法術存入@wands 法杖@。\n在世界各地都能發現法術書,應該用不了多少時間你就能找到一本。當你找到後,可將游標停留在書上,看一下這本法術書的基本資訊,也可以拿著書點擊滑鼠右鍵以閱讀更詳細的資料。", + + "相對而言卷軸則有不同的用途: 拿著卷軸點擊滑鼠右鍵便會施展上面的法術並用掉卷軸。跟法術書一樣,卷軸在世界各地都能找到,但你也可以自己@enchanting_scrolls 製作@。", + + "在你準備進行某個任務時,有些法術可能只會用到一兩次,\n所以你不想讓那些法術占用\n你的@wands 法杖@空間,此時卷軸就非常\n有用。不過得注意,比起法杖,卷軸還是效率較差的施法方式。", + + "未經訓練的眼睛無法閱讀法術中的魔法符文。然而若要鑑定一個法術,你當然可以冒著發生意外的風險來施展看看結果,但即便如此許多法術是要在特定的條件下才會發生作用。不過即便如此,還是有可能在施法時誤用了未鑑定的法術,其潛在的危險性取決於這個法術有多強大。因此更安全可靠的選擇是使用鑑定卷軸,可以在箱子裡找到或是向法師購買。拿著鑑定卷軸點擊滑鼠右鍵便會用掉卷軸並鑑定你快捷欄中第一個未知的法術書或卷軸。" + ] + }, + + "arcane_workbench": { + "title": "法術工作台", + "include_in_contents": "main_contents", + "contents": { + "id": "arcane_workbench_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "法術工作台看起來有點像附魔台, 用來升級你的@wands 法杖@、\n為其補充法力和存入@spells 法術@。\n\n其合成方式如下:", + + "#recipe arcane_workbench", + + "接下來的頁面將說明法術工作台的各種功用。", + + "#image workbench" + ], + "sections": { + "binding_spells": { + "title": "抄寫法術", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "要將@spells 法術@存入你的@wands 法杖@,只要將\n法杖放入工作台中央的槽中,然後將法術書放入周圍其中一個槽並按下按鈕。此時你會注意到,在這個過程中,法術書並沒有受到任何影響,這是因為存入法術的動作,並不是將法術從法術書中取走,只是將法術抄寫至法杖中而已。因此你可以重複這個動作,盡量將想要的法術存入你的法杖。你一次最多只能存入五種法術到法杖中,不過可用協調升級來增加法術存量。" + ] + }, + "charging_wands": { + "title": "法杖補充法力", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "要幫@wands 法杖@補充法力,先將法杖\n放入法術工作台中央的槽,並在左下方那個槽放入魔法水晶,然後按下按鈕。\n每個水晶相當於#mana_per_crystal點的@mana 法力@,\n而法杖只會在需要時用掉水晶,因此你可以將水晶留在工作台內,以便需要時供應。但是請記得,法杖只能取用整數單位的水晶,舉例來說,如果法杖只需要30點法力,那補充法力時會有#example_charging_loss點法力浪費掉。" + ] + }, + "upgrading_wands": { + "title": "升級法杖", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], + "text": [ + + "你需要對應@tiers 等級@的法術寶典來\n升級你的@wands 法杖@或進行特殊的法\n杖升級。這兩種東西都可從怪物的掉落物或向法師購買獲得。要升級法杖,先將法杖放入法術工作台中央的槽,並在右上方的槽放入升級物後按下按鈕。", + + "特殊的法杖升級可加強法杖某方面的能力,每種升級最高只能疊加三次,而法杖的總升級數取決於法杖的等級。升級後就無法移除。" + ] + }, + "enchanting_scrolls": { + "title": "製作卷軸", + "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/scrolls" + ], + "text": [ + + "法術工作台也能用來將@spells 法術@\n存入卷軸。要製作卷軸,你需要先用一張紙及一些線來合成空白卷軸,然後選一本想要作成卷軸的法術書,最後準備足夠的魔法水晶以提供施展這個法術的@mana 法力@。", + + "#recipe blank_scroll", + + "先將水晶放入左下方的槽,再將空白卷軸放入中央的槽,然後將法術書放入上方單獨的槽,最後按下按鈕以製成法術卷軸。" + ] + } + } + }, + + "wizard_armour": { + "title": "法師服", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "身為一位法師,在與生物搏鬥時需要一些東西來保護自己。雖然也能使用一般的護甲,但是為了充分發揮你的法術,你還是需要一套法師服,包括帽子、長袍、褲子和鞋子。\n與一般護甲不同的是,法師服不會破損,其使用魔法能量來保護穿著的人。因此跟法杖一樣,需要魔法水晶來補充能量。不過幸好這些服裝不會消耗太多\n@mana 法力@。\n法師服補充能量的方式也跟法杖一樣,可以用@arcane_workbench 法術工作台@或\n@mana_flasks 法力瓶@來補充,但是必須當心,\n如果法師服的法力耗盡了,你會發現自己毫無防禦力。", + + "#image wizard_armour", + + "你可以用魔法絲綢來製成法師服:", + + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + + "使用一般的附魔台就能為法師服附魔,而且由於魔法絲綢本身的特性,附魔後的效果特別好。對一個法師而言,最有用的是魔法、冰凍及衝擊三種防護附魔,有助於對抗敵人的魔法攻擊。", + + "有些專注於特定元素的法師會穿著能加強該元素力量的特殊服裝,這種整套的服裝法師們都相當喜歡,但也不容易找到。", + + "傳說中最強的法師曾經用一種法術印記來大大強化他們的服裝。" + ] + }, + + "magical_world": { + "title": "魔法世界", + "include_in_contents": "main_contents", + "contents": { + "id": "magical_world_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/on_subsection_unlock" + ], + "text": [ + + "只是待在家裡是無法成為法術大師的,到外頭探索充滿魔法的世界吧!\n若你勇於挑戰,古代遺址、遺物以及不管好的或壞的神秘生物,都等著你發現。\n最偉大的法師同時也最具好奇心,他們會不斷的探索周遭環境,並嘗試所發現的東西,來獲得豐富的知識及強大的力量。", + + "雖然法師不免大多的時間都是孤身一人,但知識的分享也是學習魔法藝術重要的一環。找尋其他法師,盡可能從他們身上學習更多知識,溝通才是一切最大的力量。" + ], + "sections": { + "crystal_flowers": { + "title": "水晶花", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/crystal_flowers" + ], + "text": [ + + "在你的旅途當中,可能在野外會不時遇到奇怪的發光花朵,這些獨特的花稱為水晶花,它們具有聚集@mana 法力@的神奇能力,至今還不\n知道原因。不過我們卻知道這些水晶花,可經由採集製作以提取法力成為水晶,這使它們成為地面上相當有用的法力來源。然而由於這種花並不大,而且生長的土地都很小塊,因此這種方式所能獲得的法力其實很有限。", + + "#image crystal_flower", + "#recipe crystal_flower_to_crystals" + ] + }, + "wizard_towers": { + "title": "法師塔", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:wizard_tower" + ], + "text": [ + + "害怕嗎?你並不是這個世界上唯一會使用魔法的人。\n在你的旅途中,你可能會遇到具有獨特尖頂或雙尖頂的高塔,這些是法師同伴居住的地方。\n隱居的生活使法師們有時候會有點古怪,但是他們通常還是友善的,而且只要你願意付出代價,還是會樂意與你分享他們的知識。\n在支付了貴重金屬及寶石後,你會收到許多驚奇的法術作為回報。", + + "如果你想尋找的是@tiers 大師級@法術,\n那你得跟專門的人交談。", + + "#image wizard_tower", + + "不幸的是,有少數法師並不歡迎訪客。這些法師通常已被驅逐,所以對於任何闖入地盤的人都充滿敵意。\n接近這些傢伙要特別小心,並做好抵擋強大魔法的準備。只要擊敗他們,他們的知識就會成為你的了。", + + "有一點必須知道,沒有法師會接受對他們攻擊或盜取他們東西的人,他們肯定不會善罷甘休。" + ] + }, + "obelisks": { + "title": "方尖碑", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/obelisks" + ], + "text": [ + + "古老魔法的遺跡散落在世界各處,其中最著名的是刻有許多符號及符文的石頭結構。這些廢墟看起來像是某種古代文明的遺跡,無論建造它們的是誰或是什麼,顯然具有相當豐富的魔法知識,且用來在這些地方設置持續至今的防衛魔法。", + + "這些結構大致上分成兩種類型,第一種是較常見的方尖碑:\n以雕刻符文石堆成高高尖頂的結構,底部開著一塊空間,存放著過去所遺留的次等魔法物品。", + + "#image obelisk", + + "這些結構通常受到魔法保護,一旦有人靠近就會召喚出充滿敵意的@creatures 魔法生物@來攻擊人類。\n對抗這些生物並摧毀其魔法源頭,那些遺物就是你的了。" + ] + }, + "shrines": { + "title": "神殿", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:visit_shrine" + ], + "text": [ + + "第二種較為罕見的結構稱之為神殿,由一個中央基座及圍繞在四周的符文石柱所組成。基座上方擺著一個裝有古代@artefacts 神器@的\n寶箱,並通常施加了防護魔法鎖,以防他人竊取。整個結構還受到封鎖力場保護,使擅闖者無法逃離。", + + "#image shrine", + + "由於這些神殿的重要意義及巨大的神秘力量,更別說裡面的寶物,對於志氣高昂的法師特別有吸引力。\n\n但是務必謹慎,有許多關於法師被關在封鎖區內,可能因為幽閉恐懼症導致慢慢發瘋的報導。且愈來愈多人認為,這就是神殿防護魔法的一個部分,而被關在其中的法師,其實是被控制用來守護神殿。這對於膽敢前往冒險的人來說,無疑是令人不寒而慄的結局..." + ] + }, + "creatures": { + "title": "魔法生物", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/magical_creatures" + ], + "text": [ + + "除了法師,還有許多其它生物也會使用魔法。其中有許多是源自於魔法,且大部分都能用特定的@spells 法術@召喚。會看到這些生物,\n大多是在守護@obelisks 方尖碑@,但也可能\n遇到了強大的召喚法師。只有非常少數的神秘生物才會偶爾在野外發現。" + ] + }, + "artefacts": { + "title": "神器", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:artefact" + ], + "text": [ + + "在探索@shrines 神殿@時,你可能會好運的\n發現某種古代魔法神器,一種能夠賦予配戴者獨特而強大能力的物品。\n目前所知的類型有三種:\n為法術附加額外能力及效果的戒指,增強防禦力的項鍊,以及各種應用魔法的寶器。\n這些神器只是放入背包是沒有用的,要擺在身上的正確位置才會發生作用。" + ] + } + } + }, + + "tiers": { + "title": "等級", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], + "text":[ + + "@wands 法杖@和@spells 法術@都分成四個等級: #colour_novice基礎#colour_reset、#colour_apprentice學徒#colour_reset、#colour_advanced進階#colour_reset以及#colour_master大師#colour_reset。每個等級都比前一級還強。", + + "#image tiers", + + "只有#colour_novice基礎#colour_reset法杖能以合成的方式製作,其最多可儲存#novice_max_charge點法力,且只能施展基礎法術。基礎法術通常不會消耗太多法力,任何人都足以施展。但這並不表示它們相較於高等法術就毫無用處。即便你已經能施展大師級法術,某些基礎法術由於消耗法力低而仍然實用。", + + "#colour_apprentice學徒#colour_reset法杖是基礎法杖的下個等級,其最多可儲存#apprentice_max_charge點法力,並可施展基礎及學徒法術。學徒法術比基礎法術更強一些,但通常也消耗更多法力。", + + "#colour_advanced進階#colour_reset法杖非常稀有也更加強大,可施展大師級以外的所有法術,並可儲存#advanced_max_charge點法力。進階法術能夠重創敵人,並擁有超人般的能力,例如隱身術。", + + "#colour_master大師#colour_reset法杖是現存最強大的法杖,其最多可儲存#master_max_charge點法力,並可施展所有法術。大師級法術書相當罕見,且法術的威力能徹底毀滅的不僅是敵人,甚至包括整個世界。務必謹慎使用!", + + "要提升至更高等級,首先法杖必須變得夠強大到足以引導該等級的法術。法杖會隨著施展法術而獲得成長,法術類型、法術力量、元素效果以及其它外部因素都可能會影響法杖的成長速度。", + + "當法杖足夠強大,法術寶典為最終將法杖提升至下個等級的關鍵物品(請參閱@upgrading_wands 升級法杖@),\n一旦完成升級,法杖將再次朝下個等級開始成長。" + ] + }, + + "elements": { + "title": "元素", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/elements" + ], + "text": [ + + "@spells 法術@各屬於不同的元素,代表\n法術的本質,且搭配使用對應的@wands 法杖@還會加強效果。", + + "#image elements", + + "#colour_fire火#colour_reset \n火元素涉及燃燒、岩漿以及爆炸,大概是最具破壞性的元素。一個強大的烈焰法師可使敵人面臨煉獄般的火海,並可能在過程中毀掉這個世界。\n大部分的火系法術會讓目標著火,使他們持續受到傷害,但是對地獄的生物則沒什麼效果。", + + "#colour_ice冰#colour_reset \n冰元素來自於所有冰冷的物質。冰系法術通常會讓敵人減速,甚至使他們完全凍結,對於火系生物特別有效。\n冰凍魔法在戰鬥之外也很有用,例如使水面結冰以過河。", + + "\n#colour_lightning電#colour_reset \n這個元素涉及雷電、風暴以及天氣。決不可小看一個強大雷電法師的力量,有些甚至能隨意召喚閃電。\n雷電法術經常能一次傷害多個敵人,還會自動搜尋目標,對任何生物都能造成有效的攻擊...但是得當心苦力怕。", + + "#colour_necromancy死靈#colour_reset \n死靈是黑暗、渾沌以及不死生物的元素。神秘的死靈法師往往被視為邪惡,儘管通常不是這樣的。\n死靈法術常召喚@creatures 生物@來為他\n戰鬥,或進而扭曲敵人的意志。", + + "#colour_earth大地#colour_reset \n大地元素來自於動植物、風等自然界的的力量。大地魔法千變萬化,從毒害敵人到控制天氣,有各式各樣的形式。\n大地法術是綜合攻擊、防禦以及實用的法術。", + + "#colour_sorcery秘術#colour_reset \n秘術是力量與變化的元素。\n秘術法師能操縱光線、重力,甚至現實世界本身來符合他們的需求。\n且不提其它用途,秘術法術可用來提供施法者魔法力量,或是任意移動物體。", + + "#colour_healing治療#colour_reset \n治療元素包括防禦和再生。\n治療法師會盡可能的保護自己及他們的同伴,因此可能會是非常難以對付的對手。\n治療法術在戰鬥中是不可或缺的,即便其通常不會用來進行攻擊,但是一些治療法術的淨化光芒會對不死生物造成相當大的傷害。", + + "不同元素之間的分界並不總是那麼明確,有些法術除了所屬元素的性質外,也會具有其它元素的特性。", + + "幸運的話,或許你能發現一種元素水晶,這是種在生長過程中吸收了元素的魔法水晶,不過實際上發生的方式及所需的條件仍然是個謎。但我們知道這種水晶能用來製作元素法杖,用來施展對應的法術,可比平常發揮更大的效果。" + ] + }, + + "miscellaneous": { + "title": "其它", + "include_in_contents": "main_contents", + "contents": { + "id": "miscellaneous_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:on_subsection_unlock" + ], + "sections": { + "mana_flasks": { + "title": "法力瓶", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/mana_flasks" + ], + "text": [ + + "亞肯多魔法用品公司 - 為您所需的魔法物品!", + + "需要在旅行中為你的@wands 法杖@補充\n法力嗎?\n沒問題! 現在@mana 法力@可以裝瓶。\n只要用一個玻璃瓶及八個魔法水晶合成出法力瓶,就可以隨身攜帶。要用的時候,只要將你的法杖與法力瓶合成,就能將法力存入法杖。(註)", + + "#recipe medium_mana_flask", + + "好消息! 即日起推出全新的小瓶裝及大瓶裝法力,可依您的需求選擇!", + + "#recipe small_mana_flask", + "#recipe large_mana_flask", + + "(註)過程中瓶子會用掉,且裝瓶時也會耗損一些法力。" + ] + }, + "throwable_items": { + "title": "投擲物", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/throwables" + ], + "text": [ + + "各種@spells 法術@的實體物,像是\n火焰彈、毒液彈、煙霧彈,還有電擊彈都能直接合成:", + + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" + ] + }, + "automated_casting": { + "title": "自動施法", + "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:enchant_scroll" + ], + "text": [ + + "近期的實驗顯示,在某種程度上只需要簡單的發射器就能自動施展@spells 法術@。沒有人知道原因,\n但看起來似乎是紅石的神奇特性竟然能觸發法術卷軸。只要將一些卷軸放入發射器,然後提供能量,就完成了這個機關..." + ] + } + } + }, + + "crafting_recipes": { + "title": "合成表", + "include_in_contents": "main_contents", + "text": [ + + "#recipe arcane_workbench", + "#recipe novice_wands", + "#recipe magic_missile_spell_book", + "#recipe wizard_handbook", + "#recipe crystal_flower_to_crystals", + "#recipe crystal_blocks", + "#recipe crystal_blocks_to_crystals", + "#recipe crystal_shard", + "#recipe small_mana_flask", + "#recipe medium_mana_flask", + "#recipe large_mana_flask", + "#recipe runestone", + "#recipe runestone_pedestal", + "#recipe transportation_stone", + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + "#recipe blank_scroll", + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" + ] + }, + + "credits": { + "title": "製作群", + "include_in_contents": "main_contents", + "text": [ + + "法術模組\n版本 #version\n支援 Minecraft #mcversion", + + "設計、程式及材質: Electroblob", + + "感謝 Minecraft Forge 及 MCP,\n沒有它們就沒有這個模組。", + + "也感謝Minecraft的模組討論區,\n總能回答我的模組問題!", + + "\n另外,我要感謝以下各位對本模組的貢獻:", + + "程式碼:", + + "》Corail31 \n》12foo \n》Shadows-of-Fire \n》HellFirePvP \n》Tora-B \n》Avatair \n》Aeronica", + + "\n\n翻譯:", + + "》繁體中文: Grant\n》(墨西哥)西班牙文: MadWrist \n》俄文: VilagVil, kellixon\n》法文: Hahdrim\n》巴西葡萄牙文: lorrampi\n》簡體中文: ZHENGLOC, dragon-evol\n》韓文: shejery, rewi_wire\n》波蘭文: Trozuu", + + "雷電音效: OhhWowProductions", + + "更多資訊請前往 @https://github.com/Electroblob77/Wizardry/wiki wiki@", + + "覺得法術模組還有不足之處? 請加入 @https://discord.gg/MTmMzMv Discord 伺服器@以獲得\n最新消息、討論及額外事務!" + ] + } + + } +} diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_festive.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_festive.png new file mode 100644 index 00000000..00fa0cdc Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_festive.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_festive_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_festive_legs.png new file mode 100644 index 00000000..9d881faf Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_festive_legs.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/gui/ore_picture.png b/src/main/resources/assets/ebwizardry/textures/gui/ore_picture.png index 6cddbc7e..2a8011ad 100644 Binary files a/src/main/resources/assets/ebwizardry/textures/gui/ore_picture.png and b/src/main/resources/assets/ebwizardry/textures/gui/ore_picture.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json index a97d369c..c61e8b52 100644 --- a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json @@ -74,5 +74,9 @@ "planks": { "texture": "ebwizardry:gui/spell_hud/planks", "metadata": "ebwizardry:gui/spell_hud/planks" + }, + "festive": { + "texture": "ebwizardry:gui/spell_hud/festive", + "metadata": "ebwizardry:gui/spell_hud/festive" } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/festive.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/festive.json new file mode 100644 index 00000000..8decb029 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/festive.json @@ -0,0 +1,33 @@ +{ + "name": "Festive", + "description": "'Tis the season!", + "width": 126, + "height": 41, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 40, + "y": 20 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 39, + "y": 1, + "length": 86, + "height": 8, + "mirror": { + "x": true, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/festive.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/festive.png new file mode 100644 index 00000000..bf786195 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/festive.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png index 074a9575..2dd8e5cb 100644 Binary files a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png and b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/scroll_festive.png b/src/main/resources/assets/ebwizardry/textures/items/scroll_festive.png new file mode 100644 index 00000000..d90a556f Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/scroll_festive.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spell_book_festive.png b/src/main/resources/assets/ebwizardry/textures/items/spell_book_festive.png new file mode 100644 index 00000000..2efce968 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/spell_book_festive.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_festive.png b/src/main/resources/assets/ebwizardry/textures/items/wand_festive.png new file mode 100644 index 00000000..6377c56c Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/items/wand_festive.png differ diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 45f9aa36..741e2e8e 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -2,10 +2,10 @@ { "modid" : "ebwizardry", "name" : "Electroblob's Wizardry", - "version" : "4.2.3", + "version" : "4.2.10", "mcversion" : "1.12.2", "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, UltraHex, Azim-Palmer, raoulvdberge.\nTranslators: MadWrist (Spanish, Mexican Spanish), VilagVil, kellixon & bigenergy (Russian), Hahdrim (French), lorrampi (Brazilian Portuguese), ZHENGLOC & dragon-evol (Chinese), shejery & rewi_wire (Korean), Trozuu (Polish), chesterccj305 (Taiwanese).", "authorList" : [ "Electroblob" ],