When I try to spawn my mob using SPC doesn't appear and no errors appear. I had it appearing a few moments ago, but after I added the code to have a name appear above the mobs head it has stopped working
Here is the code:
EntityPigman:
package net.minecraft.src;
import java.util.List;
import java.util.Random;
public class EntityPigman extends EntityCreature
{
public EntityPigman(World world)
{
super(world);
angerLevel = 0;
texture = "/mob/mymob.png";
moveSpeed = 0.5F;
attackStrength = 5;
health = 10;
int aName = rand.nextInt(6);
myName = mobName[aName];
}
protected boolean canDespawn()
{
return false;
}
protected void attackEntity(Entity entity, float f)
{
if((double)f < 2.5D && entity.boundingBox.maxY > boundingBox.minY && entity.boundingBox.minY < boundingBox.maxY)
{
attackTime = 20;
entity.attackEntityFrom(this, attackStrength);
}
}
protected int getDropItemId()
{
//This is the item your mob will drop
return Item.porkCooked.shiftedIndex;
}
protected String getLivingSound()
{
return "mob.pig";
}
protected String getHurtSound()
{
return "mob.pighurt";
}
protected String getDeathSound()
{
return "mob.pighurt";
}
public void onUpdate()
{
moveSpeed = playerToAttack == null ? 0.5F : 0.95F;
super.onUpdate();
if(worldObj.difficultySetting == 0)
{
setEntityDead();
}
}
public boolean getCanSpawnHere()
{
if(worldObj.countEntities(this.getClass()) == 1){
return false;
}
int i = MathHelper.floor_double(posX);
int j = MathHelper.floor_double(boundingBox.minY);
int k = MathHelper.floor_double(posZ);
int l = worldObj.getBlockId(i, j - 1, k);
return worldObj.checkIfAABBIsClear(boundingBox) && worldObj.getCollidingBoundingBoxes(this, boundingBox).size() == 0 && worldObj.getBlockLightValue(i, j, k) > 8 && !worldObj.getIsAnyLiquid(boundingBox);
}
protected float getBlockPathWeight(int i, int j, int k)
{
return 0.0F;
}
public void writeEntityToNBT(NBTTagCompound nbttagcompound)
{
super.writeEntityToNBT(nbttagcompound);
nbttagcompound.setShort("Anger", (short)angerLevel);
}
public void readEntityFromNBT(NBTTagCompound nbttagcompound)
{
super.readEntityFromNBT(nbttagcompound);
angerLevel = nbttagcompound.getShort("Anger");
}
protected Entity findPlayerToAttack()
{
if(angerLevel == 0)
{
return null;
} else
{
return super.findPlayerToAttack();
}
}
public void onLivingUpdate()
{
super.onLivingUpdate();
}
public boolean attackEntityFrom(Entity entity, int i)
{
if(entity instanceof EntityPlayer)
{
List list = worldObj.getEntitiesWithinAABBExcludingEntity(this, boundingBox.expand(32D, 32D, 32D));
for(int j = 0; j < list.size(); j++)
{
Entity entity1 = (Entity)list.get(j);
if(entity1 instanceof EntityPigman)
{
EntityPigman entitypigman = (EntityPigman)entity1;
entitypigman.becomeAngryAt(entity);
}
}
becomeAngryAt(entity);
ModLoader.getMinecraftInstance().ingameGUI.addChatMessage("Die");
}
return super.attackEntityFrom(entity, i);
}
private void becomeAngryAt(Entity entity)
{
playerToAttack = entity;
angerLevel = 400 + rand.nextInt(400);
}
public boolean interact(EntityPlayer entityplayer)
{
// Increment message counter
messageCount++;
// Reset message counter if total reached
if (messageCount >= TOTAL_MESSAGES) {
messageCount = 0;
}
// If the last mob the player talked to is not this one, reset the counter
if (lastMobTalkedTo != entityId) {
lastMobTalkedTo = entityId;
messageCount = 0;
}
// Send message
ItemStack itemstack = entityplayer.inventory.getCurrentItem();
{
if(itemstack != null && itemstack.itemID == Item.bone.shiftedIndex)
{
if(itemstack.stackSize <= 0)
{
entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, null);
}
if(!worldObj.multiplayerWorld)
{
if(rand.nextInt(3) == 0)
{
ModLoader.getMinecraftInstance().ingameGUI.addChatMessage("This is a test 0");
}
}
} else
{
switch (messageCount) {
case 0:
ModLoader.getMinecraftInstance().ingameGUI.addChatMessage("This is a test 1");
break;
case 1:
ModLoader.getMinecraftInstance().ingameGUI.addChatMessage("This is a test 2");
break;
}
}
return true;
}
}
public int messageCount = 0;
public static int lastMobTalkedTo = -1;
public static final int TOTAL_MESSAGES = 2;
private int angerLevel;
protected int attackStrength;
protected String[] mobName = {"Tom"
};
public String myName;
}
mod_Pigman:
package net.minecraft.src;
import java.lang.reflect.Method;
import java.util.Map;
public class mod_Pigman extends BaseMod
{
public String Version()
{
return "mod_Pigman version 0.3";
}
public mod_Pigman()
{
ModLoader.RegisterEntityID(EntityPigman.class, "Pigman", ModLoader.getUniqueEntityId());
ModLoader.AddSpawn(EntityPigman.class, 8, EnumCreatureType.creature);
}
public void AddRenderer(Map map)
{
map.put(EntityPigman.class, new RenderPigman(new ModelBiped(), 0.5F));
}
}
p.s. How do I get my mob to spawn at a specific set of coords, move from one set of coords to another and give players items? Thank you in advance.
Edit: Just adding spoiler tags for code
Are you sure all you added was the renderLivingLabel code? Take it out and see if it comes back. Is it possible that the name is null? This might crash the render.
As to spawning at a specific spot, I do that with the spawn block. I spawn it at x, y, z. As to make it got to a spot, I'm still looking over some of the behavour stuff, so not there yet.
Sorry to be a bother maybe I'm not looking properly, but how would I check or how would I know if the text is null.
Again sorry for bothering you with this, it might be just simple thing I'm over looking.
The problem is that when you initialize your creature, you set an int randomly between 0 and 5 and then try to access your array mobName[] at that position. The array only has position 0, so when the int is set to anything above that you are going to get an ArrayOutOfBoundsException. Either add 5 more names to the mobName array (so that you can never go out of bounds), or take out the random int line and make
Thank you for replaying
I changed the code as you suggested, but still the name doesn't appear above the mobs head.
This is where I changed the code :
Should I change anything here or just leave it as it is?
Thank you.
Other than that original error, I don't know much about displaying text above a creature's head. But looking into the RenderPigman file, I believe that:
Since you don't override it in the RenderPigman file, you need to tell the program where to look for the renderLivingLabel function, which is in the super class. If that doesn't fix it, i'm not sure what the problem is.
Also, if that doesn't solve it, try just putting the string "Tom" into the string parameter of the renderLivingLabel call. If it still doesn't work, then there is something wrong with the way you are using that specific function.
}
public int messageCount = 0;
public static int lastMobTalkedTo = -1;
public static final int TOTAL_MESSAGES = 2;
private int angerLevel;
protected int attackStrength;
protected String[] mobName = {"Tom"};
public String myName;
}
Should I change anything here or just leave it as it is?
Thank you.
Let's start by just setting myName = "A Name"; in your constructor, forget the random name code. One step at a time, or it will be difficult to pin point logic errors in code.
Egnore the JWingFlapper(); call, it's a custom animation for wing flaps. Ok, not a null check (not sure if I can do that with strings, but I check that the length is defined as greater than 0).
incase more refrence is needed the whole render code is:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
UPDATED 8/23/2011 - 9:50pm EST
Ok, people have been asking me about this, so I am going to post my (not finished yet, but working) code for my tameable mobs. These super class (when you want this functionality, have your entity class extend this one) will allow you to tame mobs, rename them (you will have to do your own render code for like my last post if you want the names to show), mount them, and have them follow you around (as long as you don't get too far). I'm going to try and past only the code that is finished. I still need to do the save stuff, so the stats and such stay with (tame, owned) mobs, as well as the hostile code, and hopefully the pack animal code. That means that this thread will change several times. I will post what is working, and what is in the works. That said,
inLanoche's Tamable Entity class V0.7
Please read the whole post. Features:
- tamable when given favourite item. mood boost can be defined, as well as mood needed to tame. Most other features require taming (but this can be overrided) COMPLETE
- Once tamed, GUI interface when interacting with the mob. COMPLETE
- Can name/rename through GUI. COMPLETE
- Toggle for mountable. Can also depend on having an item in hand. Item is not consumed, may change to item is in iventory, istead of having to be equiped. COMPLETE
- Toggle follow/don't follow behaviour through GUI. Mob must be within range, and can see you, or will stop following. COMPLETE
- Various levels of hostility, from doesn't attack, to attacks only players, to attacks anything that moves. Might also work in that it attacks one specific mob type only (hunting). INCOMPLETE
- Make it attack monster type mobs when tamed, can set the attack strength. INCOMPLETE
- Can set it's carry capacity, and through GUI can get to it's inventory menu. COMPLETE - Thanks to killNature!
- Flying or not flying - Might drop this, as it seems quite easy to add this in the sub class. I could just add a sub to this for flying and release that as well, with customizable wing flapping.
- Usable age. Can be used to scale the model, as well as allow for beging ridable after a certain age. COMPLETE
- Saving/Loading of Tamed mobs and their stats INCOMPLETE WIP
- Patroling an area (4 waypoints) COMPLETE - Thanks to McDog3!
Thems the features,for now. Here is a taste of the (not complete yet) code. I've tried to comment so that you can make your own changes in your sub class, and do what you want.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
/*JWorld_TamableEntiy class
* 19 Aug 2011
* http://www.minecraftforum.net/topic/529327-modloader-adding-custom-mobs-and-more/
*
* NEEDED support java files:
* JWorldGUICreatureInteract.java, JWorld_TamableRender.java, KeyBinding in your main mod_ java file.
*/
package net.minecraft.src;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import net.minecraft.client.Minecraft;
// Referenced classes of package net.minecraft.src:
// EntityAnimal, World, Item, NBTTagCompound
public class JWorld_TamableEntity extends EntityAnimal
{
//fields that are needed for all tameable mobs. Tie in to tameable menus
public String entityType; //used for the menus and other checks
public int hostile; //if the mob will attack other mobs or not. -1 not hostile, 0 attacks player only, 1 attacks any other mob
public String ownerName; //String name for the owner, if it is the player
public int mountable; //flag to see if you can mount this mob. -2 means never, 0 means need item, 1 means yes.
public int favItem; //What they like (to tame them) set the to -1 for no possible taming
public int favBoost; //how much it boosts the mood
public int mood; //how happy it is. When mood exceeds tamemood, the mob is tamed
public int tamemood; //how much mood needed to tame it
public int MountItem; //What is needed to mount them
public String myName; //if it's tamed you can name it
public boolean fly; //flag for if this mob can fly
public boolean leap; //used for flying mount control
public int myAge; //age of the mob, only really tracked in tamed mobs
public int maxAge; //age when full size
public float maxSpeed; //as fast as it goes normally
public int attackStrength; //how much damage this inflicts when it attacks. Can be scaled by age
public int maxStrength; //basic str. value
private World worldObj;
public float sizeX;
public float sizeY;
public boolean hasHead;
public static String behaveList[] = {"None", "Follow", "Defend", "Hunt", "HuntPlayer"}; //behaviors that can be set
public int myBehavior = 0;
public JWorld_TamableEntity(World world)
{
super(world);
sizeX = 1F; //set and do not change!
sizeY = 1F; //set and do not change!
texture = "/mob/char.png"; //texture needs to be set in sub class
setSize(sizeX, sizeY); //USE sizeX and sizeY to initialize this!
health = 10; //keep defaults
maxSpeed = 1.5F; //basic unmodified speed
moveSpeed = maxSpeed;
worldObj = world; //get the world object
//***set vars for tamable mobs***
entityType = ""; //set in sub class, bread name of creature
hostile = -1; //will it attack the player/other mobs or not.
ownerName = ""; //needed for finding player by owner
mountable = -2; //default to not possible
favItem = -1; //leave it negative, meaning not possible to tame. Based on Item.shiftedIndex
favBoost = 1; //default boost of 1 to mood.
mood = 0; //negative is angry, positive is happy. 10 will tame?
tamemood = 10; //how much needed to tame it
MountItem = -1; //-1 means no item needed if mountable. Based on Item.shiftedIndex
myName = ""; //Leave it un-named to not render name tag.
fly = false; //can it fly or not
leap = false; //for flying mounts
myAge = 1; //can be used for scaling and other age related code
maxAge = 10; //age when fully grown (can be older)
attackStrength = 2; //base attack strength, can be modified by age
inventory = new JWorld_TamableInventory(this);
}
//START:Age and scaling code-------------------------------------------------
public float getAgeScale()
{
//this will return a scale value that can be passed to the render java file to set a scale by age
//this should also be applied to setSize to fix bounding box. Not used by default
//Set the age scale yourself! These are my defaults
int age = getAge();
float scaler = 1F;
scaler = (float)age/(float)maxAge;
if(scaler <= 0.5) //set minimum scale factor
{
return 0.5F;
}
if(scaler <= 0.9) //medium size scale factor
{
return 0.75F;
}
return 1.25F; //if not then full size
}
public void updateAge()
{
//should be run every time the age is updated to fix speed, bounding box, etc.
float aScale = getAgeScale(); //how much to scale based on myAge vs maxAge
setSize(sizeX*aScale,sizeY*aScale); //the only way the size should change, do not adjust sizeX and sizeY after constructor
moveSpeed = maxSpeed*aScale; //scale movement to size
attackStrength = (int)(maxStrength * aScale);
if(attackStrength < 1) attackStrength = 1; //cannot be less that 1
}
//END:Age and scaling code-----------------------------------------------------
protected boolean canDespawn()
{
if(ownerName != "") //means it's owned
{
return true; //means should stay in the game
}
return true; //else... see ya!
}
//START:Inventory code-----------------------------------------------------------
public JWorld_TamableInventory inventory; //inventory object for tamable pack animals
public void openInventory(EntityPlayer theplayer)
{
ModLoader.OpenGUI(theplayer, new JWorld_TamableInvGui(theplayer, this));
}
public void onDeath(Entity entity) //when mob dies
{
inventory.dropAllItems(); // when dead drop all inventory! **
super.onDeath(entity);
}
//END:Inventory code-----------------------------------------------------------
//START: Update code. Put stuff here that needs to be constantly checked-----------------
public void onLivingUpdate()
{
//Halting movement if ridden
if(riddenByEntity != null) //ridden overrides all
{
//halt attempts to move or look around, reset behavior
setBehavior(0);
moveStrafing = 0;
moveForward = 0;
randomYawVelocity = 0;
defaultPitch = 0;
this.rotationYaw = this.prevRotationYaw; // keep head straight
this.rotationPitch = 0; // keep head straight
if(riddenByEntity.rotationYaw < (riddenByEntity.prevRotationYaw - 45) || riddenByEntity.rotationYaw > (riddenByEntity.prevRotationYaw + 45))
{
rotationYaw = riddenByEntity.rotationYaw;
}
//mod_JWorld.mountYaw = this.rotationYaw; //inLanoche's test code
}else//end of riding code
{
//mod_JWorld.mountYaw = 0; //inLanoche's test code
//manage what each behavior level does
if(getBehavior() == 1) Following();
if(getBehavior() == 2) DefendHere();
//standard movement stuff below
if(newPosRotationIncrements > 0)
{
double d = posX + (newPosX - posX) / (double)newPosRotationIncrements;
double d1 = posY + (newPosY - posY) / (double)newPosRotationIncrements;
double d2 = posZ + (newPosZ - posZ) / (double)newPosRotationIncrements;
double d3;
for(d3 = newRotationYaw - (double)rotationYaw; d3 < -180D; d3 += 360D) { }
for(; d3 >= 180D; d3 -= 360D) { }
rotationYaw += d3 / (double)newPosRotationIncrements;
rotationPitch += (newRotationPitch - (double)rotationPitch) / (double)newPosRotationIncrements;
newPosRotationIncrements--;
setPosition(d, d1, d2);
setRotation(rotationYaw, rotationPitch);
List list1 = worldObj.getCollidingBoundingBoxes(this, boundingBox.contract(0.03125D, 0.0D, 0.03125D));
if(list1.size() > 0)
{
double d4 = 0.0D;
for(int j = 0; j < list1.size(); j++)
{
AxisAlignedBB axisalignedbb = (AxisAlignedBB)list1.get(j);
if(axisalignedbb.maxY > d4)
{
d4 = axisalignedbb.maxY;
}
}
d1 += d4 - boundingBox.minY;
setPosition(d, d1, d2);
}
}
if(isMovementBlocked())
{
isJumping = false;
moveStrafing = 0.0F;
moveForward = 0.0F;
randomYawVelocity = 0.0F;
} else
if(!isMultiplayerEntity)
{
updateEntityActionState();
}
boolean flag = isInWater();
boolean flag1 = handleLavaMovement();
if(isJumping)
{
if(flag)
{
motionY += 0.039999999105930328D;
} else
if(flag1)
{
motionY += 0.039999999105930328D;
} else
if(onGround)
{
jump();
}
}
moveStrafing *= 0.98F;
moveForward *= 0.98F;
randomYawVelocity *= 0.9F;
}
//This below should stay the same
moveEntityWithHeading(moveStrafing, moveForward);
List list = worldObj.getEntitiesWithinAABBExcludingEntity(this, boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
if(list != null && list.size() > 0)
{
for(int i = 0; i < list.size(); i++)
{
Entity entity = (Entity)list.get(i);
if(entity.canBePushed())
{
entity.applyEntityCollision(this);
}
}
}
}
//END: Update code. Put stuff here that needs to be constantly checked-----------------
//START: Manage movement code------------------------------------------------------
protected boolean canTriggerWalking()
{
return false;
}
public void moveEntity(double d, double d1, double d2)
{
if(riddenByEntity != null)
{
isJumping = false; //seems to want to jump around by itself
rotationYaw = riddenByEntity.rotationYaw; //set rotation as you move.
if(leap)
{//have it fly up a bit
motionX += riddenByEntity.motionX*moveSpeed; //Should find a way to set this to normal mob speed
motionZ += riddenByEntity.motionZ*moveSpeed; //ditto
motionY += 1F;
leap = false;
}else
{//regular run on the ground movement
motionX += riddenByEntity.motionX*moveSpeed; //ditto
motionZ += riddenByEntity.motionZ*moveSpeed; //ditto
if(onGround)
{
motionY = 0; //for some reason it likes to hop
}
}
if(isCollidedHorizontally)
{
if(fly) //if it can fly
{
motionY += 0.15F; //allows it to drift up if you are hitting an obstacle in front of you
}else
{
if(onGround) //else not fly
{
jump(); //let it try to jump over obstacle
}
}
}
super.moveEntity(motionX, motionY, motionZ);
}else
{
super.moveEntity(d, d1, d2);
}
}
// from super super class Entity
public void updateRidden()
{
if(ridingEntity.isDead)//if rider is dead, drop it
{
ridingEntity = null;
return;
}
motionX = 0.0D; //set all movement to 0. Let player control it.
motionY = 0.0D;
motionZ = 0.0D;
onUpdate();
if(ridingEntity == null)
{
return;
}
ridingEntity.updateRiderPosition();
//cut a lot from the Entity.updateRidden
//test code:
}
//END: Manage movement code------------------------------------------------------
//START: Player interaction with mob-------------------------------------------
public boolean interact(EntityPlayer entityplayer)
{
ItemStack itemstack = entityplayer.inventory.getCurrentItem(); //see what the interacting player is holding
if(MountItem >= 0 && mountable != -2) //you need an item to mount
{
mountable = 0; //reset mountable in case an item is needed to mount. No cheating!
}
//if you have nothing, and it's not yours, nothing will happen
if(itemstack == null && !ownerName.equalsIgnoreCase(entityplayer.username))
{
return false;
}
//if riding, dismount, no matter what is in hand
if(riddenByEntity != null && riddenByEntity == entityplayer)
{
mountThis(entityplayer);
return true;
}
if(mountable == 0) //if you need an item to mount,
{
for(int j = 0; j < entityplayer.inventory.mainInventory.length; j++)
{
if(entityplayer.inventory.mainInventory[j] != null && entityplayer.inventory.mainInventory[j].itemID == MountItem)
{
mountable = 1;
break;
}
}
}
//if you have nothing, but own this mob, bring up the menu
if((itemstack == null) && ownerName.equalsIgnoreCase(entityplayer.username))
{
//one liner with ModLoader to open GUIs
ModLoader.OpenGUI(entityplayer, new JWorld_TamableGUIMenu(this, entityplayer));
}
//To tame it, you have to give it something it likes, and it can't be already owned, unless by you
if(itemstack != null && itemstack.itemID == favItem && (ownerName == "" || ownerName.equalsIgnoreCase(entityplayer.username)))
{
itemstack.stackSize--; //you give the item
if(itemstack.stackSize <= 0)
{
entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, null);
}
setMood(getMood() + favBoost); //boost its mood
if(getMood() >= tamemood) //check if you tamed it
{
setOwner(entityplayer.username);//need this for finding the player in the world
//should call naming GUI at this point
Minecraft mc = ModLoader.getMinecraftInstance();
ParticleFX("heart");
mc.displayGuiScreen(new JWorld_TamableGUIMenu(this, entityplayer)); //Should the GUI pop up the right now?
//maybe use just a naming GUI here...
return true;
}else
{
ParticleFX("note"); //it's happy it got something good
}
return true;
}
return false;
}
//END: Player interaction with mob-------------------------------------------
//START: Call to mount--------------------------------------------------------
public void mountThis(EntityPlayer entityplayer) //use this for mounting from GUI or direct mount
{
if (riddenByEntity == null || riddenByEntity == entityplayer)
{
rotationYaw = entityplayer.rotationYaw;
entityplayer.mountEntity(this); //climb on/get off
}
}
//END: Call to mount--------------------------------------------------------
//START: Behavior management code-----------------------------------------------------
private void Following()
{
float fRange = 18; //outside of follow range
EntityPlayer entityplayer = worldObj.getPlayerEntityByName(ownerName); //has to be done this way, no other method I know
if(entityplayer != null)
{
fRange = getDistanceToEntity(entityplayer);
if(fRange > 5F && fRange < 18F)
{
PathEntity pathentity = worldObj.getPathToEntity(this, entityplayer, 16F);
setPathToEntity(pathentity);
}else
{
setPathToEntity(null); //have it stop following if too close or out of range.
}
}
if(fRange > 18)
{
setPathToEntity(null); //Forget following, no path set.
setBehavior(0); //stop following when too far away
}
}
//track where the patrol path is for defending
private int defendX;
private int defendY;
private int defendZ;
public int nextPoint = 0;
private void DefendHere()
{
int deltaX = 0;
int deltaZ = 0;
if(nextPoint == 0) //waypoint not set yet
{
defendX = (int)posX;
defendY = (int)posY;
defendZ = (int)posZ;
nextPoint = 1;
//world.entityJoinedWorld(new EntityArrow(world, entityplayer));
}
switch(nextPoint)
{//should patrol a 16x16 square around the point where you asked it to defend
case 1: deltaX =-9; deltaZ = 9; break; //top left
case 2: deltaX = 9; deltaZ = 9; break; //top right
case 3: deltaX = 9; deltaZ =-9; break; //bottom right
case 4: deltaX =-9; deltaZ =-9; break; //bottom left
}
PathEntity patrolPath = worldObj.getEntityPathToXYZ(this,defendX+deltaX,defendY,defendZ+deltaZ,18F);
setPathToEntity(patrolPath);
if(Math.abs(posX -(deltaX + defendX)) <= 1 && Math.abs(posZ -(deltaZ + defendZ)) <= 1) nextPoint ++;
if(nextPoint > 4) nextPoint = 1;
}
//END: Behavior management code-----------------------------------------------------
//START: File handling code-------------------------------------------------------
//these need to be used to save tamed/owned creatures - in progress...
protected void entityInit()
{
super.entityInit();
//dataWatcher.addObject(16, Byte.valueOf((byte)0));
dataWatcher.addObject(17, ""); //held for the owner's name
dataWatcher.addObject(18, new Integer(health)); //store current health?
dataWatcher.addObject(19, new Integer(mood)); //store mood - marks if it is tame
dataWatcher.addObject(20, new Integer(myAge));
dataWatcher.addObject(21, new Integer(myBehavior));
}
//Guess should be following this?
public String getOwner()
{
return dataWatcher.getWatchableObjectString(17);
}
public void setOwner(String s)
{
dataWatcher.updateObject(17, s);
ownerName = s;
}
public int getMood()
{
return dataWatcher.getWatchableObjectInt(19);
}
public void setMood(int newmood)
{
dataWatcher.updateObject(19, Integer.valueOf(newmood));
}
public int getAge()
{
return dataWatcher.getWatchableObjectInt(20);
}
public void setAge(int newage)
{
dataWatcher.updateObject(20, Integer.valueOf(newage));
}
public int getBehavior()
{
return dataWatcher.getWatchableObjectInt(21);
}
public void setBehavior(int i)
{
myBehavior = i;
dataWatcher.updateObject(21, Integer.valueOf(myBehavior));
}
public void writeEntityToNBT(NBTTagCompound nbttagcompound)
{
super.writeEntityToNBT(nbttagcompound);
if(getOwner() == "")
{
nbttagcompound.setString("Owner", "");
} else
{
nbttagcompound.setString("Owner", getOwner());
nbttagcompound.setTag("Inventory", inventory.writeToNBT(new NBTTagList())); // it writes the inventory to file
nbttagcompound.setInteger("Mood", getMood());
nbttagcompound.setInteger("Age", getAge());
if(!this.isDead)
{
nbttagcompound.setInteger("myX", (int)posX);
nbttagcompound.setInteger("myY", (int)posY);
nbttagcompound.setInteger("myZ", (int)posZ);
}
}
}
public void readEntityFromNBT(NBTTagCompound nbttagcompound)
{
super.readEntityFromNBT(nbttagcompound);
String s = nbttagcompound.getString("Owner");
if(s.length() > 0)
{
setOwner(s);
//EntityPlayer theplayer = worldObj.getPlayerEntityByName(s);
//owner = theplayer.entityId; //set the id owner
NBTTagList nbttaglist = nbttagcompound.getTagList("Inventory"); // must read inventory
inventory.readFromNBT(nbttaglist);
setMood(nbttagcompound.getInteger("Mood"));
setAge(nbttagcompound.getInteger("Age"));
updateAge();
posX = (double)nbttagcompound.getInteger("myX");
posY = (double)nbttagcompound.getInteger("myY");
posZ = (double)nbttagcompound.getInteger("myZ");
}
}
//inLanoche's attempts at save code with DataSaver class
protected void saveEntity()
{
}
protected void loadEntity()
{
}
//END: File handling code------------------------------------------------------
//START: Audio sounds----------------------------------------------------------
protected String getLivingSound()
{
return "mob.chicken";
}
protected String getHurtSound()
{
return "mob.chickenhurt";
}
protected String getDeathSound()
{
return "mob.chickenhurt";
}
//END: Audio sounds----------------------------------------------------------
protected int getDropItemId()
{
return 0; //set what this drops when it dies
}
//Used for Particle effect when tamed or other particles.
public static ArrayList particleList = new ArrayList();
void ParticleFX(String fx)
{
//these are found in RenderGlobal.java
particleList.add("heart");
particleList.add("smoke");
particleList.add("splash");
particleList.add("note");
particleList.add("flame");
particleList.add("bubble");
String s = fx;
if(particleList.indexOf(fx) < 0)
{
return; //passed an improper particle type and do nothing
}
for(int i = 0; i < 7; i++)
{
double d = rand.nextGaussian() * 0.02D;
double d1 = rand.nextGaussian() * 0.02D;
double d2 = rand.nextGaussian() * 0.02D;
worldObj.spawnParticle(s, (posX + (double)(rand.nextFloat() * width * 2.0F)) - (double)width, posY + 0.5D + (double)(rand.nextFloat() * height), (posZ + (double)(rand.nextFloat() * width * 2.0F)) - (double)width, d, d1, d2);
}
}
}
UPDATED 8/30/2011 - 3:45pm EST
Some class names have changed!
Data saving is almost there. This is a major overhaul of the code, though for the most part should not affect classes that extend this. I have made changes to ALL the support files as well. ***Special thanks to McDog3 helping with the now working Patrol code!
SUPPORT FILES FOR TAMBABLE CLASS
These files are needed to run the complete Tamable entity class. Feel free to pick and chose the features you want. I will try and seperate them as much as possible, including the variable defs.
JWorld_TamableGUIMenu.java GUI class - Name has changed!
This is the interaction GUI once the mob is tamed.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
package net.minecraft.src;
import java.util.List;
import net.minecraft.client.Minecraft;
// Referenced classes of package net.minecraft.src:
// GuiScreen, GuiButton, StatCollector, GuiOptions,
// StatList, StatFileWriter, World, GuiMainMenu,
// GuiAchievements, GuiStats, MathHelper
// Code taken from GuiIngameMenu.java
public class JWorld_TamableGUIMenu extends GuiScreen
{
public JWorld_TamableGUIMenu(JWorld_TamableEntity entity, EntityPlayer player)
{
//pass the x,y and z of the spawn block being activated, so we can spawn above it
updateCounter2 = 0;
updateCounter = 0;
theplayer = player;
themob = entity;
}
public boolean doesGuiPauseGame()
{
return true; //make sure the game pauses with this interaction?
}
public void CloseGUI()
{
//use this to close out the GUI, too much repeat code in buttons
themob.myName = textBox.getText();
mc.displayGuiScreen(null);
mc.setIngameFocus();
return;
}
public void initGui()
{
updateCounter2 = 0;
controlList.clear();
byte byte0 = -16;
int yShift = 24;
controlList.add(new GuiButton(0, width / 2 - 100, height / 5 + yShift + byte0, 98, 20, "Back to game"));
controlList.add(new GuiButton(10, width / 2 + 2, height / 5 + yShift + byte0, 98, 20, "Rename :"));
//yShift += 24; //don't shift before textbox, but double shift after
textBox = new GuiTextField(this, fontRenderer, width / 2 - 100,height / 5 + yShift + 8, 200, 20, themob.myName);
textBox.isFocused = true;
textBox.setMaxStringLength(32);
textBox.setText(themob.myName);
yShift += 48; //shift for Text box is different
if(themob.mountable > 0 && themob.getAge() >= themob.maxAge) //must be mountable and old enough
{
controlList.add(new GuiButton(1, width / 2 - 100, height / 5 + yShift + byte0, "Mount"));
yShift += 24;
}
controlList.add(new GuiButton(3, width / 2 - 100, height / 5 + yShift + byte0, "Open Inventory"));
yShift += 24;
controlList.add(new GuiButton(4, width / 2 - 100, height / 5 + yShift + byte0, "Behavior:"+themob.behaveList[themob.myBehavior]));
yShift += 24;
//test code, not for final product!
controlList.add(new GuiButton(20, width / 2 - 100, height / 5 + yShift + byte0, "Increase Age by 2("+themob.getAge()+")"));
yShift += 24;
//end of test code
}
protected void actionPerformed(GuiButton guibutton)
{
if(guibutton.id == 0)
{
CloseGUI(); }
if(guibutton.id == 10)
{
//mc.displayGuiScreen(new GuiRenameWorld(this, themob.myName));
themob.myName = textBox.getText();
updateScreen(); //CloseGUI();
return;
}
if(guibutton.id == 1)
{
themob.mountThis(theplayer);
CloseGUI();
}
if(guibutton.id == 3)
{
CloseGUI();
themob.openInventory(theplayer);//and start the player to mob Inv. GUI
return;
}
if(guibutton.id == 4)
{
themob.nextPoint = 0; //reset defense spot if you toggle behavior
int i = themob.getBehavior(); //get current behavior
i += 1; //increase it
if(i >= themob.behaveList.length) i = 0; //make sure it's withing the bounds of the list
themob.setBehavior(i); //set it.
guibutton.displayString = "Behavior:"+themob.behaveList[themob.myBehavior]; //update the button label
}
//test code
if(guibutton.id == 20)
{
themob.setAge(themob.getAge() + 2); //test adding to age to see changes
themob.updateAge(); //run the age updater when age changes
CloseGUI();
return;
}
}
protected void keyTyped(char c, int i)
{
textBox.textboxKeyTyped(c, i);
//((GuiButton)controlList.get(0)).enabled = textBox.getText().trim().length() > 0;
if(c == '\r')
{
actionPerformed((GuiButton)controlList.get(0));
}
}
protected void mouseClicked(int i, int j, int k)
{
super.mouseClicked(i, j, k);
textBox.mouseClicked(i, j, k);
}
public void updateScreen()
{
super.updateScreen();
updateCounter++;
}
public void drawScreen(int i, int j, float f)
{
drawDefaultBackground();
boolean flag = !mc.theWorld.func_650_a(updateCounter2++);
if(flag || updateCounter < 20)
{
float f1 = ((float)(updateCounter % 10) + f) / 10F;
f1 = MathHelper.sin(f1 * 3.141593F * 2.0F) * 0.2F + 0.8F;
int k = (int)(255F * f1);
drawString(fontRenderer, "Saving level..", 8, height - 16, k << 16 | k << 8 | k);
}
textBox.drawTextBox();
drawCenteredString(fontRenderer, "'"+themob.ownerName +"'"+ "'s " + themob.entityType, width / 2, 20, 0xffffff);
drawCenteredString(fontRenderer, themob.myName + "("+themob.getMood()+") interacted by "+"'"+theplayer.username+"'", width / 2, 30, 0xffffff);
super.drawScreen(i, j, f);
}
private int updateCounter2;
private int updateCounter;
private EntityPlayer theplayer;
private JWorld_TamableEntity themob;
private GuiTextField textBox;
}
JWorld_TamableInvGui.java GUI class
This is the inventory interaction window GUI. To use this, I have modifed the trap.png file (which is similar to the one killNature posted) HERE. If you copy/paste my code, make sure to use the same mods folder to store this file both in the MCP temp folder, and in the minecraft.jar file.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
package net.minecraft.src;
import net.minecraft.client.Minecraft;
import org.lwjgl.opengl.GL11;
// Referenced classes of package net.minecraft.src:
// GuiContainer, ContainerChest, IInventory, FontRenderer,
// RenderEngine
public class JWorld_TamableInvGui extends GuiContainer
{
private EntityPlayer theplayer;
private JWorld_TamableEntity themob;
public JWorld_TamableInvGui(EntityPlayer p, JWorld_TamableEntity m)
{
super(new JWorld_TamableContainer(p.inventory, m.inventory));
theplayer = p;
themob = m;
}
protected void drawGuiContainerForegroundLayer()
{
fontRenderer.drawString(themob.myName +" Inventory", 52, 6, 0x404040); // name of inventory displaced on top
fontRenderer.drawString(theplayer.username + "'s Inventory", 8, (ySize - 96) + 2, 0x404040);
String s = "Press 'E' to close";
fontRenderer.drawString(s, 39, ySize + 1, 0x555555);
fontRenderer.drawString(s, 40, ySize + 2, 0xffffff);
}
protected void drawGuiContainerBackgroundLayer(float f)
{
int i = mc.renderEngine.getTexture("/mods/TamableInv.png"); //place for inventory texture
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.renderEngine.bindTexture(i);
int j = (width - xSize) / 2;
int k = (height - ySize) / 2;
drawTexturedModalRect(j, k, 0, 0, xSize, ySize + 24);
}
public boolean doesGuiPauseGame()
{
return true;
}
}
JWorld_TamableInventory.java inventory class
Still getting to know this class. Will post more info in the future. For the most part, just leave it as is, unless you know better. I don't.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
package net.minecraft.src;
import java.util.List;
// Referenced classes of package net.minecraft.src:
// IInventory, ItemStack, IInvBasic, EntityPlayer
public class JWorld_TamableInventory
implements IInventory
{
public JWorld_TamableInventory(JWorld_TamableEntity entity)
{
inventory = new ItemStack[9]; //how many items it can hold
armorInventory = new ItemStack[1]; //Not sure I need this...
inventoryChanged = false;
ent = entity; //pass the entity class
}
private int getInventorySlotContainItem(int i)
{
for(int j = 0; j < inventory.length; j++)
{
if(inventory[j] != null && inventory[j].itemID == i)
{
return j;
}
}
return -1;
}
public int storeItemStack(ItemStack itemstack)
{
for(int i = 0; i < inventory.length; i++)
{
if(inventory[i] != null && inventory[i].itemID == itemstack.itemID && inventory[i].isStackable() && inventory[i].stackSize < inventory[i].getMaxStackSize() && inventory[i].stackSize < getInventoryStackLimit() && (!inventory[i].getHasSubtypes() || inventory[i].getItemDamage() == itemstack.getItemDamage()))
{
return i;
}
}
return -1;
}
public int getFirstEmptyStack()
{
for(int i = 0; i < inventory.length; i++)
{
if(inventory[i] == null)
{
return i;
}
}
return -1;
}
private int storePartialItemStack(ItemStack itemstack)
{
int i = itemstack.itemID;
int j = itemstack.stackSize;
int k = storeItemStack(itemstack);
if(k < 0)
{
k = getFirstEmptyStack();
}
if(k < 0)
{
return j;
}
if(inventory[k] == null)
{
inventory[k] = new ItemStack(i, 0, itemstack.getItemDamage());
}
int l = j;
if(l > inventory[k].getMaxStackSize() - inventory[k].stackSize)
{
l = inventory[k].getMaxStackSize() - inventory[k].stackSize;
}
if(l > getInventoryStackLimit() - inventory[k].stackSize)
{
l = getInventoryStackLimit() - inventory[k].stackSize;
}
if(l == 0)
{
return j;
} else
{
j -= l;
inventory[k].stackSize += l;
inventory[k].animationsToGo = 5;
return j;
}
}
public boolean consumeInventoryItem(int i)
{
int j = getInventorySlotContainItem(i);
if(j < 0)
{
return false;
}
if(--inventory[j].stackSize <= 0)
{
inventory[j] = null;
}
return true;
}
public boolean addItemStackToInventory(ItemStack itemstack)
{
if(!itemstack.isItemDamaged())
{
int i;
do
{
i = itemstack.stackSize;
itemstack.stackSize = storePartialItemStack(itemstack);
} while(itemstack.stackSize > 0 && itemstack.stackSize < i);
return itemstack.stackSize < i;
}
int j = getFirstEmptyStack();
if(j >= 0)
{
inventory[j] = ItemStack.copyItemStack(itemstack);
itemstack.stackSize = 0;
return true;
} else
{
return false;
}
}
public ItemStack decrStackSize(int i, int j)
{
ItemStack aitemstack[] = inventory;
if(i >= inventory.length)
{
aitemstack = armorInventory;
i -= inventory.length;
}
if(aitemstack[i] != null)
{
if(aitemstack[i].stackSize <= j)
{
ItemStack itemstack = aitemstack[i];
aitemstack[i] = null;
return itemstack;
}
ItemStack itemstack1 = aitemstack[i].splitStack(j);
if(aitemstack[i].stackSize == 0)
{
aitemstack[i] = null;
}
return itemstack1;
} else
{
return null;
}
}
public void setInventorySlotContents(int i, ItemStack itemstack)
{
ItemStack aitemstack[] = inventory;
if(i >= aitemstack.length)
{
i -= aitemstack.length;
aitemstack = armorInventory;
}
aitemstack[i] = itemstack;
}
public NBTTagList writeToNBT(NBTTagList nbttaglist)
{
for(int i = 0; i < inventory.length; i++)
{
if(inventory[i] != null)
{
NBTTagCompound nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte)i);
inventory[i].writeToNBT(nbttagcompound);
nbttaglist.setTag(nbttagcompound);
}
}
for(int j = 0; j < armorInventory.length; j++)
{
if(armorInventory[j] != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)(j + 100));
armorInventory[j].writeToNBT(nbttagcompound1);
nbttaglist.setTag(nbttagcompound1);
}
}
return nbttaglist;
}
public void readFromNBT(NBTTagList nbttaglist)
{
inventory = new ItemStack[9];
armorInventory = new ItemStack[1];
for(int i = 0; i < nbttaglist.tagCount(); i++)
{
NBTTagCompound nbttagcompound = (NBTTagCompound)nbttaglist.tagAt(i);
int j = nbttagcompound.getByte("Slot") & 0xff;
ItemStack itemstack = new ItemStack(nbttagcompound);
if(itemstack.getItem() == null)
{
continue;
}
if(j >= 0 && j < inventory.length)
{
inventory[j] = itemstack;
}
if(j >= 100 && j < armorInventory.length + 100)
{
armorInventory[j - 100] = itemstack;
}
}
}
public int getSizeInventory()
{
return inventory.length + 1;
}
public ItemStack getStackInSlot(int i)
{
ItemStack aitemstack[] = inventory;
if(i >= aitemstack.length)
{
i -= aitemstack.length;
aitemstack = armorInventory;
}
return aitemstack[i];
}
public String getInvName()
{
return "Inventory";
}
public int getInventoryStackLimit()
{
return 64;
}
public void onInventoryChanged()
{
inventoryChanged = true;
}
public boolean canInteractWith(EntityPlayer entityplayer)
{
if(ent.isDead)
{
return false;
} else
{
return entityplayer.getDistanceSqToEntity(ent) <= 64D;
}
}
public boolean func_28018_c(ItemStack itemstack)
{
for(int i = 0; i < armorInventory.length; i++)
{
if(armorInventory[i] != null && armorInventory[i].isStackEqual(itemstack))
{
return true;
}
}
for(int j = 0; j < inventory.length; j++)
{
if(inventory[j] != null && inventory[j].isStackEqual(itemstack))
{
return true;
}
}
return false;
}
public void dropAllItems()
{
for(int i = 0; i < inventory.length; i++)
{
if(inventory[i] != null)
{
ent.entityDropItem(inventory[i], 0.0F);
inventory[i] = null;
}
}
}
public ItemStack inventory[];
public ItemStack armorInventory[];
public JWorld_TamableEntity ent;
public boolean inventoryChanged;
}
JWorld_TamableContainer.java inventory class
Same as above, I know little more than you need this. Since killNature did all the work, I'm just organizing it all together.
Tame the Tamable Code Tips
Ok, have been getting a lot of questions about this, so let's go over the basics. I won't use my code above, since it will be changing a few more times, but I will give general examples. Let's get started.
First off, Taming means nothing. It's a general term. It means something different to everyone, so if you are asking about "taming" a mods think about what that will mean. Does it just stop attacking you? Does it follow you? Will it bring up a special GUI (what I have done). Taming is just a flag, what it means is up to you.
1. Can it be Tamed?
First off, the simplest what to flag a creature tamed is with a Boolean flag. You should also set up a string holding the owner's name. This will help later on. Define the global vars such as this(if you don't know what a global var is, please look it up):
public boolean tamed;
public String ownerName;
In your constructor you will want to set tamed to false, unless you want it to start tamed. You should set the ownerName to "" (yes 2 double quotes, meaning an empty, defined string). Now it's possible to tame your mob. Let's work out how to do that
2. Tame the beast!
So now we have our tame vars, let's put them to use. Usually to tame a creature, you have to give it something. In my code I have a mood level that needs to reach a specific mark, but here we will just go by 1 item. A stick. This will be done in the interact() method. This will be a sample of a bare interact() method:
public boolean interact(EntityPlayer entityplayer)
{
ItemStack itemstack = entityplayer.inventory.getCurrentItem(); //see what the interacting player is holding
if(itemstack != null && itemstack.itemID == Item.stick.shiftedIndex)
{
itemstack.stackSize--; //you give the item
if(itemstack.stackSize <= 0)
{
entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, null);
}
tamed = true;
ownerName = entityplayer.username;
}
}
Now the flag is set, and it knows who it's owner is. Simple as that. At this point you can then check (in onLivingUpdate() method) periodically if the mob is tamed, and run what ever behavior you want.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
package net.minecraft.src;
// Referenced classes of package net.minecraft.src:
// EntityAnimal, DataWatcher, NBTTagCompound, World,
// EntityPlayer, Item, EntityPigZombie, AchievementList,
// EntityLightningBolt
public class JWorld_HorseEntity extends JWorld_TamableEntity //EntityAnimal
{
public JWorld_HorseEntity(World world)
{
super(world);
texture = "/mods/horse.png";
sizeX = 1.2F;
sizeY = 1F;
setSize(sizeX,sizeY); //set bounding box by age
maxSpeed = 5;
moveSpeed = maxSpeed;
//Tamable vars:
entityType = "Horse"; //set in sub class, bread name of creature
hostile = -1; //will it attack the player/other mobs or not.
owner = -1; //in case entityID 0 is used. < 0 means no owner. > 0 means tamed with an owner
mountable = 0; //Possible to mount without mount item
favItem = Item.stick.shiftedIndex; //leave it negative, meaning not possible to tame. Based on Item.shiftedIndex
favBoost = 5; //default boost of 1 to mood.
mood = 0; //negative is angry, positive is happy. 10 will tame?
tamemood = 10; //how much needed to tame it. Needs 2 sticks to tame
MountItem = Item.pickaxeWood.shiftedIndex; //-1 means no item needed if mountable. Based on Item.shiftedIndex
myName = ""; //Leave it un-named to not render name tag.
myAge = 1; //can be used for scaling and other age related code
maxAge = 10; //age of max size
updateAge(); //make adjustments based on age. Set myAge to maxAge to nullify this
}
/* --don't think this is needed
protected void entityInit()
{
dataWatcher.addObject(16, Byte.valueOf((byte)0));
}
*/
public void writeEntityToNBT(NBTTagCompound nbttagcompound)
{
super.writeEntityToNBT(nbttagcompound);
//nbttagcompound.setBoolean("Saddle", getSaddled());
}
public void readEntityFromNBT(NBTTagCompound nbttagcompound)
{
super.readEntityFromNBT(nbttagcompound);
//setSaddled(nbttagcompound.getBoolean("Saddle"));
}
protected String getLivingSound()
{
return "mob.pig";
}
protected String getHurtSound()
{
return "mob.pig";
}
protected String getDeathSound()
{
return "mob.pigdeath";
}
/*
public boolean interact(EntityPlayer entityplayer)
{
if(riddenByEntity == null || riddenByEntity == entityplayer)
{
entityplayer.mountEntity(this);
return true;
} else
{
return false;
}
}
*/
protected int getDropItemId()
{
return 0;
}
}
Hey, inlanoche.
I took a little break from modding, and I decided to try these tutorials again.
I'm stuck at the spawner block right now.
When I click on it, Minecraft crashes.
Here's the crash report:
Mods loaded: 2
ModLoader Beta 1.7.3
net.minecraft.src.mod_Champite 1.0 for MC Beta 1.7.3
Minecraft has crashed!
----------------------
Minecraft has stopped running because it encountered a problem.
If you wish to report this, please copy this entire text and email it to [email protected].
Please include a description of what you did when the error occured.
--- BEGIN ERROR REPORT 9b8f1121 --------
Generated 23/08/11 6:48 PM
Minecraft: Minecraft Beta 1.7.3
OS: Windows Vista (x86) version 6.0
Java: 1.6.0_26, Sun Microsystems Inc.
VM: Java HotSpot(TM) Client VM (mixed mode), Sun Microsystems Inc.
LWJGL: 2.4.2
OpenGL: GeForce 6150SE nForce 430/PCI/SSE2/3DNOW! version 2.1.2, NVIDIA Corporation
java.lang.NullPointerException
at net.minecraft.src.Champ_SpawnerBlock.onBlockClicked(Champ_SpawnerBlock.java:32)
at net.minecraft.src.PlayerControllerSP.clickBlock(PlayerControllerSP.java:63)
at net.minecraft.client.Minecraft.clickMouse(Minecraft.java:820)
at net.minecraft.client.Minecraft.runTick(Minecraft.java:1047)
at net.minecraft.client.Minecraft.run(Minecraft.java:480)
at java.lang.Thread.run(Unknown Source)
--- END ERROR REPORT a6345566 ----------
PneumonicFungus i had the same problem, it was a long time ago and i don't remember however i do remember it being something about the mob. So the reason it crashes MIGHT be something about your mob. If you can't find it in your world too it probably is the problem. Check your mob codes out.
If you still think your spawnerblock is bugged, try setting the mob that it spawns into a pig or another mob. If it crashes and doesn't spawn a pig too then your spawner is bugged, if it works then your mob is bugged.
By the way inlanoche i love your tameable mob tutorial! You are a great help i hope you keep things up :smile.gif:
PneumonicFungus i had the same problem, it was a long time ago and i don't remember however i do remember it being something about the mob. So the reason it crashes MIGHT be something about your mob. If you can't find it in your world too it probably is the problem. Check your mob codes out.
If you still think your spawnerblock is bugged, try setting the mob that it spawns into a pig or another mob. If it crashes and doesn't spawn a pig too then your spawner is bugged, if it works then your mob is bugged.
By the way inlanoche i love your tameable mob tutorial! You are a great help i hope you keep things up :smile.gif:
Thanks. Not much of a tutorial yet, but there's stuff in there that people have been asking about. I'm actually about to revise the code, but am waiting on an answer to something (need to check if an item is in your inventory, not just equiped).
The mob won't spawn naturally, and the spawn block crashes Minecraft when you left click.
Crash report:
Mods loaded: 2
ModLoader Beta 1.7.3
net.minecraft.src.mod_Champite 1.0 for MC Beta 1.7.3
Minecraft has crashed!
----------------------
Minecraft has stopped running because it encountered a problem.
If you wish to report this, please copy this entire text and email it to [email protected].
Please include a description of what you did when the error occured.
--- BEGIN ERROR REPORT 9b8f1121 --------
Generated 24/08/11 1:29 AM
Minecraft: Minecraft Beta 1.7.3
OS: Windows Vista (x86) version 6.0
Java: 1.6.0_26, Sun Microsystems Inc.
VM: Java HotSpot(TM) Client VM (mixed mode), Sun Microsystems Inc.
LWJGL: 2.4.2
OpenGL: GeForce 6150SE nForce 430/PCI/SSE2/3DNOW! version 2.1.2, NVIDIA Corporation
java.lang.NullPointerException
at net.minecraft.src.Champ_SpawnerBlock.onBlockClicked(Champ_SpawnerBlock.java:32)
at net.minecraft.src.PlayerControllerSP.clickBlock(PlayerControllerSP.java:63)
at net.minecraft.client.Minecraft.clickMouse(Minecraft.java:820)
at net.minecraft.client.Minecraft.runTick(Minecraft.java:1047)
at net.minecraft.client.Minecraft.run(Minecraft.java:480)
at java.lang.Thread.run(Unknown Source)
--- END ERROR REPORT 96ff40de ----------
Here you can find pre-made models like pig,cow,wolf etc.
PneumonicFungus did your spawner spawn pigs and such like i suggested?
I have borrowed your codes and tried to spawn your afropig in world and it actually worked.
(Although the model is kind of buggy and textureless because i don't have it)
I didn't alter any of your entity,render or model code however my mod code might be different and that might be the reason it works. I think i slowly remember that error and how i fixed it.I recreated the same error in my mod.
I recreated the same error you had by changing the "AfroPig" in spawner block code to something else. That way the spawner couldn't find the reference and crashed the game. There, try this out.
Are you sure all you added was the renderLivingLabel code? Take it out and see if it comes back. Is it possible that the name is null? This might crash the render.
As to spawning at a specific spot, I do that with the spawn block. I spawn it at x, y, z. As to make it got to a spot, I'm still looking over some of the behavour stuff, so not there yet.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
is it possible the text is null? You didn't answer the question.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
The problem is that when you initialize your creature, you set an int randomly between 0 and 5 and then try to access your array mobName[] at that position. The array only has position 0, so when the int is set to anything above that you are going to get an ArrayOutOfBoundsException. Either add 5 more names to the mobName array (so that you can never go out of bounds), or take out the random int line and make instead.
Other than that original error, I don't know much about displaying text above a creature's head. But looking into the RenderPigman file, I believe that:
should look like:
Since you don't override it in the RenderPigman file, you need to tell the program where to look for the renderLivingLabel function, which is in the super class. If that doesn't fix it, i'm not sure what the problem is.
Also, if that doesn't solve it, try just putting the string "Tom" into the string parameter of the renderLivingLabel call. If it still doesn't work, then there is something wrong with the way you are using that specific function.
Let's start by just setting myName = "A Name"; in your constructor, forget the random name code. One step at a time, or it will be difficult to pin point logic errors in code.
Actually, no it's a call to an existing method from the super class. Here is what mine looks like (with a check for a null or blank name):
Egnore the JWingFlapper(); call, it's a custom animation for wing flaps. Ok, not a null check (not sure if I can do that with strings, but I check that the length is defined as greater than 0).
incase more refrence is needed the whole render code is:
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) braces deadcode
package net.minecraft.src;
import net.minecraft.client.Minecraft;
import org.lwjgl.opengl.GL11;
// Referenced classes of package net.minecraft.src:
// RenderLiving, EntityChicken, MathHelper, ModelBase,
// EntityLiving, Entity
public class JWorld_FlythingRender extends RenderLiving
{
private JWorld_FlythingEntity holdEnt;
private JWorld_FlythingModel holdModel;
public JWorld_FlythingRender(ModelBase modelbase, float f)
{
super(modelbase, f);
holdModel = (JWorld_FlythingModel) modelbase;
}
public void renderFlything(JWorld_FlythingEntity entity, double d, double d1, double d2,
float f, float f1)
{
holdEnt = entity;
super.doRenderLiving(entity, d, d1, d2, f, f1);
if(entity.myName.length() > 0 && entity.myName != "")
{
renderLivingLabel(entity, entity.myName, d, d1, d2, 64);
}
JWingFlapper();
}
protected void JWingFlapper()
{
holdModel.slowFlap(holdEnt.flap);
}
protected float getWingRotation(JWorld_FlythingEntity entity, float f)
{
float f1 = entity.field_756_e + (entity.field_752_b - entity.field_756_e) * f;
float f2 = entity.field_757_d + (entity.destPos - entity.field_757_d) * f;
return (MathHelper.sin(f1) + 1.0F) * f2;
}
protected float func_170_d(EntityLiving entityliving, float f)
{
return getWingRotation((JWorld_FlythingEntity)entityliving, f);
}
public void doRenderLiving(EntityLiving entityliving, double d, double d1, double d2,
float f, float f1)
{
renderFlything((JWorld_FlythingEntity)entityliving, d, d1, d2, f, f1);
}
public void doRender(Entity entity, double d, double d1, double d2,
float f, float f1)
{
renderFlything((JWorld_FlythingEntity)entity, d, d1, d2, f, f1);
}
}
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Ok, people have been asking me about this, so I am going to post my (not finished yet, but working) code for my tameable mobs. These super class (when you want this functionality, have your entity class extend this one) will allow you to tame mobs, rename them (you will have to do your own render code for like my last post if you want the names to show), mount them, and have them follow you around (as long as you don't get too far). I'm going to try and past only the code that is finished. I still need to do the save stuff, so the stats and such stay with (tame, owned) mobs, as well as the hostile code, and hopefully the pack animal code. That means that this thread will change several times. I will post what is working, and what is in the works. That said,
inLanoche's Tamable Entity class V0.7
Please read the whole post.
Features:
- tamable when given favourite item. mood boost can be defined, as well as mood needed to tame. Most other features require taming (but this can be overrided) COMPLETE
- Once tamed, GUI interface when interacting with the mob. COMPLETE
- Can name/rename through GUI. COMPLETE
- Toggle for mountable. Can also depend on having an item in hand. Item is not consumed, may change to item is in iventory, istead of having to be equiped. COMPLETE
- Toggle follow/don't follow behaviour through GUI. Mob must be within range, and can see you, or will stop following. COMPLETE
- Various levels of hostility, from doesn't attack, to attacks only players, to attacks anything that moves. Might also work in that it attacks one specific mob type only (hunting). INCOMPLETE
- Make it attack monster type mobs when tamed, can set the attack strength. INCOMPLETE
- Can set it's carry capacity, and through GUI can get to it's inventory menu. COMPLETE - Thanks to killNature!
- Flying or not flying - Might drop this, as it seems quite easy to add this in the sub class. I could just add a sub to this for flying and release that as well, with customizable wing flapping.
- Usable age. Can be used to scale the model, as well as allow for beging ridable after a certain age. COMPLETE
- Saving/Loading of Tamed mobs and their stats INCOMPLETE WIP
- Patroling an area (4 waypoints) COMPLETE - Thanks to McDog3!
Thems the features,for now. Here is a taste of the (not complete yet) code. I've tried to comment so that you can make your own changes in your sub class, and do what you want.
UPDATED 8/30/2011 - 3:45pm EST
Some class names have changed!
Data saving is almost there. This is a major overhaul of the code, though for the most part should not affect classes that extend this. I have made changes to ALL the support files as well. ***Special thanks to McDog3 helping with the now working Patrol code!
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
These files are needed to run the complete Tamable entity class. Feel free to pick and chose the features you want. I will try and seperate them as much as possible, including the variable defs.
JWorld_TamableGUIMenu.java GUI class - Name has changed!
This is the interaction GUI once the mob is tamed.
JWorld_TamableInvGui.java GUI class
This is the inventory interaction window GUI. To use this, I have modifed the trap.png file (which is similar to the one killNature posted) HERE. If you copy/paste my code, make sure to use the same mods folder to store this file both in the MCP temp folder, and in the minecraft.jar file.
JWorld_TamableInventory.java inventory class
Still getting to know this class. Will post more info in the future. For the most part, just leave it as is, unless you know better. I don't.
JWorld_TamableContainer.java inventory class
Same as above, I know little more than you need this. Since killNature did all the work, I'm just organizing it all together.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Ok, have been getting a lot of questions about this, so let's go over the basics. I won't use my code above, since it will be changing a few more times, but I will give general examples. Let's get started.
First off, Taming means nothing. It's a general term. It means something different to everyone, so if you are asking about "taming" a mods think about what that will mean. Does it just stop attacking you? Does it follow you? Will it bring up a special GUI (what I have done). Taming is just a flag, what it means is up to you.
1. Can it be Tamed?
First off, the simplest what to flag a creature tamed is with a Boolean flag. You should also set up a string holding the owner's name. This will help later on. Define the global vars such as this(if you don't know what a global var is, please look it up):
In your constructor you will want to set tamed to false, unless you want it to start tamed. You should set the ownerName to "" (yes 2 double quotes, meaning an empty, defined string). Now it's possible to tame your mob. Let's work out how to do that
2. Tame the beast!
So now we have our tame vars, let's put them to use. Usually to tame a creature, you have to give it something. In my code I have a mood level that needs to reach a specific mark, but here we will just go by 1 item. A stick. This will be done in the interact() method. This will be a sample of a bare interact() method:
Now the flag is set, and it knows who it's owner is. Simple as that. At this point you can then check (in onLivingUpdate() method) periodically if the mob is tamed, and run what ever behavior you want.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
updated to V0.6
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Entity file:
Render file:
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
look closer at the example I posted. You don't ever call your renderPigman method.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
I took a little break from modding, and I decided to try these tutorials again.
I'm stuck at the spawner block right now.
When I click on it, Minecraft crashes.
Here's the crash report:
Here's the Champ_SpawnerBlock.java code:
http://pastebin.com/1a638xGM
I did declare it in my main mod file.
Any help? :S
Thanks in advance.
P.S. Would you like me to show you the code for mob(MobEntity, MobRender, MobModel)? Perhaps those affect it, considering I can't find it in-game.
If you still think your spawnerblock is bugged, try setting the mob that it spawns into a pig or another mob. If it crashes and doesn't spawn a pig too then your spawner is bugged, if it works then your mob is bugged.
By the way inlanoche i love your tameable mob tutorial! You are a great help i hope you keep things up :smile.gif:
Thanks. Not much of a tutorial yet, but there's stuff in there that people have been asking about. I'm actually about to revise the code, but am waiting on an answer to something (need to check if an item is in your inventory, not just equiped).
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
To change what mob it spawns, do you just change this (IN THE GREEN)?
for example, pig.
Were do you get the quadruped? Its not there normally and Iv searched the forums and have not found it :l
yeah, just change that string to the designated name of another mob.
Here is my spawn block (Champ_SpawnerBlock) code:
http://pastebin.com/67BjNCKK
Here is my Champ_AfroPigEntity code:
http://pastebin.com/u3pekDP5
Here is my Champ_AfroPigRender code:
http://pastebin.com/A27iz6v5
Here is my Champ_AfroPigModel code:
http://pastebin.com/S2gab33K
(everything in main mod file is done)
The mob won't spawn naturally, and the spawn block crashes Minecraft when you left click.
Crash report:
http://www.minecraftforum.net/topic/200676-modeler-techne/
Here you can find pre-made models like pig,cow,wolf etc.
PneumonicFungus did your spawner spawn pigs and such like i suggested?
I have borrowed your codes and tried to spawn your afropig in world and it actually worked.
(Although the model is kind of buggy and textureless because i don't have it)
I didn't alter any of your entity,render or model code however my mod code might be different and that might be the reason it works. I think i slowly remember that error and how i fixed it.I recreated the same error in my mod.
In your mod_blabla file over here:
If you name it "AfroPig" you must use it like that in your spawner block code too:
I recreated the same error you had by changing the "AfroPig" in spawner block code to something else. That way the spawner couldn't find the reference and crashed the game. There, try this out.