Jump to content

How to make a weapon [gun] fire faster than default speed?


HappleAcks

Recommended Posts

You're extending ItemSword, and ItemSword sets the EnumAction to .block. You have to override that and set it to .none.

So everything is working now except for the fact that if you rapidly right click, it ignores the firing speed (if you set it to slower, for example (ticksInUse % 40 == 0) ).

Link to comment
Share on other sites

  • Replies 50
  • Created
  • Last Reply

Top Posters In This Topic

Hi

 

Sounds like you just want to ignore a click if it's too soon after a previous one.  You need to be able to tell when the gun was last fired.

 

If you have a global tick counter in your code somewhere, you could refer to that.

 

For example

 

fireMyGun() {
  lastTickFired =  MyMod.getGlobalTickCount();
}

void tryToFireGun() {
int tickNow = MyMod.getGlobalTickCount();
int ticksSinceLastFired = tickNow - lastTickFired;
assert ticksSinceLastFired >= 0;

if (ticksSinceLastFire > MINIMUM_FIRING_DELAY) {
  fireMyGun()
}

 

-TGG

Link to comment
Share on other sites

Or better yet, don't extend ItemSword. You're making a rifle, not a sword, it doesn't make any sense to extend ItemSword. You should be extending Item.

 

This is one of my biggest pieces of advice to new modders -- you have to know when you should extend a class versus when you should copy a class.  If you extend a class, you need to understand the implication -- your new class will always still be considered a member of the class you're extending.

 

When you are first modding, it seems really easy to just extend a class and modify a couple things. However it will have unintended consequences.  For example, if you extend EntitySheep to make an EntityGiraffe you will have wolves still attack EntityGiraffe because they will still be also EntitySheep.

 

So very often, if you want to make something that is similar to a vanilla class it is better to copy the code rather than extend it.  A gun is not an extension of a sword, and probably not even an extension of a bow.

 

Anyway, remember that there is vanilla code that is testing against vanilla classes and if you extend a vanilla class your new class will be considered by vanilla code (and other mods!) to be the class you extended.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

You could also use a for loop in the right click method. It's better to use the ticksInUse though. I am just suggesting alternatives. :)

 

If you mean have a for loop that loops just to cause delay, then NO!  You don't want to create delays in any method of your mod, as that will delay the whole game processing (well within the thread anyway).

 

The proper way to do delays is to count ticks somehow and ignore firing until enough have passed. Like what TheGreyGhost posted.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

What you could do is use the damage bar or item metadata as a reload counter, for example if you want to have a 40 second reload you could set the meta data to 40 and then subtract 1 every tick. Example:

public void onUpdate(ItemStack par1ItemStack, World par2World, Entity par3Entity, int par4, boolean par5)
{
	par1ItemStack.getItemDamageForDisplay();
int i=par1ItemStack.getItemDamage();
	if(i>0)
	{
		par1ItemStack.setItemDamage(i-1);
	}
}

And then in your firing code check if par1ItemStack.getItemDamageForDisplay()=0 and then do par1ItemStack.setItemDamage('relaodtime");

Link to comment
Share on other sites

What you could do is use the damage bar or item metadata as a reload counter, for example if you want to have a 40 second reload you could set the meta data to 40 and then subtract 1 every tick. Example:

public void onUpdate(ItemStack par1ItemStack, World par2World, Entity par3Entity, int par4, boolean par5)
{
	par1ItemStack.getItemDamageForDisplay();
int i=par1ItemStack.getItemDamage();
	if(i>0)
	{
		par1ItemStack.setItemDamage(i-1);
	}
}

And then in your firing code check if par1ItemStack.getItemDamageForDisplay()=0 and then do par1ItemStack.setItemDamage('relaodtime");

That will cause the item to refresh its icon, giving it a weird visual effect.

 

@OP The best way, in my opinion, is to store the counter / last-time-shot directly in your item's NBT.

 

Check your NBT-based right-click cooldown / shot-time before allowing the player to set the item in use upon right click, and be sure to decrement the cooldown in your item's onUpdate method if that's the route you choose. Using world time would be easier in this case: upon setting the item in use, set a long in the NBT for current world time + number of ticks you want to stall, and you don't have to worry about updating anything, as the world time does the counting for you.

 

You could also do what TGG suggested, but I personally prefer to keep fields and methods compartmentalized within the object that requires them - for one, it makes it much easier for me to debug, since all the code is in one place.

Link to comment
Share on other sites

What you could do is use the damage bar or item metadata as a reload counter, for example if you want to have a 40 second reload you could set the meta data to 40 and then subtract 1 every tick. Example:

public void onUpdate(ItemStack par1ItemStack, World par2World, Entity par3Entity, int par4, boolean par5)
{
	par1ItemStack.getItemDamageForDisplay();
int i=par1ItemStack.getItemDamage();
	if(i>0)
	{
		par1ItemStack.setItemDamage(i-1);
	}
}

And then in your firing code check if par1ItemStack.getItemDamageForDisplay()=0 and then do par1ItemStack.setItemDamage('relaodtime");

This method turned out to be really buggy. The gun will keep firing as soon as you click once and never stop, as well as it looks weird.

 

Hi

 

Sounds like you just want to ignore a click if it's too soon after a previous one.  You need to be able to tell when the gun was last fired.

 

If you have a global tick counter in your code somewhere, you could refer to that.

 

For example

 

fireMyGun() {
  lastTickFired =  MyMod.getGlobalTickCount();
}

void tryToFireGun() {
int tickNow = MyMod.getGlobalTickCount();
int ticksSinceLastFired = tickNow - lastTickFired;
assert ticksSinceLastFired >= 0;

if (ticksSinceLastFire > MINIMUM_FIRING_DELAY) {
  fireMyGun()
}

 

-TGG

I'm not quite sure how to implement this along with my existing code.

 

@OP The best way, in my opinion, is to store the counter / last-time-shot directly in your item's NBT.

 

Check your NBT-based right-click cooldown / shot-time before allowing the player to set the item in use upon right click, and be sure to decrement the cooldown in your item's onUpdate method if that's the route you choose. Using world time would be easier in this case: upon setting the item in use, set a long in the NBT for current world time + number of ticks you want to stall, and you don't have to worry about updating anything, as the world time does the counting for you.

 

You could also do what TGG suggested, but I personally prefer to keep fields and methods compartmentalized within the object that requires them - for one, it makes it much easier for me to debug, since all the code is in one place.

I've never worked with NBT before, so I don't really know how to go about implementing this.

 

My current code:

 

 

public class SniperRifle extends ItemSword{

 

 

  public SniperRifle(int i, ToolMaterial p_i45356_1_){

super(p_i45356_1_);

setFull3D();

    this.setCreativeTab(CreativeTabs.tabCombat);

  }

 

  @Override

  public void onUsingTick(ItemStack par1ItemStack, EntityPlayer player, int count) {

  // count starts at the max duration and counts down

  int ticksInUse = getMaxItemUseDuration(par1ItemStack) - count;

 

  // this will fire every 20 ticks; change or remove to suit your needs

  if (ticksInUse % 20 == 0) {

    if(player.capabilities.isCreativeMode||player.inventory.consumeInventoryItem(darkMod.Bullet))

      {

    player.worldObj.playSoundAtEntity(player, "darkmod:Rifle", 1.0F, 1.0F);

        if (!player.worldObj.isRemote)

        {

        player.worldObj.spawnEntityInWorld(new EntityBullet(player.worldObj, player, 12.0F));

        }

      }

  }

  }

 

  @Override

  public EnumAction getItemUseAction(ItemStack par1ItemStack)

  {

      return EnumAction.none;

  }

}

 

 

 

Link to comment
Share on other sites

I've never worked with NBT before, so I don't really know how to go about implementing this.

Here is a good introduction.

 

You will need to override the onItemRightClick method, verify the ItemStack has a non-null tag compound and add one if necessary, then use that for your variable.

 

// inside the onItemRightClick method with an ItemStack stack parameter

// verify tag compound:
if (!stack.hasTagCompound()) {
// didn't have one, so make a new one:
stack.setTagCompound(new NBTTagCompound());
}

// now you can check the world time vs. the time stored in the tag
// if no time is stored, that's okay - it will return zero
if (world.getWorldTime() > stack.getTagCompound().getLong("lastShotTime")) {
// set item in use
} else {
// 'click', you can't fire yet!
}

Link to comment
Share on other sites

I've never worked with NBT before, so I don't really know how to go about implementing this.

Here is a good introduction.

 

You will need to override the onItemRightClick method

 

Would this be instead of my onUsingTick method of changing the fire rate, so I'll completely remove the old method and use the new one? Or should this be merged into it (in this case I don't really know where to go with it).

Link to comment
Share on other sites

You could use the items onUpdate method:

int tickssinceshot = 0;
@Override
public void onUpdate(ItemStack stack, World world, Entity entity, int slot,
		boolean isHeld) {
	if (isHeld) {
		if (entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;
			if (player.getHeldItem().getItem() instanceof ItemRifle) {
			ItemRifle rifle = (ItemRifle) player.getHeldItem().getItem();
                                tickssinceshot++;
                                if(tickssinceshot >= /** TICKS BETWEEN SHOTS**/){
                                /**SPAWN YOUR PROJECTILE
                                (You have to use packets for this, i'll show you below)
                                **/
                                tickssinceshot = 0;
                                }



                  }
            }
      }
}

Literally just throw this into your item class and modify the few things I commented.

 

I just realized you're gonna need packets, but they're pretty simple. To make a packet handler just register it with:

public static final MODNAMEPacketPipeline packetPipeline = new MODNAMEPacketPipeline();

In your main class (not in any load method or anything)

And put this:

	packetPipeline.initialise();

In your load method in your main class.

 

 

Next, add a packet 'template' that all your packets will extend:

 

 

package YOURPACKAGE;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;

/**
* AbstractPacket class. Should be the parent of all packets wishing to use the
* PacketPipeline.
*/
public abstract class AbstractYOURMODPacket {

/**
 * Encode the packet data into the ByteBuf stream. Complex data sets may
 * need specific data handlers (See
 * @link{cpw.mods.fml.common.network.ByteBuffUtils})
 * 
 * @param ctx
 *            channel context
 * @param buffer
 *            the buffer to encode into
 */
public abstract void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer);

/**
 * Decode the packet data from the ByteBuf stream. Complex data sets may
 * need specific data handlers (See
 * @link{cpw.mods.fml.common.network.ByteBuffUtils})
 * 
 * @param ctx
 *            channel context
 * @param buffer
 *            the buffer to decode from
 */
public abstract void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer);

/**
 * Handle a packet on the client side. Note this occurs after decoding has
 * completed.
 * 
 * @param player
 *            the player reference
 */
public abstract void handleClientSide(EntityPlayer player);

/**
 * Handle a packet on the server side. Note this occurs after decoding has
 * completed.
 * 
 * @param player
 *            the player reference
 */
public abstract void handleServerSide(EntityPlayer player);
}

 

 

 

Add a packet class that will do the bullet entity spawning:

(NOTE: You can re-use the same packet in all your guns, when you run the code to send the packet you just have to add a variable for what kind of bullet to shoot, and add a switch for it in the packet. In this example, I use bulletid as the identifier of what kind of bullet to shoot)

YOURMODBulletPacket:

 

 

package YOURPACKET;



import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.World;

public class YOURMODBulletPacket extends AbstractYOURMODPacket {

byte bulletid;


public MetroidSoundPacket(byte bulletId) {

	bulletid = bulletId;
}

@Override
public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {

	buffer.writeByte(bulletid);
}

@Override
public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {

	bulletid = buffer.readByte();
}

@Override
public void handleServerSide(EntityPlayer player) {
	World world = player.worldObj;
	if(bulletid == 1)	{
		//Spawn some kind of bullet with the normal world.spawnEntityInWorld method
	}
	if(bulletid == 2)	{
		//Spawn some other kind of bullet
	}
                 if(bulletid == 3)	{
		//And so on
	}

}

@Override
public void handleClientSide(EntityPlayer player) {

}

}

 

 

And add the class called YOURMODPacketPipline:

 

 

package YOURPACKAGE;

import java.util.*;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;

import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetHandlerPlayServer;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.FMLEmbeddedChannel;
import cpw.mods.fml.common.network.FMLOutboundHandler;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;


@ChannelHandler.Sharable
public class YOURMODPacketPipeline extends MessageToMessageCodec<FMLProxyPacket, AbstractYOURMODPacket> {

    private EnumMap<Side, FMLEmbeddedChannel>           channels;
    private LinkedList<Class<? extends AbstractYOURMODPacket>> packets           = new LinkedList<Class<? extends AbstractYOURMODPacket>>();
    private boolean                                     isPostInitialised = false;


    public boolean registerPacket(Class<? extends AbstractYOURMODPacket> clazz) {
        if (this.packets.size() > 256) {
            return false;
        }

        if (this.packets.contains(clazz)) {
            return false;
        }

        if (this.isPostInitialised) {
            return false;
        }

        this.packets.add(clazz);
        return true;
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, AbstractMetroidPacket msg, List<Object> out) throws Exception {
        ByteBuf buffer = Unpooled.buffer();
        Class<? extends AbstractMetroidPacket> clazz = msg.getClass();
        if (!this.packets.contains(msg.getClass())) {
            throw new NullPointerException("No Packet Registered for: " + msg.getClass().getCanonicalName());
        }

        byte discriminator = (byte) this.packets.indexOf(clazz);
        buffer.writeByte(discriminator);
        msg.encodeInto(ctx, buffer);
        FMLProxyPacket proxyPacket = new FMLProxyPacket(buffer.copy(), ctx.channel().attr(NetworkRegistry.FML_CHANNEL).get());
        out.add(proxyPacket);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List<Object> out) throws Exception {
        ByteBuf payload = msg.payload();
        byte discriminator = payload.readByte();
        Class<? extends AbstractMetroidPacket> clazz = this.packets.get(discriminator);
        if (clazz == null) {
            throw new NullPointerException("No packet registered for discriminator: " + discriminator);
        }

        AbstractMetroidPacket pkt = clazz.newInstance();
        pkt.decodeInto(ctx, payload.slice());

        EntityPlayer player;
        switch (FMLCommonHandler.instance().getEffectiveSide()) {
            case CLIENT:
                player = this.getClientPlayer();
                pkt.handleClientSide(player);
                break;

            case SERVER:
                INetHandler netHandler = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get();
                player = ((NetHandlerPlayServer) netHandler).playerEntity;
                pkt.handleServerSide(player);
                break;

            default:
        }

        out.add(pkt);
    }

    // Method to call from FMLInitializationEvent
    public void initialise() {
        this.channels = NetworkRegistry.INSTANCE.newChannel("YOURMOD", this);
        


       //REGISTER THE PACKETS YOU WANT TO USE HERE LIKE THIS:
       registerPacket(YOURMODShootingPacket.class);


    }

    // Method to call from FMLPostInitializationEvent
    // Ensures that packet discriminators are common between server and client by using logical sorting
    public void postInitialise() {
        if (this.isPostInitialised) {
            return;
        }

        this.isPostInitialised = true;
        Collections.sort(this.packets, new Comparator<Class<? extends AbstractYOURMODPacket>>() {

            @Override
            public int compare(Class<? extends AbstractYOURMODPacket> clazz1, Class<? extends AbstractYOURMODPacket> clazz2) {
                int com = String.CASE_INSENSITIVE_ORDER.compare(clazz1.getCanonicalName(), clazz2.getCanonicalName());
                if (com == 0) {
                    com = clazz1.getCanonicalName().compareTo(clazz2.getCanonicalName());
                }

                return com;
            }
        });
    }

    @SideOnly(Side.CLIENT)
    private EntityPlayer getClientPlayer() {
        return Minecraft.getMinecraft().thePlayer;
    }

    
    public void sendToAll(AbstractYOURMODPacket message) {
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL);
        this.channels.get(Side.SERVER).writeAndFlush(message);
    }

   
    public void sendTo(AbstractMetroidPacket message, EntityPlayerMP player) {
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER);
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player);
        this.channels.get(Side.SERVER).writeAndFlush(message);
    }

    
    public void sendToAllAround(AbstractMetroidPacket message, NetworkRegistry.TargetPoint point) {
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT);
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point);
        this.channels.get(Side.SERVER).writeAndFlush(message);
    }

   
    public void sendToDimension(AbstractMetroidPacket message, int dimensionId) {
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION);
        this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimensionId);
        this.channels.get(Side.SERVER).writeAndFlush(message);
    }

    /**
     * Send this message to the server.
     * <p/>
     * Adapted from CPW's code in cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
     *
     * @param message The message to send
     */
    public void sendToServer(AbstractMetroidPacket message) {
        this.channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER);
        this.channels.get(Side.CLIENT).writeAndFlush(message);
    }
}

 

 

 

