Jump to content

[1.6.4]Custom Golem Arm Rendering Issues [Solved]


SilasOtoko

Recommended Posts

I have several custom Golems, the first of which works fine, but the other two have glitches when attacking. When I am attacked by one, it's arms will become stuck in a half raised position. Not only this, but ALL of the custom Golems move their arms in unison to each other like some sort of weird synchronized ballet. I cannot figure out why one of my Golem types work but not the other, even after comparing the code. Any help?

 

Custom Golem that does not work:

 

 

Entity:

 

package runes.Runes;

 

import net.minecraft.block.Block;

import net.minecraft.entity.Entity;

import net.minecraft.entity.EntityLivingBase;

import net.minecraft.entity.SharedMonsterAttributes;

import net.minecraft.entity.ai.EntityAIAttackOnCollide;

import net.minecraft.entity.ai.EntityAIHurtByTarget;

import net.minecraft.entity.ai.EntityAILookIdle;

import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;

import net.minecraft.entity.ai.EntityAIMoveTowardsTarget;

import net.minecraft.entity.ai.EntityAINearestAttackableTarget;

import net.minecraft.entity.ai.EntityAIWander;

import net.minecraft.entity.ai.EntityAIWatchClosest;

import net.minecraft.entity.monster.EntityMob;

import net.minecraft.entity.monster.IMob;

import net.minecraft.entity.player.EntityPlayer;

import net.minecraft.item.ItemStack;

import net.minecraft.nbt.NBTTagCompound;

import net.minecraft.util.DamageSource;

import net.minecraft.util.MathHelper;

import net.minecraft.world.World;

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

public class EntityRuneGolem extends EntityMob {

private int attackTimer;

    private int homeCheckTimer = 0;

   

 

public EntityRuneGolem(World par1World){

super(par1World);

        this.setSize(1.4F, 2.9F);

        this.getNavigator().setAvoidsWater(true);

        this.tasks.addTask(1, new EntityAIAttackOnCollide(this, 1.0D, true));

        this.tasks.addTask(2, new EntityAIMoveTowardsTarget(this, 0.9D, 32.0F));

        this.tasks.addTask(4, new EntityAIMoveTowardsRestriction(this, 1.0D));

        this.tasks.addTask(6, new EntityAIWander(this, 0.6D));

        this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));

        this.tasks.addTask(8, new EntityAILookIdle(this));

        this.targetTasks.addTask(2, new EntityAIHurtByTarget(this, false));

        this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true));

}

 

    protected void entityInit()

    {

        super.entityInit();

            this.dataWatcher.addObject(19, new Byte((byte)0));

            this.dataWatcher.addObject(20, new Byte((byte)0));

    }

   

    /**

    * (abstract) Protected helper method to write subclass entity data to NBT.

    */

    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)

    {

        super.writeEntityToNBT(par1NBTTagCompound);

     

    }

 

    /**

    * (abstract) Protected helper method to read subclass entity data from NBT.

    */

    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)

    {

        super.readEntityFromNBT(par1NBTTagCompound);

 

    }

 

    /**

    * Returns true if the newer Entity AI code should be run

    */

    public boolean isAIEnabled()

    {

        return true;

    }

 

    /**

    * main AI tick function, replaces updateEntityActionState

    */

    protected void updateAITick()

    {

        super.updateAITick();

    }

 

    @Override

    protected void applyEntityAttributes()

    {

    super.applyEntityAttributes();

    this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(50.0D);

    this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.25D); //Recomended speed

 

    }

 

    /**

    * Decrements the entity's air supply when underwater

    */

    protected int decreaseAirSupply(int par1)

    {

        return par1;

    }

 

    @Override

    /**

    * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons

    * use this to react to sunlight and start to burn.

    */

    public void onLivingUpdate()

    {

        super.onLivingUpdate();

 

        if (this.attackTimer > 0)

        {

            --this.attackTimer;

        }

 

        if (this.motionX * this.motionX + this.motionZ * this.motionZ > 2.500000277905201E-7D && this.rand.nextInt(5) == 0)

        {

            int i = MathHelper.floor_double(this.posX);

            int j = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset);

            int k = MathHelper.floor_double(this.posZ);

            int l = this.worldObj.getBlockId(i, j, k);

 

            if (l > 0)

            {

                this.worldObj.spawnParticle("tilecrack_" + l + "_" + this.worldObj.getBlockMetadata(i, j, k), this.posX + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, this.boundingBox.minY + 0.1D, this.posZ + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, 4.0D * ((double)this.rand.nextFloat() - 0.5D), 0.5D, ((double)this.rand.nextFloat() - 0.5D) * 4.0D);

            }

        }

       

    }

 

    /**

    * Returns true if this entity can attack entities of the specified class.

    */

    @Override

    public boolean canAttackClass(Class par1Class)

    {

    return super.canAttackClass(par1Class);

    }

   

    protected void collideWithEntity(Entity par1Entity)

    {

        if (par1Entity instanceof IMob && this.getRNG().nextInt(20) == 0)

        {

            this.setAttackTarget((EntityLivingBase)par1Entity);

        }

 

        super.collideWithEntity(par1Entity);

    }

 

   

 

    public boolean attackEntityAsMob(Entity par1Entity)

    {

        this.attackTimer = 10;

        this.worldObj.setEntityState(this, (byte)4);

        boolean flag = par1Entity.attackEntityFrom(DamageSource.causeMobDamage(this), (float)(7 + this.rand.nextInt(15)));

 

        if (flag)

        {

            par1Entity.motionY += 0.4000000059604645D;

        }

 

        this.playSound("mob.irongolem.throw", 1.0F, 1.0F);

        return flag;

    }

 

    @SideOnly(Side.CLIENT)

    public void handleHealthUpdate(byte par1)

    {

        if (par1 == 4)

        {

            this.attackTimer = 10;

            this.playSound("mob.irongolem.throw", 1.0F, 1.0F);

        }

        else

        {

            super.handleHealthUpdate(par1);

        }

    }

 

    @SideOnly(Side.CLIENT)

    public int getAttackTimer()

    {

        return this.attackTimer;

    }

 

    /**

    * Returns the sound this mob makes while it's alive.

    */

    protected String getLivingSound()

    {

        return "none";

    }

 

    /**

    * Returns the sound this mob makes when it is hurt.

    */

    protected String getHurtSound()

    {

        return "mob.irongolem.hit";

    }

 

    /**

    * Returns the sound this mob makes on death.

    */

    protected String getDeathSound()

    {

        return "mob.irongolem.death";

    }

 

    /**

    * Plays step sound at given x, y, z for the entity

    */

    protected void playStepSound(int par1, int par2, int par3, int par4)

    {

        this.playSound("mob.irongolem.walk", 1.0F, 1.0F);

    }

 

    /**

    * Drop 0-2 items of this living's type. @param par1 - Whether this entity has recently been hit by a player. @param

    * par2 - Level of Looting used to kill this mob.

    */

    protected void dropFewItems(boolean par1, int par2)

    {

        int j = this.rand.nextInt(3);

        int k;

 

        for (k = 0; k < j; ++k)

        {

            this.dropItem(Main.Rune.itemID, 2);

        }

 

        k = 3 + this.rand.nextInt(3);

 

        for (int l = 0; l < k; ++l)

        {

            this.dropItem(Main.SilverEssence.itemID, 2);

        }

    }

   

 

    /**

    * Called when the mob's health reaches 0.

    */

    public void onDeath(DamageSource par1DamageSource)

    {

        super.onDeath(par1DamageSource);

    }

 

    protected boolean canDespawn()

    {

        return true;

    }

 

    public int getMaxSpawnedInChunk()

    {

        return 1;

    }

 

