In addition to these, take a look at the ZDoom forums project thread for some more development news.


Adding a new BDLite weapon - Revolver

Over on the ZDoom forum, TheEternalStruggler had a request for a pistol weapon, so I'll show how to add one on top of BDLite by creating a project on top! You could equally just go in and add all this to the PK3 as it is, but this guide will demonstrate how you can build on top of BDLite by defining any extras you need and then merging the projects together. You could also get the player to load the separate PK3s one after the other or provide a batch file to do it, but I prefer to hand the player one unified PK3 for a project.

For this miniature project example, I'll use the revolver sprites from Project Brutality, because this weapon has all the states I need (crucially, the reloading sprites).

We start off by laying out our PK3 folder - I usually create a folder per project, then a "pk3" folder under that which will contain what we want to be packaged into the PK3. The project root directory is then free to fill up with works in progress, graphic source files and miscellaneous other garbage. Using a folder structure like this for a PK3 that just contains a weapon would normally be a bit of an overkill, but it makes things consistent with how the weapon files are laid out in BDLite so that when the files are combined everything is in the right place. In this example, the folder that will contain our pk3 contents is "extension-example-pk3" - a copy of this is available in the PK3 Tools download above.

The sprites can all be dumped into the sprites/weapons/revolver folder - we don't need to change any of them. Then we create our parent DECORATE lump, which will go in the root project folder and will just refer to the pistol's dedicated file. To avoid conflicts with files from other projects when they're merged together, I name the file extension after the project - ZDoom doesn't care about the extension and will pick it up as a DECORATE lump regardless.

/DECORATE.bdliteextend
//Weapons #include decorate/weapons/Revolver.txt

Now, to actually program the thing, let's look at Project Brutality's DECORATE definition for this pistol. Oh, bloody hell - let's not, actually, because it's fourteen hundred lines. I don't want to diminish the work that people have put in to Project Brutality, though - one reason that BDLite weapons are so much more manageable is that they take out a lot of features that were in the original mod and its descendants, reducing the combinatorial explosion of different states and inventory items to keep track of when you have the options to dual wield with different firing modes and special actions.

So let's instead do this by starting again and building up from the base BDLiteWeapon class intead. As listed at the top of the base class, we'll need to provide our Spawn, Ready, ReadyLoop, Deselect and Fire states.

