Gun kit

The Delta Gun Builders Pack is a set of scripts that allow someone with minimal scripting knowledge to build a professional second life firearm. The scripts are variants of the scripts used in Delta's own weapons and are used by a number of other developers. The pack includes a fully functional pistol with silencer, tools for building guns and extensive documentation. With the addition of the rezzer pack (sold separately) it is also possible to build fast automatic weapons and shotguns; the rezzer pack has two more fully functional examples, a minigun and a shotgun.

The gun pack supports development of weaponry compatible with Linden Damage and also most safezone kinetic types: CCS, DCS etc.

Although the documentation explains how everything works, a degree of understanding of LSL is going to prove useful, and is necessary if you want to add scripts to the gun.

Many adjustable parameters including:

  • Fire mode - Semi, Burst, Auto
  • Bullet speed
  • Magazine Capacity
  • Reload Time
  • Selectable voice channels
  • Pre-defined strings for sounds and animations
and much more.

You cannot use the pack as it stands to make enhanced CCS weapons because the CCS API is not included. If you are a licensed CCS developer we can supply details of how to integrate CCS damage with the gun pack.

The developer version of the gunkit differs from the personal version only in that the guns you make with it can be sold or given to other residents. The technical documentation that follows covers both versions.


  1. Box contents
  2. Getting started
  3. Delta gun script technical reference
  4. Adding scripts
  5. The holstered gun
  6. Ammunition
  7. Slave rezzers
  8. The toolkit
  9. CCS support
  10. Dev pack restrictions
  11. Change log

1. Box contents

  1. The Delta gun script and a clean full perms setup script
  2. Pistol (boxed) (full perms except for the gun script)
  3. Toolkit (boxed): this contains the following delta products and freebies, generally copy no trans:
    • Delta resizer script
    • Delta bullet tester
    • Delta shooting target
    • Delta bullet rezzer
    • Delta channel monitor, set to the HUD channel

If you have bought the developer edition you also have:

  1. Activation notecard: a notecard telling you how to get your trans version of the main script
  2. Key finder: if you don't know your key you'll need this to get the script

As a user of the developer version, you will be able to get updates to the included personal box by rezzing the online manual, but you will need to contact Delta support for the newest personalised script.

If you bought the rezzer extension you also have the rezzer script pack. This has no separate documentation and is explained in this guide. Its contents are:

  1. Rezzer script (copy, trans)
  2. The M-134 minigun (boxed) (full perms except for the gun script)
  3. The Benelli tactical shotgun (boxed) (full perms except for the gun script)

Please note that the M-134 and Benelli models are full perms models that may be purchased on xstreet for a few linden. Thet are supplied as scripting examples, not as weapons for use.

2. Getting started

We suggest you start by unpacking the pistol and testing it. It is pre-set to use channel 5 for commands and its commands are as follows:

/5 draw
draw the gun from its holstered position
/5 sling
return the gun to its holstered position
/5 reload
reload the gun. Note that the supplied gun does not reload automatically, though you can edit the setup so that it will do so.
/5 semi
semi mode (one shot per trigger)
/5 burst
burst mode (pre-set to 3 shots per trigger)
/5 auto
full auto

The round is a simple kinetic round that does default damage in most combat systems (for example 10 damage in CCS). The package also contains a Linden damage round.

Most users will want to script a gun they have already modelled. You can get started by copying all the contents of the pistol into your own model. Or you can play around with the pistol until you are used to making changes.

To make simple modifications to the gun scripting you will need to edit the setup script. All the setting available are listed below. Suppose, for example, that you want to increase the magazine size of the gun from 6 to 10. This is what you would do:

  • Open the gun in the editor, switch to the Contents tab and open the setup script for editing
  • Find the line that says clip=6;
  • Edit the line so that is says clip=10;
  • Save the edited script
  • Whenever you change the contents of the gun the gun script is reset. When the gun script is reset you will see a message saying that it is being setup; wait until setup is complete before trying to use the gun.
  • If you were wearing the gun you must now detach and reattach it. This is because when a script is reset it loses all its permissions, such as its permission to animate your avatar, and you must reattach to get them back again.
  • Now fire the gun. You will find that it has 10 rather than 6 shots before a reload is needed.

If you are feeling more adventurous you can also add scripts of your own that work with the Delta gun script. For example, you could add some new ammunition, or you could implement a particle effect so that the gun emits a wisp of smoke when fired (we included a very simple puff of smoke for semi fire). Some examples of added scripts are given below.

3. Delta gun script technical reference

This section is a listing of the setup script with an explanation of what each line does.

Timing parameters

float t_reload=2.0;

Time to reload the gun. See loopload.

float t_fire=0.0;

Time to fire gun. Note that the script is delayed slightly when a bullet is rezzed; if you leave this parameter set to 0 you will have the gun at its maximum speed.

integer loopload=6;

If this is set to 0 then the gun is reloaded in a single operation taking t_reload seconds. If this is non zero - 2 say - then the gun will be reloaded 2 bullets at a time, each 2 bullet reload will take t_reload and the reload animation will be repeated for each 2 bullet reload.

float t_chamber=0.0;

Time to chamber the next bullet (this is useful for things like bolt action rifles).

float t_draw=0.0;

Length of draw animation

float t_sling=0.0;

Length of sling animation.

float t_autofire=0.0;

This allows you to set a separate time for firing in full auto mode. If this is set to 0 then the time used will be t_fire+t_chamber.

float t_autostart=0.0;

This specifies the delay between the user holding down the mouse button and the start of fire - this can be used for example to start a revolving barrel going. If you set a start auto sound you need to make this at least as long as the sound or it will be cut off.

Multiple rezzers

The next settings are for use with the optional rezzer script. Unless you have added slave rezzers to the gun you should set r_cycle to 0. This will disable all the settings in this section.

float r_dispersal=0.0;

This is for use with shotguns. It is the distance behind the point where bullets are rezzed where the (imaginary) paths of bullets meet. The smaller you make this, the faster bullets spread out when fired by a shotgun.

string r_barrels;

This defines the pattern used by a shotgun. There must be an entry for each pellet to be rezzed; the entries are separated by semicolons and consist of a location in polar coordinates, that is, a distance and an angle in degrees. For example the following string will create a cross shaped pattern with an extra bullet at the center:

string r_barrels="0.0;0.03,0;0.03,90;0.03,180;0.03,270";

