Browse Source

Initial commit

DricomDragon 6 years ago
commit
2816bdb789
44 changed files with 4613 additions and 0 deletions
  1. 54 0
      Ally.cpp
  2. 32 0
      Ally.h
  3. 38 0
      CMakeLists.txt
  4. 203 0
      Control/Input.cpp
  5. 66 0
      Control/Input.h
  6. 153 0
      Control/InputAndJoy.cpp
  7. 45 0
      Control/InputAndJoy.h
  8. 386 0
      FindPackageHandleStandardArgs.cmake
  9. 47 0
      FindPackageMessage.cmake
  10. 192 0
      FindSDL.cmake
  11. 73 0
      FindSDL_gfx.cmake
  12. 60 0
      Foe.cpp
  13. 57 0
      Foe.h
  14. 427 0
      Game.cpp
  15. 62 0
      Game.h
  16. 155 0
      HitManager.cpp
  17. 110 0
      HitManager.h
  18. 147 0
      Score.cpp
  19. 44 0
      Score.h
  20. 79 0
      Shot.cpp
  21. 53 0
      Shot.h
  22. 75 0
      Shot/Brexit.cpp
  23. 35 0
      Shot/Brexit.h
  24. 62 0
      Shot/Cutter.cpp
  25. 33 0
      Shot/Cutter.h
  26. 85 0
      Shot/Disper.cpp
  27. 35 0
      Shot/Disper.h
  28. 78 0
      Shot/Gun.cpp
  29. 33 0
      Shot/Gun.h
  30. 69 0
      Shot/Hecto.cpp
  31. 35 0
      Shot/Hecto.h
  32. 164 0
      Shot/Missile.cpp
  33. 49 0
      Shot/Missile.h
  34. 53 0
      Shot/Part.cpp
  35. 34 0
      Shot/Part.h
  36. 107 0
      Shot/Photo.cpp
  37. 36 0
      Shot/Photo.h
  38. 101 0
      Shot/Sniper.cpp
  39. 36 0
      Shot/Sniper.h
  40. 627 0
      SpaceShip.cpp
  41. 85 0
      SpaceShip.h
  42. 225 0
      WaveManager.cpp
  43. 55 0
      WaveManager.h
  44. 18 0
      main.cpp

+ 54 - 0
Ally.cpp

@@ -0,0 +1,54 @@
+#include "Ally.h"
+
+Ally::Ally()
+:SpaceShip( true ), m_xFront( 0 ), m_thruster( false )
+{
+    //ctor
+}
+
+Ally::~Ally()
+{
+    //dtor
+}
+
+void Ally::scroll( int rel )
+{
+    m_pos.y += rel ;
+    if ( m_pos.y < 0 )
+        m_pos.y = 0;
+    else if ( m_pos.y > 720 - m_pos.h )
+        m_pos.y = 720 - m_pos.h;
+}
+
+void Ally::loadShape( std::string path )
+{
+    // Appelle la fonction mère
+    SpaceShip::loadShape( path );
+
+    // Mets le vaisseau en position d'entrée
+    m_xFront = 1200 - m_pos.w;
+    m_pos.x = 1280;
+    m_pos.y = 300;
+
+    // Eteint le surboost de sortie
+    m_thruster = false;
+}
+
+void Ally::update()
+{
+    // Appelle la fonction mère
+    SpaceShip::update();
+
+    // Avance le vaisseau en postion de combat
+    if ( m_pos.x > m_xFront )
+        m_pos.x -= 2;
+
+    // Fait sortir le vaisseau de l'écran
+    if ( m_thruster )
+        m_pos.x -= 3;
+}
+
+void Ally::enableThruster( bool state )
+{
+    m_thruster = state;
+}

+ 32 - 0
Ally.h

@@ -0,0 +1,32 @@
+#ifndef ALLY_H
+#define ALLY_H
+
+#include "SpaceShip.h"
+
+/**
+Jovian Hersemeule
+Description du Ally :
+    Contient toutes les données relatives au vaisseau spatial du joueur.
+    C'est ce que contrôle l'utilisateur.
+**/
+
+class Ally : public SpaceShip
+{
+/// Méthodes
+    public:
+        Ally();
+        virtual ~Ally();
+
+        void scroll( int rel );
+
+        virtual void loadShape( std::string path ); // Appelle la fonction mère
+        virtual void update(); // Appelle la fonction mère
+        void enableThruster( bool state );
+
+/// Attributs
+    protected:
+        Sint16 m_xFront;
+        bool m_thruster;
+};
+
+#endif // ALLY_H

+ 38 - 0
CMakeLists.txt

@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.7)
+project(ASCCI_Space_Destroyer_CLion)
+
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
+
+find_package(SDL)
+find_package(SDL_gfx)
+
+
+include_directories(${SDL_INCLUDE_DIR} ${SDLGFX_INCLUDE_DIR})
+
+set(CMAKE_CXX_STANDARD 11)
+
+set(SOURCE_FILES
+        main.cpp
+        Ally.cpp
+        Foe.cpp
+        Game.cpp
+        HitManager.cpp
+        Score.cpp
+        Shot.cpp
+        SpaceShip.cpp
+        WaveManager.cpp
+        Control/Input.cpp
+        Control/InputAndJoy.cpp
+        Shot/Brexit.cpp
+        Shot/Cutter.cpp
+        Shot/Disper.cpp
+        Shot/Gun.cpp
+        Shot/Hecto.cpp
+        Shot/Missile.cpp
+        Shot/Part.cpp
+        Shot/Photo.cpp
+        Shot/Sniper.cpp)
+
+add_executable(ASCCI_Space_Destroyer_CLion ${SOURCE_FILES})
+
+target_link_libraries(ASCCI_Space_Destroyer_CLion ${SDL_LIBRARY} ${SDLGFX_LIBRARY})

+ 203 - 0
Control/Input.cpp

@@ -0,0 +1,203 @@
+#include "Input.h"
+
+
+// Constructeur et Destructeur
+Input::Input()
+: m_x(0), m_y(0), m_xRel(0), m_yRel(0),
+m_terminer(false), m_relativeMouse(false), m_windowHalfHeight(0), m_windowHalfWidth(0)
+{
+    // Initialisation du tableau m_touchesHeld[]
+    for(int i(0); i < SDLK_LAST; i++)
+        m_touchesHeld[i] = false;
+    std::cout << "Il y a "<<SDLK_LAST<<" touches sur le clavier."<<std::endl;
+
+    // Initialisation du tableau m_boutonsSourisHeld[]
+    for(int i(0); i < 8; i++)
+        m_boutonsSourisHeld[i] = false;
+}
+
+
+Input::~Input()
+{}
+
+
+// Méthodes
+void Input::updateEvenements()
+{
+    // Pour éviter des mouvements fictifs de la souris, on réinitialise les coordonnées relatives
+    m_xRel = 0;
+    m_yRel = 0;
+
+    // Les touches qui viennent d'être appuyées ne le sont plus
+    m_touchesInstant.clear();
+    m_boutonsSourisInstant.clear();
+
+    // Boucle d'évènements
+    while(SDL_PollEvent(&m_evenements))
+    {
+        // Switch sur le type d'évènement
+        switch(m_evenements.type)
+        {
+            // Cas d'une touche enfoncée
+            case SDL_KEYDOWN:
+                m_touchesHeld[m_evenements.key.keysym.sym] = true;
+                m_touchesInstant.push_back( m_evenements.key.keysym.sym );
+            break;
+
+            // Cas d'une touche relâchée
+            case SDL_KEYUP:
+                m_touchesHeld[m_evenements.key.keysym.sym] = false;
+            break;
+
+            // Cas de pression sur un bouton de la souris
+            case SDL_MOUSEBUTTONDOWN:
+                m_boutonsSourisHeld[m_evenements.button.button] = true;
+                m_boutonsSourisInstant.push_back( m_evenements.button.button );
+            break;
+
+            // Cas du relâchement d'un bouton de la souris
+            case SDL_MOUSEBUTTONUP:
+                m_boutonsSourisHeld[m_evenements.button.button] = false;
+            break;
+
+            // Cas d'un mouvement de souris
+            case SDL_MOUSEMOTION:
+                if (m_relativeMouse)
+                {
+                    m_xRel = m_evenements.motion.x-m_windowHalfWidth;
+                    m_yRel = m_evenements.motion.y-m_windowHalfHeight;
+                }
+                else
+                {
+                    m_x = m_evenements.motion.x;
+                    m_y = m_evenements.motion.y;
+                    m_xRel = m_evenements.motion.xrel;
+                    m_yRel = m_evenements.motion.yrel;
+                }
+
+            break;
+
+            // Cas de la fermeture de la fenêtre
+            case SDL_QUIT:
+                m_terminer = true;
+            break;
+
+            // Les autres ne nous interessent pas : on évite de faire râler g++
+            default:
+            break;
+        }
+    }
+
+    // Pour éviter que la souris se barre en mode relative, on la "warp"
+    if (m_relativeMouse)
+         SDL_WarpMouse(m_windowHalfWidth, m_windowHalfHeight);
+}
+
+
+bool Input::terminer() const
+{
+    return m_terminer;
+}
+
+
+void Input::afficherPointeur(bool reponse) const
+{
+    if(reponse)
+        SDL_ShowCursor(SDL_ENABLE);
+
+    else
+        SDL_ShowCursor(SDL_DISABLE);
+}
+
+
+void Input::capturerPointeur(bool reponse)
+{
+    m_relativeMouse = reponse;
+}
+
+
+
+// Getters
+
+bool Input::getToucheHeld(const int touche) const
+{
+    return m_touchesHeld[touche];
+}
+
+
+bool Input::getBoutonSourisHeld(const Uint8 bouton) const
+{
+    return m_boutonsSourisHeld[bouton];
+}
+
+bool Input::getToucheInstant(const int touche) const
+{
+    for ( unsigned int i(0); i < m_touchesInstant.size(); i++ ){
+        if ( m_touchesInstant[i] == touche )
+            return true;
+    }
+
+    return false;
+}
+
+
+bool Input::getBoutonSourisInstant(const Uint8 bouton) const
+{
+    for ( unsigned int i(0); i < m_boutonsSourisInstant.size(); i++ ){
+        if ( m_boutonsSourisInstant[i] == bouton )
+            return true;
+    }
+
+    return false;
+}
+
+
+bool Input::mouvementSouris() const
+{
+    if(m_xRel == 0 && m_yRel == 0)
+        return false;
+
+    else
+        return true;
+}
+
+
+// Getters concernant la position du curseur
+
+int Input::getX() const
+{
+    return m_x;
+}
+
+int Input::getY() const
+{
+    return m_y;
+}
+
+int Input::getXRel() const
+{
+    return m_xRel;
+}
+
+int Input::getYRel() const
+{
+    return m_yRel;
+}
+
+void Input::placerPtr(SDL_Surface* activWindow)
+{
+    // Détermination de l'endroit de capture du pointeur
+    m_windowHalfWidth = activWindow->w / 2;
+    m_windowHalfHeight = activWindow->h / 2;
+}
+
+int Input::getWinHalfH()
+{
+    return m_windowHalfHeight;
+}
+
+int Input::getWinHalfW()
+{
+    return m_windowHalfWidth;
+}
+

+ 66 - 0
Control/Input.h

@@ -0,0 +1,66 @@
+#ifndef DEF_INPUT
+#define DEF_INPUT
+
+///Jovian
+///Adaptation pour InputAndJoy
+
+// Include
+#include <iostream>
+#include <SDL/SDL.h>
+#include <vector>
+
+
+// Classe
+class Input
+{
+    public:
+
+    Input();
+    virtual ~Input();
+
+    virtual void updateEvenements();
+
+    bool terminer() const;
+    void afficherPointeur(bool reponse) const;
+    void capturerPointeur(bool reponse);
+
+    bool getToucheHeld(const int touche) const;
+    bool getBoutonSourisHeld(const Uint8 bouton) const;
+    bool getToucheInstant(const int touche) const;
+    bool getBoutonSourisInstant(const Uint8 bouton) const;
+    bool mouvementSouris() const;
+
+    int getX() const;
+    int getY() const;
+
+    int getXRel() const;
+    int getYRel() const;
+
+    void placerPtr(SDL_Surface* activWindow);
+
+    int getWinHalfH();
+    int getWinHalfW();
+
+
+    protected:
+
+    SDL_Event m_evenements;
+    bool m_touchesHeld[SDLK_LAST];
+    std::vector<int> m_touchesInstant;
+    bool m_boutonsSourisHeld[8];
+    std::vector<int> m_boutonsSourisInstant;
+
+    int m_x;
+    int m_y;
+    int m_xRel;
+    int m_yRel;
+
+    bool m_terminer;
+    bool m_relativeMouse;
+
+    int m_windowHalfHeight;
+    int m_windowHalfWidth;
+};
+
+#endif
+

+ 153 - 0
Control/InputAndJoy.cpp

@@ -0,0 +1,153 @@
+#include "InputAndJoy.h"
+
+InputAndJoy::InputAndJoy()
+: m_manette(0), m_nbAxes(0), m_nbBoutons(0), m_controleurType(0), m_seuil(3600)
+{
+    // Démarrage du joystick
+    if (SDL_InitSubSystem(SDL_INIT_JOYSTICK)<0)
+    {
+        std::cout << "Problème lors de l'initialisation du matériel pour les manettes : "<<SDL_GetError()<< std::endl;
+    }
+    else
+    {
+        // Ouverture du joystick
+        SDL_JoystickEventState(SDL_ENABLE);
+        m_manette = SDL_JoystickOpen(0);
+        if (m_manette == NULL)
+        {
+            std::cout << "Manette non démarrée : " << SDL_GetError() << std::endl;
+            setMainControleur(CLAVIER_SOURIS);
+        }
+        else
+        {
+            setMainControleur(MANETTE);
+            // Détermination de la valeur des attributs
+            m_nbAxes = SDL_JoystickNumAxes(m_manette);
+            m_nbBoutons = SDL_JoystickNumButtons(m_manette);
+            for (int i(0); i<m_nbAxes; i++)
+                m_axeValue.push_back(0);
+            for (int i(0); i<m_nbBoutons; i++)
+                m_boutonValue.push_back(false);
+        }
+    }
+}
+
+InputAndJoy::~InputAndJoy()
+{
+    if (m_manette != 0x0) SDL_JoystickClose(m_manette);
+}
+
+void InputAndJoy::updateEvenements()
+{
+    // Pour éviter des mouvements fictifs de la souris, on réinitialise les coordonnées relatives
+    m_xRel = 0;
+    m_yRel = 0;
+
+    // Les touches qui viennent d'être appuyées ne le sont plus
+    m_touchesInstant.clear();
+    m_boutonsSourisInstant.clear();
+
+    // Boucle d'évènements
+    while(SDL_PollEvent(&m_evenements))
+    {
+        // Switch sur le type d'évènement
+        switch(m_evenements.type)
+        {
+        /// Evenements clavier et souris
+            // Cas d'une touche enfoncée
+            case SDL_KEYDOWN:
+                m_touchesInstant[m_evenements.key.keysym.sym] = true;
+                m_touchesInstant.push_back( m_evenements.key.keysym.sym );
+            break;
+
+            // Cas d'une touche relâchée
+            case SDL_KEYUP:
+                m_touchesInstant[m_evenements.key.keysym.sym] = false;
+            break;
+
+            // Cas de pression sur un bouton de la souris
+            case SDL_MOUSEBUTTONDOWN:
+                m_boutonsSourisHeld[m_evenements.button.button] = true;
+                m_boutonsSourisInstant.push_back( m_evenements.button.button );
+            break;
+
+            // Cas du relâchement d'un bouton de la souris
+            case SDL_MOUSEBUTTONUP:
+                m_boutonsSourisHeld[m_evenements.button.button] = false;
+            break;
+
+            // Cas d'un mouvement de souris
+            case SDL_MOUSEMOTION:
+                if (m_relativeMouse)
+                {
+                    m_xRel = m_evenements.motion.x-m_windowHalfWidth;
+                    m_yRel = m_evenements.motion.y-m_windowHalfHeight;
+                }
+                else
+                {
+                    m_x = m_evenements.motion.x;
+                    m_y = m_evenements.motion.y;
+                    m_xRel = m_evenements.motion.xrel;
+                    m_yRel = m_evenements.motion.yrel;
+                }
+
+            break;
+
+            // Cas de la fermeture de la fenêtre
+            case SDL_QUIT:
+                m_terminer = true;
+            break;
+
+        /// Evenements joystick
+            case SDL_JOYAXISMOTION:
+                if (m_evenements.jaxis.value>m_seuil || m_evenements.jaxis.value<-m_seuil)
+                    m_axeValue[m_evenements.jaxis.axis] = m_evenements.jaxis.value;
+                else
+                    m_axeValue[m_evenements.jaxis.axis] = 0;
+                break;
+            case SDL_JOYBUTTONDOWN:
+                    m_boutonValue[m_evenements.jbutton.button] = true;
+                break;
+            case SDL_JOYBUTTONUP:
+                    m_boutonValue[m_evenements.jbutton.button] = false;
+                break;
+
+            default:
+            break;
+        }
+    }
+
+    // Pour éviter que la souris se barre en mode relative, on la "warp"
+    if (m_relativeMouse)
+         SDL_WarpMouse(m_windowHalfWidth, m_windowHalfHeight);
+}
+
+int InputAndJoy::getAxeValue(const Uint8 axeID) const
+{
+    if (axeID < m_nbAxes)
+        return m_axeValue[axeID];
+    else
+        std::cout << "Axe numéro " << axeID << " non-éxistant." << std::endl;
+    return -1;
+}
+
+bool InputAndJoy::getBoutonPad(const Uint8 bouton) const
+{
+    if (bouton<m_nbBoutons)
+        return m_boutonValue[bouton];
+    else
+        std::cout << "Bouton numéro "<<bouton<<" non-éxistant." << std::endl;
+    return false;
+}
+
+void InputAndJoy::setMainControleur(int type)
+{
+    if (type == CLAVIER_SOURIS || type == MANETTE)
+        if (m_manette!=0 || type!=MANETTE)
+            m_controleurType = type;
+}
+
+int InputAndJoy::getMainCtrl() const
+{
+    return m_controleurType;
+}

