diff --git a/globals.cpp b/globals.cpp index 774318f..6376f15 100644 --- a/globals.cpp +++ b/globals.cpp @@ -166,6 +166,26 @@ CBasePlayer* UTIL_PlayerByIndex(int playerIndex) #endif } +//--------------------------------------------------------------------------------- +// Purpose: Show on screen message to players. msg_dest are defined macros in globals.hpp. +//--------------------------------------------------------------------------------- +void UTIL_ClientPrint(CBasePlayer* player, int msg_dest, const char* msg_name, const char* param1, const char* param2, const char* param3, const char* param4) +{ + static auto _ClientPrint = reinterpret_cast(Memory::Scanner::Scan(SERVERDLL, "55 8B EC 83 EC 20 56 8B 75 08 85 F6 74 4C")); + _ClientPrint(player, msg_dest, msg_name, param1, param2, param3, param4); +} + +//--------------------------------------------------------------------------------- +// Purpose: Show on text on screen just like game_text does. +//--------------------------------------------------------------------------------- +void UTIL_HudMessage(CBasePlayer* pPlayer, const hudtextparms_s &textparms, const char* pMessage) +{ + static auto _HudMessage = reinterpret_cast(Memory::Scanner::Scan(SERVERDLL, "55 8B EC 83 EC 20 8D 4D ?? E8 ?? ?? ?? ?? 8B 45 ?? 8D 4D ?? 85 C0 74 ?? 50 E8 ?? ?? ?? ?? EB ?? E8 ?? ?? ?? ?? 56")); + _HudMessage(pPlayer, textparms, pMessage); +} + + + /// CBaseEntity Class Functions \\\ //--------------------------------------------------------------------------------- @@ -173,8 +193,7 @@ CBasePlayer* UTIL_PlayerByIndex(int playerIndex) //--------------------------------------------------------------------------------- void CBaseEntity__RemoveEntity(CBaseEntity* pEntity) { - //reinterpret_cast(pEntity) trust me bro aka, we know its CBaseEntity*, but we want the IServerEntity* so cast to that to get its methods - reinterpret_cast(Memory::Scanner::Scan(SERVERDLL, "55 8B EC 57 8B 7D 08 85 FF 74 72"))(reinterpret_cast(pEntity)->GetNetworkable()); + reinterpret_cast(Memory::Scanner::Scan(SERVERDLL, "55 8B EC 57 8B 7D 08 85 FF 74 72"))(reinterpret_cast(pEntity)->GetNetworkable()); } //--------------------------------------------------------------------------------- diff --git a/globals.hpp b/globals.hpp index 5fb95d7..01bf87c 100644 --- a/globals.hpp +++ b/globals.hpp @@ -41,11 +41,36 @@ class CPortal_Player; #define COMMAND_COMPLETION_MAXITEMS 64 #define COMMAND_COMPLETION_ITEM_LENGTH 64 -// Team number macros. -#define TEAM_SINGLEPLAYER 0 -#define TEAM_SPECTATOR 1 -#define TEAM_RED 2 -#define TEAM_BLUE 3 +// Player team enum. +enum +{ + TEAM_SINGLEPLAYER = 0, + TEAM_SPECTATOR, + TEAM_RED, + TEAM_BLUE +}; + +// ClientPrint msg_dest macros. +#define HUD_PRINTNOTIFY 1 // Works same as HUD_PRINTCONSOLE +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 + +// UTIL_HudMessage message parameters struct. Taken from utils.h. +typedef struct hudtextparms_s +{ + float x; + float y; + int effect; + byte r1, g1, b1, a1; + byte r2, g2, b2, a2; + float fadeinTime; + float fadeoutTime; + float holdTime; + float fxTime; + int channel; +} hudtextparms_t; + //--------------------------------------------------------------------------------- // Any ConVars or CON_COMMANDS that need to be globally available. @@ -79,6 +104,8 @@ namespace GFunc } CBasePlayer* UTIL_PlayerByIndex(int playerIndex); +void UTIL_ClientPrint(CBasePlayer* player, int msg_dest, const char* msg_name, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL, const char* param4 = NULL); +void UTIL_HudMessage(CBasePlayer* pPlayer, const hudtextparms_t &textparms, const char* pMessage); void CBaseEntity__RemoveEntity(CBaseEntity* pEntity); int CBaseEntity__GetTeamNumber(CBasePlayer* pPlayer); diff --git a/p2mm.cpp b/p2mm.cpp index 2fefe17..df11d73 100644 --- a/p2mm.cpp +++ b/p2mm.cpp @@ -285,6 +285,41 @@ CON_COMMAND(p2mm_respawnall, "Respawns all players.") } } +CON_COMMAND(p2mm_helloworld, "Hello World!") +{ + CBasePlayer* pPlayer = UTIL_PlayerByIndex(1); + UTIL_ClientPrint(pPlayer, HUD_PRINTCENTER, "HELLO WORLD! :D\n%s\n%s", "test1", "test2"); +} + +CON_COMMAND(p2mm_helloworld2, "Hello World 2: Electric Boogaloo!") +{ + hudtextparms_s helloWorldParams; + color32 RGB1 = { 0, 255, 100, 255 }; + color32 RGB2 = { 0, 50, 255, 255 }; + helloWorldParams.x = -1.f; + helloWorldParams.y = -1.f; + helloWorldParams.effect = 2; + helloWorldParams.r1 = RGB1.r; + helloWorldParams.g1 = RGB1.g; + helloWorldParams.b1 = RGB1.b; + helloWorldParams.a1 = RGB1.a; + helloWorldParams.r2 = RGB2.r; + helloWorldParams.g2 = RGB2.g; + helloWorldParams.b2 = RGB2.b; + helloWorldParams.a2 = RGB2.a; + helloWorldParams.fadeinTime = 0.5f; + helloWorldParams.fadeoutTime = 1.f; + helloWorldParams.holdTime = 1.f; + helloWorldParams.fxTime = 0.2f; + helloWorldParams.channel = V_atoi(args.Arg(2)); + + const char* msg = "Hello World 2: Electric Boogaloo!"; + if (!FStrEq(args.Arg(1), "")) + msg = args.Arg(1); + + UTIL_HudMessage(UTIL_PlayerByIndex(1), helloWorldParams, msg); +} + //--------------------------------------------------------------------------------- // Purpose: constructor //--------------------------------------------------------------------------------- diff --git a/vscript.cpp b/vscript.cpp index 5d5e120..e6e1556 100644 --- a/vscript.cpp +++ b/vscript.cpp @@ -110,39 +110,36 @@ static void InitializeEntity(HSCRIPT ent) } //--------------------------------------------------------------------------------- -// Purpose: Sends a raw message to the chat HUD. +// Purpose: Sends a raw message to the chat HUD. Specifying no playerIndex or 0 sends to all players. +// Supports printing localization strings but those that require formatting can't be formatted. //--------------------------------------------------------------------------------- -static void SendToChat(const char* msg, int playerIndex) +static void SendToChat(int playerIndex, const char* msg) { if (!msg) { return; } - bf_write* netmsg; - CFilter recipient_filter; - // Send to all players - if (playerIndex == 0) + if (!playerIndex) { - for (int i = 1; i < g_pGlobals->maxClients; i++) + for (int i = 1; i < MAX_PLAYERS; i++) { player_info_t playerinfo; if (engineServer->GetPlayerInfo(i, &playerinfo)) { - recipient_filter.AddPlayer(i); + UTIL_ClientPrint(UTIL_PlayerByIndex(i), HUD_PRINTTALK, msg); } } + return; } - else + + CBasePlayer* pPlayer = UTIL_PlayerByIndex(playerIndex); + if (!pPlayer) { - recipient_filter.AddPlayer(playerIndex); + P2MMLog(1, false, "Invalid player index specified for SendToChat!"); + return; } - - netmsg = engineServer->UserMessageBegin(&recipient_filter, 3, "SayText"); - netmsg->WriteByte(0); - netmsg->WriteString(msg); - netmsg->WriteByte(1); - engineServer->MessageEnd(); + UTIL_ClientPrint(pPlayer, HUD_PRINTTALK, msg); } //--------------------------------------------------------------------------------- @@ -202,6 +199,88 @@ static void CallFirstRunPrompt() g_P2MMServerPlugin.m_bSeenFirstRunPrompt = true; } +//--------------------------------------------------------------------------------- +// Purpose: Print a message to a player's console, unlike printl() which is just the host. +// Supports printing localization strings but those that require formatting can't be formatted. +//--------------------------------------------------------------------------------- +void ConsolePrint(int playerIndex, const char* msg) +{ + CBasePlayer* pPlayer = UTIL_PlayerByIndex(playerIndex); + if (!pPlayer) + { + P2MMLog(1, false, "Invalid playerIndex passed into ConsolePrint! playerIndex: \"%i\"", playerIndex); + return; + } + + std::string fixedMsg = std::string(msg) + "\n"; + UTIL_ClientPrint(pPlayer, HUD_PRINTCONSOLE, fixedMsg.c_str()); +} + +//--------------------------------------------------------------------------------- +// Purpose: Print a message to the top center position of a player's screen. +// Supports printing localization strings but those that require formatting can't be formatted. +//--------------------------------------------------------------------------------- +void ClientPrint(int playerIndex, const char* msg) +{ + CBasePlayer* pPlayer = UTIL_PlayerByIndex(playerIndex); + if (!pPlayer) + { + P2MMLog(1, false, "Invalid playerIndex passed into ClientPrint! playerIndex: \"%i\"", playerIndex); + return; + } + + UTIL_ClientPrint(pPlayer, HUD_PRINTCENTER, msg); +} + +//--------------------------------------------------------------------------------- +// Purpose: Print a message to the screen based on what the game_text entity does. +// See the Valve Developer Commentary page for the game_text entity to read +// what each field does. Vectors are in place for sets of RGB values. +// Supports printing localization strings but those that require formatting can't be formatted. +//--------------------------------------------------------------------------------- +void HudPrint(int playerIndex, const char* msg, + float x, float y, + int effect, + Vector RGB1, float alpha1, Vector RGB2, float alpha2, + float fadeinTime, float fadeoutTime, float holdTime, float fxTime, + int channel) +{ + CBasePlayer* pPlayer = UTIL_PlayerByIndex(playerIndex); + if (!pPlayer) + { + P2MMLog(1, false, "Invalid playerIndex passed into HudPrint! playerIndex: \"%i\"", playerIndex); + return; + } + + hudtextparms_t hudTextParams; + hudTextParams.x = x; + hudTextParams.y = y; + hudTextParams.effect = effect; + hudTextParams.r1 = RGB1.x; + hudTextParams.g1 = RGB1.y; + hudTextParams.b1 = RGB1.z; + hudTextParams.a1 = alpha1; + hudTextParams.r2 = RGB2.x; + hudTextParams.g2 = RGB2.y; + hudTextParams.b2 = RGB2.z; + hudTextParams.a2 = alpha2; + hudTextParams.fadeinTime = fadeinTime; + hudTextParams.fadeoutTime = fadeoutTime; + hudTextParams.holdTime = holdTime; + hudTextParams.fxTime = fxTime; + hudTextParams.channel = channel; + + UTIL_HudMessage(pPlayer, hudTextParams, msg); +} + +//--------------------------------------------------------------------------------- +// Purpose: Self-explanatory. +//--------------------------------------------------------------------------------- +int GetMaxPlayers() +{ + return MAX_PLAYERS; +} + void RegisterFuncsAndRun() { g_pScriptVM = **Memory::Scanner::Scan(SERVERDLL, "8B 1D ?? ?? ?? ?? 57 85 DB", 2); @@ -221,7 +300,7 @@ void RegisterFuncsAndRun() ScriptRegisterFunction (g_pScriptVM, SetMaxPortalSeparationConvar, "Sets 'portal_max_separation_force' to the supplied integer value."); ScriptRegisterFunction (g_pScriptVM, IsDedicatedServer, "Returns true if this is a dedicated server."); ScriptRegisterFunction (g_pScriptVM, InitializeEntity, "Initializes an entity. Note: Not all entities will work even after being initialized with this function."); - ScriptRegisterFunction (g_pScriptVM, SendToChat, "Sends a raw message to the chat HUD."); + ScriptRegisterFunction (g_pScriptVM, SendToChat, "Sends a raw message to the chat HUD. Specifying no playerIndex or 0 sends to all players. Supports printing localization strings but those that require formatting can't be formatted."); ScriptRegisterFunctionNamed(g_pScriptVM, GFunc::GetGameMainDir, "GetGameMainDir", "Returns the game directory. Ex. portal2"); ScriptRegisterFunctionNamed(g_pScriptVM, GFunc::GetGameBaseDir, "GetGameBaseDir", "Get the main game directory being used. Ex. Portal 2"); ScriptRegisterFunction (g_pScriptVM, GetLastMap, "Returns the last map recorded by the launcher's Last Map system."); @@ -229,9 +308,17 @@ void RegisterFuncsAndRun() ScriptRegisterFunction (g_pScriptVM, CallFirstRunPrompt, "Shows the first run prompt if enabled in config.nut."); ScriptRegisterFunctionNamed(g_pScriptVM, GFunc::GetConVarInt, "GetConVarInt", "Get the integer value of a ConVar."); ScriptRegisterFunctionNamed(g_pScriptVM, GFunc::GetConVarString, "GetConVarString", "Get the string value of a ConVar."); - ScriptRegisterFunctionNamed(g_pScriptVM, INDEXHANDLE, "PlayerIndexToPlayerHandle", "Takes the player's entity index and returns the player's script handle."); + ScriptRegisterFunctionNamed(g_pScriptVM, INDEXHANDLE, "UTIL_PlayerByIndex", "Takes the player's entity index and returns the player's script handle."); ScriptRegisterFunctionNamed(g_pScriptVM, CPortal_Player__RespawnPlayer, "RespawnPlayer", "Respawn the a player by their entity index."); ScriptRegisterFunctionNamed(g_pScriptVM, CPortal_Player__SetFlashlightState, "SetFlashlightState", "Set the flashlight for a player on or off."); + ScriptRegisterFunction (g_pScriptVM, ConsolePrint, "Print a message to the top center position of a player's screen. Supports printing localization strings but those that require formatting can't be formatted."); + ScriptRegisterFunction (g_pScriptVM, ClientPrint, "Print a message to the top center position of a player's screen. Supports printing localization strings but those that require formatting can't be formatted."); + ScriptRegisterFunction (g_pScriptVM, HudPrint, "Print a message to the screen based on what the game_text entity does.\ + See the Valve Developer Commentary page for the game_text entity to read\ + what each field does. Vectors are in place for sets of RGB values.\ + Supports printing localization strings but those that require formatting can't be formatted." + ); + ScriptRegisterFunction (g_pScriptVM, GetMaxPlayers, "Self-explanatory."); // Load up the main P2:MM VScript and set g_pScriptVM->Run("IncludeScript(\"multiplayermod/p2mm\");");