FINALLY, add this code where I said to put the bullet spawning code in the onUpdate method:

Main.packetPipeline.sendToServer(new YOURMODBulletPacket((byte) WHATEVER BULLETID YOU WANT THE PACKET TO SPAWN);

Note: I used http://www.minecraftforge.net/wiki/Netty_Packet_Handling for basically all my packet stuff, take a look at it if you're still confused! (Credit to that tutorial for this explanation aswell because I used alot of their code :) )

Creator of Metroid Cubed! Power Suits, Beams, Hypermode and more!

width=174 height=100http://i.imgur.com/ghgWmA3.jpg[/img]

Link to comment
Share on other sites

Would this be instead of my onUsingTick method of changing the fire rate, so I'll completely remove the old method and use the new one? Or should this be merged into it (in this case I don't really know where to go with it).

No, it is in addition to the onUsingTick method.

 

@Chimera ... sorry, but what the heck are you doing in that code?! For one, never use local variables in Item classes; two, 'this' is already the item rifle that is updating, which you already check that it is held by the entity, so there is no reason to get the held item and check it again; and third, why would you need a packet to spawn the entity when the update method is run on both sides? I realize you are trying to help, but that code... no.

Link to comment
Share on other sites

Would this be instead of my onUsingTick method of changing the fire rate, so I'll completely remove the old method and use the new one? Or should this be merged into it (in this case I don't really know where to go with it).

