Bobot_fuzzy.c

/***********************************************************************
3emeType
bobot_fuzzy.c
Module de logique floue
Joc : The Free Fuzzy Logic Library ne compile pas sous linux,
on fait donc nos propres fonctions de logique floue.
***********************************************************************/
#include "../game/g_local.h"
#include "bobot.h"
#include "bobot_fuzzy.h"
#include "bobot_fuzzy_rules.h"
#include "bobot_utils.h"

/***********************************************************************
Calcul la sortie pour une regle logique a 1 entrée; 1 sortie
***********************************************************************/
float BOBOT_FUZZY_GET_OUTPUT1(float Input,Fuzzy_Rules1_t Rules)
{    float mu1[FUZZY_SIZE];
    int    debut,centre,fin;
    float AireTotale,AireTriangle;
    float Output;
    int i,k;
    int rules1 = 0;

    for (i=1; i<FUZZY_SIZE ; i++)
    {    if( Input <= Rules.FuzzyInput[i])
        {    rules1 = i - 1;
            mu1[i] = ( (Input - Rules.FuzzyInput[i-1])) / (Rules.FuzzyInput[i] - Rules.FuzzyInput[i-1]);
            mu1[i-1] = 1 - mu1[i];
            break;
        }
    }
    Output = 0;
    AireTotale = 0;
    for (i=rules1; i<rules1 + 2; i++)
    {    k = Rules.Table[i];
        if (k == 0)
        { debut = Rules.FuzzyOutput[0]; }
        else
        { debut = Rules.FuzzyOutput[k - 1];    }
        if (k == FUZZY_SIZE -1 )
        { fin = Rules.FuzzyOutput[FUZZY_SIZE - 1]; }
        else
        { fin = Rules.FuzzyOutput[k + 1]; }
        centre = Rules.FuzzyOutput[k];
        AireTriangle = (fin - debut)*mu1[i] / 2.0;                   
        Output += AireTriangle * (fin + debut + centre ) / 3.0;
        AireTotale += AireTriangle;
    }   
    if(AireTotale > 0)
    { Output /=AireTotale; }
    return (int) (Output + 0.5);
}

/***********************************************************************
Calcul la sortie pour une regle logique a 2 entrées; 1 sortie
***********************************************************************/
float BOBOT_FUZZY_GET_OUTPUT2(float Input1,float Input2,Fuzzy_Rules2_t Rules)
{    float mu1[FUZZY_SIZE];
    float mu2[FUZZY_SIZE];
    int    debut,centre,fin;
    float AireTotale,AireTriangle;
    float Output;
    int i,j,k;
    int rules1 = 0,rules2 = 0;
   
    for (i=1; i<FUZZY_SIZE ; i++)
    {    if( Input1 <= Rules.FuzzyInput1[i])
        {    rules1 = i - 1;
            mu1[i] = ( (Input1 - Rules.FuzzyInput1[i-1])) / (Rules.FuzzyInput1[i] - Rules.FuzzyInput1[i-1]);
            mu1[i-1] = 1 - mu1[i];           
            break;
        }
    }
    for (i=1; i<FUZZY_SIZE ; i++)
    {    if( Input2 <= Rules.FuzzyInput2[i])
        {    rules2 = i - 1;
            mu2[i] = ( (Input2 - Rules.FuzzyInput2[i-1])) / (Rules.FuzzyInput2[i] - Rules.FuzzyInput2[i-1]);
            mu2[i-1] = 1 - mu2[i];           
            break;
        }
    }
    Output = 0;
    AireTotale = 0;
    for (i=rules1; i<rules1 + 2; i++)
    {    for(j=rules2; j<rules2 +2;j++)
        {    k = Rules.Table[i][j];
            if (k == 0)
            { debut = (int) Rules.FuzzyOutput[0];}
            else
            { debut = (int) Rules.FuzzyOutput[k - 1]; }
            if (k == FUZZY_SIZE - 1)
            { fin = (int)Rules.FuzzyOutput[FUZZY_SIZE - 1];    }
            else
            { fin = (int) Rules.FuzzyOutput[k + 1]; }
            centre = (int) Rules.FuzzyOutput[k];
            AireTriangle = (float) (fin - debut)*mu1[i]*mu2[j] / 2.0;   
            Output += (float) AireTriangle * (fin + debut + centre ) / 3.0;
            AireTotale += AireTriangle;
        }
    }
    if(AireTotale > 0)
    { Output /=AireTotale; }
    return (int) (Output + 0.5);
}

