package mhfc.net.common.ai; import com.github.worldsender.mcanm.common.animation.IAnimation; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import mhfc.net.common.ai.general.WeightedPick.WeightedItem; import mhfc.net.common.ai.manager.AIActionManager; import net.minecraft.entity.EntityLivingBase; /** * A derived class can specify an Entity-class this method is applicable to. The typeparameter T should be as narrow as * necessary but as broad as possible. E.g. to make an entity jump you would set T as {@link EntityLivingBase} because * all those entities can jump. This makes it possible to reuse attacks and (WIP) apply them to special weapons. * * @author WorldSEnder * * @param <T> * the necessary Entity class */ public interface IExecutableAction<T extends EntityLivingBase> extends WeightedItem { public static final float DONT_SELECT = 0f; /** * Tells the attack that it is rebound to the given entity. This might happen when the entity is teleported and a * new entity had to be created or when the attack is assigned to an abnormal entity through special behavior, e.g. * the player when equipping special weapons. * * @param entity */ // @SideOnly(Side.SERVER) public void rebind(T entity); /** * Gets how firmly this attack wants to be executed. The higher the value the more likely the attack will be * executed. Returning {@value #DONT_SELECT} or less means that the attack will not be executed at all. * * @return */ @Override public float getWeight(); /** * Returns if this attack has to be executed (e.g. a stun animation) this gets checked every tick to determine if * the current attack should be stopped. This also gets checked before a new animation is picked.<br> * Contract: The attacks will be checked in the order they were registered. The only exception is the currently * executed attack which will be always asked first (so one can continue to execute). If you return * <code>true</code> here you can be assured that this attack will be executed before any attack registered after * this attack will. * * @return if execution is to be forced (infinite weight) */ @Override public boolean forceSelection(); /** * Gets called at the beginning of execution. This should behave as a setup method to determine the attack target * for example. Should also be used to determine the following stance for stanced AIs. This avoids non-deterministic * behavior for staggering etc. */ // @SideOnly(Side.SERVER) public void beginAction(); /** * Should get called every tick the entity receives to update this attack. */ // @SideOnly(Side.SERVER) public void updateAction(); /** * The return value determines whether this attack should still be executed.<br> * Returning false should determines the attack instantly, call {@link #finishExecution()} on this attack, * {@link #beginExecution()} on the new attack and then proceed to the next tick * * @return a value of <code>false</code> halts execution of this attack */ // @SideOnly(Side.SERVER) public boolean shouldContinue(); /** * Finishes the execution of this attack. This method can also be called when this attack was terminated * unexpectedly, for example if some other attack did interrupt this attack.<br> * The attack is expected to clean-up and undo actions that were applied temporarily to the entity like a different * attack target. */ // @SideOnly(Side.SERVER) public void finishAction(); /** * Returns the mutex bits for the attack. * * @return * @see AIActionManager#getMutexBits() */ public byte mutexBits(); /** * Gets the animation that should be played alongside the executed attack. * * @return */ @SideOnly(Side.CLIENT) public IAnimation getCurrentAnimation(); /** * Gets the current frame, depending on the state of the attack. For example running can loop over the running part * of the animation, and play wind up and wind down only when it is needed. * * @return the current frame to display in the animation */ public int getCurrentFrame(); }