|
|
|
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 CodeThis 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 CodeNow 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