This snippet are a ROM virgin version of Modern Weapons designed
for the Metaverse Project. Its free to use, change, whatever, as long
as some basic credits for it is displayed somewhere.

Snippet start:

/********************************************************************
*  	Designed by Dex for the Metaverse Project.		    *
*	Charite@mail1.stofanet.dk				    *
*	No fancy copyrights, you most likely know the drill	    *
********************************************************************/

put this anywhere, i placed it in act.obj :

void do_shoot( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA *gun;
    OBJ_DATA *obj;
	char *mode;
	int shots, number, recoil;

    argument = one_argument( argument, arg);
    argument = one_argument( argument, arg2 );

	mode = arg;

    /* are there a target mentioned ? */
    if ( arg2[0] == '\0' && ch->fighting == NULL )
    {
	send_to_char( "Shoot at whom or what?\n\r", ch );
	return;
    }

    /* did the user select mode? */
    if ( arg[0] == '\0' && ch->fighting == NULL)
    {
	send_to_char ("Which mode?\n\r", ch);
	return;
    }

    /* do the character hold something ? */
    if ( ( gun = get_eq_char( ch, WEAR_HOLD ) ) == NULL )
    {
	send_to_char( "You hold nothing in your hand.\n\r", ch );
	return;
    }

    /* is it a gun ? */
    if ( gun->item_type != ITEM_GUN )
    {
	send_to_char( "You need a firearm to shoot.\n\r", ch );
	return;
    }

    obj = NULL;
    if ( arg2[0] == '\0' )
    {
	if ( ch->fighting != NULL )
	{
	    victim = ch->fighting;
	}
	else
	{
	    send_to_char( "Shoot whom or what?\n\r", ch );
	    return;
	}
    }
    else
    {
	/* is it really here ? */
	if ( ( victim = get_char_room ( ch, arg2 ) ) == NULL
	&&   ( obj    = get_obj_here  ( ch, arg2 ) ) == NULL )
	{
	    send_to_char( "You can't find it.\n\r", ch );
	    return;
	}
    }

    /* do we deal with a loaded gun ?*/
    if ( gun->value[2] <= 0 )
    {
	act( "The $p seems to be out of ammo.", ch, gun, NULL, TO_CHAR );
	gun->value[2] = 0;
	return;
    }
	/* Lets see how many shots to fire */
	if (( !str_cmp (mode, "dual")) && (IS_WEAPON_STAT(gun,GUN_DUAL)))
	shots = 2;
	else if (( !str_cmp (mode, "burst")) && (IS_WEAPON_STAT(gun,GUN_BURST)))
	shots = 3;
	else if (( !str_cmp (mode, "auto")) && (IS_WEAPON_STAT(gun,GUN_AUTO)))
	shots = 5;
	else if (( !str_cmp (mode, "single")) && (IS_WEAPON_STAT(gun,GUN_SINGLE)))
	shots = 1;
	else
		{
		send_to_char ("That is not an accepted mode for that weapon.\n\r", ch);
		return;
		}

	gun->value[2] = gun->value[2] - shots;

    /* Do the character know how to handle a gun ? */
    for(number = 0 ; number < shots ; number = number + 1)
	{
 	if (number_percent() <= get_skill(ch,gsn_clip) && IS_WEAPON_STAT(gun,GUN_CLIP) 
 	|| number_percent() <= get_skill(ch,gsn_energy) && IS_WEAPON_STAT(gun,GUN_ENERGY) 
 	|| number_percent() <= get_skill(ch,gsn_shell) && IS_WEAPON_STAT(gun,GUN_SHELL) 
 	|| number_percent() <= get_skill(ch,gsn_fuel) && IS_WEAPON_STAT(gun,GUN_FUEL) 
 	|| number_percent() <= get_skill(ch,gsn_rocket) && IS_WEAPON_STAT(gun,GUN_ROCKET) )
	{
	    obj_cast_spell( gun->value[3], gun->value[0], ch, victim, obj );

    /* ...and he shoots... */
    if ( gun->value[2] > 0 )
    {
		if ( victim != NULL )
		{
			act( "$n shoots $N with $p.", ch, gun, victim, TO_NOTVICT );
			act( "You shoot $N with $p.", ch, gun, victim, TO_CHAR );
			act( "$n shoots at you with $p.",ch, gun, victim, TO_VICT );
		}
		else
		{
	    act( "$n shoots $P with $p.", ch, gun, obj, TO_ROOM );
	    act( "You shoot $P with $p.", ch, gun, obj, TO_CHAR );
		}

	}

	else
	{
	    /* a missed shot */
	    act( "Your miss the target.", ch,gun,NULL,TO_CHAR);
	    act( "$n misses with a shot from $p.", ch,gun,NULL,TO_ROOM);
	    check_improve(ch,gsn_clip,FALSE,2);
		return;
	}

	/* now for a little recoil to hit. */
	/*This section could have been coded better, but it works */
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_LITTLE) && (get_curr_stat(ch,STAT_STR)) < 12)
	recoil = 1;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_NORMAL) && (get_curr_stat(ch,STAT_STR)) < 16)
	recoil = 1;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_NORMAL) && (get_curr_stat(ch,STAT_STR)) < 12)
	recoil = 2;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_HARD) && (get_curr_stat(ch,STAT_STR)) < 25)
	recoil = 1;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_HARD) && (get_curr_stat(ch,STAT_STR)) < 16)
	recoil = 2;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_HARD) && (get_curr_stat(ch,STAT_STR)) < 12)
	recoil = 3;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_SEVERE) && (get_curr_stat(ch,STAT_STR)) < 36)
	recoil = 1;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_SEVERE) && (get_curr_stat(ch,STAT_STR)) < 25)
	recoil = 2;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_SEVERE) && (get_curr_stat(ch,STAT_STR)) < 18)
	recoil = 3;
	if (IS_WEAPON_STAT(gun,GUN_RECOIL_SEVERE) && (get_curr_stat(ch,STAT_STR)) < 12)
	recoil = 4;

	if (recoil == 1)
	{
	send_to_char ("The recoil slows you down a bit.\n\r", ch);
	WAIT_STATE(ch,1 * PULSE_VIOLENCE);
	}
	if (recoil == 2)
	{
	send_to_char ("The recoil sends throws you off balance.\n\r", ch);
	WAIT_STATE(ch,2 * PULSE_VIOLENCE);
	}
	if (recoil == 3)
	{
	send_to_char ("The strong recoil almost numbs your arm.\n\r", ch);
	WAIT_STATE(ch,3 * PULSE_VIOLENCE);
	}
	if (recoil == 4)
	{
	send_to_char ("The recoil almost shatters your hand.\n\r", ch);
	WAIT_STATE(ch,4 * PULSE_VIOLENCE);
	}

	}
	}

}

