dvander@1915: /** dvander@1915: * vim: set ts=4 : dvander@1915: * ============================================================================= dvander@1915: * SourceMod dvander@1915: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. dvander@1915: * ============================================================================= dvander@1915: * dvander@1915: * This program is free software; you can redistribute it and/or modify it under dvander@1915: * the terms of the GNU General Public License, version 3.0, as published by the dvander@1915: * Free Software Foundation. dvander@1915: * dvander@1915: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@1915: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@1915: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@1915: * details. dvander@1915: * dvander@1915: * You should have received a copy of the GNU General Public License along with dvander@1915: * this program. If not, see . dvander@1915: * dvander@1915: * As a special exception, AlliedModders LLC gives you permission to link the dvander@1915: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@1915: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@1915: * by the Valve Corporation. You must obey the GNU General Public License in dvander@1915: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@1915: * this exception to all derivative works. AlliedModders LLC defines further dvander@1915: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@1915: * or . dvander@1915: * dvander@1915: * Version: $Id$ dvander@1915: */ dvander@1915: dvander@1915: #include "sm_globals.h" dvander@1915: #include "GameConfigs.h" dvander@1915: #include "UserMessages.h" dvander@1915: #include "TimerSys.h" dvander@1915: #include "PlayerManager.h" dvander@1915: #include "HandleSys.h" dvander@1915: dvander@1915: #define MAX_HUD_CHANNELS 6 dvander@1915: dvander@1915: int g_HudMsgNum = -1; dvander@1915: dvander@1915: struct hud_syncobj_t dvander@1915: { dvander@1915: int *player_channels; dvander@1915: }; dvander@1915: dvander@1915: struct player_chaninfo_t dvander@1915: { dvander@1915: double chan_times[MAX_HUD_CHANNELS]; dvander@1915: hud_syncobj_t *chan_syncobjs[MAX_HUD_CHANNELS]; dvander@1915: }; dvander@1915: dvander@1915: struct hud_text_parms dvander@1915: { dvander@1915: float x; dvander@1915: float y; dvander@1915: int effect; dvander@1915: byte r1, g1, b1, a1; dvander@1915: byte r2, g2, b2, a2; dvander@1915: float fadeinTime; dvander@1915: float fadeoutTime; dvander@1915: float holdTime; dvander@1915: float fxTime; dvander@1915: int channel; dvander@1915: }; dvander@1915: dvander@1915: class HudMsgHelpers : dvander@1915: public SMGlobalClass, dvander@1915: public IHandleTypeDispatch, dvander@1915: public IClientListener dvander@1915: { dvander@1915: public: dvander@1915: bool IsSupported() dvander@1915: { dvander@1915: return (g_HudMsgNum != -1); dvander@1915: } dvander@1915: dvander@1915: virtual void OnSourceModAllInitialized_Post() dvander@1915: { dvander@1915: const char *key; dvander@1915: dvander@1915: key = g_pGameConf->GetKeyValue("HudTextMsg"); dvander@1915: if (key != NULL) dvander@1915: { dvander@1915: g_HudMsgNum = g_UserMsgs.GetMessageIndex(key); dvander@1915: } dvander@1915: dvander@1915: if (!IsSupported()) dvander@1915: { dvander@1915: m_hHudSyncObj = 0; dvander@1915: m_PlayerHuds = NULL; dvander@1915: return; dvander@1915: } dvander@1915: dvander@1915: m_PlayerHuds = new player_chaninfo_t[256+1]; dvander@1915: m_hHudSyncObj = g_HandleSys.CreateType("HudSyncObj", this, 0, NULL, NULL, g_pCoreIdent, NULL); dvander@1915: dvander@1915: g_Players.AddClientListener(this); dvander@1915: } dvander@1915: dvander@1915: virtual void OnSourceModShutdown() dvander@1915: { dvander@1915: if (!IsSupported()) dvander@1915: { dvander@1915: return; dvander@1915: } dvander@1915: dvander@1915: delete [] m_PlayerHuds; dvander@1915: g_HandleSys.RemoveType(m_hHudSyncObj, g_pCoreIdent); dvander@1915: dvander@1915: g_Players.RemoveClientListener(this); dvander@1915: } dvander@1915: dvander@1915: virtual void OnHandleDestroy(HandleType_t type, void *object) dvander@1915: { dvander@1915: hud_syncobj_t *obj = (hud_syncobj_t *)object; dvander@1915: dvander@1915: delete [] obj->player_channels; dvander@1915: delete obj; dvander@1915: } dvander@1915: dvander@1915: virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) dvander@1915: { dvander@1915: *pSize = sizeof(unsigned int) * g_Players.GetMaxClients(); dvander@1915: return true; dvander@1915: } dvander@1915: dvander@1915: virtual void OnClientConnected(int client) dvander@1915: { dvander@1915: player_chaninfo_t *player; dvander@1915: dvander@1915: player = &m_PlayerHuds[client]; dvander@1915: memset(player->chan_syncobjs, 0, sizeof(player->chan_syncobjs)); dvander@1915: memset(player->chan_times, 0, sizeof(player->chan_times)); dvander@1915: } dvander@1915: dvander@1915: Handle_t CreateHudSyncObj(IdentityToken_t *pIdent) dvander@1915: { dvander@1915: Handle_t hndl; dvander@1915: int max_clients; dvander@1915: HandleError err; dvander@1915: hud_syncobj_t *obj; dvander@1915: HandleSecurity sec; dvander@1915: dvander@1915: if ((max_clients = g_Players.MaxClients()) == 0) dvander@1915: { dvander@1915: max_clients = 256+1; dvander@1915: } dvander@1915: dvander@1915: obj = new hud_syncobj_t; dvander@1915: obj->player_channels = new int[max_clients]; dvander@1915: dvander@1915: memset(obj->player_channels, 0, sizeof(int) * max_clients); dvander@1915: dvander@1915: sec = HandleSecurity(pIdent, g_pCoreIdent); dvander@1915: dvander@1915: if ((hndl = g_HandleSys.CreateHandleEx(m_hHudSyncObj, obj, &sec, NULL, &err)) dvander@1915: == BAD_HANDLE) dvander@1915: { dvander@1915: delete [] obj->player_channels; dvander@1915: delete obj; dvander@1915: } dvander@1915: dvander@1915: return hndl; dvander@1915: } dvander@1915: dvander@1915: HandleError ReadHudSyncObj(Handle_t hndl, dvander@1915: IdentityToken_t *pOwner, dvander@1915: hud_syncobj_t **pObj) dvander@1915: { dvander@1915: HandleSecurity sec(pOwner, g_pCoreIdent); dvander@1915: return g_HandleSys.ReadHandle(hndl, m_hHudSyncObj, &sec, (void **)pObj); dvander@1915: } dvander@1915: dvander@1915: unsigned int AutoSelectChannel(unsigned int client) dvander@1915: { dvander@1915: int last_channel; dvander@1915: player_chaninfo_t *player; dvander@1915: dvander@1915: player = &m_PlayerHuds[client]; dvander@1915: dvander@1915: last_channel = 0; dvander@1915: for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++) dvander@1915: { dvander@1915: if (player->chan_times[i] < player->chan_times[last_channel]) dvander@1915: { dvander@1915: last_channel = i; dvander@1915: } dvander@1915: } dvander@1915: dvander@1915: ManualSelectChannel(client, last_channel); dvander@1915: dvander@1915: return last_channel; dvander@1915: } dvander@1915: dvander@1915: int TryReuseLastChannel(unsigned int client, hud_syncobj_t *obj) dvander@1915: { dvander@1915: int last_channel; dvander@1915: player_chaninfo_t *player; dvander@1915: dvander@1915: player = &m_PlayerHuds[client]; dvander@1915: dvander@1915: /* First, see if we can re-use the previous channel. */ dvander@1915: last_channel = obj->player_channels[client]; dvander@1915: dvander@1915: if (player->chan_syncobjs[last_channel] == obj) dvander@1915: { dvander@1915: player->chan_times[last_channel] = *g_pUniversalTime; dvander@1915: return last_channel; dvander@1915: } dvander@1915: dvander@1915: return -1; dvander@1915: } dvander@1915: dvander@1915: int AutoSelectChannel(unsigned int client, hud_syncobj_t *obj) dvander@1915: { dvander@1915: int last_channel; dvander@1915: player_chaninfo_t *player; dvander@1915: dvander@1915: player = &m_PlayerHuds[client]; dvander@1915: dvander@1915: /* First, see if we can re-use the previous channel. */ dvander@1915: last_channel = obj->player_channels[client]; dvander@1915: dvander@1915: if (player->chan_syncobjs[last_channel] == obj) dvander@1915: { dvander@1915: player->chan_times[last_channel] = *g_pUniversalTime; dvander@1915: return last_channel; dvander@1915: } dvander@1915: dvander@1915: last_channel = 0; dvander@1915: for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++) dvander@1915: { dvander@1915: if (player->chan_times[i] < player->chan_times[last_channel]) dvander@1915: { dvander@1915: last_channel = i; dvander@1915: } dvander@1915: } dvander@1915: dvander@1915: obj->player_channels[client] = last_channel; dvander@1915: player->chan_syncobjs[last_channel] = obj; dvander@1915: player->chan_times[last_channel] = *g_pUniversalTime; dvander@1915: dvander@1915: return last_channel; dvander@1915: } dvander@1915: dvander@1915: int ManualSelectChannel(unsigned int client, int channel) dvander@1915: { dvander@1915: player_chaninfo_t *player; dvander@1915: dvander@1915: player = &m_PlayerHuds[client]; dvander@1915: player->chan_times[channel] = *g_pUniversalTime; dvander@1915: player->chan_syncobjs[channel] = NULL; dvander@1915: dvander@1915: return channel; dvander@1915: } dvander@1915: private: dvander@1915: HandleType_t m_hHudSyncObj; dvander@1915: player_chaninfo_t *m_PlayerHuds; dvander@1915: } s_HudMsgHelpers; dvander@1915: dvander@1915: hud_text_parms g_hud_params; dvander@1915: dvander@1915: static cell_t CreateHudSynchronizer(IPluginContext *pContext, const cell_t *params) dvander@1915: { dvander@1915: return s_HudMsgHelpers.CreateHudSyncObj(pContext->GetIdentity()); dvander@1915: } dvander@1915: dvander@1915: static cell_t SetHudTextParams(IPluginContext *pContext, const cell_t *params) dvander@1915: { dvander@1915: g_hud_params.x = sp_ctof(params[1]); dvander@1915: g_hud_params.y = sp_ctof(params[2]); dvander@1915: g_hud_params.holdTime = sp_ctof(params[3]); dvander@1915: g_hud_params.r1 = static_cast(params[4]); dvander@1915: g_hud_params.g1 = static_cast(params[5]); dvander@1915: g_hud_params.b1 = static_cast(params[6]); dvander@1915: g_hud_params.a1 = static_cast(params[7]); dvander@1915: g_hud_params.effect = params[8]; dvander@1915: g_hud_params.fxTime = sp_ctof(params[9]); dvander@1915: g_hud_params.fadeinTime = sp_ctof(params[10]); dvander@1915: g_hud_params.fadeoutTime = sp_ctof(params[11]); dvander@1915: g_hud_params.r2 = 255; dvander@1915: g_hud_params.g2 = 255; dvander@1915: g_hud_params.b2 = 250; dvander@1915: g_hud_params.a2 = 0; dvander@1915: dvander@1915: return 1; dvander@1915: } dvander@1915: dvander@1915: static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params) dvander@1915: { dvander@1915: cell_t *color1, *color2; dvander@1915: dvander@1915: pContext->LocalToPhysAddr(params[4], &color1); dvander@1915: pContext->LocalToPhysAddr(params[5], &color2); dvander@1915: dvander@1915: g_hud_params.x = sp_ctof(params[1]); dvander@1915: g_hud_params.y = sp_ctof(params[2]); dvander@1915: g_hud_params.holdTime = sp_ctof(params[3]); dvander@1915: g_hud_params.r1 = static_cast(color1[0]); dvander@1915: g_hud_params.g1 = static_cast(color1[1]); dvander@1915: g_hud_params.b1 = static_cast(color1[2]); dvander@1915: g_hud_params.a1 = static_cast(color1[3]); dvander@1915: g_hud_params.effect = params[6]; dvander@1915: g_hud_params.fxTime = sp_ctof(params[7]); dvander@1915: g_hud_params.fadeinTime = sp_ctof(params[8]); dvander@1915: g_hud_params.fadeoutTime = sp_ctof(params[9]); dvander@1915: g_hud_params.r2 = static_cast(color2[0]); dvander@1915: g_hud_params.g2 = static_cast(color2[1]); dvander@1915: g_hud_params.b2 = static_cast(color2[2]); dvander@1915: g_hud_params.a2 = static_cast(color2[3]); dvander@1915: dvander@1915: return 1; dvander@1915: } dvander@1915: dvander@1915: void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *pMessage) dvander@1915: { dvander@1915: bf_write *bf; dvander@1915: cell_t players[1]; dvander@1915: dvander@1915: players[0] = client; dvander@1915: dvander@1915: bf = g_UserMsgs.StartMessage(g_HudMsgNum, players, 1, 0); dvander@1915: bf->WriteByte(textparms.channel & 0xFF ); dvander@1915: bf->WriteFloat(textparms.x); dvander@1915: bf->WriteFloat(textparms.y); dvander@1915: bf->WriteByte(textparms.r1); dvander@1915: bf->WriteByte(textparms.g1); dvander@1915: bf->WriteByte(textparms.b1); dvander@1915: bf->WriteByte(textparms.a1); dvander@1915: bf->WriteByte(textparms.r2); dvander@1915: bf->WriteByte(textparms.g2); dvander@1915: bf->WriteByte(textparms.b2); dvander@1915: bf->WriteByte(textparms.a2); dvander@1915: bf->WriteByte(textparms.effect); dvander@1915: bf->WriteFloat(textparms.fadeinTime); dvander@1915: bf->WriteFloat(textparms.fadeoutTime); dvander@1915: bf->WriteFloat(textparms.holdTime); dvander@1915: bf->WriteFloat(textparms.fxTime); dvander@1915: bf->WriteString(pMessage); dvander@1915: g_UserMsgs.EndMessage(); dvander@1915: } dvander@1915: dvander@1915: static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params) dvander@1915: { dvander@1915: int client; dvander@1915: Handle_t err; dvander@1915: CPlayer *pPlayer; dvander@1915: hud_syncobj_t *obj; dvander@1915: char message_buffer[255-36]; dvander@1915: dvander@1915: if (!s_HudMsgHelpers.IsSupported()) dvander@1915: { dvander@1915: return -1; dvander@1915: } dvander@1915: dvander@1915: if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err); dvander@1915: } dvander@1915: dvander@1915: client = params[1]; dvander@1915: if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Invalid client index %d", client); dvander@1915: } dvander@1915: else if (!pPlayer->IsInGame()) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Client %d is not in-game", client); dvander@1915: } dvander@1915: dvander@1915: g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3); dvander@1915: if (pContext->GetContext()->n_err != SP_ERROR_NONE) dvander@1915: { dvander@1915: return 0; dvander@1915: } dvander@1915: dvander@1915: g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client, obj); dvander@1915: UTIL_SendHudText(client, g_hud_params, message_buffer); dvander@1915: dvander@1915: return 1; dvander@1915: } dvander@1915: dvander@1915: static cell_t ClearSyncHud(IPluginContext *pContext, const cell_t *params) dvander@1915: { dvander@1915: int client; dvander@1915: int channel; dvander@1915: Handle_t err; dvander@1915: CPlayer *pPlayer; dvander@1915: hud_syncobj_t *obj; dvander@1915: dvander@1915: if (!s_HudMsgHelpers.IsSupported()) dvander@1915: { dvander@1915: return -1; dvander@1915: } dvander@1915: dvander@1915: if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err); dvander@1915: } dvander@1915: dvander@1915: client = params[1]; dvander@1915: if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Invalid client index %d", client); dvander@1915: } dvander@1915: else if (!pPlayer->IsInGame()) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Client %d is not in-game", client); dvander@1915: } dvander@1915: dvander@1915: if ((channel = s_HudMsgHelpers.TryReuseLastChannel(client, obj)) == -1) dvander@1915: { dvander@1915: return -1; dvander@1915: } dvander@1915: dvander@1915: g_hud_params.channel = channel; dvander@1915: UTIL_SendHudText(client, g_hud_params, ""); dvander@1915: dvander@1915: return g_hud_params.channel; dvander@1915: } dvander@1915: dvander@1915: static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params) dvander@1915: { dvander@1915: int client; dvander@1915: CPlayer *pPlayer; dvander@1915: char message_buffer[255-36]; dvander@1915: dvander@1915: if (!s_HudMsgHelpers.IsSupported()) dvander@1915: { dvander@1915: return -1; dvander@1915: } dvander@1915: dvander@1915: client = params[1]; dvander@1915: if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Invalid client index %d", client); dvander@1915: } dvander@1915: else if (!pPlayer->IsInGame()) dvander@1915: { dvander@1915: return pContext->ThrowNativeError("Client %d is not in-game", client); dvander@1915: } dvander@1915: dvander@1915: g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3); dvander@1915: if (pContext->GetContext()->n_err != SP_ERROR_NONE) dvander@1915: { dvander@1915: return 0; dvander@1915: } dvander@1915: dvander@1915: if (params[2] == -1) dvander@1915: { dvander@1915: g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client); dvander@1915: } dvander@1915: else dvander@1915: { dvander@1915: g_hud_params.channel = params[2] % MAX_HUD_CHANNELS; dvander@1915: s_HudMsgHelpers.ManualSelectChannel(client, g_hud_params.channel); dvander@1915: } dvander@1915: dvander@1915: UTIL_SendHudText(client, g_hud_params, message_buffer); dvander@1915: dvander@1915: return g_hud_params.channel; dvander@1915: } dvander@1915: dvander@1915: REGISTER_NATIVES(hudNatives) dvander@1915: { dvander@1915: {"ClearSyncHud", ClearSyncHud}, dvander@1915: {"CreateHudSynchronizer", CreateHudSynchronizer}, dvander@1915: {"SetHudTextParams", SetHudTextParams}, dvander@1915: {"SetHudTextParamsEx", SetHudTextParamsEx}, dvander@1915: {"ShowHudText", ShowHudText}, dvander@1915: {"ShowSyncHudText", ShowSyncHudText}, dvander@1915: {NULL, NULL}, dvander@1915: };