public void initCreature() {

}

 

 

 

protected void addRandomArmor()

    {

        super.addRandomArmor();

 

        if (this.rand.nextFloat() < (this.worldObj.difficultySetting == 3 ? 0.05F : 0.01F))

        {

            int i = this.rand.nextInt(3);

 

            if (i == 0)

            {

                this.setCurrentItemOrArmor(0, new ItemStack(Block.plantYellow));

            }

            else

            {

                this.setCurrentItemOrArmor(0, new ItemStack(Block.plantRed));

            }

        }

    }

 

 

 

}

 

Render:

 

package runes.Runes;

 

import net.minecraft.client.renderer.entity.RenderLiving;

import net.minecraft.entity.Entity;

import net.minecraft.entity.EntityLiving;

import net.minecraft.entity.EntityLivingBase;

import net.minecraft.util.ResourceLocation;

 

import org.lwjgl.opengl.GL11;

 

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

@SideOnly(Side.CLIENT)

public class RenderRuneGolem extends RenderLiving

{

/** Iron Golem's Model. */

    protected ModelRuneGolem model;

 

    public RenderRuneGolem(ModelRuneGolem par1model, float f)

    {

        super(par1model, f);

        model = (ModelRuneGolem)mainModel;

    }

 

    public void doRenderRuneGolem(EntityRuneGolem par1EntityEnt, double par2, double par4, double par6, float par8, float par9)

    {

   

        super.doRenderLiving(par1EntityEnt, par2, par4, par6, par8, par9);

    }

 

    /**

    * Rotates Iron Golem corpse.

    */

    protected void rotateRuneGolemCorpse(EntityRuneGolem par1EntityEnt, float par2, float par3, float par4)

    {

        super.rotateCorpse(par1EntityEnt, par2, par3, par4);

 

        if ((double)par1EntityEnt.limbSwingAmount >= 0.01D)

        {

            float f3 = 13.0F;

            float f4 = par1EntityEnt.limbSwing - par1EntityEnt.limbSwingAmount * (1.0F - par4) + 6.0F;

            float f5 = (Math.abs(f4 % f3 - f3 * 0.5F) - f3 * 0.25F) / (f3 * 0.25F);

            GL11.glRotatef(6.5F * f5, 0.0F, 0.0F, 1.0F);

        }

    }

 

    /*protected void RenderRuneGolemEquippedItems(EntityRuneGolem par1EntityEnt, float par2)

    {

        super.renderEquippedItems(par1EntityEnt, par2);

 

       

    }*/

   

 

   

 

    public void doRenderLiving(EntityLiving par1EntityLiving, double par2, double par4, double par6, float par8, float par9)

    {

        this.doRenderRuneGolem((EntityRuneGolem)par1EntityLiving, par2, par4, par6, par8, par9);

    }

 

    /*protected void renderEquippedItems(EntityLivingBase par1EntityLivingBase, float par2)

    {

        this.RenderRuneGolemEquippedItems((EntityRuneGolem)par1EntityLivingBase, par2);

       

    }*/

   

    protected void rotateCorpse(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4)

    {

        this.rotateRuneGolemCorpse((EntityRuneGolem)par1EntityLivingBase, par2, par3, par4);

    }

 

    public void renderPlayer(EntityLivingBase par1EntityLivingBase, double par2, double par4, double par6, float par8, float par9)

    {

        this.doRenderRuneGolem((EntityRuneGolem)par1EntityLivingBase, par2, par4, par6, par8, par9);

    }

 

    /**

    * Actually renders the given argument. This is a synthetic bridge method, always casting down its argument and then

    * handing it off to a worker function which does the actual work. In all probabilty, the class Render is generic

    * (Render<T extends Entity) and this method has signature public void doRender(T entity, double d, double d1,

    * double d2, float f, float f1). But JAD is pre 1.5 so doesn't do that.

    */