No, it is in addition to the onUsingTick method.

 

Then in the case I'm a bit puzzled. I know I'm sound really cruddy here, but I don't know how to go about merging these methods.

Link to comment
Share on other sites

Then in the case I'm a bit puzzled. I know I'm sound really cruddy here, but I don't know how to go about merging these methods.

I'm not sure I can make it much clearer than that... you need both methods - onUsingTick to fire repeatedly while the item is in use, and onItemRightClick to prevent spamming right click from being faster than your onUsingTick rate of fire. And please don't extend ItemSword for a gun item - that just doesn't make any sense.

Link to comment
Share on other sites

I'm not sure I can make it much clearer than that... you need both methods - onUsingTick to fire repeatedly while the item is in use, and onItemRightClick to prevent spamming right click from being faster than your onUsingTick rate of fire. And please don't extend ItemSword for a gun item - that just doesn't make any sense.

It extends item sword because I made it so you can add melee attachments to the guns.

 

As for implementation, I do have both methods there, and I get that one is for holding right clicking (onUsingTick) and the onItemRightClick is for the rapid tapping.

 

My only problem is I don't know how to slow down the onItemRightClick (the speed it takes is a string?).

 

 

current code:

 

 

public class Sniper extends ItemSword{

 

  public Sniper (int i, ToolMaterial p_i45356_1_){

super(p_i45356_1_);

setFull3D();

  this.setCreativeTab(CreativeTabs.tabCombat);

}

 