int BOBOT_healthPercentage(gentity_t *bobot)
{ return 100*bobot->health / bobot->client->ps.stats[STAT_MAX_HEALTH]; }

int BOBOT_ammoPercentage(gentity_t *bobot)
{     int                NbMuni,maxammo,ammo=100;
    float            pourcent;
   
    NbMuni  = bobot->client->ps.ammoclip[BG_FindClipForWeapon(bobot->client->sess.playerWeapon)] +
              bobot->client->ps.ammo[BG_FindAmmoForWeapon(bobot->client->sess.playerWeapon)];
    maxammo = BG_MaxAmmoForWeapon( bobot->client->sess.playerWeapon, bobot->client->sess.skill );
   
    if(maxammo>0)
    {    pourcent=((float)NbMuni/(float)maxammo)*100;
        ammo=(int)pourcent;
    }
    //G_Printf("\n latchPlayerWeapon %i PlayerWeapon %i nbmuni %i maxammo %i pourcentage réel %i",bobot->client->sess.latchPlayerWeapon,bobot->client->sess.playerWeapon,NbMuni,maxammo,ammo);
    return ammo;
}

int BOBOT_distancePercentage(float distance,float max)
{ return 100*distance / max; }

/***************************************************************************
Interroge les règles floues et renvoie la priorité de l'action de récupérer un pack de soin
***************************************************************************/
int BOBOT_FUZZY_determinePriorityForHealth(Sbobot *bobotAI,int health,int distHealth)
{ return BOBOT_FUZZY_GET_OUTPUT2(health,distHealth,Th_Rules); }

/*    pareil pour un pack de munitions */
int BOBOT_FUZZY_determinePriorityForAmmo(Sbobot *bobotAI,int ammo,int distAmmo)
{ return BOBOT_FUZZY_GET_OUTPUT2(ammo,distAmmo,Ta_Rules); }

/***************************************************************************
Détermine la priorité de venir soutenir un équipier
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToBackupATeammate(Sbobot *bobotAI, int health, gentity_t *teammate, int distPercentage)
{
    if(teammate->client->ps.pm_type == PM_DEAD || teammate->client->ps.pm_flags & PMF_LIMBO)
    { return INVALID; } // il est mort, trop tard... (mais on pourrait quand même y aller, car il ne doit pas être mort pour rien)
    return BOBOT_FUZZY_GET_OUTPUT2(health,distPercentage,Bt_Rules);
}

/***************************************************************************
Détermine la priorité de trouver un coin à couvert
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToFindProtection(Sbobot *bobotAI, int health)
{ return BOBOT_FUZZY_GET_OUTPUT1(health,Fp_Rules); }

/***************************************************************************
Détermine la priorité de poursuivre un ennemi
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToChaseEnemy(Sbobot *bobotAI, int health, int distPercentage)
{    gentity_t        *ennemy = bobotAI->armsAction.ent;
   
    if (g_SniperWar.integer==1)                    // not for sniper war mode
        return INVALID;
    if(ennemy->r.svFlags & SVF_BOT)        // not for bots
        return INVALID;
    if(ennemy->client->ps.pm_type == PM_DEAD || ennemy->client->ps.pm_flags & PMF_LIMBO)
        return INVALID;                    // not if he is dead
    return BOBOT_FUZZY_GET_OUTPUT2(health,distPercentage,Ce_Rules);
}

/***************************************************************************
Détermine la priorité de défendre sa position lorsqu'on voit un ennemi
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToDefendMyPosition(Sbobot *bobotAI)
{    int    distPercentage;

    distPercentage = BOBOT_COMMON_determineClosestTeammate(bobotAI);
    return BOBOT_FUZZY_GET_OUTPUT1(distPercentage,Dp_Rules);
}


/***************************************************************************
Pour chaque équipiers blessés que le medic voit, évalue la priorité d'aller
lui donner un pack de soin. Renvoie cette priorité, et instancie la variable
chosenTeammate avec l'équipier qu'il est prioritaire de soigner.
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToGiveHealth(Sbobot *bobotAI,gentity_t **chosenTeammate)
{    det_client_t    *teammates = bobotAI->teammates;
    gentity_t        *teammate;
    int                i, priority, highestPriority = INVALID;
   
    for(i=0; i < BOBOT_DETECT_MAX_TEAMMATES; i++)
    {    teammate = teammates[i].ent;
        if( teammate == NULL || teammate->client == NULL)
        { continue; }
        if(teammate->client->ps.pm_type & PM_DEAD)
        { continue; }
        if(teammate->client->ps.pm_flags & PMF_LIMBO)
        { continue; }
        if(teammate->waterlevel>1)        //0=pas dans l'eau 1=eau aux genoux 2=eau à la poitrine 3=sous l'eau
        { continue; }
        if (teammate->client->sess.playerType == PC_MEDIC)
        { continue; }
        if((teammate->health <= 0) || (teammate->health >= 100))
        { continue; }
        priority = BOBOT_FUZZY_determinePriorityForHealth(bobotAI,teammate->health,BOBOT_distancePercentage(teammates[i].dist,BOBOT_ENEMIES_DETECTION_MAX_DIST));
        if (priority > highestPriority)
        {    highestPriority = priority;
            *chosenTeammate = teammate;
        }
    }
    return highestPriority;
}

/***************************************************************************
Pour chaque équipiers manquant de munitions que le fieldops voit, évalue la priorité d'aller
lui donner un pack. Revoie cette priorité, et instancie la variable chosenTeammate
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToGiveAmmo(Sbobot *bobotAI,gentity_t **chosenTeammate)
{    det_client_t    *teammates = bobotAI->teammates;
    gentity_t        *teammate;
    int                i, priority, highestPriority, teammateAmmo;

    highestPriority = INVALID;
    for(i=0; i < BOBOT_DETECT_MAX_TEAMMATES; i++)
    {    teammate = teammates[i].ent;
        teammateAmmo=100;
        if( teammate == NULL || teammate->client == NULL)
        { continue; }
        if (teammate->client->sess.playerType == PC_FIELDOPS)
        { continue; }
        if(teammate->client->ps.pm_type & PM_DEAD)
        { continue; }
        if(teammate->client->ps.pm_flags & PMF_LIMBO)
        { continue; }
        if(teammate->waterlevel>1)        //0=pas dans l'eau 1=eau aux genoux 2=eau à la poitrine 3=sous l'eau
        { continue; }
        teammateAmmo=BOBOT_ammoPercentage(teammate);
        if(teammateAmmo >= 100)
        { continue; }
        /* choix du teammate à qui on donne des munitions */
        priority = BOBOT_FUZZY_determinePriorityForAmmo(bobotAI,teammateAmmo,
                   BOBOT_distancePercentage(teammates[i].dist,BOBOT_ENEMIES_DETECTION_MAX_DIST));
        if (priority > highestPriority)
        {    highestPriority = priority;
            *chosenTeammate = teammate;
        }
    }
    return highestPriority;
}

