TUTORIAL 20 - Creating Classes
by Fritz
This tutorial is intended to help you create a class based mod in which players can choose from a variety of classes, each with its own unique abilities/attributes. When this tutorial is completed you should be able to choose your class (by selecting a model) and recieve different weapons and attributes based on the class you chose.
There are only 4 simple steps to this tutorial, so let's get started.
Files you will need to modify:
bg_public.h
g_local.h
g_client.c
1. Defining (bg_public.h g_local.h)
First we have to define a type to keep track of the different classes. Lets start out with 3 simple classes.
Open the file bg_public.h and Go to about line 428
typedef enum {
TEAM_FREE,
TEAM_RED,
TEAM_BLUE,
TEAM_SPECTATOR,
TEAM_NUM_TEAMS
} team_t;
typedef enum {
PCLASS_BFG,
PCLASS_LIGHTNING,
PCLASS_RAILGUN,
PCLASS_NUM_CLASSES
} pclass_t;
Next we will need a playerclass variable to keep track of what class we are, and a newplayerclass variable to store the new class we will become when we respawn.
Open the file g_local.h and about line 213 you will find the clientPersistent structure.
typedef struct {
clientConnected_t connected;
usercmd_t cmd; // we would lose angles if not persistant
qboolean localClient; // true if "ip" info key is "localhost"
qboolean initialSpawn; // the first spawn should be at a cool location
qboolean predictItemPickup; // based on cg_predictItems userinfo
char netname[36];
int maxHealth; // for handicapping
int enterTime; // level.time the client entered the game
playerTeamState_t teamState; // status in teamplay games
int voteCount; // to prevent people from constantly calling votes
qboolean teamInfo; // send team overlay updates?
pclass_t playerclass; // The players current class
pclass_t newplayerclass; // The class the player will become when it respawns
} clientPersistant_t;
This data structure is part of the gclient_t structure, and can be accessed through a gclient_t or gentity_t pointer (see below).
2. Choosing Classes (g_client.c)Ok, now we have to assign values to our newplayerclass variable when the player selects a model. The function we are about to edit is called when a client first connects to the server and whenever the player changes his user info.
Go to about line 621 and you will find the ClientUserInfoChanged() function. Notice how the
gclient_t structure is accessed from the gentity_t pointer.
// set model
Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) );
if (!Q_stricmp (model, "biker/red"))
client->pers.newplayerclass = PCLASS_BFG;
else if (!Q_stricmp (model, "anarki/blue"))
client->pers.newplayerclass = PCLASS_LIGHTNING;
else if (!Q_stricmp (model, "grunt/red"))
client->pers.newplayerclass = PCLASS_RAILGUN;
else {
client->pers.newplayerclass = PCLASS_BFG;
Q_strncpyz( model, "biker/red", sizeof( model ) );
}
client->pers.playerclass = client->pers.newplayerclass;
So far there are only class values for a couple of models, but you could easily assign values to the rest of the models. You could also assign the same number to multiple models, which would be useful if you wanted to make all the biker models, or all the larger models, etc. the same class.
If the player chooses a model that has not been assigned a class variable then they will be set to the first class by default and be given the "biker/red" model.
3.Updating The Class(g_client.c)Once a player has died we want to put the newplayerclass into playerclass when they respawn.
Go down to about line 935 in the ClientSpawn() function.
ent->flags = 0;
client->pers.playerclass = client->pers.newplayerclass;
You are finished creating your class system! You should see if your code compiles correctly at this point, but there will be absolutely no noticable changes if you run it.
2. Assigning stuff to the classes (g_client.c)
The final thing you have to do is give the players different stuff depending on what class they are.
Go to about line 945 in the ClientSpawn() function.
if ( g_gametype.integer == GT_TEAM ) {
client->ps.ammo[WP_MACHINEGUN] = 50;
} else {
client->ps.ammo[WP_MACHINEGUN] = 100;
}
//assign weapons according to class
switch (client->pers.playerclass){
case PCLASS_BFG:
client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BFG );
client->ps.ammo[WP_BFG] = 20;
break;
case PCLASS_LIGHTNING:
client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_LIGHTNING );
client->ps.ammo[WP_LIGHTNING] = 60;
break;
case PCLASS_RAILGUN:
default:
client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_RAILGUN );
client->ps.ammo[WP_RAILGUN] = 20;
break;
}
You now have working classes! Right now the only thing that distinguishes the classes are the weapons they begin with but you could easily give them different speeds, health, armour, special abilities, etc. So now its your job to flesh out your classes and make your mod interesting.
If you have any questions you'd like to ask me please e-mail me Fritz
|