    @Override

    public void doRender(Entity par1Entity, double par2, double par4, double par6, float par8, float par9)

    {

        this.doRenderRuneGolem((EntityRuneGolem)par1Entity, par2, par4, par6, par8, par9);

    }

 

@Override

protected ResourceLocation getEntityTexture(Entity entity) {

return new ResourceLocation("runes:textures/entity/RuneGolem.png");

}

}

 

 

Model:

 

package runes.Runes;

 

import net.minecraft.client.model.ModelBase;

import net.minecraft.client.model.ModelRenderer;

import net.minecraft.entity.Entity;

import net.minecraft.entity.EntityLivingBase;

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

@SideOnly(Side.CLIENT)

public class ModelRuneGolem extends ModelBase

{

    /** The head model for the iron golem. */

    public ModelRenderer runeGolemHead;

 

    /** The body model for the iron golem. */

    public ModelRenderer runeGolemBody;

 

    /** The right arm model for the iron golem. */

    public ModelRenderer runeGolemRightArm;

 

    /** The left arm model for the iron golem. */

    public ModelRenderer runeGolemLeftArm;

 

    /** The left leg model for the Iron Golem. */

    public ModelRenderer runeGolemLeftLeg;

 

    /** The right leg model for the Iron Golem. */

    public ModelRenderer runeGolemRightLeg;

 

    public ModelRuneGolem()

    {

        this(0.0F);

    }

 

    public ModelRuneGolem(float par1)

    {

        this(par1, -7.0F);

    }

 

    public ModelRuneGolem(float par1, float par2)

    {

        short short1 = 128;

        short short2 = 128;

        this.runeGolemHead = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.runeGolemHead.setRotationPoint(0.0F, 0.0F + par2, -2.0F);

        this.runeGolemHead.setTextureOffset(0, 0).addBox(-4.0F, -12.0F, -5.5F, 8, 10, 8, par1);

        this.runeGolemHead.setTextureOffset(24, 0).addBox(-1.0F, -5.0F, -7.5F, 2, 4, 2, par1);

        this.runeGolemBody = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.runeGolemBody.setRotationPoint(0.0F, 0.0F + par2, 0.0F);

        this.runeGolemBody.setTextureOffset(0, 40).addBox(-9.0F, -2.0F, -6.0F, 18, 12, 11, par1);

        this.runeGolemBody.setTextureOffset(0, 70).addBox(-4.5F, 10.0F, -3.0F, 9, 5, 6, par1 + 0.5F);

        this.runeGolemRightArm = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.runeGolemRightArm.setRotationPoint(0.0F, -7.0F, 0.0F);

        this.runeGolemRightArm.setTextureOffset(60, 21).addBox(-13.0F, -2.5F, -3.0F, 4, 30, 6, par1);

        this.runeGolemLeftArm = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.runeGolemLeftArm.setRotationPoint(0.0F, -7.0F, 0.0F);

        this.runeGolemLeftArm.setTextureOffset(60, 58).addBox(9.0F, -2.5F, -3.0F, 4, 30, 6, par1);

        this.runeGolemLeftLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);

        this.runeGolemLeftLeg.setRotationPoint(-4.0F, 18.0F + par2, 0.0F);

        this.runeGolemLeftLeg.setTextureOffset(37, 0).addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);

        this.runeGolemRightLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);

        this.runeGolemRightLeg.mirror = true;

        this.runeGolemRightLeg.setTextureOffset(60, 0).setRotationPoint(5.0F, 18.0F + par2, 0.0F);

        this.runeGolemRightLeg.addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);

    }

 

    /**

    * Sets the models various rotation angles then renders the model.

    */

    public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7)

    {

        this.setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity);

        this.runeGolemHead.render(par7);

        this.runeGolemBody.render(par7);

        this.runeGolemLeftLeg.render(par7);

        this.runeGolemRightLeg.render(par7);

        this.runeGolemRightArm.render(par7);

        this.runeGolemLeftArm.render(par7);

    }

 

    /**

    * Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms

    * and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how

    * "far" arms and legs can swing at most.

    */

    public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity)

    {

        this.runeGolemHead.rotateAngleY = par4 / (180F / (float)Math.PI);

        this.runeGolemHead.rotateAngleX = par5 / (180F / (float)Math.PI);

        this.runeGolemLeftLeg.rotateAngleX = -1.5F * this.func_78172_a(par1, 13.0F) * par2;

        this.runeGolemRightLeg.rotateAngleX = 1.5F * this.func_78172_a(par1, 13.0F) * par2;

        this.runeGolemLeftLeg.rotateAngleY = 0.0F;

        this.runeGolemRightLeg.rotateAngleY = 0.0F;

    }

 

    /**

    * Used for easily adding entity-dependent animations. The second and third float params here are the same second

    * and third as in the setRotationAngles method.

    */

    public void setLivingAnimations(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4)

    {

        EntityRuneGolem EntityRuneGolem = (EntityRuneGolem)par1EntityLivingBase;

        int i = EntityRuneGolem.getAttackTimer();

 

        if (i > 0)

        {

            this.runeGolemRightArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);

            this.runeGolemLeftArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);

        }

        /*else

        {

            int j = EntityRuneGolem.getHoldRoseTick();

 

            if (j > 0)

            {

                this.runeGolemRightArm.rotateAngleX = -0.8F + 0.025F * this.func_78172_a((float)j, 70.0F);

                this.runeGolemLeftArm.rotateAngleX = 0.0F;

            }

            else

            {

                this.runeGolemRightArm.rotateAngleX = (-0.2F + 1.5F * this.func_78172_a(par2, 13.0F)) * par3;

                this.runeGolemLeftArm.rotateAngleX = (-0.2F - 1.5F * this.func_78172_a(par2, 13.0F)) * par3;

            }

        }*/

    }

 

    private float func_78172_a(float par1, float par2)

    {

        return (Math.abs(par1 % par2 - par2 * 0.5F) - par2 * 0.25F) / (par2 * 0.25F);

    }

 

}

 

 