/***************************************************************************
Pour chaque équipiers à l'agonie que le medic voit, évalue la priorité d'aller
lui donner une dose d'adrénaline. Revoie cette priorité, et instancie la variable chosenTeammate
***************************************************************************/
int BOBOT_FUZZY_determinePriorityToRevive(Sbobot *bobotAI,gentity_t **chosenTeammate)
{    det_client_t    *teammates = bobotAI->teammates;
    gentity_t        *teammate;
    int                i, priority, highestPriority;

    highestPriority = INVALID;
    for(i=0; i < BOBOT_DETECT_MAX_TEAMMATES; i++)
    {    teammate = teammates[i].ent;
        if( teammate == NULL || teammate->client == NULL)
        { continue; }
        if(teammate->client->ps.pm_type != PM_DEAD)
        { continue; }
        if(teammate->client->ps.pm_flags & PMF_LIMBO)
        { continue; }
        if(teammate->waterlevel>1)        //0=pas dans l'eau 1=eau aux genoux 2=eau à la poitrine 3=sous l'eau
        { continue; }
        priority = BOBOT_FUZZY_determinePriorityForHealth(bobotAI,0,BOBOT_distancePercentage(teammates[i].dist,BOBOT_ENEMIES_DETECTION_MAX_DIST)); // TODO : avoir son propre fichier de règles, pour que la FFLL prenne moins de mémoire.
        if (priority > highestPriority)
        {    highestPriority = priority;
            *chosenTeammate = teammate;
        }
    }
    return highestPriority;
}