You must add 5 rezzers for this to work.

See section 7 for more details of how slave rezzers work.

integer r_initparam=0;

This is the argument to be passed to the bullet on rez. Though listed in this section it has nothing particular to do with slave rezzers.

If you use the supplied collision script in your bullet, take care not to set this to 0. That script assumes that if the bullet is rezzed with start parameter 0 it has been rezzed from inventory for editing, and will therefore not hide the bullet on collision.

integer r_cycle=0;

This is the number of 'rows' in the rezzer matrix. Usually this is set to 1 for a shotgun. To make a gun that fires 10 bullets per second, try a value between 3 and 5 for r_cycle.


integer clip=6;

This is the number of bullets loaded when the gun is reloaded. Note that when slave rezzers are in use, one ammo count is used for each row fired; so for a shotgun this is the number of cartridges, not the number of individual pellets.

string round="Kinetic bullet";

This is the name of the bullet object. The other bullet we have included is the 'Linden bullet' You can use any object you like but most second life bullets use a prim like the one supplied. Make sure it is physical (or the bullet will hang in the air without moving) and temp on rezz (so it doesn't count to the sim's prim count).

float speed=115.0;

This is the fire speed. 120 is about the highest reliable speed.

float rez_fwd=2.0;

This is the distance in front of the gun at which the bullet is rezzed. We recommend leaving this alone. If you make it too small then you will be hit by your own bullets and if you make it too large then you will be unable to hit people standing close to you.

float rez_down=0.2;

This is the distance below the gun at which the bullet is rezzed. It may appear that setting this to zero will give greatest accuracy and indeed such a setting causes the bullet to travel directly towards the cross hairs, but as a result it is obscured by the cross hairs. Most guns therefore fire slightly low so that the user can see the bullet just below the cross hairs.

float rdl=3.0;

This is the length of the round, and is only used for checking. The length of the round times 40 must exceed the bullet speed otherwise bullets will pass through prims without colliding (see ammo).

integer autoreload=0;

This lets you set the gun to either automatically reload when the magazine is empty or have you set it to a manual reload sequence. (0 for manual, 1 for automatic). If you don't mind adding a script, you can also handle reload yourself. Setting autoreload to 2 will cause the link message EMPTY to be sent to scripts when the last bullet of a round is fired. You can, for example, use this to limit access to certain kinds of ammo.

integer notifyammo=FALSE;

This allows you to switch on or off ammo notifications. Ammo notifications are useful if you want to alter the appearance of the gun as ammo decreases but on a fast gun they create a lot of link message traffic, which can be bad for performance.

integer apoint=ATTACH_RHAND;

This determines where the gun must be attached. If you don't mind set it to 0. If you wish to set a point other than the right hand use the constant defined for the lsl function llGetAttached. For example for the left hand use ATTACH_LHAND.

integer showalways=FALSE;

Set this to TRUE if you want the gun to appear in the worn position when attached. If you do this you should not supply a holstered version.


These are self explanatory. The objects named must be in the object inventory or the self test will fail.

string anim_aim="aim";

string anim_hold="ready";

string anim_reload="reload";

string anim_draw="draw";

string anim_sling="draw";

string anim_fire="";

The fire anim is only played in semi mode.

string sound_semi="s_semi";

string sound_burst="s_burst";

string sound_auto="s_auto";

Ths sound is looped during auto fire

string sound_auto_start="";

If set this sound will be played when the user depresses the trigger in auto mode. You must set t_auto_start to be at least as long as this sound lasts or it will be clipped.

string sound_auto_end="";

If set this sound will be played when the user releases the trigger in auto mode.

string sound_ssemi="";

This and the next four sounds are variants of the five above sound for use when the gun is silenced. If left blank the gun will be completely silent when silenced.

string sound_sburst="";

string sound_sauto="";

Ths sound is looped during auto fire

string sound_sauto_start="";

This is the silenced version of s_auto_start.

string sound_sauto_end="";

If set this sound will be played when the user releases the trigger in auto mode.

string sound_dryfire="s_dryfire";

string sound_reload="s_reload";

string sound_draw="s_draw";

string sound_sling="s_draw";

string sound_chamber="";

Note that any sound parameter may be left empty. The demo gun uses the same sound and animation for draw and sling but you are free to supply different ones.

Fire modes

integer modemask=7;

Binary mask setting allowed fire modes as follows:


All the values you want; so for example 4 would mean auto only. The default mode will be the least powerful allowed.

integer nburst=3;

This is the number of shots in a burst. Set it to 0 to disable burst mode. The burst sound is not looped - you must supply one sound with the right number of bangs.

If this is set it overrides the modemask setting for burst

integer auto=-1;

1 enables full auto, 0 disables, -1 takes the setting from the mode mask. This is for backward compatibility, use the mode mask for preference.

This overrides the modemask setting. Use modemask for prefrence as it gives more options.


integer voice=5;

This sets the channel on which the gun accepts voice commands.

integer hud=-909;

This allows you to script other objects to send commands to the gun. When a command is received on this channel the script tests that the owner of the sending object is the same as the gun owner.

Voice commands


This sets the command the user uses to draw the gun. For example, if there is no holstered form you may prefer to set this to "unsafe";


This sets the command the user uses to draw the gun. For example, if there is no holstered form you may prefer to set this to "safe";


This sets the command the user uses to reload the gun.

Note: If you want to handle the reload command yourself, set vc_reload to be empty and then use your COMMAND handler to handle the reload command.



This sets the name by which the weapon if referred to in messages: for example Gun reloaded

Supply a name with an upper case first letter.

4. Adding scripts

You are free to add your own scripts to the gun.

To understand how this works you need to have some understanding of lsl link messages. Whereas objects in second life communicate using chat, scripts within an object communicate using link messages. Link messages can be used to communicate between several scripts in a prim or between scripts in different prims of a link set. The delta gun script sends link messages to allow other scripts to handle events that have occurred.

In lsl a link message is sent using a statement such as

llMessageLinked(LINK_SET,0,"COMMAND",(key) "scopeon");
In this message:
  • LINK_THIS is the prim to which the message is to be sent; in this case, the same prim that contains the sending script;
  • 0 is an integer parameter;
  • "COMMAND" is a string parameter. This is the parameter the delta gun script uses to tell you what sort of event has occurred
  • (key) "scopeon" is a key parameter. This parameter id supposed to be a key, but more commonly is used to pass an extra string parameter using a cast as shown.