ClientProxy:

 

package runes.Runes;

 

import net.minecraft.client.model.ModelZombie;

import cpw.mods.fml.client.registry.RenderingRegistry;

 

public class ClientProxy extends CommonProxy{

@Override

public void registerRenderers(){

RenderingRegistry.registerEntityRenderingHandler(EntityForestWalker.class, new RenderEnt(new ModelEnt(), 0.3F));

RenderingRegistry.registerEntityRenderingHandler(EntityCreeperHeart.class, new RenderCreeperHeart(Main.CreeperHeart));

RenderingRegistry.registerEntityRenderingHandler(EntityFireTalisman.class, new RenderFireTalisman(Main.FireTalisman));

RenderingRegistry.registerEntityRenderingHandler(EntityWaterTalisman.class, new RenderWaterTalisman(Main.WaterTalisman));

RenderingRegistry.registerEntityRenderingHandler(EntityEarthTalisman.class, new RenderEarthTalisman(Main.EarthTalisman));

RenderingRegistry.registerEntityRenderingHandler(EntityEnderChild.class, new RenderEnderChild(new ModelEnderChild(), 0.3F));

RenderingRegistry.registerEntityRenderingHandler(EntityRuneArrow.class, new RenderRuneArrow());

RenderingRegistry.registerEntityRenderingHandler(EntityWaterBall.class, new RenderWaterBall(Main.WaterBall));

RenderingRegistry.registerEntityRenderingHandler(EntityForestWalkerPC.class, new RenderForestWalkerPC(new ModelForestWalkerPC(), 0.3F));

RenderingRegistry.registerEntityRenderingHandler(EntityEskimoZombie.class, new RenderEskimoZombie(new ModelEskimoZombie(), 0.3F));

RenderingRegistry.registerEntityRenderingHandler(EntityEskimoSkeleton.class, new RenderEskimoSkeleton(new ModelEskimoZombie(), 0.3F));

RenderingRegistry.registerEntityRenderingHandler(EntityYeti.class, new RenderYeti(new ModelYeti(), 0.3F));

RenderingRegistry.registerEntityRenderingHandler(EntityPineCone.class, new RenderPineCone(Main.PineCone));

RenderingRegistry.registerEntityRenderingHandler(EntityFairy.class, new RenderFairy(new ModelFairy(), 0.25F));

RenderingRegistry.registerEntityRenderingHandler(EntityRuneGolem.class, new RenderRuneGolem(new ModelRuneGolem(), 0.3F));

}

 

@Override

 

public int addArmor(String armor)

{

return RenderingRegistry.addNewArmourRendererPrefix(armor);

}

}

 

 

Main:

 

EntityRegistry.registerGlobalEntityID(EntityRuneGolem.class, "RuneGolem", 114);

    EntityRegistry.addSpawn(EntityRuneGolem.class, 2, 1, 1, EnumCreatureType.monster, RuneBiome);

    EntityRegistry.findGlobalUniqueEntityId();

    RegisterEntityEgg(EntityRuneGolem.class, 0, 0);

 

 

 

 

Custom Golem that works fine:

 

 

Entity:

 

package runes.Runes;

 

import java.util.List;

 

import net.minecraft.block.Block;

import net.minecraft.entity.Entity;

import net.minecraft.entity.EntityAgeable;

import net.minecraft.entity.EntityLiving;

import net.minecraft.entity.SharedMonsterAttributes;

import net.minecraft.entity.ai.EntityAIAttackOnCollide;

import net.minecraft.entity.ai.EntityAIHurtByTarget;

import net.minecraft.entity.ai.EntityAILookIdle;

import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;

import net.minecraft.entity.ai.EntityAIMoveTowardsTarget;

import net.minecraft.entity.ai.EntityAINearestAttackableTarget;

import net.minecraft.entity.ai.EntityAIWander;

import net.minecraft.entity.ai.EntityAIWatchClosest;

import net.minecraft.entity.monster.EntityCreeper;

import net.minecraft.entity.monster.IMob;

import net.minecraft.entity.passive.EntityAnimal;

import net.minecraft.entity.player.EntityPlayer;

import net.minecraft.item.ItemStack;

import net.minecraft.nbt.NBTTagCompound;

import net.minecraft.util.DamageSource;

import net.minecraft.util.MathHelper;

import net.minecraft.world.World;

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

public class EntityForestWalker extends EntityAnimal {

private int attackTimer;

    private int homeCheckTimer = 0;

