Bobot_ai.c (3)

/*----------------------------------------------------------------------------
Routine      : BOBOT_AI_Determine_LR_Goal
Description  : Evaluate the best long range goal and send the bot on
             : its way. This is a good time waster, so function needs
             : to be used sparingly.
             : DO NOT CALL FOR EVERY THINK CYCLE
-----------------------------------------------------------------------------*/
void BOBOT_AI_Determine_LR_Goal(gentity_t *bobot)
{    int                i,j,k,Construct_tank;
    usercmd_t        *ucmd;
    int                closest_node;
    Sbobot            *bobotAI = &bobots[bobot->s.clientNum];
    det_client_t    *teammates = bobotAI->teammates;
    gentity_t        *teammate;
    int                objectif_possible[MAX_NODES],objectif_possible2[MAX_NODES];
     int                nouvel_objectif;
    int                inmyteam = (bobotAI->myteam == TEAM_ALLIES ? NODE_TEAM_ALLIES : NODE_TEAM_AXIS);
    float            (*MinCost)[MAX_NODES][MAX_NODES];
    float            max=0,max2=0;
    float            proba[MAX_NODES],proba2[MAX_NODES];
    float            alea;
    qboolean        OnMyNode=qfalse;
       
    Construct_tank=INVALID;

    bobotAI->action = ACTION_DEFAULT;
       if ( bobot->current_node == INVALID )                                        // S'il n'y a pas de node courrent, trouver le plus près et y aller.
    {    closest_node = FUSION_NAVIGATION_FindClosestReachableNode(bobot, NODE_DENSITY, NODE_ALL);
        if ( closest_node != INVALID )
        {    bobotAI->state        = BOT_STATE_MOVE;
            bobotAI->tries        = 0;                                            // Not yet used
            bobotAI->next_node    = closest_node;                                    // Later on uset setgoal to work with
            BOBOT_MAPPING_setNextNodeNoise(bobotAI);                            // ajout de bruit à la localisation du next node
            return;
        }
        else
        {    if(random() < 0.05)
            { G_Say( bobot, NULL, SAY_ALL, "Oops !! No goal, I don't know where I go..."); }
            bobotAI->state = BOT_STATE_WANDER;
            return;
        }
    }
    // Les coverts déguisés utilisent le Mincost adverse.
    if(bobotAI->myteam == TEAM_AXIS)
    {    if(bobot->client->ps.powerups[PW_OPS_DISGUISED])
            MinCost = &AlliesMinCost;
        else
            MinCost = &AxisMinCost;
    }
    else if(bobotAI->myteam == TEAM_ALLIES)
    {    if(bobot->client->ps.powerups[PW_OPS_DISGUISED])
            MinCost = &AxisMinCost;
        else
            MinCost = &AlliesMinCost;
    }

    /*    Joc: On fait une liste des objectifs possibles dans mincost (connexion de la team) */
    j=0;
    k=0;
    for (i = 0; i < number_of_nodes; i++)
    {    float prob;
        if ( (*MinCost)[bobot->current_node][i] == NO_CONNECTION)
        { continue;    }
        if (i==bobot->current_node)
        {    OnMyNode=qtrue;
            continue;
        }
        if (NodePris[i]>0)
            continue;
        prob = (*MinCost)[bobot->current_node][i] + 1 ;                            //évite les divisions par zero
        prob = 100000000/(prob*prob);                                            //1000000000 c'est juste pour afficher une proba lisisble

        /*    PROTECTION Class:soldier,medic,covertops,fieldops Team:la sienne */
        if ((nodes[i].type & NODE_PROTECTION) && (nodes[i].type & inmyteam))
        {    if    (bobot->client->sess.playerType != PC_ENGINEER)
            {    max += prob;
                proba[j] = max;
                objectif_possible[j]=i;
                j++;
            }
            /* Si vraiment rien à faire pour l'ingénieur, alors il protège */
            max2 += prob;
            proba2[k] = max2;
            objectif_possible2[k]=i;
            k++;
        }

        /*    OBJECTIF PRIMAIRE Class:toutes Team:adverse */
        if ((nodes[i].type & NODE_OBJECTIF_PRIM) && !(nodes[i].type & inmyteam))
        {    if    (bobot->client->sess.playerType != PC_ENGINEER)
            {    max += prob;
                proba[j] = max;
                objectif_possible[j]=i;
                j++;
            }
            /* Si vraiment rien à faire pour l'ingénieur, alors il va sur l'objectif primaire */
            max2 += prob;
            proba2[k] = max2;
            objectif_possible2[k]=i;
            k++;
        }

        /*    OBJECTIF SECONDAIRE Class:soldier,medic,covertops,fieldops Team:adverse */
        if ((nodes[i].type & NODE_OBJECTIF_SEC) && !(nodes[i].type & inmyteam))
        {    if    (bobot->client->sess.playerType != PC_ENGINEER)
            {    max += prob;
                proba[j] = max;
                objectif_possible[j]=i;
                j++;
            }
            /* Si vraiment rien à faire pour l'ingénieur, alors il va sur l'objectif secondaire */
            max2 += prob;
            proba2[k] = max2;
            objectif_possible2[k]=i;
            k++;
        }
       
        /*    CONSTRUCTIONS Class:engineer Team:la sienne */
        if ((nodes[i].type & NODE_CONSTRUCTION) && (nodes[i].type & inmyteam) &&
            (bobot->client->sess.playerType == PC_ENGINEER))
        {    max += prob;
            proba[j] = max;
            objectif_possible[j]=i;
            j++;
            if (nodes[i].type & NODE_TANK)
            {    Construct_tank=i;
                //G_Printf("\n Construct_tank %i",Construct_tank);
            }
            //VectorSubtract(nodes[i].origin, bobot->r.currentOrigin, dir);
            //dist = VectorLength(dir);
        }
   
        /*    DYNAMITE Class:engineer Team:adverse */
        if ((nodes[i].type & NODE_DYNAMITE) && !(nodes[i].type & inmyteam) &&
            (bobot->client->sess.playerType == PC_ENGINEER))
        {    max += prob;
            proba[j] = max;
            objectif_possible[j]=i;
            j++;
        }
   
        /*    CHARGE Class:covertops Team:adverse */
        if ((nodes[i].type & NODE_CHARGE) && !(nodes[i].type & inmyteam) &&
            (bobot->client->sess.playerType == PC_COVERTOPS))
        {    max += prob;
            proba[j] = max;
            objectif_possible[j]=i;
            j++;
        }
   
        /*    MINE Class:engineer Team:la sienne ou allteam */
        if ((nodes[i].type & NODE_MINE) && (nodes[i].type & (inmyteam | NODE_ALLTEAM)) &&
            (bobot->client->sess.playerType == PC_ENGINEER))
        {    max += prob;
            proba[j] = max;
            objectif_possible[j]=i;
            j++;
        }
   
        /*if(    (nodes[i].type & NODE_SNIPE) && (nodes[i].type & (inmyteam | NODE_ALLTEAM)) &&
            (NodePris[i]==0) && (bobot->client->sess.playerType == PC_COVERTOPS))               
        {    max += prob;
            proba[j] = max;
            objectif_possible[j]=i;
           j++;
        }*/

        /*    HEAVY MACHINGUN Class:soldier,medic,covertops,fieldops Team:toutes */
        if ((nodes[i].type & NODE_HEAVY_MACHINGUN) /*&& (NodePris[i]==0)*/ &&
            (bobot->client->sess.playerType != PC_ENGINEER))
        {    max += prob;
            proba[j] = max;
            objectif_possible[j]=i;
            j++;
        }
    }
    i = 0;
    if(j>0)
    {    alea = random()*max;                                                        // Il faut tenir compte des probas.
        while(alea >= proba[i])
        { i++;    }
        nouvel_objectif = objectif_possible[i];
    }
    else if(k>0)
    {    alea = random()*max2;
        while(alea >= proba2[i])
        { i++; }
        nouvel_objectif = objectif_possible2[i];
    }
    else
    {    if( OnMyNode==qfalse)
        {    G_Printf("\n^1No goal into this map or no connection for going to."); }
        return;
    }

    //Si un team mate est déjà au MG nest, le bot n'y va pas.
    if (nodes[nouvel_objectif].type & NODE_HEAVY_MACHINGUN)
    {    for(i=0; i < BOBOT_DETECT_MAX_TEAMMATES; i++)
        {    teammate = teammates[i].ent;
            if( teammate == NULL || teammate->client == NULL)
            { continue; }
            if(teammate->client->ps.eFlags & (EF_MG42_ACTIVE|EF_AAGUN_ACTIVE))
            {    if(teammate->current_node == nouvel_objectif)
                    nouvel_objectif = INVALID;
                    return;
            }
        }
    }
    //Ne pas aller sur un node déjà pris
    //if ((NodePris[nouvel_objectif]>0) && (nodes[nouvel_objectif].type & inmyteam))
    //    nouvel_objectif = INVALID;

    if (nouvel_objectif == INVALID)
    { return; }

    //G_Say(bobot, NULL,SAY_ALL,va("^7nouvel_objectif %i, NodePris[nouvel_objectif]%i",nouvel_objectif,NodePris[nouvel_objectif]));
   
    if (bobot->client->sess.playerType == PC_ENGINEER)
    {    /*    Planter une mine sur un node ou il n'y en a pas */
        if ((nodes[nouvel_objectif].type & NODE_MINE) && (BOBOT_ENGINEER_FindMine(bobot,nouvel_objectif)!=0))
        { return; }
        /*    Planter une dynamite sur un node ou il n'y en a pas déjà une */
        if ((nodes[nouvel_objectif].type & NODE_DYNAMITE) && !(nodes[nouvel_objectif].type & inmyteam) &&
            (BOBOT_ENGINEER_DynamitePlantedByTeam(bobot,nouvel_objectif)!=0))
        { return; }
    }

    /*    Pour éviter les messages à profusion. */
    if(bobotAI->dit == qfalse)
    { if((nouvel_objectif != INVALID) && (Q_stricmp(MessageNode[nouvel_objectif],"")!=0))
        {    if(bobotAI->MessageNode != nouvel_objectif)
            {    bobotAI->MessageNode = nouvel_objectif;
                bobotAI->dit = qtrue;
                if( random() < 0.05)
                { G_Say(bobot, NULL,SAY_TEAM,va("^7%s",MessageNode[nouvel_objectif])); }
            }
        }
    }
    if (Construct_tank != INVALID)
    {    nouvel_objectif=Construct_tank;   
        //G_Printf("\n nouvel_objectif %i",nouvel_objectif);
    }

    BOBOT_AI_proposeAction(bobotAI,GO_TO_LR_GOAL,nouvel_objectif,NULL,NULL,GO_TO_LR_OBJ_PRIORITY);
}

