Bobot_ai.c (1)

include "../game/g_local.h"
#include "bobot_move.h"
#include "bobot.h"
#include "bobot_utils.h"
extern void ClientThink_real( gentity_t *ent );

//int Sonar_Longueur;

// le bot vient de marcher sur le goal qu'il désirait atteindre
/*BOBOT_AI_GoalReached(gentity_t* bobot)
{ Sbobot *bobotAI;

 bobotAI = &bobots[bobot->s.clientNum];
 bobotAI->moveFitness += BOBOT_COEFF_IMPORTANCE_OF_GOAL_REACHED;
}*/


/* Le bot flingue un équipier non bot qui lui tire dessus exprès + de 3 fois*/

void BOBOT_Attacker_By_Teammate(gentity_t *bobot,gentity_t *attacker)
{ Sbobot  *bobotAI;
 char  MessFingue[22][100]={"^7u hit me","^7hey !!","^7you kill me ?","^7stop this now !",
          "^7fais chier maintenant!","^7die now !","^7creve batard!","^7bastard...",
          "^7joint us or die!!","^7u kill me OK","^7hey bastard !","^7you r in my team no ?",
          "^7prends ca!","^7take this","^7wants to kill me!!","^7dont hit me",
          "^7shit","^7oops","^7idiot","^7arggggg!!!","^7bad boy","^7dont shoot me"};
 char MessaDire[100];
 int r,x;

 bobotAI = &bobots[bobot->s.clientNum];
 bobotAI->HitByTeammate+=1;
 if (bobotAI->HitByTeammate == 3)
 { r=RandInt(0,21);
  x=RandInt(0,2);
  Q_strncpyz(MessaDire,MessFingue[r],sizeof(MessFingue[r]));
  if (x==0)
  { G_Say(bobot, NULL, SAY_ALL, va("%s %s",attacker->client->pers.netname,MessaDire)); }
  else if (x==1)
  { G_Say(bobot, NULL, SAY_ALL, va("%s",MessaDire)); }
  else
  { G_Say(bobot, NULL, SAY_ALL, va("%s %s",MessaDire,attacker->client->pers.netname)); }
  if(random()<0.6)
  { G_Voice( bobot, NULL, SAY_TEAM, "HoldFire", qtrue); }
  bobotAI->DelayFireOnTeammate=level.time+5000;
 }
}