    public static boolean[] plantableBlocks = new boolean[4096];

 

public EntityForestWalker(World par1World){

super(par1World);

        this.setSize(1.4F, 2.9F);

        this.getNavigator().setAvoidsWater(true);

        this.tasks.addTask(1, new EntityAIAttackOnCollide(this, 1.0D, true));

        this.tasks.addTask(2, new EntityAIMoveTowardsTarget(this, 0.9D, 32.0F));

        this.tasks.addTask(4, new EntityAIMoveTowardsRestriction(this, 1.0D));

        this.tasks.addTask(6, new EntityAIWander(this, 0.6D));

        this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));

        this.tasks.addTask(8, new EntityAILookIdle(this));

        this.targetTasks.addTask(2, new EntityAIHurtByTarget(this, false));

        this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityLiving.class, 0, false, true, IMob.mobSelector));

}

 

    protected void entityInit()

    {

        super.entityInit();

            this.dataWatcher.addObject(19, new Byte((byte)0));

            this.dataWatcher.addObject(20, new Byte((byte)0));

    }

   

    /**

    * (abstract) Protected helper method to write subclass entity data to NBT.

    */

    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)

    {

        super.writeEntityToNBT(par1NBTTagCompound);

        par1NBTTagCompound.setShort("carried", (short)this.getCarried());

        par1NBTTagCompound.setShort("carriedData", (short)this.getCarryingData());

    }

 

    /**

    * (abstract) Protected helper method to read subclass entity data from NBT.

    */

    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)

    {

        super.readEntityFromNBT(par1NBTTagCompound);

        this.setCarried(par1NBTTagCompound.getShort("carried"));

        this.setCarryingData(par1NBTTagCompound.getShort("carriedData"));

    }

 

    /**

    * Returns true if the newer Entity AI code should be run

    */

    public boolean isAIEnabled()

    {

        return true;

    }

 

    /**

    * main AI tick function, replaces updateEntityActionState

    */

    protected void updateAITick()

    {

        super.updateAITick();

    }

 

    @Override

    protected void applyEntityAttributes()

    {

    super.applyEntityAttributes();

    this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(100.0D);

    this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.25D); //Recomended speed

    //this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setAttribute(15D);

  // this.getEntityAttribute(SharedMonsterAttributes.followRange).setAttribute(20D);

    }

 

    /**

    * Decrements the entity's air supply when underwater

    */

    protected int decreaseAirSupply(int par1)

    {

        return par1;

    }

 

    protected void collideWithEntity(Entity par1Entity)

    {

        if (par1Entity instanceof IMob && !(par1Entity instanceof EntityForestWalker) && !(par1Entity instanceof EntityCreeper) && this.getRNG().nextInt(20) == 0)

        {

            this.setAttackTarget((EntityLiving)par1Entity);

        }

 

        super.collideWithEntity(par1Entity);

    }

 

    /**

    * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons

    * use this to react to sunlight and start to burn.

    */

    public void onLivingUpdate()

    {

       

 

        if (this.attackTimer > 0)

        {

            --this.attackTimer;

        }

 

        if (this.motionX * this.motionX + this.motionZ * this.motionZ > 2.500000277905201E-7D && this.rand.nextInt(5) == 0)

        {

            int i = MathHelper.floor_double(this.posX);

            int j = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset);

            int k = MathHelper.floor_double(this.posZ);

            int l = this.worldObj.getBlockId(i, j, k);

 

            if (l > 0)

            {

                this.worldObj.spawnParticle("tilecrack_" + l + "_" + this.worldObj.getBlockMetadata(i, j, k), this.posX + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, this.boundingBox.minY + 0.1D, this.posZ + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, 4.0D * ((double)this.rand.nextFloat() - 0.5D), 0.5D, ((double)this.rand.nextFloat() - 0.5D) * 4.0D);

            }

        }

        int i;

 

        if (!this.worldObj.isRemote && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"))

        {

            int j;

            int k;

            int l;

 

            if (this.getCarried() == 0)

            {

                if (this.rand.nextInt(20) == 0)

                {

                    i = MathHelper.floor_double(this.posX - 2.0D + this.rand.nextDouble() * 4.0D);

                    j = MathHelper.floor_double(this.posY + this.rand.nextDouble() * 3.0D);

                    k = MathHelper.floor_double(this.posZ - 2.0D + this.rand.nextDouble() * 4.0D);

                    l = this.worldObj.getBlockId(i, j, k);

 

                    if (plantableBlocks[l])

                    {

                        this.setCarried(this.worldObj.getBlockId(i, j, k));

                        this.setCarryingData(this.worldObj.getBlockMetadata(i, j, k));

                        this.worldObj.setBlock(i, j, k, 0);

                    }

                }

            }

            else if (this.rand.nextInt(2000) == 0)

            {

                i = MathHelper.floor_double(this.posX - 1.0D + this.rand.nextDouble() * 2.0D);

                j = MathHelper.floor_double(this.posY + this.rand.nextDouble() * 2.0D);

                k = MathHelper.floor_double(this.posZ - 1.0D + this.rand.nextDouble() * 2.0D);

                l = this.worldObj.getBlockId(i, j, k);

                int i1 = this.worldObj.getBlockId(i, j - 1, k);

 

                if (l == 0 && i1 > 0 && Block.blocksList[i1].renderAsNormalBlock())

                {

                    this.worldObj.setBlock(i, j, k, this.getCarried(), this.getCarryingData(), 3);

                    this.setCarried(0);

                }

            }

        }

        super.onLivingUpdate();

    }

 

    /**

    * Returns true if this entity can attack entities of the specified class.

    */

    @Override

    public boolean canAttackClass(Class par1Class)

    {

        return EntityForestWalker.class != par1Class && EntityCreeper.class != par1Class;

    }

 

   

 

    public boolean attackEntityAsMob(Entity par1Entity)

    {

        this.attackTimer = 10;

        this.worldObj.setEntityState(this, (byte)4);

        boolean flag = par1Entity.attackEntityFrom(DamageSource.causeMobDamage(this), (float)(7 + this.rand.nextInt(15)));

 

        if (flag)

        {

            par1Entity.motionY += 0.4000000059604645D;

        }

 

        this.playSound("mob.irongolem.throw", 1.0F, 1.0F);

        return flag;

    }

 

    @SideOnly(Side.CLIENT)

    public void handleHealthUpdate(byte par1)

    {

        if (par1 == 4)

        {

            this.attackTimer = 10;

            this.playSound("mob.irongolem.throw", 1.0F, 1.0F);

        }

        else

        {

            super.handleHealthUpdate(par1);

        }

    }

 

    @SideOnly(Side.CLIENT)

    public int getAttackTimer()

    {

        return this.attackTimer;

    }

 

    /**

    * Returns the sound this mob makes while it's alive.

    */

    protected String getLivingSound()

    {

        return "none";

    }

 

    /**

    * Returns the sound this mob makes when it is hurt.

    */

    protected String getHurtSound()

    {

        return "mob.irongolem.hit";

    }

 

    /**

    * Returns the sound this mob makes on death.

    */

    protected String getDeathSound()

    {

        return "mob.irongolem.death";

    }

 

    /**

    * Plays step sound at given x, y, z for the entity

    */

    protected void playStepSound(int par1, int par2, int par3, int par4)

    {

        this.playSound("mob.irongolem.walk", 1.0F, 1.0F);

    }

 

    /**

    * Drop 0-2 items of this living's type. @param par1 - Whether this entity has recently been hit by a player. @param

    * par2 - Level of Looting used to kill this mob.

    */

    protected void dropFewItems(boolean par1, int par2)

    {

        int j = this.rand.nextInt(3);

        int k;

 

        for (k = 0; k < j; ++k)

        {

            this.dropItem(Main.EarthRune.itemID, 2);

        }

 

        k = 3 + this.rand.nextInt(3);

 

        for (int l = 0; l < k; ++l)

        {

            this.dropItem(Main.SilverEssence.itemID, 2);

        }

    }

   

    /**

    * Set the id of the block an enderman carries

    */

    public void setCarried(int par1)

    {

        this.dataWatcher.updateObject(19, Byte.valueOf((byte)(par1 & 255)));

    }

 

    /**

    * Get the id of the block an enderman carries

    */

    public int getCarried()

    {

        return this.dataWatcher.getWatchableObjectByte(19);

    }

 

    /**

    * Set the metadata of the block an enderman carries

    */

    public void setCarryingData(int par1)

    {

        this.dataWatcher.updateObject(20, Byte.valueOf((byte)(par1 & 255)));

    }

 

    /**

    * Get the metadata of the block an enderman carries

    */

    public int getCarryingData()

    {

        return this.dataWatcher.getWatchableObjectByte(20);

    }

 

    /**

    * Called when the mob's health reaches 0.

    */

    public void onDeath(DamageSource par1DamageSource)

    {

        super.onDeath(par1DamageSource);

    }

 

    protected boolean canDespawn()

    {

        return true;

    }

 

    public int getMaxSpawnedInChunk()

    {

        return 1;

    }

 