/*-------------------------
BOBOT_AI_inFOV .joc
----------------------------*/
qboolean BOBOT_AI_inFOV(vec3_t viewangles, float fov, vec3_t angles)
{    vec3_t    temp;

    AnglesSubtract(viewangles,angles,temp);
    if (VectorLength(temp) < fov)
    { return qtrue; }
    else
    { return qfalse; }
}

/*---------------------------------------------------------------------
3emeType : comme visible(), mais entre un joueur et une position
----------------------------------------------------------------------*/
qboolean visiblePosition(gentity_t *ent, vec3_t position)
{    trace_t    tr;
    vec3_t    pos;

    VectorCopy(ent->r.currentOrigin,pos);
    pos[2] += ent->client->ps.viewheight;
    trap_TraceNoEnts(&tr, pos, NULL, NULL, position, ent->s.number, CONTENTS_SOLID);
    if(tr.fraction < 1.f)
    { return qfalse; }
    return qtrue;
}

/*----------------------------------------------------------------------------------
Routine      :    BOBOT_AI_Detect_Clients
Description  :    Scans for enemy (very simple, just picks any visible enemy)
------------------------------------------------------------------------------------*/           
void BOBOT_AI_Detect_Clients(gentity_t *bobot)
{      int                i;
    vec3_t            dir,ang;
    vec_t            dist;
    gentity_t        *tempent;
    int                numEnemies = 0;
    int                numTeammates = 0;
    Sbobot            *bobotAI = &bobots[bobot->s.clientNum];
    det_client_t    *teammates = bobotAI->teammates;
    det_client_t    *enemies = bobotAI->enemies;
    qboolean        onSameTeam;

    for ( i =0; i< BOBOT_DETECT_MAX_ENEMIES;i++)        //joc : on mets le tableau à 0
    {    enemies[i].ent = NULL;
        teammates[i].ent = NULL;
    }
    for ( i = 0; i < MAX_CLIENTS; i++)
    {    tempent = &g_entities[i];
        if (!tempent->inuse)
        { continue; }                                    // if slot is not used go next
        if(tempent == bobot)                            // ne pas se mettre soi-meme
        { continue; }
        if(!tempent->client)                            // que les clients
        { continue; }
        VectorSubtract( tempent->r.currentOrigin, bobot->client->ps.origin, dir );
        dist = VectorLength(dir);                        // distance au joueur
        VectorNormalize( dir );
        vectoangles( dir, ang );
        onSameTeam = OnSameTeam(bobot,tempent);

        /*    les équipiers sont vus sur le radar
            pas besoin de détection complexe les ennemis sont vu dans l'angle de vision */

        if((onSameTeam && visible(bobot,tempent)) ||
           (BOBOT_AI_inFOV(bobot->client->ps.viewangles,BOBOT_ENEMIES_DETECTION_ANGLE,ang) &&
           (BOBOT_AI_CanHit(bobot,tempent) || BOBOT_AI_CanHit(tempent,bobot))))
        { if(onSameTeam)
            {    teammates[numTeammates].ent = tempent;
                teammates[numTeammates].dist = dist;
                teammates[numTeammates].isVisible = qtrue;
                numTeammates++;
            }
            else if (tempent->health > 0 && (tempent->client->sess.sessionTeam == TEAM_AXIS ||
                 tempent->client->sess.sessionTeam == TEAM_ALLIES))
            {     enemies[numEnemies].ent = tempent;
                enemies[numEnemies].dist = dist;
                enemies[numEnemies].isVisible = qtrue;
                numEnemies++;
            }
        }
    }
}