  @Override

  public void onUsingTick(ItemStack par1ItemStack, EntityPlayer player, int count) {

  // count starts at the max duration and counts down

  int ticksInUse = getMaxItemUseDuration(par1ItemStack) - count;

 

  // this will fire every 2 ticks; change or remove to suit your needs

  if (ticksInUse % 14 == 0) {

    if(player.capabilities.isCreativeMode||player.inventory.consumeInventoryItem(darkMod.bullet))

      {

    player.worldObj.playSoundAtEntity(player, "darkmod:Sniper", 1.0F, 1.0F);

        if (!player.worldObj.isRemote)

        {

        player.worldObj.spawnEntityInWorld(new EntityBullet(player.worldObj, player, 7.0F));

        }

      }

  }

  }

 

  @Override

public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) {

 

// verify tag compound:

if (!stack.hasTagCompound()) {

// didn't have one, so make a new one:

stack.setTagCompound(new NBTTagCompound());

}

 

// now you can check the world time vs. the time stored in the tag

// if no time is stored, that's okay - it will return zero

if (world.getWorldTime() > stack.getTagCompound().getLong("lastShotTime")) {

if(player.capabilities.isCreativeMode||player.inventory.consumeInventoryItem(darkMod.bullet))

      {

    player.worldObj.playSoundAtEntity(player, "darkmod:Sniper", 1.0F, 1.0F);

        if (!player.worldObj.isRemote)

        {

        player.worldObj.spawnEntityInWorld(new EntityBullet(player.worldObj, player, 9.0F));

        }

      }

// set item in use

} else {

// 'click', you can't fire yet!

}

 

  return stack;

  }

 

 

 

 

 

 

