3 * =============================================================================
5 * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
32 #include "sm_globals.h"
33 #include "sourcemod.h"
34 #include "sourcemm_api.h"
35 #include "PlayerManager.h"
36 #include "HalfLife2.h"
38 static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params)
40 engrandom->SetSeed(params[1]);
45 static cell_t GetRandomFloat(IPluginContext *pContext, const cell_t *params)
47 float fMin = sp_ctof(params[1]);
48 float fMax = sp_ctof(params[2]);
50 float fRandom = engrandom->RandomFloat(fMin, fMax);
52 return sp_ftoc(fRandom);
55 static cell_t GetRandomInt(IPluginContext *pContext, const cell_t *params)
57 return engrandom->RandomInt(params[1], params[2]);
60 static cell_t IsMapValid(IPluginContext *pContext, const cell_t *params)
63 pContext->LocalToString(params[1], &map);
65 return g_HL2.IsMapValid(map);
68 static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params)
70 return engine->IsDedicatedServer();
73 static cell_t GetEngineTime(IPluginContext *pContext, const cell_t *params)
75 #if SOURCE_ENGINE >= SE_NUCLEARDAWN
76 float fTime = Plat_FloatTime();
78 float fTime = engine->Time();
81 return sp_ftoc(fTime);
84 static cell_t GetGameTime(IPluginContext *pContext, const cell_t *params)
86 return sp_ftoc(gpGlobals->curtime);
89 static cell_t GetGameTickCount(IPluginContext *pContext, const cell_t *params)
91 return gpGlobals->tickcount;
94 static cell_t CreateFakeClient(IPluginContext *pContext, const cell_t *params)
96 if (!g_SourceMod.IsMapRunning())
98 return pContext->ThrowNativeError("Cannot create fakeclient when no map is active");
103 pContext->LocalToString(params[1], &netname);
105 #if SOURCE_ENGINE == SE_DOTA
106 int index = engine->CreateFakeClient(netname).Get();
115 edict_t *pEdict = engine->CreateFakeClient(netname);
117 /* :TODO: does the engine fire forwards for us and whatnot? no idea... */
124 return IndexOfEdict(pEdict);
128 static cell_t SetFakeClientConVar(IPluginContext *pContext, const cell_t *params)
130 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
134 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
137 if (!pPlayer->IsConnected())
139 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
142 if (!pPlayer->IsFakeClient())
144 return pContext->ThrowNativeError("Client %d is not a fake client", params[1]);
149 pContext->LocalToString(params[2], &cvar);
150 pContext->LocalToString(params[3], &value);
152 #if SOURCE_ENGINE == SE_DOTA
153 engine->SetFakeClientConVarValue(pPlayer->GetIndex(), cvar, value);
155 engine->SetFakeClientConVarValue(pPlayer->GetEdict(), cvar, value);
161 static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params)
163 const char *description;
167 description = gamedll->GetGameDescription();
169 description = SERVER_CALL(GetGameDescription)();
174 pContext->StringToLocalUTF8(params[1], params[2], description, &numBytes);
179 static cell_t GetGameFolderName(IPluginContext *pContext, const cell_t *params)
181 const char *name = g_SourceMod.GetGameFolderName();
184 pContext->StringToLocalUTF8(params[1], params[2], name, &numBytes);
189 /* Useless comment to bump the build */
190 static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params)
193 pContext->StringToLocalUTF8(params[1], params[2], STRING(gpGlobals->mapname), &bytes);
197 static cell_t PrecacheModel(IPluginContext *pContext, const cell_t *params)
200 pContext->LocalToString(params[1], &model);
202 return engine->PrecacheModel(model, params[2] ? true : false);
205 static cell_t PrecacheSentenceFile(IPluginContext *pContext, const cell_t *params)
208 pContext->LocalToString(params[1], &sentencefile);
210 return engine->PrecacheSentenceFile(sentencefile, params[2] ? true : false);
213 static cell_t PrecacheDecal(IPluginContext *pContext, const cell_t *params)
216 pContext->LocalToString(params[1], &decal);
218 return engine->PrecacheDecal(decal, params[2] ? true : false);
221 static cell_t PrecacheGeneric(IPluginContext *pContext, const cell_t *params)
224 pContext->LocalToString(params[1], &generic);
226 return engine->PrecacheGeneric(generic, params[2] ? true : false);
229 static cell_t IsModelPrecached(IPluginContext *pContext, const cell_t *params)
232 pContext->LocalToString(params[1], &model);
234 return engine->IsModelPrecached(model) ? 1 : 0;
237 static cell_t IsDecalPrecached(IPluginContext *pContext, const cell_t *params)
240 pContext->LocalToString(params[1], &decal);
242 return engine->IsDecalPrecached(decal) ? 1 : 0;
245 static cell_t IsGenericPrecached(IPluginContext *pContext, const cell_t *params)
248 pContext->LocalToString(params[1], &generic);
250 return engine->IsGenericPrecached(generic) ? 1 : 0;
253 static cell_t PrecacheSound(IPluginContext *pContext, const cell_t *params)
256 pContext->LocalToString(params[1], &sample);
258 return enginesound->PrecacheSound(sample, params[2] ? true : false) ? 1 : 0;
261 static cell_t IsSoundPrecached(IPluginContext *pContext, const cell_t *params)
264 pContext->LocalToString(params[1], &sample);
266 return enginesound->IsSoundPrecached(sample) ? 1 : 0;
269 static cell_t smn_CreateDialog(IPluginContext *pContext, const cell_t *params)
271 #if SOURCE_ENGINE == SE_DOTA
272 return pContext->ThrowNativeError("CreateDialog is not supported on this game");
276 Handle_t hndl = static_cast<Handle_t>(params[2]);
277 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
281 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
284 if (!pPlayer->IsInGame())
286 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
289 pKV = g_SourceMod.ReadKeyValuesHandle(hndl, &herr, true);
290 if (herr != HandleError_None)
292 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
295 serverpluginhelpers->CreateMessage(pPlayer->GetEdict(),
296 static_cast<DIALOG_TYPE>(params[3]),
304 static cell_t PrintToChat(IPluginContext *pContext, const cell_t *params)
306 int client = params[1];
307 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
311 return pContext->ThrowNativeError("Client index %d is invalid", client);
314 if (!pPlayer->IsInGame())
316 return pContext->ThrowNativeError("Client %d is not in game", client);
319 g_SourceMod.SetGlobalTarget(client);
322 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
324 /* Check for an error before printing to the client */
325 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
330 if (!g_HL2.TextMsg(client, HUD_PRINTTALK, buffer))
332 return pContext->ThrowNativeError("Could not send a usermessage");
338 static cell_t PrintCenterText(IPluginContext *pContext, const cell_t *params)
340 int client = params[1];
341 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
345 return pContext->ThrowNativeError("Client index %d is invalid", client);
348 if (!pPlayer->IsInGame())
350 return pContext->ThrowNativeError("Client %d is not in game", client);
353 g_SourceMod.SetGlobalTarget(client);
356 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
358 /* Check for an error before printing to the client */
359 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
364 if (!g_HL2.TextMsg(client, HUD_PRINTCENTER, buffer))
366 return pContext->ThrowNativeError("Could not send a usermessage");
372 static cell_t PrintHintText(IPluginContext *pContext, const cell_t *params)
374 int client = params[1];
375 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
379 return pContext->ThrowNativeError("Client index %d is invalid", client);
382 if (!pPlayer->IsInGame())
384 return pContext->ThrowNativeError("Client %d is not in game", client);
387 g_SourceMod.SetGlobalTarget(client);
390 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
392 /* Check for an error before printing to the client */
393 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
398 if (!g_HL2.HintTextMsg(client, buffer))
400 return pContext->ThrowNativeError("Could not send a usermessage");
406 static cell_t ShowVGUIPanel(IPluginContext *pContext, const cell_t *params)
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);
417 return pContext->ThrowNativeError("Client index %d is invalid", client);
420 if (!pPlayer->IsInGame())
422 return pContext->ThrowNativeError("Client %d is not in game", client);
425 if (hndl != BAD_HANDLE)
427 pKV = g_SourceMod.ReadKeyValuesHandle(hndl, &herr, true);
428 if (herr != HandleError_None)
430 return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
434 pContext->LocalToString(params[2], &name);
436 if (!g_HL2.ShowVGUIMenu(client, name, pKV, (params[4]) ? true : false))
438 return pContext->ThrowNativeError("Could not send a usermessage");
444 static cell_t smn_IsPlayerAlive(IPluginContext *pContext, const cell_t *params)
446 CPlayer *player = g_Players.GetPlayerByIndex(params[1]);
449 return pContext->ThrowNativeError("Invalid client index %d", params[1]);
451 else if (!player->IsInGame())
453 return pContext->ThrowNativeError("Client %d is not in game", params[1]);
456 unsigned int state = player->GetLifeState();
458 if (state == PLAYER_LIFE_UNKNOWN)
460 return pContext->ThrowNativeError("\"IsPlayerAlive\" not supported by this mod");
462 else if (state == PLAYER_LIFE_ALIVE)
472 static cell_t GuessSDKVersion(IPluginContext *pContext, const cell_t *params)
474 #if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
475 int version = g_SMAPI->GetSourceEngineBuild();
479 case SOURCE_ENGINE_ORIGINAL:
481 case SOURCE_ENGINE_EPISODEONE:
484 # if defined METAMOD_PLAPI_VERSION
486 case SOURCE_ENGINE_DARKMESSIAH:
488 case SOURCE_ENGINE_ORANGEBOX:
490 case SOURCE_ENGINE_BLOODYGOODTIME:
492 case SOURCE_ENGINE_EYE:
494 case SOURCE_ENGINE_CSS:
496 case SOURCE_ENGINE_ORANGEBOXVALVE_DEPRECATED:
497 case SOURCE_ENGINE_HL2DM:
498 case SOURCE_ENGINE_DODS:
499 case SOURCE_ENGINE_TF2:
501 case SOURCE_ENGINE_LEFT4DEAD:
503 case SOURCE_ENGINE_NUCLEARDAWN:
504 case SOURCE_ENGINE_LEFT4DEAD2:
506 case SOURCE_ENGINE_ALIENSWARM:
508 case SOURCE_ENGINE_PORTAL2:
510 case SOURCE_ENGINE_CSGO:
512 case SOURCE_ENGINE_DOTA:
517 if (g_HL2.IsOriginalEngine())
530 static cell_t GetEngineVersion(IPluginContext *pContext, const cell_t *params)
532 return g_SMAPI->GetSourceEngineBuild();
535 static cell_t IndexToReference(IPluginContext *pContext, const cell_t *params)
537 if (params[1] >= NUM_ENT_ENTRIES || params[1] < 0)
539 return pContext->ThrowNativeError("Invalid entity index %i", params[1]);
542 return g_HL2.IndexToReference(params[1]);
545 static cell_t ReferenceToIndex(IPluginContext *pContext, const cell_t *params)
547 return g_HL2.ReferenceToIndex(params[1]);
550 static cell_t ReferenceToBCompatRef(IPluginContext *pContext, const cell_t *params)
552 return g_HL2.ReferenceToBCompatRef(params[1]);
555 REGISTER_NATIVES(halflifeNatives)
557 {"CreateFakeClient", CreateFakeClient},
558 {"GetCurrentMap", GetCurrentMap},
559 {"GetEngineTime", GetEngineTime},
560 {"GetGameDescription", GetGameDescription},
561 {"GetGameFolderName", GetGameFolderName},
562 {"GetGameTime", GetGameTime},
563 {"GetGameTickCount", GetGameTickCount},
564 {"GetRandomFloat", GetRandomFloat},
565 {"GetRandomInt", GetRandomInt},
566 {"IsDedicatedServer", IsDedicatedServer},
567 {"IsMapValid", IsMapValid},
568 {"SetFakeClientConVar", SetFakeClientConVar},
569 {"SetRandomSeed", SetRandomSeed},
570 {"PrecacheModel", PrecacheModel},
571 {"PrecacheSentenceFile", PrecacheSentenceFile},
572 {"PrecacheDecal", PrecacheDecal},
573 {"PrecacheGeneric", PrecacheGeneric},
574 {"IsModelPrecached", IsModelPrecached},
575 {"IsDecalPrecached", IsDecalPrecached},
576 {"IsGenericPrecached", IsGenericPrecached},
577 {"PrecacheSound", PrecacheSound},
578 {"IsSoundPrecached", IsSoundPrecached},
579 {"CreateDialog", smn_CreateDialog},
580 {"PrintToChat", PrintToChat},
581 {"PrintCenterText", PrintCenterText},
582 {"PrintHintText", PrintHintText},
583 {"ShowVGUIPanel", ShowVGUIPanel},
584 {"IsPlayerAlive", smn_IsPlayerAlive},
585 {"GuessSDKVersion", GuessSDKVersion},
586 {"GetEngineVersion", GetEngineVersion},
587 {"EntIndexToEntRef", IndexToReference},
588 {"EntRefToEntIndex", ReferenceToIndex},
589 {"MakeCompatEntRef", ReferenceToBCompatRef},