
Quake DeveLS - Scanner Jammer
Author: Randy
Maude, aka Sniper#1
Difficulty: Medium
Preamble
--------
My friends and I liked the
scanner mod. However, it became quickly apparent that it was being
abused. Game play would screech to a halt while players sat around
watching their scanners, waiting for the other players to come around a corner.
There had to be something I could do to balance the normal game play
with the abilities of the scanner. Firstly, it had to cost players to use
the scanner. Secondly, what if each player had access to a device which
jammed the scanners so they showed garbage. I decided to charge each
player 30 cells for the use of the jamming device. The scanner would cost
any player using it a cell per server frame.
Requirements
--------
You must have already
installed the scanner mod. You must also have added the qdevels.c module to the make file.
Changes
--------
Open and edit the file scanner.c. Insert the following yellow
lines into the file:
#include
"g_local.h"
#include "scanner.h"
//
Scanner Jammer Additions
#include
"q_devels.h"
#define
JAMMER_CELLS
30 // cost in cells per jammer activation
#define JAMMER_TIME_ON 100
// server frames the jammer is active
#define JAMMER_TIME_OFF 50
// server frames required to recharge jammer
#define SCANNER_CELLS 1
// cost in cells per server frame
int
ScannerJammerStartFrame;
void
InitializeJammer( void )
{
ScannerJammerStartFrame = 0;
}
void
ActivateScanner( edict_t *ent )
{
gitem_t *item;
if ( !( ent->client->pers.scanner_active & 1 ) )
{
if ( SCANNER_CELLS == 0 )
{
Toggle_Scanner( ent );
}
else
{
item = FindItem( "cells"
);
if (
ent->client->pers.inventory[ ITEM_INDEX( item ) ] >= SCANNER_CELLS )
{
Toggle_Scanner( ent );
ent->client->pers.inventory[ ITEM_INDEX( item ) ] -= SCANNER_CELLS;
}
}
}
else
{
Toggle_Scanner( ent );
}
}
void
PowerScanner( edict_t *ent, char *string )
{
int i;
edict_t *this_ent;
gitem_t *item;
if ( ent->client->pers.scanner_active & 1 )
{
if ( SCANNER_CELLS == 0 )
{
ShowScanner( ent, string );
}
else
{
item = FindItem(
"cells" );
if (
ent->client->pers.inventory[ ITEM_INDEX( item ) ] >= SCANNER_CELLS )
{
ShowScanner(
ent, string );
ent->client->pers.inventory[ ITEM_INDEX( item ) ] -= SCANNER_CELLS;
}
else
{
for ( i = 0;
i < maxclients->value; i++ )
{
this_ent = &g_edicts[ i + 1 ];
if ( this_ent == ent )
{
ClearScanner( &game.clients[ i ] );
break;
}
}
}
}
}
}
void
ActivateJammer( edict_t *ent )
{
gitem_t *item;
if ( ( level.framenum > ScannerJammerStartFrame + JAMMER_TIME_ON
+ JAMMER_TIME_OFF ) ||
( ScannerJammerStartFrame < 1 ) )
{
// see if player has enough cells
item = FindItem( "cells" );
if ( ent->client->pers.inventory[
ITEM_INDEX( item ) ] >= JAMMER_CELLS )
{
ent->client->pers.inventory[
ITEM_INDEX( item ) ] -= JAMMER_CELLS;
ScannerJammerStartFrame =
level.framenum;
}
}
}
// Scanner Jammer End Additions
void ClearScanner(gclient_t *client)
{
client->pers.scanner_active = 0;
}
.
.
.
This creates a variable
used to track when the jammer is "recharging" and when the jammer can
be activated again. There are also four functions added which are used to
control the scanner and its use of cells, and the jammer, without requiring
that other modules know about the variable ScannerJammerStartFrame. The
first one, InitializeScanner, sets up the starting frame so that the scanner
can be activated immediately. The second, ActivateScanner, conditionally
activates the scanner, costing the player cells, or deactivates the
scanner. The third, PowerScanner, is called every server frame, and
handles the power drain of the scanner on a player's cells. The fourth,
ActivateJammer, conditionally activates the jamming device, checking first to
make sure the player can spare enough cells.
.
.
.
void ShowScanner(edict_t
*ent,char *layout)
{
int i;
// Scanner Jammer End Additions
int sx;
int sy;
int TempNumber;
// Scanner Jammer End Additions
edict_t
*player = g_edicts;
char stats[64],
*tag;
vec3_t v;
// Main scanner graphic draw
Com_sprintf (stats, sizeof(stats),"xv 80 yv 40 picn %s
", PIC_SCANNER_TAG);
SAFE_STRCAT(layout,stats,LAYOUT_MAX_LENGTH);
// Scanner Jammer Additions
if ( ( level.framenum <= ScannerJammerStartFrame +
JAMMER_TIME_ON ) &&
( ScannerJammerStartFrame > 0 ) )
{
for ( i = 0; i < game.maxclients; i++ )
{
sx = ( int ) ( 105 + rndnum(
0, SCANNER_RANGE - 1 ) );
sy = ( int ) ( 67 + rndnum( 0,
SCANNER_RANGE - 1 ) );
// setup dot graphic
TempNumber = rndnum( 0, 8 );
switch( TempNumber )
{
case 4 :
tag = PIC_QUADDOT_TAG;
break;
case 7 :
tag = PIC_INVDOT_TAG;
break;
default :
tag = PIC_DOT_TAG;
}
// Set output ...
Com_sprintf( stats, sizeof(
stats ), "xv %i yv %i picn %s ",
sx, sy, tag);
SAFE_STRCAT( layout, stats,
LAYOUT_MAX_LENGTH );
*stats = 0;
// set up/down arrow
TempNumber = rndnum( 0, 8 );
switch( TempNumber )
{
case 4 :
Com_sprintf( stats, sizeof( stats ),"yv %i picn %s ",
sy - 5, PIC_UP_TAG);
break;
case 7 :
Com_sprintf( stats, sizeof( stats ),"yv %i picn %s ",
sy + 5, PIC_DOWN_TAG);
break;
}
if ( *stats )
{
SAFE_STRCAT(
layout, stats, LAYOUT_MAX_LENGTH );
}
}
}
else
{
// Scanner Jammer End Additions
.
.
.
}
The last brace must be placed at the end of the function ShowScanner, and can be either inserted before the ending brace or placed just after the closing brace. This code outputs random noise to the scanner if the jammer is active. The number of noise dots output equals the max number of clients set for the server.
Now open the file scanner.h and add the following lines to the
end so other modules can access these functions:
// Scanner
Jammer Additions
void InitializeJammer( void );
void ActivateScanner( edict_t *ent );
void PowerScanner( edict_t *ent );
void ActivateJammer( edict_t *ent );
// Scanner Jammer End Additions
Next, open the file g_cmds.c and find the following lines:
else if
( Q_stricmp( cmd, "scanner" ) == 0 )
{
Toggle_Scanner(ent);
}
and replace them with
these lines:
else if
( Q_stricmp( cmd, "scanner" ) == 0 )
{
//
Scanner Jammer Additions
ActivateScanner( ent );
}
else if ( Q_stricmp( cmd, "jammer" ) == 0 )
{
ActivateJammer( ent );
}
// Scanner Jammer End Additions
This will cause a new front-end function to be called when the scanner command
is entered through the console. It also adds recognition of the jammer
command, entering "cmd jammer" from the console.
Next, open the file g_main.c and insert the following lines at
the start of the function EndDMLevel:
void EndDMLevel (void)
{
edict_t *ent;
//
Scanner Jammer Additions
InitializeJammer();
// Scanner Jammer End Additions
// stay on same
level flag
if ((int)dmflags->value & DF_SAME_LEVEL)
{
This ensures that the
jammer will be reset at the end of each level. Position at the top of the
file and add the following lines after the statement '#include
"g_local.h"':
// Scanner Jammer Additions
#include "scanner.h"
// Scanner Jammer End Additions
Now open the file g_save.c and find the following line in the
function InitGame:
gi.dprintf ("==== InitGame ====\n");
Add the following lines immediately following the above line:
// Scanner Jammer Additions
InitializeJammer();
// Scanner Jammer End Additions
This initializes the jammer when the game engine is started. Position at
the top of the file and add the following lines after the statement '#include
"g_local.h"':
// Scanner
Jammer Additions
#include "scanner.h"
// Scanner Jammer End Additions
Now, open the file p_hud.c and find the following lines:
// Scanner active ?
if (ent->client->pers.scanner_active & 1)
ShowScanner(ent,string);
and replace them with
these lines:
// Scanner active ?
// Scanner Jammer Additions
PowerScanner( ent, string );
// Scanner Jammer End Additions
This installs code which updates the scanner, and deducts the proper number of
cells from the player. If the player is out of cells, it also turns off
the scanner.
That's all you need.
I hope you enjoy this mod as much as I have.
Tutorial by Randy Maude, aka Sniper#1.
|
This site, and all content and graphics
displayed on it, |