Modified: trunk/darkplaces/cl_input.c
===================================================================
--- trunk/darkplaces/cl_input.c	2007-10-06 19:23:52 UTC (rev 7604)
+++ trunk/darkplaces/cl_input.c	2007-10-06 19:24:44 UTC (rev 7605)
@@ -197,31 +197,76 @@
 
 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
 
-struct
+in_bestweapon_info_t in_bestweapon_info[IN_BESTWEAPON_MAX];
+
+void IN_BestWeapon_Register(const char *name, int impulse, int weaponbit, int activeweaponcode, int ammostat, int ammomin)
 {
-	const char *name;
-	int impulse;
-	int weaponbit;
-	int ammostat;
-	int ammomin;
+	int i;
+	for(i = 0; i < IN_BESTWEAPON_MAX && in_bestweapon_info[i].impulse; ++i)
+		if(in_bestweapon_info[i].impulse == impulse)
+			break;
+	if(i >= IN_BESTWEAPON_MAX)
+	{
+		Con_Printf("no slot left for weapon definition; increase IN_BESTWEAPON_MAX\n");
+		return; // sorry
+	}
+	strlcpy(in_bestweapon_info[i].name, name, sizeof(in_bestweapon_info[i].name));
+	in_bestweapon_info[i].impulse = impulse;
+	if(weaponbit != -1)
+		in_bestweapon_info[i].weaponbit = weaponbit;
+	if(activeweaponcode != -1)
+		in_bestweapon_info[i].activeweaponcode = activeweaponcode;
+	if(ammostat != -1)
+		in_bestweapon_info[i].ammostat = ammostat;
+	if(ammomin != -1)
+		in_bestweapon_info[i].ammomin = ammomin;
 }
