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() {
if (hasEffect()) {
getEffect().render(this, getCurrentLevel());
getEffect().render(this);
}
}
@ -186,7 +186,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
setDead();
onDeath();
} else {
getEffect().update(this, getCurrentLevel());
getEffect().update(this);
}
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 (world.rand.nextInt(10) == 0) {
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
@ -213,6 +223,10 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
}
public boolean overLevelCap() {
return getCurrentLevel() > getMaxLevel();
}
@Override
protected void updateFallState(double y, boolean onGround, IBlockState state, BlockPos pos) {
this.onGround = true;
@ -286,14 +300,6 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
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);
return true;
@ -304,7 +310,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
@Override
public int getMaxLevel() {
return hasEffect() ? getEffect().getMaxLevel() : 0;
return hasEffect() ? getEffect().getMaxLevelCutOff(this) : 0;
}
@Override
@ -314,20 +320,11 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
@Override
public void setCurrentLevel(int level) {
level = Math.max(level, 0);
if (hasEffect()) {
getEffect().setCurrentLevel(level);
level = getEffect().getCurrentLevel();
}
level = Math.max(level, 1);
dataManager.set(LEVEL, level);
}
public boolean overLevelCap() {
int max = getMaxLevel();
return max > 0 && getCurrentLevel() >= (max * 1.1);
}
@Override
public Entity getEntity() {
return this;

View file

@ -7,18 +7,6 @@ public abstract class AbstractSpell implements IMagicEffect {
protected boolean isDead;
protected boolean isDirty;
private int strength = 0;
@Override
public int getCurrentLevel() {
return strength;
}
@Override
public void setCurrentLevel(int level) {
strength = level;
}
@Override
public boolean isCraftable() {
return true;
@ -44,16 +32,58 @@ public abstract class AbstractSpell implements IMagicEffect {
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
public void writeToNBT(NBTTagCompound compound) {
compound.setBoolean("dead", isDead);
compound.setInteger("spell_strength", strength);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
setDirty(false);
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
*/
public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
public interface IMagicEffect extends InbtSerialisable, IAligned {
/**
* Gets the name used to identify this effect.
@ -42,6 +42,20 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
*/
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.
*/
@ -56,7 +70,7 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
* @return true to keep alive
*/
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.
*
* @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.
@ -75,7 +88,7 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
* @param source The entity we are currently attached to.
*/
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.
*
* @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.

View file

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

View file

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

View file

@ -70,7 +70,7 @@ public class SpellDisguise extends AbstractSpell {
}
@Override
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
if (entity == null && entityNbt != null) {
entity = EntityList.createEntityFromNBT(entityNbt, source.getWorld());
@ -202,7 +202,7 @@ public class SpellDisguise extends AbstractSpell {
}
@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
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
if (firstUpdate) {
firstUpdate = false;
@ -85,16 +85,16 @@ public class SpellDrake extends AbstractSpell {
}
if (piggyBackSpell != null) {
piggyBackSpell.update(source, level);
piggyBackSpell.update(source);
}
return true;
}
@Override
public void render(ICaster<?> source, int level) {
public void render(ICaster<?> source) {
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.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();
@ -84,13 +84,13 @@ public class SpellFire extends AbstractSpell implements IUseAction, IDispenceabl
}
@Override
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
return false;
}
@Override
public void render(ICaster<?> source, int level) {
source.spawnParticles(visual_effect_region, level * 6, pos -> {
public void render(ICaster<?> source) {
source.spawnParticles(visual_effect_region, source.getCurrentLevel() * 6, pos -> {
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.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();
@ -72,12 +72,12 @@ public class SpellIce extends AbstractSpell implements IUseAction, IDispenceable
}
@Override
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
return false;
}
@Override
public void render(ICaster<?> source, int level) {
public void render(ICaster<?> source) {
}
@Override

View file

@ -67,11 +67,11 @@ public class SpellInferno extends SpellFire {
}
@Override
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
World w = source.getWorld();
if (!w.isRemote) {
int radius = 4 + (level * 4);
int radius = 4 + (source.getCurrentLevel() * 4);
IShape shape = new Sphere(false, radius);
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.World;
public class SpellNecromancy extends AbstractSpell {
public class SpellNecromancy extends AbstractSpell.RangedAreaSpell {
private final List<IMonsterSpawn<?>> spawns = Lists.newArrayList(
EntityZombie::new,
@ -44,7 +44,7 @@ public class SpellNecromancy extends AbstractSpell {
}
@Override
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
if (source.getWorld().isRemote || source.getWorld().getDifficulty() == EnumDifficulty.PEACEFUL) {
return true;
@ -53,9 +53,9 @@ public class SpellNecromancy extends AbstractSpell {
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) {
return true;
@ -63,7 +63,7 @@ public class SpellNecromancy extends AbstractSpell {
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)
.count() >= 10 * (1 + additional)) {
return true;
@ -102,8 +102,8 @@ public class SpellNecromancy extends AbstractSpell {
}
@Override
public void render(ICaster<?> source, int level) {
IShape affectRegion = new Sphere(false, (1 + level) * 4);
public void render(ICaster<?> source) {
IShape affectRegion = new Sphere(false, (1 + source.getCurrentLevel()) * 4);
source.spawnParticles(affectRegion, 5, pos -> {
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.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_Y = new Sphere(true, 1, 2, 0, 2);
@ -142,7 +142,7 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
}
@Override
public boolean update(ICaster<?> source, int level) {
public boolean update(ICaster<?> source) {
if (!source.getWorld().isRemote) {
getDestinationPortal().ifPresent(dest ->
source.getWorld().getEntitiesWithinAABB(Entity.class, getTeleportBounds().offset(source.getOrigin())).stream()
@ -159,7 +159,7 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
}
@Override
public void render(ICaster<?> source, int level) {
public void render(ICaster<?> source) {
source.spawnParticles(getPortalZone(), 10, pos -> {
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.util.math.Vec3d;
public class SpellShield extends AbstractSpell {
public class SpellShield extends AbstractSpell.RangedAreaSpell {
private Optional<IAttachableParticle> particleEffect = Optional.empty();
@ -38,13 +38,8 @@ public class SpellShield extends AbstractSpell {
}
@Override
public int getMaxLevel() {
return 17;
}
@Override
public void render(ICaster<?> source, int level) {
int radius = 4 + (level * 2);
public void render(ICaster<?> source) {
int radius = 4 + (source.getCurrentLevel() * 2);
source.spawnParticles(new Sphere(true, radius), radius * 6, pos -> {
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) {
if (super.updateOnPerson(source)) {
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)) {
setDead();
}
@ -73,13 +68,13 @@ public class SpellShield extends AbstractSpell {
return !getDead();
}
protected double getDrawDropOffRange(int level) {
return 4 + (level * 2);
protected double getDrawDropOffRange(ICaster<?> source) {
return 4 + (source.getCurrentLevel() * 2);
}
@Override
public boolean update(ICaster<?> source, int level) {
double radius = getDrawDropOffRange(level);
public boolean update(ICaster<?> source) {
double radius = getDrawDropOffRange(source);
Entity owner = source.getOwner();

View file

@ -23,18 +23,18 @@ public class SpellVortex extends SpellShield {
}
@Override
public void render(ICaster<?> source, int level) {
level = 4 + (level * 2);
public void render(ICaster<?> source) {
int range = 4 + (source.getCurrentLevel() * 2);
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));
});
}
@Override
protected double getDrawDropOffRange(int level) {
return 10 + (level * 2);
protected double getDrawDropOffRange(ICaster<?> caster) {
return 10 + (caster.getCurrentLevel() * 2);
}
@Override