// UTS 2000 - Fichier 'deplacement.cpp' Gére les déplacements programmés des trains.
// V3.7f - Le 22/09/2019
/*****************************************************************************/
/* DEPLACEMENT                                                               */
/*****************************************************************************/
#include  <windows.h>
#include  <string.h>
#include  <stdlib.h>
#include  <stdio.h>
#include  "Train_UTS.h"
#include  "deplacement.h"
#include  "canton.h"
#include  "train.h"
#include  "garage.h"

#define _CRT_SECURE_NO_WARNINGS  // Limite les messages de warning dans Visual C++

// Déclaration des fonctions externes
extern int get_line(FILE*, char [][CHAR_CONFIG_NB], int*);
extern int pio_var_ch2int(char []);
extern void EasyTextOut(int, int, char*);
extern void EasyLine(int, int, int, int);
extern cCanton  canton;
extern cTrain   train;
extern cGarage  garage;
extern int pio_set_val(int ,int);
extern int pio_define_convert(char [],char []);
extern int pio_get_val(int);

// Déclaration des variables externes
extern HDC hMemDC;
extern HFONT     bmp_fonte;
extern HPEN      bmp_stylo_noir, bmp_stylo_gris128,  bmp_stylo_gris192, bmp_stylo_blanc, bmp_stylo_jaune;
extern HBRUSH  bmp_pinceau_blanc, bmp_pinceau_gris192, bmp_pinceau_gris220, bmp_pinceau_vert, bmp_pinceau_jaune;
extern int depl_tab[DEPL_TAB_NB][DEPL_TAB_IND_TAILLE];
extern int depl_acc_dec[DEPL_TAB_INERTIE_NB]; // Accélération et décélération pour tous les déplacements.
extern int vio_garage_lock_status[NB_GARAGE]; // 0 ou 1, 1 => Le garage est isolé du canton (état réel).
extern int vio_garage_lock_res[NB_GARAGE];  // 0 ou 1, 1 => Garage réservé.
extern int x_mouse, y_mouse, touche, touche_char, x_mouse_move, y_mouse_move, screen_mode_retour;
extern int vio_det[NB_CARTE][NB_CANTON];
extern int vio_srv[NB_CARTE][NB_SERVO];
extern int vio_srv_res[NB_CARTE][NB_SERVO];
extern int vio_srv_cmd[NB_CARTE][NB_SERVO+NB_SERVO_VIT];
extern int vio_aig_res[NB_AIG];
extern int vio_aig_cmd[NB_AIG];
extern int vio_aig_pos0[NB_AIG];
extern int vio_aig_pos1[NB_AIG];
extern int vio_garage_lock_cmd[NB_GARAGE]; // 0 ou 1, 1 => Demande d'isolation du garage (Sera réalisée si il a un train sur le canton).
extern int moins_char_normal;   // 1: '-' est un caractère normal (comme 0)  0: '-' est un séparateur (comme +)
extern int screen_mode;
extern int timer_prg;             // Pas d'activation d'UTS en msec. Cadence UTS et le transfert de trame vers la carte.

//
//
//
cDeplacement deplacement;

char* depl_state_name[]= { 
//	"01234567890123456789012345678901"
	"        -  .  -  .  -          ",		// "DEPL_CST_STATE_IDLE",            Noms à afficher dans le tableau
	"EN ATTENTE RÉSERVE CANT ET AIG ",		// "DEPL_CST_STATE_RESERVATION",
	"POSITIONNE VARIABLES DEBUT_DÉPL",		// "DEPL_CST_STATE_ACTION_DEB",
	"TEMPO EN COURS AVANT DÉPLACEMEN",		// "DEPL_CST_STATE_TEMPO_DEB",
	" ÉTABLI POSITIONS D'AIGUILLAGES",		// "DEPL_CST_STATE_ACTION_AIG",
	"EN ATTENTE POSITION AIGUILLAGES",		// "DEPL_CST_STATE_WAIT_AIG",
	"RÉSERVATION+ALIMENTATION CANTON",		// "DEPL_CST_STATE_ACTION_CANTON",
	"EN ATTENTE PASSAGE CANTON PASS:",		// "DEPL_CST_STATE_WAIT_FIN0",
	"EN ATTENTE ARRIVÉE CANTON/GARAG",		// "DEPL_CST_STATE_WAIT_FIN1",
	" ÉTABLI LA TEMPO D'ARRÊT TRAIN ",		// "DEPL_CST_STATE_ACTION_TAF",
	"TEMPO EN COURS ARRÊT DU TRAIN  ",		// "DEPL_CST_STATE_WAIT_TAF",
	"FIN DÉPLACEMENT,RAZ DES CANTONS",		// "DEPL_CST_STATE_ACTION_CANTON0",
	"ÉTABLI LA TEMPO LIBÉRATION CANT",		// "DEPL_CST_STATE_ACTION_TSF",
	"TEMPO EN COURS LIBÉRATION CANTO",		// "DEPL_CST_STATE_WAIT_TSF",
	"POSITIONNE VARIABLES FIN_DEPLAC",		// "DEPL_CST_STATE_ACTION_FIN",
	"FIN RÉSERVATION CANTONS,AIG,SRV"};		// "DEPL_CST_STATE_DERESERVATION"};

//
/* Plan du programme de gestion des déplacements.
IDLE          En attente d'événement.
  |             si start manuel ou programmé.
RESERVATION   Réservation des cantons, aiguillages et servo.
  < >           si stop -> IDLE
   |            si réservation=ok
ACTION_DEB    Effectue au début du déplacement les actions prévues sur des variables.
  < >           si stop -> ACTION_DERESERVATION
   |            Positionne les variables
TEMPO_DEB     Temporise le départ effectif du déplacement.
  < >           si stop -> ACTION_DERESERVATION
   |            Attend suivant le nb de secondes indiqué.
ACTION_AIG    Demande de positionnement d'aiguillages et des servo.
  < >           si stop -> ACTION_DERESERVATION
   |            Renseigne le tableau avec la position désirée des aiguillages
WAIT_AIG      Positionne les aiguillages et attend que tous soit positionnés.
  < >            si stop -> ACTION_DERESERVATION
  < >            si il reste un aiguillage à positionner -> WAIT_AIG
ACTION_CANTON Réserve les cantons et les met sous tension.
  < >           si stop -> ACTION_DERESERVATION
   |            Réserve les cantons et les met sous tension.
WAIT_FIN0     Attend la condition de passage 'pass:"
  < >           si stop -> ACTION_DERESERVATION
  < >           si condition pass: !=1   -> WAIT_FIN0
WAIT_FIN1     Attend la condition de fin de déplacement.
  < >           si stop -> ACTION_DERESERVATION
  < >           si condition fin: !=1 (et libé: ==0)  -> WAIT_FIN1
ACTION_TAF    Mise en place tempo arrêt 'tafx' pour attendre avant la mise hors tension du canton de fin.
  < >           si stop -> ACTION_DERESERVATION
  < >           si pas de temps d'arrêt -> ACTION_CANTON0
   |            Mise en place de cette temporisation
WAIT_TAF      Attente de la fin de la temporisation de mise hors tension du canton de fin.
  < >           si stop -> ACTION_DERESERVATION
  < >           si tempo != 0 -> WAIT_TAF
ACTION_CANTON0 Actions sur les cantons
  < >           si stop -> ACTION_DERESERVATION
  < >           si vitesse !=0  -> ACTION_CANTON0
   |            Raz des cantons
ACTION_TSF    Mise en place tempo arrêt 'tsfx' pour attendre avant la libération des cantons.
  < >           si stop -> ACTION_DERESERVATION
  < >           si pas de temps d'arrêt -> ACTION_FIN
   |            Mise en place de cette temporisation
WAIT_TSF      Attente de la fin de la temporisation de libération des cantons.
  < >           si stop -> ACTION_DERESERVATION
  < >           si tempo != 0 -> WAIT_TSF
ACTION_FIN    Effectue en fin de déplacement les actions prévues sur des variables.
  < >           si stop -> ACTION_DERESERVATION
   |            Positionne les variables
DERESERVATION Fin de réservation des cantons, aiguillage et servo.
   |            Fin de réservation des cantons, aiguillage et servo
   -> IDLE
*/

//
cDeplacement::cDeplacement(void) { }


