Fix up spells slightly

This commit is contained in:
Sollace 2018-09-24 21:37:16 +02:00
parent c9e912a378
commit 38e7b8bc36
11 changed files with 200 additions and 169 deletions

View file

@ -12,12 +12,12 @@ public final class Predicates {
return player != null && PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies().canInteractWithClouds();
};
public static final Predicate<EntityPlayer> MAGI = player -> {
return player != null && PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies().canCast();
public static final Predicate<Entity> MAGI = entity -> {
return entity instanceof EntityPlayer && PlayerSpeciesList.instance().getPlayer((EntityPlayer)entity).getPlayerSpecies().canCast();
};
public static final Predicate<Entity> ITEMS = entity -> {
return entity.isEntityAlive() && entity instanceof EntityItem;
return entity instanceof EntityItem && entity.isEntityAlive();
};
public static final Predicate<EntityItem> ITEM_INTERACT_WITH_CLOUDS = item -> {

View file

@ -1,10 +1,13 @@
package com.minelittlepony.unicopia.entity;
import org.apache.commons.lang3.StringUtils;
import com.minelittlepony.unicopia.Predicates;
import com.minelittlepony.unicopia.UItems;
import com.minelittlepony.unicopia.item.ItemSpell;
import com.minelittlepony.unicopia.item.ICastable;
import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.spell.ICaster;
import com.minelittlepony.unicopia.spell.ILevelled;
import com.minelittlepony.unicopia.spell.IMagicEffect;
import com.minelittlepony.unicopia.spell.SpellRegistry;
@ -28,7 +31,7 @@ import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class EntitySpell extends EntityLiving implements IMagicals, ICaster<EntityLivingBase> {
public class EntitySpell extends EntityLiving implements IMagicals, ICaster<EntityLivingBase>, ILevelled {
private EntityLivingBase owner = null;
@ -102,7 +105,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
}
protected void setOwner(String ownerName) {
if (ownerName != null && ownerName.length() != 0) {
if (!StringUtils.isEmpty(ownerName)) {
dataManager.set(OWNER, ownerName);
}
}
@ -110,7 +113,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
protected String getOwnerName() {
String ownerName = dataManager.get(OWNER);
if (ownerName == null || ownerName.length() == 0) {
if (!StringUtils.isEmpty(ownerName)) {
if (owner instanceof EntityPlayer) {
return owner.getName();
}
@ -135,7 +138,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
protected void displayTick() {
if (hasEffect()) {
getEffect().renderAt(this, world, posX, posY, posZ, getLevel());
getEffect().render(this, getCurrentLevel());
}
}
@ -152,7 +155,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
setDead();
onDeath();
} else {
getEffect().updateAt(this, world, posX, posY, posZ, getLevel());
getEffect().update(this, getCurrentLevel());
}
if (getEffect().allowAI()) {
@ -186,7 +189,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
world.playSound(posX, posY, posZ, sound.getBreakSound(), SoundCategory.NEUTRAL, sound.getVolume(), sound.getPitch(), true);
if (world.getGameRules().getBoolean("doTileDrops")) {
int level = getLevel();
int level = getCurrentLevel();
ItemStack stack = new ItemStack(UItems.spell, level + 1);
if (hasEffect()) {
@ -204,44 +207,14 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
super.setDead();
}
public int getLevel() {
return dataManager.get(LEVEL);
}
public void setLevel(int radius) {
dataManager.set(LEVEL, radius);
}
public boolean tryLevelUp(ItemStack stack) {
if (SpellRegistry.stackHasEnchantment(stack)) {
if (!getEffect().getName().equals(SpellRegistry.getKeyFromStack(stack))) {
return false;
}
increaseLevel();
if (!world.isRemote) {
if ((rand.nextFloat() * getLevel()) > 10 || overLevelCap()) {
world.createExplosion(this, posX, posY, posZ, getLevel()/2, true);
setDead();
return false;
}
}
playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1);
return true;
}
return false;
}
public EnumActionResult applyPlayerInteraction(EntityPlayer player, Vec3d vec, EnumHand hand) {
if (Predicates.MAGI.test(player)) {
ItemStack currentItem = player.getHeldItem(EnumHand.MAIN_HAND);
if (currentItem != null && currentItem.getItem() instanceof ItemSpell) {
tryLevelUp(currentItem);
if (currentItem != null
&& currentItem.getItem() instanceof ICastable
&& ((ICastable)currentItem.getItem()).canFeed(this, currentItem)
&& tryLevelUp(currentItem)) {
if (!player.capabilities.isCreativeMode) {
currentItem.shrink(1);
@ -258,24 +231,48 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
return EnumActionResult.FAIL;
}
public void increaseLevel() {
setLevel(getLevel() + 1);
public boolean tryLevelUp(ItemStack stack) {
if (SpellRegistry.stackHasEnchantment(stack)) {
if (!getEffect().getName().equals(SpellRegistry.getKeyFromStack(stack))) {
return false;
}
public boolean canLevelUp() {
int max = getEffect().getMaxLevel();
return max < 0 || getLevel() < max;
addLevels(1);
if (!world.isRemote) {
if ((rand.nextFloat() * getCurrentLevel()) > 10 || overLevelCap()) {
world.createExplosion(this, posX, posY, posZ, getCurrentLevel()/2, true);
setDead();
return false;
}
}
playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1);
return true;
}
return false;
}
@Override
public int getMaxLevel() {
return getEffect().getMaxLevel();
}
@Override
public int getCurrentLevel() {
return dataManager.get(LEVEL);
}
@Override
public void setCurrentLevel(int level) {
dataManager.set(LEVEL, Math.min(level, 0));
}
public boolean overLevelCap() {
int max = getEffect().getMaxLevel();
return max > 0 && getLevel() >= (max * 1.1);
}
public void decreaseLevel() {
int level = getLevel() - 1;
if (level < 0) level = 0;
setLevel(level);
int max = getMaxLevel();
return max > 0 && getCurrentLevel() >= (max * 1.1);
}
@Override
@ -287,7 +284,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
public void readEntityFromNBT(NBTTagCompound compound) {
super.readEntityFromNBT(compound);
setOwner(compound.getString("ownerName"));
setLevel(compound.getInteger("level"));
setCurrentLevel(compound.getInteger("level"));
if (compound.hasKey("effect")) {
setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect")));
@ -299,7 +296,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
super.writeEntityToNBT(compound);
compound.setString("ownerName", getOwnerName());
compound.setInteger("level", getLevel());
compound.setInteger("level", getCurrentLevel());
if (hasEffect()) {
compound.setTag("effect", SpellRegistry.instance().serializeEffectToNBT(getEffect()));

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.item;
import com.minelittlepony.unicopia.entity.EntitySpell;
import com.minelittlepony.unicopia.spell.IDispenceable;
import com.minelittlepony.unicopia.spell.IMagicEffect;
import com.minelittlepony.unicopia.spell.SpellCastResult;
@ -16,4 +17,7 @@ public interface ICastable extends IMagicalItem {
SpellCastResult onDispenseSpell(IBlockSource source, ItemStack stack, IDispenceable effect);
SpellCastResult onCastSpell(EntityPlayer player, World world, BlockPos pos, ItemStack stack, IMagicEffect effect, EnumFacing side, float hitX, float hitY, float hitZ);
boolean canFeed(EntitySpell spell, ItemStack stack);
}

View file

@ -180,4 +180,12 @@ public class ItemSpell extends Item implements ICastable {
return spell;
}
@Override
public boolean canFeed(EntitySpell entity, ItemStack stack) {
IMagicEffect effect = entity.getEffect();
return effect != null && effect.getName().equals(SpellRegistry.getKeyFromStack(stack));
}
}

View file

@ -80,8 +80,8 @@ public class ModelGem extends ModelBase {
GlStateManager.translate(0, floatOffset, 0);
floatOffset = (spell.ticksExisted + stutter) / 20;
if (spell.getLevel() > 0) {
floatOffset *= spell.getLevel() + 1;
if (spell.getCurrentLevel() > 0) {
floatOffset *= spell.getCurrentLevel() + 1;
}
floatOffset += spell.hoverStart;

View file

@ -139,10 +139,10 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
setEffect(null);
} else {
if (entity.getEntityWorld().isRemote) { // && entity.getEntityWorld().getWorldTime() % 10 == 0
getEffect().render(entity);
getEffect().render(this);
}
if (!getEffect().update(entity)) {
if (!getEffect().update(this)) {
setEffect(null);
}
}

View file

@ -1,8 +1,5 @@
package com.minelittlepony.unicopia.spell;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
public abstract class AbstractSpell implements IMagicEffect {
protected boolean isDead = false;
@ -16,14 +13,4 @@ public abstract class AbstractSpell implements IMagicEffect {
public boolean getDead() {
return isDead;
}
@Override
public boolean update(Entity source) {
return false;
}
@Override
public boolean updateAt(ICaster<?> source, World w, double x, double y, double z, int level) {
return false;
}
}

View file

@ -4,6 +4,8 @@ import com.minelittlepony.unicopia.player.IOwned;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public interface ICaster<E extends EntityLivingBase> extends IOwned<E> {
void setEffect(IMagicEffect effect);
@ -20,4 +22,12 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E> {
default Entity getEntity() {
return getOwner();
}
default World getWorld() {
return getEntity().getEntityWorld();
}
default BlockPos getOrigin() {
return getEntity().getPosition();
}
}

View file

@ -0,0 +1,26 @@
package com.minelittlepony.unicopia.spell;
public interface ILevelled {
/**
* Maximum level this spell can reach or -1 for unlimited.
* <br>
* If a gem goes past this level it is more likely to explode.
*/
default int getMaxLevel() {
return 0;
}
default boolean canLevelUp() {
int max = getMaxLevel();
return max < 0 || getCurrentLevel() < max;
}
int getCurrentLevel();
void setCurrentLevel(int level);
default void addLevels(int levels) {
setCurrentLevel(getCurrentLevel() + levels);
}
}

View file

@ -2,24 +2,10 @@ package com.minelittlepony.unicopia.spell;
import com.minelittlepony.unicopia.InbtSerialisable;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
/**
*
* Interface for a magic spell
*
* Interface for a magic spells
*/
public interface IMagicEffect extends InbtSerialisable {
/**
* Maximum level this spell can reach or -1 for unlimited.
* <br>
* If a gem goes past this level it is more likely to explode.
*/
default int getMaxLevel() {
return 0;
}
public interface IMagicEffect extends InbtSerialisable, ILevelled {
String getName();
@ -39,7 +25,15 @@ public interface IMagicEffect extends InbtSerialisable {
* @param source The entity we are currently attached to.
* @return true to keep alive
*/
boolean update(Entity source);
boolean update(ICaster<?> caster);
/**
* Called every tick when attached to a gem.
*
* @param source The entity we are currently attached to.
* @param level Current active spell level
*/
boolean update(ICaster<?> source, int level);
/**
* Called every tick when attached to a player. Used to apply particle effects.
@ -47,34 +41,18 @@ public interface IMagicEffect extends InbtSerialisable {
*
* @param source The entity we are currently attached to.
*/
default void render(Entity source) {
default void render(ICaster<?> source) {
}
/**
* Called every tick when attached to a gem.
*
* @param source The entity we are attached to.
* @param w The world
* @param x Entity position x
* @param y Entity position y
* @param z Entity position z
* @param level Current spell level
*/
boolean updateAt(ICaster<?> source, World w, double x, double y, double z, int level);
/**
* Called every tick when attached to an entity to produce particle effects.
* Is only called on the client side.
*
* @param source The entity we are attached to.
* @param w The world
* @param x Entity position x
* @param y Entity position y
* @param z Entity position z
* @param level Current spell level
*/
default void renderAt(ICaster<?> source, World w, double x, double y, double z, int level) {
default void render(ICaster<?> source, int level) {
}

View file

@ -1,5 +1,8 @@
package com.minelittlepony.unicopia.spell;
import java.util.Random;
import com.minelittlepony.unicopia.Predicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.particle.Particles;
@ -15,8 +18,8 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class SpellShield extends AbstractSpell {
@ -26,10 +29,16 @@ public class SpellShield extends AbstractSpell {
}
public SpellShield(int type) {
setStrength(type);
setCurrentLevel(type);
}
public void setStrength(int level) {
@Override
public int getCurrentLevel() {
return strength;
}
@Override
public void setCurrentLevel(int level) {
strength = level;
}
@ -44,21 +53,28 @@ public class SpellShield extends AbstractSpell {
}
@Override
public void render(Entity source) {
spawnParticles(source.getEntityWorld(), source.posX, source.posY, source.posZ, 4 + (strength * 2));
public void render(ICaster<?> source) {
spawnParticles(source, 4 + (strength * 2));
}
public void renderAt(ICaster<?> source, World w, double x, double y, double z, int level) {
if (w.rand.nextInt(4 + level * 4) == 0) {
spawnParticles(w, x, y, z, 4 + (level * 2));
@Override
public void render(ICaster<?> source, int level) {
if (source.getWorld().rand.nextInt(4 + level * 4) == 0) {
spawnParticles(source, 4 + (level * 2));
}
}
protected void spawnParticles(World w, double x, double y, double z, int strength) {
protected void spawnParticles(ICaster<?> source, int strength) {
IShape sphere = new Sphere(true, strength);
Random rand = source.getWorld().rand;
int x = source.getOrigin().getX();
int y = source.getOrigin().getY();
int z = source.getOrigin().getZ();
for (int i = 0; i < strength * 6; i++) {
Vec3d pos = sphere.computePoint(w.rand);
Vec3d pos = sphere.computePoint(rand);
Particles.instance().spawnParticle(Unicopia.MAGIC_PARTICLE, false,
pos.x + x, pos.y + y, pos.z + z,
0, 0, 0);
@ -66,12 +82,12 @@ public class SpellShield extends AbstractSpell {
}
@Override
public boolean update(Entity source) {
applyEntities(null, source, source.getEntityWorld(), source.posX, source.posY, source.posZ, strength);
public boolean update(ICaster<?> source) {
update(source, strength);
if (source.getEntityWorld().getWorldTime() % 50 == 0) {
if (source.getEntity().getEntityWorld().getWorldTime() % 50 == 0) {
double radius = 4 + (strength * 2);
if (!IPower.takeFromPlayer((EntityPlayer)source, radius/4)) {
if (!IPower.takeFromPlayer((EntityPlayer)source.getOwner(), radius/4)) {
setDead();
}
}
@ -80,37 +96,41 @@ public class SpellShield extends AbstractSpell {
}
@Override
public boolean updateAt(ICaster<?> source, World w, double x, double y, double z, int level) {
return applyEntities(source, source.getOwner(), w, x, y, z, level);
}
private boolean applyEntities(ICaster<?> source, Entity owner, World w, double x, double y, double z, int level) {
public boolean update(ICaster<?> source, int level) {
double radius = 4 + (level * 2);
AxisAlignedBB bb = new AxisAlignedBB(x - radius, y - radius, z - radius, x + radius, y + radius, z + radius);
Entity owner = source.getOwner();
BlockPos pos = source.getOrigin();
for (Entity i : w.getEntitiesWithinAABBExcludingEntity(source == null ? null : source.getEntity(), bb)) {
if ((!i.equals(owner)
|| (owner instanceof EntityPlayer
&& !PlayerSpeciesList.instance().getPlayer((EntityPlayer)owner).getPlayerSpecies().canCast()))) {
int x = pos.getX(), y = pos.getY(), z = pos.getZ();
BlockPos begin = pos.add(-radius, -radius, -radius);
BlockPos end = pos.add(radius, radius, radius);
AxisAlignedBB bb = new AxisAlignedBB(begin, end);
boolean ownerIsValid = Predicates.MAGI.test(owner);
for (Entity i : source.getWorld().getEntitiesInAABBexcluding(source.getEntity(), bb, entity -> !(ownerIsValid && entity.equals(owner)))) {
double dist = i.getDistance(x, y, z);
double dist2 = i.getDistance(x, y - i.getEyeHeight(), z);
boolean projectile = ProjectileUtil.isProjectile(i);
if (dist > radius && dist2 > radius) {
continue;
}
if (dist <= radius || dist2 <= radius) {
if (projectile) {
if (ProjectileUtil.isProjectile(i)) {
if (!ProjectileUtil.isProjectileThrownBy(i, owner)) {
if (dist < radius/2) {
i.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1);
i.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1F, 1);
i.setDead();
} else {
ricochet(i, x, y, z);
ricochet(i, pos);
}
}
} else if (i instanceof EntityLivingBase) {
double force = dist;
double force = Math.min(0.25F, dist);
if (i instanceof EntityPlayer) {
force = calculateForce((EntityPlayer)i);
}
@ -121,8 +141,7 @@ public class SpellShield extends AbstractSpell {
-(z - i.posZ) / force);
}
}
}
}
return true;
}
@ -142,11 +161,11 @@ public class SpellShield extends AbstractSpell {
return force;
}
private void ricochet(Entity projectile, double x, double y, double z) {
private void ricochet(Entity projectile, BlockPos pos) {
Vec3d position = new Vec3d(projectile.posX, projectile.posY, projectile.posZ);
Vec3d motion = new Vec3d(projectile.motionX, projectile.motionY, projectile.motionZ);
Vec3d normal = position.subtract(x, y, z).normalize();
Vec3d normal = position.subtract(pos.getX(), pos.getY(), pos.getZ()).normalize();
Vec3d approach = motion.subtract(normal);
if (approach.length() >= motion.length()) {
@ -154,10 +173,12 @@ public class SpellShield extends AbstractSpell {
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setInteger("spell_strength", strength);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
strength = compound.getInteger("spell_strength");
}