/*-------------------------------------------------------------------------------------
Routine      : BOBOT_AI_Think
Description  : Main think function for bot
---------------------------------------------------------------------------------------
Organisation globale
-Detection
-Choix
-Action
il faut respecter cet ordre si on veut que les codes soient lisibles ensuite
-------------------------------------------------------------------------------------*/
void BOBOT_AI_Think(gentity_t *bobot)
{   usercmd_t  *ucmd;
 int   testtime,r;
 char  buf[1024], *args;
 qboolean showServerCommand = qtrue;
 Sbobot  *bobotAI;
 bobotAI = &bobots[bobot->s.clientNum];
  
 while( trap_BotGetServerCommand(bobot->client->ps.clientNum, buf, sizeof(buf)) && showServerCommand)
 { args = strchr( buf, ' ');
  if (!args) continue;
  *args++ = '\0';
  Q_CleanStr( args );
  if (!Q_stricmp(buf, "cp "))
  { G_DPrintf("cp: %s\n", args); }
  else if (!Q_stricmp(buf, "cs"))
  { G_DPrintf("cs: %s\n", args); }
  else if (!Q_stricmp(buf, "print"))
  { G_DPrintf("print: %s\n", args); }
  else if (!Q_stricmp(buf, "chat"))
  { G_DPrintf("chat: %s\n", args); }
  else if (!Q_stricmp(buf, "tchat"))
  { G_DPrintf("tchat: %s\n", args); }
  else if (!Q_stricmp(buf, "scores"))
  { G_DPrintf("scores: %s\n", args);}
  else if (!Q_stricmp(buf, "clientLevelShot"))
  {  G_DPrintf("clientLevelShot: %s\n", args); }
 }

 VectorCopy( bobot->client->ps.viewangles, bobot->s.angles );
 VectorSet ( bobot->client->ps.delta_angles, 0, 0, 0);
 ucmd = &bobot->client->pers.cmd;
 ucmd->forwardmove = 0;
 ucmd->upmove  = 0; 
 ucmd->rightmove  = 0;
 ucmd->buttons  &= ~BUTTON_ATTACK;  // Don't attack by default, it's just plain silly !
 ucmd->buttons  &= ~BUTTON_SPRINT;  // Always sprint...
 ucmd->buttons  &= ~BUTTON_ACTIVATE; // ne pas activer par defaut ...
 ucmd->wbuttons  = 0;
 bobot->client->ps.pm_flags &= ~PMF_DUCKED;
 
 /* Detection */
 
 if (bobotAI->goalentity != NULL)
 { if (!bobotAI->goalentity->inuse)
  { bobotAI->goalentity = NULL; }
 }

 /* AVD Send a dead bot into limbo about 300 ms before a respawn
  This gives a medic some time to revive him
  This should make sure the procedure for movement restarts */

 if (bobot->health <= 0) 
 { NodePris[bobot->current_node]=0;         // Ce node (mg42,...) est libre pour un autre bot
  if (bobotAI->BlokedNode != INVALID)
  { NodePris[bobotAI->BlokedNode]=0; }
  bobotAI->state   = BOT_STATE_POSITION;
  bobotAI->goal_node  = INVALID;
  bobotAI->next_node  = INVALID;
  bobot->current_node  = INVALID;
  bobotAI->goalentity  = NULL;
  bobotAI->last_health = bobot->client->pers.maxHealth;
  BOBOT_AI_initBot(bobotAI);
  
  /* We have a dead bot, wait with dropping it in limbo */

  if (!(bobot->client->ps.pm_flags & PMF_LIMBO))
  { qboolean qMedicProche;           // On teste si un medic de sa team est proche
   qMedicProche = BOBOT_CLASS_EstClasseProche(PC_MEDIC,bobotAI);
   if(bobot->client != NULL && bobot->s.number == 1 && bobotAI->cadence < level.time)
   { bobotAI->cadence = level.time + 1000; }
   bobotAI->lookFitness -= 4;          // UN BOT MORT PERD DES POINTS pour compenser
                   // les points qu'il perdrait s'il était en vie
   /* Not yet in limbo, MEDIC ! */
   
   if(random() < 0.05 && bobotAI->lastMedicVoiceChat+5000 < level.time && !qMedicProche)
   { r=RandInt(0,16);
    if(r==0)
    { G_Voice( bobot, NULL, SAY_ALL, "GreatShot", qtrue);
     G_Say( bobot, NULL, SAY_ALL, "Great shot!");
    }
    else if(r==1)
    { r=RandInt(0,9);
     if(r==0)
     { if(bobot->client->sess.sessionTeam == TEAM_ALLIES) 
      { G_Say( bobot, NULL, SAY_ALL, "No!");
       G_globalSound("sound/chat/allies/42b.wav");
      }
      else
      { G_Say( bobot, NULL, SAY_ALL, "Nein!");
       G_globalSound("sound/chat/axis/42c.wav");
      }
     }
     else if(r==1)
     { G_Say( bobot, NULL, SAY_TEAM, "Revive me!");
      G_Voice( bobot, NULL, SAY_TEAM, "FTReviveMe", qtrue);
     }
     else if(r==2)
     { G_Say( bobot, NULL, SAY_TEAM, "Heal me!");
      G_Voice( bobot, NULL, SAY_TEAM, "FTHealMe", qtrue);
     }
    }
    else if (r>13)
    { G_Voice( bobot, NULL, SAY_TEAM, "medic", qtrue);
     G_Say( bobot, NULL, SAY_TEAM, "Medic!");
    }
    bobotAI->lastMedicVoiceChat = level.time;
   }
   if (bobot->client->sess.sessionTeam == TEAM_AXIS)
   { testtime = (level.dwRedReinfOffset + level.timeCurrent - level.startTime) % g_redlimbotime.integer;
    if (testtime > g_redlimbotime.integer - 1000)
    { limbo(bobot,qtrue);          //on appuie 1sec avant le respawn
     bobot->client->pers.lastReinforceTime = 0;
    }
    else
    { bobot->client->pers.lastReinforceTime = testtime; }
   }
   else if (bobot->client->sess.sessionTeam == TEAM_ALLIES)
   { testtime = (level.dwBlueReinfOffset + level.timeCurrent - level.startTime) % g_bluelimbotime.integer;
    if (testtime > g_bluelimbotime.integer - 1000)
    { limbo( bobot, qtrue );         //on appuie 1 sec avant le respawn
     bobot->client->pers.lastReinforceTime = 0;
    }
    else
    { bobot->client->pers.lastReinforceTime = testtime; }
   }
  }
  else
  { if(bobot->client != NULL && bobot->s.number == 1 && bobotAI->cadence < level.time)
   { bobotAI->cadence = level.time + 1000; }
  }
 }
 
 /* Si le bot est en vie on stocke les alliés et ennemis visibles, le bot n'actualise pas sa prise de décision
  à chaque think(). Le but étant de lui donner un temps de réaction plus humain. */

 else 
 { if(bobotAI->flicker >= 8)
  { BOBOT_AI_Detect_Clients(bobot);
   BOBOT_AI_Detect_Item(bobot);
   BOBOT_AI_Choix(bobot,bobotAI,ucmd);
   bobotAI->flicker = 0;
  }
  bobotAI->flicker++;
  
  /* trace une courbe décrivant l'évolution de la vie du bot au cours d'une partie. */
  if(bobot->client != NULL && bobot->s.number == 1 && bobotAI->cadence < level.time)
  { bobotAI->cadence = level.time + 1000; }
  BOBOT_AI_Action(bobot,bobotAI,ucmd);        // mais il agit à chaque think()
 }

 /* on rafraichit la vue du bot */
 BOBOT_MOVEMENT_View_Think(bobot);
    ucmd->angles[PITCH] = ANGLE2SHORT(bobot->s.angles[PITCH]);
    ucmd->angles[YAW] = ANGLE2SHORT(bobot->s.angles[YAW]);
    ucmd->angles[ROLL] = ANGLE2SHORT(bobot->s.angles[ROLL]);
  ucmd->serverTime = level.time;
    ClientThink_real(bobot);
    bobot->nextthink = level.time + BOBOT_NEXT_THINK;
}