// Lecture dans le fichier 'config.txt' des paramètres pour la section 'déplacement'.
//
void cDeplacement::init(char filename[])
{
	FILE* pf;
	char ch[CHAR_CONFIG_NB],ch_tab[BLOC_CONFIG_NB][CHAR_CONFIG_NB],ch_error[200],ch_syst[100];
	int  ch_nb,j,i;
	int  no_depl,i_cant,i_aig,i_action;
	int  var;

	for(j=0;j<DEPL_TAB_NB;j++) for(i=0;i<DEPL_TAB_IND_TAILLE;i++) depl_tab[j][i]=-1;
	for(j=0;j<DEPL_TAB_INERTIE_NB;j++) depl_acc_dec[j]=-1;

	for(j=0;j<DEPL_TAB_NB;j++) {
		depl_tab[j][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_IDLE;
		depl_tab[j][DEPL_TAB_IND_START_RUN]=0;
		depl_tab[j][DEPL_TAB_IND_STOP]=0;		// Si = 1 = demande d'arrêt manuel du déplacement, menu : 'Tables > Déplacements' + colonne 'stop'.
		depl_tab[j][DEPL_TAB_IND_TEMPO]=0;
	}
	for(j=0;j<NB_AIG;j++) vio_aig_res[j]=0;
	for(j=0;j<DEPL_TAB_NB;j++) depl_name[j][0]='\0';
	if((pf=fopen(filename,"rt"))==NULL) {
		MessageBox(NULL,"Impossible d'ouvrir le fichier de configuration des déplacements 'Config.txt'","Erreur",MB_OK|MB_ICONERROR); exit(1);
	}
	moins_char_normal=0;
	while(fscanf(pf,"%s%*[^\n]\n",ch)!=EOF) {	// " %s" => "%s%*[^\n]\n" = Nouvelle formule au 02/03/2012, lit uniquement le permier mot de chaque ligne.
		if(STR_SAME strcmp(ch,"#depl")) {
			fscanf(pf," %s",ch);				// Ignore le caractère '['

			while(get_line(pf,ch_tab,&ch_nb)) {
				if(ch_nb>=BLOC_CONFIG_NB) {
					MessageBox(NULL,"Le fichier 'config.txt' comporte une ligne trop complexe dans la section '#depl'","Erreur",MB_OK|MB_ICONERROR);
					MessageBox(NULL,"Section '#depl' (ligne>75 blocs) commençant par (taper sur Entrée) : ","Erreur",MB_OK|MB_ICONERROR);
					strcpy(ch_error,"Section #depl Erreur ligne :");
					for(i=0;i<ch_nb;i++) { strcat(ch_error,"  "); strcat(ch_error,ch_tab[i]); }
					MessageBox(NULL,ch_error,"UTS - Erreur",MB_OK|MB_ICONERROR); exit(1);
				}
				if(ch_tab[0][0]==']') break;			// Fin de la section #aigauto
				for(i=0;i<ch_nb;i++) if(ch_tab[i][0]=='@') ch_nb=i;  // Supprime les commentaires après le caractère'@'
				i=0;
				no_depl=-1;
				while(i<ch_nb) {
//   acc-dec: 01-23  ou   acc-dec: xx-02  ou   acc-dec: 08-xx  ou   acc-dec: xx-xx  (V3.4)
					if (STR_SAME strcmp(ch_tab[i],"acc") && ch_tab[i+1][0]=='-' && STR_SAME strcmp(ch_tab[i+2],"dec") && ch_tab[i+3][0]==':' && ch_tab[i+5][0]=='-' && ch_nb-i>=6) {
						j=1;
						if (STR_DIFF strcmp(ch_tab[i+4],"xx")) { // Valeur d'inertie en accélération pour tous les déplacemenbs
							if (atoi(ch_tab[i+4])>=VITESSE_INERTIE_MINI && atoi(ch_tab[i+4])<=VITESSE_INERTIE_MAXI) {
								depl_acc_dec[DEPL_TAB_INERTIE_ACC]=atoi(ch_tab[i+4]);
							}
							else j=0; // Erreur, on sort un message.
						}
						if (STR_DIFF strcmp(ch_tab[i+6],"xx")) { // Valeur d'inertie en décélération pour tous les déplacemenbs
							if (atoi(ch_tab[i+6])>=VITESSE_INERTIE_MINI && atoi(ch_tab[i+6])<=VITESSE_INERTIE_MAXI) {
								depl_acc_dec[DEPL_TAB_INERTIE_DEC]=atoi(ch_tab[i+6]);
							}
							else j=0; // Erreur, on sort un message.
						}
						if (j==1) {i=ch_nb; continue; } // i=ch_nb => On passe à la ligne suivante, car il n'y a rien après cette directive sur la même ligne.
					}
// d0
					if (ch_nb-i>=1) {
						if( ch_tab[i][0]=='d') {
							no_depl=atoi(&ch_tab[i][1]);
							if (no_depl>=0 && no_depl<DEPL_TAB_NB) {	// N° de déplacement valide ?
								i_cant=0;    // Compte le nombre de cantons par déplacement.
								i_aig=0;     // Compte le nombre d'aiguillages par déplacement.
								i_action=0;  // Compte le nombre d'action [<sdeb|cdeb|sfin|cfin|sc> <var>] par déplacement.
								i++; continue;
							}
						}
					}
// sdeb, cdeb, sfin, cfin, sc:io_det_0
/* ossibilité également de jouer avec 4 variables avec (par ex  pour lancer des annonces):
   [<sdeb|cdeb|sfin|cfin|sc> <var>]  
   sdeb: mettre la variable à 1 au début du déplacement 
   cdeb: mettre la variable à 0 au début du déplacement 
   sfin: mettre la variable à 1 au début du déplacement 
   cfin: mettre la variable à 0 au début du déplacement 
   sc  : mettre la variable à 1 au début du déplacement et à 0 à la fin
*/
					if (ch_nb-i>=3) {
						if( !strcmp(ch_tab[i],"sdeb")||!strcmp(ch_tab[i],"cdeb")||!strcmp(ch_tab[i],"sfin")||!strcmp(ch_tab[i],"cfin")||!strcmp(ch_tab[i],"sc")) {
							if( ch_tab[i+1][0]==':') {
								if ( i_action < DEPL_CST_NB_MAX_ACTION ) { // Limite le nombre d'actions possibles.
									if(!strcmp(ch_tab[i],"sdeb")) depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP+i_action*2]=DEPL_CST_ACTION_OP_SET_DEB;
									if(!strcmp(ch_tab[i],"cdeb")) depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP+i_action*2]=DEPL_CST_ACTION_OP_CLR_DEB;
									if(!strcmp(ch_tab[i],"sfin")) depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP+i_action*2]=DEPL_CST_ACTION_OP_SET_FIN;
									if(!strcmp(ch_tab[i],"cfin")) depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP+i_action*2]=DEPL_CST_ACTION_OP_CLR_FIN;
									if(!strcmp(ch_tab[i],"sc"  )) depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP+i_action*2]=DEPL_CST_ACTION_OP_SET_CLR;
									if(pio_define_convert(ch_tab[i+2],ch_syst)==0) strcpy(ch_syst,ch_tab[i+2]);
									if((var=pio_var_ch2int(ch_syst))!=-1)          depl_tab[no_depl][DEPL_TAB_IND_ACTION_VAR+i_action*2]=var;
									i_action++;
									i=i+3; continue;
								}
							}
						}
					}
// start2:<numéro_de_canton> 
					if (ch_nb-i>=3) {
						if( STR_SAME strcmp(ch_tab[i],"start2")) {
							if( ch_tab[i+1][0]==':' && ch_tab[i+2][0]=='c') {
								if (atoi(&ch_tab[i+2][1])>=0 && atoi(&ch_tab[i+2][1])<(300+NB_CANTON) && (atoi(&ch_tab[i+2][1])%100)<NB_CANTON) {
									depl_tab[no_depl][DEPL_TAB_IND_CANT_START2]=atoi(&ch_tab[i+2][1]);
									i=i+3; continue;
								}
							}
						}
					}
// start:c<numéro_de_canton>     Le train se trouve au départ sur le canton 'numéro_de_canton'.
					if (ch_nb-i>=3) {
						if( STR_SAME strcmp(ch_tab[i],"start")) {
							if( ch_tab[i+1][0]==':' && ch_tab[i+2][0]=='c') {
								if (atoi(&ch_tab[i+2][1])>=0 && atoi(&ch_tab[i+2][1])<(300+NB_CANTON) && (atoi(&ch_tab[i+2][1])%100)<NB_CANTON) {
									depl_tab[no_depl][DEPL_TAB_IND_CANT_START]=atoi(&ch_tab[i+2][1]);
									i=i+3; continue;
								}
							}
						}
					}
// start:g<numéro_de_garage>     Le train se trouve au départ sur le garage 'numéro_de_garage'.
					if (ch_nb-i>=3) {
						if( STR_SAME strcmp(ch_tab[i],"start")) {
							if( ch_tab[i+1][0]==':' && ch_tab[i+2][0]=='g') {
								if (atoi(&ch_tab[i+2][1])>=0 && atoi(&ch_tab[i+2][1])<NB_GARAGE_REEL) {		// N° de garage valide ?
									depl_tab[no_depl][DEPL_TAB_IND_CANT_START]=1000+atoi(&ch_tab[i+2][1]);	//1000 for garage
									i=i+3; continue;
								}
							}
						}
					}
// stop:c<numéro_de_canton>
					if (ch_nb-i>=3) {
						if( STR_SAME strcmp(ch_tab[i],"stop")) {
							if (atoi(&ch_tab[i+2][1])>=0 && atoi(&ch_tab[i+2][1])<(300+NB_CANTON) && (atoi(&ch_tab[i+2][1])%100)<NB_CANTON) {
								if( ch_tab[i+1][0]==':' && ch_tab[i+2][0]=='c') {
									depl_tab[no_depl][DEPL_TAB_IND_CANT_STOP]=atoi(&ch_tab[i+2][1]);
									i=i+3; continue;
								}
							}
						}
					}
// stop:g<numéro_de_garage>        Arrivée sur une voie de garage.
					if(ch_nb-i>=3) {
						if(STR_SAME strcmp(ch_tab[i],"stop")) {
							if(ch_tab[i+1][0]==':' && ch_tab[i+2][0]=='g') {
								if (atoi(&ch_tab[i+2][1])>=0 && atoi(&ch_tab[i+2][1])<NB_GARAGE_REEL) { // N° de garage valide ?
									depl_tab[no_depl][DEPL_TAB_IND_CANT_STOP]=1000+atoi(&ch_tab[i+2][1]);
									i=i+3; continue;
								}
							}
						}
					}
// train:<numéro_de_train>
					if (ch_nb-i>=3) {
						if (STR_SAME strcmp(ch_tab[i],"train")) {
							if (ch_tab[i+1][0]==':') {
								if (atoi(ch_tab[i+2])>=0 && atoi(ch_tab[i+2])<NB_TRAIN) {				// N° de train valide ?
									depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_ONLY]=atoi(ch_tab[i+2]);
									i=i+3; continue;
								}
							}
						}
					}
