Example of a Gun That Actually Reloads

Handy guides on how to do things, written by users for users.
Forum rules
Please don't start threads here asking for help. This forum is not for requesting guides, only for posting them. If you need help, the Editing forum is for you.

Example of a Gun That Actually Reloads

Postby FluorescentGreen5 » Sat Apr 29, 2017 12:25 am

Gunlabs' tutorial of weapon reloading demonstrates a weapon that takes from both the main ammo supply and the dummy ammo. Personally I find that a bit crude. Brutal Doom (and other big mods) has a proper reload system, where is only takes from the gun's 'internal' ammo supply and then transfers ammo from the main ammo supply to the gun's 'internal' ammo supply. I have written my own code that does that, and even incorporated the "TIF_NOTAKEINFINITE" flag to allow infinite ammo power-ups to take effect, something that mods with reload don't usually do.

Didn't read the whole tutorial, how silly of me. Anyway, this is just a refined version of GunLab's Weapon Reload Tutorial.

I can understand why some mod makers went with the "count the shots and then inconvenience the player" method, I mean, just look at how complicated this code is:

Here's my code:

Code: Select allExpand view
Actor Pistol2 : Pistol //Note that you should use "Pistol2PickUp" for obtaining the weapon.
{
   Weapon.SlotNumber 0 //To make it easier to differentiate it from the original pistol.
   Weapon.AmmoType1 "PistolLoad"
   Weapon.AmmoGive1 20
   Weapon.AmmoUse1 1
   Weapon.AmmoType2 "Clip"
   AttackSound "weapons/pistol"
   
   +WEAPON.AMMO_OPTIONAL //Prevent the weapon from deselecting when running out of ammo, allowing the player to reload it.
   
   States
   {
      Ready:
         PISG A 1 A_WeaponReady(WRF_ALLOWRELOAD)
      Loop
      
      Fire:
         PISG A 0 A_JumpIfNoAmmo("Reload")
         PISG A 4
         PISG B 0 A_FireBullets(5.6, 0, 1, 5, "BulletPuff")
         PISG B 6 A_GunFlash
         PISG C 4
         PISG B 5 A_ReFire
      Goto Ready
      
      Reload:
         TNT1 A 0 A_JumpIfInventory("PistolLoad", 20, "Full")
         TNT1 A 0 A_JumpIfInventory("PowerInfiniteAmmo", 1, "InfiniteReload")
         TNT1 A 0 A_JumpIfInventory("PistolLoad", 1, "TopUpReload")
         TNT1 A 0 A_JumpIfInventory("Clip", 20, 1)
      Goto IncompleteReload
         TNT1 A 35 //Reload Animation
         TNT1 A 0 A_TakeInventory("Clip", 20)
         TNT1 A 0 A_GiveInventory("PistolLoad", 20)
      Goto Ready
      
      TopUpReload:
         TNT1 A 0 A_JumpIfInventory("Clip", 20, 1)
      Goto IncompleteTopUpReload
         TNT1 A 35 //Reload Animation
      UnitTopUpReload:
         TNT1 A 0 A_TakeInventory("Clip", 1)
         TNT1 A 0 A_GiveInventory("PistolLoad", 1)
         TNT1 A 0 A_JumpIfInventory("PistolLoad", 20, "Ready")
      Goto UnitTopUpReload
      
      IncompleteTopUpReload:
         TNT1 A 0 A_JumpIfInventory("Clip", 1, 1)
      Goto NoAmmo
         TNT1 A 35 //Reload Animation
      UnitIncompleteTopUpReload:
         TNT1 A 0 A_TakeInventory("Clip", 1)
         TNT1 A 0 A_GiveInventory("PistolLoad", 1)
         TNT1 A 0 A_JumpIfInventory("Clip", 1, "UnitIncompleteTopUpReload")
      Goto Ready
      
      IncompleteReload:
         TNT1 A 0 A_JumpIfInventory("Clip", 1, 1)
      Goto NoAmmo
         TNT1 A 35 //Reload Animation
      UnitIncompleteReload:
         TNT1 A 0 A_TakeInventory("Clip", 1)
         TNT1 A 0 A_GiveInventory("PistolLoad", 1)
         TNT1 A 0 A_JumpIfInventory("Clip", 1, "UnitIncompleteReload")
      Goto Ready
      
      InfiniteReload:
         TNT1 A 35 //Reload Animation
         TNT1 A 0 A_GiveInventory("PistolLoad", 20)
      Goto Ready
      
      Full:
         PISG A 1 A_Print("No need to reload.")
      Goto Ready
      
      NoAmmo:
         PISG A 1 A_Print("No Ammo")
      Goto Ready
   }
}

Actor PistolLoad : Ammo
{
   Inventory.MaxAmount 20
}

