core/smn_hudtext.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2175 54a8411faaac
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "sm_globals.h"
    33 #include "GameConfigs.h"
    34 #include "UserMessages.h"
    35 #include "TimerSys.h"
    36 #include "PlayerManager.h"
    37 #include "HandleSys.h"
    38 
    39 #define MAX_HUD_CHANNELS		6
    40 
    41 int g_HudMsgNum = -1;
    42 
    43 struct hud_syncobj_t
    44 {
    45 	int *player_channels;
    46 };
    47 
    48 struct player_chaninfo_t
    49 {
    50 	double chan_times[MAX_HUD_CHANNELS];
    51 	hud_syncobj_t *chan_syncobjs[MAX_HUD_CHANNELS];
    52 };
    53 
    54 struct hud_text_parms
    55 {
    56 	float       x;
    57 	float       y;
    58 	int         effect;
    59 	byte        r1, g1, b1, a1;
    60 	byte        r2, g2, b2, a2;
    61 	float       fadeinTime;
    62 	float       fadeoutTime;
    63 	float       holdTime;
    64 	float       fxTime;
    65 	int         channel;
    66 };
    67 
    68 class HudMsgHelpers : 
    69 	public SMGlobalClass,
    70 	public IHandleTypeDispatch,
    71 	public IClientListener
    72 {
    73 public:
    74 	bool IsSupported()
    75 	{
    76 		return (g_HudMsgNum != -1);
    77 	}
    78 
    79 	virtual void OnSourceModAllInitialized_Post()
    80 	{
    81 		const char *key;
    82 
    83 		key = g_pGameConf->GetKeyValue("HudTextMsg");
    84 		if (key != NULL)
    85 		{
    86 			g_HudMsgNum = g_UserMsgs.GetMessageIndex(key);
    87 		}
    88 
    89 		if (!IsSupported())
    90 		{
    91 			m_hHudSyncObj = 0;
    92 			m_PlayerHuds = NULL;
    93 			return;
    94 		}
    95 
    96 		m_PlayerHuds = new player_chaninfo_t[256+1];
    97 		m_hHudSyncObj = g_HandleSys.CreateType("HudSyncObj", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    98 
    99 		g_Players.AddClientListener(this);
   100 	}
   101 
   102 	virtual void OnSourceModShutdown()
   103 	{
   104 		if (!IsSupported())
   105 		{
   106 			return;
   107 		}
   108 
   109 		delete [] m_PlayerHuds;
   110 		g_HandleSys.RemoveType(m_hHudSyncObj, g_pCoreIdent);
   111 
   112 		g_Players.RemoveClientListener(this);
   113 	}
   114 
   115 	virtual void OnHandleDestroy(HandleType_t type, void *object)
   116 	{
   117 		hud_syncobj_t *obj = (hud_syncobj_t *)object;
   118 
   119 		delete [] obj->player_channels;
   120 		delete obj;
   121 	}
   122 
   123 	virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
   124 	{
   125 		*pSize = sizeof(unsigned int) * g_Players.GetMaxClients();
   126 		return true;
   127 	}
   128 
   129 	virtual void OnClientConnected(int client)
   130 	{
   131 		player_chaninfo_t *player;
   132 
   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));
   136 	}
   137 
   138 	Handle_t CreateHudSyncObj(IdentityToken_t *pIdent)
   139 	{
   140 		Handle_t hndl;
   141 		int max_clients;
   142 		HandleError err;
   143 		hud_syncobj_t *obj;
   144 		HandleSecurity sec;
   145 
   146 		if ((max_clients = g_Players.MaxClients()) == 0)
   147 		{
   148 			max_clients = 256+1;
   149 		}
   150 
   151 		obj = new hud_syncobj_t;
   152 		obj->player_channels = new int[max_clients];
   153 
   154 		memset(obj->player_channels, 0, sizeof(int) * max_clients);
   155 
   156 		sec = HandleSecurity(pIdent, g_pCoreIdent);
   157 		
   158 		if ((hndl = g_HandleSys.CreateHandleEx(m_hHudSyncObj, obj, &sec, NULL, &err))
   159 			== BAD_HANDLE)
   160 		{
   161 			delete [] obj->player_channels;
   162 			delete obj;
   163 		}
   164 
   165 		return hndl;
   166 	}
   167 
   168 	HandleError ReadHudSyncObj(Handle_t hndl, 
   169 		IdentityToken_t *pOwner, 
   170 		hud_syncobj_t **pObj)
   171 	{
   172 		HandleSecurity sec(pOwner, g_pCoreIdent);
   173 		return g_HandleSys.ReadHandle(hndl, m_hHudSyncObj, &sec, (void **)pObj);
   174 	}
   175 
   176 	unsigned int AutoSelectChannel(unsigned int client)
   177 	{
   178 		int last_channel;
   179 		player_chaninfo_t *player;
   180 
   181 		player = &m_PlayerHuds[client];
   182 
   183 		last_channel = 0;
   184 		for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++)
   185 		{
   186 			if (player->chan_times[i] < player->chan_times[last_channel])
   187 			{
   188 				last_channel = i;
   189 			}
   190 		}
   191 
   192 		ManualSelectChannel(client, last_channel);
   193 
   194 		return last_channel;
   195 	}
   196 
   197 	int TryReuseLastChannel(unsigned int client, hud_syncobj_t *obj)
   198 	{
   199 		int last_channel;
   200 		player_chaninfo_t *player;
   201 
   202 		player = &m_PlayerHuds[client];
   203 
   204 		/* First, see if we can re-use the previous channel. */
   205 		last_channel = obj->player_channels[client];
   206 
   207 		if (player->chan_syncobjs[last_channel] == obj)
   208 		{
   209 			player->chan_times[last_channel] = *g_pUniversalTime;
   210 			return last_channel;
   211 		}
   212 
   213 		return -1;
   214 	}
   215 
   216 	int AutoSelectChannel(unsigned int client, hud_syncobj_t *obj)
   217 	{
   218 		int last_channel;
   219 		player_chaninfo_t *player;
   220 
   221 		player = &m_PlayerHuds[client];
   222 		
   223 		/* First, see if we can re-use the previous channel. */
   224 		last_channel = obj->player_channels[client];
   225 
   226 		if (player->chan_syncobjs[last_channel] == obj)
   227 		{
   228 			player->chan_times[last_channel] = *g_pUniversalTime;
   229 			return last_channel;
   230 		}
   231 
   232 		last_channel = 0;
   233 		for (unsigned int i = 1; i < MAX_HUD_CHANNELS; i++)
   234 		{
   235 			if (player->chan_times[i] < player->chan_times[last_channel])
   236 			{
   237 				last_channel = i;
   238 			}
   239 		}
   240 
   241 		obj->player_channels[client] = last_channel;
   242 		player->chan_syncobjs[last_channel] = obj;
   243 		player->chan_times[last_channel] = *g_pUniversalTime;
   244 
   245 		return last_channel;
   246 	}
   247 
   248 	int ManualSelectChannel(unsigned int client, int channel)
   249 	{
   250 		player_chaninfo_t *player;
   251 
   252 		player = &m_PlayerHuds[client];
   253 		player->chan_times[channel] = *g_pUniversalTime;
   254 		player->chan_syncobjs[channel] = NULL;
   255 
   256 		return channel;
   257 	}
   258 private:
   259 	HandleType_t m_hHudSyncObj;
   260 	player_chaninfo_t *m_PlayerHuds;
   261 } s_HudMsgHelpers;
   262 
   263 hud_text_parms g_hud_params;
   264 
   265 static cell_t CreateHudSynchronizer(IPluginContext *pContext, const cell_t *params)
   266 {
   267 	return s_HudMsgHelpers.CreateHudSyncObj(pContext->GetIdentity());
   268 }
   269 
   270 static cell_t SetHudTextParams(IPluginContext *pContext, const cell_t *params)
   271 {
   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;
   286 	g_hud_params.a2 = 0;
   287 
   288 	return 1;
   289 }
   290 
   291 static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params)
   292 {
   293 	cell_t *color1, *color2;
   294 
   295 	pContext->LocalToPhysAddr(params[4], &color1);
   296 	pContext->LocalToPhysAddr(params[5], &color2);
   297 
   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]);
   313 
   314 	return 1;
   315 }
   316 
   317 void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *pMessage)
   318 {
   319 	bf_write *bf;
   320 	cell_t players[1];
   321 
   322 	players[0] = client;
   323 
   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();
   343 }
   344 
   345 static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params)
   346 {
   347 	int client;
   348 	Handle_t err;
   349 	CPlayer *pPlayer;
   350 	hud_syncobj_t *obj;
   351 	char message_buffer[255-36];
   352 
   353 	if (!s_HudMsgHelpers.IsSupported())
   354 	{
   355 		return -1;
   356 	}
   357 
   358 	if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
   359 	{
   360 		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
   361 	}
   362 
   363 	client = params[1];
   364 	if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
   365 	{
   366 		return pContext->ThrowNativeError("Invalid client index %d", client);
   367 	}
   368 	else if (!pPlayer->IsInGame())
   369 	{
   370 		return pContext->ThrowNativeError("Client %d is not in-game", client);
   371 	}
   372 
   373 	g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
   374 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   375 	{
   376 		return 0;
   377 	}
   378 
   379 	g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client, obj);
   380 	UTIL_SendHudText(client, g_hud_params, message_buffer);
   381 
   382 	return 1;
   383 }
   384 
   385 static cell_t ClearSyncHud(IPluginContext *pContext, const cell_t *params)
   386 {
   387 	int client;
   388 	int channel;
   389 	Handle_t err;
   390 	CPlayer *pPlayer;
   391 	hud_syncobj_t *obj;
   392 
   393 	if (!s_HudMsgHelpers.IsSupported())
   394 	{
   395 		return -1;
   396 	}
   397 
   398 	if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
   399 	{
   400 		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
   401 	}
   402 
   403 	client = params[1];
   404 	if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
   405 	{
   406 		return pContext->ThrowNativeError("Invalid client index %d", client);
   407 	}
   408 	else if (!pPlayer->IsInGame())
   409 	{
   410 		return pContext->ThrowNativeError("Client %d is not in-game", client);
   411 	}
   412 
   413 	if ((channel = s_HudMsgHelpers.TryReuseLastChannel(client, obj)) == -1)
   414 	{
   415 		return -1;
   416 	}
   417 
   418 	g_hud_params.channel = channel;
   419 	UTIL_SendHudText(client, g_hud_params, "");
   420 
   421 	return g_hud_params.channel;
   422 }
   423 
   424 static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params)
   425 {
   426 	int client;
   427 	CPlayer *pPlayer;
   428 	char message_buffer[255-36];
   429 
   430 	if (!s_HudMsgHelpers.IsSupported())
   431 	{
   432 		return -1;
   433 	}
   434 
   435 	client = params[1];
   436 	if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
   437 	{
   438 		return pContext->ThrowNativeError("Invalid client index %d", client);
   439 	}
   440 	else if (!pPlayer->IsInGame())
   441 	{
   442 		return pContext->ThrowNativeError("Client %d is not in-game", client);
   443 	}
   444 
   445 	g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
   446 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   447 	{
   448 		return 0;
   449 	}
   450 
   451 	if (params[2] == -1)
   452 	{
   453 		g_hud_params.channel = s_HudMsgHelpers.AutoSelectChannel(client);
   454 	}
   455 	else
   456 	{
   457 		g_hud_params.channel = params[2] % MAX_HUD_CHANNELS;
   458 		s_HudMsgHelpers.ManualSelectChannel(client, g_hud_params.channel);
   459 	}
   460 
   461 	UTIL_SendHudText(client, g_hud_params, message_buffer);
   462 
   463 	return g_hud_params.channel;
   464 }
   465 
   466 REGISTER_NATIVES(hudNatives)
   467 {
   468 	{"ClearSyncHud",				ClearSyncHud},
   469 	{"CreateHudSynchronizer",		CreateHudSynchronizer},
   470 	{"SetHudTextParams",			SetHudTextParams},
   471 	{"SetHudTextParamsEx",			SetHudTextParamsEx},
   472 	{"ShowHudText",					ShowHudText},
   473 	{"ShowSyncHudText",				ShowSyncHudText},
   474 	{NULL,							NULL},
   475 };