Add zombie apocalypse spell
This commit is contained in:
@@ -789,6 +789,7 @@ public class ClientProxy extends CommonProxy {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityHammer.class, RenderHammer::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityIceSpike.class, RenderIceSpike::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderForcefield::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityZombieSpawner.class, RenderZombieSpawner::new);
|
||||
//RenderingRegistry.registerEntityRenderingHandler(EntityContainmentField.class, RenderContainmentField::new);
|
||||
|
||||
// Stuff that doesn't render
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.entity.construct.EntityZombieSpawner;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class RenderZombieSpawner extends Render<EntityZombieSpawner> {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/zombie_spawner.png");
|
||||
|
||||
private static final Vec3d[] HIDDEN_BOX = WizardryUtilities.getVertices(new AxisAlignedBB(-1, 0, -1, 1, 2.1, 1));
|
||||
|
||||
public RenderZombieSpawner(RenderManager renderManager){
|
||||
super(renderManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(EntityZombieSpawner entity, double x, double y, double z, float yaw, float partialTicks){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GlStateManager.translate(x, y, z);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
// The visible bit
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
int animationTicks = 10;
|
||||
float age = entity.ticksExisted + partialTicks;
|
||||
float s = age < animationTicks ? age/animationTicks : MathHelper.clamp((entity.lifetime - age) / animationTicks, 0, 1);
|
||||
s = (float)Math.pow(s, 0.4); // Smooths the animation
|
||||
|
||||
GlStateManager.scale(s, s, s);
|
||||
GlStateManager.rotate(age, 0, 1, 0);
|
||||
|
||||
this.bindTexture(TEXTURE);
|
||||
|
||||
Vec3d[] vertices = WizardryUtilities.getVertices(entity.getEntityBoundingBox().offset(entity.getPositionVector().scale(-1)));
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
drawFace(buffer, vertices[0], vertices[1], vertices[3], vertices[2], 0, 0, 1, 1); // Top
|
||||
drawFace(buffer, vertices[1], vertices[0], vertices[2], vertices[3], 0, 0, 1, 1); // Bottom
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
// Hidden box
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.colorMask(false, false, false, false); // Magically hide the zombies
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||
|
||||
// Outside (hides everything)
|
||||
drawFaceColour(buffer, HIDDEN_BOX[6], HIDDEN_BOX[7], HIDDEN_BOX[2], HIDDEN_BOX[3], 0, 0, 0, 1); // South
|
||||
drawFaceColour(buffer, HIDDEN_BOX[5], HIDDEN_BOX[6], HIDDEN_BOX[1], HIDDEN_BOX[2], 0, 0, 0, 1); // East
|
||||
drawFaceColour(buffer, HIDDEN_BOX[4], HIDDEN_BOX[5], HIDDEN_BOX[0], HIDDEN_BOX[1], 0, 0, 0, 1); // North
|
||||
drawFaceColour(buffer, HIDDEN_BOX[7], HIDDEN_BOX[4], HIDDEN_BOX[3], HIDDEN_BOX[0], 0, 0, 0, 1); // West
|
||||
drawFaceColour(buffer, HIDDEN_BOX[5], HIDDEN_BOX[4], HIDDEN_BOX[6], HIDDEN_BOX[7], 0, 0, 0, 1); // Top
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.disableRescaleNormal();
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.colorMask(true, true, true, true);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderMultipass(EntityZombieSpawner entity, double x, double y, double z, float yaw, float partialTicks){
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultipass(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(EntityZombieSpawner entity){
|
||||
return TEXTURE;
|
||||
}
|
||||
|
||||
private static void drawFace(BufferBuilder buffer, Vec3d topLeft, Vec3d topRight, Vec3d bottomLeft, Vec3d bottomRight, float u1, float v1, float u2, float v2){
|
||||
buffer.pos(topLeft.x, topLeft.y, topLeft.z).tex(u1, v1).endVertex();
|
||||
buffer.pos(topRight.x, topRight.y, topRight.z).tex(u2, v1).endVertex();
|
||||
buffer.pos(bottomRight.x, bottomRight.y, bottomRight.z).tex(u2, v2).endVertex();
|
||||
buffer.pos(bottomLeft.x, bottomLeft.y, bottomLeft.z).tex(u1, v2).endVertex();
|
||||
}
|
||||
|
||||
private static void drawFaceColour(BufferBuilder buffer, Vec3d topLeft, Vec3d topRight, Vec3d bottomLeft, Vec3d bottomRight, float r, float g, float b, float a){
|
||||
buffer.pos(topLeft.x, topLeft.y, topLeft.z).color(r, g, b, a).endVertex();
|
||||
buffer.pos(topRight.x, topRight.y, topRight.z).color(r, g, b, a).endVertex();
|
||||
buffer.pos(bottomRight.x, bottomRight.y, bottomRight.z).color(r, g, b, a).endVertex();
|
||||
buffer.pos(bottomLeft.x, bottomLeft.y, bottomLeft.z).color(r, g, b, a).endVertex();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package electroblob.wizardry.entity.construct;
|
||||
|
||||
import electroblob.wizardry.entity.living.EntityZombieMinion;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.SpellMinion;
|
||||
import electroblob.wizardry.spell.ZombieApocalypse;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.WizardryUtilities.Operations;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.ai.attributes.IAttributeInstance;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class EntityZombieSpawner extends EntityMagicConstruct {
|
||||
|
||||
public EntityZombieSpawner(World world){
|
||||
super(world);
|
||||
this.setSize(4, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
if(!world.isRemote && rand.nextInt(Spells.zombie_apocalypse.getProperty(ZombieApocalypse.MINION_SPAWN_INTERVAL).intValue()) == 0){
|
||||
|
||||
EntityZombieMinion zombie = new EntityZombieMinion(world);
|
||||
|
||||
zombie.setPosition(this.posX, this.posY, this.posZ);
|
||||
zombie.setCaster(this.getCaster());
|
||||
// Modifier implementation
|
||||
// Attribute modifiers are pretty opaque, see https://minecraft.gamepedia.com/Attribute#Modifiers
|
||||
zombie.setLifetime(Spells.zombie_apocalypse.getProperty(SpellMinion.MINION_LIFETIME).intValue());
|
||||
IAttributeInstance attribute = zombie.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE);
|
||||
attribute.applyModifier(new AttributeModifier(SpellMinion.POTENCY_ATTRIBUTE_MODIFIER,
|
||||
damageMultiplier - 1, Operations.MULTIPLY_CUMULATIVE));
|
||||
zombie.setHealth(zombie.getMaxHealth()); // Need to set this because we may have just modified the value
|
||||
zombie.hurtResistantTime = 30; // Prevent fall damage
|
||||
zombie.showSpawnParticles = false; // Hide spawn particles or they pop out the top of the hidden box
|
||||
|
||||
world.spawnEntity(zombie);
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
float b = 0.15f;
|
||||
|
||||
for(double r = 1.5; r < 4; r += 0.2){
|
||||
ParticleBuilder.create(Type.CLOUD).clr(b-=0.02, 0, 0).pos(posX, posY - 0.3, posZ).scale(0.5f / (float)r)
|
||||
.spin(r, 0.02/r * (1 + world.rand.nextDouble())).spawn(world);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass){
|
||||
return super.shouldRenderInPass(pass);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import java.util.UUID;
|
||||
|
||||
public class EntityZombieMinion extends EntityZombie implements ISummonedCreature {
|
||||
|
||||
public boolean showSpawnParticles = true;
|
||||
|
||||
// Field implementations
|
||||
private int lifetime = -1;
|
||||
private UUID casterUUID;
|
||||
@@ -72,7 +74,7 @@ public class EntityZombieMinion extends EntityZombie implements ISummonedCreatur
|
||||
|
||||
@Override
|
||||
public void onSpawn(){
|
||||
this.spawnParticleEffect();
|
||||
if(showSpawnParticles) this.spawnParticleEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -242,6 +242,8 @@ public final class Spells {
|
||||
|
||||
public static final Spell stormcloud = placeholder();
|
||||
|
||||
public static final Spell zombie_apocalypse = placeholder();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void register(RegistryEvent.Register<Spell> event){
|
||||
|
||||
@@ -445,6 +447,8 @@ public final class Spells {
|
||||
|
||||
registry.register(new Stormcloud());
|
||||
|
||||
registry.register(new ZombieApocalypse());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -146,6 +146,7 @@ public class WizardryEntities {
|
||||
registry.register(createEntry(EntityFireRing.class, "ring_of_fire", TrackingType.CONSTRUCT).build());
|
||||
registry.register(createEntry(EntityHealAura.class, "healing_aura", TrackingType.CONSTRUCT).build());
|
||||
registry.register(createEntry(EntityDecay.class, "decay", TrackingType.CONSTRUCT).build());
|
||||
registry.register(createEntry(EntityZombieSpawner.class, "zombie_spawner", TrackingType.CONSTRUCT).build());
|
||||
|
||||
// These ones don't render, currently that makes no difference here but we might as well separate them
|
||||
registry.register(createEntry(EntityArrowRain.class, "arrow_rain", TrackingType.CONSTRUCT).build());
|
||||
|
||||
@@ -52,7 +52,7 @@ public class SpellMinion<T extends EntityLiving & ISummonedCreature> extends Spe
|
||||
* entity attribute modifier. */
|
||||
public static final String HEALTH_MODIFIER = "minion_health";
|
||||
/** The string identifier for the potency attribute modifier. */
|
||||
private static final String POTENCY_ATTRIBUTE_MODIFIER = "potency";
|
||||
public static final String POTENCY_ATTRIBUTE_MODIFIER = "potency";
|
||||
|
||||
/** A factory that creates summoned creature entities. */
|
||||
protected final Function<World, T> minionFactory;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package electroblob.wizardry.spell;
|
||||
|
||||
import electroblob.wizardry.entity.construct.EntityZombieSpawner;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ZombieApocalypse extends SpellConstruct<EntityZombieSpawner> {
|
||||
|
||||
public static final String MINION_SPAWN_INTERVAL = "minion_spawn_interval";
|
||||
|
||||
public ZombieApocalypse(){
|
||||
super("zombie_apocalypse", SpellActions.POINT_UP, EntityZombieSpawner::new, false);
|
||||
addProperties(SpellMinion.MINION_LIFETIME, MINION_SPAWN_INTERVAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
y += 8;
|
||||
return super.spawnConstruct(world, x, y, z, side, caster, modifiers);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user