diff --git a/Doxyfile b/Doxyfile index a7443b0..8baa703 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2059,7 +2059,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2067,7 +2067,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. diff --git a/Pontu/entryPoints/main.c b/Pontu/entryPoints/main.c index deadfcd..25e52db 100644 --- a/Pontu/entryPoints/main.c +++ b/Pontu/entryPoints/main.c @@ -6,6 +6,9 @@ #include "engine/TextureHandler.h" #include "model/Game.h" #include "view/GameDrawer.h" +#include "engine/ArrayUtils.h" +#include "model/arrayCoord.h" +#include "debug/printer.h" int main(int argc, char* argv[]) { @@ -27,7 +30,7 @@ int main(int argc, char* argv[]) goto Quit; } - renderer = SDL_CreateRenderer(window,-1,0); + renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED); if(!renderer) { fprintf(stderr, "Erreur : %s", SDL_GetError()); @@ -35,19 +38,22 @@ int main(int argc, char* argv[]) } InputProcessor inputProcessor = {.selectedCase = {.x=-1, .y=-1}}; + struct array_Coord interactiveCases = array_Coord_Create(); + int wBoardRect=99*3, hBoardRect=99*3; SDL_Rect boardRect = {.x=windowSize.w/2 - wBoardRect/2, .y=windowSize.h/2 - hBoardRect/2, .w=wBoardRect, .h=99*3}; const char* pseudos[] = {"Azerty","Bépo"}; - Game game = newGame(2, pseudos); + Game game = newGame(3, pseudos); TextureHandler textureHandler = newTextureHandler(renderer); + bool quit = false; while(!quit) { // Event handling InputElement inputElement; while (InputType_None != (inputElement = proccessInput(&inputProcessor, &boardRect)).type) { - + switch (inputElement.type) { case InputType_ActivateUI: @@ -66,22 +72,40 @@ int main(int argc, char* argv[]) break; case InputType_MoveGame: fprintf(stderr, "Move on board\n"); + fprintf(stderr, "From (%d; %d)\n", inputElement.data.move.start.x, inputElement.data.move.start.y); + fprintf(stderr, "To (%d; %d)\n", inputElement.data.move.end.x, inputElement.data.move.end.y); + moveOnBoard(inputElement.data.move.start, inputElement.data.move.end, &game); break; case InputType_ClickGame: fprintf(stderr, "Clic on board (%d; %d)\n", inputElement.data.coord.x, inputElement.data.coord.y); - fflush(stderr); + fprintf(stderr, "\tSelected case : (%d; %d)\n", inputProcessor.selectedCase.x, inputProcessor.selectedCase.y); + + if(!array_Coord_Contains(&interactiveCases, inputElement.data.coord, *coordEqual)) { + fprintf(stderr, "\tselected case reset\n"); + inputProcessor.selectedCase = newCoord(-1,-1); + } + if (clickOnBoard(inputElement.data.coord, &game)) { + fprintf(stderr, "\tselected case reset\n"); inputProcessor.selectedCase = newCoord(-1,-1); } + + break; case InputType_None: default: break; } + + array_Coord_Free(&interactiveCases); + interactiveCases = getInteractiveCases(&game, inputProcessor.selectedCase); + fprintf(stderr, "Interactive cases : {"); + array_Coord_Foreach(&interactiveCases, *printCoord); + fprintf(stderr, "}\n"); } - - + + fflush(stderr); // Drawing drawGame(renderer, &windowSize, &boardRect, &game, &textureHandler); @@ -95,6 +119,7 @@ int main(int argc, char* argv[]) Quit: freeTextureHandler(&textureHandler); + array_Coord_Free(&interactiveCases); if(renderer != NULL) { SDL_DestroyRenderer(renderer); } diff --git a/Pontu/include/debug/printer.h b/Pontu/include/debug/printer.h new file mode 100644 index 0000000..38064fb --- /dev/null +++ b/Pontu/include/debug/printer.h @@ -0,0 +1,8 @@ +#ifndef PRINTER_INCLUDED +#define PRINTER_INCLUDED + +#include + +void printCoord(const Coord coord); + +#endif //PRINTER_INCLUDED diff --git a/Pontu/include/engine/ArrayUtils.h b/Pontu/include/engine/ArrayUtils.h new file mode 100644 index 0000000..326e48e --- /dev/null +++ b/Pontu/include/engine/ArrayUtils.h @@ -0,0 +1,106 @@ +/** + * \file ArrayUtils.h + * \brief This file define a macro used to generate dynamic array structs and associated functions + * \author Martin Rouault + * \date 3/01/2022 + */ + +#ifndef ARRAY_UTILS_INCLUDED +#define ARRAY_UTILS_INCLUDED + +#include +#include +#include +#include + +/** + * \brief Generate a dynamic array for type T + * If you want an int array use + * GENERATE_DYNAMIC_ARRAY(int) + + * If you miss a function, write it with a type as int first then rewrite it in the macro + * You will need to follow function naming convetions to avoid multiple functions with the same name + * Functions in header must be marked as inline + * Don't forget antislashes + */ +#define GENERATE_DYNAMIC_ARRAY(T) \ +struct array_##T { \ + T* elems; \ + size_t arraySize; \ + size_t arraySpace; \ +}; \ +\ +/*Contruct an empty array*/\ +inline struct array_##T array_##T##_Create() { \ + struct array_##T array = {.elems=NULL, .arraySize=0, .arraySpace=0}; \ + return array; \ +} \ +\ +/*Free an array*/ \ +inline void array_##T##_Free(struct array_##T* array) { \ + free(array->elems); \ + array->elems = NULL; \ + array->arraySize = 0; \ + array->arraySpace = 0; \ +} \ +\ +/*Reserve space for an array*/\ +inline void array_##T##_Reserve(struct array_##T* array, const size_t space) { \ + array->arraySpace = space; \ + array->elems = realloc(array->elems, sizeof(T)*(array->arraySpace)); \ + if (array->elems == NULL) exit(errno); \ +} \ +\ +/*Fit space to size for an array*/\ +inline void array_##T##_FitToSize(struct array_##T* array) { \ + array->arraySpace = array->arraySize; \ + array->elems = realloc(array->elems, sizeof(T)*(array->arraySpace)); \ + if (array->elems == NULL) exit(errno); \ +} \ +\ +/*Add an element to an array*/\ +inline void array_##T##_AddElement(struct array_##T* array, const T element) { \ + ++(array->arraySize); \ + if (array->arraySize > array->arraySpace) { \ + ++(array->arraySpace); \ + array->elems = realloc(array->elems, sizeof(T)*(array->arraySpace)); \ + if (array->elems == NULL) exit(errno); \ + } \ + \ + array->elems[array->arraySize - 1] = element; \ +} \ +\ +/*Remove an element from an array*/\ +inline bool array_##T##_RemoveElement(struct array_##T* array, const T element, bool (*areEqual)(const T, const T)) { \ + for (size_t i=0; iarraySize; ++i) { \ + if (areEqual(array->elems[i], element)) { \ + for (;iarraySize-1; ++i) { \ + array->elems[i] = array->elems[i+1]; \ + } \ + --(array->arraySize); \ + return true; \ + } \ + } \ + return false; \ +} \ +\ +/*Check if an array contains an element*/\ +inline bool array_##T##_Contains(const struct array_##T* const array, const T element, bool (*areEqual)(const T, const T)) { \ + for (size_t i = 0; i < array->arraySize; i++) { \ + if (areEqual(array->elems[i], element)) { \ + return true; \ + } \ + } \ + return false; \ +}\ +\ +/*Apply a function to each element in the array*/\ +inline void array_##T##_Foreach(const struct array_##T* const array, void (*func)(const T)) { \ + for(size_t i = 0; iarraySize; ++i) { \ + func(array->elems[i]);\ + }\ +} + + + +#endif //ARRAY_UTILS_INCLUDED diff --git a/Pontu/include/engine/Audio.h b/Pontu/include/engine/Audio.h deleted file mode 100644 index de1be9c..0000000 --- a/Pontu/include/engine/Audio.h +++ /dev/null @@ -1,23 +0,0 @@ -/** - * \file Audio.h - * \brief Audio management - * \author Théotime Maillarbaux - * \date 13/12/2021 - */ - -#ifndef AUDIO_H -#define AUDIO_H - -#include - -/** - * \brief Fades out a music and plays another one. - * \param[in] music A pointer to the Mix_Music struct used to play the current track - * \param[in] path The path to the new track to be played - * \warning The program won't know if it failed. - * - * This function creates a thread that will detach on its own completion. - */ -void switchMusic(Mix_Music* music, char path[]); - -#endif // AUDIO_H diff --git a/Pontu/include/engine/AudioHandler.h b/Pontu/include/engine/AudioHandler.h new file mode 100644 index 0000000..cf64ba5 --- /dev/null +++ b/Pontu/include/engine/AudioHandler.h @@ -0,0 +1,126 @@ +/** + * \file AudioHandler.h + * \brief Audio management (music and sound effects) + * \author Théotime Maillarbaux + * \date 13/12/2021 + */ + +#ifndef AUDIO_H +#define AUDIO_H + +#include +#include +#include +#include + +/** + * Macro used to generate enums elements and paths for musics. + * It should take either #MACRO_MUSIC_ENUM_GEN(E) or #MACRO_TO_MUSIC_PATH(P) + * as parameter. + * + * If new audios are added to the program, they should be added here. + * \sa #MACRO_FOR_ALL_SFX(E) + */ +#define MACRO_FOR_ALL_MUSICS(M) \ + M(base_tardi) \ + M(testMus) + +/** + * Macro used to generate enums elements and paths for sound effects. + * It works the same way as #MACRO_FOR_ALL_MUSICS(M). + * \sa #MACRO_FOR_ALL_MUSICS(M) + */ +#define MACRO_FOR_ALL_SFX(M) \ + M(testClick) + +/** + * Macro used to generate the entries for the musics in #EnumAudios. + * It should be used in #MACRO_FOR_ALL_MUSICS(M) as a parameter. + * Each entry of #MACRO_FOR_ALL_MUSICS(M) will be converted as MUSIC_name. + * \sa #MACRO_SFX_ENUM_GEN(E) + */ +#define MACRO_MUSIC_ENUM_GEN(E) MUSIC_##E, + +/** + * Macro used to generate the entries for the SFX in #EnumAudios. + * It works the same way as #MACRO_MUSIC_ENUM_GEN(E), except the entries start with SFX_ + * instead of MUSIC_. + * \sa #MACRO_MUSIC_ENUM_GEN(E). + */ +#define MACRO_SFX_ENUM_GEN(E) SFX_##E, + +/** + * Macro used to generate the paths to the musics. + * It should be used in #MACRO_FOR_ALL_MUSICS(M) as a parameter. + * Each entry of #MACRO_FOR_ALL_MUSICS(M) will be converted as rsrc/music/name.mp3. + * \sa #MACRO_TO_SFX_PATH(P) + */ +#define MACRO_TO_MUSIC_PATH(P) "rsrc/music/"#P".mp3", + +/** + * Macro used to generate the paths to the SFX. + * It works the same way as #MACRO_TO_MUSIC_PATH(P), + * except the entries are converted to rsrc/sfx/name.wav. + * \sa MACRO_TO_MUSIC_PATH(P) + */ +#define MACRO_TO_SFX_PATH(P) "rsrc/sfx/"#P".wav", + +/** + * \enum EnumAudios + * \brief Lists audios used in the program. + */ +typedef enum { + MACRO_FOR_ALL_MUSICS(MACRO_MUSIC_ENUM_GEN) + NB_MUSIC_DEFINED, ///< Index of this entry == number of musics + MACRO_FOR_ALL_SFX(MACRO_SFX_ENUM_GEN) + NB_AUDIO_DEFINED ///< Index of this entry == number of audios + 1 +} EnumAudios; + +/** + * \struct AudioHandler + * \brief A struct to store and handle all audios. + */ +typedef struct { + bool canPlayAudio; ///< true if audio could be initialized, else false. It shouldn't be changed manually. + Mix_Music* musics[NB_MUSIC_DEFINED]; ///< Paths to the musics + Mix_Chunk* sfx[NB_AUDIO_DEFINED - NB_MUSIC_DEFINED - 1]; ///< Paths to the SFX +} AudioHandler; + +/** + * \brief Initializes the audio and creates a new AudioHandler. + * \param[in] volMusic Volume of the music + * \param[in] volSFX Volume of the sound effects. + * \return A new AudioHandler. + * \warning The program won't know if opening the audio device and the files failed. + */ +AudioHandler newAudioHandler(int volMusic, int volSFX); + +/** + * \brief Changes volume for the SFX. + * \param[in] volSFX The new volume for the SFX. + */ +void changeSFXVol(int volSFX); + +/** + * \brief Frees the music and SFX, and un-initializes the audio. + * \param[in,out] audioHandler A pointer to the AudioHandler to be freed. + */ +void freeAudioHandler(AudioHandler audioHandler); + +/** + * \brief Plays a music. If another music is currently playing, the previous one will fade out. + * \param[in] music The music to be played. Should be a value of #EnumAudios starting with MUSIC_. + * \param[in] audioHandler The AudioHandler used to store the musics. + */ +void playMusic(EnumAudios music, AudioHandler audioHandler); + +/** + * \brief Plays a sound effect. + * \param[in] sfx The SFX to be played. Should be a value of #EnumAudios starting with SFX_. + * \param[in] channel The channel the SFX should be played on. + * \param[in] audioHandler The AudioHandler used to store the SFX. + */ +void playSFX(EnumAudios sfx, int channel, AudioHandler audioHandler); + + +#endif // AUDIO_H diff --git a/Pontu/include/engine/TextureHandler.h b/Pontu/include/engine/TextureHandler.h index 4696d6b..149a954 100644 --- a/Pontu/include/engine/TextureHandler.h +++ b/Pontu/include/engine/TextureHandler.h @@ -12,18 +12,23 @@ #include #include "engine/TextureLoader.h" -// List here the different texture to handle -// In the enum -// Island become TEXTURE_Island -// In file -// Island become Island.png +/** List here the different texture to handle + * In the enum + * Island become TEXTURE_Island + * In file + * Island become Island.png + * \sa MACRO_TEXTURE_ENUM_GEN(E) + */ #define MACRO_FOR_ALL_TEXTURES(M) \ M(Island) \ M(Bridge) \ M(Piece) \ M(Water) -// Allow the generation of enum +/** + * \brief Allow the generation of enum + * \sa MACRO_FOR_ALL_TEXTURES(M) + */ #define MACRO_TEXTURE_ENUM_GEN(E) TEXTURE_##E, /** @@ -50,7 +55,7 @@ typedef struct /** * \brief Create a TextureHandler and load each texture defined in MACRO_FOR_ALL_TEXTURES in it * \param renderer The renderer which is passed to texture when they are created - * \return ** TextureHandler filled with textures + * \return TextureHandler filled with textures */ TextureHandler newTextureHandler(SDL_Renderer* renderer); diff --git a/Pontu/include/engine/TextureLoader.h b/Pontu/include/engine/TextureLoader.h index 8a06dbb..c006435 100644 --- a/Pontu/include/engine/TextureLoader.h +++ b/Pontu/include/engine/TextureLoader.h @@ -1,3 +1,9 @@ +/** + * \file TextureLoader.h + * \brief Define functions to load textures + * \author Allan Point + */ + #include #include #include diff --git a/Pontu/include/model/Bridge.h b/Pontu/include/model/Bridge.h index a4374a6..152a5d1 100644 --- a/Pontu/include/model/Bridge.h +++ b/Pontu/include/model/Bridge.h @@ -1,7 +1,7 @@ /** * \file Bridge.h * \brief Bridge - * \autor Martin Rouault, Jacques Thomas + * \author Martin Rouault, Jacques Thomas * \date 13/12/2021 */ diff --git a/Pontu/include/model/Coord.h b/Pontu/include/model/Coord.h index c41afbd..0891866 100644 --- a/Pontu/include/model/Coord.h +++ b/Pontu/include/model/Coord.h @@ -9,6 +9,8 @@ #define COORD_INCLUDED #include +#include "model/Island.h" +#include "engine/ArrayUtils.h" /** * \struct Coord @@ -46,4 +48,12 @@ bool coordValid(const Coord coord); */ bool coordEqual(const Coord a, const Coord b); +/** + * \brief Convert an island to a coord + * + * \param[in] island The island to convert + * \return Coord from the island + */ +Coord islandToCoord(const Island* island); + #endif //COORD_INCLUDED diff --git a/Pontu/include/model/Game.h b/Pontu/include/model/Game.h index 94ce9ab..3737dbb 100644 --- a/Pontu/include/model/Game.h +++ b/Pontu/include/model/Game.h @@ -1,7 +1,7 @@ /** * \file Game.h * \brief Management of a Game - * \author Théotime Maillarbaux, Jacques Thomas + * \author Théotime Maillarbaux, Jacques Thomas, Martin Rouault * \date 29/11/2021 */ @@ -13,6 +13,7 @@ #include "model/Bridge.h" #include "model/Island.h" #include "model/Coord.h" +#include "model/arrayCoord.h" #include #include @@ -37,7 +38,7 @@ typedef struct { //TODO duree Phase phase; ///< The current state of the game Player arrPlayers[4]; ///< The array of all the players in this game - size_t nbPlayers; + size_t nbPlayers; Board board; ///< The board for this game } Game; @@ -146,6 +147,7 @@ bool checkBridge(const Island start, const Island target, const Board* b); * \param[in] arrPieces Array of all pieces * \param[in] logicalSize The logical size of arrPieces * \param[in] island The island on the one we want to check the piece + * \return the piece address if there is one the island otherwise return NULL */ Piece* getPieceFromIsland(Piece arrPieces[9], const size_t logicalSize, const Island island); @@ -177,5 +179,14 @@ bool clickOnBoard(const Coord coord, Game* game); */ bool rmBridge(Bridge bridge, Board* board); +/** + * \brief List cases that can be interacted with for movement + * + * \param[in] game The game + * \param[in] selectedCase The selected case + * \return struct array_Coord An array of coord /!\ Care to free this array with array_Coord_Free + */ +struct array_Coord getInteractiveCases(const Game* const game, const Coord selectedCase); + #endif //GAME_H diff --git a/Pontu/include/model/arrayCoord.h b/Pontu/include/model/arrayCoord.h new file mode 100644 index 0000000..031be97 --- /dev/null +++ b/Pontu/include/model/arrayCoord.h @@ -0,0 +1,9 @@ +#ifndef ARRAY_COORD_INCLUDED +#define ARRAY_COORD_INCLUDED + +#include "model/Coord.h" +#include "engine/ArrayUtils.h" + +GENERATE_DYNAMIC_ARRAY(Coord) + +#endif //ARRAY_COORD_INCLUDED diff --git a/Pontu/rsrc/sfx/testClick.wav b/Pontu/rsrc/sfx/testClick.wav new file mode 100644 index 0000000..9a556e5 Binary files /dev/null and b/Pontu/rsrc/sfx/testClick.wav differ diff --git a/Pontu/src/debug/printer.c b/Pontu/src/debug/printer.c new file mode 100644 index 0000000..a1b8451 --- /dev/null +++ b/Pontu/src/debug/printer.c @@ -0,0 +1,7 @@ +#include "debug/printer.h" +#include + +void printCoord(const Coord coord) { + fprintf(stderr, "(%d, %d)", coord.x, coord.y); +} + diff --git a/Pontu/src/engine/Audio.c b/Pontu/src/engine/Audio.c deleted file mode 100644 index b8ba560..0000000 --- a/Pontu/src/engine/Audio.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "engine/Audio.h" - -struct params { - Mix_Music* music; // AA pointer to the Mix_Music struct used for the current track - char* path; // The path to the new track to be played -}; - -int fadeOut(void* args) { - struct params* argsCast = (struct params*)args; - Mix_Music* newMusic = Mix_LoadMUS(argsCast->path); - if (argsCast->music != NULL) { - if(Mix_FadeOutMusic(500) == 0) { - while (Mix_PlayingMusic()) { - ; - } - } - } - if (newMusic != NULL) { - argsCast->music = newMusic; - return Mix_PlayMusic(argsCast->music,-1); - } - else return -2; -} - -void switchMusic(Mix_Music* music, char path[]) { - struct params args = { - .music = music, - .path = path - }; - SDL_Thread* thread = SDL_CreateThread(&fadeOut, "Fade out", (void*)&args); - - - SDL_DetachThread(thread); // Won't wait until thread is done to continue -} - diff --git a/Pontu/src/engine/AudioHandler.c b/Pontu/src/engine/AudioHandler.c new file mode 100644 index 0000000..06e8ced --- /dev/null +++ b/Pontu/src/engine/AudioHandler.c @@ -0,0 +1,186 @@ +#include "engine/AudioHandler.h" + +// A channel represents the number of SFX we can play at the same time. +// We normally should use only 1 channel, and we add one for safety. +#define NBCHANNELS 2 + +// Local functions + +/* + * Used in a thread. Fades out the currently played music, + * then plays the music passed in as parameter. + * args should be passed as a pointer to void, + * but should actually be a pointer to Mix_Music. + * It is the music we want to play next; + */ +int fadeOut(void* args) { + // Since args is a pointer to void + // (the way C handles undefined types), + // casting args to a pointer to Mix_Music + Mix_Music* = (Mix_Music*)args; + int ret; + + if(Mix_FadeOutMusic(500) == 0) { // Starting the fadeout + while (Mix_PlayingMusic()) { + ; // Waiting until it's done + } + } else { + fprintf(stderr,"WARNING: couldn't fade out"); + Mix_HaltMusic(); + } + + ret = Mix_PlayMusic(argsCast->music,-1); + if (ret != 0) { + fprintf(stderr,"WARNING: %s\n",Mix_GetError()); + } + + // We're supposed to return an int to use SDL_thread. + // We're not using the return value though. + return ret; +} + +// Global functions + +AudioHandler newAudioHandler(int volMusic, int volSFX) { + AudioHandler audioHandler; + int nb_SFX = NB_AUDIO_DEFINED - NB_MUSC_DEFINED - 1; + + // Generating paths to musics and SFX files using macros + char* musicsPaths[] = {MACRO_FOR_ALL_MUSICS(MACRO_TO_MUSIC_PATH)}; + char* sfxPaths[] = {MACRO_FOR_ALL_SFX(MACRO_TO_SFX_PATH)}; + audioHandler.canPlayAudio = true; + + // Initialize + verify opening audio device + if (0 != Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)) { + fprintf(stderr,"Error when initializing audio.\n"); + return audioHandler; + } + + audioHandler.canPlayAudio = true; + + fprintf(stderr,"Musics: %d\nSFX: %d\n",NB_MUSIC_DEFINED,nb_SFX); + + // Loading musics + for (size_t i = 0; i < NB_MUSIC_DEFINED; i++) { + if ((audioHandler.musics[i] = LoadMUS(musicPaths[i]) == NULL)) { + fprintf(stderr,"WARNING: %s\n",Mix_GetError()); + } else { + fprintf(stderr,"Loaded %s\n",musicPaths[i]); + } + } + + Mix_VolumeMusic(volMusic); + + // Initializing SFX + Mix_AllocateChannels(NBCHANNELS); + + // Loading SFX + for (size_t i = 0; i < nb_SFX; i++) { + if ((audioHandler.sfx[i] = Mix_LoadWAV(sfxPaths[i])) == NULL) { + fprintf(stderr,"WARNING: %s\n",Mix_GetError()); + } else { + fprintf(stderr,"Loaded %s\n",sfxPaths[i]); + } + } + + changeSFXVol(volSFX); + return audioHandler; +} + +void changeSFXVol(int volSFX) { + for (size_t i = 0; i < NBCHANNELS; i++) { + Mix_Volume(i, volSFX); + } +} + +void freeAudioHandler(AudioHandler* audioHandler) { + // Freeing the music + Mix_HaltMusic(); + for (size_t i = 0; i < NB_MUSIC_DEFINED; i++) { + if (audioHandler->musics[i] != NULL) { + Mix_FreeMusic(audioHandler->musics[i]); + audioHandler->musics[i] = NULL; // "to be safe...", says the docs + } + } + + // Freeing the SFX + Mix_HaltChannel(-1); // Stopping playback on ALL channels + for (size_t i = 0; i < NB_AUDIO_DEFINED - NB_MUSIC_DEFINED - 1; i++) { + if (audioHandler->sfx[i] != NULL) { + Mix_FreeChunk(audioHandler->sfx[i]); + audioHandler->sfx[i] = NULL; // "to be safe...", says the docs + } + } + Mix_AllocateChannels(0); // Unallocating all channels + + // Un-initializing the audio + Mix_CloseAudio(); + + audioHandler->canPlayAudio = false; +} + +void playMusic(EnumAudios music, AudioHandler audioHandler) { + // music should be a value of EnumAudios that starts by MUSIC_ + // In other words, it should be an enumerator before NB_MUSIC_DEFINED. + if (music >= NB_MUSIC_DEFINED) { + fprintf(stderr,"WARNING: tried to play an arbitrary value as a music\n"); + return; + } + + // Checking if audio has been opened. + if (!(audioHandler.canPlayAudio)) { + fprintf(stderr,"WARNING: tried to play a music with an unusable AudioHandler\n"); + return; + } + + // If another music is playing, fading the previous one out + if (Mix_PlayingMusic()) { + // Creating the thread, passing the music as parameter + SDL_Thread* thread = SDL_CreateThread(&fadeOut, "Fade out", (void*)audioHandler.musics[music]); + if (thread == NULL) { + fprintf(stderr,"WARNING: couldn't create thread to fade out music\n"); + } + // playMusic won't wait until the thread is finished to end + SDL_DetachThread(thread); + // No other music is playing: starting a music normally. + } else { + if (Mix_PlayMusic(audioHandler.musics[music],-1) != 0) { + fprintf("WARNING: %s\n",Mix_GetError()); + } + } +} + +void playSFX(EnumAudios sfx, AudioHandler audioHandler) { + int nb_SFX = NB_AUDIO_DEFINED - NB_MUSIC_DEFINED - 1; + int channel; + Mix_Chunk* chunkSFX; + + // sfx should be a value of EnumAudios that starts by SFX_. + // In other words, it should be an enumerator after NB_MUSIC_DEFINED but before NB_AUDIO_DEFINED. + if (sfx <= NB_MUSIC_DEFINED || sfx >= NB_AUDIO_DEFINED) { + fprintf(stderr,"WARNING: tried to play an arbitrary value as a SFX\n"); + return; + } + + // Checking if SFX has been opened. + if (!(audioHandler.canPlayAudio)) { + fprintf(stderr,"WARNING: tried to play an SFX with an unusable AudioHandler\n"); + return; + } + + // Getting actual chunk + chunkSFX = audioHandler.sfx[sfx - NB_MUSIC_DEFINED - 1]; + // Getting first available channel + channel = Mix_GroupAvailable(-1); + if (channel == -1) { + fprintf(stderr,"WARNING: cannot play SFX because all channels are used\n"); + return; + } + + // Playing the SFX once (0 repetitions) + if (Mix_PlayChannel(channel,chunkSFX,0) != 0) { + fprintf(stderr,"WARNING: %s\n",Mix_GetError()); + return; + } +} + diff --git a/Pontu/src/model/Coord.c b/Pontu/src/model/Coord.c index 3bacee9..efd7dea 100644 --- a/Pontu/src/model/Coord.c +++ b/Pontu/src/model/Coord.c @@ -15,3 +15,8 @@ bool coordEqual(const Coord a, const Coord b) { return a.x == b.x && a.y == b.y; } + +Coord islandToCoord(const Island* island) { + Coord coord = {.x = island->x*2, .y = island->y*2}; + return coord; +} \ No newline at end of file diff --git a/Pontu/src/model/Game.c b/Pontu/src/model/Game.c index c64afbb..7382f2e 100644 --- a/Pontu/src/model/Game.c +++ b/Pontu/src/model/Game.c @@ -1,5 +1,6 @@ #include "model/Game.h" #include "model/IslandOrBridge.h" +#include "engine/ArrayUtils.h" #include // Not defined in header to not pollute inferface @@ -93,7 +94,7 @@ void changePhaseOrPlayerTurn(Game* game) game->board.nbPieces)); - fprintf(stderr, "Player n°%lld turn\n", game->currentPlayerID); + fprintf(stderr, "Player n°%ld turn\n", game->currentPlayerID); fflush(stderr); if (anyOfPlayersPiecesCanMove(game->currentPlayerID, &game->board)) @@ -189,12 +190,14 @@ bool checkBridge(const Island start, const Island target, const Board* board) // Vertical bridge if (xdiff == 0 && abs(ydiff) == 1) { - return board->vBridges[start.y + ydiff][start.x]; + const int coordY = start.y - (ydiff==-1?1:0); + return board->vBridges[coordY][start.x]; } // Horizontal bridge else if (abs(xdiff) == 1 && ydiff == 0) { - return board->hBridges[start.y][start.x + xdiff]; + const int coordX = start.x - (xdiff==-1?1:0); + return board->hBridges[start.y][coordX]; } // Not a bridge else @@ -374,3 +377,92 @@ bool rmBridge(Bridge bridge, Board* board) return false; } + + +struct array_Coord getInteractiveCases(const Game* const game, const Coord selectedCase) { + switch (game->phase) + { + case PLACEMENT: { + struct array_Coord retVal = array_Coord_Create(); + array_Coord_Reserve(&retVal, 25); + + for (int y = 0; y<5; y+=2) { + for (int x = 0; x<5; x+=2) { + array_Coord_AddElement(&retVal, newCoord(x,y)); + } + } + + for (size_t i = 0; i < game->board.nbPieces; i++) + { + if (islandValid(game->board.arrPieces[i].island)) { + array_Coord_RemoveElement(&retVal, islandToCoord(&game->board.arrPieces[i].island), &coordEqual); + } + } + + array_Coord_FitToSize(&retVal); + + return retVal; + } + case MOVE_PIECE: { + struct array_Coord retVal = array_Coord_Create(); + array_Coord_Reserve(&retVal, 4); + + for (size_t i = 0; i < game->board.nbPieces; ++i) + { + if (game->board.arrPieces[i].idJ == game->currentPlayerID && !game->board.arrPieces[i].stuck) { + size_t nbIsland; + Island* islands = islandsAround(game->board.arrPieces[i].island, &nbIsland); + + if (nbIsland != 0) { + Coord pieceCoord = islandToCoord(&game->board.arrPieces[i].island); + if (!coordValid(selectedCase)) { + array_Coord_AddElement(&retVal, pieceCoord); + } + else { + if (coordEqual(pieceCoord, selectedCase)) { + for (size_t iIsle = 0; iIsle < nbIsland; ++iIsle) + { + if (pieceCanMoveTo(&game->board.arrPieces[i], islands[iIsle], &game->board)) { + Coord coordIsland = islandToCoord(&islands[iIsle]); + array_Coord_AddElement(&retVal, coordIsland); + } + } + free(islands); + return retVal; + } + } + } + free(islands); + } + } + + array_Coord_FitToSize(&retVal); + return retVal; + } + case RM_BRIDGE: { + struct array_Coord retVal = array_Coord_Create(); + array_Coord_Reserve(&retVal, 40); + + for (size_t y = 0; y<5; ++y) { + for (size_t x = 0; x<4; ++x) { + if (game->board.hBridges[y][x]) { + Coord coord = {.x=x*2+1, .y=y*2}; + array_Coord_AddElement(&retVal, coord); + } + } + } + for (size_t y = 0; y<4; ++y) { + for (size_t x = 0; x<5; ++x) { + if (game->board.vBridges[y][x]) { + Coord coord = {.x=x*2, .y=y*2+1}; + array_Coord_AddElement(&retVal, coord); + } + } + } + + return retVal; + } + default: + return array_Coord_Create(); + } +} diff --git a/Pontu/src/view/GameDrawer.c b/Pontu/src/view/GameDrawer.c index 99f5f72..351b03e 100644 --- a/Pontu/src/view/GameDrawer.c +++ b/Pontu/src/view/GameDrawer.c @@ -4,16 +4,16 @@ bool drawGame(SDL_Renderer* renderer, const SDL_Rect* windowSize, const SDL_Rect* boardRect, const Game* game,TextureHandler* textureHandler) { - SDL_Texture* menuTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 50, 70); + //SDL_Texture* menuTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 50, 70); - SDL_SetRenderTarget(renderer, menuTexture); + /*SDL_SetRenderTarget(renderer, menuTexture); SDL_SetRenderDrawColor(renderer, 150, 243, 59, 255); SDL_Rect buttonRect = {.x = 0,.y = 0,.w = 50,.h = 70}; SDL_RenderFillRect(renderer, &buttonRect); - SDL_SetRenderTarget(renderer, NULL); + SDL_SetRenderTarget(renderer, NULL);*/ //P_Button menu = createButton(menuTexture, NULL, (windowSize->w*5)/100, (windowSize->h*5)/100, 50, 70, NULL); - P_Button menu = createButton(menuTexture, NULL, 10, 10, 50, 70, NULL); + //P_Button menu = createButton(menuTexture, NULL, 10, 10, 50, 70, NULL); drawBoard(renderer, boardRect, &(game->board), textureHandler->textures[TEXTURE_Island], textureHandler->textures[TEXTURE_Bridge], textureHandler->textures[TEXTURE_Water]);