void do_reload( CHAR_DATA *ch, char *argument )
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *ammo;
    OBJ_DATA *gun;
	int guntype, charge, maxcharge, ammotype, oldammo, newammo;

    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );

    /* not the ammo the character thinks he has */
    if ( ( ammo = get_obj_carry( ch, arg1, ch ) ) == NULL )
    {
	send_to_char( "You do not have that kind of ammo.\n\r", ch );
	return;
    }

    /* nope, that item cannot be loaded into a gun */
    if ( ammo->item_type != ITEM_AMMO )
    {
	send_to_char( "You need ammo to reload.\n\r", ch );
	return;
    }

    /* maybe the character tried to reload something besides a gun */
    if ( arg2[0] == '\0' )
    {
	send_to_char( "You need a gun to reload.\n\r", ch);
	return;
    }
    else
    {
	if   (( gun    = get_obj_here  ( ch, arg2 ) ) == NULL)
	{
	    send_to_char( "You can't find that gun.\n\r", ch );
	    return;
	}
    }
	/* comparing values */
	guntype = gun->value[4];
	ammotype = ammo->value[4];

	oldammo = gun->value[3];
	newammo = ammo->value [3];

	/* do the ammo match the gun ? */
	if (((IS_WEAPON_STAT(gun,GUN_CLIP)) && IS_WEAPON_STAT(ammo,GUN_CLIP))
	|| ((IS_WEAPON_STAT(gun,GUN_ENERGY)) && IS_WEAPON_STAT(ammo,GUN_ENERGY))
	|| ((IS_WEAPON_STAT(gun,GUN_SHELL)) && IS_WEAPON_STAT(ammo,GUN_SHELL))
	|| ((IS_WEAPON_STAT(gun,GUN_FUEL)) && IS_WEAPON_STAT(ammo,GUN_FUEL))
	|| ((IS_WEAPON_STAT(gun,GUN_ROCKET)) && IS_WEAPON_STAT(ammo,GUN_ROCKET)))
	{
		if (oldammo != newammo)
		{
			gun->value[2] = 0;
		}
		gun->value[2] = gun->value[2] + ammo->value[1];
		gun->value[3] = ammo->value[3];
	}
	else
	{
	    send_to_char( "Thats the wrong ammo for that weapon.\n\r", ch );
	    return;
	}
	
	/* do we have more ammo in the gun then it can hold */
	charge = gun->value[2];
	maxcharge = gun->value[1];

	if (charge > maxcharge)
	{
		gun->value[2] = gun->value[1];
	}

    act( "$n reloads $p.", ch, gun, NULL, TO_ROOM );
    act( "You reload $p.", ch, gun, NULL, TO_CHAR );
 

    extract_obj( ammo );
    return;
}