/*-------------------------------------------------------------------------------------
Enregistre une action avec ses propriétés dans le tableau
de toutes les actions possibles (sauf tirer)
-------------------------------------------------------------------------------------*/
void BOBOT_AI_proposeAction(Sbobot *bobotAI, objective_t obj, int nodeObj, gentity_t *ent, vec3_t lastKnownPos, int priorityObj)
{ action_t *a = &bobotAI->actions[obj];

 a->type  = obj;
 a->priority = priorityObj;
 a->node  = nodeObj;
 a->ent  = ent;
 a->timeOut = level.time + BOBOT_AI_actionToTimeOfValidityWhenHidden(obj);

 /* ce n'est pas une erreur. C'est parce que si l'action, dans la liste d'actions déclenchable,
  n'est pas remplacée par une autre action du même type, alors c'est que la cible est cachée */

 a->timeOutWhenHidden = -1;
 if(ent != NULL)           // si la cible est une entité
 { if(lastKnownPos != NULL)
  { VectorCopy(lastKnownPos,a->lastKnownPos);}
  else
  { if (PrintDebug)
   { Fuzzy_Printf("BOBOT_AI_proposeAction : Error lastKnownPos == NULL\n"); }
  }
  VectorCopy(ent->r.currentOrigin,a->predictedPos); // on triche ? ouais... juste un peu
  a->node = INVALID;
 }
 else if(nodeObj != INVALID)        // alors que si la cible est un node
 { VectorCopy(nodes[nodeObj].origin,a->lastKnownPos);
  a->ent = NULL;
 }
}

