582 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			582 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
 * vim: set ts=4 :
 | 
						|
 * =============================================================================
 | 
						|
 * SourceMod SDKTools Extension
 | 
						|
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
 | 
						|
 * =============================================================================
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it under
 | 
						|
 * the terms of the GNU General Public License, version 3.0, as published by the
 | 
						|
 * Free Software Foundation.
 | 
						|
 * 
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						|
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
						|
 * details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along with
 | 
						|
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 *
 | 
						|
 * As a special exception, AlliedModders LLC gives you permission to link the
 | 
						|
 * code of this program (as well as its derivative works) to "Half-Life 2," the
 | 
						|
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
 | 
						|
 * by the Valve Corporation.  You must obey the GNU General Public License in
 | 
						|
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
 | 
						|
 * this exception to all derivative works.  AlliedModders LLC defines further
 | 
						|
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
 | 
						|
 * or <http://www.sourcemod.net/license.php>.
 | 
						|
 *
 | 
						|
 * Version: $Id$
 | 
						|
 */
 | 
						|
 | 
						|
#include "smsdk_ext.h"
 | 
						|
#include "extension.h"
 | 
						|
#include "vdecoder.h"
 | 
						|
#include "vcallbuilder.h"
 | 
						|
 | 
						|
using namespace SourceMod;
 | 
						|
using namespace SourcePawn;
 | 
						|
 | 
						|
/**
 | 
						|
 * For object pointers, the data looks like this instead:
 | 
						|
 * 4 bytes: POINTER TO LATER
 | 
						|
 * + bytes: Object internal data
 | 
						|
 *
 | 
						|
 * We use the virtual stack as extra fake stack space and create a temp object.
 | 
						|
 * If these objects had destructors, we'd need to fake destroy toom of course.
 | 
						|
 * Of course, BinTools only reads the first four bytes and passes the pointer.
 | 
						|
 */
 | 
						|
 | 
						|
