|
|
|
@@ -22,14 +22,14 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
|
|
|
|
* Entity AI class for use by instances of {@link ISpellCaster}. This deals with pathing, the spell casting itself and
|
|
|
|
|
* the attack cooldown. Also provides an automatic implementation of continuous spell casting using the methods
|
|
|
|
|
* specified in {@code ISpellCaster}; all the entity class needs to do is implement those methods.
|
|
|
|
|
* @param <T> The type of entity that this AI belongs to; must both extend EntityLiving <i>and</i> implement ISpellCaster
|
|
|
|
|
*/
|
|
|
|
|
public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
// Mmmm generics...
|
|
|
|
|
public class EntityAIAttackSpell<T extends EntityLiving & ISpellCaster> extends EntityAIBase {
|
|
|
|
|
|
|
|
|
|
/** The entity the AI instance has been applied to. */
|
|
|
|
|
private final EntityLiving attacker;
|
|
|
|
|
/** The entity the AI instance has been applied to, but as an ISpellCaster. */
|
|
|
|
|
private final ISpellCaster caster;
|
|
|
|
|
/** The tagret to be attacked. */
|
|
|
|
|
/** The entity the AI instance has been applied to. Thanks to type parameters, methods from both EntityLiving and
|
|
|
|
|
* ISummonedCreature may be invoked on this field. */
|
|
|
|
|
private final T attacker;
|
|
|
|
|
private EntityLivingBase target;
|
|
|
|
|
/**
|
|
|
|
|
* Decremented each tick while greater than 0. When a spell is cast, this is set to that spell's cooldown plus the
|
|
|
|
@@ -65,23 +65,14 @@ public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
* attacking, and also the amount that is added to the cooldown of the spell that has just been cast.
|
|
|
|
|
* @param continuousSpellDuration The number of ticks that continuous spells will be cast for before cooling down.
|
|
|
|
|
*/
|
|
|
|
|
public EntityAIAttackSpell(ISpellCaster attacker, double speed, float maxDistance, int baseCooldown,
|
|
|
|
|
int continuousSpellDuration){
|
|
|
|
|
|
|
|
|
|
public EntityAIAttackSpell(T attacker, double speed, float maxDistance, int baseCooldown, int continuousSpellDuration){
|
|
|
|
|
this.cooldown = -1;
|
|
|
|
|
|
|
|
|
|
if(!(attacker instanceof EntityLiving)){
|
|
|
|
|
throw new IllegalArgumentException(
|
|
|
|
|
"Tried to create an EntityAICastSpell for an entity that isn't an EntityLiving");
|
|
|
|
|
}else{
|
|
|
|
|
this.caster = attacker;
|
|
|
|
|
this.attacker = (EntityLiving)attacker;
|
|
|
|
|
this.baseCooldown = baseCooldown;
|
|
|
|
|
this.continuousSpellDuration = continuousSpellDuration;
|
|
|
|
|
this.speed = speed;
|
|
|
|
|
this.maxAttackDistance = maxDistance * maxDistance;
|
|
|
|
|
this.setMutexBits(3);
|
|
|
|
|
}
|
|
|
|
|
this.attacker = attacker;
|
|
|
|
|
this.baseCooldown = baseCooldown;
|
|
|
|
|
this.continuousSpellDuration = continuousSpellDuration;
|
|
|
|
|
this.speed = speed;
|
|
|
|
|
this.maxAttackDistance = maxDistance * maxDistance;
|
|
|
|
|
this.setMutexBits(3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@@ -112,7 +103,7 @@ public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setContinuousSpellAndNotify(Spell spell, SpellModifiers modifiers){
|
|
|
|
|
caster.setContinuousSpell(spell);
|
|
|
|
|
attacker.setContinuousSpell(spell);
|
|
|
|
|
WizardryPacketHandler.net.sendToAllAround(
|
|
|
|
|
new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(),
|
|
|
|
|
EnumHand.MAIN_HAND, spell.id(), modifiers),
|
|
|
|
@@ -151,11 +142,11 @@ public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible
|
|
|
|
|
// ...or the spell is cancelled via events...
|
|
|
|
|
|| MinecraftForge.EVENT_BUS
|
|
|
|
|
.post(new SpellCastEvent.Tick(attacker, caster.getContinuousSpell(), caster.getModifiers(),
|
|
|
|
|
.post(new SpellCastEvent.Tick(attacker, attacker.getContinuousSpell(), attacker.getModifiers(),
|
|
|
|
|
Source.NPC, this.continuousSpellDuration - this.continuousSpellTimer))
|
|
|
|
|
// ...or the spell no longer succeeds...
|
|
|
|
|
|| !caster.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND,
|
|
|
|
|
this.continuousSpellDuration - this.continuousSpellTimer, target, caster.getModifiers())
|
|
|
|
|
|| !attacker.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND,
|
|
|
|
|
this.continuousSpellDuration - this.continuousSpellTimer, target, attacker.getModifiers())
|
|
|
|
|
// ...or the time has elapsed...
|
|
|
|
|
|| this.continuousSpellTimer == 0){
|
|
|
|
|
|
|
|
|
@@ -167,8 +158,8 @@ public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
|
|
|
|
|
}else if(this.continuousSpellDuration - this.continuousSpellTimer == 1){
|
|
|
|
|
// On the first tick, if the spell did succeed, fire SpellCastEvent.Post.
|
|
|
|
|
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, caster.getContinuousSpell(),
|
|
|
|
|
caster.getModifiers(), Source.NPC));
|
|
|
|
|
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, attacker.getContinuousSpell(),
|
|
|
|
|
attacker.getModifiers(), Source.NPC));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}else if(--this.cooldown == 0){
|
|
|
|
@@ -180,7 +171,7 @@ public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
double dx = target.posX - attacker.posX;
|
|
|
|
|
double dz = target.posZ - attacker.posZ;
|
|
|
|
|
|
|
|
|
|
List<Spell> spells = new ArrayList<Spell>(caster.getSpells());
|
|
|
|
|
List<Spell> spells = new ArrayList<Spell>(attacker.getSpells());
|
|
|
|
|
|
|
|
|
|
if(spells.size() > 0){
|
|
|
|
|
|
|
|
|
@@ -194,7 +185,7 @@ public class EntityAIAttackSpell extends EntityAIBase {
|
|
|
|
|
|
|
|
|
|
spell = spells.get(attacker.world.rand.nextInt(spells.size()));
|
|
|
|
|
|
|
|
|
|
SpellModifiers modifiers = caster.getModifiers();
|
|
|
|
|
SpellModifiers modifiers = attacker.getModifiers();
|
|
|
|
|
|
|
|
|
|
if(spell != null && attemptCastSpell(spell, modifiers)){
|
|
|
|
|
// The spell worked, so we're done!
|
|
|
|
|