Basic /DECORATE/Weapons/Revolver.txt
ACTOR BdRevolver : BDLiteWeapon { //Standard weapon properties - put it at the end of slot 2. Weapon.AmmoGive2 6 Weapon.SlotNumber 2 Weapon.SelectionOrder 2000 Weapon.SlotPriority 1 Obituary "%o was revolved by %k's revolver." Inventory.PickupSound "weapons/rifle/clip" Inventory.Pickupmessage "Now you'll see why they call me Revolver!" //We deal with taking ammo manually - these ammo type properties are just here so that the ZDoom HUD highlights them. Weapon.AmmoType1 "RifleAmmo" States { Spawn: RVIC A -1 //Ready plays the draw animation then falls through to ReadyLoop. Ready: TNT1 A 0 A_PlaySound("weapons/rifle/clip") REVR A 2 Offset(-50, 80) REVR A 2 Offset(-30, 65) REVR A 2 Offset(-15, 50) ReadyLoop: //Setting these two flags on WeaponReady allows us to trigger a reload or grenade ("zoom"). REVI A 1 A_WeaponReady(WRF_ALLOWRELOAD | WRF_ALLOWZOOM) Goto ReadyLoop Deselect: //Deselect plays the put-away animation then calls A_Lower like mad to finish. REVR A 2 Offset(-15, 50) REVR A 2 Offset(-30, 65) REVR A 2 Offset(-50, 80) TNT1 AAAAAAAAAAAAAAAAAA 0 A_Lower TNT1 A 1 Wait Fire: //Check we have at least 1 RifleAmmo manually first - if we don't have any, click and return to ready. TNT1 A 0 A_JumpIfInventory("RifleAmmo", 1, "ActuallyFire") REVF C 4 A_PlaySound("weapons/empty") REVI A 4 Goto ReadyLoop ActuallyFire: //Now that we know we can fire, spawn the effects, fire and take away our ammo. TNT1 A 0 A_PlaySound("weapons/rifle/fire") REVF A 3 BRIGHT A_AlertMonsters TNT1 A 0 A_SpawnItemEx("PlayerMuzzle1",30,5,30) REVF B 3 BRIGHT A_FireBullets (0, 0, 1, 14, "HitPuff") TNT1 A 0 A_Takeinventory("RifleAmmo",1) TNT1 A 0 A_FireCustomMissile("Tracer", 0, 0, -1, -12, 0, random(-1,1)) REVF C 3 A_SetPitch(pitch - 0.8) REVF D 3 A_SetPitch(pitch + 0.8) TNT1 A 0 A_Refire Goto ReadyLoop } }

In this example so far, the pistol doesn't require reloading - we take ammunition directly from the RifleAmmo stock. We could define our own unique ammunition for it if we wanted, but for simplicity we'll imagine you can just about physically cram the same bullets from the rifle into this thing. For testing, you can run gzdoom with both the PK3 and the folder for our project together:

c:\games\gzdoom\gzdoom.exe -file .\bdlite\bdlite-snapshot.pk3 .\bdlite\tools\extension-example-pk3

(video)

To add a reloading feature, we need to define a new subclass of Ammo that will represent the number of bullets currently loaded into the revolver. We'll call this "RevolverAmmoLoaded", and will take from this instead of RifleAmmo directly when we fire the weapon - if we find that we have no RevolverAmmoLoaded left, we'll start a reload, which will first check the RifleAmmo stock and transfer bullets from there to RevolverAmmoLoaded if it can.

For more about how the code for these weapons are laid out, check the Structure of BDLite Weapons tutorial.

Final /DECORATE/Weapons/Revolver.txt
//This is the ammo class that represents the bullets currently loaded into the revolver. We want six to be available at a time, and for it not to be affected by the backpack. The inventory icon is used in ZDoom's alternative HUD. ACTOR RevolverAmmoLoaded : Ammo { Inventory.Amount 0 Inventory.MaxAmount 6 Ammo.BackpackAmount 0 Ammo.BackpackMaxAmount 6 Inventory.Icon "RVICA0" } ACTOR BdRevolver : BDLiteWeapon { //Standard weapon properties - put it at the end of slot 2. Weapon.AmmoGive2 6 Weapon.SlotNumber 2 Weapon.SelectionOrder 2000 Weapon.SlotPriority 1 Obituary "%o was revolved by %k's revolver." Inventory.PickupSound "weapons/rifle/clip" Inventory.Pickupmessage "Now you'll see why they call me Revolver!" //We deal with taking ammo manually - these ammo type properties are just here so that the ZDoom HUD highlights them. Weapon.AmmoType1 "RevolverAmmoLoaded" Weapon.AmmoType2 "RifleAmmo" States { Spawn: RVIC A -1 //Ready plays the draw animation then falls through to ReadyLoop. Ready: TNT1 A 0 A_PlaySound("weapons/rifle/clip") REVR A 2 Offset(-50, 80) REVR A 2 Offset(-30, 65) REVR A 2 Offset(-15, 50) ReadyLoop: //Setting these two flags on WeaponReady allows us to trigger a reload or grenade ("zoom"). REVI A 1 A_WeaponReady(WRF_ALLOWRELOAD | WRF_ALLOWZOOM) Goto ReadyLoop Deselect: //Deselect plays the put-away animation then calls A_Lower like mad to finish. REVR A 2 Offset(-15, 50) REVR A 2 Offset(-30, 65) REVR A 2 Offset(-50, 80) TNT1 AAAAAAAAAAAAAAAAAA 0 A_Lower TNT1 A 1 Wait Fire: //Check we have at least 1 RifleAmmo manually first - if we don't have any, attempt to reload. TNT1 A 0 A_JumpIfInventory("RevolverAmmoLoaded", 1, 1) Goto Reload //We have the ammo we need - fire the weapon and return to ReadyLoop. TNT1 A 0 A_PlaySound("weapons/rifle/fire") REVF A 3 BRIGHT A_AlertMonsters TNT1 A 0 A_SpawnItemEx("PlayerMuzzle1",30,5,30) REVF B 3 BRIGHT A_FireBullets (0, 0, 1, 14, "HitPuff") TNT1 A 0 A_Takeinventory("RevolverAmmoLoaded",1) TNT1 A 0 A_FireCustomMissile("Tracer", 0, 0, -1, -12, 0, random(-1,1)) REVF C 3 A_SetPitch(pitch - 0.8) REVF D 3 A_SetPitch(pitch + 0.8) TNT1 A 0 A_Refire Goto ReadyLoop Reload: //When we reach Reload, we want to check to see if we're already full (because we can come here at the player's request) and if we have any RifleAmmo that we can use to refill our RevolverAmmoLoaded. TNT1 A 0 A_JumpIfInventory("RevolverAmmoLoaded", 6, "ReadyLoop") //Check maximum capacity TNT1 A 0 A_JumpIfInventory("RifleAmmo",1,"ReloadAnimate") REVF C 4 A_PlaySound("weapons/empty") REVI A 4 Goto ReadyLoop ReloadAnimate: //ReloadAnimate is the start of the genuine reload as the player sees it on the screen. We play the animation of the revolver opening, spit out the spent bullets, and close it again. Note that WeaponReady is called at the start - this lets the player interrupt the reload with a grenade. REVR ABCDE 2 A_WeaponReady(WRF_NOPRIMARY | WRF_ALLOWZOOM) REVR F 2 A_PlaySound("weapons/sshoto") REVR G 2 TNT1 AAAAAA 0 A_SpawnItemEx("BulletCasing", 17, 3, 35, 0, random(3,6), random(3,7)) REVR HIJ 2 TNT1 A 0 A_PlaySound("weapons/sshotc") REVR K 6 REVR LM 2 REVR DBA 2 ReloadAmmo: //After the reload animation completes, this construct will loop, removing 1 from RifleAmmo and adding 1 to RevolverAmmoLoaded until the latter is full or the former is depleted. This completes the reload and returns to ReadyLoop. TNT1 A 0 A_JumpIfInventory("RevolverAmmoLoaded", 6, "ReadyLoop") TNT1 A 0 A_JumpIfInventory("RifleAmmo", 1, 1) Goto ReadyLoop TNT1 A 0 A_Giveinventory("RevolverAmmoLoaded",1) TNT1 A 0 A_Takeinventory("RifleAmmo",1) Goto ReloadAmmo } }

Once you're happy with how the weapon works, check the Building a project with BDLite tutorial to put it all together - you can either re-zip the BDLite PK3 together with your files, or use the provided build-bdlite-extension tool to automate it.