Okay, i am back.
Button usage is actually not hard to do, you just have to know what to read.
Requirements (what should your bot have already):
- pathfinder
- some sort of 'main goal' reminder (so it knows its actual goal)
- method to change the path to a temporarily goal
- a path_walk function
Okay:
I will show all my pieces of code and explain what i do.
Most stuff happens in path_walk(). And in my case i handle different situations. I handle 'close to node' first, then i handle walking to the node, and then i handle stuck situations:
order:
- close to node? (YES-> go to next node, exit function)
- close to node? (NO-> walk to node, perform nescesary actions (swim/jump/duck)
- stuck? (should walk?)
When checking if we are close to the node we head for (or waypoint), i fire a tracehull. You can recieve the traceresult there to know if the path is going THROUGH an entity. Most of the time it will be a func_door or a func_door_rotating without button usage, and you just handle doors as you normally do. In this case you have to know a bit more about the door. So, in code:
Code:
edict_t *pEntityHit = NULL;
//Using TraceHull to detect de_aztec bridge and other entities.
//DONT_IGNORE_MONSTERS, we reached it only when there are no other bots standing in our way!
UTIL_TraceHull (vOrigin, vNode, dont_ignore_monsters, head_hull,
pBot->pEdict, &tr);
// if nothing hit:
if (tr.flFraction >= 1.0)
bReachNode = true;
else
{
// set entity info we hit
if (tr.pHit)
pEntityHit = tr.pHit;
}
Here you see, when we are obstructed by something, we remember the entity.
In my 'get stuck' part. I first check if my bot should move (perhaps its camping, so its normal and thus not stuck!). This is set in bShouldMove. After that my check for the entity happens:
Code:
// When blocked by an entity, we should figure out why:
if (pEntityHit && pBot->pButtonEdict == NULL && bShouldMove &&
pBot->fButtonTime < gpGlobals->time)
{
// hit by a door?
bool bDoor=false;
// normal door (can be used as an elevator)
if (strcmp(STRING(pEntityHit->v.classname), "func_door") == 0) bDoor=true;
// I am not 100% sure about func_wall, but include it anyway
if (strcmp(STRING(pEntityHit->v.classname), "func_wall") == 0) bDoor=true;
// rotating door
if (strcmp(STRING(pEntityHit->v.classname), "func_door_rotating") == 0) bDoor=true;
if (bDoor)
{
// check if we have to 'use' it
if (FBitSet ( pEntityHit->v.spawnflags, SF_DOOR_USE_ONLY ))
{
// use only, press use and wait
pBot->vHead = VecBModelOrigin(pEntityHit);
pBot->vBody = pBot->vHead;
UTIL_BotPressKey(pBot, IN_USE);
pBot->f_wait_time = gpGlobals->time + 0.5;
}
// this thing has a name (needs button to activate)
if (STRING(pEntityHit->v.targetname))
{
// find this entity
edict_t *pButtonEdict = NULL;
edict_t *pent = NULL;
TraceResult trb;
// search for all buttons
while ((pent = UTIL_FindEntityByClassname (pent, "func_button")) != NULL)
{
// skip anything that could be 'self' (unlikely)
if (pent == pEntityHit)
continue;
// get vectr
Vector vPentVector = VecBModelOrigin (pent);
// found button entity
if (strcmp(STRING(pent->v.target), STRING(pEntityHit->v.targetname)) == 0)
{
UTIL_TraceLine (pBot->pEdict->v.origin, vPentVector, ignore_monsters, dont_ignore_glass, pBot->pEdict, &trb);
bool isGood=false;
// if nothing hit:
if (trb.flFraction >= 1.0)
isGood=true;
else
{
// we hit this button we check for
if (trb.pHit == pent)
isGood=true;
}
if (isGood)
{
// Button found to head for!
pButtonEdict = pent;
break;
}
else
{
// we failed here
// it is probably a button 'on the other side of the wall'
// as most doors have 2 buttons to access it (ie prodigy)
}
}
}
// We have found a button to go to
if (pButtonEdict)
{
// Get its vector
Vector vButtonVector = VecBModelOrigin (pButtonEdict);
// Search a node close to it
int iButtonNode = close(vButtonVector, NODE_ZONE*2, pButtonEdict);
// When node found, create path to it
if (iButtonNode > -1)
{
// Get current node
int iCurrentNode = close(pBot->pEdict->v.origin, NODE_ZONE, pBot->pEdict);
// when valid...
if (iCurrentNode > -1)
{
pBot->bot_pathid = -1;
path(iCurrentNode, iButtonNode, pBot->iIndex, pBot, PATH_NONE);
pBot->pButtonEdict = pButtonEdict;
return;
}
} // button node
} // pButtonEdict found
}
}
}
Okay. So here is actually a big deal of the code already. In short:
- hit by an entity:
- figure out classname
- when classname is a door type (func_door or func_door_rotating, func_wall is questionable? (MAPPERS??)).
- figure out the targetname of this door.
- find a func_button with the same TARGET as the doors TARGETNAME (they are linked)
- be sure you can reach this button
- create a path to it
- remember its entity
you need to remember this entity so you can override your 'head looking' with it.
At the very top (before my NEARNODE check) i have this code:
Code:
// when pButtonEdict is filled in, we check if we are close!
if (pBot->pButtonEdict)
{
Vector vButtonVector = VecBModelOrigin ( pBot->pButtonEdict);
if (func_distance(pBot->pEdict->v.origin, vButtonVector) < 90)
{
TraceResult trb;
// TRACELINE ON PURPOSE!
UTIL_TraceLine (pBot->pEdict->v.origin, vButtonVector, ignore_monsters, dont_ignore_glass, pBot->pEdict, &trb);
bool isGood=false;
// if nothing hit:
if (trb.flFraction >= 1.0)
isGood=true;
else
{
// we hit this button we check for
if (trb.pHit == pBot->pButtonEdict)
isGood=true;
}
if (isGood)
{
pBot->vHead = vButtonVector;
pBot->vBody = pBot->vHead;
// kill edict in memory
pBot->pButtonEdict = NULL;
// press use
UTIL_BotPressKey(pBot, IN_USE);
SERVER_PRINT("This button i was looking for, is close, i can see it, i use it!!!\n");
// wait a little
pBot->f_wait_time = gpGlobals->time + 0.5;
pBot->fButtonTime = gpGlobals->time + 5.0;
return;
}
return;
}
}
this will check if we are heading for a button already; if so, we check our distance to it. Face to it, and press USE. There is not always the need of pressing USE! So the above code should be updated by checking the spawnflags. Hence, it works for now. I will update the code later.
In overall:
it took me 1 hour to get it working basicly. It is not hard to implement, it does not require special moves, so in theory its even easier than ladder usage
