1
0
mirror of https://github.com/blupi-games/planetblupi synced 2024-12-30 10:15:36 +01:00
planetblupi/arrange.cpp
Mathieu Schroeter 93047957fd Replace BOOL by bool
And replace structs that are stored from BOOL to int.
2017-01-22 00:15:32 +01:00

978 lines
18 KiB
C++

// Arrange.cpp
//
#include "DECOR.H"
#include "MISC.H"
// Cette table indique les quarts de cases contenant de
// l'eau lorsque la valeur est à un.
// 0 1
// 2 3
static char tableSee[14*4] =
{
0,0,0,0, // 1
0,1,0,1, // 2
0,0,1,1, // 3
1,0,1,0, // 4
1,1,0,0, // 5
0,0,0,1, // 6
0,0,1,0, // 7
1,0,0,0, // 8
0,1,0,0, // 9
0,1,1,1, // 10
1,0,1,1, // 11
1,1,1,0, // 12
1,1,0,1, // 13
1,1,1,1, // 14
};
// Cette table indique les quarts de cases contenant de
// la mousse ou de la terre lorsque la valeur est à un.
// 0 1
// 2 3
static char tableDark[13*4] =
{
1,1,1,1, // 20
0,1,0,1, // 21
0,0,1,1, // 22
1,0,1,0, // 23
1,1,0,0, // 24
0,0,0,1, // 25
0,0,1,0, // 26
1,0,0,0, // 27
0,1,0,0, // 28
1,1,1,0, // 29
1,1,0,1, // 30
0,1,1,1, // 31
1,0,1,1, // 32
};
// Retourne les bits contenant de l'eau.
bool CDecor::GetSeeBits(POINT cel, char *pBits, int index)
{
int icon;
pBits[0] = 0;
pBits[1] = 0;
pBits[2] = 0;
pBits[3] = 0;
if ( cel.x < 0 || cel.x >= MAXCELX ||
cel.y < 0 || cel.y >= MAXCELY ) return false;
icon = m_decor[cel.x/2][cel.y/2].floorIcon;
if ( index == 0 ) // eau ?
{
if ( icon < 1 || icon > 14 ) return true;
icon -= 1;
pBits[0] = tableSee[icon*4+0];
pBits[1] = tableSee[icon*4+1];
pBits[2] = tableSee[icon*4+2];
pBits[3] = tableSee[icon*4+3];
}
if ( index == 1 ) // mousse ?
{
if ( icon >= 2 && icon <= 14 ) return false; // eau ?
if ( icon == 66 || icon == 79 ) // mousse spéciale ?
{
pBits[0] = 1;
pBits[1] = 1;
pBits[2] = 1;
pBits[3] = 1;
return true;
}
if ( icon < 20 || icon > 32 ) return true;
icon -= 20;
pBits[0] = tableDark[icon*4+0];
pBits[1] = tableDark[icon*4+1];
pBits[2] = tableDark[icon*4+2];
pBits[3] = tableDark[icon*4+3];
}
if ( index == 2 ) // terre ?
{
if ( icon >= 2 && icon <= 14 ) return false; // eau ?
if ( (icon >= 46 && icon <= 48) || // terre spéciale ?
icon == 71 ) // terre à fer ?
{
pBits[0] = 1;
pBits[1] = 1;
pBits[2] = 1;
pBits[3] = 1;
return true;
}
if ( icon < 33 || icon > 45 ) return true;
icon -= 33;
pBits[0] = tableDark[icon*4+0];
pBits[1] = tableDark[icon*4+1];
pBits[2] = tableDark[icon*4+2];
pBits[3] = tableDark[icon*4+3];
}
return true;
}
void CopyBits(char *pDst, char *pSrc)
{
for ( int i=0 ; i<4 ; i++ )
{
*pDst++ = *pSrc++;
}
}
bool ChangeBits(char *pDst, char *pSrc)
{
for ( int i=0 ; i<4 ; i++ )
{
if ( *pDst++ != *pSrc++ ) return true;
}
return false;
}
// Retourne l'icône correspondant aux bits d'eaux.
int CDecor::GetSeeIcon(char *pBits, int index)
{
int i;
if ( index == 0 ) // eau ?
{
for ( i=0 ; i<14 ; i++ )
{
if ( tableSee[i*4+0] == pBits[0] &&
tableSee[i*4+1] == pBits[1] &&
tableSee[i*4+2] == pBits[2] &&
tableSee[i*4+3] == pBits[3] ) return i+1;
}
}
if ( index == 1 ) // mousse ?
{
for ( i=0 ; i<13 ; i++ )
{
if ( tableDark[i*4+0] == pBits[0] &&
tableDark[i*4+1] == pBits[1] &&
tableDark[i*4+2] == pBits[2] &&
tableDark[i*4+3] == pBits[3] ) return i+20;
}
}
if ( index == 2 ) // terre ?
{
for ( i=0 ; i<13 ; i++ )
{
if ( tableDark[i*4+0] == pBits[0] &&
tableDark[i*4+1] == pBits[1] &&
tableDark[i*4+2] == pBits[2] &&
tableDark[i*4+3] == pBits[3] ) return i+33;
}
}
if ( pBits[0] == 0 &&
pBits[1] == 0 &&
pBits[2] == 0 &&
pBits[3] == 0 ) return 1; // herbe
return -1;
}
// Arrange le sol après une modification.
void CDecor::ArrangeFloor(POINT cel)
{
POINT test;
int max, index, icon;
char here[4], bits[4], init[4];
bool bModif = false;
icon = m_decor[cel.x/2][cel.y/2].floorIcon;
if ( icon >= 59 && icon <= 64 ) return; // pont ?
max = 3;
if ( icon >= 15 && icon <= 18 ) // dalle spéciale ?
{
max = 1; // s'occupe que de l'eau !
}
for ( index=0 ; index<max ; index++ )
{
if ( !GetSeeBits(cel, here, index) ) continue;
test.x = cel.x -2; // en bas à gauche
test.y = cel.y +2;
if ( GetSeeBits(test, bits, index) )
{
if ( bits[2] == here[2] &&
bits[0] != here[2] &&
bits[1] != here[2] &&
bits[3] != here[2] )
{
here[2] = bits[1];
bModif = true;
}
}
test.x = cel.x -2; // en haut à gauche
test.y = cel.y -2;
if ( GetSeeBits(test, bits, index) )
{
if ( bits[0] == here[0] &&
bits[1] != here[0] &&
bits[2] != here[0] &&
bits[3] != here[0] )
{
here[0] = bits[3];
bModif = true;
}
}
test.x = cel.x +2; // en haut à droite
test.y = cel.y -2;
if ( GetSeeBits(test, bits, index) )
{
if ( bits[1] == here[1] &&
bits[0] != here[1] &&
bits[2] != here[1] &&
bits[3] != here[1] )
{
here[1] = bits[2];
bModif = true;
}
}
test.x = cel.x +2; // en bas à droite
test.y = cel.y +2;
if ( GetSeeBits(test, bits, index) )
{
if ( bits[3] == here[3] &&
bits[0] != here[3] &&
bits[1] != here[3] &&
bits[2] != here[3] )
{
here[3] = bits[0];
bModif = true;
}
}
if ( bModif )
{
icon = GetSeeIcon(here, index);
if ( icon != -1 ) m_decor[cel.x/2][cel.y/2].floorIcon = icon;
}
test.x = cel.x -2; // à gauche
test.y = cel.y;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[1] = here[0]?1:0;
bits[3] = here[2]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x -2; // en haut à gauche
test.y = cel.y -2;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[3] = here[0]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x; // en haut
test.y = cel.y -2;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[2] = here[0]?1:0;
bits[3] = here[1]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x +2; // en haut à droite
test.y = cel.y -2;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[2] = here[1]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x +2; // à droite
test.y = cel.y;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[0] = here[1]?1:0;
bits[2] = here[3]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x +2; // en bas à droite
test.y = cel.y +2;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[0] = here[3]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x; // en bas
test.y = cel.y +2;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[0] = here[2]?1:0;
bits[1] = here[3]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
test.x = cel.x -2; // en bas à gauche
test.y = cel.y +2;
if ( GetSeeBits(test, bits, index) )
{
CopyBits(init, bits);
bits[1] = here[2]?1:0;
icon = GetSeeIcon(bits, index);
if ( ChangeBits(init, bits) && icon != -1 )
{
m_decor[test.x/2][test.y/2].floorIcon = icon;
}
}
}
}
// Cette table donne les directions dans l'ordre
// est-sud-ouest-nord pour les murs.
static char tableMur[5*15] =
{
20, 1,0,1,0,
21, 0,1,0,1,
22, 1,1,0,0,
23, 0,1,1,0,
24, 0,0,1,1,
25, 1,0,0,1,
26, 1,1,1,1,
26, 0,1,1,1,
26, 1,0,1,1,
26, 1,1,0,1,
26, 1,1,1,0,
20, 1,0,0,0,
20, 0,0,1,0,
21, 0,1,0,0,
21, 0,0,0,1,
};
static short tableMurDir[4*2] =
{
+2, 0, // est
0,+2, // sur
-2, 0, // ouest
0,-2, // nord
};
// Arrange un mur en fonction des autres murs dans toutes
// les directions.
// index=0 si mur (20..26)
// index=1 si palissade (65..71)
// index=2 si barrière (106..112)
void CDecor::ArrangeMur(POINT cel, int &icon, int index)
{
int i, x, y, channel;
int first, last, matiere;
int icons[4];
char murs[4];
if ( index == 0 )
{
first = 20;
last = 26;
matiere = 44; // pierres
}
if ( index == 1 )
{
first = 65;
last = 71;
matiere = 36; // planches
}
if ( index == 2 )
{
first = 106;
last = 112;
matiere = 36; // planches
}
for ( i=0 ; i<4 ; i++ )
{
x = cel.x + tableMurDir[i*2+0];
y = cel.y + tableMurDir[i*2+1];
if ( IsValid(GetCel(x,y)) )
{
icons[i] = m_decor[x/2][y/2].objectIcon;
if ( icons[i] == matiere ) // pierres/planches ?
{
MoveGetObject(GetCel(x,y), channel, icons[i]);
}
if ( icons[i] < first || icons[i] > last )
{
icons[i] = -1;
}
}
else
{
icons[i] = -1;
}
}
for ( i=0 ; i<4 ; i++ )
{
if ( icons[i] == -1 )
{
murs[i] = 0;
}
else
{
murs[i] = tableMur[(icons[i]-first)*5+1+((i+2)%4)];
}
}
for ( i=0 ; i<15 ; i++ )
{
if ( murs[0] == tableMur[i*5+1] &&
murs[1] == tableMur[i*5+2] &&
murs[2] == tableMur[i*5+3] &&
murs[3] == tableMur[i*5+4] )
{
icon = tableMur[i*5+0];
icon += first-20;
return;
}
}
icon = -1;
}
// Arrange les objets avant une construction.
void CDecor::ArrangeBuild(POINT cel, int &channel, int &icon)
{
int index, i, x, y;
int first, last, matiere;
int oldChannel, oldIcon;
for ( index=0 ; index<3 ; index++ )
{
if ( index == 0 )
{
first = 20;
last = 26;
matiere = 44; // pierres
}
if ( index == 1 )
{
first = 65;
last = 71;
matiere = 36; // planches
}
if ( index == 2 )
{
first = 106;
last = 112;
matiere = 36; // planches
}
// Rien à faire si pas mur.
if ( channel != CHOBJECT || icon != last ) continue;
oldChannel = m_decor[cel.x/2][cel.y/2].objectChannel;
oldIcon = m_decor[cel.x/2][cel.y/2].objectIcon;
m_decor[cel.x/2][cel.y/2].objectChannel = channel;
m_decor[cel.x/2][cel.y/2].objectIcon = icon;
for ( i=0 ; i<4 ; i++ )
{
x = cel.x + tableMurDir[i*2+0];
y = cel.y + tableMurDir[i*2+1];
if ( IsValid(GetCel(x,y)) )
{
icon = m_decor[x/2][y/2].objectIcon;
if ( icon == matiere ) // pierres/planches ?
{
MoveGetObject(GetCel(x,y), channel, icon);
}
if ( icon >= first && icon <= last )
{
ArrangeMur(GetCel(x,y), icon, index);
if ( icon != -1 )
{
if ( !MovePutObject(GetCel(x,y), channel, icon) )
{
m_decor[x/2][y/2].objectChannel = channel;
m_decor[x/2][y/2].objectIcon = icon;
}
}
}
}
}
m_decor[cel.x/2][cel.y/2].objectChannel = oldChannel;
m_decor[cel.x/2][cel.y/2].objectIcon = oldIcon;
ArrangeMur(cel, icon, index);
if ( icon == -1 ) icon = last;
}
}
// Arrange les objets après une modification.
void CDecor::ArrangeObject(POINT cel)
{
int channel, icon;
int first, last;
int index, i, j, k, x, y;
POINT vector, test, pos;
bool bTour;
for ( index=0 ; index<3 ; index++ )
{
if ( index == 0 )
{
first = 20; // murs
last = 26;
}
if ( index == 1 )
{
first = 65; // palissades
last = 71;
}
if ( index == 2 )
{
first = 106; // barrière
last = 112;
}
for ( i=0 ; i<4 ; i++ )
{
x = cel.x + tableMurDir[i*2+0];
y = cel.y + tableMurDir[i*2+1];
if ( IsValid(GetCel(x,y)) )
{
icon = m_decor[x/2][y/2].objectIcon;
if ( icon >= first && icon <= last )
{
ArrangeMur(GetCel(x,y), icon, index);
if ( icon != -1 )
{
m_decor[x/2][y/2].objectChannel = CHOBJECT;
m_decor[x/2][y/2].objectIcon = icon;
}
}
}
}
if ( m_decor[cel.x/2][cel.y/2].objectIcon == last )
{
ArrangeMur(cel, icon, index);
if ( icon == -1 ) icon = last;
m_decor[cel.x/2][cel.y/2].objectChannel = CHOBJECT;
m_decor[cel.x/2][cel.y/2].objectIcon = icon;
}
}
// Arrange les rayons entre les tours.
if ( m_decor[cel.x/2][cel.y/2].objectIcon == 27 || // tour ?
m_decor[cel.x/2][cel.y/2].objectIcon == -1 ) // rien ?
{
for ( i=0 ; i<4 ; i++ )
{
vector = GetVector(i*2*16);
test = cel;
bTour = false;
j = 0;
while ( true )
{
test.x += vector.x*2;
test.y += vector.y*2;
if ( m_decor[test.x/2][test.y/2].objectIcon == 27 ) // tour ?
{
bTour = true;
break;
}
if ( m_decor[test.x/2][test.y/2].objectIcon != -1 &&
m_decor[test.x/2][test.y/2].objectIcon != 10001-i%2 )
{
break;
}
j ++;
if ( j >= 2+1 ) break;
}
if ( m_decor[cel.x/2][cel.y/2].objectIcon != 27 ) // pas tour ?
{
bTour = false;
}
test = cel;
for ( k=0 ; k<j ; k++ )
{
test.x += vector.x*2;
test.y += vector.y*2;
if ( bTour )
{
channel = CHOBJECT;
icon = 10001-i%2; // rayon e-o (10001) ou n-s (10000)
}
else
{
channel = -1;
icon = -1;
}
m_decor[test.x/2][test.y/2].objectChannel = channel;
m_decor[test.x/2][test.y/2].objectIcon = icon;
if ( !m_bBuild && bTour )
{
if ( MoveCreate(test, -1, false, CHOBJECT,-1,
-1,-1, 9999,1,0, true) )
{
MoveAddIcons(test, 5-i%2, true); // éclairs
}
pos = ConvCelToPos(test);
m_pSound->PlayImage(SOUND_RAYON1, pos);
}
if ( !m_bBuild && !bTour )
{
MoveFinish(test);
}
}
}
}
}
// Test s'il faut remplir le sol ici.
bool CDecor::ArrangeFillTestFloor(POINT cel1, POINT cel2)
{
POINT cel;
int icon1, icon2;
icon1 = m_fillSearchIcon;
icon2 = m_fillSearchIcon;
if ( m_fillPutChannel == CHFLOOR &&
m_fillPutIcon == 1 && // met de l'herbe..
m_fillSearchIcon == 14 ) // ..sur de l'eau ?
{
icon1 = 2;
icon2 = 14; // eau & rives
}
if ( m_fillPutChannel == CHFLOOR &&
m_fillPutIcon == 14 && // met de l'eau..
m_fillSearchIcon == 1 ) // ..sur de l'herbe ?
{
icon1 = 1;
icon2 = 13; // herbe & rives
}
for ( cel.x=cel1.x ; cel.x<=cel2.x ; cel.x+=2 )
{
for ( cel.y=cel1.y ; cel.y<=cel2.y ; cel.y+=2 )
{
if ( !IsValid(cel) ) continue;
if ( m_decor[cel.x/2][cel.y/2].floorChannel != m_fillSearchChannel ||
m_decor[cel.x/2][cel.y/2].floorIcon < icon1 ||
m_decor[cel.x/2][cel.y/2].floorIcon > icon2 )
{
return false;
}
if ( m_fillPutChannel == CHFLOOR &&
m_fillPutIcon == 14 && // met de l'eau ?
m_decor[cel.x/2][cel.y/2].objectIcon != -1 )
{
return false;
}
}
}
if ( m_fillPutChannel == CHFLOOR &&
m_fillPutIcon == 14 && // met de l'eau ?
IsBlupiHereEx(cel1, cel2, -1, false) )
{
return false;
}
return true;
}
// Test s'il faut remplir ici.
bool CDecor::ArrangeFillTest(POINT pos)
{
POINT cel1, cel2;
if ( m_pFillMap[(pos.x/2)+(pos.y/2)*(MAXCELX/2)] == 1 )
{
return false;
}
if ( m_bFillFloor )
{
cel1.x = pos.x-2;
cel1.y = pos.y-2;
cel2.x = pos.x+3;
cel2.y = pos.y+3;
return ArrangeFillTestFloor(cel1, cel2);
}
else
{
if ( m_decor[pos.x/2][pos.y/2].objectChannel == m_fillSearchChannel &&
m_decor[pos.x/2][pos.y/2].objectIcon == m_fillSearchIcon &&
!IsBlupiHereEx(GetCel(pos.x+0,pos.y+0),
GetCel(pos.x+1,pos.y+1), -1, false) )
{
if ( m_decor[pos.x/2][pos.y/2].floorChannel == CHFLOOR &&
m_decor[pos.x/2][pos.y/2].floorIcon >= 2 &&
m_decor[pos.x/2][pos.y/2].floorIcon <= 14 ) // rive ou eau ?
{
return false;
}
return true;
}
}
return false;
}
// Modifie le décor lors d'un remplissage.
void CDecor::ArrangeFillPut(POINT pos, int channel, int icon)
{
if ( m_bFillFloor )
{
PutFloor(pos, channel, icon);
ArrangeFloor(pos);
}
else
{
if ( icon >= 0 && icon <= 5 ) // plantes ?
{
icon = Random(0,5);
}
if ( icon >= 6 && icon <= 11 ) // arbres ?
{
icon = Random(6,11);
}
if ( icon >= 37 && icon <= 43 ) // rochers ?
{
icon = Random(37,43);
}
PutObject(pos, channel, icon);
ArrangeObject(pos);
}
}
// Rempli un sol à partir d'une position donnée.
void CDecor::ArrangeFillSearch(POINT pos)
{
int startX, endX;
// Cherche la borne gauche.
startX = pos.x;
endX = pos.x;
while ( pos.x > 0 && ArrangeFillTest(pos) )
{
pos.x -= 2;
}
startX = pos.x+2;
// Cherche la borne droite.
pos.x = endX;
while ( pos.x < MAXCELX-2 && ArrangeFillTest(pos) )
{
pos.x += 2;
}
endX = pos.x-2;
// Rempli toute la ligne trouvée.
pos.x = startX;
while ( pos.x <= endX )
{
m_pFillMap[(pos.x/2)+(pos.y/2)*(MAXCELX/2)] = 1;
pos.x += 2;
}
// Cherche la ligne au-dessus.
if ( pos.y > 0 )
{
pos.y -= 2;
pos.x = startX;
while ( pos.x <= endX )
{
while ( pos.x <= endX && !ArrangeFillTest(pos) )
{
pos.x += 2;
}
if ( pos.x > endX ) break;
if ( ArrangeFillTest(pos) )
{
ArrangeFillSearch(pos); // appel récursif
}
while ( pos.x <= endX && ArrangeFillTest(pos) )
{
pos.x += 2;
}
}
pos.y += 2;
}
// Cherche la ligne au-dessous.
if ( pos.y < MAXCELY-2 )
{
pos.y += 2;
pos.x = startX;
while ( pos.x <= endX )
{
while ( pos.x <= endX && !ArrangeFillTest(pos) )
{
pos.x += 2;
}
if ( pos.x > endX ) break;
if ( ArrangeFillTest(pos) )
{
ArrangeFillSearch(pos); // appel récursif
}
while ( pos.x <= endX && ArrangeFillTest(pos) )
{
pos.x += 2;
}
}
}
}
// Rempli un sol à partir d'une position donnée.
void CDecor::ArrangeFill(POINT pos, int channel, int icon, bool bFloor)
{
m_bFillFloor = bFloor;
pos.x = (pos.x/2)*2;
pos.y = (pos.y/2)*2;
m_fillPutChannel = channel;
m_fillPutIcon = icon;
if ( bFloor )
{
GetFloor(pos, m_fillSearchChannel, m_fillSearchIcon);
}
else
{
GetObject(pos, m_fillSearchChannel, m_fillSearchIcon);
}
m_pFillMap = (char*)malloc(MAXCELX*MAXCELY*sizeof(char)/4);
if ( m_pFillMap == NULL ) return;
memset(m_pFillMap, 0, MAXCELX*MAXCELY*sizeof(char)/4);
ArrangeFillSearch(pos);
for ( pos.x=0 ; pos.x<MAXCELX ; pos.x+=2 )
{
for ( pos.y=0 ; pos.y<MAXCELY ; pos.y+=2 )
{
if ( m_pFillMap[(pos.x/2)+(pos.y/2)*(MAXCELX/2)] == 1 )
{
ArrangeFillPut(pos, channel, icon);
}
}
}
free(m_pFillMap);
}
// Supprime tous les personnages bloqués dans des murs
// ou debout sur l'eau.
void CDecor::ArrangeBlupi()
{
int rank;
for ( rank=0 ; rank<MAXBLUPI ; rank++ )
{
if ( m_blupi[rank].bExist )
{
if ( !IsFreeCel(m_blupi[rank].cel, rank) )
{
m_blupi[rank].bExist = false;
}
}
}
}