// c0+12    c<numéro_de_canton><+-><vitesse_du_canton>
					if (ch_nb-i>=3) {
						if (ch_tab[i][0]=='c' && (ch_tab[i+1][0]=='+' || ch_tab[i+1][0]=='-')) {
							if (i_cant<DEPL_CST_NB_MAX_CANT) {											// Limite le nombre de cantons ou de garages possibles.
								if (abs(atoi(ch_tab[i+2]))!=0 && abs(atoi(ch_tab[i+2]))<=VITESSE_CANT_MAXI) { // Vitesse valide ?
									if (atoi(&ch_tab[i][1])>=0 && atoi(&ch_tab[i][1])<(300+NB_CANTON) && (atoi(&ch_tab[i][1])%100)<NB_CANTON) {
										depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+i_cant*2]=atoi(&ch_tab[i][1]);
										if(ch_tab[i+1][0]=='+') depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT+i_cant*2]=atoi(ch_tab[i+2]);
										if(ch_tab[i+1][0]=='-') depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT+i_cant*2]=0-atoi(ch_tab[i+2]);
										i_cant++;
										i=i+3; continue;
									}
								}
							}
						}
					}
// g3       g<numéro_de_garage> 
					if (ch_nb-i>=1) {
						if (ch_tab[i][0]=='g') {
							if (i_cant < DEPL_CST_NB_MAX_CANT ) { // Limite le nombre de cantons ou de garages possibles.
								if (atoi(&ch_tab[i][1])>=0 && atoi(&ch_tab[i][1])<NB_GARAGE_REEL) { // N° de garage valide ?
									depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+i_cant*2]=1000+atoi(&ch_tab[i][1]);
									depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT+i_cant*2]=-1;
									i_cant++;
									i++; continue;   // Un seul objet 'g3'.
								}
							}
						}
					}
// a3.1     a<numéro_d'aiguilage>.<position>
					if (ch_nb-i>=3) {
						if (ch_tab[i][0]=='a' && ch_tab[i+1][0]=='.') {
							if (i_aig < DEPL_CST_NB_MAX_AIG ) { // Limite le nombre d'aiguillages possibles.
								if (atoi(&ch_tab[i][1])>=0 && atoi(&ch_tab[i][1])<NB_AIG && (atoi(ch_tab[i+2])==0 || atoi(ch_tab[i+2])==1)) { // Aig valide ?
									depl_tab[no_depl][DEPL_TAB_IND_AIG_0_NO +i_aig*2]=atoi(&ch_tab[i][1]);
									depl_tab[no_depl][DEPL_TAB_IND_AIG_0_POS+i_aig*2]=atoi(ch_tab[i+2]);
									i_aig++;
									i=i+3; continue;
								}
							}
						}
					}
// taf2      taf<0-999> : Temps en secondes entre la détection de fin et la mise hors tension des cantons= temps de freinage.
					if (ch_nb-i>=1) {
						if (!strncmp(ch_tab[i],"taf",3)) {
							if (atoi(&ch_tab[i][3])>=0 && atoi(&ch_tab[i][3])<=999) {		// Nombre de seconde valide ?
								depl_tab[no_depl][DEPL_TAB_IND_TAF]=(atoi(&ch_tab[i][3])*1000)/(timer_prg+15); // Si oui converti en nombre de tic.
								i++; continue;   // Un seul objet 'tafx'.
							}
						}
					}
// tsf3      tsf<0-999> : Temps en secondes entre la détection de fin et la libération des cantons.
					if (ch_nb-i>=1) {
						if (!strncmp(ch_tab[i],"tsf",3)) {
							if (atoi(&ch_tab[i][3])>=0 && atoi(&ch_tab[i][3])<=999) {		// Nombre de seconde valide ?
								depl_tab[no_depl][DEPL_TAB_IND_TSF]=(atoi(&ch_tab[i][3])*1000)/(timer_prg+15); // Si oui converti en nombre de tic.
								i++; continue;   // Un seul objet 'tsfx'.
							}
						}
					}
// pass:det_c1  optionnel = canton de passage dans le cas ou le canton d'arrivée est aussi celui du départ.
					if (ch_nb-i>=3) {
						if (!strncmp(ch_tab[i],"pass",4) && ch_tab[i+1][0]==':' && ch_tab[i+2][0]!='!') {
							depl_tab[no_depl][DEPL_TAB_IND_FIN_P_VAL]=1;
							if (pio_define_convert(ch_tab[i+2],ch_syst)==0) {
								strcpy(ch_syst,ch_tab[i+2]);
								var=pio_var_ch2int(ch_syst);
								if (var!=-1) {												// On vérifie que la variable existe
									depl_tab[no_depl][DEPL_TAB_IND_FIN_P_VAR]=var;
									i=i+3; continue; // + 3 termes = 'pass' ':' 'det_c1'
								}
							}
						}
					}
// tempo:123  optionnel = temporisation après avoir initialiser les variables et avant de lancer le déplacement, le temps de faire une annonce sonore.
					if (ch_nb-i>=3) {
						if (!strncmp(ch_tab[i],"tempo",5) && ch_tab[i+1][0]==':') {
							if (atoi(&ch_tab[i+2][0])>=0 && atoi(&ch_tab[i+2][0])<=999) {		// Nombre de seconde valide ?
								depl_tab[no_depl][DEPL_TAB_IND_TEMPO_DEB_VAL]=(atoi(&ch_tab[i+2][0])*1000)/(timer_prg+15); // Si oui converti en nombre de tic.
								i=i+3; continue; // + 3 termes = 'tempo ':' '123'
							}
						}
					}
// libe:det_c2  optionnel = avant dernier canton que l'on doit libérer pour que la condition de fin soit valide (en plus de fin:).
					if (ch_nb-i>=3) {
						if (!strncmp(ch_tab[i],"libe",4) && ch_tab[i+1][0]==':' && ch_tab[i+2][0]!='!') {
							depl_tab[no_depl][DEPL_TAB_IND_FIN_L_VAL]=1;
							if(pio_define_convert(ch_tab[i+2],ch_syst)==0) {
								strcpy(ch_syst,ch_tab[i+2]);
								var=pio_var_ch2int(ch_syst);
								if (var!=-1) {												// On vérifie que la variable existe
									depl_tab[no_depl][DEPL_TAB_IND_FIN_L_VAR]=var;
									i=i+3; continue; // + 3 termes = 'libe' ':' 'det_c1'
								}
							}
						}
					}
// fin:det_c3   Condition obligatoire de fin = Arrivée sur le canton de fin.
					if (ch_nb-i>=3) {
						if (!strncmp(ch_tab[i],"fin",3) && ch_tab[i+1][0]==':' && ch_tab[i+2][0]!='!') {
							depl_tab[no_depl][DEPL_TAB_IND_FIN_F_VAL]=1;
							if(pio_define_convert(ch_tab[i+2],ch_syst)==0) {
								strcpy(ch_syst,ch_tab[i+2]);
								var=pio_var_ch2int(ch_syst);
								if(var!=-1) {												// On vérifie que la variable existe
									depl_tab[no_depl][DEPL_TAB_IND_FIN_F_VAR]=var;
									i=i+3; continue; // + 3 termes = 'fin' ':' 'det_c1'
								}
							}
						}
					}
					
// halt:in_23   Condition optionnelle de fin rapide = Arrivée sur un contact de fin de canton (butoir).
//    Utile quand on décroche une locomotive et que l'on passe au canton suivant, si les essieux des wagons sont résistifs,
//    la directive libe:<canton> ne suffit pas à arrêter la loco dans ce cas sur le canton d'arrivée.

					if (ch_nb-i>=3) {
						if (!strncmp(ch_tab[i],"halt",3) && ch_tab[i+1][0]==':' && ch_tab[i+2][0]!='!') {
							depl_tab[no_depl][DEPL_TAB_IND_FIN_H_VAL]=1;
							if(pio_define_convert(ch_tab[i+2],ch_syst)==0) {
								strcpy(ch_syst,ch_tab[i+2]);
								var=pio_var_ch2int(ch_syst);
								if(var!=-1) {												// On vérifie que la variable existe
									depl_tab[no_depl][DEPL_TAB_IND_FIN_H_VAR]=var;
									i=i+3; continue; // + 3 termes = 'halt' ':' 'det_c1'
								}
							}
						}
					}

					
// name:DE_gare_voie3_A_entree    Nom du déplacement sur DEPL_TAB_NOM_TAILLE caractères maximum (40 en V3.3).
					if (ch_nb-i>=3) {
						if (!strncmp(ch_tab[i],"name",4) && ch_tab[i+1][0]==':') {
							if(strlen(ch_tab[i+2])<DEPL_TAB_NOM_TAILLE) {				// Le nom du déplacement doit être inférieur ou égale à 'DEPL_TAB_NOM_TAILLE' caractères.
								strcpy(depl_name[no_depl],ch_tab[i+2]);
								i=i+3; continue; // + 3 termes = 'name' ':' 'nom'
							}
						}
					}
