The problem happens because the constant 'LANG_PLAYER' is used to send a message to all players, but when do we use the color print function on Amx Mod X 1.8.2, we have to send that message to every player, then we cannot use the constant 'LANG_PLAYER'. As we need to send the colored text to every player, we need need to use the player_id instead of the constant 'LANG_PLAYER'.
The sad part part about that is, that we cannot create a macro function that easly print colored text to all uses respecting the 'LANG_PLAYER' constant limitation on Amx Mod X '1.8.2'. Latter on, will be show a unsucessful atempt to create a general way to print colored functions on Amx Mod X '1.8.2'.
Here are present 2 new implementations for Amx Mod X '1.8.2' that are compatible simultaniasly with the Amx Mod X '1.8.3' or superior. One implementation is using a remastered ConnorMcLeod code, and another just using preprocessor directives to improve speed. And both implementations are compatible with each other, which means that you can use both at your code. Here you can find the original implementation made by ConnorMcLeod.
If you run this functions on a Game Mod that do not support colored messages, they will be displayed as normal messages without any errors or bad formats.
To this works, we need to register the LANG file dictionary as colored dictionary, then we can use '!t', '!g', and '!y' for colors at the lang file. And this allow you to use '!g for green', '!y for yellow' and '!t for team' color at the colored registred dictionary file and '^1', '^3' and '^4' inside de plugin. To register the dictionary as a colored dictionary, simple call 'register_dictionary_colored' provided here bellow, instead of 'register_dictionary' when you register your LANG dictionary.
If the player id is 0 we need to repeat this code that follow or equivalent every time we need to print a chat color, because this is the implementation based on preprocessor directives. So, if you want to use the optimized way at the Amx Mod X '1.8.2', you have to use the code as follows bellow. If you do not want to use the optimized way, just simply/normally call the function 'color_print' using the 'LANG_PLAYER' constant and do not use this preprocessor based way every time you want to print colored messages to all players.
The way as follows, is a simple call the the function 'color_print' mentioned. With the way presented bellow you do not need to start your LANG file constants with a color, as the calling function already do that using the default color '^1' yellow. You can use this, if you do not want the optimized way on the Amx Mod X '1.8.2', but despite that, this way will be optimized at the Amx Mod X '1.8.3' or superior. This is an example when the player_id is greater than 0:
This is an example, when you do not use a LANG file dictionary, and put the colors at the source code:
Code:
// Every formatted message must begin with a color.
color_print( player_id, "^1Here is everyting yellow.^3Now it is team color.^4\
Now everything is green and my poor string variable is^1 %s yellow again.", poor_string_variable )
This is when you know that it is just for only one player: (You can use this to show a colored message to all player on Amx Mod X '1.8.2' with player_id as 0 and using LANG_PLAYER instead of player_id, but it will be not optimized. But if you are at the Amx Mod X '1.8.3' or superior, it will be optimized)
Code:
color_print( player_id, "^1%L", player_id, "MY_LANG_CONSTANT")// here, use player_id instead of LANG_PLAYER
This is when you want to put a message to all players: (This is the optimized war for Amx Mod X '1.8.2' or superior)
/**
* Print colored text to a given player_id. It has to be called to each player using its player_id
* instead of 'LANG_PLAYER' constant. Just use the 'LANG_PLAYER' constant when using this function
* to display to all players.
*
* This includes the code:
* ConnorMcLeod's [Dyn Native] ColorChat v0.3.2 (04 jul 2013) register_dictionary_colored function:
* <a href="https://forums.alliedmods.net/showthread.php?p=851160">ColorChat v0.3.2</a>
*
* If you run this function on a Game Mod that do not support colored messages, they will be
* displayed as normal messages without any errors or bad formats.
*
* This allow you to use '!g for green', '!y for yellow', '!t for team' color with LANGs at a
* register_dictionary_colored file. Otherwise use '^1', '^2', '^3' and '^4'.
*
* @param player_id the player id.
* @param lang_formatting the text formatting rules to display.
* @param any the variable number of formatting parameters.
*
* @see <a href="https://www.amxmodx.org/api/amxmodx/client_print_color">client_print_color</a>
* @see <a href="https://forums.alliedmods.net/showthread.php?t=297484">vformat() ignoring user language</a>
*/stock color_print(const player_id, const lang_formatting[], any:... ){new formatted_message[ MAX_COLOR_MESSAGE ];
if( player_id ){if( g_is_color_chat_supported ){// Here all the colored messaged must to start within a color.
formatted_message[0] = '^1';
vformat( formatted_message[1], charsmax( formatted_message ) - 1, lang_formatting, 3);
if( g_coloredChatPrefix[0]){new message[ MAX_COLOR_MESSAGE ];
formatex( message, charsmax( message ), "^1%s^1%s", g_coloredChatPrefix, formatted_message[1]);
PRINT_COLORED_MESSAGE( player_id, message )}else{
PRINT_COLORED_MESSAGE( player_id, formatted_message )}}else{vformat( formatted_message, charsmax( formatted_message ), lang_formatting, 3);
REMOVE_COLOR_TAGS( formatted_message )client_print( player_id, print_chat, "%s%s", g_coloredChatPrefix, formatted_message );
}}else{new playersCount;
new players[ MAX_PLAYERS ];
// Get the server players skipping the botsget_players( players, playersCount, "c");
// Figure out if at least 1 player is connected, so we don't execute useless codeif( !playersCount ){return;
}new player_id;
new string_index;
new argument_index;
new multi_lingual_constants_number;
new params_number;
new Array:multi_lingual_indexes_array;
multi_lingual_indexes_array = ArrayCreate();
params_number = numargs();
multi_lingual_constants_number = 0;
// ML can be usedif( params_number > 3){for( argument_index = 2; argument_index < params_number; argument_index++ ){// retrieve original param value and check if it's LANG_PLAYER valueif(getarg( argument_index ) == LANG_PLAYER ){
string_index = 0;
// as LANG_PLAYER == -1, check if next param string is a registered language translationwhile(( formatted_message[ string_index ] =
getarg( argument_index + 1, string_index++ ))){}
formatted_message[ string_index ] = '^0';
if( GetLangTransKey( formatted_message ) != TransKey_Bad ){// Store that argument as LANG_PLAYER so we can alter it later
ArrayPushCell( multi_lingual_indexes_array, argument_index++ );
// Update ML array, so we'll know 1st if ML is used, 2nd how many arguments we have to change
multi_lingual_constants_number++;
}}}}for( --playersCount; playersCount >= 0; --playersCount ){
player_id = players[ playersCount ];
if( multi_lingual_constants_number ){for( argument_index = 0; argument_index < multi_lingual_constants_number; argument_index++ ){// Set all LANG_PLAYER args to player index ( = player_id ), so we can format the text for that specific playersetarg( ArrayGetCell( multi_lingual_indexes_array, argument_index ), _, player_id );
}}if( g_is_color_chat_supported ){// Here all the colored messaged must to start within a color.
formatted_message[0] = '^1';
vformat( formatted_message[1], charsmax( formatted_message ) - 1, lang_formatting, 3);
if( g_coloredChatPrefix[0]){new message[ MAX_COLOR_MESSAGE ];
formatex( message, charsmax( message ), "^1%s^1%s", g_coloredChatPrefix, formatted_message[1]);
PRINT_COLORED_MESSAGE( player_id, message )}else{
PRINT_COLORED_MESSAGE( player_id, formatted_message )}}else{vformat( formatted_message, charsmax( formatted_message ), lang_formatting, 3);
REMOVE_COLOR_TAGS( formatted_message )client_print( player_id, print_chat, "%s%s", g_coloredChatPrefix, formatted_message );
}}
ArrayDestroy( multi_lingual_indexes_array );
}}
The function 'register_dictionary_colored' | go to top
This is how was tried to create a macro function to let us to just use a simple and normal function call as in the Amx Mod X 1.8.3. But looks like that the key Variadic Macros are not supported on Pawn, because every time it was used, the preprocessor does not recognize/associate the ellipsis arguments during the macro expansion:
That code assumes that every time you call the 'PRINT_COLORED_TEXT()' macro function to display a colored message to all players, you will use the 'LANG_PLAYER_COLORED' constant, instead of the default one 'LANG_PLAYER'.
These sources used to find out that is or impossible or too cumbersome to implement a macro functions to emcapsulate the color function print on the Amx Mod X 1.8.2:
#include <amxmodx>#include <amxmisc>#define COLOR_MESSAGE 192newbool:g_is_color_chat_supported
#if AMXX_VERSION_NUM < 183#define LANG_PLAYER_COLORED g_colored_players_ids[ g_colored_current_index ]/**
* Print colored text to a given player_id. You can call this function using the player_id as 0,
* to display the colored message to all players on the server. Use 'LANG_PLAYER_COLORED' instead
* of 'LANG_PLAYER' to display a message to all player on the server using the player_id as 0.
*
* Do not use semicolon ';' after call this macro, even if you have enabled the semicolon.
* Usage example for AMX Mod X 1.8.2 or superior:
* @code{.cpp}
* PRINT_COLORED_TEXT( 0, "^1Hi^4 from %L!", LANG_PLAYER_COLORED, "LANG_USER_COUNTRY" )
*
* PRINT_COLORED_TEXT( player_id, "^1Hi^4 from %L!", player_id, "LANG_USER_COUNTRY" )
* @endcode
*
* If you run this function on a Game Mod that do not support colored messages, they will be
* displayed as normal messages without any errors or bad formats.
*
* This allow you to use '!g for green', '!y for yellow', '!t for team' color with LANGs file
* using the register_dictionary_colored file. Otherwise use '^1', '^2', '^3' and '^4'.
*
* @param player_id the player id.
* @param message[] the text formatting rules to display.
* @param any the variable number of formatting parameters.
*/#define PRINT_COLORED_TEXT(%1) \{ \
print_colored_configure( %1); \
if( g_colored_player_id ) \
{ \
client_print_color_internal( %1); \
} \
else \
{ \
get_players( g_colored_players_ids, g_colored_players_number, "ch"); \
for( g_colored_current_index = 0; g_colored_current_index < g_colored_players_number; \
g_colored_current_index++ ) \
{ \
client_print_color_internal( %1); \
} \
} \
}new g_user_msgid
new g_colored_player_id
new g_colored_players_number
new g_colored_current_index
new g_colored_players_ids[32]stock print_colored_configure( player_id, any:... ){
g_colored_player_id = player_id;
}#else#define LANG_PLAYER_COLORED LANG_PLAYER#define PRINT_COLORED_TEXT(%1) client_print_color_internal( %1 );#endifstock client_print_color_internal( player_id, message[], any: ... ){new formated_message[ COLOR_MESSAGE ]vformat( formated_message, charsmax( formated_message ), message, 3)if( g_is_color_chat_supported ){#if AMXX_VERSION_NUM < 183message_begin( MSG_ONE_UNRELIABLE, g_user_msgid, _, player_id );
write_byte( player_id );
write_string( formated_message );
message_end();
#else
client_print_color( player_id, print_team_default, formated_message )#endif}else{replace_all( formated_message, charsmax( formated_message ), "^1", "");
replace_all( formated_message, charsmax( formated_message ), "^2", "");
replace_all( formated_message, charsmax( formated_message ), "^3", "");
replace_all( formated_message, charsmax( formated_message ), "^4", "");
client_print( player_id, print_chat, formated_message )}}/**
* Called just before server deactivation and subsequent unloading of the
* plugin.
*/public plugin_cfg(){
register_dictionary_colored("your_dictionary_colored.txt");
#if AMXX_VERSION_NUM < 183
g_user_msgid = get_user_msgid("SayText")#endif
PRINT_COLORED_TEXT(0, "^1Hi^4 from %L!", LANG_PLAYER_COLORED, "LANG_USER_COUNTRY")
g_is_color_chat_supported = (is_running("czero")
|| is_running("cstrike"))}/**
* ConnorMcLeod's [Dyn Native] ColorChat v0.3.2 (04 jul 2013) register_dictionary_colored function:
* <a href="https://forums.alliedmods.net/showthread.php?p=851160">ColorChat v0.3.2</a>
*
* @param filename the dictionary file name including its file extension.
*/stock register_dictionary_colored(const filename[]){if( !register_dictionary( filename )){return0;
}new szFileName[256];
get_localinfo("amxx_datadir", szFileName, charsmax( szFileName ));
format( szFileName, charsmax( szFileName ), "%s/lang/%s", szFileName, filename );
new fp = fopen( szFileName, "rt");
if( !fp ){log_amx("Failed to open %s", szFileName );
return0;
}new szBuffer[512], szLang[3], szKey[64], szTranslation[256], TransKey:iKey;
while( !feof( fp )){fgets( fp, szBuffer, charsmax( szBuffer ));
trim( szBuffer );
if( szBuffer[0] == '['){strtok( szBuffer[1], szLang, charsmax( szLang ), szBuffer, 1, ']');
}elseif( szBuffer[0]){#if AMXX_VERSION_NUM < 183strbreak( szBuffer, szKey, charsmax( szKey ), szTranslation, charsmax( szTranslation ));
#else
argbreak( szBuffer, szKey, charsmax( szKey ), szTranslation, charsmax( szTranslation ));
#endif
iKey = GetLangTransKey( szKey );
if( iKey != TransKey_Bad ){replace_all( szTranslation, charsmax( szTranslation ), "!g", "^4");
replace_all( szTranslation, charsmax( szTranslation ), "!t", "^3");
replace_all( szTranslation, charsmax( szTranslation ), "!n", "^1");
replace_all( szTranslation, charsmax( szTranslation ), "!y", "^1");
AddTranslation( szLang, iKey, szTranslation[2]);
}}}fclose( fp );
return1;
}
stock ChatPrint_SetGlobalTransTarget(nClientIndex) {
new oldFlags = pev(nClientIndex, pev_flags);
set_pev(nClientIndex, pev_flags, FL_FAKECLIENT); // Emulate bot
console_cmd(nClientIndex, ""); // When player is bot this function call only SetDefLang function
set_pev(nClientIndex, pev_flags, oldFlags); // Restore flags
}
#endif