2017-01-21 17:27:46 +01:00
|
|
|
|
// chemin.cpp
|
|
|
|
|
|
|
|
|
|
// (c) 1997, Denis Dumoulin
|
|
|
|
|
|
|
|
|
|
#include "DECOR.H"
|
|
|
|
|
#include "FIFO.H"
|
|
|
|
|
#include "ACTION.H"
|
|
|
|
|
|
|
|
|
|
// M<>morise toutes les positions des blupi.
|
|
|
|
|
|
|
|
|
|
void CDecor::CheminMemPos(int exRank)
|
|
|
|
|
{
|
|
|
|
|
int rank, index;
|
|
|
|
|
|
|
|
|
|
m_cheminNbPos = 0;
|
|
|
|
|
index = 0;
|
|
|
|
|
for ( rank=0 ; rank<MAXBLUPI ; rank++ )
|
|
|
|
|
{
|
|
|
|
|
if ( m_blupi[rank].bExist &&
|
|
|
|
|
m_blupi[rank].perso != 6 && // pas le d<>tonnateur de mine
|
|
|
|
|
rank != exRank )
|
|
|
|
|
{
|
|
|
|
|
m_cheminPos[index] = m_blupi[rank].cel;
|
|
|
|
|
m_cheminRank[index] = rank;
|
|
|
|
|
m_cheminNbPos ++;
|
|
|
|
|
index ++;
|
|
|
|
|
|
|
|
|
|
if ( m_blupi[rank].destCel.x != m_blupi[rank].cel.x ||
|
|
|
|
|
m_blupi[rank].destCel.y != m_blupi[rank].cel.y )
|
|
|
|
|
{
|
|
|
|
|
m_cheminPos[index] = m_blupi[rank].destCel;
|
|
|
|
|
m_cheminRank[index] = rank;
|
|
|
|
|
m_cheminNbPos ++;
|
|
|
|
|
index ++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Teste si une positiion est occup<75>e par un blupi.
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
bool CDecor::CheminTestPos(POINT pos, int &rank)
|
2017-01-21 17:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for ( i=0 ; i<m_cheminNbPos ; i++ )
|
|
|
|
|
{
|
|
|
|
|
if ( pos.x == m_cheminPos[i].x &&
|
|
|
|
|
pos.y == m_cheminPos[i].y )
|
|
|
|
|
{
|
|
|
|
|
rank = m_cheminRank[i];
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return true;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// une fois le but trouv<75>, reprend en arri<72>re
|
|
|
|
|
// <20> la recherche du chemin le plus court
|
|
|
|
|
|
|
|
|
|
// retourne la direction <20> prendre
|
|
|
|
|
int CDecor::CheminARebours(int rank)
|
|
|
|
|
{
|
|
|
|
|
int pos, rebours, last, dir, set;
|
|
|
|
|
POINT v;
|
|
|
|
|
|
|
|
|
|
pos = m_blupi[rank].goalCel.y*MAXCELX + m_blupi[rank].goalCel.x;
|
|
|
|
|
|
|
|
|
|
rebours = m_cheminWork[pos];
|
|
|
|
|
|
|
|
|
|
if ( rebours == 0 ) return -1;
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
while ( true )
|
2017-01-21 17:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
bis:
|
|
|
|
|
for ( set=0 ; set<2 ; set++ )
|
|
|
|
|
{
|
|
|
|
|
for ( dir=set ; dir<8 ; dir+=2 )
|
|
|
|
|
{
|
|
|
|
|
v = GetVector(dir*16);
|
|
|
|
|
last = pos + v.y*MAXCELX+v.x;
|
|
|
|
|
|
|
|
|
|
if ( m_cheminWork[last] > 0 &&
|
|
|
|
|
m_cheminWork[last] < rebours )
|
|
|
|
|
{
|
|
|
|
|
pos = last;
|
|
|
|
|
rebours = m_cheminWork[pos];
|
|
|
|
|
if (rebours==1) return (dir>=4) ? dir-4 : dir+4;
|
|
|
|
|
goto bis; // interrompt le for...
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ne devrait jamais arriver !
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// troisi<73>me m<>thode de recherche
|
|
|
|
|
// semblable <20> la pr<70>c<EFBFBD>dente,
|
|
|
|
|
// mais les points <20> explorer sont class<73>s selon leur distance <20> la cible
|
|
|
|
|
|
|
|
|
|
void CDecor::CheminFillTerrain(int rank)
|
|
|
|
|
{
|
|
|
|
|
long pos, last, dest, dist;
|
|
|
|
|
int step, dir, cout, action, max, next, ampli;
|
|
|
|
|
int dx, dy;
|
|
|
|
|
int but = 1000;
|
|
|
|
|
|
|
|
|
|
if ( m_blupi[rank].cel.x == m_blupi[rank].goalCel.x &&
|
|
|
|
|
m_blupi[rank].cel.y == m_blupi[rank].goalCel.y ) return;
|
|
|
|
|
|
|
|
|
|
pos = m_blupi[rank].cel.y*MAXCELX + m_blupi[rank].cel.x;
|
|
|
|
|
dest = m_blupi[rank].goalCel.y*MAXCELX + m_blupi[rank].goalCel.x;
|
|
|
|
|
|
|
|
|
|
CPileTriee fifo(2*MAXCELX+2*MAXCELY); // les variantes possibles
|
|
|
|
|
|
|
|
|
|
fifo.put(pos, 0); // position de d<>part
|
|
|
|
|
m_cheminWork[pos] = 1; // premi<6D>re position
|
|
|
|
|
|
|
|
|
|
// r<>p<EFBFBD>te jusqu'<27> trouv<75> ou plus de possibilit<69>s
|
|
|
|
|
max = 500;
|
|
|
|
|
while ( max-- > 0 )
|
|
|
|
|
{
|
|
|
|
|
// reprend une variante de chemin
|
|
|
|
|
pos = fifo.get();
|
|
|
|
|
if ( pos < 0 ) break;
|
|
|
|
|
|
|
|
|
|
step = m_cheminWork[pos];
|
|
|
|
|
|
|
|
|
|
// on est arriv<69> au but ?
|
|
|
|
|
//? if ( pos == dest ) return;
|
|
|
|
|
if ( pos == dest )
|
|
|
|
|
{
|
|
|
|
|
but = step; // h<>las trop lent !
|
|
|
|
|
max = 50;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// est-ce vraiment trop loin ?
|
|
|
|
|
if ( step > 200 ) return;
|
|
|
|
|
|
|
|
|
|
// marque les cases autour du point
|
|
|
|
|
if ( step < but ) for ( dir=0 ; dir<8 ; dir++ )
|
|
|
|
|
{
|
|
|
|
|
if ( CheminTestDirection(rank, pos, dir, next, ampli, cout, action) )
|
|
|
|
|
{
|
|
|
|
|
last = pos + ampli*next;
|
|
|
|
|
if ( last<0 || last>=MAXCELX*MAXCELY ) continue;
|
|
|
|
|
|
|
|
|
|
if ( m_cheminWork[last] == 0 ||
|
|
|
|
|
m_cheminWork[last] > step+cout )
|
|
|
|
|
{
|
|
|
|
|
// marque les cases saut<75>es
|
|
|
|
|
for (int i=1; i<ampli;i++)
|
|
|
|
|
{
|
|
|
|
|
m_cheminWork[pos+i*next] = step+cout-ampli+i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_cheminWork[last] = step+cout;
|
|
|
|
|
//? char buffer[50];
|
|
|
|
|
//? sprintf(buffer, "word = %d;%d %d\n", last%200, last/200, step+cout);
|
|
|
|
|
//? OutputDebug(buffer);
|
|
|
|
|
dx = m_blupi[rank].goalCel.x - last%MAXCELX;
|
|
|
|
|
dy = m_blupi[rank].goalCel.y - last/MAXCELX;
|
|
|
|
|
//? dist = dy*dy + dx*dx;
|
|
|
|
|
dist = (long)(dy*dy) + (long)(dx*dx);
|
|
|
|
|
fifo.put(last, dist);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// routine d<>terninant si une direction est possible
|
|
|
|
|
// retourne l'incr<63>ment pour passer <20> la nouvelle case
|
|
|
|
|
// et le "prix <20> payer" pour aller dans cette direction
|
|
|
|
|
// co<63>t doit <20>tre d<>termin<69> en sortie
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
bool CDecor::CheminTestDirection(int rank, int pos, int dir,
|
2017-01-21 17:27:46 +01:00
|
|
|
|
int &next, int &li,
|
|
|
|
|
int &cout, int &action)
|
|
|
|
|
{
|
|
|
|
|
POINT cel, vector, newCel;
|
2017-01-22 00:10:12 +01:00
|
|
|
|
bool bFree;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
int tryDirect, workBlupi, rankHere;
|
|
|
|
|
|
|
|
|
|
cel.x = pos%MAXCELX;
|
|
|
|
|
cel.y = pos/MAXCELX;
|
|
|
|
|
|
|
|
|
|
tryDirect = dir*16;
|
|
|
|
|
vector = GetVector(tryDirect);
|
|
|
|
|
|
|
|
|
|
// Peut-on glisser dans cette direction ?
|
|
|
|
|
bFree = IsFreeGlisse(cel, tryDirect, rank, action);
|
|
|
|
|
cout = 5; // co<63>t <20>lev<65>
|
|
|
|
|
|
|
|
|
|
if ( !bFree )
|
|
|
|
|
{
|
|
|
|
|
// Peut-on marcher normalement ?
|
|
|
|
|
bFree = IsFreeDirect(cel, tryDirect, rank);
|
|
|
|
|
action = ACTION_MARCHE;
|
|
|
|
|
cout = 1; // co<63>t minimal
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !bFree )
|
|
|
|
|
{
|
|
|
|
|
// Peut-on sauter ?
|
|
|
|
|
bFree = IsFreeJump(cel, tryDirect, rank, action);
|
|
|
|
|
cout = 3; // co<63>t <20>lev<65>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ampli = GetAmplitude(action); // a <- amplitude (1..5)
|
|
|
|
|
cout *= ampli; // co<63>t plus <20>lev<65> si grande amplitude
|
|
|
|
|
|
|
|
|
|
// Blupi peut aller sur le lieu de la construction.
|
|
|
|
|
if ( !bFree && m_blupi[rank].passCel.x != -1 )
|
|
|
|
|
{
|
|
|
|
|
newCel = m_blupi[rank].passCel;
|
|
|
|
|
workBlupi = m_decor[newCel.x/2][newCel.y/2].workBlupi;
|
|
|
|
|
|
|
|
|
|
if ( m_blupi[rank].passCel.x/2 == (cel.x+vector.x*ampli)/2 &&
|
|
|
|
|
m_blupi[rank].passCel.y/2 == (cel.y+vector.y*ampli)/2 &&
|
|
|
|
|
(workBlupi < 0 || workBlupi == rank) )
|
|
|
|
|
{
|
2017-01-22 00:10:12 +01:00
|
|
|
|
bFree = true;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
cout = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( bFree ) // chemin libre (sans tenir compte des perso) ?
|
|
|
|
|
{
|
|
|
|
|
newCel.x = cel.x + vector.x*ampli;
|
|
|
|
|
newCel.y = cel.y + vector.y*ampli; // newCel <- arriv<69>e supos<6F>e
|
|
|
|
|
|
|
|
|
|
if ( m_blupi[rank].perso == 3 ) // tracks ?
|
|
|
|
|
{
|
|
|
|
|
// Le tracks peut aller sur les blupi
|
|
|
|
|
// pour les <20>craser !
|
2017-01-22 00:10:12 +01:00
|
|
|
|
if ( IsTracksHere(newCel, false) ) // autre perso ici ?
|
2017-01-21 17:27:46 +01:00
|
|
|
|
{
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-01-22 00:10:12 +01:00
|
|
|
|
//? if ( IsBlupiHere(newCel, false) ) // autre perso ici ?
|
2017-01-21 17:27:46 +01:00
|
|
|
|
if ( CheminTestPos(newCel, rankHere) ) // autre perso ici ?
|
|
|
|
|
{
|
|
|
|
|
// Si blupi immobile, comme si obstacle qq.
|
2017-01-22 00:10:12 +01:00
|
|
|
|
//? if ( m_blupi[m_blupiHere].goalCel.x == -1 ) return false;
|
|
|
|
|
if ( m_blupi[rankHere].goalCel.x == -1 ) return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
|
|
|
|
|
// Si blupi mobile, possible mais co<63>t <20>lev<65>.
|
|
|
|
|
cout = 20;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next = vector.y*MAXCELX + vector.x;
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return true;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
// Retourne true si on a assign<67> une nouvelle direction <20> blupi.
|
|
|
|
|
bool CDecor::CheminCherche(int rank, int &action)
|
2017-01-21 17:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
int cout; // prix pour aller dans une direction
|
|
|
|
|
int pos, dir, next, ampli;
|
|
|
|
|
|
|
|
|
|
// D<>j<EFBFBD> <20> destination ?
|
|
|
|
|
if ( m_blupi[rank].cel.x == m_blupi[rank].goalCel.x &&
|
|
|
|
|
m_blupi[rank].cel.y == m_blupi[rank].goalCel.y )
|
|
|
|
|
{
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Destination occup<75>e ?
|
2017-01-22 00:10:12 +01:00
|
|
|
|
if ( IsBlupiHereEx(m_blupi[rank].goalCel, rank, false) )
|
2017-01-21 17:27:46 +01:00
|
|
|
|
{
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-10 00:14:28 +01:00
|
|
|
|
memset(m_cheminWork, 0, (Uint8)MAXCELX*(Uint8)MAXCELY);
|
2017-01-21 17:27:46 +01:00
|
|
|
|
CheminMemPos(rank);
|
|
|
|
|
|
|
|
|
|
// fait un remplissage du map de travail
|
|
|
|
|
// autour du point de d<>part
|
|
|
|
|
CheminFillTerrain(rank);
|
|
|
|
|
|
|
|
|
|
// cherche le chemin <20> partir de la destination
|
|
|
|
|
dir = CheminARebours(rank);
|
2017-01-22 00:10:12 +01:00
|
|
|
|
if ( dir < 0 ) return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
|
|
|
|
|
pos = m_blupi[rank].cel.y*MAXCELX + m_blupi[rank].cel.x;
|
|
|
|
|
if ( CheminTestDirection(rank, pos, dir, next, ampli, cout, action) &&
|
|
|
|
|
cout < 20 )
|
|
|
|
|
{
|
|
|
|
|
m_blupi[rank].sDirect = 16*dir;
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return true;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ne devrait jamais arriver !
|
2017-01-22 00:10:12 +01:00
|
|
|
|
return false;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Teste s'il est possible de se rendre <20> un endroit donn<6E>.
|
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
bool CDecor::IsCheminFree(int rank, POINT dest, int button)
|
2017-01-21 17:27:46 +01:00
|
|
|
|
{
|
|
|
|
|
int action, sDirect;
|
|
|
|
|
POINT goalCel, passCel, limit;
|
2017-01-22 00:10:12 +01:00
|
|
|
|
bool bOK;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
|
2017-01-22 00:10:12 +01:00
|
|
|
|
if ( button == BUTTON_STOP ) return true;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
|
|
|
|
|
goalCel = m_blupi[rank].goalCel;
|
|
|
|
|
passCel = m_blupi[rank].passCel;
|
|
|
|
|
sDirect = m_blupi[rank].sDirect;
|
|
|
|
|
|
|
|
|
|
if ( IsFreeCelEmbarque(dest, rank, action, limit) )
|
|
|
|
|
{
|
|
|
|
|
dest = limit;
|
|
|
|
|
}
|
|
|
|
|
if ( IsFreeCelDebarque(dest, rank, action, limit) )
|
|
|
|
|
{
|
|
|
|
|
dest = limit;
|
|
|
|
|
}
|
|
|
|
|
if ( button == BUTTON_GO &&
|
|
|
|
|
m_decor[dest.x/2][dest.y/2].objectChannel == CHOBJECT &&
|
|
|
|
|
(m_decor[dest.x/2][dest.y/2].objectIcon == 118 || // jeep ?
|
|
|
|
|
m_decor[dest.x/2][dest.y/2].objectIcon == 16 ) && // armure ?
|
|
|
|
|
dest.x%2 == 1 && dest.y%2 == 1 )
|
|
|
|
|
{
|
|
|
|
|
dest.y --; // va <20> c<>t<EFBFBD> jeep/armure
|
|
|
|
|
}
|
|
|
|
|
if ( button == BUTTON_GO &&
|
|
|
|
|
m_decor[dest.x/2][dest.y/2].objectChannel == CHOBJECT &&
|
|
|
|
|
m_decor[dest.x/2][dest.y/2].objectIcon == 113 ) // maison ?
|
|
|
|
|
{
|
|
|
|
|
dest.x = (dest.x/2)*2+1;
|
|
|
|
|
dest.y = (dest.y/2)*2+1; // sous la porte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( m_blupi[rank].cel.x == dest.x &&
|
2017-01-22 00:10:12 +01:00
|
|
|
|
m_blupi[rank].cel.y == dest.y ) return true;
|
2017-01-21 17:27:46 +01:00
|
|
|
|
|
|
|
|
|
m_blupi[rank].goalCel = dest;
|
|
|
|
|
if ( m_decor[dest.x/2][dest.y/2].objectChannel == CHOBJECT &&
|
|
|
|
|
button != BUTTON_GO )
|
|
|
|
|
{
|
|
|
|
|
m_blupi[rank].passCel = dest; // si arbres/fleurs/bateau/etc.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bOK = CheminCherche(rank, action);
|
|
|
|
|
|
|
|
|
|
m_blupi[rank].goalCel = goalCel;
|
|
|
|
|
m_blupi[rank].passCel = passCel;
|
|
|
|
|
m_blupi[rank].sDirect = sDirect;
|
|
|
|
|
|
|
|
|
|
return bOK;
|
|
|
|
|
}
|
|
|
|
|
|