// srv0:27   srv<numéro_de_servo>:<position_du_servo>
					if((ch_nb-i)>=3)
					if( !strncmp(ch_tab[i],"srv",3) && ch_tab[i+1][0]==':') {
						depl_tab[no_depl][DEPL_TAB_IND_SRV_NO] =atoi(&ch_tab[i][3]);
						depl_tab[no_depl][DEPL_TAB_IND_SRV_VAL]=atoi(ch_tab[i+2]);
						i=i+3; continue;
					}
					strcpy(ch_error,"Fichier 'config.txt',\n\nSection #Déplacement,\n\nErreur de description sur la ligne :");
					for(i=0;i<ch_nb;i++) { strcat(ch_error,"  "); strcat(ch_error,ch_tab[i]); }
					MessageBox(NULL,ch_error,"UTS - Erreur dans 'config.txt'",MB_OK|MB_ICONERROR); 	exit(1);
				}  //fin groupe de mot
				if (no_depl>=0) {
					if ( depl_tab[no_depl][DEPL_TAB_IND_FIN_F_VAL]!=1) {
						strcpy(ch_error,"Fichier 'config.txt',\n\nSection #Déplacement, erreur il manque l'instruction 'fin:' ligne :");
						for(i=0;i<ch_nb;i++) { strcat(ch_error,"  "); strcat(ch_error,ch_tab[i]); }
						MessageBox(NULL,ch_error,"UTS - Erreur dans 'config.txt'",MB_OK|MB_ICONERROR); 	exit(1);
					} // Il faudra vérifier que start: / start2: existe
				}
			}	// While (get_line) fin de la ligne de texte.
			break; // Pour sortir de la lecture de la suite du fichier.
		}		// if(==#depl)   fin description '#depl'.
	}			// While (scanf)    fin du fichier 'config.txt'.
	moins_char_normal=1;		// '-' est un caractère normal, comme '+'.
	fclose(pf);
}



// Fonction appelée uniquement en cas de débugage volontaire.
//
void cDeplacement::verif(void)
{
	FILE* pf;
	int i,j;
	if((pf=fopen("debug_depl.txt","wt"))==NULL) {
		MessageBox(NULL,"Impossible de créer le fichier 'Debug_depl.txt'","Erreur",MB_OK|MB_ICONERROR); exit(1);
	}
	for(j=0;j<DEPL_TAB_NB;j++) {
		fprintf(pf,"\n%3d:",j);
		for(i=0;i<DEPL_TAB_IND_TAILLE;i++) fprintf(pf," %4d",depl_tab[j][i]);
	}
	fclose(pf);
}



// Gére les séquences de déplacements à chaque 'ticks'.
//
//
void cDeplacement::tick(void)
{
	int no_depl,cant,cant_start,cant_start1,cant_start2,cant_stop,aig;
	int	action,ok,ok1,ok2,i,var,val,pos,vit,t_only,g,g_start,g_stop,s;
	int tx,t1,t2;
	int var2,val2,var3,val3;
	for (no_depl = 0; no_depl < DEPL_TAB_NB; no_depl++) { // Pour tous les déplacements.
		if (depl_tab[no_depl][DEPL_TAB_IND_STOP]) { // Si = 1 = demande d'arrêt manuel du déplacement, menu : 'Tables > Déplacements' + colonne 'stop'.
			depl_tab[no_depl][DEPL_TAB_IND_STOP] = 0;
			depl_tab[no_depl][DEPL_TAB_IND_TEMPO] = 0;

			if (depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_RESERVATION) { // On était encore au stade de la réservation. 
				depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_IDLE;
				depl_tab[no_depl][DEPL_TAB_IND_START_RUN] = 0;
			}
			else if (depl_tab[no_depl][DEPL_TAB_IND_STEP] != DEPL_CST_STATE_IDLE)
				depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_DERESERVATION;
		}

		//DEPL_CST_STATE_IDLE = En attente d'événement.
		if (depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_IDLE) {
			if (depl_tab[no_depl][DEPL_TAB_IND_START_RUN] == 0) continue;       // En attente et on ne demande rien -> Goto fin.
			depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_RESERVATION; // En attente et on demande le démarrage -> Etat_réservation.
		}

		//DEPL_CST_STATE_RESERVATION = Réservation des cantons, aiguillages et servo.
		if (depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_RESERVATION) {
			// Vérification train sur canton start
			ok = 1;
			cant_start = -1;
			g_start = -1;
			cant_start1 = depl_tab[no_depl][DEPL_TAB_IND_CANT_START];
			cant_start2 = depl_tab[no_depl][DEPL_TAB_IND_CANT_START2];
			if (cant_start1 >= 1000 || cant_start2 >= 1000) { // Départ depuis un garage. >1000 corrigée en V3.3.
				if (cant_start1 >= 1000) g_start = cant_start1 - 1000; else g_start = cant_start2 - 1000;
				if (vio_garage_lock_res[g_start] == 1) continue;			// En réservation et le garage est reservé  -> Goto fin.
				if (vio_garage_lock_status[g_start] == 0) continue;		// En réservation et le garage est connecté -> Goto fin.
				tx = garage.numero_train[g_start];					    // -1 = Garage relié au canton, ou Numéro de train occupant le garage isolé du canton.
				if (tx == -1) continue;									// Le numéro de train n'est pas valide -> Goto fin.
			}
			else {  // Départ depuis un canton.
				ok1 = 0; ok2 = 0; t1 = 0; t2 = 0; tx = 0; 
				if (cant_start1 != -1) if (canton.master_selectif[cant_start1 / 100][cant_start1 % 100]) { ok1 = 1; t1 = canton.num_train[cant_start1 / 100][cant_start1 % 100]; }
				if (cant_start2 != -1) if (canton.master_selectif[cant_start2 / 100][cant_start2 % 100]) { ok2 = 1; t2 = canton.num_train[cant_start2 / 100][cant_start2 % 100]; }
				if (ok1 && ok2) if (t1 != t2) ok1 = ok2 = 0;
				if (ok1) { cant_start = cant_start1; tx = t1; }
				if (ok2) { cant_start = cant_start2; tx = t2; }
				if (cant_start == -1 || tx == -1) continue;
			}
			if (train.en_auto[tx] == 0 || train.enable[tx] == 0) ok = 0;
			t_only = depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_ONLY];
			if (t_only != -1 && t_only != tx) ok = 0;
			depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE] = tx;
			g_stop = depl_tab[no_depl][DEPL_TAB_IND_CANT_STOP]; // Le garage d'arrivé doit être libre.
			if (g_stop >= 1000) {
				if (vio_garage_lock_status[g_stop - 1000] != 0) ok = 0;
			}

			// Vérification des cantons libres et réservation
			// DEPL_CST_NB_MAX_CANT = 10
			// DEPL_TAB_IND_CANT_0_NO = 0
			//
			for (i = 0; i < DEPL_CST_NB_MAX_CANT; i++) {
				cant = depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO + 2 * i];
				if (cant < 1000) {
					if (cant != -1) if (canton.res_auto[cant / 100][cant % 100] == 1) ok = 0;
					if (cant != -1) if (cant != cant_start1 && cant != cant_start2) if (canton.master_selectif[cant / 100][cant % 100] == 1) ok = 0;
				}
				else {
					g = cant - 1000;
					if (vio_garage_lock_res[g] == 1) ok = 0; // 0 ou 1, 1 => Garage réservé.
					if (g != g_start) if (vio_garage_lock_status[g] == 1) ok = 0; // 0 ou 1, 1 => Le garage est isolé du canton (état réel).
				}
				cant = depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO + 2 * i];                     // UU-NEW-SENS
				vit = depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT + 2 * i];                     // UU-NEW-SENS
				if (cant != -1) if (cant < 1000) {                                            // UU-NEW-SENS
					if (vit > 0 && (canton.allowed_sens[cant / 100][cant % 100] & 1) == 0) ok = 0;   // UU-NEW-SENS
					if (vit < 0 && (canton.allowed_sens[cant / 100][cant % 100] & 2) == 0) ok = 0;   // UU-NEW-SENS
				}                                                                       // UU-NEW-SENS
			}

			// Vérification des aiguillages libres et réservation.
			for (i = 0; i < DEPL_CST_NB_MAX_AIG; i++) {
				aig = depl_tab[no_depl][DEPL_TAB_IND_AIG_0_NO + 2 * i];
				if (aig != -1) if (vio_aig_res[aig] == 1) { ok = 0; break; }
			}

			// Vérification des servos libres et réservation.
			s = depl_tab[no_depl][DEPL_TAB_IND_SRV_NO];
			if (s != -1) { if (vio_srv_res[s / 100][s % 100]) ok = 0; }

			// Si vérifications positives alors réservation cantons, aiguillages et servos.
			if (ok) {
				for (i = 0; i < DEPL_CST_NB_MAX_CANT; i++) {
					cant = depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO + 2 * i];
					if (cant != -1) {
						if (cant < 1000) {
							canton.res_auto[cant / 100][cant % 100] = 1;
							canton.vit_auto[cant / 100][cant % 100] = 0;
							canton.master_selectif[cant / 100][cant % 100] = 0;
							canton.num_train[cant / 100][cant % 100] = tx;
						}
					}
					if (cant >= 1000) {
						g = cant - 1000;
						vio_garage_lock_res[g] = 1; // 1 => Garage réservé.
					}
				}
				g_stop = depl_tab[no_depl][DEPL_TAB_IND_CANT_STOP]; // Le garage d'arrivé sera réservé (V3.7c).
				if (g_stop >= 1000) {
					vio_garage_lock_res[g_stop - 1000] = 1;
				}
				for (i = 0; i < DEPL_CST_NB_MAX_AIG; i++) {
					aig = depl_tab[no_depl][DEPL_TAB_IND_AIG_0_NO + 2 * i];
					if (aig != -1) vio_aig_res[aig] = 1;
				}
				s = depl_tab[no_depl][DEPL_TAB_IND_SRV_NO];
				if (s != -1) { vio_srv_res[s / 100][s % 100] = 1; }
				tx = depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE];	// vérifie le n° du train empruntant le déplacement.  Si directive name:<n°train>, attend le bon n° de train.
				strcpy(train.mode[tx], "AUTO");
				depl_tab[no_depl][DEPL_TAB_IND_END_GARAGE_LOCKED] = 0;
				depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_ACTION_DEB;
			}
		}