int BOBOT_FUZZY_determinePriorityToBackupTeammate(Sbobot *bobotAI,gentity_t **chosenTeammate,int health)
{    det_client_t    *teammates = bobotAI->teammates;
    gentity_t        *teammate;
    weapon_t        teammateWeapon;
    int                i, priority, highestPriority = -1;
   
    for(i=0; i < BOBOT_DETECT_MAX_TEAMMATES; i++)
    {    teammate = teammates[i].ent;
        if( teammate == NULL || teammate->client == NULL)
        { continue; }
        if(teammate->client->ps.pm_type & PM_DEAD)
        { continue; }
        if(teammate->client->ps.pm_flags & PMF_LIMBO)
        { continue; }
        if(teammate->waterlevel>1)        //0=pas dans l'eau 1=eau aux genoux 2=eau à la poitrine 3=sous l'eau
        { continue; }
        /*    on ne s'intéresse qu'aux équipiers qui sont en train de tirer sur un ennemi */
        teammateWeapon = teammate->client->ps.weapon;
        if((teammate->client->ps.weaponstate != WEAPON_FIRING) || (teammateWeapon < WP_KNIFE) || (teammateWeapon >= WP_NUM_WEAPONS))
        { continue; }
        priority = BOBOT_FUZZY_determinePriorityToBackupATeammate(bobotAI,health,teammate,BOBOT_distancePercentage(teammates[i].dist,BOBOT_ENEMIES_DETECTION_MAX_DIST));
        if (priority > highestPriority)
        {    highestPriority = priority;
            *chosenTeammate = teammate;
        }
    }
    return highestPriority;
}

void BOBOT_FUZZY_evaluateTakeHealth(gentity_t *bobot, Sbobot *bobotAI, int health)
{    int                priority;
    int                dist=INVALID, closestNode=INVALID;
    gentity_t        *closestTarget;

    /*    si le bot n'a pas son max en vie, il pourrait être intéressant de se soigner */
    if(health < 100)
    {    if(health<=50)    /* SE SOIGNER A UNE ARMOIRE A UNE ARMOIRE SI RESTE 50% MAX HEALTH */
        {    BOBOT_COMMON_determineClosestNodeFromCabinetsArray(bobot,bobotAI,bobotAI->cabinets_heal,MAX_CABINETS,&closestNode,&dist);
             /*    si le bot connaît un cabinet health, il détermine la priorité pour y prendre un health pack */
            if(closestNode != INVALID)
            {    priority = BOBOT_FUZZY_determinePriorityForHealth(bobotAI,health,dist);
                BOBOT_AI_proposeAction(bobotAI, GO_TO_CABINET_HEAL, closestNode, NULL, NULL, priority);
            }
        }
        /* SE SOIGNER EN RAMASSANT UNE TROUSSE DE SOIN */
        BOBOT_COMMON_determineClosestItem(bobotAI->healthPacks, &closestTarget, &dist);
        /*    si le bot voit un health pack il détermine la priorité pour le prendre */
        if(dist != INVALID)
        {    priority = BOBOT_FUZZY_determinePriorityForHealth(bobotAI,health,dist);
            BOBOT_AI_proposeAction(bobotAI, TAKE_HEALTH_PACK, INVALID, closestTarget, closestTarget->r.currentOrigin, priority);
        }
    }
    /*    si en pleine forme, inhibons les actions de soin */
    else
    {    BOBOT_AI_inhibitAction(&bobotAI->actions[GO_TO_CABINET_HEAL]);
        BOBOT_AI_inhibitAction(&bobotAI->actions[TAKE_HEALTH_PACK]);
    }
}

void BOBOT_FUZZY_evaluateTakeAmmo(gentity_t *bobot, Sbobot *bobotAI, int ammo)
{    int                priority;
    int                dist=INVALID, closestNode=INVALID;
    gentity_t        *closestTarget;
   
    if(ammo<100)
    {    if(ammo<=50)    /*    SE RAVITAILLER EN MUNITIONS A UNE ARMOIRE SI RESTE 50% MAX AMMO */
        {    BOBOT_COMMON_determineClosestNodeFromCabinetsArray(bobot,bobotAI,bobotAI->cabinets_supply,MAX_CABINETS,&closestNode,&dist);
             /*    si le bot connaît un cabinet ammo il détermine la priorité pour y prendre un ammo pack */
            if(closestNode != INVALID)
            {    priority = BOBOT_FUZZY_determinePriorityForAmmo(bobotAI,ammo,dist);
                BOBOT_AI_proposeAction(bobotAI, GO_TO_CABINET_SUPPLY, closestNode, NULL, NULL, priority);
            }
        }
        /*    SE RAVITAILLER EN RAMASSANT UNE CAISSE DE MUNITIONS */
        BOBOT_COMMON_determineClosestItem(bobotAI->ammoPacks, &closestTarget, &dist);
         /*    si le bot voit un ammo pack il détermine la priorité pour le prendre */
        if(dist != INVALID)
        {    priority = BOBOT_FUZZY_determinePriorityForAmmo(bobotAI,ammo,dist);
            BOBOT_AI_proposeAction(bobotAI, TAKE_AMMO_PACK, INVALID, closestTarget, closestTarget->r.currentOrigin,priority);
        }
    }
    /*    si assez de munitions inhibons les actions de ravitaillement */
    else
    {    BOBOT_AI_inhibitAction(&bobotAI->actions[GO_TO_CABINET_SUPPLY]);
        BOBOT_AI_inhibitAction(&bobotAI->actions[TAKE_AMMO_PACK]);
    }
}

