Tutorials & Guides / [LOCKED] The nearly complete guide to building custom projectiles.

Bolt Action Gaming
GameGuru Tool Maker
Years of Service
User Offline
Joined: 24th Oct 2013
Location: Harrisburg, PA (USA)
Posted: 7th Jun 2019 17:54
Basic concept of building custom projectiles.
Projectiles have long been implemented in GameGuru but in years gone by the implementation was poor at best.
Previously the best one could manage was to modify the three hardcoded ones (fireball, handgrenade, rpg) and use them in a way that better suited your needs. While this DID function, it had some difficulty covering more than just some very direct edge cases.

Since DX11 and more recently the 11/26 update, there's been a large change to the projectiles system which allows users to make much more advanced and capable projectiles.

I've recently delved into the mechanics of making projectiles work for my upcoming book. While I didn't get a chance to have the information ready for publication, I did discover quite a lot that I'll be providing here and now.

So let's start with the basics. Right out of the gate there are two halves of a projectile. The first half is the actual weapon being used in files\gamecore\guns\whatever. The most important piece of that is the gunspec file as that controls all of the behavior of the weapon itself. This includes rate of fire, weapon type, model, animations, textures, and sounds. Most of these behave normally but the key thing we're interested in here is the type of attack it is. Most of them break down into one of three types:
1) Single button push, single fire. Holding does nothing (Hand Grenade/RPG/Shotgun/Rifle/Magnum).
2) Single button push, single fire. Holding button down continues slow rate of fire (1911)
3) Single button push, single fire. Holding button down fires full auto (Uzi). This is far and away the most interesting one to use, in my opinion.

The rest of the statistics are mostly about setting up the weapon itself, such as fire rate.

The important piece here, however, is we need to add two lines if they don't already exist:

Name is replaced with the foldername underneath the projectiletypes folder, which we will get to shortly.

One consideration is I kept running into issues with the projectiles simply not working. When they fail, it frequently is because of the actual folder naming. For instance, I was using:


Which would intermittently fail.

The reason for this is twofold. First, it appears the code has difficulty handling sub-folders. Moving it to this format helped:


Second, inside of the projectiletypes folder is a projectile.txt file that is named ... really whatever you want. This name should match your foldername! If it does not, it may fail. An example of a failure is:


You'll know your projectiles are failing when your projectile based weapon instead acts like a raycasting gun that doesn't fire a projectile. An example of a properly setup projectile is:


Now assuming you've followed the above naming convention, then your flak= and projectile= lines in the above example will look like this:


Once you add those two lines, with a properly configured projectile (a very important contigency), some of the settings you normally rely on (damage, for instance) are now going to be pulled from the projectile information instead of from the gunspec file.

With respect to the gunspec file, my best recommendation is take a weapon you want to modify and copy it's folder, rename the folder, and then add the flak & projectile lines in to convert it. Example:

gamecore\guns\modern\uzi ---> gamecore\guns\custom\flamethrower

Once you do that, simply open the gunspec, and point it to your projectile folder.

With respect to projectile folders most of you will have 4 solid examples to work from.

- The Hand Grenade
- The RPG
- Fireball
- The Magic Bolt (*)

Now the first three are legacy items that function readily enough with a copy and paste and some modification. Each one works out of the box with minor modification. You simply copy the folder using the aforementioned naming convention and change various elements.

These basic changes are anything from texture modification to simple setting changes like adding additional bounce or damage.

So let's get into some of those settings before we get into the more complex elements of this.
Bolt Action Gaming
GameGuru Tool Maker
Years of Service
User Offline
Joined: 24th Oct 2013
Location: Harrisburg, PA (USA)
Posted: 7th Jun 2019 17:54 Edited at: 7th Jun 2019 17:55
Many of these settings have some form of simple commented documentation but this should help you understand better what they do:

Mode configures what kind of projectile this will be. 0 is basically 'not a projectile', while 1 and 2 are stated as dynamic (moving/changing) or static (nonmoving/changing).