+ 45 - 0
Control/InputAndJoy.h

@@ -0,0 +1,45 @@
+#ifndef INPUTANDJOY_H_INCLUDED
+#define INPUTANDJOY_H_INCLUDED
+
+
+///Jovian
+///Adaptation pour InputAndJoy
+
+// Include
+#include <vector>
+#include "Input.h"
+
+//Enum
+#define CLAVIER_SOURIS 1
+#define MANETTE 2
+
+// Classe
+class InputAndJoy : public Input
+{
+    public:
+
+    InputAndJoy();
+    virtual ~InputAndJoy();
+
+    virtual void updateEvenements();
+
+    int getAxeValue(const Uint8 axeID) const;
+    bool getBoutonPad(const Uint8 bouton) const;
+
+    void setMainControleur(int type);
+    int getMainCtrl() const;
+
+
+    private:
+
+    SDL_Joystick* m_manette;
+    int m_nbAxes;
+    int m_nbBoutons;
+    int m_controleurType;
+    int const m_seuil;
+
+    std::vector<int> m_axeValue;
+    std::vector<bool> m_boutonValue;
+};
+
+#endif // INPUTANDJOY_H_INCLUDED

+ 386 - 0
FindPackageHandleStandardArgs.cmake

@@ -0,0 +1,386 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPackageHandleStandardArgs
+-----------------------------
+
+This module provides a function intended to be used in :ref:`Find Modules`
+implementing :command:`find_package(<PackageName>)` calls.  It handles the
+``REQUIRED``, ``QUIET`` and version-related arguments of ``find_package``.
+It also sets the ``<PackageName>_FOUND`` variable.  The package is
+considered found if all variables listed contain valid results, e.g.
+valid filepaths.
+
+.. command:: find_package_handle_standard_args
+
+  There are two signatures::
+
+    find_package_handle_standard_args(<PackageName>
+      (DEFAULT_MSG|<custom-failure-message>)
+      <required-var>...
+      )
+
+    find_package_handle_standard_args(<PackageName>
+      [FOUND_VAR <result-var>]
+      [REQUIRED_VARS <required-var>...]
+      [VERSION_VAR <version-var>]
+      [HANDLE_COMPONENTS]
+      [CONFIG_MODE]
+      [FAIL_MESSAGE <custom-failure-message>]
+      )
+
+  The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
+  the variables ``<required-var>...`` are valid and any optional
+  constraints are satisfied, and ``FALSE`` otherwise.  A success or
+  failure message may be displayed based on the results and on
+  whether the ``REQUIRED`` and/or ``QUIET`` option was given to
+  the :command:`find_package` call.
+
+  The options are:
+
+  ``(DEFAULT_MSG|<custom-failure-message>)``
+    In the simple signature this specifies the failure message.
+    Use ``DEFAULT_MSG`` to ask for a default message to be computed
+    (recommended).  Not valid in the full signature.
+
+  ``FOUND_VAR <result-var>``
+    Obsolete.  Specifies either ``<PackageName>_FOUND`` or
+    ``<PACKAGENAME>_FOUND`` as the result variable.  This exists only
+    for compatibility with older versions of CMake and is now ignored.
+    Result variables of both names are always set for compatibility.
+
+  ``REQUIRED_VARS <required-var>...``
+    Specify the variables which are required for this package.
+    These may be named in the generated failure message asking the
+    user to set the missing variable values.  Therefore these should
+    typically be cache entries such as ``FOO_LIBRARY`` and not output
+    variables like ``FOO_LIBRARIES``.
+
+  ``VERSION_VAR <version-var>``
+    Specify the name of a variable that holds the version of the package
+    that has been found.  This version will be checked against the
+    (potentially) specified required version given to the
+    :command:`find_package` call, including its ``EXACT`` option.
+    The default messages include information about the required
+    version and the version which has been actually found, both
+    if the version is ok or not.
+
+  ``HANDLE_COMPONENTS``
+    Enable handling of package components.  In this case, the command
+    will report which components have been found and which are missing,
+    and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``
+    if any of the required components (i.e. not the ones listed after
+    the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are
+    missing.
+
+  ``CONFIG_MODE``
+    Specify that the calling find module is a wrapper around a
+    call to ``find_package(<PackageName> NO_MODULE)``.  This implies
+    a ``VERSION_VAR`` value of ``<PackageName>_VERSION``.  The command
+    will automatically check whether the package configuration file
+    was found.
+
+  ``FAIL_MESSAGE <custom-failure-message>``
+    Specify a custom failure message instead of using the default
+    generated message.  Not recommended.
+
+Example for the simple signature:
+
+.. code-block:: cmake
+
+  find_package_handle_standard_args(LibXml2 DEFAULT_MSG
+    LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
+
+The ``LibXml2`` package is considered to be found if both
+``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
+Then also ``LibXml2_FOUND`` is set to ``TRUE``.  If it is not found
+and ``REQUIRED`` was used, it fails with a
+:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
+used or not.  If it is found, success will be reported, including
+the content of the first ``<required-var>``.  On repeated CMake runs,
+the same message will not be printed again.
+
+Example for the full signature:
+
+.. code-block:: cmake
+
+  find_package_handle_standard_args(LibArchive
+    REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
+    VERSION_VAR LibArchive_VERSION)
+
+In this case, the ``LibArchive`` package is considered to be found if
+both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
+Also the version of ``LibArchive`` will be checked by using the version
+contained in ``LibArchive_VERSION``.  Since no ``FAIL_MESSAGE`` is given,
+the default messages will be printed.
+
+Another example for the full signature:
+
+.. code-block:: cmake
+
+  find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
+  find_package_handle_standard_args(Automoc4  CONFIG_MODE)
+
+In this case, a ``FindAutmoc4.cmake`` module wraps a call to
+``find_package(Automoc4 NO_MODULE)`` and adds an additional search
+directory for ``automoc4``.  Then the call to
+``find_package_handle_standard_args`` produces a proper success/failure
+message.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
+
+# internal helper macro
+macro(_FPHSA_FAILURE_MESSAGE _msg)
+    if (${_NAME}_FIND_REQUIRED)
+        message(FATAL_ERROR "${_msg}")
+    else ()
+        if (NOT ${_NAME}_FIND_QUIETLY)
+            message(STATUS "${_msg}")
+        endif ()
+    endif ()
+endmacro()
+
+
+# internal helper macro to generate the failure message when used in CONFIG_MODE:
+macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
+    # <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
+    if(${_NAME}_CONFIG)
+        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
+    else()
+        # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
+        # List them all in the error message:
+        if(${_NAME}_CONSIDERED_CONFIGS)
+            set(configsText "")
+            list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
+            math(EXPR configsCount "${configsCount} - 1")
+            foreach(currentConfigIndex RANGE ${configsCount})
+                list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
+                list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
+                string(APPEND configsText "    ${filename} (version ${version})\n")
+            endforeach()
+            if (${_NAME}_NOT_FOUND_MESSAGE)
+                string(APPEND configsText "    Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
+            endif()
+            _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
+
+        else()
+            # Simple case: No Config-file was found at all:
+            _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
+        endif()
+    endif()
+endmacro()
+
+
+function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
+
+    # Set up the arguments for `cmake_parse_arguments`.
+    set(options  CONFIG_MODE  HANDLE_COMPONENTS)
+    set(oneValueArgs  FAIL_MESSAGE  VERSION_VAR  FOUND_VAR)
+    set(multiValueArgs REQUIRED_VARS)
+
+    # Check whether we are in 'simple' or 'extended' mode:
+    set(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )
+    list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
+
+    if(${INDEX} EQUAL -1)
+        set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
+        set(FPHSA_REQUIRED_VARS ${ARGN})
+        set(FPHSA_VERSION_VAR)
+    else()
+        cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${_FIRST_ARG} ${ARGN})
+
+        if(FPHSA_UNPARSED_ARGUMENTS)
+            message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
+        endif()
+
+        if(NOT FPHSA_FAIL_MESSAGE)
+            set(FPHSA_FAIL_MESSAGE  "DEFAULT_MSG")
+        endif()
+
+        # In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
+        # when it successfully found the config-file, including version checking:
+        if(FPHSA_CONFIG_MODE)
+            list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
+            list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
+            set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
+        endif()
+
+        if(NOT FPHSA_REQUIRED_VARS)
+            message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
+        endif()
+    endif()
+
+    # now that we collected all arguments, process them
+
+    if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
+        set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
+    endif()
+
+    list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
+
+    string(TOUPPER ${_NAME} _NAME_UPPER)
+    string(TOLOWER ${_NAME} _NAME_LOWER)
+
+    if(FPHSA_FOUND_VAR)
+        if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$"  OR  FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
+            set(_FOUND_VAR ${FPHSA_FOUND_VAR})
+        else()
+            message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
+        endif()
+    else()
+        set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
+    endif()
+
+    # collect all variables which were not found, so they can be printed, so the
+    # user knows better what went wrong (#6375)
+    set(MISSING_VARS "")
+    set(DETAILS "")
+    # check if all passed variables are valid
+    set(FPHSA_FOUND_${_NAME} TRUE)
+    foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
+        if(NOT ${_CURRENT_VAR})
+            set(FPHSA_FOUND_${_NAME} FALSE)
+            string(APPEND MISSING_VARS " ${_CURRENT_VAR}")
+        else()
+            string(APPEND DETAILS "[${${_CURRENT_VAR}}]")
+        endif()
+    endforeach()
+    if(FPHSA_FOUND_${_NAME})
+        set(${_NAME}_FOUND TRUE)
+        set(${_NAME_UPPER}_FOUND TRUE)
+    else()
+        set(${_NAME}_FOUND FALSE)
+        set(${_NAME_UPPER}_FOUND FALSE)
+    endif()
+
+    # component handling
+    unset(FOUND_COMPONENTS_MSG)
+    unset(MISSING_COMPONENTS_MSG)
+
+    if(FPHSA_HANDLE_COMPONENTS)
+        foreach(comp ${${_NAME}_FIND_COMPONENTS})
+            if(${_NAME}_${comp}_FOUND)
+
+                if(NOT DEFINED FOUND_COMPONENTS_MSG)
+                    set(FOUND_COMPONENTS_MSG "found components: ")
+                endif()
+                string(APPEND FOUND_COMPONENTS_MSG " ${comp}")
+
+            else()
+
+                if(NOT DEFINED MISSING_COMPONENTS_MSG)
+                    set(MISSING_COMPONENTS_MSG "missing components: ")
+                endif()
+                string(APPEND MISSING_COMPONENTS_MSG " ${comp}")
+
+                if(${_NAME}_FIND_REQUIRED_${comp})
+                    set(${_NAME}_FOUND FALSE)
+                    string(APPEND MISSING_VARS " ${comp}")
+                endif()
+
+            endif()
+        endforeach()
+        set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
+        string(APPEND DETAILS "[c${COMPONENT_MSG}]")
+    endif()
+
+    # version handling:
+    set(VERSION_MSG "")
+    set(VERSION_OK TRUE)
+
+    # check with DEFINED here as the requested or found version may be "0"
+    if (DEFINED ${_NAME}_FIND_VERSION)
+        if(DEFINED ${FPHSA_VERSION_VAR})
+            set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})
+
+            if(${_NAME}_FIND_VERSION_EXACT)       # exact version required
+                # count the dots in the version string
+                string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${_FOUND_VERSION}")
+                # add one dot because there is one dot more than there are components
+                string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
+                if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
+                    # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
+                    # is at most 4 here. Therefore a simple lookup table is used.
+                    if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
+                        set(_VERSION_REGEX "[^.]*")
+                    elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
+                        set(_VERSION_REGEX "[^.]*\\.[^.]*")
+                    elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
+                        set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
+                    else ()
+                        set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
+                    endif ()
+                    string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${_FOUND_VERSION}")
+                    unset(_VERSION_REGEX)
+                    if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
+                        set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
+                        set(VERSION_OK FALSE)
+                    else ()
+                        set(VERSION_MSG "(found suitable exact version \"${_FOUND_VERSION}\")")
+                    endif ()
+                    unset(_VERSION_HEAD)
+                else ()
+                    if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _FOUND_VERSION)
+                        set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
+                        set(VERSION_OK FALSE)
+                    else ()
+                        set(VERSION_MSG "(found suitable exact version \"${_FOUND_VERSION}\")")
+                    endif ()
+                endif ()
+                unset(_VERSION_DOTS)
+
+            else()     # minimum version specified:
+                if (${_NAME}_FIND_VERSION VERSION_GREATER _FOUND_VERSION)
+                    set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
+                    set(VERSION_OK FALSE)
+                else ()
+                    set(VERSION_MSG "(found suitable version \"${_FOUND_VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
+                endif ()
+            endif()
+
+        else()
+
+            # if the package was not found, but a version was given, add that to the output:
+            if(${_NAME}_FIND_VERSION_EXACT)
+                set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
+            else()
+                set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
+            endif()
+
+        endif()
+    else ()
+        # Check with DEFINED as the found version may be 0.
+        if(DEFINED ${FPHSA_VERSION_VAR})
+            set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")")
+        endif()
+    endif ()
+
+    if(VERSION_OK)
+        string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]")
+    else()
+        set(${_NAME}_FOUND FALSE)
+    endif()
+
+
+    # print the result:
+    if (${_NAME}_FOUND)
+        FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
+    else ()
+
+        if(FPHSA_CONFIG_MODE)
+            _FPHSA_HANDLE_FAILURE_CONFIG_MODE()
+        else()
+            if(NOT VERSION_OK)
+                _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
+            else()
+                _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}")
+            endif()
+        endif()
+
+    endif ()
+
+    set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
+    set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
+endfunction()

+ 47 - 0
FindPackageMessage.cmake

@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindPackageMessage
+# ------------------
+#
+#
+#
+# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
+#
+# This macro is intended to be used in FindXXX.cmake modules files.  It
+# will print a message once for each unique find result.  This is useful
+# for telling the user where a package was found.  The first argument
+# specifies the name (XXX) of the package.  The second argument
+# specifies the message to display.  The third argument lists details
+# about the find result so that if they change the message will be
+# displayed again.  The macro also obeys the QUIET argument to the
+# find_package command.
+#
+# Example:
+#
+# ::
+#
+#   if(X11_FOUND)
+#     FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
+#       "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
+#   else()
+#    ...
+#   endif()
+
+function(FIND_PACKAGE_MESSAGE pkg msg details)
+    # Avoid printing a message repeatedly for the same find result.
+    if(NOT ${pkg}_FIND_QUIETLY)
+        string(REPLACE "\n" "" details "${details}")
+        set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
+        if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
+            # The message has not yet been printed.
+            message(STATUS "${msg}")
+
+            # Save the find details in the cache to avoid printing the same
+            # message again.
+            set("${DETAILS_VAR}" "${details}"
+                    CACHE INTERNAL "Details about finding ${pkg}")
+        endif()
+    endif()
+endfunction()

+ 192 - 0
FindSDL.cmake