// DEPL_CST_STATE_ACTION_DEB =     Effectue au début du déplacement les actions prévues sur des variables.
		if (depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_ACTION_DEB) {
			for (i = 0; i < DEPL_CST_NB_MAX_ACTION; i++)
				if ((action = depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP + 2 * i]) != -1) {
					var = depl_tab[no_depl][DEPL_TAB_IND_ACTION_VAR + 2 * i];
					if (action == DEPL_CST_ACTION_OP_SET_DEB || action == DEPL_CST_ACTION_OP_SET_CLR) pio_set_val(var, 1);
					if (action == DEPL_CST_ACTION_OP_CLR_DEB)                                         pio_set_val(var, 0);
				}
			if (depl_tab[no_depl][DEPL_TAB_IND_TEMPO_DEB_VAL] <=0 )  {
				depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_ACTION_AIG; // Pas de tempo prévue avant de lancer le déplacement.
			}
			else {
				depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_TEMPO_DEB; // Tempo prévue, initialise la tempo au nombre de tic à attendre.
				depl_tab[no_depl][DEPL_TAB_IND_TEMPO] = depl_tab[no_depl][DEPL_TAB_IND_TEMPO_DEB_VAL];
			}
		}

// DEPL_CST_STATE_TEMPO_DEB =    Si une tempo existe, temporise le départ effectif du déplacement.
		if (depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_TEMPO_DEB) {
			if ((depl_tab[no_depl][DEPL_TAB_IND_TEMPO]) <= 0) depl_tab[no_depl][DEPL_TAB_IND_STEP] = DEPL_CST_STATE_ACTION_AIG;
			else depl_tab[no_depl][DEPL_TAB_IND_TEMPO]--;
		}
		
// DEPL_CST_STATE_ACTION_AIG (et servo) =    Demande de positionnement d'aiguillages et servo.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_AIG) {
			for(i=0;i<DEPL_CST_NB_MAX_AIG;i++) {
				aig=depl_tab[no_depl][DEPL_TAB_IND_AIG_0_NO+2*i];
				pos=depl_tab[no_depl][DEPL_TAB_IND_AIG_0_POS+2*i];
				if(aig!=-1)  vio_aig_cmd[aig]=pos;
			}
			s=depl_tab[no_depl][DEPL_TAB_IND_SRV_NO];
			if(s!=-1) {
				val=depl_tab[no_depl][DEPL_TAB_IND_SRV_VAL];
				vio_srv_cmd[s/100][s%100]=val;
			}
			depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_WAIT_AIG;
		}

//DEPL_CST_STATE_WAIT_AIG (et servo) = Positionne les aiguillages et attend que tous soit positionnés.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_WAIT_AIG) {
			ok=1;
			for(i=0;i<DEPL_CST_NB_MAX_AIG;i++) {
				aig=depl_tab[no_depl][DEPL_TAB_IND_AIG_0_NO+2*i];
				pos=depl_tab[no_depl][DEPL_TAB_IND_AIG_0_POS+2*i];
				if(aig!=-1) if(pos==0 && vio_aig_pos0[aig]==0) ok=0;
				if(aig!=-1) if(pos==1 && vio_aig_pos1[aig]==0) ok=0;
			}
			s=depl_tab[no_depl][DEPL_TAB_IND_SRV_NO];
			if(s!=-1) {
				val=depl_tab[no_depl][DEPL_TAB_IND_SRV_VAL];
				if(vio_srv[s/100][s%100]!=val) ok=0;
			}
			if(ok) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_CANTON;
		}

//DEPL_CST_STATE_ACTION_CANTON = Réserve les cantons et les met sous tension.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_CANTON) {
// unlock
			cant_start1=depl_tab[no_depl][DEPL_TAB_IND_CANT_START];
			cant_start2=depl_tab[no_depl][DEPL_TAB_IND_CANT_START2];
			if(cant_start1>=1000 || cant_start2>=1000) { // >1000 corrigée en V3.3.
				if(cant_start1>=1000) g_start=cant_start1-1000; else g_start=cant_start2-1000;
				vio_garage_lock_cmd[g_start]=0;    // 0 => Demande pour relier le garage au canton (Sera réalisée si il a un train sur le canton).
				vio_garage_lock_status[g_start]=0; // 0 => Le garage est relié au canton (état réel).
				garage.numero_train[g_start]=-1;   // -1 = Garage relié au canton.
				tx=depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE];
				train.cant_lock[tx]=-1;
			}

// Set vit
			for(i=0;i<DEPL_CST_NB_MAX_CANT;i++) {
				cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
				vit=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT+2*i];
				if(cant!=-1) if(cant<1000) canton.vit_auto[cant/100][cant%100]=vit;
			}
			depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_WAIT_FIN0;
		}

// Etapes suivant la présence des conditions 'pass', 'libe' et 'fin'. Seule la condition 'fin' est obligatoire.
// 'pass' on doit passer par ce canton avant d'arriver à la condition de fin.
// 'libe' on doit libérer ce canton pour la condition de fin. (libére ainsi complétement l'avant dernier canton).
// FIN0          --->FIN1           [fin]  --->DEPL_CST_STATE_ACTION_TAF  
// FIN0          --->FIN1  [!libe]&&[fin]  --->DEPL_CST_STATE_ACTION_TAF  
// FIN0  [pass]  --->FIN1           [fin]  --->DEPL_CST_STATE_ACTION_TAF  
// FIN0  [pass]  --->FIN1  [!libe]&&[fin]  --->DEPL_CST_STATE_ACTION_TAF  

// DEPL_CST_STATE_WAIT_FIN0, = Attend la condition de passage 'pass:"
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_WAIT_FIN0) {
			var=depl_tab[no_depl][DEPL_TAB_IND_FIN_P_VAR];
			if(var==-1) { depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_WAIT_FIN1; } // Pas de condition de passage dans la fin de déplacement.
			else {
				val=depl_tab[no_depl][DEPL_TAB_IND_FIN_P_VAL];			// Il y a une condition de passage dans la fin de déplacement.
				if (pio_get_val(var)==val) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_WAIT_FIN1;
			}
		}

// DEPL_CST_STATE_WAIT_FIN1 = Attend la condition de fin de déplacement.
// Condition de fin = halt:<var> condition de fin = contact en fin de canton, pour arrêter net le train.
// directive 'halt:' = Utile quand on décroche une locomotive et que l'on passe au canton suivant, si les essieux des wagons sont résistifs,
// la directive libe:<canton> ne suffit pas à arrêter la loco dans ce cas.

		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_WAIT_FIN1) {
			var =depl_tab[no_depl][DEPL_TAB_IND_FIN_L_VAR]; // variable 'libe:'. Libération du canton précédent ?
			var2=depl_tab[no_depl][DEPL_TAB_IND_FIN_F_VAR]; // variable  'fin:', présence de 'fin:' obligatoire dans 'config.txt' !
			val2=depl_tab[no_depl][DEPL_TAB_IND_FIN_F_VAL]; // valeur de 'fin:'
			var3=depl_tab[no_depl][DEPL_TAB_IND_FIN_H_VAR]; // variable  'halt:', on touche le butoir de fin, arrêt net du train sans inertie.
			val3=depl_tab[no_depl][DEPL_TAB_IND_FIN_H_VAL]; // valeur de 'halt:'
			if(var3!=-1) {	// Si condition de halte, alors fin directe.
				if (pio_get_val(var3)==val3) {
					depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_TAF; // 'halt:'  =  arrêt d'urgence sans inertie.
					depl_tab[no_depl][DEPL_TAB_IND_VIT]=0;
				}
			}
			if(var==-1 && pio_get_val(var2)==val2) {  // Si pas de condition de libération de canton, alors condition de fin = 'fin:'.
				depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_TAF; 
			}
			else {
				val =depl_tab[no_depl][DEPL_TAB_IND_FIN_L_VAL]; // valeur de 'libe:'.
				if (val!=-1 ) {		// Le 21/02/2011, car 'val' peut être égale à -1, car la directive "libe:" est optionnelle si l'on va sur un garage situé sur le même canton.
					if(pio_get_val(var)!=val && pio_get_val(var2)==val2) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_TAF; // Condition de fin = 'fin:' et not'libe:'.
				}
			}
		}