/*
The specialised pickup for "Pistol2". Will give you the gun's internal ammo when you don't have the
gun already, and will give you the main ammo when you already have the gun. Maybe I should rename
the gun to "Pistol2Weapon" and "Pistol2PickUp" to "Pistol2".
*/
Actor Pistol2PickUp : CustomInventory
{
   Tag "Pistol"
   Inventory.PickupSound "misc/w_pkup"
   Inventory.PickupMessage "$PICKUP_PISTOL_DROPPED"
   
   +INVENTORY.AUTOACTIVATE
   
   States
   {
      Spawn:
         PIST A 1
      Loop
      
      Pickup:
         TNT1 A 0 A_JumpIfInventory("Pistol2", 1, 2) //You could use a state label instead.
         TNT1 A 0 A_GiveInventory("Pistol2")
      Stop
         TNT1 A 0 A_GiveInventory("Clip", 20)
      Stop
   }
}


This code can be simplified, but doing so will create overhead (if you're learning actual programming you'll know that it means it will requires more processing power). But if you don't care, here you go:

Code: Select allExpand view
Actor Pistol2 : Pistol //Note that you should use "Pistol2PickUp" for obtaining the weapon.
{
   Weapon.SlotNumber 0 //To make it easier to differentiate it from the original pistol.
   Weapon.AmmoType1 "PistolLoad"
   Weapon.AmmoGive1 20
   Weapon.AmmoUse1 1
   Weapon.AmmoType2 "Clip"
   AttackSound "weapons/pistol"
   
   +WEAPON.AMMO_OPTIONAL //Prevent the weapon from deselecting when running out of ammo, allowing the player to reload it.
   
   States
   {
      Ready:
         PISG A 1 A_WeaponReady(WRF_ALLOWRELOAD)
      Loop
      
      Fire:
         PISG A 0 A_JumpIfNoAmmo("Reload")
         PISG A 4
         PISG B 0 A_FireBullets(5.6, 0, 1, 5, "BulletPuff")
         PISG B 6 A_GunFlash
         PISG C 4
         PISG B 5 A_ReFire
      Goto Ready
      
      Reload:
         TNT1 A 0 A_JumpIfInventory("PistolLoad", 20, "Full")
         TNT1 A 35 //Reload Animation
      UnitReload:
         TNT1 A 0 A_JumpIfInventory("Clip", 1, 1)
      Goto Ready
         TNT1 A 0 A_JumpIfInventory("PistolLoad", 20, "Ready")
         
         TNT1 A 0 A_TakeInventory("Clip", 1, TIF_NOTAKEINFINITE)
         TNT1 A 0 A_GiveInventory("PistolLoad", 1)
      Goto UnitReload
      
      Full:
         PISG A 1 A_Print("No need to reload.")
      Goto Ready
      
      NoAmmo:
         PISG A 1 A_Print("No Ammo")
      Goto Ready
   }
}

Actor PistolLoad : Ammo
{
   Inventory.MaxAmount 20
}

/*
The specialised pickup for "Pistol2". Will give you the gun's internal ammo when you don't have the
gun already, and will give you the main ammo when you already have the gun. Maybe I should rename
the gun to "Pistol2Weapon" and "Pistol2PickUp" to "Pistol2".
*/
Actor Pistol2PickUp : CustomInventory
{
   Tag "Pistol"
   Inventory.PickupSound "misc/w_pkup"
   Inventory.PickupMessage "$PICKUP_PISTOL_DROPPED"
   
   +INVENTORY.AUTOACTIVATE
   
   States
   {
      Spawn:
         PIST A 1
      Loop
      
      Pickup:
         TNT1 A 0 A_JumpIfInventory("Pistol2", 1, 2) //You could use a state label instead.
         TNT1 A 0 A_GiveInventory("Pistol2")
      Stop
         TNT1 A 0 A_GiveInventory("Clip", 20)
      Stop
   }
}


You will need to change a lot of things in the code to suit your needs.
Let me know if I should add anything to the tutorial.
Last edited by FluorescentGreen5 on Mon May 01, 2017 4:10 am, edited 2 times in total.
User avatar
FluorescentGreen5
Is it a crime to enjoy Brutal DOOM?
 
Joined: 24 Dec 2016

Re: Example of a Gun That Actually Reloads

Postby wildweasel » Sat Apr 29, 2017 12:40 am

FluorescentGreen5 wrote:Gunlabs' tutorial of weapon reloading demonstrates a weapon that takes from both the main ammo supply and the dummy ammo. Personally I find that a bit crude. Brutal Doom (and other big mods) has a proper reload system, where is only takes from the gun's 'internal' ammo supply and then transfers ammo from the main ammo supply to the gun's 'internal' ammo supply

With due respect, I wonder if you read the entire tutorial? While I do Duke style reloads at first, the Gunlabs code does eventually have a proper per-bullet reload system by the end of the tutorial. Unless you meant something else?
User avatar
wildweasel
「お前はもうトースト」[you are already toast.]
Moderator Team Lead
 
Joined: 15 Jul 2003

Re: Example of a Gun That Actually Reloads

Postby FluorescentGreen5 » Sat Apr 29, 2017 1:57 am

wildweasel wrote:
FluorescentGreen5 wrote:Gunlabs' tutorial of weapon reloading demonstrates a weapon that takes from both the main ammo supply and the dummy ammo. Personally I find that a bit crude. Brutal Doom (and other big mods) has a proper reload system, where is only takes from the gun's 'internal' ammo supply and then transfers ammo from the main ammo supply to the gun's 'internal' ammo supply

