Ingame menu for server plugins (CS:S only): Difference between revisions
| mNo edit summary | |||
| Line 1: | Line 1: | ||
| == Creating an in-game menu for server plugins == | == Creating an in-game menu for server plugins == | ||
Revision as of 15:07, 18 January 2006
The ingame menu is a usermessage so we will need to include bitbuf.cpp into the project. This can be found at src/tier1/bitbuf.cpp This needs to be added to the project and have
#include "bitbuf.h"
in the includes at the top of serverplugin_empty.cpp
We will also need a Recipient Filter, I have used one from mosca.br at HL2Coding
MRecipientFilter.cpp
#include "MRecipientFilter.h"
#include "interface.h"
#include "filesystem.h"
#include "engine/iserverplugin.h"
#include "dlls/iplayerinfo.h"
#include "eiface.h"
#include "igameevents.h"
#include "convar.h"
#include "Color.h"
#include "shake.h"
#include "IEffects.h"
#include "engine/IEngineSound.h"
extern IVEngineServer   *engine;
extern IPlayerInfoManager *playerinfomanager;
extern IServerPluginHelpers *helpers;
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
MRecipientFilter::MRecipientFilter(void)
{
}
MRecipientFilter::~MRecipientFilter(void)
{
}
int MRecipientFilter::GetRecipientCount() const
{
	return m_Recipients.Size();
}
int MRecipientFilter::GetRecipientIndex(int slot) const
{
	if ( slot < 0 || slot >= GetRecipientCount() )
		return -1;
	return m_Recipients[ slot ];
}
bool MRecipientFilter::IsInitMessage() const
{
	return false;
}
bool MRecipientFilter::IsReliable() const
{
	return false;
}
void MRecipientFilter::AddAllPlayers(int maxClients)
{
	m_Recipients.RemoveAll();
	for ( int i = 1; i <= maxClients; i++ )
	{
		edict_t *pPlayer = engine->PEntityOfEntIndex(i);
		if ( !pPlayer || pPlayer->IsFree())
			continue;
		//AddRecipient( pPlayer );
		m_Recipients.AddToTail(i);
	}
} 
void MRecipientFilter::AddRecipient( int iPlayer )
{
	// Already in list
	if ( m_Recipients.Find( iPlayer ) != m_Recipients.InvalidIndex() )
		return;
	m_Recipients.AddToTail( iPlayer );
}
MRecipientFilter.h
#ifndef _MRECIPIENT_FILTER_H
#define _MRECIPIENT_FILTER_H
#include "irecipientfilter.h"
#include "bitvec.h"
#include "tier1/utlvector.h"
class MRecipientFilter : public IRecipientFilter
{
public:
	MRecipientFilter(void);
	~MRecipientFilter(void);
	virtual bool IsReliable( void ) const;
	virtual bool IsInitMessage( void ) const;
	virtual int GetRecipientCount( void ) const;
	virtual int GetRecipientIndex( int slot ) const;
	void AddAllPlayers( int maxClients );
	void AddRecipient (int iPlayer );
private:
	bool m_bReliable;
	bool m_bInitMessage;
	CUtlVector< int > m_Recipients;
};
#endif
Usage
These both need adding the project and have the line in the includes at the top or serverplugin_empty.cpp
#include "MRecipientFilter.h"
We also need a function to get the clients index from their userid.
int getIndexFromUserID(int userid)
{
	edict_t *player;
	IPlayerInfo *info;
	for(int i = 1; i <= maxplayers; i++)  //int maxplayers; has to be added after the includes and maxplayers=clientMax; in the ServerActivate function
	{
		player = engine->PEntityOfEntIndex(i);
		if(!player || player->IsFree() )
			continue;
		info = playerinfomanager->GetPlayerInfo(player);
		if(info->GetUserID() == userid)
			return i;
	}
	return -1;
}
I have used made the menu as a client command activated on the command a_menu.
	if ( FStrEq( pcmd, "a_menu" ) )
	{
		IPlayerInfo *playerInfo = playerinfomanager->GetPlayerInfo(pEntity); 
		MRecipientFilter filter;
		filter.AddRecipient(getIndexFromUserID(playerInfo->GetUserID()));
		bf_write *pBuffer = engine->UserMessageBegin( &filter, 8 );
		pBuffer->WriteShort( (1<<0) | (1<<1) | (1<<2) ); //Sets how many options the menu has
		pBuffer->WriteChar( -1 ); //Sets how long the menu stays open -1 for stay until option selected
		pBuffer->WriteByte( false );
		pBuffer->WriteString( "1.Assault Rifle\n2.AWP\n3.Exit" ); //The text shown on the menu
		engine->MessageEnd();
		return PLUGIN_STOP;
	}
This menu will be an alternative buy menu that will buy ammo, armor and grenades, as well as the primary weapon.
The WriteShort contains a number of bits which tell the game which options are enabled for the menu.
- (1<<0) is 1
- (1<<1) is 2
- etc..
If you have done this correcly so far then you should have the menu show up in game when the client types a_menu.
The menu run the command menuselect with the parameter as the option selected, so for this menu the commands would be menuselect 1, menuselect 2, and menuselect 3
	else if ( FStrEq( pcmd, "menuselect" ) )
	{
		const char *parameter = engine->Cmd_Argv(1);
		switch(atoi(parameter))
		{
		case 1:
			engine->ClientCommand (pEntity, "buy m4a1;buy ak47;buy primammo;buy vesthelm;buy deagle;buy secammo;buy flashbang;buy hegrenade;buy flashbang\n");
			break;
		case 2:
			engine->ClientCommand (pEntity, "buy awp;buy primammo;buy vesthelm;buy deagle;buy secammo;buy flashbang;buy hegrenade;buy flashbang\n");
			break;
		case 3:
			engine->ClientPrintf(pEntity, "Menu Exited");
			break;
		}
		return PLUGIN_STOP;
	}  
This will make the client run the commands to buy weapons ammo armor and grenades. The menu runs the commands. Nextly : Colored Menu (Jeanlepail) :)