Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 807fc61541 | |||
| 9741c751b3 | |||
| d3003ae473 | |||
| 9fde24f341 | |||
| 452eb17b5f | |||
| 36963aac30 | |||
| f161cdfe7c | |||
| 455c5a5e07 | |||
| 9852f61d0f | |||
| a2c8cde4c4 | |||
| 497d28eafd | |||
| f3f3377c4d | |||
| 4c81c61644 | |||
| 31a6ab6db0 | |||
| 69f2aedef7 | |||
| e8818a4db5 | |||
| 470a7e82bc | |||
| 6439c233f1 | |||
| c931d42d62 | |||
| 5b497e107a | |||
| 324094f418 | |||
| 9ade6442b2 | |||
| ffea49bc40 | |||
| 2b89a890d0 | |||
| 3a67388ff3 | |||
| 3468bbb073 | |||
| 963178c609 | |||
| cfdb049368 | |||
| 058d83fd00 | |||
| c7ccc37dca | |||
| 74345d0c3b | |||
| 907b94c74f | |||
| 2c6b397be6 | |||
| eddcb2402d | |||
| 0301f3c300 | |||
| 7a8cfb73cd | |||
| c7c6f964bf | |||
| 91df7cfd72 | |||
| 0ed9ee64c4 | |||
| f82d2871d5 | |||
| 01cea3df06 | |||
| 591cfb5857 | |||
| bc2037f74e | |||
| 6aa3b21190 | |||
| b262b6edc0 | |||
| b7be05669b | |||
| 071e299d48 | |||
| 1e885d70c3 | |||
| e04a43e56d | |||
| 378796cdda | |||
| 48c37d1c17 | |||
| fe8f9fc5cd | |||
| ced6ab7e8d | |||
| 378e02eb6c | |||
| 4677d9ff30 | |||
| 0541b2171b | |||
| dc59a14e82 | |||
| 1a13afb6e3 | |||
| 03dd76c18a | |||
| 9426a96df3 | |||
| 382faf59c9 | |||
| cab68e23ac | |||
| 60a6c5124e | |||
| 028b753be6 | |||
| d020668e0c | |||
| 656a78962e | |||
| 5a2f5aa295 | |||
| 5e37a2322c | |||
| 3ca9f200fd | |||
| 37e3a842f5 | |||
| 4e8e2c951b | |||
| 43b66df22a | |||
| b192a431d7 | |||
| 3be98ab612 | |||
| ed950322ff | |||
| 4cde8c60bc | |||
| 9924e10f13 | |||
| eeb0640525 | |||
| 693c11ada0 | |||
| 038fd7225f | |||
| 999e32f37c | |||
| 8c2ac5adbb | |||
| 9c1e2e08c3 | |||
| e7f7960540 | |||
| a46bad4497 | |||
| 06d02ad45d | |||
| c39a213e62 | |||
| 2caca39a22 | |||
| 8d46191ff8 | |||
| fb7af9328d | |||
| 0991baf964 | |||
| bdefecbe9b | |||
| eef48f319a | |||
| 3a788c867c | |||
| 1ba723ade1 | |||
| c06105cd00 | |||
| 97c72685bb | |||
| 23fccaac9c | |||
| 74b6bdba0f | |||
| d69e3a253d | |||
| 744c7a2331 | |||
| c355cb034c | |||
| 5e321cc4cf | |||
| fbecce0543 | |||
| a6c24e9cb6 | |||
| 14a624db3f | |||
| 16a4c8231f | |||
| 931c99617c | |||
| 037f340a03 | |||
| b6cc417641 | |||
| 6565a0734a | |||
| 0aac70c5fb | |||
| 8551dc407b | |||
| 1eec7921ce | |||
| 18920a24c5 | |||
| e0c6f0f00f | |||
| a4f6391fac | |||
| a570bd57d0 | |||
| f1ff179b98 | |||
| 6d09acc78e | |||
| 960d97de49 | |||
| ebe64b06e3 | |||
| 99887f95e2 | |||
| 2e5a9fce3e |
@@ -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.1.4 [change as necessary]
|
||||
Wizardry version: 4.2.7 [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.]
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about the mod or the code
|
||||
title: "[Give a brief, relevant title here]"
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
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.7 [change as necessary]
|
||||
|
||||
Question details: [explain your question here]
|
||||
|
||||
Other mods involved: [if this question involves other mods, list them here]
|
||||
@@ -23,6 +23,7 @@ run
|
||||
logs
|
||||
/misc
|
||||
/libs
|
||||
libs_src
|
||||
libsfordeobf
|
||||
generated
|
||||
Thumbs.db
|
||||
@@ -8,6 +8,8 @@ When submitting an issue, I would be grateful if you could follow these few guid
|
||||
|
||||
- Please stick to the issue template, it's there to help you provide the right information so I can fix the problem more easily. If you're not sure what to put for anything, that's ok, just leave it as it is.
|
||||
|
||||
- One issue per issue please! Make a separate issue for each bug/suggestion. If you think multiple different issues may be related, reference between them using # followed by the issue number.
|
||||
|
||||
- Please give me as much information about the issue as you can, but keep it relevant. "This is really annoying me and my friend" does not help me fix the problem!
|
||||
|
||||
- Make sure your wizardry and Forge versions are both up-to-date for the game version you are using.
|
||||
+13
-4
@@ -1,7 +1,7 @@
|
||||
# Credits
|
||||
|
||||
Electroblob's Wizardry
|
||||
Version 4.1.4
|
||||
Version 4.2.7
|
||||
For Minecraft 1.12.2
|
||||
|
||||
Designed, coded and textured by Electroblob
|
||||
@@ -18,11 +18,20 @@ In addition, I'd like to thank the following individuals for their contributions
|
||||
- 12foo
|
||||
- Shadows-of-Fire
|
||||
- HellFirePvP
|
||||
- Tora-B
|
||||
- Avatair
|
||||
- Aeronica
|
||||
- UltraHex
|
||||
- Azim-Palmer
|
||||
|
||||
#### Translations
|
||||
|
||||
- Russian: VilagVil
|
||||
- Spanish and Mexican Spanish: MadWrist
|
||||
- Chinese: ZHENGLOC and dragon-evol
|
||||
- Spanish and Mexican Spanish: MadWrist
|
||||
- Russian: VilagVil, kellixon
|
||||
- French: Hahdrim
|
||||
- Brazilian Portuguese: lorrampi
|
||||
- Chinese: ZHENGLOC, dragon-evol
|
||||
- Korean: shejery, rewi_wire
|
||||
- Polish: Trozuu
|
||||
|
||||
Lightning ray sound effect from OhhWowProductions
|
||||
|
||||
+1
-1
@@ -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.7 [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.]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/relations/dependents) [](https://discord.gg/MTmMzMv)
|
||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://discord.gg/MTmMzMv)
|
||||
|
||||

|
||||

|
||||
|
||||
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
|
||||
|
||||
Please read the [guide for contributing](guide_for_contributing.md) before submitting an issue or a PR.
|
||||
Please read the [guide for contributing](CONTRIBUTING.md) before submitting an issue or a PR.
|
||||
|
||||
<b>Links</b>
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
|
||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||
|
||||
|
||||
version = "4.2.1" // There, it matches semver, happy now?
|
||||
version = "4.2.7" // There, it matches semver, happy now?
|
||||
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
archivesBaseName = "ElectroblobsWizardry"
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -238,6 +239,9 @@ 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){}
|
||||
|
||||
/**
|
||||
* Gets the client side world using Minecraft.getMinecraft().world. <b>Only to be called client side!</b> Returns
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -89,7 +90,7 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate wizard towers. */
|
||||
public int[] towerDimensions = {0};
|
||||
/** <b>[Server-only]</b> The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */
|
||||
public int towerRarity = 600;
|
||||
public int towerRarity = 900;
|
||||
/** <b>[Server-only]</b> 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 +104,7 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate obelisks. */
|
||||
public int[] obeliskDimensions = {0, -1};
|
||||
/** <b>[Server-only]</b> The rarity of obelisks, used by the world generator. Larger numbers are rarer. */
|
||||
public int obeliskRarity = 550;
|
||||
public int obeliskRarity = 800;
|
||||
/** <b>[Server-only]</b> List of structure file locations for obelisks. */
|
||||
public ResourceLocation[] obeliskFiles = {new ResourceLocation(Wizardry.MODID, "obelisk_0"),
|
||||
new ResourceLocation(Wizardry.MODID, "obelisk_1"),
|
||||
@@ -113,7 +114,7 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate shrines. */
|
||||
public int[] shrineDimensions = {0, -1};
|
||||
/** <b>[Server-only]</b> The rarity of shrines, used by the world generator. Larger numbers are rarer. */
|
||||
public int shrineRarity = 1000;
|
||||
public int shrineRarity = 1500;
|
||||
/** <b>[Server-only]</b> List of structure file locations for shrines. */
|
||||
public ResourceLocation[] shrineFiles = {new ResourceLocation(Wizardry.MODID, "shrine_0"),
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_1"),
|
||||
@@ -168,6 +169,8 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> Whether to replace Minecraft's distance-based fall damage calculation with an equivalent,
|
||||
* velocity-based one. */
|
||||
public boolean replaceVanillaFallDamage = true;
|
||||
/** <b>[Server-only]</b> Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */
|
||||
public boolean bonemealGrowsCrystalFlowers = true;
|
||||
/**
|
||||
* <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
|
||||
* to the defaults.
|
||||
@@ -364,7 +367,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");
|
||||
@@ -541,6 +544,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);
|
||||
@@ -700,13 +710,13 @@ 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();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerRarity", 600, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000);
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerRarity", 900, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_rarity");
|
||||
property.setRequiresWorldRestart(true);
|
||||
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||
@@ -725,26 +735,26 @@ 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();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 550, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000);
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 800, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_rarity");
|
||||
property.setRequiresWorldRestart(true);
|
||||
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||
@@ -752,19 +762,19 @@ 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();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1000, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000);
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1500, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_rarity");
|
||||
property.setRequiresWorldRestart(true);
|
||||
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||
@@ -772,7 +782,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);
|
||||
|
||||
@@ -12,10 +12,10 @@ import electroblob.wizardry.misc.Forfeit;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.*;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.CustomSoundCategory;
|
||||
import electroblob.wizardry.util.SpellProperties;
|
||||
import electroblob.wizardry.worldgen.*;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* <i>"Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as
|
||||
* possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
|
||||
@@ -41,7 +44,10 @@ import org.apache.logging.log4j.Logger;
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob.wizardry.WizardryGuiFactory")
|
||||
|
||||
@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,)")
|
||||
|
||||
public class Wizardry {
|
||||
|
||||
/** Wizardry's mod ID. */
|
||||
@@ -51,14 +57,14 @@ public class Wizardry {
|
||||
/**
|
||||
* The version number for this version of wizardry. The following system is used for version numbers:
|
||||
* <p></p>
|
||||
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]
|
||||
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]</b>
|
||||
* <p></p>
|
||||
* </center></b> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
|
||||
* </center> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
|
||||
* features as Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning.
|
||||
* 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.1";
|
||||
public static final String VERSION = "4.2.7";
|
||||
|
||||
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
||||
// IDEA: Abstract the vanilla particles behind the particle builder
|
||||
@@ -79,6 +85,12 @@ public class Wizardry {
|
||||
* - <b>INFO</b>: 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;
|
||||
@@ -94,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();
|
||||
@@ -110,6 +127,9 @@ public class Wizardry {
|
||||
proxy.registerRenderers();
|
||||
proxy.registerKeyBindings();
|
||||
|
||||
// Commented out for 4.2.3 to get rid of the sound bug, reinstate once a fix is found.
|
||||
WizardrySounds.SPELLS = SoundCategory.PLAYERS;//CustomSoundCategory.add(Wizardry.MODID + "_spells");
|
||||
|
||||
WizardryBaublesIntegration.init();
|
||||
WizardryAntiqueAtlasIntegration.init();
|
||||
|
||||
@@ -148,8 +168,6 @@ public class Wizardry {
|
||||
proxy.initGuiBits();
|
||||
proxy.registerParticles();
|
||||
proxy.registerSoundEventListener();
|
||||
|
||||
WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + ":spells");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -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
|
||||
@@ -366,6 +370,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<ItemStack> 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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
@@ -34,26 +33,16 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
|
||||
|
||||
// Replaces getRenderBlockPass
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockRenderLayer getRenderLayer(){
|
||||
return BlockRenderLayer.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumBlockRenderType getRenderType(IBlockState state){
|
||||
return EnumBlockRenderType.MODEL;
|
||||
}
|
||||
|
||||
// Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not
|
||||
// Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'.
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
// See BlockTransportationStone for what all these do
|
||||
@Override public boolean isFullCube(IBlockState state){ return false; }
|
||||
@Override public boolean isBlockNormalCube(IBlockState state){ return false; }
|
||||
@Override public boolean isNormalCube(IBlockState state){ return false; }
|
||||
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
|
||||
@@ -67,12 +56,12 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// Overriden to make the block always look full brightness despite not emitting
|
||||
// full light.
|
||||
@Override
|
||||
public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
return 15;
|
||||
}
|
||||
// // Overriden to make the block always look full brightness despite not emitting
|
||||
// // full light.
|
||||
// @Override
|
||||
// public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
// return 15;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(IBlockState state){
|
||||
|
||||
@@ -62,18 +62,12 @@ public class BlockTransportationStone extends Block {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... and this one is for rendering.
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){
|
||||
return side == EnumFacing.DOWN;
|
||||
@@ -147,7 +141,8 @@ public class BlockTransportationStone extends Block {
|
||||
if(locations.isEmpty()) locations.add(here);
|
||||
else{
|
||||
locations.remove(here); // Prevents duplicates
|
||||
locations.set(locations.size() - 1, 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);
|
||||
}
|
||||
|
||||
@@ -190,6 +190,11 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playBlinkEffect(EntityPlayer player){
|
||||
if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.playBlinkEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSpellHUDSkins(){
|
||||
return GuiSpellDisplay.getSkinKeys();
|
||||
@@ -425,14 +430,15 @@ public class ClientProxy extends CommonProxy {
|
||||
// Again, no need to check if the spell succeeded, because the packet is only ever sent when it
|
||||
// succeeds.
|
||||
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, (EntityLiving)caster, message.modifiers));
|
||||
}
|
||||
|
||||
if(caster instanceof ISpellCaster){
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
((ISpellCaster)caster).setContinuousSpell(spell);
|
||||
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
|
||||
if(caster instanceof ISpellCaster){
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
((ISpellCaster)caster).setContinuousSpell(spell);
|
||||
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else if(caster != null){
|
||||
Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving");
|
||||
}
|
||||
@@ -474,6 +480,9 @@ public class ClientProxy extends CommonProxy {
|
||||
|
||||
World world = Minecraft.getMinecraft().world;
|
||||
Entity caster = world.getEntityByID(message.casterID);
|
||||
|
||||
if(caster == null) return; // Shouldn't happen
|
||||
|
||||
// Moved from when the packet is sent to when it is received; fixes the sound not playing in first person.
|
||||
caster.playSound(WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, 1, 1);
|
||||
|
||||
|
||||
@@ -23,11 +23,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 +32,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.
|
||||
@@ -71,12 +67,6 @@ public final class WizardryClientEventHandler {
|
||||
private static int blinkEffectTimer;
|
||||
/** 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);
|
||||
}
|
||||
|
||||
/** Starts the first person blink overlay effect. */
|
||||
public static void playBlinkEffect(){
|
||||
@@ -151,7 +141,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<TileEntity> tileEntities = new ArrayList<>(world.loadedTileEntityList);
|
||||
|
||||
for(TileEntity tileentity : tileEntities){
|
||||
if(tileentity instanceof TileEntityDispenser){
|
||||
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
|
||||
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
|
||||
|
||||
@@ -3,11 +3,13 @@ package electroblob.wizardry.client.gui;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.IManaStoringItem;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.item.IWorkbenchItem;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.PacketControlInput;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
@@ -29,6 +31,8 @@ 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;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
@@ -47,21 +51,25 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
private IInventory arcaneWorkbenchInventory;
|
||||
|
||||
private static final int TOOLTIP_WIDTH = 164;
|
||||
private static final int TOOLTIP_TEXT_INSET = 6;
|
||||
|
||||
/** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it.
|
||||
* For calculations, we use the size without the tooltip, which is stored in this constant. */
|
||||
private static final int MAIN_GUI_WIDTH = 176;
|
||||
|
||||
|
||||
private static final int RUNE_LEFT = 38;
|
||||
private static final int RUNE_TOP = 22;
|
||||
private static final int RUNE_WIDTH = 100;
|
||||
private static final int RUNE_HEIGHT = 100;
|
||||
|
||||
|
||||
private static final int PROGRESSION_BAR_WIDTH = 152;
|
||||
private static final int PROGRESSION_BAR_HEIGHT = 3;
|
||||
|
||||
private static final int HALO_DIAMETER = 156;
|
||||
|
||||
|
||||
private static final int TEXTURE_WIDTH = 512;
|
||||
private static final int TEXTURE_HEIGHT = 256;
|
||||
|
||||
|
||||
private int animationTimer = 0;
|
||||
private static final int ANIMATION_DURATION = 20;
|
||||
|
||||
@@ -113,28 +121,28 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
|
||||
|
||||
// Animation
|
||||
|
||||
|
||||
// Grey background
|
||||
DrawingUtils.drawTexturedRect(guiLeft + RUNE_LEFT, guiTop + RUNE_TOP, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, 0,
|
||||
RUNE_WIDTH, RUNE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
|
||||
// Yellow 'halo'
|
||||
if(animationTimer > 0){
|
||||
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
||||
int x = guiLeft + RUNE_LEFT + RUNE_WIDTH/2;
|
||||
int y = guiTop + RUNE_TOP + RUNE_HEIGHT/2;
|
||||
|
||||
|
||||
float scale = (animationTimer + partialTicks)/ANIMATION_DURATION;
|
||||
scale = (float)(1 - Math.pow(1-scale, 1.4f)); // Makes it slower at the start and speed up
|
||||
GlStateManager.scale(scale, scale, 1);
|
||||
GlStateManager.translate(x/scale, y/scale, 0);
|
||||
|
||||
|
||||
DrawingUtils.drawTexturedRect(-HALO_DIAMETER /2, -HALO_DIAMETER /2, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, RUNE_HEIGHT,
|
||||
HALO_DIAMETER, HALO_DIAMETER, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
@@ -232,6 +240,26 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
y += 14;
|
||||
}
|
||||
|
||||
// Progression bar
|
||||
if(stack.getItem() instanceof ItemWand && !Wizardry.settings.legacyWandLevelling){
|
||||
|
||||
y += 10;
|
||||
|
||||
Tier tier = ((ItemWand)stack.getItem()).tier;
|
||||
|
||||
float progressFraction = 1;
|
||||
|
||||
if(tier != Tier.MASTER){
|
||||
progressFraction = (float)WandHelper.getProgression(stack) / Tier.values()[tier.level + 1].progression;
|
||||
}
|
||||
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, MAIN_GUI_WIDTH, ySize + PROGRESSION_BAR_HEIGHT, PROGRESSION_BAR_WIDTH, PROGRESSION_BAR_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
int width = (int)(PROGRESSION_BAR_WIDTH * progressFraction);
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, MAIN_GUI_WIDTH, ySize, width, PROGRESSION_BAR_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
y += 8;
|
||||
}
|
||||
|
||||
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){
|
||||
|
||||
Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack);
|
||||
@@ -251,7 +279,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
.bindTexture(discovered ? spell.getElement().getIcon() : Element.MAGIC.getIcon());
|
||||
|
||||
// Renders the little element icon
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, y, 8, 8);
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET - 1, y, 8, 8);
|
||||
|
||||
y += 10;
|
||||
}
|
||||
@@ -270,8 +298,8 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
if(level > 0){
|
||||
ItemStack stack1 = new ItemStack(item, level);
|
||||
GlStateManager.enableDepth();
|
||||
this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y);
|
||||
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y,
|
||||
this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y);
|
||||
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y,
|
||||
null);
|
||||
x += 18;
|
||||
GlStateManager.disableDepth();
|
||||
@@ -311,7 +339,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
int y = 6;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + 6, y, 0);
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
|
||||
if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){
|
||||
y += 14;
|
||||
@@ -319,7 +347,27 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
"\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana")
|
||||
+ " " + ((IManaStoringItem)stack.getItem()).getMana(stack) + "/"
|
||||
+ ((IManaStoringItem)stack.getItem()).getManaCapacity(stack),
|
||||
MAIN_GUI_WIDTH + 6, y, 0);
|
||||
MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
}
|
||||
|
||||
// Progression tier text
|
||||
if(stack.getItem() instanceof ItemWand && !Wizardry.settings.legacyWandLevelling){
|
||||
|
||||
y += 14;
|
||||
|
||||
Tier tier = ((ItemWand)stack.getItem()).tier;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow(tier.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
|
||||
if(tier != Tier.MASTER){
|
||||
Tier nextTier = Tier.values()[tier.level + 1];
|
||||
String s = TextFormatting.DARK_GRAY.toString() + nextTier.getDisplayName();
|
||||
if(WandHelper.getProgression(stack) >= nextTier.progression) s = nextTier.getDisplayNameWithFormatting();
|
||||
this.fontRenderer.drawStringWithShadow(s, MAIN_GUI_WIDTH + TOOLTIP_WIDTH
|
||||
- TOOLTIP_TEXT_INSET - fontRenderer.getStringWidth(s), y, 0);
|
||||
}
|
||||
|
||||
y += 4;
|
||||
}
|
||||
|
||||
y += 14;
|
||||
@@ -337,10 +385,10 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
}
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + 16, y, 0);
|
||||
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + 10, y, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawStringWithShadow(
|
||||
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + 16, y, 0);
|
||||
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + 10, y, 0);
|
||||
}
|
||||
y += 10;
|
||||
}
|
||||
@@ -351,7 +399,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
y += 6;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + I18n.format("container."
|
||||
+ Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + 6, y, 0);
|
||||
+ Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
|
||||
int x = 0;
|
||||
y += 10;
|
||||
@@ -364,7 +412,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
if(level > 0){
|
||||
// The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is
|
||||
// relative to the GUI but the POINT isn't.
|
||||
if(isPointInRegion(MAIN_GUI_WIDTH + 6 + x, y, 16, 16, mouseX, mouseY)){
|
||||
if(isPointInRegion(MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y, 16, 16, mouseX, mouseY)){
|
||||
ItemStack stack1 = new ItemStack(item, level);
|
||||
this.renderToolTip(stack1, mouseX - guiLeft, mouseY - guiTop);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -14,27 +14,22 @@ import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
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<Tier, ResourceLocation> 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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +54,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);
|
||||
@@ -77,7 +72,7 @@ public class GuiSpellBook extends GuiScreen {
|
||||
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
||||
|
||||
if(spell.getTier() == Tier.NOVICE){
|
||||
// Basic is usually white but this doesn't show up.
|
||||
// Novice is usually white but this doesn't show up.
|
||||
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
|
||||
}else{
|
||||
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
||||
|
||||
@@ -184,7 +184,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge);
|
||||
addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge);
|
||||
addFormatTag("version", Wizardry.VERSION);
|
||||
addFormatTag("mcversion", Minecraft.getMinecraft().getVersion());
|
||||
addFormatTag("mcversion", "1.12.2");
|
||||
|
||||
addFormatTag("colour_novice", "\u00A77");
|
||||
addFormatTag("colour_apprentice", Tier.APPRENTICE.getFormattingCode());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -282,6 +283,9 @@ public final class WizardryModels {
|
||||
if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")){
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "overlay"));
|
||||
}else if(location.getPath().contains("spectral_block")){
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "spectral_block"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,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<ItemStack> items = NonNullList.create();
|
||||
item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK.
|
||||
for(ItemStack stack : items){
|
||||
ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(),
|
||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
}
|
||||
}
|
||||
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,8 +40,6 @@ public class ParticlePath extends ParticleWizardry {
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ParticleTornado extends ParticleDigging {
|
||||
public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos,
|
||||
double velX, double velZ, IBlockState block){
|
||||
super(world, 0, 0, 0, 0, 0, 0, block);
|
||||
float angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
this.angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = originX - MathHelper.cos(angle) * radius;
|
||||
double z = originZ + radius * MathHelper.sin(angle);
|
||||
this.radius = radius;
|
||||
|
||||
@@ -112,7 +112,7 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
|
||||
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<EntityLivingBase> {
|
||||
}
|
||||
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<EntityLivingBase> {
|
||||
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);
|
||||
|
||||
@@ -20,6 +20,9 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class RenderArcaneLock {
|
||||
|
||||
@@ -39,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);
|
||||
@@ -54,9 +58,16 @@ public class RenderArcaneLock {
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
for(TileEntity tileentity : world.loadedTileEntityList){
|
||||
// Someone managed to get a CME here so let's just copy the list to be safe
|
||||
// It's only cosmetic so if a tileentity somehow gets removed while we're rendering them it's not a big deal
|
||||
List<TileEntity> tileentities = new ArrayList<>(world.loadedTileEntityList);
|
||||
|
||||
if(tileentity.getDistanceSq(origin.x, origin.y, origin.z) <= 64*64 && tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){
|
||||
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)){
|
||||
|
||||
Vec3d[] vertices = WizardryUtilities.getVertices(world.getBlockState(tileentity.getPos()).getBoundingBox(world, tileentity.getPos()).grow(0.05).offset(tileentity.getPos()));
|
||||
|
||||
@@ -74,7 +85,9 @@ public class RenderArcaneLock {
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.enableLighting();
|
||||
if (lighting) {
|
||||
GlStateManager.enableLighting();
|
||||
}
|
||||
GlStateManager.disableRescaleNormal();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
@@ -53,9 +53,8 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
(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);
|
||||
|
||||
@@ -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, 6000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||
ADVANCED(1500, 7, 2, 9000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||
MASTER(2500, 9, 1, 15000, 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;
|
||||
|
||||
@@ -166,7 +166,10 @@ public class DispenserCastingData extends BlockCastingData<TileEntityDispenser>
|
||||
// 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<TileEntity> 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();
|
||||
|
||||
@@ -6,6 +6,7 @@ import electroblob.wizardry.enchantment.Imbuement;
|
||||
import electroblob.wizardry.entity.living.ISummonedCreature;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.PacketCastContinuousSpell;
|
||||
import electroblob.wizardry.packet.PacketPlayerSync;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
@@ -71,7 +72,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
private static final Set<IStoredVariable> storedVariables = new HashSet<>();
|
||||
|
||||
/** The maximum number of recent spells to track. */
|
||||
public static final int MAX_RECENT_SPELLS = 10;
|
||||
public static final int MAX_RECENT_SPELLS = ItemWand.BASE_SPELL_SLOTS;
|
||||
|
||||
/** The player this WizardData instance belongs to. */
|
||||
private final EntityPlayer player;
|
||||
@@ -140,7 +141,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
// All players can recognise magic missile. This is not done using discoverSpell because that seems to cause
|
||||
// a crash on load occasionally (probably something to do with achievements being initialised)
|
||||
this.spellsDiscovered.add(Spells.magic_missile);
|
||||
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 10 spells cast
|
||||
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 5 spells cast
|
||||
this.castCommandSpell = Spells.none;
|
||||
this.castCommandModifiers = new SpellModifiers();
|
||||
this.castCommandTick = 0;
|
||||
@@ -272,7 +273,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
* @param spell The spell to count casts for.
|
||||
*/
|
||||
public int countRecentCasts(Spell spell){
|
||||
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 10
|
||||
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 5
|
||||
}
|
||||
|
||||
// Imbuements
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.entity.construct;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
@@ -33,7 +34,8 @@ public class EntityCombustionRune extends EntityMagicConstruct {
|
||||
|
||||
float strength = Spells.combustion_rune.getProperty(Spell.BLAST_RADIUS).floatValue();
|
||||
|
||||
world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true, true);
|
||||
world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true,
|
||||
getCaster() != null && WizardryUtilities.canDamageBlocks(getCaster(), world));
|
||||
|
||||
// The trap is destroyed once triggered.
|
||||
this.setDead();
|
||||
|
||||
@@ -29,9 +29,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(){
|
||||
|
||||
@@ -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<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
|
||||
@@ -283,16 +289,6 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
public int getMaxSpawnedInChunk(){
|
||||
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(){
|
||||
@@ -393,4 +389,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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.getTargetSelector()));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,16 @@ 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class EntityLightningWraith extends EntityBlazeMinion {
|
||||
|
||||
public EntityLightningWraith(World world){
|
||||
@@ -74,14 +83,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,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<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.getTargetSelector()));
|
||||
|
||||
this.setAIMoveSpeed((float)AISpeed);
|
||||
|
||||
@@ -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<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.getTargetSelector()));
|
||||
|
||||
this.setAIMoveSpeed((float)AISpeed);
|
||||
|
||||
@@ -218,7 +218,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 +257,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;
|
||||
}
|
||||
|
||||
@@ -414,7 +416,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
this.spells = (List<Spell>)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{
|
||||
@@ -780,6 +782,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
Tier maxTier = Tier.NOVICE;
|
||||
|
||||
List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells);
|
||||
npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book));
|
||||
|
||||
for(int i = 0; i < n; i++){
|
||||
|
||||
|
||||
@@ -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<Entity> 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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,12 +66,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));
|
||||
}
|
||||
|
||||
@@ -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)){
|
||||
|
||||
@@ -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)
|
||||
@@ -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 -> {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<String, AttributeModifier> 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))
|
||||
|
||||
@@ -81,7 +81,9 @@ public class ItemLightningHammer extends Item implements IConjuredItem {
|
||||
Multimap<String, AttributeModifier> multimap = super.getItemAttributeModifiers(slot);
|
||||
|
||||
if(slot == EntityEquipmentSlot.MAINHAND){
|
||||
multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue(), WizardryUtilities.Operations.ADD));
|
||||
float attackDamage = Spells.lightning_hammer.arePropertiesInitialised() ?
|
||||
Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue() : 10; // Fallback for search tree init, value doesn't really matter
|
||||
multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", attackDamage, WizardryUtilities.Operations.ADD));
|
||||
multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", ATTACK_SPEED, WizardryUtilities.Operations.ADD));
|
||||
multimap.put(SharedMonsterAttributes.MOVEMENT_SPEED.getName(), new AttributeModifier(MOVEMENT_SPEED_MODIFIER, "Weapon modifier", MOVEMENT_SPEED_REDUCTION, WizardryUtilities.Operations.MULTIPLY_FLAT));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
@@ -13,15 +14,15 @@ 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;
|
||||
|
||||
public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
|
||||
@@ -33,6 +34,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
|
||||
@@ -47,13 +49,14 @@ public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
|
||||
@Override
|
||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> 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<Spell> spells = Spell.getSpells(Spell.allSpells);
|
||||
spells.removeIf(s -> !s.applicableForItem(this));
|
||||
|
||||
for(Spell spell : spells){
|
||||
list.add(new ItemStack(this, 1, spell.metadata()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +83,25 @@ public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
return Wizardry.proxy.getScrollDisplayName(stack);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void addInformation(ItemStack itemstack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag advanced){
|
||||
|
||||
if(world != null){
|
||||
|
||||
Spell spell = Spell.byMetadata(itemstack.getItemDamage());
|
||||
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(spell, itemstack);
|
||||
|
||||
// Advanced tooltips display more information, mainly for searching purposes in creative
|
||||
if(discovered && advanced.isAdvanced()){ // No cheating!
|
||||
tooltip.add(spell.getTier().getDisplayName());
|
||||
tooltip.add(spell.getElement().getDisplayName());
|
||||
tooltip.add(spell.getType().getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxItemUseDuration(ItemStack stack){
|
||||
|
||||
@@ -71,9 +71,10 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem {
|
||||
|
||||
if(!oldStack.isEmpty() || !newStack.isEmpty()){
|
||||
// We only care about the situation where we specifically want the animation NOT to play.
|
||||
if(oldStack.getItem() == newStack.getItem() && !slotChanged
|
||||
if(oldStack.getItem() == newStack.getItem() && !slotChanged)
|
||||
// This code should only run on the client side, so using Minecraft is ok.
|
||||
&& !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive())
|
||||
// Why the heck was this here?
|
||||
//&& !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Tier, ResourceLocation> guiTextures = ImmutableMap.of(
|
||||
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
||||
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
||||
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
||||
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
||||
|
||||
public ItemSpellBook(){
|
||||
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<ItemStack> 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<Spell> spells = Spell.getSpells(Spell.allSpells);
|
||||
spells.removeIf(s -> !s.applicableForItem(this));
|
||||
|
||||
for(Spell spell : spells){
|
||||
list.add(new ItemStack(this, 1, spell.metadata()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,10 +72,13 @@ public class ItemSpellBook extends Item {
|
||||
: "#\u00A79" + SpellGlyphData.getGlyphName(spell, world));
|
||||
|
||||
tooltip.add(spell.getTier().getDisplayNameWithFormatting());
|
||||
|
||||
// Advanced tooltips display more information, mainly for searching purposes in creative
|
||||
if(discovered && advanced.isAdvanced()){ // No cheating!
|
||||
tooltip.add(spell.getElement().getDisplayName());
|
||||
tooltip.add(spell.getType().getDisplayName());
|
||||
}
|
||||
}
|
||||
/* Removed to streamline the tooltip a bit. Information is now within the book. if(spell.isContinuous){
|
||||
* tooltip.add("\u00A79Mana Cost: " + spell.cost + " per second"); }else{ tooltip.add("\u00A79Mana Cost: " +
|
||||
* spell.cost); } */
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,10 +27,7 @@ import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.EnumAction;
|
||||
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.SoundCategory;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -73,6 +70,8 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
private static final int CONTINUOUS_TRACKING_INTERVAL = 20;
|
||||
/** The increase in progression for casting spells of the matching element. */
|
||||
private static final float ELEMENTAL_PROGRESSION_MODIFIER = 1.2f;
|
||||
/** The increase in progression for casting an undiscovered spell (can only happen once per spell for each player). */
|
||||
private static final float DISCOVERY_PROGRESSION_MODIFIER = 5f;
|
||||
/** The fraction of progression lost when all recently-cast spells are the same as the one being cast. */
|
||||
private static final float MAX_PROGRESSION_REDUCTION = 0.75f;
|
||||
|
||||
@@ -398,7 +397,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);
|
||||
@@ -434,7 +433,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);
|
||||
|
||||
@@ -495,7 +494,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.
|
||||
@@ -573,6 +572,11 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
progressionModifier *= ELEMENTAL_PROGRESSION_MODIFIER;
|
||||
}
|
||||
|
||||
if(WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){
|
||||
// Casting an undiscovered spell now grants 5x progression
|
||||
progressionModifier *= DISCOVERY_PROGRESSION_MODIFIER;
|
||||
}
|
||||
|
||||
modifiers.set(SpellModifiers.PROGRESSION, progressionModifier, false);
|
||||
|
||||
return modifiers;
|
||||
@@ -635,6 +639,8 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
// WandHelper.setProgression(centre.getStack(), WandHelper.getProgression(centre.getStack()) - tier.progression);
|
||||
// }
|
||||
|
||||
WandHelper.setProgression(centre.getStack(), 0);
|
||||
|
||||
ItemStack newWand = new ItemStack(WizardryItems.getWand(tier, this.element));
|
||||
newWand.setTagCompound(centre.getStack().getTagCompound());
|
||||
// This needs to be done after copying the tag compound so the mana capacity for the new wand
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -108,10 +108,14 @@ public class RandomSpell extends LootFunction {
|
||||
// element = null;
|
||||
}
|
||||
|
||||
SpellProperties.Context spellContext = context.getLootedEntity() == null ? SpellProperties.Context.TREASURE
|
||||
: SpellProperties.Context.LOOTING;
|
||||
|
||||
// Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting
|
||||
// the spell randomiser use any element) change the overall outcome at all?
|
||||
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.TREASURE));
|
||||
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, spellContext));
|
||||
|
||||
spellsList.removeIf(s -> !s.applicableForItem(stack.getItem()));
|
||||
if(stack.getItem() instanceof ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
|
||||
if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK));
|
||||
|
||||
|
||||
@@ -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<Spell> 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.");
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
@@ -375,7 +375,7 @@ public abstract class Forfeit {
|
||||
if(!w.isRemote){
|
||||
for(EnumFacing direction : EnumFacing.HORIZONTALS){
|
||||
BlockPos pos = p.getPosition().offset(direction);
|
||||
w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
|
||||
if(WizardryUtilities.canBlockBeReplaced(w, pos)) w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -410,6 +410,7 @@ public abstract class Forfeit {
|
||||
if(!w.isRemote){
|
||||
List<BlockPos> sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 4);
|
||||
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube());
|
||||
sphere.removeIf(pos -> WizardryUtilities.isBlockUnbreakable(w, pos));
|
||||
sphere.forEach(pos -> {
|
||||
EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5,
|
||||
pos.getZ() + 0.5, w.getBlockState(pos));
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package electroblob.wizardry.misc;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.IManaStoringItem;
|
||||
import electroblob.wizardry.item.ItemManaFlask;
|
||||
import net.minecraft.inventory.InventoryCrafting;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||
|
||||
/**
|
||||
* Implements a dynamic crafting recipe for recharging items with mana flasks.
|
||||
*
|
||||
* @author Corail31, Electroblob
|
||||
* @since Wizardry 4.2.2
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
||||
|
||||
private final IManaStoringItem chargeable;
|
||||
private final ItemManaFlask flask;
|
||||
|
||||
/**
|
||||
* Creates a new charging recipe for the given chargeable item using the given flask item.
|
||||
* @param chargeable The type of item to be charged
|
||||
* @param flask The mana flask used to charge the item
|
||||
*/
|
||||
public RecipeRechargeWithFlask(Item chargeable, ItemManaFlask flask){
|
||||
super(null, new ItemStack(chargeable, 1, OreDictionary.WILDCARD_VALUE),
|
||||
new ItemStack(chargeable, 1, OreDictionary.WILDCARD_VALUE), flask);
|
||||
if(!(chargeable instanceof IManaStoringItem)) throw new IllegalArgumentException("Item to be charged must be an instance of IManaStoringItem");
|
||||
this.chargeable = (IManaStoringItem)chargeable;
|
||||
this.flask = flask;
|
||||
}
|
||||
|
||||
// Commented out for now because JEI spams the log with errors about the recipe having no output
|
||||
// @Nonnull
|
||||
// @Override
|
||||
// public ItemStack getRecipeOutput(){
|
||||
// return ItemStack.EMPTY; // According to the javadoc, dynamic recipes are supposed to return an empty stack here
|
||||
// }
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingResult(InventoryCrafting inv){
|
||||
ItemStack result = super.getCraftingResult(inv);
|
||||
rechargeItemAndCopyNBT(result, inv);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(InventoryCrafting inv, World world){
|
||||
ItemStack stack = findItemToCharge(inv);
|
||||
if(!stack.isEmpty() && chargeable.isManaFull(stack)) return false;
|
||||
return super.matches(inv, world);
|
||||
}
|
||||
|
||||
private void rechargeItemAndCopyNBT(ItemStack toCharge, InventoryCrafting inv){
|
||||
if(toCharge.getItem() == chargeable){
|
||||
ItemStack stack = findItemToCharge(inv);
|
||||
if(!stack.isEmpty()) chargeable.setMana(toCharge, chargeable.getMana(stack));
|
||||
chargeable.rechargeMana(toCharge, flask.size.capacity);
|
||||
toCharge.setTagCompound(stack.getTagCompound()); // Copy NBT to new stack
|
||||
}else{
|
||||
Wizardry.logger.warn("Tried to recharge item {} with mana flask, but it did not match the recipe result {}!", toCharge.getItem(), chargeable);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack findItemToCharge(InventoryCrafting inv){
|
||||
for(int i=0; i<inv.getSizeInventory(); i++){
|
||||
ItemStack ingredient = inv.getStackInSlot(i);
|
||||
if(ingredient.getItem() == chargeable) return ingredient;
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamic(){
|
||||
return true; // Stops it appearing in the recipe book
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onItemCraftedEvent(PlayerEvent.ItemCraftedEvent event){
|
||||
// getCraftingResult seems to only work for the result that's displayed, not once it is actually taken
|
||||
// This means that although I no longer have to replace the result every tick, I still need to do it here
|
||||
// ... I thought the whole point of the new recipe system was so that I DIDN'T have to do this?!
|
||||
if(event.craftMatrix instanceof InventoryCrafting){
|
||||
for(IRecipe recipe : CraftingManager.REGISTRY){
|
||||
if(recipe instanceof RecipeRechargeWithFlask
|
||||
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
|
||||
// Have to modify the itemstack in the actual event, it cannot be replaced
|
||||
((RecipeRechargeWithFlask)recipe).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,12 @@ public final class Spells {
|
||||
IForgeRegistry<Spell> 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<EntityMagicMissile>("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());
|
||||
|
||||
@@ -86,7 +86,7 @@ public final class WizardryBlocks {
|
||||
registerBlock(registry, "crystal_flower", new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY));
|
||||
registerBlock(registry, "snare", new BlockSnare(Material.PLANTS).setHardness(0.0F));
|
||||
registerBlock(registry, "transportation_stone", new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY));
|
||||
registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F));
|
||||
registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightOpacity(1).setBlockUnbreakable().setResistance(6000000.0F));
|
||||
registerBlock(registry, "crystal_block", new BlockCrystal(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY));
|
||||
registerBlock(registry, "meteor", new Block(Material.ROCK).setLightLevel(1));
|
||||
registerBlock(registry, "vanishing_cobweb", new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F));
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -18,6 +19,7 @@ import javax.annotation.Nonnull;
|
||||
* @author Electroblob
|
||||
* @since Wizardry 2.1
|
||||
*/
|
||||
@ObjectHolder(Wizardry.MODID)
|
||||
@Mod.EventBusSubscriber
|
||||
public final class WizardryEnchantments {
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ package electroblob.wizardry.registry;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.IManaStoringItem;
|
||||
import electroblob.wizardry.item.ItemManaFlask;
|
||||
import net.minecraft.inventory.ContainerPlayer;
|
||||
import net.minecraft.inventory.ContainerWorkbench;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import electroblob.wizardry.misc.RecipeRechargeWithFlask;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.FurnaceRecipes;
|
||||
@@ -14,9 +12,6 @@ import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@@ -54,84 +49,22 @@ public final class WizardryRecipes {
|
||||
|
||||
// Mana flask recipes
|
||||
|
||||
ItemStack smallFlaskStack = new ItemStack(WizardryItems.small_mana_flask);
|
||||
ItemStack mediumFlaskStack = new ItemStack(WizardryItems.medium_mana_flask);
|
||||
ItemStack largeFlaskStack = new ItemStack(WizardryItems.large_mana_flask);
|
||||
|
||||
ItemStack chargeable;
|
||||
Item chargeable;
|
||||
|
||||
while(!chargingRecipeQueue.isEmpty()){
|
||||
// Use remove() and not poll() because the queue shouldn't be empty in here
|
||||
chargeable = new ItemStack(chargingRecipeQueue.remove(), 1, OreDictionary.WILDCARD_VALUE);
|
||||
chargeable = chargingRecipeQueue.remove();
|
||||
|
||||
registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, smallFlaskStack){
|
||||
@Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book
|
||||
}.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/small_flask_" + chargeable.getItem().getRegistryName().getPath())));
|
||||
registry.register(new RecipeRechargeWithFlask(chargeable, (ItemManaFlask)WizardryItems.small_mana_flask)
|
||||
.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/small_flask_" + chargeable.getRegistryName().getPath())));
|
||||
|
||||
registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, mediumFlaskStack){
|
||||
@Override public boolean isDynamic(){ return true; }
|
||||
}.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/medium_flask_" + chargeable.getItem().getRegistryName().getPath())));
|
||||
registry.register(new RecipeRechargeWithFlask(chargeable, (ItemManaFlask)WizardryItems.medium_mana_flask)
|
||||
.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/medium_flask_" + chargeable.getRegistryName().getPath())));
|
||||
|
||||
registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, largeFlaskStack){
|
||||
@Override public boolean isDynamic(){ return true; }
|
||||
}.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/large_flask_" + chargeable.getItem().getRegistryName().getPath())));
|
||||
registry.register(new RecipeRechargeWithFlask(chargeable, (ItemManaFlask)WizardryItems.large_mana_flask)
|
||||
.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/large_flask_" + chargeable.getRegistryName().getPath())));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
|
||||
|
||||
if(event.phase == TickEvent.Phase.START){
|
||||
|
||||
if(event.player.openContainer instanceof ContainerWorkbench){
|
||||
|
||||
IInventory craftMatrix = ((ContainerWorkbench)event.player.openContainer).craftMatrix;
|
||||
ItemStack output = ((ContainerWorkbench)event.player.openContainer).craftResult.getStackInSlot(0);
|
||||
processManaFlaskCrafting(craftMatrix, output);
|
||||
|
||||
}else if(event.player.openContainer instanceof ContainerPlayer){
|
||||
|
||||
IInventory craftMatrix = ((ContainerPlayer)event.player.openContainer).craftMatrix;
|
||||
ItemStack output = ((ContainerPlayer)event.player.openContainer).craftResult.getStackInSlot(0);
|
||||
// Unfortunately I have no choice but to call this method every tick when the player isn't using another
|
||||
// inventory, since the only thing tracking whether the player is looking at their inventory is the GUI
|
||||
// itself, which is client-side only.
|
||||
processManaFlaskCrafting(craftMatrix, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processManaFlaskCrafting(IInventory craftMatrix, ItemStack output){
|
||||
|
||||
// Charges wand using mana flask
|
||||
|
||||
ItemManaFlask flask = null;
|
||||
ItemStack input = ItemStack.EMPTY;
|
||||
|
||||
for(int i = 0; i < craftMatrix.getSizeInventory(); i++){
|
||||
|
||||
ItemStack stack = craftMatrix.getStackInSlot(i);
|
||||
|
||||
if(stack.getItem() instanceof ItemManaFlask){
|
||||
flask = (ItemManaFlask)stack.getItem();
|
||||
}
|
||||
|
||||
if(stack.getItem() instanceof IManaStoringItem){
|
||||
input = stack;
|
||||
}
|
||||
}
|
||||
|
||||
if(flask == null) return;
|
||||
|
||||
if(output.getItem() instanceof IManaStoringItem && !input.isEmpty()){
|
||||
|
||||
output.setTagCompound((input.getTagCompound()));
|
||||
|
||||
int currentMana = ((IManaStoringItem)input.getItem()).getMana(input);
|
||||
|
||||
((IManaStoringItem)output.getItem()).setMana(output, Math.min(currentMana + flask.size.capacity,
|
||||
((IManaStoringItem)input.getItem()).getManaCapacity(input)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,14 @@ public class ArrowRain extends SpellConstructRanged<EntityArrowRain> {
|
||||
|
||||
// Moves the entity back towards the caster a bit, so the area of effect is better centred on the position.
|
||||
// 3 is the distance to move the entity back towards the caster.
|
||||
double dx = caster.posX - x;
|
||||
double dz = caster.posZ - z;
|
||||
double distRatio = 3 / Math.sqrt(dx * dx + dz * dz);
|
||||
x += dx * distRatio;
|
||||
z += dz * distRatio;
|
||||
double dx = caster == null ? side.getDirectionVec().getX() : caster.posX - x;
|
||||
double dz = caster == null ? side.getDirectionVec().getZ() : caster.posZ - z;
|
||||
double dist = Math.sqrt(dx * dx + dz * dz);
|
||||
if(dist != 0){
|
||||
double distRatio = 3 / dist;
|
||||
x += dx * distRatio;
|
||||
z += dz * distRatio;
|
||||
}
|
||||
// Moves the entity up 5 blocks so that it is above mobs' heads.
|
||||
y += 5;
|
||||
|
||||
@@ -32,7 +35,11 @@ public class ArrowRain extends SpellConstructRanged<EntityArrowRain> {
|
||||
@Override
|
||||
protected void addConstructExtras(EntityArrowRain construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
// Makes the arrows shoot in the direction the caster was looking when they cast the spell.
|
||||
construct.rotationYaw = caster.rotationYawHead;
|
||||
if(caster != null){
|
||||
construct.rotationYaw = caster.rotationYawHead;
|
||||
}else{
|
||||
construct.rotationYaw = side.getHorizontalAngle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ConjureBlock extends SpellRay {
|
||||
@Override
|
||||
protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){
|
||||
if(caster.isSneaking() && world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){
|
||||
|
||||
if(!world.isRemote){
|
||||
// Dispelling of blocks
|
||||
|
||||
@@ -23,8 +23,10 @@ public class Decay extends SpellConstructRanged<EntityDecay> {
|
||||
|
||||
@Override
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
if(world.getBlockState(new BlockPos(x, y, z)).isNormalCube()) return false;
|
||||
|
||||
BlockPos origin = new BlockPos(x, y, z);
|
||||
|
||||
if(world.getBlockState(origin).isNormalCube()) return false;
|
||||
|
||||
super.spawnConstruct(world, x, y, z, side, caster, modifiers);
|
||||
|
||||
@@ -35,7 +37,7 @@ public class Decay extends SpellConstructRanged<EntityDecay> {
|
||||
int verticalRange = (int)(6 * modifiers.get(WizardryItems.blast_upgrade));
|
||||
|
||||
for(int i=0; i<quantity; i++){
|
||||
BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, horizontalRange, verticalRange);
|
||||
BlockPos pos = WizardryUtilities.findNearbyFloorSpace(world, origin, horizontalRange, verticalRange);
|
||||
if(pos == null) break;
|
||||
super.spawnConstruct(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, side, caster, modifiers);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,9 @@ public class Disintegration extends SpellRay {
|
||||
double z = (world.rand.nextDouble() - 0.5) * target.width;
|
||||
ember.setPosition(target.posX + x, target.posY + y, target.posZ + z);
|
||||
float speed = 0.2f;
|
||||
ember.setVelocity(x * speed, y * 0.5f * speed, z * speed);
|
||||
ember.motionX = x * speed;
|
||||
ember.motionY = y * 0.5f * speed;
|
||||
ember.motionZ = z * speed;
|
||||
world.spawnEntity(ember);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,20 +40,18 @@
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX,
|
||||
caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0);
|
||||
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y + 0.1, z, 0, 0, 0);
|
||||
|
||||
double particleX, particleZ;
|
||||
|
||||
for(int i=0; i<40; i++){
|
||||
|
||||
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleX = x - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = z - 1.0d + 2 * world.rand.nextDouble();
|
||||
|
||||
IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster);
|
||||
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY,
|
||||
particleZ, particleX - caster.posX, 0, particleZ - caster.posZ,
|
||||
Block.getStateId(block));
|
||||
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, y,
|
||||
particleZ, particleX - x, 0, particleZ - z, Block.getStateId(block));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +67,11 @@ 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.
|
||||
@@ -78,4 +84,5 @@ public class EmpoweringPresence extends Spell {
|
||||
event.getModifiers().get(SpellModifiers.POTENCY) * potency, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ public class FrostAxe extends SpellConjuration {
|
||||
|
||||
public FrostAxe(){
|
||||
super("frost_axe", WizardryItems.frost_axe);
|
||||
addProperties(DAMAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,8 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class Hailstorm extends SpellConstructRanged<EntityHailstorm> {
|
||||
|
||||
public Hailstorm(){
|
||||
@@ -14,15 +16,18 @@ public class Hailstorm extends SpellConstructRanged<EntityHailstorm> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
// Moves the entity back towards the caster a bit, so the area of effect is better centred on the position.
|
||||
// 3 is the distance to move the entity back towards the caster.
|
||||
double dx = caster.posX - x;
|
||||
double dz = caster.posZ - z;
|
||||
double distRatio = 3 / Math.sqrt(dx * dx + dz * dz);
|
||||
x += dx * distRatio;
|
||||
z += dz * distRatio;
|
||||
double dx = caster == null ? side.getDirectionVec().getX() : caster.posX - x;
|
||||
double dz = caster == null ? side.getDirectionVec().getZ() : caster.posZ - z;
|
||||
double dist = Math.sqrt(dx * dx + dz * dz);
|
||||
if(dist != 0){
|
||||
double distRatio = 3 / dist;
|
||||
x += dx * distRatio;
|
||||
z += dz * distRatio;
|
||||
}
|
||||
// Moves the entity up 5 blocks so that it is above mobs' heads.
|
||||
y += 5;
|
||||
|
||||
@@ -32,7 +37,11 @@ public class Hailstorm extends SpellConstructRanged<EntityHailstorm> {
|
||||
@Override
|
||||
protected void addConstructExtras(EntityHailstorm construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
// Makes the arrows shoot in the direction the caster was looking when they cast the spell.
|
||||
if(caster != null) construct.rotationYaw = caster.rotationYawHead;
|
||||
if(caster != null){
|
||||
construct.rotationYaw = caster.rotationYawHead;
|
||||
}else{
|
||||
construct.rotationYaw = side.getHorizontalAngle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ public class IceSpikes extends SpellConstructRanged<EntityIceSpike> {
|
||||
@Override
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
if(side == null) return false;
|
||||
|
||||
BlockPos blockHit = new BlockPos(x, y, z);
|
||||
if(side != null && side.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE) blockHit = blockHit.offset(side);
|
||||
if(side.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE) blockHit = blockHit.offset(side);
|
||||
|
||||
if(world.getBlockState(blockHit).isNormalCube()) return false;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -247,7 +247,7 @@ public class Possession extends SpellRay {
|
||||
}
|
||||
}
|
||||
|
||||
if(possessor.world.isRemote){
|
||||
if(possessor.world.isRemote && possessor == net.minecraft.client.Minecraft.getMinecraft().player){
|
||||
// Shaders and effects
|
||||
if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER);
|
||||
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice...
|
||||
@@ -342,7 +342,7 @@ public class Possession extends SpellRay {
|
||||
player.capabilities.isFlying = false;
|
||||
}
|
||||
|
||||
if(player.world.isRemote){
|
||||
if(player.world.isRemote && player == net.minecraft.client.Minecraft.getMinecraft().player){
|
||||
net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader();
|
||||
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice...
|
||||
}
|
||||
@@ -624,7 +624,7 @@ public class Possession extends SpellRay {
|
||||
EntityLiving possessee = getPossessee((EntityPlayer)event.getTarget());
|
||||
EntityLiving attacker = (EntityLiving)event.getEntityLiving();
|
||||
if(possessee != null && !attacker.canAttackClass(possessee.getClass())){
|
||||
event.setCanceled(true); // Mobs can't target a player possessing an entity they don't normally attack
|
||||
((EntityLiving)event.getEntityLiving()).setAttackTarget(null); // Mobs can't target a player possessing an entity they don't normally attack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 @@ 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.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
@@ -27,6 +29,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;
|
||||
@@ -82,6 +88,7 @@ import java.util.stream.Collectors;
|
||||
* @see ItemScroll ItemScroll
|
||||
* @see Spells
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements Comparable<Spell> {
|
||||
|
||||
// Spell checklist:
|
||||
@@ -115,6 +122,8 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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<String> propertyKeys = new HashSet<>();
|
||||
|
||||
@@ -221,7 +230,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
// Conversely, general spell classes ONLY EVER define the properties they ACTUALLY USE.
|
||||
public final Spell addProperties(String... keys){
|
||||
|
||||
if(properties != null) throw new IllegalStateException("Tried to add spell properties after they were initialised");
|
||||
if(arePropertiesInitialised()) throw new IllegalStateException("Tried to add spell properties after they were initialised");
|
||||
|
||||
for(String key : keys) if(propertyKeys.contains(key)) Wizardry.logger.warn("Tried to add a duplicate property key '"
|
||||
+ key + "' to spell " + this.getRegistryName());
|
||||
@@ -236,12 +245,19 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
return propertyKeys.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/** Returns true if this spell's properties have been initialised, false if not. Check this if you're attempting
|
||||
* to access them from code that could be called before wizardry's {@code init()} method (e.g. item attributes). */
|
||||
public final boolean arePropertiesInitialised(){
|
||||
return properties != null;
|
||||
}
|
||||
|
||||
/** Sets this spell's properties to the given {@link SpellProperties} object, but only if it doesn't already
|
||||
* have one. This prevents spell properties from being changed after initialisation. */
|
||||
public void setProperties(@Nonnull SpellProperties properties){
|
||||
|
||||
if(this.properties == null){
|
||||
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.");
|
||||
}
|
||||
@@ -258,9 +274,14 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,6 +574,13 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
this.enabled = isEnabled;
|
||||
}
|
||||
|
||||
/** Returns true if the given item has a variant for this spell. By default, returns true if the given item is
|
||||
* either {@link WizardryItems#spell_book} or {@link WizardryItems#scroll}. Override to give the spell a special
|
||||
* type of book or scroll. */
|
||||
public boolean applicableForItem(Item item){
|
||||
return item == WizardryItems.spell_book || item == WizardryItems.scroll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". <b>This should
|
||||
* only be used for translation purposes.</b>
|
||||
@@ -569,13 +597,23 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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). <b>Client-side
|
||||
* only!</b> 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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -583,7 +621,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
* formatting (i.e. not coloured).
|
||||
*/
|
||||
public ITextComponent getNameForTranslation(){
|
||||
return new TextComponentTranslation("spell." + unlocalisedName);
|
||||
return new TextComponentTranslation(getTranslationKey());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -592,7 +630,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -600,7 +638,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -609,7 +647,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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 ==============================================
|
||||
@@ -856,4 +894,32 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class SpellConstruct<T extends EntityMagicConstruct> extends Spell {
|
||||
* @param modifiers The modifiers with which the spell was cast.
|
||||
* @return false to cause the spell to fail, true to continue with casting.
|
||||
*/
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, @Nullable EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, @Nullable EnumFacing side, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
if(!world.isRemote){
|
||||
// Creates a new construct using the supplied factory
|
||||
|
||||
@@ -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;
|
||||
@@ -9,7 +10,11 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class SummonSnowGolem extends Spell {
|
||||
|
||||
@@ -45,4 +50,8 @@ public class SummonSnowGolem extends Spell {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTranslationKey(){
|
||||
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import electroblob.wizardry.util.SpellModifiers;
|
||||
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<EntityTornado> {
|
||||
|
||||
@@ -19,7 +23,8 @@ public class Tornado extends SpellConstruct<EntityTornado> {
|
||||
@Override
|
||||
protected void addConstructExtras(EntityTornado construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
float speed = getProperty(SPEED).floatValue();
|
||||
construct.setHorizontalVelocity(caster.getLookVec().x * speed, caster.getLookVec().z * speed);
|
||||
Vec3d direction = caster == null ? new Vec3d(side.getDirectionVec()) : caster.getLookVec();
|
||||
construct.setHorizontalVelocity(direction.x * speed, direction.z * speed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -142,12 +142,17 @@ public class TileEntityShrineCore extends TileEntity implements ITickable {
|
||||
double z = this.pos.getZ() + 0.5;
|
||||
|
||||
if(!world.isRemote){
|
||||
|
||||
WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos),
|
||||
new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64));
|
||||
}
|
||||
|
||||
world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState()
|
||||
.withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT)));
|
||||
if(world.getBlockState(pos).getBlock() == WizardryBlocks.runestone_pedestal){
|
||||
world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState()
|
||||
.withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT)));
|
||||
}else{
|
||||
Wizardry.logger.warn("What's going on?! A shrine core is being conquered but the block at its position is not a runestone pedestal!");
|
||||
}
|
||||
}
|
||||
|
||||
world.markTileEntityForRemoval(this);
|
||||
|
||||
|
||||
@@ -111,12 +111,12 @@ public final class AllyDesignationSystem {
|
||||
*/
|
||||
public static boolean isValidTarget(Entity attacker, Entity target){
|
||||
|
||||
// Always return true if the attacker is null
|
||||
if(attacker == null) return true;
|
||||
|
||||
// Always return false if the target is null
|
||||
if(target == null) return false;
|
||||
|
||||
// Always return true if the attacker is null - this must be after the target null check!
|
||||
if(attacker == null) return true;
|
||||
|
||||
// Tests whether the target is the attacker
|
||||
if(target == attacker) return false;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ public final class CustomSoundCategory {
|
||||
/**
|
||||
* Adds a new custom sound category, performing the necessary changes to GameSettings and
|
||||
*
|
||||
* @param name A unique name for the sound category
|
||||
* @param name A unique name for the sound category. <b>Must not contain any colons!</b>
|
||||
* @return The resulting SoundCategory object
|
||||
* @throws IllegalArgumentException if name is not unique
|
||||
*/
|
||||
@@ -59,8 +59,8 @@ public final class CustomSoundCategory {
|
||||
constantName = name.toUpperCase().replace(" ", "");
|
||||
referenceName = constantName.toLowerCase();
|
||||
// >> Electroblob: Removed array surrounding varargs argument
|
||||
soundCategory = EnumHelper.addEnum(SoundCategory.class , constantName, new Class[]{String.class}, referenceName);
|
||||
SOUND_CATEGORIES = ObfuscationReflectionHelper.getPrivateValue(SoundCategory.class, SoundCategory.VOICE ,"SOUND_CATEGORIES", SRG_SOUND_CATEGORIES);
|
||||
soundCategory = EnumHelper.addEnum(SoundCategory.class , constantName, new Class<?>[]{String.class}, referenceName);
|
||||
SOUND_CATEGORIES = ObfuscationReflectionHelper.getPrivateValue(SoundCategory.class, SoundCategory.VOICE, SRG_SOUND_CATEGORIES);
|
||||
if (SOUND_CATEGORIES.containsKey(referenceName))
|
||||
// >> Electroblob: changed from Error to IllegalArgumentException
|
||||
throw new IllegalArgumentException("Clash in Sound Category name pools! Cannot insert " + constantName);
|
||||
@@ -79,8 +79,7 @@ public final class CustomSoundCategory {
|
||||
// Replace the map in the GameSettings.class
|
||||
// >> Electroblob: Fully qualified names, because this class gets loaded on both sides
|
||||
ObfuscationReflectionHelper.setPrivateValue(net.minecraft.client.settings.GameSettings.class,
|
||||
net.minecraft.client.Minecraft.getMinecraft().gameSettings, soundLevels,
|
||||
"soundLevels", SRG_soundLevels);
|
||||
net.minecraft.client.Minecraft.getMinecraft().gameSettings, soundLevels, SRG_soundLevels);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String> modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet());
|
||||
|
||||
boolean flag = true;
|
||||
boolean flag = loadConfigSpellProperties();
|
||||
|
||||
for(String modID : modIDs){
|
||||
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<Spell> spells = Spell.getSpells(s -> s.getRegistryName().getNamespace().equals(modID));
|
||||
if(modID.equals(Wizardry.MODID)) spells.add(Spells.none); // In this particular case we do need the none spell
|
||||
|
||||
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
|
||||
|
||||
@@ -50,7 +50,7 @@ public final class WandHelper {
|
||||
public static final String UPGRADES_KEY = "upgrades";
|
||||
public static final String PROGRESSION_KEY = "progression";
|
||||
|
||||
private static final HashMap<Item, String> upgradeMap = new HashMap<Item, String>();
|
||||
private static final HashMap<Item, String> upgradeMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
upgradeMap.put(WizardryItems.condenser_upgrade, "condenser");
|
||||
@@ -251,11 +251,15 @@ public final class WandHelper {
|
||||
/** Returns the given wand's cooldown for the currently selected spell, or 0 if the wand has no cooldown data. */
|
||||
public static int getCurrentCooldown(ItemStack wand){
|
||||
|
||||
if(wand.getTagCompound() == null) wand.setTagCompound(new NBTTagCompound());
|
||||
|
||||
int[] cooldowns = getCooldowns(wand);
|
||||
|
||||
if(cooldowns.length == 0) return 0;
|
||||
int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
|
||||
|
||||
if(selectedSpell < 0 || cooldowns.length <= selectedSpell) return 0;
|
||||
// Don't need to check if the tag compound is null since the above check is equivalent.
|
||||
return cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)];
|
||||
return cooldowns[selectedSpell];
|
||||
}
|
||||
|
||||
/** Returns the given wand's cooldown for the spell after the currently selected spell, or 0 if the wand has no
|
||||
@@ -264,9 +268,11 @@ public final class WandHelper {
|
||||
|
||||
int[] cooldowns = getCooldowns(wand);
|
||||
|
||||
if(cooldowns.length == 0) return 0;
|
||||
int nextSpell = getNextSpellIndex(wand);
|
||||
|
||||
if(nextSpell < 0 || cooldowns.length <= nextSpell) return 0;
|
||||
// Don't need to check if the tag compound is null since the above check is equivalent.
|
||||
return cooldowns[getNextSpellIndex(wand)];
|
||||
return cooldowns[nextSpell];
|
||||
}
|
||||
|
||||
/** Returns the given wand's cooldown for the spell before the currently selected spell, or 0 if the wand has no
|
||||
@@ -275,9 +281,11 @@ public final class WandHelper {
|
||||
|
||||
int[] cooldowns = getCooldowns(wand);
|
||||
|
||||
if(cooldowns.length == 0) return 0;
|
||||
int previousSpell = getPreviousSpellIndex(wand);
|
||||
|
||||
if(previousSpell < 0 || cooldowns.length <= previousSpell) return 0;
|
||||
// Don't need to check if the tag compound is null since the above check is equivalent.
|
||||
return cooldowns[getPreviousSpellIndex(wand)];
|
||||
return cooldowns[previousSpell];
|
||||
}
|
||||
|
||||
/** Sets the given wand's cooldown for the currently selected spell. Will also set the maximum cooldown. */
|
||||
@@ -287,19 +295,24 @@ public final class WandHelper {
|
||||
|
||||
int[] cooldowns = getCooldowns(wand);
|
||||
|
||||
int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
|
||||
int spellCount = getSpells(wand).length;
|
||||
|
||||
if(spellCount <= selectedSpell) return; // Probably shouldn't happen
|
||||
|
||||
// The length of the spells array must be greater than 0 since this method can only be called if a spell is
|
||||
// cast, which is impossible if there are no spells.
|
||||
if(cooldowns.length == 0) cooldowns = new int[getSpells(wand).length];
|
||||
if(cooldowns.length <= selectedSpell) cooldowns = new int[spellCount];
|
||||
|
||||
cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown;
|
||||
cooldowns[selectedSpell] = cooldown;
|
||||
|
||||
setCooldowns(wand, cooldowns);
|
||||
|
||||
int[] maxCooldowns = getMaxCooldowns(wand);
|
||||
|
||||
if(maxCooldowns.length == 0) maxCooldowns = new int[getSpells(wand).length];
|
||||
if(maxCooldowns.length <= selectedSpell) maxCooldowns = new int[spellCount];
|
||||
|
||||
maxCooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown;
|
||||
maxCooldowns[selectedSpell] = cooldown;
|
||||
|
||||
setMaxCooldowns(wand, maxCooldowns);
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public final class WizardryUtilities {
|
||||
|
||||
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side and
|
||||
* 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. */
|
||||
@@ -870,9 +870,10 @@ public final class WizardryUtilities {
|
||||
|
||||
ItemStack stack = caster.getHeldItem(caster.getActiveHand());
|
||||
|
||||
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) == spell
|
||||
&& ((ISpellCastingItem)stack.getItem()).canCast(stack, spell, (EntityPlayer)caster,
|
||||
EnumHand.MAIN_HAND, 0, new SpellModifiers())){
|
||||
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) == spell){
|
||||
// Don't do this, it interferes with stuff! We effectively already tested this with caster.isHandActive() anyway
|
||||
// && ((ISpellCastingItem)stack.getItem()).canCast(stack, spell, (EntityPlayer)caster,
|
||||
// EnumHand.MAIN_HAND, 0, new SpellModifiers())){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,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 +119,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 <b>always</b> the northwest corner of the structure, and the y-coordinate is that of the
|
||||
* uppermost block at those (x, z) coordinates. If the structure is being rotated this needs to be altered using
|
||||
@@ -128,7 +128,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,6 +136,11 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
||||
BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16));
|
||||
|
||||
BlockPos 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)));
|
||||
Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true,
|
||||
@@ -145,8 +150,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 +217,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,7 +249,7 @@ 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());
|
||||
|
||||
@@ -306,7 +311,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
|
||||
}
|
||||
|
||||
/** Finds and removes any floating bits of tree in and above the given structure bounding box. */
|
||||
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 +359,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
|
||||
|
||||
@@ -313,7 +313,7 @@ item.ebwizardry\:amulet_auto_shield.desc=Grants a 25%% chance to trigger the shi
|
||||
item.ebwizardry\:charm_haggler.name=Haggler's Sign
|
||||
item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them
|
||||
item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent
|
||||
item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 40%%
|
||||
item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 50%%
|
||||
item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark
|
||||
item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar
|
||||
item.ebwizardry\:charm_lava_walking.name=Nether Ice Core
|
||||
@@ -719,14 +719,14 @@ spell.ebwizardry\:arc.desc=Fires a spark of lightning at the target.
|
||||
spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds.
|
||||
spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however.
|
||||
spell.ebwizardry\:arrow_rain.desc="Archers, fire!"
|
||||
spell.ebwizardry\:banish.desc=Teleports the target against its will to a random locations within a certain range.
|
||||
spell.ebwizardry\:banish.desc=Teleports the target against its will to a random location within a certain range.
|
||||
spell.ebwizardry\:black_hole.desc=Tear reality asunder.
|
||||
spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing.
|
||||
spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed.
|
||||
spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged.
|
||||
spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice.
|
||||
spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path.
|
||||
spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered locations. With this spell selected, sneak-right-click on a block to set the locations. Cast this spell normally to reveal the path. The path will fade after 90 seconds.
|
||||
spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds.
|
||||
spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken.
|
||||
spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon.
|
||||
spell.ebwizardry\:conjure_armour.desc=Creates spectral armour around the caster which offers protection equal to that of iron armour. The armour lasts for 60 seconds. The caster must have an empty armour slot.
|
||||
@@ -895,9 +895,9 @@ spell.ebwizardry\:transportation.undefined=You must remember the location of a s
|
||||
spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension...
|
||||
spell.ebwizardry\:clairvoyance.searching=Searching...
|
||||
spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point
|
||||
spell.ebwizardry\:clairvoyance.outofrange=Your remembered locations is too far away or inaccessible...
|
||||
spell.ebwizardry\:clairvoyance.undefined=You must remember a locations first!
|
||||
spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered locations is in another dimension...
|
||||
spell.ebwizardry\:clairvoyance.outofrange=Your remembered location is too far away or inaccessible...
|
||||
spell.ebwizardry\:clairvoyance.undefined=You must remember a location first!
|
||||
spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered location is in another dimension...
|
||||
spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s!
|
||||
spell.ebwizardry\:possession.success=Press %s to stop possessing
|
||||
spell.ebwizardry\:divination.nothing=Nothing happened.
|
||||
@@ -1003,6 +1003,16 @@ enchantment.ebwizardry\:magic_protection=Magic Protection
|
||||
enchantment.ebwizardry\:frost_protection=Frost Protection
|
||||
enchantment.ebwizardry\:shock_protection=Shock Protection
|
||||
|
||||
enchantment.ebwizardry.magic_sword.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.magic_bow.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.flaming_weapon.desc=Part of the Flaming Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.freezing_weapon.desc=Part of the Freezing Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.shocking_weapon.desc=Part of the Shocking Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
|
||||
enchantment.ebwizardry.magic_protection.desc=Reduces damage from all magic.
|
||||
enchantment.ebwizardry.frost_protection.desc=Reduces the effects of frost damage.
|
||||
enchantment.ebwizardry.shock_protection.desc=Reduces the effects of shock damage.
|
||||
|
||||
key.categories.ebwizardry=Wizardry
|
||||
|
||||
key.ebwizardry.next_spell=Next Spell
|
||||
@@ -1011,7 +1021,7 @@ key.ebwizardry.previous_spell=Previous Spell
|
||||
death.attack.wizardry_magic=%1$s was killed by %2$s using magic
|
||||
death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic
|
||||
|
||||
soundCategory.ebwizardry\:spells=Spells
|
||||
soundCategory.ebwizardry_spells=Spells
|
||||
|
||||
commands.ebwizardry\:cast.usage=/%1$s <spell> [player | x y z direction] [duration] [modifiers]
|
||||
commands.ebwizardry\:cast.success=Successfully cast %s
|
||||
@@ -1107,6 +1117,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
|
||||
@@ -1154,27 +1166,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
|
||||
@@ -1277,4 +1289,9 @@ 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
|
||||
|
||||
@@ -313,7 +313,7 @@ item.ebwizardry\:amulet_auto_shield.desc=Grants a 25%% chance to trigger the shi
|
||||
item.ebwizardry\:charm_haggler.name=Haggler's Sign
|
||||
item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them
|
||||
item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent
|
||||
item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 40%%
|
||||
item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 50%%
|
||||
item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark
|
||||
item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar
|
||||
item.ebwizardry\:charm_lava_walking.name=Nether Ice Core
|
||||
@@ -719,14 +719,14 @@ spell.ebwizardry\:arc.desc=Fires a spark of lightning at the target.
|
||||
spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds.
|
||||
spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however.
|
||||
spell.ebwizardry\:arrow_rain.desc="Archers, fire!"
|
||||
spell.ebwizardry\:banish.desc=Teleports the target against its will to a random locations within a certain range.
|
||||
spell.ebwizardry\:banish.desc=Teleports the target against its will to a random location within a certain range.
|
||||
spell.ebwizardry\:black_hole.desc=Tear reality asunder.
|
||||
spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing.
|
||||
spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed.
|
||||
spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged.
|
||||
spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice.
|
||||
spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path.
|
||||
spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered locations. With this spell selected, sneak-right-click on a block to set the locations. Cast this spell normally to reveal the path. The path will fade after 90 seconds.
|
||||
spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds.
|
||||
spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken.
|
||||
spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon.
|
||||
spell.ebwizardry\:conjure_armour.desc=Creates spectral armor around the caster which offers protection equal to that of iron armor. The armor lasts for 60 seconds. The caster must have an empty armor slot.
|
||||
@@ -895,9 +895,9 @@ spell.ebwizardry\:transportation.undefined=You must remember the location of a s
|
||||
spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension...
|
||||
spell.ebwizardry\:clairvoyance.searching=Searching...
|
||||
spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point
|
||||
spell.ebwizardry\:clairvoyance.outofrange=Your remembered locations is too far away or inaccessible...
|
||||
spell.ebwizardry\:clairvoyance.undefined=You must remember a locations first!
|
||||
spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered locations is in another dimension...
|
||||
spell.ebwizardry\:clairvoyance.outofrange=Your remembered location is too far away or inaccessible...
|
||||
spell.ebwizardry\:clairvoyance.undefined=You must remember a location first!
|
||||
spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered location is in another dimension...
|
||||
spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s!
|
||||
spell.ebwizardry\:possession.success=Press %s to stop possessing
|
||||
spell.ebwizardry\:divination.nothing=Nothing happened.
|
||||
@@ -1003,6 +1003,16 @@ enchantment.ebwizardry\:magic_protection=Magic Protection
|
||||
enchantment.ebwizardry\:frost_protection=Frost Protection
|
||||
enchantment.ebwizardry\:shock_protection=Shock Protection
|
||||
|
||||
enchantment.ebwizardry.magic_sword.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.magic_bow.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.flaming_weapon.desc=Part of the Flaming Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.freezing_weapon.desc=Part of the Freezing Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
enchantment.ebwizardry.shocking_weapon.desc=Part of the Shocking Weapon spell; unobtainable in survival mode (the book won't work).
|
||||
|
||||
enchantment.ebwizardry.magic_protection.desc=Reduces damage from all magic.
|
||||
enchantment.ebwizardry.frost_protection.desc=Reduces the effects of frost damage.
|
||||
enchantment.ebwizardry.shock_protection.desc=Reduces the effects of shock damage.
|
||||
|
||||
key.categories.ebwizardry=Wizardry
|
||||
|
||||
key.ebwizardry.next_spell=Next Spell
|
||||
@@ -1011,7 +1021,7 @@ key.ebwizardry.previous_spell=Previous Spell
|
||||
death.attack.wizardry_magic=%1$s was killed by %2$s using magic
|
||||
death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic
|
||||
|
||||
soundCategory.ebwizardry\:spells=Spells
|
||||
soundCategory.ebwizardry_spells=Spells
|
||||
|
||||
commands.ebwizardry\:cast.usage=/%1$s <spell> [player | x y z direction] [duration] [modifiers]
|
||||
commands.ebwizardry\:cast.success=Successfully cast %s
|
||||
@@ -1107,6 +1117,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
|
||||
@@ -1154,27 +1166,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
|
||||
@@ -1277,4 +1289,9 @@ 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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2,5 +2,13 @@
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "ebwizardry:items/scroll"
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"festive": 1
|
||||
},
|
||||
"model": "ebwizardry:item/festive_scroll"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "ebwizardry:items/scroll_festive"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "ebwizardry:items/spell_book_festive"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "item/handheld",
|
||||
"textures": {
|
||||
"layer0": "ebwizardry:items/wand_festive"
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,13 @@
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "ebwizardry:items/scroll"
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"festive": 1
|
||||
},
|
||||
"model": "ebwizardry:item/festive_scroll"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,5 +2,13 @@
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "ebwizardry:items/spell_book"
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"festive": 1
|
||||
},
|
||||
"model": "ebwizardry:item/festive_spell_book"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user