Rewrote spell levelling

This commit is contained in:
Sollace 2019-02-06 10:31:31 +02:00
parent c3eb588f3c
commit 545bd3a34b
14 changed files with 133 additions and 104 deletions

View file

@ -169,7 +169,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
protected void displayTick() { protected void displayTick() {
if (hasEffect()) { if (hasEffect()) {
getEffect().render(this, getCurrentLevel()); getEffect().render(this);
} }
} }
@ -186,7 +186,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
setDead(); setDead();
onDeath(); onDeath();
} else { } else {
getEffect().update(this, getCurrentLevel()); getEffect().update(this);
} }
if (getEffect().allowAI()) { if (getEffect().allowAI()) {
@ -194,18 +194,28 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
} }
} }
if (getCurrentLevel() > 0 && !world.isRemote && world.rand.nextInt(200) == 0) {
addLevels(-1);
if (getCurrentLevel() <= 0) {
setDead();
}
}
if (overLevelCap()) { if (overLevelCap()) {
if (world.rand.nextInt(10) == 0) { if (world.rand.nextInt(10) == 0) {
spawnExplosionParticle(); spawnExplosionParticle();
} }
if (!world.isRemote && hasEffect()) {
float exhaustionChance = getEffect().getExhaustion(this);
if (exhaustionChance == 0 || world.rand.nextInt((int)(exhaustionChance / 500)) == 0) {
addLevels(-1);
} else if (world.rand.nextInt((int)(exhaustionChance * 500)) == 0) {
setEffect(null);
} else if (world.rand.nextInt((int)(exhaustionChance * 3500)) == 0) {
world.createExplosion(this, posX, posY, posZ, getCurrentLevel()/2, true);
setDead();
}
}
} }
if (getCurrentLevel() < 0) {
setDead();
}
} }
@Override @Override
@ -213,6 +223,10 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
} }
public boolean overLevelCap() {
return getCurrentLevel() > getMaxLevel();
}
@Override @Override
protected void updateFallState(double y, boolean onGround, IBlockState state, BlockPos pos) { protected void updateFallState(double y, boolean onGround, IBlockState state, BlockPos pos) {
this.onGround = true; this.onGround = true;
@ -286,14 +300,6 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
addLevels(1); addLevels(1);
if (!world.isRemote) {
if (overLevelCap() || (rand.nextFloat() * getCurrentLevel()) > 10) {
world.createExplosion(this, posX, posY, posZ, getCurrentLevel()/2, true);
setDead();
return false;
}
}
playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1); playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1);
return true; return true;
@ -304,7 +310,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
@Override @Override
public int getMaxLevel() { public int getMaxLevel() {
return hasEffect() ? getEffect().getMaxLevel() : 0; return hasEffect() ? getEffect().getMaxLevelCutOff(this) : 0;
} }
@Override @Override
@ -314,20 +320,11 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
@Override @Override
public void setCurrentLevel(int level) { public void setCurrentLevel(int level) {
level = Math.max(level, 0); level = Math.max(level, 1);
if (hasEffect()) {
getEffect().setCurrentLevel(level);
level = getEffect().getCurrentLevel();
}
dataManager.set(LEVEL, level); dataManager.set(LEVEL, level);
} }
public boolean overLevelCap() {
int max = getMaxLevel();
return max > 0 && getCurrentLevel() >= (max * 1.1);
}
@Override @Override
public Entity getEntity() { public Entity getEntity() {
return this; return this;

View file

@ -7,18 +7,6 @@ public abstract class AbstractSpell implements IMagicEffect {
protected boolean isDead; protected boolean isDead;
protected boolean isDirty; protected boolean isDirty;
private int strength = 0;
@Override
public int getCurrentLevel() {
return strength;
}
@Override
public void setCurrentLevel(int level) {
strength = level;
}
@Override @Override
public boolean isCraftable() { public boolean isCraftable() {
return true; return true;
@ -44,16 +32,58 @@ public abstract class AbstractSpell implements IMagicEffect {
isDirty = dirty; isDirty = dirty;
} }
@Override
public int getMaxLevelCutOff(ICaster<?> source) {
return 1;
}
public float getMaxExhaustion(ICaster<?> caster) {
return 1;
}
public float getExhaustion(ICaster<?> caster) {
return 0;
}
@Override @Override
public void writeToNBT(NBTTagCompound compound) { public void writeToNBT(NBTTagCompound compound) {
compound.setBoolean("dead", isDead); compound.setBoolean("dead", isDead);
compound.setInteger("spell_strength", strength);
} }
@Override @Override
public void readFromNBT(NBTTagCompound compound) { public void readFromNBT(NBTTagCompound compound) {
setDirty(false); setDirty(false);
isDead = compound.getBoolean("dead"); isDead = compound.getBoolean("dead");
strength = compound.getInteger("spell_strength"); }
public static abstract class RangedAreaSpell extends AbstractSpell {
@Override
public int getMaxLevelCutOff(ICaster<?> source) {
return 17;
}
@Override
public float getMaxExhaustion(ICaster<?> caster) {
return 1000;
}
@Override
public float getExhaustion(ICaster<?> caster) {
float max = getMaxLevelCutOff(caster);
float current = caster.getCurrentLevel();
if (current > max) {
float maxEc = getMaxExhaustion(caster);
current -= max;
current /= max;
current /= maxEc;
return maxEc - current;
}
return super.getExhaustion(caster);
}
} }
} }

View file

@ -5,7 +5,7 @@ import com.minelittlepony.unicopia.util.serialisation.InbtSerialisable;
/** /**
* Interface for a magic spells * Interface for a magic spells
*/ */
public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned { public interface IMagicEffect extends InbtSerialisable, IAligned {
/** /**
* Gets the name used to identify this effect. * Gets the name used to identify this effect.
@ -42,6 +42,20 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
*/ */
boolean isCraftable(); boolean isCraftable();
/**
* Gets the highest level this spell can be safely operated at.
* Gems may go higher, however chance of explosion/exhaustion increases with every level.
*/
int getMaxLevelCutOff(ICaster<?> caster);
float getMaxExhaustion(ICaster<?> caster);
/**
* Gets the chances of this effect turning into an innert gem or exploding.
*/
float getExhaustion(ICaster<?> caster);
/** /**
* Called when first attached to a gem. * Called when first attached to a gem.
*/ */
@ -56,7 +70,7 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
* @return true to keep alive * @return true to keep alive
*/ */
default boolean updateOnPerson(ICaster<?> caster) { default boolean updateOnPerson(ICaster<?> caster) {
return update(caster, getCurrentLevel()); return update(caster);
} }
/** /**
@ -64,9 +78,8 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
* Called on both sides. * Called on both sides.
* *
* @param source The entity we are currently attached to. * @param source The entity we are currently attached to.
* @param level Current active spell level
*/ */
boolean update(ICaster<?> source, int level); boolean update(ICaster<?> source);
/** /**
* Called every tick when attached to a player. Used to apply particle effects. * Called every tick when attached to a player. Used to apply particle effects.
@ -75,7 +88,7 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
* @param source The entity we are currently attached to. * @param source The entity we are currently attached to.
*/ */
default void renderOnPerson(ICaster<?> source) { default void renderOnPerson(ICaster<?> source) {
render(source, getCurrentLevel()); render(source);
} }
/** /**
@ -83,9 +96,8 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
* Is only called on the client side. * Is only called on the client side.
* *
* @param source The entity we are attached to. * @param source The entity we are attached to.
* @param level Current spell level
*/ */
void render(ICaster<?> source, int level); void render(ICaster<?> source);
/** /**
* Return true to allow the gem update and move. * Return true to allow the gem update and move.

View file

@ -30,13 +30,13 @@ public class SpellAwkward extends AbstractSpell {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
return true; return true;
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
source.spawnParticles(new Sphere(false, (1 + level) * 8), 10, pos -> { source.spawnParticles(new Sphere(false, (1 + source.getCurrentLevel()) * 8), 10, pos -> {
int index = (int)MathHelper.nextDouble(source.getWorld().rand, 0, max); int index = (int)MathHelper.nextDouble(source.getWorld().rand, 0, max);
EnumParticleTypes type = EnumParticleTypes.getByName(names.get(index)); EnumParticleTypes type = EnumParticleTypes.getByName(names.get(index));

View file

@ -41,8 +41,8 @@ public class SpellCharge extends AbstractSpell {
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
if (source.getWorld().rand.nextInt(4 + level * 4) == 0) { if (source.getWorld().rand.nextInt(4 + source.getCurrentLevel() * 4) == 0) {
EntitySpell target = getTarget(source); EntitySpell target = getTarget(source);
if (target != null) { if (target != null) {
@ -83,7 +83,7 @@ public class SpellCharge extends AbstractSpell {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
if (searching) { if (searching) {
BlockPos origin = source.getOrigin(); BlockPos origin = source.getOrigin();
@ -99,7 +99,7 @@ public class SpellCharge extends AbstractSpell {
} else { } else {
EntitySpell target = getTarget(source); EntitySpell target = getTarget(source);
if (target != null && !target.overLevelCap() && level > 0) { if (target != null && !target.overLevelCap() && source.getCurrentLevel() > 0) {
source.addLevels(-1); source.addLevels(-1);
target.addLevels(1); target.addLevels(1);
} }
@ -108,11 +108,6 @@ public class SpellCharge extends AbstractSpell {
return !getDead(); return !getDead();
} }
@Override
public int getMaxLevel() {
return 2;
}
@Override @Override
public void writeToNBT(NBTTagCompound compound) { public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound); super.writeToNBT(compound);

View file

@ -70,7 +70,7 @@ public class SpellDisguise extends AbstractSpell {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
if (entity == null && entityNbt != null) { if (entity == null && entityNbt != null) {
entity = EntityList.createEntityFromNBT(entityNbt, source.getWorld()); entity = EntityList.createEntityFromNBT(entityNbt, source.getWorld());
@ -202,7 +202,7 @@ public class SpellDisguise extends AbstractSpell {
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
} }

View file

@ -53,7 +53,7 @@ public class SpellDrake extends AbstractSpell {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
if (firstUpdate) { if (firstUpdate) {
firstUpdate = false; firstUpdate = false;
@ -85,16 +85,16 @@ public class SpellDrake extends AbstractSpell {
} }
if (piggyBackSpell != null) { if (piggyBackSpell != null) {
piggyBackSpell.update(source, level); piggyBackSpell.update(source);
} }
return true; return true;
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
if (piggyBackSpell != null) { if (piggyBackSpell != null) {
piggyBackSpell.render(source, level); piggyBackSpell.render(source);
} }
} }

View file

@ -38,7 +38,7 @@ import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.world.World; import net.minecraft.world.World;
public class SpellFire extends AbstractSpell implements IUseAction, IDispenceable { public class SpellFire extends AbstractSpell.RangedAreaSpell implements IUseAction, IDispenceable {
public final StateMapList affected = new StateMapList(); public final StateMapList affected = new StateMapList();
@ -84,13 +84,13 @@ public class SpellFire extends AbstractSpell implements IUseAction, IDispenceabl
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
return false; return false;
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
source.spawnParticles(visual_effect_region, level * 6, pos -> { source.spawnParticles(visual_effect_region, source.getCurrentLevel() * 6, pos -> {
source.getWorld().spawnParticle(EnumParticleTypes.SMOKE_LARGE, pos.x, pos.y, pos.z, 0, 0, 0); source.getWorld().spawnParticle(EnumParticleTypes.SMOKE_LARGE, pos.x, pos.y, pos.z, 0, 0, 0);
}); });
} }

View file

@ -28,7 +28,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.EnumParticleTypes;
import net.minecraft.world.World; import net.minecraft.world.World;
public class SpellIce extends AbstractSpell implements IUseAction, IDispenceable { public class SpellIce extends AbstractSpell.RangedAreaSpell implements IUseAction, IDispenceable {
public final StateMapList affected = new StateMapList(); public final StateMapList affected = new StateMapList();
@ -72,12 +72,12 @@ public class SpellIce extends AbstractSpell implements IUseAction, IDispenceable
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
return false; return false;
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
} }
@Override @Override

View file

@ -67,11 +67,11 @@ public class SpellInferno extends SpellFire {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
World w = source.getWorld(); World w = source.getWorld();
if (!w.isRemote) { if (!w.isRemote) {
int radius = 4 + (level * 4); int radius = 4 + (source.getCurrentLevel() * 4);
IShape shape = new Sphere(false, radius); IShape shape = new Sphere(false, radius);
Vec3d origin = source.getOriginVector(); Vec3d origin = source.getOriginVector();

View file

@ -20,7 +20,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.EnumDifficulty; import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World; import net.minecraft.world.World;
public class SpellNecromancy extends AbstractSpell { public class SpellNecromancy extends AbstractSpell.RangedAreaSpell {
private final List<IMonsterSpawn<?>> spawns = Lists.newArrayList( private final List<IMonsterSpawn<?>> spawns = Lists.newArrayList(
EntityZombie::new, EntityZombie::new,
@ -44,7 +44,7 @@ public class SpellNecromancy extends AbstractSpell {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
if (source.getWorld().isRemote || source.getWorld().getDifficulty() == EnumDifficulty.PEACEFUL) { if (source.getWorld().isRemote || source.getWorld().getDifficulty() == EnumDifficulty.PEACEFUL) {
return true; return true;
@ -53,9 +53,9 @@ public class SpellNecromancy extends AbstractSpell {
float additional = source.getWorld().getDifficultyForLocation(source.getOrigin()).getAdditionalDifficulty(); float additional = source.getWorld().getDifficultyForLocation(source.getOrigin()).getAdditionalDifficulty();
level++; int radius = source.getCurrentLevel() + 1;
IShape affectRegion = new Sphere(false, level * 4); IShape affectRegion = new Sphere(false, radius * 4);
if (source.getWorld().rand.nextInt(100) != 0) { if (source.getWorld().rand.nextInt(100) != 0) {
return true; return true;
@ -63,7 +63,7 @@ public class SpellNecromancy extends AbstractSpell {
Vec3d origin = source.getOriginVector(); Vec3d origin = source.getOriginVector();
if (VecHelper.findAllEntitiesInRange(source.getEntity(), source.getWorld(), source.getOrigin(), level * 4) if (VecHelper.findAllEntitiesInRange(source.getEntity(), source.getWorld(), source.getOrigin(), radius * 4)
.filter(e -> e instanceof EntityZombie) .filter(e -> e instanceof EntityZombie)
.count() >= 10 * (1 + additional)) { .count() >= 10 * (1 + additional)) {
return true; return true;
@ -102,8 +102,8 @@ public class SpellNecromancy extends AbstractSpell {
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
IShape affectRegion = new Sphere(false, (1 + level) * 4); IShape affectRegion = new Sphere(false, (1 + source.getCurrentLevel()) * 4);
source.spawnParticles(affectRegion, 5, pos -> { source.spawnParticles(affectRegion, 5, pos -> {
if (!source.getWorld().isAirBlock(new BlockPos(pos).down())) { if (!source.getWorld().isAirBlock(new BlockPos(pos).down())) {

View file

@ -29,7 +29,7 @@ import net.minecraft.util.SoundCategory;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
public class SpellPortal extends AbstractSpell implements IUseAction { public class SpellPortal extends AbstractSpell.RangedAreaSpell implements IUseAction {
private static final IShape portalZone_X = new Sphere(true, 1, 0, 2, 1); private static final IShape portalZone_X = new Sphere(true, 1, 0, 2, 1);
private static final IShape portalZone_Y = new Sphere(true, 1, 2, 0, 2); private static final IShape portalZone_Y = new Sphere(true, 1, 2, 0, 2);
@ -142,7 +142,7 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
if (!source.getWorld().isRemote) { if (!source.getWorld().isRemote) {
getDestinationPortal().ifPresent(dest -> getDestinationPortal().ifPresent(dest ->
source.getWorld().getEntitiesWithinAABB(Entity.class, getTeleportBounds().offset(source.getOrigin())).stream() source.getWorld().getEntitiesWithinAABB(Entity.class, getTeleportBounds().offset(source.getOrigin())).stream()
@ -159,7 +159,7 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
source.spawnParticles(getPortalZone(), 10, pos -> { source.spawnParticles(getPortalZone(), 10, pos -> {
Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, pos, 0, 0, 0); Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, pos, 0, 0, 0);
}); });

View file

@ -18,7 +18,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents; import net.minecraft.init.SoundEvents;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class SpellShield extends AbstractSpell { public class SpellShield extends AbstractSpell.RangedAreaSpell {
private Optional<IAttachableParticle> particleEffect = Optional.empty(); private Optional<IAttachableParticle> particleEffect = Optional.empty();
@ -38,13 +38,8 @@ public class SpellShield extends AbstractSpell {
} }
@Override @Override
public int getMaxLevel() { public void render(ICaster<?> source) {
return 17; int radius = 4 + (source.getCurrentLevel() * 2);
}
@Override
public void render(ICaster<?> source, int level) {
int radius = 4 + (level * 2);
source.spawnParticles(new Sphere(true, radius), radius * 6, pos -> { source.spawnParticles(new Sphere(true, radius), radius * 6, pos -> {
Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, pos, 0, 0, 0); Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, pos, 0, 0, 0);
@ -63,7 +58,7 @@ public class SpellShield extends AbstractSpell {
public boolean updateOnPerson(ICaster<?> source) { public boolean updateOnPerson(ICaster<?> source) {
if (super.updateOnPerson(source)) { if (super.updateOnPerson(source)) {
if (source.getEntity().getEntityWorld().getWorldTime() % 50 == 0) { if (source.getEntity().getEntityWorld().getWorldTime() % 50 == 0) {
double radius = 4 + (getCurrentLevel() * 2); double radius = 4 + (source.getCurrentLevel() * 2);
if (!IPower.takeFromPlayer((EntityPlayer)source.getOwner(), radius/4)) { if (!IPower.takeFromPlayer((EntityPlayer)source.getOwner(), radius/4)) {
setDead(); setDead();
} }
@ -73,13 +68,13 @@ public class SpellShield extends AbstractSpell {
return !getDead(); return !getDead();
} }
protected double getDrawDropOffRange(int level) { protected double getDrawDropOffRange(ICaster<?> source) {
return 4 + (level * 2); return 4 + (source.getCurrentLevel() * 2);
} }
@Override @Override
public boolean update(ICaster<?> source, int level) { public boolean update(ICaster<?> source) {
double radius = getDrawDropOffRange(level); double radius = getDrawDropOffRange(source);
Entity owner = source.getOwner(); Entity owner = source.getOwner();

View file

@ -23,18 +23,18 @@ public class SpellVortex extends SpellShield {
} }
@Override @Override
public void render(ICaster<?> source, int level) { public void render(ICaster<?> source) {
level = 4 + (level * 2); int range = 4 + (source.getCurrentLevel() * 2);
Vec3d pos = source.getOriginVector(); Vec3d pos = source.getOriginVector();
source.spawnParticles(new Sphere(false, level), level * 9, p -> { source.spawnParticles(new Sphere(false, range), range * 9, p -> {
Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, p, p.subtract(pos)); Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, p, p.subtract(pos));
}); });
} }
@Override @Override
protected double getDrawDropOffRange(int level) { protected double getDrawDropOffRange(ICaster<?> caster) {
return 10 + (level * 2); return 10 + (caster.getCurrentLevel() * 2);
} }
@Override @Override