1
0
mirror of https://github.com/blupi-games/planetblupi synced 2024-12-30 10:15:36 +01:00
planetblupi/src/blupi.cpp

644 lines
16 KiB
C++
Raw Normal View History

2017-01-21 17:27:46 +01:00
#include <stdlib.h>
#include <stdio.h>
2017-02-09 23:06:36 +01:00
#include "blupi.h"
2017-01-21 17:27:46 +01:00
#include "def.h"
#include "resource.h"
#include "pixmap.h"
#include "sound.h"
#include "decor.h"
#include "movie.h"
#include "button.h"
#include "menu.h"
#include "jauge.h"
#include "event.h"
#include "misc.h"
// Global definitions
2017-01-21 17:27:46 +01:00
#define NAME "Blupi"
#define TITLE "Blupi"
2017-01-21 17:27:46 +01:00
// Global variables
2017-01-21 17:27:46 +01:00
SDL_Window *g_window;
SDL_Renderer *g_renderer;
2017-01-21 17:27:46 +01:00
CEvent *g_pEvent = nullptr;
CPixmap *g_pPixmap = nullptr; // pixmap principal
CSound *g_pSound = nullptr; // sound principal
CMovie *g_pMovie = nullptr; // movie principal
CDecor *g_pDecor = nullptr;
2017-01-21 17:27:46 +01:00
bool g_bFullScreen = false; // false si mode de test
Sint32 g_speedRate = 1;
Sint32 g_timerInterval = 50; // inverval = 50ms
Sint32 g_mouseType = MOUSETYPEGRA;
bool g_bActive = true; // is application active ?
bool g_bTermInit = false; // initialisation en cours
Uint32 g_lastPhase = 999;
2017-02-13 00:09:37 +01:00
int g_rendererType = 0;
2017-01-21 17:27:46 +01:00
2017-02-12 00:44:46 +01:00
// Lit un num�ro d�cimal.
2017-01-21 17:27:46 +01:00
static Sint32 GetNum (char *p)
2017-01-21 17:27:46 +01:00
{
Sint32 n = 0;
2017-01-21 17:27:46 +01:00
while (*p >= '0' && *p <= '9')
{
n *= 10;
n += (*p++) - '0';
}
2017-01-21 17:27:46 +01:00
return n;
2017-01-21 17:27:46 +01:00
}
// Lit le fichier de configuration.
static bool ReadConfig ()
2017-01-21 17:27:46 +01:00
{
FILE *file = nullptr;
char buffer[200];
char *pText;
size_t nb;
const auto config = GetBaseDir() + "data/config.ini";
file = fopen (config.c_str(), "rb");
if (file == nullptr)
return false;
nb = fread (buffer, sizeof (char), 200 - 1, file);
buffer[nb] = 0;
fclose (file);
pText = strstr (buffer, "SpeedRate=");
if (pText != nullptr)
{
g_speedRate = GetNum (pText + 10);
if (g_speedRate < 1)
g_speedRate = 1;
if (g_speedRate > 2)
g_speedRate = 2;
}
pText = strstr (buffer, "Timer=");
if (pText != nullptr)
{
g_timerInterval = GetNum (pText + 6);
if (g_timerInterval < 10)
g_timerInterval = 10;
if (g_timerInterval > 1000)
g_timerInterval = 1000;
}
pText = strstr (buffer, "FullScreen=");
if (pText != nullptr)
{
g_bFullScreen = !!GetNum (pText + 11);
if (g_bFullScreen != 0)
g_bFullScreen = 1;
}
pText = strstr (buffer, "MouseType=");
if (pText != nullptr)
{
g_mouseType = GetNum (pText + 10);
if (g_mouseType < 1)
g_mouseType = 1;
if (g_mouseType > 9)
g_mouseType = 9;
}
2017-02-13 00:09:37 +01:00
pText = strstr (buffer, "Renderer=");
if (pText)
{
if (!strncmp (pText + 9, "software", 8))
g_rendererType = SDL_RENDERER_SOFTWARE;
else if (!strncmp (pText + 9, "accelerated", 11))
g_rendererType = SDL_RENDERER_ACCELERATED;
}
return true;
2017-01-21 17:27:46 +01:00
}
// Main frame update
2017-01-21 17:27:46 +01:00
static void UpdateFrame (void)
2017-01-21 17:27:46 +01:00
{
RECT clip, rcRect;
Uint32 phase;
POINT posMouse;
Sint32 i, term, speed;
posMouse = g_pEvent->GetLastMousePos();
phase = g_pEvent->GetPhase();
SDL_RenderClear (g_renderer);
rcRect.left = 0;
rcRect.top = 0;
rcRect.right = LXIMAGE;
rcRect.bottom = LYIMAGE;
g_pPixmap->DrawImage (-1, CHBACK, rcRect); // dessine le fond
if (phase == WM_PHASE_INTRO1 ||
phase == WM_PHASE_INTRO2)
g_pEvent->IntroStep();
if (phase == WM_PHASE_PLAY)
{
clip.left = POSDRAWX;
clip.top = POSDRAWY + g_pDecor->GetInfoHeight();
clip.right = POSDRAWX + DIMDRAWX;
clip.bottom = POSDRAWY + DIMDRAWY;
if (g_pEvent->IsShift()) // shift en cours ?
{
g_pEvent->DecorAutoShift (posMouse);
g_pDecor->Build (clip, posMouse); // construit juste le d�cor
}
else
{
if (!g_pEvent->GetPause())
{
speed = g_pEvent->GetSpeed() * g_speedRate;
for (i = 0 ; i < speed ; i++)
{
g_pDecor->BlupiStep (i == 0); // avance tous les blupi
g_pDecor->MoveStep (i == 0); // avance tous les d�cors
g_pEvent->DemoStep(); // avance enregistrement/reproduction
}
}
g_pEvent->DecorAutoShift (posMouse);
g_pDecor->Build (clip, posMouse); // construit le d�cor
g_pDecor->NextPhase (1); // refait la carte de temps en temps
}
}
if (phase == WM_PHASE_BUILD)
{
clip.left = POSDRAWX;
clip.top = POSDRAWY;
clip.right = POSDRAWX + DIMDRAWX;
clip.bottom = POSDRAWY + DIMDRAWY;
g_pEvent->DecorAutoShift (posMouse);
g_pDecor->Build (clip, posMouse); // construit le d�cor
g_pDecor->NextPhase (-1); // refait la carte chaque fois
}
if (phase == WM_PHASE_INIT)
{
g_pEvent->DemoStep(); // d�marre �v. d�mo automatique
}
g_pEvent->DrawButtons();
g_lastPhase = phase;
if (phase == WM_PHASE_H0MOVIE ||
phase == WM_PHASE_H1MOVIE ||
phase == WM_PHASE_H2MOVIE ||
phase == WM_PHASE_PLAYMOVIE ||
phase == WM_PHASE_WINMOVIE)
{
g_pEvent->MovieToStart(); // fait d�marrer un film si n�cessaire
}
if (phase == WM_PHASE_INSERT)
g_pEvent->TryInsert();
if (phase == WM_PHASE_PLAY)
{
term = g_pDecor->IsTerminated();
if (term == 1)
g_pEvent->ChangePhase (WM_PHASE_LOST); // perdu
if (term == 2)
g_pEvent->ChangePhase (WM_PHASE_WINMOVIE); // gagn�
}
2017-01-21 17:27:46 +01:00
}
// Restore the game after a fullscreen enabling
2017-01-21 17:27:46 +01:00
static bool RestoreGame ()
2017-01-21 17:27:46 +01:00
{
if (g_pPixmap == nullptr)
return false;
2017-01-21 17:27:46 +01:00
g_pEvent->RestoreGame ();
return true;
2017-01-21 17:27:46 +01:00
}
// Flush the game before a fullscreen disabling
2017-01-21 17:27:46 +01:00
static bool FlushGame ()
2017-01-21 17:27:46 +01:00
{
if (g_pPixmap == nullptr)
return false;
2017-01-21 17:27:46 +01:00
return g_pPixmap->Flush ();
2017-01-21 17:27:46 +01:00
}
// Finished with all objects we use; release them.
static void FinishObjects (void)
2017-01-21 17:27:46 +01:00
{
if (g_pMovie != nullptr)
{
delete g_pMovie;
g_pMovie = nullptr;
}
if (g_pEvent != nullptr)
{
delete g_pEvent;
g_pEvent = nullptr;
}
if (g_pDecor != nullptr)
{
delete g_pDecor;
g_pDecor = nullptr;
}
if (g_pSound != nullptr)
{
g_pSound->StopMusic(); // stoppe la musique Midi
delete g_pSound;
g_pSound = nullptr;
}
if (g_pPixmap != nullptr)
{
delete g_pPixmap;
g_pPixmap = nullptr;
}
2017-01-21 17:27:46 +01:00
}
static void WindowProc2 (const SDL_Event &event)
2017-01-21 17:27:46 +01:00
{
POINT totalDim, iconDim;
if (g_pEvent != nullptr &&
g_pEvent->TreatEvent (event))
return;
switch (event.type)
{
case SDL_WINDOWEVENT:
{
switch (event.window.event)
{
case SDL_WINDOWEVENT_FOCUS_GAINED:
if (g_bFullScreen)
{
RestoreGame();
g_lastPhase = 999;
}
if (!g_bFullScreen && g_bTermInit)
{
totalDim.x = 64;
totalDim.y = 66;
iconDim.x = 64;
iconDim.y = 66 / 2;
2017-02-12 22:06:08 +01:00
g_pPixmap->Cache (CHHILI, "image/hili.png", totalDim, iconDim);
}
SDL_SetWindowTitle (g_window, "Blupi");
if (g_pSound != nullptr)
g_pSound->RestartMusic();
if (g_pMovie)
g_pMovie->Resume();
return;
case SDL_WINDOWEVENT_FOCUS_LOST:
if (g_bFullScreen)
FlushGame();
SDL_SetWindowTitle (g_window, "Blupi -- stop");
if (g_pSound != nullptr)
g_pSound->SuspendMusic();
if (g_pMovie)
g_pMovie->Pause();
return;
}
break;
}
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_F5:
g_pEvent->SetSpeed (1);
break;
case SDLK_F6:
g_pEvent->SetSpeed (2);
break;
case SDLK_F7:
g_pEvent->SetSpeed (4);
break;
case SDLK_F8:
g_pEvent->SetSpeed (8);
break;
}
break;
case SDL_USEREVENT:
{
switch (event.user.code)
{
case WM_UPDATE:
if (!g_pEvent->IsMovie()) // pas de film en cours ?
{
if (g_bActive)
UpdateFrame();
if (!g_pEvent->IsMovie ())
g_pPixmap->Display ();
}
break;
case WM_MUSIC_STOP:
if (g_pSound->IsStoppedOnDemand())
break;
g_pSound->RestartMusic();
break;
case WM_MOVIE_PLAY:
if (!g_pMovie->Render())
g_pEvent->StopMovie();
break;
}
break;
}
}
2017-01-28 23:34:02 +01:00
}
2017-01-21 17:27:46 +01:00
// Erreur dans DoInit.
static bool InitFail (const char *msg, bool bDirectX)
2017-01-21 17:27:46 +01:00
{
char buffer[100];
2017-01-21 17:27:46 +01:00
if (bDirectX)
strcpy (buffer, "DirectX Init FAILED\n(while ");
else
strcpy (buffer, "Error (");
strcat (buffer, msg);
strcat (buffer, ")");
2017-02-05 09:15:08 +01:00
SDL_ShowSimpleMessageBox (SDL_MessageBoxFlags::SDL_MESSAGEBOX_ERROR, "Error",
buffer, g_window);
2017-01-21 17:27:46 +01:00
FinishObjects();
return false;
2017-01-21 17:27:46 +01:00
}
// Initialisation de l'application.
static bool DoInit (Sint32 argc, char *argv[])
2017-01-21 17:27:46 +01:00
{
POINT totalDim, iconDim;
RECT rcRect;
bool bOK;
bOK = ReadConfig (); // lit le fichier config.ini
auto res = SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
if (res < 0)
return false;
// Create a window.
if (g_bFullScreen)
g_window = SDL_CreateWindow (NAME, 0, 0, LXIMAGE, LYIMAGE,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_INPUT_GRABBED);
else
g_window = SDL_CreateWindow (NAME, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, LXIMAGE, LYIMAGE, 0);
if (!g_window)
{
printf ("%s", SDL_GetError ());
return false;
}
2017-02-13 00:09:37 +01:00
g_renderer = SDL_CreateRenderer (g_window, -1, g_rendererType | SDL_RENDERER_TARGETTEXTURE);
if (!g_renderer)
{
printf ("%s", SDL_GetError ());
2017-02-13 00:09:37 +01:00
SDL_DestroyWindow (g_window);
return false;
}
if (!bOK) // config.ini pas correct ?
return InitFail ("Game not correctly installed", false);
// Cr�e le pixmap principal.
g_pPixmap = new CPixmap;
if (g_pPixmap == nullptr)
return InitFail ("New pixmap", true);
totalDim.x = LXIMAGE;
totalDim.y = LYIMAGE;
if (!g_pPixmap->Create (totalDim, g_bFullScreen, g_mouseType))
return InitFail ("Create pixmap", true);
OutputDebug ("Image: init\n");
totalDim.x = LXIMAGE;
totalDim.y = LYIMAGE;
iconDim.x = 0;
iconDim.y = 0;
2017-01-21 17:27:46 +01:00
#if _INTRO
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHBACK, "image/intro1.png", totalDim, iconDim))
2017-01-21 17:27:46 +01:00
#else
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHBACK, "image/init.png", totalDim, iconDim))
2017-01-21 17:27:46 +01:00
#endif
return false;
OutputDebug ("Image: init\n");
totalDim.x = LXIMAGE;
totalDim.y = LYIMAGE;
iconDim.x = 0;
iconDim.y = 0;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHGROUND, "image/init.png", totalDim, iconDim))
return false;
rcRect.left = 0;
rcRect.top = 0;
rcRect.right = LXIMAGE;
rcRect.bottom = LYIMAGE;
g_pPixmap->DrawImage (-1, CHBACK, rcRect); // dessine le fond
g_pPixmap->Display();
totalDim.x = DIMCELX * 2 * 16;
totalDim.y = DIMCELY * 2 * 6;
iconDim.x = DIMCELX * 2;
iconDim.y = DIMCELY * 2;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHFLOOR, "image/floor000.png", totalDim, iconDim))
return InitFail ("Cache floor000.png", true);
totalDim.x = DIMOBJX * 16;
totalDim.y = DIMOBJY * 8;
iconDim.x = DIMOBJX;
iconDim.y = DIMOBJY;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHOBJECT, "image/obj000.png", totalDim, iconDim))
return InitFail ("Cache obj000.png", true);
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHOBJECTo, "image/obj-o000.png", totalDim, iconDim))
return InitFail ("Cache obj-o000.png", true);
totalDim.x = DIMBLUPIX * 16;
totalDim.y = DIMBLUPIY * 23;
iconDim.x = DIMBLUPIX;
iconDim.y = DIMBLUPIY;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHBLUPI, "image/blupi.png", totalDim, iconDim))
return InitFail ("Cache blupi.png", true);
totalDim.x = 64;
totalDim.y = 66;
iconDim.x = 64;
iconDim.y = 66 / 2;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHHILI, "image/hili.png", totalDim, iconDim))
return InitFail ("Cache hili.png", true);
totalDim.x = DIMCELX * 2 * 3;
totalDim.y = DIMCELY * 2 * 5;
iconDim.x = DIMCELX * 2;
iconDim.y = DIMCELY * 2;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHFOG, "image/fog.png", totalDim, iconDim))
return InitFail ("Cache fog.png", true);
totalDim.x = DIMCELX * 2 * 16;
totalDim.y = DIMCELY * 2 * 1;
iconDim.x = DIMCELX * 2;
iconDim.y = DIMCELY * 2;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHMASK1, "image/mask1.png", totalDim, iconDim))
return InitFail ("Cache mask1.png", true);
totalDim.x = DIMBUTTONX * 6;
totalDim.y = DIMBUTTONY * 21;
iconDim.x = DIMBUTTONX;
iconDim.y = DIMBUTTONY;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHBUTTON, "image/button00.png", totalDim, iconDim))
return InitFail ("Cache button00.png", true);
totalDim.x = DIMJAUGEX * 1;
totalDim.y = DIMJAUGEY * 4;
iconDim.x = DIMJAUGEX;
iconDim.y = DIMJAUGEY;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHJAUGE, "image/jauge.png", totalDim, iconDim))
return InitFail ("Cache jauge.png", true);
totalDim.x = DIMTEXTX * 16;
totalDim.y = DIMTEXTY * 8 * 3;
iconDim.x = DIMTEXTX;
iconDim.y = DIMTEXTY;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHTEXT, "image/text.png", totalDim, iconDim))
return InitFail ("Cache text.png", true);
totalDim.x = DIMLITTLEX * 16;
totalDim.y = DIMLITTLEY * 8;
iconDim.x = DIMLITTLEX;
iconDim.y = DIMLITTLEY;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHLITTLE, "image/little.png", totalDim, iconDim))
return InitFail ("Cache little.png", true);
totalDim.x = 426;
totalDim.y = 52;
iconDim.x = 426;
iconDim.y = 52;
2017-02-12 22:06:08 +01:00
if (!g_pPixmap->Cache (CHBIGNUM, "image/bignum.png", totalDim, iconDim))
return InitFail ("Cache bignum.png", true);
// Load all cursors
g_pPixmap->LoadCursors();
g_pPixmap->ChangeSprite (SPRITE_WAIT); // met le sablier maison
// Cr�e le gestionnaire de son.
g_pSound = new CSound;
if (g_pSound == nullptr)
return InitFail ("New sound", true);
g_pSound->Create();
g_pSound->CacheAll();
g_pSound->SetState (true);
// Cr�e le gestionnaire de films.
g_pMovie = new CMovie;
if (g_pMovie == nullptr)
return InitFail ("New movie", false);
g_pMovie->Create();
// Cr�e le gestionnaire de d�cors.
g_pDecor = new CDecor;
if (g_pDecor == nullptr)
return InitFail ("New decor", false);
g_pDecor->Create (g_pSound, g_pPixmap);
g_pDecor->MapInitColors();
// Cr�e le gestionnaire d'�v�nements.
g_pEvent = new CEvent;
if (g_pEvent == nullptr)
return InitFail ("New event", false);
g_pEvent->Create (g_pPixmap, g_pDecor, g_pSound, g_pMovie);
g_pEvent->SetFullScreen (g_bFullScreen);
g_pEvent->SetMouseType (g_mouseType);
2017-01-21 17:27:46 +01:00
#if _INTRO
g_pEvent->ChangePhase (WM_PHASE_INTRO1);
2017-01-21 17:27:46 +01:00
#else
g_pEvent->ChangePhase (WM_PHASE_TESTCD);
2017-01-21 17:27:46 +01:00
#endif
g_bTermInit = true; // initialisation termin�e
return true;
2017-01-21 17:27:46 +01:00
}
static void initGettext ()
2017-01-21 17:27:46 +01:00
{
setlocale (LC_ALL, "");
textdomain ("planetblupi");
bindtextdomain ("planetblupi", (GetBaseDir () + "locale").c_str ());
2017-02-18 19:04:00 +01:00
bind_textdomain_codeset ("planetblupi", "UTF-8");
}
// Programme principal.
int main (int argc, char *argv[])
{
initGettext ();
if (!DoInit (argc, argv))
return -1;
SDL_TimerID updateTimer = SDL_AddTimer (g_timerInterval, [] (Uint32 interval,
void *param) -> Uint32
{
CEvent::PushUserEvent (WM_UPDATE);
return interval;
}, nullptr);
SDL_Event event;
while (SDL_WaitEvent (&event))
{
WindowProc2 (event);
if (event.type == SDL_QUIT)
break;
}
if (g_window)
SDL_DestroyWindow (g_window);
SDL_RemoveTimer (updateTimer);
FinishObjects();
SDL_Quit();
return 0;
2017-01-21 17:27:46 +01:00
}