void BOBOT_FUZZY_evaluateActionsInFrontOfEnnemy(gentity_t *bobot, Sbobot *bobotAI, int health)
{    int                    priority;
    int                    dist=INVALID;
    gentity_t            *closestTarget;
    action_t            *armsAction;
    protection_action_t protectionAction;

    armsAction = &bobotAI->armsAction;
    BOBOT_COMMON_determineClosestEnemy(bobot,&closestTarget,&dist);
    /*    si un ennemi est en vue */
    if(dist != INVALID)
    {     BOBOT_AI_proposeActionToArms(bobotAI,BOBOT_FIRE,closestTarget); // s'il voit un ennemi, il l'attaque
       
        /*    et s'il est seul, il peut être intéressant de défendre sa position en attendant des renforts
            (évite les rushs tout seul) */
        priority = BOBOT_FUZZY_determinePriorityToDefendMyPosition(bobotAI);
        BOBOT_AI_proposeAction(bobotAI,DEFEND_POSITION,INVALID,armsAction->ent,armsAction->lastKnownPos,priority);
       
        /*    il peut aussi fuir s'il est trop blesser : */
        protectionAction = BOBOT_COMMON_findProtectionFromEnemy(bobot,bobotAI);
        if(protectionAction != NOT_NECESSARY && protectionAction != NOT_POSSIBLE)
        {    bobotAI->protectionAction = protectionAction;
            priority = BOBOT_FUZZY_determinePriorityToFindProtection(bobotAI,health);
            BOBOT_AI_proposeAction(bobotAI,PROTECT_FROM_ENEMY,INVALID,NULL,bobotAI->protectionPoint,priority);
        }
    }
    /*    si pas d'ennemi en vue */
    else
    {    /*    mais s'il était en train de tirer sur un ennemi, pas les ingé qui ont autre chose à faire */
        if((armsAction->type == BOBOT_FIRE) && (bobot->client->sess.playerType != PC_ENGINEER) && (g_SniperWar.integer==0))
        {     /*    il peut être intéressant de le poursuivre dans sa cachette.
                Car s'il ne le voit plus c'est peut-être parce qu'il s'est planqué. */
            vec_t distEnemy = Distance(bobot->client->ps.origin,bobotAI->armsAction.lastKnownPos);
            int    distPercentage = BOBOT_distancePercentage(distEnemy,BOBOT_ENEMIES_DETECTION_MAX_DIST);
            priority = BOBOT_FUZZY_determinePriorityToChaseEnemy(bobotAI,health,distPercentage);
            BOBOT_AI_proposeAction(bobotAI,CHASE_ENEMY,INVALID,armsAction->ent, armsAction->lastKnownPos,priority);
        }
        bobotAI->armsAction.type = BOBOT_LOOK_AROUND; // il regarde autour de lui dans le but de détecter un ennemi
    }
}

void BOBOT_FUZZY_evaluateMedicActions(gentity_t *bobot, Sbobot *bobotAI, int health)
{    int                priority;
    gentity_t        *teammate;

    if(BOBOT_CLASS_WeaponCharged(bobot->client,WP_MEDKIT))
    {    /*    SE SOIGNER
            2 : faible distance. ce n'est pas 0 car le bot ne peut pas se donner de la vie instantanément.
            TODO : utiliser des règles plus simples pour déterminer cette priorité.
            La prise en compte de la distance prend de la mémoire pour rien dans la FFLL. */
        if(health < 100)
        { BOBOT_AI_proposeAction(bobotAI, GIVE_MYSELF_HEALTH, INVALID, bobot, bobot->client->ps.origin,
                                    BOBOT_FUZZY_determinePriorityForHealth(bobotAI,health,2));
        }
        else
        { BOBOT_AI_inhibitAction(&bobotAI->actions[GIVE_MYSELF_HEALTH]); }    // pas besoin de se soigner
       
        /*     SOIGNER UN EQUIPIER*/
        priority = BOBOT_FUZZY_determinePriorityToGiveHealth(bobotAI,&teammate);
        if(priority != INVALID)
        { BOBOT_AI_proposeAction(bobotAI,GIVE_HEALTH,INVALID,teammate,teammate->client->ps.origin,priority); }
    }
    else
    {    BOBOT_AI_inhibitAction(&bobotAI->actions[GIVE_MYSELF_HEALTH]);        // pas possible de se soigner
        BOBOT_AI_inhibitAction(&bobotAI->actions[GIVE_HEALTH]);                // pas possible de soigner quelqu'un
    }

    /*    DONNER UNE PIQÛRE A UN EQUIPIER */
    priority = BOBOT_FUZZY_determinePriorityToRevive(bobotAI,&teammate);
    if(priority != INVALID)
    {    BOBOT_AI_proposeAction(bobotAI,REVIVE,INVALID,teammate,teammate->r.currentOrigin,priority); }
}