// DEPL_CST_STATE_ACTION_TAF = Mise en place tempo arrêt 'tafx' pour attendre avant la mise hors tension du canton de fin.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_TAF) {
			if((depl_tab[no_depl][DEPL_TAB_IND_TAF])<=0) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_CANTON0;
			else {
				depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_WAIT_TAF;
				depl_tab[no_depl][DEPL_TAB_IND_TEMPO] = depl_tab[no_depl][DEPL_TAB_IND_TAF];
			}
		}

// DEPL_CST_STATE_WAIT_TAF =  Attente de la fin de la temporisation de mise hors tension du canton de fin.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_WAIT_TAF) {
			if((depl_tab[no_depl][DEPL_TAB_IND_TEMPO])<=0) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_CANTON0;
			else depl_tab[no_depl][DEPL_TAB_IND_TEMPO]--;
		}

// DEPL_CST_STATE_ACTION_CANTON0 = Actions sur les cantons
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_CANTON0) if(depl_tab[no_depl][DEPL_TAB_IND_VIT]==0) {
			for(i=0;i<DEPL_CST_NB_MAX_CANT;i++) {
				cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
				if(cant!=-1) if(cant<1000) canton.vit_auto[cant/100][cant%100]=0;
			}
			g_stop=depl_tab[no_depl][DEPL_TAB_IND_CANT_STOP];
			if(g_stop>=1000) { // corrigée en V3.3.
				g_stop=g_stop-1000; 
				cant_stop=garage.ass_canton[g_stop];
				if(cant_stop!=-1) if(vio_det[cant_stop]) {
					vio_garage_lock_cmd[g_stop]=1;     // 1 => Demande d'isolation du garage (Sera réalisée si il a un train sur le canton).
					vio_garage_lock_status[g_stop]=1;  // 1 => Le garage est isolé du canton (état réel).
					tx=depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE];
					garage.numero_train[g_stop]=tx;    // Numéro de train occupant le garage isolé du canton.
					train.cant_lock[tx]=g_stop;
					// depl_tab[no_depl][DEPL_TAB_IND_END_GARAGE_LOCKED] = 1 si le train arrive dans un garage en fin de parcours, il ne faut plus réserver de cantons en fin de parcours.
					depl_tab[no_depl][DEPL_TAB_IND_END_GARAGE_LOCKED]=1;  
				}
			}
			depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_TSF;
		}

//DEPL_CST_STATE_ACTION_TSF = Mise en place tempo arrêt 'tsfx' pour attendre avant la libération des cantons.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_TSF) {
			if(depl_tab[no_depl][DEPL_TAB_IND_TSF]<=0) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_FIN;
			else {
				depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_WAIT_TSF;
				depl_tab[no_depl][DEPL_TAB_IND_TEMPO] = depl_tab[no_depl][DEPL_TAB_IND_TSF];
			}
		}

//DEPL_CST_STATE_WAIT_TSF = Attente de la fin de la temporisation de libération des cantons.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_WAIT_TSF) {
			if((depl_tab[no_depl][DEPL_TAB_IND_TEMPO])<=0) depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_ACTION_FIN;
			else depl_tab[no_depl][DEPL_TAB_IND_TEMPO]--;
		}

//DEPL_CST_STATE_ACTION_FIN = Effectue en fin de déplacement les actions prévues sur des variables.
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_FIN) {
			for(i=0;i<DEPL_CST_NB_MAX_ACTION;i++)
			if((action=depl_tab[no_depl][DEPL_TAB_IND_ACTION_OP+2*i])!=-1) {
				var=depl_tab[no_depl][DEPL_TAB_IND_ACTION_VAR+2*i];
				if(action==DEPL_CST_ACTION_OP_SET_FIN) pio_set_val(var,1);
				if(action==DEPL_CST_ACTION_OP_CLR_FIN ||action==DEPL_CST_ACTION_OP_SET_CLR) pio_set_val(var,0);
			}
			for(i=0;i<DEPL_CST_NB_MAX_CANT;i++) { //refait canton=0 si stop (on ne verouille pas le garage fin car on ne sait pas où est le train qui passe donc en sélectif) 
				cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
				if(cant!=-1) if(cant<1000) canton.vit_auto[cant/100][cant%100]=0;
			}
			depl_tab[no_depl][DEPL_TAB_IND_TEMPO]=0; //plus beau en debug si stop
			depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_DERESERVATION;
		}

//DEPL_CST_STATE_DERESERVATION = Fin de réservation des cantons, aiguillage et servo.
//		DEPL_TAB_IND_END_GARAGE_LOCKED == 1            => Il ne faudra pas mettre un canton en mode sélectif, car l'on arrive sur un garage que l'on isole en fin de parcours.
//		canton.res_auto[cant/100][cant%100] ==1        => Le canton est réservé par un déplacement (Réservé en mode automatique).
//		canton.master_selectif[cant/100][cant%100] ==1 => Le canton est réservé en mode manuel = "sélectif".
// 
		if(depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_DERESERVATION) {
			var=0;  // var==0 => Pas de cantons détectés occupés par un train !
			for(i=0;i<DEPL_CST_NB_MAX_CANT;i++) {  // Pour tous les cantons du déplacements ...
				cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
				if(cant!=-1 && cant<1000) {
					// cant = Numéro de canton valide défini dans ce déplacement...  
					// On libére le canton de la réservation par ce déplacement (Réservé en mode automatique).
					canton.res_auto[cant/100][cant%100]=0;
					canton.vit_auto[cant/100][cant%100]=0;

					if(depl_tab[no_depl][DEPL_TAB_IND_END_GARAGE_LOCKED]==0) {
						// Si en fin de parcours le train est sur un canton,
						// Il faut remettre un canton en mode sélectif => canton.master_selectif[cant/100][cant%100]=1 (pour un canton).
						if (vio_det[cant/100][cant%100]==1) {
							// Sur ce canton il y a détection du train => On passe le canton en mode sélectif pour le conduire ensuite manuellement.
							// par contre il faudra ensuite vérifier qu'il y a au moins un canton de repassé en mode sélectif.
							canton.master_selectif[cant/100][cant%100]=1; 
							var=1;  //  On a trouvé un canton occupé => var=1.
						}
					}
					else {
						// Si en fin de parcours le train est sur un garage isolé des cantons.						
						// Il ne faut pas remettre un canton en mode sélectif.
						canton.num_train[cant/100][cant%100]=-1;
					}
				}
				if(cant>=1000) { 
					g=cant-1000; vio_garage_lock_res[g]=0;  // 0 ou 1, 1 => Garage réservé.
				}
			}
			g_stop=depl_tab[no_depl][DEPL_TAB_IND_CANT_STOP]; // Le garage d'arrivé sera dé-réservé (V3.7c).
			if (g_stop >= 1000) {
				vio_garage_lock_res[g_stop - 1000] = 0;
			}
			// Il faut vérifier si jamais il y avait un mauvais contact et qu'on a libéré tous les cantons par erreur, dans le cas ou le train n'a pas comme 
			// fin de parcours un garage. La fin du déplacement est provoqué par l'arrivée du train à sa destination finale, ou par un arrêt volontaire du déplacement.
			// On part sur le fait que la fin du déplacemente provient généralement de l'arrivée du train à sa destination. 
			// Dans ce cas on prend le dernier canton et on lui affecte le train.
			if (depl_tab[no_depl][DEPL_TAB_IND_END_GARAGE_LOCKED]==0 && var==0) {
				// La fin de parcours se situe sur un canton, mais l'on n'a pas retrouvé de canton occupé !
				// Par défaut, on va prendre le canton de fin de parcours et lui assigner le mode sélectif = conduite manuelle.
				var=-1;
				for(i=0;i<DEPL_CST_NB_MAX_CANT;i++) {  // Pour tous les cantons du déplacements ...
					cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
					if(cant!=-1 && cant<1000) var=cant; // On recherche le dernier déplacement.
				}
				if(var!=-1) canton.master_selectif[var/100][var%100]=1;
			}

			for(i=0;i<DEPL_CST_NB_MAX_AIG;i++) {
				aig=depl_tab[no_depl][DEPL_TAB_IND_AIG_0_NO+2*i];
				if(aig!=-1) vio_aig_res[aig]=0;
			}
			s=depl_tab[no_depl][DEPL_TAB_IND_SRV_NO];
			if(s!=-1) {	vio_srv_res[s/100][s%100]=0; }
			tx=depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE];
			strcpy(train.mode[tx],"SEL");
			depl_tab[no_depl][DEPL_TAB_IND_STEP]=DEPL_CST_STATE_IDLE;
			depl_tab[no_depl][DEPL_TAB_IND_START_RUN]=0;
		}
	} // Fin de boucle pour chaque déplacement.
	follow_vit();
}