@@ -0,0 +1,192 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindSDL
+# -------
+#
+# Locate SDL library
+#
+# This module defines
+#
+# ::
+#
+#   SDL_LIBRARY, the name of the library to link against
+#   SDL_FOUND, if false, do not try to link to SDL
+#   SDL_INCLUDE_DIR, where to find SDL.h
+#   SDL_VERSION_STRING, human-readable string containing the version of SDL
+#
+#
+#
+# This module responds to the flag:
+#
+# ::
+#
+#   SDL_BUILDING_LIBRARY
+#     If this is defined, then no SDL_main will be linked in because
+#     only applications need main().
+#     Otherwise, it is assumed you are building an application and this
+#     module will attempt to locate and set the proper link flags
+#     as part of the returned SDL_LIBRARY variable.
+#
+#
+#
+# Don't forget to include SDLmain.h and SDLmain.m your project for the
+# OS X framework based version.  (Other versions link to -lSDLmain which
+# this module will try to find on your behalf.) Also for OS X, this
+# module will automatically add the -framework Cocoa on your behalf.
+#
+#
+#
+# Additional Note: If you see an empty SDL_LIBRARY_TEMP in your
+# configuration and no SDL_LIBRARY, it means CMake did not find your SDL
+# library (SDL.dll, libsdl.so, SDL.framework, etc).  Set
+# SDL_LIBRARY_TEMP to point to your SDL library, and configure again.
+# Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this
+# value as appropriate.  These values are used to generate the final
+# SDL_LIBRARY variable, but when these values are unset, SDL_LIBRARY
+# does not get created.
+#
+#
+#
+# $SDLDIR is an environment variable that would correspond to the
+# ./configure --prefix=$SDLDIR used in building SDL.  l.e.galup 9-20-02
+#
+# Modified by Eric Wing.  Added code to assist with automated building
+# by using environmental variables and providing a more
+# controlled/consistent search behavior.  Added new modifications to
+# recognize OS X frameworks and additional Unix paths (FreeBSD, etc).
+# Also corrected the header search path to follow "proper" SDL
+# guidelines.  Added a search for SDLmain which is needed by some
+# platforms.  Added a search for threads which is needed by some
+# platforms.  Added needed compile switches for MinGW.
+#
+# On OSX, this will prefer the Framework version (if found) over others.
+# People will have to manually change the cache values of SDL_LIBRARY to
+# override this selection or set the CMake environment
+# CMAKE_INCLUDE_PATH to modify the search paths.
+#
+# Note that the header path has changed from SDL/SDL.h to just SDL.h
+# This needed to change because "proper" SDL convention is #include
+# "SDL.h", not <SDL/SDL.h>.  This is done for portability reasons
+# because not all systems place things in SDL/ (see FreeBSD).
+
+find_path(SDL_INCLUDE_DIR SDL.h
+        HINTS
+        ENV SDLDIR
+        PATH_SUFFIXES SDL SDL12 SDL11
+        # path suffixes to search inside ENV{SDLDIR}
+        include/SDL include/SDL12 include/SDL11 include
+        )
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+    set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+# SDL-1.1 is the name used by FreeBSD ports...
+# don't confuse it for the version number.
+find_library(SDL_LIBRARY_TEMP
+        NAMES SDL SDL-1.1
+        HINTS
+        ENV SDLDIR
+        PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+        )
+
+# Hide this cache variable from the user, it's an internal implementation
+# detail. The documented library variable for the user is SDL_LIBRARY
+# which is derived from SDL_LIBRARY_TEMP further below.
+set_property(CACHE SDL_LIBRARY_TEMP PROPERTY TYPE INTERNAL)
+
+if(NOT SDL_BUILDING_LIBRARY)
+    if(NOT SDL_INCLUDE_DIR MATCHES ".framework")
+        # Non-OS X framework versions expect you to also dynamically link to
+        # SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms
+        # seem to provide SDLmain for compatibility even though they don't
+        # necessarily need it.
+        find_library(SDLMAIN_LIBRARY
+                NAMES SDLmain SDLmain-1.1
+                HINTS
+                ENV SDLDIR
+                PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+                PATHS
+                /sw
+                /opt/local
+                /opt/csw
+                /opt
+                )
+    endif()
+endif()
+
+# SDL may require threads on your system.
+# The Apple build may not need an explicit flag because one of the
+# frameworks may already provide it.
+# But for non-OSX systems, I will use the CMake Threads package.
+if(NOT APPLE)
+    find_package(Threads)
+endif()
+
+# MinGW needs an additional link flag, -mwindows
+# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -mwindows
+if(MINGW)
+    set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW")
+endif()
+
+if(SDL_LIBRARY_TEMP)
+    # For SDLmain
+    if(SDLMAIN_LIBRARY AND NOT SDL_BUILDING_LIBRARY)
+        list(FIND SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" _SDL_MAIN_INDEX)
+        if(_SDL_MAIN_INDEX EQUAL -1)
+            set(SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" ${SDL_LIBRARY_TEMP})
+        endif()
+        unset(_SDL_MAIN_INDEX)
+    endif()
+
+    # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
+    # CMake doesn't display the -framework Cocoa string in the UI even
+    # though it actually is there if I modify a pre-used variable.
+    # I think it has something to do with the CACHE STRING.
+    # So I use a temporary variable until the end so I can set the
+    # "real" variable in one-shot.
+    if(APPLE)
+        set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa")
+    endif()
+
+    # For threads, as mentioned Apple doesn't need this.
+    # In fact, there seems to be a problem if I used the Threads package
+    # and try using this line, so I'm just skipping it entirely for OS X.
+    if(NOT APPLE)
+        set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
+    endif()
+
+    # For MinGW library
+    if(MINGW)
+        set(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP})
+    endif()
+
+    # Set the final string here so the GUI reflects the final state.
+    set(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
+endif()
+
+if(SDL_INCLUDE_DIR AND EXISTS "${SDL_INCLUDE_DIR}/SDL_version.h")
+    file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
+    file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
+    file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
+    string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MAJOR "${SDL_VERSION_MAJOR_LINE}")
+    string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MINOR "${SDL_VERSION_MINOR_LINE}")
+    string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_VERSION_PATCH "${SDL_VERSION_PATCH_LINE}")
+    set(SDL_VERSION_STRING ${SDL_VERSION_MAJOR}.${SDL_VERSION_MINOR}.${SDL_VERSION_PATCH})
+    unset(SDL_VERSION_MAJOR_LINE)
+    unset(SDL_VERSION_MINOR_LINE)
+    unset(SDL_VERSION_PATCH_LINE)
+    unset(SDL_VERSION_MAJOR)
+    unset(SDL_VERSION_MINOR)
+    unset(SDL_VERSION_PATCH)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL
+        REQUIRED_VARS SDL_LIBRARY SDL_INCLUDE_DIR
+        VERSION_VAR SDL_VERSION_STRING)

+ 73 - 0
FindSDL_gfx.cmake

@@ -0,0 +1,73 @@
+# Locate SDL_gfx library
+# This module defines
+# SDLGFX_LIBRARY, the name of the library to link against
+# SDLGFX_FOUND, if false, do not try to link to SDL
+# SDLGFX_INCLUDE_DIR, where to find SDL/SDL.h
+#
+# $SDLDIR is an environment variable that would
+# correspond to the ./configure --prefix=$SDLDIR
+# used in building SDL.
+#
+# Created by David Demelier. This was influenced by the FindSDL_mixer.cmake 
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+FIND_PATH(SDLGFX_INCLUDE_DIR SDL_gfxPrimitives.h
+  HINTS
+  $ENV{SDLGFXDIR}
+  $ENV{SDLDIR}
+  PATH_SUFFIXES include
+  PATHS
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local/include/SDL
+  /usr/include/SDL
+  /usr/local/include/SDL12
+  /usr/local/include/SDL11 # FreeBSD ports
+  /usr/include/SDL12
+  /usr/include/SDL11
+  /usr/local/include
+  /usr/include
+  /sw/include/SDL # Fink
+  /sw/include
+  /opt/local/include/SDL # DarwinPorts
+  /opt/local/include
+  /opt/csw/include/SDL # Blastwave
+  /opt/csw/include 
+  /opt/include/SDL
+  /opt/include
+)
+
+FIND_LIBRARY(SDLGFX_LIBRARY 
+  NAMES SDL_gfx
+  HINTS
+  $ENV{SDLGFXDIR}
+  $ENV{SDLDIR}
+  PATH_SUFFIXES lib64 lib
+  PATHS
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local
+  /usr
+  /sw
+  /opt/local
+  /opt/csw
+  /opt
+)
+
+SET(SDLGFX_FOUND "NO")
+IF(SDLGFX_LIBRARY AND SDLGFX_INCLUDE_DIR)
+  SET(SDLGFX_FOUND "YES")
+ENDIF(SDLGFX_LIBRARY AND SDLGFX_INCLUDE_DIR)
+

+ 60 - 0
Foe.cpp

@@ -0,0 +1,60 @@
+#include "Foe.h"
+
+Foe::Foe()
+:SpaceShip( false ), m_speed( 1 )
+{
+    Uint32 tabMins[SHOT_NB] = FOE_MIN;
+    Uint32 tabAdds[SHOT_NB] = FOE_ADD;
+
+    for ( unsigned int i(1); i < SHOT_NB; i++ )
+    {
+        m_loading[i] = SDL_GetTicks();
+        m_delay[i] = tabMins[i] + ( rand() % tabAdds[i] );
+    }
+}
+
+Foe::Foe( Uint16 speed )
+:SpaceShip( false ), m_speed( speed )
+{
+    Uint32 tabMins[SHOT_NB] = FOE_MIN;
+    Uint32 tabAdds[SHOT_NB] = FOE_ADD;
+
+    for ( unsigned int i(1); i < SHOT_NB; i++ )
+    {
+        m_loading[i] = SDL_GetTicks();
+        m_delay[i] = tabMins[i] + ( rand() % tabAdds[i] );
+    }
+}
+
+Foe::~Foe()
+{
+    //dtor
+}
+
+void Foe::update()
+{
+    // Collision
+    SpaceShip::update();
+
+    // Teste l'existence
+    if ( !getIsAlive() )
+        return ;
+
+    // Déplacement
+    m_pos.x += m_speed;
+
+    // Feu
+    Uint32 last( SDL_GetTicks() );
+    Uint32 tabMins[SHOT_NB] = FOE_MIN;
+    Uint32 tabAdds[SHOT_NB] = FOE_ADD;
+
+    for ( unsigned int i(1); i < SHOT_NB; i++ )
+    {
+        if ( last - m_loading[i] > m_delay[i] ){
+            fire( i );
+
+            m_loading[i] = SDL_GetTicks();
+            m_delay[i] = tabMins[i] + ( rand() % tabAdds[i] );
+        }
+    }
+}

+ 57 - 0
Foe.h

@@ -0,0 +1,57 @@
+#ifndef FOE_H
+#define FOE_H
+
+#include "SpaceShip.h"
+
+
+/**
+Jovian Hersemeule
+Description du Foe :
+    La classe Foe hérité de SpaceShip. Un Foe est un vaisseau ennemi que l'allié doit détruire.
+**/
+
+#define FOE_MIN_GUN 1000
+#define FOE_ADD_GUN 2142
+
+#define FOE_MIN_CUTTER 2000
+#define FOE_ADD_CUTTER 1042
+
+#define FOE_MIN_DISPER 16
+#define FOE_ADD_DISPER 32
+
+#define FOE_MIN_PHOTO 1600
+#define FOE_ADD_PHOTO 1
+
+#define FOE_MIN_MISSILE 3000
+#define FOE_ADD_MISSILE 2000
+
+#define FOE_MIN_BREXIT 1500
+#define FOE_ADD_BREXIT 1500
+
+#define FOE_MIN_HECTO 500
+#define FOE_ADD_HECTO 2200
+
+#define FOE_MIN_SNIPER 2200
+#define FOE_ADD_SNIPER 400
+
+#define FOE_MIN {0, FOE_MIN_GUN, FOE_MIN_CUTTER, FOE_MIN_DISPER, FOE_MIN_PHOTO, FOE_MIN_MISSILE, FOE_MIN_BREXIT, FOE_MIN_HECTO, FOE_MIN_SNIPER}
+#define FOE_ADD {0, FOE_ADD_GUN, FOE_ADD_CUTTER, FOE_ADD_DISPER, FOE_ADD_PHOTO, FOE_ADD_MISSILE, FOE_ADD_BREXIT, FOE_ADD_HECTO, FOE_ADD_SNIPER}
+
+class Foe : public SpaceShip
+{
+/// Méthodes
+    public:
+        Foe();
+        Foe(Uint16 speed);
+        virtual ~Foe();
+
+        virtual void update(); // Colisions et mouvements de l'IA
+
+/// Attributs
+    protected:
+        Uint16 m_speed;
+        Uint32 m_loading[SHOT_NB]; // date du dernier tir
+        Uint32 m_delay[SHOT_NB]; // temps de recharge
+};
+
+#endif // FOE_H

+ 427 - 0
Game.cpp

