core/smn_halflife.cpp
author systematicmania <systematicmania@gmail.com>
Thu Jul 18 11:38:04 2013 -0400 (2013-07-18)
changeset 3949 3fefd8346c23
parent 3942 7aaa00382627
child 3961 0dc477c29792
permissions -rw-r--r--
Fixed clients not being marked as in kick queue in some cases (bug 5746, r=psychonic).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2010 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 "sourcemod.h"
    34 #include "sourcemm_api.h"
    35 #include "PlayerManager.h"
    36 #include "HalfLife2.h"
    37 
    38 static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params)
    39 {
    40 	engrandom->SetSeed(params[1]);
    41 
    42 	return 1;
    43 }
    44 
    45 static cell_t GetRandomFloat(IPluginContext *pContext, const cell_t *params)
    46 {
    47 	float fMin = sp_ctof(params[1]);
    48 	float fMax = sp_ctof(params[2]);
    49 
    50 	float fRandom = engrandom->RandomFloat(fMin, fMax);
    51 
    52 	return sp_ftoc(fRandom);
    53 }
    54 
    55 static cell_t GetRandomInt(IPluginContext *pContext, const cell_t *params)
    56 {
    57 	return engrandom->RandomInt(params[1], params[2]);
    58 }
    59 
    60 static cell_t IsMapValid(IPluginContext *pContext, const cell_t *params)
    61 {
    62 	char *map;
    63 	pContext->LocalToString(params[1], &map);
    64 
    65 	return g_HL2.IsMapValid(map);
    66 }
    67 
    68 static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params)
    69 {
    70 	return engine->IsDedicatedServer();
    71 }
    72 
    73 static cell_t GetEngineTime(IPluginContext *pContext, const cell_t *params)
    74 {
    75 #if SOURCE_ENGINE >= SE_LEFT4DEAD2
    76 	float fTime = Plat_FloatTime();
    77 #else
    78 	float fTime = engine->Time();
    79 #endif
    80 	
    81 	return sp_ftoc(fTime);
    82 }
    83 
    84 static cell_t GetGameTime(IPluginContext *pContext, const cell_t *params)
    85 {
    86 	return sp_ftoc(gpGlobals->curtime);
    87 }
    88 
    89 static cell_t GetGameTickCount(IPluginContext *pContext, const cell_t *params)
    90 {
    91 	return gpGlobals->tickcount;
    92 }
    93 
    94 static cell_t CreateFakeClient(IPluginContext *pContext, const cell_t *params)
    95 {
    96 	if (!g_SourceMod.IsMapRunning())
    97 	{
    98 		return pContext->ThrowNativeError("Cannot create fakeclient when no map is active");
    99 	}
   100 
   101 	char *netname;
   102 
   103 	pContext->LocalToString(params[1], &netname);
   104 
   105 #if SOURCE_ENGINE == SE_DOTA
   106 	int index = engine->CreateFakeClient(netname).Get();
   107 	
   108 	if (index == -1)
   109 	{
   110 		return 0;
   111 	}
   112 
   113 	return index;
   114 #else
   115 	edict_t *pEdict = engine->CreateFakeClient(netname);
   116 
   117 	/* :TODO: does the engine fire forwards for us and whatnot? no idea... */
   118 
   119 	if (!pEdict)
   120 	{
   121 		return 0;
   122 	}
   123 
   124 	return IndexOfEdict(pEdict);
   125 #endif
   126 }
   127 
   128 static cell_t SetFakeClientConVar(IPluginContext *pContext, const cell_t *params)
   129 {
   130 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   131 
   132 	if (!pPlayer)
   133 	{
   134 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   135 	}
   136 
   137 	if (!pPlayer->IsConnected())
   138 	{
   139 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   140 	}
   141 
   142 	if (!pPlayer->IsFakeClient())
   143 	{
   144 		return pContext->ThrowNativeError("Client %d is not a fake client", params[1]);
   145 	}
   146 
   147 	char *cvar, *value;
   148 
   149 	pContext->LocalToString(params[2], &cvar);
   150 	pContext->LocalToString(params[3], &value);
   151 
   152 #if SOURCE_ENGINE == SE_DOTA
   153 	engine->SetFakeClientConVarValue(pPlayer->GetIndex(), cvar, value);
   154 #else
   155 	engine->SetFakeClientConVarValue(pPlayer->GetEdict(), cvar, value);
   156 #endif
   157 
   158 	return 1;
   159 }
   160 
   161 static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params)
   162 {
   163 	const char *description;
   164 
   165 	if (params[3])
   166 	{
   167 		description = gamedll->GetGameDescription();
   168 	} else {
   169 		description = SERVER_CALL(GetGameDescription)();
   170 	}
   171 
   172 	size_t numBytes;
   173 	
   174 	pContext->StringToLocalUTF8(params[1], params[2], description, &numBytes);
   175 
   176 	return numBytes;
   177 }
   178 
   179 static cell_t GetGameFolderName(IPluginContext *pContext, const cell_t *params)
   180 {
   181 	const char *name = g_SourceMod.GetGameFolderName();
   182 	size_t numBytes;
   183 
   184 	pContext->StringToLocalUTF8(params[1], params[2], name, &numBytes);
   185 
   186 	return numBytes;
   187 }
   188 
   189 /* Useless comment to bump the build */
   190 static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params)
   191 {
   192 	size_t bytes;
   193 	pContext->StringToLocalUTF8(params[1], params[2], STRING(gpGlobals->mapname), &bytes);
   194 	return bytes;
   195 }
   196 
   197 static cell_t PrecacheModel(IPluginContext *pContext, const cell_t *params)
   198 {
   199 	char *model;
   200 	pContext->LocalToString(params[1], &model);
   201 
   202 	return engine->PrecacheModel(model, params[2] ? true : false);
   203 }
   204 
   205 static cell_t PrecacheSentenceFile(IPluginContext *pContext, const cell_t *params)
   206 {
   207 	char *sentencefile;
   208 	pContext->LocalToString(params[1], &sentencefile);
   209 
   210 	return engine->PrecacheSentenceFile(sentencefile, params[2] ? true : false);
   211 }
   212 
   213 static cell_t PrecacheDecal(IPluginContext *pContext, const cell_t *params)
   214 {
   215 	char *decal;
   216 	pContext->LocalToString(params[1], &decal);
   217 
   218 	return engine->PrecacheDecal(decal, params[2] ? true : false);
   219 }
   220 
   221 static cell_t PrecacheGeneric(IPluginContext *pContext, const cell_t *params)
   222 {
   223 	char *generic;
   224 	pContext->LocalToString(params[1], &generic);
   225 
   226 	return engine->PrecacheGeneric(generic, params[2] ? true : false);
   227 }
   228 
   229 static cell_t IsModelPrecached(IPluginContext *pContext, const cell_t *params)
   230 {
   231 	char *model;
   232 	pContext->LocalToString(params[1], &model);
   233 
   234 	return engine->IsModelPrecached(model) ? 1 : 0;
   235 }
   236 
   237 static cell_t IsDecalPrecached(IPluginContext *pContext, const cell_t *params)
   238 {
   239 	char *decal;
   240 	pContext->LocalToString(params[1], &decal);
   241 
   242 	return engine->IsDecalPrecached(decal) ? 1 : 0;
   243 }
   244 
   245 static cell_t IsGenericPrecached(IPluginContext *pContext, const cell_t *params)
   246 {
   247 	char *generic;
   248 	pContext->LocalToString(params[1], &generic);
   249 
   250 	return engine->IsGenericPrecached(generic) ? 1 : 0;
   251 }
   252 
   253 static cell_t PrecacheSound(IPluginContext *pContext, const cell_t *params)
   254 {
   255 	char *sample;
   256 	pContext->LocalToString(params[1], &sample);
   257 
   258 	return enginesound->PrecacheSound(sample, params[2] ? true : false) ? 1 : 0;
   259 }
   260 
   261 static cell_t IsSoundPrecached(IPluginContext *pContext, const cell_t *params)
   262 {
   263 	char *sample;
   264 	pContext->LocalToString(params[1], &sample);
   265 
   266 	return enginesound->IsSoundPrecached(sample) ? 1 : 0;
   267 }
   268 
   269 static cell_t smn_CreateDialog(IPluginContext *pContext, const cell_t *params)
   270 {
   271 #if SOURCE_ENGINE == SE_DOTA
   272 	return pContext->ThrowNativeError("CreateDialog is not supported on this game");
   273 #else
   274 	KeyValues *pKV;
   275 	HandleError herr;
   276 	Handle_t hndl = static_cast<Handle_t>(params[2]);
   277 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   278 
   279 	if (!pPlayer)
   280 	{
   281 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   282 	}
   283 
   284 	if (!pPlayer->IsInGame())
   285 	{
   286 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   287 	}
   288 
   289 	pKV = g_SourceMod.ReadKeyValuesHandle(hndl, &herr, true);
   290 	if (herr != HandleError_None)
   291 	{
   292 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   293 	}
   294 
   295 	serverpluginhelpers->CreateMessage(pPlayer->GetEdict(), 
   296 		static_cast<DIALOG_TYPE>(params[3]), 
   297 		pKV, 
   298 		vsp_interface);
   299 
   300 	return 1;
   301 #endif // DOTA
   302 }
   303 
   304 static cell_t PrintToChat(IPluginContext *pContext, const cell_t *params)
   305 {
   306 	int client = params[1];
   307 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   308 
   309 	if (!pPlayer)
   310 	{
   311 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   312 	}
   313 
   314 	if (!pPlayer->IsInGame())
   315 	{
   316 		return pContext->ThrowNativeError("Client %d is not in game", client);
   317 	}
   318 
   319 	g_SourceMod.SetGlobalTarget(client);
   320 
   321 	char buffer[192];
   322 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   323 
   324 	/* Check for an error before printing to the client */
   325 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   326 	{
   327 		return 0;
   328 	}
   329 
   330 	if (!g_HL2.TextMsg(client, HUD_PRINTTALK, buffer))
   331 	{
   332 		return pContext->ThrowNativeError("Could not send a usermessage");
   333 	}
   334 
   335 	return 1;
   336 }
   337 
   338 static cell_t PrintCenterText(IPluginContext *pContext, const cell_t *params)
   339 {
   340 	int client = params[1];
   341 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   342 
   343 	if (!pPlayer)
   344 	{
   345 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   346 	}
   347 
   348 	if (!pPlayer->IsInGame())
   349 	{
   350 		return pContext->ThrowNativeError("Client %d is not in game", client);
   351 	}
   352 
   353 	g_SourceMod.SetGlobalTarget(client);
   354 
   355 	char buffer[192];
   356 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   357 
   358 	/* Check for an error before printing to the client */
   359 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   360 	{
   361 		return 0;
   362 	}
   363 
   364 	if (!g_HL2.TextMsg(client, HUD_PRINTCENTER, buffer))
   365 	{
   366 		return pContext->ThrowNativeError("Could not send a usermessage");
   367 	}
   368 
   369 	return 1;
   370 }
   371 
   372 static cell_t PrintHintText(IPluginContext *pContext, const cell_t *params)
   373 {
   374 	int client = params[1];
   375 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   376 
   377 	if (!pPlayer)
   378 	{
   379 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   380 	}
   381 
   382 	if (!pPlayer->IsInGame())
   383 	{
   384 		return pContext->ThrowNativeError("Client %d is not in game", client);
   385 	}
   386 
   387 	g_SourceMod.SetGlobalTarget(client);
   388 
   389 	char buffer[192];
   390 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   391 
   392 	/* Check for an error before printing to the client */
   393 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   394 	{
   395 		return 0;
   396 	}
   397 
   398 	if (!g_HL2.HintTextMsg(client, buffer))
   399 	{
   400 		return pContext->ThrowNativeError("Could not send a usermessage");
   401 	}
   402 
   403 	return 1;
   404 }
   405 
   406 static cell_t ShowVGUIPanel(IPluginContext *pContext, const cell_t *params)
   407 {
   408 	HandleError herr;
   409 	char *name;
   410 	KeyValues *pKV = NULL;
   411 	int client = params[1];
   412 	Handle_t hndl = static_cast<Handle_t>(params[3]);
   413 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   414 
   415 	if (!pPlayer)
   416 	{
   417 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   418 	}
   419 
   420 	if (!pPlayer->IsInGame())
   421 	{
   422 		return pContext->ThrowNativeError("Client %d is not in game", client);
   423 	}
   424 
   425 	if (hndl != BAD_HANDLE)
   426 	{
   427 		pKV = g_SourceMod.ReadKeyValuesHandle(hndl, &herr, true);
   428 		if (herr != HandleError_None)
   429 		{
   430 			return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   431 		}
   432 	}
   433 
   434 	pContext->LocalToString(params[2], &name);
   435 
   436 	if (!g_HL2.ShowVGUIMenu(client, name, pKV, (params[4]) ? true : false))
   437 	{
   438 		return pContext->ThrowNativeError("Could not send a usermessage");
   439 	}
   440 
   441 	return 1;
   442 }
   443 
   444 static cell_t smn_IsPlayerAlive(IPluginContext *pContext, const cell_t *params)
   445 {
   446 	CPlayer *player = g_Players.GetPlayerByIndex(params[1]);
   447 	if (player == NULL)
   448 	{
   449 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   450 	}
   451 	else if (!player->IsInGame())
   452 	{
   453 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   454 	}
   455 
   456 	unsigned int state = player->GetLifeState();
   457 
   458 	if (state == PLAYER_LIFE_UNKNOWN)
   459 	{
   460 		return pContext->ThrowNativeError("\"IsPlayerAlive\" not supported by this mod");
   461 	}
   462 	else if (state == PLAYER_LIFE_ALIVE)
   463 	{
   464 		return 1;
   465 	}
   466 	else
   467 	{
   468 		return 0;
   469 	}
   470 }
   471 
   472 static cell_t GuessSDKVersion(IPluginContext *pContext, const cell_t *params)
   473 {
   474 #if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
   475 	int version = g_SMAPI->GetSourceEngineBuild();
   476 
   477 	switch (version)
   478 	{
   479 	case SOURCE_ENGINE_ORIGINAL:
   480 		return 10;
   481 	case SOURCE_ENGINE_EPISODEONE:
   482 		return 20;
   483 
   484 # if defined METAMOD_PLAPI_VERSION
   485 	/* Newer games. */
   486 	case SOURCE_ENGINE_DARKMESSIAH:
   487 		return 15;
   488 	case SOURCE_ENGINE_ORANGEBOX:
   489 		return 30;
   490 	case SOURCE_ENGINE_BLOODYGOODTIME:
   491 		return 32;
   492 	case SOURCE_ENGINE_EYE:
   493 		return 33;
   494 	case SOURCE_ENGINE_CSS:
   495 		return 34;
   496 	case SOURCE_ENGINE_ORANGEBOXVALVE:
   497 		return 35;
   498 	case SOURCE_ENGINE_LEFT4DEAD:
   499 		return 40;
   500 	case SOURCE_ENGINE_LEFT4DEAD2:
   501 		return 50;
   502 	case SOURCE_ENGINE_ALIENSWARM:
   503 		return 60;
   504 	case SOURCE_ENGINE_PORTAL2:
   505 		return 70;
   506 	case SOURCE_ENGINE_CSGO:
   507 		return 80;
   508 	case SOURCE_ENGINE_DOTA:
   509 		return 90;
   510 # endif
   511 	}
   512 #else
   513 	if (g_HL2.IsOriginalEngine())
   514 	{
   515 		return 10;
   516 	}
   517 	else
   518 	{
   519 		return 20;
   520 	}
   521 #endif
   522 
   523 	return 0;
   524 }
   525 
   526 static cell_t IndexToReference(IPluginContext *pContext, const cell_t *params)
   527 {
   528 	if (params[1] >= NUM_ENT_ENTRIES || params[1] < 0)
   529 	{
   530 		return pContext->ThrowNativeError("Invalid entity index %i", params[1]);
   531 	}
   532 
   533 	return g_HL2.IndexToReference(params[1]);
   534 }
   535 
   536 static cell_t ReferenceToIndex(IPluginContext *pContext, const cell_t *params)
   537 {
   538 	return g_HL2.ReferenceToIndex(params[1]);
   539 }
   540 
   541 static cell_t ReferenceToBCompatRef(IPluginContext *pContext, const cell_t *params)
   542 {
   543 	return g_HL2.ReferenceToBCompatRef(params[1]);
   544 }
   545 
   546 REGISTER_NATIVES(halflifeNatives)
   547 {
   548 	{"CreateFakeClient",		CreateFakeClient},
   549 	{"GetCurrentMap",			GetCurrentMap},
   550 	{"GetEngineTime",			GetEngineTime},
   551 	{"GetGameDescription",		GetGameDescription},
   552 	{"GetGameFolderName",		GetGameFolderName},
   553 	{"GetGameTime",				GetGameTime},
   554 	{"GetGameTickCount",		GetGameTickCount},
   555 	{"GetRandomFloat",			GetRandomFloat},
   556 	{"GetRandomInt",			GetRandomInt},
   557 	{"IsDedicatedServer",		IsDedicatedServer},
   558 	{"IsMapValid",				IsMapValid},
   559 	{"SetFakeClientConVar",		SetFakeClientConVar},
   560 	{"SetRandomSeed",			SetRandomSeed},
   561 	{"PrecacheModel",			PrecacheModel},
   562 	{"PrecacheSentenceFile",	PrecacheSentenceFile},
   563 	{"PrecacheDecal",			PrecacheDecal},
   564 	{"PrecacheGeneric",			PrecacheGeneric},
   565 	{"IsModelPrecached",		IsModelPrecached},
   566 	{"IsDecalPrecached",		IsDecalPrecached},
   567 	{"IsGenericPrecached",		IsGenericPrecached},
   568 	{"PrecacheSound",			PrecacheSound},
   569 	{"IsSoundPrecached",		IsSoundPrecached},
   570 	{"CreateDialog",			smn_CreateDialog},
   571 	{"PrintToChat",				PrintToChat},
   572 	{"PrintCenterText",			PrintCenterText},
   573 	{"PrintHintText",			PrintHintText},
   574 	{"ShowVGUIPanel",			ShowVGUIPanel},
   575 	{"IsPlayerAlive",			smn_IsPlayerAlive},
   576 	{"GuessSDKVersion",			GuessSDKVersion},
   577 	{"EntIndexToEntRef",		IndexToReference},
   578 	{"EntRefToEntIndex",		ReferenceToIndex},
   579 	{"MakeCompatEntRef",		ReferenceToBCompatRef},
   580 	{NULL,						NULL},
   581 };