// Bot deguise
void BOBOT_Covert_Deguise(gentity_t *bobot, usercmd_t *ucmd)
{    Sbobot        *bobotAI = &bobots[bobot->s.clientNum];
    gentity_t    *enemy = bobotAI->currentAction.ent;
    vec_t        dist;
    vec3_t         dir,angles;
    qboolean    actionAuthorizedByArms;
    playerState_t *ps;
    int            hintVal;

   
    if(enemy==NULL || enemy->client==NULL || !enemy->inuse)
    {    BOBOT_AI_endOfCurrentAction(bobotAI);
        return;
    }
    if (OnSameTeam(enemy,bobot) || enemy->client->sess.sessionTeam==TEAM_SPECTATOR)
    {    BOBOT_AI_endOfCurrentAction(bobotAI);
        return;
    }
    if(enemy->health>0)
    {    BOBOT_AI_endOfCurrentAction(bobotAI);
        return;
    }
    if (g_SniperWar.integer==1)
    {    BOBOT_AI_endOfCurrentAction(bobotAI);
        return;
    }
    VectorSubtract (enemy->r.currentOrigin, bobot->client->ps.origin, dir);        // Il va vers l'ennemi mort
    dist = VectorLength(dir);
    BOBOT_Move(bobot,ucmd);
    if (dist<50.0)
    {    actionAuthorizedByArms = BOBOT_AI_proposeActionToArms(bobotAI,BOBOT_OBEY_TO_ACTION,NULL);
        if(actionAuthorizedByArms)
        {    ucmd->forwardmove = 0;
            ucmd->rightmove    = 0;
            ucmd->upmove = -48;
            dir[2] -= bobot->client->ps.viewheight;                                // le mec est un peu plus haut
            vectoangles (dir, angles);
            AnglesSubtract (angles , bobot->s.angles , angles);
            BOBOT_MOVEMENT_ChangeBotAngle(angles,bobot);
            if( !(enemy->client->ps.pm_flags & PMF_LIMBO ))
            {    if(bobot->client->ps.weapon != WP_KNIFE)
                    ucmd->weapon=WP_KNIFE;
                ucmd->buttons = BUTTON_ATTACK;
            }
            else
            {    if(random()<0.03)
                {    if(bobot->client->sess.sessionTeam==TEAM_AXIS)
                    {    G_AddEvent(bobot, EV_GLOBAL_SOUND,G_SoundIndex("sound/chat/axis/65a.wav"));        // im a covert ops
                        G_Say(bobot, NULL, SAY_TEAM, "I steal an allied uniform!");
                    }
                    else if(bobot->client->sess.sessionTeam==TEAM_ALLIES)
                    {    G_AddEvent(bobot, EV_GLOBAL_SOUND,G_SoundIndex("sound/chat/allies/65a.wav"));    // im a covert ops
                        G_Say(bobot, NULL, SAY_TEAM, "I steal an axis uniform!");
                    }
                }
               
                    bobot->client->ps.powerups[PW_OPS_DISGUISED]=1;
                    bobot->client->ps.powerups[PW_OPS_CLASS_1] = BODY_CLASS(enemy) & 1;
                    bobot->client->ps.powerups[PW_OPS_CLASS_2] = BODY_CLASS(enemy) & 2;
                    bobot->client->ps.powerups[PW_OPS_CLASS_3] = BODY_CLASS(enemy) & 4;
                    BODY_TEAM(enemy) += 4;
                    enemy->activator = bobot;
                    G_AddEvent( bobot, EV_DISGUISE_SOUND, 0 );
                    G_AddSkillPoints( bobot, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 5.f );
                    G_DebugAddSkillPoints( bobot, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 5, "stealing uniform" );
                    Q_strncpyz( bobot->client->disguiseNetname, g_entities[enemy->s.clientNum].client->pers.netname, sizeof(bobot->client->disguiseNetname) );
                    bobot->client->disguiseRank = g_entities[enemy->s.clientNum].client ? g_entities[enemy->s.clientNum].client->sess.rank : 0;
                    ClientUserinfoChanged( bobot->s.clientNum );
           
            }
        }
        else
        {    BOBOT_AI_endOfCurrentAction(bobotAI);
            BOBOT_COMMON_TakeBestWeapon(bobot,bobotAI->myteam,ucmd);
            return;
        }
    }       
}