/*------------------------------------------------------------------------------------------------
le cerveau du bot propose une action aux bras et retourne true si les bras acceptent
-------------------------------------------------------------------------------------------------*/
qboolean BOBOT_AI_proposeActionToArms(Sbobot *bobotAI, int action, gentity_t *ent)
{ action_t *attack = &bobotAI->armsAction;

 if(action == BOBOT_FIRE)    // si l'action proposée est de tirer sur un ennemi
 { attack->type = action;
  attack->ent = ent;      // elle a la priorité
  if(ent != NULL)
  { VectorCopy(ent->r.currentOrigin,attack->lastKnownPos); }
  else
  { if (PrintDebug)
   { Fuzzy_Printf("BOBOT ERROR : BOBOT_AI_proposeActionToArms, ent == NULL)\n"); }
  }
  return qtrue;
 }
 else if(attack->type != BOBOT_FIRE)  // sinon, à condition qu'un ennemi ne soit pas en vue,
 { attack->type = action;    // on peut faire autre chose
  return qtrue;
 }
 return qfalse;
}

/*-------------------------------------------------------------------------------------
compare deux actions. retourne qtrue si une différence est remarquée. qfalse sinon
-------------------------------------------------------------------------------------*/
qboolean BOBOT_AI_actionCompare(action_t *a, action_t *b)
{
 //Fuzzy_Printf("je compare ça : ");
 //BOBOT_DEBUG_printAction(a);
 //Fuzzy_Printf("\nà ça : ");
 //BOBOT_DEBUG_printAction(b);
 //Fuzzy_Printf("\n");
 if(a->type != b->type)
 { return qtrue; }
 if(a->ent != b->ent)
 { return qtrue; }
 if(a->node != b->node)
 { return qtrue; }
 return qfalse;
}

/*-------------------------------------------------------------------------------------
retourne la chaine de caractères correspondant au type d'une action
-------------------------------------------------------------------------------------*/
char* BOBOT_AI_actionToString(int action)
{
 switch(action)
 {
  case GO_TO_LR_GOAL:       return "GO TO LR GOAL";
  case GO_TO_CABINET_HEAL:     return "GO TO CABINET HEAL";
  case TAKE_HEALTH_PACK:      return "TAKE HEALTH PACK";
  case GO_TO_CABINET_SUPPLY:     return "GO TO CABINET SUPPLY";
  case TAKE_AMMO_PACK:      return "TAKE AMMO PACK";
  case DEFEND_POSITION:      return "DEFEND POSITION";
  case CHASE_ENEMY:       return "CHASE ENEMY";
  case BACKUP_TEAMMATE:      return "BACKUP TEAMMATE";
  case BACKUP:        return "BACKUP";
  case PROTECT_FROM_ENEMY:     return "PROTECT FROM ENEMY";
  case PROTECT_FROM_ENEMY_WHILE_RELOADING: return "PROTECT FROM ENEMY WHILE RELOADING";
  case CONSTRUCT:        return "CONSTRUCT";
  case PLANT_DYNAMITE:      return "PLANT_DYNAMITE";
  case ARM_DYNAMITE:       return "ARM DYNAMITE";
  case DEFUSE_DYNAMITE:      return "DEFUSE DYNAMITE";
  case GIVE_HEALTH:       return "GIVE HEALTH";
  case GIVE_MYSELF_HEALTH:     return "GIVE MYSELF HEALTH";
  case REVIVE:        return "REVIVE";
  case GIVE_AMMO:        return "GIVE AMMO";
  case GIVE_MYSELF_AMMO:      return "GIVE MYSELF AMMO";
  case BOBOT_LOOK_AROUND:      return "LOOK AROUND";
  case BOBOT_FIRE:       return "FIRE";
  case BOBOT_OBEY_TO_ACTION:     return "OBEY TO ACTION";
  case PLANT_MINE:       return "PLANT_MINE";
  case ARM_MINE:        return "ARM_MINE";
  case DEGUISE:        return "DEGUISE";
  default:         return "INVALID";
 }
}