-------------------------------------------------------------------------
in interp.c :

    { "shoot",		do_shoot,	POS_RESTING,	 0,  LOG_NORMAL, 1 },
    { "reload",		do_reload,	POS_RESTING,	 0,  LOG_NORMAL, 1 },

in interp.h :

DECLARE_DO_FUN(	do_shoot	);
DECLARE_DO_FUN(	do_reload	);
---------------------------------------------------------------------------
Several skills needs to be added, the following places for each:
(clip, shell, energy, rocket, fuel)

in const.c, anywhere in the skill section :

    {
	"clip weapons",		{ 1, 1, 1, 1},     { 3, 4, 4, 5},
	spell_null,		TAR_IGNORE,		POS_STANDING,
	&gsn_clip,		SLOT( 2),	0,	12,
	"",			"!Clip!",		""
    },

in db.c, with all the other gsn:

sh_int  		gsn_clip;

in merc.h, again with the other gsn:

extern sh_int  gsn_clip;
-----------------------------------------------------------------------
In merc.h, below the /* weapon types */ defines (after that section) :

/* gun types */
#define GUN_SINGLE		(A)
#define GUN_DUAL		(B)
#define GUN_BURST		(C)
#define GUN_AUTO		(D)
#define GUN_CLIP		(E)
#define GUN_ENERGY		(F)
#define GUN_FUEL		(G)
#define GUN_SHELL		(H)
#define GUN_ROCKET		(I)
#define GUN_RECOIL_LITTLE	(O)
#define GUN_RECOIL_NORMAL	(P)
#define GUN_RECOIL_HARD		(Q)
#define GUN_RECOIL_SEVERE	(R)

in handler.c, below, but not in, the 
char *weapon_bit_name(int weapon_flags) 
group

char *gun_bit_name(int gun_flags)
{
    static char buf[512];

    buf[0] = '\0';
    if (gun_flags & GUN_CLIP		) strcat(buf, " clip");
    if (gun_flags & GUN_ENERGY		) strcat(buf, " energy");
    if (gun_flags & GUN_FUEL		) strcat(buf, " fuel");
    if (gun_flags & GUN_SHELL		) strcat(buf, " shell");
    if (gun_flags & GUN_ROCKET		) strcat(buf, " rocket");
    if (gun_flags & GUN_DUAL		) strcat(buf, " dual");
    if (gun_flags & GUN_BURST		) strcat(buf, " burst");
    if (gun_flags & GUN_AUTO		) strcat(buf, " auto");
    if (gun_flags & GUN_SINGLE		) strcat(buf, " single");
    if (gun_flags & GUN_RECOIL_LITTLE		) strcat(buf, " little");
    if (gun_flags & GUN_RECOIL_NORMAL		) strcat(buf, " normal");
    if (gun_flags & GUN_RECOIL_HARD		) strcat(buf, " hard");
    if (gun_flags & GUN_RECOIL_SEVERE		) strcat(buf, " severe");


    return ( buf[0] != '\0' ) ? buf+1 : "none";
}

