1
0
mirror of https://github.com/blupi-games/planetblupi synced 2024-12-30 10:15:36 +01:00
planetblupi/src/decor.cxx
Mathieu Schroeter c08b750804 Fix regression where the fire was no longer propagated
It's better to keep the map as it without changing this behaviour. It's
just protected with the map editor; then everything is now working
again.

It fixes issue https://github.com/blupi-games/planetblupi/issues/54
2018-03-14 17:57:53 +01:00

3497 lines
84 KiB
C++

/*
* This file is part of the planetblupi source code
* Copyright (C) 1997, Daniel Roux & EPSITEC SA
* Copyright (C) 2017, Mathieu Schroeter
* http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include <stdio.h>
#include <stdlib.h>
#include <unordered_map>
#include "action.h"
#include "decmove.h"
#include "decor.h"
#include "def.h"
#include "fifo.h"
#include "gettext.h"
#include "misc.h"
#include "pixmap.h"
#include "sound.h"
#include "text.h"
#define TEXTDELAY 10 // délai avant apparition tooltips
Point
GetCel (Sint32 x, Sint32 y)
{
Point cel;
cel.x = x;
cel.y = y;
return cel;
}
Point
GetCel (Point cel, Sint32 x, Sint32 y)
{
cel.x += x;
cel.y += y;
return cel;
}
// Indique si une coordonnée de cellule est valide.
// On ne peut pas aller dans la dernière cellule tout au
// bord (-2) pour permettre de gérer le brouillard proprement
// jusque dans les bords !
bool
IsValid (Point cel)
{
if (cel.x < 2 || cel.x >= MAXCELX - 2 || cel.y < 2 || cel.y >= MAXCELX - 2)
return false;
return true;
}
// Retourne un vecteur orienté dans une direction donnée.
Point
GetVector (Sint32 direct)
{
Point vector;
vector.x = 0;
vector.y = 0;
switch (direct)
{
case DIRECT_E:
vector.x = +1;
break;
case DIRECT_SE:
vector.x = +1;
vector.y = +1;
break;
case DIRECT_S:
vector.y = +1;
break;
case DIRECT_SW:
vector.x = -1;
vector.y = +1;
break;
case DIRECT_W:
vector.x = -1;
break;
case DIRECT_NW:
vector.x = -1;
vector.y = -1;
break;
case DIRECT_N:
vector.y = -1;
break;
case DIRECT_NE:
vector.x = +1;
vector.y = -1;
break;
}
return vector;
}
// Constructeur.
CDecor::CDecor ()
{
m_pSound = nullptr;
m_pUndoDecor = nullptr;
m_celCorner.x = 90;
m_celCorner.y = 98;
m_celHili.x = -1;
m_celOutline1.x = -1;
m_celOutline2.x = -1;
m_bHiliRect = false; // pas de rectangle de sélection
m_shiftHili = 0;
m_shiftOffset.x = 0;
m_shiftOffset.y = 0;
m_nbBlupiHili = 0;
m_rankBlupiHili = -1;
m_rankHili = -1;
m_bFog = false;
m_bBuild = false;
m_bInvincible = false;
m_bSuper = false;
m_bHideTooltips = false;
m_bInfo = false;
m_infoHeight = 100;
m_phase = 0;
m_totalTime = 0;
m_region = 0;
m_lastRegion = 999;
m_skill = 0;
m_SurfaceMap = nullptr;
Init (CHFLOOR, 0);
BlupiFlush ();
MoveFlush ();
InitDrapeau ();
}
// Destructeur.
CDecor::~CDecor ()
{
if (m_SurfaceMap)
SDL_FreeSurface (m_SurfaceMap);
UndoClose (); // libère le buffer du undo
}
// Initialisation générale.
void
CDecor::Create (CSound * pSound, CPixmap * pPixmap)
{
m_pSound = pSound;
m_pPixmap = pPixmap;
m_bOutline = false;
}
// Initialise le décor avec un sol plat partout.
void
CDecor::Init (Sint32 channel, Sint32 icon)
{
Sint32 x, y;
for (x = 0; x < MAXCELX / 2; x++)
{
for (y = 0; y < MAXCELY / 2; y++)
{
m_decor[x][y].floorChannel = channel;
m_decor[x][y].floorIcon = icon;
m_decor[x][y].objectChannel = -1;
m_decor[x][y].objectIcon = -1;
m_decor[x][y].fog = FOGHIDE; // caché
m_decor[x][y].rankMove = -1;
m_decor[x][y].workBlupi = -1;
m_decor[x][y].fire = 0;
}
}
for (x = 0; x < MAXCELX; x++)
{
for (y = 0; y < MAXCELY; y++)
m_rankBlupi[x][y] = -1;
}
m_bOutline = false;
m_bGroundRedraw = true;
}
// Initialise le décor après une modification.
void
CDecor::InitAfterBuild ()
{
ClearFog (); // met tout sous le brouillard
ClearFire ();
MoveFixInit ();
InitDrapeau ();
BlupiDeselect ();
}
// Initialise les mises en évidence, avant de jouer.
void
CDecor::ResetHili ()
{
m_bHiliRect = false; // plus de rectangle
InitOutlineRect ();
}
// Charge les images nécessaires au décor.
bool
CDecor::LoadImages ()
{
Point totalDim, iconDim;
char filename[50];
if (m_region == m_lastRegion)
return true;
m_lastRegion = m_region;
totalDim.x = DIMCELX * 2 * 16;
totalDim.y = DIMCELY * 2 * 6;
iconDim.x = DIMCELX * 2;
iconDim.y = DIMCELY * 2;
snprintf (filename, sizeof (filename), "image/floor%.3d.png", m_region);
if (!m_pPixmap->Cache (CHFLOOR, filename, totalDim, iconDim))
return false;
totalDim.x = DIMOBJX * 16;
totalDim.y = DIMOBJY * 8;
iconDim.x = DIMOBJX;
iconDim.y = DIMOBJY;
snprintf (filename, sizeof (filename), "image/obj%.3d.png", m_region);
if (!m_pPixmap->Cache (CHOBJECT, filename, totalDim, iconDim))
return false;
snprintf (filename, sizeof (filename), "image/obj-o%.3d.png", m_region);
if (!m_pPixmap->Cache (CHOBJECTo, filename, totalDim, iconDim))
return false;
MapInitColors (); // init les couleurs pour la carte
m_bGroundRedraw = true;
return true;
}
// Met partout du brouillard, sauf aux endroits des blupi.
void
CDecor::ClearFog ()
{
Sint32 x, y, rank;
for (x = 0; x < MAXCELX / 2; x++)
{
for (y = 0; y < MAXCELY / 2; y++)
{
m_decor[x][y].fog = FOGHIDE; // caché
}
}
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (m_blupi[rank].bExist)
BlupiPushFog (rank);
}
m_bOutline = false;
}
// Permet de nouveau aux cellules brulées de bruler.
void
CDecor::ClearFire ()
{
Sint32 x, y;
for (x = 0; x < MAXCELX / 2; x++)
{
for (y = 0; y < MAXCELY / 2; y++)
{
if (m_decor[x][y].fire >= MoveMaxFire ()) // déjà brulé ?
{
m_decor[x][y].fire = 0; // pourra de nouveau bruler
}
if (m_decor[x][y].fire > 1) // en train de bruler ?
{
m_decor[x][y].fire = 1; // début du feu
}
}
}
}
// Indique le mode jeu/construction.
void
CDecor::SetBuild (bool bBuild)
{
m_bBuild = bBuild;
}
// Indique s'il faut tenir compte du brouillard.
void
CDecor::EnableFog (bool bEnable)
{
m_bFog = bEnable;
m_bOutline = false;
}
// Gestion du mode invincible.
bool
CDecor::GetInvincible ()
{
return m_bInvincible;
}
void
CDecor::SetInvincible (bool bInvincible)
{
m_bInvincible = bInvincible;
}
// Gestion du mode costaud (superblupi).
bool
CDecor::GetSuper ()
{
return m_bSuper;
}
void
CDecor::SetSuper (bool bSuper)
{
m_bSuper = bSuper;
}
// Bascule le mode outline.
void
CDecor::FlipOutline ()
{
m_bOutline = !m_bOutline;
m_timeFlipOutline = m_timeConst + 50;
}
// Initialise un sol dans une cellule.
bool
CDecor::PutFloor (Point cel, Sint32 channel, Sint32 icon)
{
if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY)
return false;
m_decor[cel.x / 2][cel.y / 2].floorChannel = channel;
m_decor[cel.x / 2][cel.y / 2].floorIcon = icon;
m_bGroundRedraw = true;
//? SubDrapeau(cel); // on pourra de nouveau planter un drapeau
return true;
}
// Initialise un objet dans une cellule.
bool
CDecor::PutObject (Point cel, Sint32 channel, Sint32 icon)
{
if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY)
return false;
if (icon == -1)
channel = -1;
m_decor[cel.x / 2][cel.y / 2].objectChannel = channel;
m_decor[cel.x / 2][cel.y / 2].objectIcon = icon;
SubDrapeau (cel); // on pourra de nouveau planter un drapeau
return true;
}
// Retourne un sol dans une cellule.
bool
CDecor::GetFloor (Point cel, Sint32 & channel, Sint32 & icon)
{
if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY)
return false;
channel = m_decor[cel.x / 2][cel.y / 2].floorChannel;
icon = m_decor[cel.x / 2][cel.y / 2].floorIcon;
return true;
}
// Retourne une objet dans une cellule.
bool
CDecor::GetObject (Point cel, Sint32 & channel, Sint32 & icon)
{
if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY)
return false;
channel = m_decor[cel.x / 2][cel.y / 2].objectChannel;
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
return true;
}
// Modifie le feu pour une cellule.
bool
CDecor::SetFire (Point cel, bool bFire)
{
if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY)
return false;
m_decor[cel.x / 2][cel.y / 2].fire = bFire ? 1 : 0;
return true;
}
void
CDecor::FixShifting (Sint32 & nbx, Sint32 & nby, Point & iCel, Point & iPos)
{
if (m_shiftOffset.x < 0) // décalage à droite ?
nbx += 2;
if (m_shiftOffset.y < 0) // décalage en bas ?
nby += 3;
if (m_shiftOffset.x > 0) // décalage à gauche ?
{
nbx += 2;
iCel.x--;
iCel.y++;
iPos = ConvCelToPos (iCel);
}
if (m_shiftOffset.y > 0) // décalage en haut ?
{
nby += 2;
iCel.x--;
iCel.y--;
iPos = ConvCelToPos (iCel);
}
}
// Modifie l'offset pour le shift.
void
CDecor::SetShiftOffset (Point offset)
{
m_shiftOffset = offset;
m_bGroundRedraw = true;
}
// Convertit la position d'une cellule en coordonnée graphique.
Point
CDecor::ConvCelToPos (Point cel)
{
Point pos;
pos.x = ((cel.x - m_celCorner.x) - (cel.y - m_celCorner.y)) * (DIMCELX / 2);
pos.y = ((cel.x - m_celCorner.x) + (cel.y - m_celCorner.y)) * (DIMCELY / 2);
pos.x += POSDRAWX + m_shiftOffset.x;
pos.y += POSDRAWY + m_shiftOffset.y;
return pos;
}
// Convertit une coordonnée graphique en cellule.
Point
CDecor::ConvPosToCel (Point pos, bool bMap)
{
Point cel;
if (
bMap && pos.x >= POSMAPX && pos.x < POSMAPX + DIMMAPX && pos.y >= POSMAPY &&
pos.y < POSMAPY + DIMMAPY)
{
pos.x -= POSMAPX;
pos.y -= POSMAPY;
return ConvMapToCel (pos);
}
pos.x -= POSDRAWX + DIMCELX / 2;
pos.y -= POSDRAWY;
cel.x = (pos.y * DIMCELX + pos.x * DIMCELY) / (DIMCELX * DIMCELY);
// cel.y = (pos.y*DIMCELX - pos.x*DIMCELY) / (DIMCELX*DIMCELY);
cel.y = (pos.y * DIMCELX - pos.x * DIMCELY);
if (cel.y < 0)
cel.y -= (DIMCELX * DIMCELY);
cel.y /= (DIMCELX * DIMCELY);
cel.x += m_celCorner.x;
cel.y += m_celCorner.y;
return cel;
}
// Convertit une coordonnée graphique en grande cellule (2x2).
Point
CDecor::ConvPosToCel2 (Point pos)
{
Point cel;
pos.x -= POSDRAWX + DIMCELX / 2;
pos.y -= POSDRAWY;
if (m_celCorner.x % 2 != 0 && m_celCorner.y % 2 == 0)
{
pos.x += DIMCELX / 2;
pos.y += DIMCELY / 2;
}
if (m_celCorner.x % 2 == 0 && m_celCorner.y % 2 != 0)
{
pos.x -= DIMCELX / 2;
pos.y += DIMCELY / 2;
}
if (m_celCorner.x % 2 != 0 && m_celCorner.y % 2 != 0)
pos.y += DIMCELY;
cel.x =
(pos.y * DIMCELX * 2 + pos.x * DIMCELY * 2) / (DIMCELX * 2 * DIMCELY * 2);
// cel.y = (pos.y*DIMCELX*2 - pos.x*DIMCELY*2) / (DIMCELX*2*DIMCELY*2);
cel.y = (pos.y * DIMCELX * 2 - pos.x * DIMCELY * 2);
if (cel.y < 0)
cel.y -= (DIMCELX * 2 * DIMCELY * 2);
cel.y /= (DIMCELX * 2 * DIMCELY * 2);
cel.x = (cel.x * 2 + m_celCorner.x) / 2 * 2;
cel.y = (cel.y * 2 + m_celCorner.y) / 2 * 2;
return cel;
}
// Attribution des blupi aux différentes cellules.
// Lorsque un blupi a deux positions (courante et destination),
// il faut toujours mettre blupi le plus au fond possible
// (minimiser x et y).
void
CDecor::BuildPutBlupi ()
{
Sint32 x, y, dx, dy, xMin, yMin, rank, clipLeft;
Point pos;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist && m_blupi[rank].channel != -1 &&
m_blupi[rank].icon != -1)
{
xMin = m_blupi[rank].destCel.x;
if (xMin > m_blupi[rank].cel.x)
xMin = m_blupi[rank].cel.x;
yMin = m_blupi[rank].destCel.y;
if (yMin > m_blupi[rank].cel.y)
yMin = m_blupi[rank].cel.y;
// Si blupi entre dans une maison, il faut initialiser
// le clipping à gauche.
m_blupi[rank].clipLeft = 0; // pas de clipping
if (
!m_bOutline && xMin > 0 && xMin % 2 == 1 && yMin % 2 == 1 &&
m_decor[xMin / 2][yMin / 2].objectChannel == CHOBJECT &&
(m_decor[xMin / 2][yMin / 2].objectIcon == 28 || // maison ?
m_decor[xMin / 2][yMin / 2].objectIcon == 101 || // usine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 103 || // usine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 105 || // usine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 116 || // usine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 120 || // usine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 18 || // usine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 122 || // mine ?
m_decor[xMin / 2][yMin / 2].objectIcon == 113) && // maison ?
m_blupi[rank].posZ > -DIMBLUPIY)
{
pos = ConvCelToPos (GetCel (xMin, yMin));
clipLeft = pos.x + 34;
if (clipLeft < POSDRAWX)
clipLeft = POSDRAWX;
m_blupi[rank].clipLeft = clipLeft;
}
x = m_blupi[rank].cel.x;
y = m_blupi[rank].cel.y;
dx = m_blupi[rank].destCel.x - x;
dy = m_blupi[rank].destCel.y - y;
if (dx != -dy) // déplacement non horizontal (ne/so) ?
{
if (dx < 0)
x = m_blupi[rank].destCel.x;
if (dy < 0)
y = m_blupi[rank].destCel.y;
}
if (dx == -1 && dy == 1) // déplacement "so" ?
{
x = m_blupi[rank].destCel.x;
y = m_blupi[rank].destCel.y;
}
if (x % 2 != 0)
{
if (
IsFreeCelObstacle (GetCel (x, y + 0)) &&
!IsFreeCelObstacle (GetCel (x, y + 1)))
x--;
}
if (x % 2 == 0 && y % 2 != 0)
{
if (!IsFreeCelObstacle (GetCel (x + 1, y)))
y--;
}
if (x % 2 != 0 && y % 2 != 0 && dx != 0 && dy == 0)
{
if (!IsFreeCelObstacle (GetCel (x + 1, y - 1)))
x++;
}
if (m_rankBlupi[x][y] != -1) // déjà occupé ?
{
if (x == m_blupi[rank].cel.x)
x--;
else
x = m_blupi[rank].cel.x;
if (m_rankBlupi[x][y] != -1) // déjà occupé ?
{
if (y == m_blupi[rank].cel.y)
y--;
else
y = m_blupi[rank].cel.y;
if (m_rankBlupi[x][y] != -1) // déjà occupé ?
{
/* HACK: It's not right but at least less Blupi are
* lost (invisible). The logic is not very clear, then
* consider the following code as a workaround.
*/
if (x == m_blupi[rank].cel.x)
x -= 2;
else
x = m_blupi[rank].cel.x;
if (m_rankBlupi[x][y] != -1)
continue; // que faire d'autre ?
}
}
}
m_rankBlupi[x][y] = rank;
}
}
}
// Dessine une cellule du décor contenant un sol animé.
void
CDecor::BuildMoveFloor (Sint32 x, Sint32 y, Point pos, Sint32 rank)
{
Sint32 icon, nb;
Sint16 * pTable;
if (m_move[rank].rankIcons == 0)
{
icon = m_move[rank].maskIcon + m_move[rank].cTotal;
m_pPixmap->BuildIconMask (
m_move[rank].maskChannel, icon, m_move[rank].channel, m_move[rank].icon,
0);
m_pPixmap->DrawIcon (-1, m_move[rank].channel, 0, pos);
}
else
{
pTable = GetListIcons (m_move[rank].rankIcons);
nb = pTable[0];
icon = pTable[1 + m_move[rank].cTotal % nb];
if (m_move[rank].cel.x % 2 == 1)
{
pos.x += DIMCELX / 2;
pos.y += DIMCELY / 2;
}
if (m_move[rank].cel.y % 2 == 1)
{
pos.x -= DIMCELX / 2;
pos.y += DIMCELY / 2;
}
m_pPixmap->DrawIcon (-1, m_move[rank].channel, icon, pos);
}
}
// Dessine une cellule du décor contenant un objet animé.
void
CDecor::BuildMoveObject (Sint32 x, Sint32 y, Point pos, Sint32 rank)
{
Sint32 hBuild, offset, startY, endY;
Sint32 channel, icon, nb;
Sint16 * pTable;
if (m_move[rank].rankMoves != 0)
{
pTable = GetListMoves (m_move[rank].rankMoves);
offset = m_move[rank].phase;
if (offset < pTable[0])
{
pos.x += pTable[1 + 2 * offset + 0];
pos.y += pTable[1 + 2 * offset + 1];
}
else
m_move[rank].rankMoves = 0;
}
// Dessine un chiffre par-dessus
if (m_move[rank].icon >= MOVEICONNB && m_move[rank].icon <= MOVEICONNB + 100)
{
Point textPos;
char string[20];
m_pPixmap->DrawIcon (
-1, m_decor[x / 2][y / 2].objectChannel, m_decor[x / 2][y / 2].objectIcon,
pos);
snprintf (string, sizeof (string), "%d", m_move[rank].icon - MOVEICONNB);
textPos.x = pos.x + DIMCELX / 2 + 32;
textPos.y = pos.y + (DIMOBJY - DIMCELY * 2) + 36;
DrawTextCenter (m_pPixmap, textPos, string, FONTLITTLE);
}
else
{
hBuild = (m_move[rank].cTotal * m_move[rank].stepY) / 100;
if (m_move[rank].stepY >= 0)
{
if (hBuild <= 0)
hBuild = 0;
if (hBuild > DIMOBJY)
hBuild = DIMOBJY;
}
else
{
if (hBuild >= 0)
hBuild = 0;
if (hBuild < -DIMOBJY)
hBuild = -DIMOBJY;
}
// Dessine l'objet actuellement dans le décor.
if (m_decor[x / 2][y / 2].objectChannel >= 0)
{
if (hBuild >= 0)
{
startY = 0;
endY = DIMOBJY - hBuild;
}
else
{
startY = -hBuild;
endY = DIMOBJY;
}
channel = m_decor[x / 2][y / 2].objectChannel;
if (m_bOutline && channel == CHOBJECT)
channel = CHOBJECTo;
m_pPixmap->DrawIconPart (
-1, channel, m_decor[x / 2][y / 2].objectIcon, pos, startY, endY);
}
// Dessine le nouvel objet par-dessus.
if (m_move[rank].icon >= 0)
{
if (hBuild >= 0)
{
startY = DIMOBJY - hBuild;
endY = DIMOBJY;
}
else
{
startY = 0;
endY = -hBuild;
}
channel = m_move[rank].channel;
if (m_bOutline && channel == CHOBJECT)
channel = CHOBJECTo;
m_pPixmap->DrawIconPart (
-1, channel, m_move[rank].icon, pos, startY, endY);
}
}
// Dessine le feu ou les rayons.
if (m_move[rank].rankIcons != 0)
{
pTable = GetListIcons (m_move[rank].rankIcons);
nb = pTable[0];
icon = pTable[1 + m_move[rank].cTotal % nb];
m_pPixmap->DrawIcon (-1, m_move[rank].channel, icon, pos);
}
}
// Déplace l'objet transporté par blupi.
void
BuildMoveTransport (Sint32 icon, Point & pos)
{
pos.x -= DIMCELX / 2;
pos.y -= 96;
// clang-format off
static Sint32 offset_bateau[16 * 2] =
{
-4, -3, // e
-2, -3,
-1, -3, // se
+1, -3,
+2, -3, // s
+5, -2,
+6, -2, // so
+5, -1,
+1, 0, // o
-1, 0,
-2, 0, // no
-2, 0,
-3, 0, // n
-4, -1,
-5, -1, // ne
-4, -2,
};
static Sint32 offset_jeep[16 * 2] =
{
-2, -6, // e
-1, -6,
-1, -6, // se
-1, -6,
+3, -6, // s
+1, -6,
+4, -6, // so
+4, -5,
+4, -5, // o
+2, -5,
+1, -4, // no
+1, -4,
-3, -3, // n
-4, -4,
-3, -4, // ne
-4, -4,
};
// clang-format on
if (icon >= 0 && icon <= 47)
pos.y -= (icon % 3) * 2;
if (icon == 114) // mange ?
{
pos.x += 1;
pos.y += 1;
}
if (icon == 106) // se penche (mèche dynamite) ?
{
pos.x += 8;
pos.y += 10;
}
if (icon == 194) // se penche (mèche dynamite) ?
{
pos.x += 9;
pos.y += 9;
}
if (icon == 347) // se penche (armure) ?
{
pos.x += 2;
pos.y += 2;
}
if (icon >= 234 && icon <= 249) // blupi en bateau ?
{
pos.x += offset_bateau[(icon - 234) * 2 + 0];
pos.y += offset_bateau[(icon - 234) * 2 + 1];
}
if (icon >= 250 && icon <= 265) // blupi en jeep ?
{
pos.x += offset_jeep[(icon - 250) * 2 + 0];
pos.y += offset_jeep[(icon - 250) * 2 + 1];
}
if (icon == 270)
pos.y += 3; // blupi électrocuté
if (icon == 271)
pos.y -= 2;
if (icon == 272)
pos.y -= 7;
}
// Construit tous les sols fixes dans CHGROUND.
void
CDecor::BuildGround (Rect clip)
{
//? OutputDebug("BuildGround\n");
Sint32 x, y, i, j, nbx, nby, width, height, channel, icon;
Point iCel, mCel, iPos, mPos, cPos, pos;
width = clip.right - clip.left;
height = clip.bottom - clip.top;
pos.x = clip.left;
pos.y = clip.top;
iCel = ConvPosToCel (pos);
mCel = iCel;
if (mCel.x % 2 == 0 && mCel.y % 2 == 0)
{
iCel.x -= 2;
width += DIMCELX;
height += DIMCELY;
}
if (mCel.x % 2 != 0 && mCel.y % 2 != 0)
{
iCel.x -= 3;
iCel.y -= 1;
width += DIMCELX;
height += DIMCELY * 2;
}
if (mCel.x % 2 == 0 && mCel.y % 2 != 0)
{
iCel.x -= 2;
iCel.y -= 1;
width += DIMCELX / 2;
height += (DIMCELY / 2) * 3;
}
if (mCel.x % 2 != 0 && mCel.y % 2 == 0)
{
iCel.x -= 3;
width += (DIMCELX / 2) * 3;
height += (DIMCELY / 2) * 3;
}
iPos = ConvCelToPos (iCel);
nbx = (width / DIMCELX) + 2;
nby = (height / (DIMCELY / 2)) + 0;
if (GetInfoHeight () != 0)
{
nbx += 2;
nby += 2;
}
this->FixShifting (nbx, nby, iCel, iPos);
// Construit les sols.
mCel = iCel;
mPos = iPos;
for (j = 0; j < nby; j++)
{
x = mCel.x;
y = mCel.y;
cPos = mPos;
for (i = 0; i < nbx; i++)
{
if (x % 2 == 0 && y % 2 == 0)
{
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y;
if (
x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2 &&
m_decor[x / 2][y / 2].floorChannel >= 0 &&
m_decor[x / 2][y / 2].floorIcon >= 0)
{
channel = m_decor[x / 2][y / 2].floorChannel;
icon = m_decor[x / 2][y / 2].floorIcon;
}
else
{
channel = CHFLOOR;
icon = 78; // losange noir
}
if (!m_bBuild && icon == 71) // terre à fer ?
{
icon = 33; // terre normale !
}
// Dessine l'eau sous les rives et les ponts.
if (
(icon >= 2 && icon <= 13) || // rive ?
(icon >= 59 && icon <= 64)) // pont ?
{
m_pPixmap->DrawIcon (CHGROUND, CHFLOOR, 14, pos); // eau
}
m_pPixmap->DrawIcon (CHGROUND, channel, icon, pos);
}
x++;
y--;
cPos.x += DIMCELX;
}
if (j % 2 == 0)
{
mCel.y++;
mPos.x -= DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
else
{
mCel.x++;
mPos.x += DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
}
m_bGroundRedraw = false;
}
// Construit le décor dans un pixmap.
void
CDecor::Build (Rect clip, Point posMouse)
{
Sint32 x, y, i, j, nbx, nby, width, height, rank, icon, channel, n;
Point iCel, mCel, cel, iPos, mPos, cPos, pos, tPos;
Rect oldClip, clipRect;
static Sint32 table_eau[6] = {70, 68, 14, 69, 14, 68};
static Sint32 table_random_x[10] = {2, 5, 1, 9, 4, 0, 6, 3, 8, 7};
static Sint32 table_random_y[10] = {4, 8, 3, 5, 9, 1, 7, 2, 0, 6};
oldClip = m_pPixmap->GetClipping ();
m_pPixmap->SetClipping (clip);
if (m_bGroundRedraw)
{
BuildGround (clip); // refait les sols fixes
}
// Dessine tous les sols fixes.
m_pPixmap->DrawImage (-1, CHGROUND, clip);
width = clip.right - clip.left;
height = clip.bottom - clip.top;
pos.x = clip.left;
pos.y = clip.top;
iCel = ConvPosToCel (pos);
mCel = iCel;
if (mCel.x % 2 == 0 && mCel.y % 2 == 0)
{
iCel.x -= 2;
width += DIMCELX;
height += DIMCELY;
}
if (mCel.x % 2 != 0 && mCel.y % 2 != 0)
{
iCel.x -= 3;
iCel.y -= 1;
width += DIMCELX;
height += DIMCELY * 2;
}
if (mCel.x % 2 == 0 && mCel.y % 2 != 0)
{
iCel.x -= 2;
iCel.y -= 1;
width += DIMCELX / 2;
height += (DIMCELY / 2) * 3;
}
if (mCel.x % 2 != 0 && mCel.y % 2 == 0)
{
iCel.x -= 3;
width += (DIMCELX / 2) * 3;
height += (DIMCELY / 2) * 3;
}
iPos = ConvCelToPos (iCel);
nbx = (width / DIMCELX) + 2;
nby = (height / (DIMCELY / 2)) + 0;
if (GetInfoHeight () != 0)
{
nbx += 2;
nby += 2;
}
this->FixShifting (nbx, nby, iCel, iPos);
// Construit les sols.
mCel = iCel;
mPos = iPos;
for (j = 0; j < nby; j++)
{
x = mCel.x;
y = mCel.y;
cPos = mPos;
for (i = 0; i < nbx; i++)
{
if (x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2)
{
m_rankBlupi[x][y] = -1; // (1), voir BuildPutBlupi
if (x % 2 == 0 && y % 2 == 0)
{
icon = m_decor[x / 2][y / 2].floorIcon;
if (!m_bBuild && icon == 71) // terre à fer ?
{
icon = 33; // terre normale !
}
// Dessine l'eau sous les rives et les ponts.
if (
(icon >= 2 && icon <= 14) || // rive ?
(icon >= 59 && icon <= 64)) // pont ?
{
// Dessine l'eau en mouvement.
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y;
n = table_eau
[(m_timeConst / 2 + // lent !
table_random_x[x % 10] + table_random_y[y % 10]) %
6];
m_pPixmap->DrawIcon (CHGROUND, CHFLOOR, n, pos); // eau
if (icon != 14)
m_pPixmap->DrawIcon (CHGROUND, CHFLOOR, icon, pos);
}
rank = m_decor[x / 2][y / 2].rankMove;
if (
rank != -1 && // décor animé ?
m_move[rank].bFloor)
{
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y;
BuildMoveFloor (x, y, pos, rank);
}
}
}
if (
m_celHili.x != -1 && x >= m_celHili.x - 1 && x <= m_celHili.x + 2 &&
y >= m_celHili.y - 1 && y <= m_celHili.y + 2)
{
icon = m_iconHili[x - (m_celHili.x - 1)][y - (m_celHili.y - 1)];
if (icon != -1)
{
// hilight cellule
m_pPixmap->DrawIconDemi (-1, CHBLUPI, icon, cPos);
}
}
if (m_bHiliRect) // rectangle de sélection existe ?
{
if (
(m_p1Hili.x == x && m_p1Hili.y == y) ||
(m_p2Hili.x == x && m_p2Hili.y == y))
m_pPixmap->DrawIconDemi (-1, CHBLUPI, ICON_HILI_SEL, cPos);
}
x++;
y--;
cPos.x += DIMCELX;
}
if (j % 2 == 0)
{
mCel.y++;
mPos.x -= DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
else
{
mCel.x++;
mPos.x += DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
}
for (j = nby; j < nby + 3; j++)
{
x = mCel.x;
y = mCel.y;
for (i = 0; i < nbx; i++)
{
if (x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2)
{
m_rankBlupi[x][y] = -1; // (1), voir BuildPutBlupi
}
x++;
y--;
}
if (j % 2 == 0)
mCel.y++;
else
mCel.x++;
}
BlupiDrawHili (); // dessine le rectangle de sélection
// Construit les objets et les blupi.
BuildPutBlupi (); // m_rankBlupi[x][y] <- rangs des blupi
this->FixShifting (nbx, nby, iCel, iPos);
mCel = iCel;
mPos = iPos;
for (j = 0; j < nby + 3; j++)
{
x = mCel.x;
y = mCel.y;
cPos = mPos;
for (i = 0; i < nbx; i++)
{
if (x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2)
{
rank = m_rankBlupi[x][y];
if (
rank != -1 && // un blupi sur cette cellule ?
!m_blupi[rank].bCache)
{
cel.x = m_blupi[rank].cel.x;
cel.y = m_blupi[rank].cel.y;
pos = ConvCelToPos (cel);
pos.x += m_blupi[rank].pos.x;
pos.y += m_blupi[rank].pos.y - (DIMBLUPIY - DIMCELY) - SHIFTBLUPIY;
if (m_blupi[rank].bHili)
{
icon = 120 + (m_blupi[rank].energy * 18) / MAXENERGY;
if (icon < 120)
icon = 120;
if (icon > 137)
icon = 137;
tPos = pos;
tPos.y += DIMCELY;
if (m_blupi[rank].vehicule == 1) // en bateau ?
tPos.y -= 6;
// Dessine la sélection/énergie
if (m_blupi[rank].clipLeft == 0)
m_pPixmap->DrawIconDemi (-1, CHBLUPI, icon, tPos);
else
{
clipRect = clip;
clipRect.left = m_blupi[rank].clipLeft;
m_pPixmap->SetClipping (clipRect);
m_pPixmap->DrawIconDemi (-1, CHBLUPI, icon, tPos);
m_pPixmap->SetClipping (clip);
}
}
// Dessine la flèche ronde "répète" sous blupi.
if (m_blupi[rank].repeatLevel != -1)
{
tPos = pos;
tPos.y += DIMCELY;
if (m_blupi[rank].vehicule == 1) // en bateau ?
tPos.y -= 6;
// Dessine la sélection/énergie
if (m_blupi[rank].clipLeft == 0)
m_pPixmap->DrawIconDemi (-1, CHBLUPI, 116, tPos);
else
{
clipRect = clip;
clipRect.left = m_blupi[rank].clipLeft;
m_pPixmap->SetClipping (clipRect);
m_pPixmap->DrawIconDemi (-1, CHBLUPI, 116, tPos);
m_pPixmap->SetClipping (clip);
}
}
// Dessine la flèche jaune sur blupi.
if (m_blupi[rank].bArrow)
{
tPos = pos;
if (m_phase % (6 * 2) < 6)
tPos.y -= DIMBLUPIY + (m_phase % 6) * 4;
else
tPos.y -= DIMBLUPIY + (6 - (m_phase % 6) - 1) * 4;
m_pPixmap->DrawIcon (-1, CHBLUPI, 132, tPos);
}
// Dessine le stop sur blupi.
if (m_blupi[rank].stop == 1)
{
tPos = pos;
tPos.x += 9;
tPos.y -= 24;
m_pPixmap->DrawIcon (-1, CHBUTTON, 46, tPos);
}
// Dessine blupi
pos.y += m_blupi[rank].posZ;
if (m_blupi[rank].clipLeft == 0)
{
m_pPixmap->DrawIcon (
-1, m_blupi[rank].channel, m_blupi[rank].icon, pos);
// Dessine l'objet transporté.
if (m_blupi[rank].takeChannel != -1)
{
BuildMoveTransport (m_blupi[rank].icon, pos);
m_pPixmap->DrawIcon (
-1, m_blupi[rank].takeChannel, m_blupi[rank].takeIcon, pos);
}
}
else
{
clipRect = clip;
clipRect.left = m_blupi[rank].clipLeft;
m_pPixmap->SetClipping (clipRect);
m_pPixmap->DrawIcon (
-1, m_blupi[rank].channel, m_blupi[rank].icon, pos);
// Dessine l'objet transporté.
if (m_blupi[rank].takeChannel != -1)
{
BuildMoveTransport (m_blupi[rank].icon, pos);
m_pPixmap->DrawIcon (
-1, m_blupi[rank].takeChannel, m_blupi[rank].takeIcon, pos);
}
m_pPixmap->SetClipping (clip);
}
}
if (x % 2 == 0 && y % 2 == 0)
{
rank = m_decor[x / 2][y / 2].rankMove;
if (m_decor[x / 2][y / 2].objectChannel >= 0)
{
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y - (DIMOBJY - DIMCELY * 2);
// Dessine l'objet
if (
rank == -1 || // décor fixe ?
m_move[rank].bFloor || m_bBuild)
{
channel = m_decor[x / 2][y / 2].objectChannel;
if (m_bOutline && channel == CHOBJECT)
channel = CHOBJECTo;
if (
m_celOutline1.x != -1 && x >= m_celOutline1.x &&
y >= m_celOutline1.y && x <= m_celOutline2.x &&
y <= m_celOutline2.y)
{
if (channel == CHOBJECT)
channel = CHOBJECTo;
else
channel = CHOBJECT;
}
m_pPixmap->DrawIcon (
-1, channel, m_decor[x / 2][y / 2].objectIcon, pos);
if (m_decor[x / 2][y / 2].objectIcon == 12) // fusée ?
{
pos.y -= DIMOBJY;
m_pPixmap->DrawIcon (-1, channel, 13, pos);
}
}
else // décor animé ?
BuildMoveObject (x, y, pos, rank);
}
else
{
if (
rank != -1 && // décor animé ?
!m_move[rank].bFloor && !m_bBuild)
{
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y - (DIMOBJY - DIMCELY * 2);
BuildMoveObject (x, y, pos, rank);
}
}
// Dessine le feu en mode construction.
if (
m_bBuild && m_decor[x / 2][y / 2].fire > 0 &&
m_decor[x / 2][y / 2].fire < MoveMaxFire ())
{
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y - (DIMOBJY - DIMCELY * 2);
m_pPixmap->DrawIcon (-1, CHOBJECT, 49, pos); // petite flamme
}
}
}
x++;
y--;
cPos.x += DIMCELX;
}
if (j % 2 == 0)
{
mCel.y++;
mPos.x -= DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
else
{
mCel.x++;
mPos.x += DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
}
// Construit le brouillard.
if (!m_bFog)
goto term;
this->FixShifting (nbx, nby, iCel, iPos);
mCel = iCel;
mPos = iPos;
for (j = 0; j < nby; j++)
{
x = mCel.x;
y = mCel.y;
cPos = mPos;
for (i = 0; i < nbx; i++)
{
if (
x >= 0 && x < MAXCELX && y >= 0 && y < MAXCELY && x % 2 == 0 &&
y % 2 == 0)
icon = m_decor[x / 2][y / 2].fog;
else
{
icon = FOGHIDE; // caché
}
if (
abs (x) % 4 == abs (y) % 4 && (abs (x) % 4 == 0 || abs (x) % 4 == 2) &&
icon != -1)
{
pos.x = cPos.x - DIMCELX / 2;
pos.y = cPos.y;
m_pPixmap->DrawIcon (-1, CHFOG, icon, pos);
}
x++;
y--;
cPos.x += DIMCELX;
}
if (j % 2 == 0)
{
mCel.y++;
mPos.x -= DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
else
{
mCel.x++;
mPos.x += DIMCELX / 2;
mPos.y += DIMCELY / 2;
}
}
term:
// Dessine la flèche jaune sur un objet.
if (m_celArrow.x != -1)
{
tPos = ConvCelToPos (m_celArrow);
if (m_phase % (6 * 2) < 6)
tPos.y -= DIMBLUPIY + (m_phase % 6) * 4;
else
tPos.y -= DIMBLUPIY + (6 - (m_phase % 6) - 1) * 4;
m_pPixmap->DrawIcon (-1, CHBLUPI, 132, tPos);
}
// Dessine le nom de l'objet pointé par la souris.
if (posMouse.x == m_textLastPos.x && posMouse.y == m_textLastPos.y)
{
if (m_textCount == 0)
{
const auto text = GetResHili (posMouse);
if (text)
{
posMouse.x += 10;
posMouse.y += 20;
DrawText (m_pPixmap, posMouse, text);
}
}
else
m_textCount--;
}
else
{
m_textLastPos = posMouse;
m_textCount = TEXTDELAY;
}
m_pPixmap->SetClipping (oldClip);
GenerateMap (); // dessine la carte miniature
GenerateStatictic (); // dessine les statistiques
}
// Augmente la phase.
// -1 mise à jour continue
// 0 début de mise à jour périodique
// 1 mise à jour périodique suivante
void
CDecor::NextPhase (Sint32 mode)
{
if (mode == -1)
m_phase = -1;
if (mode == 0)
m_phase = 0;
if (mode == 1)
m_phase++;
m_totalTime++;
}
// Modifie le temps total passé dans cette partie.
void
CDecor::SetTotalTime (Sint32 total)
{
m_totalTime = total;
}
// Retourne le temps total passé dans cette partie.
Sint32
CDecor::GetTotalTime ()
{
return m_totalTime;
}
// Compte le nombre total de sols contenus dans les décors.
Sint32
CDecor::CountFloor (Sint32 channel, Sint32 icon)
{
Sint32 x, y;
Sint32 nb = 0;
for (x = 0; x < MAXCELX / 2; x++)
{
for (y = 0; y < MAXCELY / 2; y++)
{
if (
channel == m_decor[x][y].floorChannel &&
icon == m_decor[x][y].floorIcon)
nb++;
}
}
return nb;
}
// Indique si une cellule est ok pour une action.
// Le rang du blupi qui effectuera le travail est donnée dans rank.
// action = 0 sélection jeu
// 1 construction d'une cellule 1x1
// 2 construction d'une cellule 2x2
// EV_ACTION* action
Errors
CDecor::CelOkForAction (
Point cel, Sint32 action, Sint32 rank, Sint32 icons[4][4],
Point & celOutline1, Point & celOutline2)
{
Sint32 x, y, i, j, channel, icon, nb, start, direct;
Errors error = Errors::NONE;
bool bStrong = false;
bool bTransport = false;
bool bVehicule = false;
bool bVehiculeA = false;
Point vector;
for (x = 0; x < 4; x++)
{
for (y = 0; y < 4; y++)
icons[x][y] = -1;
}
celOutline1.x = -1;
celOutline2.x = -1;
if (
action == 2 || action == EV_ACTION_ABAT1 || action == EV_ACTION_ROC1 ||
action == EV_ACTION_DROP || action == EV_ACTION_LABO ||
action == EV_ACTION_FABJEEP || action == EV_ACTION_FABARMURE ||
action == EV_ACTION_FABMINE || action == EV_ACTION_FLOWER1 ||
action == EV_ACTION_CULTIVE || action == EV_ACTION_FLAG)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
}
if (rank >= 0)
{
if (m_blupi[rank].energy > MAXENERGY / 4) // blupi fort ?
bStrong = true;
if (m_blupi[rank].takeChannel != -1) // porte qq chose ?
bTransport = true;
if (m_blupi[rank].vehicule != 0) // pas à pied ?
bVehicule = true;
if (
m_blupi[rank].vehicule != 0 && // pas à pied ?
m_blupi[rank].vehicule != 3) // pas armure ?
bVehiculeA = true;
}
if (action == 0)
{
if (IsBlupiHere (cel, false))
icons[1][1] = ICON_HILI_SEL;
else
{
if (IsFreeCel (cel, -1) && m_nbBlupiHili > 0)
icons[1][1] = ICON_HILI_ANY;
else
icons[1][1] = ICON_HILI_ERR;
}
}
if (action == 1)
{
icons[1][1] = ICON_HILI_BUILD; // action
}
if (action == 2)
{
icons[1][1] = ICON_HILI_BUILD; // action
icons[2][1] = ICON_HILI_BUILD;
icons[1][2] = ICON_HILI_BUILD;
icons[2][2] = ICON_HILI_BUILD;
}
if (action == EV_ACTION_STOP)
{
error = Errors::MISC;
if (
m_blupi[rank].stop == 0 &&
(m_blupi[rank].goalAction == EV_ACTION_GO ||
(m_blupi[rank].goalAction >= EV_ACTION_ABAT1 &&
m_blupi[rank].goalAction <= EV_ACTION_ABAT6) ||
(m_blupi[rank].goalAction >= EV_ACTION_ROC1 &&
m_blupi[rank].goalAction <= EV_ACTION_ROC7) ||
m_blupi[rank].goalAction == EV_ACTION_CULTIVE ||
m_blupi[rank].goalAction == EV_ACTION_CULTIVE2 ||
m_blupi[rank].goalAction == EV_ACTION_FLAG ||
m_blupi[rank].goalAction == EV_ACTION_FLAG2 ||
m_blupi[rank].goalAction == EV_ACTION_FLAG3 ||
m_blupi[rank].goalAction == EV_ACTION_FLOWER1 ||
m_blupi[rank].goalAction == EV_ACTION_FLOWER2 ||
m_blupi[rank].goalAction == EV_ACTION_FLOWER3))
error = Errors::NONE;
if (
m_blupi[rank].stop == 0 && m_blupi[rank].goalAction != 0 &&
m_blupi[rank].interrupt == 1)
error = Errors::NONE;
if (m_blupi[rank].repeatLevel != -1)
error = Errors::NONE;
}
if (action == EV_ACTION_GO)
{
if (m_decor[cel.x / 2][cel.y / 2].objectIcon == 113) // maison ?
{
cel.x = (cel.x / 2) * 2 + 1;
cel.y = (cel.y / 2) * 2 + 1;
}
error = Errors::MISC;
if (m_nbBlupiHili > 0)
{
nb = m_nbBlupiHili;
if (nb > 16)
nb = 16;
for (i = 0; i < nb; i++)
{
x = table_multi_goal[i * 2 + 0];
y = table_multi_goal[i * 2 + 1];
rank = GetHiliRankBlupi (i);
if (
((m_blupi[rank].takeChannel == -1) ||
(m_blupi[rank].energy > MAXENERGY / 4)) &&
IsFreeCelGo (GetCel (cel.x + x, cel.y + y), rank) &&
!IsBlupiHere (GetCel (cel.x + x, cel.y + y), true))
{
icons[1 + x][1 + y] = ICON_HILI_OP; // action
error = Errors::NONE;
}
else
icons[1 + x][1 + y] = ICON_HILI_ERR;
}
}
else
icons[1][1] = ICON_HILI_ERR;
}
if (action == EV_ACTION_ABAT1)
{
GetObject (cel, channel, icon);
if (
bStrong && !bTransport && !bVehicule && channel == CHOBJECT &&
icon >= 6 && icon <= 11 && // arbre ?
!MoveIsUsed (cel) && IsWorkableObject (cel, rank))
{
icons[1][1] = ICON_HILI_OP; // action
icons[2][1] = ICON_HILI_OP;
icons[1][2] = ICON_HILI_OP;
icons[2][2] = ICON_HILI_OP;
celOutline1 = cel;
celOutline2 = cel;
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
icons[2][1] = ICON_HILI_ERR;
icons[1][2] = ICON_HILI_ERR;
icons[2][2] = ICON_HILI_ERR;
error = Errors::MISC;
}
}
if (action == EV_ACTION_ROC1)
{
GetObject (cel, channel, icon);
if (
bStrong && !bTransport && !bVehicule &&
m_blupi[rank].perso != 8 && // pas disciple ?
channel == CHOBJECT && icon >= 37 && icon <= 43 && // rochers ?
!MoveIsUsed (cel) && IsWorkableObject (cel, rank))
{
icons[1][1] = ICON_HILI_OP; // action
icons[2][1] = ICON_HILI_OP;
icons[1][2] = ICON_HILI_OP;
icons[2][2] = ICON_HILI_OP;
celOutline1 = cel;
celOutline2 = cel;
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
icons[2][1] = ICON_HILI_ERR;
icons[1][2] = ICON_HILI_ERR;
icons[2][2] = ICON_HILI_ERR;
error = Errors::MISC;
}
}
if (action >= EV_ACTION_BUILD1 && action <= EV_ACTION_BUILD6)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
if (
action == EV_ACTION_BUILD1 || // cabane ?
action == EV_ACTION_BUILD2 || // couveuse ?
action == EV_ACTION_BUILD6) // téléporteur ?
{
GetFloor (cel, channel, icon);
if (
channel != CHFLOOR || (icon != 1 && // herbe claire ?
(icon < 19 || icon > 32))) // herbe foncée ?
{
error = Errors::GROUND; // sol pas adéquat
}
}
if (action == EV_ACTION_BUILD4) // mine ?
{
GetFloor (cel, channel, icon);
if (channel != CHFLOOR || icon != 71) // terre à fer ?
{
error = Errors::GROUND; // sol pas adéquat
}
}
if (
action == EV_ACTION_BUILD6 && // téléporteur ?
CountFloor (CHFLOOR, 80) >= 2) // déjà 2 ?
{
error = Errors::TELE2; // déjà 2 téléporteurs
}
if (action == EV_ACTION_BUILD3 || action == EV_ACTION_BUILD5)
start = 44; // pierres
else
start = 36; // planches
if (start == 44 && m_blupi[rank].perso == 8)
start = 999; // disciple ?
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != start) // planches ?
{
error = Errors::MISC; // pas de planches !
}
for (x = -1; x < 3; x++)
{
for (y = -1; y < 3; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = -1; x < 3; x++)
{
for (y = -1; y < 3; y++)
{
if (
(x < 0 || x > 1 || y < 0 || y > 1) &&
!IsFreeCel (GetCel (cel, x, y), rank))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
}
if (action == EV_ACTION_WALL)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
if (
!bStrong || bTransport || bVehicule ||
m_blupi[rank].perso == 8) // disciple ?
{
error = Errors::MISC; // pas assez fort
}
if (m_blupi[rank].energy <= MAXENERGY / 2)
error = Errors::ENERGY; // not enough energy
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 44) // pierres ?
{
error = Errors::MISC; // pas de pierres !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
}
if (action == EV_ACTION_TOWER)
{
bool bTour;
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
if (
!bStrong || bTransport || bVehicule ||
m_blupi[rank].perso == 8) // disciple ?
{
error = Errors::MISC; // pas assez fort
}
if (m_blupi[rank].energy <= MAXENERGY / 2)
error = Errors::ENERGY; // not enough energy
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 44) // pierres ?
{
error = Errors::MISC; // pas de pierres !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = -1; x < 3; x++)
{
for (y = -1; y < 3; y++)
{
if (x < 0 || x > 1 || y < 0 || y > 1) // périphérie ?
{
GetFloor (GetCel (cel, x, y), channel, icon);
if (channel == CHFLOOR && (icon >= 2 && icon <= 13)) // rive ?
{
error = Errors::TOUREAU;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
if (error == 0)
{
bTour = false;
for (i = 0; i < 4; i++)
{
vector = GetVector (i * 2 * 16);
x = cel.x;
y = cel.y;
for (j = 0; j < 3; j++)
{
x += vector.x * 2;
y += vector.y * 2;
if (m_decor[x / 2][y / 2].objectIcon == 27) // tour ?
bTour = true;
if (
MoveGetObject (GetCel (x, y), channel, icon) &&
channel == CHOBJECT && icon == 27) // tour en construction ?
bTour = true;
}
}
if (!bTour)
error = Errors::TOURISOL;
}
}
}
if (action == EV_ACTION_PALIS)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 36) // planches ?
{
error = Errors::MISC; // pas de pierres !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
}
if (action == EV_ACTION_BRIDGEE)
{
Point test;
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 36) // planches ?
{
error = Errors::MISC; // pas de pierres !
}
test = cel;
if (error == 0)
error = IsBuildPont (test, icon);
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
}
if (action == EV_ACTION_CARRY)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
GetObject (GetCel (cel, -1, -1), channel, icon);
if (
bStrong && !bTransport && !bVehiculeA && channel == CHOBJECT &&
(icon == 14 || // métal ?
icon == 36 || // planches ?
icon == 44 || // pierres ?
icon == 60 || // tomates ?
icon == 63 || // oeufs ?
icon == 80 || // bouteille ?
icon == 82 || // fleurs ?
icon == 84 || // fleurs ?
icon == 95 || // fleurs ?
icon == 85 || // dynamite ?
icon == 92 || // poison ?
icon == 93 || // piège ?
icon == 123 || // fer ?
icon == 125) && // mine ?
(!IsBlupiHereEx (GetCel (cel, -1, 0), rank, false) ||
!IsBlupiHereEx (GetCel (cel, 0, -1), rank, false)))
{
icons[1][1] = ICON_HILI_OP; // action
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
error = Errors::MISC;
}
}
}
if (action == EV_ACTION_DROP)
{
if (!bTransport || bVehiculeA)
{
error = Errors::MISC; // ne transporte rien
}
GetObject (GetCel ((cel.x / 2) * 2, (cel.y / 2) * 2), channel, icon);
if (icon != -1 && icon != 124) // pas drapeau ?
error = Errors::MISC;
start = 0;
if (error == 0)
{
GetFloor (cel, channel, icon);
if (
channel == CHFLOOR && icon == 52 && // nurserie ?
m_blupi[rank].takeChannel == CHOBJECT &&
m_blupi[rank].takeIcon == 63) // oeufs ?
{
for (x = -1; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (
!IsFreeCelDepose (GetCel (cel, x, y), rank) ||
IsBlupiHereEx (GetCel (cel, x, y), rank, false))
error = Errors::MISC;
}
}
start = -1;
}
else
{
if (
!IsFreeCelDepose (GetCel (cel, 1, 1), rank) ||
IsBlupiHereEx (GetCel (cel, 1, 1), rank, false))
error = Errors::MISC;
else
{
if (
!IsFreeCelDepose (GetCel (cel, 0, 1), rank) ||
IsBlupiHereEx (GetCel (cel, 0, 1), rank, false))
{
if (
!IsFreeCelDepose (GetCel (cel, 1, 0), rank) ||
IsBlupiHereEx (GetCel (cel, 1, 0), rank, false))
error = Errors::MISC;
}
}
}
}
for (x = start; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
}
if (action == EV_ACTION_CULTIVE)
{
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 61) // maison ?
{
error = Errors::MISC; // pas de maison !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::MISC;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
if (action == EV_ACTION_LABO)
{
if (!bStrong || !bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (
channel != CHOBJECT || icon != 28 || // laboratoire ?
m_blupi[rank].takeChannel != CHOBJECT ||
(m_blupi[rank].takeIcon != 82 && // fleurs ?
m_blupi[rank].takeIcon != 84 && // fleurs ?
m_blupi[rank].takeIcon != 95 && // fleurs ?
m_blupi[rank].takeIcon != 60)) // tomates ?
{
error = Errors::MISC; // pas de laboratoire !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::MISC;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
if (action == EV_ACTION_FLOWER1)
{
GetObject (cel, channel, icon);
if (
bStrong && !bTransport && !bVehicule && channel == CHOBJECT &&
(icon == 81 || icon == 83 || icon == 94) && // fleurs ?
!MoveIsUsed (cel) && IsWorkableObject (cel, rank))
{
icons[1][1] = ICON_HILI_OP; // action
icons[2][1] = ICON_HILI_OP;
icons[1][2] = ICON_HILI_OP;
icons[2][2] = ICON_HILI_OP;
celOutline1 = cel;
celOutline2 = cel;
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
icons[2][1] = ICON_HILI_ERR;
icons[1][2] = ICON_HILI_ERR;
icons[2][2] = ICON_HILI_ERR;
error = Errors::MISC;
}
}
if (action == EV_ACTION_DYNAMITE)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
//? if ( !bStrong || bVehicule )
if (bVehiculeA)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (icon != 85 && icon != 125) // dynamite/mine ?
{
error = Errors::MISC; // pas de dynamite !
}
for (x = 0; x < 2; x++)
{
for (y = 1; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 1; y < 2; y++)
{
if (
(x < 0 || x > 1 || y < 0 || y > 1) &&
!IsFreeCel (GetCel (cel, x, y), rank))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
}
if (action == EV_ACTION_EAT)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
GetObject (GetCel (cel, -1, -1), channel, icon);
if (
!m_blupi[rank].bMalade && !bVehicule &&
m_blupi[rank].perso != 8 && // pas disciple ?
channel == CHOBJECT && icon == 60 && // tomates ?
(!IsBlupiHereEx (GetCel (cel, -1, 0), rank, false) ||
!IsBlupiHereEx (GetCel (cel, 0, -1), rank, false)))
{
icons[1][1] = ICON_HILI_OP; // action
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
error = Errors::MISC;
}
}
}
if (action == EV_ACTION_DRINK)
{
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
GetObject (GetCel (cel, -1, -1), channel, icon);
if (
m_blupi[rank].bMalade && !bVehicule &&
m_blupi[rank].perso != 8 && // pas disciple ?
channel == CHOBJECT && icon == 80 && // bouteille ?
(!IsBlupiHereEx (GetCel (cel, -1, 0), rank, false) ||
!IsBlupiHereEx (GetCel (cel, 0, -1), rank, false)))
{
icons[1][1] = ICON_HILI_OP; // action
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
error = Errors::MISC;
}
}
}
if (action == EV_ACTION_BOATE)
{
Point test;
if (cel.x % 2 != 1 || cel.y % 2 != 1)
{
icons[1][1] = ICON_HILI_ERR;
error = Errors::MISC;
}
else
{
cel.x--;
cel.y--;
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 36) // planches ?
{
error = Errors::MISC; // pas de pierres !
}
test = cel;
if (error == 0 && !IsBuildBateau (test, direct))
{
error = Errors::MISC; // impossible ici !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::FREE;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
}
if (action == EV_ACTION_DJEEP)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
error = Errors::MISC;
if (
m_blupi[rank].vehicule == 2 && // en jeep ?
m_decor[cel.x / 2][cel.y / 2].objectIcon == -1 &&
m_decor[cel.x / 2][cel.y / 2].floorIcon != 80) // pas téléporteur ?
{
if (
IsFreeCelGo (GetCel (cel, +1, 0), rank) &&
IsFreeCelGo (GetCel (cel, +1, +1), rank) &&
!IsBlupiHereEx (GetCel (cel, +1, 0), rank, false) &&
!IsBlupiHereEx (GetCel (cel, +1, +1), rank, false))
{
icons[1][1] = ICON_HILI_OP; // action
icons[2][1] = ICON_HILI_OP;
icons[1][2] = ICON_HILI_OP;
icons[2][2] = ICON_HILI_OP;
error = Errors::NONE;
}
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
icons[2][1] = ICON_HILI_ERR;
icons[1][2] = ICON_HILI_ERR;
icons[2][2] = ICON_HILI_ERR;
}
}
if (action == EV_ACTION_DARMURE)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
error = Errors::MISC;
if (
m_blupi[rank].vehicule == 3 && // armure ?
!bTransport && m_decor[cel.x / 2][cel.y / 2].objectIcon == -1 &&
m_decor[cel.x / 2][cel.y / 2].floorIcon != 80) // pas téléporteur ?
{
if (
IsFreeCelGo (GetCel (cel, +1, 0), rank) &&
IsFreeCelGo (GetCel (cel, +1, +1), rank) &&
!IsBlupiHereEx (GetCel (cel, +1, 0), rank, false) &&
!IsBlupiHereEx (GetCel (cel, +1, +1), rank, false))
{
icons[1][1] = ICON_HILI_OP; // action
icons[2][1] = ICON_HILI_OP;
icons[1][2] = ICON_HILI_OP;
icons[2][2] = ICON_HILI_OP;
error = Errors::NONE;
}
}
else
{
icons[1][1] = ICON_HILI_ERR; // croix
icons[2][1] = ICON_HILI_ERR;
icons[1][2] = ICON_HILI_ERR;
icons[2][2] = ICON_HILI_ERR;
}
}
if (action == EV_ACTION_FLAG)
{
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetFloor (cel, channel, icon);
if ((icon < 33 || icon > 48) && icon != 71) // pas terre ?
{
error = Errors::MISC; // terrain pas adapté
}
GetObject (cel, channel, icon);
if (channel == CHOBJECT) // y a-t-il un objet ?
{
error = Errors::MISC; // terrain pas adapté
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::MISC;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
if (action == EV_ACTION_EXTRAIT)
{
if (!bStrong || bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 122) // mine de fer ?
{
error = Errors::MISC; // pas de mine
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::MISC;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
if (
action == EV_ACTION_FABJEEP || action == EV_ACTION_FABMINE ||
action == EV_ACTION_FABARMURE)
{
if (!bStrong || !bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
if (action == EV_ACTION_FABJEEP && m_blupi[rank].perso == 8) // disciple ?
{
error = Errors::MISC; // impossible
}
if (action == EV_ACTION_FABARMURE && m_blupi[rank].perso == 8) // disciple ?
{
error = Errors::MISC; // impossible
}
GetObject (cel, channel, icon);
if (
channel != CHOBJECT || icon != 120 || // usine ?
m_blupi[rank].takeChannel != CHOBJECT ||
m_blupi[rank].takeIcon != 123) // fer ?
{
error = Errors::MISC; // pas d'usine !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::MISC;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
if (action == EV_ACTION_FABDISC)
{
if (!bStrong || !bTransport || bVehicule)
{
error = Errors::MISC; // pas assez fort
}
GetObject (cel, channel, icon);
if (
channel != CHOBJECT || icon != 120 || // usine ?
m_blupi[rank].takeChannel != CHOBJECT ||
m_blupi[rank].takeIcon != 14) // métal ?
{
error = Errors::MISC; // pas d'usine !
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (error)
icons[x + 1][y + 1] = ICON_HILI_ERR;
else
icons[x + 1][y + 1] = ICON_HILI_OP;
}
}
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++)
{
if (IsBlupiHereEx (GetCel (cel, x, y), rank, false))
{
error = Errors::MISC;
icons[x + 1][y + 1] = ICON_HILI_ERR; // croix
}
}
}
}
return error;
}
// Indique si une cellule est ok pour une action.
// Le rang du blupi qui effectuera le travail est donnée dans rank.
Errors
CDecor::CelOkForAction (Point cel, Sint32 action, Sint32 rank)
{
Sint32 icons[4][4];
Point celOutline1, celOutline2;
return CelOkForAction (cel, action, rank, icons, celOutline1, celOutline2);
}
// Retourne le rang du nième blupi sélectionné.
Sint32
CDecor::GetHiliRankBlupi (Sint32 nb)
{
Sint32 rank;
if (m_nbBlupiHili == 0)
return -1;
if (m_nbBlupiHili == 1)
{
if (nb == 0)
return m_rankBlupiHili;
return -1;
}
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (m_blupi[rank].bExist && m_blupi[rank].bHili)
{
if (nb == 0)
return rank;
nb--;
}
}
return -1;
}
// Marque la cellule visée par la souris.
// action = 0 sélection jeu
// 1 construction d'une cellule 1x1
// 2 construction d'une cellule 2x2
void
CDecor::CelHili (Point pos, Sint32 action)
{
Sint32 x, y, i, channel, icon, rank, nb;
Point cel;
for (x = 0; x < 4; x++)
{
for (y = 0; y < 4; y++)
m_iconHili[x][y] = -1;
}
m_celOutline1.x = -1;
m_celOutline2.x = -1;
m_rankHili = -1;
if (action == 0) // sélection pendant jeu ?
{
rank = GetTargetBlupi (pos);
if (rank >= 0)
{
m_celHili = m_blupi[rank].cel;
m_rankHili = rank;
m_iconHili[1][1] = ICON_HILI_SEL;
}
else
{
m_celHili = ConvPosToCel (pos);
if (IsBlupiHere (m_celHili, false))
{
m_rankHili = m_blupiHere;
m_iconHili[1][1] = ICON_HILI_SEL;
}
else
{
if (m_nbBlupiHili > 0)
{
nb = m_nbBlupiHili;
if (nb > 16)
nb = 16;
for (i = 0; i < nb; i++)
{
x = table_multi_goal[i * 2 + 0];
y = table_multi_goal[i * 2 + 1];
cel.x = m_celHili.x + x;
cel.y = m_celHili.y + y;
rank = GetHiliRankBlupi (i);
if (IsFreeCelHili (cel, rank))
m_iconHili[1 + x][1 + y] = ICON_HILI_ANY;
else
m_iconHili[1 + x][1 + y] = ICON_HILI_ERR;
}
}
else
m_iconHili[1][1] = ICON_HILI_ERR;
m_celOutline1.x = (m_celHili.x / 2) * 2;
m_celOutline1.y = (m_celHili.y / 2) * 2;
if (
GetObject (m_celOutline1, channel, icon) && channel == CHOBJECT &&
(icon == 14 // métal ?
|| icon == 36 // planches ?
|| icon == 44 // pierres ?
|| icon == 60 // tomates ?
|| icon == 64 // oeufs ?
|| icon == 80 // bouteille ?
|| icon == 82 // fleurs ?
|| icon == 84 // fleurs ?
|| icon == 95 // fleurs ?
|| icon == 85 // dynamite ?
|| icon == 92 // poison ?
|| icon == 93 // piège ?
|| icon == 123 // fer ?
|| icon == 125)) // mine ?
{
if (m_celHili.x % 2 == 0 || m_celHili.y % 2 == 0)
m_celOutline1.x = -1;
}
m_celOutline2 = m_celOutline1;
}
}
}
if (action == 1) // construction d'une cellule 1x1 ?
{
m_celHili = ConvPosToCel (pos);
m_iconHili[1][1] = ICON_HILI_BUILD; // action
}
if (action == 2) // construction d'une cellule 2x2 ?
{
m_celHili = ConvPosToCel2 (pos);
m_iconHili[1][1] = ICON_HILI_BUILD; // action
m_iconHili[2][1] = ICON_HILI_BUILD;
m_iconHili[1][2] = ICON_HILI_BUILD;
m_iconHili[2][2] = ICON_HILI_BUILD;
}
}
// Marque la cellule visée par la souris pour un bouton donné.
void
CDecor::CelHiliButton (Point cel, Sint32 button)
{
Point celOutline1, celOutline2;
CelOkForAction (
cel, table_actions[button], m_rankBlupiHili, m_iconHili, celOutline1,
celOutline2);
if (
button == BUTTON_ABAT || button == BUTTON_ABATn || button == BUTTON_ROC ||
button == BUTTON_ROCn || button == BUTTON_WALL || button == BUTTON_TOWER ||
button == BUTTON_PALIS || button == BUTTON_BRIDGE ||
button == BUTTON_CULTIVE || button == BUTTON_DEPOSE ||
button == BUTTON_LABO || button == BUTTON_FLOWER ||
button == BUTTON_FLOWERn || button == BUTTON_DYNAMITE ||
button == BUTTON_BOAT || button == BUTTON_DJEEP ||
button == BUTTON_DARMOR || button == BUTTON_FLAG ||
button == BUTTON_EXTRAIT || button == BUTTON_FABJEEP ||
button == BUTTON_MAKEARMOR || button == BUTTON_FABMINE ||
button == BUTTON_FABDISC ||
(button >= BUTTON_BUILD1 && button <= BUTTON_BUILD6))
{
m_celHili.x = (cel.x / 2) * 2;
m_celHili.y = (cel.y / 2) * 2;
}
else
m_celHili = cel;
}
// Marque la cellule visée par la souris pour une répétition donnée.
void
CDecor::CelHiliRepeat (Sint32 list)
{
Sint32 rank, button, x, y, i;
Point cel;
for (x = 0; x < 4; x++)
{
for (y = 0; y < 4; y++)
m_iconHili[x][y] = -1;
}
if (m_nbBlupiHili != 1)
return;
rank = m_rankBlupiHili;
i = m_blupi[rank].repeatLevelHope - list;
if (i < 0 || i > m_blupi[rank].repeatLevelHope)
return;
button = m_blupi[rank].listButton[i];
if (
button == BUTTON_ABAT || button == BUTTON_ABATn || button == BUTTON_ROC ||
button == BUTTON_ROCn || button == BUTTON_WALL || button == BUTTON_TOWER ||
button == BUTTON_PALIS || button == BUTTON_BRIDGE ||
button == BUTTON_CULTIVE || button == BUTTON_DEPOSE ||
button == BUTTON_LABO || button == BUTTON_FLOWER ||
button == BUTTON_FLOWERn || button == BUTTON_DYNAMITE ||
button == BUTTON_BOAT || button == BUTTON_DJEEP ||
button == BUTTON_DARMOR || button == BUTTON_FLAG ||
button == BUTTON_EXTRAIT || button == BUTTON_FABJEEP ||
button == BUTTON_MAKEARMOR || button == BUTTON_FABMINE ||
button == BUTTON_FABDISC ||
(button >= BUTTON_BUILD1 && button <= BUTTON_BUILD6))
{
m_iconHili[1][1] = ICON_HILI_OP; // action
m_iconHili[2][1] = ICON_HILI_OP; // action
m_iconHili[1][2] = ICON_HILI_OP; // action
m_iconHili[2][2] = ICON_HILI_OP; // action
cel = m_blupi[rank].listCel[i];
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
}
else
{
m_iconHili[1][1] = ICON_HILI_OP; // action
cel = m_blupi[rank].listCel[i];
}
m_celHili = cel;
}
// Retourne l'identificateur du texte correspondant à
// l'objet ou au blupi visé par la souris.
const char *
CDecor::GetResHili (Point posMouse)
{
Sint32 icon;
// The `corner == true` values are corresponding to the objects
// positionned at the bottom/right corner of the cell.
struct object_t {
bool corner;
const char * text;
};
static const std::unordered_map<size_t, object_t> tableObject = {
{6, {false, translate ("Tree")}},
{7, {false, translate ("Tree")}},
{8, {false, translate ("Tree")}},
{9, {false, translate ("Tree")}},
{10, {false, translate ("Tree")}},
{11, {false, translate ("Tree")}},
{12, {false, translate ("Enemy rocket")}},
{14, {false, translate ("Platinium")}},
{16, {true, translate ("Armour")}},
{17, {false, translate ("Enemy construction")}},
{18, {false, translate ("Enemy construction")}},
{20, {false, translate ("Wall")}},
{21, {false, translate ("Wall")}},
{22, {false, translate ("Wall")}},
{23, {false, translate ("Wall")}},
{24, {false, translate ("Wall")}},
{25, {false, translate ("Wall")}},
{26, {false, translate ("Wall")}},
{27, {false, translate ("Protection tower")}},
{28, {false, translate ("Laboratory")}},
{29, {false, translate ("Laboratory")}},
{30, {false, translate ("Tree trunks")}},
{31, {false, translate ("Tree trunks")}},
{32, {false, translate ("Tree trunks")}},
{33, {false, translate ("Tree trunks")}},
{34, {false, translate ("Tree trunks")}},
{35, {false, translate ("Tree trunks")}},
{36, {true, translate ("Planks")}},
{37, {false, translate ("Rocks")}},
{38, {false, translate ("Rocks")}},
{39, {false, translate ("Rocks")}},
{40, {false, translate ("Rocks")}},
{41, {false, translate ("Rocks")}},
{42, {false, translate ("Rocks")}},
{43, {false, translate ("Rocks")}},
{44, {true, translate ("Stones")}},
{45, {false, translate ("Fire")}},
{46, {false, translate ("Fire")}},
{47, {false, translate ("Fire")}},
{48, {false, translate ("Fire")}},
{49, {false, translate ("Fire")}},
{50, {false, translate ("Fire")}},
{51, {false, translate ("Fire")}},
{52, {false, translate ("Fire")}},
{57, {true, translate ("Tomatoes")}},
{58, {true, translate ("Tomatoes")}},
{59, {true, translate ("Tomatoes")}},
{60, {true, translate ("Tomatoes")}},
{61, {false, translate ("Garden shed")}},
{62, {false, translate ("Garden shed")}},
{63, {true, translate ("Eggs")}},
{64, {false, translate ("Eggs")}},
{65, {false, translate ("Palisade")}},
{66, {false, translate ("Palisade")}},
{67, {false, translate ("Palisade")}},
{68, {false, translate ("Palisade")}},
{69, {false, translate ("Palisade")}},
{70, {false, translate ("Palisade")}},
{71, {false, translate ("Palisade")}},
{72, {false, translate ("Bridge")}},
{73, {false, translate ("Bridge")}},
{80, {true, translate ("Medical potion")}},
{81, {false, translate ("Flowers")}},
{82, {true, translate ("Bunch of flowers")}},
{83, {false, translate ("Flowers")}},
{84, {true, translate ("Bunch of flowers")}},
{85, {true, translate ("Dynamite")}},
{86, {true, translate ("Dynamite")}},
{87, {true, translate ("Dynamite")}},
{92, {true, translate ("Poison")}},
{93, {true, translate ("Sticky trap")}},
{94, {false, translate ("Flowers")}},
{95, {true, translate ("Bunch of flowers")}},
{96, {true, translate ("Trapped enemy")}},
{97, {true, translate ("Trapped enemy")}},
{98, {true, translate ("Trapped enemy")}},
{99, {false, translate ("Enemy construction")}},
{100, {false, translate ("Enemy construction")}},
{101, {false, translate ("Enemy construction")}},
{102, {false, translate ("Enemy construction")}},
{103, {false, translate ("Enemy construction")}},
{104, {false, translate ("Enemy construction")}},
{105, {false, translate ("Enemy construction")}},
{106, {false, translate ("Enemy construction")}},
{107, {false, translate ("Enemy construction")}},
{108, {false, translate ("Enemy construction")}},
{109, {false, translate ("Enemy construction")}},
{110, {false, translate ("Enemy construction")}},
{111, {false, translate ("Enemy construction")}},
{112, {false, translate ("Enemy construction")}},
{113, {false, translate ("Blupi's house")}},
{114, {true, translate ("Trapped enemy")}},
{115, {false, translate ("Enemy construction")}},
{116, {false, translate ("Enemy construction")}},
{117, {true, translate ("Boat")}},
{118, {true, translate ("Jeep")}},
{119, {false, translate ("Workshop")}},
{120, {false, translate ("Workshop")}},
{121, {false, translate ("Mine")}},
{122, {false, translate ("Mine")}},
{123, {true, translate ("Iron")}},
{124, {false, translate ("Flag")}},
{125, {true, translate ("Time bomb")}},
{126, {false, translate ("Mine")}},
{127, {true, translate ("Time bomb")}},
{128, {false, translate ("Enemy construction")}},
{129, {false, translate ("Enemy construction")}},
{130, {true, translate ("Trapped enemy")}},
};
static const std::unordered_map<size_t, object_t> tableFloor = {
{1, {false, translate ("Normal ground")}},
{2, {false, translate ("Bank")}},
{3, {false, translate ("Bank")}},
{4, {false, translate ("Bank")}},
{5, {false, translate ("Bank")}},
{6, {false, translate ("Bank")}},
{7, {false, translate ("Bank")}},
{8, {false, translate ("Bank")}},
{9, {false, translate ("Bank")}},
{10, {false, translate ("Bank")}},
{11, {false, translate ("Bank")}},
{12, {false, translate ("Bank")}},
{13, {false, translate ("Bank")}},
{14, {false, translate ("Water")}},
{15, {false, translate ("Paving stones")}},
{16, {false, translate ("Paving stones")}},
{17, {false, translate ("Striped paving stones")}},
{18, {false, translate ("Ice")}},
{19, {false, translate ("Burnt ground")}},
{20, {false, translate ("Inflammable ground")}},
{21, {false, translate ("Miscellaneous ground")}},
{22, {false, translate ("Miscellaneous ground")}},
{23, {false, translate ("Miscellaneous ground")}},
{24, {false, translate ("Miscellaneous ground")}},
{25, {false, translate ("Miscellaneous ground")}},
{26, {false, translate ("Miscellaneous ground")}},
{27, {false, translate ("Miscellaneous ground")}},
{28, {false, translate ("Miscellaneous ground")}},
{29, {false, translate ("Miscellaneous ground")}},
{30, {false, translate ("Miscellaneous ground")}},
{31, {false, translate ("Miscellaneous ground")}},
{32, {false, translate ("Miscellaneous ground")}},
{33, {false, translate ("Sterile ground")}},
{34, {false, translate ("Miscellaneous ground")}},
{35, {false, translate ("Miscellaneous ground")}},
{36, {false, translate ("Miscellaneous ground")}},
{37, {false, translate ("Miscellaneous ground")}},
{38, {false, translate ("Miscellaneous ground")}},
{39, {false, translate ("Miscellaneous ground")}},
{40, {false, translate ("Miscellaneous ground")}},
{41, {false, translate ("Miscellaneous ground")}},
{42, {false, translate ("Miscellaneous ground")}},
{43, {false, translate ("Miscellaneous ground")}},
{44, {false, translate ("Miscellaneous ground")}},
{45, {false, translate ("Miscellaneous ground")}},
{46, {false, translate ("Sterile ground")}},
{47, {false, translate ("Sterile ground")}},
{48, {false, translate ("Sterile ground")}},
{49, {false, translate ("Normal ground")}},
{50, {false, translate ("Normal ground")}},
{51, {false, translate ("Normal ground")}},
{52, {false, translate ("Incubator")}},
{53, {false, translate ("Incubator")}},
{54, {false, translate ("Incubator")}},
{55, {false, translate ("Incubator")}},
{56, {false, translate ("Incubator")}},
{57, {false, translate ("Normal ground")}},
{58, {false, translate ("Inflammable ground")}},
{59, {false, translate ("Bridge")}},
{60, {false, translate ("Bridge")}},
{61, {false, translate ("Bridge")}},
{62, {false, translate ("Bridge")}},
{63, {false, translate ("Bridge")}},
{64, {false, translate ("Bridge")}},
{65, {false, translate ("Enemy ground")}},
{66, {false, translate ("Miscellaneous ground")}},
{67, {false, translate ("Enemy ground")}},
{68, {false, translate ("Water")}},
{69, {false, translate ("Water")}},
{70, {false, translate ("Water")}},
{71, {false, translate ("Sterile ground")}},
{78, {false, translate ("Miscellaneous ground")}},
{79, {false, translate ("Miscellaneous ground")}},
{80, {false, translate ("Teleporter")}},
{81, {false, translate ("Teleporter")}},
{82, {false, translate ("Teleporter")}},
{83, {false, translate ("Teleporter")}},
{84, {false, translate ("Teleporter")}},
};
if (m_bHideTooltips)
return nullptr; // rien si menu présent
if (
posMouse.x < POSDRAWX || posMouse.x > POSDRAWX + DIMDRAWX ||
posMouse.y < POSDRAWY || posMouse.y > POSDRAWY + DIMDRAWY)
return nullptr;
if (m_celHili.x != -1)
{
if (m_rankHili != -1) // blupi visé ?
{
switch (m_blupi[m_rankHili].perso)
{
case 0: // blupi ?
if (m_blupi[m_rankHili].energy <= MAXENERGY / 4)
return gettext ("Tired Blupi");
if (m_blupi[m_rankHili].bMalade)
return gettext ("Sick Blupi");
return gettext ("Blupi");
case 1: // spider ?
return gettext ("Spider");
case 2: // virus ?
return gettext ("Virus");
case 3: // tracks ?
return gettext ("Bulldozer");
case 4: // robot ?
return gettext ("Master robot");
case 5: // bombe ?
return gettext ("Bouncing bomb");
case 7: // electro ?
return gettext ("Electrocutor");
case 8: // disciple ?
return gettext ("Helper robot");
}
return nullptr;
}
icon = m_decor[m_celHili.x / 2][m_celHili.y / 2].objectIcon;
if (icon != -1)
{
const auto obj = tableObject.find (icon);
if (obj != tableObject.end ())
{
if (!obj->second.corner)
return gettext (obj->second.text);
if (m_celHili.x % 2 && m_celHili.y % 2)
return gettext (obj->second.text);
}
}
icon = m_decor[m_celHili.x / 2][m_celHili.y / 2].floorIcon;
if (icon != -1)
{
const auto obj = tableFloor.find (icon);
if (obj != tableFloor.end ())
return gettext (obj->second.text);
}
}
return nullptr;
}
// Indique si le menu est présent et qu'il faut cacher
// les tooltips du décor.
void
CDecor::HideTooltips (bool bHide)
{
m_bHideTooltips = bHide;
}
// Modifie l'origine supérieure/gauche du décor.
void
CDecor::SetCorner (Point corner, bool bCenter)
{
if (bCenter)
{
corner.x -= 10;
corner.y -= 2;
}
if (corner.x < -8)
corner.x = -8;
if (corner.x > MAXCELX - 12)
corner.x = MAXCELX - 12;
if (corner.y < -2)
corner.y = -2;
if (corner.y > MAXCELY - 4)
corner.y = MAXCELY - 4;
m_celCorner = corner;
m_bGroundRedraw = true; // faudra redessiner les sols
m_celHili.x = -1;
m_textLastPos.x = -1; // tooltips plus lavable !
}
Point
CDecor::GetCorner ()
{
return m_celCorner;
}
Point
CDecor::GetHome ()
{
return m_celHome;
}
// Mémoirise une position pendant le jeu.
void
CDecor::MemoPos (Sint32 rank, bool bRecord)
{
Point pos;
pos.x = LXIMAGE / 2;
pos.y = LYIMAGE / 2;
if (rank < 0 || rank >= 4)
return;
if (bRecord)
{
m_pSound->PlayImage (SOUND_CLOSE, pos);
m_memoPos[rank] = m_celCorner;
}
else
{
if (m_memoPos[rank].x == 0 && m_memoPos[rank].y == 0)
m_pSound->PlayImage (SOUND_BOING, pos);
else
{
m_pSound->PlayImage (SOUND_GOAL, pos);
SetCorner (m_memoPos[rank], false);
}
}
}
// Gestion du temps absolu global.
void
CDecor::SetTime (Sint32 time)
{
m_time = time;
m_timeConst = time; // vraiment ?
m_timeFlipOutline = time;
}
Sint32
CDecor::GetTime ()
{
return m_time;
}
// Gestion de la musique midi.
void
CDecor::SetMusic (Sint32 music)
{
m_music = music;
}
Sint32
CDecor::GetMusic ()
{
return m_music;
}
// Gestion de la difficulté.
void
CDecor::SetSkill (Sint32 skill)
{
m_skill = skill;
}
Sint32
CDecor::GetSkill ()
{
return m_skill;
}
// Gestion de la région.
// 0 = normal
// 1 = palmier
// 2 = hiver
// 3 = sapin
void
CDecor::SetRegion (Sint32 region)
{
m_region = region;
}
Sint32
CDecor::GetRegion ()
{
return m_region;
}
// Gestion des infos.
void
CDecor::SetInfoMode (bool bInfo)
{
m_bInfo = bInfo;
m_bGroundRedraw = true; // faudra redessiner les sols
}
bool
CDecor::GetInfoMode ()
{
return m_bInfo;
}
void
CDecor::SetInfoHeight (Sint32 height)
{
m_infoHeight = height;
m_bGroundRedraw = true; // faudra redessiner les sols
}
Sint32
CDecor::GetInfoHeight ()
{
if (m_bInfo)
return m_infoHeight;
else
return 0;
}
// Retourne le pointeur à la liste des boutons existants.
char *
CDecor::GetButtonExist ()
{
return m_buttonExist;
}
// Ouvre le buffer pour le undo pendant la construction.
void
CDecor::UndoOpen ()
{
if (m_pUndoDecor == nullptr)
m_pUndoDecor =
(Cellule *) malloc (sizeof (Cellule) * (MAXCELX / 2) * (MAXCELY / 2));
}
// Ferme le buffer pour le undo pendant la construction.
void
CDecor::UndoClose ()
{
if (m_pUndoDecor != nullptr)
{
free (m_pUndoDecor);
m_pUndoDecor = nullptr;
}
}
// Copie le décor dans le buffer pour le undo.
void
CDecor::UndoCopy ()
{
UndoOpen (); // ouvre le buffer du undo si nécessaire
if (m_pUndoDecor != nullptr)
memcpy (
m_pUndoDecor, &m_decor, sizeof (Cellule) * (MAXCELX / 2) * (MAXCELY / 2));
}
// Revient en arrière pour tout le décor.
void
CDecor::UndoBack ()
{
if (m_pUndoDecor != nullptr)
{
memcpy (
&m_decor, m_pUndoDecor, sizeof (Cellule) * (MAXCELX / 2) * (MAXCELY / 2));
UndoClose ();
m_bGroundRedraw = true;
}
}
// Indique s'il est possible d'effectuer un undo.
bool
CDecor::IsUndo ()
{
return (m_pUndoDecor != nullptr);
}