@@ -0,0 +1,427 @@
+#include "Game.h"
+
+using namespace std;
+
+Game::Game()
+:m_screen( 0x0 ), m_lvlSelect(0), m_shipSelect(0), m_pSelect(0)
+{
+    //ctor
+}
+
+Game::~Game()
+{
+    if ( m_screen ) SDL_FreeSurface( m_screen );
+    m_screen = 0x0;
+}
+
+/// Public
+bool Game::init()
+{
+    /// [1] Démarrage
+    // [1.1] Démarrages SDL
+    if ( SDL_Init( SDL_INIT_VIDEO ) < 0)
+    {
+        cout << "Impossible d'initialiser la SDL: " << SDL_GetError() << endl;
+        return false;
+    }
+
+    // [1.2] Préparation de fermeture
+    atexit(SDL_Quit);
+
+    // [1.3] Para-fenêtre
+    SDL_WM_SetCaption("ASCII Space Destroyer", 0);
+
+    // [1.4] Seed pour nombres aléatoires
+    srand( time(0) );
+
+    /// [2] Préparation des composants
+    // [2.1] Préparation de la fenêtre
+    m_screen = SDL_SetVideoMode(1280, 720, 32, SDL_HWSURFACE|SDL_DOUBLEBUF );
+    if ( !m_screen )
+    {
+        cout << "Bug à l'initialisation: " << SDL_GetError() << endl;
+        return false;
+    }
+
+    // [2.2] Préparation du WaveManager
+    m_waver.giveHitManager( &m_hiter );
+
+    // [2.3] Préparation du joueur
+    m_player.giveHitManager( &m_hiter );
+
+    // [2.4] Préparation du HitManager
+    //...
+
+    /// [3] Finalisation de la procédure
+    return true;
+}
+
+void Game::run()
+{
+    string msg;
+
+    while ( true )
+    {
+        msg = menu();
+
+        if ( msg == "Quit" )
+            return;
+
+        msg.erase(0, 2);
+
+        if ( rush( msg ) && ( msg != "Tutoriel" ) )
+        {
+            m_score.addVictory();
+            m_score.giveLoot( msg );
+        }
+
+        m_score.save();
+    }
+}
+
+/// Protected
+string Game::menu()
+{
+    /// [1] Préparation
+    // [1.2] Chargement des index
+    ifstream levelStream("Levels/index.txt");
+    ifstream shipStream("Ships/index.txt");
+    ifstream playerStream("Saves/index.txt");
+
+    // [1.3] Variables
+    string line;
+    vector< vector<string> > levelDetail;
+    vector<string> shipNames;
+    vector<Uint32> shipCpu;
+    vector<string> playerNames;
+    bool loop( true );
+    bool canDrive( false );
+
+    // [1.3] Lecture des planètes
+    while ( getline( levelStream, line ) )
+    {
+        if ( line[0] == '>' )
+        {
+            // Nouvelle planète
+            levelDetail.push_back( {} );
+        }
+
+        levelDetail.back().push_back( line );
+    }
+    levelStream.close();
+
+    // [1.4] Lecture des vaisseaux
+    while ( getline( shipStream, line ) )
+    {
+        shipNames.push_back( line );
+        shipCpu.push_back( 0 );
+    }
+    shipStream.close();
+
+    // [1.4] Lecture des joueurs
+    while ( getline( playerStream, line ) )
+    {
+        playerNames.push_back( line );
+    }
+    playerStream.close();
+
+    // [1._] Erreurs
+    if ( levelDetail.empty() || shipNames.empty() )
+    {
+        cout << "Problème de lecture d'un index." << endl;
+        return "Quit";
+    }
+
+    // [1.1] Préparation du joueur
+    m_player.loadShape( "Ships/" + shipNames[m_shipSelect] + ".txt" );
+    m_player.setPos( 50, 100 );
+    shipCpu[m_shipSelect] = m_player.countCPU();
+    string weapNames[ SHOT_NB ] = ACTOR_NAME;
+
+    m_score.load( playerNames[m_pSelect] );
+
+    // [1. ] Pointeur souris
+    m_input.placerPtr( m_screen );
+    m_input.afficherPointeur( true );
+    m_input.capturerPointeur( false );
+
+    /// [2] Lancement boucle principale
+    while ( loop )
+    {
+        /// [3] Évènements
+        // [2.1] Mise à jour des évènements
+        m_input.updateEvenements();
+
+        // [2.2] Gestion de la boucle
+        loop = !m_input.terminer() && !m_input.getToucheHeld( SDLK_ESCAPE );
+
+        if ( loop && m_input.getToucheHeld( SDLK_RETURN ) && canDrive )
+            loop = false;
+
+        // [2.2] Gestion évènements choix du vaisseau
+        if ( m_input.getToucheInstant( SDLK_RIGHT )
+                || ( m_input.getBoutonSourisInstant( 1 )
+                    && m_input.getX() < m_screen->w / 2
+                    && m_input.getY() < m_screen->h / 2 ) )
+        {
+            m_shipSelect += 1;
+            if ( m_shipSelect >= shipNames.size() ) m_shipSelect = 0;
+
+            m_player.loadShape( "Ships/" + shipNames[m_shipSelect] + ".txt" );
+            m_player.setPos( 50, 100 );
+
+            if ( shipCpu[m_shipSelect] == 0 ) shipCpu[m_shipSelect] = m_player.countCPU();
+        }
+
+        if ( m_input.getToucheInstant( SDLK_LEFT )
+                || ( m_input.getBoutonSourisInstant( 3 )
+                    && m_input.getX() < m_screen->w / 2
+                    && m_input.getY() < m_screen->h / 2 ) )
+        {
+            m_shipSelect -= 1;
+            if ( m_shipSelect >= shipNames.size() ) m_shipSelect = shipNames.size() - 1;
+
+            m_player.loadShape( "Ships/" + shipNames[m_shipSelect] + ".txt" );
+            m_player.setPos( 50, 100 );
+
+            if ( shipCpu[m_shipSelect] == 0 ) shipCpu[m_shipSelect] = m_player.countCPU();
+        }
+
+        // [2.2] Gestion évènements choix du joueur
+        if ( m_input.getToucheInstant( SDLK_d )
+                || ( m_input.getBoutonSourisInstant( 1 )
+                    && m_input.getX() < m_screen->w / 2
+                    && m_input.getY() > m_screen->h / 2 ) )
+        {
+            m_pSelect += 1;
+            if ( m_pSelect >= playerNames.size() ) m_pSelect = 0;
+
+            m_score.load( playerNames[ m_pSelect ] );
+        }
+
+        if ( m_input.getToucheInstant( SDLK_a ) || m_input.getToucheInstant( SDLK_q )
+                || ( m_input.getBoutonSourisInstant( 3 )
+                    && m_input.getX() < m_screen->w / 2
+                    && m_input.getY() > m_screen->h / 2 ) )
+        {
+            m_pSelect -= 1;
+            if ( m_pSelect >= playerNames.size() ) m_pSelect = playerNames.size() - 1;
+
+            m_score.load( playerNames[ m_pSelect ] );
+        }
+
+
+        // [3.3] Gestion évènements choix du niveau
+        if ( m_input.getToucheInstant( SDLK_DOWN )
+                || ( m_input.getBoutonSourisInstant( 1 )
+                    && m_input.getX() > m_screen->w / 2 ) )
+        {
+            m_lvlSelect += 1;
+            if ( m_lvlSelect >= levelDetail.size() ) m_lvlSelect = 0;
+        }
+
+        if ( m_input.getToucheInstant( SDLK_UP )
+                || ( m_input.getBoutonSourisInstant( 3 )
+                    && m_input.getX() > m_screen->w / 2 ) )
+        {
+            m_lvlSelect -= 1;
+            if ( m_lvlSelect >= levelDetail.size() ) m_lvlSelect = levelDetail.size() - 1;
+        }
+
+        /// [4] Validité du vaisseau
+        canDrive = true;
+        canDrive = canDrive && shipCpu[ m_shipSelect ] <= m_score.getCpuLoad();
+        canDrive = canDrive && ( m_score.hasShield() || !m_player.hasShield() );
+
+        for ( unsigned int i(1); i < SHOT_NB; i++ )
+            canDrive = canDrive && ( m_score.hasWeapon(i) || !m_player.hasWeapon(i) );
+
+        /// [5] Dessin des composants
+        // [4.1] Nettoyage fenêtre
+        SDL_FillRect(m_screen, 0, 0x000000);
+
+        // [4.2] Affichage de vaisseau
+        m_player.draw( m_screen );
+
+        stringRGBA( m_screen, 50, 50, shipNames[m_shipSelect].c_str(), 255, 255, 255, 255 );
+
+        stringRGBA( m_screen, 50, 60, "CPU needed :", 255, 255, 255, 255 );
+        for ( unsigned int i(0); i < 6; i++ )
+        {
+            char s[2];
+            s[0] = (char)( shipCpu[m_shipSelect] % (Uint32)pow(10, 6 - i) / pow(10, 5 - i) );
+            s[0] += 48;
+            s[1] = 0;
+            stringRGBA( m_screen, 146 + i*8, 60, s, 255, 255, 255, 255 );
+        }
+
+        stringRGBA( m_screen, 50, 70, "Can be driven :", 255, 255, 255, 255 );
+        if ( canDrive ) stringRGBA( m_screen, 178, 70, "Yes", 0, 255, 42, 255 );
+        else stringRGBA( m_screen, 178, 70, "No", 255, 0, 0, 255 );
+
+        // [4.3] Affichage du niveau
+        for ( unsigned int i(0); i < levelDetail[m_lvlSelect].size(); i++)
+        {
+            stringRGBA( m_screen, m_screen->w / 2, 50 + i * 12, levelDetail[m_lvlSelect][i].c_str(), 255, 255, 255, 255 );
+        }
+
+        // [4.4] Affichage des données du joueur
+        stringRGBA( m_screen, 50, m_screen->h / 2, m_score.getName().c_str(), 255, 255, 255, 255 );
+
+        stringRGBA( m_screen, 50, m_screen->h / 2 + 12, "Nombre de victoires :", 255, 255, 255, 255 );
+        for ( unsigned int i(0); i < 6; i++ )
+        {
+            char vict[2];
+            vict[0] = (char)( m_score.getWinNumber() % (Uint32)pow(10, 6 - i) / pow(10, 5 - i) );
+            vict[0] += 48;
+            vict[1] = 0;
+            stringRGBA( m_screen, 224 + i*8, m_screen->h / 2 + 12, vict, 255, 255, 255, 255 );
+        }
+
+        stringRGBA( m_screen, 50, m_screen->h / 2 + 24, "CPU disponible :", 255, 255, 255, 255 );
+        for ( unsigned int i(0); i < 6; i++ )
+        {
+            char s[2];
+            s[0] = (char)( m_score.getCpuLoad() % (Uint32)pow(10, 6 - i) / pow(10, 5 - i) );
+            s[0] += 48;
+            s[1] = 0;
+            stringRGBA( m_screen, 186 + i*8, m_screen->h / 2 + 24, s, 255, 255, 255, 255 );
+        }
+
+        stringRGBA( m_screen, 50, m_screen->h / 2 + 36, "Possede le bouclier :", 255, 255, 255, 255 );
+
+        if ( m_score.hasShield() ) stringRGBA( m_screen, 224, m_screen->h / 2 + 36, "Oui", 0, 255, 42, 255 );
+        else stringRGBA( m_screen, 224, m_screen->h / 2 + 36, "Non", 255, 0, 0, 255 );
+
+        for ( unsigned int i(1); i < SHOT_NB; i ++ )
+        {
+            stringRGBA( m_screen, 50, m_screen->h / 2 + 36 + 12 * i, weapNames[i].c_str(), 255, 255, 255, 255 );
+
+            if ( m_score.hasWeapon( i ) )
+                stringRGBA( m_screen, 60 + 8 * weapNames[i].size(), m_screen->h / 2 + 36 + 12 * i, ": Disponible", 0, 255, 42, 255 );
+            else
+                stringRGBA( m_screen, 60 + 8 * weapNames[i].size(), m_screen->h / 2 + 36 + 12 * i, ": Inconnue", 255, 0, 0, 255 );
+        }
+
+        // [4.5] Double buff
+        SDL_Flip( m_screen );
+
+        /// [6] Temps
+        SDL_Delay( 16 ); // Economie du CPU
+    }
+
+    /// [7] Fin
+    if ( m_input.getToucheHeld( SDLK_RETURN ) )
+        return levelDetail[m_lvlSelect][0];
+    else
+        return "Quit";
+}
+
+bool Game::rush( string planet )
+{
+    /// [1] Préparation
+    // [1.1] Préparation du joueur
+    //m_player.loadShape("Ships/LightBeam.txt");
+    m_player.setPos( m_screen->w, m_screen->h / 2 );
+
+    // [1.2] Nettoyage
+    m_hiter.clean();
+    m_waver.reset();
+
+    // [1.3] Paramètrage des vagues
+    m_waver.setPlanet( planet );
+
+    // [1.4] Variables du temps
+    Uint32 lastFresh( SDL_GetTicks() );
+
+    // [1.5] Capturer le pointeur
+    m_input.placerPtr( m_screen );
+    m_input.afficherPointeur( false );
+    m_input.capturerPointeur( true );
+
+    /// [2] Boucle principale
+    while ( !m_input.terminer() && !m_input.getToucheHeld( SDLK_ESCAPE ) )
+    {
+        // [2.1] Mise à jour des évènements
+        m_input.updateEvenements();
+
+        // [2.2] Gestion évènements
+        m_player.scroll( m_input.getYRel() );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getBoutonSourisHeld( 1 ) ) // Clic gauche
+            m_player.fire( GUN_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getBoutonSourisHeld( 3 ) ) // Clic droit
+            m_player.fire( CUTTER_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getToucheHeld( SDLK_a ) ) // Touche a
+            m_player.fire( PHOTO_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getToucheHeld( SDLK_z ) ) // Touche z
+            m_player.fire( MISSILE_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getToucheHeld( SDLK_e ) ) // Touche e
+            m_player.fire( DISPER_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getToucheHeld( SDLK_r ) ) // Touche r
+            m_player.fire( BREXIT_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getToucheHeld( SDLK_t ) ) // Touche r
+            m_player.fire( HECTO_ID );
+
+        if ( m_input.getToucheHeld( SDLK_SPACE ) || m_input.getToucheHeld( SDLK_y ) ) // Touche r
+            m_player.fire( SNIPER_ID );
+
+        // [2.3] Mise à jour des éléments
+        m_player.enableThruster( m_waver.hasWon() );
+
+        m_player.update();
+        m_waver.update();
+
+        m_hiter.setNearPt( m_waver.nearestFromPoint( m_player.getHeartPos() ) );
+        m_hiter.setNearAxe( m_waver.nearestFromAxe( m_player.getHeartPos() ) );
+        m_hiter.setNearAlly( m_player.getHeartPos() );
+
+        m_hiter.update();
+
+        // [2.4] Dessin des composants
+        SDL_FillRect(m_screen, 0, 0x000000);
+
+        m_waver.draw( m_screen );
+        m_player.draw( m_screen );
+        m_hiter.draw( m_screen );
+
+        if ( !m_player.getIsAlive() || m_waver.hasLost() )
+            printGameOver();
+
+        SDL_Flip( m_screen );
+
+        // [2.5] Temps
+        while( SDL_GetTicks() - lastFresh < 16 )
+        {
+            if ( SDL_GetTicks() - lastFresh < 12 )
+                SDL_Delay( 2 ); // Economie du CPU
+        }
+        lastFresh = SDL_GetTicks();
+    }
+
+    /// [3] Fin
+    // [3. ] Si victoire
+    bool victory( m_waver.hasWon() );
+
+    // [3._] Nettoyage
+    m_hiter.clean();
+    m_waver.clean();
+
+    // [3._] Attente de la touche echape
+    while ( m_input.getToucheHeld( SDLK_ESCAPE ) ) m_input.updateEvenements();
+
+    // [3._] Retour
+    return m_player.getIsAlive() && victory;
+}
+
+/// Private
+void Game::printGameOver()
+{
+    stringRGBA( m_screen, 12, 30, "GAME OVER", 255, 255, 255, 255 );
+}

+ 62 - 0
Game.h

@@ -0,0 +1,62 @@
+#ifndef GAME_H
+#define GAME_H
+
+// Basiques
+#include <iostream>
+#include <cstdlib>
+#include <ctime>
+
+// SDL
+#include <SDL/SDL.h>
+#undef main
+#include <SDL/SDL_gfxPrimitives.h>
+
+// Local
+#include "HitManager.h"
+#include "Ally.h"
+#include "Score.h"
+#include "WaveManager.h"
+#include "Control/Input.h"
+
+/**
+Jovian Hersemeule
+Description du Game :
+    Le Game gère le jeu en cours dans sa globalité.
+    La fonction run() est la fonction principale et se
+    contente d'appeler alternativement menu() et rush().
+**/
+
+class Game
+{
+/// Méthodes
+    public:
+        Game();
+        virtual ~Game();
+        bool init();
+        void run();
+
+    protected:
+        std::string menu(); // Renvoie le nom de la planète
+        bool rush( std::string planet );
+
+    private:
+        void printGameOver();
+
+/// Attributs
+    private:
+        SDL_Surface* m_screen;
+
+        Ally m_player;
+        Score m_score;
+
+        HitManager m_hiter;
+        WaveManager m_waver;
+
+        Input m_input;
+
+        Uint16 m_lvlSelect;
+        Uint16 m_shipSelect;
+        Uint16 m_pSelect;
+};
+
+#endif // GAME_H

+ 155 - 0
HitManager.cpp

@@ -0,0 +1,155 @@
+#include "HitManager.h"
+
+#include "Shot/Gun.h"
+#include "Shot/Part.h"
+#include "Shot/Cutter.h"
+#include "Shot/Disper.h"
+#include "Shot/Photo.h"
+#include "Shot/Missile.h"
+#include "Shot/Brexit.h"
+#include "Shot/Hecto.h"
+#include "Shot/Sniper.h"
+
+HitManager::HitManager()
+:m_window( {0, 0, 1280, 720} )
+{
+    //ctor
+}
+
+HitManager::~HitManager()
+{
+    //dtor
+}
+
+void HitManager::draw( SDL_Surface* screen )
+{
+    for ( unsigned int i(0); i < m_shots.size(); i++) {
+        m_shots[i]->draw( screen );
+    }
+}
+
+void HitManager::addShot( Shot* tir )
+{
+    m_shots.push_back( tir );
+}
+
+void HitManager::triggerWeapon( int weapId, Sint16 x, Sint16 y, bool ally )
+{
+    switch ( weapId )
+    {
+    case GUN_ID :
+        addShot( new Gun( x, y, ally ) );
+        break;
+    case CUTTER_ID :
+        addShot( new Cutter( x, y, ally ) );
+        break;
+    case DISPER_ID :
+        for ( int vy(-4); vy <= 4; vy++ )
+            addShot( new Disper( x, y, vy, ally ) );
+        break;
+    case PHOTO_ID :
+        if ( ally )
+            addShot( new Photo( x, y, m_nearPt.x, m_nearPt.y, ally ) );
+        else
+            addShot( new Photo( x, y, m_nearAlly.x, m_nearAlly.y, ally  ) );
+        break;
+    case MISSILE_ID :
+        if ( ally )
+            addShot( new Missile( x, y, m_nearAxe.x, m_nearAxe.y, ally ) );
+        else
+            addShot( new Missile( x, y, m_nearAlly.x, m_nearAlly.y, ally ) );
+        break;
+    case BREXIT_ID :
+        addShot( new Brexit(x, y, true, ally ) );
+        addShot( new Brexit(x, y, false, ally ) );
+        break;
+    case HECTO_ID :
+        addShot( new Hecto( x, y, ally ) );
+        break;
+    case SNIPER_ID :
+        addShot( new Sniper( x, y, ally ) );
+        break;
+    default :
+        break;
+    }
+}
+
+Sint32 HitManager::absorb( bool isAlly, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    Sint32 deg( 0 );
+
+    for ( unsigned int i(0); i < m_shots.size(); i++) {
+        if ( isAlly != m_shots[i]->getIsAlly() && m_shots[i]->isIn( hitbox ) )
+            deg += m_shots[i]->takeDegat();
+    }
+
+    return deg;
+}
+
+bool HitManager::colide( bool isAlly, Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox  )
+{
+    bool rep( false );
+    for ( unsigned int i(0); i < m_shots.size(); i++) {
+        if ( isAlly != m_shots[i]->getIsAlly() && m_shots[i]->isIn( hitbox ) )
+            rep = rep || m_shots[i]->damageSolid( solid, dimH, dimW, hitbox );
+    }
+
+    return rep;
+}
+
+void HitManager::update()
+{
+    // Raccourcissement de la file
+    while ( !m_shots.empty() && ( !m_shots.front()->isIn(m_window) || !m_shots.front()->getExist() ) ) {
+        delete m_shots.front();
+        m_shots.front() = 0x0;
+        m_shots.pop_front();
+    }
+
+    // Déplacement des tirs
+    for ( unsigned int i(0); i < m_shots.size(); i++) {
+
+        m_shots[i]->update() ;
+
+        // Destruction des tirs hors champs
+        if ( !m_shots[i]->isIn( m_window ) )
+            m_shots[i]->setExist( false );
+    }
+}
+
+void HitManager::clean()
+{
+    while ( !m_shots.empty() ) {
+        delete m_shots.front();
+        m_shots.front() = 0x0;
+        m_shots.pop_front();
+    }
+}
+
+unsigned int HitManager::getDecay( unsigned int weapId )
+{
+    if ( weapId >= SHOT_NB )
+    {
+        std::cout << "getDecay : Bug cher ami !" << std::endl;
+        return 16;
+    }
+
+    unsigned int decTab[ SHOT_NB ] = ACTOR_DECAY;
+
+    return decTab[ weapId ];
+}
+
+void HitManager::setNearPt( SDL_Rect nearPt )
+{
+    m_nearPt = nearPt;
+}
+
+void HitManager::setNearAxe( SDL_Rect nearAxe )
+{
+    m_nearAxe = nearAxe;
+}
+
+void HitManager::setNearAlly( SDL_Rect nearAlly )
+{
+    m_nearAlly = nearAlly;
+}

+ 110 - 0
HitManager.h

