0
\$\begingroup\$

I'm developing a top-down shooter in Java with Slick2D, and I've been ignoring this bug for a while because I'm not sure what causes it. I have numerous weapons that you can buy from the shop and cycle through using the scroll wheel or Q and E. The problem is that I've had a persistent bug where if you run out of ammo for one weapon, switch to another and try to fire, it will say you're out of ammo, even if the other weapon is full up. Then, after pressing reload for the second weapon, it will not let you fire the weapon. But if you then switch back to the weapon that was out of ammo and back again, it will allow you to fire.

I was wondering if someone could take a look at the logic for my weapon switching and reloading and tell me if there's a flaw in how it's being handled:

The following is the method that actually refills the clip, if there's any ammo left.

protected void reload() { 
    int takeFromInv = getClipCapacity() - ammoInClip; 
    int taken = Math.min(takeFromInv, ammoInInventory); 
    ammoInInventory -= taken; 
    ammoInClip += taken; 

    reloading = false; 
}

This is called during the update() method...

public void update(BasicGameState gs, long cTime, int delta) { 
    // Basically just checking to see if the reload time has elapsed. 
    if(reloading && !isReloading(cTime)) reload();
    ...

...once the reload timer has elapsed:

public boolean isReloading(long cTime) { 
    long elapsed = cTime - reloadStart; 
    return ((elapsed < getReloadTimeTotal()) && reloading); 
}

The reload timer is kicked off when this method is called by the Player class when the 'R' key is pressed.

public void reload(long cTime) { 
    if(getInventoryAmmo() > 0) { 
        reloading = true; 
        reloadStart = cTime; 
        if(Talents.Munitions.HASTE.active()) { 
            float roll = Globals.rand.nextFloat(); 
            if(roll <= 0.1f) { 
                reload(); 
                StatusMessages.getInstance().addMessage("Haste!", Player.getPlayer(), Player.ABOVE_1, cTime, 1_000L); 
            } 
        }

        if(reloadSound != null) reloadSound.play(); 
    } 
}

The method that determines if the weapon can be used (fired) is:

public boolean canUse(long cTime) { 
    if(reloading) return false; 
    boolean clipNotEmpty = ammoInClip > 0; 
    boolean cool = (cTime - lastUsed) >= getTotalCooldown(); 

    if(!clipNotEmpty) return false; 

    return (Player.getPlayer().isAlive() && equipped && cool && (automatic || release)); 
}

Finally, the weapon switching is handled in the Player class as such:

public void weaponRotate(int direction) { 
    int wc = getRangedWeapons().size(); 
    if(wc > 0) { 
        // have to use floorMod because apparently Java % is remainder only, not modulus... -_- 
        int i = Math.floorMod((rangedIndex + direction), wc); 
        setCurrentRanged(i); 
    } 
}

And here's the setCurrentRanged method:

public void setCurrentRanged(int wi) { 
    List<RangedWeapon> weapons = getRangedWeapons(); 
    if(!weapons.isEmpty()) { 
        if((wi >= 0) && (wi < weapons.size())) { 
            // If the player actually has the weapon bound to the key that was pressed... 
            getCurrentRanged().unequip(); 
            rangedIndex = wi; 
            getCurrentRanged().equip();
        }
    }
}

And finally, getCurrentRanged():

public RangedWeapon getCurrentRanged() { 
    List<RangedWeapon> weapons = getRangedWeapons(); 
    if(rangedIndex >= weapons.size()) return weapons.get(0); 
    if(!weapons.isEmpty()) return weapons.get(rangedIndex); 
    else return null; 
} 

I realize that's a lot of code to look over, but those are the relevant functions to my reload and weapon switching processes. I never realized it would be so difficult to implement a good, working reload system. So can anyone spot what might be causing this issue, or any other bugs that might pop up as a result of the way I implemented this?

\$\endgroup\$
  • \$\begingroup\$ where does ammoInClip live? \$\endgroup\$ – ratchet freak Apr 18 '19 at 14:08
  • \$\begingroup\$ It's a member variable of the RangedWeapon class, which is where the reload methods live. \$\endgroup\$ – Darin Beaudreau Apr 18 '19 at 14:27
  • \$\begingroup\$ Sounds like an incomplete/corrupt weapon state that you somehow get when switching weapons (while doing XY). Perhaps isolate the weapon firing, reloading and switching code and then use a debugger to accurately track the values of your different weapon instances? \$\endgroup\$ – Ignatiamus Apr 22 '19 at 12:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.