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