char* BOBOT_AI_stateToString(int state)
{
 switch(state)
 { case BOT_STATE_STAND:        return "STAND";
  case BOT_STATE_MOVE:        return "MOVE";
  case BOT_STATE_ATTACK:        return "ATTACK";
  case BOT_STATE_WANDER:        return "WANDER";
  case BOT_STATE_FLEE:        return "FLEE";
  case BOT_STATE_POSITION:       return "POSITION";
  case BOT_STATE_GETFLAG:        return "GET FLAG";
  case BOT_STATE_DEFEND_POSITION:      return "DEFEND POSITION";
  case BOT_STATE_CHASE_ENEMY:       return "CHASE ENEMY";
  case BOT_STATE_BACKUP_TEAMMATE:      return "BACKUP TEAMMATE";
  case BOT_STATE_PROTECT_FROM_ENEMY:     return "PROTECT FROM ENEMY";
  case BOT_STATE_PROTECT_FROM_ENEMY_WHILE_RELOADING: return "BOT STATE PROTECT FROM ENEMY WHILE RELOADING";
  case BOT_STATE_SPECIAL_MOVE:      return "SPECIAL MOVE";
  case BOT_STATE_CONSTRUCT:       return "CONSTRUCT";
  case BOT_STATE_DYNAMITE:       return "DYNAMITE";
  case BOT_STATE_ARMING_DYNA:       return "ARMING DYNA";
  case BOT_STATE_DEFUSE:        return "DEFUSE";
  case BOT_STATE_REVIVE:        return "REVIVE";
  case BOT_STATE_GIVE_HEALTH:       return "GIVE HEALTH";
  case BOT_STATE_GIVE_AMMO:       return "GIVE AMMO";
  case BOT_STATE_TAKE_PACK:       return "TAKE PACK";
  case BOT_STATE_TOUT_DROIT:       return "TOUT DROIT";
  case BOT_STATE_MINE:        return "MINE";
  case BOT_STATE_ARMING_MINE:       return "ARMING MINE";
  case BOT_STATE_BACKUP:        return "BACKUP";
  case BOT_STATE_DEGUISE:        return "DEGUISE";
  default:           return "INVALID";
 }
}

/*-------------------------------------------------------------------------------------
retourne le temps maximum de validité d'un type d'action donné
-------------------------------------------------------------------------------------*/
int BOBOT_AI_actionToTimeOfValidity(int action)
{
 switch(action)
 {
  case GO_TO_LR_GOAL:       return UNLIMITED; // pas de timeOut, il faut finir la mission !
  case GO_TO_CABINET_HEAL:     return 20000;
  case TAKE_HEALTH_PACK:      return 8000;
  case GO_TO_CABINET_SUPPLY:     return 20000;
  case TAKE_AMMO_PACK:      return 8000;
  case DEFEND_POSITION:      return 5000;
  case CHASE_ENEMY:       return 8000;
  case BACKUP_TEAMMATE:      return 3000;
  case PROTECT_FROM_ENEMY:     return 8000;
  case PROTECT_FROM_ENEMY_WHILE_RELOADING: return 2000;  // juste le temps de reloader
  case CONSTRUCT:        return 10000;
  case PLANT_DYNAMITE:      return 10000;
  case PLANT_MINE:       return 10000;
  case ARM_DYNAMITE:       return 10000;
  case ARM_MINE :       return 10000;
  case DEFUSE_DYNAMITE:      return 10000;
  case GIVE_HEALTH:       return 8000;
  case GIVE_MYSELF_HEALTH:     return 3000;
  case REVIVE:        return 8000;
  case GIVE_AMMO:        return 8000;
  case GIVE_MYSELF_AMMO:      return 3000;
  case DEGUISE:        return 60000;
  default:         return 0;
 }
}

