Quake DeveLS - Radio

Author: Xaos
Difficulty: Easy

NOTE: The file radio.zip must be downloaded in order for this tutorial to work! I have included sample wav files in a pak file as well as a sample chat config script to use it.


Preamble
--------

You're a Space Marine, right? RIGHT!

Space Marines have radios, right? RIGHT!

Here is a modification which will allow you to use your radio to "chat" with the other Marines. Using pre-recorded messages, you will actually be able to hear what others have to say.


First, create a file called "x_radio.h" in your Quake 2 DLL project workspace. Into this, put the following lines of code :

// radio functions
void X_Radio_Power_f(edict_t *self, char *state);
void X_Radio_f(edict_t *self, char *channel, char *msg);

Explanation : These lines of code are the function prototypes. I find it nice to keep as much of my code as possible in separate files so that I don't muck up the original code much. I'll explain these functions later on in the tutorial.

Next insert the following code at the end of the "client_persistant_t" structure in "g_local.h" (about line 836)

	//========================================================
	//XAOS Radio Code
	//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	int radio_power;
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation : This will hold the status for the radio in the clients structure. Setting it to 1 allows the player to hear messages while setting it to 0 disables all message reception for that player.

Next insert the following code at end of qboolean ClientConnect (edict_t *ent, char *userinfo) before ClientUserinfoChanged (ent, userinfo) in "p_client.c" (about line 1383)

	//========================================================
	//XAOS Initialize Radio Power Switch to OFF
	//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	ent->client->pers.radio_power = 0;
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation : This initializes the Radio in the OFF state when the Client first connects to the server. I decided to set it to OFF first since not everyone will want to hear the chatter. Those that do can simply turn it back on in their autoexec.cfg.

Now we are going to setup the commands which you can use to turn your radio on and off as well as send messages.

Insert the following code at beginning of "g_cmds.c"

	//========================================================
	//XAOS Added include file
	//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	#include "x_radio.h"
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

And the foloowing at the end of void ClientCommand (edict_t *ent) [At the end of the file]

	//========================================================
	//XAOS Radio Code
	//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	else if (Q_stricmp (cmd, "radio_power") == 0)	//Radio Power Switch
		X_Radio_Power_f(ent, gi.argv(1));
	else if (Q_stricmp (cmd, "radio") == 0)		//Radio to All Players
		X_Radio_f(ent, 'ALL', gi.argv(1));
	else if (Q_stricmp (cmd, "tradio") == 0)		//Radio to Team
		X_Radio_f(ent, 'TEAM', gi.argv(1));
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Explanation : This sets up 3 new commands.
radio_power [0/1]
This turns the radio ON(1) or OFF(0)
radio "wavfile"
This plays "wavfile" on all players radios who have them turned ON
tradio "wavfile"
This plays "wavfile" on all teammates (CTF only) radios who have them turned ON

Now to the heart of the radio code. Place the following into a new file called "x_radio.c" in your Quake 2 DLL project workspace.

#include "g_local.h"
#include "q_devels.h"
#include "x_radio.h"

void X_Radio_Power_f(edict_t *self, char *state)
{
	if (Q_stricmp (state, "1") == 0)
	{
		self->client->pers.radio_power = 1;
		gi.cprintf(self, PRINT_HIGH, "Radio ON\n");
	}
	else
	{
		self->client->pers.radio_power = 0;
		gi.cprintf(self, PRINT_HIGH, "Radio OFF\n");
	}
}

void X_Radio_f(edict_t *self, char *channel, char *msg)
{
	edict_t *player;
	int i;
	char *cmd, *pos;
	
	cmd = "\0";				// Initialize cmd variable
	if(pos = strstr(msg,";"))			// Check if msg contains ';'
		pos[0]=0;			//	 If so, terminate string there
	sprintf( cmd, "play radio/%s\n", msg);		// Build command to send

	if (Q_stricmp (channel, "ALL") == 0)		// To All Players
	{
		for_each_player(player, i)
		{
			if (player->client->pers.radio_power)
				x_stuffcmd(player, cmd);
		}
	}
	else if (Q_stricmp (channel, "TEAM") == 0)	// To Team Members
	{
		for_each_player(player, i)
		{
			if (player->client->resp.ctf_team == self->client->resp.ctf_team)
				if (player->client->pers.radio_power)
					x_stuffcmd(player, cmd);
		}
	}
}

Explanation: X_Radio_Power_f sets the variable we added to the persistent client data earlier and prints a message to the console to indicate the changed status.

X_Radio_f first searches the message string for any ';'s and if it finds any, it terminates the string at that point. This has to be done to keep players from sending additional commends to other players' consoles (e.g. 'kill'). It then builds up the command string to send to the other players. By building it like this, we can limit the possible wave files to ones in the baseq2/sound/radio sub-directory.

We then check to see which players we need to send the message to. The message is sent by using the stuffcmd (renamed to x_stuffcmd so that it doesn't conflict with Zoid's CTF II function) function as defined in q_devels.c (renamed here as well). This actually sends the command to play the wavefile to another players console instead of burdening the network with transferring the massive amounts of data that actuall voice transmission would require.


And that's about it ! :) The only thing left is for you to bind "radio_power" to a suitable key, set up your aliases to play the wav files, and boot-up Quake 2 !!

There are loads of possibilities for further modifications :

	1) Implement channels so that you can have subdivisions on a team (e.g. channel 15 = Blue team defense, 16 = Blue team offense)

	2) Send to a specific player. (e.g. pradio "player_name" "wavfile" )

	3) Send to a the last player to hurt you (your enemy). (e.g. eradio "wavfile" )

I'd like to thank Kevin for his assistance on plugging the security hole which would allow additional commands to be sent to other clients. I'd also like to thank the team that helped beta test this mod at or last Quakefest. Thanks guys!!

Enjoy !

Tutorial by Xaos .

This site, and all content and graphics displayed on it,
are ©opyrighted to the Quake DeveLS team. All rights received.
Got a suggestion? Comment? Question? Hate mail? Send it to us!
Oh yeah, this site is best viewed in 16 Bit or higher, with the resolution on 800*600.
Thanks to Planet Quake for their great help and support with hosting.
Best viewed with Netscape 4