There are a few requirements before I begin, you will need to have:
- An operating system (Mac, Linux, Windows, etc)
- A basic knowledge of C
- A shell program (like MSys(windows) or Terminal(Linux/mac))
- A working server (optional, only for testing the compiled qvm)
Note: make sure the shell program has SVN, "make", and a patcher
Ok, if you meet those requirements, then continue
If you don't have tremulous source, download it
svn co svn://svn.icculus.org/tremulous/trunk QVM -r966
(a lot of patches use revision 966)
What we want to focus on right now is "(place you svn'd tremulous to)/src/game"
There should be numerous files:
bg_lib.c
bg_lib.h
bg_local.h
bg_misc.c
bg_pmove.c
bg_public.h
bg_sidemove.c
g_active.c
g_admin.c
g_admin.h
g_buildable.c
g_client.c
g_cmds.c
g_combat.c
g_local.h
g_main.c
g_maprotation.c
g_mem.c
g_misc.c
g_missile.c
g_mover.c
g_physics.c
g_ptr.c
g_public.h
g_session.c
g_spawn.c
g_svcmds.c
g_syscalls.asm
g_syscalls.c
g_target.c
g_team.c
g_trigger.c
g_utils.c
g_weapon.c
tremulous.h
Each file has many different uses, but the ones that you will use most are most likely
g_admin.c
g_admin.h
g_cmds.c
g_local.h
g_main.c
tremulous.h
so I'll start with those
==================================================================================================================================
g_admin.c and g_admin.h are for making ! commands (eg !help)
to begin, I'll start with ! commands
use any text editor and open g_admin.c and g_admin.h
g_admin.c is where all the command coding will be, and g_admin.h is all the definitions of the commands
okay, now to add commands, in admin.c, you'll want to edit 2 places, around lines 40 and 180
to have a command show up in !help and to have them usable, find something that looks like
g_admin_cmd_t g_admin_cmds[ ] =
{
(line 39-40 if not patched)
You will see things like
{"admintest", G_admin_admintest, "a",
"display your current admin level",
""
},
{"allowbuild", G_admin_denybuild, "d",
"restore a player's ability to build",
"[^3name|slot#^7]"
},
{"allready", G_admin_allready, "y",
"makes everyone ready in intermission",
""
},
these are where you want to edit
If you want to keep it in alphabetical order, put the command wherever it fits, otherwise just add it anywhere
{"[command name]", [command qboolean], "[flag]",
"[description in !help]",
"[usage]"
},
***NOTE***
If you put the command at the end, do not include the "," after the "}"
okay now that the command is made, go down to around 180 where the array ends
now add a qboolean (no not bool, qboolean)
qboolean [whatever you made the command qboolean]( gentity_t *ent, int skiparg )
{
[command code goes here]
}
( gentity_t *ent, int skiparg )
do not modify that code, the qvm expects it that way
ok once you finished all of that, it's time to declare the command
in g_admin.h, go down to where it says "// ! command functions" (line 144)
anywhere below that and above "#endif /* ifndef _G_ADMIN_H */" is the area you want to edit
add a new line:
qboolean [command qboolean name]( gentity_t *ent, int skiparg );
and you've made a ! command!
==================================================================================================================================
Now, some commands require g_ variables, this can be achieved through g_local.h and g_main.c
At the bottom, (starting at line 1097 if unpatched), you will see a whole bunch of declarations:
extern vmCvar_t g_dedicated;
extern vmCvar_t g_cheats;
extern vmCvar_t g_maxclients; // allow this many total, including spectators
extern vmCvar_t g_maxGameClients; // allow this many active
extern vmCvar_t g_restarted;
extern vmCvar_t g_minCommandPeriod;
extern vmCvar_t g_minNameChangePeriod;
extern vmCvar_t g_maxNameChanges;
(just a few)
basically, just add the new variable:
extern vmCvar_t g_[variable name];
the reason we use g_ variables for qvms is because g = game, (as cg=cgame.qvm, ui=ui.qvm, r=renderer, etc)
then in g_main.c starting at line 42, you should see something like:
vmCvar_t g_fraglimit;
vmCvar_t g_timelimit;
vmCvar_t g_suddenDeathTime;
vmCvar_t g_capturelimit;
vmCvar_t g_friendlyFire;
add another line:
vmCvar_t g_[variable name];
and now a little further down (start at line 154 just to be safe) you should see:
// change anytime vars
{ &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
{ &g_suddenDeathTime, "g_suddenDeathTime", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
{ &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
{ &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE, 0, qtrue },
add a new line, and now it gets interesting

here's the format:
{ &[variable name], "[variable name in cvarlist]", "[default value]", [flags], 0(not sure what that does), [qboolean, show when changed? ("sv_timelimit has changed to XXX")] },
again drop the "," if it's the last one in the list
everything is pretty straightforward except flags,
here's a list of flags:
CVAR_ARCHIVE* (set to cause it to be saved to vars.rc used for system variables, not for player specific configurations)
CVAR_USERINFO (sent to server on connect or change)
CVAR_SERVERINFO (sent in response to front end requests)
CVAR_SYSTEMINFO (these cvars will be duplicated on all clients)
CVAR_INIT* (don't allow change from console at all, but can be set from command-line
CVAR_LATCH (will only change when C code next does a Cvar_Get(), so it can't be changed without proper initialization. Modified will be set, even though the value hasn't changed yet)
CVAR_ROM* (display only, cannot be set by a user at all)
CVAR_USER_CREATED (created by a set command)
CVAR_TEMP (can be set even when cheats are disabled, but is not archived)
CVAR_CHEAT* (cannot be changed if cheats are disabled)
CVAR_NORESTART (do not clear when a cvar_restart is issued)
CVAR_SERVER_CREATED (cvar was created by a server the client connected to)
CVAR_NONEXISTENT (cvar doesn't exist)
* = ones you will most likely only need
***NOTE***
All cvars are stored as strings, to convert to integer, use "g_[variable name]->integer"
==================================================================================================================================
Next is g_cmds.c
This is where all the / commands are (like /god or /a)
to make a new / command, start anywhere in the file not in the middle of a function, but after '#include "g_local.h"'
instead of qboolean, this will be a void
void Cmd_[command name]_f( gentity_t *ent )
{
[code goes here]
}
I'm sure many people have wondered how to get arguments, it's with
trap_Argv( [argument number starting with 1], [variable name (char[])], sizeof( [variable name] ) );
ok now that we have our command code, we can add it to the / list (line 2822)
you will notice it looks a lot like adding cvars
the syntax is a little different though:
{ "[command name (like /god)]", [flags], Cmd_[command name]_f },
once again, drop the "," if it's the last one in the list
The different flags are:
CMD_CHEAT (Can only be used when cheats are enabled)
CMD_MESSAGE (Sends message to others (skips when muted))
CMD_TEAM (Must be on a team)
CMD_NOTEAM (Must not be on a team)
CMD_ALIEN (Must be on aliens)
CMD_HUMAN (Must be on humans)
CMD_LIVING (Must be living)
CMD_INTERMISSION (Can only be used during intermission)
==================================================================================================================================
And finally, Tremulous.h
This file is where all the gameplay variable defaults are defined
i believe it's pretty straightforward, change the values (I'd suggest adding a comment after the value with the default)
"What is ADM and HDM?"
ADM/HDM = Damage modifier for each team, you should see
#define ALIEN_WDMG_MODIFIER 1.0f
and
#define HUMAN_WDMG_MODIFIER 1.0f
don't worry about them, they're damage multipliers.
==================================================================================================================================
This post will be updated regularly to answer questions and such,
once i get enough I'll start a FAQ

Any questions? feel free to post!