int BOBOT_AI_actionToTimeOfValidityWhenHidden(int action)
{
 switch(action)
 {
  case GO_TO_LR_GOAL:      return UNLIMITED; // pas de timeOut, un node se voit toujours
  case GO_TO_CABINET_HEAL:    return UNLIMITED; // pas de timeOut, un node se voit toujours
  case TAKE_HEALTH_PACK:     return 5000;
  case GO_TO_CABINET_SUPPLY:    return UNLIMITED; // pas de timeOut, un node se voit toujours
  case TAKE_AMMO_PACK:     return 5000;
  case DEFEND_POSITION:     return 2000;  // ça serait bien de faire un random, pour surprendre l'adversaire
  case CHASE_ENEMY:      return 8000;  // pendant cette action l'ennemi est forcément caché
  case BACKUP_TEAMMATE:     return 1500;
  case PROTECT_FROM_ENEMY:    return 8000;  // doit être identique à l'autre
  case PROTECT_FROM_ENEMY_WHILE_RELOADING:return 2000;  // juste le temps de reloader
  case CONSTRUCT:       return UNLIMITED; // pas de timeOut, un node se voit toujours
  case PLANT_DYNAMITE:     return UNLIMITED; // pas de timeOut, un node se voit toujours
  case ARM_MINE:       return 5000;  // pas de timeOut, un node se voit toujours
  case ARM_DYNAMITE:      return 5000;
  case DEFUSE_DYNAMITE:     return 5000;
  case GIVE_HEALTH:      return 2000;
  case GIVE_MYSELF_HEALTH:    return UNLIMITED; // pas de timeOut, le bot se voit toujours
  case REVIVE:       return 2000;
  case GIVE_AMMO:       return 2000;
  case GIVE_MYSELF_AMMO:     return UNLIMITED; // pas de timeOut, le bot se voit toujours
  case PLANT_MINE:      return UNLIMITED; // pas de timeOut, un node se voit toujours
  case FOLLOW_TEAMMATE:     return UNLIMITED;
  case BACKUP:       return 90000;
  default:        return 0;
 }
}

int BOBOT_AI_actionToState(Sbobot *bobotAI, int action)

 switch(action)
 {
  case GO_TO_LR_GOAL:
  case GO_TO_CABINET_HEAL:
  case GO_TO_CABINET_SUPPLY:
   if(bobotAI->state == BOT_STATE_SPECIAL_MOVE)
   { return BOT_STATE_SPECIAL_MOVE; }
   else if (bobotAI->state == BOT_STATE_TOUT_DROIT)
   { return BOT_STATE_TOUT_DROIT; }
   else
   { return BOT_STATE_MOVE; }
  case TAKE_HEALTH_PACK:      return BOT_STATE_TAKE_PACK;
  case TAKE_AMMO_PACK:      return BOT_STATE_TAKE_PACK;
  case DEFEND_POSITION:      return BOT_STATE_DEFEND_POSITION;
  case CHASE_ENEMY:       return BOT_STATE_CHASE_ENEMY;
  case BACKUP_TEAMMATE:      return BOT_STATE_BACKUP_TEAMMATE;
  case PROTECT_FROM_ENEMY:     return BOT_STATE_PROTECT_FROM_ENEMY;
  case PROTECT_FROM_ENEMY_WHILE_RELOADING: return BOT_STATE_PROTECT_FROM_ENEMY_WHILE_RELOADING;
  case CONSTRUCT:        return BOT_STATE_CONSTRUCT;
  case PLANT_DYNAMITE:      return BOT_STATE_DYNAMITE;
  case ARM_DYNAMITE:       return BOT_STATE_ARMING_DYNA;
  case DEFUSE_DYNAMITE:      return BOT_STATE_DEFUSE;
  case GIVE_HEALTH:       return BOT_STATE_GIVE_HEALTH;
  case GIVE_MYSELF_HEALTH:     return BOT_STATE_GIVE_HEALTH;
  case REVIVE:        return BOT_STATE_REVIVE;
  case GIVE_AMMO:        return BOT_STATE_GIVE_AMMO;
  case GIVE_MYSELF_AMMO:      return BOT_STATE_GIVE_AMMO;
  case PLANT_MINE:       return BOT_STATE_MINE;
  case ARM_MINE:        return BOT_STATE_ARMING_MINE;
  case FOLLOW_TEAMMATE:      return BOT_STATE_FOLLOW_TEAMMATE;
  case BACKUP:        return BOT_STATE_BACKUP;
  case DEGUISE:        return BOT_STATE_DEGUISE;
  default:         return 0;
 }
}