// Alimente les cantons en fonction des déplacements actifs.
// En V 4.3 gére l'inertie en fonction de 'depl_acc_dec[]' ou de l'inertie des trains.
// Corrigé en V3.6a pour avoir une vitesse moyenne si le train est entre deux cantons.
// En V3.6c Possibilité de déplacements avec mélange de canton à vitesses positives et négatives.
void cDeplacement::follow_vit(void)
{
	int no_depl, i, j, cons, vit, cant, acc_n ,dec_n, frein_n;
	for(no_depl=0; no_depl<DEPL_TAB_NB; no_depl++) {
// Régulation de la vitesse sur cantons actifs seulement.
		if (depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_WAIT_FIN0
			|| depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_WAIT_FIN1
			|| depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_ACTION_TAF
			|| depl_tab[no_depl][DEPL_TAB_IND_STEP] == DEPL_CST_STATE_WAIT_TAF) {
			// Fait la moyenne des consignes des cantons occupés.
			// Si aucun canton n'est occupé, la consigne sera de -10 ou +10.
			// Si le dernier canton est occupé, c'est sa vitesse qui est imposée, pour ne pas aller trop vite en fin de parcours.
			if (depl_tab[no_depl][DEPL_TAB_IND_CONS] == -1) depl_tab[no_depl][DEPL_TAB_IND_CONS] = 30; // Anti-blocage pour le départ.
			j = 0;	cons = 0;
			for (i = 0; i < DEPL_CST_NB_MAX_CANT; i++) { // Pour tout les cantons d'un déplacement.
				cant = depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO + (2 * i)];
				if (cant == -1) break; // V3.4 Fin du tableau.
				if (cant < 1000) { // Pas un garage
					if (vio_det[cant / 100][cant % 100]) { // Si le canton est bien occupé...
						j++;
						cons += abs(depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT + (2 * i)]); // Moyenne pour initialiser la variable 'vit' ou valeur du dernier canton si c'est de dernier canton qui est occupé.
						if (i == DEPL_CST_NB_MAX_CANT-1 || (depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO + (2 * (i + 1))] == -1)) {
							cons = abs(depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT + (2 * i)]); j = 1;
						}
					}
				}
			}
			if (j != 0) cons = cons / j; // On fait la moyenne.
			else cons = 10; // Pas de canton avec un train détecté dessus.
			depl_tab[no_depl][DEPL_TAB_IND_CONS]=cons;
			
			// Calcul de la vitesse
// V3.4 Calcul de l'inertie en fonction du paramètre 'acc-decc:' de la section '#depl'.
			if (depl_acc_dec[DEPL_TAB_INERTIE_ACC]==-1) acc_n=train.acc[depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE]];
			else acc_n=min(depl_acc_dec[DEPL_TAB_INERTIE_ACC],train.acc[depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE]]);

			if (depl_acc_dec[DEPL_TAB_INERTIE_DEC]==-1) dec_n=train.dec[depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE]];
			else dec_n=min(depl_acc_dec[DEPL_TAB_INERTIE_DEC],train.dec[depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE]]);
			frein_n=-1; // Pas de frein.
//			cons=depl_tab[no_depl][DEPL_TAB_IND_CONS]; // Consigne.
//
			vit=depl_tab[no_depl][DEPL_TAB_IND_VIT]; // Vitesse qui tend vers la consigne.
			vit=train.dynamique_vit(cons, vit, acc_n, dec_n, frein_n);  // acc, dec et frein = 1 à 28 ! En V4.3, vrai gestion de l'inertie des déplacements.
			depl_tab[no_depl][DEPL_TAB_IND_VIT ]=vit;
//
// Attribution de la vitesse aux cantons.
			for(i=0; i<DEPL_CST_NB_MAX_CANT; i++) {
				cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
				if (cant==-1) break; // V3.4 Fin du tableau.
				if (cant!=-1) if (cant<1000) {
					if (depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT + (2 * i)]>=0) canton.vit_auto[cant/100][cant%100]=vit;
					else canton.vit_auto[cant / 100][cant % 100] = -vit;
				}
			}
		}
// Freinage pour arrêt => cons=0.
		else if (depl_tab[no_depl][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_ACTION_CANTON0) {
// Calcul de la vitesse (consigne à 0)
			// si 'dec' global = -1 => On prend 'dec' du train, même si il vaut -1 => Pas d'inertie.
			if (depl_acc_dec[DEPL_TAB_INERTIE_DEC]==-1) dec_n=train.dec[depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE]];
			else dec_n=min(depl_acc_dec[DEPL_TAB_INERTIE_DEC],train.dec[depl_tab[no_depl][DEPL_TAB_IND_TR_NUM_SAVE]]);
			acc_n=dec_n; // Normalement 'acc_n' ne doit pas servir, car ici l'on ne fait que freiner.
			frein_n=-1; // Pas de frein.
			cons=0;
			vit=depl_tab[no_depl][DEPL_TAB_IND_VIT ];
			vit=train.dynamique_vit(cons, vit, acc_n, dec_n, frein_n);  // En V4.3, vrai gestion de l'inertie des déplacements.
			depl_tab[no_depl][DEPL_TAB_IND_VIT ]=vit;
// Attribution aux cantons
			for(i=0;i<DEPL_CST_NB_MAX_CANT;i++) {
				cant=depl_tab[no_depl][DEPL_TAB_IND_CANT_0_NO+2*i];
				if(cant!=-1) if(cant<1000) {
					if (depl_tab[no_depl][DEPL_TAB_IND_CANT_0_VIT + (2 * i)] >= 0) canton.vit_auto[cant / 100][cant % 100] = vit; // V3.6c
					else canton.vit_auto[cant / 100][cant % 100] = -vit; // V3.6c

				}
			}
		}
// Hors régulation
		else { depl_tab[no_depl][DEPL_TAB_IND_CONS]=-1; depl_tab[no_depl][DEPL_TAB_IND_VIT ]=0; }
	}
}

