Follow these steps on coding a QVM on Microsoft Windows 2000/XP/Vista/7.LAST UPDATED ON JANUARY 21, 2010
BEFORE ANYTHING, please read "
The short and sweet guide to compiling SVN 895 on Windows", by
Risujin, but skip instruction #9-14. If you need more help with installing MSYS check out this awesome
tutorial on installing MSYS.
Most people on Windows XP have a Error with MSYS. MSYS would quickly open the close. This error occurs because of multiple reason. One reason is that your Operating System is outdated. Try buying a newer Operating System. Another reason is that your bin/msys-1.0.dll is old. Try downloading an updated msys-1.0.dll from Source Files. If neither of these help, try buying larger computer
RAM (Random Access Memory). After doing all of this and MSYS still does not load try trouble shooting at the
MSYS Forums.
Getting and Building a QVM
Now if you don't have these, install them now:
MinGWWhat is MinGW?
MinGW [Minimalist GNU for Windows], formerly mingw32, is a native software port of the GNU Compiler Collection (GCC) to Microsoft Windows, along with a set of freely distributable import libraries and header files for the Windows API.MSYSWhat is MSYS?
MSYS [Minimalist GNU for Windows], (an acronym for "Minimal SYStem"), is a command line environment based on bash, (the GNU Bourne Again Shell).Notepad++What is Notepad++?
Notepad++ [Notepad-Plus-Plus] is a text editor and source code editor for Windows, though it can run on Linux and Mac OS X, using software such as Wine[1].
What is Subversion?
Subversion is a free/open-source version control system.
What is TortoiseSVN?
TortoiseSVN is a Subversion client, implemented as a Microsoft Windows shell extension.After installing all of the above restart/reboot your computer.
Getting a QVM
When your back at your desktop right click your desktop and click
SVN Checkout. A screen will load, fill the information blanks with the following information given:

Press Ok and wait until the SVN Checkout is finished *Completed At revision: ####*. Then close it by clicking Ok.
Building a QVM
First
open/load MSYS. Now in MSYS
type the following:
When the build
is finished it should go back to what it was before. If there are
no errors go to
your build/vm folder and you will find
your game.qvm there. To test it
copy your game.qvm and
drag your game.qvm into
your server's vm folder. In
your server's console type either
!map atcs or for a easier way to test it
do !devmap atcs. Test it and have fun!
Modifying a QVM
Opening the file
Open
My Computer then click
(DRIVE NAME)(C:). Open the

folder, then the

folder, after that open the

