One of the more obscure tricks with weapons is the ability to add a new firing state (a state that can be activated aside from primary and alternate fire). This is usually used to have a key that specifically zooms or reloads. However, this is actually quite a simple trick.
For reference, here are three wiki pages:
I'll put it in basic terms, then explain each part further. Essentially, you have a dummy inventory item as a flag for the weapon to check for in the Ready state, and this item is given and taken away by a pair of CustomInventory items which are bound to a key.
I'll use a third Fire state as an example. To explain further, we start with our fake inventory item; an item that literally has
no use besides A_JumpIfInventory to check for:
Actor IsFiring : Inventory
{
Inventory.Amount 1 //This doesn't technically need to be here but it's better to make sure
Inventory.MaxAmount 1
-INVBAR //Keeps it from displaying in the inventory bar, but you don't have to worry
States
{
Spawn:
TNT1 A 1
Fail //Keeps it from really doing anything in the world
}
All this will do is sit in your inventory. Now we have an alternate pistol checking for this:
Actor Pistol2 : DoomWeapon 5010 //Named differently so it won't conflict with Doom's
{
Game Doom
Weapon.SelectionOrder 1900
Weapon.AmmoUse 1
Weapon.AmmoGive 20
Weapon.AmmoType "Clip"
AttackSound "weapons/pistol"
Obituary "$OB_MPPISTOL"
+WEAPON.WIMPY_WEAPON
Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"
Decal BulletChip
States
{
Ready:
PISG A 0 A_JumpIfInventory("IsFiring", 1, "AltAltFire") //We're checking for the fake inventory item
PISG A 1 A_WeaponReady
Loop
Deselect:
PISG A 1 A_Lower
Loop
Select:
PISG A 1 A_Raise
Loop
Fire:
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltFire: //Because why not, we're already using altfire!
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltAltFire:
PISG A 4
PISG BBB 0 A_FirePistol
PISG B 6 A_FirePistol //Fires four times so we know it's working
PISG C 4
PISG B 5 A_ReFire
Goto Ready
Flash:
PISF A 7 Bright A_Light1
Goto LightDone
PISF A 7 Bright A_Light0
Goto LightDone
Spawn:
PIST A -1
Stop
}
}
{
Game Doom
Weapon.SelectionOrder 1900
Weapon.AmmoUse 1
Weapon.AmmoGive 20
Weapon.AmmoType "Clip"
AttackSound "weapons/pistol"
Obituary "$OB_MPPISTOL"
+WEAPON.WIMPY_WEAPON
Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"
Decal BulletChip
States
{
Ready:
PISG A 0 A_JumpIfInventory("IsFiring", 1, "AltAltFire") //We're checking for the fake inventory item
PISG A 1 A_WeaponReady
Loop
Deselect:
PISG A 1 A_Lower
Loop
Select:
PISG A 1 A_Raise
Loop
Fire:
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltFire: //Because why not, we're already using altfire!
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltAltFire:
PISG A 4
PISG BBB 0 A_FirePistol
PISG B 6 A_FirePistol //Fires four times so we know it's working
PISG C 4
PISG B 5 A_ReFire
Goto Ready
Flash:
PISF A 7 Bright A_Light1
Goto LightDone
PISF A 7 Bright A_Light0
Goto LightDone
Spawn:
PIST A -1
Stop
}
}
There! Our pistol is checking for that item, and has a new firing state. Now we just need those two CustomInventory items:
Actor Action_Fire : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_GiveInventory("IsFiring", 1)
Fail // It's important that these items end in "Fail" instead of "Stop" or else they are removed from inventory as soon as they are used. Fail will keep them in your inventory.
}
}
Actor Action_FireCancel : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_TakeInventory("IsFiring", 1)
Fail
}
}
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_GiveInventory("IsFiring", 1)
Fail // It's important that these items end in "Fail" instead of "Stop" or else they are removed from inventory as soon as they are used. Fail will keep them in your inventory.
}
}
Actor Action_FireCancel : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_TakeInventory("IsFiring", 1)
Fail
}
}
When Action_Fire is used, it will give the fake item, but when Action_FireCancel is used, it will take it away again. Thus, using one will make the pistol fire, and the other will make it stop. It is important that both of these are given to the player at the start with Player.StartItem, or this will not work.
Now to bind these two items to a key:
AddKeySection "Your Section Name" YourSectionsName
AddMenuKey "Alternate AltFire" +altaltfire
Alias +altaltfire "Use Action_Fire" // + events occur when the key is pressed.
Alias -altaltfire "Use Action_FireCancel" // - events occur when the key is released.
DefaultBind x +altaltfire // only the + event needs to be bound.
AddMenuKey "Alternate AltFire" +altaltfire
Alias +altaltfire "Use Action_Fire" // + events occur when the key is pressed.
Alias -altaltfire "Use Action_FireCancel" // - events occur when the key is released.
DefaultBind x +altaltfire // only the + event needs to be bound.
Check the wiki link above about adding keysections for explanations of what these do. Now, when the key is pressed it will give the item (activating AltAltFire), and when the key is released, it will take the item away (making it stop firing).
And it's that simple! If you want to test it out, here's a full Decorate and KeyConf:
Actor Pistol2 : DoomWeapon 5010 //Named differently so it won't conflict with Doom's
{
Game Doom
Weapon.SelectionOrder 1900
Weapon.AmmoUse 1
Weapon.AmmoGive 20
Weapon.AmmoType "Clip"
AttackSound "weapons/pistol"
Obituary "$OB_MPPISTOL"
+WEAPON.WIMPY_WEAPON
Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"
Decal BulletChip
States
{
Ready:
PISG A 0 A_JumpIfInventory("IsFiring", 1, "AltAltFire") //We're checking for the fake inventory item
PISG A 1 A_WeaponReady
Loop
Deselect:
PISG A 1 A_Lower
Loop
Select:
PISG A 1 A_Raise
Loop
Fire:
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltFire: //Because why not, we're already using altfire!
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltAltFire:
PISG A 4
PISG BBB 0 A_FirePistol
PISG B 6 A_FirePistol //Fires four times so we know it's working
PISG C 4
PISG B 5 A_ReFire
Goto Ready
Flash:
PISF A 7 Bright A_Light1
Goto LightDone
PISF A 7 Bright A_Light0
Goto LightDone
Spawn:
PIST A -1
Stop
}
}
Actor IsFiring : Inventory
{
Inventory.Amount 1 //This doesn't technically need to be here but it's better to make sure
Inventory.MaxAmount 1
-INVBAR //Keeps it from displaying in the inventory bar, but you don't have to worry
States
{
Spawn:
TNT1 A 1
Fail //Keeps it from really doing anything in the world
}
}
Actor Action_Fire : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_GiveInventory("IsFiring", 1)
Fail // It's important that these items end in "Fail" instead of "Stop" or else they are removed from inventory as soon as they are used. Fail will keep them in your inventory.
}
}
Actor Action_FireCancel : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_TakeInventory("IsFiring", 1)
Fail
}
}
Actor DoomPlayer2 : DoomPlayer
{
Player.StartItem "Pistol2", 1
Player.StartItem "Clip", 50
Player.StartItem "Fist"
Player.StartItem "Action_Fire", 1
Player.StartItem "Action_FireCancel", 1
}
{
Game Doom
Weapon.SelectionOrder 1900
Weapon.AmmoUse 1
Weapon.AmmoGive 20
Weapon.AmmoType "Clip"
AttackSound "weapons/pistol"
Obituary "$OB_MPPISTOL"
+WEAPON.WIMPY_WEAPON
Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"
Decal BulletChip
States
{
Ready:
PISG A 0 A_JumpIfInventory("IsFiring", 1, "AltAltFire") //We're checking for the fake inventory item
PISG A 1 A_WeaponReady
Loop
Deselect:
PISG A 1 A_Lower
Loop
Select:
PISG A 1 A_Raise
Loop
Fire:
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltFire: //Because why not, we're already using altfire!
PISG A 4
PISG B 6 A_FirePistol
PISG C 4
PISG B 5 A_ReFire
Goto Ready
AltAltFire:
PISG A 4
PISG BBB 0 A_FirePistol
PISG B 6 A_FirePistol //Fires four times so we know it's working
PISG C 4
PISG B 5 A_ReFire
Goto Ready
Flash:
PISF A 7 Bright A_Light1
Goto LightDone
PISF A 7 Bright A_Light0
Goto LightDone
Spawn:
PIST A -1
Stop
}
}
Actor IsFiring : Inventory
{
Inventory.Amount 1 //This doesn't technically need to be here but it's better to make sure
Inventory.MaxAmount 1
-INVBAR //Keeps it from displaying in the inventory bar, but you don't have to worry
States
{
Spawn:
TNT1 A 1
Fail //Keeps it from really doing anything in the world
}
}
Actor Action_Fire : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_GiveInventory("IsFiring", 1)
Fail // It's important that these items end in "Fail" instead of "Stop" or else they are removed from inventory as soon as they are used. Fail will keep them in your inventory.
}
}
Actor Action_FireCancel : CustomInventory
{
Inventory.Amount 1
Inventory.MaxAmount 1
-INVBAR
States
{
Use:
TNT1 A 0 A_TakeInventory("IsFiring", 1)
Fail
}
}
Actor DoomPlayer2 : DoomPlayer
{
Player.StartItem "Pistol2", 1
Player.StartItem "Clip", 50
Player.StartItem "Fist"
Player.StartItem "Action_Fire", 1
Player.StartItem "Action_FireCancel", 1
}
KeyConf:
ClearPlayerClasses
AddPlayerClass DoomPlayer2
AddKeySection "Your Section Name" YourSectionsName
AddMenuKey "Alternate AltFire" +altaltfire
Alias +altaltfire "Use Action_Fire" // + events occur when the key is pressed.
Alias -altaltfire "Use Action_FireCancel" // - events occur when the key is released.
DefaultBind x +altaltfire // only the + event needs to be bound.
AddPlayerClass DoomPlayer2
AddKeySection "Your Section Name" YourSectionsName
AddMenuKey "Alternate AltFire" +altaltfire
Alias +altaltfire "Use Action_Fire" // + events occur when the key is pressed.
Alias -altaltfire "Use Action_FireCancel" // - events occur when the key is released.
DefaultBind x +altaltfire // only the + event needs to be bound.
Keep in mind, by the way, Fire and AltFire have some special behavior that alerts monsters, and A_Refire only works for Fire/Hold and AltFire/AltHold. Here's another AltAltFire that emulates that behavior:
AltAltFire:
PISG A 4 A_AlertMonsters //Because it alerts monsters as soon as the state is entered.
PISG BBB 0 A_FirePistol
PISG B 6 A_FirePistol //Fires four times so we know it's working
PISG C 4
PISG B 5 A_JumpIfInventory("IsFiring", 1, "AltAltFire") //Fire again if the button is still pressed, like A_Refire.
Goto Ready
PISG A 4 A_AlertMonsters //Because it alerts monsters as soon as the state is entered.
PISG BBB 0 A_FirePistol
PISG B 6 A_FirePistol //Fires four times so we know it's working
PISG C 4
PISG B 5 A_JumpIfInventory("IsFiring", 1, "AltAltFire") //Fire again if the button is still pressed, like A_Refire.
Goto Ready