1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/smn_hudtext.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,475 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include "sm_globals.h"
1.36 +#include "GameConfigs.h"
1.37 +#include "UserMessages.h"
1.38 +#include "TimerSys.h"
1.39 +#include "PlayerManager.h"
1.40 +#include "HandleSys.h"
1.41 +
1.42 +#define MAX_HUD_CHANNELS 6
1.43 +
1.44 +int g_HudMsgNum = -1;
1.45 +
1.46 +struct hud_syncobj_t
1.47 +{
1.48 + int *player_channels;
1.49 +};
1.50 +
1.51 +struct player_chaninfo_t
1.52 +{
1.53 + double chan_times[MAX_HUD_CHANNELS];
1.54 + hud_syncobj_t *chan_syncobjs[MAX_HUD_CHANNELS];
1.55 +};
1.56 +
1.57 +struct hud_text_parms
1.58 +{
1.59 + float x;
1.60 + float y;
1.61 + int effect;
1.62 + byte r1, g1, b1, a1;
1.63 + byte r2, g2, b2, a2;
1.64 + float fadeinTime;
1.65 + float fadeoutTime;
1.66 + float holdTime;
1.67 + float fxTime;
1.68 + int channel;
1.69 +};
1.70 +
1.71 +class HudMsgHelpers :
1.72 + public SMGlobalClass,
1.73 + public IHandleTypeDispatch,
1.74 + public IClientListener
1.75 +{
1.76 +public:
1.77 + bool IsSupported()
1.78 + {
1.79 + return (g_HudMsgNum != -1);
1.80 + }
1.81 +
1.82 + virtual void OnSourceModAllInitialized_Post()
1.83 + {
1.84 + const char *key;
1.85 +
1.86 + key = g_pGameConf->GetKeyValue("HudTextMsg");
1.87 + if (key != NULL)
1.88 + {
1.89 + g_HudMsgNum = g_UserMsgs.GetMessageIndex(key);
1.90 + }
1.91 +
1.92 + if (!IsSupported())
1.93 + {
1.94 + m_hHudSyncObj = 0;
1.95 + m_PlayerHuds = NULL;
1.96 + return;
1.97 + }
1.98 +
1.99 + m_PlayerHuds = new player_chaninfo_t[256+1];
1.100 + m_hHudSyncObj = g_HandleSys.CreateType("HudSyncObj", this, 0, NULL, NULL, g_pCoreIdent, NULL);
1.101 +
1.102 + g_Players.AddClientListener(this);
1.103 + }
1.104 +
1.105 + virtual void OnSourceModShutdown()
1.106 + {
1.107 + if (!IsSupported())
1.108 + {
1.109 + return;
1.110 + }
1.111 +
1.112 + delete [] m_PlayerHuds;
1.113 + g_HandleSys.RemoveType(m_hHudSyncObj, g_pCoreIdent);
1.114 +
1.115 + g_Players.RemoveClientListener(this);
1.116 + }
1.117 +
1.118 + virtual void OnHandleDestroy(HandleType_t type, void *object)
1.119 + {
1.120 + hud_syncobj_t *obj = (hud_syncobj_t *)object;
1.121 +
1.122 + delete [] obj->player_channels;
1.123 + delete obj;
1.124 + }
1.125 +
1.126 + virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
1.127 + {
1.128 + *pSize = sizeof(unsigned int) * g_Players.GetMaxClients();
1.129 + return true;
1.130 + }
1.131 +
1.132 + virtual void OnClientConnected(int client)
1.133 + {
1.134 + player_chaninfo_t *player;
1.135 +
1.136 + player = &m_PlayerHuds[client];
1.137 + memset(player->chan_syncobjs, 0, sizeof(player->chan_syncobjs));
1.138 + memset(player->chan_times, 0, sizeof(player->chan_times));
1.139 + }
1.140 +
1.141 + Handle_t CreateHudSyncObj(IdentityToken_t *pIdent)
1.142 + {
1.143 + Handle_t hndl;
1.144 + int max_clients;
1.145 + HandleError err;
1.146 + hud_syncobj_t *obj;
1.147 + HandleSecurity sec;
1.148 +
1.149 + if ((max_clients = g_Players.MaxClients()) == 0)
1.150 + {
1.151 + max_clients = 256+1;
1.152 + }
1.153 +
1.154 + obj = new hud_syncobj_t;
1.155 + obj->player_channels = new int[max_clients];
1.156 +
1.157 + memset(obj->player_channels, 0, sizeof(int) * max_clients);
1.158 +
1.159 + sec = HandleSecurity(pIdent, g_pCoreIdent);
1.160 +
1.161 + if ((hndl = g_HandleSys.CreateHandleEx(m_hHudSyncObj, obj, &sec, NULL, &err))
1.162 + == BAD_HANDLE)
1.163 + {
1.164 + delete [] obj->player_channels;
1.165 + delete obj;
1.166 + }
1.167 +
1.168 + return hndl;
1.169 + }
1.170 +
1.171 + HandleError ReadHudSyncObj(Handle_t hndl,
1.172 + IdentityToken_t *pOwner,
1.173 + hud_syncobj_t **pObj)
1.174 + {
1.175 + HandleSecurity sec(pOwner, g_pCoreIdent);
1.176 + return g_HandleSys.ReadHandle(hndl, m_hHudSyncObj, &sec, (void **)pObj);
1.177 + }
1.178 +
1.179 + unsigned int AutoSelectChannel(unsigned int client)
1.180 + {
1.181 + int last_channel;
1.182 + player_chaninfo_t *player;
1.183 +
1.184 + player = &m_PlayerHuds[client];
1.185 +
1.186 + last_channel = 0;
1.187 + for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++)
1.188 + {
1.189 + if (player->chan_times[i] < player->chan_times[last_channel])
1.190 + {
1.191 + last_channel = i;
1.192 + }
1.193 + }
1.194 +
1.195 + ManualSelectChannel(client, last_channel);
1.196 +
1.197 + return last_channel;
1.198 + }
1.199 +
1.200 + int TryReuseLastChannel(unsigned int client, hud_syncobj_t *obj)
1.201 + {
1.202 + int last_channel;
1.203 + player_chaninfo_t *player;
1.204 +
1.205 + player = &m_PlayerHuds[client];
1.206 +
1.207 + /* First, see if we can re-use the previous channel. */
1.208 + last_channel = obj->player_channels[client];
1.209 +
1.210 + if (player->chan_syncobjs[last_channel] == obj)
1.211 + {
1.212 + player->chan_times[last_channel] = *g_pUniversalTime;
1.213 + return last_channel;
1.214 + }
1.215 +
1.216 + return -1;
1.217 + }
1.218 +
1.219 + int AutoSelectChannel(unsigned int client, hud_syncobj_t *obj)
1.220 + {
1.221 + int last_channel;
1.222 + player_chaninfo_t *player;
1.223 +
1.224 + player = &m_PlayerHuds[client];
1.225 +
1.226 + /* First, see if we can re-use the previous channel. */
1.227 + last_channel = obj->player_channels[client];
1.228 +
1.229 + if (player->chan_syncobjs[last_channel] == obj)
1.230 + {
1.231 + player->chan_times[last_channel] = *g_pUniversalTime;
1.232 + return last_channel;
1.233 + }
1.234 +
1.235 + last_channel = 0;
1.236 + for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++)
1.237 + {
1.238 + if (player->chan_times[i] < player->chan_times[last_channel])
1.239 + {
1.240 + last_channel = i;
1.241 + }
1.242 + }
1.243 +
1.244 + obj->player_channels[client] = last_channel;
1.245 + player->chan_syncobjs[last_channel] = obj;
1.246 + player->chan_times[last_channel] = *g_pUniversalTime;
1.247 +
1.248 + return last_channel;
1.249 + }
1.250 +
1.251 + int ManualSelectChannel(unsigned int client, int channel)
1.252 + {
1.253 + player_chaninfo_t *player;
1.254 +
1.255 + player = &m_PlayerHuds[client];
1.256 + player->chan_times[channel] = *g_pUniversalTime;
1.257 + player->chan_syncobjs[channel] = NULL;
1.258 +
1.259 + return channel;
1.260 + }
1.261 +private:
1.262 + HandleType_t m_hHudSyncObj;
1.263 + player_chaninfo_t *m_PlayerHuds;
1.264 +} s_HudMsgHelpers;
1.265 +
1.266 +hud_text_parms g_hud_params;
1.267 +
1.268 +static cell_t CreateHudSynchronizer(IPluginContext *pContext, const cell_t *params)
1.269 +{
1.270 + return s_HudMsgHelpers.CreateHudSyncObj(pContext->GetIdentity());
1.271 +}
1.272 +
1.273 +static cell_t SetHudTextParams(IPluginContext *pContext, const cell_t *params)
1.274 +{
1.275 + g_hud_params.x = sp_ctof(params[1]);
1.276 + g_hud_params.y = sp_ctof(params[2]);
1.277 + g_hud_params.holdTime = sp_ctof(params[3]);
1.278 + g_hud_params.r1 = static_cast<byte>(params[4]);
1.279 + g_hud_params.g1 = static_cast<byte>(params[5]);
1.280 + g_hud_params.b1 = static_cast<byte>(params[6]);
1.281 + g_hud_params.a1 = static_cast<byte>(params[7]);
1.282 + g_hud_params.effect = params[8];
1.283 + g_hud_params.fxTime = sp_ctof(params[9]);
1.284 + g_hud_params.fadeinTime = sp_ctof(params[10]);
1.285 + g_hud_params.fadeoutTime = sp_ctof(params[11]);
1.286 + g_hud_params.r2 = 255;
1.287 + g_hud_params.g2 = 255;
1.288 + g_hud_params.b2 = 250;
1.289 + g_hud_params.a2 = 0;
1.290 +
1.291 + return 1;
1.292 +}
1.293 +
1.294 +static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params)
1.295 +{
1.296 + cell_t *color1, *color2;
1.297 +
1.298 + pContext->LocalToPhysAddr(params[4], &color1);
1.299 + pContext->LocalToPhysAddr(params[5], &color2);
1.300 +
1.301 + g_hud_params.x = sp_ctof(params[1]);
1.302 + g_hud_params.y = sp_ctof(params[2]);
1.303 + g_hud_params.holdTime = sp_ctof(params[3]);
1.304 + g_hud_params.r1 = static_cast<byte>(color1[0]);
1.305 + g_hud_params.g1 = static_cast<byte>(color1[1]);
1.306 + g_hud_params.b1 = static_cast<byte>(color1[2]);
1.307 + g_hud_params.a1 = static_cast<byte>(color1[3]);
1.308 + g_hud_params.effect = params[6];
1.309 + g_hud_params.fxTime = sp_ctof(params[7]);
1.310 + g_hud_params.fadeinTime = sp_ctof(params[8]);
1.311 + g_hud_params.fadeoutTime = sp_ctof(params[9]);
1.312 + g_hud_params.r2 = static_cast<byte>(color2[0]);
1.313 + g_hud_params.g2 = static_cast<byte>(color2[1]);
1.314 + g_hud_params.b2 = static_cast<byte>(color2[2]);
1.315 + g_hud_params.a2 = static_cast<byte>(color2[3]);
1.316 +
1.317 + return 1;
1.318 +}
1.319 +
1.320 +void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *pMessage)
1.321 +{
1.322 + bf_write *bf;
1.323 + cell_t players[1];
1.324 +
1.325 + players[0] = client;
1.326 +
1.327 + bf = g_UserMsgs.StartMessage(g_HudMsgNum, players, 1, 0);
1.328 + bf->WriteByte(textparms.channel & 0xFF );
1.329 + bf->WriteFloat(textparms.x);
1.330 + bf->WriteFloat(textparms.y);
1.331 + bf->WriteByte(textparms.r1);
1.332 + bf->WriteByte(textparms.g1);
1.333 + bf->WriteByte(textparms.b1);
1.334 + bf->WriteByte(textparms.a1);
1.335 + bf->WriteByte(textparms.r2);
1.336 + bf->WriteByte(textparms.g2);
1.337 + bf->WriteByte(textparms.b2);
1.338 + bf->WriteByte(textparms.a2);
1.339 + bf->WriteByte(textparms.effect);
1.340 + bf->WriteFloat(textparms.fadeinTime);
1.341 + bf->WriteFloat(textparms.fadeoutTime);
1.342 + bf->WriteFloat(textparms.holdTime);
1.343 + bf->WriteFloat(textparms.fxTime);
1.344 + bf->WriteString(pMessage);
1.345 + g_UserMsgs.EndMessage();
1.346 +}
1.347 +
1.348 +static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params)
1.349 +{
1.350 + int client;
1.351 + Handle_t err;
1.352 + CPlayer *pPlayer;
1.353 + hud_syncobj_t *obj;
1.354 + char message_buffer[255-36];
1.355 +
1.356 + if (!s_HudMsgHelpers.IsSupported())
1.357 + {
1.358 + return -1;
1.359 + }
1.360 +
1.361 + if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
1.362 + {
1.363 + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
1.364 + }
1.365 +
1.366 + client = params[1];
1.367 + if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
1.368 + {
1.369 + return pContext->ThrowNativeError("Invalid client index %d", client);
1.370 + }
1.371 + else if (!pPlayer->IsInGame())
1.372 + {
1.373 + return pContext->ThrowNativeError("Client %d is not in-game", client);
1.374 + }
1.375 +
1.376 + g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
1.377 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.378 + {
1.379 + return 0;
1.380 + }
1.381 +
1.382 + g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client, obj);
1.383 + UTIL_SendHudText(client, g_hud_params, message_buffer);
1.384 +
1.385 + return 1;
1.386 +}
1.387 +
1.388 +static cell_t ClearSyncHud(IPluginContext *pContext, const cell_t *params)
1.389 +{
1.390 + int client;
1.391 + int channel;
1.392 + Handle_t err;
1.393 + CPlayer *pPlayer;
1.394 + hud_syncobj_t *obj;
1.395 +
1.396 + if (!s_HudMsgHelpers.IsSupported())
1.397 + {
1.398 + return -1;
1.399 + }
1.400 +
1.401 + if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
1.402 + {
1.403 + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
1.404 + }
1.405 +
1.406 + client = params[1];
1.407 + if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
1.408 + {
1.409 + return pContext->ThrowNativeError("Invalid client index %d", client);
1.410 + }
1.411 + else if (!pPlayer->IsInGame())
1.412 + {
1.413 + return pContext->ThrowNativeError("Client %d is not in-game", client);
1.414 + }
1.415 +
1.416 + if ((channel = s_HudMsgHelpers.TryReuseLastChannel(client, obj)) == -1)
1.417 + {
1.418 + return -1;
1.419 + }
1.420 +
1.421 + g_hud_params.channel = channel;
1.422 + UTIL_SendHudText(client, g_hud_params, "");
1.423 +
1.424 + return g_hud_params.channel;
1.425 +}
1.426 +
1.427 +static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params)
1.428 +{
1.429 + int client;
1.430 + CPlayer *pPlayer;
1.431 + char message_buffer[255-36];
1.432 +
1.433 + if (!s_HudMsgHelpers.IsSupported())
1.434 + {
1.435 + return -1;
1.436 + }
1.437 +
1.438 + client = params[1];
1.439 + if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
1.440 + {
1.441 + return pContext->ThrowNativeError("Invalid client index %d", client);
1.442 + }
1.443 + else if (!pPlayer->IsInGame())
1.444 + {
1.445 + return pContext->ThrowNativeError("Client %d is not in-game", client);
1.446 + }
1.447 +
1.448 + g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
1.449 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.450 + {
1.451 + return 0;
1.452 + }
1.453 +
1.454 + if (params[2] == -1)
1.455 + {
1.456 + g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client);
1.457 + }
1.458 + else
1.459 + {
1.460 + g_hud_params.channel = params[2] % MAX_HUD_CHANNELS;
1.461 + s_HudMsgHelpers.ManualSelectChannel(client, g_hud_params.channel);
1.462 + }
1.463 +
1.464 + UTIL_SendHudText(client, g_hud_params, message_buffer);
1.465 +
1.466 + return g_hud_params.channel;
1.467 +}
1.468 +
1.469 +REGISTER_NATIVES(hudNatives)
1.470 +{
1.471 + {"ClearSyncHud", ClearSyncHud},
1.472 + {"CreateHudSynchronizer", CreateHudSynchronizer},
1.473 + {"SetHudTextParams", SetHudTextParams},
1.474 + {"SetHudTextParamsEx", SetHudTextParamsEx},
1.475 + {"ShowHudText", ShowHudText},
1.476 + {"ShowSyncHudText", ShowSyncHudText},
1.477 + {NULL, NULL},
1.478 +};