package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.item.SpellActions; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities.Operations; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.World; import javax.annotation.Nullable; import java.util.function.Function; /** * Generic superclass for all spells which summon minions (i.e. instances of {@link ISummonedCreature}). * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple * instantiation of this class is sufficient to create a minion spell; if something extra needs to be done, such as * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. * It is encouraged, however, to put extra functionality in the summoned creature class instead whenever possible. *

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

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

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

* By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 */ public class SpellMinion extends Spell { public static final String MINION_LIFETIME = "minion_lifetime"; public static final String MINION_COUNT = "minion_count"; public static final String SUMMON_RADIUS = "summon_radius"; /** The string identifier for the minion health spell modifier, which doubles as the identifier for the * entity attribute modifier. */ public static final String HEALTH_MODIFIER = "minion_health"; /** The string identifier for the potency attribute modifier. */ private static final String POTENCY_ATTRIBUTE_MODIFIER = "potency"; /** A factory that creates summoned creature entities. */ protected final Function minionFactory; /** Whether the minions are spawned in mid-air. Defaults to false. */ protected boolean flying = false; public SpellMinion(String name, Function minionFactory){ this(Wizardry.MODID, name, minionFactory); } public SpellMinion(String modID, String name, Function minionFactory){ super(modID, name, SpellActions.SUMMON, false); this.minionFactory = minionFactory; addProperties(MINION_LIFETIME, MINION_COUNT, SUMMON_RADIUS); this.npcSelector((e, o) -> true); } /** * Sets whether the minions are spawned in mid-air. * @param flying True to spawn the minions in mid-air, false to spawn them on the ground. * @return The spell instance, allowing this method to be chained onto the constructor. */ public SpellMinion flying(boolean flying){ this.flying = flying; return this; } @Override public boolean requiresPacket(){ return false; } @Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(!this.spawnMinions(world, caster, modifiers)) return false; this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @Override public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ if(!this.spawnMinions(world, caster, modifiers)) return false; this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @Override public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ BlockPos pos = new BlockPos(x, y, z); // In this case it looks nice to have them all explode out from one position! (It also makes the code simpler...) if(!world.isRemote){ for(int i=0; i