.:: Bots United ::.

.:: Bots United ::. (http://forums.bots-united.com/index.php)
-   General Bot Coding (http://forums.bots-united.com/forumdisplay.php?f=24)
-   -   How to detect entity [properties] ? (http://forums.bots-united.com/showthread.php?t=1773)

Tea 26-05-2004 00:31

How to detect entity [properties] ?
 
Code:

if (strcmp("dod_control_point", item_name) == 0)
I can use this code to detect a control point, however, I need more information of this control point, I knew the dod_control_point have more properties like :

point_allies_model
point_allies_model_bodygroup
point_allies_target
point_allies_win_string
etc......

But how can I detect it ?

Pierre-Marie Baty 26-05-2004 01:07

Re: How to detect entity [properties] ?
 
I don't know... are you talking about the entity's infobuffer ?

Look in some CS bot source code for the function that tells which team a bot is on. It calls the infobuffer and retrieves the "model" field. You may use the same method I believe. (curious, though, as I believed only game clients could have infobuffers ?)

botman 26-05-2004 15:13

Re: How to detect entity [properties] ?
 
PM, I think he's refering to properties (key/value pairs) that can be set by level designers (mappers).

Tea, entity variables are usually stored as Class member variables in the MOD source code class definition (which you don't have the source code for). You can access these values by using the pvPrivateData point in the entvars structure. The pvPrivateData will point to the memory allocated by the engine for that Class instance. For example, if you create a CBasePlayer class in the MOD code, the engine will allocate space for the CBasePlayer class (which will probably not contain the same variables that the standard Half-Life SDK source code comes with, so don't assume these are the same). You can dump the pvPrivateData section of memory to see what byte values change when one of these class member variables is updated.

A cleaner way to do this is to intercept the entity being spawned by the engine. The HPB bot does this for several entities, for example in TFC, the "info_tfdetect" entity is used to determine how many players are allowed on each team and how many teams there are. I intercept the "info_tfdetect" entity when it is being spawned and save the values of the key/value pairs in DispatchKeyValue() (in the dll.cpp file) when the entity is spawned. This method will ONLY work for things that DON'T change their value while the game is being played. For example, if you had something that toggle off and on (like a capture point) while the game is playing, you would have to intercept other network messages to know what the current state of that entity is.

botman

BAStumm 26-05-2004 18:04

Re: How to detect entity [properties] ?
 
Code:

                //DoD flag info
                for (i = 0; i < DOD_FLAG_MAX && (pent = UTIL_FindEntityByClassname(pent, "dod_control_point")) != NULL; i++)
                {
                                flag_team = -1;
               
                                sprintf(temp_data[DOD_FLAG_NUM][i + 1], "%i", i);
                                sprintf(temp_data[DOD_FLAG_X_COORD][i + 1], "%f", pent->v.origin.x - x_offset);
                                sprintf(temp_data[DOD_FLAG_Y_COORD][i + 1], "%f", pent->v.origin.y - y_offset);
                                sprintf(temp_data[DOD_FLAG_Z_COORD][i + 1], "%f", pent->v.origin.z);
                                sprintf(temp_data[DOD_FLAG_TEAM][i + 1], "%i", pent->v.body);
                                sprintf(temp_data[DOD_FLAG_MODEL][i + 1], "%s", STRING(pent->v.model));
                                sprintf(temp_data[DOD_FLAG_NAME][i + 1], "%s", STRING(pent->v.netname));
                }


Tea 26-05-2004 23:01

Re: How to detect entity [properties] ?
 
Code:


 
void KeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
int dod_flag = 0;
 
if (mod_id == DOD_DLL)
{
        if (pentKeyvalue == pent_dod_control_point)
        {
                if (strcmp(pkvd->szKeyName, "point_allies_target") == 0)
                        dod_flag = atoi(pkvd->szValue);
        }
}
 
RETURN_META (MRES_IGNORED);
}

Botman tks for the reply, I have added this code in dll.cpp, is it correct ? And if I want to call this function in bot.cpp, what command should I use ? something like keyvalue ( ??? ); ?

BAStumm, since I am very new of bot coding and C++ so I didn't understand the code you show me, could you tell me more detail what are each line of the code doing so I can learn it but not just copy it, thank you very much. :)

botman 27-05-2004 15:25

Re: How to detect entity [properties] ?
 
Intercepting the key/value pairs of an entity is a little more complex than that. First you have to store the entvars pointer when the entity is created, then in DispatchKeyValue, when keys are stored for that specific entity, you can examine what the values of those keys are.

For the HPB bot, I keep a global variable to store the pent (entvars pointer)...

Code:

edict_t *pent_info_tfdetect = NULL;
This variable gets NULLed out everytime a new map begins loading (when the code sees the "worldspawn" entity being created).

In DispatchKeyValue(), I check to see if an entity is being created by looking for the "classname" key (since Worldcraft/Hammer always makes the "classname" for entities the first key to be passed into the MOD code)...
Code:

        else if (pent_info_tfdetect == NULL)
        {
                if ((strcmp(pkvd->szKeyName, "classname") == 0) &&
                        (strcmp(pkvd->szValue, "info_tfdetect") == 0))
                {
                        pent_info_tfdetect = pentKeyvalue;
                }
        }

....and then, also in DispatchKeyValue(), when other keys are being passed to the MOD code, I compare the pentKeyvalue being passed in to the pointer of the specific entity I am looking for and check which key is being passed in...
Code:

if (mod_id == TFC_DLL)
{
        if (pentKeyvalue == pent_info_tfdetect)
        {
                if (strcmp(pkvd->szKeyName, "ammo_medikit") == 0) // max BLUE players
                        max_team_players[0] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "ammo_detpack") == 0) // max RED players
                        max_team_players[1] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "maxammo_medikit") == 0) // max YELLOW players
                        max_team_players[2] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "maxammo_detpack") == 0) // max GREEN players
                        max_team_players[3] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "maxammo_shells") == 0) // BLUE class limits
                        team_class_limits[0] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "maxammo_nails") == 0) // RED class limits
                        team_class_limits[1] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "maxammo_rockets") == 0) // YELLOW class limits
                        team_class_limits[2] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "maxammo_cells") == 0) // GREEN class limits
                        team_class_limits[3] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "team1_allies") == 0) // BLUE allies
                        team_allies[0] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "team2_allies") == 0) // RED allies
                        team_allies[1] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "team3_allies") == 0) // YELLOW allies
                        team_allies[2] = atoi(pkvd->szValue);
                else if (strcmp(pkvd->szKeyName, "team4_allies") == 0) // GREEN allies
                        team_allies[3] = atoi(pkvd->szValue);
        }

