core/smn_entities.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4266 b6060fd93236
permissions -rw-r--r--
Update CS:GO team score gamedata.
     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 #include <IGameConfigs.h>
    38 #include "sm_stringutil.h"
    39 #include "logic_bridge.h"
    40 
    41 // These values need to mirror the values in entity_prop_stocks
    42 #define ENTFLAG_ONGROUND		(1 << 0)
    43 #define ENTFLAG_DUCKING			(1 << 1)
    44 #define ENTFLAG_WATERJUMP		(1 << 2)
    45 #define ENTFLAG_ONTRAIN			(1 << 3)
    46 #define ENTFLAG_INRAIN			(1 << 4)
    47 #define ENTFLAG_FROZEN			(1 << 5)
    48 #define ENTFLAG_ATCONTROLS		(1 << 6)
    49 #define ENTFLAG_CLIENT			(1 << 7)
    50 #define ENTFLAG_FAKECLIENT		(1 << 8)
    51 #define ENTFLAG_INWATER			(1 << 9)
    52 #define ENTFLAG_FLY				(1 << 10)
    53 #define ENTFLAG_SWIM			(1 << 11)
    54 #define ENTFLAG_CONVEYOR		(1 << 12)
    55 #define ENTFLAG_NPC				(1 << 13)
    56 #define ENTFLAG_GODMODE			(1 << 14)
    57 #define ENTFLAG_NOTARGET		(1 << 15)
    58 #define ENTFLAG_AIMTARGET		(1 << 16)
    59 #define ENTFLAG_PARTIALGROUND	(1 << 17)
    60 #define ENTFLAG_STATICPROP		(1 << 18)
    61 #define ENTFLAG_GRAPHED			(1 << 19)
    62 #define ENTFLAG_GRENADE			(1 << 20)
    63 #define ENTFLAG_STEPMOVEMENT	(1 << 21)
    64 #define ENTFLAG_DONTTOUCH		(1 << 22)
    65 #define ENTFLAG_BASEVELOCITY	(1 << 23)
    66 #define ENTFLAG_WORLDBRUSH		(1 << 24)
    67 #define ENTFLAG_OBJECT			(1 << 25)
    68 #define ENTFLAG_KILLME			(1 << 26)
    69 #define ENTFLAG_ONFIRE			(1 << 27)
    70 #define ENTFLAG_DISSOLVING		(1 << 28)
    71 #define ENTFLAG_TRANSRAGDOLL	(1 << 29)
    72 #define ENTFLAG_UNBLOCKABLE_BY_PLAYER	(1 << 30)
    73 #define ENTFLAG_FREEZING		(1 << 31)
    74 #define ENTFLAG_EP2V_UNKNOWN1	(1 << 31)
    75 
    76 // Not defined in the sdk as we have no clue what it is
    77 #define FL_EP2V_UNKNOWN			(1 << 2)
    78 
    79 enum PropType
    80 {
    81 	Prop_Send = 0,
    82 	Prop_Data
    83 };
    84 
    85 enum PropFieldType
    86 {
    87 	PropField_Unsupported,		/**< The type is unsupported. */
    88 	PropField_Integer,			/**< Valid for SendProp and Data fields */
    89 	PropField_Float,			/**< Valid for SendProp and Data fields */
    90 	PropField_Entity,			/**< Valid for Data fields only (SendProp shows as int) */
    91 	PropField_Vector,			/**< Valid for SendProp and Data fields */
    92 	PropField_String,			/**< Valid for SendProp and Data fields */
    93 	PropField_String_T,			/**< Valid for Data fields.  Read only! */
    94 };
    95 
    96 inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
    97 {
    98 	IServerUnknown *pUnk = (IServerUnknown *)pEntity;
    99 	IServerNetworkable *pNet = pUnk->GetNetworkable();
   100 
   101 	if (!pNet)
   102 	{
   103 		return NULL;
   104 	}
   105 
   106 	return pNet->GetEdict();
   107 }
   108 
   109 inline edict_t *GetEdict(cell_t num)
   110 {
   111 	edict_t *pEdict;
   112 	if (!IndexToAThings(num, NULL, &pEdict))
   113 	{
   114 		return NULL;
   115 	}
   116 	
   117 	return pEdict;
   118 }
   119 
   120 inline CBaseEntity *GetEntity(cell_t num)
   121 {
   122 	CBaseEntity *pEntity;
   123 	if (!IndexToAThings(num, &pEntity, NULL))
   124 	{
   125 		return NULL;
   126 	}
   127 
   128 	return pEntity;
   129 }
   130 
   131 /* Given an entity reference or index, fill out a CBaseEntity and/or edict.
   132    If lookup is successful, returns true and writes back the two parameters.
   133    If lookup fails, returns false and doesn't touch the params.  */
   134 bool IndexToAThings(cell_t num, CBaseEntity **pEntData, edict_t **pEdictData)
   135 {
   136 	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
   137 
   138 	if (!pEntity)
   139 	{
   140 		return false;
   141 	}
   142 
   143 	int index = g_HL2.ReferenceToIndex(num);
   144 	if (index > 0 && index <= g_Players.GetMaxClients())
   145 	{
   146 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   147 		if (!pPlayer || !pPlayer->IsConnected())
   148 		{
   149 			return false;
   150 		}
   151 	}
   152 
   153 	if (pEntData)
   154 	{
   155 		*pEntData = pEntity;
   156 	}
   157 
   158 	if (pEdictData)
   159 	{
   160 		edict_t *pEdict = ::BaseEntityToEdict(pEntity);
   161 		if (!pEdict || pEdict->IsFree())
   162 		{
   163 			pEdict = NULL;
   164 		}
   165 
   166 		*pEdictData = pEdict;
   167 	}
   168 
   169 	return true;
   170 }
   171 /*
   172   <predcrab> AThings is like guaranteed r+ by dvander though
   173   <predcrab> he wont even read the rest of the patch to nit stuff
   174   <Fyren> Like I wasn't going to r? you anyway!
   175   <predcrab> he still sees!
   176   <predcrab> he's everywhere
   177 */
   178 
   179 class VEmptyClass {};
   180 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
   181 {
   182 	void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
   183 	void **vtable = *reinterpret_cast<void ***>(pThisPtr);
   184 	void *vfunc = vtable[offset];
   185 
   186 	union
   187 	{
   188 		datamap_t *(VEmptyClass::*mfpnew)();
   189 #ifndef PLATFORM_POSIX
   190 		void *addr;
   191 	} u;
   192 	u.addr = vfunc;
   193 #else
   194 		struct  
   195 		{
   196 			void *addr;
   197 			intptr_t adjustor;
   198 		} s;
   199 	} u;
   200 	u.s.addr = vfunc;
   201 	u.s.adjustor = 0;
   202 #endif
   203 
   204 	return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
   205 }
   206 
   207 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
   208 {
   209 	int offset;
   210 
   211 	if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
   212 	{
   213 		return NULL;
   214 	}
   215 
   216 	return VGetDataDescMap(pEntity, offset);
   217 }
   218 
   219 /* :TODO: Move this! */
   220 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
   221 {
   222 	return CBaseEntity_GetDataDescMap(pEntity);
   223 }
   224 
   225 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
   226 {
   227 	return gpGlobals->maxEntities;
   228 }
   229 
   230 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
   231 {
   232 	edict_t *pEdict = engine->CreateEdict();
   233 
   234 	if (!pEdict)
   235 	{
   236 		return 0;
   237 	}
   238 
   239 	return IndexOfEdict(pEdict);
   240 }
   241 
   242 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
   243 {
   244 	edict_t *pEdict = GetEdict(params[1]);
   245 
   246 	if (!pEdict)
   247 	{
   248 		return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
   249 	}
   250 
   251 	engine->RemoveEdict(pEdict);
   252 
   253 	return 1;
   254 }
   255 
   256 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
   257 {
   258 	edict_t *pEdict = GetEdict(params[1]);
   259 
   260 	if (!pEdict)
   261 	{
   262 		return 0;
   263 	}
   264 
   265 	/* Shouldn't be necessary... not sure though */
   266 	return pEdict->IsFree() ? 0 : 1;
   267 }
   268 
   269 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
   270 {
   271 	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
   272 
   273 	return (pEntity != NULL) ? 1 : 0;
   274 }
   275 
   276 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
   277 {
   278 	edict_t *pEdict = GetEdict(params[1]);
   279 
   280 	if (!pEdict)
   281 	{
   282 		return 0;
   283 	}
   284 
   285 	return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
   286 }
   287 
   288 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
   289 {
   290 	return engine->GetEntityCount();
   291 }
   292 
   293 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
   294 {
   295 	edict_t *pEdict = GetEdict(params[1]);
   296 
   297 	if (!pEdict)
   298 	{
   299 		return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   300 	}
   301 
   302 	return pEdict->m_fStateFlags;
   303 }
   304 
   305 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
   306 {
   307 	edict_t *pEdict = GetEdict(params[1]);
   308 
   309 	if (!pEdict)
   310 	{
   311 		return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   312 	}
   313 
   314 	pEdict->m_fStateFlags = params[2];
   315 
   316 	return 1;
   317 }
   318 
   319 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
   320 {
   321 	edict_t *pEdict = GetEdict(params[1]);
   322 
   323 	if (!pEdict)
   324 	{
   325 		return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   326 	}
   327 
   328 	const char *cls = g_HL2.GetEntityClassname(pEdict);
   329 
   330 	if (!cls || cls[0] == '\0')
   331 	{
   332 		return 0;
   333 	}
   334 
   335 	pContext->StringToLocal(params[2], params[3], cls);
   336 
   337 	return 1;
   338 }
   339 
   340 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
   341 {
   342 	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
   343 
   344 	IServerUnknown *pUnk = (IServerUnknown *)pEntity;
   345 
   346 	if (!pEntity)
   347 	{
   348 		return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   349 	}
   350 
   351 	IServerNetworkable *pNet = pUnk->GetNetworkable();
   352 	if (!pNet)
   353 	{
   354 		return 0;
   355 	}
   356 
   357 	ServerClass *pClass = pNet->GetServerClass();
   358 
   359 	pContext->StringToLocal(params[2], params[3], pClass->GetName());
   360 
   361 	return 1;
   362 }
   363 
   364 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
   365 {
   366 	CBaseEntity *pEntity = GetEntity(params[1]);
   367 
   368 	if (!pEntity)
   369 	{
   370 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   371 	}
   372 
   373 	int offset = params[2];
   374 	if (offset <= 0 || offset > 32768)
   375 	{
   376 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   377 	}
   378 
   379 	switch (params[3])
   380 	{
   381 	case 4:
   382 		return *(int *)((uint8_t *)pEntity + offset);
   383 	case 2:
   384 		return *(short *)((uint8_t *)pEntity + offset);
   385 	case 1:
   386 		return *((uint8_t *)pEntity + offset);
   387 	default:
   388 		return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
   389 	}
   390 }
   391 
   392 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
   393 {
   394 	CBaseEntity *pEntity;
   395 	edict_t *pEdict;
   396 
   397 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
   398 	{
   399 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   400 	}
   401 
   402 	int offset = params[2];
   403 	if (offset <= 0 || offset > 32768)
   404 	{
   405 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   406 	}
   407 
   408 	if (params[5] && (pEdict != NULL))
   409 	{
   410 		g_HL2.SetEdictStateChanged(pEdict, offset);
   411 	}
   412 
   413 	switch (params[4])
   414 	{
   415 	case 4:
   416 		{
   417 			*(int *)((uint8_t *)pEntity + offset) = params[3];
   418 			break;
   419 		}
   420 	case 2:
   421 		{
   422 			*(short *)((uint8_t *)pEntity + offset) = params[3];
   423 			break;
   424 		}
   425 	case 1:
   426 		{
   427 			*((uint8_t *)pEntity + offset) = params[3];
   428 			break;
   429 		}
   430 	default:
   431 		return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
   432 	}
   433 
   434 	return 1;
   435 }
   436 
   437 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   438 {
   439 	CBaseEntity *pEntity = GetEntity(params[1]);
   440 
   441 	if (!pEntity)
   442 	{
   443 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   444 	}
   445 
   446 	int offset = params[2];
   447 	if (offset <= 0 || offset > 32768)
   448 	{
   449 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   450 	}
   451 
   452 	float f = *(float *)((uint8_t *)pEntity + offset);
   453 
   454 	return sp_ftoc(f);
   455 }
   456 
   457 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   458 {
   459 	CBaseEntity *pEntity;
   460 	edict_t *pEdict;
   461 
   462 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
   463 	{
   464 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   465 	}
   466 
   467 	int offset = params[2];
   468 	if (offset <= 0 || offset > 32768)
   469 	{
   470 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   471 	}
   472 
   473 	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
   474 
   475 	if (params[4] && (pEdict != NULL))
   476 	{
   477 		g_HL2.SetEdictStateChanged(pEdict, offset);
   478 	}
   479 
   480 	return 1;
   481 }
   482 
   483 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
   484 {
   485 	CBaseEntity *pEntity = GetEntity(params[1]);
   486 
   487 	if (!pEntity)
   488 	{
   489 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   490 	}
   491 
   492 	int offset = params[2];
   493 	if (offset <= 0 || offset > 32768)
   494 	{
   495 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   496 	}
   497 
   498 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
   499 
   500 	cell_t *vec;
   501 	pContext->LocalToPhysAddr(params[3], &vec);
   502 
   503 	vec[0] = sp_ftoc(v->x);
   504 	vec[1] = sp_ftoc(v->y);
   505 	vec[2] = sp_ftoc(v->z);
   506 
   507 	return 1;
   508 }
   509 
   510 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
   511 {
   512 	CBaseEntity *pEntity;
   513 	edict_t *pEdict;
   514 
   515 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
   516 	{
   517 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   518 	}
   519 
   520 	int offset = params[2];
   521 	if (offset <= 0 || offset > 32768)
   522 	{
   523 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   524 	}
   525 
   526 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
   527 
   528 	cell_t *vec;
   529 	pContext->LocalToPhysAddr(params[3], &vec);
   530 
   531 	v->x = sp_ctof(vec[0]);
   532 	v->y = sp_ctof(vec[1]);
   533 	v->z = sp_ctof(vec[2]);
   534 
   535 	if (params[4] && (pEdict != NULL))
   536 	{
   537 		g_HL2.SetEdictStateChanged(pEdict, offset);
   538 	}
   539 
   540 	return 1;
   541 }
   542 
   543 /* THIS GUY IS DEPRECATED. */
   544 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
   545 {
   546 	CBaseEntity *pEntity = GetEntity(params[1]);
   547 
   548 	if (!pEntity)
   549 	{
   550 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   551 	}
   552 
   553 	int offset = params[2];
   554 	if (offset <= 0 || offset > 32768)
   555 	{
   556 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   557 	}
   558 
   559 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   560 
   561 	if (!hndl.IsValid())
   562 	{
   563 		return 0;
   564 	}
   565 
   566 	int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
   567 	return g_HL2.ReferenceToBCompatRef(ref);
   568 }
   569 
   570 int CheckBaseHandle(CBaseHandle &hndl)
   571 {
   572 	if (!hndl.IsValid())
   573 	{
   574 		return -1;
   575 	}
   576 
   577 	int index = hndl.GetEntryIndex();
   578 
   579 	edict_t *pStoredEdict;
   580 	CBaseEntity *pStoredEntity;
   581 
   582 	if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict))
   583 	{
   584 		return -1;
   585 	}
   586 
   587 	if (pStoredEdict == NULL || pStoredEntity == NULL)
   588 	{
   589 		return -1;
   590 	}
   591 
   592 	IServerEntity *pSE = pStoredEdict->GetIServerEntity();
   593 
   594 	if (pSE == NULL)
   595 	{
   596 		return -1;
   597 	}
   598 
   599 	if (pSE->GetRefEHandle() != hndl)
   600 	{
   601 		return -1;
   602 	}
   603 
   604 	return index;
   605 }
   606 
   607 static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
   608 {
   609 	CBaseEntity *pEntity = GetEntity(params[1]);
   610 
   611 	if (pEntity == NULL)
   612 	{
   613 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   614 	}
   615 
   616 	int offset = params[2];
   617 	if (offset <= 0 || offset > 32768)
   618 	{
   619 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   620 	}
   621 
   622 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   623 	CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex());
   624 
   625 	if (!pHandleEntity || hndl != reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
   626 		return -1;
   627 
   628 	return g_HL2.EntityToBCompatRef(pHandleEntity);
   629 }
   630 
   631 /* THIS GUY IS DEPRECATED. */
   632 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
   633 {
   634 	CBaseEntity *pEntity;
   635 	edict_t *pEdict;
   636 
   637 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
   638 	{
   639 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   640 	}
   641 
   642 	int offset = params[2];
   643 	if (offset <= 0 || offset > 32768)
   644 	{
   645 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   646 	}
   647 
   648 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   649 
   650 	if (params[3] == 0 || (unsigned)params[3] == INVALID_EHANDLE_INDEX)
   651 	{
   652 		hndl.Set(NULL);
   653 	} else {
   654 		CBaseEntity *pOther = GetEntity(params[3]);
   655 
   656 		if (!pOther)
   657 		{
   658 			return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
   659 		}
   660 
   661 		IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
   662 		hndl.Set(pHandleEnt);
   663 	}
   664 
   665 	if (params[4] && (pEdict != NULL))
   666 	{
   667 		g_HL2.SetEdictStateChanged(pEdict, offset);
   668 	}
   669 
   670 	return 1;
   671 }
   672 
   673 static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
   674 {
   675 	CBaseEntity *pEntity;
   676 	edict_t *pEdict;
   677 
   678 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
   679 	{
   680 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   681 	}
   682 
   683 	int offset = params[2];
   684 	if (offset <= 0 || offset > 32768)
   685 	{
   686 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   687 	}
   688 
   689 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   690 
   691 	if ((unsigned)params[3] == INVALID_EHANDLE_INDEX)
   692 	{
   693 		hndl.Set(NULL);
   694 	}
   695 	else
   696 	{
   697 		CBaseEntity *pOther = GetEntity(params[3]);
   698 
   699 		if (!pOther)
   700 		{
   701 			return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
   702 		}
   703 
   704 		IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
   705 		hndl.Set(pHandleEnt);
   706 	}
   707 
   708 	if (params[4] && (pEdict != NULL))
   709 	{
   710 		g_HL2.SetEdictStateChanged(pEdict, offset);
   711 	}
   712 
   713 	return 1;
   714 }
   715 
   716 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
   717 {
   718 	edict_t *pEdict = GetEdict(params[1]);
   719 
   720 	if (!pEdict)
   721 	{
   722 		return pContext->ThrowNativeError("Edict %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   723 	}
   724 
   725 	g_HL2.SetEdictStateChanged(pEdict, params[2]);
   726 
   727 	return 1;
   728 }
   729 
   730 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
   731 {
   732 	char *cls, *prop;
   733 	pContext->LocalToString(params[1], &cls);
   734 	pContext->LocalToString(params[2], &prop);
   735 
   736 	SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
   737 
   738 	if (!pSend)
   739 	{
   740 		return -1;
   741 	}
   742 
   743 	return pSend->GetOffset();
   744 }
   745 
   746 static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
   747 {
   748 	char *cls, *prop;
   749 	sm_sendprop_info_t info;
   750 	cell_t *pType, *pBits, *pLocal;
   751 
   752 	pContext->LocalToString(params[1], &cls);
   753 	pContext->LocalToString(params[2], &prop);
   754 
   755 	if (!g_HL2.FindSendPropInfo(cls, prop, &info))
   756 	{
   757 		return -1;
   758 	}
   759 
   760 	pContext->LocalToPhysAddr(params[3], &pType);
   761 	pContext->LocalToPhysAddr(params[4], &pBits);
   762 	pContext->LocalToPhysAddr(params[5], &pLocal);
   763 
   764 	switch (info.prop->GetType())
   765 	{
   766 	case DPT_Int:
   767 		{
   768 			*pType = PropField_Integer;
   769 			break;
   770 		}
   771 	case DPT_Float:
   772 		{
   773 			*pType = PropField_Float;
   774 			break;
   775 		}
   776 	case DPT_String:
   777 		{
   778 			*pType = PropField_String;
   779 			break;
   780 		}
   781 	case DPT_Vector:
   782 		{
   783 			*pType = PropField_Vector;
   784 			break;
   785 		}
   786 	default:
   787 		{
   788 			*pType = PropField_Unsupported;
   789 			break;
   790 		}
   791 	}
   792 
   793 	*pBits = info.prop->m_nBits;
   794 	*pLocal = info.prop->GetOffset();
   795 
   796 	return info.actual_offset;
   797 }
   798 
   799 static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * pType)
   800 {
   801 	switch (td->fieldType)
   802 	{
   803 	case FIELD_TICK:
   804 	case FIELD_MODELINDEX:
   805 	case FIELD_MATERIALINDEX:
   806 	case FIELD_INTEGER:
   807 	case FIELD_COLOR32:
   808 		{
   809 			*pType = PropField_Integer;
   810 			*pSize = 32;
   811 			break;
   812 		}
   813 	case FIELD_VECTOR:
   814 	case FIELD_POSITION_VECTOR:
   815 		{
   816 			*pType = PropField_Vector;
   817 			*pSize = 12;
   818 			break;
   819 		}
   820 	case FIELD_SHORT:
   821 		{
   822 			*pType = PropField_Integer;
   823 			*pSize = 16;
   824 			break;
   825 		}
   826 	case FIELD_BOOLEAN:
   827 		{
   828 			*pType = PropField_Integer;
   829 			*pSize = 1;
   830 			break;
   831 		}
   832 	case FIELD_CHARACTER:
   833 		{
   834 			if (td->fieldSize == 1)
   835 			{
   836 				*pType = PropField_Integer;
   837 				*pSize = 8;
   838 			}
   839 			else
   840 			{
   841 				*pType = PropField_String;
   842 				*pSize = 8 * td->fieldSize;
   843 			}
   844 			break;
   845 		}
   846 	case FIELD_MODELNAME:
   847 	case FIELD_SOUNDNAME:
   848 	case FIELD_STRING:
   849 		{
   850 			*pSize = sizeof(string_t);
   851 			*pType = PropField_String_T;
   852 			break;
   853 		}
   854 	case FIELD_FLOAT:
   855 	case FIELD_TIME:
   856 		{
   857 			*pType = PropField_Float;
   858 			*pSize = 32;
   859 			break;
   860 		}
   861 	case FIELD_EHANDLE:
   862 		{
   863 			*pType = PropField_Entity;
   864 			*pSize = 32;
   865 			break;
   866 		}
   867 	default:
   868 		{
   869 			*pType = PropField_Unsupported;
   870 			*pSize = 0;
   871 		}
   872 	}
   873 }
   874 
   875 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
   876 {
   877 	CBaseEntity *pEntity;
   878 	datamap_t *pMap;
   879 	typedescription_t *td;
   880 	char *offset;
   881 	pEntity = GetEntity(params[1]);
   882 
   883 	if (!pEntity)
   884 	{
   885 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   886 	}
   887 
   888 	if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   889 	{
   890 		return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
   891 	}
   892 
   893 	pContext->LocalToString(params[2], &offset);
   894 	sm_datatable_info_t info;
   895 	if (!g_HL2.FindDataMapInfo(pMap, offset, &info))
   896 	{
   897 		return -1;
   898 	}
   899 	
   900 	td = info.prop;
   901 
   902 	if (params[0] == 4)
   903 	{
   904 		cell_t *pType, *pSize;
   905 
   906 		pContext->LocalToPhysAddr(params[3], &pType);
   907 		pContext->LocalToPhysAddr(params[4], &pSize);
   908 		
   909 		GuessDataPropTypes(td, pSize, pType);
   910 	}
   911 
   912 	return GetTypeDescOffs(td);
   913 }
   914 
   915 static cell_t FindDataMapInfo(IPluginContext *pContext, const cell_t *params)
   916 {
   917 	CBaseEntity *pEntity;
   918 	datamap_t *pMap;
   919 	typedescription_t *td;
   920 	char *offset;
   921 	pEntity = GetEntity(params[1]);
   922 
   923 	if (!pEntity)
   924 	{
   925 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   926 	}
   927 
   928 	if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   929 	{
   930 		return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
   931 	}
   932 
   933 	pContext->LocalToString(params[2], &offset);
   934 	sm_datatable_info_t info;
   935 	if (!g_HL2.FindDataMapInfo(pMap, offset, &info))
   936 	{
   937 		return -1;
   938 	}
   939 	
   940 	td = info.prop;
   941 
   942 	if (params[0] >= 4)
   943 	{
   944 		cell_t *pType, *pSize;
   945 
   946 		pContext->LocalToPhysAddr(params[3], &pType);
   947 		pContext->LocalToPhysAddr(params[4], &pSize);
   948 		
   949 		GuessDataPropTypes(td, pSize, pType);
   950 		
   951 		if (params[0] == 5)
   952 		{
   953 			cell_t *pLocalOffs;
   954 			
   955 			pContext->LocalToPhysAddr(params[5], &pLocalOffs);
   956 			
   957 			*pLocalOffs = GetTypeDescOffs(info.prop);
   958 		}
   959 	}
   960 
   961 	return info.actual_offset;
   962 }
   963 
   964 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
   965 {
   966 	CBaseEntity *pEntity = GetEntity(params[1]);
   967 
   968 	if (!pEntity)
   969 	{
   970 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   971 	}
   972 
   973 	int offset = params[2];
   974 	if (offset < 0 || offset > 32768)
   975 	{
   976 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   977 	}
   978 
   979 	size_t len;
   980 	char *src = (char *)((uint8_t *)pEntity + offset);
   981 	pContext->StringToLocalUTF8(params[3], params[4], src, &len);
   982 
   983 	return len;
   984 }
   985 
   986 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
   987 {
   988 	CBaseEntity *pEntity;
   989 	edict_t *pEdict;
   990 
   991 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
   992 	{
   993 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   994 	}
   995 
   996 	int offset = params[2];
   997 	if (offset < 0 || offset > 32768)
   998 	{
   999 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
  1000 	}
  1001 
  1002 	char *src;
  1003 	char *dest = (char *)((uint8_t *)pEntity + offset);
  1004 
  1005 	pContext->LocalToString(params[3], &src);
  1006 	size_t len = strncopy(dest, src, params[4]);
  1007 
  1008 	if (params[5] && (pEdict != NULL))
  1009 	{
  1010 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1011 	}
  1012 
  1013 	return len;
  1014 }
  1015 
  1016 #define FIND_PROP_DATA(td) \
  1017 	datamap_t *pMap; \
  1018 	if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
  1019 	{ \
  1020 		return pContext->ThrowNativeError("Could not retrieve datamap"); \
  1021 	} \
  1022 	sm_datatable_info_t info; \
  1023 	if (!g_HL2.FindDataMapInfo(pMap, prop, &info)) \
  1024 	{ \
  1025 		const char *class_name = g_HL2.GetEntityClassname(pEntity); \
  1026 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
  1027 			prop, \
  1028 			params[1], \
  1029 			((class_name) ? class_name : "")); \
  1030 	} \
  1031 	td = info.prop;
  1032 
  1033 #define CHECK_SET_PROP_DATA_OFFSET() \
  1034 	if (element < 0 || element >= td->fieldSize) \
  1035 	{ \
  1036 		return pContext->ThrowNativeError("Element %d is out of bounds (Prop %s has %d elements).", \
  1037 			element, \
  1038 			prop, \
  1039 			td->fieldSize); \
  1040 	} \
  1041 	\
  1042 	offset = info.actual_offset + (element * (td->fieldSizeInBytes / td->fieldSize));
  1043 
  1044 #define FIND_PROP_SEND(type, type_name) \
  1045 	sm_sendprop_info_t info;\
  1046 	SendProp *pProp; \
  1047 	IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
  1048 	IServerNetworkable *pNet = pUnk->GetNetworkable(); \
  1049 	if (!pNet) \
  1050 	{ \
  1051 		return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
  1052 	} \
  1053 	if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) \
  1054 	{ \
  1055 		const char *class_name = g_HL2.GetEntityClassname(pEntity); \
  1056 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
  1057 			prop, \
  1058 			params[1], \
  1059 			((class_name) ? class_name : "")); \
  1060 	} \
  1061 	\
  1062 	offset = info.actual_offset; \
  1063 	pProp = info.prop; \
  1064 	bit_count = pProp->m_nBits; \
  1065 	\
  1066 	switch (pProp->GetType()) \
  1067 	{ \
  1068 	case type: \
  1069 		{ \
  1070 			if (element != 0) \
  1071 			{ \
  1072 				return pContext->ThrowNativeError("SendProp %s is not an array. Element %d is invalid.", \
  1073 					prop, \
  1074 					element); \
  1075 			} \
  1076 			break; \
  1077 		} \
  1078 	case DPT_DataTable: \
  1079 		{ \
  1080 			FIND_PROP_SEND_IN_SENDTABLE(info, pProp, element, type, type_name); \
  1081 			\
  1082 			offset += pProp->GetOffset(); \
  1083 			bit_count = pProp->m_nBits; \
  1084 			break; \
  1085 		} \
  1086 	default: \
  1087 		{ \
  1088 			return pContext->ThrowNativeError("SendProp %s type is not " type_name " (%d != %d)", \
  1089 				prop, \
  1090 				pProp->GetType(), \
  1091 				type); \
  1092 		} \
  1093 	} \
  1094 
  1095 #define FIND_PROP_SEND_IN_SENDTABLE(info, pProp, element, type, type_name) \
  1096 	SendTable *pTable = pProp->GetDataTable(); \
  1097 	if (!pTable) \
  1098 	{ \
  1099 		return pContext->ThrowNativeError("Error looking up DataTable for prop %s", \
  1100 			prop); \
  1101 	} \
  1102 	\
  1103 	int elementCount = pTable->GetNumProps(); \
  1104 	if (element < 0 || element >= elementCount) \
  1105 	{ \
  1106 		return pContext->ThrowNativeError("Element %d is out of bounds (Prop %s has %d elements).", \
  1107 			element, \
  1108 			prop, \
  1109 			elementCount); \
  1110 	} \
  1111 	\
  1112 	pProp = pTable->GetProp(element); \
  1113 	if (pProp->GetType() != type) \
  1114 	{ \
  1115 		return pContext->ThrowNativeError("SendProp %s type is not " type_name " ([%d,%d] != %d)", \
  1116 			prop, \
  1117 			pProp->GetType(), \
  1118 			pProp->m_nBits, \
  1119 			type); \
  1120 	}
  1121 
  1122 
  1123 inline int MatchFieldAsInteger(int field_type)
  1124 {
  1125 	switch (field_type)
  1126 	{
  1127 	case FIELD_TICK:
  1128 	case FIELD_MODELINDEX:
  1129 	case FIELD_MATERIALINDEX:
  1130 	case FIELD_INTEGER:
  1131 	case FIELD_COLOR32:
  1132 		return 32;
  1133 	case FIELD_SHORT:
  1134 		return 16;
  1135 	case FIELD_CHARACTER:
  1136 		return 8;
  1137 	case FIELD_BOOLEAN:
  1138 		return 1;
  1139 	default:
  1140 		return 0;
  1141 	}
  1142 
  1143 	return 0;
  1144 }
  1145 
  1146 static cell_t GetEntPropArraySize(IPluginContext *pContext, const cell_t *params)
  1147 {
  1148 	CBaseEntity *pEntity;
  1149 	char *prop;
  1150 	edict_t *pEdict;
  1151 
  1152 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1153 	{
  1154 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1155 	}
  1156 
  1157 	pContext->LocalToString(params[3], &prop);
  1158 
  1159 	switch (params[2])
  1160 	{
  1161 	case Prop_Data:
  1162 		{
  1163 			typedescription_t *td;
  1164 
  1165 			FIND_PROP_DATA(td);
  1166 
  1167 			return td->fieldSize;
  1168 		}
  1169 	case Prop_Send:
  1170 		{
  1171 			sm_sendprop_info_t info;
  1172 			
  1173 			IServerUnknown *pUnk = (IServerUnknown *)pEntity;
  1174 			IServerNetworkable *pNet = pUnk->GetNetworkable();
  1175 			if (!pNet)
  1176 			{
  1177 				return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1178 			}
  1179 			if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info))
  1180 			{
  1181 				const char *class_name = g_HL2.GetEntityClassname(pEntity);
  1182 				return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)",
  1183 					prop,
  1184 					params[1],
  1185 					((class_name) ? class_name : ""));
  1186 			}
  1187 
  1188 			if (info.prop->GetType() != DPT_DataTable)
  1189 			{
  1190 				return 0;
  1191 			}
  1192 
  1193 			SendTable *pTable = info.prop->GetDataTable();
  1194 			if (!pTable)
  1195 			{
  1196 				return pContext->ThrowNativeError("Error looking up DataTable for prop %s", prop);
  1197 			}
  1198 			
  1199 			return pTable->GetNumProps();
  1200 		}
  1201 	default:
  1202 		{
  1203 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1204 		}
  1205 	}
  1206 
  1207 	return 1;
  1208 }
  1209 
  1210 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
  1211 {
  1212 	CBaseEntity *pEntity;
  1213 	char *prop;
  1214 	int offset;
  1215 	edict_t *pEdict;
  1216 	int bit_count;
  1217 	bool is_unsigned = false;
  1218 
  1219 	int element = 0;
  1220 	if (params[0] >= 5)
  1221 	{
  1222 		element = params[5];
  1223 	}
  1224 
  1225 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1226 	{
  1227 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1228 	}
  1229 
  1230 	pContext->LocalToString(params[3], &prop);
  1231 
  1232 	switch (params[2])
  1233 	{
  1234 	case Prop_Data:
  1235 		{
  1236 			typedescription_t *td;
  1237 
  1238 			FIND_PROP_DATA(td);
  1239 
  1240 			if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
  1241 			{
  1242 				return pContext->ThrowNativeError("Data field %s is not an integer (%d)", 
  1243 					prop,
  1244 					td->fieldType);
  1245 			}
  1246 
  1247 			CHECK_SET_PROP_DATA_OFFSET();
  1248 
  1249 			break;
  1250 		}
  1251 	case Prop_Send:
  1252 		{
  1253 			FIND_PROP_SEND(DPT_Int, "integer");
  1254 			is_unsigned = ((pProp->GetFlags() & SPROP_UNSIGNED) == SPROP_UNSIGNED);
  1255 
  1256 			// This isn't in CS:S yet, but will be, doesn't hurt to add now, and will save us a build later
  1257 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
  1258 			if (pProp->GetFlags() & SPROP_VARINT)
  1259 			{
  1260 				bit_count = sizeof(int) * 8;
  1261 			}
  1262 #endif
  1263 			break;
  1264 		}
  1265 	default:
  1266 		{
  1267 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1268 		}
  1269 	}
  1270 
  1271 	if (bit_count < 1)
  1272 	{
  1273 		bit_count = params[4] * 8;
  1274 	}
  1275 
  1276 	if (bit_count >= 17)
  1277 	{
  1278 		return *(int32_t *)((uint8_t *)pEntity + offset);
  1279 	}
  1280 	else if (bit_count >= 9)
  1281 	{
  1282 		if (is_unsigned)
  1283 		{
  1284 			return *(uint16_t *)((uint8_t *)pEntity + offset);
  1285 		}
  1286 		else
  1287 		{
  1288 			return *(int16_t *)((uint8_t *)pEntity + offset);
  1289 		}
  1290 	}
  1291 	else if (bit_count >= 2)
  1292 	{
  1293 		if (is_unsigned)
  1294 		{
  1295 			return *(uint8_t *)((uint8_t *)pEntity + offset);
  1296 		}
  1297 		else
  1298 		{
  1299 			return *(int8_t *)((uint8_t *)pEntity + offset);
  1300 		}
  1301 	}
  1302 	else
  1303 	{
  1304 		return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
  1305 	}
  1306 
  1307 	return 0;
  1308 }
  1309 
  1310 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
  1311 {
  1312 	CBaseEntity *pEntity;
  1313 	char *prop;
  1314 	int offset;
  1315 	edict_t *pEdict;
  1316 	int bit_count;
  1317 
  1318 	int element = 0;
  1319 	if (params[0] >= 6)
  1320 	{
  1321 		element = params[6];
  1322 	}
  1323 
  1324 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1325 	{
  1326 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1327 	}
  1328 
  1329 	pContext->LocalToString(params[3], &prop);
  1330 
  1331 	switch (params[2])
  1332 	{
  1333 	case Prop_Data:
  1334 		{
  1335 			typedescription_t *td;
  1336 
  1337 			FIND_PROP_DATA(td);
  1338 
  1339 			if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
  1340 			{
  1341 				return pContext->ThrowNativeError("Data field %s is not an integer (%d)", 
  1342 					prop,
  1343 					td->fieldType);
  1344 			}
  1345 
  1346 			CHECK_SET_PROP_DATA_OFFSET();
  1347 
  1348 			break;
  1349 		}
  1350 	case Prop_Send:
  1351 		{
  1352 			FIND_PROP_SEND(DPT_Int, "integer");
  1353 
  1354 			// This isn't in CS:S yet, but will be, doesn't hurt to add now, and will save us a build later
  1355 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
  1356 			if (pProp->GetFlags() & SPROP_VARINT)
  1357 			{
  1358 				bit_count = sizeof(int) * 8;
  1359 			}
  1360 #endif
  1361 			break;
  1362 		}
  1363 	default:
  1364 		{
  1365 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1366 		}
  1367 	}
  1368 
  1369 	if (bit_count < 1)
  1370 	{
  1371 		bit_count = params[5] * 8;
  1372 	}
  1373 
  1374 	if (bit_count >= 17)
  1375 	{
  1376 		*(int32_t *)((uint8_t *)pEntity + offset) = params[4];
  1377 	}
  1378 	else if (bit_count >= 9)
  1379 	{
  1380 		*(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
  1381 	}
  1382 	else if (bit_count >= 2)
  1383 	{
  1384 		*(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
  1385 	}
  1386 	else
  1387 	{
  1388 		*(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
  1389 	}
  1390 	
  1391 	if (params[2] == Prop_Send && (pEdict != NULL))
  1392 	{
  1393 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1394 	}
  1395 
  1396 	return 0;
  1397 }
  1398 
  1399 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
  1400 {
  1401 	CBaseEntity *pEntity;
  1402 	char *prop;
  1403 	int offset;
  1404 	int bit_count;
  1405 	edict_t *pEdict;
  1406 
  1407 	int element = 0;
  1408 	if (params[0] >= 4)
  1409 	{
  1410 		element = params[4];
  1411 	}
  1412 
  1413 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1414 	{
  1415 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1416 	}
  1417 
  1418 	pContext->LocalToString(params[3], &prop);
  1419 
  1420 	switch (params[2])
  1421 	{
  1422 	case Prop_Data:
  1423 		{
  1424 			typedescription_t *td;
  1425 
  1426 			FIND_PROP_DATA(td);
  1427 
  1428 			if (td->fieldType != FIELD_FLOAT
  1429 				&& td->fieldType != FIELD_TIME)
  1430 			{
  1431 				return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])", 
  1432 					prop,
  1433 					td->fieldType,
  1434 					FIELD_FLOAT,
  1435 					FIELD_TIME);
  1436 			}
  1437 
  1438 			CHECK_SET_PROP_DATA_OFFSET();
  1439 
  1440 			break;
  1441 		}
  1442 	case Prop_Send:
  1443 		{
  1444 			FIND_PROP_SEND(DPT_Float, "float");
  1445 			break;
  1446 		}
  1447 	default:
  1448 		{
  1449 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1450 		}
  1451 	}
  1452 
  1453 	float val = *(float *)((uint8_t *)pEntity + offset);
  1454 
  1455 	return sp_ftoc(val);
  1456 }
  1457 
  1458 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
  1459 {
  1460 	CBaseEntity *pEntity;
  1461 	char *prop;
  1462 	int offset;
  1463 	int bit_count;
  1464 	edict_t *pEdict;
  1465 
  1466 	int element = 0;
  1467 	if (params[0] >= 5)
  1468 	{
  1469 		element = params[5];
  1470 	}
  1471 
  1472 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1473 	{
  1474 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1475 	}
  1476 
  1477 	pContext->LocalToString(params[3], &prop);
  1478 
  1479 	switch (params[2])
  1480 	{
  1481 	case Prop_Data:
  1482 		{
  1483 			typedescription_t *td;
  1484 
  1485 			FIND_PROP_DATA(td);
  1486 
  1487 			if (td->fieldType != FIELD_FLOAT
  1488 				&& td->fieldType != FIELD_TIME)
  1489 			{
  1490 				return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])", 
  1491 					prop,
  1492 					td->fieldType,
  1493 					FIELD_FLOAT,
  1494 					FIELD_TIME);
  1495 			}
  1496 
  1497 			CHECK_SET_PROP_DATA_OFFSET();
  1498 
  1499 			break;
  1500 		}
  1501 	case Prop_Send:
  1502 		{
  1503 			FIND_PROP_SEND(DPT_Float, "float");
  1504 			break;
  1505 		}
  1506 	default:
  1507 		{
  1508 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1509 		}
  1510 	}
  1511 
  1512 	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
  1513 
  1514 	if (params[2] == Prop_Send && (pEdict != NULL))
  1515 	{
  1516 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1517 	}
  1518 
  1519 	return 1;
  1520 }
  1521 
  1522 static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
  1523 {
  1524 	CBaseEntity *pEntity;
  1525 	char *prop;
  1526 	int offset;
  1527 	int bit_count;
  1528 	edict_t *pEdict;
  1529 
  1530 	int element = 0;
  1531 	if (params[0] >= 4)
  1532  	{
  1533 		element = params[4];
  1534  	}
  1535 
  1536 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1537 	{
  1538 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1539 	}
  1540 
  1541 	pContext->LocalToString(params[3], &prop);
  1542 
  1543 	switch (params[2])
  1544 	{
  1545 	case Prop_Data:
  1546 		{
  1547 			typedescription_t *td;
  1548 
  1549 			FIND_PROP_DATA(td);
  1550 
  1551 			if (td->fieldType != FIELD_EHANDLE)
  1552 			{
  1553 				return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)", 
  1554 					prop,
  1555 					td->fieldType,
  1556 					FIELD_EHANDLE);
  1557 			}
  1558 
  1559 			CHECK_SET_PROP_DATA_OFFSET();
  1560 
  1561 			break;
  1562 		}
  1563 	case Prop_Send:
  1564 		{
  1565 			FIND_PROP_SEND(DPT_Int, "integer");
  1566 			break;
  1567 		}
  1568 	default:
  1569 		{
  1570 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1571 		}
  1572 	}
  1573 
  1574 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
  1575 	CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex());
  1576 
  1577 	if (!pHandleEntity || hndl != reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
  1578 		return -1;
  1579 
  1580 	return g_HL2.EntityToBCompatRef(pHandleEntity);
  1581 }
  1582 
  1583 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
  1584 {
  1585 	CBaseEntity *pEntity;
  1586 	char *prop;
  1587 	int offset;
  1588 	int bit_count;
  1589 	edict_t *pEdict;
  1590 
  1591 	int element = 0;
  1592 	if (params[0] >= 5)
  1593  	{
  1594 		element = params[5];
  1595  	}
  1596 
  1597 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1598 	{
  1599 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1600 	}
  1601 
  1602 	pContext->LocalToString(params[3], &prop);
  1603 
  1604 	switch (params[2])
  1605 	{
  1606 	case Prop_Data:
  1607 		{
  1608 			typedescription_t *td;
  1609 
  1610 			FIND_PROP_DATA(td);
  1611 
  1612 			if (td->fieldType != FIELD_EHANDLE)
  1613 			{
  1614 				return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)", 
  1615 					prop,
  1616 					td->fieldType,
  1617 					FIELD_EHANDLE);
  1618 			}
  1619 
  1620 			CHECK_SET_PROP_DATA_OFFSET();
  1621 
  1622 			break;
  1623 		}
  1624 	case Prop_Send:
  1625 		{
  1626 			FIND_PROP_SEND(DPT_Int, "integer");
  1627 			break;
  1628 		}
  1629 	default:
  1630 		{
  1631 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1632 		}
  1633 	}
  1634 
  1635 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
  1636 
  1637 	if (params[4] == -1)
  1638 	{
  1639 		hndl.Set(NULL);
  1640 	}
  1641 	else
  1642 	{
  1643 		CBaseEntity *pOther = GetEntity(params[4]);
  1644 
  1645 		if (!pOther)
  1646 		{
  1647 			return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[4]), params[4]);
  1648 		}
  1649 
  1650 		IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
  1651 		hndl.Set(pHandleEnt);
  1652 	}
  1653 
  1654 	if (params[2] == Prop_Send && (pEdict != NULL))
  1655 	{
  1656 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1657 	}
  1658 
  1659 	return 1;
  1660 }
  1661 
  1662 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
  1663 {
  1664 	CBaseEntity *pEntity;
  1665 	char *prop;
  1666 	int offset;
  1667 	int bit_count;
  1668 	edict_t *pEdict;
  1669 
  1670 	int element = 0;
  1671 	if (params[0] >= 5)
  1672  	{
  1673 		element = params[5];
  1674  	}
  1675 	
  1676 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1677 	{
  1678 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1679 	}
  1680 
  1681 	pContext->LocalToString(params[3], &prop);
  1682 
  1683 	switch (params[2])
  1684 	{
  1685 	case Prop_Data:
  1686 		{
  1687 			typedescription_t *td;
  1688 			
  1689 			FIND_PROP_DATA(td);
  1690 
  1691 			if (td->fieldType != FIELD_VECTOR
  1692 				&& td->fieldType != FIELD_POSITION_VECTOR)
  1693 			{
  1694 				return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])", 
  1695 					prop,
  1696 					td->fieldType,
  1697 					FIELD_VECTOR,
  1698 					FIELD_POSITION_VECTOR);
  1699 			}
  1700 
  1701 			CHECK_SET_PROP_DATA_OFFSET();
  1702 
  1703 			break;
  1704 		}
  1705 	case Prop_Send:
  1706 		{
  1707 			FIND_PROP_SEND(DPT_Vector, "vector");
  1708 			break;
  1709 		}
  1710 	default:
  1711 		{
  1712 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1713 		}
  1714 	}
  1715 
  1716 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
  1717 
  1718 	cell_t *vec;
  1719 	pContext->LocalToPhysAddr(params[4], &vec);
  1720 
  1721 	vec[0] = sp_ftoc(v->x);
  1722 	vec[1] = sp_ftoc(v->y);
  1723 	vec[2] = sp_ftoc(v->z);
  1724 
  1725 	return 1;
  1726 }
  1727 
  1728 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
  1729 {
  1730 	CBaseEntity *pEntity;
  1731 	char *prop;
  1732 	int offset;
  1733 	int bit_count;
  1734 	edict_t *pEdict;
  1735 
  1736 	int element = 0;
  1737 	if (params[0] >= 5)
  1738  	{
  1739 		element = params[5];
  1740  	}
  1741 	
  1742 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1743 	{
  1744 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1745 	}
  1746 
  1747 	pContext->LocalToString(params[3], &prop);
  1748 
  1749 	switch (params[2])
  1750 	{
  1751 	case Prop_Data:
  1752 		{
  1753 			typedescription_t *td;
  1754 			
  1755 			FIND_PROP_DATA(td);
  1756 
  1757 			if (td->fieldType != FIELD_VECTOR
  1758 				&& td->fieldType != FIELD_POSITION_VECTOR)
  1759 			{
  1760 				return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])", 
  1761 					prop,
  1762 					td->fieldType,
  1763 					FIELD_VECTOR,
  1764 					FIELD_POSITION_VECTOR);
  1765 			}
  1766 
  1767 			CHECK_SET_PROP_DATA_OFFSET();
  1768 
  1769 			break;
  1770 		}
  1771 	case Prop_Send:
  1772 		{
  1773 			FIND_PROP_SEND(DPT_Vector, "vector");			
  1774 			break;
  1775 		}
  1776 	default:
  1777 		{
  1778 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1779 		}
  1780 	}
  1781 
  1782 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
  1783 
  1784 	cell_t *vec;
  1785 	pContext->LocalToPhysAddr(params[4], &vec);
  1786 
  1787 	v->x = sp_ctof(vec[0]);
  1788 	v->y = sp_ctof(vec[1]);
  1789 	v->z = sp_ctof(vec[2]);
  1790 
  1791 	if (params[2] == Prop_Send && (pEdict != NULL))
  1792 	{
  1793 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1794 	}
  1795 
  1796 	return 1;
  1797 }
  1798 
  1799 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
  1800 {
  1801 	CBaseEntity *pEntity;
  1802 	char *prop;
  1803 	int offset;
  1804 	edict_t *pEdict;
  1805 	bool bIsStringIndex;
  1806 
  1807 	int element = 0;
  1808 	if (params[0] >= 6)
  1809  	{
  1810 		element = params[6];
  1811  	}
  1812 	
  1813 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1814 	{
  1815 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1816 	}
  1817 
  1818 	pContext->LocalToString(params[3], &prop);
  1819 
  1820 	bIsStringIndex = false;
  1821 
  1822 	switch (params[2])
  1823 	{
  1824 	case Prop_Data:
  1825 		{
  1826 			typedescription_t *td;
  1827 			
  1828 			FIND_PROP_DATA(td);
  1829 
  1830 			if (td->fieldType != FIELD_CHARACTER
  1831 				&& td->fieldType != FIELD_STRING
  1832 				&& td->fieldType != FIELD_MODELNAME 
  1833 				&& td->fieldType != FIELD_SOUNDNAME)
  1834 			{
  1835 				return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)", 
  1836 					prop,
  1837 					td->fieldType,
  1838 					FIELD_CHARACTER);
  1839 			}
  1840 
  1841 			bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
  1842 
  1843 			if (bIsStringIndex && (element < 0 || element >= td->fieldSize))
  1844 			{
  1845 				return pContext->ThrowNativeError("Element %d is out of bounds (Prop %s has %d elements).",
  1846 					element,
  1847 					prop,
  1848 					td->fieldSize);
  1849 			}
  1850 			else if (element != 0)
  1851 			{
  1852 				return pContext->ThrowNativeError("Prop %s is not an array. Element %d is invalid.",
  1853 					prop,
  1854 					element);
  1855 			}
  1856 
  1857 			offset = info.actual_offset;
  1858 			if (bIsStringIndex)
  1859 			{
  1860 				offset += (element * (td->fieldSizeInBytes / td->fieldSize));
  1861 			}
  1862 			break;
  1863 		}
  1864 	case Prop_Send:
  1865 		{
  1866 			sm_sendprop_info_t info;
  1867 			
  1868 			IServerUnknown *pUnk = (IServerUnknown *)pEntity;
  1869 			IServerNetworkable *pNet = pUnk->GetNetworkable();
  1870 			if (!pNet)
  1871 			{
  1872 				return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1873 			}
  1874 			if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info))
  1875 			{
  1876 				const char *class_name = g_HL2.GetEntityClassname(pEntity);
  1877 				return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)",
  1878 					prop,
  1879 					params[1],
  1880 					((class_name) ? class_name : ""));
  1881 			}
  1882 
  1883 			offset = info.actual_offset;
  1884 
  1885 			if (info.prop->GetType() != DPT_String)
  1886 			{
  1887 				return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
  1888 					prop,
  1889 					info.prop->GetType(),
  1890 					DPT_String);
  1891 			}
  1892 			else if (element != 0)
  1893 			{
  1894 				return pContext->ThrowNativeError("SendProp %s is not an array. Element %d is invalid.",
  1895 					prop,
  1896 					element);
  1897  			}
  1898 			
  1899 			break;
  1900 		}
  1901 	default:
  1902 		{
  1903 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1904 		}
  1905 	}
  1906 
  1907 	size_t len;
  1908 	const char *src; 
  1909 	
  1910 	if (!bIsStringIndex)
  1911 	{
  1912 		src = (char *)((uint8_t *)pEntity + offset);
  1913 	}
  1914 	else
  1915 	{
  1916 		string_t idx;
  1917 
  1918 		idx = *(string_t *)((uint8_t *)pEntity + offset);
  1919 		src = (idx == NULL_STRING) ? "" : STRING(idx);
  1920 	}
  1921 
  1922 	pContext->StringToLocalUTF8(params[4], params[5], src, &len);
  1923 
  1924 	return len;
  1925 }
  1926 
  1927 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
  1928 {
  1929 	CBaseEntity *pEntity;
  1930 	char *prop;
  1931 	int offset;
  1932 	int maxlen;
  1933 	edict_t *pEdict;
  1934 
  1935 	if (!IndexToAThings(params[1], &pEntity, &pEdict))
  1936 	{
  1937 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  1938 	}
  1939 
  1940 	switch (params[2])
  1941 	{
  1942 	case Prop_Data:
  1943 		{
  1944 			datamap_t *pMap;
  1945 			if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
  1946 			{
  1947 				return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
  1948 			}
  1949 			pContext->LocalToString(params[3], &prop);
  1950 			sm_datatable_info_t info;
  1951 			if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
  1952 			{
  1953 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
  1954 			}
  1955 			
  1956 			typedescription_t *td = info.prop;
  1957 			if (td->fieldType != FIELD_CHARACTER)
  1958 			{
  1959 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
  1960 			}
  1961 			offset = info.actual_offset;
  1962 			maxlen = td->fieldSize;
  1963 			break;
  1964 		}
  1965 	case Prop_Send:
  1966 		{
  1967 			char *prop;
  1968 			IServerUnknown *pUnk = (IServerUnknown *)pEntity;
  1969 			IServerNetworkable *pNet = pUnk->GetNetworkable();
  1970 			if (!pNet)
  1971 			{
  1972 				return pContext->ThrowNativeError("The edict is not networkable");
  1973 			}
  1974 			pContext->LocalToString(params[3], &prop);
  1975 			SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
  1976 			if (!pSend)
  1977 			{
  1978 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
  1979 			}
  1980 			if (pSend->GetType() != DPT_String)
  1981 			{
  1982 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
  1983 			}
  1984 			offset = pSend->GetOffset();
  1985 			maxlen = DT_MAX_STRING_BUFFERSIZE;
  1986 			break;
  1987 		}
  1988 	default:
  1989 		{
  1990 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1991 		}
  1992 	}
  1993 
  1994 	char *src;
  1995 	char *dest = (char *)((uint8_t *)pEntity + offset);
  1996 
  1997 	pContext->LocalToString(params[4], &src);
  1998 	size_t len = strncopy(dest, src, maxlen);
  1999 
  2000 	if (params[2] == Prop_Send && (pEdict != NULL))
  2001 	{
  2002 		g_HL2.SetEdictStateChanged(pEdict, offset);
  2003 	}
  2004 
  2005 	return len;
  2006 }
  2007 
  2008 static int32_t SDKEntFlagToSMEntFlag(int flag)
  2009 {
  2010 	switch (flag)
  2011 	{
  2012 		case FL_ONGROUND:
  2013 			return ENTFLAG_ONGROUND;
  2014 		case FL_DUCKING:
  2015 			return ENTFLAG_DUCKING;
  2016 		case FL_WATERJUMP:
  2017 			return ENTFLAG_WATERJUMP;
  2018 		case FL_ONTRAIN:
  2019 			return ENTFLAG_ONTRAIN;
  2020 		case FL_INRAIN:
  2021 			return ENTFLAG_INRAIN;
  2022 		case FL_FROZEN:
  2023 			return ENTFLAG_FROZEN;
  2024 		case FL_ATCONTROLS:
  2025 			return ENTFLAG_ATCONTROLS;
  2026 		case FL_CLIENT:
  2027 			return ENTFLAG_CLIENT;
  2028 		case FL_FAKECLIENT:
  2029 			return ENTFLAG_FAKECLIENT;
  2030 		case FL_INWATER:
  2031 			return ENTFLAG_INWATER;
  2032 		case FL_FLY:
  2033 			return ENTFLAG_FLY;
  2034 		case FL_SWIM:
  2035 			return ENTFLAG_SWIM;
  2036 		case FL_CONVEYOR:
  2037 			return ENTFLAG_CONVEYOR;
  2038 		case FL_NPC:
  2039 			return ENTFLAG_NPC;
  2040 		case FL_GODMODE:
  2041 			return ENTFLAG_GODMODE;
  2042 		case FL_NOTARGET:
  2043 			return ENTFLAG_NOTARGET;
  2044 		case FL_AIMTARGET:
  2045 			return ENTFLAG_AIMTARGET;
  2046 		case FL_PARTIALGROUND:
  2047 			return ENTFLAG_PARTIALGROUND;
  2048 		case FL_STATICPROP:
  2049 			return ENTFLAG_STATICPROP;
  2050 		case FL_GRAPHED:
  2051 			return ENTFLAG_GRAPHED;
  2052 		case FL_GRENADE:
  2053 			return ENTFLAG_GRENADE;
  2054 		case FL_STEPMOVEMENT:
  2055 			return ENTFLAG_STEPMOVEMENT;
  2056 		case FL_DONTTOUCH:
  2057 			return ENTFLAG_DONTTOUCH;
  2058 		case FL_BASEVELOCITY:
  2059 			return ENTFLAG_BASEVELOCITY;
  2060 		case FL_WORLDBRUSH:
  2061 			return ENTFLAG_WORLDBRUSH;
  2062 		case FL_OBJECT:
  2063 			return ENTFLAG_OBJECT;
  2064 		case FL_KILLME:
  2065 			return ENTFLAG_KILLME;
  2066 		case FL_ONFIRE:
  2067 			return ENTFLAG_ONFIRE;
  2068 		case FL_DISSOLVING:
  2069 			return ENTFLAG_DISSOLVING;
  2070 		case FL_TRANSRAGDOLL:
  2071 			return ENTFLAG_TRANSRAGDOLL;
  2072 		case FL_UNBLOCKABLE_BY_PLAYER:
  2073 			return ENTFLAG_UNBLOCKABLE_BY_PLAYER;
  2074 #if SOURCE_ENGINE == SE_ALIENSWARM
  2075 		case FL_FREEZING:
  2076 			return ENTFLAG_FREEZING;
  2077 #elif SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2
  2078 		case FL_EP2V_UNKNOWN:
  2079 			return ENTFLAG_EP2V_UNKNOWN1;
  2080 #endif
  2081 		default:
  2082 			return 0;
  2083 	}
  2084 }
  2085 
  2086 static int32_t SMEntFlagToSDKEntFlag(int32_t flag)
  2087 {
  2088 	switch (flag)
  2089 	{
  2090 		case ENTFLAG_ONGROUND:
  2091 			return FL_ONGROUND;
  2092 		case ENTFLAG_DUCKING:
  2093 			return FL_DUCKING;
  2094 		case ENTFLAG_WATERJUMP:
  2095 			return FL_WATERJUMP;
  2096 		case ENTFLAG_ONTRAIN:
  2097 			return FL_ONTRAIN;
  2098 		case ENTFLAG_INRAIN:
  2099 			return FL_INRAIN;
  2100 		case ENTFLAG_FROZEN:
  2101 			return FL_FROZEN;
  2102 		case ENTFLAG_ATCONTROLS:
  2103 			return FL_ATCONTROLS;
  2104 		case ENTFLAG_CLIENT:
  2105 			return FL_CLIENT;
  2106 		case ENTFLAG_FAKECLIENT:
  2107 			return FL_FAKECLIENT;
  2108 		case ENTFLAG_INWATER:
  2109 			return FL_INWATER;
  2110 		case ENTFLAG_FLY:
  2111 			return FL_FLY;
  2112 		case ENTFLAG_SWIM:
  2113 			return FL_SWIM;
  2114 		case ENTFLAG_CONVEYOR:
  2115 			return FL_CONVEYOR;
  2116 		case ENTFLAG_NPC:
  2117 			return FL_NPC;
  2118 		case ENTFLAG_GODMODE:
  2119 			return FL_GODMODE;
  2120 		case ENTFLAG_NOTARGET:
  2121 			return FL_NOTARGET;
  2122 		case ENTFLAG_AIMTARGET:
  2123 			return FL_AIMTARGET;
  2124 		case ENTFLAG_PARTIALGROUND:
  2125 			return FL_PARTIALGROUND;
  2126 		case ENTFLAG_STATICPROP:
  2127 			return FL_STATICPROP;
  2128 		case ENTFLAG_GRAPHED:
  2129 			return FL_GRAPHED;
  2130 		case ENTFLAG_GRENADE:
  2131 			return FL_GRENADE;
  2132 		case ENTFLAG_STEPMOVEMENT:
  2133 			return FL_STEPMOVEMENT;
  2134 		case ENTFLAG_DONTTOUCH:
  2135 			return FL_DONTTOUCH;
  2136 		case ENTFLAG_BASEVELOCITY:
  2137 			return FL_BASEVELOCITY;
  2138 		case ENTFLAG_WORLDBRUSH:
  2139 			return FL_WORLDBRUSH;
  2140 		case ENTFLAG_OBJECT:
  2141 			return FL_OBJECT;
  2142 		case ENTFLAG_KILLME:
  2143 			return FL_KILLME;
  2144 		case ENTFLAG_ONFIRE:
  2145 			return FL_ONFIRE;
  2146 		case ENTFLAG_DISSOLVING:
  2147 			return FL_DISSOLVING;
  2148 		case ENTFLAG_TRANSRAGDOLL:
  2149 			return FL_TRANSRAGDOLL;
  2150 		case ENTFLAG_UNBLOCKABLE_BY_PLAYER:
  2151 			return FL_UNBLOCKABLE_BY_PLAYER;
  2152 #if SOURCE_ENGINE == SE_ALIENSWARM
  2153 		case ENTFLAG_FREEZING:
  2154 			return FL_FREEZING;
  2155 #elif SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2
  2156 		case ENTFLAG_EP2V_UNKNOWN1:
  2157 			return FL_EP2V_UNKNOWN;
  2158 #endif
  2159 		default:
  2160 			return 0;
  2161 	}
  2162 }
  2163 
  2164 static cell_t GetEntityFlags(IPluginContext *pContext, const cell_t *params)
  2165 {
  2166 	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
  2167 	if (!pEntity)
  2168 	{
  2169 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  2170 	}
  2171 
  2172 	const char *prop = g_pGameConf->GetKeyValue("m_fFlags");
  2173 	if (!prop)
  2174 	{
  2175 		return pContext->ThrowNativeError("Could not find m_fFlags prop in gamedata");
  2176 	}
  2177 
  2178 	datamap_t *pMap;
  2179 
  2180 	if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL)
  2181 	{
  2182 		return pContext->ThrowNativeError("Could not retrieve datamap");
  2183 	}
  2184 	
  2185 	sm_datatable_info_t info;
  2186 	if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
  2187 	{
  2188 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d)",
  2189 			prop,
  2190 			params[1]);
  2191 	}
  2192 
  2193 	int offset = info.actual_offset;
  2194 
  2195 	int32_t actual_flags = *(int32_t *)((uint8_t *)pEntity + offset);
  2196 	int32_t sm_flags = 0;
  2197 
  2198 	for (int32_t i = 0; i < 32; i++)
  2199 	{
  2200 		int32_t flag = (1<<i);
  2201 		if ((actual_flags & flag) == flag)
  2202 		{
  2203 			sm_flags |= SDKEntFlagToSMEntFlag(flag);
  2204 		}
  2205 	}
  2206 
  2207 	return sm_flags;
  2208 }
  2209 
  2210 static cell_t SetEntityFlags(IPluginContext *pContext, const cell_t *params)
  2211 {
  2212 	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
  2213 	if (!pEntity)
  2214 	{
  2215 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  2216 	}
  2217 
  2218 	const char *prop = g_pGameConf->GetKeyValue("m_fFlags");
  2219 	if (!prop)
  2220 	{
  2221 		return pContext->ThrowNativeError("Could not find m_fFlags prop in gamedata");
  2222 	}
  2223 
  2224 	datamap_t *pMap;
  2225 
  2226 	if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL)
  2227 	{
  2228 		return pContext->ThrowNativeError("Could not retrieve datamap");
  2229 	}
  2230 	
  2231 	sm_datatable_info_t info;
  2232 	if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
  2233 	{
  2234 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d)",
  2235 			prop,
  2236 			params[1]);
  2237 	}
  2238 
  2239 	int offset = info.actual_offset;
  2240 
  2241 	int32_t sm_flags = params[2];
  2242 	int32_t actual_flags = 0;
  2243 
  2244 	for (int32_t i = 0; i < 32; i++)
  2245 	{
  2246 		int32_t flag = (1<<i);
  2247 		if ((sm_flags & flag) == flag)
  2248 		{
  2249 			actual_flags |= SMEntFlagToSDKEntFlag(flag);
  2250 		}
  2251 	}
  2252 
  2253 	*(int32_t *)((uint8_t *)pEntity + offset) = actual_flags;
  2254 
  2255 	return 0;
  2256 }
  2257 
  2258 static cell_t GetEntityAddress(IPluginContext *pContext, const cell_t *params)
  2259 {
  2260 	CBaseEntity * pEntity = GetEntity(params[1]);
  2261 	if (!pEntity)
  2262 	{
  2263 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
  2264 	}
  2265 	return reinterpret_cast<cell_t>(pEntity);
  2266 }
  2267 
  2268 REGISTER_NATIVES(entityNatives)
  2269 {
  2270 	{"ChangeEdictState",		ChangeEdictState},
  2271 	{"CreateEdict",				CreateEdict},
  2272 	{"FindDataMapOffs",			FindDataMapOffs},
  2273 	{"FindSendPropInfo",		FindSendPropInfo},
  2274 	{"FindSendPropOffs",		FindSendPropOffs},
  2275 	{"GetEdictClassname",		GetEdictClassname},
  2276 	{"GetEdictFlags",			GetEdictFlags},
  2277 	{"GetEntData",				GetEntData},
  2278 	{"GetEntDataEnt",			GetEntDataEnt},		/** DEPRECATED */
  2279 	{"GetEntDataEnt2",			GetEntDataEnt2},
  2280 	{"GetEntDataFloat",			GetEntDataFloat},
  2281 	{"GetEntDataString",		GetEntDataString},
  2282 	{"GetEntDataVector",		GetEntDataVector},
  2283 	{"GetEntProp",				GetEntProp},
  2284 	{"GetEntPropArraySize",		GetEntPropArraySize},
  2285 	{"GetEntPropEnt",			GetEntPropEnt},
  2286 	{"GetEntPropFloat",			GetEntPropFloat},
  2287 	{"GetEntPropString",		GetEntPropString},
  2288 	{"GetEntPropVector",		GetEntPropVector},
  2289 	{"GetEntityCount",			GetEntityCount},
  2290 	{"GetEntityFlags",			GetEntityFlags},
  2291 	{"GetEntityNetClass",		GetEntityNetClass},
  2292 	{"GetMaxEntities",			GetMaxEntities},
  2293 	{"IsEntNetworkable",		IsEntNetworkable},
  2294 	{"IsValidEdict",			IsValidEdict},
  2295 	{"IsValidEntity",			IsValidEntity},
  2296 	{"RemoveEdict",				RemoveEdict},
  2297 	{"SetEdictFlags",			SetEdictFlags},
  2298 	{"SetEntData",				SetEntData},
  2299 	{"SetEntDataEnt",			SetEntDataEnt},		/** DEPRECATED */
  2300 	{"SetEntDataEnt2",			SetEntDataEnt2},
  2301 	{"SetEntDataFloat",			SetEntDataFloat},
  2302 	{"SetEntDataVector",		SetEntDataVector},
  2303 	{"SetEntDataString",		SetEntDataString},
  2304 	{"SetEntityFlags",			SetEntityFlags},
  2305 	{"SetEntProp",				SetEntProp},
  2306 	{"SetEntPropEnt",			SetEntPropEnt},
  2307 	{"SetEntPropFloat",			SetEntPropFloat},
  2308 	{"SetEntPropString",		SetEntPropString},
  2309 	{"SetEntPropVector",		SetEntPropVector},
  2310 	{"GetEntityAddress",		GetEntityAddress},
  2311 	{"FindDataMapInfo",		FindDataMapInfo},
  2312 	{NULL,						NULL}
  2313 };