public void initCreature() {

}

 

static

    {

        plantableBlocks[block.sapling.blockID] = true;

        plantableBlocks[block.plantYellow.blockID] = true;

        plantableBlocks[block.plantRed.blockID] = true;

        plantableBlocks[block.mushroomBrown.blockID] = true;

        plantableBlocks[block.mushroomRed.blockID] = true;

        plantableBlocks[block.cactus.blockID] = true;

        plantableBlocks[block.pumpkin.blockID] = true;

        plantableBlocks[block.melon.blockID] = true;

    }

 

protected void addRandomArmor()

    {

        super.addRandomArmor();

 

        if (this.rand.nextFloat() < (this.worldObj.difficultySetting == 3 ? 0.05F : 0.01F))

        {

            int i = this.rand.nextInt(3);

 

            if (i == 0)

            {

                this.setCurrentItemOrArmor(0, new ItemStack(Block.sapling));

            }

            else

            {

                this.setCurrentItemOrArmor(0, new ItemStack(Block.plantRed));

            }

        }

    }

 

@Override

public EntityAgeable createChild(EntityAgeable entityageable) {

// TODO Auto-generated method stub

return null;

}

 

/*@Override

public boolean getCanSpawnHere()

    {

float f = 8.0F;

        List list;

        int i;

       

 

            list = this.worldObj.getEntitiesWithinAABB(EntityForestWalker.class, this.boundingBox.expand((double)f, (double)f, (double)f));

 

            if (list.size() > 0){

            return false;

            }

            else

            {

            return true;

            }

 

    }  */

}

 

 

Render:

 

package runes.Runes;

 

import net.minecraft.block.Block;

import net.minecraft.client.model.ModelBase;

import net.minecraft.client.model.ModelIronGolem;

import net.minecraft.client.model.ModelQuadruped;

import net.minecraft.client.renderer.OpenGlHelper;

import net.minecraft.client.renderer.entity.RenderLiving;

import net.minecraft.client.renderer.texture.TextureMap;

import net.minecraft.entity.Entity;

import net.minecraft.entity.EntityLiving;

import net.minecraft.entity.EntityLivingBase;

import net.minecraft.entity.monster.EntityEnderman;

import net.minecraft.entity.monster.EntityIronGolem;

import net.minecraft.entity.passive.EntityMooshroom;

import net.minecraft.util.ResourceLocation;

 

import org.lwjgl.opengl.GL11;

import org.lwjgl.opengl.GL12;

 

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

@SideOnly(Side.CLIENT)

public class RenderEnt extends RenderLiving

{

/** Iron Golem's Model. */

    protected ModelEnt model;

 

    public RenderEnt(ModelEnt par1model, float f)

    {

        super(par1model, f);

        model = (ModelEnt)mainModel;

    }

 

    public void doRenderEnt(EntityForestWalker par1EntityEnt, double par2, double par4, double par6, float par8, float par9)

    {

    this.model.isCarrying = par1EntityEnt.getCarried() > 0;

        super.doRenderLiving(par1EntityEnt, par2, par4, par6, par8, par9);

    }

 

    /**

    * Rotates Iron Golem corpse.

    */

    protected void rotateEntCorpse(EntityForestWalker par1EntityEnt, float par2, float par3, float par4)

