Initial commit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user