So in your case, you would need a global variable for the control_flag entity (assuming that was what DoD called that entity)...
Code:

edict_t *control_point = NULL;
int dod_flag; // entity 'control_flag' key "point_allies_target" calue gets stored here

...you would need to NULL it out when the world is spawned (in DispatchSpawn)...
Code:

        if (strcmp(pClassname, "worldspawn") == 0)
        {
                // do level initialization stuff here...
 
                control_point = NULL;

...and you need to add the checks in DispatchKeyValue()...
Code:

if (mod_id == DOD_DLL)
{
        if (pentKeyvalue == control_point)
        {
                if (strcmp(pkvd->szKeyName, "point_allies_target") == 0)
                        dod_flag = atoi(pkvd->szValue);
        }
        else if (control_point == NULL)
        {
                if ((strcmp(pkvd->szKeyName, "classname") == 0) &&
                        (strcmp(pkvd->szValue, "control_point") == 0))
                {
                        control_point = pentKeyvalue;
                }
        }

...and then once the map is completely loaded, you can just examine the 'dod_flag' variable to see what the 'control_point' entity had in the "point_allies_target" key when that entity was spawned.

If there was more than one 'control_point' entity, then you would have to create and array of global edict_t pointers, and store each one separately. All of the entities that I intercept in the HPB bot code are assumed to have only 1 of those entities in each map (the HPB bot code doesn't contain any examples of reading the key/value properties from a bunch of entities having the exact same classname).

botman

Tea 28-05-2004 02:06

Re: How to detect entity [properties] ?
 
I have tired your suggest but still no luck, then I think maybe the point_allies_target not use in this way, so I have changed to use flag_model to detect, but the result is the same........ :(

Code:

edict_t *dod_control_point = NULL;
int dod_flag;

Code:

int Spawn( edict_t *pent )
{
dod_control_point = NULL;

Code:


void KeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
if (mod_id == DOD_DLL)
{
if (pentKeyvalue == dod_control_point)
{
if ((strcmp(pkvd->szKeyName, "mdl") == 0) &&
        (strcmp(pkvd->szValue, "models/w_aflag.mdl") == 0))
{
        //allies flag
        dod_flag = 1;
}
else if ((strcmp(pkvd->szKeyName, "mdl") == 0) &&
        (strcmp(pkvd->szValue, "models/w_gflag.mdl") == 0))
{
        //axis flag
        dod_flag = 2;
}
else if ((strcmp(pkvd->szKeyName, "mdl") == 0) &&
        (strcmp(pkvd->szValue, "models/w_wflag.mdl") == 0))
{
        //free flag
        dod_flag = 0;
}
}
else if (dod_control_point == NULL)
{
if ((strcmp(pkvd->szKeyName, "classname") == 0) &&
        (strcmp(pkvd->szValue, "dod_control_point") == 0))
{
        dod_control_point = pentKeyvalue;
}
}
}
RETURN_META (MRES_IGNORED);
}

And I have added some code in bot.cpp under BotFindItem()

Code:


void BotFindItem( bot_t *pBot )
extern int dod_flag;
{
if ((strcmp("dod_control_point", item_name) == 0) && (dod_flag = 0))
{
                        // check if the item is not visible (i.e. has not respawned)
                        if (pent->v.effects & EF_NODRAW)
                                continue;
 
                        FakeClientCommand(pEdict,"say","This is a FREE FLAG",0);
                        can_pickup = TRUE;
}
else if ((strcmp("dod_control_point", item_name) == 0) && (dod_flag = 1))
{
                        // check if the item is not visible (i.e. has not respawned)
                        if (pent->v.effects & EF_NODRAW)
                                continue;
 
                        FakeClientCommand(pEdict,"say","This is a ALLIES FLAG",0);
                        can_pickup = TRUE;
}
else if ((strcmp("dod_control_point", item_name) == 0) && (dod_flag = 2))
{
                        // check if the item is not visible (i.e. has not respawned)
                        if (pent->v.effects & EF_NODRAW)
                                continue;
 
                        FakeClientCommand(pEdict,"say","This is a AXIS FLAG",0);
                        can_pickup = TRUE;
}
}

Now I have few questions:

1: Bots are only keep saying This is a ALLIES FLAG no matter which flag he saw, even before he spawn(in the dead mode), he has already keep saying this, that mean dod_flag always = 1, botman could you take a quick look of my above code to see if I have any mistake ?

2: Even I force the dod_flag to 0 (dod_flag = 0) at the top of BotFindItem(), bot still keep say this is a ALLIES FLAG but not FREE flag. ???:(

3: How do I know if my Keyvalue() have already ran and work ?
FakeClientCommand(pEdict,"say","XXXX",0); not work in Keyvalue() , I have tried ClientPrint( pPlayer, HUD_PRINTNOTIFY, "XXXX\n"); but didn't see any message(maybe Keyvalue run before client connect ?), could you teach me which command can I use to debug in keyvalue ?

4: How can I call the Keyvalue() anytime just like the way I call the UTIL_GetTeam(pEdict) ? Please tell me the full command since I donno enter what after Keyvalue ?
Code:

Keyvalue (What should I enter here ?);
5: Which command should I use to show the pkvd->szValue to me ? Let say:
Code:


if (strcmp(pkvd->szKeyName, "point_allies_target") == 0)
 
{
Which command should I use to show this pkvd->szValue to me on screen ?
}

Thank you very much again for your time. :)

Pierre-Marie Baty 28-05-2004 03:26

Re: How to detect entity [properties] ?
 
I don't understand why all this stuff is needed.

Wouldn't it be more simple to have something like this :
Code:

#define FLAG_ALLIES 2
#define FLAG_AXIS 1
#define FLAG_FREE 0

Code:

int GetFlagType (edict_t *pFlagEdict)
{
  // look inside pFlagEdict's entvars and stop by the model...
  if (strcmp ("models/w_aflag.mdl", STRING (pFlagEdict->v.model)) == 0)
          return (FLAG_ALLIES); // this one is an allied flag
  else if (strcmp ("models/w_gflag.mdl", STRING (pFlagEdict->v.model)) == 0)
          return (FLAG_AXIS); // this one is an evil nazi flag
  else
          return (FLAG_FREE); // if none of the above, the flag must be free
}

and then later on use it like this
Code:

// in BotFindItem()
int flag_team = GetFlagType (pent);
 
if ((strcmp("dod_control_point", item_name) == 0) && (flag_team == FLAG_ALLIES))
  // do stuff for allies flag
else if ((strcmp("dod_control_point", item_name) == 0) && (flag_team == FLAG_AXIS))
  // do stuff for axis flag
else if ((strcmp("dod_control_point", item_name) == 0) && (flag_team == FLAG_FREE))
  // do stuff for free flag


Tea 28-05-2004 03:56

Re: How to detect entity [properties] ?
 
PM this code can work in most of the mod but not DoD, since bot in DoD can't see any w_sub_flag.mdl, they(allies and axis) only can see one model name w_flag.mdl.

DoD team use the properties function to let client show the right flag model only after you captured it.

Cpl. Shrike 31-05-2004 11:55

Re: How to detect entity [properties] ?
 
You have to dinamicaly store the flags state during gameplay.
Don't scan the flag but catch the dod net message "CapMsg"
Store the value then let the bots check that value when it sees that flag.

"CapMsg" has 2 important variables.
the flags name (location)
the team it's owned by.

Those to variables are enuf to store the owner to the flag location.

KickBot 31-05-2004 14:36

Re: How to detect entity [properties] ?
 
Quote:

Originally Posted by Tea
2: Even I force the dod_flag to 0 (dod_flag = 0) at the top of BotFindItem(), bot still keep say this is a ALLIES FLAG but not FREE flag. ???:(

You use the "=" assignment operator instead of comparison "==" in all your "dod_flag" tests in this function. :)
I can't help with your other questions, I have no experience with the keys system or Dod in general. :(

Tea 03-06-2004 12:41

Re: How to detect entity [properties] ?
 
OMG KickBot you got a pair of bright eyes and help me a lot ! Thank you very much :D

Now my final question is how can I call the Keyvalue() in the bot.cpp ? Please teach me the full command, botman could you give me the last help ? thanks. :)

Shrike thanks for you suggest, I have think of this way before, but I think botman way is better, since if I can get use to the keyvalue function, my bot can auto detect many other thing so I don't have to use many specific waypoint.

botman 03-06-2004 16:08

Re: How to detect entity [properties] ?
 
"Now my final question is how can I call the Keyvalue() in the bot.cpp ?"

DispatchKeyValue() is used by the engine to tell the MOD DLL code what a value for a key is for an entity.

The engine creates the entity, then calls DispatchKeyValue() for each key in the entity that the level designer has specified (see the Worldcraft/Hammer .fgd file for details on which key/value pairs exist for each entity in the MOD). If there are 5 keys in the entity, DispatchKeyValue() will be called 5 times with the same edict_t pointer value (pointing to the same entity).

You can intercept these calls to DispatchKeyValue() to observe what values are being assigned to an entity when it spawns.

Go back and look at the code I posted for the "info_tfdetect" entity for TFC. That shows how you intercept the key/value data.

I can't explain it any more than this. The HPB bot code shows how it's done. You might want to set breakpoints in the DispatchKeyValue() function in the HPB bot and trace through that code to see what the engine is passing to the MOD code.

botman

Cpl. Shrike 03-06-2004 17:17

Re: How to detect entity [properties] ?
 
Quote:

Originally Posted by Tea
Shrike thanks for you suggest, I have think of this way before, but I think botman way is better, since if I can get use to the keyvalue function, my bot can auto detect many other thing so I don't have to use many specific waypoint.

I didn't mean to store it in a waypoint.
Only store the flags team owner.

Tea 03-06-2004 17:46

Re: How to detect entity [properties] ?
 
botman I understand how is keyvalue work but I don't know how to call it again after the bot spawned, because now it only detect one time when the bot spawn, but since the flag model in dod always change when someone captured it, so I have to call keyvalue () again before to detect the flag model each time.

Like when I want to call a XXXX(void),
I have to type XXXX();

When I want to call the ClientPrint( edict_t *pEntity, int msg_dest, const char *msg_name),
I have to type ClientPrint(pEntity, HUD_PRINTNOTIFY, "testing");

But how to call KeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ),
I have to type KeyValue( xxxxxxxxxxxxxx ); ???

Tea 03-06-2004 17:57

Re: How to detect entity [properties] ?
 
Shrike I know what you mean, but if KeyValue() can do the same thing than I don't have to store the flag data everytime, since KeyValue() also can do many other thing rather than check the flag model, if I know how to use it, I can also detect a breakable wall is belong to axis or allies, a breakable tank is belong to axis or allies...etc, since those map marker did store many very useful information in the entity properties.

BTW if you know my question (how to call KeyValue() again after the bot spawned), could you help me ?

Cpl. Shrike 03-06-2004 20:20

Re: How to detect entity [properties] ?
 
I didn't find a way to detect that on the dod flags.
because they are dynamical.
breakable walls and stuff are static... created at map start.
Well the flag is also created at map start but DOD sends a netmessage to client and on that the client displays the right flag model.
Well actually it the same for breakable wall but then the not_draw flag gets set.

Pierre-Marie Baty 04-06-2004 02:40

Re: How to detect entity [properties] ?
 
Quote:

Originally Posted by Tea
botman I understand how is keyvalue work but I don't know how to call it again after the bot spawned, because now it only detect one time when the bot spawn, but since the flag model in dod always change when someone captured it, so I have to call keyvalue () again before to detect the flag model each time.

Like when I want to call a XXXX(void),
I have to type XXXX();

When I want to call the ClientPrint( edict_t *pEntity, int msg_dest, const char *msg_name),
I have to type ClientPrint(pEntity, HUD_PRINTNOTIFY, "testing");

But how to call KeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ),
I have to type KeyValue( xxxxxxxxxxxxxx ); ???

Hmm no, you did not understand how that keyvalue works.
DispatchKeyValue() is not a function you can CALL.
DispatchKeyValue() is a function you HOOK. It is part of the GameDLL interface.
Look around in the HPB_bot code and you'll see that nowhere ever does botman call DispatchKeyValue() from the bot code.
DispatchKeyValue() is just like StartFrame(). You don't CALL StartFrame(), you let the engine call it.
It's the same thing here.
The Dispatch() series of functions are called by the engine into the GameDLL code in order to setup an entity, and they are called along with a pointer to the entity they refer to.
So in order to store particular informations about these entities that you couldn't be able to get through their entvars (pEdict->v.something), you have to count how many of them there are in the game and fill an array with them. An array of structures, in each of which you can put as many information as you want. And why not the whole key/value string.
AS SOON as the engine calls DispatchKeyValue(), fill in this array with the appropriate changes.
THEN, whenever you want, make your bot code read the information it needs from the right slot in the array that holds these entitie's extra informations.

Have you ever read botman's readme.txt file that comes with his HPB template ?

Tea 04-06-2004 06:48

Re: How to detect entity [properties] ?
 
Quote:


This method will ONLY work for things that DON'T change their value while the game is being played

Thanks PM, after I read the reply from botman again, I found out botman did answer me already. :(

So I think catch the net message is the only way, thanks Shrike for the suggestion. :)


All times are GMT +2. The time now is 23:59.

Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.