    {

        super.rotateCorpse(par1EntityEnt, par2, par3, par4);

 

        if ((double)par1EntityEnt.limbSwingAmount >= 0.01D)

        {

            float f3 = 13.0F;

            float f4 = par1EntityEnt.limbSwing - par1EntityEnt.limbSwingAmount * (1.0F - par4) + 6.0F;

            float f5 = (Math.abs(f4 % f3 - f3 * 0.5F) - f3 * 0.25F) / (f3 * 0.25F);

            GL11.glRotatef(6.5F * f5, 0.0F, 0.0F, 1.0F);

        }

    }

 

    protected void renderEntEquippedItems(EntityForestWalker par1EntityEnt, float par2)

    {

        super.renderEquippedItems(par1EntityEnt, par2);

 

        this.bindTexture(TextureMap.locationBlocksTexture);

            GL11.glEnable(GL11.GL_CULL_FACE);

            GL11.glPushMatrix();

            GL11.glScalef(1.0F, -1.0F, 1.0F);

            GL11.glTranslatef(0.2F, 0.4F, 0.5F);

            GL11.glRotatef(42.0F, 50.0F, 1.0F, 0.0F); //Second Float changes X axis Tilt

            this.renderBlocks.renderBlockAsItem(Main.ForestWalkerSapling, 0, 1.0F);

            GL11.glTranslatef(0.1F, 0.0F, -0.6F);

            GL11.glRotatef(42.0F, 0.0F, 1.0F, 0.0F);

            this.renderBlocks.renderBlockAsItem(Main.ForestWalkerSapling, 0, 1.0F);

            GL11.glPopMatrix();

            GL11.glPushMatrix();

            GL11.glScalef(1.0F, -1.0F, 1.0F);

            GL11.glTranslatef(0.0F, 0.75F, -0.2F);

            GL11.glRotatef(12.0F, 0.0F, 1.0F, 0.0F);

            //this.renderBlocks.renderBlockAsItem(TutorialMod.SilverSapling, 0, 1.0F);

            GL11.glPopMatrix();

            GL11.glDisable(GL11.GL_CULL_FACE);

    }

   

    protected void renderCarrying(EntityForestWalker par1EntityEnt, float par2)

    {

        super.renderEquippedItems(par1EntityEnt, par2);

 

        if (par1EntityEnt.getCarried() > 0)

        {

            GL11.glEnable(GL12.GL_RESCALE_NORMAL);

            GL11.glPushMatrix();

            float f1 = 0.5F;

            GL11.glTranslatef(0.0F, 0.6875F, -0.75F);

            f1 *= 1.0F;

            GL11.glRotatef(20.0F, 1.0F, 0.0F, 0.0F);

            GL11.glRotatef(45.0F, 0.0F, 1.0F, 0.0F);

            GL11.glScalef(-f1, -f1, f1);

            int i = par1EntityEnt.getBrightnessForRender(par2);

            int j = i % 65536;

            int k = i / 65536;

            OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);

            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);

            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);

            this.bindTexture(TextureMap.locationBlocksTexture);

            this.renderBlocks.renderBlockAsItem(Block.blocksList[par1EntityEnt.getCarried()], par1EntityEnt.getCarryingData(), 1.0F);

            GL11.glPopMatrix();

            GL11.glDisable(GL12.GL_RESCALE_NORMAL);

        }

    }

 

    public void doRenderLiving(EntityLiving par1EntityLiving, double par2, double par4, double par6, float par8, float par9)

    {

        this.doRenderEnt((EntityForestWalker)par1EntityLiving, par2, par4, par6, par8, par9);

    }

 

    protected void renderEquippedItems(EntityLivingBase par1EntityLivingBase, float par2)

    {

        this.renderEntEquippedItems((EntityForestWalker)par1EntityLivingBase, par2);

        this.renderCarrying((EntityForestWalker)par1EntityLivingBase, par2);

    }

   

    protected void rotateCorpse(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4)

    {

        this.rotateEntCorpse((EntityForestWalker)par1EntityLivingBase, par2, par3, par4);

    }

 

    public void renderPlayer(EntityLivingBase par1EntityLivingBase, double par2, double par4, double par6, float par8, float par9)

    {

        this.doRenderEnt((EntityForestWalker)par1EntityLivingBase, par2, par4, par6, par8, par9);

    }

 

    /**

    * Actually renders the given argument. This is a synthetic bridge method, always casting down its argument and then

    * handing it off to a worker function which does the actual work. In all probabilty, the class Render is generic

    * (Render<T extends Entity) and this method has signature public void doRender(T entity, double d, double d1,

    * double d2, float f, float f1). But JAD is pre 1.5 so doesn't do that.

    */

    @Override

    public void doRender(Entity par1Entity, double par2, double par4, double par6, float par8, float par9)

    {

        this.doRenderEnt((EntityForestWalker)par1Entity, par2, par4, par6, par8, par9);

    }

 

@Override

protected ResourceLocation getEntityTexture(Entity entity) {

return new ResourceLocation("runes:textures/armor/Ent.png");

}

}

 

Model:

 

package runes.Runes;

 

import net.minecraft.client.model.ModelBase;

import net.minecraft.client.model.ModelIronGolem;

import net.minecraft.client.model.ModelRenderer;

import net.minecraft.entity.Entity;

import net.minecraft.entity.EntityLiving;

import net.minecraft.entity.EntityLivingBase;

import net.minecraft.entity.monster.EntityIronGolem;

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

@SideOnly(Side.CLIENT)

public class ModelEnt extends ModelBase

{

public boolean isCarrying;

 

/** The head model for the iron golem. */

    public ModelRenderer ironGolemHead;

 

    /** The body model for the iron golem. */

    public ModelRenderer ironGolemBody;

 

    /** The right arm model for the iron golem. */

    public ModelRenderer ironGolemRightArm;

 