/*---------------------------------------------------------------
vérifie si l'item est détectée par le bot.
ce n'est pas tout à fait le même code que visible()
-----------------------------------------------------------------*/
qboolean itemVisible (gentity_t *self, gentity_t *item)
{    trace_t        tr;
    gentity_t    *traceEnt;

    trap_Trace (&tr, self->r.currentOrigin, NULL, NULL, item->r.currentOrigin, self->s.number, MASK_SHOT);
    traceEnt = &g_entities[ tr.entityNum ];
    if(tr.fraction >= 1.0)
    { return qtrue; }
    return qfalse;   
}

/*------------------------------------------------------------------------------------
regarde dans les tableaux de détection si l'entité a été détectée par le bot
-------------------------------------------------------------------------------------*/
qboolean entityDetected(Sbobot *bobotAI,gentity_t *entity)
{    int                i;
    det_client_t    *clients;
    gentity_t        *ent;
    det_item_t        *items = bobotAI->healthPacks;

    for(i=0;i<BOBOT_DETECT_MAX_PACKS;i++)
    {    ent = items[i].ent;
        if(ent == NULL)
        { break; }
        if(ent == entity)
        { return qtrue; }
    }
    items = bobotAI->ammoPacks;
    for(i=0;i<BOBOT_DETECT_MAX_PACKS;i++)
    {    ent = items[i].ent;
        if(ent == NULL)
        { break; }
        if(ent == entity)
        { return qtrue; }
    }
    clients = bobotAI->teammates;
    for(i=0;i<BOBOT_DETECT_MAX_TEAMMATES;i++)
    {    ent = clients[i].ent;
        if(ent == NULL)
        { break; }
        if(ent == entity)
        { return qtrue; }
    }
    clients = bobotAI->enemies;
    for(i=0;i<BOBOT_DETECT_MAX_ENEMIES;i++)
    {    ent = clients[i].ent;
        if(ent == NULL)
        { break; }
        if(ent == entity)
        { return qtrue; }
    }
    return qfalse;
}

