PlanetQuake | Code3Arena | Tutorials | << Prev | Tutorial 22 | Next >>


  • Home/News
  • ModSource
  • Compiling
  • Help!!!
  • Submission
  • Contributors
  • Staff
  • Downloads

    < Index >
    1. Mod making 101
    2. Up 'n running
    3. Hello, QWorld!
    4. Infinite Haste
    5. Armor Piercing Rails
    6. Bouncing Rockets
    7. Cloaking
    8. Ladders
    9. Favourite Server
    10. Flame Thrower
    11. Vortex Grenades
    12. Grapple
    13. Lightning Discharge
    14. Locational Damage
    15. Leg Shots
    16. Weapon Switching
    17. Scoreboard frag-rate
    18. Vortex Grenades II
    19. Vulnerable Missiles
    20. Creating Classes
    21. Scrolling Credits
    22. Weapon Dropping
    23. Anti-Gravity Boots
    24. HUD scoreboard
    25. Flashlight and laser
    26. Weapon Positioning
    27. Weapon Reloading
    28. Progressive Zooming
    29. Rotating Doors
    30. Beheading (headshot!)
    31. Alt Weapon Fire
    32. Popup Menus I
    33. Popup Menus II
    34. Cluster Grenades
    35. Homing Rockets
    36. Spreadfire Powerup
    37. Instagib gameplay
    38. Accelerating rockets
    39. Server only Instagib
    40. Advanced Grapple Hook
    41. Unlagging your mod

    < Index >
    1. Entities
    2. Vectors
    3. Good Coding
    4. Compilers I
    5. Compilers II
    6. UI Menu Primer I
    7. UI Menu Primer II
    8. UI Menu Primer III
    9. QVM Communication, Cvars, commands
    10. Metrowerks CodeWarrior
    11. 1.27g code, bugs, batch


  • Quake3 Files
  • Quake3 Forums
  • Q3A Editing Message Board
  • Quake3 Editing


  • SumFuka
  • Calrathan
  • HypoThermia
  • WarZone

    Site Design by:
    ICEmosis Design

    TUTORIAL 22 - Weapon dropping
    by [SuB]paranoid

    Some of the most played mods on the Internet are team based. The goal is to eliminate the enemy and help your teammates to accomplish your mission objectives. Teamplay is all about strategy and tactics and there's a well known feature from Quake II (missing in Quake 3) that increases this even more: the ability to drop weapons.

    Let's get started.

    1. Files we will be modifying from the game source code:

    Source files edited:

    • g_local.h
    • g_active.c
    • g_items.c
    • g_cmds.c
    • cg_consolecmds.c - adding function declarations and an entity flag

    Functions added/modified:

    • adding ThrowWeapon()
    • adding dropWeapon(), modifying LaunchItem()
    • adding the "drop" command
    • registering the "drop" command (optional)

    2. Changing the Q3 code

    You may experience some problems with copying text from html files so I provided a textfile with the main functions.

    2.1 g_local.h about line 33

    Open g_local.h and add this line to the gentity->flags definitions:

    #define FL_THROWN_ITEM		0x00008000  // XRAY FMJ weapon throwing
    This defines a new flag we will use to identify dropped items. Add these two lines at 360:
    void ThrowWeapon( gentity_t *ent );
    gentity_t *dropWeapon( gentity_t *ent, gitem_t *item, float angle, int xr_flags );  // XRAY FMJ

    This declarates our two new functions. We are done with this file so you can save and close g_local.h now.

    2.2 g_active.c, about line 518

    Now open g_active.c and paste the function ThrowWeapon() before this line:

    void BotTestSolid(vec3_t origin);
    void ThrowWeapon( gentity_t *ent )
    	gclient_t	*client;
    	usercmd_t	*ucmd;
    	gitem_t		*xr_item;
    	gentity_t	*xr_drop;
    	byte i;
    	int amount;
    	client = ent->client;
    	ucmd = &ent->client->pers.cmd;
    	if( client->ps.weapon == WP_GAUNTLET
    		|| client->ps.weapon == WP_MACHINEGUN
    		|| client->ps.weapon == WP_GRAPPLING_HOOK
    		|| ( ucmd->buttons & BUTTON_ATTACK ))
    	xr_item = BG_FindItemForWeapon( client->ps.weapon );
    	amount= client->ps.ammo[ client->ps.weapon ]; // XRAY save amount
    	client->ps.ammo[ client->ps.weapon ] = 0;
    	client->ps.stats[STAT_WEAPONS] &= ~( 1 << client->ps.weapon );
    	client->ps.weapon = WP_MACHINEGUN;
    	for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) {
    		if ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) ) {
    			client->ps.weapon = i;
    	xr_drop= dropWeapon( ent, xr_item, 0, FL_DROPPED_ITEM | FL_THROWN_ITEM );
    	if( amount != 0)
    		xr_drop->count= amount;
    		xr_drop->count= -1; // XRAY FMJ 0 is already taken, -1 means no ammo

    This function finds out what weapon the player is carrying and it removes the weapon and its ammo from the players inventory, if it isn't the gauntlet, the machinegun, or grapple. It also makes sure the player is not firing.

    Then the function calls dropWeapon() with the chosen weapon. dropWeapon() returns the new entity and we can set the amount of ammo a player gets if he picks the weapon up again.

    Save and close g_active.c.

    2.3 g_items.c, about line 401

    Find the function LaunchItem() in g_items.c, now add "int xr_flags" to the parameter list:

    gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity , int xr_flags ) {  // XRAY FMJ 

    now replace the line: dropped->flags = FL_DROPPED_ITEM; with these lines at about 434:

    dropped->flags =  xr_flags; // FL_DROPPED_ITEM; // XRAY FMJ FL_THROWN_ITEM
    if( xr_flags & FL_THROWN_ITEM) {
        dropped->clipmask = MASK_SHOT; // XRAY FMJ
        dropped->s.pos.trTime = level.time - 50;	// move a bit on the very first frame
        VectorScale( velocity, 500, dropped->s.pos.trDelta ); // 700
        SnapVector( dropped->s.pos.trDelta );		// save net bandwidth
        dropped->physicsBounce= 0.65;

    If the weapon has the dropped flag, the function now sets some special entity values borrowed from the grenade_launcher function in g_weapon.c. If you think about it, a flying grenade and a dropped weapon are pretty similar at least from a programmers point of view :P

    But this alone did not work nice... there was no arch and the dropped weapon almost immediately stopped flying. I had a hard time solving the problem until I found the physicsBounce property. The value is a float from 0 to 1 and it determines how long the dropped item will bounce.

    Now the problem was that new entities always spawn with physicsBounce= 0. So we need to set this to a more appropriate value ! Well as you can see I use 0.65 wich looks pretty nice. Set it to 1 and it will bounce very long :)

    Additionally the VectorScale() function sets the overall flying speed of the dropped weapon or item. You can also change this if you like.

    g_items.c, about line 469

    Since we changed the parameter list of LaunchItem() we need to change the function call to it too ! The function got called only by dropItem() before, take a look at line 469. Change the call so it looks like this:

    return LaunchItem( item, ent->s.pos.trBase, velocity, FL_DROPPED_ITEM);

    Now paste the function dropWeapon() right after our modified function LaunchItem() :

    dropWeapon XRAY FMJ
    gentity_t *dropWeapon( gentity_t *ent, gitem_t *item, float angle, int xr_flags ) { // XRAY FMJ
    	vec3_t	velocity;
    	vec3_t	origin;
    	VectorCopy( ent->s.pos.trBase, origin );
    	// set aiming directions
    	AngleVectors (ent->client->ps.viewangles, velocity, NULL, NULL);
    	origin[2] += ent->client->ps.viewheight;
    	VectorMA( origin, 34, velocity, origin ); // 14
    	// snap to integer coordinates for more efficient network bandwidth usage
    	SnapVector( origin);
    	// extra vertical velocity
    	velocity[2] += 0.2;
    	VectorNormalize( velocity );
    	return LaunchItem( item, origin, velocity, xr_flags );

    This function gets called from our ThrowWeapon() function and then calls LaunchItem() itself. What this fuction does is it calculates the exact spawnpoint ( which is the muzzlepoint here btw) and the direction the player is viewing, which will become the flying direction for the weapon (the var is called velocity).

    We're almost through ! :)

    2.4 g_cmds.c, about line 1030

    Add this function in g_cmds.c:

    Cmd_Drop_f XRAY FMJ
    void Cmd_Drop_f( gentity_t *ent ) {
    	ThrowWeapon( ent );

    This function only calls ThrowWeapon() and follows the programming style of id soft.

    g_cmds.c, about line 1109:

    Now near the end of g_cmds.c add our new command to the function ClientCommand():

    else if (Q_stricmp (cmd, "setviewpos") == 0)
        Cmd_SetViewpos_f( ent );
    else if (Q_stricmp (cmd, "drop") == 0)  // XRAY FMJ
        Cmd_Drop_f( ent );
        trap_SendServerCommand( clientNum, va("print \"unknown cmd %s\n\"", cmd ) );

    ClientCommand() compares a user-consolecommand to all available commands and if it finds the command it calls its appropriate function.

    2.5 cg_consolecmds.c, about line 207

    Search for the function CG_InitConsoleCommands( void ) in cg_consolecmds.c then add this line to the end of the list:

    trap_AddCommand ("drop");	// XRAY FMJ weap drop cmd

    This line registers the "drop" command so it will be tab completable. Be aware that this line doesn't add very much functionality but requires you to compile and publish your cgame.qvm together with your qagame.qvm.

    So you might want to leave it out, weapon dropping will work fine without it :)

    3. General Explanation

    Basically I combined the functions that get called when a player dies and looses all his powerups and chosen weapon, and the function that gets called when you use the grenade launcher.

    First a player uses the "drop" command, this action calls Cmd_Drop_f(). Now in this order the functions ThrowWeapon(), dropWeapon() and finally LaunchItem() get called. LauchItem() returns the new entity so it can be additionally modified, which happens back in ThrowWeapon().

    From now on the functions G_RunItem() and G_BounceItem() in g_items.c take over the control over our dropped weapon ( and every item btw ) and this is also the place were the "physicsBounce" value is so important. You may want to read through these functions to understand the behaviour of dropped and other items a little more.

    4. Using the new feature

    This is the easy part, just bind a key to the command "drop" in the console like this:

    bind q drop

    5. Customizing the functions

    There are several ways to change the behaviour of the dropped weapon, the main ways are:

    • physicsBounce: the higher the value the longer the weapon will bounce.
    • VectorScale( velocity, 500, dropped->s.pos.trDelta ), here 500 is the initial speed of the dropped weapon.
    • velocity[2] += 0.2, a larger value makes the weapon fly higher.
    • dropped->nextthink = level.time + 30000; (g_items.c - line 431) sets the time in milliseconds the dropped weapon will stay in the level.

    And you can also change the name of the command to whatever you like, just check that you don't use names that are already taken by the game.

    Well thats all and you made it. Build your qagame.qvm file and have some fun !

    Contact Information:

    If there is demand I will add an ammo and item-dropping tutorial, but you should be able to build them by yourself now, because its pretty similar to weapon dropping. Just copy and paste the throwWeapon() function in g_active two times and rename and change the settings accordingly, also add two more commands in g_cmds.c and cg_consolecmds.c.

    If you experience problems feel free to email me. - the mod I made weapon dropping for: Full Metal Jacket. - my clan and my Q3dominator mod.
    I will upload a teamplay mod with weapon dropping there shortly.

    If you use this code I would appreciate a link to your mod. Please give credit where credit is due.

    Ray, [SuB]paranoid

    PlanetQuake | Code3Arena | Tutorials | << Prev | Tutorial 22 | Next >>