    /** The left arm model for the iron golem. */

    public ModelRenderer ironGolemLeftArm;

 

    /** The left leg model for the Iron Golem. */

    public ModelRenderer ironGolemLeftLeg;

 

    /** The right leg model for the Iron Golem. */

    public ModelRenderer ironGolemRightLeg;

 

    public ModelEnt()

    {

        this(0.0F);

    }

 

    public ModelEnt(float par1)

    {

        this(par1, -7.0F);

    }

 

    public ModelEnt(float par1, float par2)

    {

        short short1 = 128;

        short short2 = 128;

        this.ironGolemHead = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.ironGolemHead.setRotationPoint(0.0F, 0.0F + par2, -2.0F);

        this.ironGolemHead.setTextureOffset(0, 0).addBox(-4.0F, -12.0F, -5.5F, 8, 10, 8, par1);

        this.ironGolemHead.setTextureOffset(24, 0).addBox(-1.0F, -5.0F, -7.5F, 2, 4, 2, par1);

        this.ironGolemBody = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.ironGolemBody.setRotationPoint(0.0F, 0.0F + par2, 0.0F);

        this.ironGolemBody.setTextureOffset(0, 40).addBox(-9.0F, -2.0F, -6.0F, 18, 12, 11, par1);

        this.ironGolemBody.setTextureOffset(0, 70).addBox(-4.5F, 10.0F, -3.0F, 9, 5, 6, par1 + 0.5F);

        this.ironGolemRightArm = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.ironGolemRightArm.setRotationPoint(0.0F, -7.0F, 0.0F);

        this.ironGolemRightArm.setTextureOffset(60, 21).addBox(-13.0F, -2.5F, -3.0F, 4, 30, 6, par1);

        this.ironGolemLeftArm = (new ModelRenderer(this)).setTextureSize(short1, short2);

        this.ironGolemLeftArm.setRotationPoint(0.0F, -7.0F, 0.0F);

        this.ironGolemLeftArm.setTextureOffset(60, 58).addBox(9.0F, -2.5F, -3.0F, 4, 30, 6, par1);

        this.ironGolemLeftLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);

        this.ironGolemLeftLeg.setRotationPoint(-4.0F, 18.0F + par2, 0.0F);

        this.ironGolemLeftLeg.setTextureOffset(37, 0).addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);

        this.ironGolemRightLeg = (new ModelRenderer(this, 0, 22)).setTextureSize(short1, short2);

        this.ironGolemRightLeg.mirror = true;

        this.ironGolemRightLeg.setTextureOffset(60, 0).setRotationPoint(5.0F, 18.0F + par2, 0.0F);

        this.ironGolemRightLeg.addBox(-3.5F, -3.0F, -3.0F, 6, 16, 5, par1);

    }

 

    /**

    * Sets the models various rotation angles then renders the model.

    */

    public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7)

    {

        this.setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity);

        this.ironGolemHead.render(par7);

        this.ironGolemBody.render(par7);

        this.ironGolemLeftLeg.render(par7);

        this.ironGolemRightLeg.render(par7);

        this.ironGolemRightArm.render(par7);

        this.ironGolemLeftArm.render(par7);

    }

 

    /**

    * Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms

    * and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how

    * "far" arms and legs can swing at most.

    */

    public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity)

    {

        this.ironGolemHead.rotateAngleY = par4 / (180F / (float)Math.PI);

        this.ironGolemHead.rotateAngleX = par5 / (180F / (float)Math.PI);

        this.ironGolemLeftLeg.rotateAngleX = -1.5F * this.func_78172_a(par1, 13.0F) * par2;

        this.ironGolemRightLeg.rotateAngleX = 1.5F * this.func_78172_a(par1, 13.0F) * par2;

        this.ironGolemLeftLeg.rotateAngleY = 0.0F;

        this.ironGolemRightLeg.rotateAngleY = 0.0F;

    }

 

    /**

    * Used for easily adding entity-dependent animations. The second and third float params here are the same second

    * and third as in the setRotationAngles method.

    */

    public void setLivingAnimations(EntityLivingBase par1EntityLivingBase, float par2, float par3, float par4)

    {

        EntityForestWalker entityforestwalker = (EntityForestWalker)par1EntityLivingBase;

        int i = entityforestwalker.getAttackTimer();

 

        if (i > 0)

        {

            this.ironGolemRightArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);

            this.ironGolemLeftArm.rotateAngleX = -2.0F + 1.5F * this.func_78172_a((float)i - par4, 10.0F);

        }

        else

        {

            if (this.isCarrying)

            {

            this.ironGolemRightArm.rotateAngleX = -0.5F;

                this.ironGolemLeftArm.rotateAngleX = -0.5F;

                this.ironGolemRightArm.rotateAngleZ = 0.05F;

                this.ironGolemLeftArm.rotateAngleZ = -0.05F;

            }

            else

            {

                this.ironGolemRightArm.rotateAngleX = (-0.2F + 1.5F * this.func_78172_a(par2, 13.0F)) * par3;

                this.ironGolemLeftArm.rotateAngleX = (-0.2F - 1.5F * this.func_78172_a(par2, 13.0F)) * par3;

            }

        }

    }

 

    private float func_78172_a(float par1, float par2)

    {

        return (Math.abs(par1 % par2 - par2 * 0.5F) - par2 * 0.25F) / (par2 * 0.25F);

    }

}

 

 

Main Registry and ClientProxy are exactly the same for both except for changes in name and ID of course.

 

 

 

Solved:

Well my first problem was in declaring the EntityRuneGolem variable as EntityRuneGolem in the Model class, but that wasn't causing the problem. I fixed it by adding in the holdRose methods back into the Entity and Model classes. Not sure why this was causing problems before.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.