
|
|
|
|
Previous code New code Tutorial in brief: 1) How to implement classes 2) How to do 2 type of observer modes before selecting a class. 3) How to make menus and select them 4) Using Titles.txt for menus 5) Using the console to access menus and functions 6) Show Player Info (additional function) 7) Show Class Info (additional function) 8) Modifying the controls section to call our functionsWell, here's my first (somewhat basic however though) tutorial. Hope this goes well. So this tutorial is a basic class sytem (2 classes to choose from) with additional features that you'll see later. The first thing we're going to do is open player.h (line 72):
class CBasePlayer : public CBaseMonster
{
public:
// Start modification code
int m_iPlayerClass;// player's present class
int m_iFutureClass;// player's future class
int menu; // What menu we're displaying
// End modification code
int m_iPlayerSound;// the index of the sound list slot reservered for this player
int m_iTargetVolume;// ideal sound volume.
Now that should be pretty simple to understand. PS: If you don't save
each different working version of your mod in different folders, it is
good to have // Start modification code and // End modification code so
you can skip to your modification bits. NEVER delete the REAL Half-Life
source code. Just comment it with /* and */ so you can replace it with
your modification code. You don't have to but I think it's a good
idea.
Next up, open multiplay_gamerules.cpp (line 441):
if ( addDefault )
{
/* Original Half-Life Code
pPlayer->GiveNamedItem( "weapon_crowbar" );
pPlayer->GiveNamedItem( "weapon_9mmhandgun" );
pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads
*/
// Start modification code
if (pPlayer->m_iFutureClass < 1 || pPlayer -> m_iFutureClass > 3) // If they're not a valid class
pPlayer->m_iFutureClass = 1; // Set them to the first class
pPlayer->m_iPlayerClass = pPlayer->m_iFutureClass; // It's not the future class anymore. It's the present
if (pPlayer->m_iPlayerClass == 1) // If he's class 1 (Marine)
{//Marine
g_engfuncs.pfnSetClientMaxspeed( ENT(pPlayer->pev), 400); // Set his max speed to 400
pPlayer->pev->health = 125; // Set health to 125
pPlayer->pev->armorvalue = 110; // Set armor to 110
pPlayer->GiveNamedItem( "weapon_crowbar" ); // Give him a crowbar
pPlayer->GiveNamedItem( "handgrenade" ); // Give him 2 grenades
pPlayer->GiveNamedItem( "handgrenade" );
pPlayer->GiveNamedItem( "weapon_9mmAR" ); // Give him a MP5
pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY ); // Give him ammo for it
ClientPrint( pPlayer->pev , HUD_PRINTTALK , "You are now a Marine!" ); // Tell him he's a Marine
}
else if (pPlayer->m_iPlayerClass == 2) // If he's class 2 (Messenger)
{//Messenger
g_engfuncs.pfnSetClientMaxspeed( ENT(pPlayer->pev), 1200); // Set his max speed to 1200
pPlayer->pev->health = 90; // Set health to 90
pPlayer->pev->armorvalue = 90; // Set armor to 90
pPlayer->GiveNamedItem( "weapon_crowbar" ); // Give him a crowbar
pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); // Give him the normal hand gun
pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY ); // Give him ammo
ClientPrint( pPlayer->pev , HUD_PRINTTALK , "You are now a Messenger!" ); // Tell him he's a Messenger
}
// End Modification Code
}
That code is now in CHalfLifeMultiplay :: PlayerSpawn(...). Or at least
should be heh. If you're wondering, up at the top of the new code for
this part it is pPlayer->m_iFutureClass > 3 The 3rd is a simple
observer mode à la TFC. What's different between mine and the TFC one
is that you "observe" from where you will spawn the first time you join.
Let's work on this part now. Open teamplay_gamerules.cpp (line 268):
void CHalfLifeTeamplay::InitHUD( CBasePlayer * pPlayer )
{
// Start Modification Code
pPlayer->m_iPlayerClass = 3; // Sets present class to 3
pPlayer->m_iFutureClass = 3; // Sets future class to 3
ShowMenu(pPlayer,0xFF,0,0,"#selectclass"); // Shows the class menu
// End Modification Code
CHalfLifeMultiplay::InitHUD( pPlayer );
RecountTeams();
Now skip to the end of this function...
MESSAGE_END();
}
}
// Start Modification Code
pPlayer->pev->solid = 0; // I'm invisible
pPlayer->pev->takedamage = DAMAGE_NO; // I don't take damage
pPlayer->EnableControl( false ); // and I can't move!
// Instead of the above line, put in the following:
// pPlayer->pev->movetype = MOVETYPE_NOCLIP;
// to be able to move freely. TAKE NOTE: When you select a class you will spawn wherever you are!
ClientPrint( pPlayer->pev, HUD_PRINTTALK, "Welcome to my mod!"); // Prints Welcome to my mod! on player's screen
// End Modification Code
}
At the beginning... it sets are class and future class to 3 meaning we
are observing. If you're wondering how I got the ShowMenu(...) function
I'll tell you where and what to write in a jiffy. The code at the
bottom makes you invisible, unable to take damage, disables your
controls and prints to the player a welcome message.
Now here's the ShowMenu(...) function. Go to teamplay_gamerules.cpp
(line 31):
extern DLL_GLOBAL_BOOL g_fGameOver;
// Start Modification Code
extern int gmsgShowMenu;
void ShowMenu(CBasePlayer * pPlayer, int bitsValidSlots, int DisplayTime, bool DisplayNow, char menu[500])
{
MESSAGE_BEGIN( MSG_ONE, gmsgShowMenu, NULL, pPlayer->pev);
WRITE_SHORT( bitsValidSlots );
WRITE_CHAR( DisplayTime );
WRITE_BYTE( DisplayNow );
WRITE_STRING ( menu );
MESSAGE_END();
}
// End Modification Code
Let me explain:
pPlayer -> This is which client's screen it will print the menu on
bitsValidSlots -> Uses bits to determine which slots are selectable
(If you set it to 0xFF ALL slots are available)
DisplayTime -> from 1 to 127 for amount of time the menu shows.
If it's 0 to -128 it's unlimited.
DisplayNow -> If set to 0, it will display the menu right away.
If set to 1, it'll know that it needs more information to display it's menu
menu[500] -> Contains the text the menu will display (limit 499 characters on this one)
That should do it.
Now how are you going to get the selected class? I'll show you. teamplay_gamerules.cpp (line 159):
BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer * pPlayer, const char *pcmd )
{
if ( FStrEq( pcmd, "menuselect" ) )
{
if ( CMD_ARGV() < 2)
return TRUE;
int slot = atoi( CMD_ARGS(1) );
// Start Modification Code
// If it's the changeclass menu...
if (pPlayer->menu == 1)
{
if (slot > 0 && slot < 3) // If it's not a valid class #, ignore it
{
pPlayer->m_iFutureClass = slot;
if (pPlayer->m_iPlayerClass==3)
{
pPlayer->pev->solid = 1; // They're visible
pPlayer->pev->takedamage = DAMAGE_YES; // They take damage
pPlayer->EnableControl( true ); // Controls enabled
// If in the InitHUD function (you'll see later) you wrote
// pPlayer->pev->movetype = MOVETYPE_NOCLIP; instead,
// Write: pPlayer->pev->movetype = 1; instead of EnableControl( true );
CHalfLifeMultiplay :: InitHUD (pPlayer);
}
}
}
else if (pPlayer->menu == 2)
{
if (slot > 0 && slot < 3) // If it's a valid class #, display the info
ShowClassInfo(pPlayer,slot);
}
// End Modification Code
return TRUE;
}
// Start Modification Code
else if ( FStrEq( pcmd, "changeclass" ) ) // If player typed changeclass on the console
{
pPlayer->menu = 1;
ShowMenu(pPlayer,0xFF,0,0,"#selectclass"); // Show selectclass menu
return TRUE; // It worked fine. Do not return error message
}
else if ( FStrEq( pcmd, "playerinfo" ) )
{
ShowPlayerInfo(pPlayer); // Show player's info
return TRUE; // It worked fine. Do not return error message
}
else if ( FStrEq( pcmd, "classinfo" ) )
{
pPlayer->menu = 2;
ShowMenu(pPlayer,0xFF,0,0,"#classinfo"); // Show's selectclass menu
return TRUE;
}
// End Modification Code
return FALSE;
}
OK that should still be pretty easy. If the player wrote menuselect,
it'll see if he wrote a number beside it. If so, it puts that number to
int slot. Our code checks if the slot is a valid class #. If so, we
have a new future class. If the player wrote changeclass in the
console, We show the selectclass menu. If he wrote playerinfo, we show
the player info. But what is the selectclass menu and what is
ShowPlayerInfo(pPlayer)? That's due up next.
selectclass
{
Select a class:
1. Marine
2. Messenger
}
That's it! So when we show a selectclass menu, it'll write what we just wrote between the { and }.
Now for playerinfo. teamplay_gamerules.cpp (line 46 (should be right underneath our ShowMenu command)):
// Start Modification Code
void ShowPlayerInfo(CBasePlayer * pPlayer)
{
if (pPlayer->m_iPlayerClass == 1)
ClientPrint(pPlayer->pev, HUD_PRINTTALK, "You are a Marine");
else if (pPlayer->m_iPlayerClass == 2)
ClientPrint(pPlayer->pev, HUD_PRINTTALK, "You are a Messenger");
else if (pPlayer->m_iPlayerClass == 3)
ClientPrint(pPlayer->pev, HUD_PRINTTALK, "Awaiting decision");
if (pPlayer->m_iFutureClass == 1)
ClientPrint(pPlayer->pev, HUD_PRINTTALK, "You will be a Marine");
else if (pPlayer->m_iFutureClass == 2)
ClientPrint(pPlayer->pev, HUD_PRINTTALK, "You will be a Messenger");
}
// End Modification Code
This tells what the player is. Marine, Messenger or if he hasn't picked
yet it'll tell him so. It'll also tell him what his future class is.
Next up is classinfo. teamplay_gamerules.cpp (underneath what we just did):
// Start Modification Code
void ShowClassInfo(CBasePlayer * pPlayer, int PlayerClass)
{
if (PlayerClass == 1)
ShowMenu(pPlayer,0x0,64,0,"#MarineInfo");
if (PlayerClass == 2)
ShowMenu(pPlayer,0x0,64,0,"#MessengerInfo");
}
// End Modification Code
Now we'll need to write the info down for each character. Half-Life/MyMod/Titles.txt (at bottom):
MarineInfo
{
Class: Marine
The Marine is an average type.
He has 1/3 the speed of a Messenger.
He has a crowbar, an mp5 and
2 hand greandes.
Health: 125
Armor: 110
}
MessengerInfo
{
Class: Messenger
The Messenger is a speedy type.
He is very quick.
He has a crowbar and a 9mm hand gun.
Health: 90
Armor: 90
}
Note: By default, Half-Life binds keys 1 through 5 but not 6 through 0. So in Half-Life/MyMod/config.cfg add:
bind "6" "slot6" bind "7" "slot7" bind "8" "slot8" bind "9" "slot9" bind "0" "slot10" There you have it! Now when you're in the game, go to the console and type: changeclass to show the menu. Type: playerinfo to show your info. Type: classinfo to get class information.Here's some additional stuff. Before I start, let me tell you this: I do not have good experience with PAK files... it always messes my files up (almost). But here's what you can do. You may have realized that there is a Controls section in Half-Life (if not, dear god!) and in some mods there are more controls. How do they do that? It's actually quite simple. Get a PAK Editor (I prefer QPed 2) and open up Half-Life/valve/pak0.PAK. Go to the folder gfx/shell and export kb_act.lst and kb_def.lst to Half-Life/MyMod. I'm not quite sure which one is which, but there is one that looks like this:
"UPARROW" "+forward" "DOWNARROW" "+backward" and there's one that looks like this: "+forward" "Move forward" "+backward "Move backward" at the top of the first one, add: "b" "changeclass" "i" "playerinfo" "c" "classinfo" and in the top of the second one add: "changeclass" "Change class" "playerinfo" "Show player info" "classinfo" "Show class info" And that's the end of my tutorial!
Any questions or suggestions should be sent to me:
rkzad@hotmail.com