qboolean BOBOT_AI_currentTargetVisible(gentity_t * bobot, Sbobot *bobotAI)
{    gentity_t    *ent = bobotAI->currentAction.ent;
   
    if(ent == NULL)        // si la cible de l'action n'est pas une entité c'est que c'est un node
    { return qtrue; }    // un node est toujours "visible", enfin il ne bouge pas donc on sait où il est
    return entityDetected(bobotAI,ent);
}

/*----------------------------------------------------------------------------------
Joc modified by 3emeType : trouve les items proches du bobot
----------------------------------------------------------------------------------*/
void BOBOT_AI_Detect_Item(gentity_t *bobot)
{    vec_t        dist;
    vec3_t        dir,ang;
    Sbobot        *bobotAI = &bobots[bobot->s.clientNum];
    int            i,h,a;
    gitem_t        *item;
    vec3_t        mins,maxs,origin;
    int            num;
    int            touch[MAX_GENTITIES];

    VectorSet(mins, -MAX_DETECTION_ITEM_DISTANCE, -MAX_DETECTION_ITEM_DISTANCE, -MAX_DETECTION_ITEM_DISTANCE);
    VectorSet(maxs, MAX_DETECTION_ITEM_DISTANCE, MAX_DETECTION_ITEM_DISTANCE, MAX_DETECTION_ITEM_DISTANCE);
    VectorCopy( bobot->r.currentOrigin, origin );
    SnapVector( origin );
    VectorAdd( origin, mins, mins );
    VectorAdd( origin, maxs, maxs );
    num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
    for(h=0; h<BOBOT_DETECT_MAX_PACKS; h++)                                // initialisation
    { bobotAI->healthPacks[h].ent = NULL; }
    for(a=0; a<BOBOT_DETECT_MAX_PACKS; a++)
    { bobotAI->ammoPacks[a].ent = NULL; }
    for( i = 0, h=0, a=0; i < num && h < BOBOT_DETECT_MAX_PACKS && a < BOBOT_DETECT_MAX_PACKS; i++ )
    {    gentity_t* ent = &g_entities[touch[i]];
        if (ent->s.eType != ET_ITEM)                                    // on ne veut que les items
        { continue; }
        VectorSubtract( ent->r.currentOrigin, bobot->client->ps.origin, dir );
        dist = VectorLength(dir);                                        // distance à l'item
        VectorNormalize( dir );
        vectoangles( dir, ang );
        if( !itemVisible(bobot,ent))
        { continue; }                                                    // on ne s'occupe pas de cet item
        item = &bg_itemlist[ent->s.modelindex];
        switch(item->giType)
        {    case IT_HEALTH:                                                // Cabinet de soin
                bobotAI->healthPacks[h].ent = ent;
                bobotAI->healthPacks[h].dist = dist;
                bobotAI->healthPacks[h].isVisible = qtrue;                // je ne détecte que le visible
                h++;
                break;
            case IT_WEAPON:                                                // Cabinet de munitions
                if(item->giTag == WP_AMMO)
                {     bobotAI->ammoPacks[a].ent = ent;
                    bobotAI->ammoPacks[a].dist = dist;
                    bobotAI->ammoPacks[a].isVisible = qtrue;            // je ne détecte que le visible
                    a++;
                }
                break;
            default:
                break;
        }
    }
}