Cachenumber controls the number of pre-cached projectiles. Over-caching can cause memory issues but does have value (as you will see later). I have cached at most 100 at a time. There are hard limits, however, that cannot be avoided which we will also see later.

object is your model id. The models appear to have a poly mesh scan done for physics as well so your model shape will matter as it doesn't use a simple physics box or capsule. I recommend a low poly model that meets your needs. Good choices can be found in the FPSC Classics folder, if you have that. Many of our examples will rely on those.

Texture D/N/S will control your DNIS textures. Please note, I never successfully achieved getting illumination working on projectiles. Assume it doesn't work until someone else proves me wrong

Scalemin/max (XYZ) controls the percent the projectile can scale when it comes out. This allows for variability in the projectile sizes. The default value is typically 100/100, ensuring it's a consistent size. Configuring it to 50/150 would give every projectile a size based on a random value in the range of 50 through 150.

Avoidplayerpenetration helps configure whether the projectile will start inside the player or not. Sometimes you may need to configure this value to higher unit levels to get it to start in the proper location. For instance, with my plasma thrower, setting it to 30 ensured it was 30 units out from the player. This corrected an issue where shots were emanating BEHIND the player to start.

Attach to weapon limb corresponds to the weapon limb used by the first-player model used.

AccuracyX/Y controls the inaccuracy of the projectile on an X/Y axis, similar to gunspec's configuration setting. While gunspec controls the point of origin for the initial shot, however, this controls the initial LAUNCH direction of the projectile.

Life and range are two very important settings. They control how long a projectile lives when isn't destroyed by other means (such as hitting an enemy or exploding). As far as I can tell, in both cases it ALWAYS explodes when it reaches maximum life or range. I recommend severely reducing the range value and life value. This is because if you are using many projectiles, you want as FEW ACTIVE PROJECTILES AS POSSIBLE. This will ensure minimum problems or wonkiness.

SpeedMin and speedMax act as a range in units per second of speed. Each projectile will come out between that variable range for it's INITIAL SPEED (pre-thrust). Very high values for speed can cause errors with the life/range detection, so be careful going over 800 or so. If you want a consistent speed, make these values matching.

Damage configures your raw 'damage on hit' value. This is modified by damagerandom, which should ALWAYS BE LESS THAN DAMAGE. Otherwise you leave the possibility of doing 0 damage on a hit.

Fulldamagerange is a weird setting. It causes damage to reduce as it approaches maximum range. This value acts as the high end range for that value and thus reduces damage at extreme range, if that's something you want to do.

Damageradius controls the radius of the unit's explosion upon the projectile's end of life. The FORCE of the blast, however, seems unmodified.

