[HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

For scripting examples for learning how to use AMXX.
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

[HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

I noticed that many coders dealing with weapon drop. Often they have problems with detection of some of the following details:
- WeaponBoxOwnerClientIndex
- WeaponDropType
- WeaponIndex
- WeaponName
- WeaponBoxEntityIndex
- WeaponEntityIndex
- WeaponBoxModel
Note: The weaponbox entity is not the actual weapon, it is the "box" entity that "contain" the weapon_* entity, i.e. the actual weapon entity. Of course weapon_* entities classnames (which equal to weapon names) are unique for the different weapon types. The actual weapon type is stored in the weapon's entity private data area that can be easily accessed via corresponding native function from the cstrike module.

This script shows how to retrieve the details that is listed above:

Code: Select all

/* AMX Mod X
*   Weapon Drop Details
*
* (c) Copyright 2007 by VEN
*
* This file is provided as is (no warranties)
*/

#include <amxmodx>
#include <fakemeta>
#include <cstrike>

#define PLUGIN_NAME "Weapon Drop Details"
#define PLUGIN_VERSION "0.1"
#define PLUGIN_AUTHOR "VEN"

enum droptype {
    droptype_manual,
    droptype_onbuy,
    droptype_ondeath,
    droptype_ondisconnect
}

new const g_drop_type[droptype][] = {
    "Manual",
    "OnBuy",
    "OnDeath",
    "OnDisconnect"
}

new const g_drop[] = "drop"

#define MAX_PLAYERS 32
new g_command[MAX_PLAYERS + 1][sizeof g_drop + 1]

new const g_wbox_class[] = "weaponbox"
new const g_wbox_model[] = "models/w_weaponbox.mdl"
new const g_wbox_model_prefix[] = "models/w_"

stock const g_start_client_index = 1

new g_max_clients
new g_max_entities

public plugin_init() {
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

    register_forward(FM_SetModel, "forward_set_model")

    g_max_clients = global_get(glb_maxClients)
    g_max_entities = global_get(glb_maxEntities)
}

public client_command(id) {
    read_argv(0, g_command[id], sizeof g_drop)
}

public forward_set_model(ent, const model[]) {
    if (!pev_valid(ent) || !equali(model, g_wbox_model_prefix, sizeof g_wbox_model_prefix - 1) || equali(model, g_wbox_model))
        return FMRES_IGNORED

    new id = pev(ent, pev_owner)
    if (!(g_start_client_index <= id <= g_max_clients))
        return FMRES_IGNORED

    static class[32]
    pev(ent, pev_classname, class, sizeof class - 1)
    if (!equal(class, g_wbox_class))
        return FMRES_IGNORED

    for (new i = g_max_clients + 1; i < g_max_entities; ++i) {
        if (!pev_valid(i) || ent != pev(i, pev_owner))
            continue

        new wid = cs_get_weapon_id(i)
        new droptype:drop_type
        if (!is_user_connected(id))
            drop_type = droptype_ondisconnect
        else if (!is_user_alive(id))
            drop_type = droptype_ondeath
        else if (equal(g_command[id], g_drop))
            drop_type = droptype_manual
        else if (wid != CSW_C4)
            drop_type = droptype_onbuy
        else
            return FMRES_IGNORED

        pev(i, pev_classname, class, sizeof class - 1)

        server_print("BoxOwnerClientIndex: %2d, DropType: %-12s, Index: %2d, Name: %-16s, BoxEntityIndex: %3d, EntityIndex: %3d, BoxModel: %s", id, g_drop_type[drop_type], wid, class, ent, i, model)

        return FMRES_IGNORED
    }

    return FMRES_IGNORED
}
Attachments
weapon_drop_details.sma.zip
(1.12 KiB) Downloaded 17 times
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

Re: [HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

Here is the similar script but for Touch case, now with comments

Code: Select all

/* AMX Mod X
*   Weapon Touch Details
*
* (c) Copyright 2007 by VEN
*
* This file is provided as is (no warranties)
*/

#include <amxmodx>
#include <fakemeta>
#include <cstrike>

#define PLUGIN_NAME "Weapon Touch Details"
#define PLUGIN_VERSION "0.1"
#define PLUGIN_AUTHOR "VEN"

// comment to also process a weapons that isn't on the floor/ground
#define SKIP_WEAPS_THAT_ISNT_ON_GROUND

new const g_wbox_class[] = "weaponbox"
new const g_wbox_model[] = "models/w_weaponbox.mdl"

stock const g_wbox_custom_iuser_pev_num = pev_iuser3

stock const g_client_start_index = 1

new g_max_clients
new g_max_entities

public plugin_init() {
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

    register_forward(FM_Touch, "forward_touch")

    g_max_clients = global_get(glb_maxClients)
    g_max_entities = global_get(glb_maxEntities)
}

public forward_touch(ent, toucher) {
    // if toucher isn't a client or entity isn't valid
    if (!(g_client_start_index <= toucher <= g_max_clients) || !pev_valid(ent))
        return FMRES_IGNORED

#if defined SKIP_WEAPS_THAT_ISNT_ON_GROUND
    // is weapon not on the floor/ground?
    if (!engfunc(EngFunc_EntIsOnFloor, ent))
        return FMRES_IGNORED
#endif

    // if this check is return true then this is a weaponbox that already touched by this player
    // so to avoid flood of our informational text in the server console do not go further
    if (pev(ent, g_wbox_custom_iuser_pev_num) == toucher)
        return FMRES_IGNORED

    static string[32]
    pev(ent, pev_classname, string, sizeof string - 1)

    // required entity classname are "weaponbox"
    if (!equal(string, g_wbox_class))
        return FMRES_IGNORED

    new id = pev(ent, pev_owner)

    // weaponbox must be owned by a player, in other case it is kind of invalid weaponbox o_O
    if (!(g_client_start_index <= id <= g_max_clients))
        return FMRES_IGNORED

    pev(ent, pev_model, string, sizeof string - 1)

    // if weaponbox model are "models/w_weaponbox.mdl" then weapon_* entity isn't linked to that weaponbox yet
    if (equali(string, g_wbox_model))
        return FMRES_IGNORED

    for (new i = g_max_clients + 1; i < g_max_entities; ++i) {
        // search for an entity that is owned by the weaponbox, this should be a weapon_* entity
        if (!pev_valid(i) || ent != pev(i, pev_owner))
            continue

        // get a weapon type of the weapon_* entity
        new wid = cs_get_weapon_id(i)

        // the a clsssname of the weapon_* entity (it is equal to a weapon name)
        pev(i, pev_classname, string, sizeof string - 1)

        // set the toucher client index to the custom iuser pev field
        set_pev(ent, g_wbox_custom_iuser_pev_num, toucher)

        // output details to the server console
        server_print("BoxToucherClientIndex: %2d, BoxOwnerClientIndex: %2d, Index: %2d, Name: %-16s, BoxEntityIndex: %3d, EntityIndex: %3d", toucher, id, wid, string, ent, i)

        return FMRES_IGNORED
    }

    return FMRES_IGNORED
}
Attachments
weapon_drop_details.sma.2.zip
(1.36 KiB) Downloaded 19 times
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

Re: [HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

Nice work! But, for this to distinguish properly between dropped manually and dropped on buy, I must assume that a client_command is called when a user buys something via clicking the menus?
Yes, the client_command is called on buy of course. But i didn't care to check that because any drop that isn't related to Manual/OnDeath/OnDisconnect should be OnBuy (at least for CS, i do not know another drop type). But i should warn that amxmodx/metamod plugins/modules could mess with the command checking by emulating the commands.
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

Re: [HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

I wonder if you could figure out how to do this for The Specialists. I've tried similar methods to yours for trying to determine who dropped a weapon without success.

The classname of the dropped weapon is WorldGun, the pev_owner is always 0. I've tried accessing the pdata of WorldGun but the server crashes when I attempt to do so. Maybe I was accessing the pdata too soon? (FM_SetModel)

I've looked at pev_euser*, pev_fuser*, pev_iuser*, pev_vuser*, pev_controller, pev_controller_*, but none of these values have the id of the client who dropped the weapon. Most of the values are all 0. Only pev_fuser1 was 1.

If you can give me some ideas, I'll test them myself. I'd appreciate your input, VEN.

EDIT: I was accessing the pdata too soon. I threw in a set_task() to delay checking the pdata, but still no luck. No values that match the client's id.
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

Re: [HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

yea VEN please help us with this it looks a bit gay when i have my custom v_model & p_model but when i throw it away its the standard katana :O pleeeaaaseee help stupok with this
Try this

Code: Select all

 static Float:origin[3]
        pev(ent, pev_origin, origin)

        new x = FM_NULLENT
        while ((x = engfunc(EngFunc_FindEntityInSphere, x, origin, 16.0))) {
                if (!(g_client_start_index <= x <= g_max_clients))
                        continue

                static Float:v1[3], Float:v2[3]
                pev(x, pev_origin, v1)
                pev(x, pev_angles, v2)
                engfunc(EngFunc_MakeVectors, v2)
                global_get(glb_v_forward, v2)
                xs_vec_mul_scalar(v2, 10.0, v2)
                xs_vec_add(v1, v2, v1)
                if (!xs_vec_equal(v1, origin))
                        continue

                server_print("WeaponOwnerClientIndex: %d", x)
                break
        }
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

Re: [HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

Thanks for your input.

I'm wondering, when should I execute that code? FM_SetOrigin?

EDIT:

I tried doing something similar on my own, checking for an entity in the sphere around the weapon that was dropped. However, it seems the weapon that was dropped is not assigned an origin until it collides with something. FM_SetOrigin is called on the dropped weapon when it hits a wall or touches the floor.

Here's what I'm doing:

Code: Select all

public VEN_function(ent)
{
    static Float:origin[3]
    pev(ent, pev_origin, origin)
    
    server_print("ent origin: %f %f %f", origin[0], origin[1], origin[2])
    
    new x = FM_NULLENT
    while ((x = engfunc(EngFunc_FindEntityInSphere, x, origin, 16.0)))
    {
        server_print("x: %i", x)
        
        if (!(g_client_start_index <= x <= g_max_clients))
            continue
        
        server_print("x is valid")
        
        static Float:v1[3], Float:v2[3]
        pev(x, pev_origin, v1)
        pev(x, pev_angles, v2)
        
        server_print("x origin: %f %f %f", v1[0], v1[1] ,v1[2])
        server_print("x angles: %f %f %f", v2[0], v2[1], v2[2])
        
        engfunc(EngFunc_MakeVectors, v2)
        global_get(glb_v_forward, v2)
        xs_vec_mul_scalar(v2, 10.0, v2)
        xs_vec_add(v1, v2, v1)
        
        server_print("modified v1: %f %f %f", v1[0], v1[1] ,v1[2])
        
        if (!xs_vec_equal(v1, origin))
            continue
        
        server_print("WeaponOwnerClientIndex: %d", x)
        break
    }
}

public forward_SetModel(ent, model[])
{
    if(equal(model, "models/w_katana.mdl"))
    {
        VEN_function(ent)
    }
    
    return FMRES_IGNORED
}
Here is the output from my debug messages:

Code: Select all

ent origin: 0.000000 0.000000 0.000000
x: 12
x: 13
x: 14
x: 15
x: 249
x: 250
(This is on a 10 slot server, g_client_start_index is set to 1)
User avatar
Archive-Poster
Posts: 1249
Gender:
United States of America

Re: [HowTo] Detect weapon Drop/Touch details [including drop type, weapon type, etc]

Post by Archive-Poster »

what's wrong with Ham_Item_Drop ??
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest