Initial commit

This commit is contained in:
Electroblob
2018-01-19 20:33:04 +00:00
commit da6b007a3a
945 changed files with 60616 additions and 0 deletions
@@ -0,0 +1,176 @@
package electroblob.wizardry;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.PacketClairvoyance;
import electroblob.wizardry.packet.PacketGlyphData;
import electroblob.wizardry.packet.PacketNPCCastSpell.Message;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.common.config.Property;
/**
* The common proxy for wizardry, serving the usual purpose of dealing with all things that need to be handled
* differently on the client and the server. A lot of the methods here appear to do absolutely nothing; this is
* because they do client-only things which are only handled in the client proxy.
* @see {@link electroblob.wizardry.client.ClientProxy}
* @author Electroblob
* @since Wizardry 1.0
* */
@SuppressWarnings("deprecation")
public class CommonProxy {
// SECTION Registry
// ===============================================================================================================
public void registerRenderers(){}
public void initialiseLayers(){}
public void registerKeyBindings(){}
public void registerSpellHUD(){}
public net.minecraft.client.model.ModelBiped getWizardArmourModel(){ return null; }
public void initMixedFontRenderer(){}
// SECTION Particles
// ===============================================================================================================
/**
* Spawns a custom particle of the specified type.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
* @param r Red component of particle colour; will be clamped to between 0 and 1
* @param g Red component of particle colour; will be clamped to between 0 and 1
* @param b Red component of particle colour; will be clamped to between 0 and 1
* @param doGravity Whether the particle is affected by gravity (only affects SPARKLE at the moment)
* @param radius The radius of the particle's motion, for cirular motion particles
*/
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){
// Does nothing since particles are client-side only
}
/** Spawns a custom particle of the specified type. doGravity defaults to false and radius defaults to 0.
* Note that some of these settings may not affect the particle; some particles are always affected by
* gravity, for instance.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
* @param r Red component of particle colour; will be clamped to between 0 and 1 (unless this is a MAGIC_FIRE particle, in which case this is the scale)
* @param g Red component of particle colour; will be clamped to between 0 and 1
* @param b Red component of particle colour; will be clamped to between 0 and 1
*/
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b){
this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, r, g, b, false, 0);
}
/** Spawns a custom particle of the specified type. Colour defaults to white, doGravity defaults to false and radius
* defaults to 0. Note that some of these settings may not affect the particle; some particles are always affected by
* gravity, for instance.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
*/
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge){
this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, 1, 1, 1, false, 0);
}
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){}
// SECTION Items
// ===============================================================================================================
public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack) {
return null;
}
/** Returns the translated name of the scroll, taking spell discovery into account. If, for some reason, this gets
* called server-side, it uses the deprecated server version of I18n, with a warning. Since any likely server-side
* use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since no
* particular player instance can be accessed, spell discovery is ignored. */
public String getScrollDisplayName(ItemStack scroll){
// I have now learnt that the server side I18n always translates to the default en_US, so I could just return
// a hardcoded name in English instead.
Wizardry.logger.info("A mod has called ItemScroll#getItemStackDisplayName from the server side. Using the"
+ "deprecated server-side translation methods as a fallback.");
// Displays [Empty slot] if spell is continuous.
Spell spell = Spell.get(scroll.getItemDamage());
if(spell.isContinuous) spell = Spells.none;
return I18n.translateToLocalFormatted("item.wizardry:wizardry:scroll.name", I18n.translateToLocal("spell." + spell.getUnlocalisedName())).trim();
}
public double getConjuredBowDurability(ItemStack stack){
return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack);
}
// SECTION Packet Handlers
// ===============================================================================================================
public void handlePlayerSyncPacket(PacketPlayerSync.Message message){}
public void handleGlyphDataPacket(PacketGlyphData.Message message){}
public void handleCastSpellPacket(PacketCastSpell.Message message){}
public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){}
public void handleNPCCastSpellPacket(Message message){}
public void handleTransportationPacket(PacketTransportation.Message message){}
public void handleClairvoyancePacket(PacketClairvoyance.Message message){}
// SECTION Misc
// ===============================================================================================================
public void setToNumberSliderEntry(Property property){}
//public void setToEntityNameEntry(Property property){}
/** Plays a sound which moves with the given entity.
*
* @param entity The source of the sound
* @param sound The SoundEvent to play
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually)
*/
public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){}
/** Gets the client side world using Minecraft.getMinecraft().theWorld. <b>Only to be called client side!</b>
* Returns null on the server side. */
public World getTheWorld(){ return null; }
}
@@ -0,0 +1,507 @@
package electroblob.wizardry;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import electroblob.wizardry.packet.PacketSyncSettings;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.common.config.ConfigCategory;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
/** Singleton class which deals with everything related to wizardry's config file. To access individual settings, use
* {@link Wizardry#settings}. Also stores a few string constants for easy access.
* <p>
* As part of the 1.2 update and code overhaul, the way the config settings work in multiplayer has been tightened up.
* Importantly, there are <b>three</b> different types of config options:
* <p>
* <li>Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only
* has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. Examples
* include worldgen, mob drops and commands.
* <li>Synchronised settings. These settings affect both client-side AND server-side code, and are synchronised with
* each client on login via {@link Settings#sync(EntityPlayerMP)}. Changing these locally
* only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
* Examples include discovery mode and crafting recipes. <i> Note that as far as users are concerned,
* there is no difference in behaviour between server-only and synchronised settings.</i>
* <li>Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys
* its own values for these, and changing them on a dedicated server will have no effect. These are usually only display
* and controls settings.</li>
* <p>
* Each of the settings fields in this class is marked with one of the above categories to indicate which it belongs
* to. This in turn dictates which logical side it should be called from: client, server or both. <b> Do not access a
* config setting from the wrong side, because it may cause unexpected or strange behaviour.</b>
* @since Wizardry 1.2
* @author Electroblob */
// NOTE: We could convert over to the @Config system IF it is sufficiently complete in this Forge version for my purposes.
// (For one, I know that the LangKey annotation is not applicable to type declarations in 1.10.2, unlike in 1.11.2)
//@Config(modid = Wizardry.MODID)
@SuppressWarnings("deprecation") // Used server I18n deliberately; we want to write the comments in english.
public final class Settings {
// Category names
/** The unlocalised name of the spells config category. */
public static final String SPELLS_CATEGORY = "spells";
/** The unlocalised name of the resistances config category. */
public static final String RESISTANCES_CATEGORY = "resistances";
/** The unlocalised name of the client config category. */
public static final String CLIENT_CATEGORY = "client";
/** The unlocalised name of the commands config category. */
public static final String COMMANDS_CATEGORY = "commands";
/** The unlocalised name of the worldgen config category. */
public static final String WORLDGEN_CATEGORY = "worldgen";
/** The unlocalised name of the global config category. */
public static final String GLOBAL_CATEGORY = "global";
/** The wizardry config file. */
private Configuration config;
// Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only
// has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
// Worldgen
/** <b>[Server-only]</b> The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */
public int towerRarity = 8;
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] oreDimensions = {0};
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] flowerDimensions = {0};
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] towerDimensions = {0};
/** <b>[Server-only]</b> Whether or not wizardry loot should generate in dungeon chests. Note that this does not
* affect the generation of loot in wizard towers. */
public boolean generateLoot = true;
// Entities' drops, targeting, damage, etc.
/** <b>[Server-only]</b> Chance (out of 200) for mobs to drop spell books. */
public int spellBookDropChance = 3;
/** <b>[Server-only]</b> Whether or not players can teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. */
public boolean teleportThroughUnbreakableBlocks = false;
/** <b>[Server-only]</b> Whether to allow players to damage their designated allies using magic. */
public boolean friendlyFire = true;
/** <b>[Server-only]</b> Whether to allow players to disarm other players using the telekinesis spell. */
public boolean telekineticDisarmament = true;
/** <b>[Server-only]</b> Whether summoned creatures can revenge attack their caster if their caster attacks them. */
public boolean minionRevengeTargeting = true;
/** <b>[Server-only]</b> List of names of entities which summoned creatures are allowed to attack, in addition to the defaults. */
public String[] summonedCreatureTargetsWhitelist = {};
/** <b>[Server-only]</b> List of names of entities which summoned creatures are specifically not allowed to attack, overriding the defaults and the whitelist. */
public String[] summonedCreatureTargetsBlacklist = {"creeper"};
/** <b>[Server-only]</b> Global damage scaling factor for all player magic damage. */
public double playerDamageScale = 1.0f;
/** <b>[Server-only]</b> Global damage scaling factor for all npc magic damage. */
public double npcDamageScale = 1.0f;
// Commands (these don't need synchronising since typing a command always queries the server).
/** <b>[Server-only]</b> The maximum allowed multiplier for the /cast command. This limit is here to stop people from accidentally
* breaking their worlds! */
public double maxSpellCommandMultiplier = 20d;
/** <b>[Server-only]</b> The name of the /cast command. */
public String castCommandName = "cast";
/** <b>[Server-only]</b> The name of the /discoverspell command. */
public String discoverspellCommandName = "discoverspell";
/** <b>[Server-only]</b> The name of the /ally command. */
public String allyCommandName = "ally";
/** <b>[Server-only]</b> The name of the /allies command. */
public String alliesCommandName = "allies";
// Synchronised settings. These settings affect both client-side AND server-side code. Changing these locally
// only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
// Recipes (only need syncing for display in the wizard's handbook)
/** <b>[Synchronised]</b> Whether or not firebombs should be craftable. */
public boolean firebombIsCraftable = true;
/** <b>[Synchronised]</b> Whether or not poison bombs should be craftable. */
public boolean poisonBombIsCraftable = true;
/** <b>[Synchronised]</b> Whether or not poison bombs should be craftable. */
public boolean smokeBombIsCraftable = true;
/** <b>[Synchronised]</b> Whether to require a magic crystal in the blank scroll crafting recipe (in case it conflicts with another mod). */
public boolean useAlternateScrollRecipe = false;
// Gamemodes
/** <b>[Synchronised]</b> When set to true, spells a player hasn't cast yet will be unreadable until they are cast (on a per-world basis). Has no effect when in creative mode. Spells of
* identification will be unobtainable in survival mode if this is false. */
public boolean discoveryMode = true;
// Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys
// its own values for these, and changing them on a dedicated server will have no effect.
// Controls
/** <b>[Client-only]</b> Whether the player can switch between spells on a wand by scrolling with the mouse wheel while
* sneaking. */
public boolean enableShiftScrolling = true;
// Display
/** <b>[Client-only]</b> Whether to show summoned creatures' names and owners above their heads. */
public boolean showSummonedCreatureNames = true;
/** <b>[Client-only]</b> The position of the spell HUD. */
public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT;
/** Set of constants for each of the four positions that the spell HUD can be in. */
public enum GuiPosition {
BOTTOM_LEFT("Bottom left"),
TOP_LEFT("Top left"),
TOP_RIGHT("Top right"),
BOTTOM_RIGHT("Bottom right");
/** Constant array storing the names of each of the constants, in the order they are declared. */
public static final String[] names;
static {
names = new String[values().length];
for(GuiPosition position : values()){
names[position.ordinal()] = position.name;
}
}
/** The readable name for this GUI position that will be displayed on the button in the config GUI. */
public final String name;
GuiPosition(String name){
this.name = name;
}
/** Gets a GUI position from its string name (ignoring case), or BOTTOM_LEFT if the given name is not a valid position. */
public static GuiPosition fromName(String name){
for(GuiPosition position : values()){
if(position.name.equalsIgnoreCase(name)) return position;
}
Wizardry.logger.info("Invalid string for the spell HUD position. Using default (bottom left) instead.");
return BOTTOM_LEFT;
}
}
// As of Wizardry 1.1, all keys used in the config file itself are now hardcoded, not localised. The localisations
// are done in the config GUI. The config file has to be written in one language or it will end up with multiple
// options for different languages.
// These methods are package-protected to stop anyone else from calling them.
/** Called from preInit to initialise the config file. The first part of the config file has to be done here (as is
* conventional) so that the various registries can change what they do accordingly. The spell part of the config
* has to be done in the init method.*/
void initConfig(FMLPreInitializationEvent event){
config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
Wizardry.logger.info("Setting up main config");
setupGeneralConfig();
config.save();
}
/** Called from init to initialise the parts of the config file that depend on other mods. For example, the spell
* config is done here and not in preInit because all spells must be registered before it is added, including
* those in other mods. */
void initConfigExtras(){
Wizardry.logger.info("Setting up spells config for " + Spell.getTotalSpellCount() + " spells");
setupSpellsConfig();
config.save();
}
/** Called to save changes to the config file after it has been edited in game from the menus. */
void saveConfigChanges(){
Wizardry.logger.info("Saving in-game config changes");
setupGeneralConfig();
setupSpellsConfig();
config.save();
}
/** Sends a packet to the specified player's client containing all the <b>synchronised</b> settings. */
public void sync(EntityPlayerMP player){
Wizardry.logger.info("Synchronising config settings for " + player.getName());
IMessage message = new PacketSyncSettings.Message(this);
WizardryPacketHandler.net.sendTo(message, player);
}
public ConfigCategory getConfigCategory(String name){
return config.getCategory(name);
}
private void setupSpellsConfig(){
config.addCustomCategoryComment(SPELLS_CATEGORY, "Set a spell to false to disable it. Disabled spells will still have their associated spell book (mainly so the spell books don't all change) and can still be bound to wands, but cannot be cast in game, will not appear in any subsequently generated chests or wizard trades and will not drop from mobs. Disable a spell if it is causing problems, conflicts with another mod or creates an unintended exploit.");
Property property;
for(Spell spell : Spell.getSpells(Spell.allSpells)){
property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true,
I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc"));
// Uses the same config key as the spell name, because - well, that's what it's called!
property.setLanguageKey("spell." + spell.getUnlocalisedName());
spell.setEnabled(property.getBoolean());
}
}
private void setupGeneralConfig(){
// This trick is borrowed from forge; it sorts the config options into the order you want them.
List<String> propOrder = new ArrayList<String>();
Property property;
config.addCustomCategoryComment(Configuration.CATEGORY_GENERAL, "Please note that changing some of these settings may make the mod very difficult to play.");
property = config.get(Configuration.CATEGORY_GENERAL, "towerRarity", 8, "Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely.", 0, 50);
property.setLanguageKey("config.wizardry.tower_rarity");
property.setRequiresWorldRestart(true);
Wizardry.proxy.setToNumberSliderEntry(property);
towerRarity = property.getInt();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "spellBookDropChance", 3, "The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops.", 0, 200);
property.setLanguageKey("config.wizardry.spell_book_drop_chance");
Wizardry.proxy.setToNumberSliderEntry(property);
spellBookDropChance = property.getInt();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!");
property.setLanguageKey("config.wizardry.ore_dimensions");
property.setRequiresWorldRestart(true);
oreDimensions = property.getIntList();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "flowerDimensions", new int[]{0}, "List of dimension ids in which crystal flowers will generate.");
property.setLanguageKey("config.wizardry.flower_dimensions");
property.setRequiresWorldRestart(true);
flowerDimensions = property.getIntList();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate.");
property.setLanguageKey("config.wizardry.tower_dimensions");
property.setRequiresWorldRestart(true);
towerDimensions = property.getIntList();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "generateLoot", true, "Whether to generate wizardry loot in dungeon chests.");
property.setLanguageKey("config.wizardry.generate_loot");
property.setRequiresWorldRestart(true);
generateLoot = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "firebombIsCraftable", true, "Whether firebombs can be crafted or not.");
property.setLanguageKey("config.wizardry.firebomb_is_craftable");
property.setRequiresMcRestart(true);
firebombIsCraftable = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "poisonBombIsCraftable", true, "Whether poison bombs can be crafted or not.");
property.setLanguageKey("config.wizardry.poison_bomb_is_craftable");
property.setRequiresMcRestart(true);
poisonBombIsCraftable = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "smokeBombIsCraftable", true, "Whether smoke bombs can be crafted or not.");
property.setLanguageKey("config.wizardry.smoke_bomb_is_craftable");
property.setRequiresMcRestart(true);
smokeBombIsCraftable = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "useAlternateScrollRecipe", false, "Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe.");
property.setLanguageKey("config.wizardry.use_alternate_scroll_recipe");
property.setRequiresMcRestart(true);
useAlternateScrollRecipe = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "teleportThroughUnbreakableBlocks", false, "Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell.");
property.setLanguageKey("config.wizardry.teleport_through_unbreakable_blocks");
teleportThroughUnbreakableBlocks = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "showSummonedCreatureNames", true, "Whether to show summoned creatures' names and owners above their heads.");
property.setLanguageKey("config.wizardry.show_summoned_creature_names");
showSummonedCreatureNames = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "friendlyFire", true, "Whether to allow players to damage their designated allies using magic.");
property.setLanguageKey("config.wizardry.friendly_fire");
friendlyFire = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "telekineticDisarmament", true, "Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items.");
property.setLanguageKey("config.wizardry.telekinetic_disarmament");
telekineticDisarmament = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "discoveryMode", true, "For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false.");
property.setLanguageKey("config.wizardry.discovery_mode");
property.setRequiresWorldRestart(true);
discoveryMode = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "enableShiftScrolling", true, "Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings.");
property.setLanguageKey("config.wizardry.enable_shift_scrolling");
property.setRequiresWorldRestart(false);
enableShiftScrolling = property.getBoolean();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "minionRevengeTargeting", true, "Whether summoned creatures can revenge attack their owner if their owner attacks them.");
property.setLanguageKey("config.wizardry.minion_revenge_targeting");
property.setRequiresWorldRestart(false);
minionRevengeTargeting = property.getBoolean();
propOrder.add(property.getName());
// These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a
// scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the damage,
// it doesn't give fine enough control for values less than 1.
property = config.get(Configuration.CATEGORY_GENERAL, "playerDamageScaling", 1.0, "Global damage scaling factor for the damage dealt by players casting spells, relative to 1.", 0, 20);
property.setLanguageKey("config.wizardry.player_damage_scaling");
playerDamageScale = property.getDouble();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "npcDamageScaling", 1.0, "Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1.", 0, 20);
property.setLanguageKey("config.wizardry.npc_damage_scaling");
npcDamageScale = property.getDouble();
propOrder.add(property.getName());
// This one isn't a slider either because people are likely to want exact values ("it must be at most 50.3" is a bit strange!).
property = config.get(Configuration.CATEGORY_GENERAL, "castCommandMultiplierLimit", 20.0, "Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned!", 1, 255);
property.setLanguageKey("config.wizardry.cast_command_multiplier_limit");
maxSpellCommandMultiplier = property.getDouble();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "summonedCreatureTargetsWhitelist", new String[0], "List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.summoned_creature_targets_whitelist");
property.setRequiresWorldRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
summonedCreatureTargetsWhitelist = property.getStringList();
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<summonedCreatureTargetsWhitelist.length; i++){
summonedCreatureTargetsWhitelist[i] = summonedCreatureTargetsWhitelist[i].toLowerCase(Locale.ROOT).trim();
}
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "summonedCreatureTargetsBlacklist", new String[]{"creeper"}, "List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.summoned_creature_targets_blacklist");
property.setRequiresWorldRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
summonedCreatureTargetsBlacklist = property.getStringList();
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<summonedCreatureTargetsBlacklist.length; i++){
summonedCreatureTargetsBlacklist[i] = summonedCreatureTargetsBlacklist[i].toLowerCase(Locale.ROOT).trim();
}
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "spellHUDPosition", GuiPosition.BOTTOM_LEFT.name, "The position of the spell HUD.", GuiPosition.names);
property.setLanguageKey("config.wizardry.spell_hud_position");
spellHUDPosition = GuiPosition.fromName(property.getString());
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "castCommandName", "cast", "The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead.");
property.setLanguageKey("config.wizardry.cast_command_name");
property.setRequiresWorldRestart(true);
castCommandName = property.getString();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "discoverspellCommandName", "discoverspell", "The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead.");
property.setLanguageKey("config.wizardry.discoverspell_command_name");
property.setRequiresWorldRestart(true);
discoverspellCommandName = property.getString();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "allyCommandName", "ally", "The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead.");
property.setLanguageKey("config.wizardry.ally_command_name");
property.setRequiresWorldRestart(true);
allyCommandName = property.getString();
propOrder.add(property.getName());
property = config.get(Configuration.CATEGORY_GENERAL, "alliesCommandName", "allies", "The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead.");
property.setLanguageKey("config.wizardry.allies_command_name");
property.setRequiresWorldRestart(true);
alliesCommandName = property.getString();
propOrder.add(property.getName());
config.setCategoryPropertyOrder(Configuration.CATEGORY_GENERAL, propOrder);
// Resistances
List<String> propOrder1 = new ArrayList<String>();
config.addCustomCategoryComment(RESISTANCES_CATEGORY, "Settings which allow entities to be made immune to certain types of magic. In multiplayer, the server/LAN host settings will apply.");
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToFire", new String[]{}, "List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_fire");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.FIRE);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToIce", new String[]{}, "List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_ice");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.FROST);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToLightning", new String[]{}, "List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_lightning");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.SHOCK);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToWither", new String[]{}, "List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_wither");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.WITHER);
}
propOrder1.add(property.getName());
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToPoison", new String[]{}, "List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. wizardry:Wizard).");
property.setLanguageKey("config.wizardry.mobs_immune_to_poison");
property.setRequiresMcRestart(true);
//Wizardry.proxy.setToEntityNameEntry(property);
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
for(int i=0; i<property.getStringList().length; i++){
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
MagicDamage.addEntityImmunity(EntityList.NAME_TO_CLASS.get(property.getStringList()[i]), DamageType.POISON);
}
propOrder1.add(property.getName());
config.setCategoryPropertyOrder(RESISTANCES_CATEGORY, propOrder1);
// config.addCustomCategoryComment(CLIENT_CATEGORY, "Client-side settings that only affect the local minecraft game. They have no effect on a server; each player obeys their own settings.");
// config.addCustomCategoryComment(COMMANDS_CATEGORY, "Settings for the commands added by Wizardry. In multiplayer, the server/LAN host settings will apply.");
// config.addCustomCategoryComment(WORLDGEN_CATEGORY, "Settings that affect world generation. In multiplayer, the server/LAN host settings will apply.");
// config.addCustomCategoryComment(GLOBAL_CATEGORY, "Global settings that affect game mechanics. In multiplayer, the server/LAN host settings will apply.");
}
}
@@ -0,0 +1,161 @@
package electroblob.wizardry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.commons.lang3.RandomStringUtils;
import electroblob.wizardry.packet.PacketGlyphData;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraftforge.common.util.Constants.NBT;
/** Class responsible for generating and storing the randomised spell names and descriptions for each world, which are
* displayed as glyphs using the SGA font renderer.
* @since Wizardry 1.1 */
public class SpellGlyphData extends WorldSavedData {
public static final String NAME = Wizardry.MODID + "_glyphData";
public Map<Spell, String> randomNames = new HashMap<Spell, String>(Spell.getTotalSpellCount());
public Map<Spell, String> randomDescriptions = new HashMap<Spell, String>(Spell.getTotalSpellCount());
// Required constructors
public SpellGlyphData() {
this(NAME);
}
public SpellGlyphData(String name){
super(name);
}
/** Generates random names and descriptions for any spells which don't already have them. */
public void generateGlyphNames(World world){
for(Spell spell : Spell.getSpells(Spell.allSpells)){
if(!randomNames.containsKey(spell)) randomNames.put(spell, generateRandomName(world.rand));
}
for(Spell spell : Spell.getSpells(Spell.allSpells)){
if(!randomDescriptions.containsKey(spell)) randomDescriptions.put(spell, generateRandomDescription(world.rand));
}
this.markDirty();
}
private String generateRandomName(Random random){
String name = "";
for(int i=0; i<random.nextInt(2)+2; i++){
name = name + RandomStringUtils.random(3 + random.nextInt(5), "abcdefghijklmnopqrstuvwxyz") + " ";
}
return name.trim();
}
private String generateRandomDescription(Random random){
String name = "";
for(int i=0; i<random.nextInt(16)+8; i++){
name = name + RandomStringUtils.random(2 + random.nextInt(7), "abcdefghijklmnopqrstuvwxyz") + " ";
}
return name.trim();
}
/** Returns the spell glyph data for this world, or creates a new instance if it doesn't exist yet. Also checks
* for any spells that are missing glyph data and adds it accordingly. */
public static SpellGlyphData get(World world) {
SpellGlyphData instance = (SpellGlyphData) world.loadItemData(SpellGlyphData.class, NAME);
if(instance == null){
instance = new SpellGlyphData();
}
// These two conditions are a bit of backwards compatibility from when I added the descriptions to the
// glyph data. Shouldn't be needed in normal operation, but I might as well leave it here.
// Edit: More backwards compatibility, this time for the future - should any new spells be added, this now ensures
// existing worlds will generate random names and descriptions for any new spells whilst keeping the old ones.
if(instance.randomNames.size() < Spell.getTotalSpellCount() || instance.randomDescriptions.size() < Spell.getTotalSpellCount()){
instance.generateGlyphNames(world);
world.setItemData(NAME, instance);
}
return instance;
}
/** Sends the random spell names for this world to the specified player's client. */
public void sync(EntityPlayerMP player){
List<String> names = new ArrayList<String>();
List<String> descriptions = new ArrayList<String>();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
names.add(this.randomNames.get(spell));
descriptions.add(this.randomDescriptions.get(spell));
}
PacketGlyphData.Message msg = new PacketGlyphData.Message(names, descriptions);
WizardryPacketHandler.net.sendTo(msg, player);
}
/** Helper method to retrieve the random glyph name for the given spell from the map stored in the given world. */
public static String getGlyphName(Spell spell, World world){
Map<Spell, String> names = SpellGlyphData.get(world).randomNames;
return names == null ? "" : names.get(spell);
}
/** Helper method to retrieve the random glyph description for the given spell from the map stored in the given world. */
public static String getGlyphDescription(Spell spell, World world){
Map<Spell, String> descriptions = SpellGlyphData.get(world).randomDescriptions;
return descriptions == null ? "" : descriptions.get(spell);
}
@Override
public void readFromNBT(NBTTagCompound nbt){
this.randomNames = new HashMap<Spell, String>();
this.randomDescriptions = new HashMap<Spell, String>();
NBTTagList tagList = nbt.getTagList("spellGlyphData", NBT.TAG_COMPOUND);
for(int i=0; i<tagList.tagCount(); i++){
NBTTagCompound tag = tagList.getCompoundTagAt(i);
randomNames.put(Spell.get(tag.getInteger("spell")), tag.getString("name"));
randomDescriptions.put(Spell.get(tag.getInteger("spell")), tag.getString("description"));
}
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbt){
NBTTagList tagList = new NBTTagList();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
// Much like the enchantments tag for items, this stores a list of spell-id-to-name tag pairs
// The description is now also included; there's no point in making a second compound tag!
NBTTagCompound tag = new NBTTagCompound();
tag.setInteger("spell", spell.id());
tag.setString("name", this.randomNames.get(spell));
tag.setString("description", this.randomDescriptions.get(spell));
tagList.appendTag(tag);
}
nbt.setTag("spellGlyphData", tagList);
return nbt;
}
}
@@ -0,0 +1,581 @@
package electroblob.wizardry;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.enchantment.Imbuement;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryAchievements;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
/** Capability-based replacement for the old ExtendedPlayer class from 1.7.10. This has been reworked to leave
* minimum external changes (for my own sanity, mainly!). Turns out the only major difference between an internal
* capability and an IEEP is a couple of redundant classes and a different way of registering it.
* <p>
* Forge seems to have separate classes to hold the Capability<...> instance ('key') and
* methods for getting the capability, but in my opinion there are already too many classes to deal with, so I'm not
* adding any more than are necessary, meaning those constants and values are kept here instead.
* @since Wizardry 1.2
* @author Electroblob */
// On the plus side, having to rethink this class allowed me to clean it up a lot.
public class WizardData implements INBTSerializable<NBTTagCompound> {
/** Static instance of what I like to refer to as the capability key. Private because, well, it's internal! */
// This annotation does some crazy Forge magic behind the scenes and assigns this field a value.
@CapabilityInject(WizardData.class)
private static final Capability<WizardData> WIZARD_DATA_CAPABILITY = null;
private final EntityPlayer player;
// This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry.
private Map<Imbuement, Integer> imbuementDurations;
public boolean hasSpiritWolf;
public boolean hasSpiritHorse;
/** Whether this player is currently casting a continuous spell via commands. Not saved over world reload
* and reset on player death. */
private Spell currentlyCasting;
/** The time for which this player has been casting a continuous spell via commands. Increments by 1 each tick.
* Not saved over world reload and reset on player death. */
private int castingTick;
/** SpellModifiers object for the current continuous spell cast via commands. Not saved over world reload and
* reset on player death. */
private SpellModifiers spellModifiers;
/** Coordinates for the saved transportation stone circle location. Will be null if no location is saved. */
private BlockPos stoneCircleLocation;
/** Dimension id which the saved stone circle is in. */
private int stoneCircleDimension;
/** Time left until the player teleports under the effect of transportation */
private int tpCountdown;
/** Coordinates for the saved clairvoyance location. Will be null if no location is saved. */
private BlockPos clairvoyanceLocation;
/** Dimension id which the saved clairvoyance point is in. */
private int clairvoyanceDimension;
public EntityShield shield;
public WeakReference<ISummonedCreature> selectedMinion;
/** Set of this player's discovered spells. <b>Do not write to this list directly</b>, use
* {@link WizardData#discoverSpell(Spell)} instead. */
public Set<Spell> spellsDiscovered;
private Set<UUID> allies;
/** List of usernames of this player's allies. May not be accurate 100% of the time. This is here so that a player
* can view the usernames of their allies even when those allies are not online.
* <b> Do not use this for any other purpose than displaying the names! */
public Set<String> allyNames;
private Set<UUID> soulboundCreatures;
public WizardData(EntityPlayer player){
this.player = player;
this.imbuementDurations = new HashMap<Imbuement, Integer>();
this.spellsDiscovered = new HashSet<Spell>();
// 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 initalised)
this.spellsDiscovered.add(Spells.magic_missile);
this.hasSpiritWolf = false;
this.hasSpiritHorse = false;
this.currentlyCasting = Spells.none;
this.spellModifiers = new SpellModifiers();
this.castingTick = 0;
this.stoneCircleDimension = 0;
this.clairvoyanceDimension = 0;
this.setTpCountdown(0);
this.allies = new HashSet<UUID>();
this.allyNames = new HashSet<String>();
this.soulboundCreatures = new HashSet<UUID>();
}
public boolean hasSpellBeenDiscovered(Spell spell){
return spellsDiscovered.contains(spell) || spell instanceof None;
}
/**
* Adds the given spell to the list of discovered spells for this player. Automatically takes into account
* whether the spell has been discovered. Use this method rather than adding directly to the list because it
* handles achievements.
* @param spell The spell to be discovered
* @return True if the spell had not already been discovered; false otherwise.
*/
public boolean discoverSpell(Spell spell){
if(spellsDiscovered == null){
spellsDiscovered = new HashSet<Spell>();
}
// The 'none' spell cannot be discovered
if(spell instanceof None) return false;
// Tries to add the spell to the list of discovered spells, and returns false if it was already present
if(!spellsDiscovered.add(spell)) return false;
// If the spell had not already been discovered, achievements can be triggered and the method returns true
if(spellsDiscovered.containsAll(Spell.getSpells(Spell::isEnabled))){
this.player.addStat(WizardryAchievements.all_spells);
}
for(Element element : Element.values()){
if(element != Element.MAGIC && spellsDiscovered.containsAll(Spell.getSpells(new Spell.TierElementFilter(null, element)))){
this.player.addStat(WizardryAchievements.element_master);
}
}
return true;
}
/** Sets the player's saved transportation stone location and dimension. */
public void setStoneCircleLocation(BlockPos pos, int dimensionID){
this.stoneCircleLocation = pos;
this.stoneCircleDimension = dimensionID;
}
/** Returns the coordinates of the associated player's saved transportation stone circle. */
public BlockPos getStoneCircleLocation(){ return stoneCircleLocation; }
/** Returns the dimension ID of the associated player's saved transportation stone circle. */
public int getStoneCircleDimension(){ return stoneCircleDimension; }
public int getTpCountdown() { return tpCountdown; }
public void setTpCountdown(int tpCountdown) { this.tpCountdown = tpCountdown; }
/** Sets the player's saved clairvoyance location. */
public void setClairvoyancePoint(BlockPos pos, int dimensionID){
this.clairvoyanceLocation = pos;
this.clairvoyanceDimension = dimensionID;
}
/** Returns the coordinates for the saved clairvoyance location. Will be null if no location is saved. */
public BlockPos getClairvoyanceLocation(){ return clairvoyanceLocation; }
/** Returns the dimension ID for the saved clairvoyance location. Will be null if no location is saved. */
public int getClairvoyanceDimension(){ return clairvoyanceDimension; }
/** Overwrites the imbuement duration associated with the given imubement for this player, or creates it if there
* was none previously.
* @throws IllegalArgumentException if the given {@link Enchantment} is not an {@link Imbuement}. */
public void setImbuementDuration(Enchantment enchantment, int duration){
// It is best to throw an exception here, because otherwise the error would either go unnoticed (if non-imbuements
// were ignored) or cause a ClassCastException later (if non-imbuements were allowed to be added).
if(enchantment instanceof Imbuement){
this.imbuementDurations.put((Imbuement) enchantment, duration);
}else{
throw new IllegalArgumentException("Attempted to set an imbuement duration for something that isn't an Imbuement! (This exception has been thrown now to prevent a ClassCastException from occurring later.)");
}
}
/** Returns the imbuement duration associated with the given imbuement for this player, or 0 if it does not exist. */
public int getImbuementDuration(Enchantment enchantment){
// Need to check that i is not null, otherwise it throws an NPE when Java auto-unboxes it.
// What's nice here is that the map simply accepts objects as keys, so there's no need to cast or throw exceptions.
Integer i = this.imbuementDurations.get(enchantment);
// If i is null, returns 0; otherwise returns i, auto-unboxed to an int.
return i == null ? 0 : i;
}
/** Decrements the duration for each conjured item by 1, and removes from the map any that are 0 or less or that
* the player no longer has. Also deletes the item from the player's inventory if it runs out of time. */
private void updateImbuedItems(){
Set<Imbuement> activeImbuements = new HashSet<Imbuement>();
// For each item in the player's inventory
for(ItemStack stack : player.inventory.mainInventory){
if(stack != null && stack.isItemEnchanted()){
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(stack);
Iterator<Entry<Enchantment, Integer>> iterator = enchantments.entrySet().iterator();
// For each of the item's enchantments
while(iterator.hasNext()){
Enchantment enchantment = iterator.next().getKey();
// Ignores the enchantment unless it is an imbuement
if(enchantment instanceof Imbuement){
int duration = this.getImbuementDuration(enchantment);
// If the imbuement is still active:
if(duration > 0){
// Decrements the timer
this.imbuementDurations.put((Imbuement)enchantment, duration-1);
// Adds this imbuement to the set of imbuements that need to be kept
activeImbuements.add((Imbuement)enchantment);
// Otherwise:
}else{
// Removes the enchantment from the enchantment map
iterator.remove();
// Applies the new enchantment map to the item
EnchantmentHelper.setEnchantments(enchantments, stack);
}
}
}
}
}
// Removes all imbuements from the map that are no longer active
this.imbuementDurations.keySet().retainAll(activeImbuements);
}
/** Adds the given player to the list of allies belonging to the associated player, or removes the player if
* they are already in the list of allies. Returns true if the player was added, false if they were removed. */
public boolean toggleAlly(EntityPlayer player){
if(this.isPlayerAlly(player)){
this.allies.remove(player.getUniqueID());
// The remove method uses .equals() rather than == so this will work fine.
this.allyNames.remove(player.getName());
return false;
}else{
this.allies.add(player.getUniqueID());
this.allyNames.add(player.getName());
return true;
}
}
/** Returns whether the given player is in this player's list of allies, or is on the same team as this player. */
public boolean isPlayerAlly(EntityPlayer player){
return this.allies.contains(player.getUniqueID()) || this.player.isOnSameTeam(player);
}
/** Adds the given entity to this player's list of soulbound creatures, and returns whether it succeeded. */
public boolean soulbind(EntityLivingBase target){
return this.soulboundCreatures.add(target.getUniqueID());
}
/** Returns whether the given entity has been soulbound to this player. */
public boolean isCreatureSoulbound(EntityPlayer target){
return this.soulboundCreatures.contains(target.getUniqueID());
}
/** Damages all creatures soulbound to this player by the given amount, and removes from the list any that no
* longer exist. */
public void damageAllSoulboundCreatures(float damage){
for(Iterator<UUID> iterator = this.soulboundCreatures.iterator(); iterator.hasNext();){
Entity entity = WizardryUtilities.getEntityByUUID(this.player.worldObj, iterator.next());
if(entity == null) iterator.remove();
if(entity instanceof EntityLivingBase){
// Retaliatory effect
if(entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(this.player, DamageType.MAGIC, true), damage)){
// Sound only plays if the damage succeeds
player.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, player.worldObj.rand.nextFloat() * 0.2F + 1.0F);
}
}
}
}
/** Starts casting the given spell with the given modifiers. */
public void startCastingContinuousSpell(Spell spell, SpellModifiers modifiers){
this.currentlyCasting = spell;
this.spellModifiers = modifiers;
if(!this.player.worldObj.isRemote){
PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(),
spell.id(), this.spellModifiers);
WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.getDimension());
}
}
/** Stops casting the current spell. */
public void stopCastingContinuousSpell(){
this.currentlyCasting = Spells.none;
this.castingTick = 0;
this.spellModifiers.reset();
if(!this.player.worldObj.isRemote){
PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(),
Spells.none.id(), this.spellModifiers);
WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.getDimension());
}
}
/** Returns whether this player is currently casting a continuous spell via commands. */
public boolean isCasting(){
return this.currentlyCasting != null && this.currentlyCasting != Spells.none;
}
/** Returns the continuous spell this player is currently casting via commands, or the 'none' spell if they aren't
* casting anything. */
public Spell currentlyCasting(){
return currentlyCasting;
}
/** Called from the event handler each time the associated player is updated. */
public void update(){
if(this.selectedMinion != null && this.selectedMinion.get() == null) this.selectedMinion = null;
// This new system removes a lot of repetitive event handler code and inflexible variables which had duplicate
// functions, just for different enchantments.
updateImbuedItems();
if(!player.worldObj.isRemote){
if(getTpCountdown() == 1){
player.setPositionAndUpdate(this.stoneCircleLocation.getX() + 0.5, this.stoneCircleLocation.getY(),
this.stoneCircleLocation.getZ() + 0.5);
player.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 50, 0));
IMessage msg = new PacketTransportation.Message(player.getEntityId());
WizardryPacketHandler.net.sendToDimension(msg, player.worldObj.provider.getDimension());
}
if(getTpCountdown() > 0){
setTpCountdown(getTpCountdown() - 1);
}
}
if(this.currentlyCasting != null && this.currentlyCasting.isContinuous){
this.currentlyCasting.cast(player.worldObj, player, EnumHand.MAIN_HAND, castingTick++, this.spellModifiers);
}else{
this.castingTick = 0;
}
}
/**
* Returns the WizardData instance for the specified player.
*/
public static final WizardData get(EntityPlayer player){
return player.getCapability(WIZARD_DATA_CAPABILITY, null);
}
/** Called from the event handler each time the associated player entity is cloned, i.e. on respawn or when
* travelling to a different dimension. Used to copy over any variables that should persist over player death.
* This is the inverse of the old onPlayerDeath method, which reset the variables that shouldn't persist.
* @param data The old WizardData whose variables are to be copied over.
* @param respawn True if the player died and is respawning, false if they are just travelling between dimensions. */
public void copyFrom(WizardData data, boolean respawn){
// TODO: What happens with spirit wolf and spirit horse?
this.hasSpiritHorse = data.hasSpiritHorse;
this.hasSpiritWolf = data.hasSpiritWolf;
this.allies = data.allies;
this.allyNames = data.allyNames;
this.clairvoyanceDimension = data.clairvoyanceDimension;
this.clairvoyanceLocation = data.clairvoyanceLocation;
this.selectedMinion = data.selectedMinion;
// Curse of soulbinding is lifted when the caster dies, but not when they switch dimensions.
if(!respawn) this.soulboundCreatures = data.soulboundCreatures;
this.spellsDiscovered = data.spellsDiscovered;
this.stoneCircleDimension = data.stoneCircleDimension;
this.stoneCircleLocation = data.stoneCircleLocation;
// Imbuements are lost on death so their durations do not persist.
// Command spell casting is reset on death so the associated variables do not persist.
// tpCountdown is reset both when the player dies and when they switch dimensions.
}
/** Sends a packet to this player's client to synchronise necessary information. Only called server side. */
public void sync(){
if(this.player instanceof EntityPlayerMP){
int id = -1;
if(this.selectedMinion != null && this.selectedMinion.get() instanceof Entity) id = ((Entity)this.selectedMinion.get()).getEntityId();
IMessage msg = new PacketPlayerSync.Message(this.spellsDiscovered, id);
WizardryPacketHandler.net.sendTo(msg, (EntityPlayerMP)this.player);
}
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound properties = new NBTTagCompound();
// ...so Java 8 allows you to do stuff like this:
properties.setTag("imbuements", WizardryUtilities.mapToNBT(this.imbuementDurations,
imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new));
properties.setBoolean("hasSpiritWolf", this.hasSpiritWolf);
properties.setBoolean("hasSpiritHorse", this.hasSpiritHorse);
if(this.stoneCircleLocation != null) properties.setLong("stoneCircleLocation", this.stoneCircleLocation.toLong());
properties.setInteger("stoneCircleDimension", this.stoneCircleDimension);
properties.setInteger("tpCountdown", this.tpCountdown);
if(this.clairvoyanceLocation != null) properties.setLong("clairvoyanceLocation", this.clairvoyanceLocation.toLong());
properties.setInteger("clairvoyanceDimension", this.getClairvoyanceDimension());
// THIS is why I wrote the list/map <-> NBT methods. Look how neat this is!
properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound));
properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new));
properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound));
// Might be worth converting this over to WizardryUtilities.listToNBT.
int[] spells = new int[this.spellsDiscovered.size()];
int i=0;
for(Spell spell : this.spellsDiscovered){
spells[i] = spell.id();
i++;
}
properties.setIntArray("discoveredSpells", spells);
return properties;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
if(nbt != null){
this.imbuementDurations = WizardryUtilities.NBTToMap(nbt.getTagList("imbuements", NBT.TAG_COMPOUND),
(NBTTagInt tag) -> (Imbuement)Enchantment.getEnchantmentByID(tag.getInt()), NBTTagInt::getInt);
this.hasSpiritWolf = nbt.getBoolean("hasSpiritWolf");
this.hasSpiritHorse = nbt.getBoolean("hasSpiritHorse");
this.stoneCircleLocation = BlockPos.fromLong(nbt.getLong("stoneCircleLocation"));
this.stoneCircleDimension = nbt.getInteger("stoneCircleDimension");
this.tpCountdown = nbt.getInteger("tpCountdown");
this.clairvoyanceLocation = BlockPos.fromLong(nbt.getLong("clairvoyanceLocation"));
this.clairvoyanceDimension = nbt.getInteger("clairvoyanceDimension");
this.allies = new HashSet<UUID>(WizardryUtilities.NBTToList(nbt.getTagList("allies", NBT.TAG_COMPOUND),
WizardryUtilities::tagCompoundToUUID));
this.allyNames = new HashSet<String>(WizardryUtilities.NBTToList(nbt.getTagList("allyNames", NBT.TAG_STRING),
NBTTagString::getString));
this.soulboundCreatures = new HashSet<UUID>(WizardryUtilities.NBTToList(nbt.getTagList("soulboundCreatures", NBT.TAG_COMPOUND),
WizardryUtilities::tagCompoundToUUID));
this.spellsDiscovered = new HashSet<Spell>();
for(int id : nbt.getIntArray("discoveredSpells")){
spellsDiscovered.add(Spell.get(id));
}
}
}
/** This is a nested class for a few reasons: firstly, it makes sense because instances of this and WizardData go
* hand-in-hand; secondly, it's too short to be worth a separate file; and thirdly (and most importantly) it allows
* me to access WIZARD_DATA_CAPABILITY while keeping it private. */
public static class Provider implements ICapabilitySerializable<NBTTagCompound> {
private final WizardData data;
public Provider(EntityPlayer player){
data = new WizardData(player);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
return capability == WIZARD_DATA_CAPABILITY;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
if(capability == WIZARD_DATA_CAPABILITY){
return WIZARD_DATA_CAPABILITY.cast(data);
}
return null;
}
@Override
public NBTTagCompound serializeNBT() {
return data.serializeNBT();
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
data.deserializeNBT(nbt);
}
}
// Ended up deleting IWizardData because it was unnecessary. This is the comment that was at the start of it:
/* I'm not going to lie, I will never find the capabilities system even remotely intuitive so this is a bare-minimum
* approach just to get things working (four classes where one would have done?!) At one point I considered simply
* wrapping my old IEEP inside a single-field capability, but I eventually decided I would at least *try* to do it
* properly.
*
* "...without having to directly implement many interfaces." - Forge Docs. I still can't see what's wrong with
* implementing many interfaces; surely that's what Java interfaces are designed for?
*
* Other things I find annoying:
* - IStorage. It's completely redundant in the majority of cases, and I don't understand why we need yet another
* separate class.
* - Making an interface, only to implement it once and once only. This completely defeats the point of interfaces.
* - The EnumFacing parameter, which is again redundant for everything that isn't a tile entity. So much for a clean,
* neat system.
*
* What Forge has effectively done is conflated two different functions: attaching data to stuff and cross-mod
* integration/soft dependencies. I think this is bad design; it would have been better to keep the two features separate.
*
* Here's my current understanding of how the capability system works:
* - You make an interface which defines the things your capability can do (this class). I will call this the TEMPLATE.
* - You implement that interface with your default implementation (WizardData). This is the closest analog to your old
* IEEP implementation class. THIS CLASS STORES ALL THE VARIABLES, and hence has one instance for each instance of whatever
* it is attached to. I will call this the DATA.
* - The DATA class implements INBTSerializable (assuming you want it to be saved, which is nearly always the case)
* - Despite its name, Capability<T> does NOT represent a capability itself. Instead, it acts as a sort of identifier/key,
* the idea being that you can access a particular instance of your DATA given the key (which tells forge that you want a
* capability of type TEMPLATE) and the object you want the DATA for. This is what Entity.getCapability(...) does.
*
* To really understand what's going on though, you need to sift through Forge's verbose data structures and find where
* capabilities are actually hooked into vanilla:
* - Anything that implements ICapabilityProvider will have a private CapabilityDispatcher field. This holds other
* ICapabilityProviders. (I know. This inheritance pattern DOES NOT MAKE SENSE, because these could, in theory, be OTHER
* ENTITIES!)
* - This field is assigned a value through Forge's event factory, which, as we are all familiar with, calls all the
* methods marked with @SubscribeEvent. These methods add individual ICapabilityProviders to a Map stored in the event,
* which the event factory then wraps in a CapabilityDispatcher (which is itself an ICapabilityProvider) for the object
* that called it.
* - In your event handler, you return a custom ICapabilityProvider which is effectively bolted on to the player, and
* duplicates the ICapabilityProvider methods so you can hook into them and return an instance of your DATA class.
* - Where before there was a simple collection of IEEPs stored in the player, there is now a tree of ICapabilityProviders:
*
* - Entity/TileEntity/ItemStack
* - Vanilla ICapabilityProviders, mostly IItemHandlers, stored as fields.
* - CapabilityDispatcher, stored as a field.
* - Custom ICapabilityProviders
* - Custom CapabilityDispatchers
* - ...
*
* Most importantly, EACH PLAYER HOLDS THEIR OWN INSTANCE OF THIS TREE.
*
* When a capability is retrieved, the following process happens:
* 1. For the Entity/TileEntity/ItemStack instance, ICapabilityProvider.getCapability(...) is called.
* 2. The request propogates through the tree and finds the requested capability. */
}
@@ -0,0 +1,265 @@
package electroblob.wizardry;
import org.apache.logging.log4j.Logger;
import electroblob.wizardry.command.CommandCastSpell;
import electroblob.wizardry.command.CommandDiscoverSpell;
import electroblob.wizardry.command.CommandSetAlly;
import electroblob.wizardry.command.CommandViewAllies;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardryAchievements;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryRegistry;
import electroblob.wizardry.registry.WizardryTabs;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTBase;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.AchievementPage;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.Capability.IStorage;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry.Type;
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob." + Wizardry.MODID + ".WizardryGuiFactory")
public class Wizardry {
/** Wizardry's mod ID. */
public static final String MODID = "wizardry";
/** Wizardry's mod name, in readable form. */
public static final String NAME = "Electroblob's Wizardry";
/** The version number for this version of wizardry. The following system is used for version numbers:
* <p><center><b>[major Minecraft version].[major mod version].[minor mod version/patch]<p></center></b>
* 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 = "2.1.0";
// IDEA: Improve the algorithm that finds a place to summon creatures to take walls into account.
// IDEA: Replace all uses of Math.cos and Math.sin with MathHelper versions
// IDEA: API feature that automatically injects custom wand upgrades into wizardry's loot tables
// IDEA: Support for the @e selector in the /cast command (the methods already exist, just plug them in)
// IDEA: Dispensers shooting spells from scrolls! Imagine the possibilities!
// == Rendering overhaul! ==
// IDEA: Make spirit animals fade away when dispelled
// IDEA: Use your newfound knowledge of OpenGL to render animated boxes around entities being buffed, similar to creeper charge
// IDEA: Redo RenderArc so it looks like lightning (it's literally a load of translucent boxes inside each other)
// IDEA: The arcane workbench could use a few particles
// IDEA: Add a box to the wizard armour model so that the robes bend when the wearer is sneaking
// IDEA: Flash particle (I think it exists in vanilla somewhere) on spell impact
// IDEA: Dust particles spray out from projectiles as they move
// IDEA: Colour fading for particles
// IDEA: Make lightning and other effects particles. There's no reason why you can't pass in a player argument and have the particles move with them!
/* Minor bugs that need fixing at some point:
* - Player skin hat layer shows through wizard hats
* - Wizard armour breaks rather than just running out of mana (I can't seem to replicate this bug, but I have had
* it happen to me before...)
* - Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be
* transferred when it should be just one (this is a bug with vanilla as well - try putting a stack of bottles into
* a brewing stand). I have at least made it so only one gets used now, so it has no impact on the game.
* - When a spell is on cooldown, you can't break blocks when holding a wand. */
// FIXME: Wizardry enchantments appear on enchanted books in dungeon chests when they shouldn't.
// TODO: So somehow I have managed to overlook the fact that health is actually a float. What this means is that
// I can make the healing spells use damage multipliers - hurrah!
// TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.)
// TODO: Triggering of inbuilt Forge events in relevant places?
// TODO: Implement custom events
// TODO: Rearrange the config gui and file
// TODO: Have particles obey Minecraft's particle setting where appropriate
// (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java)
// NOTE: Add melee upgrades to loot tables when they are added.
/** Static instance of the {@link Settings} object for Wizardry. */
public static final Settings settings = new Settings();
/** Static instance of the {@link Logger} object for Wizardry. */
public static Logger logger;
//private static Pattern entityNamePattern;
// EventManager
WizardryWorldGenerator generator = new WizardryWorldGenerator();
// The instance of wizardry that Forge uses.
@Instance(Wizardry.MODID)
public static Wizardry instance;
// Location of the proxy code, used by Forge.
@SidedProxy(clientSide="electroblob.wizardry.client.ClientProxy", serverSide="electroblob.wizardry.CommonProxy")
public static CommonProxy proxy;
@EventHandler
public void preInit(FMLPreInitializationEvent event){
logger = event.getModLog();
// The array in question no longer exists, so I'm pretty sure this isn't necessary any more.
// expandPotionTypesArray();
settings.initConfig(event);
// Yes - by the looks of it, having an interface is completely unnecessary in this case.
CapabilityManager.INSTANCE.register(WizardData.class, new IStorage<WizardData>(){
// These methods are only called by Capability.writeNBT() or Capability.readNBT(), which in turn are
// NEVER CALLED. Unless I'm missing some reflective invocation, that means this entire class serves only
// to allow capabilities to be saved and loaded manually. What that would be useful for I don't know.
// (If an API forces most users to write redundant code for no reason, it's not user friendly, is it?)
// ... well, that's my rant for today!
@Override public NBTBase writeNBT(Capability<WizardData> capability, WizardData instance, EnumFacing side){ return null; }
@Override public void readNBT(Capability<WizardData> capability, WizardData instance, EnumFacing side, NBTBase nbt){}
}, WizardData.class);
WizardryRegistry.registerTileEntities();
WizardryRegistry.registerEntities(this);
// The check for the generateLoot setting is now done within this method.
WizardryRegistry.registerLoot();
// NOTE: Will need to be moved to init for 1.12, as will anything that needs to be after the registry events.
WizardryTabs.sort();
// Moved to preInit, because apparently it has to be here now.
proxy.registerRenderers();
}
@EventHandler
public void init(FMLInitializationEvent event){
settings.initConfigExtras();
proxy.registerKeyBindings();
// Event Handlers
GameRegistry.registerWorldGenerator(generator, 0);
MinecraftForge.EVENT_BUS.register(new WizardryKeyHandler());
MinecraftForge.EVENT_BUS.register(instance);
proxy.registerSpellHUD(); // This can't easily be converted to use the new @Mod.EventBusSubscriber system
NetworkRegistry.INSTANCE.registerGuiHandler(this, new WizardryGuiHandler());
WizardryPacketHandler.initPackets();
// Achievements
AchievementPage.registerAchievementPage(WizardryAchievements.WIZARDRY_ACHIEVEMENT_PAGE);
// Recipes
WizardryRegistry.registerRecipes();
proxy.initMixedFontRenderer();
}
@EventHandler
public void postInit(FMLPostInitializationEvent event){
// This needs to be here or it won't necessarily include all the mods' entities.
// TODO: Re-implement this when the Forge bug is fixed.
/* Doesn't seem to be doing anything...
String entityNames = "";
for(Object name : EntityList.classToStringMapping.values()){
if(name instanceof String){
entityNames = entityNames + name + '|';
}
}
// Cuts off the last '|'
entityNames = entityNames.substring(0, entityNames.length()-1);
entityNamePattern = Pattern.compile(entityNames);
*/
proxy.initialiseLayers();
}
@EventHandler
public void serverStarting(FMLServerStartingEvent event){
event.registerServerCommand(new CommandCastSpell());
event.registerServerCommand(new CommandSetAlly());
event.registerServerCommand(new CommandViewAllies());
event.registerServerCommand(new CommandDiscoverSpell());
}
@SubscribeEvent
public void onConfigChanged(net.minecraftforge.fml.client.event.ConfigChangedEvent.OnConfigChangedEvent event){
if(event.getModID().equals(Wizardry.MODID)){
settings.saveConfigChanges();
// All of the synchronised settings require a world restart anyway so this doesn't need syncing.
}
}
// 2.1 changed some item ids, so this fixes them for existing worlds
// NOTE: Needs changing to RegistryEvent.MissingMapping in 1.12, or just removing since nobody updates minecraft
// versions when using mods.
@EventHandler
public static void onMissingMappingEvent(FMLMissingMappingsEvent event){
// Just get, not getAll, since the mod id didn't change!
for(FMLMissingMappingsEvent.MissingMapping mapping : event.get()){
if(mapping.type == Type.ITEM && mapping.resourceLocation.getResourceDomain().equals(Wizardry.MODID)){
Item replacement = null;
switch(mapping.resourceLocation.getResourcePath()){
case "wand_basic": replacement = WizardryItems.magic_wand; break;
case "wand_basic_fire": replacement = WizardryItems.basic_fire_wand; break;
case "wand_basic_ice": replacement = WizardryItems.basic_ice_wand; break;
case "wand_basic_lightning": replacement = WizardryItems.basic_lightning_wand; break;
case "wand_basic_necromancy": replacement = WizardryItems.basic_necromancy_wand; break;
case "wand_basic_earth": replacement = WizardryItems.basic_earth_wand; break;
case "wand_basic_sorcery": replacement = WizardryItems.basic_sorcery_wand; break;
case "wand_basic_healing": replacement = WizardryItems.basic_healing_wand; break;
case "wand_apprentice": replacement = WizardryItems.apprentice_wand; break;
case "wand_apprentice_fire": replacement = WizardryItems.apprentice_fire_wand; break;
case "wand_apprentice_ice": replacement = WizardryItems.apprentice_ice_wand; break;
case "wand_apprentice_lightning": replacement = WizardryItems.apprentice_lightning_wand; break;
case "wand_apprentice_necromancy": replacement = WizardryItems.apprentice_necromancy_wand; break;
case "wand_apprentice_earth": replacement = WizardryItems.apprentice_earth_wand; break;
case "wand_apprentice_sorcery": replacement = WizardryItems.apprentice_sorcery_wand; break;
case "wand_apprentice_healing": replacement = WizardryItems.apprentice_healing_wand; break;
case "wand_advanced": replacement = WizardryItems.advanced_wand; break;
case "wand_advanced_fire": replacement = WizardryItems.advanced_fire_wand; break;
case "wand_advanced_ice": replacement = WizardryItems.advanced_ice_wand; break;
case "wand_advanced_lightning": replacement = WizardryItems.advanced_lightning_wand; break;
case "wand_advanced_necromancy": replacement = WizardryItems.advanced_necromancy_wand; break;
case "wand_advanced_earth": replacement = WizardryItems.advanced_earth_wand; break;
case "wand_advanced_sorcery": replacement = WizardryItems.advanced_sorcery_wand; break;
case "wand_advanced_healing": replacement = WizardryItems.advanced_healing_wand; break;
case "wand_master": replacement = WizardryItems.master_wand; break;
case "wand_master_fire": replacement = WizardryItems.master_fire_wand; break;
case "wand_master_ice": replacement = WizardryItems.master_ice_wand; break;
case "wand_master_lightning": replacement = WizardryItems.master_lightning_wand; break;
case "wand_master_necromancy": replacement = WizardryItems.master_necromancy_wand; break;
case "wand_master_earth": replacement = WizardryItems.master_earth_wand; break;
case "wand_master_sorcery": replacement = WizardryItems.master_sorcery_wand; break;
case "wand_master_healing": replacement = WizardryItems.master_healing_wand; break;
case "upgrade_storage": replacement = WizardryItems.storage_upgrade; break;
case "upgrade_siphon": replacement = WizardryItems.siphon_upgrade; break;
case "upgrade_condenser": replacement = WizardryItems.condenser_upgrade; break;
case "upgrade_range": replacement = WizardryItems.range_upgrade; break;
case "upgrade_duration": replacement = WizardryItems.duration_upgrade; break;
case "upgrade_cooldown": replacement = WizardryItems.cooldown_upgrade; break;
case "upgrade_blast": replacement = WizardryItems.blast_upgrade; break;
case "upgrade_attunement": replacement = WizardryItems.attunement_upgrade; break;
// If it didn't match any of the ones that changed, do nothing.
default: return;
}
// No need to log, Forge does that.
mapping.remap(replacement);
}
}
}
}
@@ -0,0 +1,938 @@
package electroblob.wizardry;
import java.util.List;
import java.util.Map;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.enchantment.Imbuement;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.entity.construct.EntityDecay;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.item.IConjuredItem;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.item.ItemWizardArmour;
import electroblob.wizardry.potion.ICustomPotionParticles;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryAchievements;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryEnchantments;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Clairvoyance;
import electroblob.wizardry.spell.FreezingWeapon;
import electroblob.wizardry.spell.Intimidate;
import electroblob.wizardry.spell.MindControl;
import electroblob.wizardry.spell.ShadowWard;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.IElementalDamage;
import electroblob.wizardry.util.IndirectMinionDamage;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.MinionDamage;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryParticleType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.passive.EntityPig;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.init.Blocks;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.ContainerPlayer;
import net.minecraft.inventory.ContainerWorkbench;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemBow;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.EntityDamageSourceIndirect;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraft.world.storage.loot.LootEntry;
import net.minecraft.world.storage.loot.LootEntryTable;
import net.minecraft.world.storage.loot.LootPool;
import net.minecraft.world.storage.loot.RandomValueRange;
import net.minecraft.world.storage.loot.conditions.LootCondition;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.LootTableLoadEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.EntityStruckByLightningEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.event.entity.player.BonemealEvent;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.BreakSpeed;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
// TODO: This class is waaaay too long. We need to either:
// - Split it into several separate handlers, each with a logical area to deal with
// - Remove most of the stuff, and have individual spell, item, block, entity, etc. classes handle their own events
// - Keep all the methods, but delegate near-repeated behaviours to their individual spell/potion/whatever classes
/**
* Wizardry's main event handler class for common code.
* @author Electroblob
* @since Wizardry 1.0
*/
@Mod.EventBusSubscriber
public final class WizardryEventHandler {
@SubscribeEvent
// The type parameter here has to be Entity, not EntityPlayer, or the event won't get fired.
public static void onCapabilityLoad(AttachCapabilitiesEvent<Entity> event){
if(event.getObject() instanceof EntityPlayer)
event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), new WizardData.Provider((EntityPlayer)event.getObject()));
// This demonstrates why capabilities are badly structured: The following code compiles, but what it does is put
// a player into a CapabilityDispatcher, which is in turn stored in that very same player, which makes no sense
// at all!
//event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), event.getObject());
}
@SubscribeEvent
public static void onPlayerCloneEvent(PlayerEvent.Clone event){
WizardData newData = WizardData.get(event.getEntityPlayer());
WizardData oldData = WizardData.get(event.getOriginal());
newData.copyFrom(oldData, event.isWasDeath());
}
@SubscribeEvent
public static void onWorldLoadEvent(WorldEvent.Load event){
if(!event.getWorld().isRemote && event.getWorld().provider.getDimension() == 0){
// Called to initialise the spell glyph data when a world loads, if it isn't already.
// NOTE: Do we actually need this, or can we just let it initialise the first time it is needed? (see below)
SpellGlyphData.get(event.getWorld());
}
}
// IDEA: Config option allowing users to specify loot locations
private static final String[] LOOT_INJECTION_LOCATIONS = {
"minecraft:chests/simple_dungeon",
"minecraft:chests/abandoned_mineshaft",
"minecraft:chests/desert_pyramid",
"minecraft:chests/jungle_temple",
"minecraft:chests/stronghold_corridor",
"minecraft:chests/stronghold_crossing",
"minecraft:chests/stronghold_library",
"minecraft:chests/igloo_chest"
};
@SubscribeEvent
public static void onLootTableLoadEvent(LootTableLoadEvent event){
if(Wizardry.settings.generateLoot){
for(String location : LOOT_INJECTION_LOCATIONS){
if(event.getName().toString().matches(location)){
event.getTable().addPool(getAdditive("wizardry:chests/dungeon_additions"));
}
}
}
}
private static LootPool getAdditive(String entryName){
return new LootPool(new LootEntry[] { getAdditiveEntry(entryName, 1) }, new LootCondition[0], new RandomValueRange(1), new RandomValueRange(0, 1), Wizardry.MODID + "_additive_pool");
}
private static LootEntryTable getAdditiveEntry(String name, int weight){
return new LootEntryTable(new ResourceLocation(name), weight, 0, new LootCondition[0], Wizardry.MODID + "_additive_entry");
}
/* There is a subtle but important difference between LivingAttackEvent and LivingHurtEvent - LivingAttackEvent
* fires immediately when attackEntityFrom is called, whereas LivingHurtEvent only fires if the attack actually
* succeeded, i.e. if the entity in question takes damage (though the event is fired before that so you can cancel
* the damage). Things are processed in the following order:
* * LivingAttackEvent *
* - Invulnerability
* - Already-dead-ness
* - Fire resistance
* - Helmets vs. falling things
* - Hurt resistant time
* - Invulnerability (again)
* * LivingHurtEvent *
* - Armour
* - Potions
* - Health is finally changed
* Of course, there are no guarantees that other mods hooking into these two events will be called before or after
* yours, but you can have some degree of control by choosing which event to use.
* EDIT: Actually, there are. Firstly, you can set a priority in the @SubscribeEvent annotation which defines how
* early (higher priority) or late (lower priority) the method is called. Methods with the same priority are sorted
* alphabetically by mod id (so it's safe to assume wizardry would be fairly late on!). I wonder if there are any
* conventions for what sort of things take what priority...? */
@SubscribeEvent
public static void onLivingAttackEvent(LivingAttackEvent event){
// Rather than bother overriding entire attack methods in ISummonedCreature implementations, it's easier (and
// more robust) to use LivingAttackEvent to modify the damage source.
if(event.getSource().getEntity() instanceof ISummonedCreature){
EntityLivingBase summoner = ((ISummonedCreature)event.getSource().getEntity()).getCaster();
if(summoner != null){
event.setCanceled(true);
DamageSource newSource = event.getSource();
// Copies over the original DamageType if appropriate.
DamageType type = event.getSource() instanceof IElementalDamage ? ((IElementalDamage)event.getSource()).getType() : DamageType.MAGIC;
// Copies over the original isRetaliatory flag if appropriate.
boolean isRetaliatory = event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).isRetaliatory();
// All summoned creatures are classified as magic, so it makes sense to do it this way.
if(event.getSource() instanceof EntityDamageSourceIndirect){
newSource = new IndirectMinionDamage(event.getSource().damageType, event.getSource().getSourceOfDamage(), event.getSource().getEntity(), summoner, type, isRetaliatory);
}else if(event.getSource() instanceof EntityDamageSource){
// Name is copied over so it uses the appropriate vanilla death message
newSource = new MinionDamage(event.getSource().damageType, event.getSource().getEntity(), summoner, type, isRetaliatory);
}
// Copy over any relevant 'attributes' the original DamageSource might have had.
if(event.getSource().isExplosion()) newSource.setExplosion();
if(event.getSource().isFireDamage()) newSource.setFireDamage();
if(event.getSource().isProjectile()) newSource.setProjectile();
// For some reason Minecraft calculates knockback relative to DamageSource#getEntity. In vanilla this
// is unnoticeable, but it looks a bit weird with summoned creatures involved - so let's fix that!
if(WizardryUtilities.attackEntityWithoutKnockback(event.getEntity(), newSource, event.getAmount())){
WizardryUtilities.applyStandardKnockback(event.getSource().getEntity(), event.getEntityLiving());
((ISummonedCreature)event.getSource().getEntity()).onSuccessfulAttack(event.getEntityLiving());
}
return;
}
}
// Prevents any damage to allies from magic if friendly fire is enabled
if(!Wizardry.settings.friendlyFire && event.getSource() != null && event.getSource().getEntity() instanceof EntityPlayer
&& event.getEntity() instanceof EntityPlayer && event.getSource() instanceof IElementalDamage){
if(WizardryUtilities.isPlayerAlly((EntityPlayer)event.getSource().getEntity(), (EntityPlayer)event.getEntity())){
event.setCanceled(true);
// I think this ought to be here, since if the event is cancelled nothing else needs to happen.
return;
}
}
if(event.getSource() instanceof IElementalDamage){
if(MagicDamage.isEntityImmune(((IElementalDamage)event.getSource()).getType(), event.getEntity())){
event.setCanceled(true);
// I would have liked to have done the 'resist' chat message here, but I overlooked the fact that I
// would need an instance of the spell to get its display name!
return;
}
// One convenient side effect of the new damage type system is that I can get rid of all the places where
// creepers are charged and just put them here under shock damage - this is precisely the sort of
// repetitive code I was trying to get rid of, since errors can (and did!) occur.
if(event.getEntityLiving() instanceof EntityCreeper && !((EntityCreeper)event.getEntityLiving()).getPowered()
&& ((IElementalDamage)event.getSource()).getType() == DamageType.SHOCK){
// Charges creepers when they are hit by shock damage
WizardryUtilities.chargeCreeper((EntityCreeper)event.getEntityLiving());
// Gives the player that caused the shock damage the 'It's Gonna Blow' achievement
if(event.getSource().getEntity() instanceof EntityPlayer){
((EntityPlayer)event.getSource().getEntity()).addStat(WizardryAchievements.charge_creeper);
}
}
}
// Bursts bubble when the creature inside takes damage
if(event.getEntityLiving().getRidingEntity() instanceof EntityBubble &&
!((EntityBubble)event.getEntityLiving().getRidingEntity()).isDarkOrb){
event.getEntityLiving().getRidingEntity().playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f);
event.getEntityLiving().getRidingEntity().setDead();
}
// Prevents all unblockable damage while transience is active
if(event.getEntityLiving().isPotionActive(WizardryPotions.transience) && event.getSource() != null && !event.getSource().isUnblockable()){
event.setCanceled(true);
// Again, I think this ought to be here, since if the event is cancelled nothing else needs to happen.
return;
}
if(event.getSource() != null && event.getSource().getEntity() instanceof EntityLivingBase){
// Cancels the mind trick effect if the creature takes damage
// This has been moved to within the (event.getSource().getEntity() instanceof EntityLivingBase) check so it doesn't
// crash the game with a ConcurrentModificationException. If you think about it, mind trick only ought to be
// cancelled if something attacks the entity since potions, drowning, cacti etc. don't affect the targeting.
if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_trick)){
event.getEntityLiving().removePotionEffect(WizardryPotions.mind_trick);
}
// 'Revenge' effects
EntityLivingBase attacker = (EntityLivingBase)event.getSource().getEntity();
World world = event.getEntityLiving().worldObj;
if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin) && !event.getSource().isProjectile()){
if(!MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving())) attacker.setFire(5);
}
if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud) && !event.getSource().isProjectile()){
if(!MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
attacker.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0));
}
if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura) && !event.getSource().isProjectile()){
if(!world.isRemote){
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(event.getEntityLiving().posX, event.getEntityLiving().posY + 1, event.getEntityLiving().posZ,
attacker.posX, attacker.posY + attacker.height/2, attacker.posZ);
world.spawnEntityInWorld(arc);
}else{
for(int i=0;i<8;i++){
Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, attacker.posX + world.rand.nextFloat() - 0.5, attacker.getEntityBoundingBox().minY + attacker.height/2 + world.rand.nextFloat()*2 - 1, attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3);
world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, attacker.posX + world.rand.nextFloat() - 0.5, attacker.getEntityBoundingBox().minY + attacker.height/2 + world.rand.nextFloat()*2 - 1, attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0);
}
}
attacker.attackEntityFrom(MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.SHOCK, true), 4.0f);
attacker.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F);
}
// Shadow ward
if(event.getEntityLiving() instanceof EntityPlayer){
ItemStack wand = event.getEntityLiving().getActiveItemStack();
if(wand != null && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand
&& WandHelper.getCurrentSpell(wand) instanceof ShadowWard && !event.getSource().isUnblockable()){
event.setCanceled(true);
// This DamageSource.magic and not event.getSource() because the latter would cause an infinite loop.
event.getEntityLiving().attackEntityFrom(DamageSource.magic, event.getAmount()/2);
attacker.attackEntityFrom(MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.MAGIC, true), event.getAmount()/2);
}
}
// Transience
if(attacker.isPotionActive(WizardryPotions.transience)){
event.setCanceled(true);
}
}
}
@SubscribeEvent
public static void onLivingHurtEvent(LivingHurtEvent event){
// Curse of soulbinding
if(!event.getEntity().worldObj.isRemote && event.getEntityLiving() instanceof EntityPlayer && !event.getSource().isUnblockable()){
WizardData properties = WizardData.get((EntityPlayer)event.getEntityLiving());
if(properties != null){
properties.damageAllSoulboundCreatures(event.getAmount());
}
}
// Flaming and freezing swords
if(event.getSource().getEntity() instanceof EntityLivingBase){
EntityLivingBase attacker = (EntityLivingBase)event.getSource().getEntity();
// Players can only ever attack with their main hand, so this is the right method to use here.
if(attacker.getHeldItemMainhand() != null && attacker.getHeldItemMainhand().getItem() instanceof ItemSword){
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, attacker.getHeldItemMainhand());
if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving()))
event.getEntityLiving().setFire(level*4);
level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, attacker.getHeldItemMainhand());
// Frost lasts for longer because it doesn't do any actual damage
if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, level*200, 0));
}
}
// Freezing bow
if(event.getSource().getSourceOfDamage() instanceof EntityArrow && event.getSource().getSourceOfDamage().getEntityData() != null){
int level = event.getSource().getSourceOfDamage().getEntityData().getInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY);
if(level > 0 && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, level*150, 0));
}
// Damage scaling
if(event.getSource() != null && event.getSource() instanceof IElementalDamage){
if(event.getSource().getEntity() instanceof EntityPlayer){
event.setAmount((float)(event.getAmount() * Wizardry.settings.playerDamageScale));
}else{
event.setAmount((float)(event.getAmount() * Wizardry.settings.npcDamageScale));
}
}
}
@SubscribeEvent
public static void onBlockPlaceEvent(BlockEvent.PlaceEvent event){
if(event.getPlayer().isPotionActive(WizardryPotions.transience)){
event.setCanceled(true);
return;
}
// Spectral blocks cannot be built on
if(event.getPlacedAgainst() == WizardryBlocks.spectral_block){
event.setCanceled(true);
return;
}
}
@SubscribeEvent
public static void onBlockBreakEvent(BlockEvent.BreakEvent event){
if(event.getPlayer().isPotionActive(WizardryPotions.transience)){
event.setCanceled(true);
return;
}
// Makes wizards angry if a player breaks a block in their tower
if(!(event.getPlayer() instanceof FakePlayer)){
List<EntityWizard> wizards = WizardryUtilities.getEntitiesWithinRadius(64, event.getPos().getX(),
event.getPos().getY(), event.getPos().getZ(), event.getWorld(), EntityWizard.class);
if(!wizards.isEmpty()){
for(EntityWizard wizard : wizards){
if(wizard.isBlockPartOfTower(event.getPos())){
wizard.setRevengeTarget(event.getPlayer());
event.getPlayer().addStat(WizardryAchievements.anger_wizard);
}
}
}
}
}
@SubscribeEvent
public static void onEntityStruckByLightningEvent(EntityStruckByLightningEvent event){
if(event.getLightning().getEntityData() != null && event.getLightning().getEntityData().hasKey("summoningPlayer")){
EntityPlayer player = (EntityPlayer)WizardryUtilities.getEntityByUUID(event.getLightning().worldObj, event.getLightning().getEntityData().getUniqueId("summoningPlayer"));
if(event.getEntity() instanceof EntityCreeper){
player.addStat(WizardryAchievements.charge_creeper);
}
if(event.getEntity() instanceof EntityPig){
player.addStat(WizardryAchievements.frankenstein);
}
}
}
@SubscribeEvent
public static void onLivingUpdateEvent(LivingUpdateEvent event){
// TODO: Move the player stuff to a PlayerTickEvent and separate methods out for clarity
if(event.getEntityLiving() instanceof EntityPlayer){
EntityPlayer entityplayer = (EntityPlayer)event.getEntityLiving();
if(WizardData.get(entityplayer) != null){
WizardData.get(entityplayer).update();
}
if(entityplayer.openContainer instanceof ContainerWorkbench){
craftingTableTick(entityplayer);
}
if(entityplayer.openContainer instanceof ContainerPlayer){
// 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.
playerInventoryTick(entityplayer);
}
testForArmourSet:{
for(ItemStack stack : entityplayer.getArmorInventoryList()){
if(stack == null || !(stack.getItem() instanceof ItemWizardArmour)){
break testForArmourSet;
}
}
entityplayer.addStat(WizardryAchievements.armour_set);
}
}
if(event.getEntityLiving().worldObj.isRemote){
// Behold the power of interfaces! TODO: Backport.
for(PotionEffect effect : event.getEntityLiving().getActivePotionEffects()){
if(effect.getPotion() instanceof ICustomPotionParticles && effect.doesShowParticles()){
double x = event.getEntityLiving().posX + (event.getEntityLiving().worldObj.rand.nextDouble() - 0.5)*event.getEntityLiving().width;
double y = event.getEntityLiving().getEntityBoundingBox().minY + event.getEntityLiving().worldObj.rand.nextDouble()*event.getEntityLiving().height;
double z = event.getEntityLiving().posZ + (event.getEntityLiving().worldObj.rand.nextDouble() - 0.5)*event.getEntityLiving().width;
((ICustomPotionParticles)effect.getPotion()).spawnCustomParticle(event.getEntityLiving().worldObj, x, y, z);
}
}
// Client-side continuous spell casting for NPCs
if(event.getEntity() instanceof ISpellCaster && event.getEntity() instanceof EntityLiving){
Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell();
if(spell != null && spell != Spells.none){
spell.cast(event.getEntity().worldObj, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0,
// TODO: This implementation of modifiers relies on them being accessible client-side.
((EntityLiving)event.getEntity()).getAttackTarget(), ((ISpellCaster)event.getEntity()).getModifiers());
}
}
}else{
if(event.getEntityLiving().isPotionActive(WizardryPotions.decay) && event.getEntityLiving().onGround && event.getEntityLiving().ticksExisted % Constants.DECAY_SPREAD_INTERVAL == 0){
List<Entity> list = event.getEntityLiving().worldObj.getEntitiesWithinAABBExcludingEntity(event.getEntityLiving(), event.getEntityLiving().getEntityBoundingBox());
boolean flag = true;
for(Object object : list){
if(object instanceof EntityDecay) flag = false;
}
if(flag){
// The victim spreading the decay is the 'caster' here, so that it can actually wear off, otherwise it just gets infected with its own decay and the effect lasts forever.
event.getEntityLiving().worldObj.spawnEntityInWorld(new EntityDecay(event.getEntityLiving().worldObj, event.getEntityLiving().posX, event.getEntityLiving().posY, event.getEntityLiving().posZ, event.getEntityLiving()));
}
}
}
// Mind Control
// This was added because something got changed in the AI classes which means LivingSetAttackTargetEvent doesn't
// get fired when I want it to... so I'm firing it myself.
if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_control) && event.getEntityLiving() instanceof EntityLiving
&& ((EntityLiving)event.getEntityLiving()).getAttackTarget() != null
&& !((EntityLiving)event.getEntityLiving()).getAttackTarget().isEntityAlive())
((EntityLiving)event.getEntityLiving()).setAttackTarget(null); // Causes the event to be fired
/* Old AI no longer exists!
// Mind trick
if(event.getEntityLiving().isPotionActive(Wizardry.mindTrick) && event.getEntityLiving() instanceof EntityLiving){
// Old AI (this can't be done in onLivingSetAttackTargetEvent because that only fires for the new AI).
if(event.getEntityLiving() instanceof EntityCreature) ((EntityCreature)event.getEntityLiving()).setTarget(null);
}
// Mind control - old AI (this can't be done in onLivingSetAttackTargetEvent because that only fires for the new AI).
mindcontrol:
if(event.getEntityLiving().isPotionActive(Wizardry.mindControl) && event.getEntityLiving() instanceof EntityLiving){
NBTTagCompound entityNBT = event.getEntityLiving().getEntityData();
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){
Entity caster = WizardryUtilities.getEntityByUUID(event.getEntity().worldObj, UUID.fromString(entityNBT.getString(MindControl.NBT_KEY)));
if(caster instanceof EntityLivingBase){
if(MindControl.findMindControlTarget((EntityLiving)event.getEntityLiving(), (EntityLivingBase)caster, event.getEntity().worldObj)){
// If it worked, skip setting the target to null.
break mindcontrol;
}
}
}
// If the caster couldn't be found or no valid target was found, this just acts like mind trick.
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
*/
// Intimidate
if(event.getEntityLiving().isPotionActive(WizardryPotions.fear) && event.getEntityLiving() instanceof EntityCreature){
NBTTagCompound entityNBT = event.getEntityLiving().getEntityData();
EntityCreature creature = (EntityCreature)event.getEntityLiving();
if(entityNBT != null && entityNBT.hasKey(Intimidate.NBT_KEY)){
Entity caster = WizardryUtilities.getEntityByUUID(creature.worldObj, entityNBT.getUniqueId(Intimidate.NBT_KEY));
if(caster instanceof EntityLivingBase){
Intimidate.runAway(creature, (EntityLivingBase)caster);
}
}
}
}
@SubscribeEvent
public static void onBreakSpeedEvent(BreakSpeed event){
if(event.getEntityPlayer().isPotionActive(WizardryPotions.frost)){
// Amplifier + 1 because it starts at 0
event.setNewSpeed(event.getOriginalSpeed() * (1 - Constants.FROST_FATIGUE_PER_LEVEL*(event.getEntityPlayer().getActivePotionEffect(WizardryPotions.frost).getAmplifier() + 1)));
}
}
private static void playerInventoryTick(EntityPlayer player) {
// Charges wand using mana flask. It is here rather than in the crafting handler so the result displays
// the proper damage before it is actually crafted.
boolean flag = false;
ItemStack wand = null;
ItemStack armour = null;
IInventory craftMatrix = ((ContainerPlayer)player.openContainer).craftMatrix;
ItemStack outputItem = ((ContainerPlayer)player.openContainer).craftResult.getStackInSlot(0);
for(int i = 0; i < craftMatrix.getSizeInventory(); i++){
if(craftMatrix.getStackInSlot(i) != null){
ItemStack itemstack = craftMatrix.getStackInSlot(i);
if(itemstack.getItem() == WizardryItems.mana_flask){
flag = true;
}
if(itemstack.getItem() instanceof ItemWand){
wand = itemstack;
}
if(itemstack.getItem() instanceof ItemWizardArmour){
armour = itemstack;
}
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWand && flag && wand != null){
outputItem.setTagCompound((wand.getTagCompound()));
if(wand.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWizardArmour && flag && armour != null){
outputItem.setTagCompound((armour.getTagCompound()));
if(armour.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
}
private static void craftingTableTick(EntityPlayer player) {
// Charges wand using mana flask. It is here rather than in the crafting handler so the result displays
// the proper damage before it is actually crafted.
boolean flag = false;
ItemStack wand = null;
ItemStack armour = null;
IInventory craftMatrix = ((ContainerWorkbench)player.openContainer).craftMatrix;
ItemStack outputItem = ((ContainerWorkbench)player.openContainer).craftResult.getStackInSlot(0);
for (int i = 0; i < craftMatrix.getSizeInventory(); i++){
if(craftMatrix.getStackInSlot(i) != null){
ItemStack itemstack = craftMatrix.getStackInSlot(i);
if(itemstack.getItem() == WizardryItems.mana_flask){
flag = true;
}
if(itemstack.getItem() instanceof ItemWand){
wand = itemstack;
}
if(itemstack.getItem() instanceof ItemWizardArmour){
armour = itemstack;
}
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWand && flag && wand != null){
outputItem.setTagCompound((wand.getTagCompound()));
if(wand.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
if(outputItem != null && outputItem.getItem() instanceof ItemWizardArmour && flag && armour != null){
outputItem.setTagCompound((armour.getTagCompound()));
if(armour.getItemDamage()-Constants.MANA_PER_FLASK < 0){
outputItem.setItemDamage(0);
}else{
outputItem.setItemDamage(wand.getItemDamage()-Constants.MANA_PER_FLASK);
}
}
}
@SubscribeEvent
public static void onLivingDeathEvent(LivingDeathEvent event){
if(event.getSource().getEntity() instanceof EntityPlayer){
EntityPlayer player = (EntityPlayer)event.getSource().getEntity();
for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){
if(stack != null && stack.getItem() instanceof ItemWand && stack.isItemDamaged() && WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) > 0){
int damage = stack.getItemDamage() - Constants.SIPHON_MANA_PER_LEVEL*WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) - player.worldObj.rand.nextInt(Constants.SIPHON_MANA_PER_LEVEL);
if(damage < 0) damage = 0;
stack.setItemDamage(damage);
break;
}
}
if(event.getEntityLiving() == player && event.getSource() instanceof IElementalDamage){
player.addStat(WizardryAchievements.self_destruct);
}
}
}
@SubscribeEvent
public static void onPlayerLoggedInEvent(PlayerLoggedInEvent event){
// When a player logs in, they are sent the glyph data and the server's settings.
if(event.player instanceof EntityPlayerMP){
SpellGlyphData.get(event.player.worldObj).sync((EntityPlayerMP)event.player);
Wizardry.settings.sync((EntityPlayerMP)event.player);
}
}
@SubscribeEvent
public static void onEntityJoinWorld(EntityJoinWorldEvent event){
if(!event.getEntity().worldObj.isRemote && event.getEntity() instanceof EntityPlayerMP){
// Synchronises wizard data after loading.
WizardData data = WizardData.get((EntityPlayer)event.getEntity());
if(data != null) data.sync();
}
// Rather long-winded (but necessary) way of getting an arrow just after it has been fired, checking if the bow
// that fired it has the imbuement enchantment, and applying extra damage accordingly.
if(!event.getEntity().worldObj.isRemote && event.getEntity() instanceof EntityArrow){
EntityArrow arrow = (EntityArrow)event.getEntity();
magicBow:
if(arrow.shootingEntity instanceof EntityLivingBase){
EntityLivingBase archer = (EntityLivingBase)arrow.shootingEntity;
ItemStack bow = archer.getHeldItemMainhand();
if(bow == null || !(bow.getItem() instanceof ItemBow)){
bow = archer.getHeldItemOffhand();
// Break used because return would skip the entire method, bypassing anything that might be added
// further down.
if(bow == null || !(bow.getItem() instanceof ItemBow)) break magicBow;
}
// Taken directly from ItemBow, so it works exactly the same as the power enchantment.
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.magic_bow, bow);
if(level > 0){
arrow.setDamage(arrow.getDamage() + (double)level * 0.5D + 0.5D);
}
if(EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, bow) > 0){
// Again, this is exactly what happens in ItemBow (flame is flame; level does nothing).
arrow.setFire(100);
}
level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, bow);
if(level > 0){
if(arrow.getEntityData() != null){
arrow.getEntityData().setInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY, level);
}
}
}
}
}
@SubscribeEvent
public static void onLivingDropsEvent(LivingDropsEvent event){
// TODO: Really, this should be in a loot table (mob_additions), however I can't seem to find a way of
// automatically adding it to all subclasses of IMob.
// Evil wizards drop spell books themselves
if(event.getEntityLiving() instanceof IMob && !(event.getEntityLiving() instanceof EntityEvilWizard)
// TODO: Backport when you backport the new summoned creature system.
&& !(event.getEntityLiving() instanceof ISummonedCreature) && event.getSource().getEntity() instanceof EntityPlayer
&& Wizardry.settings.spellBookDropChance > 0){
// This does exactly what the entity drop method does, but with a different random number so that the
// spell book doesn't always drop with other rare drops.
int rareDropNumber = event.getEntity().worldObj.rand.nextInt(200) - event.getLootingLevel();
if(rareDropNumber < Wizardry.settings.spellBookDropChance){
// Drops a spell book
int id = WizardryUtilities.getStandardWeightedRandomSpellId(event.getEntity().worldObj.rand);
event.getDrops().add(new EntityItem(event.getEntityLiving().worldObj, event.getEntityLiving().posX, event.getEntityLiving().posY, event.getEntityLiving().posZ,
new ItemStack(WizardryItems.spell_book, 1, id)));
}
}
for(EntityItem item : event.getDrops()){
// Destroys conjured items if their caster dies.
if(item.getEntityItem().getItem() instanceof IConjuredItem){
item.setDead();
}
// Instantly disenchants an imbued weapon if it is dropped when the player dies.
if(item.getEntityItem().isItemEnchanted()){
// No need to check what enchantments the item has, since remove() does nothing if the element does not exist.
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(item.getEntityItem());
// Removes the magic weapon enchantments from the enchantment map
// An excellent demonstration of the usefulness of both interfaces and Java 8.
enchantments.entrySet().removeIf(entry -> entry.getKey() instanceof Imbuement);
// Applies the new enchantment map to the item
EnchantmentHelper.setEnchantments(enchantments, item.getEntityItem());
}
}
}
@SubscribeEvent
public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){
// Mind trick
// If the target is null already, no need to set it to null, or infinite loops will occur.
if((event.getEntityLiving().isPotionActive(WizardryPotions.mind_trick) || event.getEntityLiving().isPotionActive(WizardryPotions.fear)) && event.getEntityLiving() instanceof EntityLiving && event.getTarget() != null){
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
// Mind control
mindcontrol:
if(event.getEntityLiving().isPotionActive(WizardryPotions.mind_control) && event.getEntityLiving() instanceof EntityLiving){
NBTTagCompound entityNBT = event.getEntityLiving().getEntityData();
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY + "Most")){
Entity caster = WizardryUtilities.getEntityByUUID(event.getEntity().worldObj, entityNBT.getUniqueId(MindControl.NBT_KEY));
// If the target that the event tried to set is already a valid mind control target, nothing happens.
if(event.getTarget() != null && WizardryUtilities.isValidTarget(caster, event.getTarget())) break mindcontrol;
if(caster instanceof EntityLivingBase){
if(MindControl.findMindControlTarget((EntityLiving)event.getEntityLiving(), (EntityLivingBase)caster, event.getEntity().worldObj)){
// If it worked, skip setting the target to null.
break mindcontrol;
}
}
}
// If the caster couldn't be found or no valid target was found, this just acts like mind trick.
// If the target is null already, no need to set it to null, or infinite loops will occur.
if(event.getTarget() != null) ((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
}
}
@SubscribeEvent
public static void onItemPickupEvent(EntityItemPickupEvent event){
if(event.getItem().getEntityItem().getItem() == WizardryItems.magic_crystal){
event.getEntityPlayer().addStat(WizardryAchievements.crystal, 1);
}
}
@SubscribeEvent
public static void onItemTossEvent(ItemTossEvent event){
// Prevents conjured items being thrown by dragging and dropping outside the inventory.
if(event.getEntityItem().getEntityItem().getItem() instanceof IConjuredItem){
event.setCanceled(true);
event.getPlayer().inventory.addItemStackToInventory(event.getEntityItem().getEntityItem());
}
// Instantly disenchants an imbued weapon if it is thrown on the ground.
if(event.getEntityItem().getEntityItem().isItemEnchanted()){
// No need to check what enchantments the item has, since remove() does nothing if the element does not exist.
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(event.getEntityItem().getEntityItem());
// Removes the magic weapon enchantments from the enchantment map
enchantments.entrySet().removeIf(entry -> entry.getKey() instanceof Imbuement);
// Applies the new enchantment map to the item
EnchantmentHelper.setEnchantments(enchantments, event.getEntityItem().getEntityItem());
}
}
@SubscribeEvent
public static void onRightClickBlockEvent(PlayerInteractEvent.RightClickBlock event){
if(event.getEntityPlayer().isSneaking()){
// The event now has an ItemStack, which greatly simplifies hand-related stuff.
ItemStack wand = event.getItemStack();
if(wand != null && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Clairvoyance){
WizardData properties = WizardData.get(event.getEntityPlayer());
if(properties != null){
// THIS is why BlockPos is a thing - in 1.7.10 this requires a clumsy switch statement.
BlockPos pos = event.getPos().offset(event.getFace());
properties.setClairvoyancePoint(pos, event.getWorld().provider.getDimension());
if(!event.getWorld().isRemote){
event.getEntityPlayer().addChatMessage(new TextComponentTranslation("spell.clairvoyance.confirm", Spells.clairvoyance.getNameForTranslationFormatted()));
}
event.setCanceled(true);
}
}
}
}
@SubscribeEvent
public static void onBonemealEvent(BonemealEvent event){
// Grows crystal flowers when bonemeal is used on grass
if(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),
event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8));
if (event.getWorld().isAirBlock(new BlockPos(pos)) && (!event.getWorld().provider.getHasNoSky() || pos.getY() < 127) && WizardryBlocks.crystal_flower.canPlaceBlockAt(event.getWorld(), pos))
{
event.getWorld().setBlockState(pos, WizardryBlocks.crystal_flower.getDefaultState(), 2);
}
}
}
}
@@ -0,0 +1,36 @@
package electroblob.wizardry;
import java.util.Set;
import electroblob.wizardry.client.GuiConfigWizardry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.IModGuiFactory;
public class WizardryGuiFactory implements IModGuiFactory {
@Override
public void initialize(Minecraft minecraftInstance)
{
}
@Override
public Class<? extends GuiScreen> mainConfigGuiClass()
{
return GuiConfigWizardry.class;
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories()
{
return null;
}
@SuppressWarnings("deprecation") // It's a bit of Forge that hasn't been tidied up, but we have to implement it.
@Override
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element)
{
return null;
}
}
@@ -0,0 +1,66 @@
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;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.IGuiHandler;
public class WizardryGuiHandler implements IGuiHandler {
/** Incrementable index for the gui ID */
private static int nextGuiId = 0;
public static final int SPELL_BOOK = nextGuiId++;
public static final int ARCANE_WORKBENCH = nextGuiId++;
public static final int WIZARD_HANDBOOK = nextGuiId++;
public static final int PORTABLE_CRAFTING = nextGuiId++;
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
if(id == ARCANE_WORKBENCH){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityArcaneWorkbench){
return new ContainerArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity);
}
}
else if(id == PORTABLE_CRAFTING){
return new ContainerPortableWorkbench(player.inventory, world, new BlockPos(x, y, z));
}
return null;
}
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
if(id == ARCANE_WORKBENCH){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityArcaneWorkbench){
return new electroblob.wizardry.client.GuiArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity);
}
}
else if(id == WIZARD_HANDBOOK
&& ((player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook)
|| (player.getHeldItemOffhand() != null && player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook))){
return new electroblob.wizardry.client.GuiWizardHandbook();
}
else if(id == SPELL_BOOK){
if(player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage()));
}else if(player.getHeldItemOffhand() != null && player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemOffhand().getItemDamage()));
}
}
else if(id == PORTABLE_CRAFTING){
return new electroblob.wizardry.client.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
}
return null;
}
}
@@ -0,0 +1,67 @@
package electroblob.wizardry;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.client.ClientProxy;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class WizardryKeyHandler {
boolean NkeyPressed = false;
boolean BkeyPressed = false;
boolean NkeyAlreadyPressed = false;
boolean BkeyAlreadyPressed = false;
@SubscribeEvent
public void onKeyInput(InputEvent.KeyInputEvent event) {
// Key pressed
if(Keyboard.getEventKeyState()){
if(Wizardry.proxy instanceof ClientProxy){
if(ClientProxy.NEXT_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){
if(!NkeyPressed){
NkeyPressed = true;
}else{
NkeyAlreadyPressed = true;
}
if(!NkeyAlreadyPressed){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}
}
if(ClientProxy.PREVIOUS_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){
if(!BkeyPressed){
BkeyPressed = true;
}else{
BkeyAlreadyPressed = true;
}
if(!BkeyAlreadyPressed){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
}
// Key released
else{
if(NkeyPressed){
NkeyPressed = false;
NkeyAlreadyPressed = false;
}else if(BkeyPressed){
BkeyPressed = false;
BkeyAlreadyPressed = false;
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,120 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockArcaneWorkbench extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D);
public BlockArcaneWorkbench(){
super(Material.ROCK);
this.setLightLevel(0.8f);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityArcaneWorkbench();
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return false;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player,
EnumHand hand, ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity == null || player.isSneaking()){
return false;
}
player.openGui(Wizardry.instance, WizardryGuiHandler.ARCANE_WORKBENCH, world, pos.getX(), pos.getY(), pos.getZ());
return true;
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState block)
{
Random random = new Random();
TileEntityArcaneWorkbench tileentityarcaneworkbench = (TileEntityArcaneWorkbench)world.getTileEntity(pos);
if (tileentityarcaneworkbench != null)
{
for (int j1 = 0; j1 < tileentityarcaneworkbench.getSizeInventory(); ++j1)
{
ItemStack itemstack = tileentityarcaneworkbench.getStackInSlot(j1);
if (itemstack != null)
{
float f = random.nextFloat() * 0.8F + 0.1F;
float f1 = random.nextFloat() * 0.8F + 0.1F;
EntityItem entityitem;
for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; world.spawnEntityInWorld(entityitem))
{
int k1 = random.nextInt(21) + 10;
if (k1 > itemstack.stackSize)
{
k1 = itemstack.stackSize;
}
itemstack.stackSize -= k1;
entityitem = new EntityItem(world, (double)((float)pos.getX() + f), (double)((float)pos.getY() + f1), (double)((float)pos.getZ() + f2), new ItemStack(itemstack.getItem(), k1, itemstack.getItemDamage()));
float f3 = 0.05F;
entityitem.motionX = (double)((float)random.nextGaussian() * f3);
entityitem.motionY = (double)((float)random.nextGaussian() * f3 + 0.2F);
entityitem.motionZ = (double)((float)random.nextGaussian() * f3);
if (itemstack.hasTagCompound())
{
entityitem.getEntityItem().setTagCompound(((NBTTagCompound)itemstack.getTagCompound().copy()));
}
}
}
}
//par1World.func_96440_m(par2, par3, par4, block);
}
super.breakBlock(world, pos, block);
}
}
@@ -0,0 +1,46 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.BlockBush;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.EnumPlantType;
// Extending BlockBush allows me to remove nearly everything from this class.
public class BlockCrystalFlower extends BlockBush {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.5F - 0.2f, 0.0F, 0.5F - 0.2f, 0.5F + 0.2f, 0.2f * 3.0F, 0.5F + 0.2f);
public BlockCrystalFlower(Material par2Material) {
super(par2Material);
this.setLightLevel(0.5f);
this.setTickRandomly(true);
this.setSoundType(SoundType.PLANT);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
{
return AABB;
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
if(world.isRemote && random.nextBoolean()){
Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, pos.getX()+random.nextDouble(), pos.getY()+random.nextDouble()/2+0.5, pos.getZ()+random.nextDouble(), 0d, 0.01, 0d, 20 + random.nextInt(10), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2));
}
}
@Override
public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) {
return EnumPlantType.Plains;
}
}
@@ -0,0 +1,35 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
public class BlockCrystalOre extends Block {
public BlockCrystalOre(Material material) {
super(material);
this.setSoundType(SoundType.STONE);
setResistance(5.0F);
setHarvestLevel("pickaxe", 2);
}
@Override
public int quantityDropped(IBlockState state, int fortune, Random random)
{
if(fortune > 0){
return random.nextInt(2) + 1 + random.nextInt(fortune);
}else{
return random.nextInt(2) + 1;
}
}
@Override
public Item getItemDropped(IBlockState state, Random random, int fortune){
return WizardryItems.magic_crystal;
}
}
@@ -0,0 +1,58 @@
package electroblob.wizardry.block;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockMagicLight extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
public BlockMagicLight(Material par2Material) {
super(par2Material);
this.setLightLevel(1.0f);
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos){
// The other two bounding box methods in Block aren't nullable, so this is the only one that can return NULL_AABB.
return NULL_AABB;
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public boolean isCollidable(){
return false;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityMagicLight(600);
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) {
return false;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state) {
return EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
}
}
@@ -0,0 +1,110 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.tileentity.TileEntityPlayerSave;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.MobEffects;
import net.minecraft.item.Item;
import net.minecraft.potion.PotionEffect;
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.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
// TODO: Apparently you shouldn't extend BlockContainer. I feel like BlockArcaneWorkbench should, but what about the rest?
public class BlockSnare extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0f, 0.0f, 0.0f, 1.0f, 0.0625f, 1.0f);
public BlockSnare(Material par2Material){
super(par2Material);
this.setSoundType(SoundType.PLANT);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos){
return NULL_AABB;
}
@Override
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
if(!world.isRemote && entity instanceof EntityLivingBase){
if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){
TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos);
if(WizardryUtilities.isValidTarget(tileentity.getCaster(), entity)){
((EntityLivingBase)entity).attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), 6);
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 100, 2));
world.destroyBlock(pos, false);
}
}
}
}
// The similarly named onNeighborChange method does NOT do the same thing.
@SuppressWarnings("deprecation")
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block blockIn){
super.neighborChanged(state, world, pos, blockIn);
if(!world.isSideSolid(pos.down(), EnumFacing.UP, false)){
world.setBlockToAir(pos);
}
}
@Override
public BlockRenderLayer getBlockLayer(){
return BlockRenderLayer.CUTOUT;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune){
return null;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityPlayerSave();
}
}
@@ -0,0 +1,94 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.TileEntityTimer;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
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;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on
// block break.
public class BlockSpectral extends BlockContainer {
public BlockSpectral(Material material) {
super(material);
this.setSoundType(SoundType.GLASS);
}
// Replaces getRenderBlockPass
@Override
public BlockRenderLayer getBlockLayer(){
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;
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random) {
// Middle of block
Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+random.nextDouble(), pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
// Top surface
Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+1, pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX()+random.nextDouble(), pos.getY()+1, pos.getZ()+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
}
// 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 TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityTimer(1200);
}
@Override
public int quantityDropped(Random par1Random){
return 0;
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side){
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
Block block = iblockstate.getBlock();
return block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
}
@@ -0,0 +1,146 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.spell.Petrify;
import electroblob.wizardry.tileentity.TileEntityStatue;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
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.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class BlockStatue extends BlockContainer {
private boolean isIce;
public BlockStatue(Material material) {
super(material);
this.isIce = material == Material.ICE;
if(this.isIce){
this.slipperiness = 0.98F;
this.setSoundType(SoundType.GLASS);
}
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
// Not a good idea to call getBlockBoundsMinX() or whatever from in here, since this method changes those!
if(!this.isIce){
if(world.getTileEntity(pos) instanceof TileEntityStatue){
TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(pos);
if(statue.creature != null){
// Block bounds are set to match the width and height of the entity, clamped to within 1 block.
return new AxisAlignedBB((float)Math.max(0.5 - statue.creature.width/2, 0), 0,
(float)Math.max(0.5 - statue.creature.width/2, 0),
(float)Math.min(0.5 + statue.creature.width/2, 1),
// This checks if the block is the top one and if so reduces its height so the top lines up with
// the top of the entity model.
statue.position == statue.parts ? (float)Math.min(statue.creature.height - statue.parts + 1, 1) : 1,
(float)Math.min(0.5 + statue.creature.width/2, 1));
}
}
}
return FULL_BLOCK_AABB;
}
// getCollisionBoundingBox eventually calls getBoundingBox anyway, and since I want the collision box and the block
// outline to be the same here, I've removed that getCollisionBoundingBox entirely.
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
// connections (fences, glass panes, etc.)...
@Override public boolean isFullCube(IBlockState state) { return false; }
// ...this one isn't used much but has something to do with redstone...
@Override public boolean isBlockNormalCube(IBlockState state) { return false; }
// ... this one is for most other game logic...
@Override public boolean isNormalCube(IBlockState state) { 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 BlockRenderLayer getBlockLayer(){
return this.isIce ? BlockRenderLayer.TRANSLUCENT : BlockRenderLayer.SOLID;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return this.isIce ? EnumBlockRenderType.MODEL : EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityStatue(this.isIce);
}
@Override
public int quantityDropped(Random random){
return 0;
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState state){
if(!world.isRemote){
TileEntityStatue tileentity = (TileEntityStatue)world.getTileEntity(pos);
if(tileentity != null){
if(tileentity.parts == 2){
if(tileentity.position == 2){
world.destroyBlock(pos.down(), false);
}else{
world.destroyBlock(pos.up(), false);
}
}else if(tileentity.parts == 3){
if(tileentity.position == 3){
world.destroyBlock(pos.down(), false);
world.destroyBlock(pos.down(2), false);
}else if(tileentity.position == 2){
world.destroyBlock(pos.down(), false);
world.destroyBlock(pos.up(), false);
}else{
world.destroyBlock(pos.up(), false);
world.destroyBlock(pos.up(2), false);
}
}
}
// This is only when position == 1 because world.destroyBlock calls this function for the other blocks.
if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){
tileentity.creature.getEntityData().removeTag(Petrify.NBT_KEY);
tileentity.creature.isDead = false;
world.spawnEntityInWorld(tileentity.creature);
}
}
super.breakBlock(world, pos, state);
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side){
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
Block block = iblockstate.getBlock();
return this.isIce && block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
}
@@ -0,0 +1,115 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryBlocks;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockTransportationStone extends Block {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0625f*5, 0, 0.0625f*5, 0.0625f*11, 0.0625f*6, 0.0625f*11);
public BlockTransportationStone(Material material){
super(material);
this.setTickRandomly(true);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
// connections (fences, glass panes, etc.)...
@Override public boolean isFullCube(IBlockState state) { return false; }
// ...this one isn't used much but has something to do with redstone...
@Override public boolean isBlockNormalCube(IBlockState state) { return false; }
// ... this one is for most other game logic...
@Override public boolean isNormalCube(IBlockState state) { 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 void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor){
super.onNeighborChange(world, pos, neighbor);
if(!world.isSideSolid(pos.down(), EnumFacing.UP, false) && world instanceof World){
this.dropBlockAsItem((World) world, pos, world.getBlockState(pos), 0);
((World)world).setBlockToAir(pos);
}
}
@Override
public void updateTick(World world, BlockPos pos, IBlockState state, Random random) {
if(!world.isSideSolid(pos.down(), EnumFacing.UP)){
this.dropBlockAsItem(world, pos, world.getBlockState(pos), 0);
world.setBlockToAir(pos);
}
}
@Override
public boolean canPlaceBlockAt(World world, BlockPos pos){
return super.canPlaceBlockAt(world, pos) && world.isSideSolid(pos.down(), EnumFacing.UP);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player,
EnumHand hand, ItemStack stack, EnumFacing side, float hitX, float hitY, float hitZ) {
if(stack != null && stack.getItem() instanceof ItemWand){
if(WizardData.get(player) != null){
WizardData data = WizardData.get(player);
for(int x=-1; x<=1; x++){
for(int z=-1; z<=1; z++){
BlockPos pos1 = pos.add(x, 0, z);
if(testForCircle(world, pos1)){
data.setStoneCircleLocation(pos1, world.provider.getDimension());
if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("tile.wizardry:transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()));
return true;
}
}
}
if(!world.isRemote) player.addChatMessage(new TextComponentTranslation("tile.wizardry:transportation_stone.invalid"));
return true;
}
}
return false;
}
/** Returns whether the specified location is surrounded by a complete cicle of 8 transportation stones. */
public static boolean testForCircle(World world, BlockPos pos){
if(world.getBlockState(pos).getMaterial().blocksMovement()) return false;
for(int x=-1; x<=1; x++){
for(int z=-1; z<=1; z++){
if(world.getBlockState(pos.add(x, 0, z)).getBlock() != WizardryBlocks.transportation_stone){
if(x != 0 || z != 0) return false;
}
}
}
return true;
}
}
@@ -0,0 +1,70 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.tileentity.TileEntityTimer;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on block break.
public class BlockVanishingCobweb extends BlockContainer {
public BlockVanishingCobweb(Material material) {
super(material);
}
@SideOnly(Side.CLIENT)
public BlockRenderLayer getBlockLayer()
{
return BlockRenderLayer.CUTOUT;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state)
{
return false;
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos)
{
return NULL_AABB;
}
@Override
public boolean isFullCube(IBlockState state)
{
return false;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
return new TileEntityTimer(400);
}
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity){
entity.setInWeb();
}
@Override
public int quantityDropped(Random par1Random){
return 0;
}
}
@@ -0,0 +1,579 @@
package electroblob.wizardry.client;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.CommonProxy;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelWizardArmour;
import electroblob.wizardry.client.particle.ParticleBlizzard;
import electroblob.wizardry.client.particle.ParticleDarkMagic;
import electroblob.wizardry.client.particle.ParticleDust;
import electroblob.wizardry.client.particle.ParticleGiantBubble;
import electroblob.wizardry.client.particle.ParticleIce;
import electroblob.wizardry.client.particle.ParticleLeaf;
import electroblob.wizardry.client.particle.ParticleMagicFlame;
import electroblob.wizardry.client.particle.ParticlePath;
import electroblob.wizardry.client.particle.ParticleRotatingSparkle;
import electroblob.wizardry.client.particle.ParticleSnow;
import electroblob.wizardry.client.particle.ParticleSpark;
import electroblob.wizardry.client.particle.ParticleSparkle;
import electroblob.wizardry.client.particle.ParticleTornado;
import electroblob.wizardry.client.renderer.LayerStone;
import electroblob.wizardry.client.renderer.RenderArc;
import electroblob.wizardry.client.renderer.RenderArcaneWorkbench;
import electroblob.wizardry.client.renderer.RenderBlackHole;
import electroblob.wizardry.client.renderer.RenderBlank;
import electroblob.wizardry.client.renderer.RenderBubble;
import electroblob.wizardry.client.renderer.RenderDecay;
import electroblob.wizardry.client.renderer.RenderDecoy;
import electroblob.wizardry.client.renderer.RenderEvilWizard;
import electroblob.wizardry.client.renderer.RenderFireRing;
import electroblob.wizardry.client.renderer.RenderForceArrow;
import electroblob.wizardry.client.renderer.RenderHammer;
import electroblob.wizardry.client.renderer.RenderIceGiant;
import electroblob.wizardry.client.renderer.RenderIceSpike;
import electroblob.wizardry.client.renderer.RenderLightningDisc;
import electroblob.wizardry.client.renderer.RenderLightningPulse;
import electroblob.wizardry.client.renderer.RenderMagicArrow;
import electroblob.wizardry.client.renderer.RenderMagicLight;
import electroblob.wizardry.client.renderer.RenderPhoenix;
import electroblob.wizardry.client.renderer.RenderProjectile;
import electroblob.wizardry.client.renderer.RenderSigil;
import electroblob.wizardry.client.renderer.RenderSpiritHorse;
import electroblob.wizardry.client.renderer.RenderSpiritWolf;
import electroblob.wizardry.client.renderer.RenderStatue;
import electroblob.wizardry.client.renderer.RenderWizard;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.construct.EntityArrowRain;
import electroblob.wizardry.entity.construct.EntityBlackHole;
import electroblob.wizardry.entity.construct.EntityBlizzard;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.entity.construct.EntityDecay;
import electroblob.wizardry.entity.construct.EntityEarthquake;
import electroblob.wizardry.entity.construct.EntityFireRing;
import electroblob.wizardry.entity.construct.EntityFireSigil;
import electroblob.wizardry.entity.construct.EntityForcefield;
import electroblob.wizardry.entity.construct.EntityFrostSigil;
import electroblob.wizardry.entity.construct.EntityHailstorm;
import electroblob.wizardry.entity.construct.EntityHammer;
import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityIceSpike;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import electroblob.wizardry.entity.construct.EntityLightningSigil;
import electroblob.wizardry.entity.construct.EntityTornado;
import electroblob.wizardry.entity.living.EntityDecoy;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityIceGiant;
import electroblob.wizardry.entity.living.EntityIceWraith;
import electroblob.wizardry.entity.living.EntityLightningWraith;
import electroblob.wizardry.entity.living.EntityPhoenix;
import electroblob.wizardry.entity.living.EntityShadowWraith;
import electroblob.wizardry.entity.living.EntitySpiritHorse;
import electroblob.wizardry.entity.living.EntitySpiritWolf;
import electroblob.wizardry.entity.living.EntityStormElemental;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.entity.projectile.EntityDarknessOrb;
import electroblob.wizardry.entity.projectile.EntityDart;
import electroblob.wizardry.entity.projectile.EntityFirebolt;
import electroblob.wizardry.entity.projectile.EntityFirebomb;
import electroblob.wizardry.entity.projectile.EntityForceArrow;
import electroblob.wizardry.entity.projectile.EntityForceOrb;
import electroblob.wizardry.entity.projectile.EntityIceCharge;
import electroblob.wizardry.entity.projectile.EntityIceLance;
import electroblob.wizardry.entity.projectile.EntityIceShard;
import electroblob.wizardry.entity.projectile.EntityLightningArrow;
import electroblob.wizardry.entity.projectile.EntityLightningDisc;
import electroblob.wizardry.entity.projectile.EntityMagicMissile;
import electroblob.wizardry.entity.projectile.EntityPoisonBomb;
import electroblob.wizardry.entity.projectile.EntitySmokeBomb;
import electroblob.wizardry.entity.projectile.EntitySpark;
import electroblob.wizardry.entity.projectile.EntitySparkBomb;
import electroblob.wizardry.entity.projectile.EntityThunderbolt;
import electroblob.wizardry.item.ItemScroll;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.PacketNPCCastSpell;
import electroblob.wizardry.packet.PacketPlayerSync.Message;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Clairvoyance;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import electroblob.wizardry.tileentity.TileEntityStatue;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryParticleType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.RenderBlaze;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityBlaze;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.client.config.GuiConfigEntries.NumberSliderEntry;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
/**
* The client proxy for wizardry.
* @author Electroblob
* @since Wizardry 1.0
*/
public class ClientProxy extends CommonProxy {
/** Static instance of the mixed font renderer */
public static MixedFontRenderer mixedFontRenderer;
// Key Bindings
public static final KeyBinding NEXT_SPELL = new KeyBinding("key.wizardry:next_spell", Keyboard.KEY_N, "key.categories.wizardry");
public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key.wizardry:previous_spell", Keyboard.KEY_B, "key.categories.wizardry");
// Armour Model
public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f);
// SECTION Registry
// ===============================================================================================================
@Override
public ModelBiped getWizardArmourModel(){
return WIZARD_ARMOUR_MODEL;
}
@Override
public void registerKeyBindings(){
ClientRegistry.registerKeyBinding(NEXT_SPELL);
ClientRegistry.registerKeyBinding(PREVIOUS_SPELL);
}
@Override
public void registerSpellHUD(){
MinecraftForge.EVENT_BUS.register(new GuiSpellDisplay(Minecraft.getMinecraft()));
}
@Override
public void initMixedFontRenderer(){
mixedFontRenderer = new MixedFontRenderer(Minecraft.getMinecraft().gameSettings,
new ResourceLocation("textures/font/ascii.png"), Minecraft.getMinecraft().renderEngine, false);
}
// SECTION Misc
// ===============================================================================================================
@Override
public void setToNumberSliderEntry(Property property) {
property.setConfigEntryClass(NumberSliderEntry.class);
}
@Override
public World getTheWorld() {
return Minecraft.getMinecraft().theWorld;
}
@Override
public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){
Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity(entity, sound, volume, pitch, repeat));
}
// SECTION Items
// ===============================================================================================================
@Override
public FontRenderer getFontRenderer(ItemStack stack){
Spell spell = Spells.none;
if(stack.getItem() instanceof ItemWand){
spell = WandHelper.getCurrentSpell(stack);
}else if(stack.getItem() instanceof ItemSpellBook || stack.getItem() instanceof ItemScroll){
spell = Spell.get(stack.getItemDamage());
}
if(Minecraft.getMinecraft().thePlayer != null && Wizardry.settings.discoveryMode
&& WizardData.get(Minecraft.getMinecraft().thePlayer) != null
&& !Minecraft.getMinecraft().thePlayer.capabilities.isCreativeMode
&& !WizardData.get(Minecraft.getMinecraft().thePlayer).hasSpellBeenDiscovered(spell)){
return mixedFontRenderer;
}
return null;
}
@Override
public String getScrollDisplayName(ItemStack scroll){
// Displays [Empty slot] if spell is continuous.
Spell spell = Spell.get(scroll.getItemDamage());
if(spell.isContinuous) spell = Spells.none;
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
boolean discovered = true;
// It seems that this method is called when the world is loading, before thePlayer has been initialised.
// If the player is null, the spell is assumed to be discovered.
if(player != null && Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode
&& WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){
discovered = false;
}
if(discovered){
return I18n.format("item.wizardry:scroll.name", spell.getDisplayName()).trim();
}else{
return I18n.format("item.wizardry:scroll.undiscovered.name", "#" + SpellGlyphData.getGlyphName(spell, player.worldObj) + "#").trim();
}
}
@Override
public double getConjuredBowDurability(ItemStack stack){
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
if(player.getActiveItemStack() == stack){
return (double)(stack.getItemDamage() + (player.getItemInUseMaxCount()) ) / (double)stack.getMaxDamage();
}
return super.getConjuredBowDurability(stack);
}
// SECTION Particles
// ===============================================================================================================
@Override
public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){
// Colour values are now automatically clamped to between 0 and 1, as values outside this range seem to
// cause strange effects in 1.10 (or more specifically, particles that are bright pink!)
// TODO: This is a terrible dirty fix, but it'll do for now. Find a nicer way in future.
if(type != WizardryParticleType.MAGIC_FIRE) r = MathHelper.clamp_float(r, 0, 1);
g = MathHelper.clamp_float(g, 0, 1);
b = MathHelper.clamp_float(b, 0, 1);
switch(type){
case BLIZZARD:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleBlizzard(world, maxAge, x, z, radius, y));
break;
case BRIGHT_DUST:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, false));
break;
case DARK_MAGIC:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDarkMagic(world, x, y, z, velX, velY, velZ, r, g, b));
break;
case DUST:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, true));
break;
case ICE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleIce(world, x, y, z, velX, velY, velZ, maxAge));
break;
case LEAF:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleLeaf(world, x, y, z, velX, velY, velZ, maxAge));
break;
case MAGIC_BUBBLE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleGiantBubble(world, x, y, z, velX, velY, velZ));
break;
case MAGIC_FIRE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleMagicFlame(world, x, y, z, velX, velY, velZ, maxAge, r == 0 ? 1 + world.rand.nextFloat() : r));
break;
case PATH:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticlePath(world, x, y, z, velX, velY, velZ, r, g, b, maxAge));
break;
case SNOW:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSnow(world, x, y, z, velX, velY, velZ));
break;
case SPARK:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSpark(world, x, y, z, velX, velY, velZ));
break;
case SPARKLE:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, velX, velY, velZ, r, g, b, maxAge, doGravity));
break;
case SPARKLE_ROTATING:
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleRotatingSparkle(world, maxAge, x, z, radius, y, r, g, b));
break;
default:
break;
}
}
@Override
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));//, world.rand.nextInt(6)));
}
// SECTION Packet Handlers
// ===============================================================================================================
@Override
public void handleCastSpellPacket(PacketCastSpell.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
Spell spell = Spell.get(message.spellID);
// Should always be true
if(caster instanceof EntityPlayer){
((EntityPlayer)caster).setActiveHand(message.hand);
// Duration isn't needed because it only ever affects things server-side, and anything that is
// seen client-side gets synced elsewhere.
spell.cast(world, (EntityPlayer)caster, message.hand, 0, new SpellModifiers());
// Updates the spell discovery data client-side. Could be done by calling sync(), but that means sending
// another packet unnecessarily.
if(WizardData.get((EntityPlayer)caster) != null){
WizardData.get((EntityPlayer)caster).discoverSpell(spell);
}
}else{
Wizardry.logger.warn("Recieved a PacketCastSpell, but the caster ID was not the ID of a player");
}
}
@Override
public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
Spell spell = Spell.get(message.spellID);
// Should always be true
if(caster instanceof EntityPlayer){
WizardData data = WizardData.get((EntityPlayer)caster);
if(data != null){
if(data.isCasting()){
WizardData.get((EntityPlayer)caster).stopCastingContinuousSpell();
}else{
WizardData.get((EntityPlayer)caster).startCastingContinuousSpell(spell, message.modifiers);
}
}
}else{
Wizardry.logger.warn("Recieved a PacketCastContinuousSpell, but the caster ID was not the ID of a player");
}
}
@Override
public void handleNPCCastSpellPacket(PacketNPCCastSpell.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
Entity target = message.targetID == -1 ? null : world.getEntityByID(message.targetID);
Spell spell = Spell.get(message.spellID);
// Should always be true
if(caster instanceof EntityLiving){
if(target instanceof EntityLivingBase){
spell.cast(world, (EntityLiving)caster, message.hand, 0, (EntityLivingBase)target, message.modifiers);
}
if(caster instanceof ISpellCaster){
if(spell.isContinuous || spell instanceof None){
((ISpellCaster)caster).setContinuousSpell(spell);
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
}
}
}else{
Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving");
}
}
@Override
public void handleTransportationPacket(PacketTransportation.Message message){
World world = Minecraft.getMinecraft().theWorld;
Entity caster = world.getEntityByID(message.casterID);
// Moved from when the packet is sent to when it is received; fixes the sound not playing in first person.
caster.playSound(SoundEvents.BLOCK_PORTAL_TRAVEL, 1, 1);
for(int i=0; i<20; i++){
double radius = 1;
double angle = world.rand.nextDouble()*Math.PI*2;
double x = caster.posX + radius*Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2;
double z = caster.posZ + radius*Math.sin(angle);
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, 0, 0.02, 0, 0.6f, 1.0f, 0.6f, 80 + world.rand.nextInt(10)));
}
for(int i=0; i<20; i++){
double radius = 1;
double angle = world.rand.nextDouble()*Math.PI*2;
double x = caster.posX + radius*Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2;
double z = caster.posZ + radius*Math.sin(angle);
world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, x, y, z, 0, 0.02, 0);
}
for(int i=0; i<20; i++){
double radius = 1;
double angle = world.rand.nextDouble()*Math.PI*2;
double x = caster.posX + radius*Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble()*2;
double z = caster.posZ + radius*Math.sin(angle);
world.spawnParticle(EnumParticleTypes.ENCHANTMENT_TABLE, x, y, z, 0, 0.02, 0);
}
}
@Override
public void handlePlayerSyncPacket(Message message){
WizardData properties = WizardData.get(Minecraft.getMinecraft().thePlayer);
if(properties != null){
properties.spellsDiscovered = message.spellsDiscovered;
if(message.selectedMinionID == -1){
properties.selectedMinion = null;
}else{
Entity entity = Minecraft.getMinecraft().theWorld.getEntityByID(message.selectedMinionID);
if(entity instanceof ISummonedCreature){
properties.selectedMinion = new WeakReference<ISummonedCreature>((ISummonedCreature)entity);
}else{
properties.selectedMinion = null;
}
}
}
}
@Override
public void handleGlyphDataPacket(electroblob.wizardry.packet.PacketGlyphData.Message message){
SpellGlyphData data = SpellGlyphData.get(Minecraft.getMinecraft().theWorld);
data.randomNames = new HashMap<Spell, String>();
data.randomDescriptions = new HashMap<Spell, String>();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
// -1 because the none spell isn't included
data.randomNames.put(spell, message.names.get(spell.id() - 1));
data.randomDescriptions.put(spell, message.descriptions.get(spell.id() - 1));
}
}
@Override
public void handleClairvoyancePacket(electroblob.wizardry.packet.PacketClairvoyance.Message message) {
Clairvoyance.spawnPathPaticles(Minecraft.getMinecraft().theWorld, message.path, message.durationMultiplier);
}
// SECTION Rendering
// ===============================================================================================================
private static final ResourceLocation ICE_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_wraith.png");
private static final ResourceLocation LIGHTNING_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_wraith.png");
/** Static instance of the statue renderer, used to access the block breaking texture. */
public static RenderStatue renderStatue;
@Override
public void initialiseLayers(){
LayerStone.initialiseLayers();
}
@Override
public void registerRenderers(){
// Minions
// Yet another advantage to the new system: turns out you don't even need to register the renderer if you
// just want the vanilla one for the mob you're extending.
// An anonymous class in a lambda expression! No point writing a separate class really, is there?
RenderingRegistry.registerEntityRenderingHandler(EntityLightningWraith.class, manager -> new RenderBlaze(manager){
@Override
protected ResourceLocation getEntityTexture(EntityBlaze entity){
return LIGHTNING_WRAITH_TEXTURE;
}
});
RenderingRegistry.registerEntityRenderingHandler(EntityIceWraith.class, manager -> new RenderBlaze(manager){
@Override
protected ResourceLocation getEntityTexture(EntityBlaze entity){
return ICE_WRAITH_TEXTURE;
}
});
RenderingRegistry.registerEntityRenderingHandler(EntityIceGiant.class, RenderIceGiant::new);
RenderingRegistry.registerEntityRenderingHandler(EntityPhoenix.class, RenderPhoenix::new);
// Projectiles
RenderingRegistry.registerEntityRenderingHandler(EntityMagicMissile.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/magic_missile.png"), false, 8.0, 4.0, 16, 9, false));
RenderingRegistry.registerEntityRenderingHandler(EntityIceShard.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_shard.png"), false, 8.0, 2.0, 16, 5, false));
RenderingRegistry.registerEntityRenderingHandler(EntityLightningArrow.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_arrow.png"), true, 8.0, 2.0, 16, 5, false));
RenderingRegistry.registerEntityRenderingHandler(EntityDart.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/dart.png"), false, 8.0, 2.0, 16, 5, true));
RenderingRegistry.registerEntityRenderingHandler(EntityIceLance.class, manager -> new RenderMagicArrow(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, true));
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
// Creatures
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, manager -> new RenderSpiritWolf(manager, 0.5f));
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, manager -> new RenderSpiritHorse(manager, 0.5f));
RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new);
// Throwables
RenderingRegistry.registerEntityRenderingHandler(EntitySparkBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark_bomb.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityFirebomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/firebomb.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityPoisonBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/poison_bomb.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityIceCharge.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/ice_charge.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityForceOrb.class, manager -> new RenderProjectile(manager, 0.7f, new ResourceLocation(Wizardry.MODID, "textures/entity/force_orb.png"), true));
RenderingRegistry.registerEntityRenderingHandler(EntitySpark.class, manager -> new RenderProjectile(manager, 0.4f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark.png"), true));
RenderingRegistry.registerEntityRenderingHandler(EntityDarknessOrb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/darkness_orb.png"), true));
RenderingRegistry.registerEntityRenderingHandler(EntityFirebolt.class, manager -> new RenderProjectile(manager, 0.2f, new ResourceLocation(Wizardry.MODID, "textures/entity/firebolt.png"), false));
RenderingRegistry.registerEntityRenderingHandler(EntityLightningDisc.class, manager -> new RenderLightningDisc(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f));
RenderingRegistry.registerEntityRenderingHandler(EntitySmokeBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false));
// Effects and constructs
RenderingRegistry.registerEntityRenderingHandler(EntityArc.class, RenderArc::new);
RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new);
RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new);
RenderingRegistry.registerEntityRenderingHandler(EntityHammer.class, RenderHammer::new);
RenderingRegistry.registerEntityRenderingHandler(EntityIceSpike.class, RenderIceSpike::new);
// Stuff that doesn't render
RenderingRegistry.registerEntityRenderingHandler(EntityBlizzard.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityTornado.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityArrowRain.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityShadowWraith.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityThunderbolt.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityStormElemental.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityEarthquake.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityHailstorm.class, RenderBlank::new);
// Runes on ground
RenderingRegistry.registerEntityRenderingHandler(EntityHealAura.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/healing_aura.png"), 5.0f, false));
RenderingRegistry.registerEntityRenderingHandler(EntityFireSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/fire_sigil.png"), 2.0f, true));
RenderingRegistry.registerEntityRenderingHandler(EntityFrostSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/frost_sigil.png"), 2.0f, true));
RenderingRegistry.registerEntityRenderingHandler(EntityLightningSigil.class, manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f, true));
RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f));
RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new);
RenderingRegistry.registerEntityRenderingHandler(EntityLightningPulse.class, manager -> new RenderLightningPulse(manager, 8.0f));
// TESRs
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench());
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityStatue.class, renderStatue = new RenderStatue());
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityMagicLight.class, new RenderMagicLight());
}
}
@@ -0,0 +1,76 @@
package electroblob.wizardry.client;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.EntityList;
import net.minecraftforge.fml.client.config.GuiButtonExt;
import net.minecraftforge.fml.client.config.GuiEditArray;
import net.minecraftforge.fml.client.config.GuiEditArrayEntries;
import net.minecraftforge.fml.client.config.GuiEditArrayEntries.StringEntry;
import net.minecraftforge.fml.client.config.GuiSelectString;
import net.minecraftforge.fml.client.config.IConfigElement;
/** [NYI] Intended as a way of choosing entities by name from all those currently registered, within the config file, so
* that users don't have to look up the entity IDs. I can't get this to work correctly at the moment. */
public class EntityNameEntry extends StringEntry {
protected final GuiButtonExt btnValue;
protected Object entityClass;
public EntityNameEntry(GuiEditArray owningScreen, GuiEditArrayEntries owningEntryList, IConfigElement configElement, Object value)
{
super(owningScreen, owningEntryList, configElement, value);
this.btnValue = new GuiButtonExt(0, 0, 0, owningEntryList.controlWidth, 18, I18n.format(this.textFieldValue.getText()));
//this.btnValue.enabled = owningScreen.enabled;
}
@Override
public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected)
{
//super.drawEntry(slotIndex, x, y, listWidth, slotHeight, tessellator, mouseX, mouseY, isSelected);
this.btnValue.xPosition = listWidth / 4;
this.btnValue.yPosition = y;
String trans = I18n.format(this.textFieldValue.getText());
if (!trans.equals(this.textFieldValue.getText()))
this.btnValue.displayString = trans;
else
this.btnValue.displayString = this.textFieldValue.getText();
//btnValue.packedFGColour = value ? GuiUtils.getColorCode('2', true) : GuiUtils.getColorCode('4', true);
this.btnValue.drawButton(owningEntryList.getMC(), mouseX, mouseY);
}
@Override
public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY)
{
if (this.btnValue.mousePressed(owningEntryList.getMC(), x, y))
{
btnValue.playPressSound(owningEntryList.getMC().getSoundHandler());
// Some sort of type incompatiblity meant that I had to do this first.
Map<Object, String> map = new HashMap<Object, String>(EntityList.CLASS_TO_NAME);
Minecraft.getMinecraft().displayGuiScreen(new GuiSelectString(this.owningScreen, configElement, index, map, this.getValue(), true));
owningEntryList.recalculateState();
return true;
}
return super.mousePressed(index, x, y, mouseEvent, relativeX, relativeY);
}
@Override
public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY)
{
this.btnValue.mouseReleased(x, y);
super.mouseReleased(index, x, y, mouseEvent, relativeX, relativeY);
}
@Override
public Object getValue()
{
return this.textFieldValue.getText();
}
}
@@ -0,0 +1,230 @@
package electroblob.wizardry.client;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class GuiArcaneWorkbench extends GuiContainer {
private GuiButton applyBtn;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png");
private IInventory playerInventory;
private IInventory arcaneWorkbenchInventory;
private final int tooltipWidth = 164;
public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity) {
super(new ContainerArcaneWorkbench(invPlayer, entity));
this.playerInventory = invPlayer;
this.arcaneWorkbenchInventory = entity;
xSize = 176;
ySize = 220;
}
@Override
public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){
// Tests if there is a wand in the workbench and edits the positioning accordingly
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
guiLeft = (this.width - this.xSize - tooltipWidth)/2;
this.applyBtn.xPosition = (this.width - tooltipWidth)/2 + 48;
}else{
guiLeft = (this.width - this.xSize)/2;
this.applyBtn.xPosition = this.width/2 + 48;
}
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack()){
this.applyBtn.enabled = true;
}else{
this.applyBtn.enabled = false;
}
super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_);
}
@Override
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
GlStateManager.pushAttrib();
GlStateManager.color(1F, 1F, 1F, 1F);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
// Main inventory
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
// Changing slots
for(int i=0; i<ContainerArcaneWorkbench.CRYSTAL_SLOT; i++){
Slot slot = this.inventorySlots.getSlot(i);
if(slot.xDisplayPosition >=0 && slot.yDisplayPosition >= 0)
this.drawTexturedModalRect(guiLeft + slot.xDisplayPosition - 10, guiTop + slot.yDisplayPosition - 10,
0, 220, 36, 36);
}
// Tooltip only drawn if there is a wand
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
// Tooltip box
drawTexturedModalRect(guiLeft + xSize, guiTop, xSize, 0, 256 - xSize - 4, ySize);
drawTexturedModalRect(guiLeft + 252, guiTop, xSize + 4, 0, tooltipWidth - 2*(256 - xSize - 4), ySize);
drawTexturedModalRect(guiLeft + xSize + tooltipWidth - (256 - xSize - 4), guiTop, xSize + 4, 0, 256 - xSize - 4, ySize);
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack();
Spell[] spells = WandHelper.getSpells(wand);
int i=0;
for(Spell spell : spells){
boolean discovered = true;
if(!this.mc.thePlayer.capabilities.isCreativeMode && WizardData.get(this.mc.thePlayer) != null){
discovered = WizardData.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell);
}
// As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on
// mods to add their own.
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.element.getIcon() : Element.MAGIC.getIcon());
// Renders the little element icon
WizardryUtilities.drawTexturedRect(guiLeft + xSize + 5, guiTop + 34 + 10*i++, 8, 8);
}
int x = 0;
int y = guiTop + 50 + spells.length*10;
// Look how much shorter this is with the WandHelper class!
for(Item item : WandHelper.getSpecialUpgrades()){
int level = WandHelper.getUpgradeLevel(wand, item);
if(level > 0){
ItemStack stack = new ItemStack(item, level);
GlStateManager.enableDepth();
this.itemRender.renderItemAndEffectIntoGUI(stack, guiLeft + xSize + 6 + x, y);
this.itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, stack, guiLeft + xSize + 6 + x, y, null);
x += 18;
GlStateManager.disableDepth();
}
}
}
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
// Fixes the bug that caused the slot hightlight to render opaque. I don't know why it works, it just works!
GlStateManager.disableBlend();
GlStateManager.enableAlpha();
GlStateManager.popAttrib();
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
this.fontRendererObj.drawString(this.arcaneWorkbenchInventory.hasCustomName() ? this.arcaneWorkbenchInventory.getName() : I18n.format(this.arcaneWorkbenchInventory.getName()), 8, 6, 4210752);
this.fontRendererObj.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName() : I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752);
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack();
this.fontRendererObj.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSize + 6, 6, 0);
this.fontRendererObj.drawStringWithShadow("\u00A77" + I18n.format("container.wizardry:arcane_workbench.mana") + " " + (wand.getMaxDamage() - wand.getItemDamage()) + "/" + wand.getMaxDamage(), xSize + 6, 20, 0);
Spell[] spells = WandHelper.getSpells(wand);
int y = 34;
for(Spell spell : spells){
boolean discovered = true;
if(!this.mc.thePlayer.capabilities.isCreativeMode && WizardData.get(this.mc.thePlayer) != null){
discovered = WizardData.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell);
}
if(discovered){
this.fontRendererObj.drawStringWithShadow(spell.getDisplayNameWithFormatting(), xSize + 16, y, 0);
}else{
this.mc.standardGalacticFontRenderer.drawStringWithShadow("\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.theWorld), xSize + 16, y, 0);
}
y += 10;
}
if(WandHelper.getTotalUpgrades(wand) > 0){
this.fontRendererObj.drawStringWithShadow("\u00A7f" + I18n.format("container.wizardry:arcane_workbench.upgrades"), xSize + 6, y + 6, 0);
int x = 0;
y = 50 + spells.length*10;
// Wand upgrade tooltips
for(Item item : WandHelper.getSpecialUpgrades()){
int level = WandHelper.getUpgradeLevel(wand, item);
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(xSize + 6 + x, y, 16, 16, mouseX, mouseY)){
ItemStack stack = new ItemStack(item, level);
this.renderToolTip(stack, mouseX - guiLeft, mouseY - guiTop);
}
x += 18;
}
}
}
}
}
@Override
public void initGui(){
this.mc.thePlayer.openContainer = this.inventorySlots;
this.guiLeft = (this.width - this.xSize) / 2;
this.guiTop = (this.height - this.ySize) / 2;
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width/2 + 48, this.height/2 + 3));
}
@Override
public void onGuiClosed(){
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
@Override
protected void actionPerformed(GuiButton button){
if(button.enabled){
if(button.id == 0){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.APPLY_BUTTON);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
}
@@ -0,0 +1,41 @@
package electroblob.wizardry.client;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
class GuiButtonApply extends GuiButton {
public GuiButtonApply(int id, int x, int y){
super(id, x, y, 32, 16, I18n.format("container.wizardry:arcane_workbench.apply"));
}
@Override
public void drawButton(Minecraft minecraft, int mouseX, int mouseY){
// Whether the button is highlighted
this.hovered = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height;
int k = 36;
int l = 220;
int colour = 14737632;
if(this.enabled){
if(this.hovered){
k += this.width*2;
colour = 16777120;
}
}else{
k += this.width;
colour = 10526880;
}
WizardryUtilities.drawTexturedRect(this.xPosition, this.yPosition, k, l, this.width, this.height, 256, 256);
this.drawCenteredString(minecraft.fontRendererObj, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, colour);
}
}
@@ -0,0 +1,23 @@
package electroblob.wizardry.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
class GuiButtonInvisible extends GuiButton {
public GuiButtonInvisible(int id, int x, int y, int width, int height){
super(id, x, y, width, height, "");
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft par1Minecraft, int par2, int par3){
this.hovered = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
}
}
@@ -0,0 +1,52 @@
package electroblob.wizardry.client;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
class GuiButtonTurnPage extends GuiButton {
/** True for pointing right (next page), false for pointing left (previous page). */
private final boolean nextPage;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
public GuiButtonTurnPage(int id, int x, int y, boolean isNextPage)
{
super(id, x, y, 23, 13, "");
this.nextPage = isNextPage;
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft par1Minecraft, int par2, int par3)
{
if (this.visible)
{
boolean flag = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
par1Minecraft.getTextureManager().bindTexture(texture);
int k = 0;
int l = 192;
if (flag)
{
k += 23;
}
if (!this.nextPage)
{
l += 13;
}
WizardryUtilities.drawTexturedRect(this.xPosition, this.yPosition, k, l, 23, 13, 288, 256);
}
}
}
@@ -0,0 +1,80 @@
package electroblob.wizardry.client;
import java.util.ArrayList;
import java.util.List;
import electroblob.wizardry.Settings;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.common.config.ConfigElement;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.client.config.DummyConfigElement.DummyCategoryElement;
import net.minecraftforge.fml.client.config.GuiConfig;
import net.minecraftforge.fml.client.config.GuiConfigEntries;
import net.minecraftforge.fml.client.config.GuiConfigEntries.CategoryEntry;
import net.minecraftforge.fml.client.config.IConfigElement;
public class GuiConfigWizardry extends GuiConfig {
public GuiConfigWizardry(GuiScreen parent){
super(parent, getConfigEntries(), Wizardry.MODID, false, false, Wizardry.NAME + " - " + I18n.format("config.wizardry.title.general"));
//this.titleLine2 = "File location: " + Wizardry.config.getConfigFile().getAbsolutePath();
}
private static List<IConfigElement> getConfigEntries(){
List<IConfigElement> configList = new ArrayList<IConfigElement>(1);
configList.add(new DummyCategoryElement("spellsConfig", "config.wizardry.category." + Settings.SPELLS_CATEGORY, SpellsCategory.class));
configList.add(new DummyCategoryElement("resistancesConfig", "config.wizardry.category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class));
configList.addAll(new ConfigElement(Wizardry.settings.getConfigCategory(Configuration.CATEGORY_GENERAL)).getChildElements());
return configList;
}
/** Spells category of the config gui. This adds a button which opens up the spells category config. */
public static class SpellsCategory extends CategoryEntry
{
public SpellsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig spellsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.settings.getConfigCategory(Settings.SPELLS_CATEGORY))).getChildElements(),
this.owningScreen.modID, Settings.SPELLS_CATEGORY, false, false,
Wizardry.NAME + " - " + I18n.format("config.wizardry.title." + Settings.SPELLS_CATEGORY));
spellsMenu.titleLine2 = I18n.format("config.wizardry.subtitle." + Settings.SPELLS_CATEGORY);
return spellsMenu;
}
}
/** Resistances category of the config gui. */
public static class ResistancesCategory extends CategoryEntry
{
public ResistancesCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig idsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.settings.getConfigCategory(Settings.RESISTANCES_CATEGORY))).getChildElements(),
this.owningScreen.modID, Settings.RESISTANCES_CATEGORY, false, false,
Wizardry.NAME + " - " + I18n.format("config.wizardry.title." + Settings.RESISTANCES_CATEGORY));
idsMenu.titleLine2 = I18n.format("config.wizardry.subtitle." + Settings.RESISTANCES_CATEGORY);
return idsMenu;
}
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.ContainerWorkbench;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/** Crafting table GUI that doesn't require a crafting table container object. */
public class GuiPortableCrafting extends GuiContainer {
private static final ResourceLocation craftingTableGuiTextures = new ResourceLocation("textures/gui/container/crafting_table.png");
public GuiPortableCrafting(InventoryPlayer p_i1084_1_, World p_i1084_2_, BlockPos pos)
{
super(new ContainerWorkbench(p_i1084_1_, p_i1084_2_, pos));
}
/**
* Draw the foreground layer for the GuiContainer (everything in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int p_146979_1_, int p_146979_2_)
{
this.fontRendererObj.drawString(I18n.format("container.crafting"), 28, 6, 4210752);
this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 96 + 2, 4210752);
}
protected void drawGuiContainerBackgroundLayer(float p_146976_1_, int p_146976_2_, int p_146976_3_)
{
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(craftingTableGuiTextures);
int k = (this.width - this.xSize) / 2;
int l = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize);
}
}
@@ -0,0 +1,127 @@
package electroblob.wizardry.client;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
public class GuiSpellBook extends GuiScreen {
private int xSize, ySize;
private Spell spell;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spellbook.png");
public GuiSpellBook(Spell spell) {
super();
xSize = 288;
ySize = 180;
this.spell = spell;
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
int xPos = this.width/2 - xSize/2;
int yPos = this.height/2 - this.ySize/2;
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
boolean discovered = true;
if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null
&& !WizardData.get(player).hasSpellBeenDiscovered(spell)){
discovered = false;
}
// Draws spell illustration on opposite page, underneath the book so it shows through the hole.
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
WizardryUtilities.drawTexturedRect(xPos + 145, yPos + 20, 0, 0, 128, 128, 128, 128);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
super.drawScreen(par1, par2, par3);
if(discovered){
this.fontRendererObj.drawString(spell.getDisplayName(), xPos+17, yPos+14, 0);
this.fontRendererObj.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777);
}else{
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.worldObj), xPos+17, yPos+14, 0);
this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777);
}
this.fontRendererObj.drawString("-------------------", xPos+17, yPos+34, 0);
if(spell.tier == Tier.BASIC){
// Basic is usually white but this doesn't show up.
this.fontRendererObj.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos+17, yPos+44, 0);
}else{
this.fontRendererObj.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos+17, yPos+44, 0);
}
String element = "Element: " + spell.element.getFormattingCode() + spell.element.getDisplayName();
if(!discovered) element = "Element: ?";
this.fontRendererObj.drawString(element, xPos+17, yPos+56, 0);
String manaCost = "Mana Cost: " + spell.cost;
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second";
if(!discovered) manaCost = "Mana Cost: ?";
this.fontRendererObj.drawString(manaCost, xPos+17, yPos+68, 0);
if(discovered){
this.fontRendererObj.drawSplitString(spell.getDescription(), xPos+17, yPos+82, 118, 0);
}else{
this.mc.standardGalacticFontRenderer.drawSplitString(SpellGlyphData.getGlyphDescription(spell, player.worldObj), xPos+17, yPos+82, 118, 0);
}
/*
// Word wrapping
int charNumber = 0;
int lineNumber = 0;
while(charNumber < spell.desc.length()){
int lineLength = 0;
String line;
if(spell.desc.length() - charNumber > 22){
for(int i = charNumber; i < charNumber+23; i++){
if(spell.desc.charAt(i) == ' '){
lineLength = i - charNumber;
}
}
line = spell.desc.substring(charNumber, charNumber + lineLength);
}else{
line = spell.desc.substring(charNumber, spell.desc.length());
charNumber = spell.desc.length();
}
this.fontRendererObj.drawString("\u00A7o" + line, xPos+17, yPos+82+10*lineNumber, 0);
charNumber+=(lineLength+1);
lineNumber++;
}
*/
}
public void initGui()
{
super.initGui();
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
}
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
}
@@ -0,0 +1,155 @@
package electroblob.wizardry.client;
import java.util.List;
import electroblob.wizardry.Settings.GuiPosition;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class GuiSpellDisplay extends Gui {
private Minecraft mc;
private static final ResourceLocation hudTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png");
public GuiSpellDisplay(Minecraft par1Minecraft) {
super();
this.mc = par1Minecraft;
}
@SubscribeEvent
public void draw(RenderGameOverlayEvent event){
EntityPlayer player = this.mc.thePlayer;
// If the player has a wand in each hand, only displays for the one in the main hand.
ItemStack wand = player.getHeldItemMainhand();
if(wand == null || !(wand.getItem() instanceof ItemWand)){
wand = player.getHeldItemOffhand();
// If the player isn't holding a wand, then nothing else needs to be done.
if(wand == null || !(wand.getItem() instanceof ItemWand)) return;
}
int width = event.getResolution().getScaledWidth();
int height = event.getResolution().getScaledHeight();
Spell spell = WandHelper.getCurrentSpell(wand);
int cooldown = WandHelper.getCurrentCooldown(wand);
float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade)*Constants.COOLDOWN_REDUCTION_PER_LEVEL;
if(player.isPotionActive(WizardryPotions.font_of_mana)){
// Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously
cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier();
}
// Coordinates of the top left corner of the HUD.
int left = 0;
int top = 0;
boolean mirror = false;
if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_LEFT){
left = 0;
top = height-36;
}else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_LEFT){
left = 0;
top = 0;
}else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_RIGHT){
left = width-128;
top = 0;
mirror = true;
}else if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_RIGHT){
left = width-128;
top = height-36;
mirror = true;
}
boolean discovered = true;
if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){
discovered = WizardData.get(player).hasSpellBeenDiscovered(spell);
}
if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){
// Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect
String colour = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode();
if(!discovered) colour = "\u00A79";
String spellName = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.worldObj);
FontRenderer font = discovered ? this.mc.fontRendererObj : this.mc.standardGalacticFontRenderer;
int maxWidth = 90;
if(font.getStringWidth(spellName) <= maxWidth){
// Single line is rendered more centrally
font.drawStringWithShadow(colour + spellName, mirror ? left+5 : left+41, top+13, 0xffffffff);
}else{
int lineNumber = 0;
List<String> lines = font.listFormattedStringToWidth(spellName, maxWidth);
for(Object line : lines){
if(line instanceof String){
font.drawStringWithShadow(colour + (String)line, mirror ? left+5 : left+41, top+6 + 11*lineNumber, 0xffffffff);
}
lineNumber++;
}
}
}else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){
GlStateManager.pushAttrib();
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
GlStateManager.color(1, 1, 1);
this.mc.renderEngine.bindTexture(hudTexture);
// Background of spell hud
this.drawTexturedModalRect(left, top, 0, mirror ? 36 : 0, 128, 36);
// Cooldown bar
if(cooldown > 0){
this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 6, 82, 6);
int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown)
/ (double)(spell.cooldown * cooldownMultiplier)) * 82);
this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 0, l, 6);
}
// Spell illustration
this.mc.renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
WizardryUtilities.drawTexturedRect(mirror ? left+94 : left+2, top+2, 0, 0, 32, 32, 32, 32);
GlStateManager.popAttrib();
}
}
}
@@ -0,0 +1,809 @@
package electroblob.wizardry.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.Charsets;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class GuiWizardHandbook extends GuiScreen {
private int xSize, ySize;
private int pageNumber = 0;
private static final int PAGE_WIDTH = 120;
/** The integer colour for black passed into the font renderer methods. This used to be 0 but that's now white
* for some reason, so I've made a it a constant in case it changes again. */
// I think this is actually ever-so-slightly lighter than pure black, but the difference is unnoticeable.
private static final int BLACK = 1;
public static final ResourceLocation regularHandbook = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
public static final ResourceLocation ore = new ResourceLocation(Wizardry.MODID, "textures/gui/ore_picture.png");
public static final ResourceLocation crystal = new ResourceLocation(Wizardry.MODID, "textures/items/magic_crystal.png");
public static final ResourceLocation workbenchGui = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png");
public static final ResourceLocation craftingGrids = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook_recipes.png");
private ArrayList<ArrayList<String>> text;
private ArrayList<Section> sections;
private int guiPage, imagePage;
public GuiWizardHandbook() {
super();
xSize = 288;
ySize = 180;
}
@Override
public void drawScreen(int mouseX, int mouseY, float par3){
int xPos = this.width/2 - xSize/2;
int yPos = this.height/2 - this.ySize/2;
// Tests for crafting recipes section
if(pageNumber >= (sections.get(sections.size()-1).pageNumber-1)/2 && pageNumber < (sections.get(sections.size()-1).pageNumber-1)/2 + 4){
Minecraft.getMinecraft().renderEngine.bindTexture(craftingGrids);
}else{
Minecraft.getMinecraft().renderEngine.bindTexture(regularHandbook);
}
WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
// Arcane workbench gui picture
if(pageNumber == (this.guiPage-1)/2){
Minecraft.getMinecraft().renderEngine.bindTexture(workbenchGui);
this.drawTexturedModalRect(this.guiPage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 14, 28, 12, 120, 118);
}
// Magic crystal and crystal ore images
if(pageNumber == (this.imagePage-1)/2){
Minecraft.getMinecraft().renderEngine.bindTexture(ore);
WizardryUtilities.drawTexturedRect(this.imagePage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 80, 0, 0, 64, 64, 64, 64);
Minecraft.getMinecraft().renderEngine.bindTexture(crystal);
drawTexturedStretchedRect(this.imagePage % 2 == 1 ? xPos + 17 + 64 : this.width/2 + 7 + 62, yPos + 80, 0, 0, 64, 64, 1, 1);
}
this.fontRendererObj.drawString("" + (pageNumber*2 + 1), xPos + xSize/4 - 3, yPos + ySize - 20, 0);
this.fontRendererObj.drawString("" + (pageNumber*2 + 2), xPos + 3*xSize/4 - 5, yPos + ySize - 20, 0);
super.drawScreen(mouseX, mouseY, par3);
int lineNumber = 0;
if(pageNumber == 1){
for(Section s : sections){
s.drawContents();
}
}else{
for(Section s : sections){
s.hideButton();
}
}
for(String paragraph : text.get(pageNumber*2)){
this.fontRendererObj.drawSplitString(paragraph, xPos + 17, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK);
List<String> list = new ArrayList<String>(this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH));
lineNumber += list.size();
}
lineNumber = 0;
// Prevents crash when the last page is blank (and hence is not in the list of pages)
if(text.size() > pageNumber*2 + 1){
for(String paragraph : text.get(pageNumber*2 + 1)){
// First page is centred
if(pageNumber == 0){
int startX = this.width/2 + 7 + PAGE_WIDTH/2 - this.fontRendererObj.getStringWidth(paragraph)/2;
this.fontRendererObj.drawSplitString(paragraph, startX, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK);
}else{
this.fontRendererObj.drawSplitString(paragraph, this.width/2 + 7, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, PAGE_WIDTH, BLACK);
}
List<String> list = new ArrayList<String>(this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH));
lineNumber += list.size();
}
}
ItemStack[][] craftingGrid;
ItemStack craftingResult;
// Tooltips are rendered after recipes to prevent tooltips on the left appearing behind items on the right.
if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[1][0] = new ItemStack(Blocks.CARPET, 1, 10);
craftingGrid[2][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Blocks.LAPIS_BLOCK);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(Blocks.STONE);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][2] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.arcane_workbench);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.STICK);
craftingGrid[0][2] = new ItemStack(Items.GOLD_NUGGET);
craftingResult = new ItemStack(WizardryItems.magic_wand);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.BOOK);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BOOK);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.wizard_handbook);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryBlocks.crystal_flower);
craftingResult = new ItemStack(WizardryItems.magic_crystal, 2);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.mana_flask);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Blocks.STONE);
craftingGrid[0][1] = new ItemStack(Blocks.STONE);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][1] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[0][1] = new ItemStack(Items.STRING);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Items.STRING);
craftingGrid[2][1] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.magic_silk, 2);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_hat);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_robe);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_leggings);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_boots);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){
if(Wizardry.settings.useAlternateScrollRecipe){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}else{
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.firebombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[1][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.firebomb, 3);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.poisonBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[1][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.poison_bomb, 3);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.smokeBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.COAL);
craftingGrid[1][0] = new ItemStack(Items.COAL);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
}
if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[1][0] = new ItemStack(Blocks.CARPET, 1, 10);
craftingGrid[2][0] = new ItemStack(Items.GOLD_NUGGET);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Blocks.LAPIS_BLOCK);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(Blocks.STONE);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][2] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.arcane_workbench);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.STICK);
craftingGrid[0][2] = new ItemStack(Items.GOLD_NUGGET);
craftingResult = new ItemStack(WizardryItems.magic_wand);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.BOOK);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BOOK);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.wizard_handbook);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryBlocks.crystal_flower);
craftingResult = new ItemStack(WizardryItems.magic_crystal, 2);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.mana_flask);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Blocks.STONE);
craftingGrid[0][1] = new ItemStack(Blocks.STONE);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Blocks.STONE);
craftingGrid[2][1] = new ItemStack(Blocks.STONE);
craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[0][1] = new ItemStack(Items.STRING);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_crystal);
craftingGrid[1][2] = new ItemStack(Items.STRING);
craftingGrid[2][1] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.magic_silk, 2);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_hat);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_robe);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[1][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][2] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][2] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_leggings);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[0][1] = new ItemStack(WizardryItems.magic_silk);
craftingGrid[2][1] = new ItemStack(WizardryItems.magic_silk);
craftingResult = new ItemStack(WizardryItems.wizard_boots);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){
if(Wizardry.settings.useAlternateScrollRecipe){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingGrid[2][0] = new ItemStack(WizardryItems.magic_crystal);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}else{
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.PAPER);
craftingGrid[1][0] = new ItemStack(Items.STRING);
craftingResult = new ItemStack(WizardryItems.blank_scroll);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.firebombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[1][0] = new ItemStack(Items.BLAZE_POWDER);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.firebomb, 3);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.poisonBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[1][0] = new ItemStack(Items.SPIDER_EYE);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.poison_bomb, 3);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.settings.smokeBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.COAL);
craftingGrid[1][0] = new ItemStack(Items.COAL);
craftingGrid[0][1] = new ItemStack(Items.GLASS_BOTTLE);
craftingGrid[1][1] = new ItemStack(Items.GUNPOWDER);
craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
}
}
private void renderCraftingRecipe(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) {
GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GlStateManager.enableLighting();
itemRender.zLevel = 100.0F;
for(int i=0; i<craftingGrid.length; i++){
for(int j=0; j<craftingGrid[i].length; j++){
if(craftingGrid[i][j] != null){
itemRender.renderItemAndEffectIntoGUI(craftingGrid[i][j], xPos + 18*i, yPos + 18*j);
itemRender.renderItemOverlays(this.fontRendererObj, craftingGrid[i][j], xPos + 18*i, yPos + 18*j);
}
}
}
if(craftingResult != null){
itemRender.renderItemAndEffectIntoGUI(craftingResult, xPos + 86, yPos + 18);
itemRender.renderItemOverlays(this.fontRendererObj, craftingResult, xPos + 86, yPos + 18);
}
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
}
private void renderCraftingTooltips(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) {
int guiLeft = this.width/2 - xSize/2;
int guiTop = this.height/2 - this.ySize/2;
GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
itemRender.zLevel = 0.0F;
GlStateManager.disableLighting();
for(int i=0; i<craftingGrid.length; i++){
for(int j=0; j<craftingGrid[i].length; j++){
if(craftingGrid[i][j] != null && isPointInRegion(xPos + 18*i, yPos + 18*j, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
this.renderToolTip(craftingGrid[i][j], mouseX, mouseY);
}
}
}
if(craftingResult != null && isPointInRegion(xPos + 86, yPos + 18, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
this.renderToolTip(craftingResult, mouseX, mouseY);
}
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
}
@Override
public void initGui(){
super.initGui();
Keyboard.enableRepeatEvents(true);
int nextButtonId = 0;
this.buttonList.clear();
this.buttonList.add(new GuiButtonTurnPage(nextButtonId++, this.width/2 + this.xSize/2 - 22 - 23, this.height/2 + this.ySize/2 - 10 - 13, true));
this.buttonList.add(new GuiButtonTurnPage(nextButtonId++, this.width/2 - this.xSize/2 + 21, this.height/2 + this.ySize/2 - 10 - 13, false));
text = new ArrayList<ArrayList<String>>(1);
sections = new ArrayList<Section>(1);
BufferedReader bufferedreader = null;
String textFilepath = "wizardry:texts/handbook_" + Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".txt";
try {
bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8));
} catch (IOException e){
Wizardry.logger.info("Wizard handbook text file missing for the current language. Using default (English - US) instead.");
textFilepath = "wizardry:texts/handbook_en_US.txt";
try {
bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8));
} catch (IOException x){
Wizardry.logger.error("Couldn't find file: wizardry:assets/texts/handbook_en_US.txt. The file may be"
+ "missing; please try re-downloading and reinstalling Wizardry.", x);
}
}
if(bufferedreader != null){
try {
String paragraph = bufferedreader.readLine();
ArrayList<String> page = new ArrayList<String>(1);
int linesPerPage = 16;
int lineNumber = 0;
while(paragraph != null){
//System.out.println(paragraph);
if(paragraph.contains("PAGEBREAK") || lineNumber >= linesPerPage){
text.add(page);
page = new ArrayList<String>(1);
lineNumber = 0;
if(paragraph.contains("PAGEBREAK")) paragraph = bufferedreader.readLine();
}else if(paragraph.contains("LINEBREAK")){
lineNumber++;
page.add("");
paragraph = bufferedreader.readLine();
}else if(paragraph.contains("SECTION")){
sections.add(new Section(paragraph.replace("SECTION ", ""), text.size() + 1, this.width/2 + 7,
this.height/2 - this.ySize/2 + 14 + (sections.size()+2)*this.fontRendererObj.FONT_HEIGHT, nextButtonId++));
paragraph = bufferedreader.readLine();
}else if(paragraph.contains("IMAGE")){
if(paragraph.contains("WORKBENCH")){
this.guiPage = text.size() + 1;
}else if(paragraph.contains("CRYSTAL")){
this.imagePage = text.size() + 1;
}
paragraph = bufferedreader.readLine();
}else{
paragraph = paragraph.replaceAll("NEXT_SPELL_KEY", Keyboard.getKeyName(ClientProxy.NEXT_SPELL.getKeyCode()));
paragraph = paragraph.replaceAll("PREVIOUS_SPELL_KEY", Keyboard.getKeyName(ClientProxy.PREVIOUS_SPELL.getKeyCode()));
paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL_MINUS_30", "" + (Constants.MANA_PER_CRYSTAL - 30));
paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL", "" + Constants.MANA_PER_CRYSTAL);
paragraph = paragraph.replaceAll("BASIC_MAX_CHARGE", "" + Tier.BASIC.maxCharge);
paragraph = paragraph.replaceAll("APPRENTICE_MAX_CHARGE", "" + Tier.APPRENTICE.maxCharge);
paragraph = paragraph.replaceAll("ADVANCED_MAX_CHARGE", "" + Tier.ADVANCED.maxCharge);
paragraph = paragraph.replaceAll("MASTER_MAX_CHARGE", "" + Tier.MASTER.maxCharge);
paragraph = paragraph.replaceAll("BASIC_COLOUR", "\u00A77");
paragraph = paragraph.replaceAll("APPRENTICE_COLOUR", Tier.APPRENTICE.getFormattingCode());
paragraph = paragraph.replaceAll("ADVANCED_COLOUR", Tier.ADVANCED.getFormattingCode());
paragraph = paragraph.replaceAll("MASTER_COLOUR", Tier.MASTER.getFormattingCode());
paragraph = paragraph.replaceAll("FIRE_COLOUR", Element.FIRE.getFormattingCode());
paragraph = paragraph.replaceAll("ICE_COLOUR", Element.ICE.getFormattingCode());
paragraph = paragraph.replaceAll("LIGHTNING_COLOUR", Element.LIGHTNING.getFormattingCode());
paragraph = paragraph.replaceAll("NECROMANCY_COLOUR", Element.NECROMANCY.getFormattingCode());
paragraph = paragraph.replaceAll("EARTH_COLOUR", Element.EARTH.getFormattingCode());
paragraph = paragraph.replaceAll("SORCERY_COLOUR", Element.SORCERY.getFormattingCode());
paragraph = paragraph.replaceAll("HEALING_COLOUR", Element.HEALING.getFormattingCode());
paragraph = paragraph.replaceAll("RESET_COLOUR", "\u00A70");
paragraph = paragraph.replaceAll("VERSION", Wizardry.VERSION);
int linesInParagraph = this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH).size();
// Ignores empty lines at the top of a page.
if(paragraph.isEmpty() && lineNumber == 0){
paragraph = bufferedreader.readLine();
// Normal paragraph, all on one page
}else if(lineNumber + linesInParagraph <= linesPerPage){
page.add(paragraph);
lineNumber += linesInParagraph;
paragraph = bufferedreader.readLine();
// Paragraphs split across two pages (or more?)
}else{
int linesInFirstPart = linesPerPage - lineNumber;
String paragraphFirstPart = "";
String paragraphLastPart = "";
int i = 0;
List<String> strings = this.fontRendererObj.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH);
for(Object s : strings){
if(i < linesInFirstPart){
paragraphFirstPart = paragraphFirstPart.concat((String)s + " ");
}else{
paragraphLastPart = paragraphLastPart.concat((String)s + " ");
}
i++;
}
//System.out.println("Paragraph crosses page boundary; string split into: \"" + paragraphFirstPart + "\" and \"" + paragraphLastPart + "\"");
page.add(paragraphFirstPart);
lineNumber += linesInFirstPart;
paragraph = paragraphLastPart;
}
}
}
text.add(page);
} catch (IOException e){
Wizardry.logger.error("Something went wrong reading file: " + textFilepath + ". The file may be damaged;"
+ "please try re-downloading and reinstalling wizardry.", e);
}
}
}
private class Section {
/** The integer text colour used for the section when it is moused over. Currently orange. */
private static final int HIGHLIGHT_COLOUR = 0xdd4c1d;
String name;
int pageNumber;
int x, y;
int buttonId;
Section(String name, int pageNumber, int x, int y, int id){
this.name = name;
this.pageNumber = pageNumber;
this.x = x;
this.y = y;
this.buttonId = id;
GuiWizardHandbook.this.buttonList.add(new GuiButtonInvisible(id, x, y, GuiWizardHandbook.PAGE_WIDTH, GuiWizardHandbook.this.fontRendererObj.FONT_HEIGHT));
}
void hideButton(){
GuiWizardHandbook.this.buttonList.get(buttonId).visible = false;
}
void drawContents(){
GuiWizardHandbook.this.buttonList.get(buttonId).visible = true;
GuiWizardHandbook.this.fontRendererObj.drawString(name, x, y, GuiWizardHandbook.this.buttonList.get(buttonId).isMouseOver() ? HIGHLIGHT_COLOUR : BLACK);
int nameWidth = GuiWizardHandbook.this.fontRendererObj.getStringWidth(name);
String dotsAndNumber = " " + this.pageNumber;
while(GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){
dotsAndNumber = "." + dotsAndNumber;
}
GuiWizardHandbook.this.fontRendererObj.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber), y, BLACK);
}
}
@Override
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
*/
@Override
protected void actionPerformed(GuiButton par1GuiButton){
if(par1GuiButton.enabled){
if(par1GuiButton.id == 0){
if(pageNumber < (text.size()-1)/2) pageNumber++;
}else if(par1GuiButton.id == 1){
if(pageNumber > 0) pageNumber--;
}else{
if(pageNumber == 1) pageNumber = (sections.get(par1GuiButton.id - 2).pageNumber-1)/2;
}
}
}
/**
* Args: left, top, width, height, pointX, pointY. Note: left, top are local to Gui, pointX, pointY are local to
* screen
*/
protected boolean isPointInRegion(int par1, int par2, int par3, int par4, int par5, int par6)
{
int k1 = this.width/2 - xSize/2;
int l1 = this.height/2 - this.ySize/2;
par5 -= k1;
par6 -= l1;
return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1;
}
/**
* Draws a textured rectangle, stretching the section of the image to fit the size given.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the image width
* @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the image width
* @param finalWidth The width as rendered
* @param finalHeight The height as rendered
* @param width The width of the section, expressed as a fraction of the image width
* @param height The height of the section, expressed as a fraction of the image width
*/
public static void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width, int height){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((x), y + finalHeight, 0).tex(u, v + height).endVertex();
buffer.pos(x + finalWidth, y + finalHeight, 0).tex(u + width, v + height).endVertex();
buffer.pos(x + finalWidth, (y), 0).tex(u + width, v).endVertex();
buffer.pos((x), (y), 0).tex(u, v).endVertex();
tessellator.draw();
}
}
@@ -0,0 +1,94 @@
package electroblob.wizardry.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/** Font renderer that renders parts of strings surrounded by '#' (without quotes) in the SGA instead of normal text.
* @since Wizardry 1.1 */
@SideOnly(Side.CLIENT)
public class MixedFontRenderer extends FontRenderer {
public MixedFontRenderer(GameSettings p_i1035_1_, ResourceLocation p_i1035_2_, TextureManager p_i1035_3_,
boolean p_i1035_4_) {
super(p_i1035_1_, p_i1035_2_, p_i1035_3_, p_i1035_4_);
}
@Override
public int drawString(String string, float x, float y, int colour, boolean shadow){
int l = 0;
boolean sga = false;
while(string.indexOf('#') > -1){
String section = string.substring(0, string.indexOf('#'));
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(section, x, y, colour, shadow);
x += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRendererObj.drawString(section, x, y, colour, shadow);
x += Minecraft.getMinecraft().fontRendererObj.getStringWidth(section);
}
string = string.substring(string.indexOf('#') + 1);
sga = !sga;
}
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(string, x, y, colour, shadow);
}else{
l += Minecraft.getMinecraft().fontRendererObj.drawString(string, x, y, colour, shadow);
}
return l;
}
@Override
public int getStringWidth(String string){
int l = 0;
boolean sga = false;
while(string.indexOf('#') > -1){
String section = string.substring(0, string.indexOf('#'));
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRendererObj.getStringWidth(section);
}
string = string.substring(string.indexOf('#') + 1);
sga = !sga;
}
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(string);
}else{
l += Minecraft.getMinecraft().fontRendererObj.getStringWidth(string);
}
return l;
}
// This doesn't work the same way yet
@Override
public void drawSplitString(String string, int x, int y, int width, int colour){
if(string.contains("#")){
Minecraft.getMinecraft().standardGalacticFontRenderer.drawSplitString(string.substring(1), x, y, width, colour);
}else{
Minecraft.getMinecraft().fontRendererObj.drawSplitString(string, x, y, width, colour);
}
}
}
@@ -0,0 +1,59 @@
package electroblob.wizardry.client;
import net.minecraft.client.audio.MovingSound;
import net.minecraft.entity.Entity;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// Copied from MovingSoundMinecart; if it ever breaks between updates take a look at that.
@SideOnly(Side.CLIENT)
public class MovingSoundEntity extends MovingSound
{
private final Entity source;
private float distance = 0.0F;
public MovingSoundEntity(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat)
{
// Uses BLOCKS because that's the closest thing to inanimate entities. Could use NEUTRAL like MovingSoundMinecart.
super(sound, SoundCategory.BLOCKS);
this.source = entity;
this.repeat = repeat;
this.volume = volume;
this.pitch = pitch;
this.repeatDelay = 0;
}
/**
* Updates the JList with a new model.
*/
@Override
public void update()
{
if (this.source.isDead && repeat)
{
this.donePlaying = true;
}
else
{
this.xPosF = (float)this.source.posX;
this.yPosF = (float)this.source.posY;
this.zPosF = (float)this.source.posZ;
float f = MathHelper.sqrt_double(this.source.motionX * this.source.motionX + this.source.motionY * this.source.motionY + this.source.motionZ * this.source.motionZ);
// Is this something to do with the Doppler effect?
if ((double)f >= 0.01D)
{
this.distance = MathHelper.clamp_float(this.distance + 0.0025F, 0.0F, 1.0F);
this.volume = 0.0F + MathHelper.clamp_float(f, 0.0F, 0.5F) * 0.7F;
}
else
{
//this.pitch = 0.0F;
//this.volume = 0.0F;
}
}
}
}
@@ -0,0 +1,752 @@
package electroblob.wizardry.client;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Flight;
import electroblob.wizardry.spell.ShadowWard;
import electroblob.wizardry.spell.Shield;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
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.math.RayTraceResult;
import net.minecraftforge.client.event.FOVUpdateEvent;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
/**
* Event handler responsible for all client-side only events, mostly rendering.
* @author Electroblob
* @since Wizardry 1.0
*/
@Mod.EventBusSubscriber(Side.CLIENT)
public final class WizardryClientEventHandler {
private static final ResourceLocation shieldTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shield.png");
private static final ResourceLocation wingTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/wing.png");
private static final ResourceLocation shadowWardTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shadow_ward.png");
private static final ResourceLocation sixthSenseTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/sixth_sense.png");
private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/sixth_sense_overlay.png");
private static final ResourceLocation frostOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_overlay.png");
private static final ResourceLocation pointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/pointer.png");
private static final ResourceLocation targetPointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/target_pointer.png");
@SubscribeEvent
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL);
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE);
}
// Shift-scrolling to change spells
@SubscribeEvent
public static void onMouseEvent(MouseEvent event){
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
ItemStack wand = player.getHeldItemMainhand();
if(wand == null || !(wand.getItem() instanceof ItemWand)){
wand = player.getHeldItemOffhand();
// If the player isn't holding a wand, then nothing else needs to be done.
if(wand == null || !(wand.getItem() instanceof ItemWand)) return;
}
if(Minecraft.getMinecraft().inGameHasFocus && wand != null && event.getDwheel() != 0 && player.isSneaking()
&& Wizardry.settings.enableShiftScrolling){
event.setCanceled(true);
if(event.getDwheel() > 0){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}else if(event.getDwheel() < 0){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
@SubscribeEvent
public static void onFOVUpdateEvent(FOVUpdateEvent event){
// Bow zoom. Taken directly from AbstractClientPlayer so it works exactly like vanilla.
if(event.getEntity().isHandActive() && event.getEntity().getActiveItemStack() != null
&& event.getEntity().getActiveItemStack().getItem() instanceof ItemSpectralBow){
int maxUseTicks = event.getEntity().getItemInUseMaxCount();
float maxUseSeconds = (float)maxUseTicks / 20.0F;
if(maxUseSeconds > 1.0F){
maxUseSeconds = 1.0F;
}else{
maxUseSeconds = maxUseSeconds * maxUseSeconds;
}
event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F);
}
}
// Third person
@SubscribeEvent
public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){
renderShieldIfActive(event.getEntityPlayer());
renderWingsIfActive(event.getEntityPlayer(), event.getPartialRenderTick());
renderShadowWardIfActive(event.getEntityPlayer());
}
// First person
@SubscribeEvent
public static void onRenderWorldLastEvent(RenderWorldLastEvent event){
// Now only fires in first person.
if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){
renderShieldFirstPerson(Minecraft.getMinecraft().thePlayer);
renderShadowWardFirstPerson(Minecraft.getMinecraft().thePlayer);
}
}
@SubscribeEvent
public static void onRenderLivingEvent(RenderLivingEvent.Post<EntityLivingBase> event){
/*
// Frost effect
if(event.entity.isPotionActive(Wizardry.frost)){
GlStateManager.pushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float someScalingFactor = 0.0625f;
float yaw = event.entity.prevRotationYaw;
//int brightness = event.entity.getBrightnessForRender(0);
//int j = brightness % 65536;
//int k = brightness / 65536;
//OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
//GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.translate(event.x, event.y, event.z);
GlStateManager.rotate(-yaw + 180, 0F, 1F, 0F);
Render render = renderManager.getEntityRenderObject(event.entity);
RenderLiving renderliving = event.renderer;
// Reflection
try {
Timer timer = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "timer");
// Chooses the appropriate zombie model, normal or villager
// Fixed by moving before the model fields are accessed
if(render instanceof RenderZombie && event.entity instanceof EntityZombie){
// The second argument is never used...
ReflectionHelper.findMethod(RenderZombie.class, (RenderZombie)render, new String[]{"func_82427_a"}, EntityZombie.class)
.invoke(renderliving, (EntityZombie)event.entity);
}
// Turns out that java automatically infers the type parameter T in this method from the type
// I am assigning the returned value to. Neat!
ModelBase mainModel = ReflectionHelper.getPrivateValue(RenderLiving.class, renderliving, "mainModel");
mainModel.isRiding = event.entity.isRiding();
mainModel.isChild = event.entity.isChild();
GlStateManager.enableRescaleNormal();
GlStateManager.scale(-1.0F, -1.0F, 1.0F);
// The second argument is never used...
ReflectionHelper.findMethod(RenderLiving.class, renderliving, new String[]{"preRenderCallback"}, EntityLivingBase.class, float.class)
.invoke(renderliving, event.entity, someScalingFactor);
// Why is this -1.5f? No idea!
GlStateManager.translate(0, -1.5f, 0);
float f6 = event.entity.prevLimbSwingAmount + (event.entity.limbSwingAmount - event.entity.prevLimbSwingAmount) * timer.renderPartialTicks;
float f7 = event.entity.limbSwing - event.entity.limbSwingAmount * (1.0F - timer.renderPartialTicks);
if (event.entity.isChild())
{
f7 *= 3.0F;
}
if (f6 > 1.0F)
{
f6 = 1.0F;
}
mainModel.setLivingAnimations(event.entity, f7, f6, timer.renderPartialTicks);
GlStateManager.enableAlpha();
GlStateManager.color(0.5f, 0.7f, 1, 0.5f);
mainModel.render(event.entity, f7, f6, 0, 0, 0, someScalingFactor);
GL11.glDepthMask(true);
// 'Pokemon' exception handling... Because why not?!
} catch (Exception e) {
System.err.println("Something went very wrong! Error while rendering frost effect:");
e.printStackTrace();
}
GlStateManager.disableAlpha();
GlStateManager.disableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableRescaleNormal();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GlStateManager.popMatrix();
}
*/
Minecraft mc = Minecraft.getMinecraft();
WizardData properties = WizardData.get(mc.thePlayer);
RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.theWorld, mc.thePlayer, 16);
RenderManager renderManager = event.getRenderer().getRenderManager();
ItemStack wand = mc.thePlayer.getHeldItemMainhand();
if(wand == null || !(wand.getItem() instanceof ItemWand)){
wand = mc.thePlayer.getHeldItemOffhand();
}
// Target selection pointer
if(mc.thePlayer.isSneaking() && wand != null && wand.getItem() instanceof ItemWand && rayTrace != null
&& rayTrace.entityHit instanceof EntityLivingBase && rayTrace.entityHit == event.getEntity()
&& properties != null && properties.selectedMinion != null){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
mc.renderEngine.bindTexture(targetPointerTexture);
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
buffer.pos(0.2, 0.24, 0).tex(9f/16f, 0).endVertex();
buffer.pos(0.2, -0.24, 0).tex(9f/16f, 11f/16f).endVertex();
buffer.pos(-0.2, -0.24, 0).tex(0, 11f/16f).endVertex();
tessellator.draw();
GlStateManager.enableCull();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.popMatrix();
}
// Summoned creature selection pointer
if(properties != null && properties.selectedMinion != null && properties.selectedMinion.get() == event.getEntity()){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
mc.renderEngine.bindTexture(pointerTexture);
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
buffer.pos(0.2, 0.24, 0).tex(9f/16f, 0).endVertex();
buffer.pos(0.2, -0.24, 0).tex(9f/16f, 11f/16f).endVertex();
buffer.pos(-0.2, -0.24, 0).tex(0, 11f/16f).endVertex();
tessellator.draw();
GlStateManager.enableCull();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.popMatrix();
}
// Sixth sense
if(mc.thePlayer.isPotionActive(WizardryPotions.sixth_sense) && event.getEntity() != mc.thePlayer
&& mc.thePlayer.getActivePotionEffect(WizardryPotions.sixth_sense) != null
&& event.getEntity().getDistanceToEntity(mc.thePlayer) < 20*(1+mc.thePlayer.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier()*Constants.RANGE_INCREASE_PER_LEVEL)){
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height * 0.6, event.getZ());
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
mc.renderEngine.bindTexture(sixthSenseTexture);
buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex();
buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex();
buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex();
buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.popMatrix();
}
}
@SubscribeEvent
public static void onRenderGameOverlayEvent(RenderGameOverlayEvent.Post event){
if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET
&& Minecraft.getMinecraft().thePlayer.isPotionActive(WizardryPotions.sixth_sense)){
GlStateManager.pushMatrix();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDepthMask(false);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.disableAlpha();
Minecraft.getMinecraft().renderEngine.bindTexture(sixthSenseOverlayTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex();
buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex();
tessellator.draw();
GL11.glDepthMask(true);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.enableAlpha();
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.popMatrix();
}
if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET
&& Minecraft.getMinecraft().thePlayer.isPotionActive(WizardryPotions.frost)){
GlStateManager.pushMatrix();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDepthMask(false);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.disableAlpha();
Minecraft.getMinecraft().renderEngine.bindTexture(frostOverlayTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D).endVertex();
buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex();
buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex();
tessellator.draw();
GL11.glDepthMask(true);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GlStateManager.enableAlpha();
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.popMatrix();
}
}
// FIXME: Something in here is making the first person shadow ward rather translucent.
private static void renderShadowWardFirstPerson(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isHandActive() && wand != null && wand.getItemDamage() < wand.getMaxDamage()
&& wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
GlStateManager.disableAlpha();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.translate(0, 1.2, 0);
GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0);
GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture);
GlStateManager.pushMatrix();
GlStateManager.translate(0, 0, 1.2);
GlStateManager.rotate(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1);
GlStateManager.scale(1.1, 1.1, 1.1);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
private static void renderShadowWardIfActive(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.rotate(180, 0, 1, 0);
GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.translate(0, 1.2, 0);
GlStateManager.rotate(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1);
GlStateManager.scale(1.1, 1.1, 1.1);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex();
buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex();
buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex();
buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
private static void renderWingsIfActive(EntityPlayer entityplayer, float partialTickTime){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer).currentlyCasting() instanceof Flight || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Flight)){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
//GlStateManager.rotate(-entityplayer.rotationYawHead, 0, 1, 0);
GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0);
//GlStateManager.rotate(180, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(wingTexture);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.translate(0.1, 0.4, -0.15);
GlStateManager.rotate(20 + 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.pushMatrix();
GlStateManager.translate(-0.1, 0.4, -0.15);
GlStateManager.rotate(-200 - 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 2, 0).tex(0, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
buffer.pos(2, 0, 0).tex(1, 1).endVertex();
buffer.pos(2, 2, 0).tex(1, 0).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
private static void renderShieldFirstPerson(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.translate(0, 1.4, 0);
GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0);
GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0);
GlStateManager.translate(0, 0, 0.8);
Tessellator tessellator = Tessellator.getInstance();
Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture);
renderShield(tessellator);
GlStateManager.enableLighting();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
//RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
}
private static void renderShieldIfActive(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getActiveItemStack();
if(WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isHandActive() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
// For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the inner
// edges to appear black, so I have changed it to this, which looks very slightly different.
GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.translate(0, 1.3, 0);
//GlStateManager.rotate(180, 0, 1, 0);
GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0);
//GlStateManager.rotate(-entityplayer.rotationPitch, 1, 0, 0);
GlStateManager.translate(0, 0, 0.8);
Tessellator tessellator = Tessellator.getInstance();
Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture);
renderShield(tessellator);
GlStateManager.enableLighting();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
//RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
}
private static void renderShield(Tessellator tessellator){
VertexBuffer buffer = tessellator.getBuffer();
double widthOuter = 0.6d;
double heightOuter = 0.7d;
double widthInner = 0.3d;
double heightInner = 0.4d;
double depth = 0.2d;
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthInner, heightOuter, -depth).tex(0.2, 0).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, heightOuter, -depth).tex(0.8, 0).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthOuter, heightInner, -depth).tex(1, 0.2).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthOuter, -heightInner, -depth).tex(1, 0.8).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, -heightOuter, -depth).tex(0.8, 1).color(0, 0, 0, 255).endVertex();
buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthInner, -heightOuter, -depth).tex(0.2, 1).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthOuter, -heightInner, -depth).tex(0, 0.8).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex();
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex();
buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex();
buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex();
tessellator.draw();
}
}
@@ -0,0 +1,83 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
public class ModelHammer extends ModelBase
{
ModelRenderer Shape1;
ModelRenderer Shape2;
ModelRenderer Shape3;
ModelRenderer Shape4;
ModelRenderer Shape5;
ModelRenderer Shape6;
public ModelHammer()
{
textureWidth = 64;
textureHeight = 64;
Shape1 = new ModelRenderer(this, 0, 0);
Shape1.addBox(0F, 0F, 0F, 20, 12, 12);
Shape1.setRotationPoint(-10F, 12F, -6F);
Shape1.setTextureSize(64, 64);
Shape1.mirror = true;
setRotation(Shape1, 0F, 0F, 0F);
Shape2 = new ModelRenderer(this, 0, 24);
Shape2.addBox(0F, 0F, 0F, 4, 14, 4);
Shape2.setRotationPoint(-2F, -2F, -2F);
Shape2.setTextureSize(64, 64);
Shape2.mirror = true;
setRotation(Shape2, 0F, 0F, 0F);
Shape3 = new ModelRenderer(this, 0, 49);
Shape3.addBox(0F, 0F, 0F, 5, 5, 5);
Shape3.setRotationPoint(-2.5F, -7F, -2.5F);
Shape3.setTextureSize(64, 64);
Shape3.mirror = true;
setRotation(Shape3, 0F, 0F, 0F);
Shape4 = new ModelRenderer(this, 0, 42);
Shape4.addBox(0F, 0F, 0F, 5, 2, 5);
Shape4.setRotationPoint(-2.5F, 10F, -2.5F);
Shape4.setTextureSize(64, 64);
Shape4.mirror = true;
setRotation(Shape4, 0F, 0F, 0F);
Shape5 = new ModelRenderer(this, 20, 24);
Shape5.addBox(0F, 0F, 0F, 2, 14, 14);
Shape5.setRotationPoint(-8F, 11F, -7F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, 0F, 0F, 0F);
Shape6 = new ModelRenderer(this, 20, 24);
Shape6.addBox(0F, 0F, 0F, 2, 14, 14);
Shape6.setRotationPoint(6F, 11F, -7F);
Shape6.setTextureSize(64, 64);
Shape6.mirror = true;
setRotation(Shape6, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
Shape1.render(f5);
Shape2.render(f5);
Shape3.render(f5);
Shape4.render(f5);
Shape5.render(f5);
Shape6.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
}
@@ -0,0 +1,321 @@
package electroblob.wizardry.client.model;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import electroblob.wizardry.entity.living.EntityIceGiant;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ModelIceGiant extends ModelBase
{
/** The head model for the iron golem. */
public ModelRenderer iceGiantHead;
/** The body model for the iron golem. */
public ModelRenderer iceGiantBody;
/** The right arm model for the iron golem. */
public ModelRenderer iceGiantRightArm;
/** The left arm model for the iron golem. */
public ModelRenderer iceGiantLeftArm;
/** The left leg model for the Iron Golem. */
public ModelRenderer iceGiantLeftLeg;
/** The right leg model for the Iron Golem. */
public ModelRenderer iceGiantRightLeg;
ModelRenderer headSpike1;
ModelRenderer headSpike2;
ModelRenderer headSpike3;
ModelRenderer headSpike4;
ModelRenderer headSpike5;
ModelRenderer headSpike6;
ModelRenderer headSpike7;
ModelRenderer rightArmSpike1;
ModelRenderer rightArmSpike2;
ModelRenderer leftArmSpike1;
ModelRenderer leftArmSpike2;
ModelRenderer bodySpike1;
ModelRenderer bodySpike2;
ModelRenderer bodySpike3;
ModelRenderer bodySpike4;
ModelRenderer bodySpike5;
public ModelIceGiant()
{
this(0.0F);
}
public ModelIceGiant(float par1)
{
this(par1, -7.0F);
}
public ModelIceGiant(float par1, float par2)
{
short short1 = 128;
short short2 = 128;
this.iceGiantHead = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantHead.setRotationPoint(0.0F, 0.0F + par2, -1.0F);
this.iceGiantHead.setTextureOffset(0, 10).addBox(-6.0F, -14.0F, -6.5F, 12, 12, 12, par1);
this.iceGiantBody = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantBody.setRotationPoint(0.0F, 0.0F + par2, 0.0F);
this.iceGiantBody.setTextureOffset(0, 40).addBox(-9.0F, -2.0F, -6.0F, 18, 12, 11, par1);
this.iceGiantBody.setTextureOffset(0, 70).addBox(-4.5F, 10.0F, -3.0F, 9, 5, 6, par1 + 0.5F);
this.iceGiantRightArm = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantRightArm.setRotationPoint(0.0F, -7.0F, 0.0F);
this.iceGiantRightArm.setTextureOffset(60, 21).addBox(-13.0F, -2.5F, -3.0F, 4, 30, 6, par1);
this.iceGiantLeftArm = (new ModelRenderer(this)).setTextureSize(short1, short2);
this.iceGiantLeftArm.setRotationPoint(0.0F, -7.0F, 0.0F);
this.iceGiantLeftArm.setTextureOffset(60, 58).addBox(9.0F, -2.5F, -3.0F, 4, 30, 6, par1);
this.iceGiantLeftLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);
this.iceGiantLeftLeg.setRotationPoint(-4.0F, 18.0F + par2, 0.0F);
this.iceGiantLeftLeg.setTextureOffset(37, 0).addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);
this.iceGiantRightLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);
this.iceGiantRightLeg.mirror = true;
this.iceGiantRightLeg.setTextureOffset(60, 0).setRotationPoint(5.0F, 18.0F + par2, 0.0F);
this.iceGiantRightLeg.addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);
headSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike1.addBox(-4F, -4F, 0F, 4, 4, 4);
headSpike1.setRotationPoint(-4F, -10F, -5F);
headSpike1.mirror = true;
setRotationWithEulerYzx(headSpike1, -0.1047198F, -0.5235988F, 0.9599311F);
headSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike2.addBox(0F, -4F, 0F, 4, 4, 4);
headSpike2.setRotationPoint(4F, -16F, 0F);
headSpike2.mirror = true;
setRotationWithEulerYzx(headSpike2, 0.5585054F, 0.9250245F, -0.5235988F);
headSpike3 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike3.addBox(-2F, -2F, -2F, 4, 4, 4);
headSpike3.setRotationPoint(4F, -13F, 4F);
headSpike3.mirror = true;
setRotationWithEulerYzx(headSpike3, 0.7853982F, -1.396263F, 0.7853982F);
headSpike4 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike4.addBox(-4F, -4F, 0F, 4, 4, 4);
headSpike4.setRotationPoint(-4F, -16F, 0F);
headSpike4.mirror = true;
setRotationWithEulerYzx(headSpike4, 0.5585054F, -0.9250245F, 0.5235988F);
headSpike5 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike5.addBox(0F, -4F, 0F, 4, 4, 4);
headSpike5.setRotationPoint(4F, -10F, -5F);
headSpike5.mirror = true;
setRotationWithEulerYzx(headSpike5, 0.5235988F, -0.9599311F, 0.1047198F);
rightArmSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
rightArmSpike1.addBox(-2F, -2F, -2F, 4, 4, 4);
rightArmSpike1.setRotationPoint(-11F, -8F, 0F);
rightArmSpike1.mirror = true;
setRotationWithEulerYzx(rightArmSpike1, 0.7853982F, 1.134464F, 0.9599311F);
headSpike6 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike6.addBox(-2F, -2F, -2F, 4, 4, 4);
headSpike6.setRotationPoint(-4F, -13F, 4F);
headSpike6.mirror = true;
setRotationWithEulerYzx(headSpike6, 0.7853982F, -1.745329F, 0.7853982F);
leftArmSpike1 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
leftArmSpike1.addBox(-2F, -2F, -2F, 4, 4, 4);
leftArmSpike1.setRotationPoint(11F, -8F, 0F);
leftArmSpike1.mirror = true;
setRotationWithEulerYzx(leftArmSpike1, 0.7853982F, -1.134464F, -0.9599311F);
leftArmSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
leftArmSpike2.addBox(-2F, -2F, -2F, 4, 4, 4);
leftArmSpike2.setRotationPoint(12F, -4F, 0F);
leftArmSpike2.mirror = true;
setRotationWithEulerYzx(leftArmSpike2, 0.7853982F, 0F, -0.9599311F);
bodySpike1 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2);
bodySpike1.addBox(-3F, -3F, -3F, 6, 6, 6);
bodySpike1.setRotationPoint(-4F, -4F, 3F);
bodySpike1.mirror = true;
setRotationWithEulerYzx(bodySpike1, 0.2808018F, 0.8096675F, 0.8339369F);
rightArmSpike2 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
rightArmSpike2.addBox(-2F, -2F, -2F, 4, 4, 4);
rightArmSpike2.setRotationPoint(-12F, -4F, 0F);
rightArmSpike2.mirror = true;
setRotationWithEulerYzx(rightArmSpike2, 0.7853982F, 0F, 0.9599311F);
bodySpike2 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2);
bodySpike2.addBox(-3F, -3F, -3F, 6, 6, 6);
bodySpike2.setRotationPoint(4F, -4F, 3F);
bodySpike2.mirror = true;
setRotationWithEulerYzx(bodySpike2, 0.2808018F, -0.8096757F, -0.8339358F);
bodySpike3 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
bodySpike3.addBox(-2F, -2F, -2F, 4, 4, 4);
bodySpike3.setRotationPoint(6F, -2F, -5F);
bodySpike3.mirror = true;
setRotationWithEulerYzx(bodySpike3, 1.120006F, -1.347726F, -0.8969422F);
bodySpike4 = new ModelRenderer(this, 32, 69).setTextureSize(short1, short2);
bodySpike4.addBox(-3F, -3F, -3F, 6, 6, 6);
bodySpike4.setRotationPoint(0F, -4F, -4F);
bodySpike4.mirror = true;
setRotationWithEulerYzx(bodySpike4, 0.7853982F, -1.570796F, 0.9599311F);
headSpike7 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
headSpike7.addBox(-2F, -2F, -2F, 4, 4, 4);
headSpike7.setRotationPoint(0F, -20F, 4F);
headSpike7.mirror = true;
setRotationWithEulerYzx(headSpike7, 0.7853982F, 1.570796F, 0.7853982F);
bodySpike5 = new ModelRenderer(this, 0, 0).setTextureSize(short1, short2);
bodySpike5.addBox(-2F, -2F, -2F, 4, 4, 4);
bodySpike5.setRotationPoint(-6F, -2F, -5F);
bodySpike5.mirror = true;
setRotationWithEulerYzx(bodySpike5, 1.120006F, 1.347725F, 0.896934F);
this.convertToChild(this.iceGiantHead, headSpike1);
this.convertToChild(this.iceGiantHead, headSpike2);
this.convertToChild(this.iceGiantHead, headSpike3);
this.convertToChild(this.iceGiantHead, headSpike4);
this.convertToChild(this.iceGiantHead, headSpike5);
this.convertToChild(this.iceGiantHead, headSpike6);
this.convertToChild(this.iceGiantHead, headSpike7);
this.convertToChild(this.iceGiantRightArm, rightArmSpike1);
this.convertToChild(this.iceGiantRightArm, rightArmSpike2);
this.convertToChild(this.iceGiantLeftArm, leftArmSpike1);
this.convertToChild(this.iceGiantLeftArm, leftArmSpike2);
this.convertToChild(this.iceGiantBody, bodySpike1);
this.convertToChild(this.iceGiantBody, bodySpike2);
this.convertToChild(this.iceGiantBody, bodySpike3);
this.convertToChild(this.iceGiantBody, bodySpike4);
this.convertToChild(this.iceGiantBody, bodySpike5);
}
/**
* Sets the models various rotation angles then renders the model.
*/
public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7)
{
this.setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity);
this.iceGiantHead.render(par7);
this.iceGiantBody.render(par7);
this.iceGiantLeftLeg.render(par7);
this.iceGiantRightLeg.render(par7);
this.iceGiantRightArm.render(par7);
this.iceGiantLeftArm.render(par7);
}
/**
* Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms
* and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how
* "far" arms and legs can swing at most.
*/
public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity)
{
this.iceGiantHead.rotateAngleY = par4 / (180F / (float)Math.PI);
this.iceGiantHead.rotateAngleX = par5 / (180F / (float)Math.PI);
this.iceGiantLeftLeg.rotateAngleX = -1.5F * this.func_78172_a(par1, 13.0F) * par2;
this.iceGiantRightLeg.rotateAngleX = 1.5F * this.func_78172_a(par1, 13.0F) * par2;
this.iceGiantLeftLeg.rotateAngleY = 0.0F;
this.iceGiantRightLeg.rotateAngleY = 0.0F;
}
/**
* Used for easily adding entity-dependent animations. The second and third float params here are the same second
* and third as in the setRotationAngles method.
*/
public void setLivingAnimations(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4)
{
EntityIceGiant entityicegiant = (EntityIceGiant)par1EntityLivingBase;
int i = entityicegiant.getAttackTimer();
if (i > 0)
{
this.iceGiantRightArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);
this.iceGiantLeftArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);
}
else
{
this.iceGiantRightArm.rotateAngleX = (-0.2F + 1.5F * this.func_78172_a(par2, 13.0F)) * par3;
this.iceGiantLeftArm.rotateAngleX = (-0.2F - 1.5F * this.func_78172_a(par2, 13.0F)) * par3;
}
}
private float func_78172_a(float par1, float par2)
{
return (Math.abs(par1 % par2 - par2 * 0.5F) - par2 * 0.25F) / (par2 * 0.25F);
}
/** This is really useful for converting the source from a Techne model export
* which will have absolute rotation points that need to be converted before
* creating the addChild() relationship. [Courtesy of jabelar] */
protected void convertToChild(ModelRenderer parent, ModelRenderer child)
{
// move child rotation point to be relative to parent
child.rotationPointX -= parent.rotationPointX;
child.rotationPointY -= parent.rotationPointY;
child.rotationPointZ -= parent.rotationPointZ;
// make rotations relative to parent
child.rotateAngleX -= parent.rotateAngleX;
child.rotateAngleY -= parent.rotateAngleY;
child.rotateAngleZ -= parent.rotateAngleZ;
// create relationship
parent.addChild(child);
}
/** Fixes the Techne rotation order bug. [Courtesy of tprk77] */
private Vector3f ConvertEulerYzxToZyx(Vector3f eulerYzx) {
// Create a matrix from YZX ordered Euler angles
float a = MathHelper.cos(eulerYzx.x);
float b = MathHelper.sin(eulerYzx.x);
float c = MathHelper.cos(eulerYzx.y);
float d = MathHelper.sin(eulerYzx.y);
float e = MathHelper.cos(eulerYzx.z);
float f = MathHelper.sin(eulerYzx.z);
Matrix4f matrix = new Matrix4f();
matrix.m00 = c * e;
matrix.m01 = b * d - a * c * f;
matrix.m02 = b * c * f + a * d;
matrix.m10 = f;
matrix.m11 = a * e;
matrix.m12 = -b * e;
matrix.m20 = -d * e;
matrix.m21 = a * d * f + b * c;
matrix.m22 = a * c - b * d * f;
matrix.m33 = 1.0F;
// Create ZYX ordered Euler angles from the matrix
Vector3f eulerZyx = new Vector3f();
eulerZyx.y = (float) Math.asin(MathHelper.clamp_float(-matrix.m20, -1, 1));
if (MathHelper.abs(matrix.m20) < 0.99999) {
eulerZyx.x = (float) Math.atan2(matrix.m21, matrix.m22);
eulerZyx.z = (float) Math.atan2(matrix.m10, matrix.m00);
} else {
eulerZyx.x = 0.0F;
eulerZyx.z = (float) Math.atan2(-matrix.m01, matrix.m11);
}
return eulerZyx;
}
private void setRotationWithEulerYzx(ModelRenderer model, float x, float y, float z) {
Vector3f eulerYzx = new Vector3f(x, y, z);
Vector3f eulerZyx = ConvertEulerYzxToZyx(eulerYzx);
model.rotateAngleX = eulerZyx.x;
model.rotateAngleY = eulerZyx.y;
model.rotateAngleZ = eulerZyx.z;
}
}
@@ -0,0 +1,139 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
public class ModelPhoenix extends ModelBase {
ModelRenderer body;
ModelRenderer rightWing;
ModelRenderer leftWing;
ModelRenderer tailFeathers;
ModelRenderer tail;
ModelRenderer head;
ModelRenderer neck;
ModelRenderer beak;
ModelRenderer plume;
public ModelPhoenix()
{
textureWidth = 64;
textureHeight = 64;
/* For future reference:
* - setRotationPoint sets the origin of a part relative to that of its parent.
* - The first 3 arguments of addBox set the position of a part relative to its rotation point, and the last
* 3 arguments are the size of the part.
* (This means that rotation point and position seem to be the wrong way round, since changing the rotation point
* will move the component without changing which point on the component it rotates about.)
* - The two integer arguments in the ModelRenderer constructor are the texture offset.
* - Mirror does nothing unless you set it before addBox.
* - Rotation is the usual pitch, yaw, roll.
*/
body = new ModelRenderer(this, 0, 34);
body.addBox(0F, 0F, -3F, 6, 15, 6);
body.setRotationPoint(-3F, 0F, -5F);
body.setTextureSize(64, 64);
body.mirror = true;
setRotation(body, 0.296706F, 0F, 0F);
rightWing = new ModelRenderer(this, 0, 0);
rightWing.mirror = true;
rightWing.addBox(-27F, -27F, 0F, 27, 34, 0);
rightWing.setRotationPoint(0F, 5F, 0F);
rightWing.setTextureSize(64, 64);
setRotation(rightWing, 0.1745329F, 0F, 0F);
leftWing = new ModelRenderer(this, 0, 0);
leftWing.addBox(0F, -27F, 0F, 27, 34, 0);
leftWing.setRotationPoint(6F, 5F, 0F);
leftWing.setTextureSize(64, 64);
setRotation(leftWing, 0.1745329F, 0F, 0F);
tailFeathers = new ModelRenderer(this, 0, 57);
tailFeathers.addBox(-5F, 0F, 0F, 10, 7, 0);
tailFeathers.setRotationPoint(0F, 7F, 1F);
tailFeathers.setTextureSize(64, 64);
tailFeathers.mirror = true;
setRotation(tailFeathers, 0.5235988F, 0F, 0F);
tail = new ModelRenderer(this, 20, 55);
tail.addBox(-1F, 0F, -1F, 2, 7, 2);
tail.setRotationPoint(3F, 15F, 2F);
tail.setTextureSize(64, 64);
tail.mirror = true;
setRotation(tail, 0.4014257F, 0F, 0F);
head = new ModelRenderer(this, 24, 34);
head.addBox(-2F, -4F, -5F, 4, 4, 6);
head.setRotationPoint(0F, -4F, 0F);
head.setTextureSize(64, 64);
head.mirror = true;
setRotation(head, 0F, 0F, 0F);
neck = new ModelRenderer(this, 24, 44);
neck.addBox(-1F, -4F, -1F, 2, 4, 2);
neck.setRotationPoint(0F, 0F, -4F);
neck.setTextureSize(64, 64);
neck.mirror = true;
setRotation(neck, 0.2443461F, 0F, 0F);
beak = new ModelRenderer(this, 32, 44);
beak.addBox(-0.5F, 4F, -1F, 1, 2, 3);
beak.setRotationPoint(0F, -5F, -8F);
beak.setTextureSize(64, 64);
beak.mirror = true;
setRotation(beak, 0.2792527F, 0F, 0F);
plume = new ModelRenderer(this, 28, 50);
plume.addBox(-0.03333334F, 1F, 0F, 0, 5, 5);
plume.setRotationPoint(0F, -7F, 0F);
plume.setTextureSize(64, 64);
plume.mirror = true;
setRotation(plume, 0F, 0F, 0F);
neck.addChild(head);
head.addChild(plume);
head.addChild(beak);
tail.addChild(tailFeathers);
body.addChild(tail);
body.addChild(rightWing);
body.addChild(leftWing);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
//float f6 = (180F / (float)Math.PI);
this.neck.rotateAngleX = f4 / (180F / (float)Math.PI);
this.neck.rotateAngleY = f3 / (180F / (float)Math.PI);
this.neck.rotateAngleZ = 0.0F;
this.body.rotateAngleX = 0.3f + MathHelper.cos(f2 * 0.1F) * 0.15F;
this.body.rotateAngleY = 0.0F;
this.tail.rotateAngleX = this.body.rotateAngleX * 1.1f;
this.tailFeathers.rotateAngleX = this.body.rotateAngleX * 1.2f;
this.rightWing.rotateAngleY = MathHelper.cos(f2 * 0.3F) * (float)Math.PI * 0.15F;
this.leftWing.rotateAngleY = -this.rightWing.rotateAngleY;
body.render(f5);
neck.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
}
@@ -0,0 +1,174 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelRenderer;
public class ModelWizard extends ModelBiped
{
//fields
ModelRenderer Shape5;
ModelRenderer Shape8;
ModelRenderer Shape9;
ModelRenderer Shape10;
ModelRenderer Shape7;
ModelRenderer Shape11;
ModelRenderer Shape12;
ModelRenderer beard;
ModelRenderer Shape13;
public ModelWizard()
{
//super(0, 0, 64, 32);
/*
bipedRightLeg = new ModelRenderer(this, 32, 0); // 32 and 0 are the x and y texture offsets respectively.
bipedRightLeg.addBox(-2F, 0F, -2F, 4, 12, 4); // x, y, z, u, v, w.
bipedRightLeg.setRotationPoint(-2F, 12F, 0F); // Rotation point xyz (absolute, not relative)
bipedRightLeg.setTextureSize(64, 64);
bipedRightLeg.mirror = true;
setRotation(bipedRightLeg, 0F, 0F, 0F);
bipedLeftLeg.mirror = true;
bipedLeftLeg = new ModelRenderer(this, 32, 0);
bipedLeftLeg.addBox(-2F, 0F, -2F, 4, 12, 4);
bipedLeftLeg.setRotationPoint(2F, 12F, 0F);
bipedLeftLeg.setTextureSize(64, 64);
bipedLeftLeg.mirror = true;
setRotation(bipedLeftLeg, 0F, 0F, 0F);
bipedLeftLeg.mirror = false;
bipedBody = new ModelRenderer(this, 0, 16);
bipedBody.addBox(0F, 0F, 0F, 8, 12, 4);
bipedBody.setRotationPoint(-4F, 0F, -2F);
bipedBody.setTextureSize(64, 64);
bipedBody.mirror = true;
setRotation(bipedBody, 0F, 0F, 0F);
bipedLeftArm.mirror = true;
bipedLeftArm = new ModelRenderer(this, 48, 0);
bipedLeftArm.addBox(-1F, 0F, -2F, 4, 12, 4);
bipedLeftArm.setRotationPoint(4F, 0F, 0F);
bipedLeftArm.setTextureSize(64, 64);
bipedLeftArm.mirror = true;
setRotation(bipedLeftArm, 0F, 0F, 0F);
bipedLeftArm.mirror = false;
bipedRightArm = new ModelRenderer(this, 48, 0);
bipedRightArm.addBox(-3F, 0F, -2F, 4, 12, 4);
bipedRightArm.setRotationPoint(-4F, 0F, 0F);
bipedRightArm.setTextureSize(64, 64);
bipedRightArm.mirror = true;
setRotation(bipedRightArm, 0F, 0F, 0F);
bipedHead = new ModelRenderer(this, 0, 0);
bipedHead.addBox(-4F, -8F, -4F, 8, 8, 8);
bipedHead.setRotationPoint(0F, 0F, 0F);
bipedHead.setTextureSize(64, 64);
bipedHead.mirror = true;
setRotation(bipedHead, 0F, 0F, 0F);
*/
Shape5 = new ModelRenderer(this, 0, 51);
Shape5.addBox(0F, 0F, 0F, 12, 1, 12);
Shape5.setRotationPoint(-6F, -7F, -6F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, 0F, 0F, 0F);
Shape8 = new ModelRenderer(this, 0, 32);
Shape8.addBox(0F, 0F, 0F, 6, 1, 6);
Shape8.setRotationPoint(-3F, -9F, -3F);
Shape8.setTextureSize(64, 64);
Shape8.mirror = true;
setRotation(Shape8, -0.0349066F, 0F, 0F);
Shape9 = new ModelRenderer(this, 24, 32);
Shape9.addBox(0F, 0F, 0F, 3, 3, 3);
Shape9.setRotationPoint(-1.5F, -13F, -0.5F);
Shape9.setTextureSize(64, 64);
Shape9.mirror = true;
setRotation(Shape9, -0.2511622F, 0F, 0F);
Shape10 = new ModelRenderer(this, 0, 39);
Shape10.addBox(0F, 0F, 0F, 5, 1, 5);
Shape10.setRotationPoint(-2.5F, -10F, -2.5F);
Shape10.setTextureSize(64, 64);
Shape10.mirror = true;
setRotation(Shape10, -0.0698132F, 0F, 0F);
Shape7 = new ModelRenderer(this, 0, 45);
Shape7.addBox(0F, 0F, 0F, 4, 2, 4);
Shape7.setRotationPoint(-2F, -11F, -1.5F);
Shape7.setTextureSize(64, 64);
Shape7.mirror = true;
setRotation(Shape7, -0.1396263F, 0F, 0F);
Shape11 = new ModelRenderer(this, 20, 39);
Shape11.addBox(0F, 0F, 0F, 2, 3, 2);
Shape11.setRotationPoint(-1F, -15F, 1F);
Shape11.setTextureSize(64, 64);
Shape11.mirror = true;
setRotation(Shape11, -0.4363323F, 0F, 0F);
Shape12 = new ModelRenderer(this, 28, 39);
Shape12.addBox(0F, 0F, 0F, 1, 2, 1);
Shape12.setRotationPoint(-0.5F, -16F, 2.5F);
Shape12.setTextureSize(64, 64);
Shape12.mirror = true;
setRotation(Shape12, -0.715585F, 0F, 0F);
beard = new ModelRenderer(this, 32, 0);
beard.addBox(0F, 0F, 0F, 8, 5, 0);
beard.setRotationPoint(-4F, 0F, -4F);
beard.setTextureSize(64, 64);
beard.mirror = true;
setRotation(beard, 0F, 0F, 0F);
Shape13 = new ModelRenderer(this, 36, 16);
Shape13.addBox(4F, 0F, 2F, 8, 20, 6);
Shape13.setRotationPoint(-4F, 0F, -3F);
Shape13.setTextureSize(64, 64);
Shape13.mirror = true;
setRotation(Shape13, 0F, 0F, 0F);
// Makes head bits move with head
//bipedHead.addChild(Shape5);
bipedHead.addChild(beard);
//bipedHead.addChild(Shape7);
//bipedHead.addChild(Shape8);
//bipedHead.addChild(Shape9);
//bipedHead.addChild(Shape10);
//bipedHead.addChild(Shape11);
//bipedHead.addChild(Shape12);
// Makes cloak attached to body
//bipedBody.addChild(Shape13);
// No outer head layer
this.bipedHeadwear.isHidden = true;
}
/*
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
bipedRightLeg.render(f5);
bipedLeftLeg.render(f5);
bipedBody.render(f5);
bipedLeftArm.render(f5);
bipedRightArm.render(f5);
bipedHead.render(f5);
Shape5.render(f5);
Shape8.render(f5);
Shape9.render(f5);
Shape10.render(f5);
Shape7.render(f5);
Shape11.render(f5);
Shape12.render(f5);
Shape6.render(f5);
Shape13.render(f5);
}
*/
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
/*
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
*/
}
@@ -0,0 +1,111 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
public class ModelWizardArmour extends ModelBiped
{
ModelRenderer Shape1;
ModelRenderer Shape2;
ModelRenderer Shape3;
ModelRenderer Shape4;
ModelRenderer Shape5;
ModelRenderer Shape6;
ModelRenderer Shape7;
ModelRenderer robe;
public ModelWizardArmour(float scale){
super(scale, 0, 64, 64);
// This is necessary to stop the head from scaling.
this.bipedHead = new ModelRenderer(this, 0, 0);
this.bipedHead.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, 0.1f);
this.bipedHead.setRotationPoint(0.0F, 0.0F + 0, 0.0F);
Shape1 = new ModelRenderer(this, -16, 32);
Shape1.addBox(-8F, -7F, -8F, 16, 0, 16);
Shape1.setRotationPoint(0F, 0F, 0F);
Shape1.setTextureSize(64, 64);
Shape1.mirror = true;
setRotation(Shape1, 0F, 0F, 0F);
Shape2 = new ModelRenderer(this, 0, 48);
Shape2.addBox(0F, 0F, 0F, 6, 2, 6);
Shape2.setRotationPoint(-3F, -10F, -3F);
Shape2.setTextureSize(64, 64);
Shape2.mirror = true;
setRotation(Shape2, -0.1396263F, 0F, 0F);
Shape3 = new ModelRenderer(this, 0, 56);
Shape3.addBox(0F, 0F, 0F, 5, 2, 5);
Shape3.setRotationPoint(-2.5F, -11.53333F, -2F);
Shape3.setTextureSize(64, 64);
Shape3.mirror = true;
setRotation(Shape3, -0.2443461F, 0F, 0F);
Shape4 = new ModelRenderer(this, 24, 48);
Shape4.addBox(0F, 0F, 0F, 4, 2, 4);
Shape4.setRotationPoint(-2F, -13F, -1F);
Shape4.setTextureSize(64, 64);
Shape4.mirror = true;
setRotation(Shape4, -0.4014257F, 0F, 0F);
Shape5 = new ModelRenderer(this, 24, 54);
Shape5.addBox(0F, 0F, 0F, 3, 2, 3);
Shape5.setRotationPoint(-1.5F, -14F, 0F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, -0.5759587F, 0F, 0F);
Shape6 = new ModelRenderer(this, 20, 59);
Shape6.addBox(0F, 0F, 0F, 2, 2, 2);
Shape6.setRotationPoint(-1F, -14F, 0F);
Shape6.setTextureSize(64, 64);
Shape6.mirror = true;
setRotation(Shape6, 0.3316126F, 0F, 0F);
Shape7 = new ModelRenderer(this, 28, 59);
Shape7.addBox(0F, 0F, 0F, 1, 1, 3);
Shape7.setRotationPoint(-0.5F, -14.5F, 2F);
Shape7.setTextureSize(64, 64);
Shape7.mirror = true;
setRotation(Shape7, -0.5585054F, 0F, 0F);
// The robe is now the body
bipedBody = new ModelRenderer(this, 40, 42);
bipedBody.addBox(-4F, 0F, -2F, 8, 18, 4, scale);
bipedBody.setRotationPoint(0F, 0F, 0F);
bipedBody.setTextureSize(64, 64);
bipedBody.mirror = true;
setRotation(bipedBody, 0F, 0F, 0F);
// Makes the hat rotate with the head.
bipedHead.addChild(Shape1);
bipedHead.addChild(Shape2);
bipedHead.addChild(Shape3);
bipedHead.addChild(Shape4);
bipedHead.addChild(Shape5);
bipedHead.addChild(Shape6);
bipedHead.addChild(Shape7);
// Makes the robe move with the body
//bipedBody.addChild(robe);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
private void setRotation(ModelRenderer model, float x, float y, float z){
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity){
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
}
}
@@ -0,0 +1,192 @@
package electroblob.wizardry.client.model;
import java.util.ArrayList;
import java.util.List;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
/**
* Class responsible for registering all of wizardry's item (and itemblock) models.
* @author Electroblob
* @since Wizardry 2.1
*/
@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(Side.CLIENT)
public final class WizardryItemModels {
@SubscribeEvent
public static void register(ModelRegistryEvent event){
// ItemBlocks
registerItemModel(Item.getItemFromBlock(WizardryBlocks.arcane_workbench));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_ore));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_flower));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.transportation_stone));
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_block));
// Items
registerItemModel(WizardryItems.magic_crystal);
registerItemModel(WizardryItems.magic_wand);
registerItemModel(WizardryItems.apprentice_wand);
registerItemModel(WizardryItems.advanced_wand);
registerItemModel(WizardryItems.master_wand);
registerItemModel(WizardryItems.spell_book);
// Wildcard registered for wizard trades.
registerItemModel(WizardryItems.spell_book, OreDictionary.WILDCARD_VALUE, "normal");
registerItemModel(WizardryItems.arcane_tome);
registerItemModel(WizardryItems.wizard_handbook);
registerItemModel(WizardryItems.basic_fire_wand);
registerItemModel(WizardryItems.basic_ice_wand);
registerItemModel(WizardryItems.basic_lightning_wand);
registerItemModel(WizardryItems.basic_necromancy_wand);
registerItemModel(WizardryItems.basic_earth_wand);
registerItemModel(WizardryItems.basic_sorcery_wand);
registerItemModel(WizardryItems.basic_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);
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);
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);
registerItemModel(WizardryItems.spectral_sword);
registerItemModel(WizardryItems.spectral_pickaxe);
registerItemModel(WizardryItems.spectral_bow);
registerItemModel(WizardryItems.mana_flask);
registerItemModel(WizardryItems.storage_upgrade);
registerItemModel(WizardryItems.siphon_upgrade);
registerItemModel(WizardryItems.condenser_upgrade);
registerItemModel(WizardryItems.range_upgrade);
registerItemModel(WizardryItems.duration_upgrade);
registerItemModel(WizardryItems.cooldown_upgrade);
registerItemModel(WizardryItems.blast_upgrade);
registerItemModel(WizardryItems.attunement_upgrade);
registerItemModel(WizardryItems.flaming_axe);
registerItemModel(WizardryItems.frost_axe);
registerItemModel(WizardryItems.firebomb);
registerItemModel(WizardryItems.poison_bomb);
registerItemModel(WizardryItems.blank_scroll);
registerItemModel(WizardryItems.scroll);
registerItemModel(WizardryItems.armour_upgrade);
registerItemModel(WizardryItems.magic_silk);
registerItemModel(WizardryItems.wizard_hat);
registerItemModel(WizardryItems.wizard_robe);
registerItemModel(WizardryItems.wizard_leggings);
registerItemModel(WizardryItems.wizard_boots);
registerItemModel(WizardryItems.wizard_hat_fire);
registerItemModel(WizardryItems.wizard_robe_fire);
registerItemModel(WizardryItems.wizard_leggings_fire);
registerItemModel(WizardryItems.wizard_boots_fire);
registerItemModel(WizardryItems.wizard_hat_ice);
registerItemModel(WizardryItems.wizard_robe_ice);
registerItemModel(WizardryItems.wizard_leggings_ice);
registerItemModel(WizardryItems.wizard_boots_ice);
registerItemModel(WizardryItems.wizard_hat_lightning);
registerItemModel(WizardryItems.wizard_robe_lightning);
registerItemModel(WizardryItems.wizard_leggings_lightning);
registerItemModel(WizardryItems.wizard_boots_lightning);
registerItemModel(WizardryItems.wizard_hat_necromancy);
registerItemModel(WizardryItems.wizard_robe_necromancy);
registerItemModel(WizardryItems.wizard_leggings_necromancy);
registerItemModel(WizardryItems.wizard_boots_necromancy);
registerItemModel(WizardryItems.wizard_hat_earth);
registerItemModel(WizardryItems.wizard_robe_earth);
registerItemModel(WizardryItems.wizard_leggings_earth);
registerItemModel(WizardryItems.wizard_boots_earth);
registerItemModel(WizardryItems.wizard_hat_sorcery);
registerItemModel(WizardryItems.wizard_robe_sorcery);
registerItemModel(WizardryItems.wizard_leggings_sorcery);
registerItemModel(WizardryItems.wizard_boots_sorcery);
registerItemModel(WizardryItems.wizard_hat_healing);
registerItemModel(WizardryItems.wizard_robe_healing);
registerItemModel(WizardryItems.wizard_leggings_healing);
registerItemModel(WizardryItems.wizard_boots_healing);
registerItemModel(WizardryItems.spectral_helmet);
registerItemModel(WizardryItems.spectral_chestplate);
registerItemModel(WizardryItems.spectral_leggings);
registerItemModel(WizardryItems.spectral_boots);
registerItemModel(WizardryItems.smoke_bomb);
registerItemModel(WizardryItems.identification_scroll);
}
// Moved from the proxies
/** 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(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The passed in item
* <b>must</b> allow null to be passed in for the creative tab parameter in the aforementioned method, or a
* {@link NullPointerException} will result. */
private static void registerItemModel(Item item){
if(item.getHasSubtypes()){
List<ItemStack> items = new ArrayList<ItemStack>();
item.getSubItems(item, null, 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"));
}
/** Registers an item model for the given metadata, using the item's registry name as the model name (this
* convention makes it easier to keep track of everything). This is intended for registering additional metadata
* values which aren't displayed in the creative menu, for example the wildcard spell book used in wizard trades. */
private static void registerItemModel(Item item, int metadata, String variant) {
ModelLoader.setCustomModelResourceLocation(item, metadata, new ModelResourceLocation(item.getRegistryName(), variant));
}
}
@@ -0,0 +1,72 @@
package electroblob.wizardry.client.particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleBlizzard extends ParticleSnow {
private double angle;
private double radius;
private double speed;
public ParticleBlizzard(World world, int maxAge, double originX, double originZ, double radius, double yPos){
super(world, 0, 0, 0, 0, 0, 0, maxAge);
this.angle = this.rand.nextDouble() * Math.PI * 2;
double x = originX - Math.cos(angle)*radius;
double z = originZ + radius*Math.sin(angle);
this.radius = radius;
this.setPosition(x, yPos, z);
this.prevPosX = x;
this.prevPosY = yPos;
this.prevPosZ = z;
if(rand.nextBoolean()){
speed = rand.nextDouble()*2 + 1;
}else{
speed = rand.nextDouble()*-2 - 1;
}
this.multipleParticleScaleBy(1.5f);
}
@Override
public void init(){
super.init();
this.fullBrightness = true;
}
// @Override
// public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
// if(this.particleAge < this.particleMaxAge / 3 || (this.particleAge + this.particleMaxAge) / 3 % 2 == 0){
// super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
// }
// }
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if(this.particleAge++ >= this.particleMaxAge){
this.setExpired();
}
// This is in radians per tick...
double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius));
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
this.angle += omega;
this.motionY -= 0.04D * (double)this.particleGravity;
this.motionZ = radius * omega * Math.cos(angle);
this.motionX = radius * omega * Math.sin(angle);
this.moveEntity(motionX, motionY, motionZ);
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
}
}
@@ -0,0 +1,195 @@
package electroblob.wizardry.client.particle;
import java.util.List;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/**
* Abstract superclass for all particles that use custom textures. This is intended to centralise as much code as
* possible; all subclasses need to do is to define the texture to use, how the frames are arranged (and which to
* choose), and any properties like gravity and collisions.
* @author Electroblob
* @since Wizardry 1.2
*/
@SideOnly(Side.CLIENT)
public abstract class ParticleCustomTexture extends Particle {
/** True if the particle always renders at full brightness. Defaults to false. */
protected boolean fullBrightness = false;
public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
this.motionX = vx;
this.motionY = vy;
this.motionZ = vz;
this.init();
}
public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
this(world, x, y, z, vx, vy, vz);
this.particleMaxAge = maxAge;
}
/** Called from both constructors to set constants, avoiding duplicate code. Common fields to set here
* include: particleScale, particleGravity, canCollide, fullBrightness and setting the texture index. */
public abstract void init();
/** Returns a ResourceLocation for the particle's texture sheet. Do not create a new ResourceLocation in this
* method, only return a constant. */
public abstract ResourceLocation getTexture();
/** Returns how many 'frames' there are in the x direction on the texture. */
protected abstract int getXFrames();
/** Returns how many 'frames' there are in the y direction on the texture. */
protected abstract int getYFrames();
/* There are 4 layers of particles, specified as 0-3 by the method below.
* - Layer 0 causes the normal particles.png to be bound to the render engine for normal particles.
* - Layer 1 causes the block textures to be bound to the render engine for digging fx and falling fx.
* - Layer 2 causes the item textures to be bound to the render engine for tool breaking fx, snowballpoofs, slime particles, etc.
* - Layer 3 is not used in vanilla minecraft and was presumably added by forge for exactly this reason.
* This means no texture is bound by vanilla minecraft, meaning you are free to do as you wish without possibly
* overwriting vanilla particles. Mod particles won't be overwritten anyway since they bind their own textures.
* It is of course important to bind the texture every time you render a custom particle, but I don't see how
* you could do it any other way, since you don't have access to EffectRenderer. */
@Override
public int getFXLayer() {
// This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer.
return 3;
}
@Override
public void setParticleTextureIndex(int index){
this.particleTextureIndexX = index % getXFrames();
this.particleTextureIndexY = index / getYFrames();
}
// Overridden to fix the bug with vanilla that makes particles frictionless. (y != y... seriously, Mojang?)
@Override
public void moveEntity(double x, double y, double z){
double d0 = y;
if (this.canCollide)
{
List<AxisAlignedBB> list = this.worldObj.getCollisionBoxes((Entity)null, this.getEntityBoundingBox().addCoord(x, y, z));
for (AxisAlignedBB axisalignedbb : list)
{
y = axisalignedbb.calculateYOffset(this.getEntityBoundingBox(), y);
}
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(0.0D, y, 0.0D));
for (AxisAlignedBB axisalignedbb1 : list)
{
x = axisalignedbb1.calculateXOffset(this.getEntityBoundingBox(), x);
}
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, 0.0D, 0.0D));
for (AxisAlignedBB axisalignedbb2 : list)
{
z = axisalignedbb2.calculateZOffset(this.getEntityBoundingBox(), z);
}
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(0.0D, 0.0D, z));
}
else
{
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, y, z));
}
this.resetPositionToBB();
this.isCollided = d0 != y && d0 < 0.0D;
/* Can never be true! - But this doesn't seem to make any difference anyway.
if (x != x)
{
this.motionX = 0.0D;
}
if (z != z)
{
this.motionZ = 0.0D;
}
*/
}
// Overridden to bind the new texture. I think this can be done with TextureAtlasSprite, but this works as it is
// so I'm not changing it for the time being.
@Override
public void renderParticle(VertexBuffer buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
GlStateManager.pushMatrix();
GlStateManager.pushAttrib();
this.applyGLStateChanges();
// This stuff does the shading. It vanilla does this later on for each point, but this also seems to work.
int brightness = this.getBrightnessForRender(partialTicks);
int lightmapX = brightness % 65536;
int lightmapY = brightness / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lightmapX / 1.0F, (float)lightmapY / 1.0F);
RenderHelper.disableStandardItemLighting();
Minecraft.getMinecraft().getTextureManager().bindTexture(getTexture());
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
float u1 = (float)this.particleTextureIndexX / (float)getXFrames();
float u2 = u1 + 1.0f/getXFrames();
float v1 = (float)this.particleTextureIndexY / (float)getYFrames();
float v2 = v1 + 1.0f/getYFrames();
float scale = 0.1F * this.particleScale;
// I'm pretty sure these were always static.
Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks;
Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks;
Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks;
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
buffer.pos((double)(x - rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), (double)(z - rotationYZ * scale - rotationXZ * scale)).tex(u2, v2).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos((double)(x - rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), (double)(z - rotationYZ * scale + rotationXZ * scale)).tex(u2, v1).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos((double)(x + rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), (double)(z + rotationYZ * scale + rotationXZ * scale)).tex(u1, v1).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos((double)(x + rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), (double)(z + rotationYZ * scale - rotationXZ * scale)).tex(u1, v2).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();;
Tessellator.getInstance().draw();
this.undoGLStateChanges();
GlStateManager.popAttrib();
GlStateManager.popMatrix();
}
/** Override to add any GL state changes, like blending. Does nothing by default. <b>State changes should be
* done using GLStateManager, not using GL11 directly</b> (as is the case with all rendering code now). */
public void applyGLStateChanges(){}
/** Override to undo any GL state changes, like blending. Does nothing by default. <b>State changes should be
* done using GLStateManager, not using GL11 directly</b> (as is the case with all rendering code now). */
public void undoGLStateChanges(){}
@Override
public int getBrightnessForRender(float partialTick){
return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick);
}
}
@@ -0,0 +1,90 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleDarkMagic extends Particle {
/** Base spell texture index */
private int baseSpellTextureIndex = 128;
public ParticleDarkMagic(World par1World, double par2, double par4, double par6, double par8, double par10, double par12, float r, float g, float b)
{
super(par1World, par2, par4, par6, par8, par10, par12);
this.motionY *= 0.20000000298023224D;
this.particleRed = r;
this.particleGreen = g;
this.particleBlue = b;
this.particleScale *= 0.75F;
this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
this.canCollide = true;
}
@Override
public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ)
{
float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge * 32.0F;
if (f6 < 0.0F)
{
f6 = 0.0F;
}
if (f6 > 1.0F)
{
f6 = 1.0F;
}
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if (this.particleAge++ >= this.particleMaxAge)
{
this.setExpired();
}
this.setParticleTextureIndex(this.baseSpellTextureIndex + (7 - this.particleAge * 8 / this.particleMaxAge));
this.motionY += 0.004D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
/*
if (this.posY == this.prevPosY)
{
this.motionX *= 1.1D;
this.motionZ *= 1.1D;
}
*/
this.motionX *= 0.9599999785423279D;
this.motionY *= 0.9599999785423279D;
this.motionZ *= 0.9599999785423279D;
if (this.isCollided)
{
this.motionX *= 0.699999988079071D;
this.motionZ *= 0.699999988079071D;
}
}
/**
* Sets the base spell texture index
*/
public void setBaseSpellTextureIndex(int par1)
{
this.baseSpellTextureIndex = par1;
}
}
@@ -0,0 +1,57 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleDust extends Particle {
private final boolean shaded;
public ParticleDust(World par1World, double x, double y, double z, double par8, double par10, double par12, float r, float g, float b, boolean shaded)
{
super(par1World, x, y, z, par8, par10, par12);
this.particleRed = r;
this.particleGreen = g;
this.particleBlue = b;
this.setParticleTextureIndex(0);
this.setSize(0.01F, 0.01F);
this.particleScale *= this.rand.nextFloat() + 0.2F;
this.motionX = par8;
this.motionY = par10;
this.motionZ = par12;
this.particleMaxAge = (int)(16.0D / (Math.random() * 0.8D + 0.2D));
this.shaded = shaded;
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
//this.moveEntity(this.motionX, this.motionY, this.motionZ);
if (this.particleMaxAge-- <= 0)
{
this.setExpired();
}
}
@Override
public int getBrightnessForRender(float par1)
{
return shaded ? super.getBrightnessForRender(par1) : 15728880;
}
/*
@Override
public float getBrightness(float par1)
{
return shaded ? super.getBrightness(par1) : 1.0F;
}
*/
}
@@ -0,0 +1,50 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.particle.Particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleGiantBubble extends Particle
{
/** The name used to identify this particle. Uses the mod id to avoid any possible conflicts (Not that there would
* be any, but I may as well.) */
public static final String NAME = Wizardry.MODID + "magicbubble";
public ParticleGiantBubble(World par1World, double par2, double par4, double par6, double par8, double par10, double par12)
{
super(par1World, par2, par4, par6, par8, par10, par12);
this.particleRed = 1.0F;
this.particleGreen = 1.0F;
this.particleBlue = 1.0F;
this.setParticleTextureIndex(32);
this.setSize(0.02F, 0.02F);
this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F;
this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.motionY += 0.002D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.8500000238418579D;
this.motionY *= 0.8500000238418579D;
this.motionZ *= 0.8500000238418579D;
if (this.particleMaxAge-- <= 0)
{
this.setExpired();
}
}
}
@@ -0,0 +1,34 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleIce extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png");
public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
}
public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
}
@Override
public void init(){
this.setParticleTextureIndex(rand.nextInt(8));
this.particleScale *= 0.75f;
this.particleGravity = 1;
this.canCollide = true;
this.fullBrightness = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
}
@@ -0,0 +1,33 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleLeaf extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/leaf_particles.png");
public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
}
public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
}
@Override
public void init() {
this.setParticleTextureIndex(rand.nextInt(16));
this.particleScale *= 1.4f;
this.particleGravity = 0;
this.canCollide = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
}
@@ -0,0 +1,47 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleMagicFlame extends Particle {
/** The scale of the flame particle */
private float flameScale;
public ParticleMagicFlame(World par1World, double par2, double par4, double par6, double par8, double par10, double par12, int maxAge, float scale)
{
super(par1World, par2, par4, par6, par8, par10, par12);
this.motionX = this.motionX * 0.009999999776482582D + par8;
this.motionY = this.motionY * 0.009999999776482582D + par10;
this.motionZ = this.motionZ * 0.009999999776482582D + par12;
this.flameScale = scale;
this.particleRed = this.particleGreen = this.particleBlue = 1.0F;
if(maxAge == 0){
this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D));
}else{
this.particleMaxAge = maxAge;
}
// IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff.
this.canCollide = false;
this.setParticleTextureIndex(48);
}
@Override
public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ)
{
float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge;
this.particleScale = this.flameScale * (1.0F - f6 * f6 * 0.5F);
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
}
@Override
public int getBrightnessForRender(float par1)
{
return 256;
}
}
@@ -0,0 +1,93 @@
package electroblob.wizardry.client.particle;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.spell.Clairvoyance;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticlePath extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/path_particles.png");
private final double originX, originY, originZ;
public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b){
super(world, x, y, z, vx, vy, vz);
this.setRBGColorF(r, g, b);
this.originX = x;
this.originY = y;
this.originZ = z;
}
public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
this.setRBGColorF(r, g, b);
this.originX = x;
this.originY = y;
this.originZ = z;
}
@Override
public void init(){
this.setParticleTextureIndex(0);
// Set to a constant to remove the randomness from Particle.
this.particleScale = 1.25f;
this.particleGravity = 0;
this.fullBrightness = true;
this.canCollide = false;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 1; }
@Override protected int getYFrames(){ return 1; }
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if (this.particleAge++ >= this.particleMaxAge)
{
this.setExpired();
}
this.moveEntity(this.motionX, this.motionY, this.motionZ);
// Fading
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - 2 * (((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge));
}
if(this.particleAge % Clairvoyance.PARTICLE_MOVEMENT_INTERVAL == 0){
this.setPosition(this.originX, this.originY, this.originZ);
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
}
}
@Override
public void applyGLStateChanges(){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// TESTME: Are these two actually necessary?
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
}
@Override
public void undoGLStateChanges(){
GlStateManager.disableBlend();
GlStateManager.enableLighting();
}
}
@@ -0,0 +1,59 @@
package electroblob.wizardry.client.particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleRotatingSparkle extends ParticleSparkle {
private double angle;
private double radius;
private double speed;
public ParticleRotatingSparkle(World world, int maxAge, double originX, double originZ, double radius, double yPos, float r, float g , float b){
super(world, 0, 0, 0, 0, 0, 0, r, g, b, maxAge);
this.angle = this.rand.nextDouble() * Math.PI * 2;
double x = originX - Math.cos(angle)*radius;
double z = originZ + radius*Math.sin(angle);
this.radius = radius;
this.setPosition(x, yPos, z);
this.prevPosX = x;
this.prevPosY = yPos;
this.prevPosZ = z;
if(rand.nextBoolean()){
speed = rand.nextDouble()*2 + 1;
}else{
speed = rand.nextDouble()*-2 - 1;
}
this.multipleParticleScaleBy(1.5f);
}
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if(this.particleAge++ >= this.particleMaxAge){
this.setExpired();
}
// This is in radians per tick...
double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius));
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
this.angle += omega;
this.motionY -= 0.04D * (double)this.particleGravity;
this.motionZ = radius * omega * Math.cos(angle);
this.motionX = radius * omega * Math.sin(angle);
this.moveEntity(motionX, motionY, motionZ);
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
}
}
@@ -0,0 +1,33 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleSnow extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/snow_particles.png");
public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz){
super(world, x, y, z, vx, vy, vz);
}
public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
}
@Override
public void init(){
this.setParticleTextureIndex(rand.nextInt(8));
this.particleScale *= 0.6f;
this.particleGravity = 0;
this.canCollide = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
}
@@ -0,0 +1,58 @@
package electroblob.wizardry.client.particle;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleSpark extends ParticleCustomTexture {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/lightning_particles.png");
public ParticleSpark(World world, double x, double y, double z, double vx, double vy, double vz){
// Max age is always 3.
super(world, x, y, z, vx, vy, vz, 3);
}
@Override
public void init(){
// Multiplied by 4 because the index works slightly differently for spark particles.
this.setParticleTextureIndex(rand.nextInt(8)*4);
this.particleScale *= 1.4f;
this.fullBrightness = true;
this.canCollide = false;
}
@Override
public void onUpdate(){
super.onUpdate();
// Well this is handy! Looks like vanilla uses the texture index like this too.
this.nextTextureIndexX();
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 8; }
@Override
public void applyGLStateChanges(){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// TESTME: Are these two actually necessary?
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
}
@Override
public void undoGLStateChanges(){
GlStateManager.disableBlend();
GlStateManager.enableLighting();
}
}
@@ -0,0 +1,96 @@
package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleSparkle extends ParticleCustomTexture {
/* I have now figured out what particle factories are for: they separate out the individual uses of the varargs
* parameter in spawnParticle so they are kept with the particle class. For my purposes, it would be easier to do
* that in the particle spawning method itself. */
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/sparkle_particles.png");
// NOTE: Uncomment once 2.1.0 is released
//private final float initialRed;
//private final float initialGreen;
//private final float initialBlue;
// TODO: Assign these via the constructors, as part of the refactoring for particle parameters.
// NOTE: Uncomment once 2.1.0 is released
// private final float fadeRed = 1;
// private final float fadeGreen = 1;
// private final float fadeBlue = 0;
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b){
super(world, x, y, z, vx, vy, vz);
this.setRBGColorF(r, g, b);
// NOTE: Uncomment once 2.1.0 is released
//initialRed = r;
//initialGreen = g;
//initialBlue = b;
this.particleMaxAge = 48 + this.rand.nextInt(12);
}
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge){
super(world, x, y, z, vx, vy, vz, maxAge);
this.setRBGColorF(r, g, b);
// NOTE: Uncomment once 2.1.0 is released
//initialRed = r;
//initialGreen = g;
//initialBlue = b;
}
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, boolean doGravity){
this(world, x, y, z, vx, vy, vz, r, g, b);
this.particleGravity = doGravity ? 1 : 0;
}
public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, float b, int maxAge, boolean doGravity){
this(world, x, y, z, vx, vy, vz, r, g, b, maxAge);
this.particleGravity = doGravity ? 1 : 0;
}
@Override
public void init(){
this.setParticleTextureIndex(rand.nextInt(16));
this.particleScale *= 0.75f;
this.particleGravity = 0;
this.canCollide = false;
this.fullBrightness = true;
}
@Override public ResourceLocation getTexture(){ return TEXTURE; }
@Override protected int getXFrames(){ return 4; }
@Override protected int getYFrames(){ return 4; }
@Override
public void onUpdate(){
super.onUpdate();
// Fading
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
// Colour fading TODO Uncomment once 2.1.0 is released
// float ageFraction = (float)this.particleAge / (float)this.particleMaxAge;
// this.setRBGColorF(this.initialRed + (this.fadeRed - this.initialRed)*ageFraction,
// this.initialGreen + (this.fadeGreen - this.initialGreen)*ageFraction,
// this.initialBlue + (this.fadeBlue - this.initialBlue)*ageFraction);
//
// this.setParticleTextureIndex((this.particleAge * 11)/this.particleMaxAge);
}
/*
* As a side note, I see a lot of magic mods with fancy-looking particle effects that really seem to 'glow'. It's
* actually not that hard - you simply create a reasonably high-res texture with translucency and then set the
* OpenGL blend function to something like SRC_ALPHA, SRC_ALPHA or ONE, ONE. The thing is... they're not very
* Minecraft-y. I still maintain that part of wizardry's appeal is that it stays true to the game's pixelated charm,
* rather than trying to make it something it's not. Still, the newer textures are much better than the defaults I
* used to use.
*/
}
@@ -0,0 +1,83 @@
package electroblob.wizardry.client.particle;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.particle.ParticleDigging;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleTornado extends ParticleDigging {
private double angle;
private double radius;
private double speed;
/** Velocity of the tornado itself; in other words the velocity of the point the particle circles around. */
private double velX, velZ;
private boolean fullBrightness = false;
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);
this.angle = this.rand.nextDouble() * Math.PI * 2;
double x = originX - Math.cos(angle)*radius;
double z = originZ + radius*Math.sin(angle);
this.radius = radius;
this.setPosition(x, yPos, z);
this.prevPosX = x;
this.prevPosY = yPos;
this.prevPosZ = z;
//this.particleScale *= 0.75F;
this.particleMaxAge = maxAge;
this.canCollide = false;
// Grass has special treatment, since it has a colourised top but the rest is normal.
// Commented out for now since vanilla does something about this now, but I'm not sure what exactly
//if(block.getBlock() != Blocks.GRASS || side == 1) this.setColour(block.getRenderColor(side));
// Blocks that emit light are rendered with full brightness.
if(block.getLightValue(world, new BlockPos(this.posX, this.posY, this.posZ)) == 0){
this.particleRed *= 0.75;
this.particleGreen *= 0.75;
this.particleBlue *= 0.75;
}else{
this.fullBrightness = true;
}
speed = rand.nextDouble()*2 + 1;
this.velX = velX;
this.velZ = velZ;
}
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if(this.particleAge++ >= this.particleMaxAge){
this.setExpired();
}
// This is in radians per tick...
double omega = Math.signum(speed) * ((Math.PI*2)/20 - speed/(20*radius));
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
this.angle += omega;
this.motionZ = radius * omega * Math.cos(angle);
this.motionX = radius * omega * Math.sin(angle);
this.moveEntity(motionX + velX, 0, motionZ + velZ);
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
}
@Override
public int getBrightnessForRender(float partialTicks){
return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTicks);
}
}
@@ -0,0 +1,191 @@
package electroblob.wizardry.client.renderer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map.Entry;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.ClientProxy;
import electroblob.wizardry.spell.Petrify;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.client.renderer.entity.RenderZombie;
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
/**
* Layer used to render the stone texture on a petrified creature. Handles dynamic tiling of the stone texture and
* reflective access for classes that don't play nicely (looking at you, {@link RenderZombie}).
* @author Electroblob
* @since Wizardry 1.2
*/
public class LayerStone implements LayerRenderer<EntityLivingBase> {
protected ModelBase model;
private final RenderLivingBase<?> renderer;
private static final ResourceLocation texture = new ResourceLocation("textures/blocks/stone.png");
private static final Field zombieLayers = ReflectionHelper.findField(RenderZombie.class, "defaultLayers", "field_177122_o");
private static final Field zombieVillagerLayers = ReflectionHelper.findField(RenderZombie.class, "villagerLayers", "field_177121_n");
private static final Method swapZombieModel = ReflectionHelper.findMethod(RenderZombie.class, null,
new String[]{"swapArmor", "func_82427_a"}, EntityZombie.class); // Second parameter (null) is unused
@SuppressWarnings("unchecked") // The compiler is being annoying and I know that what I'm doing is type-safe.
public static void initialiseLayers(){
for(Entry<Class<? extends Entity>, Render<? extends Entity>> entry : Minecraft.getMinecraft().getRenderManager().entityRenderMap.entrySet()){
// Zombies don't play nicely because they have their own, private lists of layers for the regular zombie
// and the zombie villager, which are assigned within the constructor for RenderZombie and swapped out
// as necessary. However, Mojang, in their infinite wisdom, haven't bothered to override addLayer to
// modify those internal lists, so that method is useless.
if(entry.getValue() instanceof RenderZombie){
try {
Object layers = zombieLayers.get(entry.getValue());
if(layers instanceof List<?>){
// Nice as the layer renderer system is, it doesn't lend itself to reflective access.
// I KNOW that 'layers' (which was obtained using reflection) is of the type
// List<LayerRenderer<EntityZombie>>, because that's what it's declared as. However, if I cast
// 'layers' to List<LayerRenderer<EntityZombie>>, I can't add a LayerStone because it's only a
// LayerRenderer<EntityLivingBase>, not a LayerRenderer<EntityZombie>.
((List<LayerRenderer<EntityLivingBase>>)layers).add(new LayerStone((RenderLivingBase<?>)entry.getValue()));
}
layers = zombieVillagerLayers.get(entry.getValue());
if(layers instanceof List<?>){
((List<LayerRenderer<EntityLivingBase>>)layers).add(new LayerStone((RenderLivingBase<?>)entry.getValue()));
}
} catch (IllegalArgumentException | IllegalAccessException e){
Wizardry.logger.error("Error while reflectively accessing zombie render layers");
e.printStackTrace();
}
}else if(entry.getValue() instanceof RenderLivingBase){
// Adds a stone layer to all the living entity renderers in the game. Whether it is actually rendered
// is decided in doRenderLayer below on a per-entity basis.
((RenderLivingBase<?>)entry.getValue()).addLayer(new LayerStone((RenderLivingBase<?>)entry.getValue()));
}
// NOTE: May have to do some special stuff for players if they are to be added; see Minecraft.getMinecraft().getRenderManager().getSkinMap()
}
}
public LayerStone(RenderLivingBase<?> renderer){
this.renderer = renderer;
this.model = renderer.getMainModel();
}
@Override
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){
if(entity.getEntityData().getBoolean(Petrify.NBT_KEY)){
GlStateManager.enableLighting();
int i = this.getBlockBrightnessForEntity(entity, partialTicks);
int j = i % 65536;
int k = i / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
ResourceLocation breakingTexture = ClientProxy.renderStatue.getBlockBreakingTexture();
if(breakingTexture != null){
// Block breaking animation
// TODO: Spider eyes and enderman eyes (any others?) show through the stone when the block is being broken...
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
this.renderer.bindTexture(breakingTexture);
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
GlStateManager.disableBlend();
}else{
// Stone texture
this.renderer.bindTexture(texture);
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
}
}
}
private int getBlockBrightnessForEntity(Entity entity, float partialTicks){
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor_double(entity.posX), 0, MathHelper.floor_double(entity.posZ));
if(entity.worldObj.isBlockLoaded(pos)){
pos.setY(MathHelper.floor_double(entity.posY + (double)entity.getEyeHeight()));
return entity.worldObj.getCombinedLight(pos, 0);
}else{
return 0;
}
}
private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){
GlStateManager.pushMatrix();
// Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam)
// TODO: Backport this improvement
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth)
// In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason.
// Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example,
// but with translation instead of scaling.
GlStateManager.matrixMode(GL11.GL_TEXTURE);
GlStateManager.loadIdentity();
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){
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
scaleX = (double)model.textureWidth/16d;
scaleY = (double)model.textureHeight/16d;
}
GlStateManager.scale(scaleX, scaleY, 1);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
// Lets RenderZombie do its (stupid and inflexible) model switching thing
if(this.renderer instanceof RenderZombie && entity instanceof EntityZombie){
try {
swapZombieModel.invoke(this.renderer, entity);
this.model = this.renderer.getMainModel();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
Wizardry.logger.error("Error while reflectively calling RenderZombie#swapArmor");
e.printStackTrace();
}
}
// Hides the hat layer for bipeds
if(this.model instanceof ModelBiped) ((ModelBiped) this.model).bipedHeadwear.isHidden = true;
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;
// Undoes the texture scaling
GlStateManager.matrixMode(GL11.GL_TEXTURE);
GlStateManager.loadIdentity();
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.popMatrix();
}
@Override
public boolean shouldCombineTextures(){
return false;
}
}
@@ -0,0 +1,48 @@
package electroblob.wizardry.client.renderer;
/** Instances of this class can calculate their distance from the camera viewpoint and sort themselves accordingly. */
class RayHelper implements Comparable<RayHelper> {
int ordinal;
double x1, y1, z1;
double x2, y2, z2;
double offsetX, offsetY, offsetZ;
RayHelper(int ordinal, double x1, double y1, double z1, double x2, double y2, double z2, double offsetX, double offsetY, double offsetZ){
this.ordinal = ordinal;
this.x1 = x1;
this.y1 = y1;
this.z1 = z1;
this.x2 = x2;
this.y2 = y2;
this.z2 = z2;
this.offsetX = offsetX;
this.offsetY = offsetY;
this.offsetZ = offsetZ;
}
double getDistanceFromViewpoint(){
double midX = (x1+x2)/2;
double midY = (y1+y2)/2;
double midZ = (z1+z2)/2;
double absoluteX = offsetX+midX;
double absoluteY = offsetY+midY;
double absoluteZ = offsetZ+midZ;
return Math.sqrt(absoluteX*absoluteX + absoluteY*absoluteY + absoluteZ*absoluteZ);
}
@Override
public int compareTo(RayHelper ray){
if(this.getDistanceFromViewpoint() > ray.getDistanceFromViewpoint()){
return -1;
}else if(this.getDistanceFromViewpoint() < ray.getDistanceFromViewpoint()){
return 1;
}else{
return 0;
}
}
}
@@ -0,0 +1,129 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.EntityArc;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderArc extends Render<EntityArc> {
private static final ResourceLocation[] textures = new ResourceLocation[16];
public RenderArc(RenderManager renderManager){
super(renderManager);
for(int i=0;i<16;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/arc_" + i + ".png");
}
}
@Override
public void doRender(EntityArc arc, double d0, double d1, double d2,
float fa, float fb) {
GlStateManager.pushMatrix();
GlStateManager.translate((float)d0, (float)d1, (float)d2);
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //This line fixes the weird brightness bug.
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
//System.out.println("Entity coords: " + entity.posX + ", " + entity.posY + ", " + entity.posZ);
//System.out.println("doRender parameters: " + d0 + ", " + d1 + ", " + d2 + ", " + fa + ", " + fb);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
bindTexture(textures[arc.textureIndex]); // This MUST be after the tessellator declaration and the gl stuff
/**
* Note: A lot of the maths here works on similar triangles and the ratios between them, avoiding too much
* pythagoras and eliminating the need for any trig. Ratios are used for the positioning of the arc endpoints.
* Ratios are usually used swapping x and z because the triangles are rotated through 90 degrees.
*/
double dx = -d0;
double dy = -d1;
double dz = -d2;
if(arc.x1 != 0){
dx = arc.x1 - arc.posX;// - d2/lengthOffsetRatio;
dy = arc.y1 - arc.posY + 0.3;
dz = arc.z1 - arc.posZ;// + d0/lengthOffsetRatio;
//The distance from caster to target
double arcLength = Math.sqrt(dz*dz+dx*dx);
//The ratio between the length of the arc and the offset of the start point from the player's centre (which is always 0.3).
//double lengthOffsetRatio = arcLength/0.3;
//EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer;
//double xViewDist = player.posX - d0;
//double yViewDist = player.posY + player.eyeHeight - d1;
//double zViewDist = player.posZ - d2;
//double xzViewDist = Math.sqrt(xViewDist * xViewDist + zViewDist * zViewDist);
//The angle above the horizontal that this particular player is viewing the arc from
//double viewAngle = Math.atan(yViewDist/xzViewDist);
//Half the width of the arc
double arcWidth = 0.3d;
//Right hand side of vertical plane
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//Target end
buffer.pos(0, -0.5, 0).tex(1, 1).endVertex();
buffer.pos(0, 0.5, 0).tex(1, 0).endVertex();
//Caster end
buffer.pos(dx, dy, dz).tex(0, 0).endVertex();
buffer.pos(dx, dy-1, dz).tex(0, 1).endVertex();
tessellator.draw();
//Left
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
//Target end
buffer.pos(0, -0.5, 0).tex(1, 1).endVertex();
//Caster end
buffer.pos(dx, dy-1, dz).tex(0, 1).endVertex();
buffer.pos(dx, dy, dz).tex(0, 0).endVertex();
//Target end
buffer.pos(0, 0.5, 0).tex(1, 0).endVertex();
tessellator.draw();
//Bottom of horizontal plane
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos((arcWidth/arcLength)*dz, 0, (-arcWidth/arcLength)*dx).tex(1, 1).endVertex();
buffer.pos(dx + (arcWidth/arcLength)*dz, dy-0.5, dz - (arcWidth/arcLength)*dx).tex(0, 1).endVertex();
buffer.pos(dx - (arcWidth/arcLength)*dz, dy-0.5, dz + (arcWidth/arcLength)*dx).tex(0, 0).endVertex();
buffer.pos((-arcWidth/arcLength)*dz, 0, (arcWidth/arcLength)*dx).tex(1, 0).endVertex();
tessellator.draw();
//Top
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos((arcWidth/arcLength)*dz, 0, (-arcWidth/arcLength)*dx).tex(1, 1).endVertex();
buffer.pos((-arcWidth/arcLength)*dz, 0, (arcWidth/arcLength)*dx).tex(1, 0).endVertex();
buffer.pos(dx - (arcWidth/arcLength)*dz, dy-0.5, dz + (arcWidth/arcLength)*dx).tex(0, 0).endVertex();
buffer.pos(dx + (arcWidth/arcLength)*dz, dy-0.5, dz - (arcWidth/arcLength)*dx).tex(0, 1).endVertex();
tessellator.draw();
}
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityArc entity) {
return textures[entity.textureIndex];
}
}
@@ -0,0 +1,99 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class RenderArcaneWorkbench extends TileEntitySpecialRenderer<TileEntityArcaneWorkbench> {
private static final ResourceLocation runeTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/rune.png");
public RenderArcaneWorkbench(){}
@Override
public void renderTileEntityAt(TileEntityArcaneWorkbench tileentity, double x, double y, double z, float partialTicks, int destroyStage) {
GlStateManager.pushMatrix();
// This line makes stuff render in the same place relative to the world wherever the player is.
GlStateManager.translate((float)x + 0.5F, (float)y + 1.5F, (float)z + 0.5F);
GlStateManager.rotate(180, 0F, 0F, 1F);
GlStateManager.pushMatrix();
double angle = 0.0d;
if(x < -0.5){
angle = Math.toDegrees(Math.atan((z+0.5)/(x+0.5))) + 180;
}else{
angle = Math.toDegrees(Math.atan((z+0.5)/(x+0.5)));
}
this.renderEffect(tileentity);
this.renderWand(tileentity, angle);
GlStateManager.popMatrix();
GlStateManager.popMatrix();
}
private void renderEffect(TileEntityArcaneWorkbench tileentity) {
ItemStack itemstack = tileentity.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT);
if(itemstack != null){
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //This line fixes the weird brightness bug.
GlStateManager.rotate(tileentity.timer, 0.0f, 1.0f, 0.0f);
GlStateManager.translate(0.0f, 0.65f, 0.0f);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
bindTexture(runeTexture);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5f, 0, -0.5f).tex(0, 0).endVertex();
buffer.pos(0.5f, 0, -0.5f).tex(1, 0).endVertex();
buffer.pos(0.5f, 0, 0.5f).tex(1, 1).endVertex();
buffer.pos(-0.5f, 0, 0.5f).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
}
/**
* Renders the wand on the workbench as 3D on the model. Currently doesn't do much on 'fast' graphics!
* @param tileentity The instance of the workbench tile entity
*/
private void renderWand(TileEntityArcaneWorkbench tileentity, double viewAngle)
{
ItemStack stack = tileentity.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT);
if(stack != null){
GlStateManager.pushMatrix();
GlStateManager.rotate(180.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.rotate(180, 0, 1, 0);
// View angle is negated because of the 180 flip.
GlStateManager.rotate((float)(-viewAngle-90f), 0, 0, 1);
// Does the floaty thing
GlStateManager.translate(0.0F, 0.0F, (float)tileentity.yOffset/5000.0F - 0.55f);
GlStateManager.scale(0.75F, 0.75F, 0.75F);
// This is what the item frame uses so it's definitely what we want.
Minecraft.getMinecraft().getRenderItem().renderItem(stack, TransformType.FIXED);
GlStateManager.popMatrix();
}
}
}
@@ -0,0 +1,180 @@
package electroblob.wizardry.client.renderer;
import java.util.ArrayList;
import java.util.Collections;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityBlackHole;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderBlackHole extends Render<EntityBlackHole> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/dark_ray.png");
private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID, "textures/entity/black_hole.png");
public RenderBlackHole(RenderManager renderManager) {
super(renderManager);
}
@Override
public void doRender(EntityBlackHole blackhole, double x, double y, double z, float fa, float fb) {
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
RenderHelper.disableStandardItemLighting();
GlStateManager.translate(x, y, z);
//float pitch = (float) Math.toDegrees(Math.atan(y/(x*x+z*z)));
//float yaw = (float) Math.toDegrees(Math.atan(x/z));
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
if(blackhole.ticksExisted < 10){
GlStateManager.scale((float)blackhole.ticksExisted/10, (float)blackhole.ticksExisted/10, (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);
}
this.bindTexture(texture);
// In theory this stuff should sort the rays into the correct render order based on the distance from
// the 'camera' (i.e. the player's viewpoint)
// In the end it was easier to do away with the openGL rotation because for some reason it produced
// coordinates which were inconsistent with my calculated ones. Since I know those will give the desired
// effect anyway, I just used them directly instead.
ArrayList<RayHelper> rays = new ArrayList<RayHelper>(1);
for(int j=0; j<30; j++){
float scale = 3.0f;
int a = blackhole.randomiser[j];
int b = blackhole.randomiser2[j];
int sliceAngle = 20 + a;
double x1 = scale*Math.sin((blackhole.ticksExisted + 40*j)*(Math.PI/180));
//double y1 = 0.7*Math.cos((blackhole.timer - 40*j)*(Math.PI/180))*j/10;
double z1 = scale*Math.cos((blackhole.ticksExisted + 40*j)*(Math.PI/180));
double x2 = scale*Math.sin((blackhole.ticksExisted + 40*j - sliceAngle)*(Math.PI/180));
//double y2 = 0.7*Math.sin((blackhole.timer - 40*j)*(Math.PI/180))*j/10;
double z2 = scale*Math.cos((blackhole.ticksExisted + 40*j - sliceAngle)*(Math.PI/180));
double absoluteX = x1*Math.cos(31*b);
double absoluteY = z1*Math.sin(31*a) + x1*Math.cos(31*a)*Math.sin(31*b);
double absoluteZ = z1*Math.cos(31*a);
double absoluteX2 = x2*Math.cos(31*b);
double absoluteY2 = z2*Math.sin(31*a) + x2*Math.cos(31*a)*Math.sin(31*b);
double absoluteZ2 = z2*Math.cos(31*a);
/*
buffer.begin(0, DefaultVertexFormats.POSITION_TEX);
tessellator.setColorOpaque(255, 255, 255);
GL11.glPointSize(5);
tessellator.addVertex(absoluteX-x, 0, 0);
tessellator.addVertex(0, absoluteY-y, 0);
tessellator.addVertex(0, 0, absoluteZ-z);
tessellator.draw();
*/
rays.add(new RayHelper(j, absoluteX, absoluteY, absoluteZ, absoluteX2, absoluteY2, absoluteZ2, x, y, z));
}
Collections.sort(rays);
for(RayHelper ray : rays){
GlStateManager.pushMatrix();
//GlStateManager.rotate(31*blackhole.randomiser[ray.ordinal], 1, 0, 0);
//GlStateManager.rotate(31*blackhole.randomiser2[ray.ordinal], 0, 0, 1);
buffer.begin(5, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA(255, 255, 255, 0);
buffer.pos(0, 0, 0).tex(0, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).endVertex();
//tessellator.setColorRGBA(0, 0, 0, 255);
buffer.pos(ray.x1, ray.y1, ray.z1).tex(1, 0).endVertex();
buffer.pos(ray.x2, ray.y2, ray.z2).tex(1, 1).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
}
GlStateManager.pushMatrix();
/* Deprecated in favour of particle style method.
GlStateManager.rotate(yaw, 0, 1, 0);
// GL transformations are relative, hence only x rotation
if(z < 0){
GlStateManager.rotate(pitch, 1, 0, 0);
}else{
GlStateManager.rotate(-1*pitch, 1, 0, 0);
}
*/
// Renders the aura effect
// This counteracts the reverse rotation behaviour when in front f5 view. Vanilla now has this fix too.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX;
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
this.bindTexture(texture2);
buffer.pos(-0.4, 0.4, 0).tex(0, 0).endVertex();
buffer.pos(0.4, 0.4, 0).tex(1, 0).endVertex();
buffer.pos(0.4, -0.4, 0).tex(1, 1).endVertex();
buffer.pos(-0.4, -0.4, 0).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityBlackHole entity) {
return texture;
}
}
@@ -0,0 +1,25 @@
package electroblob.wizardry.client.renderer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
public class RenderBlank extends Render<Entity> {
public RenderBlank(RenderManager renderManager) {
super(renderManager);
}
@Override
public void doRender(Entity entity, double d0, double d1, double d2,
float f, float f1) {
}
@Override
protected ResourceLocation getEntityTexture(Entity entity) {
return null;
}
}
@@ -0,0 +1,104 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderBubble extends Render<EntityBubble> {
private static final ResourceLocation particleTextures = new ResourceLocation("textures/particle/particles.png");
private static final ResourceLocation darkOrbTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/dark_orb.png");
public RenderBubble(RenderManager renderManager) {
super(renderManager);
}
@Override
public void doRender(EntityBubble entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
if(WizardryUtilities.getRider(entity) != null){
yOffset = WizardryUtilities.getRider(entity).height/2;
}
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(((EntityBubble)entity).isDarkOrb ? darkOrbTexture : particleTextures);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
if(((EntityBubble)entity).isDarkOrb){
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
}else{
int j = entity.getBrightnessForRender(par9);
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)k / 1.0F, (float)l / 1.0F);
}
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX;
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
float f11 = 3.0F;
GlStateManager.scale(f11, f11, f11);
double pixelwidth = (1.0d/128);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
if(((EntityBubble)entity).isDarkOrb){
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(0, 0).endVertex();
}else{
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 24).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth*8, pixelwidth * 24).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth*8, pixelwidth * 17).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 17).endVertex();
}
tessellator.draw();
GlStateManager.disableBlend();
if(((EntityBubble)entity).isDarkOrb){
GlStateManager.enableLighting();
}
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityBubble entity) {
return null;
}
}
@@ -0,0 +1,74 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityDecay;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderDecay extends Render<EntityDecay> {
private static final ResourceLocation[] textures = new ResourceLocation[10];
public RenderDecay(RenderManager renderManager){
super(renderManager);
for(int i=0;i<10;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/decay_" + i + ".png");
}
}
@Override
public void doRender(EntityDecay entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(textures[((EntityDecay)entity).textureIndex]);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
float scale = 2*Math.min(1, (float)(EntityDecay.LIFETIME - entity.ticksExisted)/50f);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityDecay entity) {
return null;
}
}
@@ -0,0 +1,108 @@
package electroblob.wizardry.client.renderer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.living.EntityDecoy;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// TODO: Backport the rewrite of this entire class.
@SideOnly(Side.CLIENT)
public class RenderDecoy extends RenderBiped<EntityDecoy> {
private static final ResourceLocation steveTextures = new ResourceLocation("textures/entity/steve.png");
private static final Method getEntityTexture = ReflectionHelper.findMethod(Render.class, null,
new String[]{"getEntityTexture", "func_110775_a"}, Entity.class); // Generic parameter T is erased to Entity at runtime.
public RenderDecoy(RenderManager manager){
super(manager, new ModelBiped(0.0f), 0.5f);
}
@Override
public void doRender(EntityDecoy entity, double x, double y, double z, float entityYaw, float partialTicks) {
if(entity.getCaster() != null){
this.renderName(entity, x, y, z);
// Save relevant animation fields from the caster to local variables
float pitch = entity.getCaster().rotationPitch;
float prevPitch = entity.getCaster().prevRotationPitch;
float swing = entity.getCaster().swingProgress;
float prevSwing = entity.getCaster().prevSwingProgress;
float yawOffset = entity.getCaster().renderYawOffset;
float prevYawOffset = entity.getCaster().prevRenderYawOffset;
float yaw = entity.getCaster().rotationYawHead;
float prevYaw = entity.getCaster().prevRotationYawHead;
float limbSwing = entity.getCaster().limbSwing;
float limbSwingAmount = entity.getCaster().limbSwingAmount;
float prevLimbSwingAmount = entity.getCaster().prevLimbSwingAmount;
int hurtTime = entity.getCaster().hurtTime;
boolean sneak = entity.getCaster().isSneaking();
Entity mount = entity.getCaster().getRidingEntity();
// Assign decoy's animation fields to the caster
entity.getCaster().rotationPitch = entity.rotationPitch;
entity.getCaster().prevRotationPitch = entity.prevRotationPitch;
entity.getCaster().swingProgress = entity.swingProgress;
entity.getCaster().prevSwingProgress = entity.prevSwingProgress;
entity.getCaster().renderYawOffset = entity.renderYawOffset;
entity.getCaster().prevRenderYawOffset = entity.prevRenderYawOffset;
entity.getCaster().rotationYawHead = entity.rotationYawHead;
entity.getCaster().prevRotationYawHead = entity.prevRotationYawHead;
entity.getCaster().limbSwing = entity.limbSwing;
entity.getCaster().limbSwingAmount = entity.limbSwingAmount;
entity.getCaster().prevLimbSwingAmount = entity.prevLimbSwingAmount;
entity.getCaster().hurtTime = entity.hurtTime;
entity.getCaster().setSneaking(false); // Decoys can't sneak FIXME Not working!
entity.getCaster().dismountRidingEntity(); // Decoys can't ride anything
// Do the rendering
renderManager.getEntityRenderObject(entity.getCaster()).doRender(entity.getCaster(), x, y, z, entityYaw, partialTicks);
// Reset caster's animation fields to their original values
entity.getCaster().rotationPitch = pitch;
entity.getCaster().prevRotationPitch = prevPitch;
entity.getCaster().swingProgress = swing;
entity.getCaster().prevSwingProgress = prevSwing;
entity.getCaster().renderYawOffset = yawOffset;
entity.getCaster().prevRenderYawOffset = prevYawOffset;
entity.getCaster().rotationYawHead = yaw;
entity.getCaster().prevRotationYawHead = prevYaw;
entity.getCaster().limbSwing = limbSwing;
entity.getCaster().limbSwingAmount = limbSwingAmount;
entity.getCaster().prevLimbSwingAmount = prevLimbSwingAmount;
entity.getCaster().hurtTime = hurtTime;
entity.getCaster().setSneaking(sneak);
if(mount != null) entity.getCaster().startRiding(mount);
}else{
super.doRender(entity, x, y, z, entityYaw, partialTicks);
}
}
@Override
protected ResourceLocation getEntityTexture(EntityDecoy entity){
if(entity.getCaster() != null){
try {
return (ResourceLocation)getEntityTexture.invoke(renderManager.getEntityRenderObject(entity.getCaster()));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassCastException e){
Wizardry.logger.error("Error while reflectively calling Render#getEntityTexture as part of decoy rendering");
e.printStackTrace();
}
}
// Fallback to steve textures
return steveTextures;
}
}
@@ -0,0 +1,34 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelWizard;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.layers.LayerBipedArmor;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderEvilWizard extends RenderBiped<EntityEvilWizard>
{
static final ResourceLocation[] textures = new ResourceLocation[6];
public RenderEvilWizard(RenderManager renderManager){
super(renderManager, new ModelWizard(), 0.5F);
for(int i=0;i<6;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/evil_wizard_" + i + ".png");
}
// Just using the default without overriding models, since the armour sets its own model anyway.
this.addLayer(new LayerBipedArmor(this));
}
@Override
protected ResourceLocation getEntityTexture(EntityEvilWizard wizard) {
return textures[wizard.textureIndex];
}
}
@@ -0,0 +1,180 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.construct.EntityFireRing;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
public class RenderFireRing extends Render<EntityFireRing> {
private final ResourceLocation texture;
private float scale = 1.0f;
public RenderFireRing(RenderManager renderManager, ResourceLocation texture, float scale) {
super(renderManager);
this.texture = texture;
this.scale = scale;
}
@Override
public void doRender(EntityFireRing entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(texture);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
// Fire
GlStateManager.disableLighting();
TextureAtlasSprite icon = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(Blocks.FIRE.getDefaultState()).getParticleTexture();
int sides = 16;
float height = 1.0f;
for(int k=0; k<sides; k++){
GlStateManager.pushMatrix();
GlStateManager.translate((float)par2, (float)par4 + 0.05f, (float)par6);
float f1 = 1.0f;
GlStateManager.scale(f1, f1, f1);
float f2 = 0.5F;
float f3 = 0.0F;
float f4 = 0.2f;
float f5 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
float f61 = 0.0F;
int i = 0;
GlStateManager.rotate((360f/(float)sides)*k, 0, 1, 0);
GlStateManager.translate(0, 0, -2.3f);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
while (f4 > 0.0F){
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
float f71 = icon.getMinU();
float f81 = icon.getMinV();
float f9 = icon.getMaxU();
float f10 = icon.getMaxV();
if (i / 2 % 2 == 0)
{
float f11 = f9;
f9 = f71;
f71 = f11;
}
buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81).endVertex();
buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81).endVertex();
f4 -= 0.45F;
f5 -= 0.45F;
f2 *= 0.9F;
f61 += 0.03F;
++i;
}
tessellator.draw();
GlStateManager.popMatrix();
}
for(int k=0; k<sides; k++){
GlStateManager.pushMatrix();
GlStateManager.translate((float)par2, (float)par4 + 0.05f, (float)par6);
float f1 = 1.0f;
GlStateManager.scale(f1, f1, f1);
float f2 = 0.5F;
float f3 = 0.0F;
float f4 = 0.2f;
float f5 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
float f61 = 0.0F;
int i = 0;
GlStateManager.rotate((360f/(float)sides)*k, 0, 1, 0);
GlStateManager.translate(0, 0, 2.3f);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
while (f4 > 0.0F){
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
float f71 = icon.getMinU();
float f81 = icon.getMinV();
float f9 = icon.getMaxU();
float f10 = icon.getMaxV();
if (i / 2 % 2 == 0)
{
float f11 = f9;
f9 = f71;
f71 = f11;
}
buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10).endVertex();
buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81).endVertex();
buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81).endVertex();
f4 -= 0.45F;
f5 -= 0.45F;
f2 *= 0.9F;
f61 += 0.03F;
++i;
}
tessellator.draw();
GlStateManager.popMatrix();
}
GlStateManager.enableLighting();
}
@Override
protected ResourceLocation getEntityTexture(EntityFireRing entity) {
return null;
}
}
@@ -0,0 +1,127 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.projectile.EntityForceArrow;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderForceArrow extends Render<EntityForceArrow>{
private static final ResourceLocation arrowTextures = new ResourceLocation(Wizardry.MODID, "textures/entity/force_arrow.png");
public RenderForceArrow(RenderManager renderManager){
super(renderManager);
}
@Override
public void doRender(EntityForceArrow arrow, double par2, double par4, double par6, float par8, float par9){
this.bindEntityTexture(arrow);
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.translate((float)par2, (float)par4, (float)par6);
GlStateManager.rotate(arrow.prevRotationYaw + (arrow.rotationYaw - arrow.prevRotationYaw) * par9 - 90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(arrow.prevRotationPitch + (arrow.rotationPitch - arrow.prevRotationPitch) * par9, 0.0F, 0.0F, 1.0F);
GlStateManager.rotate(180, 0, 1, 0);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
float pixel = 1.0f/32.0f;
float u1 = 0.0f;
float u2 = pixel*14;
float v1 = 0.0f;
float v2 = pixel*7;
float u3 = pixel*16;
float u4 = 1.0f;
float v3 = 0.0f;
float v4 = pixel*16;
float u5 = 0.0f;
float u6 = pixel*7;
float v5 = pixel*25;
float v6 = 1.0f;
float scale = 0.05625F;
float f11 = 0.0f;
GlStateManager.enableRescaleNormal();
//f11 = (float)par1EntityArrow.arrowShake - par9;
if (f11 > 0.0F)
{
float f12 = -MathHelper.sin(f11 * 3.0F) * f11;
GlStateManager.rotate(f12, 0.0F, 0.0F, 1.0F);
}
scale*=0.8f;
GlStateManager.rotate(45.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.scale(scale, scale, scale);
GlStateManager.translate(-4.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-5, 3.5, -3.5).tex((double)u5, (double)v5).endVertex();
buffer.pos(-5, 3.5, 3.5).tex((double)u6, (double)v5).endVertex();
buffer.pos(-5, -3.5, 3.5).tex((double)u6, (double)v6).endVertex();
buffer.pos(-5, -3.5, -3.5).tex((double)u5, (double)v6);
tessellator.draw();
for(int i=0; i<5; i++){
GlStateManager.color(1, 1, 1, 1 - i*0.2f);
double j = i + ((double)arrow.ticksExisted%3)/3;
double width = 2.0d + (Math.sqrt(j*2)-0.6)*2;
GL11.glNormal3f(scale, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-10 + j*4, -width, -width).tex((double)u3, (double)v3).endVertex();
buffer.pos(-10 + j*4, -width, width).tex((double)u4, (double)v3).endVertex();
buffer.pos(-10 + j*4, width, width).tex((double)u4, (double)v4).endVertex();
buffer.pos(-10 + j*4, width, -width).tex((double)u3, (double)v4).endVertex();
tessellator.draw();
GL11.glNormal3f(-scale, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-10 + j*4, width, -width).tex((double)u3, (double)v3).endVertex();
buffer.pos(-10 + j*4, width, width).tex((double)u4, (double)v3).endVertex();
buffer.pos(-10 + j*4, -width, width).tex((double)u4, (double)v4).endVertex();
buffer.pos(-10 + j*4, -width, -width).tex((double)u3, (double)v4).endVertex();
tessellator.draw();
}
GlStateManager.color(1, 1, 1, 1);
for (int i = 0; i < 4; ++i)
{
GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
GL11.glNormal3f(0.0F, 0.0F, scale);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-10.0D, -4.0D, 0.0D).tex((double)u1, (double)v1).endVertex();
buffer.pos(10.0D, -4.0D, 0.0D).tex((double)u2, (double)v1).endVertex();
buffer.pos(10.0D, 4.0D, 0.0D).tex((double)u2, (double)v2).endVertex();
buffer.pos(-10.0D, 4.0D, 0.0D).tex((double)u1, (double)v2).endVertex();
tessellator.draw();
}
GlStateManager.disableBlend();
GlStateManager.disableRescaleNormal();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityForceArrow par1Entity)
{
return arrowTextures;
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelHammer;
import electroblob.wizardry.entity.construct.EntityHammer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
public class RenderHammer extends Render<EntityHammer> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_hammer.png");
private ModelHammer model = new ModelHammer();
public RenderHammer(RenderManager renderManager){
super(renderManager);
}
@Override
public void doRender(EntityHammer entity, double x, double y, double z, float f, float f1) {
GlStateManager.pushMatrix();
GlStateManager.translate(x, y+1.5, z);
GlStateManager.rotate(180, 0F, 0F, 1F);
this.bindTexture(texture);
model.render(entity, 0, 0, 0, 0, 0, 0.0625f);
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityHammer entity) {
return texture;
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelIceGiant;
import electroblob.wizardry.entity.living.EntityIceGiant;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderIceGiant extends RenderLiving<EntityIceGiant> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_giant.png");
public RenderIceGiant(RenderManager renderManager){
super(renderManager, new ModelIceGiant(), 0.5F);
}
@Override
protected ResourceLocation getEntityTexture(EntityIceGiant entity){
return texture;
}
@Override
protected void rotateCorpse(EntityIceGiant entityLiving, float pitch, float yaw, float partialTicks){
super.rotateCorpse(entityLiving, pitch, yaw, partialTicks);
if ((double)entityLiving.limbSwingAmount >= 0.01D){
float f3 = 13.0F;
float f4 = entityLiving.limbSwing - entityLiving.limbSwingAmount * (1.0F - partialTicks) + 6.0F;
float f5 = (Math.abs(f4 % f3 - f3 * 0.5F) - f3 * 0.25F) / (f3 * 0.25F);
GlStateManager.rotate(6.5F * f5, 0.0F, 0.0F, 1.0F);
}
}
}
@@ -0,0 +1,84 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityIceSpike;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderIceSpike extends Render<EntityIceSpike> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_spike.png");
public RenderIceSpike(RenderManager renderManager){
super(renderManager);
}
@Override
public void doRender(EntityIceSpike entity, double x, double y, double z, float fa, float partialTickTime) {
GlStateManager.pushMatrix();
GlStateManager.translate((float)x, (float)y, (float)z);
// Apparently, disabling lighting... doesn't disable lighting. Or at least, you can still set the brightness
// with setLightmapTextureCoords.
GlStateManager.disableLighting();
int j = entity.getBrightnessForRender(partialTickTime);
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)k / 1.0F, (float)l / 1.0F);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
bindTexture(texture);
// West face
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 0, 0.5).tex(1, 1).endVertex();
buffer.pos(0, 1, 0.5).tex(1, 0).endVertex();
buffer.pos(0, 1, -0.5).tex(0, 0).endVertex();
buffer.pos(0, 0, -0.5).tex(0, 1).endVertex();
tessellator.draw();
// South face
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos( 0.5, 0, 0).tex(1, 1).endVertex();
buffer.pos( 0.5, 1, 0).tex(1, 0).endVertex();
buffer.pos(-0.5, 1, 0).tex(0, 0).endVertex();
buffer.pos(-0.5, 0, 0).tex(0, 1).endVertex();
tessellator.draw();
// East face
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, 0, -0.5).tex(0, 1).endVertex();
buffer.pos(0, 1, -0.5).tex(0, 0).endVertex();
buffer.pos(0, 1, 0.5).tex(1, 0).endVertex();
buffer.pos(0, 0, 0.5).tex(1, 1).endVertex();
tessellator.draw();
// North face
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos(-0.5, 0, 0).tex(0, 1).endVertex();
buffer.pos(-0.5, 1, 0).tex(0, 0).endVertex();
buffer.pos( 0.5, 1, 0).tex(1, 0).endVertex();
buffer.pos( 0.5, 0, 0).tex(1, 1).endVertex();
tessellator.draw();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityIceSpike entity) {
return texture;
}
}
@@ -0,0 +1,82 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.projectile.EntityLightningDisc;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderLightningDisc extends Render<EntityLightningDisc> {
private final ResourceLocation texture;
private float scale = 1.0f;
public RenderLightningDisc(RenderManager renderManager, ResourceLocation texture, float scale) {
super(renderManager);
this.texture = texture;
this.scale = scale;
}
@Override
public void doRender(EntityLightningDisc entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(texture);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
GlStateManager.rotate(entity.ticksExisted*8, 0, 0, 1);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityLightningDisc entity) {
return null;
}
}
@@ -0,0 +1,72 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderLightningPulse extends Render<EntityLightningPulse> {
private final ResourceLocation[] textures = new ResourceLocation[8];
private float scale = 1.0f;
public RenderLightningPulse(RenderManager renderManager, float scale) {
super(renderManager);
for(int i=0; i<textures.length; i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_pulse_" + i + ".png");
}
this.scale = scale;
}
@Override
public void doRender(EntityLightningPulse entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(textures[entity.ticksExisted]);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityLightningPulse entity) {
return null;
}
}
@@ -0,0 +1,122 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.projectile.EntityMagicArrow;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderMagicArrow extends Render<EntityMagicArrow> {
private final ResourceLocation texture;
private boolean blend;
private boolean renderEnds;
private double length = 8.0, width = 2.0;
private int pixelsLong = 16, pixelsWide = 5;
public RenderMagicArrow(RenderManager renderManager, ResourceLocation texture, boolean blend, double length, double width, int pixelsLong, int pixelsWide, boolean renderEnds){
super(renderManager);
this.texture = texture;
this.blend = blend;
this.renderEnds = renderEnds;
this.length = length;
this.width = width;
this.pixelsLong = pixelsLong;
this.pixelsWide = pixelsWide;
}
@Override
public void doRender(EntityMagicArrow entity, double par2, double par4, double par6, float par8, float par9){
this.bindEntityTexture(entity);
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
if(this.blend){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
GlStateManager.translate((float)par2, (float)par4, (float)par6);
GlStateManager.rotate(entity.prevRotationYaw + (entity.rotationYaw - entity.prevRotationYaw) * par9 - 90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * par9, 0.0F, 0.0F, 1.0F);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
float f2 = 0.0F;
float f3 = pixelsLong / 32.0F;
float f4 = 0.0F;
float f5 = pixelsWide / 32.0F;
float f6 = 0.0F;
float f7 = 0.15625F;
float f8 = (float)5 / 32.0F;
float f9 = (float)10 / 32.0F;
float f10 = 0.05625F;
float f11 = 0.0f;
GlStateManager.enableRescaleNormal();
//f11 = (float)par1EntityArrow.arrowShake - par9;
if (f11 > 0.0F)
{
float f12 = -MathHelper.sin(f11 * 3.0F) * f11;
GlStateManager.rotate(f12, 0.0F, 0.0F, 1.0F);
}
GlStateManager.rotate(45.0F, 1.0F, 0.0F, 0.0F);
GlStateManager.scale(f10, f10, f10);
GlStateManager.translate(-4.0F, 0.0F, 0.0F);
GL11.glNormal3f(f10, 0.0F, 0.0F);
if(renderEnds){
// Ends
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-7.0D, -width, -width).tex((double)f6, (double)f8).endVertex();
buffer.pos(-7.0D, -width, width).tex((double)f7, (double)f8).endVertex();
buffer.pos(-7.0D, width, width).tex((double)f7, (double)f9).endVertex();
buffer.pos(-7.0D, width, -width).tex((double)f6, (double)f9).endVertex();
tessellator.draw();
GL11.glNormal3f(-f10, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-7.0D, width, -width).tex((double)f6, (double)f8).endVertex();
buffer.pos(-7.0D, width, width).tex((double)f7, (double)f8).endVertex();
buffer.pos(-7.0D, -width, width).tex((double)f7, (double)f9).endVertex();
buffer.pos(-7.0D, -width, -width).tex((double)f6, (double)f9).endVertex();
tessellator.draw();
}
for (int i = 0; i < 4; ++i){
// Sides
GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
GL11.glNormal3f(0.0F, 0.0F, f10);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(-length, -width, 0.0D).tex((double)f2, (double)f4).endVertex();
buffer.pos(length, -width, 0.0D).tex((double)f3, (double)f4).endVertex();
buffer.pos(length, width, 0.0D).tex((double)f3, (double)f5).endVertex();
buffer.pos(-length, width, 0.0D).tex((double)f2, (double)f5).endVertex();
tessellator.draw();
}
if(this.blend){
GlStateManager.disableBlend();
}
GlStateManager.disableRescaleNormal();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityMagicArrow arrow)
{
return texture;
}
}
@@ -0,0 +1,130 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderMagicLight extends TileEntitySpecialRenderer<TileEntityMagicLight> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/light_ray.png");
private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID, "textures/entity/light_aura.png");
@Override
public void renderTileEntityAt(TileEntityMagicLight tileentity, double x, double y, double z, float f, int destroyStage){
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.shadeModel(GL11.GL_SMOOTH);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
RenderHelper.disableStandardItemLighting();
GlStateManager.translate(x + 0.5, y + 0.5, z + 0.5);
if(tileentity.timer < 10){
GlStateManager.scale((float)tileentity.timer/10, (float)tileentity.timer/10, (float)tileentity.timer/10);
}
if(tileentity.timer > tileentity.maxTimer-10){
GlStateManager.scale((float)(tileentity.maxTimer-tileentity.timer)/10, (float)(tileentity.maxTimer-tileentity.timer)/10, (float)(tileentity.maxTimer-tileentity.timer)/10);
}
// Renders the aura effect
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? Minecraft.getMinecraft().getRenderManager().playerViewX : -Minecraft.getMinecraft().getRenderManager().playerViewX;
GlStateManager.rotate(180.0F - Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
this.bindTexture(texture2);
buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex();
buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex();
buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex();
buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
// Renders the rays
// For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the innermost
// ends of the rays to appear black, so I have changed it to this, which looks very slightly different.
GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA);
this.bindTexture(texture);
if(tileentity.randomiser.length >= 30){
for(int j=0; j<30; j++){
int sliceAngle = 20 + tileentity.randomiser[j];
float scale = 0.5f;
GlStateManager.pushMatrix();
GlStateManager.rotate(31*tileentity.randomiser[j], 1, 0, 0);
GlStateManager.rotate(31*tileentity.randomiser2[j], 0, 0, 1);
/*
* OK, so here are the changes to rendering as far as I know:
* Vertex formats specify how the methods are arranged
* Color has to be called for every vertex, I think.
* The new methods thing is a bit weird, because other than the number of arguments there is
* essentially no difference between pos, tex, color, normal and lightmap. At least they make
* the code more readable.
*/
buffer.begin(5, DefaultVertexFormats.POSITION_TEX_COLOR);
buffer.pos(0, 0, 0).tex(0, 0).color(255, 255, 255, 0).endVertex();
buffer.pos(0, 0, 0).tex(0, 1).color(255, 255, 255, 0).endVertex();
double x1 = scale*Math.sin((tileentity.timer + 40*j)*(Math.PI/180));
//double y1 = 0.7*Math.cos((timerentity.timer - 40*j)*(Math.PI/180))*j/10;
double z1 = scale*Math.cos((tileentity.timer + 40*j)*(Math.PI/180));
double x2 = scale*Math.sin((tileentity.timer + 40*j - sliceAngle)*(Math.PI/180));
//double y2 = 0.7*Math.sin((timerentity.timer - 40*j)*(Math.PI/180))*j/10;
double z2 = scale*Math.cos((tileentity.timer + 40*j - sliceAngle)*(Math.PI/180));
buffer.pos(x1, 0, z1).tex(1, 0).color(0, 0, 0, 255).endVertex();
buffer.pos(x2, 0, z2).tex(1, 1).color(0, 0, 0, 255).endVertex();
tessellator.draw();
GlStateManager.popMatrix();
}
}
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
RenderHelper.enableStandardItemLighting();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,52 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelPhoenix;
import electroblob.wizardry.entity.living.EntityPhoenix;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderPhoenix extends RenderLiving<EntityPhoenix> {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/phoenix.png");
public RenderPhoenix(RenderManager renderManager){
super(renderManager, new ModelPhoenix(), 1.0f);
}
@Override
protected ResourceLocation getEntityTexture(EntityPhoenix entity){
return texture;
}
@Override
protected void rotateCorpse(EntityPhoenix par1EntityPhoenix, float par2, float par3, float par4){
GlStateManager.translate(0.0F, -0.1F, 0.0F);
super.rotateCorpse(par1EntityPhoenix, par2, par3, par4);
}
@Override
public void doRender(EntityPhoenix phoenix, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
super.doRender(phoenix, par2, par4, par6, par8, par9);
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,88 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.projectile.EntityMagicProjectile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderProjectile extends Render<EntityMagicProjectile> {
private float scale;
private boolean blend = false;
private final ResourceLocation texture;
public RenderProjectile(RenderManager renderManager, float scale, ResourceLocation texture, boolean doBlending)
{
super(renderManager);
this.scale = scale;
this.texture = texture;
this.blend = doBlending;
}
@Override
public void doRender(EntityMagicProjectile entity, double par2, double par4, double par6, float par8, float par9){
GlStateManager.pushMatrix();
this.bindTexture(texture);
GlStateManager.translate((float)par2, (float)par4, (float)par6);
GlStateManager.enableRescaleNormal();
if(blend){
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
float f2 = this.scale;
GlStateManager.scale(f2 / 1.0F, f2 / 1.0F, f2 / 1.0F);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
float f3 = 0.0f;
float f4 = 1.0f;
float f5 = 0.0f;
float f6 = 1.0f;
float f7 = 1.0F;
float f8 = 0.5F;
float f9 = 0.25F;
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2 ? this.renderManager.playerViewX : -this.renderManager.playerViewX;
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f8), (double)(0.0F - f9), 0.0D).tex((double)f3, (double)f6).endVertex();
buffer.pos((double)(f7 - f8), (double)(0.0F - f9), 0.0D).tex((double)f4, (double)f6).endVertex();
buffer.pos((double)(f7 - f8), (double)(1.0F - f9), 0.0D).tex((double)f4, (double)f5).endVertex();
buffer.pos((double)(0.0F - f8), (double)(1.0F - f9), 0.0D).tex((double)f3, (double)f5).endVertex();
tessellator.draw();
GlStateManager.disableRescaleNormal();
if(blend){
GlStateManager.disableBlend();
}
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityMagicProjectile par1Entity){
return texture;
}
}
@@ -0,0 +1,89 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityMagicConstruct;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
public class RenderSigil extends Render<EntityMagicConstruct> {
private final ResourceLocation texture;
private float scale = 1.0f;
private boolean invisibleToEnemies;
public RenderSigil(RenderManager renderManager, ResourceLocation texture, float scale, boolean invisibleToEnemies) {
super(renderManager);
this.texture = texture;
this.scale = scale;
this.invisibleToEnemies = invisibleToEnemies;
}
@Override
public void doRender(EntityMagicConstruct entity, double par2, double par4, double par6, float par8, float par9){
// Makes the sigil invisible to enemies of the player that created it
if(this.invisibleToEnemies){
if(entity.getCaster() instanceof EntityPlayer
&& !WizardryUtilities.isPlayerAlly((EntityPlayer)entity.getCaster(), Minecraft.getMinecraft().thePlayer)){
return;
}
}
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float yOffset = 0;
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
this.bindTexture(texture);
float f6 = 1.0F;
float f7 = 0.5F;
float f8 = 0.5F;
GlStateManager.rotate(-90, 1, 0, 0);
// Healing aura rotates slowly
if(entity instanceof EntityHealAura) GlStateManager.rotate(entity.ticksExisted/3.0f, 0, 0, 1);
GlStateManager.scale(scale, scale, scale);
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
//tessellator.setColorRGBA_I(k1, 128);
//buffer.normal(0.0F, 1.0F, 0.0F);
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@Override
protected ResourceLocation getEntityTexture(EntityMagicConstruct entity) {
return null;
}
}
@@ -0,0 +1,36 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.model.ModelHorse;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderHorse;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderSpiritHorse extends RenderHorse {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_horse.png");
public RenderSpiritHorse(RenderManager renderManager, float par2){
super(renderManager, new ModelHorse(), par2);
}
@Override
protected ResourceLocation getEntityTexture(EntityHorse entity) {
return texture;
}
@Override
protected void preRenderCallback(EntityHorse entitylivingbaseIn, float partialTickTime){
super.preRenderCallback(entitylivingbaseIn, partialTickTime);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -0,0 +1,35 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.model.ModelWolf;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.RenderWolf;
import net.minecraft.entity.passive.EntityWolf;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderSpiritWolf extends RenderWolf {
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_wolf.png");
public RenderSpiritWolf(RenderManager renderManager, float par3){
super(renderManager, new ModelWolf(), par3);
}
@Override
protected ResourceLocation getEntityTexture(EntityWolf entity) {
return texture;
}
@Override
protected void preRenderCallback(EntityWolf entity, float partialTickTime){
super.preRenderCallback(entity, partialTickTime);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -0,0 +1,64 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.tileentity.TileEntityStatue;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
public class RenderStatue extends TileEntitySpecialRenderer<TileEntityStatue> {
private int destroyStage = 0; // Gets set each time a statue is rendered to allow access from the layer renderer
@Override
public void renderTileEntityAt(TileEntityStatue statue, double x, double y, double z, float partialTicks, int destroyStage){
// Multiblock support for the breaking animation. The chest has its own way of doing this in
// TileEntityRendererDispatcher, but I don't have access to that.
if(statue.position != 1 && destroyStage >= 0){
TileEntity tileentity = statue.getWorld().getTileEntity(statue.getPos().down(statue.position-1));
//System.out.println(tileentity);
if(tileentity instanceof TileEntityStatue){
// If this is the block breaking animation pass and this isn't the bottom block, divert the call to
// the bottom block.
this.renderTileEntityAt((TileEntityStatue)tileentity, x, y - (statue.position-1), z, partialTicks, destroyStage);
}
}
if(statue.creature != null && statue.position == 1){
this.destroyStage = destroyStage;
GlStateManager.pushMatrix();
// The next line makes stuff render in the same place relative to the world wherever the player is.
GlStateManager.translate((float)x + 0.5F, (float)y, (float)z + 0.5F);
GlStateManager.enableLighting();
float yaw = statue.creature.prevRotationYaw;
int i = statue.creature.getBrightnessForRender(0);
int j = i % 65536;
int k = i / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.rotate(-yaw, 0F, 1F, 0F);
// Stops the normal model from rendering.
if(!statue.isIce) statue.creature.setInvisible(true);
// Setting the last parameter to true prevents the debug bounding box from rendering.
// For some reason, passing in the partialTicks causes the entity to spin round really fast
Minecraft.getMinecraft().getRenderManager().doRenderEntity(statue.creature, 0, 0, 0, 0, 0, true);
if(!statue.isIce) statue.creature.setInvisible(false);
GlStateManager.popMatrix();
}
}
public ResourceLocation getBlockBreakingTexture(){
return destroyStage < 0 ? null : DESTROY_STAGES[destroyStage];
}
}
@@ -0,0 +1,34 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelWizard;
import electroblob.wizardry.entity.living.EntityWizard;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.layers.LayerBipedArmor;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderWizard extends RenderBiped<EntityWizard> {
static final ResourceLocation[] textures = new ResourceLocation[6];
public RenderWizard(RenderManager renderManager){
super(renderManager, new ModelWizard(), 0.5F);
for(int i=0;i<6;i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/wizard_" + i + ".png");
}
// Just using the default without overriding models, since the armour sets its own model anyway.
this.addLayer(new LayerBipedArmor(this));
}
@Override
protected ResourceLocation getEntityTexture(EntityWizard wizard) {
return textures[wizard.textureIndex];
}
}
@@ -0,0 +1,26 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.entity.living.EntityBlazeMinion;
import net.minecraft.client.model.ModelBlaze;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderWraithMinion extends RenderLiving<EntityBlazeMinion>
{
private ResourceLocation texture = new ResourceLocation("textures/entity/blaze.png");
public RenderWraithMinion(RenderManager renderManagerIn)
{
super(renderManagerIn, new ModelBlaze(), 0.5F);
}
@Override
protected ResourceLocation getEntityTexture(EntityBlazeMinion entity)
{
return texture;
}
}
@@ -0,0 +1,183 @@
package electroblob.wizardry.command;
import java.util.List;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.NumberInvalidException;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.server.MinecraftServer;
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.util.text.TextFormatting;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
public class CommandCastSpell extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.castCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 2;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:cast.usage";
//return I18n.format("commands.wizardry:cast.usage", Wizardry.settings.castCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, Spell.getSpellNames());
case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
if(arguments.length < 1){
throw new WrongUsageException("commands.wizardry:cast.usage", Wizardry.settings.castCommandName);
}else{
int i=0;
EntityPlayerMP entityplayermp = null;
try{
entityplayermp = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
Spell spell = Spell.get(arguments[i++]);
if(spell == null){
throw new NumberInvalidException("commands.wizardry:cast.not_found", new Object[]{arguments[i-1]});
}
boolean castAsOtherPlayer = false;
if(i < arguments.length){
try{
// If the second argument is a player and is not the player that gave the command, the spell is cast
// as the given player rather than the command sender, and there is a different chat readout.
EntityPlayerMP entityplayermp1 = getPlayer(server, sender, arguments[i++]);
if(entityplayermp != entityplayermp1){
castAsOtherPlayer = true;
entityplayermp = entityplayermp1;
}
}catch(PlayerNotFoundException exception){
// If no player was found, rather than give an error it simply assumes the player was unspecified.
i--;
}
}
// If, after this point, the player is still null, the sender must be a command block or the console and the
// player must not have been specified, meaning an exception should be thrown.
if(entityplayermp == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
SpellModifiers modifiers = new SpellModifiers();
if(i < arguments.length){
// Copied from CommandGive. Why it doesn't just use arguments[i] itself I don't know.
String nbt = getChatComponentFromNthArg(sender, arguments, i++).getUnformattedText();
try{
modifiers = SpellModifiers.fromNBT(JsonToNBT.getTagFromJson(nbt));
}catch(NBTException nbtexception){
throw new CommandException("commands.wizardry:cast.tag_error", nbtexception.getMessage());
}
for(float multiplier : modifiers.getModifiers().values()){
if(multiplier < 0){
throw new NumberInvalidException("commands.generic.double.tooSmall", multiplier, 0);
}else if(multiplier > Wizardry.settings.maxSpellCommandMultiplier){
throw new NumberInvalidException("commands.generic.double.tooBig", multiplier, Wizardry.settings.maxSpellCommandMultiplier);
}
}
}
if(spell.isContinuous){
WizardData properties = WizardData.get((EntityPlayer)entityplayermp);
if(properties != null){
if(properties.isCasting()){
WizardData.get((EntityPlayer)entityplayermp).stopCastingContinuousSpell();
}else{
WizardData.get((EntityPlayer)entityplayermp).startCastingContinuousSpell(spell, modifiers);
if(castAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_remote_continuous", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}else{
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_continuous", spell.getNameForTranslationFormatted()));
}
}
return;
}
}else{
if(spell.cast(entityplayermp.worldObj, entityplayermp, EnumHand.MAIN_HAND, 0, modifiers)){
if(spell.doesSpellRequirePacket()){
// Sends a packet to all players in dimension to tell them to spawn particles.
// Only sent if the spell succeeded, because if the spell failed, you wouldn't
// need to spawn any particles!
IMessage msg = new PacketCastSpell.Message(entityplayermp.getEntityId(), null, spell.id(), modifiers);
WizardryPacketHandler.net.sendToDimension(msg, entityplayermp.worldObj.provider.getDimension());
}
if(WizardData.get((EntityPlayer)entityplayermp) != null){
// Added optimisation from 1.7.10: if the spell was already discovered, nothing happens.
if(WizardData.get((EntityPlayer)entityplayermp).discoverSpell(spell)){
// If the spell didn't send a packet itself, the extended player needs to be synced so the
// spell discovery updates on the client.
if(!spell.doesSpellRequirePacket()) WizardData.get((EntityPlayer)entityplayermp).sync();
}
}
if(castAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success_remote", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}else{
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:cast.success", spell.getNameForTranslationFormatted()));
}
return;
}
}
ITextComponent message = new TextComponentTranslation("commands.wizardry:cast.fail", spell.getNameForTranslationFormatted());
message.getStyle().setColor(TextFormatting.RED);
sender.addChatMessage(message);
}
}
}
@@ -0,0 +1,130 @@
package electroblob.wizardry.command;
import java.util.List;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.NumberInvalidException;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
public class CommandDiscoverSpell extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.discoverspellCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 2;
}
/*
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender sender){
// Only ops (multiplayer) or players with cheats enabled (singleplayer/LAN) can use /discoverspell.
return !(sender instanceof EntityPlayer) || server.getServer().getConfigurationManager().func_152596_g(((EntityPlayer)sender).getGameProfile());
}
*/
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:discoverspell.usage";
//return I18n.format("commands.wizardry:discoverspell.usage", Wizardry.settings.discoverspellCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, Spell.getSpellNames());
case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
if(arguments.length < 1){
throw new WrongUsageException("commands.wizardry:discoverspell.usage", Wizardry.settings.discoverspellCommandName);
}else{
int i=0;
boolean clear = false;
boolean all = false;
EntityPlayerMP entityplayermp = null;
try{
entityplayermp = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
Spell spell = Spells.none;
if(arguments[i].equals("clear")){
clear = true;
i++;
}else if(arguments[i].equals("all")){
all = true;
i++;
}else{
spell = Spell.get(arguments[i++]);
if(spell == null){
throw new NumberInvalidException("commands.wizardry:discoverspell.not_found", new Object[]{arguments[i-1]});
}
}
if(i < arguments.length){
// If the second argument is a player and is not the player that gave the command, the spell is
// discovered as the given player rather than the command sender.
EntityPlayerMP entityplayermp1 = getPlayer(server, sender, arguments[i++]);
if(entityplayermp != entityplayermp1){
entityplayermp = entityplayermp1;
}
}
// If, after this point, the player is still null, the sender must be a command block or the console and the
// player must not have been specified, meaning an exception should be thrown.
if(entityplayermp == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
WizardData properties = WizardData.get(entityplayermp);
if(properties != null){
if(clear){
properties.spellsDiscovered.clear();
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.clear", entityplayermp.getName()));
}else if(all){
properties.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells));
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.all", entityplayermp.getName()));
}else{
if(properties.hasSpellBeenDiscovered(spell)){
properties.spellsDiscovered.remove(spell);
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.removespell", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}else{
properties.discoverSpell(spell);
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:discoverspell.addspell", spell.getNameForTranslationFormatted(), entityplayermp.getName()));
}
}
properties.sync();
}
}
}
}
@@ -0,0 +1,113 @@
package electroblob.wizardry.command;
import java.util.List;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.NumberInvalidException;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
public class CommandSetAlly extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.allyCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 0;
}
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender p_71519_1_)
{
return true;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:ally.usage";
//return I18n.format("commands.wizardry:ally.usage", Wizardry.settings.allyCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
case 2: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
if(arguments.length < 1){
throw new WrongUsageException("commands.wizardry:ally.usage", Wizardry.settings.allyCommandName);
}else{
EntityPlayerMP allyOf = null;
try{
allyOf = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
boolean executeAsOtherPlayer = false;
EntityPlayerMP ally = getPlayer(server, sender, arguments[0]);
// Don't want to catch the exception here, because the first player argument is always required.
if(arguments.length > 1){
allyOf = getPlayer(server, sender, arguments[1]);
// Don't want to catch the exception here either, because there can be no other second argument.
if(allyOf != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){
// Displays a chat message if a non-op tries to modify another player's allies.
TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation("commands.wizardry:ally.permission");
TextComponentTranslation2.getStyle().setColor(TextFormatting.RED);
allyOf.addChatMessage(TextComponentTranslation2);
return;
}
if(allyOf != sender) executeAsOtherPlayer = true;
}
// If, after this point, allyOf is still null, the sender must be a command block or the console and two
// players must not have been specified, meaning an exception should be thrown.
if(allyOf == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
if(allyOf == ally) throw new NumberInvalidException("commands.wizardry:ally.self");
if(WizardData.get(allyOf) != null){
String string = WizardData.get(allyOf).toggleAlly(ally) ? "add" : "remove";
if(executeAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:ally." + string + "ally", ally.getName(), allyOf.getName()));
// In this case, the player whose allies have been modified is also notified.
allyOf.addChatMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName()));
}else{
sender.addChatMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName()));
}
}
}
}
}
@@ -0,0 +1,112 @@
package electroblob.wizardry.command;
import java.util.List;
import java.util.Set;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.resources.I18n;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.PlayerNotFoundException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
public class CommandViewAllies extends CommandBase {
@Override
public String getCommandName(){
return Wizardry.settings.alliesCommandName;
}
@Override
public int getRequiredPermissionLevel(){
// I *think* it's something like 0 = everyone, 1 = moderator, 2 = op/admin, 3 = op/console...
return 0;
}
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender p_71519_1_)
{
return true;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_){
// Not ideal, but the way this is implemented means I have no choice. Only used in the help command, so in there
// the custom command name will not display.
return "commands.wizardry:allies.usage";
//return I18n.format("commands.wizardry:allies.usage", Wizardry.settings.alliesCommandName);
}
@Override
public List<String> getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] arguments, BlockPos pos) {
switch(arguments.length){
case 1: return getListOfStringsMatchingLastWord(arguments, server.getAllUsernames());
}
return super.getTabCompletionOptions(server, sender, arguments, pos);
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] arguments) throws CommandException {
EntityPlayerMP player = null;
try{
player = getCommandSenderAsPlayer(sender);
}catch(PlayerNotFoundException exception){
// Nothing here since the player specifying is done later, I just don't want it to throw an exception here.
}
boolean executeAsOtherPlayer = false;
if(arguments.length > 0){
player = getPlayer(server, sender, arguments[0]);
// Don't want to catch the exception here either, because there can be no other first argument.
if(player != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){
// Displays a chat message if a non-op tries to view another player's allies.
TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation("commands.wizardry:allies.permission");
TextComponentTranslation2.getStyle().setColor(TextFormatting.RED);
player.addChatMessage(TextComponentTranslation2);
return;
}
if(player != sender) executeAsOtherPlayer = true;
}
// If, after this point, player is still null, the sender must be a command block or the console and the
// player must not have been specified, meaning an exception should be thrown.
if(player == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on.");
if(WizardData.get(player) != null){
String string = "";
Set<String> names = WizardData.get(player).allyNames;
if(!names.isEmpty()){
for(String name : names){
string = string + name + ", ";
}
// Cuts the last " ," off of the string.
string = string.substring(0, string.length() - 2);
}else{
string = I18n.format("commands.wizardry:allies.none");
}
if(executeAsOtherPlayer){
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:allies.list_other", player.getName(), string));
}else{
sender.addChatMessage(new TextComponentTranslation("commands.wizardry:allies.list", string));
}
}
}
}
@@ -0,0 +1,44 @@
package electroblob.wizardry.constants;
import electroblob.wizardry.WizardryEventHandler;
/** Stores various global constants used in Wizardry. */
public final class Constants {
/** The amount of mana each magic crystal is worth */
public static final int MANA_PER_CRYSTAL = 100;
/** The amount of mana each mana flask can hold */
public static final int MANA_PER_FLASK = 700;
/** The maximum number of one type of wand upgrade which can be applied to a wand. */
public static final int UPGRADE_STACK_LIMIT = 3;
/** The fraction by which cooldowns are reduced for each level of cooldown upgrade. */
public static final float COOLDOWN_REDUCTION_PER_LEVEL = 0.15f;
/** The fraction by which maximum charge is increased for each level of storage upgrade. */
public static final float STORAGE_INCREASE_PER_LEVEL = 0.15f;
/** The fraction by which damage is increased for each tier of matching wand. */
public static final float DAMAGE_INCREASE_PER_TIER = 0.15f;
/** The fraction by which costs are reduced for each piece of matching armour. Note that changing this value will not
* affect continuous spells, since they are handled differently. */
public static final float COST_REDUCTION_PER_ARMOUR = 0.2f;
/** The fraction by which spell duration is increased for each level of duration upgrade. */
public static final float DURATION_INCREASE_PER_LEVEL = 0.25f;
/** The fraction by which spell range is increased for each level of range upgrade. */
public static final float RANGE_INCREASE_PER_LEVEL = 0.25f;
/** The fraction by which spell blast radius is increased for each level of range upgrade. */
public static final float BLAST_RADIUS_INCREASE_PER_LEVEL = 0.25f;
/** The fraction by which movement speed is reduced per level of frost effect. */
public static final double FROST_SLOWNESS_PER_LEVEL = 0.5;
/** The fraction by which movement speed is reduced per level of decay effect. */
public static final double DECAY_SLOWNESS_PER_LEVEL = 0.2;
/** The fraction by which dig speed is reduced per level of frost effect. */
public static final float FROST_FATIGUE_PER_LEVEL = 0.45f;
/** The number of ticks between each mana increase for wands with the condenser upgrade. */
public static final int CONDENSER_TICK_INTERVAL = 50;
/** The amount of mana given for a kill for each level of siphon upgrade. A random amount from 0 to this number - 1
* is also added. See {@link WizardryEventHandler#onLivingDeathEvent} for more details. */
public static final int SIPHON_MANA_PER_LEVEL = 3;
/** The number of ticks between the spawning of patches of decay when an entity has the decay effect.
* Note that decay won't spawn again if something is already standing in it. */
public static final int DECAY_SPREAD_INTERVAL = 8;
}
@@ -0,0 +1,67 @@
package electroblob.wizardry.constants;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public enum Element {
/** The 'default' element, with {@link electroblob.wizardry.spell.MagicMissile MagicMissile} being its only spell. */
MAGIC(new Style().setColor(TextFormatting.GRAY), "simple", Wizardry.MODID),
FIRE(new Style().setColor(TextFormatting.DARK_RED), "fire", Wizardry.MODID),
ICE(new Style().setColor(TextFormatting.AQUA), "ice", Wizardry.MODID),
LIGHTNING(new Style().setColor(TextFormatting.DARK_AQUA), "lightning", Wizardry.MODID),
NECROMANCY(new Style().setColor(TextFormatting.DARK_PURPLE), "necromancy", Wizardry.MODID),
EARTH(new Style().setColor(TextFormatting.DARK_GREEN), "earth", Wizardry.MODID),
SORCERY(new Style().setColor(TextFormatting.GREEN), "sorcery", Wizardry.MODID),
HEALING(new Style().setColor(TextFormatting.YELLOW), "healing", Wizardry.MODID);
/** Display colour for this element */
private final Style colour;
/** Unlocalised name for this element */
private final String unlocalisedName;
/** The {@link ResourceLocation} for this element's 8x8 icon (displayed in the arcane workbench GUI) */
private final ResourceLocation icon;
private Element(Style colour, String name, String modid){
this.colour = colour;
this.unlocalisedName = name;
this.icon = new ResourceLocation(modid, "textures/gui/element_icon_" + unlocalisedName + ".png");
}
/** Returns the translated display name of this element, without formatting. */
@SideOnly(Side.CLIENT)
public String getDisplayName(){
return net.minecraft.client.resources.I18n.format("element." + getUnlocalisedName());
}
/** Returns the {@link Style} object representing the colour of this element. */
public Style getColour(){
return colour;
}
/** Returns the string formatting code which corresponds to the colour of this element. */
public String getFormattingCode(){
return colour.getFormattingCode();
}
/** Returns the translated display name for wizards of this element, shown in the trading GUI. */
public ITextComponent getWizardName(){
return new TextComponentTranslation("element." + getUnlocalisedName() + ".wizard");
}
/** Returns this element's unlocalised name. */
public String getUnlocalisedName(){
return unlocalisedName;
}
/** Returns the {@link ResourceLocation} for this element's 8x8 icon (displayed in the arcane workbench GUI). */
public ResourceLocation getIcon(){
return icon;
}
}
@@ -0,0 +1,23 @@
package electroblob.wizardry.constants;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public enum SpellType {
ATTACK("attack"),
DEFENCE("defence"),
UTILITY("utility"),
MINION("minion");
private final String unlocalisedName;
SpellType(String name){
this.unlocalisedName = name;
}
@SideOnly(Side.CLIENT)
public String getDisplayName(){
return net.minecraft.client.resources.I18n.format("spelltype." + unlocalisedName);
}
}
@@ -0,0 +1,81 @@
package electroblob.wizardry.constants;
import java.util.Random;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public enum Tier {
BASIC(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "basic"),
APPRENTICE(1000, 4, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"),
ADVANCED(1500, 5, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
MASTER(2500, 6, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
/** Maximum mana a wand of this tier can store. */
public final int maxCharge;
/** Just an ordinal. Shouldn't really be needed but no point changing it now. */
public final int level;
/** The maximum number of upgrades that can be applied to a wand of this tier. */
public final int upgradeLimit;
/** The weight given to this tier in the standard weighting. */
public final int weight;
/** The colour of text associated with this tier. */
// Changed to a Style object for consistency.
private final Style colour;
private final String unlocalisedName;
private Tier(int maxCharge, int upgradeLimit, int weight, Style colour, String name){
this.maxCharge = maxCharge;
this.level = ordinal();
this.upgradeLimit = upgradeLimit;
this.weight = weight;
this.colour = colour;
this.unlocalisedName = name;
}
@SideOnly(Side.CLIENT)
public String getDisplayName() {
return net.minecraft.client.resources.I18n.format("tier." + unlocalisedName);
}
@SideOnly(Side.CLIENT)
public String getDisplayNameWithFormatting() {
return this.getFormattingCode() + net.minecraft.client.resources.I18n.format("tier." + unlocalisedName);
}
public String getUnlocalisedName(){
return unlocalisedName;
}
public String getFormattingCode(){
return colour.getFormattingCode();
}
/** Returns a random tier based on the standard weighting. Currently, the standard weighting is: Basic (Novice) 60%,
* Apprentice 25%, Advanced 10%, Master 5%. If an array of tiers is given, it picks a tier from the array, with the
* same relative weights for each. For example, if the array contains APPRENTICE and MASTER, then the weighting will
* become: Apprentice 83.3%, Master 16.7%. */
public static Tier getWeightedRandomTier(Random random, Tier... tiers){
if(tiers.length == 0) tiers = values();
int totalWeight = 0;
for(Tier tier : tiers) totalWeight += tier.weight;
int randomiser = random.nextInt(totalWeight);
int cumulativeWeight = 0;
for(Tier tier : tiers){
cumulativeWeight += tier.weight;
if(randomiser < cumulativeWeight) return tier;
}
// This will never happen, but it might as well be a sensible result.
return tiers[tiers.length-1];
}
}
@@ -0,0 +1,59 @@
package electroblob.wizardry.enchantment;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentDamage;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
// This one is for imbued swords. The only reason this is separate is that the way vanilla is written allows me to hook
// into the damage increase for melee weapons, meaning I don't have to use events - always handy!
public class EnchantmentMagicSword extends EnchantmentDamage implements Imbuement {
public EnchantmentMagicSword() {
super(Enchantment.Rarity.COMMON, 0, EntityEquipmentSlot.MAINHAND);
// Setting this to null stops the book appearing in the creative inventory
this.type = null;
}
@Override
public boolean canApply(ItemStack p_92089_1_){
return false;
}
/**
* Returns the maximum level that the enchantment can have.
*/
// Here, enchantment level is the damage multiplier of the spell used to apply the enchantment, i.e. with an
// non-sorcerer wand it is level 1, a basic sorcerer wand is level 2, and so on. Note that basic sorcerer wands can't
// cast the imbue weapon spell, so level 2 is actually for apprentice wands.
@Override
public int getMaxLevel()
{
return 4;
}
// Returns the number by which the damage should be increased (or something)
@Override
public float calcDamageByCreature(int p_152376_1_, EnumCreatureAttribute p_152376_2_)
{
return (float)p_152376_1_ * 1.25F;
}
@Override
public String getName()
{
return "enchantment." + this.getRegistryName();
}
@Override
public boolean isAllowedOnBooks(){
return false;
}
@Override
public boolean canApplyAtEnchantingTable(ItemStack stack) {
return false;
}
}
@@ -0,0 +1,48 @@
package electroblob.wizardry.enchantment;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
// This one is for everything other than imbued swords.
public class EnchantmentTimed extends Enchantment implements Imbuement {
public EnchantmentTimed() {
// Setting enchantment type to null stops the book appearing in the creative inventory
super(Enchantment.Rarity.COMMON, null, new EntityEquipmentSlot[]{EntityEquipmentSlot.MAINHAND});
}
@Override
public boolean canApply(ItemStack p_92089_1_){
return false;
}
@Override
public String getName()
{
return "enchantment." + this.getRegistryName();
}
/**
* Returns the maximum level that the enchantment can have.
*/
// Here, enchantment level is the damage multiplier of the spell used to apply the enchantment, i.e. with an
// non-sorcerer wand it is level 1, an apprentice sorcerer wand is level 2, and so on. Note that basic sorcerer wands can't
// cast the imbue weapon spell, so level 2 is actually for apprentice wands.
@Override
public int getMaxLevel()
{
return 4;
}
@Override
public boolean isAllowedOnBooks(){
return false;
}
@Override
public boolean canApplyAtEnchantingTable(ItemStack stack) {
return false;
}
}
@@ -0,0 +1,11 @@
package electroblob.wizardry.enchantment;
/** Interface for temporary enchantments that last for a certain duration ('imbuements'). This interface allows
* {@link EnchantmentMagicSword} and {@link EnchantmentTimed} to both be treated as instances of a
* single type, rather than having to deal with each of them separately,
* which would be inefficient and cumbersome (the former of those classes cannot extend the latter because they both
* need to extend different subclasses of {@link net.minecraft.enchantment.Enchantment}).
* @since Wizardry 1.2 */
public interface Imbuement {
}
@@ -0,0 +1,73 @@
package electroblob.wizardry.entity;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
public class EntityArc extends Entity implements IEntityAdditionalSpawnData {
public int textureIndex = 0;
public double x1, y1, z1, x2, y2, z2;
// The number of ticks the arc lasts for before disappearing
public int lifetime = 3;
public double offsetX, offsetZ;
public EntityArc(World par1World) {
super(par1World);
textureIndex = this.rand.nextInt(16);
this.ignoreFrustumCheck = true;
}
public void setEndpointCoords(double x1, double y1, double z1, double x2, double y2, double z2){
this.x1 = x1;
this.y1 = y1;
this.z1 = z1;
this.x2 = x2;
this.y2 = y2;
this.z2 = z2;
this.setPosition(x2, y2, z2);
}
@Override
public void onUpdate(){
if(this.ticksExisted >= lifetime){
this.setDead();
}
}
protected void entityInit()
{
}
@Override
protected void readEntityFromNBT(NBTTagCompound nbttagcompound) {
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {
// Nothing needed here; arc is merely a graphic effect that only exists for a few ticks; as such there is no need to save it.
}
@Override
public boolean isInRangeToRenderDist(double distance) {
return true;
}
@Override
public void writeSpawnData(ByteBuf data) {
data.writeDouble(this.x1);
data.writeDouble(this.y1);
data.writeDouble(this.z1);
}
@Override
public void readSpawnData(ByteBuf data) {
this.x1 = data.readDouble();
this.y1 = data.readDouble();
this.z1 = data.readDouble();
}
}
@@ -0,0 +1,127 @@
package electroblob.wizardry.entity;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class EntityMeteor extends EntityFallingBlock {
/** The entity blast multiplier. Only some projectiles cause a blast, which is why this isn't in EntityMagicProjectile. */
public float blastMultiplier;
public EntityMeteor(World world){
super(world);
// Superconstructor doesn't call this.
this.setSize(0.98F, 0.98F);
}
public EntityMeteor(World world, double x, double y, double z, float blastMultiplier){
super(world, x, y, z, WizardryBlocks.meteor.getDefaultState());
this.motionY = -1.0D;
this.setFire(200);
this.blastMultiplier = blastMultiplier;
}
@Override
public double getYOffset() {
return this.height / 2.0F;
}
@Override
public void onUpdate(){
if(this.ticksExisted % 16 == 1 && worldObj.isRemote){
Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_FIRE, 3.0f, 1.0f, false);
}
// You'd think the best way to do this would be to call super and do all the exploding stuff in fall() instead.
// However, for some reason, fallTile is null on the client side, causing an NPE in super.onUpdate()
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
++this.fallTime;
this.motionY -= 0.1d; //0.03999999910593033D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.9800000190734863D;
this.motionY *= 0.9800000190734863D;
this.motionZ *= 0.9800000190734863D;
if(!this.worldObj.isRemote){
if(this.onGround){
this.motionX *= 0.699999988079071D;
this.motionZ *= 0.699999988079071D;
this.motionY *= -0.5D;
this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, 2.0f*blastMultiplier, true);
for(int i1=-3; i1<4; i1++){
for(int j1=-3; j1<4; j1++){
int y = WizardryUtilities.getNearestFloorLevelB(this.worldObj, new BlockPos(this.posX + i1, this.posY, this.posZ + j1), 7);
//System.out.println(y);
double dist = this.getDistance((int)this.posX + i1, y, (int)this.posZ + j1);
// Randomised with weighting so that the nearer the block the more likely it is to be set on fire.
if(y != -1 && rand.nextInt((int)dist*2 + 1) < 3 && dist < 4){
this.worldObj.setBlockState(new BlockPos(this.posX + i1, y, this.posZ + j1), Blocks.FIRE.getDefaultState());
}
}
}
this.setDead();
}
}
}
@Override
public void fall(float distance, float damageMultiplier){
// Don't need to do anything here, the meteor should have already exploded.
}
@SideOnly(Side.CLIENT)
@Override
public boolean canRenderOnFire(){
return true;
}
@Override
public IBlockState getBlock(){
return WizardryBlocks.meteor.getDefaultState(); // For some reason the superclass version returns null on the client
}
@SideOnly(Side.CLIENT)
@Override
public int getBrightnessForRender(float partialTicks){
return 15728880;
}
@Override
public float getBrightness(float partialTicks){
return 1.0F;
}
@Override
public boolean isInRangeToRenderDist(double distance){
return true;
}
@Override
public void readEntityFromNBT(NBTTagCompound nbttagcompound){
super.readEntityFromNBT(nbttagcompound);
blastMultiplier = nbttagcompound.getFloat("blastMultiplier");
}
@Override
public void writeEntityToNBT(NBTTagCompound nbttagcompound){
super.writeEntityToNBT(nbttagcompound);
nbttagcompound.setFloat("blastMultiplier", blastMultiplier);
}
}
@@ -0,0 +1,94 @@
package electroblob.wizardry.entity;
import java.lang.ref.WeakReference;
import electroblob.wizardry.WizardData;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.registry.WizardrySounds;
import net.minecraft.entity.Entity;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.World;
public class EntityShield extends Entity {
public WeakReference<EntityPlayer> player;
public EntityShield(World world){
super(world);
this.noClip = true;
this.width = 1.2f;
this.height = 1.4f;
}
public EntityShield(World par1World, EntityPlayer player) {
super(par1World);
this.width = 1.2f;
this.height = 1.4f;
this.player = new WeakReference<EntityPlayer>(player);
this.noClip = true;
this.setPositionAndRotation(player.posX + player.getLookVec().xCoord, player.posY + 1 + player.getLookVec().yCoord, player.posZ + player.getLookVec().zCoord, player.rotationYawHead, player.rotationPitch);
this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 0.6f, this.posY - 0.7f, this.posZ - 0.6f, this.posX + 0.6f, this.posY + 0.7f, this.posZ + 0.6f));
}
@Override
public void onUpdate(){
//System.out.println("Shield exists, ID: " + this.getUniqueID().toString());
EntityPlayer entityplayer = player != null ? player.get() : null;
if(entityplayer != null){
this.setPositionAndRotation(entityplayer.posX + entityplayer.getLookVec().xCoord*0.3, entityplayer.posY + 1 + entityplayer.getLookVec().yCoord*0.3, entityplayer.posZ + entityplayer.getLookVec().zCoord*0.3, entityplayer.rotationYawHead, entityplayer.rotationPitch);
if(!entityplayer.isHandActive() || entityplayer.getHeldItem(entityplayer.getActiveHand()) == null || !(entityplayer.getHeldItem(entityplayer.getActiveHand()).getItem() instanceof ItemWand)){
WizardData.get(entityplayer).shield = null;
this.setDead();
}
}else if(!worldObj.isRemote){
this.setDead();
}
}
// Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow
// it to stick in blocks.
public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
{
this.setPosition(par1, par3, par5);
this.setRotation(par7, par8);
}
public boolean attackEntityFrom(DamageSource par1DamageSource, float par2)
{
if(par1DamageSource != null && par1DamageSource.getSourceOfDamage() instanceof IProjectile){
par1DamageSource.getSourceOfDamage().playSound(WizardrySounds.SPELL_DEFLECTION, 0.3f, 1.3f);
}
super.attackEntityFrom(par1DamageSource, par2);
return false;
}
public boolean canBeCollidedWith()
{
return !this.isDead;
}
public AxisAlignedBB getCollisionBox(Entity par1Entity)
{
return par1Entity.getEntityBoundingBox();
}
@Override
protected void entityInit() {
}
@Override
protected void readEntityFromNBT(NBTTagCompound nbttagcompound) {
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.entity.construct;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.projectile.EntityTippedArrow;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public class EntityArrowRain extends EntityMagicConstruct {
public EntityArrowRain(World par1World) {
super(par1World);
this.height = 3.0f;
this.width = 5.0f;
}
public EntityArrowRain(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) {
super(world, x, y, z, caster, lifetime, damageMultiplier);
this.height = 3.0f;
this.width = 5.0f;
}
public void onUpdate(){
super.onUpdate();
if(!this.worldObj.isRemote){
EntityTippedArrow arrow = new EntityTippedArrow(worldObj, this.posX + rand.nextDouble()*6 - 3, this.posY + rand.nextDouble()*4 - 2, this.posZ + rand.nextDouble()*6 - 3);
arrow.motionX = Math.cos(Math.toRadians(this.rotationYaw + 90));
arrow.motionY = -0.6;
arrow.motionZ = Math.sin(Math.toRadians(this.rotationYaw + 90));
arrow.shootingEntity = this.getCaster();
arrow.setDamage(7.0d*damageMultiplier);
arrow.setPotionEffect(new ItemStack(Items.ARROW));
this.worldObj.spawnEntityInWorld(arrow);
}
}
}
@@ -0,0 +1,138 @@
package electroblob.wizardry.entity.construct;
import java.util.List;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.server.SPacketEntityVelocity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class EntityBlackHole extends EntityMagicConstruct {
public int[] randomiser;
public int[] randomiser2;
public EntityBlackHole(World world){
super(world);
this.width = 6.0f;
this.height = 3.0f;
randomiser = new int[30];
for(int i=0; i<randomiser.length; i++){
randomiser[i] = this.rand.nextInt(10);
}
randomiser2 = new int[30];
for(int i=0; i<randomiser2.length; i++){
randomiser2[i] = this.rand.nextInt(10);
}
}
public EntityBlackHole(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) {
super(world, x, y, z, caster, lifetime, damageMultiplier);
this.width = 6.0f;
this.height = 3.0f;
randomiser = new int[30];
for(int i=0; i<randomiser.length; i++){
randomiser[i] = this.rand.nextInt(10);
}
randomiser2 = new int[30];
for(int i=0; i<randomiser2.length; i++){
randomiser2[i] = this.rand.nextInt(10);
}
}
@Override
protected void readEntityFromNBT(NBTTagCompound nbttagcompound) {
super.readEntityFromNBT(nbttagcompound);
randomiser = nbttagcompound.getIntArray("randomiser");
randomiser2 = nbttagcompound.getIntArray("randomiser2");
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {
super.writeEntityToNBT(nbttagcompound);
nbttagcompound.setIntArray("randomiser", randomiser);
nbttagcompound.setIntArray("randomiser2", randomiser2);
}
public void onUpdate(){
super.onUpdate();
//System.out.println("Client side: " + this.worldObj.isRemote + ", Caster: " + this.caster);
// Particle effect. Finishes 40 ticks before the end so the particles disappear at the same time.
if(this.ticksExisted + 40 < this.lifetime){
for (int i=0; i<5; i++){
//this.worldObj.spawnParticle(EnumParticleTypes.PORTAL, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height - 0.75D, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, (this.rand.nextDouble() - 0.5D) * 2.0D, -this.rand.nextDouble(), (this.rand.nextDouble() - 0.5D) * 2.0D);
this.worldObj.spawnParticle(EnumParticleTypes.PORTAL, this.posX, this.posY, this.posZ, (this.rand.nextDouble() - 0.5D) * 4.0D, (this.rand.nextDouble() - 0.5D) * 4.0D - 1, (this.rand.nextDouble() - 0.5D) * 4.0D);
}
}
if(this.lifetime - this.ticksExisted == 75){
this.playSound(SoundEvents.BLOCK_PORTAL_TRIGGER, 1.5f, 1.0f);
}else if(this.ticksExisted % 80 == 1 && this.ticksExisted + 80 < this.lifetime){
this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.5f, 1.0f);
}
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(6.0d, this.posX, this.posY, this.posZ, this.worldObj);
if(!this.worldObj.isRemote){
for(EntityLivingBase target : targets){
if(this.isValidTarget(target)){
// Sucks the target in
if(this.posX > target.posX && target.motionX < 1){
target.motionX+=0.1;
}else if(this.posX < target.posX && target.motionX > -1){
target.motionX-=0.1;
}
if(this.posY > target.posY && target.motionY < 1){
target.motionY+=0.1;
}else if(this.posY < target.posY && target.motionY > -1){
target.motionY-=0.1;
}
if(this.posZ > target.posZ && target.motionZ < 1){
target.motionZ+=0.1;
}else if(this.posZ < target.posZ && target.motionZ > -1){
target.motionZ-=0.1;
}
// Player motion is handled on that player's client so needs packets
if(target instanceof EntityPlayerMP){
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
}
if(this.getDistanceToEntity(target) <= 2){
// Damages the target if it is close enough
if(this.getCaster() != null){
target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), 2*damageMultiplier);
}else{
target.attackEntityFrom(DamageSource.magic, 2*damageMultiplier);
}
}
}
}
}
}
/**
* Checks using a Vec3dd to determine if this entity is within range of that vector to be rendered. Args: Vec3dD
*/
public boolean isInRangeToRenderVec3dD(Vec3d par1Vec3d)
{
return true;
}
}
@@ -0,0 +1,68 @@
package electroblob.wizardry.entity.construct;
import java.util.List;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryParticleType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
public class EntityBlizzard extends EntityMagicConstruct {
public EntityBlizzard(World par1World) {
super(par1World);
this.height = 1.0f;
this.width = 1.0f;
}
public EntityBlizzard(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, float damageMultiplier) {
super(world, x, y, z, caster, lifetime, damageMultiplier);
this.height = 1.0f;
this.width = 1.0f;
}
public void onUpdate(){
if(this.ticksExisted % 120 == 1){
this.playSound(WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f);
}
super.onUpdate();
if(!this.worldObj.isRemote){
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(3.0d, this.posX, this.posY, this.posZ, this.worldObj);
for(EntityLivingBase target : targets){
if(this.isValidTarget(target)){
if(this.getCaster() != null){
WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.FROST), 1*damageMultiplier);
}else{
WizardryUtilities.attackEntityWithoutKnockback(target, DamageSource.magic, 1*damageMultiplier);
}
}
// All entities are slowed, even the caster (except those immune to frost effects)
if(!MagicDamage.isEntityImmune(DamageType.FROST, target))
target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 20, 0));
}
}else{
// For some reason this number of particles now causes the game to lag significantly, despite it being fine
// in 1.7.10. I thought particles were supposed to be LESS laggy now...
for(int i=1; i<6; i++){
float brightness = 0.5f + (rand.nextFloat()/2);
Wizardry.proxy.spawnParticle(WizardryParticleType.BLIZZARD, worldObj, this.posX, this.posY + rand.nextDouble()*3, this.posZ, 0, 0, 0, 100, brightness, brightness + 0.1f, 1.0f, false, rand.nextDouble() * 2.5d + 0.5d);
Wizardry.proxy.spawnParticle(WizardryParticleType.BLIZZARD, worldObj, this.posX, this.posY + rand.nextDouble()*3, this.posZ, 0, 0, 0, 100, 1.0f, 1.0f, 1.0f, false, rand.nextDouble() * 2.5d + 0.5d);
}
}
}
}
@@ -0,0 +1,123 @@
package electroblob.wizardry.entity.construct;
import java.lang.ref.WeakReference;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.world.World;
public class EntityBubble extends EntityMagicConstruct {
public boolean isDarkOrb;
private WeakReference<EntityLivingBase> rider;
public EntityBubble(World world){
super(world);
}
public EntityBubble(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, boolean isDarkOrb, float damageMultiplier) {
super(world, x, y, z, caster, lifetime, damageMultiplier);
//this.setSize(0.1f, 0.1f);
this.isDarkOrb = isDarkOrb;
}
@Override
public double getMountedYOffset()
{
return 0.1;
}
@Override
public boolean shouldRiderSit(){
return false;
}
public void onUpdate(){
super.onUpdate();
// Synchronises the rider field
if((this.rider == null || this.rider.get() == null) && WizardryUtilities.getRider(this) instanceof EntityLivingBase
&& !WizardryUtilities.getRider(this).isDead){
this.rider = new WeakReference<EntityLivingBase>((EntityLivingBase) WizardryUtilities.getRider(this));
}
// Prevents dismounting
if(WizardryUtilities.getRider(this) == null && this.rider != null && this.rider.get() != null && !this.rider.get().isDead){
this.rider.get().startRiding(this);
}
// Stops the bubble bursting instantly.
if(this.ticksExisted < 1 && !isDarkOrb) ((EntityLivingBase)WizardryUtilities.getRider(this)).hurtTime = 0;
this.moveEntity(0, 0.03, 0);
if(isDarkOrb){
if(WizardryUtilities.getRider(this) != null && this.ticksExisted % 30 == 0){
if(this.getCaster() != null){
WizardryUtilities.getRider(this).attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), 1*damageMultiplier);
}else{
WizardryUtilities.getRider(this).attackEntityFrom(DamageSource.magic, 1*damageMultiplier);
}
}
for(int i=0; i<5; i++){
this.worldObj.spawnParticle(EnumParticleTypes.PORTAL, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height + 0.5d, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, (this.rand.nextDouble() - 0.5D) * 2.0D, -this.rand.nextDouble(), (this.rand.nextDouble() - 0.5D) * 2.0D);
}
if(lifetime - this.ticksExisted == 75){
this.playSound(SoundEvents.BLOCK_PORTAL_TRIGGER, 1.5f, 1.0f);
}else if(this.ticksExisted % 100 == 1 && this.ticksExisted < 150){
this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.5f, 1.0f);
}
}
// Bubble bursts if the entity is hurt (see event handler) or killed, or if the bubble has existed for more than 10 seconds.
if(WizardryUtilities.getRider(this) == null && this.ticksExisted > 1){
if(!this.isDarkOrb) this.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f);
this.setDead();
}
}
@Override
public void despawn(){
if(WizardryUtilities.getRider(this) != null){
((EntityLivingBase)WizardryUtilities.getRider(this)).dismountEntity(this);
}
if(!this.isDarkOrb) this.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f);
super.despawn();
}
@Override
protected void readEntityFromNBT(NBTTagCompound nbttagcompound) {
super.readEntityFromNBT(nbttagcompound);
isDarkOrb = nbttagcompound.getBoolean("isDarkOrb");
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {
super.writeEntityToNBT(nbttagcompound);
nbttagcompound.setBoolean("isDarkOrb", isDarkOrb);
}
@Override
public void writeSpawnData(ByteBuf data) {
super.writeSpawnData(data);
data.writeBoolean(this.isDarkOrb);
}
@Override
public void readSpawnData(ByteBuf data) {
super.readSpawnData(data);
this.isDarkOrb = data.readBoolean();
}
}
@@ -0,0 +1,78 @@
package electroblob.wizardry.entity.construct;
import java.util.List;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.util.WizardryParticleType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class EntityDecay extends EntityMagicConstruct {
public int textureIndex = 0;
public static final int LIFETIME = 400;
public EntityDecay(World par1World) {
super(par1World);
textureIndex = this.rand.nextInt(10);
this.height = 0.2f;
this.width = 2.0f;
}
public EntityDecay(World par1World, double x, double y, double z, EntityLivingBase caster) {
super(par1World, x, y, z, caster, LIFETIME, 1);
textureIndex = this.rand.nextInt(10);
this.height = 0.2f;
this.width = 2.0f;
}
@Override
public void onUpdate(){
super.onUpdate();
if(this.rand.nextInt(700) == 0 && this.ticksExisted+100 < LIFETIME) this.playSound(SoundEvents.BLOCK_LAVA_AMBIENT, 0.2F + rand.nextFloat() * 0.2F, 0.6F + rand.nextFloat() * 0.15F);
if(!this.worldObj.isRemote){
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, this.posZ, this.worldObj);
for(EntityLivingBase target : targets){
if(target != this.getCaster()){
// If this check wasn't here the potion would be reapplied every tick and hence the entity would be damaged each tick.
// In this case, we do want particles to be shown.
if(!target.isPotionActive(WizardryPotions.decay)) target.addPotionEffect(new PotionEffect(WizardryPotions.decay, LIFETIME, 0));
}
}
}else if(this.rand.nextInt(15) == 0){
double radius = rand.nextDouble()*0.8;
double angle = rand.nextDouble()*Math.PI*2;
float brightness = rand.nextFloat()*0.4f;
Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, worldObj, this.posX + radius*Math.cos(angle), this.posY, this.posZ + radius*Math.sin(angle), 0, 0, 0, 0, brightness, 0, brightness+0.1f);
}
}
protected void entityInit(){}
@Override
protected void readEntityFromNBT(NBTTagCompound nbttagcompound) {
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {
}
/**
* Checks using a Vec3dd to determine if this entity is within range of that vector to be rendered. Args: Vec3dD
*/
public boolean isInRangeToRenderVec3dD(Vec3d par1Vec3d)
{
return true;
}
}
@@ -0,0 +1,107 @@
package electroblob.wizardry.entity.construct;
import java.util.List;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.MobEffects;
import net.minecraft.network.play.server.SPacketEntityVelocity;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EntityEarthquake extends EntityMagicConstruct {
public EntityEarthquake(World world){
super(world);
this.height = 1.0f;
this.width = 1.0f;
}
public EntityEarthquake(World world, double x, double y, double z, EntityLivingBase caster, int lifetime,
float damageMultiplier) {
super(world, x, y, z, caster, lifetime, damageMultiplier);
this.height = 1.0f;
this.width = 1.0f;
}
public void onUpdate(){
super.onUpdate();
if(!worldObj.isRemote){
double speed = 0.4;
// The further the earthquake is going to spread, the finer the angle increments.
for(double angle=0; angle < 2*Math.PI; angle+=Math.PI/(lifetime*1.5)){
// Calculates coordinates for the block to be moved. The radius increases with time. The +1.5 is to leave
// blocks in the centre untouched.
int x = this.posX < 0 ? (int)(this.posX + ((this.ticksExisted*speed)+1.5)*Math.sin(angle) - 1) : (int)(this.posX + ((this.ticksExisted*speed)+1.5)*Math.sin(angle));
int y = (int)(this.posY - 0.5);
int z = this.posZ < 0 ? (int)(this.posZ + ((this.ticksExisted*speed)+1.5)*Math.cos(angle) - 1) : (int)(this.posZ + ((this.ticksExisted*speed)+1.5)*Math.cos(angle));
BlockPos pos = new BlockPos(x, y, z);
if(!WizardryUtilities.isBlockUnbreakable(worldObj, pos) && !worldObj.isAirBlock(pos) && worldObj.isBlockNormalCube(pos, false)
// Checks that the block above is not solid, since this causes the falling sand to vanish.
&& !worldObj.isBlockNormalCube(pos.up(), false)){
// Falling blocks do the setting block to air themselves.
EntityFallingBlock fallingblock = new EntityFallingBlock(worldObj, x+0.5, y+0.5, z+0.5, worldObj.getBlockState(new BlockPos(x, y, z)));
fallingblock.motionY = 0.3;
worldObj.spawnEntityInWorld(fallingblock);
}
}
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius((this.ticksExisted*speed)+1.5, this.posX, this.posY, this.posZ, worldObj);
// In this particular instance, the caster is completely unaffected because they will always be in the centre.
targets.remove(this.getCaster());
for(EntityLivingBase target : targets){
// Searches in a 1 wide ring.
if(this.getDistanceToEntity(target) > (this.ticksExisted*speed)+0.5 && target.posY < this.posY + 1 && target.posY > this.posY - 1){
// Knockback must be removed in this instance, or the target will fall into the floor.
double motionX = target.motionX;
double motionZ = target.motionZ;
if(this.isValidTarget(target)){
target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.BLAST), 10*this.damageMultiplier);
target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 400, 1));
}
// All targets are thrown, even those immune to the damage, so they don't fall into the ground.
target.motionX = motionX;
target.motionY = 0.8; // Throws target into the air.
target.motionZ = motionZ;
// Player motion is handled on that player's client so needs packets
if(target instanceof EntityPlayerMP){
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
}
}
}
// TODO: Uncomment once 2.1.0 is released
// }else{
//
// // Constant 15 blocks for now
// List<EntityPlayer> targets = WizardryUtilities.getEntitiesWithinRadius(15, this.posX, this.posY, this.posZ, worldObj, EntityPlayer.class);
//
// float magnitude = 6f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime;
//
// // Makes the screen shake
// for(EntityLivingBase target : targets){
// target.setAngles(0, this.ticksExisted % 4 < 2 ? magnitude : -magnitude);
// }
}
}
}

Some files were not shown because too many files have changed in this diff Show More