Bug: Weapons picked up after being dropped...

Tue Oct 23, 2018 5:46 pm

..do not have the correct amount of ammo in them if dropped again on death and then picked up.

Context: normally, a weapon dropped by a player upon their death (if sv_weapondrop is true), when picked up again, should have the same amounts of ammo in it as the previous owner had in their inventory when they died. However, there is a case where this doesn't turn out to be true.

This seems to be a unintentional side-effect of how sv_weapondrop mechanic works: it doesn't re-use the existing weapon (the one the player has upon death), but creates a new instance instead. Then it checks the AmmoGive1 and AmmoGive2 values on the existing weapon, and if they are greater than 0, then the values of AmmoGive1 and AmmoGive2 on the newly created weapon are replaced with the deceased player's corresponding ammo amounts. Normally, if the weapon uses ammo, then AmmoGive1 is never 0 (at least in vanilla Doom). However, it can become 0 if the weapon has been previously dropped with the "weapdrop" command. In this case, the AmmoGive values on the new weapon instance created upon death will not be replaced with the player's ammo amounts, and the weapon will have its default AmmoGive values instead.

To reproduce this, no test samples are needed. Two testing procedures are given below, one to demonstrate the normal behavior and another one to demonstrate the buggy behavior. The code blocks are console commands.

Normal behavior

1. Load any map, then give / summon a weapon and some ammo, for example, a shotgun and some shells:
give shotgun
give shell
give shell

2. In this particular example, you should have 16 ammo (unless altered by the game skill). Now enable sv_weapondrop:
sv_weapondrop 1

3. Then commit suicide:

4. Then resurrect and remove all weapons and ammo from the inventory so that they do not mess up the testing results:
resurrect; take weapons; take ammo

5. Pick up the shotgun that has been dropped upon death and note that it has 16 ammo, as before. This is expected behavior.

Buggy behavior

Start a new game, repeat steps 1 and 2 of the above. Then drop the weapon:

and pick it up again. Note that the weapon still has 16 ammo (this is, of course, to be expected), but not for long. Repeat steps 3, 4, and 5. Now the shotgun has only 4 ammo, which is not expected behavior.

IMO, those AmmoGive checks shouldn't be there, though maybe there is a case when they are actually needed to avoid some other unexpected outcome. Then I have no idea how this may be fixed. Also, speaking of sv_weapondrop mechanic in general, if it is not possible to re-use the existing weapon instance when generating the dropped weapon, I wish that there at least was some function which the newly generated weapon would call on the old weapon instance, so that the old weapon could pass information to the new one. Currently, it is not possible to copy custom state information when the dropped weapon is generated, aside maybe with some gross hack that I have no desire to look for and implement.

Tested in GZDoom 3.6.0, g3.7pre-15-g43c30ff48

Re: Bug: Weapons picked up after being dropped...

Sat Oct 27, 2018 3:33 am

Sorry for the double post and the bump. Just wanted to share some additional thoughts on this.

As for the bug itself: I guess the AmmoGive1 / AmmoGive2 checks are there to prevent the dropped weapon from giving any ammo if the weapon is not supposed to give ammo in the first place. In this case, the bug could be fixed (and the original behavior preserved) by checking the weapon's default values of AmmoGive1 / AmmoGive2 instead of the current ones.

As for the inability to transfer information between the original weapon and the dropped weapon: IMO, this whole mechanic where a copy of the weapon is created on death is flawed. Ideally, there shouldn't be any copies at all, and the dropped weapon should be taken straight from the (former) owner's inventory. In this case, a check could be added to one of the corresponding functions (for example, DetachFromOwner or CreateTossable) where the weapon would check if the owner's health is 0, and if it is, then the weapon's AmmoGive values would be synchronized with its ammo amounts.

However, in case it is currently not possible to implement the above logic for some reason, then a new virtual function could be added (let's name it, say, PlayerDroppedWeapon) which would synchronize ammo by default and could be overridden to enable extra behavior. This function would be called on the existing weapon (which resides in the owner's inventory at the moment of their death) and the newly created (dropped) weapon would be passed to it as an argument.

You may also ask, why does the dropped weapon need to know about the original weapon in the first place? Well, here's an example. Suppose we have a weapon that can switch between different firing modes. We want the dropped weapon to be in the same firing mode that the owner's weapon was in at the moment they died. With the current logic and the lack of any (non-hacky) methods to pass information to the dropped weapon, it is not possible to implement such a mechanic at this time.