Add disintegrate animation, plus misc tweaks to disintegration

This commit is contained in:
Electroblob77
2020-06-05 17:11:19 +01:00
parent ce92d564f4
commit a54f00875f
24 changed files with 106 additions and 19 deletions
@@ -692,6 +692,7 @@ public class ClientProxy extends CommonProxy {
LayerTiledOverlay.initialiseLayers(LayerStone::new);
LayerTiledOverlay.initialiseLayers(LayerFrost::new);
LayerTiledOverlay.initialiseLayers(LayerSummonAnimation::new);
LayerTiledOverlay.initialiseLayers(LayerDisintegrateAnimation::new);
}
@Override
@@ -0,0 +1,70 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.spell.Disintegration;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
/**
* Layer used to render the appear/disappear animation for summoned creatures.
*
* @author Electroblob
* @since Wizardry 4.3
*/
@EventBusSubscriber
public class LayerDisintegrateAnimation<T extends EntityLivingBase> extends LayerTiledOverlay<T> {
private static final int ANIMATION_TICKS = 19; // One less than the max death time
private static final ResourceLocation[] TEXTURES = new ResourceLocation[ANIMATION_TICKS];
static {
for(int i=0; i<ANIMATION_TICKS; i++){
TEXTURES[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/disintegrate_overlay/disintegrate_overlay_" + i + ".png");
}
}
public LayerDisintegrateAnimation(RenderLivingBase<?> renderer){
super(renderer, 32, 32);
}
@Override
public boolean shouldRender(T entity, float partialTicks){
return entity.getEntityData().hasKey(Disintegration.NBT_KEY);
}
@Override
public ResourceLocation getTexture(T entity, float partialTicks){
return TEXTURES[MathHelper.clamp(entity.ticksExisted - entity.getEntityData().getInteger(Disintegration.NBT_KEY), 0, ANIMATION_TICKS - 1)];
}
@Override
public void doRenderLayer(T entity, float limbSwing, float limbSwingAmount, float partialTicks,
float ageInTicks, float netHeadYaw, float headPitch, float scale){
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
GlStateManager.enableLighting();
}
@SubscribeEvent
public static void onRenderLivingEvent(RenderLivingEvent.Pre<EntityLivingBase> event){
if(event.getEntity().getEntityData().hasKey(Disintegration.NBT_KEY)){
event.getEntity().deathTime = 0;
event.getEntity().setInvisible(true);
}
}
@SubscribeEvent
public static void onRenderLivingEvent(RenderLivingEvent.Post<EntityLivingBase> event){
if(event.getEntity().getEntityData().hasKey(Disintegration.NBT_KEY)) event.getEntity().setInvisible(false);
}
}
@@ -39,9 +39,9 @@ public class EntityEmber extends EntityMagicProjectile {
@Override
protected void onImpact(RayTraceResult result){
if(result.entityHit != null){
result.entityHit.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue());
}
// if(result.entityHit != null){
// result.entityHit.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue());
// }
if(result.typeOfHit == RayTraceResult.Type.BLOCK){
this.inGround = true;
@@ -60,7 +60,7 @@ public class EntityEmber extends EntityMagicProjectile {
super.applyEntityCollision(entity);
if(entity instanceof EntityLivingBase){
if(entity instanceof EntityLivingBase && ((EntityLivingBase)entity).getHealth() > 0){
entity.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue());
}
}
@@ -77,6 +77,7 @@ public class EntityEmber extends EntityMagicProjectile {
}
world.getEntitiesInAABBexcluding(thrower, this.getEntityBoundingBox(), e -> e instanceof EntityLivingBase)
.stream().filter(e -> !(e instanceof EntityLivingBase) || ((EntityLivingBase)e).getHealth() > 0)
.forEach(e -> e.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue()));
// Copied from ParticleLava
@@ -25,6 +25,8 @@ public class Disintegration extends SpellRay {
public static final String EMBER_COUNT = "ember_count";
public static final String EMBER_LIFETIME = "ember_lifetime";
public static final String NBT_KEY = "disintegrating";
public Disintegration(){
super("disintegration", false, SpellActions.POINT);
addProperties(DAMAGE, BURN_DURATION, EMBER_LIFETIME, EMBER_COUNT);
@@ -43,7 +45,7 @@ public class Disintegration extends SpellRay {
MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE),
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
if(!world.isRemote && target instanceof EntityLivingBase && ((EntityLivingBase)target).getHealth() <= 0){
if(target instanceof EntityLivingBase && ((EntityLivingBase)target).getHealth() <= 0){
spawnEmbers(world, caster, target, getProperty(EMBER_COUNT).intValue());
}
}
@@ -53,17 +55,28 @@ public class Disintegration extends SpellRay {
public static void spawnEmbers(World world, EntityLivingBase caster, Entity target, int count){
for(int i = 0; i < count; i++){
EntityEmber ember = new EntityEmber(world, caster);
double x = (world.rand.nextDouble() - 0.5) * target.width;
double y = world.rand.nextDouble() * target.height;
double z = (world.rand.nextDouble() - 0.5) * target.width;
ember.setPosition(target.posX + x, target.posY + y, target.posZ + z);
float speed = 0.2f;
ember.motionX = x * speed;
ember.motionY = y * 0.5f * speed;
ember.motionZ = z * speed;
world.spawnEntity(ember);
target.extinguish();
if(world.isRemote){ // FIXME: Various syncing issues here!
// Set NBT client-side, it's only for rendering
// Normally dying entities are ignored but we're fiddling with them here so double-check
if(!target.getEntityData().hasKey(NBT_KEY)){
target.getEntityData().setInteger(NBT_KEY, target.ticksExisted);
}
}else{
for(int i = 0; i < count; i++){
EntityEmber ember = new EntityEmber(world, caster);
double x = (world.rand.nextDouble() - 0.5) * target.width;
double y = world.rand.nextDouble() * target.height;
double z = (world.rand.nextDouble() - 0.5) * target.width;
ember.setPosition(target.posX + x, target.posY + y, target.posZ + z);
ember.ticksExisted = world.rand.nextInt(20);
float speed = 0.2f;
ember.motionX = x * speed;
ember.motionY = y * 0.5f * speed;
ember.motionZ = z * speed;
world.spawnEntity(ember);
}
}
}
@@ -80,15 +80,17 @@ public final class RayTracer {
/**
* Helper method for use with {@link RayTracer#rayTrace(World, Vec3d, Vec3d, float, boolean, boolean, boolean, Class, Predicate)}
* which returns a {@link Predicate} that returns true for the given entity, plus any entities that have zero health
* or less (i.e. are in the process of dying). This is a commonly used filter in spells.
* which returns a {@link Predicate} that returns true for the given entity, plus any entities that are in the
* process of dying. This is a commonly used filter in spells.
*
* @param entity The entity that the returned predicate should return true for.
* @return A {@link Predicate} that returns true for the given entity and any entities that are in the process of
* dying, false for all other entities.
*/
public static Predicate<Entity> ignoreEntityFilter(Entity entity){
return e -> e == entity || (e instanceof EntityLivingBase && ((EntityLivingBase)e).getHealth() <= 0);
// Use deathTime > 0 so we still hit stuff that has *just* died, otherwise SpellRay#onEntityHit doesn't get
// called on the client side when the entity is killed
return e -> e == entity || (e instanceof EntityLivingBase && ((EntityLivingBase)e).deathTime > 0);
}
/**