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