From 9e37c60bc543676cbd659621a129bd953fc71473 Mon Sep 17 00:00:00 2001 From: Vincent Herbet Date: Sat, 24 Aug 2013 01:03:13 +0200 Subject: [PATCH] Add client_print_color native (CS only) (bug 5823, r=Nextra) --- amxmodx/CLang.cpp | 42 +++++++++++++++++++++++ amxmodx/CMisc.cpp | 2 ++ amxmodx/CMisc.h | 3 +- amxmodx/amxmodx.cpp | 65 ++++++++++++++++++++++++++++++++++++ amxmodx/amxmodx.h | 13 ++++++++ amxmodx/emsg.cpp | 22 ++++++++++++ amxmodx/meta_api.cpp | 2 ++ amxmodx/util.cpp | 26 +++++++++++++++ plugins/include/amxconst.inc | 8 +++++ plugins/include/amxmodx.inc | 27 +++++++++++++++ 10 files changed, 209 insertions(+), 1 deletion(-) diff --git a/amxmodx/CLang.cpp b/amxmodx/CLang.cpp index da9b4710..83cf30c3 100755 --- a/amxmodx/CLang.cpp +++ b/amxmodx/CLang.cpp @@ -316,6 +316,46 @@ void CLangMngr::MergeDefinitions(const char *lang, CQueue &tmpVec) language->MergeDefinitions(tmpVec); } +void reparse_color(String* def) +{ + size_t len = def->size(); + int offs = 0; + int c; + + if (!len) + return; + + for (size_t i = 0; i < len; i++) + { + c = def->at(i); + if (c == '^' && (i != len-1)) + { + c = def->at(++i); + if (c >= '1' && c <= '4') + { + switch(c) + { + case '1' : c = '\x01'; break; + case '2' : c = '\x02'; break; + case '3' : c = '\x03'; break; + case '4' : c = '\x04'; break; + } + + if (!g_bmod_cstrike) // remove completely these two characters if not under CS + { + offs += 2; + continue; + } + + offs++; + } + } + def->at(i-offs, c); + } + + def->at(len-offs, '\0'); +} + //this is the file parser for dictionary text files // -- BAILOPAN int CLangMngr::MergeDefinitionFile(const char *file) @@ -438,6 +478,7 @@ int CLangMngr::MergeDefinitionFile(const char *file) tmpEntry.definition = new String; tmpEntry.definition->assign(def.c_str()); tmpEntry.definition->trim(); + reparse_color(tmpEntry.definition); tmpEntry.definition->reparse_newlines(); Defq.push(tmpEntry); tmpEntry.key = -1; @@ -465,6 +506,7 @@ int CLangMngr::MergeDefinitionFile(const char *file) } else { if (buf[0] == ':') { + reparse_color(tmpEntry.definition); tmpEntry.definition->reparse_newlines(); Defq.push(tmpEntry); tmpEntry.key = -1; diff --git a/amxmodx/CMisc.cpp b/amxmodx/CMisc.cpp index b5a1021d..3cf9957f 100755 --- a/amxmodx/CMisc.cpp +++ b/amxmodx/CMisc.cpp @@ -41,6 +41,7 @@ void CPlayer::Init(edict_t* e, int i) initialized = false; ingame = false; authorized = false; + teamIdsInitialized = false; current = 0; teamId = -1; @@ -62,6 +63,7 @@ void CPlayer::Disconnect() ingame = false; initialized = false; authorized = false; + teamIdsInitialized = false; if (newmenu != -1) { diff --git a/amxmodx/CMisc.h b/amxmodx/CMisc.h index 807e55d5..8e20d1f1 100755 --- a/amxmodx/CMisc.h +++ b/amxmodx/CMisc.h @@ -85,7 +85,8 @@ public: bool initialized; bool ingame; bool authorized; - bool vgui; + bool vgui; + bool teamIdsInitialized; float time; float playtime; diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 0b9fdbae..ab5617d0 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -338,6 +338,70 @@ static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */ return len; } +static cell AMX_NATIVE_CALL client_print_color(AMX *amx, cell *params) /* 3 param */ +{ + if (!g_bmod_cstrike) + { + params[2] = print_chat; + return client_print(amx, params); + } + + int len = 0; + char *msg; + int index = params[1]; + int sender = params[2]; + + if (sender < print_team_blue || sender > gpGlobals->maxClients) + { + sender = print_team_default; + } + else if (sender < print_team_default) + { + sender = abs(sender) + 32; // align indexes to the TeamInfo ones. + } + + if (!index) + { + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + CPlayer *pPlayer = GET_PLAYER_POINTER_I(i); + + if (pPlayer->ingame && !pPlayer->IsBot()) + { + g_langMngr.SetDefLang(i); + msg = format_amxstring(amx, params, 3, len); + msg[len++] = '\n'; + msg[len] = 0; + + UTIL_ClientSayText(pPlayer->pEdict, sender ? sender : i, msg); + } + } + } + else + { + if (index < 1 || index > gpGlobals->maxClients) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index); + return 0; + } + + CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); + + if (pPlayer->ingame && !pPlayer->IsBot()) + { + g_langMngr.SetDefLang(index); + + msg = format_amxstring(amx, params, 3, len); + msg[len++] = '\n'; + msg[len] = 0; + + UTIL_ClientSayText(pPlayer->pEdict, sender ? sender : index, msg); + } + } + + return len; +} + static cell AMX_NATIVE_CALL show_motd(AMX *amx, cell *params) /* 3 param */ { int ilen; @@ -4715,6 +4779,7 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"change_task", change_task}, {"client_cmd", client_cmd}, {"client_print", client_print}, + {"client_print_color", client_print_color}, {"console_cmd", console_cmd}, {"console_print", console_print}, {"cvar_exists", cvar_exists}, diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index c7310b4a..a8f834d8 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -143,6 +143,8 @@ void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const ch void UTIL_IntToString(int value, char *output); void UTIL_ShowMOTD(edict_t *client, char *motd, int mlen, const char *name); void UTIL_ShowMenu(edict_t* pEntity, int slots, int time, char *menu, int mlen); +void UTIL_ClientSayText(edict_t *pEntity, int sender, char *msg); +void UTIL_TeamInfo(edict_t *pEntity, int playerIndex, char *pszTeamName); char *UTIL_VarArgs(const char *fmt, ...); @@ -235,6 +237,8 @@ extern int gmsgWeaponList; extern int gmsgintermission; extern int gmsgResetHUD; extern int gmsgRoundTime; +extern int gmsgSayText; +extern int gmsgInitHUD; void Client_AmmoPickup(void*); void Client_AmmoX(void*); @@ -247,6 +251,7 @@ void Client_VGUIMenu(void*); void Client_WeaponList(void*); void Client_DamageEnd(void*); void Client_DeathMsg(void*); +void Client_InitHUDEnd(void*); void amx_command(); void plugin_srvcmd(); @@ -353,6 +358,14 @@ enum AdminProperty Admin_Flags }; +enum PrintColor +{ + print_team_default = 0, + print_team_grey =-1, + print_team_red = -2, + print_team_blue = -3, +}; + extern enginefuncs_t *g_pEngTable; #endif // AMXMODX_H diff --git a/amxmodx/emsg.cpp b/amxmodx/emsg.cpp index 1e43fd4c..0c0e47a0 100755 --- a/amxmodx/emsg.cpp +++ b/amxmodx/emsg.cpp @@ -52,6 +52,8 @@ int gmsgWeaponList; int gmsgintermission; int gmsgResetHUD; int gmsgRoundTime; +int gmsgSayText; +int gmsgInitHUD; TeamIds g_teamsIds; WeaponsVault g_weaponsData[MAX_WEAPONS]; @@ -328,6 +330,26 @@ void Client_DeathMsg(void* mValue) victim->death_tk = (killer->teamId == victim->teamId); } } + +void Client_InitHUDEnd(void* mValue) +{ + if (!g_bmod_cstrike) + return; + + CPlayer *pPlayer = mPlayer; + + if (!pPlayer->teamIdsInitialized && !pPlayer->IsBot()) + { + // This creates specific indexes (> maxplayers) for print_chat_color(). + // 33 : print_team_grey / spectator + // 34 : print_team_red / terrorist + // 35 : print_team_blue / ct + UTIL_TeamInfo(pPlayer->pEdict, 33 + 1, "TERRORIST"); // print_team_red + UTIL_TeamInfo(pPlayer->pEdict, 33 + 2, "CT"); // print_team_blue + pPlayer->teamIdsInitialized = true; + } +} + /* void Client_SendAudio(void* mValue) { diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 4e0acd18..e67ed0d7 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -564,6 +564,8 @@ struct sUserMsg {"WeapPickup", &gmsgWeapPickup, 0, false, false}, {"ResetHUD", &gmsgResetHUD, 0, false, false}, {"RoundTime", &gmsgRoundTime, 0, false, false}, + {"SayText", &gmsgSayText, 0, false, false}, + {"InitHUD", &gmsgInitHUD, Client_InitHUDEnd, true, false}, {0, 0, 0, false, false} }; diff --git a/amxmodx/util.cpp b/amxmodx/util.cpp index fcc30bcc..438ebf8b 100755 --- a/amxmodx/util.cpp +++ b/amxmodx/util.cpp @@ -294,6 +294,32 @@ void UTIL_ClientPrint(edict_t *pEntity, int msg_dest, char *msg) msg[190] = c; } +void UTIL_ClientSayText(edict_t *pEntity, int sender, char *msg) +{ + if (!gmsgSayText) + return; // :TODO: Maybe output a warning log? + + char c = msg[190]; + msg[190] = 0; // truncate without checking with strlen() + + MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pEntity); + WRITE_BYTE(sender); + WRITE_STRING(msg); + MESSAGE_END(); + msg[190] = c; +} + +void UTIL_TeamInfo(edict_t *pEntity, int playerIndex, char *pszTeamName) +{ + if (!gmsgTeamInfo) + return; + + MESSAGE_BEGIN(MSG_ONE, gmsgTeamInfo, NULL, pEntity); + WRITE_BYTE(playerIndex); + WRITE_STRING(pszTeamName); + MESSAGE_END(); +} + // UTIL_FakeClientCommand // PURPOSE: Sends a fake client command to GameDLL // HOW DOES IT WORK: diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index 6aa150c9..05f06ff6 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -175,6 +175,14 @@ enum { print_center, }; +/* Color types for client_print_color() */ +enum { + print_team_default = 0, + print_team_grey = -1, + print_team_red = -2, + print_team_blue = -3, +}; + /* Destination types for engclient_print() */ enum { engprint_console = 0, diff --git a/plugins/include/amxmodx.inc b/plugins/include/amxmodx.inc index 358cb518..99e666ae 100755 --- a/plugins/include/amxmodx.inc +++ b/plugins/include/amxmodx.inc @@ -102,6 +102,33 @@ native show_motd(player,const message[],const header[]=""); /* Sends message to player. Set index to 0 to send text globaly. */ native client_print(index,type,const message[],any:...); +/** + * Sends colored message to player. Set index to 0 to send text globally. + * This works only under Counter-Strike 1.6 and Counter-Strike: Condition Zero. + * + * The available colors identifiers are : + * green ^4 ; use location color from this point forward + * red/blue/grey ^3 ; use team color from this point forward + * red/blue/grey ^2 ; use team color up to the end of the player name. This only works at the start of the string, and precludes using the other control characters. + * normal ^1 ; use normal color from this point forward + * + * The team color is defined either with a sender's index, or a specific team color using print_team_* constants (print_team_blue, print_team_red, print_team_grey). + * A message must start with a default color. + * + * An example would be: client_print_color(id, print_team_red, "^4This is green ^3this is red, ^1this is your default chat text color"); + * Another with index : client_print_color(id, idOther, "^4This is green ^3this idOther's team color, ^1this is your default chat text color"); + * In multilingual file : KEY = ^1This is normal color, ^4this is green, ^1normal again ^3and now team color. + * + * @param index This is the player index (1 to maxplayer) you want to send the message, use 0 to send to all players. + * @param sender This is the player index you want to use the team color, see print_team_* constants if you want to force a color. + * @param fmt Format string in which patterns gonna be replaced with argument list. + * + * @return 1 if the message has been sent, + * 0 if the index specified is a not connected player, + * or if a global message has not been sent because there are no humans players. + */ +native client_print_color(index, sender, const message[], any:...); + /* Sends message to player by engine. Set index to 0 to send text globaly. */ native engclient_print(player,type,const message[],any:...);