/*-------------------------------------------------------------------------------------
retire de la pile les actions qui ont atteint leur time out
et qui sont au dessus de la pile.
-------------------------------------------------------------------------------------*/
void BOBOT_AI_cleanActionsInStack(Sbobot *bobotAI)
{ int i;

 for(i=bobotAI->sp; i>=0 ; i--)
 { if(bobotAI->actionsStack[i].timeOut < level.time) // si l'action est périmée
  { bobotAI->sp--; }         // l'action est abandonnée
  else
  { return; }           // on n'abandonne pas une action périmée si elle n'est pas au sommet de la pile
 }
}

/*-------------------------------------------------------------------------------------
retire du tableau des actions déclenchables celles qui ont atteint leur time out
-------------------------------------------------------------------------------------*/
void BOBOT_AI_cleanActions(action_t *actions)
{ int   i;
 action_t *action;

 for(i=0; i<NB_COMMON_OBJECTIVES; i++)
 { action = &actions[i];
  if(action->timeOut < level.time)     // si l'action est périmée
  { BOBOT_AI_inhibitAction(action); }
 }
}

/*-------------------------------------------------------------------------------------
place l'action courante en sommet de pile
(car elle a été interrompue par une autre action plus prioritaire)
-------------------------------------------------------------------------------------*/
void BOBOT_AI_pushCurrentAction(gentity_t *bobot,Sbobot *bobotAI)
{ int spPlusPlus;

 BOBOT_AI_cleanActionsInStack(bobotAI);
 spPlusPlus = bobotAI->sp+1;
 if(spPlusPlus >= NB_MAX_ACTIONS_IN_STACK)
 { if (PrintDebug)
  { Fuzzy_Printf("BOBOT_AI_pushCurrentAction : STACK FULL, CANNOT PUSH ACTION\n"); }
 }
 else
 { bobotAI->sp = spPlusPlus;
  bobotAI->actionsStack[spPlusPlus] = bobotAI->currentAction;
  if (PrintDebug)
  { Fuzzy_Printf("BOBOT_AI_pushCurrentAction : PUSH %s\n",BOBOT_AI_actionToString(bobotAI->currentAction.type)); }
 }
}

/*-------------------------------------------------------------------------------------
3emeType
Dépile l'action au sommet de la pile, et l'instaure en tant qu'action courante.
-------------------------------------------------------------------------------------*/
void BOBOT_AI_popInCurrentAction(gentity_t *bobot,Sbobot *bobotAI)
{ int sp;

 BOBOT_AI_cleanActionsInStack(bobotAI);     // d'abord le ménage
 sp = bobotAI->sp;
 if(sp < 0)
 { BOBOT_AI_inhibitAction(&bobotAI->currentAction); } // pas d'action en cours
 else
 { bobotAI->currentAction = bobotAI->actionsStack[sp];
  bobotAI->sp--;
  if (PrintDebug)
  { Fuzzy_Printf("BOBOT_AI_popInCurrentAction:POP %s\n",BOBOT_AI_actionToString(bobotAI->currentAction.type)); }
 }
}  