@@ -0,0 +1,110 @@
+#ifndef HITMANAGER_H
+#define HITMANAGER_H
+
+// Basiques
+#include <iostream>
+#include <cmath>
+#include <deque>
+#include <vector>
+
+// SDL
+#include <SDL/SDL.h>
+#undef main
+#include <SDL/SDL_gfxPrimitives.h>
+
+// Combat
+#include "Shot.h"
+
+// Nombre de projectiles différents
+#define SHOT_NB 9
+
+// Identifiants
+#define PART_ID 0
+#define GUN_ID 1
+#define CUTTER_ID 2
+#define DISPER_ID 3
+#define PHOTO_ID 4
+#define MISSILE_ID 5
+#define BREXIT_ID 6
+#define HECTO_ID 7
+#define SNIPER_ID 8
+
+// Noms
+#define PART_NAME "Part"
+#define GUN_NAME "Gun"
+#define CUTTER_NAME "Cutter"
+#define DISPER_NAME "Disper"
+#define PHOTO_NAME "ProtoSeeker"
+#define MISSILE_NAME "Missile Launcher"
+#define BREXIT_NAME "Brexit Launcher"
+#define HECTO_NAME "Hecto Combustion"
+#define SNIPER_NAME "Sniper Rifle"
+#define ACTOR_NAME { PART_NAME, GUN_NAME, CUTTER_NAME, DISPER_NAME, PHOTO_NAME, MISSILE_NAME, BREXIT_NAME, HECTO_NAME, SNIPER_NAME }
+
+// Délais
+#define GUN_DECAY 256
+#define CUTTER_DECAY 272
+#define DISPER_DECAY 200
+#define PHOTO_DECAY 100
+#define MISSILE_DECAY 800
+#define BREXIT_DECAY 106
+#define HECTO_DECAY 350
+#define SNIPER_DECAY 700
+#define ACTOR_DECAY { 0, GUN_DECAY, CUTTER_DECAY, DISPER_DECAY, PHOTO_DECAY, MISSILE_DECAY, BREXIT_DECAY, HECTO_DECAY, SNIPER_DECAY }
+
+// Charges CPU
+#define PART_CPU 1
+#define GUN_CPU 20
+#define CUTTER_CPU 22
+#define DISPER_CPU 24
+#define PHOTO_CPU 22
+#define MISSILE_CPU 70
+#define BREXIT_CPU 27
+#define HECTO_CPU 56
+#define SNIPER_CPU 50
+#define ACTOR_CPU { PART_CPU, GUN_CPU, CUTTER_CPU, DISPER_CPU, PHOTO_CPU, MISSILE_CPU, BREXIT_CPU, HECTO_CPU, SNIPER_CPU }
+#define SHIELD_CPU 30
+
+/**
+Jovian Hersemeule
+Description du HitManager :
+    Le HitManager contient toutes les données à propos des projectiles tirés
+    par les entittés du jeu. Elle affiche les tirs, les fait bouger, les créé,
+    les détruit, et permet aux entités de tester la collision.
+**/
+
+class HitManager
+{
+/// Méthodes
+    public:
+        HitManager();
+        virtual ~HitManager();
+
+        virtual void draw( SDL_Surface* screen );
+
+        virtual void addShot( Shot* tir );
+        virtual void triggerWeapon( int weapId, Sint16 x, Sint16 y, bool ally = false );
+
+        virtual Sint32 absorb( bool isAlly, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+        virtual bool colide( bool isAlly, Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+        virtual void update();
+        virtual void clean();
+
+        unsigned int getDecay( unsigned int weapId );
+
+        void setNearPt( SDL_Rect nearPt );
+        void setNearAxe( SDL_Rect nearAxe );
+        void setNearAlly( SDL_Rect nearAlly );
+
+/// Attributs
+    protected:
+        SDL_Rect m_window;
+        std::deque<Shot*> m_shots;
+
+        SDL_Rect m_nearPt;
+        SDL_Rect m_nearAxe;
+        SDL_Rect m_nearAlly;
+};
+
+#endif // HITMANAGER_H

+ 147 - 0
Score.cpp

@@ -0,0 +1,147 @@
+#include "Score.h"
+
+using namespace std;
+
+Score::Score()
+:m_name("Unloaded"), m_cpuLoad( 40 ), m_winNumber( 0 ), m_hasShield( false )
+{
+    m_hasWeapon[ GUN_ID ] = true;
+
+    for ( unsigned int i(2); i < SHOT_NB; i ++ )
+    {
+        m_hasWeapon[i] = false;
+    }
+}
+
+Score::~Score()
+{
+    //dtor
+}
+
+void Score::load( std::string name )
+{
+    // Chemin
+    m_name = name;
+    string chemin( "Saves/" + name + ".txt" );
+
+    // Flux
+    ifstream loadStream( chemin.c_str() );
+
+    // Lecture
+    loadStream >> m_cpuLoad;
+    loadStream >> m_winNumber;
+    loadStream >> m_hasShield;
+
+    for ( unsigned int i(1); i < SHOT_NB; i ++ )
+        loadStream >> m_hasWeapon[i];
+}
+
+void Score::save()
+{
+    // Chemin
+    string chemin( "Saves/" + m_name + ".txt" );
+
+    // Flux
+    ofstream writeStream( chemin.c_str() );
+
+    // Ecriture
+    writeStream << m_cpuLoad << endl;
+    writeStream << m_winNumber << endl;
+    writeStream << m_hasShield << endl;
+
+    for ( unsigned int i(1); i < SHOT_NB; i ++ )
+        writeStream << m_hasWeapon[i] << endl;
+}
+
+std::string Score::getName()
+{
+    return m_name;
+}
+
+Uint32 Score::getCpuLoad()
+{
+    return m_cpuLoad;
+}
+
+Uint32 Score::getWinNumber()
+{
+    return m_winNumber;
+}
+
+bool Score::hasShield()
+{
+    return m_hasShield;
+}
+
+bool Score::hasWeapon( int weapId )
+{
+    if ( weapId < SHOT_NB )
+        return m_hasWeapon[ weapId ];
+    else
+        return false;
+}
+
+void Score::addVictory()
+{
+    m_winNumber ++;
+}
+
+void Score::giveLoot( std::string planet )
+{
+    // Arme en récompense
+    if ( planet == "Alderande" )
+    {
+        m_hasWeapon[ DISPER_ID ] = true;
+        return;
+    }
+
+    if ( planet == "Faiz" )
+    {
+        m_hasWeapon[ CUTTER_ID ] = true;
+        return;
+    }
+
+    if ( planet == "Kratarite" )
+    {
+        m_hasWeapon[ PHOTO_ID ] = true;
+        return;
+    }
+
+    if ( planet == "DistantSite2016_UK" )
+    {
+        m_hasWeapon[ BREXIT_ID ] = true;
+        return;
+    }
+
+    if ( planet == "Telurande" )
+    {
+        m_hasWeapon[ HECTO_ID ] = true;
+        return;
+    }
+
+    // Bouclier de combat en recompene
+    if ( planet == "Titan" )
+    {
+        m_hasShield = true;
+        return;
+    }
+
+    // Majoration du CPU
+    if ( planet == "BlueMoon" && m_cpuLoad < 100 )
+    {
+        m_cpuLoad = 100;
+        return;
+    }
+
+    if ( planet == "KeplerSite429_M75" && m_cpuLoad < 200 )
+    {
+        m_cpuLoad = 200;
+        return;
+    }
+
+    if ( planet == "Genii" && m_cpuLoad < 300 )
+    {
+        m_cpuLoad = 300;
+        return;
+    }
+}

+ 44 - 0
Score.h

@@ -0,0 +1,44 @@
+#ifndef SCORE_H
+#define SCORE_H
+
+#include "HitManager.h"
+#include <fstream>
+
+/**
+Jovian Hersemeule
+Description du Ally :
+    Contient toutes les données relatives au sauvegardes du joueur.
+**/
+
+class Score
+{
+/// Méthodes
+    public:
+        Score();
+        virtual ~Score();
+
+        void load( std::string name );
+        void save();
+
+        std::string getName();
+        Uint32 getCpuLoad();
+        Uint32 getWinNumber();
+
+        bool hasShield();
+        bool hasWeapon( int weapId );
+
+        void addVictory();
+        void giveLoot( std::string planet );
+
+/// Attributs
+    protected:
+        std::string m_name;
+
+        Uint32 m_cpuLoad;
+        Uint32 m_winNumber;
+
+        bool m_hasShield;
+        bool m_hasWeapon[SHOT_NB];
+};
+
+#endif // SCORE_H

+ 79 - 0
Shot.cpp

@@ -0,0 +1,79 @@
+#include "Shot.h"
+
+Shot::Shot()
+:m_x(12), m_y(12), m_degat( 12 ), m_ally( true ), m_exist( true )
+{
+    //ctor
+}
+
+Shot::Shot( Sint32 degat, bool ally )
+:m_x(12), m_y(12), m_degat( degat ), m_ally( ally ), m_exist( true )
+{
+    //ctor
+}
+
+Shot::Shot( Sint32 degat, Sint16 x, Sint16 y, bool ally )
+:m_x(x), m_y(y), m_degat( degat ), m_ally( ally ), m_exist( true )
+{
+    //ctor
+}
+
+Shot::~Shot()
+{
+    //dtor
+}
+
+
+bool Shot::isIn( const SDL_Rect& hitbox )
+{
+    return m_exist &&
+            m_x > hitbox.x &&
+            m_x < hitbox.x + hitbox.w &&
+            m_y > hitbox.y &&
+            m_y < hitbox.y + hitbox.h ;
+}
+
+bool Shot::getIsAlly()
+{
+    return m_ally;
+}
+
+bool Shot::getExist()
+{
+    return m_exist;
+}
+
+void Shot::setExist( bool exist )
+{
+    m_exist = exist;
+}
+
+Sint32 Shot::takeDegat()
+{
+    if ( m_exist )
+    {
+        m_exist = false;
+        return m_degat;
+    }
+
+    return 0;
+}
+
+bool Shot::damageBloc( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const Uint16 y, const Uint16 x, const Uint8 bam)
+{
+    // Sortie de tableau
+    if ( x >= dimW || y >= dimH )
+            return false;
+
+    // Pas de dégats, renvoie false
+    if ( solid[y][x] == 0 )
+        return false;
+
+    // On fait des dégats !!!
+    if ( solid[y][x] < bam )
+        solid[y][x] = 0;
+    else
+        solid[y][x] -= bam;
+
+    return true;
+}

+ 53 - 0
Shot.h

@@ -0,0 +1,53 @@
+#ifndef SHOT_H
+#define SHOT_H
+
+#include <iostream>
+#include <cmath>
+
+// SDL
+#include <SDL/SDL.h>
+#undef main
+#include <SDL/SDL_gfxPrimitives.h>
+
+/**
+Jovian Hersemeule
+Description du Shot :
+    La classe shot contient toutes les infos à propos du tir : dégâts, positions.
+    C'est une classe abstraite dont héritent les différents projectiles ( missiles, lasers, ..).
+**/
+
+class Shot
+{
+/// Méthodes
+    public:
+        Shot();
+        Shot( Sint32 degat, bool ally = false );
+        Shot( Sint32 degat, Sint16 x, Sint16 y, bool ally = false ); // Set les positons coin haut gauche
+        virtual ~Shot();
+
+        bool isIn( const SDL_Rect& hitbox );
+        bool getIsAlly();
+        bool getExist();
+        void setExist( bool exist );
+        virtual Sint32 takeDegat();
+
+        virtual void update() = 0;
+        virtual void draw( SDL_Surface* screen ) = 0;
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox ) = 0;
+
+    protected:
+        bool damageBloc( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const Uint16 y, const Uint16 x, const Uint8 bam);
+
+/// Attributs
+    protected:
+        Sint16 m_x; // Position du centre du tir
+        Sint16 m_y;
+
+        Sint32 m_degat;
+
+        bool m_ally;
+
+        bool m_exist;
+};
+
+#endif // SHOT_H

+ 75 - 0
Shot/Brexit.cpp

@@ -0,0 +1,75 @@
+#include "Brexit.h"
+
+Brexit::Brexit()
+:Shot( BREXIT_DEGAT ), m_vx( -BREXIT_SPEED_X), m_vy( BREXIT_SPEED_Y )
+{
+    //ctor
+}
+
+Brexit::Brexit( Sint16 x, Sint16 y, bool up, bool ally )
+:Shot( BREXIT_DEGAT, x, y, ally ), m_vx( BREXIT_SPEED_X ), m_vy( BREXIT_SPEED_Y )
+{
+    if ( ally )
+        m_vx = -m_vx;
+
+    if ( up )
+        m_vy = -m_vy;
+}
+
+Brexit::~Brexit()
+{
+    //dtor
+}
+
+void Brexit::update()
+{
+    m_x += m_vx;
+    m_y += m_vy;
+}
+
+void Brexit::draw( SDL_Surface* screen )
+{
+    if ( !m_exist )
+        return;
+
+    stringRGBA(screen, m_x - 4, m_y - 4, "X", 0, 255, 0, 255);
+}
+
+bool Brexit::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer l'ordonnée d'impact discret
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+    Uint16 xImpct( ( m_x - hitbox.x ) / 8 );
+
+    Sint16 yAdd(1);
+    if ( m_vy < 0 ) yAdd = -1;
+
+    Sint16 xAdd(1);
+    if ( m_ally ) xAdd = -1;
+
+    // Détermination du bord de pénétration
+    while ( yImpct != 0 && xImpct != 0 && yImpct != dimH - 1 && xImpct != dimW - 1 )
+    {
+        xImpct -= xAdd;
+        yImpct -= yAdd;
+    }
+
+    // Détermination de l'abscisse d'impact
+    while ( solid[yImpct][xImpct] == 0 )
+    {
+        xImpct += xAdd;
+        yImpct += yAdd;
+
+        if ( xImpct >= dimW || yImpct >= dimH )
+            return false;
+    }
+
+    // Déstruction du centre
+    damageBloc( solid, dimH, dimW, yImpct, xImpct, 150 );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + xAdd, 150 );
+    damageBloc( solid, dimH, dimW, yImpct + yAdd, xImpct, 150 );
+
+    // Déstruction du projectile
+    m_exist = false;
+    return true;
+}

+ 35 - 0
Shot/Brexit.h

@@ -0,0 +1,35 @@
+#ifndef BREXIT_H
+#define BREXIT_H
+
+#include "../Shot.h"
+
+#define BREXIT_DEGAT 900
+#define BREXIT_SPEED_X 18
+#define BREXIT_SPEED_Y 9
+
+/**
+Jovian Hersemeule
+Description du Brexit :
+    L'arme Brexit lance deux tirs en diagonale, très utile
+    pour flinguer les ennemis sans se faire toucher.
+**/
+
+class Brexit : public Shot
+{
+/// Méthodes
+    public:
+        Brexit();
+        Brexit( Sint16 x, Sint16 y, bool up, bool ally = false );
+        virtual ~Brexit();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        int m_vx;
+        int m_vy;
+};
+
+#endif // BREXIT_H

+ 62 - 0
Shot/Cutter.cpp

@@ -0,0 +1,62 @@
+#include "Cutter.h"
+
+Cutter::Cutter()
+:Shot( CUTTER_DEGAT ), m_velocity( -CUTTER_SPEED )
+{
+    //ctor
+}
+
+Cutter::Cutter( Sint16 x, Sint16 y, bool ally )
+:Shot( CUTTER_DEGAT, x, y, ally ), m_velocity( CUTTER_SPEED )
+{
+    if ( ally )
+        m_velocity = -m_velocity;
+}
+
+Cutter::~Cutter()
+{
+    //dtor
+}
+
+void Cutter::update()
+{
+    m_x += m_velocity;
+}
+
+void Cutter::draw( SDL_Surface* screen )
+{
+    if ( m_exist )
+        stringRGBA(screen, m_x - 4, m_y - 4, "|", 255, 255, 0, 255);
+}
+
+bool Cutter::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer l'ordonnée d'impact
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+
+    // Détermination de l'abscisse d'impact
+    Sint16 xImpct(0);
+    if ( m_ally )
+        xImpct = dimW - 1;
+
+    while ( solid[yImpct][xImpct] == 0 )
+    {
+        if ( m_ally )
+            xImpct --;
+        else
+            xImpct ++;
+
+        if ( xImpct == -1 || xImpct == dimW )
+            return false;
+    }
+
+    // Déstruction de la ligne
+    for ( int i(0); i < dimH; i++ ) {
+        damageBloc( solid, dimH, dimW, i, xImpct, 128 );
+    }
+
+
+    // Le projectile a atteint sa cible
+    m_exist = false;
+    return true;
+}

+ 33 - 0
Shot/Cutter.h

@@ -0,0 +1,33 @@
+#ifndef CUTTER_H
+#define CUTTER_H
+
+#include "../Shot.h"
+
+#define CUTTER_DEGAT 1280
+#define CUTTER_SPEED 16
+
+/**
+Jovian Hersemeule
+Description du Cutter :
+    Le tir de type Cutter est assez rapide et très tactique :
+    il peut trancher des vaisseaux en deux dans le sens de la hauteur !
+**/
+
+class Cutter : public Shot
+{
+/// Méthodes
+    public:
+        Cutter();
+        Cutter( Sint16 x, Sint16 y, bool ally = false );
+        virtual ~Cutter();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        int m_velocity;
+};
+
+#endif // CUTTER_H

+ 85 - 0
Shot/Disper.cpp

@@ -0,0 +1,85 @@
+#include "Disper.h"
+
+#define DISPER_LIFE 25
+
+Disper::Disper()
+:Shot ( DISPER_DEGAT ), m_vx( -DISPER_SPEED ), m_vy( 0 ), m_life( DISPER_LIFE )
+{
+    //ctor
+}
+
+Disper::Disper( Sint16 x, Sint16 y, Sint16 vy, bool ally )
+:Shot( DISPER_DEGAT, x, y, ally ), m_vx( DISPER_SPEED ), m_vy( vy ), m_life( DISPER_LIFE )
+{
+    m_vx -= abs( vy );
+
+    if ( ally )
+        m_vx = -m_vx;
+}
+
+Disper::~Disper()
+{
+    //dtor
+}
+
+void Disper::update()
+{
+    m_x += m_vx;
+    m_y += m_vy;
+
+    m_life -= 1;
+    if ( m_life == 0 )
+        m_exist = false;
+}
+
+void Disper::draw( SDL_Surface* screen )
+{
+    if ( !m_exist )
+        return;
+
+    stringRGBA(screen, m_x - 4, m_y - 4, "*", 255, m_life * 255 / DISPER_LIFE, m_life * 128 / DISPER_LIFE, 255);
+}
+
+bool Disper::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer l'ordonnée d'impact
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+
+    // Détermination de l'abscisse d'impact
+    Sint16 xImpct(0);
+    if ( m_ally )
+        xImpct = dimW - 1;
+
+    while ( solid[yImpct][xImpct] == 0 )
+    {
+        if ( m_ally )
+            xImpct --;
+        else
+            xImpct ++;
+
+        if ( xImpct == -1 || xImpct == dimW )
+            return false;
+    }
+
+    // Déstruction du centre
+    damageBloc( solid, dimH, dimW, yImpct, xImpct, 255 );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct, 255 );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct, 255 );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 1, 255 );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 1, 255 );
+
+    // Dégats sur l'immédiat
+    Uint16 nearBam( m_life * 50 + 5 );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct - 1, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct - 1, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct + 1, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct + 1, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct - 2, xImpct, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct + 2, xImpct, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 2, nearBam );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 2, nearBam );
+
+    // Déstruction du projectile
+    m_exist = false;
+    return true;
+}

+ 35 - 0
Shot/Disper.h

@@ -0,0 +1,35 @@
+#ifndef DISPER_H
+#define DISPER_H
+
+#include "../Shot.h"
+
+#define DISPER_DEGAT 3315
+#define DISPER_SPEED 20
+
+/**
+Jovian Hersemeule
+Description du Disper :
+    Le tir de type Disper est rapide. Il inflige de gros dégâts localisés.
+    La puissance diminue avec la distance.
+**/
+
+class Disper : public Shot
+{
+/// Méthodes
+    public:
+        Disper();
+        Disper( Sint16 x, Sint16 y, Sint16 vy, bool ally = false );
+        virtual ~Disper();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        Sint16 m_vx;
+        Sint16 m_vy;
+        Uint8 m_life;
+};
+
+#endif // DISPER_H

+ 78 - 0
Shot/Gun.cpp

