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