// Bot deguise evaluation
void BOBOT_FUZZY_evaluateCovertopsActions(gentity_t *bobot, Sbobot *bobotAI)
{    int                priority,i;
    gentity_t        *enemy;
    gclient_t        *cl;
    vec3_t             dir,angles;
    vec_t            dist,BestDist;

    BestDist=0.0;
    if (g_SniperWar.integer==1)
        return;
    if(bobot->client->sess.playerType!=PC_COVERTOPS)
        return;
    if(bobot->client->ps.powerups[PW_OPS_DISGUISED])
        return;
    for( i = 0; i < level.numConnectedClients; i++ )
    {    cl = &level.clients[i];
        if ( cl )
        {    enemy = &g_entities[i];
            if( enemy)
            {    if (OnSameTeam(enemy,bobot))
                    continue;
                if( enemy->client->ps.pm_flags & PMF_LIMBO )
                    continue;
                if( enemy->health>0 )
                    continue;
                if(enemy->waterlevel>1)
                    continue;
                VectorSubtract(enemy->r.currentOrigin, bobot->client->ps.origin, dir);
                dist = VectorLength(dir);
                if (dist<1500.0)
                {    BestDist=dist;
                    break;
                }
            }
        }
    }
    if(BestDist>0.0)
    {    if(enemy==NULL || enemy->client==NULL || !enemy->inuse)
            BOBOT_AI_inhibitAction(&bobotAI->actions[DEGUISE]);
        else
        {    priority = 50;
            BOBOT_AI_proposeAction(bobotAI,DEGUISE,INVALID,enemy,enemy->r.currentOrigin,priority);
        }
    }
    else
        BOBOT_AI_inhibitAction(&bobotAI->actions[DEGUISE]);
}

void BOBOT_FUZZY_evaluateFieldopsActions(gentity_t *bobot, Sbobot *bobotAI, int ammo)
{    int                priority;
    gentity_t        *teammate;

    if(BOBOT_CLASS_WeaponCharged(bobot->client,WP_AMMO))
    {    /*     SE RAVITAILLER*/
        if(ammo < 100)
        {    priority=BOBOT_FUZZY_determinePriorityForAmmo(bobotAI,ammo,2);
            if(priority != INVALID)
            { BOBOT_AI_proposeAction(bobotAI,GIVE_MYSELF_AMMO,INVALID,bobot,bobot->client->ps.origin,priority); }
        }
        else    // pas besoin de se ravitailler
        {    BOBOT_AI_inhibitAction(&bobotAI->actions[GIVE_MYSELF_AMMO]); }
        /*    RAVITAILLER UN EQUIPIER */
        priority = BOBOT_FUZZY_determinePriorityToGiveAmmo(bobotAI,&teammate);
        if(priority != INVALID)
        { BOBOT_AI_proposeAction(bobotAI,GIVE_AMMO,INVALID,teammate,teammate->r.currentOrigin,priority); }
    }
    else
    {    BOBOT_AI_inhibitAction(&bobotAI->actions[GIVE_MYSELF_AMMO]);        // pas possible de se ravitailler
        BOBOT_AI_inhibitAction(&bobotAI->actions[GIVE_AMMO]);                // pas possible de ravitailler quelqu'un
    }
}

void BOBOT_FUZZY_evaluateBackupTeammate(Sbobot *bobotAI, int health)
{    int            priority;
    gentity_t    *teammate;

    priority = BOBOT_FUZZY_determinePriorityToBackupTeammate(bobotAI,&teammate,health);
    if(teammate->r.svFlags & SVF_BOT)
        priority = INVALID;
    if(priority != INVALID)
    { BOBOT_AI_proposeAction(bobotAI,BACKUP_TEAMMATE,INVALID,teammate,teammate->client->ps.origin,priority); }
}