@@ -0,0 +1,78 @@
+#include "Gun.h"
+
+Gun::Gun()
+:Shot( GUN_DEGAT ), m_velocity( -GUN_SPEED )
+{
+    //ctor
+}
+
+Gun::Gun( Sint16 x, Sint16 y, bool ally )
+:Shot( GUN_DEGAT, x, y, ally ), m_velocity( GUN_SPEED )
+{
+    if ( ally )
+        m_velocity = -m_velocity;
+}
+
+Gun::~Gun()
+{
+    //dtor
+}
+
+void Gun::update()
+{
+    m_x += m_velocity;
+}
+
+void Gun::draw( SDL_Surface* screen )
+{
+    if ( m_exist )
+        stringRGBA(screen, m_x - 4, m_y - 4, "+", 255, 255, 255, 255);
+}
+
+bool Gun::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer l'ordonnée d'impact
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+
+    // Détermination de l'abscisse d'impact
+    Sint16 xImpct(0);
+    if ( m_ally )
+        xImpct = dimW - 1;
+
+    while ( solid[yImpct][xImpct] == 0 )
+    {
+        if ( m_ally )
+            xImpct --;
+        else
+            xImpct ++;
+
+        if ( xImpct == -1 || xImpct == dimW )
+            return false;
+    }
+
+    // Déstruction du centre
+    #define GUN_CENTER_BAM 200
+    damageBloc( solid, dimH, dimW, yImpct, xImpct, GUN_CENTER_BAM );
+
+    // Forts dégats sur l'immédiat
+    #define GUN_NEAREST_BAM 130
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct, GUN_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct, GUN_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 1, GUN_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 1, GUN_NEAREST_BAM );
+
+    // Faibles dégats sur l'adjacent
+    #define GUN_FAR_BAM 60
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct - 1, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct - 1, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct + 1, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct + 1, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct - 2, xImpct, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 2, xImpct, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 2, GUN_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 2, GUN_FAR_BAM );
+
+    // Déstruction du projectile
+    m_exist = false;
+    return true;
+}

+ 33 - 0
Shot/Gun.h

@@ -0,0 +1,33 @@
+#ifndef GUN_H
+#define GUN_H
+
+#include "../Shot.h"
+
+#define GUN_DEGAT 1095
+#define GUN_SPEED 18
+
+/**
+Jovian Hersemeule
+Description du Gun :
+    Le tir de type Gun est rapide et rectiligne. Il inflige de petits dégâts
+    qui se dispersent en croix.
+**/
+
+class Gun : public Shot
+{
+/// Méthodes
+    public:
+        Gun();
+        Gun( Sint16 x, Sint16 y, bool ally = false );
+        virtual ~Gun();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        int m_velocity;
+};
+
+#endif // GUN_H

+ 69 - 0
Shot/Hecto.cpp

@@ -0,0 +1,69 @@
+#include "Hecto.h"
+
+Hecto::Hecto()
+:Shot( HECTO_DEGAT ), m_velocity( -HECTO_SPEED ), m_life( HECTO_DURABILTY )
+{
+    //ctor
+}
+
+Hecto::Hecto( Sint16 x, Sint16 y, bool ally )
+:Shot( HECTO_DEGAT, x, y, ally ), m_velocity( HECTO_SPEED ), m_life( HECTO_DURABILTY )
+{
+    if ( ally )
+        m_velocity = -m_velocity;
+}
+
+Hecto::~Hecto()
+{
+    //dtor
+}
+
+void Hecto::update()
+{
+    m_x += m_velocity;
+}
+
+void Hecto::draw( SDL_Surface* screen )
+{
+    if ( m_exist )
+        stringRGBA(screen, m_x - 4, m_y - 4, "H", 128, m_life * 255 / HECTO_DURABILTY, 0, 255);
+}
+
+bool Hecto::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer les cordonnées de l'impact
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+    Uint16 xImpct( ( m_x - hitbox.x ) / 8 );
+
+    // Bloc présent ?
+    if ( solid[yImpct][xImpct] == 0 )
+        return false;
+
+    // Déstruction du centre
+    damageBloc( solid, dimH, dimW, yImpct, xImpct, 255 );
+
+    // Forts dégats sur l'immédiat
+    #define HECTO_NEAREST_BAM 200
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 1, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 1, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct - 1, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct - 1, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct + 1, HECTO_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct + 1, HECTO_NEAREST_BAM );
+
+    // Faibles dégats sur l'adjacent
+    #define HECTO_FAR_BAM 60
+    damageBloc( solid, dimH, dimW, yImpct - 2, xImpct, HECTO_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 2, xImpct, HECTO_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 2, HECTO_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 2, HECTO_FAR_BAM );
+
+    // Déstruction du projectile
+    m_life-- ;
+    if ( m_life == 0 )
+        m_exist = false;
+
+    return true;
+}

+ 35 - 0
Shot/Hecto.h

@@ -0,0 +1,35 @@
+#ifndef HECTO_H
+#define HECTO_H
+
+#include "../Shot.h"
+
+#define HECTO_DEGAT 2095
+#define HECTO_SPEED 7
+#define HECTO_DURABILTY 6
+
+/**
+Jovian Hersemeule
+Description du Hecto :
+    Le tir de type Hecto est rapide et rectiligne. Il inflige de petits dégâts
+    qui se dispersent en croix.
+**/
+
+class Hecto : public Shot
+{
+/// Méthodes
+    public:
+        Hecto();
+        Hecto( Sint16 x, Sint16 y, bool ally = false );
+        virtual ~Hecto();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        int m_velocity;
+        Uint16 m_life;
+};
+
+#endif // HECTO_H

+ 164 - 0
Shot/Missile.cpp

@@ -0,0 +1,164 @@
+#include "Missile.h"
+
+Missile::Missile()
+:Shot( MISSILE_DEGAT ), m_xHim( 0 ), m_yHim( 0 ), m_hasTgt( false ), m_decay( 0 ), m_dir( MISSILE_BOOST )
+{
+    //ctor 1
+}
+
+Missile::Missile( Sint16 xMe, Sint16 yMe, bool ally )
+:Shot( MISSILE_DEGAT, xMe, yMe, ally ), m_xHim( 0 ), m_yHim( 0 ), m_hasTgt( false ), m_decay( 0 ), m_dir( MISSILE_BOOST )
+{
+    //ctor 2
+}
+
+Missile::Missile( Sint16 xMe, Sint16 yMe, Sint16 xHim, Sint16 yHim, bool ally )
+:Shot( MISSILE_DEGAT, xMe, yMe, ally ), m_xHim( xHim ), m_yHim( yHim ), m_hasTgt( true ), m_decay( 0 ), m_dir( MISSILE_BOOST )
+{
+    //ctor 3
+    if ( ally )
+        m_decay = abs( yHim - yMe ) / MISSILE_TURN_SPEED;
+}
+
+Missile::~Missile()
+{
+    //dtor
+}
+
+void Missile::update()
+{
+    if ( m_dir == MISSILE_BOOST )
+    {
+        if ( m_ally )
+        {
+            m_x -= MISSILE_BOOST_SPEED;
+            m_xHim += 1;
+
+            if ( m_hasTgt && m_xHim >= m_x ) turn();
+        }
+        else
+        {
+            m_x += MISSILE_BOOST_SPEED;
+
+            if ( m_hasTgt && m_xHim <= m_x ) turn();
+        }
+    }
+    else
+    {
+        m_y += m_dir * MISSILE_TURN_SPEED;
+    }
+}
+
+void Missile::draw( SDL_Surface* screen )
+{
+    if ( !m_exist )
+        return;
+
+    switch ( m_dir )
+    {
+        case MISSILE_BOOST:
+            if ( m_ally ) stringRGBA(screen, m_x - 8, m_y - 4, "<-", 255, 120, 0, 255);
+            else stringRGBA(screen, m_x - 8, m_y - 4, "->", 255, 120, 0, 255);
+            break;
+        case MISSILE_DOWN:
+            stringRGBA(screen, m_x - 4, m_y - 8, "|", 255, 120, 0, 255);
+            stringRGBA(screen, m_x - 4, m_y, "v", 255, 120, 0, 255);
+            break;
+        case MISSILE_UP:
+            stringRGBA(screen, m_x - 4, m_y - 8, "^", 255, 120, 0, 255);
+            stringRGBA(screen, m_x - 4, m_y, "|", 255, 120, 0, 255);
+            break;
+        default:
+            stringRGBA(screen, m_x - 4, m_y - 4, "X", 255, 120, 0, 255);
+            break;
+    }
+
+}
+
+bool Missile::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Coordonnées impact
+    Uint16 yImpct, xImpct;
+
+    if ( m_dir == MISSILE_BOOST )
+    {
+        // Pénétration axe horizontal
+        yImpct = ( m_y - hitbox.y ) / 8;
+
+        if ( m_ally )
+            xImpct = dimW - 1;
+        else
+            xImpct = 0;
+
+        while ( solid[yImpct][xImpct] == 0 )
+        {
+            if ( m_ally )
+                xImpct --;
+            else
+                xImpct ++;
+
+            if ( xImpct >= dimW )
+                return false;
+        }
+    }
+    else
+    {
+        // Pénétration verticale
+        xImpct = ( m_x - hitbox.x ) / 8;
+
+        Sint8 adder( 0 );
+
+        if ( m_dir == MISSILE_UP ) {
+            yImpct = dimH - 1;
+            adder = MISSILE_UP;
+        }
+        else {
+            yImpct = 0;
+            adder = MISSILE_DOWN;
+        }
+
+        while ( solid[yImpct][xImpct] == 0 )
+        {
+            yImpct += adder;
+
+            if ( yImpct >= dimH )
+                return false;
+        }
+    }
+
+    // Déstruction du centre
+    damageBloc( solid, dimH, dimW, yImpct, xImpct, 255 );
+
+    // Forts dégats sur l'immédiat
+    #define MISSILE_NEAREST_BAM 250
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 1, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 1, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct - 1, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct - 1, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct - 1, xImpct + 1, MISSILE_NEAREST_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 1, xImpct + 1, MISSILE_NEAREST_BAM );
+
+    // Faibles dégats sur l'adjacent
+    #define MISSILE_FAR_BAM 200
+    damageBloc( solid, dimH, dimW, yImpct - 2, xImpct, MISSILE_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct + 2, xImpct, MISSILE_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct - 2, MISSILE_FAR_BAM );
+    damageBloc( solid, dimH, dimW, yImpct, xImpct + 2, MISSILE_FAR_BAM );
+
+    // Déstruction du projectile
+    m_exist = false;
+    return true;
+}
+
+void Missile::turn()
+{
+    m_x = m_xHim + m_decay ;
+
+    if ( m_yHim > m_y )
+        m_dir = MISSILE_DOWN;
+    else
+        m_dir = MISSILE_UP;
+}
+

+ 49 - 0
Shot/Missile.h

@@ -0,0 +1,49 @@
+#ifndef MISSILE_H
+#define MISSILE_H
+
+#include "../Shot.h"
+
+#define MISSILE_DEGAT 3055
+#define MISSILE_BOOST_SPEED 28
+#define MISSILE_TURN_SPEED 22
+
+/**
+Jovian Hersemeule
+Description du Missile :
+    Le tir de type missile est assez lent à recharger mais offre
+    des capacités extraordinaires de destruction. Le missile commence
+    une approche en ligne droite avant de tourner à 90° vers le coeur
+    de la cible.
+**/
+
+class Missile : public Shot
+{
+/// Méthodes
+    public:
+        Missile();
+        Missile( Sint16 xMe, Sint16 yMe, bool ally = false );
+        Missile( Sint16 xMe, Sint16 yMe, Sint16 xHim, Sint16 yHim, bool ally = false );
+        virtual ~Missile();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+    private:
+        void turn();
+
+/// Attributs
+    private:
+        Sint16 m_xHim;
+        Sint16 m_yHim;
+
+        bool m_hasTgt;
+        Sint16 m_decay;
+
+        Sint8 m_dir;
+        #define MISSILE_UP -1
+        #define MISSILE_DOWN 1
+        #define MISSILE_BOOST 0
+};
+
+#endif // MISSILE_H

+ 53 - 0
Shot/Part.cpp

@@ -0,0 +1,53 @@
+#include "Part.h"
+
+Part::Part()
+:Shot( PART_DEGAT ), m_speedX( 5 ), m_speedY( 1 ), m_lvl( 255 )
+{
+    m_part[0] = '#';
+    m_part[1] = 0;
+}
+
+Part::Part( Sint16 x, Sint16 y, Sint16 speedX, Sint16 speedY, Uint8 lvl, char part, bool ally )
+:Shot( PART_DEGAT, x, y, ally ), m_speedX( speedX ), m_speedY( speedY ), m_lvl( lvl )
+{
+    m_part[0] = part;
+    m_part[1] = 0;
+}
+
+Part::~Part()
+{
+    //dtor
+}
+
+void Part::update()
+{
+    if ( !m_exist )
+        return;
+
+    m_x += m_speedX;
+    m_y += m_speedY;
+
+    Uint8 deg( 1 + ( rand() % 20 ) );
+
+    if ( m_lvl < deg)
+        m_exist = false;
+
+    m_lvl -= deg;
+}
+
+void Part::draw( SDL_Surface* screen )
+{
+    if ( m_exist )
+        stringRGBA(screen, m_x - 4, m_y - 4, m_part, 255, m_lvl, m_lvl, 255);
+}
+
+bool Part::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer les coordonnées d'impact
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+    Uint16 xImpct( ( m_x - hitbox.x ) / 8 );
+
+    // Débris détruit si contact
+    m_exist = !damageBloc( solid, dimH, dimW, yImpct, xImpct, 42 );
+    return !m_exist;
+}

+ 34 - 0
Shot/Part.h

@@ -0,0 +1,34 @@
+#ifndef PART_H
+#define PART_H
+
+#include "../Shot.h"
+#define PART_DEGAT 42
+
+/**
+Jovian Hersemeule
+Description de Part :
+    Le tir de type Part est en fait un débris de vaisseau qui
+    a explosé. Cela fait très peu de dégâts.
+**/
+
+class Part : public Shot
+{
+/// Méthodes
+    public:
+        Part();
+        Part( Sint16 x, Sint16 y, Sint16 speedX, Sint16 speedY, Uint8 lvl, char part, bool ally = false );
+        virtual ~Part();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        Sint16 m_speedX;
+        Sint16 m_speedY;
+        Uint8 m_lvl;
+        char m_part[2];
+};
+
+#endif // PART_H

+ 107 - 0
Shot/Photo.cpp

@@ -0,0 +1,107 @@
+#include "Photo.h"
+
+Photo::Photo()
+:Shot( PHOTO_DEGAT ), m_vx( -PHOTO_SPEED ), m_vy( 0 )
+{
+    //ctor 1
+}
+
+Photo::Photo( Sint16 xMe, Sint16 yMe, bool ally )
+:Shot( PHOTO_DEGAT, xMe, yMe, ally ), m_vx( PHOTO_SPEED ), m_vy( 0 )
+{
+    if ( ally )
+        m_vx = -m_vx;
+}
+
+Photo::Photo( Sint16 xMe, Sint16 yMe, Sint16 xHim, Sint16 yHim, bool ally )
+:Shot( PHOTO_DEGAT, xMe, yMe, ally )
+{
+    m_vx = xHim - xMe ;
+    m_vy = yHim - yMe ;
+    Sint16 norme( std::sqrt( m_vx * m_vx + m_vy * m_vy ) ) ;
+
+    xHim += norme / PHOTO_SPEED ; // Anticipe le mouvement de l'ennemi !
+
+    m_vx = xHim - xMe ;
+    m_vy = yHim - yMe ;
+    norme = std::sqrt(m_vx * m_vx + m_vy * m_vy ) ;
+
+    m_vx = m_vx * PHOTO_SPEED / norme ;
+    m_vy = m_vy * PHOTO_SPEED / norme ;
+}
+
+Photo::~Photo()
+{
+    //dtor
+}
+
+void Photo::update()
+{
+    m_x += m_vx;
+    m_y += m_vy;
+}
+
+void Photo::draw( SDL_Surface* screen )
+{
+    if ( m_exist )
+        stringRGBA(screen, m_x - 4, m_y - 4, "o", 0, 100, 255, 255);
+}
+
+bool Photo::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Coordonnées impact
+    Uint16 yImpct, xImpct;
+
+    if ( m_vy == 0 )
+    {
+        // Pénétration axe horizontal
+        yImpct = ( m_y - hitbox.y ) / 8;
+
+        if ( m_ally )
+            xImpct = dimW - 1;
+        else
+            xImpct = 0;
+
+        while ( solid[yImpct][xImpct] == 0 )
+        {
+            if ( m_ally )
+                xImpct --;
+            else
+                xImpct ++;
+
+            if ( xImpct >= dimW )
+                return false;
+        }
+    }
+    else
+    {
+        // Pénétration verticale
+        xImpct = ( m_x - hitbox.x ) / 8;
+
+        Sint8 adder( 0 );
+
+        if ( m_vy < 0 ) {
+            yImpct = dimH - 1;
+            adder = -1;
+        }
+        else {
+            yImpct = 0;
+            adder = 1;
+        }
+
+        while ( solid[yImpct][xImpct] == 0 )
+        {
+            yImpct += adder;
+
+            if ( yImpct >= dimH )
+                return false;
+        }
+    }
+
+    // Déstruction du centre
+    damageBloc( solid, dimH, dimW, yImpct, xImpct, 123 );
+
+    // Déstruction du projectile
+    m_exist = false;
+    return true;
+}

+ 36 - 0
Shot/Photo.h

@@ -0,0 +1,36 @@
+#ifndef PHOTO_H
+#define PHOTO_H
+
+#include "../Shot.h"
+
+#define PHOTO_DEGAT 42
+#define PHOTO_SPEED 22
+
+/**
+Jovian Hersemeule
+Description du Photo :
+    Le tir de type Photo est un projectile très rapide
+    qui fonce vers la cible la plus proche mais qui
+    inflige de faibles dégâts.
+**/
+
+class Photo : public Shot
+{
+/// Méthodes
+    public:
+        Photo();
+        Photo( Sint16 xMe, Sint16 yMe, bool ally = false );
+        Photo( Sint16 xMe, Sint16 yMe, Sint16 xHim, Sint16 yHim, bool ally = false );
+        virtual ~Photo();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        Sint16 m_vx;
+        Sint16 m_vy;
+};
+
+#endif // PHOTO_H

+ 101 - 0
Shot/Sniper.cpp

