The way dynamic lights are added to the Pistol, Shotgun, Super Shotgun, and Chaingun in unmodified GZDoom without running any additional mods is by attaching a dynamic light to the player during the PLAYF frame set, which will work because it's just a sprite frame in the world that works like a projectile, attach a light to it, it will work. This method will still work, however only if all your weapons have the same color weapon flash.
It would be strange seeing a yellow flash come from a weapon that fires a blue flash, like a plasma shotgun or something. You can actually observe this behavior in unmodified GZDoom by firing the BFG and you will notice a yellow flash right before the green light comes in from the BFGBall projectile.
This doesn't happen on the Plasma Rifle, Fist, or Chainsaw because the PLAYF frames aren't called during the player animation (from third person or chasecam). I believe this is something defined in the game's source code, because it's not defined in any DECORATE definitions for those three weapons to NOT call that frame.
You can observe all of the light behavior by going into chasecam in GZDoom and firing all the weapons. You will notice the weapons that have a light attached to the player sprite itself are the ones that call the PLAYF frames.
So, enough explaining, let's get onto the tutorial.
The method I would advise using to attach a dynamic light to a weapon that uses a hitscan attack would be to modify the actor's DECORATE definition to fire a dummy projectile, and attach the dynamic light to that. Attaching a light to the first person sprite frame will NOT work. The light will not appear in-game when fired. Why this doesn't work, I'm not sure, but I'm assuming it has something to do with the fact that first person sprites are rendered on screen from the first person perspective and the game wouldn't know how to attach a light to the first person view, since dynamic lights work through being spawned in the world.
So let's start off by writing the dummy projectile definition in DECORATE:
- Code: Select all • Expand view
ACTOR DummyProjectile1
{
Radius 0
Height 0
Speed 0
Damage 0
Projectile
SeeSound "Null"
DeathSound "Null"
+THRUACTORS
+NONSHOOTABLE
+NOGRAVITY
States
{
Spawn:
TNT1 A 4
Death:
TNT1 A 0
Stop
}
}
As you can see, this projectile is set up to be invisible, automatically dies, causes no damage, no speed, no gravity, goes through actors, no sound, etc. You get the idea. You can adjust the tics on the spawn and death frames if you'd like, I've found having 4 or 5 tics on the spawn state and none on death seems to work best (closest to standard PLAYF lights).
If you want more dummy projectiles (to attach different colored lights, since you can't attach two different lights to the same projectile and have it be used for multiple weapons), simply inherit from the first dummy projectile like so:
- Code: Select all • Expand view
ACTOR DummyProjectile2 : DummyProjectile1 {}
ACTOR DummyProjectile3 : DummyProjectile1 {}
ACTOR DummyProjectile4 : DummyProjectile1 {}
Now we want to create our light definitions in GLDEFS:
- Code: Select all • Expand view
flickerlight2 HITSCAN_X1
{
color 0.9 0.8 0.4
size 64
secondarySize 80
interval 1
offset 0 40 0
}
flickerlight2 HITSCAN_X2
{
color 0.3 0.1 0.8
size 64
secondarySize 80
interval 1
offset 0 40 0
}
flickerlight2 HITSCAN_X3
{
color 0.0 1.0 0.0
size 80
secondarySize 96
interval 1
offset 0 40 0
}
As you can see, we have three hitscan lights set up. One is a yellow-ish flash much like you'd expect out of the normal GLDEFS, the second one is a purple-blue flash, and the last is a green flash.
Now we will attach the lights to the objects in question like so:
- Code: Select all • Expand view
object DummyProjectile1
{
frame TNT1A { light HITSCAN_X1 }
}
object DummyProjectile2
{
frame TNT1A { light HITSCAN_X2 }
}
object DummyProjectile3
{
frame TNT1A { light HITSCAN_X3 }
}
So now the dummy projectiles are set up and so are the lights for them. The last step is to attach them to our weapon actors at the right places:
- Code: Select all • Expand view
States
{
Fire:
CHGG A 0 A_GunFlash
CHGG A 0 A_FireCustomMissile("DummyProjectile2", 0, 0, 0, 0, 0, 0)
CHGG A 0 A_FireBullets(5.6, 0, 1, 5, "BulletPuff")
CHGG A 1 A_PlaySound("weapons/chngun", CHAN_WEAPON, 1, 0, ATTN_NORM)
CHGG B 1
CHGG C 1
CHGG D 1
CHGG A 0 A_GunFlash
CHGG A 0 A_FireCustomMissile("DummyProjectile2", 0, 0, 0, 0, 0, 0)
CHGG A 0 A_FireBullets(5.6, 0, 1, 5, "BulletPuff")
CHGG A 1 A_PlaySound("weapons/chngun", CHAN_WEAPON, 1, 0, ATTN_NORM)
CHGG B 1
CHGG C 1
CHGG D 1
CHGG C 0 A_ReFire
Goto Ready
Flash:
CHGF A 1 BRIGHT A_Light2
CHGF C 1 BRIGHT A_Light2
Goto LightDone
}
In the above example, this weapon is set up to fire the purple-blue flash at the same time as the weapon itself fires. The PLAYF frame will still play but the light attached will now match the muzzleflash of the weapon being fired.
You can also redefine the lights for the enemies too if you'd want them to match like so:
- Code: Select all • Expand view
object ZombieMan
{
frame POSSF { light HITSCAN_X1 }
}
object ShotgunGuy
{
frame SPOSF { light HITSCAN_X1 }
}
object 64ChaingunGuy
{
frame CPOSE { light HITSCAN_X2 }
frame CPOSF { light HITSCAN_X2 }
}
I've used this method so far without issue, if someone can suggest areas for improvement it would be much appreciated, and please tell me if I made any mistakes.