qboolean BOBOT_AI_CanHit(gentity_t *bobot, gentity_t *other)
{    //    int            dist = 8192;
    //    vec3_t    viawang,end,muzzleTrace,forward,right,up;
    vec3_t        start,end;
    trace_t        tr;
    gentity_t    *traceEnt;

    if(visible(bobot,other))
    { return qtrue; }
    //    copie de calcmuzzlepoint (g_weapon.c)
    //    VectorCopy(bobot->client->ps.viewangles, viewang);
    //    AngleVectors (viewang, forward, right, up);
    VectorCopy( bobot->s.pos.trBase, start );
    start[2] += bobot->client->ps.viewheight;
    VectorCopy( other->s.pos.trBase, end );
    end[2] += other->client->ps.viewheight;
    // snap to integer coordinates for more efficient network bandwidth usage
    SnapVector( start );
    // VectorMA (muzzleTrace, dist, forward, end);
    trap_Trace (&tr, start, NULL, NULL, end, bobot->s.number, MASK_SHOT);
    traceEnt = &g_entities[ tr.entityNum ];
    if (traceEnt == other)
    { return qtrue; }
    trap_Trace (&tr, bobot->r.currentOrigin, NULL, NULL, end, bobot->s.number, MASK_SHOT);
    traceEnt = &g_entities[ tr.entityNum ];
    if (traceEnt == other)
    { return qtrue; }
    trap_Trace (&tr, start, NULL, NULL, other->r.currentOrigin, bobot->s.number, MASK_SHOT);
    traceEnt = &g_entities[ tr.entityNum ];
    if (traceEnt == other)
    { return qtrue; }
    return qfalse;   
}

