3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "sm_globals.h"
33 #include "GameConfigs.h"
34 #include "UserMessages.h"
36 #include "PlayerManager.h"
37 #include "HandleSys.h"
39 #define MAX_HUD_CHANNELS 6
48 struct player_chaninfo_t
50 double chan_times[MAX_HUD_CHANNELS];
51 hud_syncobj_t *chan_syncobjs[MAX_HUD_CHANNELS];
70 public IHandleTypeDispatch,
71 public IClientListener
76 return (g_HudMsgNum != -1);
79 virtual void OnSourceModAllInitialized_Post()
83 key = g_pGameConf->GetKeyValue("HudTextMsg");
86 g_HudMsgNum = g_UserMsgs.GetMessageIndex(key);
96 m_PlayerHuds = new player_chaninfo_t[256+1];
97 m_hHudSyncObj = g_HandleSys.CreateType("HudSyncObj", this, 0, NULL, NULL, g_pCoreIdent, NULL);
99 g_Players.AddClientListener(this);
102 virtual void OnSourceModShutdown()
109 delete [] m_PlayerHuds;
110 g_HandleSys.RemoveType(m_hHudSyncObj, g_pCoreIdent);
112 g_Players.RemoveClientListener(this);
115 virtual void OnHandleDestroy(HandleType_t type, void *object)
117 hud_syncobj_t *obj = (hud_syncobj_t *)object;
119 delete [] obj->player_channels;
123 virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
125 *pSize = sizeof(unsigned int) * g_Players.GetMaxClients();
129 virtual void OnClientConnected(int client)
131 player_chaninfo_t *player;
133 player = &m_PlayerHuds[client];
134 memset(player->chan_syncobjs, 0, sizeof(player->chan_syncobjs));
135 memset(player->chan_times, 0, sizeof(player->chan_times));
138 Handle_t CreateHudSyncObj(IdentityToken_t *pIdent)
146 if ((max_clients = g_Players.MaxClients()) == 0)
151 obj = new hud_syncobj_t;
152 obj->player_channels = new int[max_clients];
154 memset(obj->player_channels, 0, sizeof(int) * max_clients);
156 sec = HandleSecurity(pIdent, g_pCoreIdent);
158 if ((hndl = g_HandleSys.CreateHandleEx(m_hHudSyncObj, obj, &sec, NULL, &err))
161 delete [] obj->player_channels;
168 HandleError ReadHudSyncObj(Handle_t hndl,
169 IdentityToken_t *pOwner,
170 hud_syncobj_t **pObj)
172 HandleSecurity sec(pOwner, g_pCoreIdent);
173 return g_HandleSys.ReadHandle(hndl, m_hHudSyncObj, &sec, (void **)pObj);
176 unsigned int AutoSelectChannel(unsigned int client)
179 player_chaninfo_t *player;
181 player = &m_PlayerHuds[client];
184 for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++)
186 if (player->chan_times[i] < player->chan_times[last_channel])
192 ManualSelectChannel(client, last_channel);
197 int TryReuseLastChannel(unsigned int client, hud_syncobj_t *obj)
200 player_chaninfo_t *player;
202 player = &m_PlayerHuds[client];
204 /* First, see if we can re-use the previous channel. */
205 last_channel = obj->player_channels[client];
207 if (player->chan_syncobjs[last_channel] == obj)
209 player->chan_times[last_channel] = *g_pUniversalTime;
216 int AutoSelectChannel(unsigned int client, hud_syncobj_t *obj)
219 player_chaninfo_t *player;
221 player = &m_PlayerHuds[client];
223 /* First, see if we can re-use the previous channel. */
224 last_channel = obj->player_channels[client];
226 if (player->chan_syncobjs[last_channel] == obj)
228 player->chan_times[last_channel] = *g_pUniversalTime;
233 for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++)
235 if (player->chan_times[i] < player->chan_times[last_channel])
241 obj->player_channels[client] = last_channel;
242 player->chan_syncobjs[last_channel] = obj;
243 player->chan_times[last_channel] = *g_pUniversalTime;
248 int ManualSelectChannel(unsigned int client, int channel)
250 player_chaninfo_t *player;
252 player = &m_PlayerHuds[client];
253 player->chan_times[channel] = *g_pUniversalTime;
254 player->chan_syncobjs[channel] = NULL;
259 HandleType_t m_hHudSyncObj;
260 player_chaninfo_t *m_PlayerHuds;
263 hud_text_parms g_hud_params;
265 static cell_t CreateHudSynchronizer(IPluginContext *pContext, const cell_t *params)
267 return s_HudMsgHelpers.CreateHudSyncObj(pContext->GetIdentity());
270 static cell_t SetHudTextParams(IPluginContext *pContext, const cell_t *params)
272 g_hud_params.x = sp_ctof(params[1]);
273 g_hud_params.y = sp_ctof(params[2]);
274 g_hud_params.holdTime = sp_ctof(params[3]);
275 g_hud_params.r1 = static_cast<byte>(params[4]);
276 g_hud_params.g1 = static_cast<byte>(params[5]);
277 g_hud_params.b1 = static_cast<byte>(params[6]);
278 g_hud_params.a1 = static_cast<byte>(params[7]);
279 g_hud_params.effect = params[8];
280 g_hud_params.fxTime = sp_ctof(params[9]);
281 g_hud_params.fadeinTime = sp_ctof(params[10]);
282 g_hud_params.fadeoutTime = sp_ctof(params[11]);
283 g_hud_params.r2 = 255;
284 g_hud_params.g2 = 255;
285 g_hud_params.b2 = 250;
291 static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params)
293 cell_t *color1, *color2;
295 pContext->LocalToPhysAddr(params[4], &color1);
296 pContext->LocalToPhysAddr(params[5], &color2);
298 g_hud_params.x = sp_ctof(params[1]);
299 g_hud_params.y = sp_ctof(params[2]);
300 g_hud_params.holdTime = sp_ctof(params[3]);
301 g_hud_params.r1 = static_cast<byte>(color1[0]);
302 g_hud_params.g1 = static_cast<byte>(color1[1]);
303 g_hud_params.b1 = static_cast<byte>(color1[2]);
304 g_hud_params.a1 = static_cast<byte>(color1[3]);
305 g_hud_params.effect = params[6];
306 g_hud_params.fxTime = sp_ctof(params[7]);
307 g_hud_params.fadeinTime = sp_ctof(params[8]);
308 g_hud_params.fadeoutTime = sp_ctof(params[9]);
309 g_hud_params.r2 = static_cast<byte>(color2[0]);
310 g_hud_params.g2 = static_cast<byte>(color2[1]);
311 g_hud_params.b2 = static_cast<byte>(color2[2]);
312 g_hud_params.a2 = static_cast<byte>(color2[3]);
317 void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *pMessage)
324 bf = g_UserMsgs.StartMessage(g_HudMsgNum, players, 1, 0);
325 bf->WriteByte(textparms.channel & 0xFF );
326 bf->WriteFloat(textparms.x);
327 bf->WriteFloat(textparms.y);
328 bf->WriteByte(textparms.r1);
329 bf->WriteByte(textparms.g1);
330 bf->WriteByte(textparms.b1);
331 bf->WriteByte(textparms.a1);
332 bf->WriteByte(textparms.r2);
333 bf->WriteByte(textparms.g2);
334 bf->WriteByte(textparms.b2);
335 bf->WriteByte(textparms.a2);
336 bf->WriteByte(textparms.effect);
337 bf->WriteFloat(textparms.fadeinTime);
338 bf->WriteFloat(textparms.fadeoutTime);
339 bf->WriteFloat(textparms.holdTime);
340 bf->WriteFloat(textparms.fxTime);
341 bf->WriteString(pMessage);
342 g_UserMsgs.EndMessage();
345 static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params)
351 char message_buffer[255-36];
353 if (!s_HudMsgHelpers.IsSupported())
358 if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
360 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
364 if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
366 return pContext->ThrowNativeError("Invalid client index %d", client);
368 else if (!pPlayer->IsInGame())
370 return pContext->ThrowNativeError("Client %d is not in-game", client);
373 g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
374 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
379 g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client, obj);
380 UTIL_SendHudText(client, g_hud_params, message_buffer);
385 static cell_t ClearSyncHud(IPluginContext *pContext, const cell_t *params)
393 if (!s_HudMsgHelpers.IsSupported())
398 if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
400 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
404 if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
406 return pContext->ThrowNativeError("Invalid client index %d", client);
408 else if (!pPlayer->IsInGame())
410 return pContext->ThrowNativeError("Client %d is not in-game", client);
413 if ((channel = s_HudMsgHelpers.TryReuseLastChannel(client, obj)) == -1)
418 g_hud_params.channel = channel;
419 UTIL_SendHudText(client, g_hud_params, "");
421 return g_hud_params.channel;
424 static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params)
428 char message_buffer[255-36];
430 if (!s_HudMsgHelpers.IsSupported())
436 if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
438 return pContext->ThrowNativeError("Invalid client index %d", client);
440 else if (!pPlayer->IsInGame())
442 return pContext->ThrowNativeError("Client %d is not in-game", client);
445 g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
446 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
453 g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client);
457 g_hud_params.channel = params[2] % MAX_HUD_CHANNELS;
458 s_HudMsgHelpers.ManualSelectChannel(client, g_hud_params.channel);
461 UTIL_SendHudText(client, g_hud_params, message_buffer);
463 return g_hud_params.channel;
466 REGISTER_NATIVES(hudNatives)
468 {"ClearSyncHud", ClearSyncHud},
469 {"CreateHudSynchronizer", CreateHudSynchronizer},
470 {"SetHudTextParams", SetHudTextParams},
471 {"SetHudTextParamsEx", SetHudTextParamsEx},
472 {"ShowHudText", ShowHudText},
473 {"ShowSyncHudText", ShowSyncHudText},