/**
*	Currently the plugin could add tag to Steam players only
*
*
*	Credits:
*	- kroshk4 for plugin 'VipMenu'
*	- serfreeman1337 for plugin 'Top SayPrefix'
*	- Lev for dproto & plugin 'UpdateHint'
*
*
*	SayText standard message structure for player chat:
*	  MSG_ONE, 4 arguments
*	  Arg 1 (Byte "1")
*	  Arg 2 (String "#Cstrike_Chat_<>")
*	  Arg 3 (String "")
*	  Arg 4 (String "<text>^n")
*/

#include <amxmodx>
#tryinclude <updatehint>

#define PLUGIN "Say Prefix"
#define VERSION "0.93"
#define AUTHOR "Safety1st"

// customizable parameters
new const STEAM_PREFIX[] = "^4[STEAM]^1"
// end of customizable parameters


// macro; %1 - variable being modified, %2 - player id
#define CheckFlag(%1,%2)  (%1 &   (1 << (%2 & 31)))
#define SetFlag(%1,%2)    (%1 |=  (1 << (%2 & 31)))
#define ClearFlag(%1,%2)  (%1 &= ~(1 << (%2 & 31)))
new gbIsSteam

new giMaxPlayers

#if !defined _updatehint_included
	/* plugin 'Update Client Hint' (c-s.net.ua/forum/topic44709.html) is not used.
	   we should get player auth by ourselves. */
	new pDprotoProvider
	#define DP_AUTH_STEAM 2 	// native Steam
#endif

public plugin_init() {
	register_plugin( PLUGIN, VERSION, AUTHOR )

	register_message( get_user_msgid("SayText"), "Msg_SayText" )

	giMaxPlayers = get_maxplayers()

#if !defined _updatehint_included
	pDprotoProvider = get_cvar_pointer( "dp_r_id_provider" )	// dproto interface
#endif
}

public client_putinserver(id) {
	is_user_steam(id) ? SetFlag( gbIsSteam, id ) : ClearFlag( gbIsSteam, id )
}

public Msg_SayText( msgid, dest, receiver ) {
	// remember: we care about standard game chat messages only!

	if( dest != MSG_ONE )
		// ignore any other messages; for example '#Cstrike_Name_Change' that is sent as MSG_BROADCAST
		return PLUGIN_CONTINUE

	#define ARG_SENDERID     1
	#define ARG_MAIN_STRING  2
	#define STD_MSG_ARGS_NUM 4

	new id = get_msg_arg_int(ARG_SENDERID)
	if( !id || id > giMaxPlayers )
		return PLUGIN_CONTINUE

	if( !CheckFlag( gbIsSteam, id ) )
		// nothing to worry about
		return PLUGIN_CONTINUE

	new paramsCount = get_msg_args()
	if( paramsCount != STD_MSG_ARGS_NUM ) {
		/* generally SayText usermsg could have any number of arguments;
		   ignore all MSG_ONE messages that are definitely not a standard chat ones */
		return PLUGIN_CONTINUE
	}

	#define REQ_SIZE 64 	// ARG_MAIN_STRING size
	/* Minimum size is sizeof STEAM_PREFIX + 21 (the longest #Cstrike_Chat_<> string) + 1 (space between them).
		Maximum one is limited by user message size - 192 bytes for whole message.
		I decided not to take into account 3rd party tags and possible double-byte character truncating */

	// checking cache
	static msgLastId, Float:msgLastTime, msgHolder[ REQ_SIZE ]

	if( msgLastId == id && msgLastTime == get_gametime() ) {
		// we are not cache get_gametime() value because assuming it mostly used one time
		set_msg_arg_string( ARG_MAIN_STRING, msgHolder )
		return PLUGIN_CONTINUE
	}

	static const szChatAll[] = "#Cstrike_Chat_All"
	static szMsg[REQ_SIZE], szNewMsg[REQ_SIZE]

	get_msg_arg_string( ARG_MAIN_STRING, szMsg, charsmax(szMsg) )
	if( !strcmp( szMsg, szChatAll ) ) {
		// create template entirely because original one is unusable due to STX symbol
		// formatex is not suitable here because of %s parameters intended for processing by the game
		copy( szNewMsg, charsmax(szNewMsg), STEAM_PREFIX )
		add( szNewMsg, charsmax(szNewMsg), " ^3%s1^1 :  %s2" )
	}
	else
		formatex( szNewMsg, charsmax(szNewMsg), "%s %s", STEAM_PREFIX, szMsg )

	set_msg_arg_string( ARG_MAIN_STRING, szNewMsg )

	// save to cache
	msgLastId = id
	msgLastTime = get_gametime()
	copy( msgHolder, charsmax(msgHolder), szNewMsg )

	return PLUGIN_CONTINUE
}

#if !defined _updatehint_included
	is_user_steam(id) {
		if ( !pDprotoProvider )
			return 0

		if( is_user_bot(id) || is_user_hltv(id) )
			return 0

		server_cmd( "dp_clientinfo %d", id )
		server_exec()

		return get_pcvar_num( pDprotoProvider ) == DP_AUTH_STEAM ? 1 : 0
	}
#endif