size_t ValveParamToBinParam(ValveType type, 
 | 
						|
						  PassType pass,
 | 
						|
						  unsigned int flags,
 | 
						|
						  PassInfo *info,
 | 
						|
						  bool &needs_extra)
 | 
						|
{
 | 
						|
	needs_extra = false;
 | 
						|
	switch (type)
 | 
						|
	{
 | 
						|
	case Valve_Vector:
 | 
						|
		{
 | 
						|
			size_t mySize = sizeof(Vector *);
 | 
						|
			if (pass == PassType_Basic)
 | 
						|
			{
 | 
						|
				if (flags & PASSFLAG_BYREF)
 | 
						|
				{
 | 
						|
					return 0;
 | 
						|
				}
 | 
						|
				info->type = PassType_Basic;
 | 
						|
				info->flags = flags;
 | 
						|
				info->size = sizeof(Vector *);
 | 
						|
				mySize = sizeof(Vector);
 | 
						|
				needs_extra = true;
 | 
						|
			} else if (pass == PassType_Object) {
 | 
						|
				info->type = PassType_Object;
 | 
						|
				info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
 | 
						|
				info->size = sizeof(Vector);
 | 
						|
			} else {
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			return mySize;
 | 
						|
		}
 | 
						|
	case Valve_QAngle:
 | 
						|
		{
 | 
						|
			size_t mySize = sizeof(QAngle *);
 | 
						|
			if (pass == PassType_Basic)
 | 
						|
			{
 | 
						|
				if (flags & PASSFLAG_BYREF)
 | 
						|
				{
 | 
						|
					return 0;
 | 
						|
				}
 | 
						|
				info->type = PassType_Basic;
 | 
						|
				info->flags = flags;
 | 
						|
				info->size = sizeof(QAngle *);
 | 
						|
				mySize = sizeof(QAngle);
 | 
						|
				needs_extra = true;
 | 
						|
			} else if (pass == PassType_Object) {
 | 
						|
				info->type = PassType_Object;
 | 
						|
				info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
 | 
						|
				info->size = sizeof(QAngle);
 | 
						|
			} else {
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			return mySize;
 | 
						|
		}
 | 
						|
	case Valve_CBaseEntity:
 | 
						|
	case Valve_CBasePlayer:
 | 
						|
	case Valve_Edict:
 | 
						|
	case Valve_String:
 | 
						|
		{
 | 
						|
			if (pass != PassType_Basic || (flags & PASSFLAG_BYREF))
 | 
						|
			{
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			info->type = PassType_Basic;
 | 
						|
			info->flags = flags;
 | 
						|
			info->size = sizeof(void *);
 | 
						|
			return sizeof(void *);
 | 
						|
		}
 | 
						|
	case Valve_POD:
 | 
						|
		{
 | 
						|
			info->type = PassType_Basic;
 | 
						|
			info->flags = flags;
 | 
						|
			if (flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				needs_extra = true;
 | 
						|
				info->size = sizeof(int *);
 | 
						|
				return sizeof(int *) + sizeof(int);
 | 
						|
			} else {
 | 
						|
				info->size = sizeof(int);
 | 
						|
				return sizeof(int);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case Valve_Bool:
 | 
						|
		{
 | 
						|
			info->type = PassType_Basic;
 | 
						|
			info->flags = flags;
 | 
						|
			if (flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				needs_extra = true;
 | 
						|
				info->size = sizeof(bool *);
 | 
						|
				return sizeof(bool *) + sizeof(bool);
 | 
						|
			} else {
 | 
						|
				info->size = sizeof(bool);
 | 
						|
				return sizeof(bool);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case Valve_Float:
 | 
						|
		{
 | 
						|
			info->flags = flags;
 | 
						|
			if (flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				needs_extra = true;
 | 
						|
				info->type = PassType_Basic;
 | 
						|
				info->size = sizeof(float *);
 | 
						|
				return sizeof(float *) + sizeof(float);
 | 
						|
			} else {
 | 
						|
				info->type = PassType_Float;
 | 
						|
				info->size = sizeof(float);
 | 
						|
				return sizeof(float);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
DataStatus EncodeValveParam(IPluginContext *pContext,
 | 
						|
							cell_t param, 
 | 
						|
							const ValveCall *pCall,
 | 
						|
							const ValvePassInfo *data,
 | 
						|
							const void *_buffer)
 | 
						|
{
 | 
						|
	const void *buffer = (const unsigned char *)_buffer + data->offset;
 | 
						|
	switch (data->vtype)
 | 
						|
	{
 | 
						|
	case Valve_Vector:
 | 
						|
		{
 | 
						|
			Vector *v = NULL;
 | 
						|
 | 
						|
			if (data->type == PassType_Basic)
 | 
						|
			{
 | 
						|
				v = *(Vector **)buffer;
 | 
						|
			} else if (data->type == PassType_Object) {
 | 
						|
				v = (Vector *)buffer;
 | 
						|
			}
 | 
						|
 | 
						|
			cell_t *addr;
 | 
						|
			pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			addr[0] = sp_ftoc(v->x);
 | 
						|
			addr[1] = sp_ftoc(v->y);
 | 
						|
			addr[2] = sp_ftoc(v->z);
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_QAngle:
 | 
						|
		{
 | 
						|
			QAngle *q = NULL;
 | 
						|
 | 
						|
			if (data->type == PassType_Basic)
 | 
						|
			{
 | 
						|
				q = *(QAngle **)buffer;
 | 
						|
			} else if (data->type == PassType_Object) {
 | 
						|
				q = (QAngle *)buffer;
 | 
						|
			}
 | 
						|
 | 
						|
			cell_t *addr;
 | 
						|
			pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			addr[0] = sp_ftoc(q->x);
 | 
						|
			addr[1] = sp_ftoc(q->y);
 | 
						|
			addr[2] = sp_ftoc(q->z);
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_CBaseEntity:
 | 
						|
	case Valve_CBasePlayer:
 | 
						|
		{
 | 
						|
			cell_t *addr;
 | 
						|
			pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			CBaseEntity *pEntity = *(CBaseEntity **)buffer;
 | 
						|
			if (pEntity)
 | 
						|
			{
 | 
						|
				*addr = gamehelpers->EntityToBCompatRef(pEntity);
 | 
						|
			} else {
 | 
						|
				*addr = -1;
 | 
						|
			}
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_Edict:
 | 
						|
		{
 | 
						|
			cell_t *addr;
 | 
						|
			pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			edict_t *pEdict = *(edict_t **)buffer;
 | 
						|
			if (pEdict)
 | 
						|
			{
 | 
						|
				*addr = IndexOfEdict(pEdict);
 | 
						|
			} else {
 | 
						|
				*addr = -1;
 | 
						|
			}
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_POD:
 | 
						|
	case Valve_Float:
 | 
						|
		{
 | 
						|
			cell_t *addr;
 | 
						|
			pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			if (data->flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				buffer = *(cell_t **)buffer;
 | 
						|
			}
 | 
						|
 | 
						|
			*addr = *(cell_t *)buffer;
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_Bool:
 | 
						|
		{
 | 
						|
			cell_t *addr;
 | 
						|
			pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			if (data->flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				buffer = *(bool **)buffer;
 | 
						|
			}
 | 
						|
 | 
						|
			*addr = *(bool *)buffer ? 1 : 0;
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return Data_Fail;
 | 
						|
}
 | 
						|
 | 
						|
DataStatus DecodeValveParam(IPluginContext *pContext,
 | 
						|
					  cell_t param,
 | 
						|
					  const ValveCall *pCall,
 | 
						|
					  const ValvePassInfo *data,
 | 
						|
					  void *_buffer)
 | 
						|
{
 | 
						|
	void *buffer = (unsigned char *)_buffer + data->offset;
 | 
						|
	switch (data->vtype)
 | 
						|
	{
 | 
						|
	case Valve_Vector:
 | 
						|
		{
 | 
						|
			cell_t *addr;
 | 
						|
			int err;
 | 
						|
			err = pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			unsigned char *mem = (unsigned char *)buffer;
 | 
						|
			if (data->type == PassType_Basic)
 | 
						|
			{
 | 
						|
				/* Store the object in the next N bytes, and store
 | 
						|
				 * a pointer to that object right beforehand.
 | 
						|
				 */
 | 
						|
				Vector **realPtr = (Vector **)buffer;
 | 
						|
 | 
						|
				if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
 | 
						|
				{
 | 
						|
					if (data->decflags & VDECODE_FLAG_ALLOWNULL)
 | 
						|
					{
 | 
						|
						*realPtr = NULL;
 | 
						|
						return Data_Okay;
 | 
						|
					} else {
 | 
						|
						pContext->ThrowNativeError("NULL not allowed");
 | 
						|
						return Data_Fail;
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
 | 
						|
					*realPtr = (Vector *)mem;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (err != SP_ERROR_NONE)
 | 
						|
			{
 | 
						|
				pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
 | 
						|
				return Data_Fail;
 | 
						|
			}
 | 
						|
 | 
						|
			/* Use placement new to initialize the object cleanly
 | 
						|
			 * This has no destructor so we don't need to do 
 | 
						|
			 * DestroyValveParam() or something :]
 | 
						|
			 */
 | 
						|
			Vector *v = new (mem) Vector(
 | 
						|
				sp_ctof(addr[0]),
 | 
						|
				sp_ctof(addr[1]),
 | 
						|
				sp_ctof(addr[2]));
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_QAngle:
 | 
						|
		{
 | 
						|
			cell_t *addr;
 | 
						|
			int err;
 | 
						|
			err = pContext->LocalToPhysAddr(param, &addr);
 | 
						|
 | 
						|
			unsigned char *mem = (unsigned char *)buffer;
 | 
						|
			if (data->type == PassType_Basic)
 | 
						|
			{
 | 
						|
				/* Store the object in the next N bytes, and store
 | 
						|
				 * a pointer to that object right beforehand.
 | 
						|
				 */
 | 
						|
				QAngle **realPtr = (QAngle **)buffer;
 | 
						|
 | 
						|
				if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
 | 
						|
				{
 | 
						|
					if (!(data->decflags & VDECODE_FLAG_ALLOWNULL))
 | 
						|
					{
 | 
						|
						pContext->ThrowNativeError("NULL not allowed");
 | 
						|
						return Data_Fail;
 | 
						|
					} else {
 | 
						|
						*realPtr = NULL;
 | 
						|
						return Data_Okay;
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
 | 
						|
					*realPtr = (QAngle *)mem;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (err != SP_ERROR_NONE)
 | 
						|
			{
 | 
						|
				pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
 | 
						|
				return Data_Fail;
 | 
						|
			}
 | 
						|
 | 
						|
			/* Use placement new to initialize the object cleanly
 | 
						|
			 * This has no destructor so we don't need to do 
 | 
						|
			 * DestroyValveParam() or something :]
 | 
						|
			 */
 | 
						|
			QAngle *v = new (mem) QAngle(
 | 
						|
				sp_ctof(addr[0]),
 | 
						|
				sp_ctof(addr[1]),
 | 
						|
				sp_ctof(addr[2]));
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_CBasePlayer:
 | 
						|
		{
 | 
						|
			CBaseEntity *pEntity = NULL;
 | 
						|
			if (data->decflags & VDECODE_FLAG_BYREF)
 | 
						|
			{
 | 
						|
				cell_t *addr;
 | 
						|
				pContext->LocalToPhysAddr(param, &addr);
 | 
						|
				param = *addr;
 | 
						|
			}
 | 
						|
			int index = gamehelpers->ReferenceToIndex(param);
 | 
						|
			if ((unsigned)index == INVALID_EHANDLE_INDEX && param != -1)
 | 
						|
			{
 | 
						|
				return Data_Fail;
 | 
						|
			}
 | 
						|
			if (index >= 1 && index <= playerhelpers->GetMaxClients())
 | 
						|
			{
 | 
						|
				IGamePlayer *player = playerhelpers->GetGamePlayer(index);
 | 
						|
				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
 | 
						|
					&& !player->IsConnected())
 | 
						|
				{
 | 
						|
					pContext->ThrowNativeError("Client %d is not connected", param);
 | 
						|
					return Data_Fail;
 | 
						|
				} else if (!player->IsInGame()) {
 | 
						|
					pContext->ThrowNativeError("Client %d is not in game", param);
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
				pEntity = gamehelpers->ReferenceToEntity(param);
 | 
						|
			} else if (param == -1) {
 | 
						|
				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
 | 
						|
				{
 | 
						|
					pEntity = NULL;
 | 
						|
				} else {
 | 
						|
					pContext->ThrowNativeError("NULL not allowed");
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				pContext->ThrowNativeError("Entity index %d is not a valid client", param);
 | 
						|
				return Data_Fail;
 | 
						|
			}
 | 
						|
			
 | 
						|
			CBaseEntity **ebuf = (CBaseEntity **)buffer;
 | 
						|
			*ebuf = pEntity;
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_CBaseEntity:
 | 
						|
		{
 | 
						|
			CBaseEntity *pEntity = NULL;
 | 
						|
			if (data->decflags & VDECODE_FLAG_BYREF)
 | 
						|
			{
 | 
						|
				cell_t *addr;
 | 
						|
				pContext->LocalToPhysAddr(param, &addr);
 | 
						|
				param = *addr;
 | 
						|
			}
 | 
						|
			int index = gamehelpers->ReferenceToIndex(param);
 | 
						|
			if ((unsigned)index == INVALID_EHANDLE_INDEX && param != -1)
 | 
						|
			{
 | 
						|
				return Data_Fail;
 | 
						|
			}
 | 
						|
			if (index >= 1 && index <= playerhelpers->GetMaxClients())
 | 
						|
			{
 | 
						|
				IGamePlayer *player = playerhelpers->GetGamePlayer(index);
 | 
						|
				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
 | 
						|
					&& !player->IsConnected())
 | 
						|
				{
 | 
						|
					pContext->ThrowNativeError("Client %d is not connected", param);
 | 
						|
					return Data_Fail;
 | 
						|
				} else if (!player->IsInGame()) {
 | 
						|
					pContext->ThrowNativeError("Client %d is not in game", param);
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
				pEntity = gamehelpers->ReferenceToEntity(param);
 | 
						|
			} else if (param == -1) {
 | 
						|
				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
 | 
						|
				{
 | 
						|
					pEntity = NULL;
 | 
						|
				} else {
 | 
						|
					pContext->ThrowNativeError("NULL not allowed");
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			} else if (index == 0) {
 | 
						|
				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
 | 
						|
				{
 | 
						|
					pEntity = gamehelpers->ReferenceToEntity(0);
 | 
						|
				} else {
 | 
						|
					pContext->ThrowNativeError("World not allowed");
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				pEntity = gamehelpers->ReferenceToEntity(param);
 | 
						|
				if (!pEntity)
 | 
						|
				{
 | 
						|
					pContext->ThrowNativeError("Entity %d is not valid", param);
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			CBaseEntity **ebuf = (CBaseEntity **)buffer;
 | 
						|
			*ebuf = pEntity;
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_Edict:
 | 
						|
		{
 | 
						|
			edict_t *pEdict;
 | 
						|
			if (data->decflags & VDECODE_FLAG_BYREF)
 | 
						|
			{
 | 
						|
				cell_t *addr;
 | 
						|
				pContext->LocalToPhysAddr(param, &addr);
 | 
						|
				param = *addr;
 | 
						|
			}
 | 
						|
			if (param >= 1 && param <= playerhelpers->GetMaxClients())
 | 
						|
			{
 | 
						|
				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
 | 
						|
				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
 | 
						|
					&& !player->IsConnected())
 | 
						|
				{
 | 
						|
					pContext->ThrowNativeError("Client %d is not connected", param);
 | 
						|
					return Data_Fail;
 | 
						|
				} else if (!player->IsInGame()) {
 | 
						|
					pContext->ThrowNativeError("Client %d is not in game", param);
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
				pEdict = player->GetEdict();
 | 
						|
			} else if (param == -1) {
 | 
						|
				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
 | 
						|
				{
 | 
						|
					pEdict = NULL;
 | 
						|
				} else {
 | 
						|
					pContext->ThrowNativeError("NULL not allowed");
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			} else if (param == 0) {
 | 
						|
				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
 | 
						|
				{
 | 
						|
					pEdict = PEntityOfEntIndex(0);
 | 
						|
				} else {
 | 
						|
					pContext->ThrowNativeError("World not allowed");
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				pEdict = PEntityOfEntIndex(param);
 | 
						|
				if (!pEdict || pEdict->IsFree())
 | 
						|
				{
 | 
						|
					pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
 | 
						|
					return Data_Fail;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			edict_t **ebuf = (edict_t **)buffer;
 | 
						|
			*ebuf = pEdict;
 | 
						|
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_POD:
 | 
						|
	case Valve_Float:
 | 
						|
		{
 | 
						|
			if (data->decflags & VDECODE_FLAG_BYREF)
 | 
						|
			{
 | 
						|
				cell_t *addr;
 | 
						|
				pContext->LocalToPhysAddr(param, &addr);
 | 
						|
				param = *addr;
 | 
						|
			}
 | 
						|
			if (data->flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				*(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
 | 
						|
				buffer = *(void **)buffer;
 | 
						|
			}
 | 
						|
			*(cell_t *)buffer = param;
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_Bool:
 | 
						|
		{
 | 
						|
			if (data->decflags & VDECODE_FLAG_BYREF)
 | 
						|
			{
 | 
						|
				cell_t *addr;
 | 
						|
				pContext->LocalToPhysAddr(param, &addr);
 | 
						|
				param = *addr;
 | 
						|
			}
 | 
						|
			if (data->flags & PASSFLAG_ASPOINTER)
 | 
						|
			{
 | 
						|
				*(bool **)buffer = (bool *)((unsigned char *)_buffer + pCall->stackEnd + data->obj_offset);
 | 
						|
				buffer = *(bool **)buffer;
 | 
						|
			}
 | 
						|
			*(bool *)buffer = param ? true : false;
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	case Valve_String:
 | 
						|
		{
 | 
						|
			char *addr;
 | 
						|
			pContext->LocalToString(param, &addr);
 | 
						|
			*(char **)buffer = addr;
 | 
						|
			return Data_Okay;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return Data_Fail;
 | 
						|
}
 |