qboolean BOBOT_FUZZY_evaluateFindProtectionWhileReloading(gentity_t *bobot,Sbobot *bobotAI)
{    /*    si devant un ennemi et plus de munitions. le bot reload en se couvrant (si possible) */
    weapon_t weapon = bobot->client->ps.weapon;
    if((bobotAI->armsAction.type == BOBOT_FIRE) && !(bobot->client->ps.ammoclip[BG_FindClipForWeapon(weapon)])
        && (bobot->client->ps.ammo[BG_FindAmmoForWeapon(weapon)]))
    {    protection_action_t protectionAction = BOBOT_COMMON_findProtectionFromEnemy(bobot,bobotAI);
        if((protectionAction != NOT_NECESSARY) && (protectionAction != NOT_POSSIBLE))
        {    bobotAI->protectionAction = protectionAction;
            BOBOT_AI_proposeAction(bobotAI,PROTECT_FROM_ENEMY_WHILE_RELOADING,INVALID,NULL,bobotAI->protectionPoint,100);
            /*    priorité max (action obligatoire) */
            return qtrue;
        }
    }
    //    BOBOT_AI_inhibitAction(&bobotAI->actions[PROTECT_FROM_ENEMY_WHILE_RELOADING]);
    return qfalse;
}

/*void BOBOT_FUZZY_evaluateFindProtection(gentity_t *bobot, Sbobot *bobotAI, int health)
{    int priority;
    if(bobotAI->armsAction.type != BOBOT_FIRE)
        return;
}*/

/***************************************************************************
Pour un bot, évalue la priorité des objectifs à moyen terme
Transmet ça dans le tableau actions[] du bot.
Le bot n'aura plus qu'à choisir son action en fonction de sa priorité
(et d'éventuels coefficients dynamiques attribués selon les objectifs ou la classe de perso :
attitude défensive ou offensive).
***************************************************************************/
void BOBOT_FUZZY_evaluateMediumRangeObjectives(gentity_t *bobot, Sbobot *bobotAI)
{    int health = bobot->health;    //BOBOT_healthPercentage(bobot); // pourcentage de vie du bot par rapport à son max possible
    int ammo = BOBOT_ammoPercentage(bobot);        // pourcentage de nb de munitions du bot par rapport à son max

    /*    Commençons par les objectifs communs à toutes les classes de bots*/
    if(BOBOT_FUZZY_evaluateFindProtectionWhileReloading(bobot,bobotAI))        //    se protéger en reloadant
    { return; }
    /*    trouver une bonne planque, pav j'ai décommenté cette ligne  */
    //BOBOT_FUZZY_evaluateFindProtection(bobot,bobotAI,health);

    //    Se soigner Les médecins laissent les packs de de soins aux autres.
    if(bobot->client->sess.playerType != PC_MEDIC)
    {    BOBOT_FUZZY_evaluateTakeHealth(bobot,bobotAI,health); }
   
    //    Se ravitailler en munitions, Les field ops laissent les packs de munitions aux autres.
    if(bobot->client->sess.playerType != PC_FIELDOPS)
    {    BOBOT_FUZZY_evaluateTakeAmmo(bobot,bobotAI,ammo);    }
   
    BOBOT_FUZZY_evaluateActionsInFrontOfEnnemy(bobot,bobotAI,health);        //    Attaquer / Se défendre, face à un ennemi
    if(bobot->client->sess.playerType != PC_ENGINEER)                        //    Venir en aide à un équipier qui attaque un ennemi...
    { BOBOT_FUZZY_evaluateBackupTeammate(bobotAI,health); }                    //    les ingés ne perdent pas de temps à aider leurs potes, ils foncent aux objectifs

    /*    Passons maintenant aux objectifs spécifiques des bots, en fonction de leur classe */
    if(bobot->client->sess.playerType == PC_MEDIC)                            //    MEDIC - Soigner un team mate ou soi même
    { BOBOT_FUZZY_evaluateMedicActions(bobot,bobotAI,health); }
    else if(bobot->client->sess.playerType == PC_FIELDOPS)                    //    FIELDOPS - Ravitailler en munitions un team mate ou soi même
    { BOBOT_FUZZY_evaluateFieldopsActions(bobot,bobotAI,ammo); }
    else if(bobot->client->sess.playerType == PC_COVERTOPS)                    //    CovertOPS - Déguisé
    {    if(!g_SniperWar.integer)
        {    if (bot_covertstealuniform.integer)
            {    if(bobot->client->ps.powerups[PW_OPS_DISGUISED]==0)
                    BOBOT_FUZZY_evaluateCovertopsActions(bobot,bobotAI);
            }
        }
    }
}

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