diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 236ffe23..965e9260 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -967,21 +967,94 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params) class_name); \ } -#define FIND_PROP_SEND(pProp) \ +#define CHECK_SET_PROP_DATA_OFFSET() \ + if (element >= td->fieldSize) \ + { \ + return pContext->ThrowNativeError("Element %d is out of bounds (Prop %s has %d elements).", \ + element, \ + prop, \ + td->fieldSize); \ + } \ + \ + offset = GetTypeDescOffs(td) + (element * (td->fieldSizeInBytes / td->fieldSize)); + +#define FIND_PROP_SEND(type, type_name) \ + sm_sendprop_info_t info;\ IServerUnknown *pUnk = (IServerUnknown *)pEntity; \ IServerNetworkable *pNet = pUnk->GetNetworkable(); \ if (!pNet) \ { \ return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \ } \ - if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \ + if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) \ { \ return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \ prop, \ params[1], \ class_name); \ + } \ + \ + offset = info.actual_offset; \ + bit_count = info.prop->m_nBits; \ + \ + switch (info.prop->GetType()) \ + { \ + case type: \ + { \ + if (element > 0) \ + { \ + return pContext->ThrowNativeError("SendProp %s is not an array. Element %d is invalid.", \ + prop, \ + element); \ + } \ + break; \ + } \ + case DPT_DataTable: \ + { \ + SendProp *pProp; \ + FIND_PROP_SEND_IN_SENDTABLE(info, pProp, element, type, type_name); \ + \ + offset += pProp->GetOffset(); \ + bit_count = pProp->m_nBits; \ + break; \ + } \ + default: \ + { \ + return pContext->ThrowNativeError("SendProp %s type is not " type_name " (%d != %d)", \ + prop, \ + info.prop->GetType(), \ + type); \ + } \ + } \ + +#define FIND_PROP_SEND_IN_SENDTABLE(info, pProp, element, type, type_name) \ + SendTable *pTable = info.prop->GetDataTable(); \ + if (!pTable) \ + { \ + return pContext->ThrowNativeError("Error looking up DataTable for prop %s", \ + prop); \ + } \ + \ + int elementCount = pTable->GetNumProps(); \ + if (element >= elementCount) \ + { \ + return pContext->ThrowNativeError("Element %d is out of bounds (Prop %s has %d elements).", \ + element, \ + prop, \ + elementCount); \ + } \ + \ + pProp = pTable->GetProp(element); \ + if (pProp->GetType() != type) \ + { \ + return pContext->ThrowNativeError("SendProp %s type is not " type_name " ([%d,%d] != %d)", \ + prop, \ + info.prop->GetType(), \ + info.prop->m_nBits, \ + type); \ } + inline int MatchFieldAsInteger(int field_type) { switch (field_type) @@ -1005,6 +1078,75 @@ inline int MatchFieldAsInteger(int field_type) return 0; } +static cell_t GetEntPropArraySize(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity *pEntity; + char *prop; + const char *class_name; + edict_t *pEdict; + + if (!IndexToAThings(params[1], &pEntity, &pEdict)) + { + return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); + } + + if (!pEdict || (class_name = pEdict->GetClassName()) == NULL) + { + class_name = ""; + } + + pContext->LocalToString(params[3], &prop); + + switch (params[2]) + { + case Prop_Data: + { + typedescription_t *td; + + FIND_PROP_DATA(td); + + return td->fieldSize; + } + case Prop_Send: + { + sm_sendprop_info_t info; + + IServerUnknown *pUnk = (IServerUnknown *)pEntity; + IServerNetworkable *pNet = pUnk->GetNetworkable(); + if (!pNet) + { + return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); + } + if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) + { + return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", + prop, + params[1], + class_name); + } + + if (info.prop->GetType() != DPT_DataTable) + { + return 0; + } + + SendTable *pTable = info.prop->GetDataTable(); + if (!pTable) + { + return pContext->ThrowNativeError("Error looking up DataTable for prop %s", prop); + } + + return pTable->GetNumProps(); + } + default: + { + return pContext->ThrowNativeError("Invalid Property type %d", params[2]); + } + } + + return 1; +} + static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params) { CBaseEntity *pEntity; @@ -1014,6 +1156,12 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params) edict_t *pEdict; int bit_count; + int element = 0; + if (params[0] >= 5) + { + element = params[5]; + } + if (!IndexToAThings(params[1], &pEntity, &pEdict)) { return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); @@ -1042,26 +1190,13 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params) td->fieldType); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Int) - { - return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)", - prop, - info.prop->GetType(), - info.prop->m_nBits, - DPT_Int); - } - - bit_count = info.prop->m_nBits; - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Int, "integer"); break; } default: @@ -1104,6 +1239,12 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params) edict_t *pEdict; int bit_count; + int element = 0; + if (params[0] >= 6) + { + element = params[6]; + } + if (!IndexToAThings(params[1], &pEntity, &pEdict)) { return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); @@ -1131,26 +1272,13 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params) td->fieldType); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Int) - { - return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)", - prop, - info.prop->GetType(), - info.prop->m_nBits, - DPT_Int); - } - - bit_count = info.prop->m_nBits; - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Int, "integer"); break; } default: @@ -1194,9 +1322,16 @@ static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity; char *prop; int offset; + int bit_count; const char *class_name; edict_t *pEdict; + int element = 0; + if (params[0] >= 4) + { + element = params[4]; + } + if (!IndexToAThings(params[1], &pEntity, &pEdict)) { return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); @@ -1227,24 +1362,13 @@ static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params) FIELD_TIME); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Float) - { - return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)", - prop, - info.prop->GetType(), - DPT_Float); - } - - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Float, "float"); break; } default: @@ -1263,9 +1387,16 @@ static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity; char *prop; int offset; + int bit_count; const char *class_name; edict_t *pEdict; + int element = 0; + if (params[0] >= 5) + { + element = params[5]; + } + if (!IndexToAThings(params[1], &pEntity, &pEdict)) { return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); @@ -1296,24 +1427,13 @@ static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params) FIELD_TIME); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Float) - { - return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)", - prop, - info.prop->GetType(), - DPT_Float); - } - - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Float, "float"); break; } default: @@ -1337,9 +1457,16 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity; char *prop; int offset; + int bit_count; const char *class_name; edict_t *pEdict; + int element = 0; + if (params[0] >= 4) + { + element = params[4]; + } + if (!IndexToAThings(params[1], &pEntity, &pEdict)) { return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); @@ -1368,24 +1495,13 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) FIELD_EHANDLE); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Int) - { - return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)", - prop, - info.prop->GetType(), - DPT_Int); - } - - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Int, "integer"); break; } default: @@ -1405,9 +1521,16 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity; char *prop; int offset; + int bit_count; const char *class_name; edict_t *pEdict; + int element = 0; + if (params[0] >= 5) + { + element = params[5]; + } + if (!IndexToAThings(params[1], &pEntity, &pEdict)) { return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); @@ -1436,24 +1559,13 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) FIELD_EHANDLE); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Int) - { - return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)", - prop, - info.prop->GetType(), - DPT_Int); - } - - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Int, "integer"); break; } default: @@ -1494,8 +1606,15 @@ static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity; char *prop; int offset; + int bit_count; const char *class_name; edict_t *pEdict; + + int element = 0; + if (params[0] >= 5) + { + element = params[5]; + } if (!IndexToAThings(params[1], &pEntity, &pEdict)) { @@ -1527,24 +1646,13 @@ static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params) FIELD_POSITION_VECTOR); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Vector) - { - return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)", - prop, - info.prop->GetType(), - DPT_Vector); - } - - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Vector, "vector"); break; } default: @@ -1570,8 +1678,15 @@ static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity; char *prop; int offset; + int bit_count; const char *class_name; edict_t *pEdict; + + int element = 0; + if (params[0] >= 5) + { + element = params[5]; + } if (!IndexToAThings(params[1], &pEntity, &pEdict)) { @@ -1603,24 +1718,13 @@ static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params) FIELD_POSITION_VECTOR); } - offset = GetTypeDescOffs(td); + CHECK_SET_PROP_DATA_OFFSET(); + break; } case Prop_Send: { - sm_sendprop_info_t info; - - FIND_PROP_SEND(&info); - - if (info.prop->GetType() != DPT_Vector) - { - return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)", - prop, - info.prop->GetType(), - DPT_Vector); - } - - offset = info.actual_offset; + FIND_PROP_SEND(DPT_Vector, "vector"); break; } default: @@ -1654,6 +1758,12 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params) const char *class_name; edict_t *pEdict; bool bIsStringIndex; + + int element = 0; + if (params[0] >= 6) + { + element = params[6]; + } if (!IndexToAThings(params[1], &pEntity, &pEdict)) { @@ -1690,14 +1800,46 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params) bIsStringIndex = (td->fieldType != FIELD_CHARACTER); + if (bIsStringIndex && element >= td->fieldSize) + { + return pContext->ThrowNativeError("Element %d is out of bounds (Prop %s has %d elements).", + element, + prop, + td->fieldSize); + } + else if (element > 1) + { + return pContext->ThrowNativeError("Prop %s is not an array. Element %d is invalid.", + prop, + element); + } + offset = GetTypeDescOffs(td); + if (bIsStringIndex) + { + offset += (element * (td->fieldSizeInBytes / td->fieldSize)); + } break; } case Prop_Send: { sm_sendprop_info_t info; + + IServerUnknown *pUnk = (IServerUnknown *)pEntity; + IServerNetworkable *pNet = pUnk->GetNetworkable(); + if (!pNet) + { + return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); + } + if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) + { + return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", + prop, + params[1], + class_name); + } - FIND_PROP_SEND(&info); + offset = info.actual_offset; if (info.prop->GetType() != DPT_String) { @@ -1706,9 +1848,13 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params) info.prop->GetType(), DPT_String); } - - offset = info.actual_offset; - break; + else if (element > 0) + { + return pContext->ThrowNativeError("SendProp %s is not an array. Element %d is invalid.", + prop, + element); + } + break; } default: @@ -2080,6 +2226,7 @@ REGISTER_NATIVES(entityNatives) {"GetEntDataString", GetEntDataString}, {"GetEntDataVector", GetEntDataVector}, {"GetEntProp", GetEntProp}, + {"GetEntPropArraySize", GetEntPropArraySize}, {"GetEntPropEnt", GetEntPropEnt}, {"GetEntPropFloat", GetEntPropFloat}, {"GetEntPropString", GetEntPropString}, diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 78da4e72..46810e9b 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * SourceMod (C)2004-2011 AlliedModders LLC. All rights reserved. * ============================================================================= * * This file is part of the SourceMod/SourcePawn SDK. @@ -504,10 +504,11 @@ stock GetEntSendPropOffs(ent, const String:prop[], bool:actual=false) * @param size Number of bytes to write (valid values are 1, 2, or 4). * This value is auto-detected, and the size parameter is * only used as a fallback in case detection fails. + * @param element Element # (starting from 0) if property is an array. * @return Value at the given property offset. * @error Invalid entity or property not found. */ -native GetEntProp(entity, PropType:type, const String:prop[], size=4); +native GetEntProp(entity, PropType:type, const String:prop[], size=4, element=0); /** * Sets an integer value in an entity's property. @@ -518,13 +519,15 @@ native GetEntProp(entity, PropType:type, const String:prop[], size=4); * @param entity Entity/edict index. * @param type Property type. * @param prop Property name. + * @param value Value to set. * @param size Number of bytes to write (valid values are 1, 2, or 4). * This value is auto-detected, and the size parameter is * only used as a fallback in case detection fails. + * @param element Element # (starting from 0) if property is an array. * @error Invalid entity or offset out of reasonable bounds. * @noreturn */ -native SetEntProp(entity, PropType:type, const String:prop[], any:value, size=4); +native SetEntProp(entity, PropType:type, const String:prop[], any:value, size=4, element=0); /** * Retrieves a float value from an entity's property. @@ -535,10 +538,11 @@ native SetEntProp(entity, PropType:type, const String:prop[], any:value, size=4) * @param entity Entity/edict index. * @param type Property type. * @param prop Property name. + * @param element Element # (starting from 0) if property is an array. * @return Value at the given property offset. * @error Invalid entity or offset out of reasonable bounds. */ -native Float:GetEntPropFloat(entity, PropType:type, const String:prop[]); +native Float:GetEntPropFloat(entity, PropType:type, const String:prop[], element=0); /** * Sets a float value in an entity's property. @@ -550,10 +554,11 @@ native Float:GetEntPropFloat(entity, PropType:type, const String:prop[]); * @param type Property type. * @param prop Property name. * @param value Value to set. + * @param element Element # (starting from 0) if property is an array. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -native SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value); +native SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value, element=0); /** * Retrieves an entity index from an entity's property. @@ -564,12 +569,13 @@ native SetEntPropFloat(entity, PropType:type, const String:prop[], Float:value); * @param entity Entity/edict index. * @param type Property type. * @param prop Property name. + * @param element Element # (starting from 0) if property is an array. * @return Entity index at the given property. * If there is no entity, or the entity is not valid, * then -1 is returned. * @error Invalid entity or offset out of reasonable bounds. */ -native GetEntPropEnt(entity, PropType:type, const String:prop[]); +native GetEntPropEnt(entity, PropType:type, const String:prop[], element=0); /** * Sets an entity index in an entity's property. @@ -581,10 +587,11 @@ native GetEntPropEnt(entity, PropType:type, const String:prop[]); * @param type Property type. * @param prop Property name. * @param other Entity index to set, or -1 to unset. + * @param element Element # (starting from 0) if property is an array. * @noreturn * @error Invalid entity or offset out of reasonable bounds. */ -native SetEntPropEnt(entity, PropType:type, const String:prop[], other); +native SetEntPropEnt(entity, PropType:type, const String:prop[], other, element=0); /** * Retrieves a vector of floats from an entity, given a named network property. @@ -596,11 +603,12 @@ native SetEntPropEnt(entity, PropType:type, const String:prop[], other); * @param type Property type. * @param prop Property name. * @param vec Vector buffer to store data in. + * @param element Element # (starting from 0) if property is an array. * @noreturn * @error Invalid entity, property not found, or property not * actually a vector data type. */ -native GetEntPropVector(entity, PropType:type, const String:prop[], Float:vec[3]); +native GetEntPropVector(entity, PropType:type, const String:prop[], Float:vec[3], element=0); /** * Sets a vector of floats in an entity, given a named network property. @@ -612,11 +620,12 @@ native GetEntPropVector(entity, PropType:type, const String:prop[], Float:vec[3] * @param type Property type. * @param prop Property name. * @param vec Vector to set. + * @param element Element # (starting from 0) if property is an array. * @noreturn * @error Invalid entity, property not found, or property not * actually a vector data type. */ -native SetEntPropVector(entity, PropType:type, const String:prop[], const Float:vec[3]); +native SetEntPropVector(entity, PropType:type, const String:prop[], const Float:vec[3], element=0); /** * Gets a network property as a string. @@ -626,10 +635,11 @@ native SetEntPropVector(entity, PropType:type, const String:prop[], const Float: * @param prop Property to use. * @param buffer Destination string buffer. * @param maxlen Maximum length of output string buffer. + * @param element Element # (starting from 0) if property is an array. * @return Number of non-null bytes written. * @error Invalid entity, offset out of reasonable bounds, or property is not a valid string. */ -native GetEntPropString(entity, PropType:type, const String:prop[], String:buffer[], maxlen); +native GetEntPropString(entity, PropType:type, const String:prop[], String:buffer[], maxlen, element=0); /** * Sets a network property as a string. @@ -646,6 +656,17 @@ native GetEntPropString(entity, PropType:type, const String:prop[], String:buffe */ native SetEntPropString(entity, PropType:type, const String:prop[], const String:buffer[]); +/** + * Retrieves the count of values that an entity property's array can store. + * + * @param entity Entity/edict index. + * @param type Property type. + * @param prop Property name. + * @return Size of array (in elements) or 1 if property is not an array. + * @error Invalid entity or property not found. + */ +native GetEntPropArraySize(entity, PropType:type, const String:prop[]); + /** * Copies an array of cells from an entity at a given offset. * diff --git a/plugins/testsuite/entpropelements.sp b/plugins/testsuite/entpropelements.sp new file mode 100644 index 00000000..32355a12 --- /dev/null +++ b/plugins/testsuite/entpropelements.sp @@ -0,0 +1,163 @@ +#include +#include + +// Coverage: +// GetEntPropArraySize - PropSend/PropData + +// GetEntPropString - PropData + +// GetEntProp - PropSend/PropData +// GetEntPropEnt - PropSend/PropData + +// SetEntProp - PropSend/PropData + +public OnPluginStart() +{ + RegConsoleCmd("sm_listammo", sm_listammo, "sm_listammo [target] - Lists current ammo for self or specified player"); + RegConsoleCmd("sm_listweapons", sm_listweapons, "sm_listweapons [target] - Lists current weapons for self or specified player"); + RegConsoleCmd("sm_setammo", sm_setammo, "sm_setammo [target]"); + RegConsoleCmd("sm_teststrings", sm_teststrings); +} + +public Action:sm_listammo(client, argc) +{ + decl String:buffer[64]; + new target = client; + if (argc >= 2) + { + GetCmdArg(2, buffer, sizeof(buffer)); + target = FindTarget(client, buffer, false, false); + if (target <= 0) + { + ReplyToCommand(client, "Bad client"); + return Plugin_Handled; + } + } + else if (client == 0) + { + ReplyToCommand(client, "Dillweed"); + return Plugin_Handled; + } + + new PropType:proptype = PropType:-1; + GetCmdArg(1, buffer, sizeof(buffer)); + if (!strcmp(buffer, "send")) + proptype = Prop_Send; + else if (!strcmp(buffer, "data")) + proptype = Prop_Data; + + new ammo; + new max = GetEntPropArraySize(target, proptype, "m_iAmmo"); + for (new i = 0; i < max; i++) + { + if ((ammo = GetEntProp(target, proptype, "m_iAmmo", _, i)) > 0) + ReplyToCommand(client, "Slot %d, Ammo %d", i, ammo); + } + + return Plugin_Handled; +} + +public Action:sm_listweapons(client, argc) +{ + decl String:buffer[64]; + new target = client; + if (argc >= 2) + { + GetCmdArg(2, buffer, sizeof(buffer)); + target = FindTarget(client, buffer, false, false); + if (target <= 0) + { + ReplyToCommand(client, "Bad client"); + return Plugin_Handled; + } + } + else if (client == 0) + { + ReplyToCommand(client, "Dillweed"); + return Plugin_Handled; + } + + new PropType:proptype = PropType:-1; + GetCmdArg(1, buffer, sizeof(buffer)); + if (!strcmp(buffer, "send")) + proptype = Prop_Send; + else if (!strcmp(buffer, "data")) + proptype = Prop_Data; + + new weapon, String:classname[64]; + new max = GetEntPropArraySize(target, proptype, "m_hMyWeapons"); + for (new i = 0; i < max; i++) + { + if ((weapon = GetEntPropEnt(target, proptype, "m_hMyWeapons", i)) == -1) + continue; + + GetEdictClassname(weapon, classname, sizeof(classname)); + ReplyToCommand(client, "Slot %d - \"%s\"", i, classname); + } + + return Plugin_Handled; +} + +public Action:sm_setammo(client, argc) +{ + decl String:buffer[64]; + new target = client; + if (argc >= 4) + { + GetCmdArg(4, buffer, sizeof(buffer)); + target = FindTarget(client, buffer, false, false); + if (target <= 0) + { + ReplyToCommand(client, "Bad client"); + return Plugin_Handled; + } + } + else if (client == 0) + { + ReplyToCommand(client, "Dillweed"); + return Plugin_Handled; + } + + new PropType:proptype = PropType:-1; + GetCmdArg(3, buffer, sizeof(buffer)); + if (!strcmp(buffer, "send")) + proptype = Prop_Send; + else if (!strcmp(buffer, "data")) + proptype = Prop_Data; + + new max = GetEntPropArraySize(target, proptype, "m_iAmmo"); + + GetCmdArg(1, buffer, sizeof(buffer)); + new ammotype = StringToInt(buffer); + + if (ammotype >= max) + { + ReplyToCommand(client, "Ammotype out of bounds"); + return Plugin_Handled; + } + + GetCmdArg(2, buffer, sizeof(buffer)); + new amount = StringToInt(buffer); + + SetEntProp(target, proptype, "m_iAmmo", amount, _, ammotype); + + return Plugin_Handled; +} + +public Action:sm_teststrings(client, argc) +{ + new gpe = CreateEntityByName("game_player_equip"); + DispatchKeyValue(gpe, "tf_weapon_rocketlauncher", "2"); + DispatchKeyValue(gpe, "tf_weapon_pistol", "1"); + + decl String:value[64]; + for (new i = 0; i < 2; i++) + { + GetEntPropString(gpe, Prop_Data, "m_weaponNames", value, sizeof(value), i); + ReplyToCommand(client, "At %d, I see a \"%s\"", i, value); + } + + AcceptEntityInput(gpe, "Kill"); + + return Plugin_Handled; +}