In your script you must have a link message handler that will receive notifications from the gun script. This will look like this:
link_message(integer p,integer x,string m,key k){...}
Here the first parameter is the number of the prim from which the message is sent: it isn't normally necessary to use this. The other three parameters are exactly the three that are sent by the llMessageLinked statement.

It is a common scripting mistake to mix the link message sender up with the handler. This will cause errors when you try to save the script. You can sent a linked message from anywhere but the handler must be in the default section or some other section. The code that deals with the message must appear between the two brackets at the end.

The events the gun script will send messages for are as follows:

Unknown command.
When a voice command that the gun script does not recognise is received it will send a COMMAND message. The example above shows what happens if the gun user types /5 scopeon. You can then treat this command yourself. This will be shown in mode detail in our first example below.
Gun fired
When the gun is fired the message FIRE is sent to every prim in the link set. As the name suggests this can be used to implement a wisp of smoke or, more ambitiously, a muzzle flash. The integer parameter sent with the message is used as follows:
1Semi fire
2Burst fire
3Start of auto fire
4End of auto fire fire
Request permissions
The message PERMS is sent when the delta script requests permissions. If your added script needs permissions of any kind (for example to play an animation) this is the time to request them. We don't recommend taking controls: if two scripts try to take controls the results can be unpredictable.
When the gun is drawn or slung the message DRAWSLING is sent with integer parameter TRUE when drawn and FALSE when slung. This can be used to control other attachments such as a holstered gun, and also to alpha out parts of the gun you don't want to appear until needed, such as the scope in the example below. You don't need to use this if you are using the supplied holstered script because the delta gun script has built-in support for that.
Whenever the number of rounds loaded changes, the message AMMO is sent with the integer parameter set to the number left. You can use this for example if you want to change the appearance of the gun to show how many rounds it contains. Note: You must set notifyammo to TRUE in the setup file to receive these messages.
Reload needed
If you set the autoreload parameter to 2 (meaning you want to handle reload in your own script) then the EMPTY link message will be sent when the gun runs out of bullets. You can use the link message RELOAD to trigger a reload.

It is possible to change some but not all of the gun parameters in response to a link message. The link messages to do this can easily be found by examining the setup script, because that script sends each setting using a link message. Useful messages are:

Change ammo. The message
llMessageLinked(LINK_THIS,clip,"ROUND",(key) round);
sets the bullet name to round and the clip to clip just as though you had set those variables in the setup script. If you pass an empty string as round the round will be unchanged. If you pass 0 as the clip argument the old clip size will remain in force. At any event the gun will be reloaded. You can simply reload the gun by using the script llMessageLinked(LINK_THIS,0,"ROUND",(key) "")
Switch the silencer on or off. The message
sets the silencer. If x is 0 the silencer is off. If x is 100 the silenced sounds will be played full volume (meaning silence if they sre set empty). Any other value reduces the normal sound volume by x%.
Switch the gun on or off. The message
can be used to switch the gun on (x=TRUE) or off (x=FALSE). This is intended for use when the gun script is to be embedded in some larger device. Note that the gun cannot be disabled while it is aimed.
This message causes the script to reinitialise the slave rezzers. It must be sent after you have made any changes to the slave rezzer parameters r_dispersal, r_barrels or r_cycle, and also after changing the rezz parameters fwd and dep and speed if you are using slave rezzers as these are cached in the barrel scripts. It isn't necessary to reset the matrix after changing the round. At the moment the matrix must be reset after changing init_param but that is obviously wrong.
This message reloads the gun.
This message causes the gun to leave full auto even though the user has not lifted the mouse button. This happens when the gun is empty but the link message allows the builder to respond to other events.
This message sets the command channel to x.
MODE [1.15]
This message sets the mode to x (0=semi 1=burst 2=auto). The new value is not checked against the mode mask and there is no user message, so you must add your own.

Now for some examples

Set ammo

The first example is a very simple comand handler. This allows the user to switch between the supplied rounds: /5 ldb selects the Linden damage round and /5 kb the kinetic bullet. Remember that commands other than those the script itself understands are passed to your script using the COMMAND link message. This very simple example has nothing but a link message handler: if you want to try it out and are not very sure how to handle scripts try this:

  • Edit the gun, select the content tab and press the new script button
  • A script will be added which (somewhat annoyingly) says "Hello avatar". Look in the content pane: it is called New script. You may want to give it a more useful name.
  • Now open the script and copy the script below over the contents. For example you could highlight the text below, copy it using Ctrl-C, select the script you opened and type Ctrl-A (to highlight all the old stuff) and then Ctrl-V (to replace it with the new).
  • Save the script and wait until the selftest message shows that the gun is working
  • Close the script window, exit the editor and, if you were wearing the gun, detach and reattach it to avoid permission errors.
  • Now draw the gun and type /5 kb in chat: the gun will say Kinetic round selected. You have now added your new command.
In the remaining examples we shall not repeat details of how to edit script.

