Post tutorial Report content RSS feed Adding a new weapon (Melee)

Adding a new weapon is simple.. adding a MELEE weapons isn't as easy! If you've tried coding in Q2, you'll notice that you cannot use Fire_Hit for player weapons! This will fix that with a whole new Fire Function! Get ready to knife em up!

Posted by on - Intermediate Server Side Coding

[page=New weapon (Melee)]
Ok, first we need to define the fire function.

Open up g_weapon.c, head to the bottom, all the way to the bottom... further... after fire_bfg.. further... yes, right there. Add all this in straight from the bottom:

/*
/*
==================
Fire_Punch
Commented for Moddb Tutorial
==================
*/

void fire_punch (edict_t *self, vec3_t start, vec3_t aim, int reach, int damage, int kick, int quiet, int mod)
{
	vec3_t		forward, right, up;
	vec3_t		v;
	vec3_t		point;
	trace_t		tr;

	vectoangles2 (aim, v);                   //
	AngleVectors (v, forward, right, up);    //
	VectorNormalize (forward);               //
	VectorMA( start, reach, forward, point); // Aiming stuff

	//see if the hit connects
	tr = gi.trace(start, NULL, NULL, point, self, MASK_SHOT);
	if(tr.fraction ==  1.0)
	{
		if(!quiet) //not needed, it's better to follow my later steps
			//gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/swish.wav"), 1, ATTN_NORM, 0);
		return;
	}

	if(tr.ent->takedamage == DAMAGE_YES || tr.ent->takedamage == DAMAGE_AIM) // Make sure they took damage
	{
		// pull the player forward if you do damage
		VectorMA(self->velocity, 75, forward, self->velocity); // Pull forward
		VectorMA(self->velocity, 75, up, self->velocity); // Pull up a tad bit. You can't slide&#59;)

		// do the damage
		// FIXME - make the damage appear at right spot and direction
			T_Damage (tr.ent, self, self, vec3_origin, tr.ent->s.origin, vec3_origin, damage, kick/2, 
            			DAMAGE_ENERGY, mod); // Time to Slice my friends
			            gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/phitw1.wav"), 1, ATTN_IDLE, 0); // Used for my Punch. 
                               //Rename and use for whatever
		
		if(!quiet)
			gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/meatht.wav"), 1, ATTN_NORM, 0); // Don't change this. 
                            //This is only used if your weapon is not quiet.. Chainfist isn't quiet, knife is
	}
	else
	{
		if(!quiet)
			gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/tink1.wav"), 1, ATTN_NORM, 0); //same as above

		VectorScale (tr.plane.normal, 256, point);
		gi.WriteByte (svc_temp_entity);
		gi.WriteByte (TE_SPARKS); //make sparks, not gunshot..
		gi.WritePosition (tr.endpos);
		gi.WriteDir (point);
		gi.multicast (tr.endpos, MULTICAST_PVS);
        gi.sound (self, CHAN_AUTO, gi.soundindex("weapons/phitw2.wav") , 1, ATTN_NORM, 0);  //hit wall sound
	}
}

Whew. That's alot of code.

Now, let's go to p_weapon.c, and make sure you've got a model! Put this code to the way bottom, like g_weapon

/*
=======================
Punching/Melee
=======================
*/

void Null_Fire(edict_t *ent)
{
	int	i;
	vec3_t		start;
	vec3_t		forward, right;
	vec3_t		angles;
	int			damage = 5; //change to whatever
	int			kick = 2; //ditto here
	vec3_t		offset;

	if (ent->client->ps.gunframe == 11) //rename 11 to after you're attack frame
	{
		ent->client->ps.gunframe++;
		return;
	}

	AngleVectors (ent->client->v_angle, forward, right, NULL);

	VectorScale (forward, -2, ent->client->kick_origin);
	ent->client->kick_angles[0] = -2;

	VectorSet(offset, 0, 8,  ent->viewheight-8 );
	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); //where does the hit start from?

	if (is_quad)
	{
		damage *= 4;
		kick *= 4;
	}

	// get start / end positions
	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
	AngleVectors (angles, forward, right, NULL);
	VectorSet(offset, 0, 8, ent->viewheight-8 );
	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
	fire_punch (ent, start, forward, 45, damage, 200, 1, MOD_PUNCH); // yep, matches the fire_ function	

	ent->client->ps.gunframe++; //NEEDED
	PlayerNoise(ent, start, PNOISE_WEAPON); //NEEDED

//	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
//		ent->client->pers.inventory[ent->client->ammo_index]--; // comment these out to prevent the Minus NULL Ammo bug
}

void Weapon_Null (edict_t *ent)
{
	static int	pause_frames[]	= {10, 21, 0};
	static int	fire_frames[]	= {6, 0}; // Frame stuff here

	Weapon_Generic (ent, 3, 9, 22, 24, pause_frames, fire_frames, Null_Fire);
}

Ok, now, let's head to g_items.c, near the beginning.

You'll see