-in_bestweapon_info[] =
+
+void IN_BestWeapon_ResetData (void)
 {
-	{"1", 1, IT_AXE, STAT_SHELLS, 0},
-	{"2", 2, IT_SHOTGUN, STAT_SHELLS, 1},
-	{"3", 3, IT_SUPER_SHOTGUN, STAT_SHELLS, 1},
-	{"4", 4, IT_NAILGUN, STAT_NAILS, 1},
-	{"5", 5, IT_SUPER_NAILGUN, STAT_NAILS, 1},
-	{"6", 6, IT_GRENADE_LAUNCHER, STAT_ROCKETS, 1},
-	{"7", 7, IT_ROCKET_LAUNCHER, STAT_ROCKETS, 1},
-	{"8", 8, IT_LIGHTNING, STAT_CELLS, 1},
-	{"9", 9, 128, STAT_CELLS, 1}, // generic energy weapon for mods
-	{"p", 209, 128, STAT_CELLS, 1}, // dpmod plasma gun
-	{"w", 210, 8388608, STAT_CELLS, 1}, // dpmod plasma wave cannon
-	{"l", 225, HIT_LASER_CANNON, STAT_CELLS, 1}, // hipnotic laser cannon
-	{"h", 226, HIT_MJOLNIR, STAT_CELLS, 0}, // hipnotic mjolnir hammer
-	{NULL, 0, 0, 0, 0}
-};
+	memset(in_bestweapon_info, 0, sizeof(in_bestweapon_info));
+	IN_BestWeapon_Register("1", 1, IT_AXE, IT_AXE, STAT_SHELLS, 0);
+	IN_BestWeapon_Register("2", 2, IT_SHOTGUN, IT_SHOTGUN, STAT_SHELLS, 1);
+	IN_BestWeapon_Register("3", 3, IT_SUPER_SHOTGUN, IT_SUPER_SHOTGUN, STAT_SHELLS, 1);
+	IN_BestWeapon_Register("4", 4, IT_NAILGUN, IT_NAILGUN, STAT_NAILS, 1);
+	IN_BestWeapon_Register("5", 5, IT_SUPER_NAILGUN, IT_SUPER_NAILGUN, STAT_NAILS, 1);
+	IN_BestWeapon_Register("6", 6, IT_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER, STAT_ROCKETS, 1);
+	IN_BestWeapon_Register("7", 7, IT_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER, STAT_ROCKETS, 1);
+	IN_BestWeapon_Register("8", 8, IT_LIGHTNING, IT_LIGHTNING, STAT_CELLS, 1);
+	IN_BestWeapon_Register("9", 9, 128, 128, STAT_CELLS, 1); // generic energy weapon for mods
+	IN_BestWeapon_Register("p", 209, 128, 128, STAT_CELLS, 1); // dpmod plasma gun
+	IN_BestWeapon_Register("w", 210, 8388608, 8388608, STAT_CELLS, 1); // dpmod plasma wave cannon
+	IN_BestWeapon_Register("l", 225, HIT_LASER_CANNON, HIT_LASER_CANNON, STAT_CELLS, 1); // hipnotic laser cannon
+	IN_BestWeapon_Register("h", 226, HIT_MJOLNIR, HIT_MJOLNIR, STAT_CELLS, 0); // hipnotic mjolnir hammer
+}
+
+void IN_BestWeapon_Register_f (void)
+{
+	if(Cmd_Argc() == 7)
+	{
+		IN_BestWeapon_Register(
+			Cmd_Argv(1),
+			atoi(Cmd_Argv(2)),
+			atoi(Cmd_Argv(3)),
+			atoi(Cmd_Argv(4)),
+			atoi(Cmd_Argv(5)),
+			atoi(Cmd_Argv(6))
+		);
+	}
+	else if(Cmd_Argc() == 2 && !strcmp(Cmd_Argv(1), "clear"))
+	{
+		memset(in_bestweapon_info, 0, sizeof(in_bestweapon_info));
+	}
+	else if(Cmd_Argc() == 2 && !strcmp(Cmd_Argv(1), "quake"))
+	{
+		IN_BestWeapon_ResetData();
+	}
+	else
+	{
+		Con_Printf("Usage: %s weaponshortname impulse itemcode activeweaponcode ammostat ammomin; %s clear; %s quake\n", Cmd_Argv(0), Cmd_Argv(0), Cmd_Argv(0));
+	}
+}
+
 void IN_BestWeapon (void)
 {
 	int i, n;
@@ -235,7 +280,7 @@
 	{
 		t = Cmd_Argv(i);
 		// figure out which weapon this character refers to
-		for (n = 0;in_bestweapon_info[n].name;n++)
+		for (n = 0;n < IN_BESTWEAPON_MAX && in_bestweapon_info[n].impulse;n++)
 		{
 			if (!strcmp(in_bestweapon_info[n].name, t))
 			{
@@ -256,6 +301,53 @@
 	// if we couldn't find any of the weapons, there's nothing more we can do...
 }
 
+void IN_CycleWeapon (void)
+{
+	int i, n;
+	int first = -1;
+	qboolean found = false;
+	const char *t;
+	if (Cmd_Argc() < 2)
+	{
+		Con_Printf("bestweapon requires 1 or more parameters\n");
+		return;
+	}
+	for (i = 1;i < Cmd_Argc();i++)
+	{
+		t = Cmd_Argv(i);
+		// figure out which weapon this character refers to
+		for (n = 0;n < IN_BESTWEAPON_MAX && in_bestweapon_info[n].impulse;n++)
+		{
+			if (!strcmp(in_bestweapon_info[n].name, t))
+			{
+				// we found out what weapon this character refers to
+				// check if the inventory contains the weapon and enough ammo
+				if ((cl.stats[STAT_ITEMS] & in_bestweapon_info[n].weaponbit) && (cl.stats[in_bestweapon_info[n].ammostat] >= in_bestweapon_info[n].ammomin))
+				{
+					// we found one of the weapons the player wanted
+					if(first == -1)
+						first = n;
+					if(found)
+					{
+						in_impulse = in_bestweapon_info[n].impulse;
+						return;
+					}
+					if(cl.stats[STAT_ACTIVEWEAPON] == in_bestweapon_info[n].activeweaponcode)
+						found = true;
+				}
+				break;
+			}
+		}
+		// if we couldn't identify the weapon we just ignore it and continue checking for other weapons
+	}
+	if(first != -1)
+	{
+		in_impulse = in_bestweapon_info[first].impulse;
+		return;
+	}
+	// if we couldn't find any of the weapons, there's nothing more we can do...
+}
+
 /*
 ===============
 CL_KeyState
@@ -1649,6 +1741,8 @@
 
 	// LordHavoc: added bestweapon command
 	Cmd_AddCommand ("bestweapon", IN_BestWeapon, "send an impulse number to server to select the first usable weapon out of several (example: 8 7 6 5 4 3 2 1)");
+	Cmd_AddCommand ("cycleweapon", IN_CycleWeapon, "send an impulse number to server to select the next usable weapon out of several (example: 9 4 8) if you are holding one of these, and choose the first one if you are holding none of these");
+	Cmd_AddCommand ("register_bestweapon", IN_BestWeapon_Register_f, "(for QC usage only) change weapon parameters to be used by bestweapon; stuffcmd this in ClientConnect");
 
 	Cvar_RegisterVariable(&cl_movement);
 	Cvar_RegisterVariable(&cl_movement_minping);

Modified: trunk/darkplaces/cl_main.c
===================================================================
--- trunk/darkplaces/cl_main.c	2007-10-06 19:23:52 UTC (rev 7604)
+++ trunk/darkplaces/cl_main.c	2007-10-06 19:24:44 UTC (rev 7605)
@@ -201,6 +201,9 @@
 	// mark all frames invalid for delta
 	memset(cl.qw_deltasequence, -1, sizeof(cl.qw_deltasequence));
 
+	// set bestweapon data back to Quake data
+	IN_BestWeapon_ResetData();
+
 	CL_Screen_NewMap();
 }
 

Modified: trunk/darkplaces/darkplaces.txt
===================================================================
--- trunk/darkplaces/darkplaces.txt	2007-10-06 19:23:52 UTC (rev 7604)
+++ trunk/darkplaces/darkplaces.txt	2007-10-06 19:24:44 UTC (rev 7605)
@@ -1038,7 +1038,7 @@
 -use                                              stop using something
 alias                                             create a script function (parameters are passed in as $1 through $9, and $* for all parameters)
 begin                                             signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)
-bestweapon                                        send an impulse number to server to select the first usable weapon out of several (example: 87654321)
+bestweapon                                        send an impulse number to server to select the first usable weapon out of several (example: 8 7 6 5 4 3 2 1)
 bf                                                briefly flashes a bright color tint on view (used when items are picked up)
 bind                                              binds a command to the specified key in bindmap 0
 bottomcolor                                       QW command to set bottom color without changing top color
@@ -1047,6 +1047,7 @@
 centerview                                        gradually recenter view (stop looking up/down)
 changelevel                                       change to another level, bringing along all connected clients
 changing                                          sent by qw servers to tell client to wait for level change
+cycleweapon                                       send an impulse number to server to select the next usable weapon out of several, or the first if you are not holding any (example: 8 7 3)
 cl_areastats                                      prints statistics on entity culling during collision traces
 cl_begindownloads                                 used internally by darkplaces client while connecting (causes loading of models and sounds or triggers downloads for missing ones)
 cl_downloadbegin                                  (networking) informs client of download file information, client replies with sv_startsoundload to begin the transfer

Modified: trunk/darkplaces/input.h
===================================================================
--- trunk/darkplaces/input.h	2007-10-06 19:23:52 UTC (rev 7604)
+++ trunk/darkplaces/input.h	2007-10-06 19:24:44 UTC (rev 7605)
@@ -33,5 +33,20 @@
 void IN_Move (void);
 // add additional movement on top of the keyboard move cmd
 
+#define IN_BESTWEAPON_MAX 32
+typedef struct
+{
+	char name[32];
+	int impulse;
+	int activeweaponcode;
+	int weaponbit;
+	int ammostat;
+	int ammomin;
+	// TODO add a parameter for the picture to be used by the sbar, and use it there
+}
+in_bestweapon_info_t;
+extern in_bestweapon_info_t in_bestweapon_info[IN_BESTWEAPON_MAX];
+void IN_BestWeapon_ResetData(void); // call before each map so QC can start from a clean state
+
 #endif
 

Modified: trunk/darkplaces/svvm_cmds.c
===================================================================
--- trunk/darkplaces/svvm_cmds.c	2007-10-06 19:23:52 UTC (rev 7604)
+++ trunk/darkplaces/svvm_cmds.c	2007-10-06 19:24:44 UTC (rev 7605)
@@ -142,6 +142,7 @@
 "DP_SV_CMD "
 "DP_QC_CMD "
 "FTE_STRINGS "
+"DP_CON_BESTWEAPON "
 ;
 
 /*