With due respect, I wonder if you read the entire tutorial? While I do Duke style reloads at first, the Gunlabs code does eventually have a proper per-bullet reload system by the end of the tutorial. Unless you meant something else?


It seems I have dun goofed. But then again, the GunLabs tutorial wasn't exactly the cleanest. I will replace what I have with a refined version of their code.
User avatar
FluorescentGreen5
Is it a crime to enjoy Brutal DOOM?
 
Joined: 24 Dec 2016

Re: Example of a Gun That Actually Reloads

Postby Matt » Fri Jan 05, 2018 7:24 pm

If we're going to have a reloading tutorial on the first page of this forum can we update it to use countinv and min instead of those loops?

Those 45 lines could be replaced with the following 23:
Code: Select allExpand view
      Reload:
         TNT1 A 0 A_JumpIfInventory("PistolLoad", 20, "Full")
         TNT1 A 0 A_JumpIfInventory("PowerInfiniteAmmo", 1, "ReallyReload")
         TNT1 A 0 A_JumpIfInventory("Clip", 1, "ReallyReload")
         Goto NoAmmo
      ReallyReload
:
         TNT1 A 35 //Reload Animation
         TNT1 A 0
         
{
            //you can replace this with "int tempammocounter..." in zscript
            A_SetInventory("TempAmmoCounter",
                min(
                    20-countinv("PistolLoad"),
                    countinv("Clip")
                )
            );
            A_GiveInventory("PistolLoad", countinv("TempAmmoCounter"));
            if (!countinv("PowerInfiniteAmmo"))
            {
                A_TakeInventory("Clip", countinv("TempAmmoCounter"), TIF_NOTAKEINFINITE);
            }
         }
         Goto Ready

plus 5 lines for the following counter which could be reused for other weapons:
Code: Select allExpand view
actor TempAmmoCounter : Inventory
{
    inventory.maxamount 1000000
    
//or whatever the highest number is that you need
}
User avatar
Matt
Putting the XD into *xdeath since 2007
 
 
 
Joined: 04 Jan 2004
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: Example of a Gun That Actually Reloads

Postby phantombeta » Fri Jan 05, 2018 8:02 pm

Here's something way better for ZScript, although it shouldn't be impossible to port to DECORATE.
Code: Select allExpand view
    Reload:
        TNT1 A 0 {
            if (CheckInventory (invoker.ammoType1, 0) || !CheckInventory (invoker.ammoType2, 1))
                return ResolveState ("Ready");

            int ammoAmount = min (FindInventory (invoker.ammoType1).maxAmount - CountInv (invoker.ammoType1), CountInv (invoker.ammoType2));
            if (ammoAmount <= 0)
                return ResolveState ("Ready");

            GiveInventory (invoker.ammoType1, ammoAmount);
            TakeInventory (invoker.ammoType2, ammoAmount);

            return ResolveState ("ReloadFinish");
        }

With this you don't even need to change anything in the code for different weapons. You could even just shove it into a base weapon class and use the same code for every weapon.
User avatar
phantombeta
In the meadow of sinful thoughts, every flower's a perfect one
 
Joined: 02 May 2013
Location: The United Soviet Socialist Dictatorship of Hueland
Discord: phantombeta#2461
Twitch ID: phantombeta_

Re: Example of a Gun That Actually Reloads

Postby Matt » Fri Jan 05, 2018 8:42 pm

I don't think FindInventory would be available in Decorate, given neither variables nor even "invoker" are, so the counter item and manually inserting the correct ammo class names would still be required.

(but that is an excellent solution and anyone using ZScript should use that instead - I would, however, call an A_SetInventory or whatever to make sure that the FindInventory...maxAmount wouldn't crash)
User avatar
Matt
Putting the XD into *xdeath since 2007
 
 
 
Joined: 04 Jan 2004
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: Example of a Gun That Actually Reloads

Postby ramon.dexter » Sun Jan 07, 2018 4:53 am

phantombeta wrote:Here's something way better for ZScript, although it shouldn't be impossible to port to DECORATE.
Code: Select allExpand view
    Reload:
        TNT1 A 0 {
            if (CheckInventory (invoker.ammoType1, 0) || !CheckInventory (invoker.ammoType2, 1))
                return ResolveState ("Ready");

            int ammoAmount = min (FindInventory (invoker.ammoType1).maxAmount - CountInv (invoker.ammoType1), CountInv (invoker.ammoType2));
            if (ammoAmount <= 0)
                return ResolveState ("Ready");

            GiveInventory (invoker.ammoType1, ammoAmount);
            TakeInventory (invoker.ammoType2, ammoAmount);

            return ResolveState ("ReloadFinish");
        }

With this you don't even need to change anything in the code for different weapons. You could even just shove it into a base weapon class and use the same code for every weapon.


This is just sweet! Thank you! :wub:
User avatar
ramon.dexter
rudebwoy
 
Joined: 20 Oct 2015
Location: Kozolupy, Bohemia


Return to Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest