Add remnants

This commit is contained in:
Electroblob77
2020-05-21 18:40:01 +01:00
parent 30f2a99a2c
commit 1275f1d31f
21 changed files with 665 additions and 1 deletions
@@ -40,7 +40,7 @@ public class BlockReceptacle extends BlockTorch implements ITileEntityProvider {
private static final double WALL_PARTICLE_OFFSET = 3/16d;
private static final Map<Element, int[]> PARTICLE_COLOURS;
public static final Map<Element, int[]> PARTICLE_COLOURS;
static {
@@ -746,6 +746,7 @@ public class ClientProxy extends CommonProxy {
RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new);
RenderingRegistry.registerEntityRenderingHandler(EntityRemnant.class, RenderRemnant::new);
// Throwables
RenderingRegistry.registerEntityRenderingHandler(EntitySparkBomb.class,
@@ -0,0 +1,48 @@
package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
/** Based on ModelEnderCrystal */
public class ModelRemnant extends ModelBase {
private final ModelRenderer cube = new ModelRenderer(this, "cube");
public ModelRemnant(){
this.cube.setTextureOffset(0, 0).addBox(-4.0F, -4.0F, -4.0F, 8, 8, 8);
}
@Override
public void render(Entity entity, float rotationSpeed, float expandFraction, float age, float netHeadYaw, float headPitch, float scale){
GlStateManager.pushMatrix();
// GlStateManager.scale(2.0F, 2.0F, 2.0F);
// GlStateManager.translate(0.0F, -0.5F, 0.0F);
GlStateManager.disableCull();
GlStateManager.translate(0.0F, entity.height/2, 0.0F);
float s = expandFraction + MathHelper.sin(age * 0.1f) * 0.06f;
GlStateManager.scale(s, s, s);
GlStateManager.rotate(age * rotationSpeed/2, 0.0F, 1.0F, 0.0F);
GlStateManager.rotate(60.0F, 0.7071F, 0.0F, 0.7071F);
GlStateManager.rotate(age * rotationSpeed, 0.0F, 1.0F, 0.0F);
this.cube.render(scale);
GlStateManager.scale(0.875F, 0.875F, 0.875F);
GlStateManager.rotate(60.0F, 0.7071F, 0.0F, 0.7071F);
GlStateManager.rotate(age * rotationSpeed, 0.0F, 1.0F, 0.0F);
this.cube.render(scale);
GlStateManager.enableCull();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,75 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.model.ModelRemnant;
import electroblob.wizardry.entity.living.EntityRemnant;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import javax.annotation.Nullable;
public class RenderRemnant extends Render<EntityRemnant> {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/remnant.png");
private final ModelRemnant model;
public RenderRemnant(RenderManager manager){
super(manager);
model = new ModelRemnant();
}
@Override
public void doRender(EntityRemnant entity, double x, double y, double z, float entityYaw, float partialTicks){
float age = (float)entity.ticksExisted + partialTicks;
GlStateManager.pushMatrix();
GlStateManager.translate((float)x, (float)y, (float)z);
this.bindTexture(TEXTURE);
// float whatIsThis = MathHelper.sin(age * 0.2F) / 2.0F + 0.5F;
// whatIsThis = whatIsThis * whatIsThis + whatIsThis;
if(this.renderOutlines){
GlStateManager.enableColorMaterial();
GlStateManager.enableOutlineMode(this.getTeamColor(entity));
}
float expansion = 0.9f;
if(entity.deathTime > 0){
float f = (entity.deathTime + partialTicks) * 0.25f;
f = 1 - (1 / (f + 1));
expansion -= f * 0.75f;
}else if(entity.hurtTime > 0){
float f = (entity.hurtTime - partialTicks) / entity.maxHurtTime;
// Neat bit of maths borrowed from the camera tilt effect when hurt
f = MathHelper.sin(f * f * f * f * (float)Math.PI);
expansion += f * 0.2f;
}
// if(entity.isAttacking()) s -= 0.4f;
float rotationSpeed = entity.isAttacking() ? 10 : 3;
this.model.render(entity, rotationSpeed, expansion, age, 0, 0, 0.0625f);
if(this.renderOutlines){
GlStateManager.disableOutlineMode();
GlStateManager.disableColorMaterial();
}
GlStateManager.popMatrix();
super.doRender(entity, x, y, z, entityYaw, partialTicks);
}
@Nullable
@Override
protected ResourceLocation getEntityTexture(EntityRemnant entity){
return TEXTURE;
}
}
@@ -0,0 +1,332 @@
package electroblob.wizardry.entity.living;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockReceptacle;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.ParticleBuilder;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public class EntityRemnant extends EntityMob {
/** Data parameter for the remnant's element. */
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityRemnant.class, DataSerializers.VARINT);
/** Data parameter that tracks whether the remnant is currently attacking (charging). */
private static final DataParameter<Boolean> ATTACKING = EntityDataManager.createKey(EntityRemnant.class, DataSerializers.BOOLEAN);
private ResourceLocation lootTable;
@Nullable
private BlockPos boundOrigin;
public EntityRemnant(World world){
super(world);
this.setSize(0.8f, 0.8f);
this.isImmuneToFire = true;
this.moveHelper = new EntityRemnant.AIMoveControl(this);
this.experienceValue = 8;
}
@Override
protected void entityInit(){
super.entityInit();
this.dataManager.register(ELEMENT, 1); // Default to fire
this.dataManager.register(ATTACKING, false); // Default to fire
}
@Override
protected void initEntityAI(){
super.initEntityAI();
this.tasks.addTask(0, new EntityAISwimming(this));
this.tasks.addTask(4, new EntityRemnant.AIChargeAttack());
this.tasks.addTask(8, new EntityRemnant.AIMoveRandom());
this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityPlayer.class, 3.0F, 1.0F));
this.tasks.addTask(10, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true, EntityRemnant.class));
this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<>(this, EntityPlayer.class, true));
}
@Override
protected void applyEntityAttributes(){
super.applyEntityAttributes();
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(16);
this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(4);
}
@Nullable
@Override
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata){
this.setElement(Element.values()[1 + rand.nextInt(Element.values().length - 1)]); // Exclude MAGIC
this.setBoundOrigin(new BlockPos(this));
return super.onInitialSpawn(difficulty, livingdata);
}
public Element getElement(){
return Element.values()[this.dataManager.get(ELEMENT)];
}
public void setElement(Element element){
this.dataManager.set(ELEMENT, element.ordinal());
this.lootTable = new ResourceLocation(Wizardry.MODID, "entities/remnant/" + element.getName());
}
public boolean isAttacking(){
return this.dataManager.get(ATTACKING);
}
public void setAttacking(boolean attacking){
this.dataManager.set(ATTACKING, attacking);
}
@Nullable
public BlockPos getBoundOrigin(){
return this.boundOrigin;
}
public void setBoundOrigin(@Nullable BlockPos boundOriginIn){
this.boundOrigin = boundOriginIn;
}
@Override
protected boolean isValidLightLevel(){
return true;
}
@Override
public void onUpdate(){
// Use the same trick as EntityVex to fly through stuff
this.noClip = true;
super.onUpdate();
this.noClip = false;
this.setNoGravity(true);
if(world.isRemote){
Vec3d centre = this.getPositionVector().add(0, height/2, 0);
int[] colours = BlockReceptacle.PARTICLE_COLOURS.get(this.getElement());
if(rand.nextInt(10) == 0){
ParticleBuilder.create(ParticleBuilder.Type.FLASH).entity(this).pos(0, height/2, 0).scale(width).time(48).clr(colours[0]).spawn(world);
}
double r = width/3;
double x = r * (rand.nextDouble() * 2 - 1);
double y = r * (rand.nextDouble() * 2 - 1);
double z = r * (rand.nextDouble() * 2 - 1);
if(this.deathTime > 0){
// Spew out particles on death
for(int i = 0; i < 8; i++){
ParticleBuilder.create(ParticleBuilder.Type.DUST, rand, centre.x + x, centre.y + y, centre.z + z, 0.1, true)
.time(12).clr(colours[1]).fade(colours[2]).spawn(world);
}
}else{
ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(centre.x + x, centre.y + y, centre.z + z)
.vel(x * -0.03, 0.02, z * -0.03).time(24 + rand.nextInt(8)).clr(colours[1]).fade(colours[2]).spawn(world);
}
}
}
@Override
protected SoundEvent getAmbientSound(){
return WizardrySounds.ENTITY_REMNANT_AMBIENT;
}
@Override
protected SoundEvent getDeathSound(){
return WizardrySounds.ENTITY_REMNANT_DEATH;
}
@Override
protected SoundEvent getHurtSound(DamageSource source){
return WizardrySounds.ENTITY_REMNANT_HURT;
}
@Nullable
@Override
protected ResourceLocation getLootTable(){
return lootTable;
}
@Override
public void readEntityFromNBT(NBTTagCompound nbt){
super.readEntityFromNBT(nbt);
this.setElement(Element.values()[nbt.getInteger("Element")]);
if(nbt.hasKey("BoundOrigin")) boundOrigin = NBTUtil.getPosFromTag(nbt.getCompoundTag("BoundOrigin"));
}
@Override
public void writeEntityToNBT(NBTTagCompound nbt){
super.writeEntityToNBT(nbt);
nbt.setInteger("Element", this.getElement().ordinal());
if(boundOrigin != null) nbt.setTag("BoundOrigin", NBTUtil.createPosTag(boundOrigin));
}
// AI classes (copied from EntityVex)
class AIChargeAttack extends EntityAIBase {
public AIChargeAttack(){
this.setMutexBits(1);
}
@Override
public boolean shouldExecute(){
if(EntityRemnant.this.getAttackTarget() != null && !EntityRemnant.this.getMoveHelper().isUpdating() && EntityRemnant.this.rand.nextInt(7) == 0){
return EntityRemnant.this.getDistanceSq(EntityRemnant.this.getAttackTarget()) > 4.0D;
}else{
return false;
}
}
@Override
public boolean shouldContinueExecuting(){
return EntityRemnant.this.getMoveHelper().isUpdating() && EntityRemnant.this.isAttacking() && EntityRemnant.this.getAttackTarget() != null && EntityRemnant.this.getAttackTarget().isEntityAlive();
}
@Override
public void startExecuting(){
EntityLivingBase entitylivingbase = EntityRemnant.this.getAttackTarget();
Vec3d vec3d = entitylivingbase.getPositionEyes(1.0F);
EntityRemnant.this.moveHelper.setMoveTo(vec3d.x, vec3d.y, vec3d.z, 1.0D);
EntityRemnant.this.setAttacking(true);
// EntityRemnant.this.playSound(SoundEvents.ENTITY_VEX_CHARGE, 1.0F, 1.0F);
}
@Override
public void resetTask(){
EntityRemnant.this.setAttacking(false);
}
@Override
public void updateTask(){
EntityLivingBase entitylivingbase = EntityRemnant.this.getAttackTarget();
if(EntityRemnant.this.getEntityBoundingBox().intersects(entitylivingbase.getEntityBoundingBox())){
EntityRemnant.this.attackEntityAsMob(entitylivingbase);
EntityRemnant.this.setAttacking(false);
}else{
double d0 = EntityRemnant.this.getDistanceSq(entitylivingbase);
if(d0 < 9.0D){
Vec3d vec3d = entitylivingbase.getPositionEyes(1.0F);
EntityRemnant.this.moveHelper.setMoveTo(vec3d.x, vec3d.y, vec3d.z, 1.0D);
}
}
}
}
class AIMoveControl extends EntityMoveHelper {
public AIMoveControl(EntityRemnant host){
super(host);
}
@Override
public void onUpdateMoveHelper(){
if(this.action == EntityMoveHelper.Action.MOVE_TO){
double d0 = this.posX - EntityRemnant.this.posX;
double d1 = this.posY - EntityRemnant.this.posY;
double d2 = this.posZ - EntityRemnant.this.posZ;
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
d3 = MathHelper.sqrt(d3);
if(d3 < EntityRemnant.this.getEntityBoundingBox().getAverageEdgeLength()){
this.action = EntityMoveHelper.Action.WAIT;
EntityRemnant.this.motionX *= 0.5D;
EntityRemnant.this.motionY *= 0.5D;
EntityRemnant.this.motionZ *= 0.5D;
}else{
EntityRemnant.this.motionX += d0 / d3 * 0.05D * this.speed;
EntityRemnant.this.motionY += d1 / d3 * 0.05D * this.speed;
EntityRemnant.this.motionZ += d2 / d3 * 0.05D * this.speed;
if(EntityRemnant.this.getAttackTarget() == null){
EntityRemnant.this.rotationYaw = -((float)MathHelper.atan2(EntityRemnant.this.motionX, EntityRemnant.this.motionZ)) * (180F / (float)Math.PI);
}else{
double d4 = EntityRemnant.this.getAttackTarget().posX - EntityRemnant.this.posX;
double d5 = EntityRemnant.this.getAttackTarget().posZ - EntityRemnant.this.posZ;
EntityRemnant.this.rotationYaw = -((float)MathHelper.atan2(d4, d5)) * (180F / (float)Math.PI);
}
EntityRemnant.this.renderYawOffset = EntityRemnant.this.rotationYaw;
}
}
}
}
class AIMoveRandom extends EntityAIBase {
public AIMoveRandom(){
this.setMutexBits(1);
}
@Override
public boolean shouldExecute(){
return !EntityRemnant.this.getMoveHelper().isUpdating() && EntityRemnant.this.rand.nextInt(7) == 0;
}
@Override
public boolean shouldContinueExecuting(){
return false;
}
@Override
public void updateTask(){
BlockPos blockpos = EntityRemnant.this.getBoundOrigin();
if(blockpos == null){
blockpos = new BlockPos(EntityRemnant.this);
}
for(int i = 0; i < 3; ++i){
BlockPos blockpos1 = blockpos.add(EntityRemnant.this.rand.nextInt(15) - 7, EntityRemnant.this.rand.nextInt(11) - 5, EntityRemnant.this.rand.nextInt(15) - 7);
if(EntityRemnant.this.world.isAirBlock(blockpos1)){
EntityRemnant.this.moveHelper.setMoveTo((double)blockpos1.getX() + 0.5D, (double)blockpos1.getY() + 0.5D, (double)blockpos1.getZ() + 0.5D, 0.25D);
if(EntityRemnant.this.getAttackTarget() == null){
EntityRemnant.this.getLookHelper().setLookPosition((double)blockpos1.getX() + 0.5D, (double)blockpos1.getY() + 0.5D, (double)blockpos1.getZ() + 0.5D, 180.0F, 20.0F);
}
break;
}
}
}
}
}
@@ -103,6 +103,7 @@ public class WizardryEntities {
.spawn(EnumCreatureType.MONSTER, Wizardry.settings.evilWizardSpawnRate, 1, 1, ForgeRegistries.BIOMES.getValuesCollection().stream()
.filter(b -> !Arrays.asList(Wizardry.settings.mobSpawnBiomeBlacklist).contains(b.getRegistryName()))
.collect(Collectors.toSet())).build());
registry.register(createEntry(EntityRemnant.class, "remnant", TrackingType.LIVING).egg(0xe4c7cd, 0x9d2cf3).build());
// Directed projectiles
registry.register(createEntry(EntityMagicMissile.class, "magic_missile", TrackingType.PROJECTILE).build());
@@ -75,6 +75,9 @@ public final class WizardrySounds {
public static final SoundEvent ENTITY_PHOENIX_FLAP = createSound("entity.phoenix.flap");
public static final SoundEvent ENTITY_PHOENIX_HURT = createSound("entity.phoenix.hurt");
public static final SoundEvent ENTITY_PHOENIX_DEATH = createSound("entity.phoenix.death");
public static final SoundEvent ENTITY_REMNANT_AMBIENT = createSound("entity.remnant.ambient");
public static final SoundEvent ENTITY_REMNANT_HURT = createSound("entity.remnant.hurt");
public static final SoundEvent ENTITY_REMNANT_DEATH = createSound("entity.remnant.death");
public static final SoundEvent ENTITY_SHADOW_WRAITH_AMBIENT = createSound("entity.shadow_wraith.ambient");
public static final SoundEvent ENTITY_SHADOW_WRAITH_NOISE = createSound("entity.shadow_wraith.noise");
public static final SoundEvent ENTITY_SHADOW_WRAITH_HURT = createSound("entity.shadow_wraith.hurt");
@@ -207,6 +210,9 @@ public final class WizardrySounds {
event.getRegistry().register(ENTITY_PHOENIX_FLAP);
event.getRegistry().register(ENTITY_PHOENIX_HURT);
event.getRegistry().register(ENTITY_PHOENIX_DEATH);
event.getRegistry().register(ENTITY_REMNANT_AMBIENT);
event.getRegistry().register(ENTITY_REMNANT_HURT);
event.getRegistry().register(ENTITY_REMNANT_DEATH);
event.getRegistry().register(ENTITY_SHADOW_WRAITH_AMBIENT);
event.getRegistry().register(ENTITY_SHADOW_WRAITH_NOISE);
event.getRegistry().register(ENTITY_SHADOW_WRAITH_HURT);