@@ -0,0 +1,101 @@
+#include "Sniper.h"
+
+Sniper::Sniper()
+:Shot( SNIPER_DEGAT ), m_velocity( -SNIPER_MIN_SPEED )
+{
+    //ctor
+}
+
+Sniper::Sniper( Sint16 x, Sint16 y, bool ally )
+:Shot( SNIPER_DEGAT, x, y, ally ), m_velocity( SNIPER_MIN_SPEED )
+{
+    if ( ally )
+        m_velocity = -m_velocity;
+}
+
+Sniper::~Sniper()
+{
+    //dtor
+}
+
+void Sniper::update()
+{
+    m_x += m_velocity;
+
+    if ( m_ally )
+    {
+        m_velocity -= SNIPER_ACC;
+
+        if ( m_velocity < -SNIPER_MAX_SPEED )
+            m_velocity = -SNIPER_MAX_SPEED;
+    }
+    else
+    {
+        m_velocity += SNIPER_ACC;
+
+        if ( m_velocity > SNIPER_MAX_SPEED )
+            m_velocity = SNIPER_MAX_SPEED;
+    }
+
+
+
+
+}
+
+void Sniper::draw( SDL_Surface* screen )
+{
+    if ( m_exist )
+        stringRGBA(screen, m_x - 4, m_y - 4, "=", 255, 0, abs( m_velocity ) * 255 / SNIPER_MAX_SPEED, 255);
+}
+
+bool Sniper::damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox )
+{
+    // Déterminer l'ordonnée d'impact
+    Uint16 yImpct( ( m_y - hitbox.y ) / 8 );
+
+    // Détermination de l'abscisse d'impact
+    Uint16 xImpct(0);
+    if ( m_ally )
+        xImpct = dimW - 1;
+
+    while ( solid[yImpct][xImpct] == 0 )
+    {
+        if ( m_ally )
+            xImpct --;
+        else
+            xImpct ++;
+
+        if ( xImpct >= dimW )
+            return false;
+    }
+
+    // Déstruction
+    Uint8 power( abs( m_velocity ) * 255 / SNIPER_MAX_SPEED );
+
+    while ( xImpct < dimW && power >= SNIPER_BREAK )
+    {
+        // Dommage central
+        if ( damageBloc( solid, dimH, dimW, yImpct, xImpct, power ) )
+        {
+            // Baisse de puissance
+            power -= SNIPER_BREAK;
+        }
+
+        // Dégâts latéraux
+        damageBloc( solid, dimH, dimW, yImpct + 1, xImpct, power / 2 );
+        damageBloc( solid, dimH, dimW, yImpct - 1, xImpct, power / 2 );
+
+        // Mouvement
+        if ( m_ally )
+            xImpct --;
+        else
+            xImpct ++;
+    }
+
+    if ( xImpct < dimW && power > 0 )
+        damageBloc( solid, dimH, dimW, yImpct, xImpct, power );
+
+    // Déstruction du projectile
+    m_exist = false;
+    return true;
+}

+ 36 - 0
Shot/Sniper.h

@@ -0,0 +1,36 @@
+#ifndef SNIPER_H
+#define SNIPER_H
+
+#include "../Shot.h"
+
+#define SNIPER_DEGAT 4000
+#define SNIPER_MIN_SPEED 1
+#define SNIPER_MAX_SPEED 40
+#define SNIPER_ACC 1
+#define SNIPER_BREAK 10
+
+/**
+Jovian Hersemeule
+Description du Sniper :
+    Le tir de type Sniper est horizontal et accelerant. PLus sa vitesse est
+    grande, plus il fait de dégâts.
+**/
+
+class Sniper : public Shot
+{
+/// Méthodes
+    public:
+        Sniper();
+        Sniper( Sint16 x, Sint16 y, bool ally = false );
+        virtual ~Sniper();
+
+        virtual void update();
+        virtual void draw( SDL_Surface* screen );
+        virtual bool damageSolid( Uint8** solid, const Uint16 dimH, const Uint16 dimW, const SDL_Rect& hitbox );
+
+/// Attributs
+    protected:
+        int m_velocity;
+};
+
+#endif // SNIPER_H

+ 627 - 0
SpaceShip.cpp

@@ -0,0 +1,627 @@
+#include "SpaceShip.h"
+
+struct Actor
+{
+    Uint16 idY;
+    Uint16 idX;
+};
+
+struct Laser
+{
+    Uint16 idY;
+    Uint16 idX;
+    Uint8 r;
+    Uint8 g;
+    Uint8 b;
+    Uint8 a;
+};
+
+SpaceShip::SpaceShip()
+:m_heartX(0), m_heartY(0), m_ally( false ),
+ m_pos( {1100, 300, 42, 42} ),
+ m_shH(0), m_shW(0), m_shape(0x0), m_solid(0x0),
+ m_hiter(0x0),
+ m_shieldLeft(0), m_shieldMax(0), m_shieldLast(0), m_shieldDelay(SHIELD_MAX_DELAY)
+{
+    for ( int i(0); i < SHOT_NB; i++ )
+        m_loading[i] = 0;
+}
+
+SpaceShip::SpaceShip( bool ally )
+:m_heartX(0), m_heartY(0), m_ally( ally ),
+ m_pos( {1100, 300, 42, 42} ),
+ m_shH(0), m_shW(0), m_shape(0x0), m_solid(0x0),
+ m_hiter(0x0),
+ m_shieldLeft(0), m_shieldMax(0), m_shieldLast(0), m_shieldDelay(SHIELD_MAX_DELAY)
+{
+    //ctor ally setter
+}
+
+SpaceShip::~SpaceShip()
+{
+    destroyTabs();
+}
+
+void SpaceShip::giveHitManager( HitManager* theHitManager )
+{
+    m_hiter = theHitManager;
+}
+
+void SpaceShip::setPos( Sint16 x, Sint16 y )
+{
+    m_pos.x = x;
+    m_pos.y = y;
+}
+
+SDL_Rect* SpaceShip::getPos()
+{
+    return &m_pos;
+}
+
+SDL_Rect SpaceShip::getHeartPos()
+{
+    SDL_Rect rep;
+
+    rep.x = m_pos.x + 8 * m_heartX + 4;
+    rep.y = m_pos.y + 8 * m_heartY + 4;
+
+    return rep;
+}
+
+bool SpaceShip::getIsAlive()
+{
+    return m_solid[m_heartY][m_heartX] > 0;
+}
+
+SDL_Rect* SpaceShip::getHitBox()
+{
+    return &m_pos;
+}
+
+void SpaceShip::loadShape( std::string path )
+{
+    /// Reinitialisation
+    // Déstruction structure et modèle
+    destroyTabs();
+
+    // Initialisation des dimensions
+    m_shH = 0;
+    m_shW = 0;
+    m_heartY = 0;
+    m_heartX = 0;
+
+    // Initialisation du bouclier
+    m_shieldLeft = 0;
+    m_shieldMax = 0;
+    m_shieldLast = 0;
+    m_shieldDelay = SHIELD_MAX_DELAY;
+
+    /// Lecture du fichier
+    // Création du flux
+    std::ifstream flux( path.c_str() );
+
+    // Lecture du modèle
+    std::queue<std::string> tempo ;
+    std::string line ;
+
+    while ( std::getline(flux, line) )
+    {
+        tempo.push( line );
+        if ( line.length() > m_shW )
+            m_shW = line.length();
+    }
+
+    /// Ecriture du shape ET du solid
+    // Dimensions du vaisseau
+    m_shH = tempo.size();
+    m_pos.h = 8 * m_shH ;
+    m_pos.w = 8 * m_shW ;
+
+    // Création des tableaux statiques
+    m_shape = new char*[ m_shH ];
+    for ( int i(0); i < m_shH; i ++ )
+        m_shape[i] = new char[ m_shW ];
+
+    m_solid = new Uint8*[ m_shH ];
+    for ( int i(0); i < m_shH; i ++ )
+        m_solid[i] = new Uint8[ m_shW ];
+
+    // Lecture des caractères
+    for ( int i(0); i < m_shH; i++ )
+    {
+        line = tempo.front();
+
+        for ( unsigned int j(0); j < m_shW; j++ )
+        {
+            if ( j < line.length() && line[j] != ' ' ) {
+                // Présence d'une pièce
+                m_shape[i][j] = line.c_str()[j];
+                m_solid[i][j] = 255;
+
+                // Détection du cœur
+                if ( m_shape[i][j] == 'm' ){
+                    m_heartY = i;
+                    m_heartX = j;
+                }
+            }
+            else {
+                // Pas de bloc à cet endroit
+                m_shape[i][j] = ' ';
+                m_solid[i][j] = 0;
+            }
+        }
+
+        tempo.pop();
+    }
+
+    /// Détection des actionneurs
+    for ( int i(0); i < m_shH; i++ )
+    {
+        for ( unsigned int j(0); j < m_shW - 1; j++ )
+        {
+            // Détection d'une arme
+            if ( m_shape[i][j] == '[' )
+            {
+                switch ( m_shape[i][j + 1] )
+                {
+                case '-':
+                    m_act[GUN_ID].push_back( { i, j + 1} );
+                    break;
+                case '<':
+                    m_act[DISPER_ID].push_back( { i, j + 1} );
+                    break;
+                case '|':
+                    m_act[CUTTER_ID].push_back( { i, j + 1} );
+                    break;
+                case 'O':
+                    m_act[PHOTO_ID].push_back( { i, j + 1} );
+                    break;
+                case '>':
+                    m_act[MISSILE_ID].push_back( { i, j + 1} );
+                    break;
+                case '{':
+                    m_act[BREXIT_ID].push_back( { i, j + 1} );
+                    break;
+                case '~':
+                    m_act[HECTO_ID].push_back( { i, j + 1} );
+                    break;
+                case '=':
+                    m_act[SNIPER_ID].push_back( { i, j + 1} );
+                    break;
+                default :
+                    break;
+                }
+            }
+            // Détection d'un bouclier
+            else if ( m_shape[i][j] == '(' && m_shape[i][j+1] == ')' )
+            {
+                m_shieldMax += SHIELD_1_EARN_HP;
+                m_shieldLeft += SHIELD_1_EARN_HP;
+                m_shieldDelay -= SHIELD_1_EARN_DELAY;
+                m_shields.push_back( { i, j } );
+
+                // Blocage du délai minimal
+                if ( m_shieldDelay < SHIELD_MIN_DELAY )
+                    m_shieldDelay = SHIELD_MIN_DELAY;
+            }
+            // Détection d'un pointeur
+            else if ( j < m_shW - 2 && m_shape[i][j] == '{' && m_shape[i][j+2] == '}' )
+            {
+                // Couleur
+                Uint8 r(0), g(0), b(0);
+                if ( m_shape[i][j+1] == 'y' )
+                {
+                    b = 255;
+                    g = 255;
+                }
+                else if ( m_shape[i][j+1] == 'r' )
+                {
+                    r = 255;
+                }
+                else if ( m_shape[i][j+1] == 'g' )
+                {
+                    g = 255;
+                }
+                else if ( m_shape[i][j+1] == 'b' )
+                {
+                    b = 255;
+                }
+                else
+                {
+                    r = g = b = 255;
+                }
+
+                // Ajout du pointeur
+                m_lasers.push_back( { i, j + 1, r, g, b, 128 } );
+            }
+        }
+    }
+
+    /// Inversion du vaisseau si il est allié
+    if ( m_ally ){
+        char sw_c;
+        Uint8 sw_s;
+        // Inversion des composants
+        for ( unsigned int i(0); i < m_shH; i++ ) {
+            for ( unsigned int j(0); j < m_shW / 2; j++ ) {
+                sw_c = m_shape[i][j];
+                m_shape[i][j] = m_shape[i][m_shW - j - 1];
+                m_shape[i][m_shW - j - 1] = sw_c;
+
+                sw_s = m_solid[i][j];
+                m_solid[i][j] = m_solid[i][m_shW - j - 1];
+                m_solid[i][m_shW - j - 1] = sw_s;
+            }
+        }
+
+        // Inversion du cockpit
+        m_heartX = m_shW - m_heartX - 1;
+
+        // Inversion des armes
+        for ( unsigned int i(0); i < SHOT_NB; i++) {
+            for ( unsigned int k(0); k < m_act[i].size(); k++ ){
+                m_act[i][k].idX = m_shW - 1 - m_act[i][k].idX;
+            }
+        }
+
+        // Inversion des boucliers
+        for ( unsigned int k(0); k < m_shields.size(); k++ ){
+            m_shields[k].idX = m_shW - 1 - m_shields[k].idX;
+        }
+
+        // Inversion des boucliers
+        for ( unsigned int k(0); k < m_lasers.size(); k++ ){
+            m_lasers[k].idX = m_shW - 1 - m_lasers[k].idX;
+        }
+
+        // Traitement des caractères orientés
+        for ( unsigned int i(0); i < m_shH; i++ ) {
+            for ( unsigned int j(0); j < m_shW; j++ ) {
+                switch ( m_shape[i][j] ){
+                case '<':
+                    m_shape[i][j] = '>';
+                    break;
+                case '>':
+                    m_shape[i][j] = '<';
+                    break;
+                case ']':
+                    m_shape[i][j] = '[';
+                    break;
+                case '[':
+                    m_shape[i][j] = ']';
+                    break;
+                case ')':
+                    m_shape[i][j] = '(';
+                    break;
+                case '(':
+                    m_shape[i][j] = ')';
+                    break;
+                case '}':
+                    m_shape[i][j] = '{';
+                    break;
+                case '{':
+                    m_shape[i][j] = '}';
+                    break;
+                case '/':
+                    m_shape[i][j] = '\\';
+                    break;
+                case '\\':
+                    m_shape[i][j] = '/';
+                    break;
+                default :
+                    break;
+                }
+            }
+        }
+    }
+}
+
+Uint32 SpaceShip::countCPU()
+{
+    Uint32 c( 0 );
+
+    // CPU des blocs
+    for ( unsigned int i(0); i < m_shH; i++ )
+    {
+        for ( unsigned int j(0); j < m_shW; j++ )
+        {
+            if ( m_shape[i][j] != ' ' )
+                c += PART_CPU;
+        }
+    }
+
+    // CPU des armes
+    Uint32 weapCpu[SHOT_NB] = ACTOR_CPU;
+
+    for ( unsigned int i(1); i < SHOT_NB; i++ )
+    {
+        c += m_act[i].size() * weapCpu[i];
+    }
+
+    // CPU des boucliers
+    c += SHIELD_CPU * m_shields.size();
+
+    // Fin
+    return c;
+}
+
+bool SpaceShip::hasShield()
+{
+    return m_shields.size() > 0;
+}
+
+bool SpaceShip::hasWeapon( int weapId )
+{
+    return m_act[ weapId ].size() > 0;
+}
+
+void SpaceShip::draw( SDL_Surface* screen )
+{
+    // N'affiche rien si déjà mort
+    if ( !getIsAlive() )
+        return ;
+
+    // Enveloppe du bouclier
+    Uint8 shieldLvl(128);
+    if ( m_shieldLeft > 0 )
+    {
+        shieldLvl = m_shieldLeft * 255 / m_shieldMax ;
+
+        for ( int i(-2); i < m_shH + 2; i++ )
+        {
+            stringRGBA( screen, m_pos.x - 16, m_pos.y + 8 * i, "+", 0, shieldLvl, shieldLvl, 255 );
+            stringRGBA( screen, m_pos.x + m_pos.w + 8, m_pos.y + 8 * i, "+", 0, shieldLvl, shieldLvl, 255 );
+        }
+
+        for ( int j(-1); j <= m_shW; j++ )
+        {
+            stringRGBA( screen, m_pos.x + 8 * j, m_pos.y - 16, "+", 0, shieldLvl, shieldLvl, 255 );
+            stringRGBA( screen, m_pos.x + 8 * j, m_pos.y + m_pos.h + 8, "+", 0, shieldLvl, shieldLvl, 255 );
+        }
+    }
+
+    // Balayae du carénage
+    for ( int i(0); i < m_shH; i++ )
+    {
+        for ( int j(0); j < m_shW; j++ )
+        {
+            // Existence d'une pièce
+            if ( m_solid[i][j] > 0 )
+            {
+                char s[2];
+                s[0] = m_shape[i][j];
+                s[1] = 0;
+
+                // Energie de bouclier disponible
+                if ( m_shieldLeft > 0 )
+                {
+                    stringRGBA( screen, m_pos.x + 8 * j, m_pos.y + 8 * i, s, 255 - shieldLvl, m_solid[i][j], shieldLvl, 255 );
+
+                }
+                // Affichage basique
+                else
+                    stringRGBA( screen, m_pos.x + 8 * j, m_pos.y + 8 * i, s, 255, m_solid[i][j], m_solid[i][j], 255 );
+            }
+        }
+    }
+
+    // Affichage des pointeurs
+    Sint16 u, v, c;
+    for ( unsigned int i(0); i < m_lasers.size(); i ++ )
+    {
+        u = m_lasers[i].idX * 8 + m_pos.x - 9;
+        v = m_lasers[i].idY * 8 + m_pos.y;
+
+        while ( u > -8 )
+        {
+            stringRGBA( screen, u, v, "-", m_lasers[i].r, m_lasers[i].g, m_lasers[i].b, m_lasers[i].a );
+            u -= 36;
+        }
+    }
+}
+
+void SpaceShip::fire( int weapId )
+{
+    if ( ( SDL_GetTicks() - m_loading[weapId] ) > m_hiter->getDecay( weapId ) )
+    {
+        for ( unsigned int k(0); k < m_act[weapId].size(); k++ )
+        {
+            if ( m_solid[ m_act[weapId][k].idY ][ m_act[weapId][k].idX ] > 0 )
+            {
+                m_hiter->triggerWeapon( weapId, m_pos.x + 8*m_act[weapId][k].idX + 4, m_pos.y + 8*m_act[weapId][k].idY + 4, m_ally );
+            }
+        }
+        m_loading[weapId] = SDL_GetTicks();
+    }
+}
+
+void SpaceShip::update()
+{
+    // Si le vaisseau n'est plus existant, alors rien n'existe
+    if ( !getIsAlive() )
+        return ;
+
+    // S'il reste du bouclier, il peut absorber les dégats !
+    if ( m_shieldLeft > 0 )
+    {
+        Sint32 deg( m_hiter->absorb( m_ally, m_shH, m_shW, m_pos ) );
+
+        if ( deg > 0 )
+        {
+            // La recharge du bouclier est retardée
+            m_shieldLast = SDL_GetTicks();
+
+            // Le bouclier en prend un coup
+            if ( deg > m_shieldLeft )
+                m_shieldLeft = 0;
+            else
+                m_shieldLeft -= deg;
+        }
+    }
+
+    // S'il reste un carénage, il peut subir des dégâts !
+    else if ( m_hiter->colide( m_ally, m_solid, m_shH, m_shW, m_pos ) )
+    {
+        // La recharge du bouclier est retardée
+        m_shieldLast = SDL_GetTicks();
+
+        // Peut être que certains blocs ne sont plus attachés au vaisseau !
+        integrity();
+
+        // Certains boucliers sont peut être hors service !
+        if ( m_shieldMax > 0 )
+            resetShields();
+    }
+
+    // Recharge éventuelle du bouclier
+    if ( m_shieldLeft < m_shieldMax && ( SDL_GetTicks() - m_shieldLast > m_shieldDelay ) )
+    {
+        m_shieldLeft += SHIELD_REGEN ;
+
+        if ( m_shieldLeft > m_shieldMax ) m_shieldLeft = m_shieldMax ;
+    }
+}
+
+void SpaceShip::destroyTabs()
+{
+    // Destruction du modèle graphic
+    if ( m_shape != 0x0 )
+    {
+        for ( int i(0); i < m_shH; i++ ) {
+            delete[] m_shape[i];
+            m_shape[i] = 0x0;
+        }
+
+        delete[] m_shape;
+        m_shape = 0x0;
+    }
+
+    // Destruction de la carte du blindage
+    if ( m_solid != 0x0 )
+    {
+        for ( int i(0); i < m_shH; i++ ) {
+            delete[] m_solid[i];
+            m_solid[i] = 0x0;
+        }
+
+        delete[] m_solid;
+        m_solid = 0x0;
+    }
+
+    // Destruction des armes
+    for ( unsigned int i(0); i < SHOT_NB; i++ )
+    {
+        m_act[i].clear();
+    }
+
+    // Destruction du bouclier
+    m_shields.clear();
+
+    // Destruction des pointeurs
+    m_lasers.clear();
+}
+
+void SpaceShip::integrity()
+{
+    // Création du tableau des liens
+    Sint8 network[ m_shH ][ m_shW ];
+    for ( int i(0); i < m_shH; i++ )
+    {
+        for ( int j(0); j < m_shW; j++ )
+        {
+            network[i][j] = -1;
+        }
+    }
+
+    // Création du réseau
+    if ( getIsAlive() )
+    {
+        network[ m_heartY ][ m_heartX ] = 1;
+        std::queue<Actor> q; // Couples à tester
+        Uint16 y, x;
+
+        if ( m_heartY > 0 ) q.push( { m_heartY - 1, m_heartX } );
+        if ( m_heartX > 0 ) q.push( { m_heartY, m_heartX - 1 } );
+        if ( m_heartY + 1 < m_shH ) q.push( { m_heartY + 1, m_heartX } );
+        if ( m_heartX + 1 < m_shW ) q.push( { m_heartY, m_heartX + 1} );
+
+        while ( !q.empty() )
+        {
+            y = q.front().idY;
+            x = q.front().idX;
+
+            if ( m_solid[ y ][ x ] == 0 )
+            {
+                // Bloc détruit
+                network[ y ][ x ] = 0;
+            }
+            else if ( ( y > 0 && network[ y - 1 ][ x ] == 1 ) // Haut
+                    || ( y < m_shH - 1 && network[ y + 1 ][ x ] == 1 ) // Bas
+                    || ( x > 0 && network[ y ][ x - 1 ] == 1 ) // Gauche
+                    || ( x < m_shW - 1 && network[ y ][ x + 1 ] == 1 ) ) // Droite
+            {
+                // Bloc présent
+                network[ y ][ x ] = 1;
+
+                // Connexion des blocs adjacents
+                if ( y > 0 && network[ y - 1 ][ x ] == -1 )// Haut
+                    q.push( { y - 1, x } );
+
+
+                if ( y < m_shH - 1 && network[ y + 1 ][ x ] == -1 )// Bas
+                    q.push( { y + 1, x } );
+
+
+                if ( x > 0 && network[ y ][ x - 1 ] == -1 )// Gauche
+                    q.push( { y, x - 1 } );
+
+
+                if ( x < m_shW - 1 && network[ y ][ x + 1 ] == -1 )// Doite
+                    q.push( { y, x + 1 } );
+            }
+            else
+            {
+                // Bloc non connecté
+                network[ y ][ x ] = 0;
+            }
+
+            q.pop();
+        }
+    }
+
+    // Destruction des pièces non connectées
+    for ( int i(0); i < m_shH; i++ )
+    {
+        for ( int j(0); j < m_shW; j++ )
+        {
+            if ( m_solid[i][j] > 0 && network[i][j] == -1 ) {
+                Sint16 vx( j - m_heartX );
+                Sint16 vy( i - m_heartY );
+
+                m_hiter->addShot( new Part( m_pos.x + j*8, m_pos.y + i*8, vx, vy, m_solid[i][j], m_shape[i][j], m_ally ) );
+                m_solid[i][j] = 0;
+            }
+        }
+    }
+}
+
+void SpaceShip::resetShields()
+{
+    m_shieldDelay = SHIELD_MAX_DELAY;
+    m_shieldMax = 0;
+
+    for ( unsigned int k(0); k < m_shields.size(); k++ )
+    {
+        if ( m_solid[ m_shields[k].idY ][ m_shields[k].idX ] > 0 )
+        {
+            m_shieldDelay -= SHIELD_1_EARN_DELAY;
+            m_shieldMax += SHIELD_1_EARN_HP;
+        }
+    }
+
+    if ( m_shieldLeft > m_shieldMax )
+        m_shieldLeft = m_shieldMax;
+
+    if ( m_shieldDelay < SHIELD_MIN_DELAY )
+        m_shieldDelay = SHIELD_MIN_DELAY;
+}

