dvander@1915: /**
dvander@1915: * vim: set ts=4 :
dvander@1915: * =============================================================================
dvander@1915: * SourceMod
ds@1947: * Copyright (C) 2004-2008 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@3010: #include
dvander@1915: #include "UserMessages.h"
dvander@1915: #include "TimerSys.h"
dvander@1915: #include "PlayerManager.h"
dvander@1915: #include "HandleSys.h"
dvander@3010: #include "logic_bridge.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@2816: int player_channels[256 + 1];
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;
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: HandleError err;
dvander@1915: hud_syncobj_t *obj;
dvander@1915: HandleSecurity sec;
dvander@1915:
dvander@2816: obj = new hud_syncobj_t;
dvander@1915:
dvander@2816: memset(obj->player_channels, 0, sizeof(obj->player_channels));
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;
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@2175: if (pContext->GetLastNativeError() != 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@2175: if (pContext->GetLastNativeError() != 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: };