1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/extensions/sdktools/outputnatives.cpp Wed Apr 02 01:22:02 2008 +0000
1.3 @@ -0,0 +1,611 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod SDKTools Extension
1.8 + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id: outputnatives.cpp 1521 2007-10-01 21:20:30Z faluco $
1.33 + */
1.34 +
1.35 +#include "extension.h"
1.36 +#include "output.h"
1.37 +
1.38 +
1.39 +// HookSingleEntityOutput(ent, const String:output[], function, bool:once);
1.40 +cell_t HookSingleEntityOutput(IPluginContext *pContext, const cell_t *params)
1.41 +{
1.42 + if (!g_OutputManager.IsEnabled())
1.43 + {
1.44 + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details");
1.45 + }
1.46 +
1.47 + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
1.48 + if (!pEdict)
1.49 + {
1.50 + return pContext->ThrowNativeError("Invalid Entity index %i", params[1]);
1.51 + }
1.52 + const char *classname = pEdict->GetClassName();
1.53 +
1.54 + char *outputname;
1.55 + pContext->LocalToString(params[2], &outputname);
1.56 +
1.57 + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, true);
1.58 +
1.59 + //Check for an existing identical hook
1.60 + SourceHook::List<omg_hooks *>::iterator _iter;
1.61 +
1.62 + omg_hooks *hook;
1.63 +
1.64 + IPluginFunction *pFunction;
1.65 + pFunction = pContext->GetFunctionById(params[3]);
1.66 +
1.67 + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
1.68 + {
1.69 + hook = (omg_hooks *)*_iter;
1.70 + if (hook->pf == pFunction && hook->entity_filter == pEdict->m_NetworkSerialNumber)
1.71 + {
1.72 + return 0;
1.73 + }
1.74 + }
1.75 +
1.76 + hook = g_OutputManager.NewHook();
1.77 +
1.78 + hook->entity_filter = pEdict->m_NetworkSerialNumber;
1.79 + hook->entity_index = engine->IndexOfEdict(pEdict);
1.80 + hook->only_once= !!params[4];
1.81 + hook->pf = pFunction;
1.82 + hook->m_parent = pOutputName;
1.83 + hook->in_use = false;
1.84 + hook->delete_me = false;
1.85 +
1.86 + pOutputName->hooks.push_back(hook);
1.87 +
1.88 + g_OutputManager.OnHookAdded();
1.89 +
1.90 + IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
1.91 + SourceHook::List<omg_hooks *> *pList = NULL;
1.92 +
1.93 + if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList)
1.94 + {
1.95 + pList = new SourceHook::List<omg_hooks *>;
1.96 + pPlugin->SetProperty("OutputHookList", pList);
1.97 + }
1.98 +
1.99 + pList->push_back(hook);
1.100 +
1.101 + return 1;
1.102 +}
1.103 +
1.104 +
1.105 +// HookEntityOutput(const String:classname[], const String:output[], function);
1.106 +cell_t HookEntityOutput(IPluginContext *pContext, const cell_t *params)
1.107 +{
1.108 + if (!g_OutputManager.IsEnabled())
1.109 + {
1.110 + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details");
1.111 + }
1.112 +
1.113 + //Find or create the base structures for this classname and the output
1.114 + char *classname;
1.115 + pContext->LocalToString(params[1], &classname);
1.116 +
1.117 + char *outputname;
1.118 + pContext->LocalToString(params[2], &outputname);
1.119 +
1.120 + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, true);
1.121 +
1.122 + //Check for an existing identical hook
1.123 + SourceHook::List<omg_hooks *>::iterator _iter;
1.124 +
1.125 + omg_hooks *hook;
1.126 +
1.127 + IPluginFunction *pFunction;
1.128 + pFunction = pContext->GetFunctionById(params[3]);
1.129 +
1.130 + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
1.131 + {
1.132 + hook = (omg_hooks *)*_iter;
1.133 + if (hook->pf == pFunction && hook->entity_filter == -1)
1.134 + {
1.135 + //already hooked to this function...
1.136 + //throw an error or just let them get away with stupidity?
1.137 + // seems like poor coding if they dont know if something is hooked or not
1.138 + return 0;
1.139 + }
1.140 + }
1.141 +
1.142 + hook = g_OutputManager.NewHook();
1.143 +
1.144 + hook->entity_filter = -1;
1.145 + hook->pf = pFunction;
1.146 + hook->m_parent = pOutputName;
1.147 + hook->in_use = false;
1.148 + hook->delete_me = false;
1.149 +
1.150 + pOutputName->hooks.push_back(hook);
1.151 +
1.152 + g_OutputManager.OnHookAdded();
1.153 +
1.154 + IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
1.155 + SourceHook::List<omg_hooks *> *pList = NULL;
1.156 +
1.157 + if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList)
1.158 + {
1.159 + pList = new SourceHook::List<omg_hooks *>;
1.160 + pPlugin->SetProperty("OutputHookList", pList);
1.161 + }
1.162 +
1.163 + pList->push_back(hook);
1.164 +
1.165 + return 1;
1.166 +}
1.167 +
1.168 +// UnHookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback);
1.169 +cell_t UnHookEntityOutput(IPluginContext *pContext, const cell_t *params)
1.170 +{
1.171 + if (!g_OutputManager.IsEnabled())
1.172 + {
1.173 + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details");
1.174 + }
1.175 +
1.176 + char *classname;
1.177 + pContext->LocalToString(params[1], &classname);
1.178 +
1.179 + char *outputname;
1.180 + pContext->LocalToString(params[2], &outputname);
1.181 +
1.182 + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, false);
1.183 +
1.184 + if (!pOutputName)
1.185 + {
1.186 + return 0;
1.187 + }
1.188 +
1.189 + //Check for an existing identical hook
1.190 + SourceHook::List<omg_hooks *>::iterator _iter;
1.191 +
1.192 + omg_hooks *hook;
1.193 +
1.194 + IPluginFunction *pFunction;
1.195 + pFunction = pContext->GetFunctionById(params[3]);
1.196 +
1.197 + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
1.198 + {
1.199 + hook = (omg_hooks *)*_iter;
1.200 + if (hook->pf == pFunction && hook->entity_filter == -1)
1.201 + {
1.202 + // remove this hook.
1.203 + if (hook->in_use)
1.204 + {
1.205 + hook->delete_me = true;
1.206 + return 1;
1.207 + }
1.208 +
1.209 + pOutputName->hooks.erase(_iter);
1.210 + g_OutputManager.CleanUpHook(hook);
1.211 +
1.212 + return 1;
1.213 + }
1.214 + }
1.215 +
1.216 + return 0;
1.217 +}
1.218 +
1.219 +// UnHookSingleEntityOutput(entity, const String:output[], EntityOutput:callback);
1.220 +cell_t UnHookSingleEntityOutput(IPluginContext *pContext, const cell_t *params)
1.221 +{
1.222 + if (!g_OutputManager.IsEnabled())
1.223 + {
1.224 + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details");
1.225 + }
1.226 +
1.227 + // Find the classname of the entity and lookup the classname and output structures
1.228 + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
1.229 + if (!pEdict)
1.230 + {
1.231 + return pContext->ThrowNativeError("Invalid Entity index %i", params[1]);
1.232 + }
1.233 +
1.234 + const char *classname = pEdict->GetClassName();
1.235 +
1.236 + char *outputname;
1.237 + pContext->LocalToString(params[2], &outputname);
1.238 +
1.239 + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, false);
1.240 +
1.241 + if (!pOutputName)
1.242 + {
1.243 + return 0;
1.244 + }
1.245 +
1.246 + //Check for an existing identical hook
1.247 + SourceHook::List<omg_hooks *>::iterator _iter;
1.248 +
1.249 + omg_hooks *hook;
1.250 +
1.251 + IPluginFunction *pFunction;
1.252 + pFunction = pContext->GetFunctionById(params[3]);
1.253 +
1.254 + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
1.255 + {
1.256 + hook = (omg_hooks *)*_iter;
1.257 + if (hook->pf == pFunction && hook->entity_index == engine->IndexOfEdict(pEdict))
1.258 + {
1.259 + // remove this hook.
1.260 + if (hook->in_use)
1.261 + {
1.262 + hook->delete_me = true;
1.263 + return 1;
1.264 + }
1.265 +
1.266 + pOutputName->hooks.erase(_iter);
1.267 + g_OutputManager.CleanUpHook(hook);
1.268 +
1.269 + return 1;
1.270 + }
1.271 + }
1.272 +
1.273 + return 0;
1.274 +}
1.275 +
1.276 +#if 0
1.277 +static cell_t GetVariantType(IPluginContext *pContext, const cell_t *params)
1.278 +{
1.279 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.280 + HandleError err;
1.281 + varhandle_t *pInfo;
1.282 + HandleSecurity sec;
1.283 +
1.284 + sec.pOwner = NULL;
1.285 + sec.pIdentity = myself->GetIdentity();
1.286 +
1.287 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.288 + != HandleError_None)
1.289 + {
1.290 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.291 + }
1.292 +
1.293 + return pInfo->crab.FieldType();
1.294 +}
1.295 +
1.296 +static cell_t GetVariantInt(IPluginContext *pContext, const cell_t *params)
1.297 +{
1.298 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.299 + HandleError err;
1.300 + varhandle_t *pInfo;
1.301 + HandleSecurity sec;
1.302 +
1.303 + sec.pOwner = NULL;
1.304 + sec.pIdentity = myself->GetIdentity();
1.305 +
1.306 +
1.307 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.308 + != HandleError_None)
1.309 + {
1.310 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.311 + }
1.312 +
1.313 + if (pInfo->crab.FieldType() != FIELD_INTEGER)
1.314 + {
1.315 + return pContext->ThrowNativeError("Variant is not an integer");
1.316 + }
1.317 +
1.318 + return pInfo->crab.Int();
1.319 +}
1.320 +
1.321 +static cell_t GetVariantBool(IPluginContext *pContext, const cell_t *params)
1.322 +{
1.323 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.324 + HandleError err;
1.325 + varhandle_t *pInfo;
1.326 + HandleSecurity sec;
1.327 +
1.328 + sec.pOwner = NULL;
1.329 + sec.pIdentity = myself->GetIdentity();
1.330 +
1.331 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.332 + != HandleError_None)
1.333 + {
1.334 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.335 + }
1.336 +
1.337 + if (pInfo->crab.FieldType() != FIELD_BOOLEAN)
1.338 + {
1.339 + return pContext->ThrowNativeError("Variant is not a boolean");
1.340 + }
1.341 +
1.342 + return pInfo->crab.Bool();
1.343 +}
1.344 +
1.345 +static cell_t GetVariantEntity(IPluginContext *pContext, const cell_t *params)
1.346 +{
1.347 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.348 + HandleError err;
1.349 + varhandle_t *pInfo;
1.350 + HandleSecurity sec;
1.351 +
1.352 + sec.pOwner = NULL;
1.353 + sec.pIdentity = myself->GetIdentity();
1.354 +
1.355 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.356 + != HandleError_None)
1.357 + {
1.358 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.359 + }
1.360 +
1.361 + if (pInfo->crab.FieldType() != FIELD_EHANDLE)
1.362 + {
1.363 + return pContext->ThrowNativeError("Variant is not an entity");
1.364 + }
1.365 +
1.366 + edict_t *pEdict = g_OutputManager.BaseHandleToEdict((CBaseHandle)pInfo->crab.Entity());
1.367 +
1.368 + return engine->IndexOfEdict(pEdict);
1.369 +}
1.370 +
1.371 +static cell_t GetVariantFloat(IPluginContext *pContext, const cell_t *params)
1.372 +{
1.373 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.374 + HandleError err;
1.375 + varhandle_t *pInfo;
1.376 + HandleSecurity sec;
1.377 +
1.378 + sec.pOwner = NULL;
1.379 + sec.pIdentity = myself->GetIdentity();
1.380 +
1.381 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.382 + != HandleError_None)
1.383 + {
1.384 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.385 + }
1.386 +
1.387 + if (pInfo->crab.FieldType() != FIELD_FLOAT)
1.388 + {
1.389 + return pContext->ThrowNativeError("Variant is not a float");
1.390 + }
1.391 +
1.392 + return sp_ftoc(pInfo->crab.Float());
1.393 +}
1.394 +
1.395 +static cell_t GetVariantVector(IPluginContext *pContext, const cell_t *params)
1.396 +{
1.397 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.398 + HandleError err;
1.399 + varhandle_t *pInfo;
1.400 + HandleSecurity sec;
1.401 +
1.402 + sec.pOwner = NULL;
1.403 + sec.pIdentity = myself->GetIdentity();
1.404 +
1.405 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.406 + != HandleError_None)
1.407 + {
1.408 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.409 + }
1.410 +
1.411 + if (pInfo->crab.FieldType() != FIELD_VECTOR)
1.412 + {
1.413 + return pContext->ThrowNativeError("Variant is not a vector");
1.414 + }
1.415 +
1.416 + cell_t *r;
1.417 + pContext->LocalToPhysAddr(params[2], &r);
1.418 +
1.419 + Vector temp;
1.420 + pInfo->crab.Vector3D(temp);
1.421 +
1.422 + r[0] = sp_ftoc(temp[0]);
1.423 + r[1] = sp_ftoc(temp[1]);
1.424 + r[2] = sp_ftoc(temp[2]);
1.425 +
1.426 + return 0;
1.427 +}
1.428 +
1.429 +static cell_t GetVariantColour(IPluginContext *pContext, const cell_t *params)
1.430 +{
1.431 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.432 + HandleError err;
1.433 + varhandle_t *pInfo;
1.434 + HandleSecurity sec;
1.435 +
1.436 + sec.pOwner = NULL;
1.437 + sec.pIdentity = myself->GetIdentity();
1.438 +
1.439 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.440 + != HandleError_None)
1.441 + {
1.442 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.443 + }
1.444 +
1.445 + if (pInfo->crab.FieldType() != FIELD_COLOR32)
1.446 + {
1.447 + return pContext->ThrowNativeError("Variant is not a colour");
1.448 + }
1.449 +
1.450 + cell_t *r;
1.451 + pContext->LocalToPhysAddr(params[2], &r);
1.452 +
1.453 + color32 temp = pInfo->crab.Color32();
1.454 +
1.455 + r[0] = temp.r;
1.456 + r[1] = temp.g;
1.457 + r[2] = temp.b;
1.458 + r[4] = temp.a;
1.459 +
1.460 + return 0;
1.461 +}
1.462 +
1.463 +static cell_t GetVariantString(IPluginContext *pContext, const cell_t *params)
1.464 +{
1.465 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.466 + HandleError err;
1.467 + varhandle_t *pInfo;
1.468 + HandleSecurity sec;
1.469 +
1.470 + sec.pOwner = NULL;
1.471 + sec.pIdentity = myself->GetIdentity();
1.472 +
1.473 + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo))
1.474 + != HandleError_None)
1.475 + {
1.476 + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err);
1.477 + }
1.478 +
1.479 + char *dest;
1.480 + const char *src = pInfo->crab.String();
1.481 + size_t len;
1.482 +
1.483 + pContext->LocalToString(params[2], &dest);
1.484 +
1.485 + /* Perform bounds checking */
1.486 + len = strlen(src);
1.487 + if (len >= (unsigned)params[3])
1.488 + {
1.489 + len = params[3] - 1;
1.490 + } else {
1.491 + len = params[3];
1.492 + }
1.493 +
1.494 + /* Copy */
1.495 + memmove(dest, src, len);
1.496 +
1.497 + dest[len] = '\0';
1.498 +
1.499 + return 0;
1.500 +}
1.501 +#endif
1.502 +
1.503 +sp_nativeinfo_t g_EntOutputNatives[] =
1.504 +{
1.505 + {"HookEntityOutput", HookEntityOutput},
1.506 + {"UnHookEntityOutput", UnHookEntityOutput},
1.507 + {"HookSingleEntityOutput", HookSingleEntityOutput},
1.508 + {"UnHookSingleEntityOutput", UnHookSingleEntityOutput},
1.509 +#if 0 //Removed because we don't need them
1.510 + {"GetVariantType", GetVariantType},
1.511 + {"GetVariantInt", GetVariantInt},
1.512 + {"GetVariantFloat", GetVariantFloat},
1.513 + {"GetVariantBool", GetVariantBool},
1.514 + {"GetVariantString", GetVariantString},
1.515 + {"GetVariantEntity", GetVariantEntity},
1.516 + {"GetVariantVector", GetVariantVector},
1.517 + {"GetVariantColour", GetVariantColour},
1.518 +#endif
1.519 + {NULL, NULL},
1.520 +};
1.521 +
1.522 +#if 0
1.523 +//Include file stuff that wasn't needed:
1.524 +
1.525 +enum FieldType
1.526 +{
1.527 + FieldType_Float = 1,
1.528 + FieldType_String = 2,
1.529 + FieldType_Vector = 3,
1.530 + FieldType_Int = 5,
1.531 + FieldType_Bool = 6,
1.532 + FieldType_Colour = 9,
1.533 + FieldType_Entity = 13
1.534 +}
1.535 +
1.536 +/**
1.537 + * Gets the current type of a variant handle
1.538 + *
1.539 + * @param variant A variant handle.
1.540 + * @return Current type of the variant.
1.541 + */
1.542 +native FieldType:GetVariantType(Handle:variant);
1.543 +
1.544 +/**
1.545 + * Retreives a Float from a variant handle.
1.546 + *
1.547 + * @param variant A variant handle.
1.548 + * @return Float value.
1.549 + * @error Variant handle is not type FieldType_Float
1.550 + */
1.551 +native Float:GetVariantFloat(Handle:variant);
1.552 +
1.553 +/**
1.554 + * Retreives an Integer from a variant handle.
1.555 + *
1.556 + * @param variant A variant handle.
1.557 + * @return Int value.
1.558 + * @error Variant handle is not type FieldType_Int
1.559 + */
1.560 +native GetVariantInt(Handle:variant);
1.561 +
1.562 +/**
1.563 + * Retreives a bool from a variant handle.
1.564 + *
1.565 + * @param variant A variant handle.
1.566 + * @return bool value.
1.567 + * @error Variant handle is not type FieldType_Bool
1.568 + */
1.569 +native bool:GetVariantBool(Handle:variant);
1.570 +
1.571 +/**
1.572 + * Retreives an entity from a variant handle.
1.573 + *
1.574 + * @param variant A variant handle.
1.575 + * @return Entity Index.
1.576 + * @error Variant handle is not type FieldType_Entity
1.577 + */
1.578 +native GetVariantEntity(Handle:variant);
1.579 +
1.580 +/**
1.581 + * Retreives a Vector from a variant handle.
1.582 + *
1.583 + * @param variant A variant handle.
1.584 + * @param vec buffer to store the Vector.
1.585 + * @noreturn
1.586 + * @error Variant handle is not type FieldType_Vector
1.587 + */
1.588 +native GetVariantVector(Handle:variant, Float:vec[3]);
1.589 +
1.590 +/**
1.591 + * Retreives a String from a variant handle.
1.592 + *
1.593 + * @note This native does not require the variant to be FieldType_String,
1.594 + * It can convert any type into a string representation.
1.595 + *
1.596 + * @param variant A variant handle.
1.597 + * @param buffer buffer to store the string in
1.598 + * @param maxlen Maximum length of buffer.
1.599 + * @noreturn
1.600 + */
1.601 +native GetVariantString(Handle:variant, String:buffer[], maxlen);
1.602 +
1.603 +/**
1.604 + * Retreives a Colour from a variant handle.
1.605 + *
1.606 + * @note Colour is in format r,g,b,a
1.607 + *
1.608 + * @param variant A variant handle.
1.609 + * @param colour buffer array to store the colour in.
1.610 + * @noreturn
1.611 + * @error Variant handle is not type FieldType_Colour
1.612 + */
1.613 +native GetVariantColour(Handle:variant, colour[4]);
1.614 +#endif