+ 85 - 0
SpaceShip.h

@@ -0,0 +1,85 @@
+#ifndef SPACESHIP_H
+#define SPACESHIP_H
+
+#include "HitManager.h"
+#include <string>
+#include <fstream>
+#include <queue>
+
+#include "Shot/Part.h"
+
+#define SHIELD_MAX_DELAY 10000
+#define SHIELD_MIN_DELAY 1000
+#define SHIELD_REGEN 10
+#define SHIELD_1_EARN_DELAY 350
+#define SHIELD_1_EARN_HP 3000
+#define SHIELD_2_EARN_DELAY 500
+#define SHIELD_2_EARN_HP 30000
+
+/**
+Jovian Hersemeule
+Description du SpaceShip :
+    Contient toutes les données relatives au vaisseau spatial,
+    sa structure, sa vie, ses armes, ses modules ...
+**/
+
+struct Actor;
+
+struct Laser;
+
+class SpaceShip
+{
+/// Méthodes
+    public:
+        SpaceShip();
+        SpaceShip( bool ally );
+        virtual ~SpaceShip();
+
+        void giveHitManager( HitManager* theHitManager );
+        void setPos( Sint16 x, Sint16 y );
+        SDL_Rect* getPos();
+        SDL_Rect getHeartPos();
+        bool getIsAlive();
+        SDL_Rect* getHitBox();
+
+        virtual void loadShape( std::string path );
+        virtual Uint32 countCPU();
+        bool hasShield();
+        bool hasWeapon( int weapId );
+
+        virtual void draw( SDL_Surface* screen );
+        virtual void fire( int weapId );
+        virtual void update(); // Met à jour la structure du vaisseau ( collisions )
+
+    protected:
+        void destroyTabs();
+        void integrity();
+        void resetShields();
+
+/// Attributs
+    protected:
+        Uint16 m_heartX;
+        Uint16 m_heartY;
+        const bool m_ally;
+
+        SDL_Rect m_pos; // Hitbox du vaisseau
+
+        Uint16 m_shH;
+        Uint16 m_shW;
+        char** m_shape; // Tableau
+        Uint8** m_solid; // Tableau
+
+        HitManager* m_hiter;
+        std::vector<Actor> m_act[SHOT_NB]; // Les différentes armes du vaisseau
+        Uint32 m_loading[SHOT_NB]; // Les recharges des armes
+
+        Uint16 m_shieldLeft;
+        Uint16 m_shieldMax;
+        Uint32 m_shieldLast; // Date de dernier contact
+        Uint32 m_shieldDelay;
+        std::vector<Actor> m_shields;
+
+        std::vector<Laser> m_lasers;
+};
+
+#endif // SPACESHIP_H

+ 225 - 0
WaveManager.cpp

@@ -0,0 +1,225 @@
+#include "WaveManager.h"
+
+WaveManager::WaveManager()
+:m_lvl(0), m_chrono( SDL_GetTicks() ), m_allDead( true ), m_complete( false ), m_gameLost( false ), m_planet("Sideral Space"),
+ m_hiter( 0x0 )
+{
+    //ctor
+}
+
+WaveManager::~WaveManager()
+{
+    //dtor
+}
+
+void WaveManager::giveHitManager( HitManager* theHitManager )
+{
+    m_hiter = theHitManager;
+}
+
+void WaveManager::draw( SDL_Surface* screen )
+{
+    // Affiche le n° de vague
+    std::string wave( "Vague numero ");
+    wave += char( m_lvl + 48 );
+    stringRGBA( screen, 12, 10, wave.c_str(), 255, 255, 255, 255 );
+
+    // Affiche le nome de la planète
+    stringRGBA( screen, 12, 20, m_planet.c_str(), 255, 255, 255, 255 );
+
+    // Affiche si victoire !!!
+    if ( m_complete )
+    {
+        stringRGBA( screen, 12, 30, "Mission accomplie !", 255, 255, 255, 255 );
+        stringRGBA( screen, 12, 40, "Appuyer sur ECHAP pour rentrer a la base.", 255, 255, 255, 255 );
+    }
+
+    // Affiche vaisseau
+    for ( unsigned int i(0); i < m_escadron.size(); i++ ) {
+        m_escadron[i]->draw( screen );
+    }
+}
+
+void WaveManager::update()
+{
+
+    // Actionne les ennemis
+    for ( unsigned int i(0); i < m_escadron.size(); i++ ) {
+        m_escadron[i]->update();
+
+        // Regarde s'il sort de l'écran
+        if ( m_escadron[i]->getPos()->x > 1280 )
+            m_gameLost = true;
+    }
+
+    // Vague suivante
+    if ( !m_allDead && !m_complete ){
+        m_allDead = allDead();
+
+        if ( m_allDead )
+            m_chrono = SDL_GetTicks();
+    }
+    else if ( SDL_GetTicks() - m_chrono > 3000 ){
+        nextWave();
+    }
+}
+
+void WaveManager::clean()
+{
+    while ( !m_escadron.empty() ) {
+        delete m_escadron.back();
+        m_escadron.back() = 0x0;
+        m_escadron.pop_back();
+    }
+}
+
+void WaveManager::reset()
+{
+    clean();
+    m_lvl = 0;
+    m_allDead = true;
+    m_complete = false;
+}
+
+bool WaveManager::allDead()
+{
+    for ( unsigned int i(0); i < m_escadron.size(); i++ ) {
+        if ( m_escadron[i]->getIsAlive() )
+            return false;
+    }
+
+    return true;
+}
+
+bool WaveManager::hasWon()
+{
+    return m_complete;
+}
+
+bool WaveManager::hasLost()
+{
+    return m_gameLost;
+}
+
+void WaveManager::setPlanet( std::string planet )
+{
+    m_planet = planet;
+}
+
+std::vector< Foe* >* WaveManager::getFoes()
+{
+    return &m_escadron;
+}
+
+void WaveManager::nextWave()
+{
+    // Réinitialisation de l'état de l'escadron
+    m_allDead = false;
+    m_gameLost = false;
+
+    // Augmentation de la difficulté
+    m_lvl ++;
+
+    // Destruction des anciens
+    clean();
+
+    // Création des nouveaux de manière procédurale
+    /*Sint16 disp( 0 );
+    if ( m_lvl > 1 )
+        disp = 540 / (m_lvl - 1);
+
+    for ( unsigned int i(0); i < m_lvl; i++) {
+        m_escadron.push_back( new Foe );
+        m_escadron.back()->loadShape("Ships/Bloc10.txt");
+        m_escadron.back()->giveHitManager( m_hiter );
+        Uint16 dec( m_escadron.back()->getHitBox()->w );
+        m_escadron.back()->setPos( -dec, 50 + i * disp );
+    }*/
+
+    // Par lecture
+    std::string lvlPath("Levels/" + m_planet + "/w_" + (char)(m_lvl + 48) + ".txt" );
+    std::ifstream flux( lvlPath.c_str() );
+    std::string shipName;
+    Sint16 shipPos;
+    Sint16 shipLate;
+
+    while ( flux >> shipName )
+    {
+        // Lecture
+        flux >> shipPos;
+        flux >> shipLate;
+
+        // Création
+        m_escadron.push_back( new Foe );
+        m_escadron.back()->loadShape("Levels/" + m_planet + "/" + shipName + ".txt");
+        m_escadron.back()->giveHitManager( m_hiter );
+
+        Uint16 dec( m_escadron.back()->getHitBox()->w );
+        m_escadron.back()->setPos( -dec - shipLate, 720 * shipPos / 100 );
+    }
+
+    // Si la vague est vide, c'est que c'est fini !
+    if ( m_escadron.empty() )
+    {
+        m_complete = true;
+        m_lvl --;
+    }
+}
+
+SDL_Rect WaveManager::nearestFromPoint( SDL_Rect pos_ref )
+{
+    SDL_Rect pos_rep( pos_ref );
+    pos_rep.x = -10000; // Tire devant si pas de target
+
+    SDL_Rect pos_i;
+
+    Sint32 dist_min( 2147483647 ); // Nombre maximal du Sint16
+    Sint32 dist_i;
+    Sint32 x_i;
+    Sint32 y_i;
+
+    for ( unsigned int i(0); i < m_escadron.size(); i++ )
+    {
+        pos_i = m_escadron[i]->getHeartPos();
+
+        x_i = ( pos_i.x - pos_ref.x );
+        y_i = ( pos_i.y - pos_ref.y );
+
+        dist_i = x_i * x_i + y_i * y_i;
+
+        if ( dist_i < dist_min && m_escadron[i]->getIsAlive() )
+        {
+            dist_min = dist_i;
+            pos_rep = pos_i;
+        }
+    }
+
+    //pos_rep.x += std::sqrt( dist_min ) / 20 ;
+    return pos_rep;
+}
+
+SDL_Rect WaveManager::nearestFromAxe( SDL_Rect pos_ref )
+{
+    SDL_Rect pos_rep( pos_ref );
+    pos_rep.x = -10000; // Tire devant si pas de target
+
+    SDL_Rect pos_i;
+
+    Sint32 dist_min( 2147483647 ); // Nombre maximal du Sint16
+    Sint32 dist_i;
+
+    for ( unsigned int i(0); i < m_escadron.size(); i++ )
+    {
+        pos_i = m_escadron[i]->getHeartPos();
+
+        dist_i = abs( pos_i.y - pos_ref.y );
+
+        if ( dist_i < dist_min && m_escadron[i]->getIsAlive() )
+        {
+            dist_min = dist_i;
+            pos_rep = pos_i;
+        }
+    }
+
+    return pos_rep;
+}

+ 55 - 0
WaveManager.h

@@ -0,0 +1,55 @@
+#ifndef WAVEMANAGER_H
+#define WAVEMANAGER_H
+
+#include "HitManager.h"
+#include "Foe.h"
+#include <vector>
+
+/**
+Jovian Hersemeule
+Description du WaveManager :
+    Le WaveManager contient toutes les données à propos des ennemis, le numéro de la vague,
+    leur quantité, taille, puissance. Il les affiche aussi, évidemment.
+**/
+
+class WaveManager
+{
+/// Méthodes
+    public:
+        WaveManager();
+        virtual ~WaveManager();
+
+        void giveHitManager( HitManager* theHitManager );
+
+        virtual void draw( SDL_Surface* screen );
+
+        virtual void update(); // Actionne ennemis, collisions et vague suivante
+        virtual void clean();
+        void reset(); // Réinitialise le niveau
+        virtual bool allDead(); // Vrai si tout le monde est mort
+        virtual bool hasWon(); // Vrai si la vague est terminée
+        virtual bool hasLost(); // Vrai si un vaisseau ennemi arrive à sortir de l'écran
+
+        void setPlanet( std::string planet ); // Charge un niveau
+        std::vector< Foe* >* getFoes(); // Retourne un pointeur sur le tableau d'ennemis
+
+        SDL_Rect nearestFromPoint( SDL_Rect pos_ref );
+        SDL_Rect nearestFromAxe( SDL_Rect pos_ref );
+
+    protected:
+        virtual void nextWave();
+
+/// Attributs
+    private:
+        Uint16 m_lvl;
+        Uint32 m_chrono;
+        bool m_allDead;
+        bool m_complete;
+        bool m_gameLost;
+        std::string m_planet;
+
+        HitManager* m_hiter;
+        std::vector<Foe*> m_escadron;
+};
+
+#endif // WAVEMANAGER_H

+ 18 - 0
main.cpp

@@ -0,0 +1,18 @@
+#include "Game.h"
+
+int main ( int argc, char** argv )
+{
+    /// [1] Construction
+    Game myGame;
+
+    /// [2] Initialisation
+    if ( !myGame.init() )
+        return 1;
+
+    /// [3] Procédure
+    myGame.run();
+
+    /// [4] Fin
+    std::cout << "Programme terminé." << std::endl;
+    return 0;
+}