// Affiche le tableau avec des états des déplacements. Appel de cet écran depuis le menu : 'Tables > Déplacements'.
// Suivant la valeur de 'screen_mode' on affiche les déplacements de 0 à 29, 30 à 59, 60 à 89, 90 à 119, 120 à 149, 150 à 179, 180 à 199
//
void cDeplacement::debug(int action)
{
	int i;
	static int depl_deb=0;
	char ch[200];

	static int dimnx=44;		// Dimension horizontal de la colonne 'Numéro'.
	static int dimcx=50;		// Dimension horizontal des autres colonnes.
	static int dimy=18;			// Dimension verticale d'une cellule avec désignation possible !
	static int nblignes=30;		// Nombre de lignes dans le tableau (sans le titre)
	static int decaly=20;		// Décalage vers le bas de la premiére ligne du tableau.

	SelectObject(hMemDC,bmp_fonte); SetBkMode(hMemDC,TRANSPARENT);
	SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);

	if(action==DEBUG_TOTAL_PAINT) {     // ACTION = REDESSINE TOUTE LA FENETRE.
		Rectangle(hMemDC,0,0,800,700);
		SelectObject(hMemDC,bmp_pinceau_gris192); SelectObject(hMemDC,bmp_stylo_gris192); Rectangle(hMemDC,800-15,15,800-2,2); // Rectangle gris pour fermer la fenêtre.
		SelectObject(hMemDC,bmp_stylo_noir); EasyLine(800-14,3,800-3,14 ); EasyLine(800-14,13,800-3,2); // Croix noire.
		SelectObject(hMemDC,bmp_stylo_noir);  EasyLine(800-2,1,800-2,16); EasyLine(800-16,15,800-1,15); // Trait noir.
		SelectObject(hMemDC,bmp_stylo_gris128); EasyLine(800-3,2,800-3,15); EasyLine(800-15,14,800-2,14); // Trait gris foncé.
		SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);
		SetTextColor(hMemDC,RGB(0,0,0));	// Texte en noir.
		EasyTextOut(2,2,"AFFICHE LES VALEURS NON NULLES DES PARAMÈTRES DES DÉPLACEMENTS (200 maximum)"); EasyTextOut(800-140,2,"(QUITTER = ESC)");
		EasyTextOut(2,(nblignes+3)*dimy,"Section '#depl' Paramètres globaux 'Accélération - Décélération' = ");
		SelectObject(hMemDC,bmp_stylo_noir); SelectObject(hMemDC,bmp_pinceau_gris220); // Rectangle gris foncé.
		Rectangle(hMemDC,0,decaly+(nblignes+3)*dimy-4, 97, decaly+(nblignes+4)*dimy-4);
		SelectObject(hMemDC,bmp_stylo_gris128);
		EasyLine(1,  decaly+(nblignes+4)*dimy-4-2, 96, decaly+(nblignes+4)*dimy-4-2);  	// Relief rectangle.
		EasyLine(95, decaly+(nblignes+3)*dimy-4+1, 95, decaly+(nblignes+4)*dimy-4-2);	// Relief rectangle.
		SelectObject(hMemDC,bmp_stylo_noir);
		EasyLine(97-10, decaly+(nblignes+4)*dimy-4-2, 97, decaly+(nblignes+4)*dimy-4-12);  // Dessine un trait dans l'angle = valeurs modifiables.
		SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);
		EasyTextOut(2,(nblignes+4)*dimy," CLIC-DROIT :AFFICHE LES PAGES 1->2->3- - ->7, [00-29]->[30-59]->[60-89]->[90-119]- - ->[180-199]");
		EasyTextOut(2,(nblignes+5)*dimy,"CLIQUEZ dans la colonne 'Start' ou 'Stop' pour lancer ou annuler un déplacement.");
		
		SelectObject(hMemDC,bmp_pinceau_vert); // Rectangle vert.
		Rectangle(hMemDC,0, -2+(nblignes+6)*dimy,96,-2+(nblignes+7)*dimy);
		EasyTextOut(2,(nblignes+6)*dimy,"LIGNE VERTE = Déplacement en action.");

		SelectObject(hMemDC,bmp_pinceau_jaune); // Rectangle jaune.
		Rectangle(hMemDC,0, -2+(nblignes+7)*dimy,96,-2+(nblignes+8)*dimy);
		SelectObject(hMemDC,bmp_pinceau_blanc);
		EasyTextOut(2,(nblignes+7)*dimy,"LIGNE JAUNE = Déplacement en attente de libération canton, aiguillage ou de train de type 'Auto'.");

		EasyTextOut(2,(nblignes+8)*dimy,"              Si stopper un déplacement est impossible, voir si une action horaire est en cours.");

		SetTextColor(hMemDC,RGB(0,0,255)); // Texte en bleu.
		if (depl_acc_dec[DEPL_TAB_INERTIE_ACC]==-1) sprintf_s(ch,"xx -");
		else sprintf_s(ch,"%2d -",depl_acc_dec[DEPL_TAB_INERTIE_ACC]);
		EasyTextOut(540,(nblignes+3)*dimy,ch);
		if (depl_acc_dec[DEPL_TAB_INERTIE_DEC]==-1) sprintf_s(ch,"xx");
		else sprintf_s(ch,"%-2d",depl_acc_dec[DEPL_TAB_INERTIE_DEC]);
		EasyTextOut(580,(nblignes+3)*dimy,ch);
		SetTextColor(hMemDC,RGB(255,0,0)); // Texte des titres de colonnes en rouge.
		EasyTextOut(              2, 2+dimy,"  n°");
		EasyTextOut(        dimnx+5, 2+dimy,"Start");  // Colonne 'Start' marquée '/' = valeurs modifiables
		EasyTextOut(1*dimcx+dimnx+7, 2+dimy,"Stop");   // Colonne 'Stop'  marquée '/' = valeurs modifiables
		EasyTextOut(2*dimcx+dimnx+5, 2+dimy,"Tempo");
		EasyTextOut(3*dimcx+dimnx+15,2+dimy,"Etat");
		EasyTextOut(8*dimcx+dimnx+15,2+dimy,"Nom du déplacement");
		EasyLine(       0,      dimy        ,  800,  dimy); // Dessine le traits au dessus du titre des colonnes 
		EasyLine(   dimnx,      dimy        ,dimnx,2*dimy); // Dessine les traits verticaux
		EasyLine(1*dimcx+dimnx, dimy,1*dimcx+dimnx,2*dimy);
		EasyLine(2*dimcx+dimnx, dimy,2*dimcx+dimnx,2*dimy);
		EasyLine(3*dimcx+dimnx, dimy,3*dimcx+dimnx,2*dimy);
		EasyLine(8*dimcx+dimnx, dimy,8*dimcx+dimnx,2*dimy);
		EasyLine(1*dimcx+dimnx-10,2*dimy, 1*dimcx+dimnx,2*dimy-10);  // Dessine un trait dans l'angle = valeurs modifiables
		EasyLine(2*dimcx+dimnx-10,2*dimy, 2*dimcx+dimnx,2*dimy-10);  // Dessine un trait dans l'angle = valeurs modifiables
	}

	if(action==DEBUG_MOUSE) {      // ACTION = CLIC GAUCHE DE LA SOURIS.
		if ((x_mouse > 0 && x_mouse < 97) && (y_mouse > decaly+(nblignes+3)*dimy-4 && y_mouse < decaly+(nblignes+4)*dimy-4)) { //	Clique dans [CLIC DROIT]
			action=DEBUG_MOUSE_RIGHT; //	Simule le clique-droit traité plus loin.
		}
		else {
			if ((x_mouse > 800-15 && x_mouse < 800-2) && (y_mouse > 2 && y_mouse < 15)) {
				screen_mode= screen_mode_retour; 
				return;	// On ferme la fenêtre.
			}
			i=(y_mouse-2*dimy)/dimy;
			if(y_mouse>2*dimy && i>=0 && i<nblignes && depl_deb+i<DEPL_TAB_NB) {
				if (depl_tab[depl_deb+i][DEPL_TAB_IND_CANT_START]!=-1) {
					if(x_mouse>dimnx       && x_mouse<dimnx+dimcx)   depl_tab[depl_deb+i][DEPL_TAB_IND_START_RUN]= 1;	// Lance le déplacement.
					if(x_mouse>dimnx+dimcx && x_mouse<dimnx+2*dimcx) depl_tab[depl_deb+i]     [DEPL_TAB_IND_STOP]= 1;	// Arrête le déplacement (clic en colonne 'Stop').
				}
			}
		}
	}

	if(action==DEBUG_MOUSE_RIGHT) {    // ACTION = CLIC DROIT DE LA SOURIS, on passe à la page suivante.
		switch(depl_deb/nblignes) {
			case 0 : { screen_mode= MD_ECRAN_DEPL2; break;}
			case 1 : { screen_mode= MD_ECRAN_DEPL3; break;}
			case 2 : { screen_mode= MD_ECRAN_DEPL4; break;}
			case 3 : { screen_mode= MD_ECRAN_DEPL5; break;}
			case 4 : { screen_mode= MD_ECRAN_DEPL6; break;}
			case 5 : { screen_mode= MD_ECRAN_DEPL7; break;}
			case 6 : { screen_mode= MD_ECRAN_DEPL1; break;}
			default: break;
		}
	}

	if (screen_mode==MD_ECRAN_DEPL1) depl_deb= 0;	// Valeur du premier déplacement à afficher.
	if (screen_mode==MD_ECRAN_DEPL2) depl_deb=   nblignes;
	if (screen_mode==MD_ECRAN_DEPL3) depl_deb= 2*nblignes;
	if (screen_mode==MD_ECRAN_DEPL4) depl_deb= 3*nblignes;
	if (screen_mode==MD_ECRAN_DEPL5) depl_deb= 4*nblignes;
	if (screen_mode==MD_ECRAN_DEPL6) depl_deb= 5*nblignes;
	if (screen_mode==MD_ECRAN_DEPL7) depl_deb= 6*nblignes;

	if(action==DEBUG_KEY) { }          // ACTION = TOUCHE ENFONCEE

	SetTextColor(hMemDC,RGB(0,0,255)); // Texte en bleu
	for(i=0;i<nblignes;i++) {
		SelectObject(hMemDC,bmp_pinceau_blanc);

		if((depl_deb+i)<DEPL_TAB_NB) {
			if(depl_tab[depl_deb+i][DEPL_TAB_IND_STEP]==DEPL_CST_STATE_RESERVATION) SelectObject(hMemDC,bmp_pinceau_jaune);
			else if(depl_tab[depl_deb+i][DEPL_TAB_IND_START_RUN])                   SelectObject(hMemDC,bmp_pinceau_vert);
			else                                                                    SelectObject(hMemDC,bmp_pinceau_blanc);
		}
		else { SelectObject(hMemDC,bmp_pinceau_blanc); }
		Rectangle(hMemDC,0,dimy*(i+2),800,dimy*(i+3)+1);
		EasyLine(        dimnx,dimy*(i+2),        dimnx,dimy*(i+3)); 	// Dessine les traits verticaux du tableau.
		EasyLine(1*dimcx+dimnx,dimy*(i+2),1*dimcx+dimnx,dimy*(i+3));
		EasyLine(2*dimcx+dimnx,dimy*(i+2),2*dimcx+dimnx,dimy*(i+3)); 
		EasyLine(3*dimcx+dimnx,dimy*(i+2),3*dimcx+dimnx,dimy*(i+3));
		EasyLine(8*dimcx+dimnx,dimy*(i+2),8*dimcx+dimnx,dimy*(i+3));

		if((depl_deb+i)<DEPL_TAB_NB) {
			if(depl_tab[depl_deb+i][DEPL_TAB_IND_CANT_START]==-1) 	SetTextColor(hMemDC,RGB(192,192,192)); // Texte en gris
			sprintf_s(ch,"%3d",depl_deb+i);                                         EasyTextOut(        10,3+dimy*(i+2),ch);
			SetTextColor(hMemDC,RGB(0,0,255)); // Texte en bleu
			if(depl_tab[depl_deb+i][DEPL_TAB_IND_CANT_START]==-1) continue;	// On sort de la boucle si le déplacement n'est pas valide.
			if (depl_tab[depl_deb+i][DEPL_TAB_IND_START_RUN]!=0) {
				sprintf_s(ch,"%3d",depl_tab[depl_deb+i][DEPL_TAB_IND_START_RUN]);   EasyTextOut(        50,3+dimy*(i+2),ch);}
			if (depl_tab[depl_deb+i][DEPL_TAB_IND_STOP]!=0) {
				sprintf_s(ch,"%4d",depl_tab[depl_deb+i][DEPL_TAB_IND_STOP]);        EasyTextOut(1*dimcx+54,3+dimy*(i+2),ch);}
			if (depl_tab[depl_deb+i][DEPL_TAB_IND_TEMPO]!=0) {
				sprintf_s(ch,"%4d",depl_tab[depl_deb+i][DEPL_TAB_IND_TEMPO]);       EasyTextOut(2*dimcx+54,3+dimy*(i+2),ch);}
			strcpy(ch,depl_state_name[depl_tab[depl_deb+i][DEPL_TAB_IND_STEP]]);    EasyTextOut(3*dimcx+45,3+dimy*(i+2),ch);
			strcpy(ch,depl_name[depl_deb+i]);                                       EasyTextOut(8*dimcx+50,3+dimy*(i+2),ch);
		}
	}
}
