Follow these steps on coding a QVM on Microsoft Windows XP.
RECENTLY UPDATED ON DECEMBER 24, 2009Before anything, read and follow "
The short and sweet guide to compiling SVN 895 on Windows", by Risujin (NOTE: DO NOT DO A SVN CHECKOUT USING MSYS)
For some people MSYS has a bug where is opens, then closes, it means your msys-1.0.dll is out dated, your computer's RAM is out of space, or you have a(n) old Operating System. Google a(n) updated msys-1.0.dll, buy a larger RAM, or buy Windows 7. Delete your current msys-1.0.dll from C:\msys\bin and then replace it with the one you download from source files. This recently usually occurs on Windows XP.
Make sure you installed:


MinGWMsysNow lets get started...
TortoiseSVN- Restart your PC
- Right click your desktop and click SVN Checkout

- A screen will pop up, fill in the information with the following:

- Press Ok and wait until the checkout is finished (Completed At revision: ####)
- Click Ok
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Opening Files- Open My Computer
then click (DRIVE NAME)(C:) [EXAMPLE] - Click
, then
, then
, then open
with Notepad++ [EXAMPLE] if Notepad++ is not in recommended programs to open it with, browse it:
[/list]
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...
(NOTE: IF YOU CHANGE ANYTHING REMEMBER TO COPY THE FILE AND PASTE IT IN A BACKUP FOLDER JUST IN CASE OF A(N) ERROR)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX
Layout of a CMDWhen g_admin.c is open the first command should be
[/list]
{"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 //begging of (YOUR NAME)'s commands
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
The layout of a CMDThe way a CMD is typed is
{"(COMMAND)", G_admin_(COMMAND), "(COMMAND'S GENRE)",
"(DESCRIPTION)",
"(USAGE)"
},
So if you want to make a CMD you would do
{"slap", G_admin_slap, "funny",
"slap the s#$% out of a player",
"[name|slot#]"
},
(EXAMPLE)
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
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
The bottom of g_admin.cNow, jump to line 2890 in g_admin.c
Here is the bottom of the page, 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.
Below
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;
}
Type /begging of (YOUR NAME)'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 (!slap) so it would be
qboolean G_admin_slap( 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
qboolean G_admin_slap( gentity_t *ent, int skiparg )
{
int pids[ MAX_CLIENTS ], found, damage = 0;
char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ],
command[ MAX_ADMIN_CMD_LEN ], *cmd;
gentity_t *vic;
vec3_t dir;
if( level.intermissiontime ) return qfalse;
if( G_SayArgc() < 2 + skiparg )
{
ADMP( "^3!slap: ^7usage: slap [name|slot#]\n" );
return qfalse;
}
G_SayArgv( skiparg, command, sizeof( command ) );
cmd = command;
if( cmd && *cmd == '!' )
cmd++;
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3!slap: ^7%s\n", err ) );
return qfalse;
}
if( !admin_immune_check( ent, &g_entities[ pids[ 0 ] ] ) )
{
ADMP( "^3!slap: ^7sorry, but your intended victim has immunity to"
" commands issued by your admin type\n" );
return qfalse;
}
vic = &g_entities[ pids[ 0 ] ];
// cant slap spectators
if( vic->client->pers.teamSelection == TEAM_NONE ||
vic->client->pers.classSelection == PCL_NONE ) {
ADMP( "^3!slap: ^7can't slap thin air\n" );
return qfalse;
}
// knockback in a random direction
dir[0] = crandom();
dir[1] = crandom();
dir[2] = random();
G_Knockback( vic, dir, g_slapKnockback.integer );
// play a sound
//G_AddEvent( vic, EV_SLAP, 0 );
if( vic != ent )
trap_SendServerCommand( vic-g_entities,
va( "cp \"%s^7 is not amused\n\"",
ent ? ent->client->pers.netname : "console" ) );
if( g_slapDamage.integer > 0 ) {
// !slap (name) [damage] syntax
if( G_SayArgc() > 2 + skiparg ) {
char dmg_str[ MAX_STRING_CHARS ];
G_SayArgv( 2 + skiparg, dmg_str, sizeof( dmg_str ) );
damage = atoi(dmg_str);
if( damage < 0 ) damage = 0;
} else {
if( g_slapDamage.integer > 100 ) g_slapDamage.integer = 100;
damage = BG_FindHealthForClass( vic->client->ps.stats[ STAT_CLASS ] ) *
g_slapDamage.integer / 100;
if( damage < 1 ) damage = 1;
}
vic->health -= damage;
vic->client->ps.stats[ STAT_HEALTH ] = vic->health;
vic->lastDamageTime = level.time;
if( vic->health <= 0 )
{
vic->flags |= FL_NO_KNOCKBACK;
vic->enemy = &g_entities[ pids[ 0 ] ];
vic->die( vic, ent, ent, damage, MOD_SLAP );
} else if( vic->pain ) vic->pain( vic, &g_entities[ pids[ 0 ] ], damage );
}
return qtrue;
}
Once we compile this and go into Tremulous and start a LAN server with the QVM we compiled and used !slap it would damage the player and push it slightly. In other cases if you just want to make the command send a text to someone just use
qboolean G_admin_(COMMAND)( gentity_t *ent, int skiparg )
{
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.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
G_admin.hThe 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 );
Type //begging of (YOUR NAME)'s commands
then once you typed the begging of a command in g_admin.c you would copy the G_admin_(COMMAND) and paste it below //begging of (YOUR NAME)'s commands. After you typed all of your G_admin_(COMMAND)s type below that //end of (YOUR NAME)'s commands.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
The tremulous.hNow 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
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
The bg_misc.cIn 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
Buildable namesThe 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.
Class/Level namesClass/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.
Error and warning textError 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;
}
*.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 );
}
Weapon names and their descriptionWeapon 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.
Upgrade names and their descriptionUpgrade 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.
Event namesEvent 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
Team namesTeam names start at line 3965
Here are the team names that you type in the CONSOLE.
Team names end at line 3974
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
12.) With
MSYS- Type cd c:
- Type cd tremulous
- Type make
- Wait...
- The game.qvm should be found in the build/vm folder
- Place it in your server's vm folder
- Run your server, type !map atcs or !devmap atcs
- Test it, use it, Enjoy
- Please do not release your qvm, keep it on your server, the last thing Tremulous needs is a million qvm downloads everywhere like the maps
NOTE: I am not responsible for server crashes. If any marks within the qvm are placed or deleted, errors will occur.
How to mod your own QVM (LINUX BASED!)A longer version will be on the
FuN Website.