void Weapon_Blaster (edict_t *ent);
void Weapon_Shotgun (edict_t *ent);
void Weapon_SuperShotgun (edict_t *ent);
void Weapon_Machinegun (edict_t *ent);
void Weapon_Chaingun (edict_t *ent);
void Weapon_HyperBlaster (edict_t *ent);
void Weapon_RocketLauncher (edict_t *ent);
void Weapon_Grenade (edict_t *ent);
void Weapon_GrenadeLauncher (edict_t *ent);
void Weapon_Railgun (edict_t *ent);
void Weapon_BFG (edict_t *ent);

under that, add

void Weapon_Null (edict_t *ent);

That was easy! now, go lower, and find:

/* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
always owned, never in the world
*/
	{
		"weapon_blaster", 
		NULL,
		Use_Weapon,
		NULL,
		Weapon_Blaster,
		"misc/w_pkup.wav",
		NULL, 0,
		"models/weapons/v_blast/tris.md2",
/* icon */		"w_blaster",
/* pickup */	"Blaster",
		0,
		0,
		NULL,
		IT_WEAPON|IT_STAY_COOP,
		WEAP_BLASTER,
		NULL,
		0,
/* precache */ "weapons/blastf1a.wav misc/lasfly.wav"
	},

above that, add this:

{
        "weapon_null",           //  The map entity name. dont include this in a map whatever you do.
        NULL,                    // The pickup function
        Use_Weapon,              // How to use
        NULL,                    // the drop function
       Weapon_Null,             //What the use function is
       "misc/w_pkup.wav",
       "models/nullweapon.md2",0,
       "models/nullweapon.md2", //The models stuff.(This is my Hands model)
       "w_blaster",             //Icon to be used. you could create another, you probably should
       "Hands",             //Pickup name. use this to give the item to someone at the start of the game
        0,
        0,
        NULL,
        IT_WEAPON|IT_STAY_COOP,
        WEAP_BLASTER,            // the model index, just an integer defined in g_local.h
        NULL,
        0,
        ""
},

Ok, now that that's done, let's head on over to g_local.c Find:

#define MOD_EXIT			28
#define MOD_SPLASH			29
#define MOD_TARGET_LASER	30
#define MOD_TRIGGER_HURT	31
#define MOD_HIT				32
#define MOD_TARGET_BLASTER	33
#define MOD_FRIENDLY_FIRE	0x8000000

below them, add

#define MOD_PUNCH    34

Now, go to p_client.c, and find

case MOD_TELEFRAG:
	message = "tried to invade";
	message2 = "'s personal space";
	break;

under it, add this:

case MOD_PUNCH:
	message = "took";
	message2 = "'s fist in the face";
	break;

Now that we have the means of death, let's replace the blaster with it! Find:

PrecacheItem (FindItem ("Blaster"));

replace with

PrecacheItem (FindItem ("Hands"));

Find

if (weapon && !oldcount)
	{
		if (other->client->pers.weapon != ent->item && ( !deathmatch->value || other->client->pers.weapon == FindItem("Blaster") ) )
			other->client->newweapon = ent->item;
	}

Replace with

if (weapon && !oldcount)
	{
		if (other->client->pers.weapon != ent->item && ( !deathmatch->value || other->client->pers.weapon == FindItem("Hands") ) )
			other->client->newweapon = ent->item;
	}

Find

item = self->client->pers.weapon;
	if (! self->client->pers.inventory[self->client->ammo_index] )
		item = NULL;
	if (item && (strcmp (item->pickup_name, "Blaster") == 0))
		item = NULL;

Replace again with

item = self->client->pers.weapon;
	if (! self->client->pers.inventory[self->client->ammo_index] )
		item = NULL;
	if (item && (strcmp (item->pickup_name, "Hands") == 0))
		item = NULL;

Find

if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
	{
		ent->client->newweapon = FindItem ("shotgun");
		return;
	}
	ent->client->newweapon = FindItem ("Blaster");
}

Replace with

if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
	{
		ent->client->newweapon = FindItem ("shotgun");
		return;
	}
	ent->client->newweapon = FindItem ("Hands");
}

Find

item = FindItem("Blaster");
        client->pers.selected_item = ITEM_INDEX(item);
        client->pers.inventory[client->pers.selected_item] = 1;

Replace with

item = FindItem("Hands");
        client->pers.selected_item = ITEM_INDEX(item);
        client->pers.inventory[client->pers.selected_item] = 1;

There you go! Now go punch some Strogg, and go punch and humiliate your foes.

Post comment Comments
SvenBoogie
SvenBoogie

Why is this in the f.e.a.r. section?

Reply Good karma Bad karma+1 vote
Paril Author
Paril

Shouldn't be..?

Reply Good karma+1 vote
MOST
MOST

good

Reply Good karma Bad karma+1 vote
flobblob
flobblob

Jesus! Look at all the coding! When I tried to do even a basic mod with quake 3 and just changed the rocket speed, then clicked compile, It wrecked the game. It always happens to what I do with other ones like Doom.

Reply Good karma Bad karma+1 vote
Post a comment

You are not logged in, your comment will be anonymous unless you join the community. Or sign in with your social account:

Tutorial
Browse
Tutorials
Share
Related Games
Quake 2
Quake 2 First Person Shooter
Related Engines
id Tech 2
id Tech 2 GPL
Related Groups
Activision
Activision Developer & Publisher
id Software
id Software Developer & Publisher