Link to comment
Share on other sites

I'm not sure I can make it much clearer than that... you need both methods - onUsingTick to fire repeatedly while the item is in use, and onItemRightClick to prevent spamming right click from being faster than your onUsingTick rate of fire. And please don't extend ItemSword for a gun item - that just doesn't make any sense.

My only problem is I don't know how to slow down the onItemRightClick (the speed it takes is a string?).

current code:

 

 

public class Sniper extends ItemSword{

 

  public Sniper (int i, ToolMaterial p_i45356_1_){

super(p_i45356_1_);

setFull3D();

  this.setCreativeTab(CreativeTabs.tabCombat);

}

 

  @Override

  public void onUsingTick(ItemStack par1ItemStack, EntityPlayer player, int count) {

  // count starts at the max duration and counts down

  int ticksInUse = getMaxItemUseDuration(par1ItemStack) - count;

 

  // this will fire every 2 ticks; change or remove to suit your needs

  if (ticksInUse % 14 == 0) {

    if(player.capabilities.isCreativeMode||player.inventory.consumeInventoryItem(darkMod.bullet))

      {

    player.worldObj.playSoundAtEntity(player, "darkmod:Sniper", 1.0F, 1.0F);

        if (!player.worldObj.isRemote)

        {

        player.worldObj.spawnEntityInWorld(new EntityBullet(player.worldObj, player, 7.0F));

        }

      }

  }

  }

 