void FUSION_AI_BotPain(gentity_t *self, gentity_t *attacker, int damage, vec3_t point)
{
    Bobot_Printf("%s\n", attacker->client->pers.netname);
}

/*---------------------------------------------------------------------
3emeType : inhibe une action. la retire des actions déclenchables.
-----------------------------------------------------------------------*/
void BOBOT_AI_inhibitAction(action_t *action)
{
    action->type                = INVALID;
    action->priority            = INVALID;
    action->ent                    = NULL;
    action->node                = INVALID;
    action->timeOut                = INVALID;
    action->timeOutWhenHidden    = INVALID;
    VectorClear(action->lastKnownPos);
    VectorClear(action->predictedPos);
}

/*--------------------------------------------------------------
3emeType : quelques initialisations nécessaires à chaque respawn
---------------------------------------------------------------*/
void BOBOT_AI_initBot(Sbobot *bobotAI)
{    int i;

    BOBOT_LOOK_initBot(bobotAI);
    /*    init des actions */
    bobotAI->armsAction.ent        = NULL;
    bobotAI->passeporte            = qfalse;
    bobotAI->DansTank            = qfalse;
    bobotAI->dit                = qfalse;
    bobotAI->prone                = qfalse;
    bobotAI->Bloked                = qfalse;
    bobotAI->BlokedNode            = INVALID;
    bobotAI->TimeOnStuckNode    = 0;            // Temps passé sur un même node
    bobotAI->StuckedNode        = INVALID;        // Bloqué oui/non (blockage non voulu)
    bobotAI->TimeSatchel        = 0;
    bobotAI->TimeUseObject        = 0;
    bobotAI->TimeNode            = 0;
    bobotAI->MessageNode        = 0;
    bobotAI->Ducked                = 0;
    bobotAI->HitByTeammate        = 0;
    bobotAI->DelayFireOnTeammate= 0;
    bobotAI->UseGrenade            = 0;
    bobotAI->TimeLanceGrenade    = 0;
    bobotAI->TimeFollow            = 0;
    bobotAI->armsAction.type    = BOBOT_LOOK_AROUND;
    for(i=0; i<NB_COMMON_OBJECTIVES; i++)
    { BOBOT_AI_inhibitAction(&bobotAI->actions[i]); }
    BOBOT_AI_inhibitAction(&bobotAI->currentAction);
    bobotAI->sp = -1; // pile vide
}

Créer un site gratuit avec e-monsite - Signaler un contenu illicite sur ce site