Ammunitions are limited, once you have finished them you'll have to wait for the automatic reload process to finish, if you don't manually reload by yourself.
Also, it will allow you to draw/holster your weapon using simple commands.
This adds a bit of realism that those infinite-ammo weapons don't have uh?
Ok, how to try it:
01) create 2 cylinders, resize them to 0.100x0.100x0.350, name cylinder number 1 "gun" and cylinder number 2 "holstered gun"
02) pick up them
03) right click on "gun" then select Attach To > Right Hand
04) adjust gun's rotation
05) right click on "holstered gun" then select Attach To > R Upper Leg
06) adjust holstered gun's position
07) open the gun's inventory, drop in the "Gun - Limited ammunitions - Automatic reload" script
0

09) open the holstered gun's inventory, drop in the "Holstered weapon" script
10) close the holstered gun's inventory
11) create a sphere, resize it to 0.25x0.25x0.25, name it "bullet"
12) put the "Generic anti prim-littering bullet" script into the sphere, as soon as you've done it pick it up before it selfdeletes
13) open your gun's inventory and drop inside the bullet
14) say /78 draw to draw your gun (mouselook, left mouseclick to shoot)
15) say /78 holster to holster your gun
16) say /78 recharge to recharge your gun
17) optionally, create gestures to speed up things
-----------------------
Gun - Limited ammunitions - Automatic reload
----------------------
// Script based on:
//
// the Eric Linden's popgun script
// ( Inventory > Library > Objects > popgun )
//
// and a full permissions “hide/show” script that whose I can't remember
// the creator's name (my apologies)!
integer AMMO; // Used to store the number of available bullets
float SPEED = 75.0; // Speed of bullets in meters/sec.
float DELAY = 0.25; // Delay between shots to impose.
vector vel; // Used to store the velocity of the bullets to be shot.
vector pos; // Used to store the position of the bullets to be shot.
rotation rot; // Used to store the rotation of the bullets to be shot.
integer have_permissions = FALSE;
// Indicates whether wearer has yet given permission
// to take over their controls and animation.
// Follows the function used to fire each time that the left mouse button
// is pressed.
fire()
{
rot = llGetRot();
vel = llRot2Fwd(rot);
pos = llGetPos();
pos = pos + vel;
pos.z += 0.85; // This value is used to slightly correct the
// final Z position of the bullet to be shot,
// in few words it determines a little vertical
// shift of the aim point from the crosshair.
vel = vel * SPEED;
AMMO = AMMO -1; // This subtracts 1 point from the available
// total number of bullets each time that a
// bullet is shot.
llRezObject("bullet", pos, vel, rot, 0);
// This rezzes the prim-bullet contained into your weapon,
// giving it all the needed values (position, velocity,
// rotation).
}
default
{
changed(integer change)
{
if (change & CHANGED_OWNER)
{
llOwnerSay("/me owner is changed, script resetted." );
llResetScript();
}
}
// If the object's owner is changed then a message is sent and the
// script is resetted to its default values (state_entry section).
on_rez(integer param)
{
llResetScript();
}
// Script is resetted to its default values on object's rezzing
// (state_entry section), this avoids rezzing a weapon with few
// bullets.
state_entry()
{
AMMO = 10;
// Sets the number of available bullets when the weapon is
// rezzed.
llListen(78,"",llGetOwner(),"draw"

// Listens on channel 78 for owner's draw command.
// For example:
// /78 draw
llListen(78,"",llGetOwner(),"holster"

// Listens on channel 78 for owner's holster command.
// For example:
// /78 holster
llListen(78,"",llGetOwner(),"recharge"

// Listens on channel 78 for owner's recharge command.
// For example:
// /78 recharge
}
listen(integer channel, string name, key id, string message)
{
if(llToLower(message) == "draw"

{
llSetLinkAlpha(LINK_SET,1.0,ALL_SIDES);
// If the draw command is given, the whole link of prims
// composing the weapon being held in the avatar's hand
// will be turned visible.
if (!have_permissions)
{
llRequestPermissions(llGetOwner(),
PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS);
// Requests permissions to trigger animations and to
// take the avatar's controls.
}
}
if(llToLower(message) == "holster"

{
llSetLinkAlpha(LINK_SET,0.0,ALL_SIDES);
// If the holster command is given, the whole link of prims
// composing the weapon being held in the avatar's hand will
// be turned invisible.
llStopAnimation("hold_R_handgun"

// The current “hold the weapon” animation is stopped.
// http://wiki.secondlife.com/wiki/Internal_Animations
llStopAnimation("aim_R_handgun"

// The current “aim” animation is stopped.
// http://wiki.secondlife.com/wiki/Internal_Animations
llReleaseControls();
// Avatar's controls are released.
// http://wiki.secondlife.com/wiki/LlReleaseControls
if (have_permissions)
{
have_permissions = FALSE;
}
// Permissions are disabled.
}
if (llToLower(message) == "recharge"

{
llWhisper(0, "/me recharging started..."

// Recharge's message is whispered.
llSleep(3);
// Script is paused for 3 seconds.
AMMO = 10;
// Available bullets number is restored to 10.
llWhisper (0, "/me recharged."

// Recharge's end message is sent.
}
}
run_time_permissions(integer permissions)
{
if (permissions == PERMISSION_TRIGGER_ANIMATION |
PERMISSION_TAKE_CONTROLS)
{
llTakeControls(CONTROL_ML_LBUTTON, TRUE, FALSE);
// The mouselook button is activated.
llStartAnimation("hold_R_handgun"

// The current “hold the weapon” animation is started.
// http://wiki.secondlife.com/wiki/Internal_Animations
have_permissions = TRUE;
// Permissions are enabled.
}
}
control(key name, integer levels, integer edges)
{
if ( ((edges & CONTROL_ML_LBUTTON) == CONTROL_ML_LBUTTON)
&&

{
if (AMMO > 0)
{
fire();
llSleep(DELAY);
}
// If AMMO's number is greater than 0 then FIRE function
// is executed and the script paused to put a pause between
// the shots.
else
{
llWhisper (0, "/me recharging started..."

llSleep(3);
AMMO = 10;
llWhisper (0, "/me recharged."

}
// If AMMO's number is equal to 0 then the recharge process
// is automatically started: recharge's begin message will
// be whispered, the script paused for 3 seconds, available
// AMMO's number restored to 10 and finally recharge's end
// message will be whispered.
}
}
}
----------------------
Holstered weapon
----------------------
default
{
changed(integer change)
{
if (change & CHANGED_OWNER)
{
llOwnerSay("/me owner is changed, script resetted." );
llResetScript();
}
}
// If the object's owner is changed then a message is sent and the
// script is resetted to its default values (state_entry section).
on_rez(integer a)
{
llResetScript();
}
// Script is resetted to its default values on object's rezzing
// (state_entry section).
state_entry()
{
llListen(78,"",llGetOwner(),"draw"

// Listens on channel 78 for owner's draw command.
// For example:
// /78 draw
llListen(78,"",llGetOwner(),"holster"

// Listens on channel 78 for owner's holster command.
// For example:
// /78 holster
}
listen(integer channel, string name, key id, string message)
{
if(llToLower(message) == "draw"

{
llSetLinkAlpha(LINK_SET,0.0,ALL_SIDES);
// If the draw command is given, the whole link of prims
// composing the weapon being held in the holster will
// be turned invisible.
}
if(llToLower(message) == "holster"

{
llSetLinkAlpha(LINK_SET,1.0,ALL_SIDES);
// If the holster command is given, the whole link of prims
// composing the weapon being held in the holster will
// be turned visible.
}
}
}
-----------------------
Generic anti prim-littering bullet
-----------------------
default
{
on_rez(integer a)
{
llResetScript();
}
// Script is resetted to its default values on object's rezzing
// (state_entry section).
state_entry()
{
llSetTimerEvent(7);
// Timer event set on 7 seconds.
llSetStatus(STATUS_PHYSICS, TRUE);
// Object's physics status set to TRUE
// http://lslwiki.net/lslwiki/wakka.php?wakka=STATUS_PHYSICS
llSetStatus(STATUS_DIE_AT_EDGE, FALSE);
// Object can do sim crossing.
// Set to TRUE to make it selfdelete on sim crossing.
llSetPrimitiveParams(
[PRIM_TEMP_ON_REZ, TRUE,
PRIM_MATERIAL, PRIM_MATERIAL_METAL]
);
// Object is set to be a temporary prim (if not yet): it will
// selfdelete after 60/70 seconds in sims where scripts are
// disabled. Object's material is set to METAL.
// http://wiki.secondlife.com/wiki/PRIM_MATERIAL
llSetBuoyancy(1);
// Gravity's effect on the object.
// 1 means less or more "no fall and no rise".
// http://wiki.secondlife.com/wiki/LlSetBuoyancy
llSetDamage(15);
// In damage active sims, the object will do 15% of damage
// when colliding with avatars.
// http://wiki.secondlife.com/wiki/LlSetDamage
llPlaySound("4dd615aa-d35d-de4e-2a6f-ee36af0631f1", 1);
// This plays at full volume a laser shot sound.
// Change the UUID between quotes to play another one.
// http://wiki.secondlife.com/wiki/LlPlaySound
}
collision_start(integer a)
{
llDie();
}
// Object selfdeletes on avatar or object collision.
touch_start(integer a)
{
llDie();
}
// Object selfdeletes on touch.
land_collision_start(vector a)
{
llDie();
}
// Object selfdeletes on land collision.
timer()
{
llDie();
}
// Object selfdeletes on timer event.
}