1
0
mirror of https://github.com/blupi-games/planetblupi synced 2024-12-30 10:15:36 +01:00
planetblupi/src/decblupi.cxx
Mathieu Schroeter 3e0bce333e Cosmetic
2017-08-06 21:27:06 +02:00

4639 lines
117 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 <unordered_map>
#include "action.h"
#include "decgoal.h"
#include "decor.h"
#include "def.h"
#include "gettext.h"
#include "misc.h"
// Cette table donne l'action à effectuer pour un bouton
// enfoncé.
const Sint16 table_actions[] = {
WM_ACTION_GO, WM_ACTION_STOP, WM_ACTION_MANGE, WM_ACTION_CARRY,
WM_ACTION_DEPOSE, WM_ACTION_ABAT1, WM_ACTION_ROC1, WM_ACTION_CULTIVE,
WM_ACTION_BUILD1, WM_ACTION_BUILD2, WM_ACTION_BUILD3, WM_ACTION_BUILD4,
WM_ACTION_BUILD5, WM_ACTION_BUILD6, WM_ACTION_MUR, WM_ACTION_PALIS,
WM_ACTION_ABAT1, WM_ACTION_ROC1, WM_ACTION_PONTE, WM_ACTION_TOUR,
WM_ACTION_BOIT, WM_ACTION_LABO, WM_ACTION_FLEUR1, WM_ACTION_FLEUR1,
WM_ACTION_DYNAMITE, WM_ACTION_BATEAUE, WM_ACTION_DJEEP, WM_ACTION_DRAPEAU,
WM_ACTION_EXTRAIT, WM_ACTION_FABJEEP, WM_ACTION_FABMINE, WM_ACTION_FABDISC,
WM_ACTION_REPEAT, WM_ACTION_DARMURE, WM_ACTION_FABARMURE,
};
// Supprime tous les blupi.
void CDecor::BlupiFlush ()
{
Sint32 i;
memset (m_blupi, 0, sizeof (Blupi) * MAXBLUPI);
for (i = 0; i < MAXBLUPI; i++)
m_blupi[i].bExist = false;
}
// Crée un nouveau blupi, et retourne son rang.
Sint32 CDecor::BlupiCreate (
POINT cel, Sint32 action, Sint32 direct, Sint32 perso, Sint32 energy)
{
Sint32 rank;
if (
perso == 0 && action == ACTION_STOP && // blupi ?
energy <= MAXENERGY / 4)
action = ACTION_STOPf;
if (perso == 1 && action == ACTION_STOP) // araignée ?
action = ACTION_A_STOP;
if (perso == 2 && action == ACTION_STOP) // virus ?
action = ACTION_V_STOP;
if (perso == 3 && action == ACTION_STOP) // tracks ?
action = ACTION_T_STOP;
if (perso == 4 && action == ACTION_STOP) // robot ?
action = ACTION_R_STOP;
if (perso == 5 && action == ACTION_STOP) // bombe ?
action = ACTION_B_STOP;
if (perso == 7 && action == ACTION_STOP) // électro ?
action = ACTION_E_STOP;
if (perso == 8 && action == ACTION_STOP) // disciple ?
action = ACTION_D_STOP;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist && m_blupi[rank].cel.x == cel.x &&
m_blupi[rank].cel.y == cel.y)
{
m_blupi[rank].aDirect = ((m_blupi[rank].aDirect / 16 + 1) % 8) * 16;
m_blupi[rank].sDirect = m_blupi[rank].aDirect;
m_blupi[rank].perso = perso;
m_blupi[rank].energy = energy;
m_blupi[rank].action = action;
BlupiActualise (rank);
return rank;
}
}
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (!m_blupi[rank].bExist)
{
m_blupi[rank].bExist = true;
m_blupi[rank].bHili = false;
m_blupi[rank].perso = perso;
m_blupi[rank].energy = energy;
m_blupi[rank].goalAction = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].goalCel.y = -1;
m_blupi[rank].cel = cel;
m_blupi[rank].fix = cel;
m_blupi[rank].action = action;
m_blupi[rank].interrupt = 1;
m_blupi[rank].aDirect = direct;
m_blupi[rank].sDirect = direct;
m_blupi[rank].phase = 0;
m_blupi[rank].step = rank * 13; // un peu de hazard !
m_blupi[rank].channel = -1;
m_blupi[rank].icon = -1;
m_blupi[rank].lastIcon = -1;
m_blupi[rank].pos.x = 0;
m_blupi[rank].pos.y = 0;
m_blupi[rank].posZ = 0;
m_blupi[rank].takeChannel = -1;
m_blupi[rank].passCel.x = -1;
m_blupi[rank].jaugePhase = -1;
m_blupi[rank].jaugeMax = -1;
m_blupi[rank].stop = 0;
m_blupi[rank].bArrow = false;
m_blupi[rank].bRepeat = false;
m_blupi[rank].bMalade = false;
m_blupi[rank].bCache = false;
m_blupi[rank].vehicule = 0;
m_blupi[rank].busyCount = 0;
m_blupi[rank].busyDelay = 0;
m_blupi[rank].clicCount = 0;
m_blupi[rank].clicDelay = 0;
ListFlush (rank);
FlushUsed (rank);
BlupiDestCel (rank);
BlupiPushFog (rank);
BlupiActualise (rank);
return rank;
}
}
return -1;
}
// Supprime un blupi existant.
// Si perso == -1, supprime n'importe quel personnage ici.
// Si perso >= 0, supprime seulement ce personnage.
bool CDecor::BlupiDelete (POINT cel, Sint32 perso)
{
Sint32 rank;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist && m_blupi[rank].cel.x == cel.x &&
m_blupi[rank].cel.y == cel.y &&
(perso == -1 || m_blupi[rank].perso == perso))
{
m_blupi[rank].bExist = false;
if (!m_bBuild) // phase de jeu ?
{
if (perso == 6) // détonnateur invisible ?
{
MoveFinish (rank); // stoppe décompte à rebourd
}
if (m_nbBlupiHili > 0 && m_rankBlupiHili == rank) // est-ce le blupi
// sélectionné ?
{
m_nbBlupiHili = 0;
m_rankBlupiHili = -1;
}
}
return true;
}
}
return false;
}
// Supprime un blupi existant.
void CDecor::BlupiDelete (Sint32 rank)
{
m_blupi[rank].bExist = false;
if (
!m_bBuild && // phase de jeu ?
m_nbBlupiHili > 0 &&
m_rankBlupiHili == rank) // est-ce le blupi sélectionné ?
{
m_nbBlupiHili = 0;
m_rankBlupiHili = -1;
}
}
// Supprime tout dans un périmètre donné suite à une explosion.
// type=0 -> explosion
// type=1 -> électro
void CDecor::BlupiKill (Sint32 exRank, POINT cel, Sint32 type)
{
Sint32 rank, action, x, y, icon;
for (rank = 0; rank < MAXBLUPI; rank++)
{
// Supprime sans condition les blupi placés
// dans la cellule où a lieu l'explosion.
if (
rank != exRank && m_blupi[rank].bExist &&
m_blupi[rank].vehicule != 3 && // pas armure ?
!m_bInvincible && m_blupi[rank].cel.x >= cel.x &&
m_blupi[rank].cel.x <= cel.x + 1 && m_blupi[rank].cel.y >= cel.y &&
m_blupi[rank].cel.y <= cel.y + 1)
{
GoalUnwork (rank);
if (type == 0) // explosion ?
{
m_blupi[rank].bExist = false; // mort instantannée
}
if (type == 1) // électro ?
{
x = m_blupi[rank].cel.x;
y = m_blupi[rank].cel.y;
icon = m_decor[x / 2][y / 2].objectIcon;
if (
m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 0 && // à pied ?
!m_bInvincible && icon != 113 && // maison ?
icon != 28 && icon != 29 && // laboratoire ?
icon != 119 && icon != 120 && // usine ?
icon != 121 && icon != 122) // mine de fer ?
{
if (m_blupi[rank].bMalade)
action = WM_ACTION_ELECTROm;
else
action = WM_ACTION_ELECTRO;
GoalStart (rank, action, m_blupi[rank].cel);
//? BlupiChangeAction(rank, ACTION_ELECTRO);
}
}
}
// Supprime les blupi placés une case autour de la
// cellule où a lieu l'explosion, seulement s'ils
// ne sont pas cachés (pas dans un batiment).
if (
type == 0 && rank != exRank && m_blupi[rank].bExist &&
m_blupi[rank].vehicule != 3 && // pas armure ?
!m_bInvincible && !m_blupi[rank].bCache && // pas dans un batiment ?
m_blupi[rank].cel.x >= cel.x - 1 && m_blupi[rank].cel.x <= cel.x + 2 &&
m_blupi[rank].cel.y >= cel.y - 1 && m_blupi[rank].cel.y <= cel.y + 2)
{
GoalUnwork (rank);
m_blupi[rank].bExist = false;
}
}
}
// Test si un blupi existe.
bool CDecor::BlupiIfExist (Sint32 rank)
{
return !!m_blupi[rank].bExist;
}
// Triche pour tous les blupi.
// #1 -> (POWER) redonne l'énergie maximale
// #2 -> (LONESOME) tue toutes les araignées/virus/etc.
void CDecor::BlupiCheat (Sint32 cheat)
{
Sint32 rank;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (cheat == 1) // power ?
{
if (m_blupi[rank].bExist && m_blupi[rank].perso == 0)
{
m_blupi[rank].energy = MAXENERGY;
m_blupi[rank].bMalade = false;
}
}
if (cheat == 2) // lonesome ?
{
if (
m_blupi[rank].bExist && m_blupi[rank].perso != 0 &&
m_blupi[rank].perso != 8) // araignée/virus/etc. ?
m_blupi[rank].bExist = false;
}
}
}
// Actualise un blupi pour pouvoir le dessiner dans son état.
void CDecor::BlupiActualise (Sint32 rank)
{
Sint16 sound;
Action (
m_blupi[rank].action, m_blupi[rank].aDirect, m_blupi[rank].phase,
m_blupi[rank].step, m_blupi[rank].channel, m_blupi[rank].icon,
m_blupi[rank].pos, m_blupi[rank].posZ, sound);
BlupiAdaptIcon (rank);
m_blupi[rank].lastIcon = -1;
m_blupi[rank].phase = 0;
m_blupi[rank].pos.x = 0;
m_blupi[rank].pos.y = 0;
m_blupi[rank].posZ = 0;
}
// Adapte une icône.
void CDecor::BlupiAdaptIcon (Sint32 rank)
{
Sint32 direct;
if (m_blupi[rank].icon == -1)
return;
if (m_blupi[rank].bMalade) // malade ?
{
if (m_blupi[rank].icon >= 69 && m_blupi[rank].icon <= 92)
{
m_blupi[rank].icon += 100; // 169..192 (tout vert)
}
else if (m_blupi[rank].icon == 270) // écrasé ?
m_blupi[rank].icon = 271;
else if (
m_blupi[rank].icon < 318 || // pas télétransporté ?
m_blupi[rank].icon > 321)
{
direct = GetIconDirect (m_blupi[rank].icon);
if (direct < 0)
{
m_blupi[rank].icon = 169; // debout direction est !
}
else
m_blupi[rank].icon = 169 + 3 * (direct / 16);
}
}
if (m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 1) // en bateau ?
{
direct = GetIconDirect (m_blupi[rank].icon);
if (direct < 0)
{
m_blupi[rank].icon = 234; // bateau direction est !
}
else
m_blupi[rank].icon = 234 + (direct / (16 / 2));
}
if (m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 2) // en jeep ?
{
direct = GetIconDirect (m_blupi[rank].icon);
if (direct < 0)
{
m_blupi[rank].icon = 250; // bateau direction est !
}
else
m_blupi[rank].icon = 250 + (direct / (16 / 2));
}
if (m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 3) // armure ?
{
if (m_blupi[rank].icon < 322 || m_blupi[rank].icon > 347)
{
if (
m_blupi[rank].icon == 106 || // élan pour saut ?
m_blupi[rank].icon == 194) // mèche ?
m_blupi[rank].icon = 347;
else
{
direct = GetIconDirect (m_blupi[rank].icon);
if (direct < 0)
{
m_blupi[rank].icon = 322; // armure direction est !
}
else
m_blupi[rank].icon = 322 + 3 * (direct / 16);
}
}
}
if (m_blupi[rank].perso == 8) // disciple ?
{
direct = GetIconDirect (m_blupi[rank].icon);
if (direct < 0)
{
m_blupi[rank].icon = 290; // disciple direction est !
}
else
m_blupi[rank].icon = 290 + (direct / (16 / 2));
}
}
// Fait entendre un son pour un blupi.
// Si bStop=true, on stoppe le son précédent associé
// à ce blupi (rank), si nécessaire.
void CDecor::BlupiSound (Sint32 rank, Sint32 sound, POINT pos, bool bStop)
{
Sint32 newSound;
if (rank == -1)
rank = m_rankBlupiHili;
if (rank != -1 && m_blupi[rank].perso == 8) // disciple ?
{
if (
sound == SOUND_HOP || sound == SOUND_BRULE || sound == SOUND_TCHAO ||
sound == SOUND_FLEUR || sound == SOUND_ARROSE)
newSound = -1;
else
newSound = sound;
if (
sound == SOUND_BOING || sound == SOUND_BOING1 || sound == SOUND_BOING2 ||
sound == SOUND_BOING3)
newSound = SOUND_D_BOING;
if (
sound == SOUND_GO1 || sound == SOUND_GO2 || sound == SOUND_GO3 ||
sound == SOUND_GO4 || sound == SOUND_GO5 || sound == SOUND_GO6)
newSound = SOUND_D_GO;
if (
sound == SOUND_OK1 || sound == SOUND_OK2 || sound == SOUND_OK3 ||
sound == SOUND_OK4 || sound == SOUND_OK5 || sound == SOUND_OK6 ||
sound == SOUND_OK1f || sound == SOUND_OK2f || sound == SOUND_OK3f ||
sound == SOUND_OK1e || sound == SOUND_OK2e || sound == SOUND_OK3e)
newSound = SOUND_D_OK;
if (
sound == SOUND_TERM1 || sound == SOUND_TERM2 || sound == SOUND_TERM3 ||
sound == SOUND_TERM4 || sound == SOUND_TERM5 || sound == SOUND_TERM6)
newSound = SOUND_D_TERM;
if (newSound == -1)
return;
sound = newSound;
}
if (bStop)
m_pSound->PlayImage (sound, pos, rank);
else
m_pSound->PlayImage (sound, pos);
}
// Sons associés à des actions.
// clang-format off
static const Sint16 tableSound[] = {
ACTION_BRULE, SOUND_BRULE,
ACTION_TCHAO, SOUND_TCHAO,
ACTION_MANGE, SOUND_MANGE,
ACTION_BOIT, SOUND_BOIT,
ACTION_GLISSE, SOUND_GLISSE,
ACTION_R_CHARGE, SOUND_R_CHARGE,
-1
};
// clang-format on
// Effectue quelques initialisations pour une nouvelle action.
void CDecor::BlupiInitAction (Sint32 rank, Sint32 action, Sint32 direct)
{
const auto * pTable = tableSound;
POINT pos;
Sint32 rand;
while (*pTable != -1)
{
if (pTable[0] == action)
{
pos = ConvCelToPos (m_blupi[rank].cel);
BlupiSound (rank, pTable[1], pos);
break;
}
pTable += 2;
}
m_blupi[rank].action = action;
if (m_blupi[rank].perso == 0) // blupi ?
{
if (m_blupi[rank].vehicule == 1) // en bateau ?
{
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_STOPb;
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_MARCHEb;
}
if (m_blupi[rank].vehicule == 2) // en jeep ?
{
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_STOPj;
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_MARCHEj;
}
if (m_blupi[rank].vehicule == 3) // armure ?
{
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_STOPa;
if (m_blupi[rank].action == ACTION_MARCHE)
{
m_blupi[rank].action = ACTION_MARCHEa;
m_blupi[rank].step = (m_blupi[rank].step / 2) * 2;
}
}
if (m_blupi[rank].energy <= MAXENERGY / 4) // peu de forces ?
{
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_STOPf;
if (m_blupi[rank].action == ACTION_MARCHE)
{
m_blupi[rank].action = ACTION_MARCHEf;
m_blupi[rank].step = (m_blupi[rank].step / 2) * 2;
}
}
if (
m_blupi[rank].action == ACTION_STOP &&
m_blupi[rank].goalAction == 0) // à pied ?
{
rand = Random (0, 400);
if (rand >= 10 && rand <= 15 && m_blupi[rank].takeChannel == -1)
{
m_blupi[rank].action = ACTION_MISC1; // épaules
m_blupi[rank].step = 0;
}
if (rand >= 20 && rand <= 23)
{
m_blupi[rank].action = ACTION_MISC2; // grat-grat
m_blupi[rank].step = 0;
}
if (rand == 30 && m_blupi[rank].takeChannel == -1)
{
m_blupi[rank].action = ACTION_MISC3; // yoyo
m_blupi[rank].step = 0;
}
if (rand >= 40 && rand <= 45)
{
m_blupi[rank].action = ACTION_MISC4; // ferme les yeux
m_blupi[rank].step = 0;
}
if (rand == 50 && m_blupi[rank].takeChannel == -1)
{
m_blupi[rank].action = ACTION_MISC5; // ohé
m_blupi[rank].step = 0;
}
if (rand == 60)
{
m_blupi[rank].action = ACTION_MISC6; // diabolo
m_blupi[rank].step = 0;
}
}
if (m_blupi[rank].action == ACTION_STOPf && m_blupi[rank].goalAction == 0)
{
rand = Random (0, 100);
if (
rand == 10 && // propabilité 1/100
m_blupi[rank].takeChannel == -1)
{
m_blupi[rank].action = ACTION_MISC1f;
m_blupi[rank].step = 0;
}
}
if (direct != -1)
m_blupi[rank].sDirect = direct;
if (
m_blupi[rank].action == ACTION_BUILD ||
m_blupi[rank].action == ACTION_BUILDBREF ||
m_blupi[rank].action == ACTION_BUILDSEC ||
m_blupi[rank].action == ACTION_BUILDSOURD ||
m_blupi[rank].action == ACTION_BUILDPIERRE ||
m_blupi[rank].action == ACTION_PIOCHE ||
m_blupi[rank].action == ACTION_PIOCHEPIERRE ||
m_blupi[rank].action == ACTION_PIOCHESOURD ||
m_blupi[rank].action == ACTION_ARROSE ||
m_blupi[rank].action == ACTION_BECHE ||
m_blupi[rank].action == ACTION_SCIE ||
m_blupi[rank].action == ACTION_TAKE ||
m_blupi[rank].action == ACTION_DEPOSE ||
m_blupi[rank].action == ACTION_BRULE ||
m_blupi[rank].action == ACTION_TCHAO ||
m_blupi[rank].action == ACTION_GRILLE1 ||
m_blupi[rank].action == ACTION_GRILLE2 ||
m_blupi[rank].action == ACTION_GRILLE3 ||
m_blupi[rank].action == ACTION_ELECTRO ||
m_blupi[rank].action == ACTION_MANGE ||
m_blupi[rank].action == ACTION_BOIT ||
m_blupi[rank].action == ACTION_NAISSANCE ||
m_blupi[rank].action == ACTION_SAUTE1 ||
m_blupi[rank].action == ACTION_SAUTE2 ||
m_blupi[rank].action == ACTION_SAUTE3 ||
m_blupi[rank].action == ACTION_SAUTE4 ||
m_blupi[rank].action == ACTION_SAUTE5 ||
//? m_blupi[rank].action == ACTION_GLISSE ||
m_blupi[rank].action == ACTION_PONT ||
m_blupi[rank].action == ACTION_MECHE ||
m_blupi[rank].action == ACTION_A_GRILLE ||
m_blupi[rank].action == ACTION_V_GRILLE ||
m_blupi[rank].action == ACTION_T_ECRASE ||
m_blupi[rank].action == ACTION_R_MARCHE ||
m_blupi[rank].action == ACTION_R_APLAT ||
m_blupi[rank].action == ACTION_R_BUILD ||
m_blupi[rank].action == ACTION_R_CHARGE ||
m_blupi[rank].action == ACTION_B_MARCHE ||
m_blupi[rank].action == ACTION_E_MARCHE ||
m_blupi[rank].action == ACTION_MARCHEb ||
m_blupi[rank].action == ACTION_MARCHEj ||
m_blupi[rank].action == ACTION_TELEPORTE1 ||
m_blupi[rank].action == ACTION_TELEPORTE2 ||
m_blupi[rank].action == ACTION_TELEPORTE3 ||
m_blupi[rank].action == ACTION_ARMUREOPEN ||
m_blupi[rank].action == ACTION_ARMURECLOSE)
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 1) // araignée ?
{
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_A_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
{
m_blupi[rank].action = ACTION_A_STOP;
m_blupi[rank].sDirect = Random (0, 7) * 16;
}
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 2) // virus ?
{
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_V_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_V_STOP;
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 3) // tracks ?
{
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_T_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_T_STOP;
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 4) // robot ?
{
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_R_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_R_STOP;
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 5) // bombe ?
{
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_B_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_B_STOP;
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 7) // électro ?
{
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_E_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_E_STOP;
m_blupi[rank].step = 0;
}
if (m_blupi[rank].perso == 8) // disciple ?
{
if (direct != -1)
m_blupi[rank].sDirect = direct;
if (m_blupi[rank].action == ACTION_MARCHE)
m_blupi[rank].action = ACTION_D_MARCHE;
if (m_blupi[rank].action == ACTION_STOP)
m_blupi[rank].action = ACTION_D_STOP;
if (m_blupi[rank].action == ACTION_PIOCHE)
m_blupi[rank].action = ACTION_D_PIOCHE;
if (m_blupi[rank].action == ACTION_BUILD)
m_blupi[rank].action = ACTION_D_BUILD;
if (m_blupi[rank].action == ACTION_SCIE)
m_blupi[rank].action = ACTION_D_SCIE;
if (m_blupi[rank].action == ACTION_TCHAO)
m_blupi[rank].action = ACTION_D_TCHAO;
if (m_blupi[rank].action == ACTION_CUEILLE1)
m_blupi[rank].action = ACTION_D_CUEILLE1;
if (m_blupi[rank].action == ACTION_CUEILLE2)
m_blupi[rank].action = ACTION_D_CUEILLE2;
if (m_blupi[rank].action == ACTION_MECHE)
m_blupi[rank].action = ACTION_D_MECHE;
if (m_blupi[rank].action == ACTION_ARROSE)
m_blupi[rank].action = ACTION_D_ARROSE;
if (m_blupi[rank].action == ACTION_BECHE)
m_blupi[rank].action = ACTION_D_BECHE;
m_blupi[rank].step = 0;
}
}
// Change l'action de blupi.
void CDecor::BlupiChangeAction (Sint32 rank, Sint32 action, Sint32 direct)
{
if (rank < 0)
return;
BlupiInitAction (rank, action, direct);
BlupiDestCel (rank);
m_blupi[rank].phase = 0;
m_blupi[rank].pos.x = 0;
m_blupi[rank].pos.y = 0;
BlupiNextAction (rank);
}
// Vide la liste des actions.
void CDecor::ListFlush (Sint32 rank)
{
Sint32 i;
for (i = 0; i < MAXLIST; i++)
m_blupi[rank].listButton[i] = -1;
m_blupi[rank].repeatLevelHope = -1;
m_blupi[rank].repeatLevel = -1;
}
// Retourne le paramètre associé à une action.
Sint32 CDecor::ListGetParam (Sint32 rank, Sint32 button, POINT cel)
{
Sint32 icon;
if (button == BUTTON_CARRY || button == BUTTON_FLEUR)
return m_decor[cel.x / 2][cel.y / 2].objectIcon;
if (button == BUTTON_DEPOSE)
return m_blupi[rank].takeIcon;
if (button == BUTTON_GO && cel.x % 2 == 1 && cel.y % 2 == 1)
{
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
if (
icon == 117 || // bateau ?
icon == 118) // voiture ?
return icon;
}
return -1;
}
// Ajoute une action dans la liste.
bool CDecor::ListPut (Sint32 rank, Sint32 button, POINT cel, POINT cMem)
{
Sint32 i, last;
if (button == BUTTON_REPEAT || button == BUTTON_GO)
return true;
// Mémorise "mange" seulement après un "cultive".
if (button == BUTTON_MANGE && m_blupi[rank].listButton[0] != BUTTON_CULTIVE)
return true;
// Si prend/dépose à la suite au même endroit,
// il est inutile de mémoriser !
last = m_blupi[rank].listButton[0];
if (
(button == BUTTON_CARRY && last == BUTTON_DEPOSE) ||
(button == BUTTON_DEPOSE && last == BUTTON_CARRY))
{
if (
cel.x / 2 == m_blupi[rank].listCel[0].x / 2 &&
cel.y / 2 == m_blupi[rank].listCel[0].y / 2)
{
ListRemove (rank);
return true;
}
}
for (i = MAXLIST - 1; i > 0; i--)
{
m_blupi[rank].listButton[i] = m_blupi[rank].listButton[i - 1];
m_blupi[rank].listCel[i] = m_blupi[rank].listCel[i - 1];
m_blupi[rank].listParam[i] = m_blupi[rank].listParam[i - 1];
}
m_blupi[rank].listButton[0] = button;
m_blupi[rank].listCel[0] = cMem;
m_blupi[rank].listParam[0] = ListGetParam (rank, button, cel);
return true;
}
// Enlève la dernière action ajoutée dans la liste.
void CDecor::ListRemove (Sint32 rank)
{
Sint32 i;
if (m_blupi[rank].listButton[0] == BUTTON_CULTIVE)
return;
for (i = 0; i < MAXLIST - 1; i++)
{
m_blupi[rank].listButton[i] = m_blupi[rank].listButton[i + 1];
m_blupi[rank].listCel[i] = m_blupi[rank].listCel[i + 1];
m_blupi[rank].listParam[i] = m_blupi[rank].listParam[i + 1];
}
m_blupi[rank].listButton[MAXLIST - 1] = -1;
}
// Cherche une action à répéter dans la liste.
// Retourne la profondeur de la répétition.
// Retourne -1 si aucune répétiton n'est possible.
Sint32 CDecor::ListSearch (
Sint32 rank, Sint32 button, POINT cel, const char *& textForButton)
{
Sint32 i, j, param, nb;
static const char * errors[] = {
/* 0 */ translate ("1: Grow tomatoes\n2: Eat"),
/* 1 */ translate ("1: Make a bunch\n2: Transform"),
/* 2 */ translate ("1: Take\n2: Transform"),
/* 3 */ translate ("1: Extract iron\n2: Make a bomb"),
/* 4 */ translate ("1: Extract iron\n2: Make a Jeep"),
/* 5 */ translate ("1: Extract iron\n2: Make an armour"),
/* 6 */ translate ("1: Cut down a tree \n2: Make a palisade"),
/* 7 */ translate ("1: Take\n2: Build palisade"),
/* 8 */ translate ("1: Cut down a tree \n2: Build a bridge"),
/* 9 */ translate ("1: Take\n2: Build a bridge"),
/* 10 */ translate ("1: Cut down a tree \n2: Make a boat"),
/* 11 */ translate ("1: Take\n2: Make a boat"),
};
static Sint32 table_series[] = {
0, // errors
2, BUTTON_CULTIVE, BUTTON_MANGE,
1, // errors
4, BUTTON_FLEUR, BUTTON_CARRY, BUTTON_LABO, BUTTON_DEPOSE,
2, // errors
3, BUTTON_CARRY, BUTTON_LABO, BUTTON_DEPOSE,
3, // errors
3, BUTTON_EXTRAIT, BUTTON_FABMINE, BUTTON_DEPOSE,
4, // errors
3, BUTTON_EXTRAIT, BUTTON_FABJEEP, BUTTON_DJEEP,
5, // errors
3, BUTTON_EXTRAIT, BUTTON_FABARMURE, BUTTON_DARMURE,
6, // errors
4, BUTTON_ABAT, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_PALIS,
7, // errors
3, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_PALIS,
8, // errors
4, BUTTON_ABAT, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_PONT,
9, // errors
3, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_PONT,
10, // errors
4, BUTTON_ABAT, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_BATEAU,
11, // errors
3, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_BATEAU,
-1,
};
param = ListGetParam (rank, button, cel);
i = 0;
while (table_series[i] != -1)
{
nb = table_series[i + 1];
if (
button == m_blupi[rank].listButton[nb - 1] &&
param == m_blupi[rank].listParam[nb - 1] &&
cel.x >= m_blupi[rank].listCel[nb - 1].x - 50 &&
cel.x <= m_blupi[rank].listCel[nb - 1].x + 50 &&
cel.y >= m_blupi[rank].listCel[nb - 1].y - 50 &&
cel.y <= m_blupi[rank].listCel[nb - 1].y + 50)
{
for (j = 0; j < nb; j++)
{
if (table_series[i + 2 + j] != m_blupi[rank].listButton[nb - 1 - j])
goto next;
}
textForButton = gettext (errors[table_series[i]]);
return nb - 1;
}
next:
i += nb + 2;
}
#if 0
for (i = 0 ; i < MAXLIST ; i++)
{
if (button == m_blupi[rank].listButton[i] &&
param == m_blupi[rank].listParam[i] &&
cel.x >= m_blupi[rank].listCel[i].x - 50 &&
cel.x <= m_blupi[rank].listCel[i].x + 50 &&
cel.y >= m_blupi[rank].listCel[i].y - 50 &&
cel.y <= m_blupi[rank].listCel[i].y + 50)
return i;
}
#endif
return -1;
}
// Ajuste une action à répéter.
bool CDecor::RepeatAdjust (
Sint32 rank, Sint32 button, POINT & cel, POINT & cMem, Sint32 param,
Sint32 list)
{
Sint32 i, channel, icon, icon1, icon2, flags;
POINT test;
static Sint32 table_object[] = {
BUTTON_ABAT,
CHOBJECT,
6,
11,
BUTTON_ROC,
CHOBJECT,
37,
43,
BUTTON_MANGE,
CHOBJECT,
60,
60,
BUTTON_PALIS,
CHOBJECT,
36,
36,
BUTTON_BATEAU,
CHOBJECT,
36,
36,
BUTTON_DEPOSE,
-1,
-1,
-1,
BUTTON_DJEEP,
-1,
-1,
-1,
BUTTON_DARMURE,
-1,
-1,
-1,
0,
};
static Sint32 table_mur[] = {
+2, 0, // 1<<0
0, +2, // 1<<1
-2, 0, // 1<<2
0, -2, // 1<<3
};
if (
button == BUTTON_DEPOSE && // dépose pour une palissade ?
list > 0 && m_blupi[rank].listButton[list - 1] == BUTTON_PALIS)
{
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
flags = 0;
if (icon == 65)
flags = (1 << 0) | (1 << 2);
if (icon == 66)
flags = (1 << 1) | (1 << 3);
if (icon == 67)
flags = (1 << 0) | (1 << 1);
if (icon == 68)
flags = (1 << 1) | (1 << 2);
if (icon == 69)
flags = (1 << 2) | (1 << 3);
if (icon == 70)
flags = (1 << 0) | (1 << 3);
if (icon == 71)
{
for (i = 0; i < 4; i++)
{
test.x = cel.x + table_mur[i * 2 + 0];
test.y = cel.y + table_mur[i * 2 + 1];
if (
IsValid (test) &&
m_decor[test.x / 2][test.y / 2].floorIcon == 15 && // dalle grise ?
CelOkForAction (test, WM_ACTION_DEPOSE, rank) == 0)
{
cel = test;
cMem = test;
goto ok;
}
}
flags = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);
}
if (flags == 0)
{
if (CelOkForAction (cel, WM_ACTION_DEPOSE, rank) == 0)
goto ok;
}
for (i = 0; i < 4; i++)
{
if (flags & (1 << i))
{
test.x = cel.x + table_mur[i * 2 + 0];
test.y = cel.y + table_mur[i * 2 + 1];
if (CelOkForAction (test, WM_ACTION_DEPOSE, rank) == 0)
{
cel = test;
cMem = test;
goto ok;
}
}
}
return false;
}
if (
button == BUTTON_DEPOSE && // dépose pour un bateau ?
list > 0 && m_blupi[rank].listButton[list - 1] == BUTTON_BATEAU)
{
if (SearchOtherBateau (rank, cel, 100, test, icon))
{
cel = test;
cMem = test;
goto ok;
}
return false;
}
//? if ( button == BUTTON_MANGE )
//? {
//? cel = m_blupi[rank].cel; // cherche là où est blupi !
//? }
i = 0;
channel = -2;
icon1 = -1;
icon2 = -1;
while (table_object[i] != 0)
{
if (button == table_object[i])
{
channel = table_object[i + 1];
icon1 = table_object[i + 2];
icon2 = table_object[i + 3];
break;
}
i += 4;
}
if (button == BUTTON_CARRY || button == BUTTON_FLEUR)
{
channel = CHOBJECT;
icon1 = param;
icon2 = param;
}
if (
button == BUTTON_GO && // va en bateau/jeep ?
param != -1)
{
channel = CHOBJECT;
icon1 = param;
icon2 = param;
}
if (channel != -2)
{
if (!SearchOtherObject (
rank, cel, table_actions[button], 50 * 2, channel, icon1, icon2, -1,
-1, cel, icon1))
return false;
}
if (button == BUTTON_PALIS)
cMem = cel;
ok:
if (cel.x % 2 == 0)
cel.x++;
if (cel.y % 2 == 0)
cel.y++; // sur l'objet
m_blupi[rank].interrupt = 1;
return true;
}
// Démarre une action.
void CDecor::GoalStart (Sint32 rank, Sint32 action, POINT cel)
{
m_blupi[rank].goalHili = cel;
m_blupi[rank].goalAction = action;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].bRepeat = false;
GoalInitJauge (rank);
FlushUsed (rank);
}
// Effectue la méta opération suivante.
// Retourne false lorsque c'est fini !
bool CDecor::GoalNextPhase (Sint32 rank)
{
Sint16 * pTable;
Sint32 i, nb;
if (m_blupi[rank].goalAction == 0)
return false;
pTable = GetTableGoal (m_blupi[rank].goalAction);
if (pTable == nullptr)
{
GoalStop (rank, true);
return false;
}
for (i = 0; i < m_blupi[rank].goalPhase; i++)
{
if (*pTable == 0)
return false;
pTable += 1 + table_goal_nbop[*pTable];
}
if (*pTable == GOAL_GROUP)
{
m_blupi[rank].goalPhase++;
nb = pTable[1];
pTable += 2;
for (i = 0; i < nb; i++)
{
m_blupi[rank].goalPhase++;
if (!GoalNextOp (rank, pTable))
return false;
pTable += 1 + table_goal_nbop[*pTable];
}
}
m_blupi[rank].goalPhase++;
return GoalNextOp (rank, pTable);
}
// Initialise la jauge pour une méta opération.
void CDecor::GoalInitJauge (Sint32 rank)
{
Sint16 * pTable;
Sint32 max = 0, op;
m_blupi[rank].jaugePhase = -1;
m_blupi[rank].jaugeMax = -1;
if (m_blupi[rank].perso != 0 && m_blupi[rank].perso != 8)
return; // araignée/virus/etc. ?
if (m_blupi[rank].goalAction == 0)
return;
pTable = GetTableGoal (m_blupi[rank].goalAction);
if (pTable == nullptr)
goto term;
while (true)
{
op = *pTable;
if (op == 0 || op == GOAL_TERM)
goto term;
if (op == GOAL_ACTION && pTable[1] != ACTION_STOP)
max++;
pTable += 1 + table_goal_nbop[*pTable];
}
term:
if (max > 0)
{
m_blupi[rank].jaugePhase = 0;
m_blupi[rank].jaugeMax = max;
}
}
// Permet de passer à travers certains arbres.
void CDecor::GoalInitPassCel (Sint32 rank)
{
POINT cel;
Sint32 channel, icon;
cel.x = (m_blupi[rank].goalCel.x / 2) * 2;
cel.y = (m_blupi[rank].goalCel.y / 2) * 2;
GetObject (cel, channel, icon);
if (
channel == CHOBJECT &&
((icon >= 8 && icon <= 11) || // arbres touffus ?
(icon >= 30 && icon <= 35) || // arbres touffus sans feuilles ?
(icon >= 37 && icon <= 43) || // rochers ?
(icon == 81 || icon == 83 || icon == 94) || // fleurs ?
(icon >= 100 && icon <= 105) || // usine ?
(icon == 115 || icon == 116) || // usine ?
(icon == 17 || icon == 18) || // usine ?
(icon == 117) || // bateau ?
(icon == 118) || // jeep ?
(icon == 16))) // armure ?
m_blupi[rank].passCel = m_blupi[rank].goalCel;
else
m_blupi[rank].passCel.x = -1;
}
// Ajuste une coordonnée de cellule.
void CDecor::GoalAdjustCel (Sint32 rank, Sint32 & x, Sint32 & y)
{
if (x == -10 && y == -10)
{
if (m_blupi[rank].goalAction == WM_ACTION_PONTEL)
{
x = m_blupi[rank].fix.x + m_blupi[rank].cLoop * 2;
y = m_blupi[rank].fix.y;
return;
}
if (m_blupi[rank].goalAction == WM_ACTION_PONTOL)
{
x = m_blupi[rank].fix.x - m_blupi[rank].cLoop * 2;
y = m_blupi[rank].fix.y;
return;
}
if (m_blupi[rank].goalAction == WM_ACTION_PONTSL)
{
x = m_blupi[rank].fix.x;
y = m_blupi[rank].fix.y + m_blupi[rank].cLoop * 2;
return;
}
if (m_blupi[rank].goalAction == WM_ACTION_PONTNL)
{
x = m_blupi[rank].fix.x;
y = m_blupi[rank].fix.y - m_blupi[rank].cLoop * 2;
return;
}
}
x += m_blupi[rank].cel.x;
y += m_blupi[rank].cel.y;
}
// Liste des buts multiples.
Sint32 table_multi_goal[16 * 2] = {
0, 0, +1, 0, 0, +1, +1, +1, 0, -1, +1, -1, 0, +2, +1, +2,
-1, -1, -1, 0, -1, +1, -1, +2, +2, -1, +2, 0, +2, +1, +2, +2,
};
// Effectue une méta opération.
bool CDecor::GoalNextOp (Sint32 rank, Sint16 * pTable)
{
Sint32 op, x, y;
Sint32 action, direct, channel, icon, mchannel, micon;
Sint32 total, step, delai, first, last, first2, last2, flag, i;
Sint32 button, param;
POINT pos, cel, cMem, destCel;
bool bOK, bError = true;
pos = ConvCelToPos (m_blupi[rank].cel);
op = *pTable++;
if (op == GOAL_ACTION && *pTable != ACTION_STOP)
m_blupi[rank].jaugePhase++;
if (op == GOAL_GOHILI)
{
m_blupi[rank].goalCel.x = m_blupi[rank].goalHili.x + (*pTable++);
m_blupi[rank].goalCel.y = m_blupi[rank].goalHili.y + (*pTable++);
flag = *pTable++;
//? m_blupi[rank].passCel.x = -1;
FlushUsed (rank);
return true;
}
if (op == GOAL_GOHILI2)
{
cel.x = (m_blupi[rank].goalHili.x / 2) * 2 + (*pTable++);
cel.y = (m_blupi[rank].goalHili.y / 2) * 2 + (*pTable++);
flag = *pTable++;
if (!!flag)
{
m_blupi[rank].goalCel = cel;
GoalInitPassCel (rank);
}
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
return true;
}
if (op == GOAL_GOBLUPI)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
flag = *pTable++;
if (!!flag)
{
if (IsBlupiHereEx (cel, rank, false)) // destination occupée ?
{
m_blupi[rank].goalPhase--; // on attend ...
return true;
}
m_blupi[rank].goalCel = cel;
GoalInitPassCel (rank);
}
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
return true;
}
if (op == GOAL_TESTOBJECT)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
channel = *pTable++;
icon = *pTable++;
GetObject (cel, mchannel, micon);
if (channel != mchannel || icon != micon)
goto error;
return true;
}
if (op == GOAL_PUTFLOOR)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
channel = *pTable++;
icon = *pTable++;
if (icon == -2)
icon = m_blupi[rank].vIcon;
PutFloor (GetCel (x, y), channel, icon);
return true;
}
if (op == GOAL_PUTOBJECT)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
channel = *pTable++;
icon = *pTable++;
if (channel == -3 && icon == -3) // l'objet transporté ?
{
channel = m_blupi[rank].takeChannel;
icon = m_blupi[rank].takeIcon;
}
PutObject (GetCel (x, y), channel, icon);
return true;
}
if (op == GOAL_BUILDFLOOR)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
cel.x = (x / 2) * 2;
cel.y = (y / 2) * 2;
GetFloor (cel, channel, i);
channel = *pTable++;
icon = *pTable++;
mchannel = *pTable++;
micon = *pTable++;
total = *pTable++;
delai = *pTable++;
step = *pTable++;
if (
i >= 19 && i <= 32 && // herbe foncée ?
icon == 57)
icon = 58; // sol tomate foncé
if (i == 58 && icon == 1)
icon = 20; // remet herbe foncée
if (!MoveCreate (
cel, rank, true, channel, icon, mchannel, micon, total, delai, step))
goto error;
return true;
}
if (op == GOAL_BUILDOBJECT)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
cel.x = (x / 2) * 2;
cel.y = (y / 2) * 2;
channel = *pTable++;
icon = *pTable++;
mchannel = *pTable++;
micon = *pTable++;
total = *pTable++;
delai = *pTable++;
step = *pTable++;
if (channel == -2 && icon == -2) // l'objet actuel ?
GetObject (cel, channel, icon);
ArrangeBuild (cel, channel, icon); // arrange les murs autour
if (!MoveCreate (
cel, rank, false, channel, icon, mchannel, micon, total, delai, step))
goto error;
return true;
}
if (op == GOAL_FINISHMOVE)
{
MoveFinish (rank);
return true;
}
if (op == GOAL_ARRANGEOBJECT)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
MoveFinish (GetCel (x, y));
ArrangeObject (GetCel (x, y));
return true;
}
if (op == GOAL_EXPLOSE1)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
cel = GetCel (x, y);
BlupiKill (rank, cel, 0);
MoveFinish (cel);
// Faut-il démarrer une explosion en chaîne.
GetObject (cel, channel, icon);
if (channel == CHOBJECT && icon == 85) // dynamite ?
{
rank = BlupiCreate (
GetCel (cel, 1, 1), ACTION_STOP, DIRECT_E, 6,
MAXENERGY); // crée un détonnateur
if (rank >= 0)
{
GoalStart (rank, WM_ACTION_T_DYNAMITE, cel);
m_blupi[rank].bCache = true;
}
}
else
{
PutObject (cel, -1, -1); // supprime l'objet
ArrangeObject (cel);
}
return true;
}
if (op == GOAL_EXPLOSE2)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
cel = GetCel ((x / 2) * 2, (y / 2) * 2);
GetObject (cel, channel, icon);
if (channel != CHOBJECT || icon != 85) // dynamite ?
{
channel = CHOBJECT;
icon = -1;
ArrangeBuild (cel, channel, icon); // arrange les murs autour
if (!MoveCreate (cel, rank, false, CHOBJECT, -1, -1, -1, 10, 1, -1 * 100))
goto error;
MoveAddIcons (cel, 6); // explosion
}
return true;
}
if (op == GOAL_ADDMOVES)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
icon = *pTable++;
MoveAddMoves (GetCel (x, y), icon);
return true;
}
if (op == GOAL_ADDICONS)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
icon = *pTable++;
MoveAddIcons (GetCel (x, y), icon);
return true;
}
if (op == GOAL_ACTION)
{
action = *pTable++;
direct = *pTable++;
BlupiInitAction (rank, action, direct);
return true;
}
if (op == GOAL_ELECTRO)
{
x = *pTable++;
y = *pTable++;
GoalAdjustCel (rank, x, y);
cel = GetCel ((x / 2) * 2, (y / 2) * 2);
icon = *pTable++;
if (MoveCreate (
cel, rank, true, CHFLOOR, -1, -1, -1, 100, 1, 100, false, true))
MoveAddIcons (cel, icon);
BlupiKill (rank, cel, 1);
return true;
}
if (op == GOAL_MALADE)
{
m_blupi[rank].bMalade = *pTable++;
return true;
}
if (op == GOAL_WORK)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
m_decor[cel.x / 2][cel.y / 2].workBlupi = rank;
return true;
}
if (op == GOAL_INTERRUPT)
{
m_blupi[rank].interrupt = *pTable++; // change le niveau
return true;
}
if (op == GOAL_ENERGY)
{
if (m_blupi[rank].energy <= *pTable++)
goto error;
return true;
}
if (op == GOAL_ISNOMALADE)
{
if (m_blupi[rank].bMalade)
goto error;
return true;
}
if (op == GOAL_TAKE)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
MoveFinish (rank);
m_blupi[rank].takeChannel = m_decor[cel.x / 2][cel.y / 2].objectChannel;
m_blupi[rank].takeIcon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
m_decor[cel.x / 2][cel.y / 2].objectChannel = -1;
m_decor[cel.x / 2][cel.y / 2].objectIcon = -1;
return true;
}
if (op == GOAL_TAKEOBJECT)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
channel = *pTable++;
icon = *pTable++;
m_blupi[rank].takeChannel = channel;
m_blupi[rank].takeIcon = icon;
return true;
}
if (op == GOAL_LABO)
{
m_blupi[rank].takeChannel = CHOBJECT;
if (m_blupi[rank].takeIcon == 82) // fleurs normales ?
{
m_blupi[rank].takeIcon = 80; // bouteille
}
if (m_blupi[rank].takeIcon == 84) // fleurs foncées ?
{
m_blupi[rank].takeIcon = 85; // dynamite
}
if (m_blupi[rank].takeIcon == 95) // fleurs vertes ?
{
m_blupi[rank].takeIcon = 93; // piège
}
if (m_blupi[rank].takeIcon == 60) // tomates ?
{
m_blupi[rank].takeIcon = 92; // poison
}
return true;
}
if (op == GOAL_CACHE)
{
m_blupi[rank].bCache = *pTable++;
if (
*pTable++ && // bDynamite ?
m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 3 && // armure ?
!m_bInvincible)
m_blupi[rank].bCache = false;
return true;
}
if (op == GOAL_DELETE)
{
if (
m_blupi[rank].perso == 0 && // blupi ?
m_blupi[rank].vehicule == 3 && // armure ?
!m_bInvincible)
return true;
BlupiDelete (rank); // snif ...
return true;
}
if (op == GOAL_DEPOSE)
{
m_blupi[rank].takeChannel = -1;
return true;
}
if (op == GOAL_NEWBLUPI)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
PutObject (cel, -1, -1); // enlève les oeufs
rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4);
if (rank >= 0)
{
m_blupi[rank].energy = MAXENERGY / 4;
BlupiInitAction (rank, ACTION_NAISSANCE);
}
cel.x++;
rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4);
if (rank >= 0)
{
m_blupi[rank].energy = MAXENERGY / 4;
BlupiInitAction (rank, ACTION_NAISSANCE);
}
cel.x--;
cel.y++;
rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4);
if (rank >= 0)
{
m_blupi[rank].energy = MAXENERGY / 4;
BlupiInitAction (rank, ACTION_NAISSANCE);
}
cel.x++;
rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4);
if (rank >= 0)
{
m_blupi[rank].energy = MAXENERGY / 4;
BlupiInitAction (rank, ACTION_NAISSANCE);
}
return true;
}
if (op == GOAL_NEWPERSO)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
icon = *pTable++;
destCel = cel;
destCel.x++;
if (IsBlupiHereEx (destCel, rank, false)) // destination occupée ?
{
m_blupi[rank].goalPhase--; // on attend ...
return true;
}
destCel.x++;
if (IsBlupiHereEx (destCel, rank, false)) // destination occupée ?
{
destCel.y--;
if (
icon == 5 || // bombe ?
IsBlupiHereEx (destCel, rank, false)) // destination occupée ?
{
m_blupi[rank].goalPhase--; // on attend ...
return true;
}
}
rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, icon, MAXENERGY);
if (rank >= 0)
m_blupi[rank].goalCel = destCel;
return true;
}
if (op == GOAL_USINEBUILD)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
if (!IsUsineBuild (rank, cel))
goto error;
return true;
}
if (op == GOAL_USINEFREE)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
if (!IsUsineFree (rank, cel))
{
GoalStop (rank, true);
m_blupi[rank].goalCel = GetCel (cel, 1, -1); // à côté de la porte
//? m_blupi[rank].goalAction = 0; // stoppe sitôt après
//? m_blupi[rank].interrupt = 1;
//? GoalUnwork(rank);
//? FlushUsed(rank);
}
return true;
}
if (op == GOAL_AMORCE)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
if (IsBlupiHereEx (cel, rank, false))
goto error;
// Crée un détonnateur de mine (blupi invisible).
rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 6, MAXENERGY);
if (rank >= 0)
{
m_blupi[rank].bCache = true; // invisible
m_blupi[rank].goalAction = WM_ACTION_MINE2;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].interrupt = 1;
}
return true;
}
if (op == GOAL_VEHICULE)
{
m_blupi[rank].vehicule = *pTable++;
if (
m_blupi[rank].vehicule != 0 && // pas à pied ?
m_blupi[rank].takeChannel != -1 && // porte qq chose ?
m_blupi[rank].energy <= MAXENERGY / 4) // faible ?
m_blupi[rank].energy = MAXENERGY / 4 + 1;
return true;
}
if (op == GOAL_ACTUALISE)
{
BlupiActualise (rank);
return true;
}
if (op == GOAL_SOUND)
{
icon = *pTable++;
BlupiSound (rank, icon, pos);
return true;
}
if (op == GOAL_REPEAT)
{
icon = *pTable++;
m_blupi[rank].bRepeat = icon;
return true;
}
if (op == GOAL_OTHER)
{
if (!m_blupi[rank].bRepeat)
goto term;
// Bouton stop pressé ?
if (m_blupi[rank].stop == 1)
goto term;
channel = *pTable++;
first = *pTable++;
last = *pTable++;
first2 = *pTable++;
last2 = *pTable++;
action = *pTable++;
if (!SearchOtherObject (
rank, m_blupi[rank].cel, action, 100, channel, first, last, first2,
last2, m_blupi[rank].goalHili, icon))
goto term;
if (action == WM_ACTION_ABAT1 || action == WM_ACTION_ROC1)
{
action += icon - first; // WM_ACTION_ABAT1..6
}
m_blupi[rank].goalAction = action;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].interrupt = 1;
GoalInitJauge (rank);
GoalUnwork (rank);
FlushUsed (rank);
return true;
}
if (op == GOAL_OTHERFIX)
{
if (!m_blupi[rank].bRepeat)
goto term;
// Bouton stop pressé ?
if (m_blupi[rank].stop == 1)
goto term;
channel = *pTable++;
first = *pTable++;
last = *pTable++;
first2 = *pTable++;
last2 = *pTable++;
action = *pTable++;
if (!SearchOtherObject (
rank, m_blupi[rank].fix, action, 100, channel, first, last, first2,
last2, m_blupi[rank].goalHili, icon))
goto term;
if (action == WM_ACTION_ABAT1 || action == WM_ACTION_ROC1)
{
action += icon - first; // WM_ACTION_ABAT1..6
}
m_blupi[rank].goalAction = action;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].interrupt = 1;
GoalInitJauge (rank);
GoalUnwork (rank);
FlushUsed (rank);
return true;
}
if (op == GOAL_OTHERLOOP)
{
action = *pTable++;
if (m_blupi[rank].cLoop < m_blupi[rank].nLoop)
{
m_blupi[rank].goalAction = action;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].interrupt = 1;
GoalInitJauge (rank);
GoalUnwork (rank);
FlushUsed (rank);
}
return true;
}
if (op == GOAL_NEXTLOOP)
{
m_blupi[rank].cLoop++;
return true;
}
if (op == GOAL_FIX)
{
m_blupi[rank].fix.x = m_blupi[rank].cel.x + (*pTable++);
m_blupi[rank].fix.y = m_blupi[rank].cel.y + (*pTable++);
return true;
}
if (op == GOAL_FLOORJUMP)
{
channel = *pTable++;
icon = *pTable++;
action = *pTable++;
GetFloor (m_blupi[rank].cel, mchannel, micon);
if (channel == mchannel && icon == micon)
{
m_blupi[rank].goalAction = action;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].interrupt = 1;
GoalInitJauge (rank);
GoalUnwork (rank);
FlushUsed (rank);
}
return true;
}
if (op == GOAL_ADDDRAPEAU)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
AddDrapeau (cel); // cellule sondée
return true;
}
if (op == GOAL_TELEPORTE)
{
pos.x = *pTable++;
pos.y = *pTable++;
cMem = m_blupi[rank].cel;
GetFloor (cMem, channel, icon);
PutFloor (cMem, -1, -1);
bOK = SearchOtherObject (
rank, m_blupi[rank].cel, WM_ACTION_GO, 1000, CHFLOOR, 80, 80, -1, -1, cel,
i);
PutFloor (cMem, channel, icon);
if (!bOK)
goto error;
cel.x += pos.x;
cel.y += pos.y;
if (IsBlupiHereEx (cel, rank, false) || !IsFreeCel (cel, rank))
goto error;
m_blupi[rank].cel = cel;
BlupiPushFog (rank);
if (m_blupi[rank].bHili)
SetCoin (cel, true);
return true;
}
if (op == GOAL_IFTERM)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
if (!IsFreeCel (cel, rank) || IsBlupiHereEx (cel, rank, false))
goto term;
return true;
}
if (op == GOAL_IFDEBARQUE)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
m_blupi[rank].vehicule = 0; // à pied
bOK = IsFreeCel (cel, rank) && !IsBlupiHereEx (cel, rank, false);
m_blupi[rank].vehicule = 1; // en bateau
if (!bOK)
goto term;
return true;
}
if (op == GOAL_SKIPSKILL)
{
i = (*pTable++);
total = (*pTable++);
if (m_skill == i)
{
m_blupi[rank].goalPhase += total; // saute qq instructions
}
return true;
}
if (op == GOAL_TERM)
{
term:
bError = false;
}
if (op == GOAL_WAITFREE)
{
cel.x = m_blupi[rank].cel.x + (*pTable++);
cel.y = m_blupi[rank].cel.y + (*pTable++);
if (IsBlupiHereEx (cel, rank, false)) // destination occupée ?
{
m_blupi[rank].goalPhase--; // on attend ...
rank = m_blupiHere;
if (
m_blupi[rank].goalAction != WM_ACTION_GO &&
m_blupi[rank].goalAction != WM_ACTION_ELECTRO &&
m_blupi[rank].goalAction != WM_ACTION_ELECTROm)
{
destCel.x = cel.x;
destCel.y = cel.y - 1;
if (!IsBlupiHereEx (destCel, rank, false))
{
GoalStart (rank, WM_ACTION_GO, destCel);
return true;
}
destCel.x = cel.x + 1;
destCel.y = cel.y;
if (!IsBlupiHereEx (destCel, rank, false))
{
GoalStart (rank, WM_ACTION_GO, destCel);
return true;
}
destCel.x = cel.x;
destCel.y = cel.y + 1;
if (!IsBlupiHereEx (destCel, rank, false))
{
GoalStart (rank, WM_ACTION_GO, destCel);
return true;
}
destCel.x = cel.x + 1;
destCel.y = cel.y - 1;
if (!IsBlupiHereEx (destCel, rank, false))
{
GoalStart (rank, WM_ACTION_GO, destCel);
return true;
}
destCel.x = cel.x + 1;
destCel.y = cel.y + 1;
if (!IsBlupiHereEx (destCel, rank, false))
{
GoalStart (rank, WM_ACTION_GO, destCel);
return true;
}
if (m_blupi[rank].perso == 0)
{
if (m_blupi[rank].bMalade)
action = WM_ACTION_ELECTROm;
else
action = WM_ACTION_ELECTRO;
GoalStart (rank, action, m_blupi[rank].cel);
return true;
}
}
}
return true;
}
error:
i = m_blupi[rank].repeatLevel;
GoalStop (rank, bError, i == -1);
if (i != -1) // répétition en cours ?
{
button = m_blupi[rank].listButton[i];
cMem = m_blupi[rank].listCel[i];
param = m_blupi[rank].listParam[i];
cel = cMem;
if (RepeatAdjust (rank, button, cel, cMem, param, i))
{
if (IsBlupiHereEx (cel, rank, false)) // destination occupée ?
{
m_blupi[rank].repeatLevel = i; // on continue ...
GoalStart (rank, WM_ACTION_GO, m_blupi[rank].cel); // on attend ...
return true;
}
if (BlupiGoal (rank, button, cel, cMem))
{
m_blupi[rank].repeatLevel = i; // on continue ...
return true;
}
}
}
return false;
}
// Supprime le blocage de la cellule dans laquelle
// blupi travaille.
void CDecor::GoalUnwork (Sint32 rank)
{
Sint32 x, y;
for (x = 0; x < MAXCELX / 2; x++)
{
for (y = 0; y < MAXCELY / 2; y++)
{
if (m_decor[x][y].workBlupi == rank)
{
m_decor[x][y].workBlupi = -1; // débloque
}
}
}
}
// Stoppe complètement une action.
void CDecor::GoalStop (Sint32 rank, bool bError, bool bSound)
{
POINT pos;
static Sint32 table_sound_term[6] = {
SOUND_TERM1, SOUND_TERM2, SOUND_TERM3,
SOUND_TERM4, SOUND_TERM5, SOUND_TERM6,
};
static Sint32 table_sound_boing[3] = {
SOUND_BOING1, SOUND_BOING2, SOUND_BOING3,
};
if (bError && bSound)
{
ListRemove (rank); // supprime la dernière action mémorisée
}
m_blupi[rank].goalAction = 0;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].jaugePhase = -1;
m_blupi[rank].jaugeMax = -1;
m_blupi[rank].interrupt = 1; // remet le niveau normal
m_blupi[rank].busyCount = 0;
m_blupi[rank].busyDelay = 0;
m_blupi[rank].repeatLevel = -1; // stoppe la répétition
FlushUsed (rank);
MoveFinish (rank);
GoalUnwork (rank);
// En cas d'erreur, il faut accepter de traverser la
// construction avortée (par exemple, le massif d'arbres
// dans lequel blupi se trouve, mais qui n'a pas pu
// être abattu).
if (!bError)
m_blupi[rank].passCel.x = -1;
m_blupi[rank].stop = 0; // relâche bouton stop
if (
bSound && (m_blupi[rank].perso == 0 || // blupi ?
m_blupi[rank].perso == 8)) // assistant ?
{
if (bError)
{
pos.x = LXIMAGE / 2;
pos.y = LYIMAGE / 2;
BlupiSound (rank, table_sound_boing[Random (0, 2)], pos, true);
}
else
{
pos = ConvCelToPos (m_blupi[rank].cel);
BlupiSound (rank, table_sound_term[Random (0, 5)], pos, true);
}
}
}
// Teste si une cellule est déjà utilisée comme but pour
// n'importe quel blupi.
bool CDecor::BlupiIsGoalUsed (POINT cel)
{
Sint32 rank;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist && m_blupi[rank].goalCel.x / 2 == cel.x / 2 &&
m_blupi[rank].goalCel.y / 2 == cel.y / 2)
return true;
}
return false;
}
// Démarre ou stoppe un rayon entre deux tours.
void CDecor::BlupiStartStopRayon (Sint32 rank, POINT startCel, POINT endCel)
{
Sint32 i, icon, icon2;
POINT cel, cel2, vector, pos;
if (
m_blupi[rank].perso == 1 || // araignée ?
m_blupi[rank].perso == 2) // virus ?
return;
// Stoppe un rayon.
cel.x = (endCel.x / 2) * 2;
cel.y = (endCel.y / 2) * 2;
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
if ((icon == 10000 || icon == 10001) && MoveIsUsed (cel))
{
if (MoveIsUsed (cel))
{
MoveFinish (cel);
pos = ConvCelToPos (cel);
BlupiSound (rank, SOUND_RAYON2, pos);
}
for (i = 0; i < 4; i++)
{
vector = GetVector (i * 2 * 16);
cel.x = (endCel.x / 2) * 2 + vector.x * 2;
cel.y = (endCel.y / 2) * 2 + vector.y * 2;
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
if (icon == 10000 || icon == 10001)
MoveFinish (cel);
}
}
// Démarre un rayon.
cel.x = (startCel.x / 2) * 2;
cel.y = (startCel.y / 2) * 2;
cel2.x = (endCel.x / 2) * 2;
cel2.y = (endCel.y / 2) * 2;
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
icon2 = m_decor[cel2.x / 2][cel2.y / 2].objectIcon;
if ((icon == 10000 || icon == 10001) && icon2 != 10000 && icon2 != 10001)
{
if (MoveCreate (cel, -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true))
{
MoveAddIcons (cel, icon == 10000 ? 4 : 5, true); // éclairs
}
pos = ConvCelToPos (cel);
BlupiSound (rank, SOUND_RAYON1, pos);
for (i = 0; i < 4; i++)
{
vector = GetVector (i * 2 * 16);
cel.x = (startCel.x / 2) * 2 + vector.x * 2;
cel.y = (startCel.y / 2) * 2 + vector.y * 2;
icon = m_decor[cel.x / 2][cel.y / 2].objectIcon;
if (icon == 10000 || icon == 10001)
{
if (MoveCreate (cel, -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true))
{
MoveAddIcons (cel, icon == 10000 ? 4 : 5, true); // éclairs
}
}
}
}
}
// Tourne un blupi, si nécessaire.
// Retourne false si ce n'est pas nécessaire.
bool CDecor::BlupiRotate (Sint32 rank)
{
Sint32 aDirect, sDirect, ip, in, sens = 0;
bool bOK;
POINT pos;
aDirect = m_blupi[rank].aDirect;
sDirect = m_blupi[rank].sDirect;
if (aDirect == sDirect)
return false;
if (sDirect > aDirect)
ip = sDirect + 0 * 16 - aDirect;
else
ip = sDirect + 8 * 16 - aDirect;
if (aDirect > sDirect)
in = aDirect + 0 * 16 - sDirect;
else
in = aDirect + 8 * 16 - sDirect;
if (ip == 0 || in == 0)
{
m_blupi[rank].aDirect = m_blupi[rank].sDirect;
return false;
}
if (
m_blupi[rank].perso == 0 && // blupi ?
m_blupi[rank].vehicule == 1) // en bateau ?
{
if (ip == in)
sens = Random (0, 1) ? 8 : 8 * 16 - 8;
if (ip < in)
sens = 8;
if (ip > in)
sens = 8 * 16 - 8;
aDirect = (aDirect + sens) % (8 * 16);
}
else if (
m_blupi[rank].perso == 0 && // blupi ?
m_blupi[rank].vehicule == 2) // en jeep ?
{
if (ip == in)
sens = Random (0, 1) ? 8 : 8 * 16 - 8;
if (ip < in)
sens = 8;
if (ip > in)
sens = 8 * 16 - 8;
aDirect = (aDirect + sens) % (8 * 16);
}
else if (
m_blupi[rank].perso == 0 && // blupi ?
m_blupi[rank].vehicule == 3) // armure ?
{
if (ip == in)
sens = Random (0, 1) ? 4 : 8 * 16 - 4;
if (ip < in)
sens = 4;
if (ip > in)
sens = 8 * 16 - 4;
aDirect = (aDirect + sens) % (8 * 16);
}
else if (m_blupi[rank].perso == 3) // tracks ?
{
if (ip == in)
sens = Random (0, 1) ? 4 : 8 * 16 - 4;
if (ip < in)
sens = 4;
if (ip > in)
sens = 8 * 16 - 4;
aDirect = (aDirect + sens) % (8 * 16);
}
else if (m_blupi[rank].perso == 4) // robot ?
{
pos = ConvCelToPos (m_blupi[rank].cel);
BlupiSound (rank, SOUND_R_ROTATE, pos);
if (ip == in)
sens = Random (0, 1) ? 2 : 8 * 16 - 2;
if (ip < in)
sens = 2;
if (ip > in)
sens = 8 * 16 - 2;
aDirect = (aDirect + sens) % (8 * 16);
}
else if (m_blupi[rank].perso == 8) // disciple ?
{
if (ip == in)
sens = Random (0, 1) ? 8 : 8 * 16 - 8;
if (ip < in)
sens = 8;
if (ip > in)
sens = 8 * 16 - 8;
aDirect = (aDirect + sens) % (8 * 16);
}
else
{
if (ip == in)
sens = Random (0, 1) ? 1 : 7;
if (ip < in)
sens = 1;
if (ip > in)
sens = 7;
aDirect = ((aDirect / 16 + sens) % 8) * 16;
}
m_blupi[rank].lastIcon = m_blupi[rank].icon;
bOK = Rotate (m_blupi[rank].icon, aDirect);
if (bOK)
{
m_blupi[rank].aDirect = aDirect;
return true;
}
else
{
m_blupi[rank].aDirect = m_blupi[rank].sDirect;
return false;
}
}
// Avance un blupi existant.
bool CDecor::BlupiNextAction (Sint32 rank)
{
bool bOK;
POINT pos, iCel;
Sint32 a, min;
Sint16 sound;
if (!m_blupi[rank].bExist)
return false;
if (m_blupi[rank].clicDelay > 0)
m_blupi[rank].clicDelay--;
if (m_blupi[rank].clicDelay == 0)
m_blupi[rank].clicCount = 0;
bOK = true;
if (!BlupiRotate (rank)) // si rotation pas nécessaire
{
m_blupi[rank].lastIcon = m_blupi[rank].icon;
bOK = Action (
m_blupi[rank].action, m_blupi[rank].aDirect, m_blupi[rank].phase,
m_blupi[rank].step, m_blupi[rank].channel, m_blupi[rank].icon,
m_blupi[rank].pos, m_blupi[rank].posZ, sound);
BlupiAdaptIcon (rank);
if (sound != -1)
{
pos = ConvCelToPos (m_blupi[rank].cel);
BlupiSound (rank, sound, pos);
}
}
a = GetAmplitude (m_blupi[rank].action);
iCel = m_blupi[rank].cel;
if (
m_blupi[rank].pos.x == (DIMCELX / 2) * a &&
m_blupi[rank].pos.y == (DIMCELY / 2) * a)
{
m_blupi[rank].cel.x += a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (
m_blupi[rank].pos.x == -(DIMCELX / 2) * a &&
m_blupi[rank].pos.y == -(DIMCELY / 2) * a)
{
m_blupi[rank].cel.x -= a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (
m_blupi[rank].pos.x == -(DIMCELX / 2) * a &&
m_blupi[rank].pos.y == (DIMCELY / 2) * a)
{
m_blupi[rank].cel.y += a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (
m_blupi[rank].pos.x == (DIMCELX / 2) * a &&
m_blupi[rank].pos.y == -(DIMCELY / 2) * a)
{
m_blupi[rank].cel.y -= a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (m_blupi[rank].pos.x == 0 && m_blupi[rank].pos.y == DIMCELY * a)
{
m_blupi[rank].cel.x += a;
m_blupi[rank].cel.y += a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (m_blupi[rank].pos.x == 0 && m_blupi[rank].pos.y == -DIMCELY * a)
{
m_blupi[rank].cel.x -= a;
m_blupi[rank].cel.y -= a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (m_blupi[rank].pos.x == DIMCELX * a && m_blupi[rank].pos.y == 0)
{
m_blupi[rank].cel.x += a;
m_blupi[rank].cel.y -= a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
if (m_blupi[rank].pos.x == -DIMCELX * a && m_blupi[rank].pos.y == 0)
{
m_blupi[rank].cel.x -= a;
m_blupi[rank].cel.y += a;
BlupiPushFog (rank);
BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel);
}
// Blupi perd de l'énergie s'il fait qq chose.
if (
m_blupi[rank].action != ACTION_STOP &&
m_blupi[rank].action != ACTION_STOPf &&
m_blupi[rank].action != ACTION_STOPb &&
m_blupi[rank].action != ACTION_STOPj &&
m_blupi[rank].action != ACTION_MISC1 &&
m_blupi[rank].action != ACTION_MISC2 &&
m_blupi[rank].action != ACTION_MISC3 &&
m_blupi[rank].action != ACTION_MISC4 &&
m_blupi[rank].action != ACTION_MISC5 &&
m_blupi[rank].action != ACTION_MISC6 &&
m_blupi[rank].action != ACTION_MISC1f)
{
if (
m_blupi[rank].energy > 0 && m_blupi[rank].perso == 0 && // blupi ?
m_blupi[rank].vehicule == 0) // à pied ?
{
if (m_bSuper)
a = 0;
else
a = 1;
min = 0;
if (
m_blupi[rank].goalAction == WM_ACTION_MUR ||
m_blupi[rank].goalAction == WM_ACTION_TOUR)
{
a = 5;
min = 1;
}
if (m_blupi[rank].action == ACTION_GLISSE)
{
if (m_bSuper)
a = 0;
else
a = 40;
}
m_blupi[rank].energy -= a; // blupi se fatigue +/-
if (m_blupi[rank].energy < min)
m_blupi[rank].energy = min;
}
}
// Blupi prend de l'énergie s'il mange.
if (m_blupi[rank].action == ACTION_MANGE)
{
if (m_blupi[rank].energy < MAXENERGY)
m_blupi[rank].energy += MAXENERGY / (40 * 3);
}
// Le robot perd de l'énergie s'il fait qq chose.
if (m_blupi[rank].action != ACTION_R_STOP)
{
if (m_blupi[rank].energy > 0 && m_blupi[rank].perso == 4)
{
m_blupi[rank].energy -= 3; // le robot se fatigue
if (m_blupi[rank].energy < 1)
m_blupi[rank].energy = 1;
}
}
// Le robot prend de l'énergie s'il se recharge.
if (m_blupi[rank].action == ACTION_R_CHARGE)
{
if (m_blupi[rank].energy < MAXENERGY)
m_blupi[rank].energy = MAXENERGY;
}
// Blupi guérrit s'il boit.
if (m_blupi[rank].action == ACTION_BOIT)
{
m_blupi[rank].bMalade = false;
if (m_blupi[rank].energy < MAXENERGY)
m_blupi[rank].energy += MAXENERGY / (40 * 3);
}
// Si blupi est presque complètement épuisé, il stoppe.
if (
!bOK && m_blupi[rank].perso == 0 && m_blupi[rank].energy < 50 &&
m_blupi[rank].energy != 0 && m_blupi[rank].action == ACTION_MARCHEf)
{
BlupiInitAction (rank, ACTION_STOP);
GoalStop (rank, true);
}
return bOK;
}
// Action suivante pour un blupi existant.
void CDecor::BlupiNextGoal (Sint32 rank)
{
Sint32 direct, action, channel, icon, min, lg, fRank, i;
POINT pos, cel, vector;
if (!m_blupi[rank].bExist)
return;
pos = ConvCelToPos (m_blupi[rank].cel);
// Si blupi termine une action "mort", il doit disparaître.
if (
m_blupi[rank].action == ACTION_BRULE ||
m_blupi[rank].action == ACTION_TCHAO ||
m_blupi[rank].action == ACTION_A_GRILLE ||
m_blupi[rank].action == ACTION_V_GRILLE)
{
BlupiDelete (rank); // snif ...
return;
}
// Si blupi passe trop prêt du feu, aie aie aie ...
if (IsFireCel (m_blupi[rank].cel)) // blupi se brule les ailes ?
{
if (
m_blupi[rank].perso == 0 && m_blupi[rank].vehicule != 3 && // pas armure ?
!m_bInvincible && m_blupi[rank].goalAction != WM_ACTION_GRILLE)
{
BlupiDeselect (rank);
GoalStart (rank, WM_ACTION_GRILLE, m_blupi[rank].cel);
goto goal;
//? BlupiInitAction(rank, ACTION_BRULE);
//? goto init;
}
if (
m_blupi[rank].perso == 1 || // araignée ?
m_blupi[rank].perso == 2) // virus ?
{
BlupiDelete (rank); // la bestiole meurt
return;
}
}
// Si blupi passe trop prêt d'un virus ...
if (
m_blupi[rank].perso == 0 &&
m_blupi[rank].vehicule != 1 && // pas en bateau ?
m_blupi[rank].vehicule != 3 && // pas armure ?
!m_blupi[rank].bMalade && // en bonne santé ?
m_blupi[rank].goalAction != WM_ACTION_GRILLE &&
m_blupi[rank].goalAction != WM_ACTION_ELECTRO &&
m_blupi[rank].goalAction != WM_ACTION_ELECTROm &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUDE &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUDS &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUDO &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUDN &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUAE &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUAS &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUAO &&
m_blupi[rank].goalAction != WM_ACTION_BATEAUAN && !m_bInvincible &&
IsVirusCel (m_blupi[rank].cel)) // blupi chope un virus ?
{
m_blupi[rank].bMalade = true;
if (m_blupi[rank].energy > MAXENERGY / 4)
m_blupi[rank].energy = MAXENERGY / 4;
BlupiSound (rank, SOUND_VIRUS, pos);
if (m_blupi[rank].vehicule == 2) // en jeep ?
{
GoalStart (rank, WM_ACTION_DJEEP, m_blupi[rank].cel);
goto goal;
}
}
// Si blupi est complètement épuisé, il meurt.
if (m_blupi[rank].perso == 0 && m_blupi[rank].energy == 0)
{
BlupiDeselect (rank);
BlupiInitAction (rank, ACTION_TCHAO);
goto init;
}
// Assigne un but s'il s'agit d'une araignée.
if (
m_blupi[rank].perso == 1 && // araignée ?
m_blupi[rank].goalAction != WM_ACTION_A_MORT)
{
cel = m_blupi[rank].cel;
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (
channel == CHOBJECT && (icon == 10000 || icon == 10001) && // rayon ?
MoveIsUsed (cel)) // enclenché ?
{
BlupiInitAction (rank, ACTION_A_GRILLE);
goto init;
}
cel = m_blupi[rank].cel;
if (cel.x % 2 != 0 && cel.y % 2 != 0)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (channel == CHOBJECT && icon == 60) // tomates ?
{
PutObject (cel, -1, -1); // plus de tomates
BlupiSound (rank, SOUND_A_HIHI, pos);
}
if (channel == CHOBJECT && icon == 92) // poison ?
{
PutObject (cel, -1, -1); // plus de poison
BlupiInitAction (rank, ACTION_STOP);
GoalStart (rank, WM_ACTION_A_MORT, m_blupi[rank].cel);
m_blupi[rank].goalCel = m_blupi[rank].cel;
goto goal;
//? BlupiSound(rank, SOUND_A_POISON, pos);
//? BlupiInitAction(rank, ACTION_A_POISON);
//? goto init;
}
if (channel == CHOBJECT && icon == 93) // piège ?
{
BlupiSound (rank, SOUND_PIEGE, pos);
PutObject (cel, CHOBJECT, 96); // araignée piégée
BlupiDelete (rank); // supprime araignée
return;
}
}
m_blupi[rank].bExist = false;
if (
m_time % 5 == rank % 5 && // pas trop souvent !
SearchSpiderObject (rank, m_blupi[rank].cel, 100, cel, icon))
{
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
// direct = DirectSearch(m_blupi[rank].cel, cel);
// if ( direct != -1 )
// {
// vector = GetVector(direct);
// m_blupi[rank].goalCel.x = m_blupi[rank].cel.x + vector.x;
// m_blupi[rank].goalCel.y = m_blupi[rank].cel.y + vector.y;
// FlushUsed(rank);
// }
}
m_blupi[rank].bExist = true;
}
// Assigne un but s'il s'agit d'un virus.
if (m_blupi[rank].perso == 2) // virus ?
{
cel = m_blupi[rank].cel;
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (
channel == CHOBJECT && (icon == 10000 || icon == 10001) && // rayon ?
MoveIsUsed (cel)) // enclenché ?
{
BlupiInitAction (rank, ACTION_V_GRILLE);
goto init;
}
min = 50; // ignore si trop loin !
fRank = -1;
for (i = 0; i < MAXBLUPI; i++)
{
if (m_blupi[i].bExist && m_blupi[i].perso == 0 && !m_blupi[i].bMalade)
{
lg = abs (m_blupi[rank].cel.x - m_blupi[i].cel.x) +
abs (m_blupi[rank].cel.y - m_blupi[i].cel.y);
if (lg < min)
{
min = lg;
fRank = i;
}
}
}
if (fRank != -1)
{
direct = DirectSearch (m_blupi[rank].cel, m_blupi[fRank].cel);
if (direct != -1)
{
vector = GetVector (direct);
m_blupi[rank].goalCel.x = m_blupi[rank].cel.x + vector.x;
m_blupi[rank].goalCel.y = m_blupi[rank].cel.y + vector.y;
FlushUsed (rank);
}
}
}
// Assigne un but s'il s'agit d'un tracks.
if (
m_blupi[rank].perso == 3 && // tracks ?
m_blupi[rank].goalAction != WM_ACTION_T_DYNAMITE)
{
cel = m_blupi[rank].cel;
if (cel.x % 2 != 0 && cel.y % 2 != 0)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (channel == CHOBJECT && IsTracksObject (icon))
{
if (icon == 85) // dynamite ?
{
BlupiInitAction (rank, ACTION_STOP);
GoalStart (rank, WM_ACTION_T_DYNAMITE, cel);
goto goal;
}
if (
icon == 125 || // mine ?
icon == 127)
{
// Supprime le détonnateur.
BlupiDelete (GetCel (cel.x + 1, cel.y + 1), 6);
}
if (icon == 93) // piège ?
{
BlupiSound (rank, SOUND_PIEGE, pos);
PutObject (cel, CHOBJECT, 97); // tracks piégé
BlupiDelete (rank); // supprime tracks
return;
}
PutObject (cel, -1, -1); // plus d'objet
BlupiSound (rank, SOUND_T_ECRASE, pos);
BlupiInitAction (rank, ACTION_T_ECRASE);
goto init;
}
}
cel = m_blupi[rank].cel;
m_blupi[rank].bExist = false;
if (
IsBlupiHere (cel, false) && m_blupi[m_blupiHere].perso == 0 &&
m_blupi[m_blupiHere].vehicule == 0) // à pied ?
{
m_blupi[rank].bExist = true;
// Blupi écrasé au sol.
if (MoveCreate (
cel, rank, true, CHFLOOR, -1, -1, -1, 100, 1, 100, false, true))
{
if (m_blupi[m_blupiHere].bMalade)
MoveAddIcons (cel, 10);
else
MoveAddIcons (cel, 9);
}
BlupiDelete (m_blupiHere); // plus de blupi !
BlupiSound (rank, SOUND_AIE, pos);
BlupiInitAction (rank, ACTION_T_ECRASE); // écrase blupi
goto init;
}
m_blupi[rank].bExist = true;
// if ( m_blupi[rank].goalCel.x != -1 )
// {
// GetObject(m_blupi[rank].goalCel, channel, icon);
// if ( IsTracksObject(icon) ) goto action;
// }
m_blupi[rank].bExist = false;
if (
m_time % 5 == rank % 5 && // pas trop souvent !
SearchTracksObject (rank, m_blupi[rank].cel, 25, cel, icon))
{
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
}
m_blupi[rank].bExist = true;
}
// Assigne un but s'il s'agit d'un robot.
if (
m_blupi[rank].perso == 4 && // robot ?
m_blupi[rank].goalAction != WM_ACTION_T_DYNAMITE)
{
cel = m_blupi[rank].cel;
if (cel.x % 2 != 0 && cel.y % 2 != 0)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (channel == CHOBJECT && IsRobotObject (icon))
{
if (icon == 85) // dynamite ?
{
BlupiInitAction (rank, ACTION_STOP);
GoalStart (rank, WM_ACTION_T_DYNAMITE, cel);
goto goal;
}
if (
icon == 125 || // mine ?
icon == 127)
{
// Supprime le détonnateur.
BlupiDelete (GetCel (cel.x + 1, cel.y + 1), 6);
}
if (icon == 93) // piège ?
{
BlupiSound (rank, SOUND_PIEGE, pos);
PutObject (cel, CHOBJECT, 98); // robot piégé
BlupiDelete (rank); // supprime robot
return;
}
PutObject (cel, -1, -1); // plus d'objet
BlupiSound (rank, SOUND_T_ECRASE, pos);
BlupiInitAction (rank, ACTION_R_ECRASE);
goto init;
}
}
cel = m_blupi[rank].cel;
if (
m_blupi[rank].goalAction == 0 &&
m_time % 17 == rank % 17 && // pas trop souvent !
SearchRobotObject (rank, m_blupi[rank].fix, 50, cel, icon, action))
{
if (action == -1)
{
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
}
else
{
BlupiInitAction (rank, ACTION_STOP);
GoalStart (rank, action, cel);
goto goal;
}
}
}
// Assigne un but s'il s'agit d'une bombe.
if (
m_blupi[rank].perso == 5 && // bombe ?
m_blupi[rank].goalAction != WM_ACTION_T_DYNAMITE)
{
cel = m_blupi[rank].cel;
if (cel.x % 2 != 0 && cel.y % 2 != 0)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (channel == CHOBJECT && icon == 93) // piège ?
{
BlupiSound (rank, SOUND_PIEGE, pos);
PutObject (cel, CHOBJECT, 114); // bombe piégée
BlupiDelete (rank); // supprime bombe
return;
}
}
for (i = 0; i < 4; i++)
{
vector = GetVector (i * 2 * 16);
cel.x = ((m_blupi[rank].cel.x + vector.x * 2) / 2) * 2;
cel.y = ((m_blupi[rank].cel.y + vector.y * 2) / 2) * 2;
GetObject (cel, channel, icon);
if (
channel == CHOBJECT &&
IsBombeObject (icon) && // cabane, palissade, etc. ?
icon != 93) // pas piège ?
{
BlupiInitAction (rank, ACTION_STOP);
GoalStart (rank, WM_ACTION_T_DYNAMITE, m_blupi[rank].cel);
goto goal;
}
}
cel = m_blupi[rank].cel;
if (
m_blupi[rank].goalAction == 0 &&
m_time % 17 == rank % 17 && // pas trop souvent !
SearchBombeObject (rank, cel, 100, cel, icon))
{
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
}
}
// Assigne un but s'il s'agit d'un électro.
if (m_blupi[rank].perso == 7) // électro ?
{
cel = m_blupi[rank].cel;
if (cel.x % 2 != 0 && cel.y % 2 != 0)
{
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (channel == CHOBJECT && icon == 93) // piège ?
{
BlupiSound (rank, SOUND_PIEGE, pos);
PutObject (cel, CHOBJECT, 19); // électro piégée
BlupiDelete (rank); // supprime électro
return;
}
}
cel = m_blupi[rank].cel;
if (
m_blupi[rank].goalAction == 0 && m_blupi[rank].goalCel.x == -1 &&
m_time % 37 == rank % 37 && // pas trop souvent !
SearchElectroObject (rank, cel, 100, cel, icon))
{
if (icon == -1) // sur un blupi ?
{
BlupiInitAction (rank, ACTION_STOP);
GoalStart (rank, WM_ACTION_E_RAYON, cel);
m_blupi[rank].fix = cel;
goto goal;
}
m_blupi[rank].goalCel = cel;
FlushUsed (rank);
}
}
BlupiInitAction (rank, ACTION_STOP);
goal:
if (m_blupi[rank].goalCel.x != -1) // y a-t-il un but ?
{
direct = DirectSearch (m_blupi[rank].cel, m_blupi[rank].goalCel);
if (direct == -1) // but atteint ?
{
m_blupi[rank].goalCel.x = -1;
FlushUsed (rank);
}
else
{
// Si blupi a peu d'énergie et qu'il transporte
// qq chose, il doit stopper !
if (
m_blupi[rank].energy <= MAXENERGY / 4 &&
m_blupi[rank].takeChannel != -1 &&
(m_blupi[rank].vehicule == 0 || // à pied ?
m_blupi[rank].vehicule == 3)) // armure ?
{
// Si blupi est en train de descendre de la jeep
// et qu'il est malade tout en transportant qq
// chose, il ne faut pas stopper !!!
cel = m_blupi[rank].cel;
if (
cel.x % 2 != 0 && cel.y % 2 != 0 &&
m_decor[cel.x / 2][cel.y / 2].objectIcon == 118 && // jeep
m_blupi[rank].bMalade && m_blupi[rank].takeChannel != -1)
goto search;
GoalStop (rank, true);
}
else
{
search:
//- BlupiInitAction(rank, ACTION_MARCHE, direct);
if (SearchBestPass (rank, action))
{
//- if ( (action >= ACTION_SAUTE2 &&
//- action <= ACTION_SAUTE5) ||
//- action == ACTION_GLISSE )
//- {
BlupiInitAction (rank, action);
//- }
}
else
{
BlupiInitAction (rank, ACTION_STOP);
if (
m_blupi[rank].perso == 0 || // blupi ?
m_blupi[rank].perso == 8) // disciple ?
{
if (m_blupi[rank].busyCount == 0) // dernière tentative ?
{
GoalStop (rank, true);
m_blupi[rank].goalCel.x = -1;
m_blupi[rank].goalPhase = 0;
m_blupi[rank].interrupt = 1;
}
}
else // perso ennemi ?
{
// On cherchera un autre but !
GoalStop (rank, true);
//? m_blupi[rank].goalCel.x = -1;
//? m_blupi[rank].goalPhase = 0;
//? m_blupi[rank].interrupt = 1;
}
}
}
}
}
else
{
GoalNextPhase (rank); // méta opération suivante
}
init:
BlupiDestCel (rank);
m_blupi[rank].phase = 0;
m_blupi[rank].pos.x = 0;
m_blupi[rank].pos.y = 0;
BlupiNextAction (rank);
}
// Calcule la cellule de destination.
void CDecor::BlupiDestCel (Sint32 rank)
{
Sint32 a;
POINT vector;
m_blupi[rank].destCel = m_blupi[rank].cel;
if (
m_blupi[rank].action == ACTION_MARCHE ||
m_blupi[rank].action == ACTION_MARCHEf ||
m_blupi[rank].action == ACTION_MARCHEb ||
m_blupi[rank].action == ACTION_MARCHEj ||
m_blupi[rank].action == ACTION_MARCHEa ||
m_blupi[rank].action == ACTION_A_MARCHE ||
m_blupi[rank].action == ACTION_V_MARCHE ||
m_blupi[rank].action == ACTION_T_MARCHE ||
m_blupi[rank].action == ACTION_R_MARCHE ||
m_blupi[rank].action == ACTION_B_MARCHE ||
m_blupi[rank].action == ACTION_E_MARCHE ||
m_blupi[rank].action == ACTION_D_MARCHE)
{
vector = GetVector (m_blupi[rank].sDirect);
m_blupi[rank].destCel.x += vector.x;
m_blupi[rank].destCel.y += vector.y;
}
a = GetAmplitude (m_blupi[rank].action);
if (a > 1)
{
vector = GetVector (m_blupi[rank].sDirect);
m_blupi[rank].destCel.x += vector.x * a;
m_blupi[rank].destCel.y += vector.y * a;
}
}
// Avance tous les blupis.
void CDecor::BlupiStep (bool bFirst)
{
Sint32 rank;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (m_blupi[rank].bExist)
{
if (!BlupiNextAction (rank))
BlupiNextGoal (rank);
}
}
if (bFirst)
{
m_timeConst++; // avance le temps absolu global constant
if (m_timeConst == m_timeFlipOutline)
{
m_bOutline = false; // supprime le mode "outline"
}
}
m_time++; // avance le temps absolu global
}
// Retourne le rectangle occupé par un blupi,
// pour les sélections (pas exact).
void CDecor::BlupiGetRect (Sint32 rank, RECT & rect)
{
POINT pos;
pos = ConvCelToPos (m_blupi[rank].cel);
pos.x += m_blupi[rank].pos.x;
pos.y += m_blupi[rank].pos.y - (DIMBLUPIY - DIMCELY) - SHIFTBLUPIY;
rect.left = pos.x + 16;
rect.top = pos.y + 10;
rect.right = pos.x + DIMBLUPIX - 16;
rect.bottom = pos.y + DIMBLUPIY;
}
// Retourne le blupi visé par la souris.
Sint32 CDecor::GetTargetBlupi (POINT pos)
{
Sint32 rank, found, prof;
POINT test, rel, cel;
cel = ConvPosToCel (pos);
found = -1;
prof = 0;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist && (m_blupi[rank].perso == 0 || // blupi ?
m_blupi[rank].perso == 8)) // disciple ?
{
test = ConvCelToPos (m_blupi[rank].cel);
test.x += m_blupi[rank].pos.x;
test.y += m_blupi[rank].pos.y - (DIMBLUPIY - DIMCELY) - SHIFTBLUPIY;
if (
pos.x >= test.x && pos.x <= test.x + DIMBLUPIX && pos.y >= test.y &&
pos.y <= test.y + DIMBLUPIY)
{
rel.x = pos.x - test.x;
rel.y = pos.y - test.y;
if (
(cel.x == m_blupi[rank].cel.x && cel.y == m_blupi[rank].cel.y) ||
(cel.x == m_blupi[rank].destCel.x &&
cel.y == m_blupi[rank].destCel.y) ||
m_pPixmap->IsIconPixel (
m_blupi[rank].channel, m_blupi[rank].icon, rel))
{
if (found != -1 && test.y < prof)
continue;
found = rank;
prof = test.y;
}
}
}
}
return found;
}
// Déslectionne tous les blupi.
void CDecor::BlupiDeselect ()
{
Sint32 rank;
for (rank = 0; rank < MAXBLUPI; rank++)
{
m_blupi[rank].bHili = false;
m_blupi[rank].bArrow = false;
}
m_nbBlupiHili = 0;
m_rankBlupiHili = -1;
}
// Déslectionne un blupi.
void CDecor::BlupiDeselect (Sint32 rank)
{
m_blupi[rank].bHili = false;
m_blupi[rank].bArrow = false;
if (m_nbBlupiHili > 0 && m_rankBlupiHili == rank) // est-ce le blupi
// sélectionné ?
{
m_nbBlupiHili = 0;
m_rankBlupiHili = -1;
}
}
// Met ou enlève une flèche au blupi sélectionné blupi.
void CDecor::BlupiSetArrow (Sint32 rank, bool bArrow)
{
m_celArrow.x = -1;
if (bArrow)
m_blupi[rank].bArrow = true;
else
{
for (rank = 0; rank < MAXBLUPI; rank++)
m_blupi[rank].bArrow = false;
}
}
// Initialise la zone outline en fonction du rectangle de sélection.
void CDecor::InitOutlineRect ()
{
if (!m_bOutline && m_bHiliRect)
{
m_celOutline1.x = m_p1Hili.x < m_p2Hili.x ? m_p1Hili.x : m_p2Hili.x;
m_celOutline1.y = m_p1Hili.y < m_p2Hili.y ? m_p1Hili.y : m_p2Hili.y;
m_celOutline2.x = m_p1Hili.x > m_p2Hili.x ? m_p1Hili.x : m_p2Hili.x;
m_celOutline2.y = m_p1Hili.y > m_p2Hili.y ? m_p1Hili.y : m_p2Hili.y;
m_celOutline1.x = (m_celOutline1.x / 2) * 2;
m_celOutline1.y = (m_celOutline1.y / 2) * 2;
m_celOutline2.x += 2;
m_celOutline2.y += 2;
}
else
{
m_celOutline1.x = -1;
m_celOutline2.x = -1;
}
}
// Sélectionne un blupi lorsque le bouton est pressé.
void CDecor::BlupiHiliDown (POINT pos, bool bAdd)
{
if (MapMove (pos))
return;
if (!bAdd)
BlupiDeselect ();
m_p1Hili = ConvPosToCel (pos);
m_p2Hili = ConvPosToCel (pos);
m_bHiliRect = true;
m_celHili.x = -1;
InitOutlineRect ();
}
// Sélectionne un blupi lorsque la souris est déplacée.
void CDecor::BlupiHiliMove (POINT pos)
{
if (m_bHiliRect) // rectangle de sélection existe ?
{
m_p2Hili = ConvPosToCel (pos);
InitOutlineRect ();
}
}
// Sélectionne un blupi lorsque le bouton est relâché.
// Retourne false si la sélection n'a pas changé !
void CDecor::BlupiHiliUp (POINT pos)
{
Sint32 rank, r, nb, sound;
bool bEnerve = false;
POINT c1, c2;
static Sint32 table_sound_ok[6] = {
SOUND_OK1, SOUND_OK2, SOUND_OK3, SOUND_OK4, SOUND_OK5, SOUND_OK6,
};
static Sint32 table_sound_okf[3] = // si fatigué
{
SOUND_OK1f, SOUND_OK2f, SOUND_OK3f,
};
static Sint32 table_sound_oke[3] = // si énervé
{
SOUND_OK1e, SOUND_OK2e, SOUND_OK3e,
};
if (m_bHiliRect) // rectangle de sélection existe ?
{
nb = 0;
if (m_p1Hili.x == m_p2Hili.x && m_p1Hili.y == m_p2Hili.y)
{
rank = GetTargetBlupi (pos); // rank <- blupi visé par la souris
if (rank != -1)
{
m_blupi[rank].bHili = !m_blupi[rank].bHili;
if (m_blupi[rank].bHili)
{
if (m_blupi[rank].clicDelay > 0)
{
m_blupi[rank].clicDelay = 80;
m_blupi[rank].clicCount++;
if (m_blupi[rank].clicCount > 4)
bEnerve = true;
}
else
m_blupi[rank].clicDelay = 40;
nb = 1;
}
}
}
else
{
if (m_p1Hili.x < m_p2Hili.x)
{
c1.x = m_p1Hili.x;
c2.x = m_p2Hili.x + 1;
}
else
{
c1.x = m_p2Hili.x;
c2.x = m_p1Hili.x + 1;
}
if (m_p1Hili.y < m_p2Hili.y)
{
c1.y = m_p1Hili.y;
c2.y = m_p2Hili.y + 1;
}
else
{
c1.y = m_p2Hili.y;
c2.y = m_p1Hili.y + 1;
}
for (r = 0; r < MAXBLUPI; r++)
{
if (
m_blupi[r].bExist && (m_blupi[r].perso == 0 || // blupi ?
m_blupi[r].perso == 8)) // disciple ?
{
if (
m_blupi[r].cel.x >= c1.x && m_blupi[r].cel.x < c2.x &&
m_blupi[r].cel.y >= c1.y && m_blupi[r].cel.y < c2.y)
{
m_blupi[r].bHili = true;
nb++;
rank = r;
}
}
}
}
m_bHiliRect = false; // plus de rectangle
InitOutlineRect ();
if (nb > 0)
{
if (nb > 1) // sélection multiple ?
sound = table_sound_ok[Random (0, 5)];
else
{
if (m_blupi[rank].energy <= MAXENERGY / 4)
sound = table_sound_okf[Random (0, 2)];
else
sound = table_sound_ok[Random (0, 5)];
if (bEnerve) // déjà sélectionné y'a peu ?
sound = table_sound_oke[Random (0, 2)];
}
BlupiSound (rank, sound, pos, true);
}
}
m_nbBlupiHili = 0;
m_rankBlupiHili = -1;
for (rank = 0; rank < MAXBLUPI; rank++)
{
m_blupi[rank].bArrow = false;
if (m_blupi[rank].bExist && m_blupi[rank].bHili)
{
m_nbBlupiHili++;
m_rankBlupiHili = rank;
}
}
}
// Dessine le rectangle de sélection, si nécessaire.
void CDecor::BlupiDrawHili ()
{
POINT c1, c2, cc;
POINT p1, p2, p3, p4;
POINT start, pos;
RECT rect;
Sint32 shift;
if (!m_bHiliRect)
return;
if (m_p1Hili.x < m_p2Hili.x)
{
c1.x = m_p1Hili.x;
c2.x = m_p2Hili.x + 1;
}
else
{
c1.x = m_p2Hili.x;
c2.x = m_p1Hili.x + 1;
}
if (m_p1Hili.y < m_p2Hili.y)
{
c1.y = m_p1Hili.y;
c2.y = m_p2Hili.y + 1;
}
else
{
c1.y = m_p2Hili.y;
c2.y = m_p1Hili.y + 1;
}
p1 = ConvCelToPos (c1); // p1 en haut
p2 = ConvCelToPos (c2); // p2 en bas
cc.x = c1.x;
cc.y = c2.y;
p3 = ConvCelToPos (cc); // p3 à gauche
cc.x = c2.x;
cc.y = c1.y;
p4 = ConvCelToPos (cc); // p4 à droite
p1.x += DIMCELX / 2;
p2.x += DIMCELX / 2;
p3.x += DIMCELX / 2;
p4.x += DIMCELX / 2;
shift = m_shiftHili % (64 / 2);
start.x = p1.x - shift * 2;
start.y = p1.y - shift - 1;
while (start.x < p4.x)
{
pos = start;
rect.left = 0;
rect.right = 64;
rect.top = 0;
rect.bottom = 66 / 2;
if (pos.x + rect.right > p4.x)
rect.right = p4.x - pos.x;
if (pos.x < p1.x)
{
rect.left += p1.x - pos.x;
rect.top += (p1.x - pos.x) / 2;
pos.x = p1.x;
pos.y = p1.y - 1;
}
m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p1-p4
start.x += 64;
start.y += 64 / 2;
}
start.x = p3.x - shift * 2;
start.y = p3.y - shift - 1;
while (start.x < p2.x)
{
pos = start;
rect.left = 0;
rect.right = 64;
rect.top = 0;
rect.bottom = 66 / 2;
if (pos.x + rect.right > p2.x)
rect.right = p2.x - pos.x;
if (pos.x < p3.x)
{
rect.left += p3.x - pos.x;
rect.top += (p3.x - pos.x) / 2;
pos.x = p3.x;
pos.y = p3.y - 1;
}
m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p3-p2
start.x += 64;
start.y += 64 / 2;
}
start.x = p3.x - shift * 2;
start.y = p3.y + shift - 66 / 2;
while (start.x < p1.x)
{
pos = start;
rect.left = 0;
rect.right = 64;
rect.top = 66 / 2;
rect.bottom = 66;
if (pos.x + rect.right > p1.x)
rect.right = p1.x - pos.x;
if (pos.x < p3.x)
{
rect.left += p3.x - pos.x;
rect.bottom -= (p3.x - pos.x) / 2;
pos.x = p3.x;
}
m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p3-p1
start.x += 64;
start.y -= 64 / 2;
}
start.x = p2.x - shift * 2;
start.y = p2.y + shift - 66 / 2;
while (start.x < p4.x)
{
pos = start;
rect.left = 0;
rect.right = 64;
rect.top = 66 / 2;
rect.bottom = 66;
if (pos.x + rect.right > p4.x)
rect.right = p4.x - pos.x;
if (pos.x < p2.x)
{
rect.left += p2.x - pos.x;
rect.bottom -= (p2.x - pos.x) / 2;
pos.x = p2.x;
}
m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p2-p4
start.x += 64;
start.y -= 64 / 2;
}
m_shiftHili += 3;
}
// Retourne le bouton par défaut à un endroit donné.
// Est utilisé pour trouver que faire lors d'un clic
// avec le bouton de droite.
Sint32 CDecor::GetDefButton (POINT cel)
{
Sint32 button, rank, channel, icon;
POINT iCel;
iCel = cel;
cel.x = (cel.x / 2) * 2;
cel.y = (cel.y / 2) * 2;
GetObject (cel, channel, icon);
if (m_nbBlupiHili == 0)
return -1;
if (m_nbBlupiHili > 1)
return BUTTON_GO;
rank = m_rankBlupiHili;
button = BUTTON_GO;
if (channel == CHOBJECT)
{
if (icon >= 7 && icon <= 11)
button = BUTTON_ABAT;
if (icon >= 37 && icon <= 43)
button = BUTTON_ROC;
if (icon == 61)
button = BUTTON_CULTIVE; // cabane
if (icon == 122)
button = BUTTON_EXTRAIT; // extrait
if (iCel.x % 2 == 1 && iCel.y % 2 == 1)
{
if (icon == 14)
button = BUTTON_CARRY; // métal
if (icon == 36)
button = BUTTON_CARRY; // planches
if (icon == 44)
button = BUTTON_CARRY; // pierres
if (icon == 60)
button = BUTTON_MANGE; // tomates
if (icon == 63)
button = BUTTON_CARRY; // oeufs
if (icon == 80)
button = BUTTON_BOIT; // bouteille
if (icon == 82)
button = BUTTON_CARRY; // fleurs
if (icon == 84)
button = BUTTON_CARRY; // fleurs
if (icon == 95)
button = BUTTON_CARRY; // fleurs
if (icon == 85)
button = BUTTON_CARRY; // dynamite
if (icon == 92)
button = BUTTON_CARRY; // poison
if (icon == 93)
button = BUTTON_CARRY; // piège
if (icon == 123)
button = BUTTON_CARRY; // fer
if (icon == 125)
button = BUTTON_CARRY; // mine
}
if (
icon == 28 && // laboratoire ?
m_blupi[rank].energy > MAXENERGY / 4 &&
m_blupi[rank].takeChannel == CHOBJECT &&
(m_blupi[rank].takeIcon == 82 || // porte fleurs ?
m_blupi[rank].takeIcon == 84 || m_blupi[rank].takeIcon == 95 ||
m_blupi[rank].takeIcon == 60)) // porte tomates ?
{
button = BUTTON_LABO; // transforme
}
}
if (!m_blupi[rank].bMalade && button == BUTTON_BOIT)
{
button = BUTTON_CARRY; // porte la bouteille si pas malade
}
if (
(m_blupi[rank].energy <= MAXENERGY / 4 ||
m_blupi[rank].takeChannel != -1) &&
(button == BUTTON_ABAT || button == BUTTON_CARRY || button == BUTTON_ROC ||
button == BUTTON_CULTIVE))
return -1;
if (m_blupi[rank].energy > (MAXENERGY / 4) * 3 && button == BUTTON_MANGE)
button = BUTTON_CARRY;
if (m_buttonExist[button] == 0) // bouton existe ?
return -1;
return button;
}
// Indique un but visé à Sint32 terme, pour un blupi donné.
bool CDecor::BlupiGoal (Sint32 rank, Sint32 button, POINT cel, POINT cMem)
{
POINT goalHili, goalHili2, goal, test;
Sint32 i, action, channel, icon, error, direct, step;
bool bRepeat = false;
// Si plusieurs blupi sont sélectionnés, ils ne vont pas
// tous à la même destination.
if (button == BUTTON_GO)
{
step = 0;
for (i = 0; i < rank; i++)
{
if (m_blupi[i].bExist && m_blupi[i].bHili)
step++;
}
if (step > 15)
step = 15;
cel.x += table_multi_goal[step * 2 + 0];
cel.y += table_multi_goal[step * 2 + 1];
cMem.x += table_multi_goal[step * 2 + 0];
cMem.y += table_multi_goal[step * 2 + 1];
}
if (!IsCheminFree (rank, cel, button))
return false;
goal = cel;
goalHili = cel;
goalHili2.x = (cel.x / 2) * 2;
goalHili2.y = (cel.y / 2) * 2;
if (
button == BUTTON_GO &&
m_decor[goalHili.x / 2][goalHili.y / 2].objectIcon == 113) // maison ?
{
goalHili.x = (goalHili.x / 2) * 2 + 1;
goalHili.y = (goalHili.y / 2) * 2 + 1;
}
if (button == BUTTON_ABATn)
{
button = BUTTON_ABAT;
bRepeat = true;
}
if (button == BUTTON_ROCn)
{
button = BUTTON_ROC;
bRepeat = true;
}
if (button == BUTTON_FLEURn)
{
button = BUTTON_FLEUR;
bRepeat = true;
}
action = table_actions[button];
if (action == WM_ACTION_STOP)
{
if (m_blupi[rank].goalAction != 0 && m_blupi[rank].interrupt <= 0)
{
m_blupi[rank].stop = 1; // faudra stopper
}
else
{
m_blupi[rank].goalCel = m_blupi[rank].destCel;
m_blupi[rank].goalAction = 0;
}
m_blupi[rank].repeatLevel = -1; // stoppe la répétition
return false;
}
// Action prioritaire en cours ?
if (m_blupi[rank].goalAction != 0 && m_blupi[rank].interrupt <= 0)
return false;
error = CelOkForAction (goalHili, action, rank);
if (error != 0 && error != Errors::TOURISOL)
return false;
if (
action == WM_ACTION_GO && m_blupi[rank].energy <= MAXENERGY / 4 &&
m_blupi[rank].takeChannel != -1)
return false;
if (action == WM_ACTION_GO)
{
GetObject (goalHili2, channel, icon);
if (
channel == CHOBJECT && icon == 120 && // usine ?
goalHili.x % 2 == 0 && // au fond ?
goalHili.y % 2 == 1)
{
return false; // action refusée
}
if (
m_blupi[rank].perso != 8 && // pas disciple ?
channel == CHOBJECT && icon == 118 && // jeep ?
goalHili.x % 2 == 1 && // sur la jeep ?
goalHili.y % 2 == 1)
action = WM_ACTION_MJEEP;
if (
m_blupi[rank].perso != 8 && // pas disciple ?
m_blupi[rank].takeChannel == -1 && // ne porte rien ?
channel == CHOBJECT && icon == 16 && // armure ?
goalHili.x % 2 == 1 && // sur l'armure ?
goalHili.y % 2 == 1)
action = WM_ACTION_MARMURE;
if (
m_blupi[rank].perso != 8 && // pas disciple ?
channel == CHOBJECT && icon == 113) // maison ?
action = WM_ACTION_MAISON;
GetFloor (goalHili2, channel, icon);
if (
m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 0 && // à pied ?
m_blupi[rank].takeChannel == -1 && // ne porte rien ?
channel == CHFLOOR && icon == 80) // téléporteur ?
{
if (cel.x % 2 == 0 && cel.y % 2 == 0)
action = WM_ACTION_TELEPORTE00;
if (cel.x % 2 == 1 && cel.y % 2 == 0)
action = WM_ACTION_TELEPORTE10;
if (cel.x % 2 == 0 && cel.y % 2 == 1)
action = WM_ACTION_TELEPORTE01;
if (cel.x % 2 == 1 && cel.y % 2 == 1)
action = WM_ACTION_TELEPORTE11;
}
IsFreeCelEmbarque (goalHili, rank, action, goal);
IsFreeCelDebarque (goalHili, rank, action, goal);
}
if (action == WM_ACTION_DEPOSE && m_blupi[rank].energy <= MAXENERGY / 4)
{
// Energie juste pour déposer l'objet transporté.
m_blupi[rank].energy = MAXENERGY / 4 + 20;
}
if (action == WM_ACTION_ABAT1)
{
GetObject (goalHili2, channel, icon);
if (channel == CHOBJECT && icon >= 6 && icon <= 11) // arbre ?
{
action += icon - 6; // WM_ACTION_ABAT1..6
}
}
if (action == WM_ACTION_ROC1)
{
GetObject (goalHili2, channel, icon);
if (channel == CHOBJECT && icon >= 37 && icon <= 43) // rochers ?
{
action += icon - 37; // WM_ACTION_ROC1..7
}
}
if (action == WM_ACTION_FLEUR1)
{
GetObject (goalHili2, channel, icon);
if (channel == CHOBJECT && icon == 83) // fleurs foncées ?
action = WM_ACTION_FLEUR2;
if (channel == CHOBJECT && icon == 94) // fleurs vertes ?
action = WM_ACTION_FLEUR3;
}
if (action == WM_ACTION_PONTE)
{
cel = goalHili2;
test = goalHili2;
if (IsBuildPont (test, icon) != 0)
return false;
m_blupi[rank].nLoop =
static_cast<Sint16> (abs ((test.x - cel.x) + (test.y - cel.y)) / 2);
m_blupi[rank].cLoop = 0;
m_blupi[rank].vIcon = icon;
m_blupi[rank].fix = cel;
if (test.x - cel.x < 0)
action = WM_ACTION_PONTO;
if (test.y - cel.y > 0)
action = WM_ACTION_PONTS;
if (test.y - cel.y < 0)
action = WM_ACTION_PONTN;
}
if (action == WM_ACTION_BATEAUE)
{
if (!IsBuildBateau (goalHili2, direct))
return false;
if (direct == DIRECT_S)
action = WM_ACTION_BATEAUS;
if (direct == DIRECT_O)
action = WM_ACTION_BATEAUO;
if (direct == DIRECT_N)
action = WM_ACTION_BATEAUN;
}
if (action == WM_ACTION_CARRY)
{
if (IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true))
action = WM_ACTION_CARRY2;
}
if (action == WM_ACTION_DEPOSE)
{
GetFloor (goalHili2, channel, icon);
if (
channel == CHFLOOR && icon == 52 && // nurserie ?
m_blupi[rank].takeChannel == CHOBJECT &&
m_blupi[rank].takeIcon == 63) // oeufs ?
action = WM_ACTION_NEWBLUPI;
if (
!IsFreeCelDepose (GetCel (goalHili2, 0, 1), rank) ||
IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true))
action = WM_ACTION_DEPOSE2;
}
if (action == WM_ACTION_MANGE)
{
if (IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true))
action = WM_ACTION_MANGE2;
}
if (action == WM_ACTION_BOIT)
{
if (IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true))
action = WM_ACTION_BOIT2;
}
if (action == WM_ACTION_DYNAMITE)
{
GetObject (goalHili2, channel, icon);
if (channel == CHOBJECT && icon == 125) // mine ?
action = WM_ACTION_MINE;
else
{
if (
m_blupi[rank].takeChannel == CHOBJECT &&
m_blupi[rank].takeIcon == 85) // porte dynamite ?
action = WM_ACTION_DYNAMITE2;
}
}
GoalStart (rank, action, goal);
m_blupi[rank].bRepeat = bRepeat;
m_blupi[rank].busyCount = 5; // 5 tentatives au maximum
m_blupi[rank].busyDelay = 0;
if (action == WM_ACTION_REPEAT)
{
m_blupi[rank].repeatLevel = m_blupi[rank].repeatLevelHope;
m_blupi[rank].listCel[m_blupi[rank].repeatLevel] = goal;
}
else
ListPut (rank, button, goal, cMem);
return true;
}
// Indique un but visé à Sint32 terme, pour tous les blupi
// sélectionnés.
void CDecor::BlupiGoal (POINT cel, Sint32 button)
{
POINT bPos, avg;
Sint32 rank, nb, nbHili;
static Sint32 table_sound_go[6] = {
SOUND_GO1, SOUND_GO2, SOUND_GO3, SOUND_GO4, SOUND_GO5, SOUND_GO6,
};
static Sint32 table_sound_gom[3] = {
SOUND_GO4, SOUND_GO5, SOUND_GO6,
};
static Sint32 table_sound_boing[3] = {
SOUND_BOING1, SOUND_BOING2, SOUND_BOING3,
};
if (button == -1)
{
avg = ConvCelToPos (cel);
m_pSound->PlayImage (table_sound_boing[Random (0, 2)], avg);
return;
}
avg.x = 0;
avg.y = 0;
nb = 0;
nbHili = 0;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (m_blupi[rank].bExist && m_blupi[rank].bHili)
{
bPos = ConvCelToPos (m_blupi[rank].cel);
avg.x += bPos.x;
avg.y += bPos.y;
nbHili++;
if (BlupiGoal (rank, button, cel, cel))
nb++;
}
}
if (button == BUTTON_STOP)
return;
if (nbHili > 0)
{
avg.x /= nbHili;
avg.y /= nbHili;
}
if (avg.x < 0)
avg.x = 0;
if (avg.x > LXIMAGE)
avg.x = LXIMAGE;
avg.y = LYIMAGE / 2;
if (nb == 0 && nbHili > 0)
{
if (nbHili == 1)
BlupiSound (m_rankBlupiHili, table_sound_boing[Random (0, 2)], avg, true);
else
m_pSound->PlayImage (table_sound_boing[Random (0, 2)], avg);
}
if (nb > 0)
{
if (nbHili == 1)
BlupiSound (m_rankBlupiHili, table_sound_go[Random (0, 5)], avg, true);
else
m_pSound->PlayImage (table_sound_gom[Random (0, 2)], avg);
}
}
// Indique si une cellule est occupée pour un tracks.
// La cellule est considérée libre uniquement si elle
// contient un blupi à pied ou un détonnateur de mine
// (personnage invisible).
bool CDecor::IsTracksHere (POINT cel, bool bSkipInMove)
{
Sint32 rank;
if (!IsValid (cel))
return false;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist &&
(m_blupi[rank].perso != 0 || // blupi ?
m_blupi[rank].vehicule != 0 || // à pied ?
m_bInvincible) &&
m_blupi[rank].perso != 6) // détonnateur ?
{
if (bSkipInMove && m_blupi[rank].goalCel.x != -1)
continue;
if (cel.x == m_blupi[rank].cel.x && cel.y == m_blupi[rank].cel.y)
{
m_blupiHere = rank;
return true;
}
if (cel.x == m_blupi[rank].destCel.x && cel.y == m_blupi[rank].destCel.y)
{
m_blupiHere = rank;
return true;
}
}
}
return false;
}
// Indique si une cellule est occupée par un blupi.
// Le blupi donné dans exRank est ignoré !
bool CDecor::IsBlupiHereEx (
POINT cel1, POINT cel2, Sint32 exRank, bool bSkipInMove)
{
Sint32 rank;
if (!IsValid (cel1))
return false;
if (!IsValid (cel2))
return false;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist &&
m_blupi[rank].perso != 6 && // pas le détonnateur de mine
rank != exRank)
{
if (bSkipInMove && m_blupi[rank].goalCel.x != -1)
continue;
if (
cel1.x <= m_blupi[rank].cel.x && cel2.x >= m_blupi[rank].cel.x &&
cel1.y <= m_blupi[rank].cel.y && cel2.y >= m_blupi[rank].cel.y)
{
m_blupiHere = rank;
return true;
}
if (
cel1.x <= m_blupi[rank].destCel.x &&
cel2.x >= m_blupi[rank].destCel.x &&
cel1.y <= m_blupi[rank].destCel.y && cel2.y >= m_blupi[rank].destCel.y)
{
m_blupiHere = rank;
return true;
}
}
}
return false;
}
// Indique si une cellule est occupée par un blupi.
// Le blupi donné dans exRank est ignoré !
bool CDecor::IsBlupiHereEx (POINT cel, Sint32 exRank, bool bSkipInMove)
{
Sint32 rank;
if (!IsValid (cel))
return false;
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (
m_blupi[rank].bExist &&
m_blupi[rank].perso != 6 && // pas le détonnateur de mine
rank != exRank)
{
if (bSkipInMove && m_blupi[rank].goalCel.x != -1)
continue;
if (cel.x == m_blupi[rank].cel.x && cel.y == m_blupi[rank].cel.y)
{
m_blupiHere = rank;
return true;
}
if (cel.x == m_blupi[rank].destCel.x && cel.y == m_blupi[rank].destCel.y)
{
m_blupiHere = rank;
return true;
}
}
}
return false;
}
// Indique si une cellule est occupée par un blupi.
bool CDecor::IsBlupiHere (POINT cel, bool bSkipInMove)
{
return IsBlupiHereEx (cel, -1, bSkipInMove);
}
// Indique si une cellule future (dans une direction donnée)
// est déjà occupée par un blupi.
bool CDecor::IsBlupiHere (POINT cel, Sint32 direct, bool bSkipInMove)
{
POINT vector;
vector = GetVector (direct);
cel.x += vector.x;
cel.y += vector.y;
return IsBlupiHereEx (cel, -1, bSkipInMove);
}
// Retourne les niveaux des jauges.
void CDecor::GetLevelJauge (Sint32 * pLevels, Sint32 * pTypes)
{
Sint32 rank;
pLevels[0] = -1;
pLevels[1] = -1;
rank = m_rankBlupiHili;
if (m_nbBlupiHili == 1) // un seul blupi sélectionné ?
{
pLevels[0] = (m_blupi[rank].energy * 100) / MAXENERGY;
pTypes[0] = 1; // rouge
if (m_blupi[rank].energy > MAXENERGY / 4)
{
pTypes[0] = 2; // bleu
}
}
if (m_blupi[rank].interrupt == 0 && m_blupi[rank].jaugeMax > 0)
{
pLevels[1] = (m_blupi[rank].jaugePhase * 100) / m_blupi[rank].jaugeMax;
pTypes[1] = 3; // jaune
}
}
// Retourne true si un blupi est déjà sélectionné et qu'il
// effectue une action prioritaire. Dans ce cas, il faut tout
// de suite mettre le menu "stoppe" s'il est cliqué.
bool CDecor::IsWorkBlupi (Sint32 rank)
{
if (
m_blupi[rank].bHili && m_blupi[m_rankBlupiHili].goalAction != 0 &&
m_blupi[m_rankBlupiHili].interrupt <= 0)
return true;
return false;
}
// Retourne les boutons possibles à un endroit donné,
// pour le blupi sélectionné.
void CDecor::BlupiGetButtons (
POINT pos, Sint32 & nb, Sint32 * pButtons, Errors * pErrors,
std::unordered_map<Sint32, const char *> & texts, Sint32 & perso)
{
Sint32 * pB = pButtons;
Errors * pE = pErrors;
POINT cel, cel2;
Sint32 i, rank, button, channel, icon;
Errors error;
bool bBuild = false;
bool bPut;
const char * textForButton;
static Sint32 table_buttons[] = {BUTTON_GO,
0,
BUTTON_DJEEP,
0,
BUTTON_DARMURE,
0,
BUTTON_MANGE,
0,
BUTTON_BOIT,
0,
BUTTON_CARRY,
0,
BUTTON_DEPOSE,
0,
BUTTON_LABO,
0,
BUTTON_ABAT,
0,
BUTTON_ABATn,
0,
BUTTON_ROC,
0,
BUTTON_ROCn,
0,
BUTTON_CULTIVE,
0,
BUTTON_FLEUR,
0,
BUTTON_FLEURn,
0,
BUTTON_DYNAMITE,
0,
BUTTON_DRAPEAU,
0,
BUTTON_EXTRAIT,
0,
BUTTON_FABJEEP,
0,
BUTTON_FABMINE,
0,
BUTTON_FABDISC,
0,
BUTTON_FABARMURE,
0,
BUTTON_BUILD1,
36, // si planches (cabane)
BUTTON_BUILD2,
36, // si planches (nurserie)
BUTTON_BUILD4,
36, // si planches (mine)
BUTTON_PALIS,
36, // si planches
BUTTON_PONT,
36, // si planches
BUTTON_BATEAU,
36, // si planches
BUTTON_BUILD6,
36, // si planches (téléporteur)
BUTTON_BUILD3,
44, // si pierres (laboratoire)
BUTTON_BUILD5,
44, // si pierres (usine)
BUTTON_MUR,
44, // si pierres
BUTTON_TOUR,
44, // si pierres
BUTTON_STOP,
0,
-1};
nb = 0;
perso = 0;
cel = ConvPosToCel (pos);
cel2 = ConvPosToCel2 (pos);
if (m_nbBlupiHili == 0)
return;
if (m_nbBlupiHili > 1) // sélection multiple ?
{
error = CelOkForAction (cel, table_actions[BUTTON_GO], m_rankBlupiHili);
if (error == 0)
{
*pB++ = BUTTON_GO;
*pE++ = Errors::NONE;
nb++;
}
for (rank = 0; rank < MAXBLUPI; rank++)
{
if (m_blupi[rank].bExist && m_blupi[rank].goalAction != 0)
{
*pB++ = BUTTON_STOP;
*pE++ = Errors::NONE;
nb++;
break;
}
}
return;
}
if (m_nbBlupiHili != 1)
return;
perso = m_blupi[m_rankBlupiHili].perso;
// Si action prioritaire en cours -> seulement stoppe.
if (
m_blupi[m_rankBlupiHili].goalAction != 0 &&
m_blupi[m_rankBlupiHili].interrupt <= 0)
{
if (
abs (m_blupi[m_rankBlupiHili].cel.x - cel.x) <= 3 &&
abs (m_blupi[m_rankBlupiHili].cel.y - cel.y) <= 3 &&
CelOkForAction (cel, table_actions[BUTTON_STOP], m_rankBlupiHili) == 0)
{
*pB++ = BUTTON_STOP;
*pE++ = Errors::NONE;
nb++;
}
return;
}
// Vérifie si le blupi sélectionné peut construire.
if (m_rankBlupiHili >= 0)
{
if (
m_blupi[m_rankBlupiHili].energy > MAXENERGY / 4 &&
m_blupi[m_rankBlupiHili].takeChannel == -1 &&
m_blupi[m_rankBlupiHili].vehicule == 0) // à pied ?
bBuild = true;
}
// Met les différentes actions.
i = 0;
while (table_buttons[i] != -1)
{
button = table_buttons[i];
if (m_buttonExist[button] == 0)
goto next;
error = CelOkForAction (cel, table_actions[button], m_rankBlupiHili);
if (error == 0)
bPut = true;
else
bPut = false;
if (
bBuild && table_buttons[i + 1] != 0 && // toujours présent si matière ?
(m_rankBlupiHili < 0 ||
m_blupi[m_rankBlupiHili].perso != 8 || // pas disciple ?
table_buttons[i + 1] != 44)) // ni pierres ?
{
GetObject (cel2, channel, icon);
if (
channel == CHOBJECT && icon == table_buttons[i + 1] && // matière ?
cel.x % 2 == 1 && cel.y % 2 == 1)
{
bPut = true; // bouton présent, mais disable !
}
}
if (bPut)
{
*pB++ = button;
*pE++ = error;
nb++;
}
next:
i += 2;
}
// Si le premier bouton est "abat", ajoute "va" devant !
if (pButtons[0] == BUTTON_ABAT)
{
for (i = nb; i > 0; i--)
{
pButtons[i] = pButtons[i - 1];
pErrors[i] = pErrors[i - 1];
}
pButtons[0] = BUTTON_GO;
pErrors[0] = Errors::MISC;
nb++;
}
// Regarde s'il faut ajouter le bouton "répète".
if (
m_blupi[m_rankBlupiHili].repeatLevel != -1 ||
m_blupi[m_rankBlupiHili].energy <= MAXENERGY / 4 ||
m_buttonExist[BUTTON_REPEAT] == 0)
return;
for (i = 0; i < nb; i++)
{
rank = ListSearch (m_rankBlupiHili, pButtons[i], cel, textForButton);
if (rank > 0) // au moins 2 actions à répéter ?
{
m_blupi[m_rankBlupiHili].repeatLevelHope = rank;
pButtons[nb] = BUTTON_REPEAT;
pErrors[nb] = Errors::REPEAT;
texts[nb] = textForButton;
nb++;
return;
}
}
}
// Initialise les conditions de fin.
void CDecor::TerminatedInit ()
{
m_winCount = 50;
m_winLastHachBlupi = 0;
m_winLastHachPlanche = 0;
m_winLastHachTomate = 0;
m_winLastHachMetal = 0;
m_winLastHachRobot = 0;
m_winLastHome = 0;
m_winLastHomeBlupi = 0;
m_winLastRobots = 0;
}
// Vérifie si la partie est terminée.
// Retourne 0 si la partie n'est pas terminée.
// Retourne 1 si la partie est perdue.
// Retourne 2 si la partie est gagnée.
Sint32 CDecor::IsTerminated ()
{
Sint32 nb, count, out;
POINT pos;
pos.x = LXIMAGE / 2;
pos.y = LYIMAGE / 2;
count = m_winCount;
m_winCount = 50;
if (m_winLastHome > m_nbStatHome) // une maison en moins ?
{
out = 1; // perdu
goto delay;
}
m_winLastHome = m_nbStatHome;
nb = StatisticGetBlupi ();
if (nb < m_term.nbMinBlupi)
{
out = 1; // perdu
goto delay;
}
if (nb < m_term.nbMaxBlupi)
return 0; // continue
if (m_term.bStopFire)
{
nb = StatisticGetFire ();
if (nb > 0)
return 0; // continue;
}
if (m_term.bHachBlupi)
{
if (m_winLastHachBlupi < m_nbStatHachBlupi)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastHachBlupi = m_nbStatHachBlupi;
if (m_nbStatHachBlupi < m_nbStatHach * 4)
return 0; // continue;
}
if (m_term.bHachPlanche)
{
if (m_winLastHachPlanche < m_nbStatHachPlanche)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastHachPlanche = m_nbStatHachPlanche;
if (m_nbStatHachPlanche < m_nbStatHach)
return 0; // continue;
}
if (m_term.bHachTomate)
{
if (m_winLastHachTomate < m_nbStatHachTomate)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastHachTomate = m_nbStatHachTomate;
if (m_nbStatHachTomate < m_nbStatHach)
return 0; // continue;
}
if (m_term.bHachMetal)
{
if (m_winLastHachMetal < m_nbStatHachMetal)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastHachMetal = m_nbStatHachMetal;
if (m_nbStatHachMetal < m_nbStatHach)
return 0; // continue;
}
if (m_term.bHachRobot)
{
if (m_winLastRobots > m_nbStatRobots)
{
out = 1; // perdu
goto delay;
}
m_winLastRobots = m_nbStatRobots;
if (m_winLastHachRobot < m_nbStatHachRobot)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastHachRobot = m_nbStatHachRobot;
if (m_nbStatHachRobot < m_nbStatHach)
return 0; // continue;
}
if (m_term.bHomeBlupi)
{
if (m_winLastHomeBlupi < m_nbStatHomeBlupi)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastHomeBlupi = m_nbStatHomeBlupi;
if (m_nbStatHomeBlupi < m_nbStatHome)
return 0; // continue;
}
if (m_term.bKillRobots)
{
if (m_winLastRobots > m_nbStatRobots)
m_pSound->PlayImage (SOUND_BUT, pos);
m_winLastRobots = m_nbStatRobots;
if (m_nbStatRobots > 0)
return 0; // continue;
}
out = 2; // gagné
delay:
m_winCount = count;
if (m_winCount == 0)
{
if (out == 1) // perdu ?
{
if (!m_pSound->PlayImage (SOUND_LOST, pos))
m_pSound->PlayImage (SOUND_BUT, pos);
}
else
{
if (!m_pSound->PlayImage (SOUND_WIN, pos))
m_pSound->PlayImage (SOUND_BUT, pos);
}
return out; // perdu/gagné
}
m_winCount--;
return 0; // continue
}
// Retourne la structure pour terminer une partie.
Term * CDecor::GetTerminated ()
{
return &m_term;
}