Thrusttime and thrustdelay allow interesting possibilities. They control how LONG a projectile will thrust forwards (adding velocity on top of speedmin/max) and WHEN it will begin (the delay after firing before it's initial speed is increased by the thrust value (which rapidly ramps up speed). The value of actual thrust is controlled later through thrustModifier. We'll get that one in a bit.

Next are the speedangmin/max (XYZ) settings. These are values that control the 'angular speed of a projectile'. Basically it will cause it to pitch/roll/yaw but not actually change the direction of travel.

Speedturnmin/max XYZ, however, DOES control the direction of travel and can allow you to create wildly random projectile arcs upon firing. Generally speaking you won't want much here for most projectiles, barring specific examples (see examples section below).

The physics settings are bundled into several pieces. First is 'userealphysics'. This uses a boolean flag (0 is off, 1 is on). Now bear in mind that physics are always partially enabled for projectiles, so what this does (as far as I can tell) is enable whether secondary physics effects beyond actual collisions work such as air friction, ground friction, etc.

Those settings are controlled via 'gravitymodifier' - which controls what % gravity will pull on the projectile. 1.0 = 100% and airfrictionmodifier which configures how much friction the 'air' has in the game on it as it flies forward (affecting forward velocity). Groundfrictionmodifier controls how much it skids or rolls along the ground.

Now we see 'thrustModifier' in the middle of the physics settings, for some inexplicable reason. This setting controls what % of the initial speed is added to the projectile per second while thrusting. For example, if you have an RPG with an initial speed of 150 and it's set to thrust for 3 seconds after launch at 1.0 (100%) thrust, it will start slow and end up very fast (150 --> 300 --> 450 --> 600!).

Bounceflag is a simple boolean flag for ANY projectile that determines if it will bounce when it hits something. Bounce modifier controls how much of it's original velocity is retained after the bounce as a percentage. The example for handgrenade shows .5, which is 50%. I prefer values between .15 and .30 (15 and 30%, respectively).

Sound, soundloopflag, sounddopplerflag, sounddopplerbasespeed, soundinterval, are all fairly well documented. Sounddeath is the 'death of the object' sound, or the explosion sound.

There are also many 'result' flags. These flags control the effect of the projectile upon reaching specific conditions. The flag can be a 0 for 'nothing', 1 for 'damage hit object' or '2 create explosion'. 0 and 2 work fairly reliably. 1, however, causes the object to 'disappear' upon dealing damage, removing it's persistence from the world.

Resultendoflife controls what happens when the life value is exceeded.
Resultifdamaged is if it gets hit by the enemies in mid-air. This, in my testing, seems ignored.
Resultifdamageddelay controls a delay on what happens after the hit in midair. Again, seems not to work.
Resultoninterval means this object can basically explode constantly on a set interval.
resultonintervaltime controls the time in MS that this occurs. I have not extensively tested this system.
Resultbounce controls the result if it detects a collision. In most cases, if you want your object to bounce, you'll leave this on 0.

There's also a simple particletype setting that is in the fireball/handgrenade/rpg folders you can apply to any of your custom projectiles based on these. Please bear in mind these use the OLD system which rely on the lackluster projectiles built into GG.

Please note that this system was DRASTICALLY overhauled in the upgraded new particle effects system which is demonstrated in the magicbolt projectile.

So the above is actually nothing new. If you've been monkeying with projectiles, as I have, for several years all of this is just introductory groundwork.
Bolt Action Gaming
GameGuru Tool Maker
Years of Service
User Offline
Joined: 24th Oct 2013
Location: Harrisburg, PA (USA)
Posted: 7th Jun 2019 17:54 Edited at: 7th Jun 2019 17:55
Advanced projectiles (magicbolt)

The magicbolt projectile exists as a means for regular joes to examine the newer settings available as part of the expanded particles system built into GG as of 11/26/2018. This particle effects system allows a massive overhaul to the existing particle library and nearly complete customization of the actual projectile particle system itself as well.

So starting in the magicbolt.txt file, you can see right off the bat there are two significantly different settings.
effect = decal_animate8.fx
noZWrite = 1

Effect allows a huge range of potential shader effects to be added to our projectiles. While obviously I haven't tested them all, I have tested the pre-made ones as well as a few other decal sheets and they work just fine. This might open the way up for illuminated projectiles, but again, I haven't tested this yet. It makes REASONABLE sense it would work.

The remainder of the file is mostly identical to previous iterations, save at the bottom. So let's scroll all the way down.

Our 'simplistic' particle setup has now taken a drastic departure to this:

overridespotlighting = 1 - This boolean value either enables an override on the spotlighting of the weapon or on the projectile. There are a limited number of spotlights available so expect this to only ever show 1 at any given time.

particleType = 99 - While the traditional 0,1,2 and 3 still remain, we now have a special '99' value which when entered, allows us to configure a custom graphic for the particle trail. This is an 8x8 sprite sheet by default.
particleName = trail.dds - A DDS file which is used as a sprite sheet for the effect trail. If you are using a custom one, you MUST save it with mipmaps or else the projectile will fail to load.

Past this we also can greatly configure a custom explosion now.

explosionType = 99 - When we set this value to 99, it will allow us to customize the graphic for the explosion. This is, in my opinion, a huge leap forward. The explosions are a multi-layered system consisting of the explosion, some sparks, and a smoke cloud (rising upwards).
explosionName = explode.dds - This is the explosion sprite sheet, which again follows an 8x8 format and requires mipmaps to be saved on the file to function properly.
explosionLightFlag = 1 - This is a boolean flag which configures whether the explosion will create a light spot or not (about 100 units wide). 0 is no light spot, 1 is a light spot.
explosionSmokeName = smoke.dds - This is the smoke sprite sheet, which again follows an 8x8 sprite sheet format and requires mipmaps to be saved to function properly. That said, if you do not specify smoke, the default smoke will be selected.
explosionSparksCount = 20 - A raw spark number. I am not able to confirm, but I experienced great difficulty getting this value to work with anything other than a 0 (no sparks) or 20 (the default value).

projectileEventType = 1 - This is a global event trigger in Lua you can use and hook into, in case you want to really setup some cool effects (such as custom particles systems, physics effects, or the like).

Now, in parsing the github code, there's also an undocumented function or two.
'explosionSmokeSize' - this allows you to configure the size of the custom smoke graphic listed above. It's a 0-1 value taken as a percentage, so 1.0 is 100%, 1.5 is 150%, .5 is 50%, and so on.
'explosionSparksSize' - this allows you to configure the size of the custom explosion sparks listed above. It's a 0-1 value taken as a percentage, so 1.0 is 100%, 1.5 is 150%, .5 is 50%, and so on.

Please also note if you have logging enabled, that images not being found WILL show in your log files as: Could not find particle image file specified by particleName" or similar.
Bolt Action Gaming
GameGuru Tool Maker
Years of Service
User Offline
Joined: 24th Oct 2013
Location: Harrisburg, PA (USA)
Posted: 7th Jun 2019 17:54 Edited at: 7th Jun 2019 18:05
Specific examples (to be added at a later date when I have time at the right PC):
Videos for now, actual txt files available soonish

1- The plasma launcher

(sound is desynced, I will fix later). This is an older video which also demonstrates not only a gun being included with my book but also the problem of the projectile spawning behind the player.

2- The flamethrower

Sound is desynced and this is before my more recent attempts for fixing the flamethrower which require a custom shader AND a custom object file.

3- The dynamite
This is the DX11 copy:

Features custom projectile, smoke, sparks, PBR textures, etc.

This is the DX9 copy (no special custom projectile stuff past editing default particles).

Again, sound is desynced.

4- The tennis ball

The tennis ball is a grenade that bounces off enemies, doing no damage. It 'explodes' but the damage is 0, the radius is 1, and the custom explosion is an empty sprite sheet.

5- The drunk missiles
So Rise of the Triad is one of my favorite dumb shooters and I absolutely love the 'drunk' missiles in them. I've emulated them here in this quasi-goofy video for GG. This one requires some changes to the gunspec and massive changes to the projectile text file.

Forum Support
Years of Service
User Offline
Joined: 24th Jan 2014
Posted: 7th Jun 2019 18:24
Awesome thanks I will have a good read through later
The only person ever to get all his work done by "Friday" was Robinson Crusoe..
Forum Support
Years of Service
User Offline
Joined: 27th Aug 2002
Location: United Kingdom
Posted: 7th Jun 2019 19:06
Very cool B A G Thank you

Windows 10 Pro 64 bit
GeForce GTX 1050 Ti
AMD FX (tm)-9590 Eight-core Processor
31.96 GB RAM
1920x1080,60 Hz
3D Media Maker
Years of Service
User Offline
Joined: 5th Jun 2014
Location: South Africa
Posted: 9th Jun 2019 06:50
Thanks for this, B.A.G., very useful.
i3 8350k 3GB GTX1060 8GB RAM Windows 10

Login to post a reply

Server time is: 2024-05-28 12:58:13
Your offset time is: 2024-05-28 12:58:13