/*-------------------------------------------------------------------------------------
3emeType : pour debug
-------------------------------------------------------------------------------------*/
void BOBOT_DEBUG_printAction(action_t *a)
{
 G_Printf("\nBOBOT_DEBUG_printAction: %s | timeOut : %d | priority : %d",BOBOT_AI_actionToString(a->type),a->timeOut,a->priority);
}

void BOBOT_DEBUG_showState(Sbobot *bobotAI)
{
 G_Printf("\nBOBOT_DEBUG_showState ---------------------------------------------------------");
 G_Printf("\ntime : %d, current Action : %s, timeOut : %d, timeOutHidden : %d",
    level.time, BOBOT_AI_actionToString(bobotAI->currentAction.type),bobotAI->currentAction.timeOut,
    bobotAI->currentAction.timeOutWhenHidden);
 
 if(bobotAI->currentAction.node != INVALID)
 { G_Printf(", cible : node %d",bobotAI->currentAction.node); }
 
 G_Printf(" | arms action : %s\n",BOBOT_AI_actionToString(bobotAI->armsAction.type));
 G_Printf("\nSTATE : %s\n", BOBOT_AI_stateToString(bobotAI->state));
 
}

void BOBOT_DEBUG_showStack(Sbobot *bobotAI)
{ int i;

 if(bobotAI->sp < 0)
 { return; }
 G_Printf("\nBOBOT_DEBUG_showStack : Etat de la pile :\n");
 for(i=bobotAI->sp; i>=0; i--)
 { BOBOT_DEBUG_printAction(&bobotAI->actionsStack[i]); }
 G_Printf("\n");
}  

void BOBOT_DEBUG_showActions(gentity_t *bobot, Sbobot *bobotAI)
{ int i;
 action_t *a;

 G_Printf("\nBOBOT_DEBUG_showActions : Actions déclenchables :\n");
 for(i=0; i<NB_COMMON_OBJECTIVES; i++)
 { a = &bobotAI->actions[i];
  if(a->priority != INVALID)
  { G_Printf("BOBOT_DEBUG_showActions : %s, priority : %d\n",BOBOT_AI_actionToString(a->type),a->priority); }
 }
 Fuzzy_Printf("\n");
}

/*-------------------------------------------------------------------------------------
L'action courante est terminée, on désactive son déclenchement
-------------------------------------------------------------------------------------*/
void BOBOT_AI_endOfCurrentAction(Sbobot *bobotAI)
{
 BOBOT_AI_inhibitAction(&bobotAI->actions[bobotAI->currentAction.type]);
 bobotAI->state = BOT_STATE_POSITION;
}

/*-------------------------------------------------------------------------------------
L'action prioritaire devient l'action courante
-------------------------------------------------------------------------------------*/
void BOBOT_AI_startNewAction(Sbobot *bobotAI, int action)
{ action_t *a = &bobotAI->actions[action];

 bobotAI->currentAction.type   = a->type;
 bobotAI->currentAction.ent   = a->ent;
 bobotAI->currentAction.node   = a->node;
 bobotAI->currentAction.priority  = a->priority;
 bobotAI->currentAction.timeOut  = level.time + BOBOT_AI_actionToTimeOfValidity(action);
 bobotAI->currentAction.timeOutWhenHidden= -1;
 VectorCopy(a->lastKnownPos,bobotAI->currentAction.lastKnownPos);
 if (PrintDebug)
 { Fuzzy_Printf("BOBOT_AI_startNewAction : New action : ");
  BOBOT_DEBUG_printAction(&bobotAI->currentAction);
 }
}

/*-------------------------End part 1, loot at part 2

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