  @Override

public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) {

 

// verify tag compound:

if (!stack.hasTagCompound()) {

// didn't have one, so make a new one:

stack.setTagCompound(new NBTTagCompound());

}

 

// now you can check the world time vs. the time stored in the tag

// if no time is stored, that's okay - it will return zero

if (world.getWorldTime() > stack.getTagCompound().getLong("lastShotTime")) {

if(player.capabilities.isCreativeMode||player.inventory.consumeInventoryItem(darkMod.bullet))

      {

    player.worldObj.playSoundAtEntity(player, "darkmod:Sniper", 1.0F, 1.0F);

        if (!player.worldObj.isRemote)

        {

        player.worldObj.spawnEntityInWorld(new EntityBullet(player.worldObj, player, 9.0F));

        }

      }

// set item in use

} else {

// 'click', you can't fire yet!

}

 

  return stack;

  }

 

 

Does anybody know about how to slow this down, after implementation it still fires at a very rapid speed when tapping (probably because I don't know how to slow down the speed from onItemRightClick). I should also mention that the onItemRightClick has also sped up the holding-down speed (once again, probably because it is too fast).  Also, I've tried adding a large number after the stack.getTagCompound().getLong("lastShotTime") but it doesn't seem to affect anything.

Link to comment
Share on other sites

Just add a variable in your item class called tickssincefired, and every tick increase it by one, and if it = 4 then fire a bullet and set it to 0. This is basic logic. -_-

That's literally what this whole thread has been about how to go about doing. "-.-"

 

CoolAlias has gotten me really close, but I don't know how to slow it down with his method.

 

 

Link to comment
Share on other sites

Why are you trying to store ticks in use as the max use duration? After your constructor, put

int tickssincefired = 0;

 

Then in the onUsingItem method put

 

if (tickssincefired = 4){

//Fire the bullet

}else {

tickssincefired++;

}

 

I don't know why you're trying to store it somewhere, it doesn't need to persist across relog or anything like that, and that variable won't get reset any time other then that.

Creator of Metroid Cubed! Power Suits, Beams, Hypermode and more!

width=174 height=100http://i.imgur.com/ghgWmA3.jpg[/img]

Link to comment
Share on other sites

Why are you trying to store ticks in use as the max use duration? After your constructor, put

int tickssincefired = 0;

 

Then in the onUsingItem method put

 

if (tickssincefired = 4){

//Fire the bullet

}else {

tickssincefired++;

}

 

I don't know why you're trying to store it somewhere, it doesn't need to persist across relog or anything like that, and that variable won't get reset any time other then that.

Earlier in the thread I mentioned this method is ineffective because then you can't just right click and shoot after X ticks, it'll require you hold it for X ticks first, since it only counts ticks up when in use, not while not in use. This is why the other method is used, which also works. The only thing I'm wondering how I do is change the speed, and if I know that it works 100%.

Link to comment
Share on other sites

 

 

int tickssinceshot = 0;

 

if(tickssinceshot = 0){

 

Do crap

Tickssinceshot = 4;

}

Else {

Tickssinceshot--;

}

 

 

 

Problem solved.

Reversing it literally changes nothing. The exact same problem occurs, except it counts down. It starts at 4 (or X) and then counts down to 0 WHEN USING IT (because it's in the UsingItem method, which only is called when it's in use). This means that when you are not using it, the countdown stops. That's why I'm using the method CoolAlias provided, because it doesn't do that and will work at all times, except when spam right clicking (however he provided a solution to this, but I needed clarification for slowing down the speed, as I mentioned earlier).

Link to comment
Share on other sites

Just add a variable in your item class called tickssincefired, and every tick increase it by one, and if it = 4 then fire a bullet and set it to 0. This is basic logic. -_-

The reason you don't do that is because that variable will be the same for every single instance of the Item, making it incompatible in multiplayer for sure, and possibly in single player as well if you have two or more of the item in question.

 

@OP Your code is close, but when you right click, you forgot to set the time at which it was fired, meaning that every click will allow it to fire as world time > 0 is always true ;)

 

Add this to your right-click method after determining that you should fire a shot:

stack.getTagCompound().setLong("lastShotTime", world.getWorldTime() + delay);
// where 'delay' is an integer equal to the number of ticks you want to delay between shots

 

That should now prevent you from spamming right click to fire quickly, while still allowing you to hold right-click and fire continuously while the item is in use.

Link to comment
Share on other sites

Just add a variable in your item class called tickssincefired, and every tick increase it by one, and if it = 4 then fire a bullet and set it to 0. This is basic logic. -_-

The reason you don't do that is because that variable will be the same for every single instance of the Item, making it incompatible in multiplayer for sure, and possibly in single player as well if you have two or more of the item in question.

 

@OP Your code is close, but when you right click, you forgot to set the time at which it was fired, meaning that every click will allow it to fire as world time > 0 is always true ;)

 

Add this to your right-click method after determining that you should fire a shot:

stack.getTagCompound().setLong("lastShotTime", world.getWorldTime() + delay);
// where 'delay' is an integer equal to the number of ticks you want to delay between shots

 

That should now prevent you from spamming right click to fire quickly, while still allowing you to hold right-click and fire continuously while the item is in use.

Worked, thank you so much!

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.