folder, and last but most importantly
open the g_admin.c file with Notepad++. If Notepad++ is not in recommended programs to open it with, browse it:
C:\Program Files\Notepad++\notepad++.exe
To jump to a line in Notepad++ go to the Search tab on the top, then click Go To... this will be needed all throughout the tutorial. (NOTE: of you change anything remember to copy the file and past it in a backup directory in case of a(n) error)
The beginning of your Commands
When g_admin.c is open the first command should be
{"adjustban", G_admin_adjustban, "ban",
"change the duration or reason of a ban. duration is specified as "
"numbers followed by units 'w' (weeks), 'd' (days), 'h' (hours) or "
"'m' (minutes), or seconds if no units are specified. if the duration is"
" preceded by a + or -, the ban duration will be extended or shortened by"
" the specified amount",
"[^3ban#^7] (^5/mask^7) (^5duration^7) (^5reason^7)"
},
Scroll down until you reach
{"unmute", G_admin_mute, "mute",
"unmute a muted player",
"[^3name|slot#^7]"
}
Below this type
//Beginning of (YOUR NAME)'s commands
or if you find this easier
//Start of (YOUR NAME)'s commands
my result would be
//Beginning of Lonly's commands
or
//Start of Lonly's commands
The layout of the Command
The way a Command is typed is
{"(COMMAND)", G_admin_(COMMAND), "(COMMAND'S GENRE)",
"(DESCRIPTION)",
"(USAGE)"
},
So if you want to make a Command you would do
{"kick", G_admin_kick, "kick",
"kick a player with an optional reason",
"[^3name|slot#^7] (^5reason^7)"
},
Your last command, at the bottom of it make sure that }, is only } all the other commands must have }, with the exception of the last one. Once you've typed all of your commands below that type
//End of (YOUR NAME)'s commands
or if you find this easier
//Finish of (YOUR NAME)'s commands
my result would be
//End of Lonly's commands
or
//Finish of Lonly's commands
The function of the Command
Now, jump to line 2890 in g_admin.c, below this is something else we won't be going over. At the bottom of the page is the "function" of the command. Basically it tells what the command should do and alternate errors and warnings.
AP( va( "print \"^3%s: ^7the %s team has been %slocked by %s\n\"",
command, BG_TeamName( team ), lock ? "" : "un",
ent ? ent->client->pers.netname : "console" ) );
return qtrue;
}
Below this type
//Beginning of (YOUR NAME)'s commands
or if you find this easier
//Start of (YOUR NAME)'s commands
my result would be
//Beginning of Lonly's commands
or
//Start of Lonly's commands
Now type,
qboolean G_admin_(YOUR COMMAND)( gentity_t *ent ) <- (YOUR COMMAND = the one from g_admin.h)
Were going to follow our example (!kick) so it would be
qboolean G_admin_kick( gentity_t *ent )
Then below this we would add the function. This requires learning how to code. So once you learn how to code you code out the function, which in this case would be
{
int pids[ MAX_CLIENTS ], found;
char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
int minargc;
gentity_t *vic;
minargc = 3;
if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
minargc = 2;
if( trap_Argc() < minargc )
{
ADMP( "^3kick: ^7usage: kick [name] [reason]\n" );
return qfalse;
}
trap_Argv( 1, name, sizeof( name ) );
reason = ConcatArgs( 2 );
if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3kick: ^7%s\n", err ) );
return qfalse;
}
vic = &g_entities[ pids[ 0 ] ];
if( !admin_higher( ent, vic ) )
{
ADMP( "^3kick: ^7sorry, but your intended victim has a higher admin"
" level than you\n" );
return qfalse;
}
if( vic->client->pers.localClient )
{
ADMP( "^3kick: ^7disconnecting the host would end the game\n" );
return qfalse;
}
admin_create_ban( ent,
vic->client->pers.netname,
vic->client->pers.guid,
vic->client->pers.ip,
MAX( 1, G_admin_parse_time( g_adminTempBan.string ) ),
( *reason ) ? reason : "kicked by admin" );
admin_writeconfig();
return qtrue;
}
Once we compile this and go into Tremulous and start a LAN server with the QVM we compiled and used !kick it would kick a player out of the server. When ever you see something like
AP( va(
"print \"^3denybuild: ^7building rights for ^7%s^7 revoked by ^7%s\n\"",
vic->client->pers.netname,
( ent ) ? ent->client->pers.netname : "console" ) );
}
return qtrue;
}
If you were wondering what %s means, it is always found at the end of the print. In this case the first %s means
,vic->client->pers.netname
Which means the name given by the player who used the command, and the second %s means
,( ent ) ? ent->client->pers.netname : "console"
Which means the player's name who used the command. For example if I used deny build in Tremulous it would look like
!denybuild terminator
then a text will appear in the console/text saying
denybuild: building rights for terminator has been revoked by Lonly
If you are just wondering how to make something appear as text on someone's screen when they use the command you would use
qboolean G_admin_(COMMAND)( gentity_t *ent, int )
{
ADMP("(YOUR TEXT)\n" );
}
return qtrue;
}
That will show up in the console, currently I do not know how to make it show up on the screen.
The g_admin.h
The G_admin_(COMMAND) would go in the g_admin.c and it sorta connects to the g_admin.h
If you open the g_admin.c, which is right next to the g_admin.h if it is sorted by name you would find at line 151
// ! command functions
Below this is a list of the G_admin_(COMMANDS)
qboolean G_admin_time( gentity_t *ent );
qboolean G_admin_setlevel( gentity_t *ent );
qboolean G_admin_kick( gentity_t *ent );
etc.
Below
qboolean G_admin_nextmap( gentity_t *ent );
qboolean G_admin_namelog( gentity_t *ent );
qboolean G_admin_lock( gentity_t *ent );
Below this type
//Beginning of (YOUR NAME)'s commands
or if you find this easier
//Start of (YOUR NAME)'s commands
my result would be
//Beginning of Lonly's commands
or
//Start of Lonly's commands
Then once you typed //Beginning of (YOUR NAME)'s commands in g_admin.c you would copy the G_admin_(COMMAND) and paste it below //Beginning of (YOUR NAME)'s commands. After you typed all of your G_admin_(COMMAND)s type below that
//End of (YOUR NAME)'s commands
or if you find this easier
//Finish of (YOUR NAME)'s commands
my result would be
//End of Lonly's commands
or
//Finish of Lonly's commands
The tremulous.h
Now open the tremulous.h (the last file if sorted by name)
In the tremulous.h you will find:
1. Classes/Levels and their abilities (speed, value, regen, and cost)
2. Weapons and their abilities
3. Upgrades and their abilities
4. Buildables and their abilities
5. Other
If you change anything remember to write after your change //(default)
Also if you edit the tremulous.h remember to try your best to make the teams even to win
Some places you would find a time number, most of the time it goes by Milliseconds
The bg_misc.c
In the bg_misc.c you would find
1. Buildable names and their description
2. Classes/Levels names and their description
3. Error and warning text
3. *.PK3 directories
4. Weapon names and their description
5. Upgrade names and their description
6. Event names
7. Team names
The bg_misc.c (CONTINUED: Buildable's names)
The buildable names start at line 38
"eggpod", //char *buildName;
is the console CMD name to build the buildable. If you joined a server and (as a granger) typed /build eggpod you would build the buildable [
EXAMPLE(1.1)] [
AFTER ENTERED(1.1)].
"Egg", //char *humanName;
is the buildable name in the list of buildables. [
EXAMPLE(1.1)]
This goes for every other buildable. Buildable names end at line 599.
The bg_misc.c (CONTINUED: Class/Level's names)
Class/Level names starts at line 888.
"builder", //char *className;
is the name of the class that if you type in the console you spawn as it.
"Responsible for building and maintaining all the alien structures. "
"Has a weak melee slash attack.",
is the description of the class. [
EXAMPLE(1.1)]
Class/level names end at line 1245.
The bg_misc.c (CONTINUED: Class/Level's names)
Error and warning text are scattered everywhere and they look like:
{
Com_Printf( S_COLOR_RED "ERROR: Buildable file %s doesn't exist\n", filename );
return qfalse;
}
The bg_misc.c (CONTINUED: *.PK3 directories)
*.PK3 Directories are scattered everywhere and some look like:
{
bc = BG_BuildableConfig( i );
Com_Memset( bc, 0, sizeof( buildableConfig_t ) );
BG_ParseBuildableFile( va( "configs/buildables/%s.cfg",
BG_Buildable( i )->name ), bc );
}
The bg_misc.c (CONTINUED: Weapon names and descriptions)
Weapon names and their description starts at line 1935.
( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
is the stages available to be bought at the Armoury.
"rifle", //char *weaponName;
is the text you would type in the console.
"Rifle", //char *humanName;
is the text on the list at the Armoury.
"Basic weapon. Cased projectile weapon, with a slow clip based "
"reload system.",
is the description of the weapon.
qfalse, //int infiniteAmmo;
qfalse means it does not have unlimited ammunition and qtrue means it has unlimited ammunition.
qfalse, //int usesEnergy;
qfalse means it does not use energy and qtrue means it uses energy.
qfalse, //qboolean canZoom;
qfalse means you cannot zoom in with it and qtrue means you can zoom in with it.
qtrue, //qboolean purchasable
qtrue means it is purchasable and qfalse means it is not purchasable.
TEAM_HUMANS //team_t team;
is the team that is allowed to purchase it/use it.
Weapon names and their description ends at line 2400.
The bg_misc.c (CONTINUED: Upgrade names and descriptions)
Upgrade names and their description starts at line 2454.
( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
is the stages available to be bought at the Armoury.
"larmour", //char *upgradeName;
is the text you would type in the console.
"Light Armour", //char *humanName;
is the text on the list at the Armoury.
"Protective armour that helps to defend against light alien melee "
"attacks.",
is the description of the upgrade.
"icons/iconu_larmour",
is the directory where the Upgrade's icon is found in the *.PK3.
qtrue, //qboolean purchasable
qtrue means it is purchasable and qfalse means it is not purchasable.
qfalse, //qboolean usable
qtrue means in the game it is not shaded grey and unusable and qfalse means it is grey and unusable (Default = qfalse because there is a bind to use it)
TEAM_HUMANS //team_t team;
is the team that is allowed to purchase it/use it.
Upgrade names and their description end at line 2566.
The bg_misc.c (CONTINUED: Event names)
Event names start at line 2733
We do not recommend changing this unless you are a professional. I do not know how to change this or what anything means.
Event names end at line 2832
The bg_misc.c (CONTINUED: Team names)
Team names start at line 3965
Here are the team names that you type in the CONSOLE. [Example: /team humans /team aliens /team spectators
Team names end at line 3974
The cg_main.c
Open the cg_main.c file in the src/cgame folder. Here are mostly *.PK3 directories and cg_commands. The *.PK3 directories are at lines 610 - 875. The cg_commands are at lines 50 - 355. This file is mostly edited by HUD makers and modders.
Side Notes
NOTE: I am not responsible for server crashes. If any marks within the qvm are placed or deleted, errors will occur.
WikipediaScreenshot StudioGimp 2.6.8000webhost