Genericise spell casting AI class

This commit is contained in:
Electroblob
2018-06-09 17:36:54 +01:00
parent 719c6d5fbb
commit b6400c72a7
6 changed files with 26 additions and 35 deletions
@@ -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 * 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 * 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. * 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. */ /** The entity the AI instance has been applied to. Thanks to type parameters, methods from both EntityLiving and
private final EntityLiving attacker; * ISummonedCreature may be invoked on this field. */
/** The entity the AI instance has been applied to, but as an ISpellCaster. */ private final T attacker;
private final ISpellCaster caster;
/** The tagret to be attacked. */
private EntityLivingBase target; 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 * 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. * 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. * @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, public EntityAIAttackSpell(T attacker, double speed, float maxDistance, int baseCooldown, int continuousSpellDuration){
int continuousSpellDuration){
this.cooldown = -1; this.cooldown = -1;
this.attacker = attacker;
if(!(attacker instanceof EntityLiving)){ this.baseCooldown = baseCooldown;
throw new IllegalArgumentException( this.continuousSpellDuration = continuousSpellDuration;
"Tried to create an EntityAICastSpell for an entity that isn't an EntityLiving"); this.speed = speed;
}else{ this.maxAttackDistance = maxDistance * maxDistance;
this.caster = attacker; this.setMutexBits(3);
this.attacker = (EntityLiving)attacker;
this.baseCooldown = baseCooldown;
this.continuousSpellDuration = continuousSpellDuration;
this.speed = speed;
this.maxAttackDistance = maxDistance * maxDistance;
this.setMutexBits(3);
}
} }
@Override @Override
@@ -112,7 +103,7 @@ public class EntityAIAttackSpell extends EntityAIBase {
} }
private void setContinuousSpellAndNotify(Spell spell, SpellModifiers modifiers){ private void setContinuousSpellAndNotify(Spell spell, SpellModifiers modifiers){
caster.setContinuousSpell(spell); attacker.setContinuousSpell(spell);
WizardryPacketHandler.net.sendToAllAround( WizardryPacketHandler.net.sendToAllAround(
new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(), new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(),
EnumHand.MAIN_HAND, spell.id(), modifiers), EnumHand.MAIN_HAND, spell.id(), modifiers),
@@ -151,11 +142,11 @@ public class EntityAIAttackSpell extends EntityAIBase {
if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible
// ...or the spell is cancelled via events... // ...or the spell is cancelled via events...
|| MinecraftForge.EVENT_BUS || 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)) Source.NPC, this.continuousSpellDuration - this.continuousSpellTimer))
// ...or the spell no longer succeeds... // ...or the spell no longer succeeds...
|| !caster.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND, || !attacker.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND,
this.continuousSpellDuration - this.continuousSpellTimer, target, caster.getModifiers()) this.continuousSpellDuration - this.continuousSpellTimer, target, attacker.getModifiers())
// ...or the time has elapsed... // ...or the time has elapsed...
|| this.continuousSpellTimer == 0){ || this.continuousSpellTimer == 0){
@@ -167,8 +158,8 @@ public class EntityAIAttackSpell extends EntityAIBase {
}else if(this.continuousSpellDuration - this.continuousSpellTimer == 1){ }else if(this.continuousSpellDuration - this.continuousSpellTimer == 1){
// On the first tick, if the spell did succeed, fire SpellCastEvent.Post. // On the first tick, if the spell did succeed, fire SpellCastEvent.Post.
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, caster.getContinuousSpell(), MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, attacker.getContinuousSpell(),
caster.getModifiers(), Source.NPC)); attacker.getModifiers(), Source.NPC));
} }
}else if(--this.cooldown == 0){ }else if(--this.cooldown == 0){
@@ -180,7 +171,7 @@ public class EntityAIAttackSpell extends EntityAIBase {
double dx = target.posX - attacker.posX; double dx = target.posX - attacker.posX;
double dz = target.posZ - attacker.posZ; 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){ if(spells.size() > 0){
@@ -194,7 +185,7 @@ public class EntityAIAttackSpell extends EntityAIBase {
spell = spells.get(attacker.world.rand.nextInt(spells.size())); spell = spells.get(attacker.world.rand.nextInt(spells.size()));
SpellModifiers modifiers = caster.getModifiers(); SpellModifiers modifiers = attacker.getModifiers();
if(spell != null && attemptCastSpell(spell, modifiers)){ if(spell != null && attemptCastSpell(spell, modifiers)){
// The spell worked, so we're done! // The spell worked, so we're done!
@@ -55,7 +55,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData { public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<EntityEvilWizard>(this, 0.5D, 14.0F, 30, 50);
public int textureIndex = 0; public int textureIndex = 0;
@@ -27,7 +27,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
private double AISpeed = 0.5; private double AISpeed = 0.5;
// Can attack for 7 seconds, then must cool down for 3. // Can attack for 7 seconds, then must cool down for 3.
private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 60, 140); private EntityAIAttackSpell<EntityPhoenix> spellAttackAI = new EntityAIAttackSpell<EntityPhoenix>(this, AISpeed, 15f, 60, 140);
private Spell continuousSpell; private Spell continuousSpell;
@@ -31,7 +31,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
private double AISpeed = 1.0; private double AISpeed = 1.0;
private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); private EntityAIAttackSpell<EntityShadowWraith> spellAttackAI = new EntityAIAttackSpell<EntityShadowWraith>(this, AISpeed, 15f, 30, 0);
private static final List<Spell> attack = Collections.singletonList(Spells.darkness_orb); private static final List<Spell> attack = Collections.singletonList(Spells.darkness_orb);
@@ -29,7 +29,7 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe
private double AISpeed = 1.0; private double AISpeed = 1.0;
private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); private EntityAIAttackSpell<EntityStormElemental> spellAttackAI = new EntityAIAttackSpell<EntityStormElemental>(this, AISpeed, 15f, 30, 0);
private static final List<Spell> attack = Collections.singletonList(Spells.lightning_disc); private static final List<Spell> attack = Collections.singletonList(Spells.lightning_disc);
@@ -84,7 +84,7 @@ import net.minecraftforge.oredict.OreDictionary;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISpellCaster, IEntityAdditionalSpawnData { public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISpellCaster, IEntityAdditionalSpawnData {
private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); private EntityAIAttackSpell<EntityWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
public int textureIndex = 0; public int textureIndex = 0;