in merc.h, below 
char *	weapon_bit_name	args( ( int weapon_flags ) );

add
char *	gun_bit_name	args( ( int gun_flags ) );
----------------------------------------------------------------------
in wiz.c, in the do_ostat command, add anywhere in 
   switch ( obj->item_type ):

    	case ITEM_GUN: 
	    sprintf( buf, "Has %d(%d) units left of ",
	    	obj->value[1], obj->value[2]);
	    send_to_char( buf, ch );
      
	    if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL )
	    {
	    	send_to_char( " '", ch );
	    	send_to_char( skill_table[obj->value[3]].name, ch );
	    	send_to_char( "'", ch );
	    }

	    send_to_char( ".\n\r", ch );
	    if (obj->value[4])
	    {
	        sprintf(buf,"Gun flags: %s\n\r",
		    gun_bit_name(obj->value[4]));
	        send_to_char(buf,ch);
         }
	break;

in const.c below
const struct item_type		item_table	[]	=

add somewhere
    {	ITEM_GUN,	"gun"		},
    {   ITEM_AMMO,		"ammo"	},


in db.c, below 	switch ( pObjIndex->item_type )

add anywhere
	case ITEM_GUN:
	case ITEM_AMMO:
	    pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );
		break;

in db.c, below      
* Mess with object properties.

add anywhere in the switch structure
    case ITEM_GUN:
	if (level != -1 && !pObjIndex->new_format)
	{
	    obj->value[0]	= number_fuzzy( obj->value[0] );
	    obj->value[1]	= number_fuzzy( obj->value[1] );
	    obj->value[2]	= obj->value[1];
	}
	if (!pObjIndex->new_format)
	    obj->cost *= 2;
	break;

	case ITEM_AMMO:
	break;

in db2.c, below 
void load_objects( FILE *fp )

in the :
switch(pObjIndex->item_type)

add anywhere in the switch structure
	case ITEM_GUN:
	case ITEM_AMMO:
	    pObjIndex->value[0]		= fread_number(fp);
	    pObjIndex->value[1]		= fread_number(fp);
	    pObjIndex->value[2]		= fread_number(fp);
	    pObjIndex->value[3]		= skill_lookup(fread_word(fp));
	    pObjIndex->value[4]		= fread_flag(fp);
	    break;

in merc.h, in the
 * Used in #OBJECTS.
section add

#define ITEM_GUN		      xx <- any available number
#define ITEM_AMMO		      xx <- any available number

in save.c, below 
void fwrite_obj( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest )
in the
switch ( obj->item_type )

add in the switch structure
    case ITEM_GUN:
	if ( obj->value[3] > 0 )
	{
	    fprintf( fp, "Spell 3 '%s'\n", 
		skill_table[obj->value[3]].name );
	}
-----------------------------------------------------------------------
Now you need to add spells to your spell structure, representing the
ammo required for the gun. This can be any spell in the game really,
but i made a selection of spells special for the guns, one example
included :

void spell_regular_shots(int sn,int level,CHAR_DATA *ch,void *vo,int target)
{
    CHAR_DATA *victim = (CHAR_DATA *) vo;
    int dam;
 
    dam = number_range( 1, 4 );
	dam = dam * level;

    if ( saves_spell( level, victim, DAM_BASH) )
        dam /= 2;
    damage_old( ch, victim, dam, sn, DAM_BASH ,TRUE);
    return;
}

    {
	"regular shots",		{ 1, 1, 1, 1 },     { 1,  1,  1,  1},
	spell_regular_shots,	TAR_CHAR_OFFENSIVE,		POS_FIGHTING,
	NULL,			SLOT(203),	0,	0,
	"Regular Shots",		"!Regular!",		""
    },
------------------------------------------------------------------------
Together with this file belongs a text document explaning how to design
firearms in the object file and in more detail, what the gun actually
are doing.

If you encounter any problems, bugs or you have suggestions/corrections
for this snippet, feel free to contact me.

Dex.
