Miscellaneous setup
This commit is contained in:
@@ -1,72 +1,47 @@
|
||||
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.event.DiscoverSpellEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
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.SpellModifiers;
|
||||
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;
|
||||
@@ -74,73 +49,41 @@ 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.common.MinecraftForge;
|
||||
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
|
||||
// Better ways of organising event handling:
|
||||
// - Split it into several separate handlers, each with a logical area to deal with (see Astral Sorcery)
|
||||
// - Remove most of the stuff, and have individual spell, item, block, entity, etc. classes handle their own events
|
||||
// (see Botania)
|
||||
// - Keep all the methods, but delegate near-repeated behaviours to their individual spell/potion/whatever classes
|
||||
// (TGG does this, apparently)
|
||||
// Incidentally, Twilight Forest still has one big event handler class - and a comment about how it's so long...!
|
||||
|
||||
// In the end, I decided the most pragmatic solution was to either use the second option or keep things how they were,
|
||||
// whichever will result in more readable/easily maintainable code in each case. To keep in line with the modularity
|
||||
// of the spell system, the goal is to have nothing in here which relates to a specific spell (mostly done, but a few
|
||||
// things remain).
|
||||
|
||||
/**
|
||||
* Wizardry's main event handler class for common code.
|
||||
* As of Wizardry 2.1, most of the code in this class has been relocated somewhere sensible, leaving only a few
|
||||
* miscellaneous things that don't make much sense anywhere else, or that are better kept together. Previously, this was
|
||||
* a gigantic class with about half of the entire mod's logic in it!
|
||||
* @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",
|
||||
@@ -152,7 +95,7 @@ public final class WizardryEventHandler {
|
||||
"minecraft:chests/stronghold_library",
|
||||
"minecraft:chests/igloo_chest"
|
||||
};
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLootTableLoadEvent(LootTableLoadEvent event){
|
||||
if(Wizardry.settings.generateLoot){
|
||||
@@ -172,6 +115,60 @@ public final class WizardryEventHandler {
|
||||
return new LootEntryTable(new ResourceLocation(name), weight, 0, new LootCondition[0], Wizardry.MODID + "_additive_entry");
|
||||
}
|
||||
|
||||
@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 onSpellCastPreEvent(SpellCastEvent.Pre event){
|
||||
// If a spell is disabled in the config, it will not work.
|
||||
if(!event.getSpell().isEnabled()){
|
||||
if(!event.getEntityLiving().worldObj.isRemote)
|
||||
event.getEntity().addChatMessage(new TextComponentTranslation("spell.disabled", event.getSpell().getNameForTranslationFormatted()));
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onSpellCastPostEvent(SpellCastEvent.Post event){
|
||||
|
||||
// Spell discovery (only players can discover spells, obviously)
|
||||
if(event.getEntity() instanceof EntityPlayer){
|
||||
|
||||
EntityPlayer player = (EntityPlayer)event.getEntity();
|
||||
|
||||
WizardData data = WizardData.get(player);
|
||||
|
||||
if(data != null){
|
||||
// Data is updated on both sides (This line was added client-side to fix a bug back in 1.1.3, so now
|
||||
// it's in common code, which is nice!)
|
||||
// Short-circuiting AND means that discoverSpell is only called if the event isn't cancelled.
|
||||
if(!MinecraftForge.EVENT_BUS.post(new DiscoverSpellEvent(player, event.getSpell(),
|
||||
DiscoverSpellEvent.Source.CASTING)) && data.discoverSpell(event.getSpell())){
|
||||
|
||||
// If the spell wasn't already discovered, other stuff happens:
|
||||
if(event.getSource() == SpellCastEvent.Source.COMMAND){
|
||||
// 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(!event.getSpell().doesSpellRequirePacket()) data.sync();
|
||||
|
||||
}else if(!event.getEntity().worldObj.isRemote && !player.capabilities.isCreativeMode
|
||||
&& Wizardry.settings.discoveryMode){
|
||||
// Sound and text only happen server-side, in survival, with discovery mode on, and only when
|
||||
// the spell wasn't cast using commands.
|
||||
WizardryUtilities.playSoundAtPlayer(player, SoundEvents.ENTITY_PLAYER_LEVELUP, 1.25f, 1);
|
||||
player.addChatMessage(new TextComponentTranslation("spell.discover", event.getSpell().getNameForTranslationFormatted()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -197,115 +194,39 @@ public final class WizardryEventHandler {
|
||||
@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.
|
||||
// This needs 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
|
||||
// Retaliatory effects
|
||||
// These are better off here because the revenge effects are pretty similar, and I'd rather keep the (lengthy)
|
||||
// if statement in one place.
|
||||
if(event.getSource() != null && event.getSource().getEntity() instanceof EntityLivingBase
|
||||
&& !event.getSource().isProjectile() && !(event.getSource() instanceof IElementalDamage &&
|
||||
((IElementalDamage)event.getSource()).isRetaliatory())){
|
||||
|
||||
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);
|
||||
}
|
||||
// Fireskin
|
||||
if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin)
|
||||
&& !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));
|
||||
}
|
||||
// Ice Shroud
|
||||
if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud) &&
|
||||
!MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()))
|
||||
attacker.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0));
|
||||
|
||||
// Static Aura
|
||||
if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){
|
||||
|
||||
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,
|
||||
@@ -317,44 +238,17 @@ public final class WizardryEventHandler {
|
||||
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){
|
||||
|
||||
@@ -395,212 +289,132 @@ public final class WizardryEventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
EntityPlayer player = (EntityPlayer)event.getEntityLiving();
|
||||
|
||||
if(WizardData.get(entityplayer) != null){
|
||||
WizardData.get(entityplayer).update();
|
||||
if(player.worldObj.isRemote) hackilyFixContinuousSpellCasting(player);
|
||||
|
||||
if(player.openContainer instanceof ContainerWorkbench){
|
||||
craftingTableTick(player);
|
||||
}
|
||||
|
||||
if(entityplayer.openContainer instanceof ContainerWorkbench){
|
||||
craftingTableTick(entityplayer);
|
||||
}
|
||||
|
||||
if(entityplayer.openContainer instanceof ContainerPlayer){
|
||||
if(player.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);
|
||||
playerInventoryTick(player);
|
||||
}
|
||||
|
||||
testForArmourSet:{
|
||||
for(ItemStack stack : entityplayer.getArmorInventoryList()){
|
||||
for(ItemStack stack : player.getArmorInventoryList()){
|
||||
if(stack == null || !(stack.getItem() instanceof ItemWizardArmour)){
|
||||
break testForArmourSet;
|
||||
}
|
||||
}
|
||||
entityplayer.addStat(WizardryAchievements.armour_set);
|
||||
player.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();
|
||||
SpellModifiers modifiers = ((ISpellCaster)event.getEntity()).getModifiers();
|
||||
|
||||
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(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(event.getEntityLiving(), spell, modifiers,
|
||||
SpellCastEvent.Source.NPC, 0))){
|
||||
|
||||
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(), modifiers);
|
||||
}
|
||||
}
|
||||
// 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)));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void playerInventoryTick(EntityPlayer player) {
|
||||
@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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onItemPickupEvent(EntityItemPickupEvent event){
|
||||
if(event.getItem().getEntityItem().getItem() == WizardryItems.magic_crystal){
|
||||
event.getEntityPlayer().addStat(WizardryAchievements.crystal, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Private helper methods
|
||||
// ================================================================================================================
|
||||
|
||||
/**
|
||||
* Detects inconsistencies between player.getActiveItemStack and the actual itemstack and forces them to be equal.
|
||||
* Fixes issue #25.
|
||||
* @param player
|
||||
*/
|
||||
private static void hackilyFixContinuousSpellCasting(EntityPlayer player){
|
||||
if(player.isHandActive() && player.getHeldItem(player.getActiveHand()) != null
|
||||
&& player.getHeldItem(player.getActiveHand()).getItem() instanceof ItemWand
|
||||
&& WandHelper.getCurrentSpell(player.getHeldItem(player.getActiveHand())).isContinuous){
|
||||
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())){
|
||||
player.setHeldItem(player.getActiveHand(), player.getActiveItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -650,8 +464,7 @@ public final class WizardryEventHandler {
|
||||
|
||||
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.
|
||||
// Charges wand using mana flask
|
||||
|
||||
boolean flag = false;
|
||||
ItemStack wand = null;
|
||||
@@ -696,243 +509,4 @@ public final class WizardryEventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@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