diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 97faaa79..57e5400e 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -12,9 +12,11 @@ import net.minecraft.item.crafting.IRecipe; import net.minecraft.potion.Potion; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.event.entity.ProjectileImpactEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent; import net.minecraftforge.event.entity.player.PlayerDropsEvent; @@ -222,6 +224,17 @@ public class Unicopia implements IGuiHandler { } } + @SubscribeEvent + public static void onProjectileHit(ProjectileImpactEvent event) { + RayTraceResult ray = event.getRayTraceResult(); + + if (ray.typeOfHit == RayTraceResult.Type.ENTITY && ray.entityHit instanceof EntityPlayer) { + if (!PlayerSpeciesList.instance().getPlayer((EntityPlayer)ray.entityHit).onProjectileImpact(event.getEntity())) { + event.setCanceled(true); + } + } + } + @SubscribeEvent public static void onPlayerTossItem(ItemTossEvent event) { Race race = PlayerSpeciesList.instance().getPlayer(event.getPlayer()).getPlayerSpecies(); diff --git a/src/main/java/com/minelittlepony/unicopia/player/IPlayer.java b/src/main/java/com/minelittlepony/unicopia/player/IPlayer.java index bb4eda48..cd869422 100644 --- a/src/main/java/com/minelittlepony/unicopia/player/IPlayer.java +++ b/src/main/java/com/minelittlepony/unicopia/player/IPlayer.java @@ -18,52 +18,122 @@ import net.minecraft.item.ItemStack; import net.minecraft.server.MinecraftServer; import net.minecraftforge.fml.common.FMLCommonHandler; +/** + * The player. + * + * This is the core of unicopia. + */ public interface IPlayer extends ICaster, IRaceContainer, ITransmittable, IPageOwner { + /** + * Gets the player's magical abilities delegate responsible for all spell casting and persisting/updating. + */ IAbilityReceiver getAbilities(); + /** + * Gets the gravity delegate responsible for updating flight states + */ IGravity getGravity(); + /** + * Gets the player's viewport. + */ IView getCamera(); + /** + * Gets the food delegate to handle player eating. + */ IFood getFood(); + /** + * Gets an animation interpolator. + */ IInterpolator getInterpolator(); + /** + * Gets the amount of exertion this player has put toward any given activity. + * This is simillar to tiredness. + */ float getExertion(); + /** + * Sets the player's exertion level. + */ void setExertion(float exertion); + /** + * Adds player tiredness. + */ default void addExertion(int exertion) { setExertion(getExertion() + exertion/100F); } + /** + * Gets the amount of excess energy the player has. + * This is increased by eating sugar. + */ float getEnergy(); + /** + * Sets the player's energy level. + */ void setEnergy(float energy); + /** + * Adds energy to the player's existing energy level. + */ default void addEnergy(int energy) { setEnergy(getEnergy() + energy / 100F); } - default boolean isClientPlayer() { - return UClient.instance().isClientPlayer(getOwner()); - } + /** + * Returns true if this player is fully invisible. + * Held items and other effects will be hidden as well. + */ + boolean isInvisible(); + + /** + * Sets whether this player should be invisible. + */ + void setInvisible(boolean invisible); void copyFrom(IPlayer oldPlayer); - void onEat(ItemStack stack, @Nullable ItemFood food); - + /** + * Called when the player steps on clouds. + */ boolean stepOnCloud(); - boolean isInvisible(); - - void setInvisible(boolean invisible); + /** + * Called when this player finishes eating food. + */ + void onEat(ItemStack stack, @Nullable ItemFood food); + /** + * Called when this player falls. + */ void onFall(float distance, float damageMultiplier); + /** + * Event triggered when this player is hit by a projectile. + * @param projectile The projectile doing the hitting. + * + * @return True if the hit was successful. + */ + boolean onProjectileImpact(Entity projectile); + + /** + * Called at the beginning of a player's update cycle. + */ void beforeUpdate(EntityPlayer entity); + /** + * Returns true if this player is the use. + */ + default boolean isClientPlayer() { + return UClient.instance().isClientPlayer(getOwner()); + } + static EntityPlayer getPlayerFromServer(UUID playerId) { MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); diff --git a/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java index 0792b16e..b551f908 100644 --- a/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java @@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.network.EffectSync; import com.minelittlepony.unicopia.network.MsgPlayerCapabilities; import com.minelittlepony.unicopia.spell.IMagicEffect; import com.minelittlepony.unicopia.spell.SpellAffinity; +import com.minelittlepony.unicopia.spell.SpellDisguise; import com.minelittlepony.unicopia.spell.SpellRegistry; import net.minecraft.entity.Entity; @@ -233,6 +234,23 @@ class PlayerCapabilities implements IPlayer { } } + @Override + public boolean onProjectileImpact(Entity projectile) { + + if (hasEffect()) { + IMagicEffect effect = getEffect(); + if (effect instanceof SpellDisguise && !effect.getDead()) { + Entity disguise = ((SpellDisguise)effect).getDisguise(); + + if (disguise == projectile) { + return false; + } + } + } + + return true; + } + @Override public boolean stepOnCloud() { EntityPlayer player = getOwner();