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