default {
    link_message(integer p,integer x,string m,key k)
        if (m=="COMMAND") {
            string s=(string) k;
            if (s=="ldb") {
                llMessageLinked(LINK_THIS,0,"ROUND",(key) "Linden bullet");
                llOwnerSay("Linden damage selected");
            } else if (s=="kb") {
                llMessageLinked(LINK_THIS,0,"ROUND",(key) "Kinetic bullet");
                llOwnerSay("Kinetic round selected");


In this example we shall add a silencer to the gun. The user will be able to add the silencer using the command /5 silenceron and remove it using /5 silenceroff.

First make your silencer! It can be as simple or complicated as you like but

  • each prim must be called the same (SILENCER in our example code);
  • textures must all have trasparency 0;
  • prims may be coloured as well as textured but each face of any one prim must be the same color

If these conditions aren't met you'll have to make your own script to hide and show.

Next we need to set up the prim set in the setup script. The line to edit is this one: primsets="";

We're going to specify the silencer as a set of prims each called SILENCER.

Next, a silencer isn't a silencer unless it makes the gun quieter! The SILENCER link message is a little complex so lets start by looking at options we have.

  • We could make the gun go completely silent
  • We could play the same sounds but at reduced volumes
  • We could go out and make special silenced sounds for our gun

To cope with all these options in one link message the x parameter of the linked message is interpreted as follows:

  • If x is 100 silenced sounds will be played full volume; if there are none the gun will be silent
  • If x is less than 100 the normal sounds will be played but with volume reduced by x%. So (special case) if x is zero normal sounds are played at normal volume, that is, no silencer!

Of course the silencer only affects firing sounds. The reload sound isn't affected.

We are going to be lazy and just reduce the sounds we have to 50% volume. So the script needs to do separate things: show or hide the silencer and set the sound volume. Here goes.

string silencer_name="SILENCER"; // Name of prim scope - make sure scope prim has this name
list ls;
integer bSil=FALSE;

    integer n=llGetNumberOfPrims();
    integer i;
    for (i=0;i<n;i++) {
        string s=llGetLinkName(i+1);
        if (s=="SILENCER") ls+=[i];

show_silencer(integer b)
    float a=0.0;
    if (b) a=1.0;
    integer n=llGetListLength(ls);
    integer i;
    for (i=0;i<n;i++) {

setlinkalphafast(integer p,float a)

silencer(integer b) // Show/hide silencer
    integer x=0;
    if (b) x=50;

default {
    link_message(integer p,integer x,string m,key k)
        if (m=="COMMAND") {
            string s=(string) k;
            if (s=="silenceron") {
            } else if (s=="silenceroff") {
        } else if (m=="DRAWSLING")

The script above is in the demo pistol (Silencer script).

Fire effect

Our next example shows how to use a script in a different prim. We want to arrange for a wisp of smoke to appear at the end of the barrel of the gun when the gun is fired. The wisp is a particle effect and particle effects emerge from the prim they are placed in, so if we simply place the script in the root prim the effect will look completely wrong. We use the 1.38 API fast functions to manipuate the particle effect from the root prim.

This is not a tutorial about how to make particle effects and we shall assume you already have one. The various tools available for making effects usually yield a script that fires the effect when reset or when the object is touched. Neither of these is of any use to us but we can at any rate take the particle effect from such a script and reuse it in our prim script.

Particle effects belong to the prim not the script and if you use a script to start one and then remove the script the effect will go on. It's therefore a good idea to arrange a way to stop the effect, and in our script resetting the script will do that.

To add a particle effect to your gun:

  • First make your particle effect, either by scripting or by using a script generator. Either way, when done copy just the call to llParticleSystem().
  • Find a prim near the point where you want the effect or make a very small prim for this purpose and link it in in the right place so it isn't too conspicuous. Give the prim a name (we'll call it WISP) so the script can find it (hard coding prim numbers is a bad idea, you relink the object and forget!).
  • Make a new script and replace its content with the script from below
  • Save the script, detach and reattach if necessary, and fire the gun. You should see a somewhat tenuous wisp of smoke from your prim. Adjust the prim location if necessary.
  • Now replace the list in our version of llParticleSystem() with your own probably much better effect. You'll see that we have PSYS_SRC_TEXTURE set empty so the effect uses no texture; if you want to use a texture remember to add it to the gun too or use its UUID.

This very simple effect is set to work only in semi fire.

string wisp_name="WISP"; // name we called our prim for the particles
integer pw=-1; 

wisp(integer b)
if (b) 
    llLinkParticleSystem(pw+1,[  PSYS_PART_MAX_AGE, 2.000000,
PSYS_PART_START_COLOR, <0.35000, 0.35000, 0.35000>,
PSYS_PART_END_COLOR, <0.15000, 0.15000, 0.15000>,
PSYS_PART_START_SCALE, <0.00000, 0.00000, 0.00000>,
PSYS_PART_END_SCALE, <0.10253, 0.09671, 0.00000>,
PSYS_SRC_ACCEL,<0.00000, 0.00000, 0.30000>,
PSYS_SRC_OMEGA,<0.00000, 0.00000, 0.00000>,

    integer n=llGetNumberOfPrims();
    integer i;
    for (i=0;i<n;i++) {
        string s=llGetLinkName(i+1);
        if (s==wisp_name) pw=i;


    link_message(integer p,integer x,string m,key k)
        if (m=="FIRE" && x==1) {

This is the Wisp script in the demo pistol.

Magazine eject

Finally a simple example to show how to handle reload in your own script. In this case we want the gun to autoreload but we also want to add an effect - dropping a spent magazine. Remove the lines commented autoreload if you don't want autoreload. For this example you need an object called mag: make it physical (or it will float in the air) and temporary (or it will lie there forever); also a suitable sound which we have called clink.

// For this script to work you need the following settings in the setup script:
// integer autoreload=2;
// string vc_reload="";


    link_message(integer c,integer x,string m,key k)
        if (m=="EMPTY")                                    // autoreload
        {                                                  // autoreload
            spent_mag();                                   // autoreload
            llMessageLinked(LINK_THIS,0,"ROUND",(key) ""); // autoreload
        }                                                  // autoreload
        else                                               // autoreload
        if (m=="COMMAND") {
            string c=(string) k;
            if (c=="reload") {
                llMessageLinked(LINK_THIS,0,"ROUND",(key) "");

5. The holstered gun

Making a holster

The holstered form of the pistol supplied is just the pistol with a very simple holster added. Whereas the working form goes in your hand, the holstered form attaches to your hip. The two models supplied work as a pair: when the gun is drawn the gun part of the one on your hip becomes transparent and the one on your hand appears; and when it is slung the hand one vanishes and the one attached to your hip appears.

Suppose first of all that you don't want any of this. You may have designed a gun that is always held in the hand with no holster. Simple: find the variable showalways in the setup script and set it to TRUE. And don't bother wearing the holstered version.

If you simply place the holstered script in your own holster model you will probably find that the entire holster vanishes when you draw the gun. You need to tell the scripts which prims in your holstered gun are holster and which are gun. You do this by naming the prims in the gun ALPHA. Make sure the root prim is part of the holster, because if you name that ALPHA you will change the name of the hostered gun thus causing immense confusion. If you feel you absolutely must have the root prim in the gun for some reason you will have to edit the slung script.

When the gun is drawn the holstered form will behave in different ways depending on whether there are any prims called ALPHA. If there are no prims called ALPHA the whole holstered form will vanish; but if there are prims called ALPHA only those prims will vanish. However, if the script finds that there are no prims called ALPHA it will alpha the entire model.

Be warned that making prims vanish one by one takes longer than making the whole gun vanish. For this reason you need to minimize the number of gun prims in the holstered form. There are several tricks worth knowing:

  • There may be prims in the gun that are concealed by the holster: you can unlink these from the holstered gun and nobody will know. We haven't done this in the simple model but it's a good way of reducing the prim count of a more elaborate gun.
  • If the number of prims in the holster is many fewer than the number in the gun it may be faster to alpha the whole holstered form and then bring back the holster prims. This requires you to edit the slung script.

Having said that, the 1.38 fast link functions have made alphaing of linked prims a lot faster, and the holster script has been rewritten to use them. Unless your gun is very complex you probably don't need to mess about removing hidden prims any more.

Finally for incorrigible scripters we list here the complete slung script. Note the following:

  • The gun listens on the HUD channel, -909, for commands showslung and hideslung. These comands are sent by the gun and are not intended for use by the gun user. If you change the HUD channel you will need to edit the setting in the slung script to the same value
  • If (as mentioned above) you really must include the root prim in the gun part, simply initialise the list la in prim_analyisis() to [0].
  • Prims are numbered from 1 up, the root being 1. As normal software conventions like to number from 0 all prim numbers have to be offset by 1 in the script.
  • The gun listens for comands on the HUD channel, so touching the holster will draw the gun. You can use the HUD listen to make a control HUD for your gun (that's why it's called the HUD channel). Note the test necessary to prevent others from drawing your gun for you!
  • The first line of the listen handler is essential to avoid cross chat; remove it and your holster will vanish when anyone in chat range draws a gun.

integer cc=-909;

list la;

    integer n=llGetNumberOfPrims();
    integer i;
    for (i=0;i<n;i++) {
        if (llGetLinkName(i+1)=="ALPHA") la+=[i];


show(integer b)
    if (la != [] && !b) {hideprims(); return;}
    float a=1.0;
    if (!b) a=0.0;

// Note that the next function only works if you want to
// set all faces of a linked prim to the same alpha and color

setlinkalphafast(integer i,float a)
    list l=llGetLinkPrimitiveParams(i,[PRIM_COLOR,ALL_SIDES]);
    vector col=llList2Vector(l,0);

    integer n=llGetListLength(la);
    integer i;
    for (i=0;i<n;i++) {
        integer p=llList2Integer(la,i);

    on_rez(integer x)

    touch_start(integer total_number)
        if (llDetectedKey(0) != llGetOwner()) return;
    listen(integer c,string n,key k,string m)
        if (llGetOwner() != llGetOwnerKey(k)) return;
        list l=llParseString2List(m,[" "],[]);
        string m=llToLower(llList2String(l,0));
        if (m=="showslung") show(TRUE);
        else if (m=="hideslung") show(FALSE);

Making a HUD

A HUD is a prim attached to the HUD that allows the user to control the gun and may also give visual feedback. The sample HUD supplied with the pistol is a very simple one-prim HUD that allows the user to draw, holster or reload the gun.

What makes the HUD work is the HUD channel, an alternative source of voice commands for the gun. The gun listens both to the command channel (5 by default) and the HUD channel (-909 by default). So all you need to do to make the HUD control the gun is make it whisper the same commands that you would give the gun by voice commands.

The HUD script used in the sample HUD is listed below. In fact most of the script goes into working out which button the user has pressed.

If you want to add feedback from the gun to the HUD, you will have to add a script to the gun that sends data. For example, you might use the AMMO linked message to tell the HUD how many bullets the gun has loaded. You are, of course, free to use any channel you like for communications but it makes sense to use the HUD channel. You will also have to add a listen on the HUD channel to the HUD script, of course.

// To customize this very simple HUD, you need first of all to make
// a texture with buttons for the commands you want. Arrange the
// buttons in a simple table. For each command, work out the chat
// command that it should execute.

// Now customize the script as follows:
// (1) change lcommands to the list og voice commands, reading 
// row by row
// (2) change nbuttonx to the number of columns of buttons 
// (3) change nbuttonx to the number of rows of buttons 
// (4) if you changed the HUD channel in the gun change it here too.

// Texture the HUD with your texture, add your modded script,
// attach the HUD and test that it works with the gun.

integer hudchan=-909;

integer nbuttonsx=1;
integer nbuttonsy=3;

list lcommands=["draw","sling","reload"];

button(integer x)


    touch_start(integer total_number)
        vector v=llDetectedTouchUV(0);
        integer x=(integer) ((1-v.x)*nbuttonsx);        
        integer y=(integer) ((1-v.y)*nbuttonsy);

If you encounter scripting problems with either a holster or the HUD you can use the channel monitor in the toolkit to snoop communications on the HUD channel.

6. Ammunition

A bullet needs to be a physical object (otherwise it won't go anywhere) that will somehow damage an avatar with which it collides and (hopefully) then vanish.

There are two basic ways in which a bullet can damage an avatar.

  • In damage enabled area a bullet can have damage set by a special lsl function. This damage is subtracted from the avatar's health on collision. When the avatar's health falls to zero the avatar is sent home.
  • In non damage areas it is only possible to damage an avatar if they have attached some combat system. Most combat systems will treat physical collisions above a certain speed as bullet impacts. CCS and DCS are examples.

Bullets with Linden damage set will die on impact without more ado; other bullets must be cleared up somehow. It's a good idea to make bullets temp-on-rezz so that they won't count against the sim prim count; it's also a good idea not to rely on this. Include a timer as a failsafe, and delete bullets that hit the ground straight away rather then leaving them around.

If you are planning to make your own bullets yopu need first to understand a little about sl physics. Physics in the real world is continuous; if you throw an object across the room and it hits me then it will occupy every position between us (albeit instantaneously) in the course of its journey. Physics in sl is simulated by a number of timeframes. At each timeframe the positions of all physical objects are calculated based on their speed; if you throw an object at me it will hop forward from timeframe to timeframe. In sl there are about 40 timeframes per second. That means that if you throw an object at me at 80 m/s, it will move precisely two metres each timeframe.

Now let's consider collisions. Suppose the object you threw at me was 1m long and suppose (but only for the sake of argument) that I am infinitely thin. If the center of the object is 1m in front of me at one time frame, it's tip will be 0.5m in front of me and so it won't collide with me. Now let's look back 1/40s later. The object has moved 2m forward and so now it's 1m behind me and it's tail has passed me and is 0.5m behind me. So it's not going to collide now either. So the object has passed right through me without colliding.

What if the object had been 2m long? In that case its tip would have just touched me on one time frame and its tail on the next so it would have collided (not very reliably you may think). If it had been 3m long I'd have been properly skewered

The faster the object, the longer it needs to be to avoid passing through things like this. In fact, if your maths is strong you may have already noticed that there is a formula. If an object is x metres long, the fastest it can reliably travel is 40 times x metres/second. Our 1m object shouldn't have been going above 40m/s and at 80 was definitely speeding! Looked at the other way round, if you want a bullet that travels at 120m/s (and speeds higher than that aren't very reliable in sl physics) it needs to be at least 3m long. Now a 3m long bullet might better be described as a javelin. Bullet makers in sl have a number of tricks to make bullets look OK:

  • Texture part of the bullet length invisible so it looks shorter
  • Keep the bullet really slender or it will push hard, not a popular thing in roleplay sims
  • Alpha the bullet as soon as possible after a collision in case it bounces round before dying

The supplied rounds are 2m long, which means they should not be fired faster than 80m/s. It's easy to stretch them to 3m in the editor if you need a faster bullet.

Assuming you have made your bullet lets look now at scripting

First here is a kinetic bullet script. The bullet should have been set physical and temporary in the editor. All the work of the script goes to deleting the bullet. One small wrinkle is useful rather than essential: make a special case of rezzing the bullet with start parameter 0 so that when you rezz it to edit it it won't die after collisions or timeouts. The gun never rezzes the bullet with parameter 0, but when you rezz an item from inventory the parameter is always 0.

float gTimeToDie = 60.0;

integer bReal=0;

    on_rez(integer start_param)
        if (start_param == 0) return;

    collision_start(integer count)
        if (bReal) {
// insert any combat system specific damage code here
    land_collision_start(vector pos)
        if (bReal) llDie();
        if (bReal) {

For a Linden damage bullet just add the line

to the rezz handler. Remember in this case that the collision handler will not be invoked (that's why it's necessary to set a collision sound rather than just play the sound in the collision handler).

It's useful to add another small script to each bullet. This usually does nothing but may help if there is a lot of lag. You will sometimes find in very laggy conditions that your bullets bounce around alarmingly because the script is still stuck in the rezz code when collision occurs. What follows is just a cosmetic adjustment - it doesn't stop the bullets bouncing, it just means people won't notice so much. It's important to put this in a separate script because the handler in the main bullet script won't start to execute until any other handlers have finished.

integer bReal=FALSE;

list ppdead=[PRIM_COLOR,ALL_SIDES,<1,1,1>,0.0,

    on_rez(integer b)

    collision_start(integer total_number)
        if (!bReal) return;
    land_collision_start(vector v)
        if (!bReal) return;

We recommend for the time being that you compile bullet scripts with the mono checkbox disabled. The overhead of starting the CIL virtual machine and JIT compiling the bytecode each time a bullet is fired appears to outweigh any advantage from the faster resulting code. This only applies to bullet scripts, scripts in the gun itself are best compiled using mono.

Note on buoyancy

If you have made a bullet following all the rules above and carefully limited the speed as suggested you may be disappointed to find that the bullet falls to the ground quite soon. The maximum reliable speed at which sl can process a bullet - around 120m/s - is much lower than the speed of real bullets. As bullets should be next to invisible people will not notice this, but it will show up in limited range. Solving this problem requires a little physics, so we suggest you skip now to the next section unless you need to correct the range of your bullet.

All objects in the earth's gravitational field have an acceleration towards the centre of the earth, and near the surface of the earth the magnitude of this acceleration is approximately 9.8m/s. In second life gravity is simulated by a force that causes the object to move groundwards with this acceleration. As Galileo famously showed neither the horizontal speed nor the mass of the projectile has any effect on the time that it takes for a body to fall to the ground: all that matters is how far off the ground it was when it started. In t seconds the distance an object moves towards the ground is g*t*t/2 where g is the acceleration due to gravity.

It follows that if you fire a bullet from xm above the ground we can find out how long it flies by solving the equation

(we did warn you about the maths!). Bullets are fired from the avatar's camera position - an average value for this is 3.1m above the ground, which makes t about 0.8s. That means that if the speed of your bullet is 80m/s its range will be about 65m. If you are very tall or very short or standing at the top of the leaning tower of Pisa this figure will vary somewhat but let's accept it for now.

The point we are getting towards is that sl provides a mechanism that allows you to vary the effect that gravity has on your bullet: this is called buoyancy. Buoyancy is an upward force and so counters the effect of gravity. When an object has buoyancy 1 the force completely cancels out gravity; if it is less than 1 it reduces the effect of gravity, if it is more than 1 it causes the object to float upwards. So right away we can see that by adding the line

to the state_entry handler of our bullet script we can create a bullet that goes on and on forever.

However, if we really want to see this topic through we should consider other values. If we set buoyancy to b we replace g in the above equations by g(1-b). So the flight time of the bullet becomes

It's easiest to interpret this by looking at what change the buoyancy makes to the range. If we divide the new flight time (and therefore range) by the old lots of the nasty symbols go away and we get the interesting ratio
That means to double the bullet's range we must set b to 0.75 (work it out!) and in general to multiply the range by n we set buoyancy to 1-1/n*n. To treble it we'd make buoyancy 0.888 for example.

So as a reward for getting this far here is a table of approximate ranges of bullets.


The Delta bullet tester (see section 8) is useful for measuring bullet fire rate and range

I'm odd

7. Slave rezzers

Rezzers are an optional upgrade to the gun script added to version 1.14. The gun script will work as before if there are no rezzers in the gun. However, by making a number of copies of the rezzer script the builder can create a rezzer matrix that makes the gun pack suitable for building very fast guns and also shotguns.

Users may wonder why they can't just set the firing interval very short and have a fast gun without any more ado. The answer to this is that Second Life will only allow a script to rezz objects quite slowly, maybe 3 or 4 a second at most. After an object is rezzed the script 'sleeps' for a few frames. If you try to fire faster than that the gun will misbehave, firing slowly and possibly continuing firing after you life the trigger. To get around this you need to add extra scripts to rezz bullets in parallel. The rezzer extension pack lets you do that.

It is intended that by use of rezzers developers should be able to add auto or shotgun support without the need for any scripting. Some of the effects described here will require scripting: for example, muzzle flash. These will be implemented by new link message commands and notifications.

Rezzer matrices

The rezzer script is used to allow fast firing or firing of multiple shots simultaneously, as in a shotgun. Rezzers form a matrix, and although they are in fact multiple copies of the same script, it may help to explain them by reference to a hardware model.

A matrix can be thought of as a battery of guns arranged in a square formation. It has a number of rows and a number of columns. A matrix with n rows and m columns will have n times m guns. For example, a matrix with 6 rows each of two guns would have 12 guns.

Now there are two rules to be remembered:

  1. All the guns in a given column must have exactly the same configuration.
  2. All the guns in a given row must be fired simultaneously
Rows are fired in sequence starting from the front and moving backwards. After the last row has been fired, the first row is fired again.

An arrangement with one row would be suitable for a shotgun. Each 'gun' could be given a slightly different dispersal and offset and all the guns (formed in just one row) would fire one pellet, making up a shotgun effect. A shotgun with 8 pellets is called an 8 by 1 rezz matrix.

An arrangement with one column would be suitable for a minigun. On each shot a new row is fired. As rezzers can take up to 0.5s to recover after firing a minigun firing 10 bullets per second might require 5 rows. This would be called a 1 by 5 matrix.

The number of rows in the matrix is set by the r_cycle parameter. Each row of the cycle is fired in turn. Multiple cycles have no effect on the gun configuration and are simply there to increase speed.

The number of columns in a matrix is set to be the number of semicolon separated entries in the r_barrels string. Each entry determines the location and rotation of the bullet rezzed by that barrel.

The number of rezzer scripts required will be the product of the number of rows and the number of columns. You must copy at least this number of rezzers into the gun before configuring it, otherwise an error will be given. You need do nothing else to the rezzer scripts (in fact you can't because they are no mod); they will be assigned matrix locations by the gun script.

It is possible to reconfigure the matrix in a single gun, but only one matrix will be active at any time. For example, to simulate an assault rifle with a shotgun attachment, a gun might contain a 1 by 2 machine gun matrix and an 8 by 1 shotgun matrix. To switch between the two set the rezzer parameters as required and then send the script the MATRIX linked message.

Rezzer settings

Each column of rezzers shares a number of parameters:

  • Dispersal: This is the local rotation of the 'gun' from camera rotation. In a shotgun the rotations of the rezzers determine the pattern in which pellets are fired. Typically the angle of each rotation will the the same but the axes of the rotations will form a star pattern normal to the end of the gun, causing pellets to emerge in a cone, whose half angle will be the angle of the rotation.
  • Offset: This is the offset of the rezz position for this 'gun' from camera position. Unless this is set non zero all the pellets of a shotgun will collide and have no effect.

Step by step: making a minigun

  1. Decide on the fire rate required in full auto
  2. Divide the bps fire rate required by 2; this is the number of rezzers needed
  3. Make that number of copies of the rezzer script
  4. Add these to the gun's inventory
  5. Set the variable t_autofire in the setup script to the time between shots in full auto
  6. Set the r_cycle parameter to the number of rezzers you copied.

Note that second life timers can be triggered at most 40 times a second, so the best fire rate you can achieve is 40bps; in fact to achieve speeds of this order it is probably better to make a matrix with only 10 or so rows and 4 columns. But any gun firing at this speed will cause damage much faster than most combat systems can register it.

Step by step: making a shotgun

  1. Decide on the number of pellets: this is the number of rezzers needed
  2. Make that number of copies of the rezzer script
  3. Add these to the gun's inventory
  4. Set the variable r_dispersal to the distance of the convergence point of the pellets behind the rezz point
  5. Set the variable r_barrels to the list of barrel settings required
  6. Set r_cycle to 1

Shotgun patterns explained

If you have a shotgun, you may like to start by examining the pattern of shot it fires. You can use the Delta target in the toolbox for this. Fire one shell at the target and examine the pattern. Stand quite close. The image on the right shows the pattern from firing the Delta steam shotgun in this way.

In this case the pattern consists of a single pellet in the center and a circle of eight pellets around it. The circle is squashed into an ellipse by gravity. Using different color markers you can compare the patterns of different shotguns.

When it comes to design your shotgun you need to decide two things: what pattern of pellets do you want, and how fast do you want the pellets to spread out. Shotguns generally have a choke at the end of the barrel to prevent shot from spreading too widely. In a sawed off shotgun the choke is removed and so the pellets are spread more widely, making the weapon very damaging at close quarters but not much use at a distance.

The image on the left shows what happens when the steam shotgun is fired again with the choke removed (blue markers this time). It was fired from the same distance but has spread more widely. One of the pellets has gone missing: this isn't unusual. The important thing to understand is that the same pattern was used for each shot, but the dispersal was changed.

It may help to think of pellets as though they were rays of light. Suppose you were to take a piece of card and punch holes in it, in roughly the pattern in the diagram, that is, with a hole in the middle and a circle of holes around. Now imagine you held a light behind the card so that light shining through the holes fell on a target similar to the one shown. When the light is right up by the card the light will spread out and the pattern on the target will be large. Now as you pull the light back away from the card, the apttern will get tighter and tighter until it's practically indistinguishable from the pattern on the card. The distance between the light and the card is similar to what we call the dispersal. The higher the dispersal, the closer packed the pattern will be.

The r_barrels setting gives the details of the pattern. If you are used to thinking of graphs, you might expect to just give the x and y coordinates of each hole on the card, but as most people want to make circular patterns that would mean delving into trigonometry so to make it simpler we use what are called polar coordinates. In x y ('cartesian') coordinates you specify a place by saying how far to the right and above the center it is. In polar coordinates you say how far away it is and at what angle.

You can find out more about polar coordinates in Wikipedia.

The advantage of polar coordinates are that they make it easy to specify a circle. A circle of five pellets distance 0.03 from the center would be given by


because a whole circle is 360 degrees and 72 is 360 divided by 5. To add a hole at the center just make the string


Once you get the hang of it it's easy to change the number of pellets in the circle or make more exciting modifications such as adding a second outer circle. Don't get carried away, though, nine pellets is about the maximum that will do effective damage.

8. The toolkit

The gun pack contains a toolkit with some useful tools for gun makers. Some of these are products in their own right and some are just simple devices to make easier.

Bullet tester

The bullet tester is for measuring rate of fire. Rez the tester it somewhere suitable and simply fire at it. Once you stop firing (after a 5 second pause) it will give you information about the bullets that hit it.

For example

Delta Bullet tester: 12 hits in all
Delta Bullet tester: 9 collision events
Delta Bullet tester: 3 potential multiple shot losses
Delta Bullet tester: Average velocity 153.33 m/s
Delta Bullet tester: Time taken= 1.058746seconds
Delta Bullet tester: 11.334160 bps 
Taking this line by line:
  • 12 bullets hit the target
  • 9 time frames detected one or more collision events
  • 3 bullets were 'second hits', that is, they arrived at the same time as another bullet. Second hits are not detected in some combat meters (CCS for example)
  • The average velocity of the bullets was 153.33 m/s (this is very fast)
  • The time from the first to the last collision was 1.058746 seconds
  • That makes the fire rate 11.334160 bullets per second (that's also very fast - I was firing a Black Ops SOCOM M4A2 in full auto)

Resize script

This is a separate product, and details are here. We describe here how to integrate the resizer into your gun and holster. Make sure you understand the resize script before continuing.

Simply resizing the gun is a breeze! You just need to add a resize command for the user to use to start resizing. If you don't already have a command hanlder script you can use this one.

default {
    link_message(integer p,integer x,string m,key k)
        if (m=="COMMAND") {
            string s=(string) k;
            if (s=="resize") {

Now put this script and the resize script in the gun and that's it. If you want to be clever and change resize options read the resizer page.

Suppose now you have a holster that you want to resize too? That's a little more complicated but only a little. This time we have to put the resize script in gun and holster too and let them talk to one another. We already explained that the gun uses the HUD channel (-909 by default) to talk to other devices such as the holster. We may as well use that channel too for the resize scripts/

We could simply leave the holster resizer listening for commands on the HUD channel but that's a bit watseful. So instead we have a command from the gun tell the holster when the resizer is needed. The revised script in the main gun will look like this.

integer cc=-909;

default {
    link_message(integer p,integer x,string m,key k)
        if (m=="COMMAND") {
            string s=(string) k;
            if (s=="resize") {
        } else if (m=="RESIZE_END") {

Now look at the code for the holster script in section 5. The command handler looks like this.

listen(integer c,string n,key k,string m)
        if (llGetOwner() != llGetOwnerKey(k)) return;
        list l=llParseString2List(m,[" "],[]);
        string m=llToLower(llList2String(l,0));
        if (m=="showslung") show(TRUE);
        else if (m=="hideslung") show(FALSE);

We need to handle our two new commands. Here's the code with the extra lines. Remember the value cc was defined right at the start of the holster script.

listen(integer c,string n,key k,string m)
        if (llGetOwner() != llGetOwnerKey(k)) return;
        list l=llParseString2List(m,[" "],[]);
        string m=llToLower(llList2String(l,0));
        if (m=="showslung") show(TRUE);
        else if (m=="hideslung") show(FALSE);
        else if (m=="resize") llMessageLinked(LINK_THIS,cc,"RESIZE_SLAVE",NULL_KEY);
        else if (m=="resizecomplete") llMessageLinked(LINK_THIS,0,"RESIZE_COMPLETE",NULL_KEY);


The toolkit includes the Delta target pack. The target pack (apart from being useful for firing practice) is good for assessing shotgun fire patterns, and is also useful for testing the accuracy of sniper rifles - it's designed to work between sims for just that reason.

Bullet rezzer

The bullet rezzer allows you to test a bullet by shooting yourself. Add any bullets you want to the inventory first. The coloured top of the box gives a menu of available bullets. Touching the box anywhere else makes it shoot you with the bullet.

HUD channel monitor

Simply rezz the monitor and click it to turn it on. It will tell you in owner say anything that it hears on the HUD channel. If you change the HUD channel, edit the monitor and look at its description: it is the channel to be monitored. Simply edit the description and reset the monitor. Of course, you can in this way use the monitor to snoop any channel you like, but if you need to snoop multiple channels you will find it easier to use one of the many channel monitors sold in Second Life, for example, the one made by Novatech.

The channel monitor gives its location with each message. The first time you lose one while it is switched on you will realise why.

9. CCS support

This gun does not come with CCS ammo, though the kinetic ammo will do normal CCS damage. However, the gun is CCS compatible, so that if you put the CCS 3rd party script in the gun and make CCS ammo then you can arrange to do extra CCS damage.

The CCS 3rd party API is obtainable from Suzanna Soyinka. You may *not* put the CCS module in the supplied gun model - it is a condition of the licensing of the CCS module that you place it in a prim you have made yourself. If you place the module in the supplied gun it will cease to work.

Getting approval for any CCS enhanced gun you build is your responsibility.

10. Dev pack restrictions

The redistributable script given to buyers of the dev gun kit will check for the following each time the gun is attached, unless it is attached by the licensee:

  • The delta gun script is no mod (this will be set before the script is supplied
  • The creator of the object with the script in is the licensee
  • All added scripts were created by the licensee
  • All scripts are no mod
We strongly advise that you make any weapons that you distribute no mod, but this is not a requirement.

11. Change log

  • Release
  • Fix bug that prevents a script from changing ammo
  • Allow attachment anywhere
  • Make holstered version optional
  • Allow separate animations for draw and sling
  • Add support for partial alphaing of holster
  • Merge ROUND and CLIP to avoid double reload
  • Set CLIP to 0 for unlimited ammo (illegal in some sims eg CCS)
  • Fix anim sticking when gun is holstered while aimed
  • Fix draw sequence sometimes inserted after gun fired
  • Made draw and sling commands settings (so you can call them unsafe and safe say)
  • Add support for HUD channel
  • Add fire anim
  • Stopped non owners drawing holstered gun by touching
  • Added wname parameter
  • Added optional EMPTY link message when ammo is exhausted
  • Added reload command setting
  • Added DRAWSLING notification
  • Redesign main script to allow all settings to change dynamically
  • Switch to demo holster that uses partial alpha
  • Added slave rezzers (optional addon)
  • Added end auto sound
  • Added silencer support
  • Added gun enable/disable
  • Renamed WISP to FIRE and added extra parameter
  • Added check to stop auto fire if user leaves mouselook
  • Added timer to restart hold and aim anims after tp etc
  • Added modemask to allow arbitrary mix of modes

Planned for 1.15

See separate page