<commit_before>#include "GameState.hpp"
#include "Planet.hpp"
#include "Ship.hpp"
#include "Weapon.hpp"
#include "../Application.hpp"

#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/RenderTarget.hpp>

#include <unordered_map>
#include <functional>
#include <string>

GameState::GameState() : mMouseDrag(false), mMoving(false), mLoadState("Creating the universe")
{

}
GameState::~GameState()
{

}

bool GameState::load()
{
    static std::unordered_map<std::string, std::function<void()> > loadStates;
    if (loadStates.empty())
    {
        loadStates["Creating the universe"] = [&]() {
            static int stage = 0;
            switch (stage++)
            {
            case 0:
                mWorld.init();
                mWorld.setSize(sf::Vector2f(2048, 2048));
                break;

            case 1:
                mWorld.updateWalls();
                break;

            default:
                mLoadState = "Placing planets";
            }
        };
        loadStates["Placing planets"] = [&]() {
            static int totalPlanets = 0;
            
            if (totalPlanets++ > 9)
                mLoadState = "Adding retards";
            else
            {
                Game::Planet p;

                mWorld.addPlanet(p);
            }
        };
        loadStates["Adding retards"] = [&]() {
            static int totalRetards = 0;

            if (totalRetards++ > 4)
                mLoadState = "Giving them guns";
            else
            {
                Game::Ship s;

                mWorld.addShip(s);
            }
        };
        loadStates["Giving them guns"] = [&]() {
            static int scripts = 0;

            if (scripts++ > 0)
                mLoadState = "Finalizing";
            else
            {
                ///\TODO Load weapons from scripts.
            }
        };
        loadStates["Finalizing"] = [&]() { 
            static int finalizeWait = 0;

            if (finalizeWait++ > 0)
                mLoadState = "Reticulating splines";
        };
        loadStates["Reticulating splines"] = [&]() { 
            static int noWait = 0;

            if (noWait++ > 0)
                mLoadState = "Done";
        };
    }

    if (loadStates.count(mLoadState) == 0)
    {
        sanitizeCamera();
        return true;
    }

    loadStates[mLoadState]();
    return false;
}
void GameState::unload()
{

}

bool GameState::event(const sf::Event& ev)
{
    if (!mMoving)
    if (ev.type == sf::Event::MouseButtonPressed && ev.mouseButton.button == sf::Mouse::Left)
    {
        mMouseDrag = true;
        mLastMouse = getApplication().getMouse();
    }
    else if (ev.type == sf::Event::MouseButtonReleased && ev.mouseButton.button == sf::Mouse::Left)
        mMouseDrag = false;
    else if (ev.type == sf::Event::MouseButtonReleased && ev.mouseButton.button == sf::Mouse::Right)
    {
        sf::Vector2f mPos = getApplication().getMouse();
        auto& ships = mWorld.getShips();
        FOR_EACH(Game::Ship& s, ships)
        {
            auto pos = s.getPosition();

            float force = std::min(sqrt(((pos.x - mPos.x)*(pos.x - mPos.x)) + ((pos.y - mPos.y)*(pos.y - mPos.y))), 100.f);

            Game::Weapon fired(&s, atan2(mPos.y - pos.y, mPos.x - pos.x), force);

            mWorld.addWeapon(fired);
        }
    }
    else if (ev.type == sf::Event::MouseWheelMoved)
    {
        static float zoomFactor = 5.f;
        int delta = -ev.mouseWheel.delta;

        sf::Vector2f curMouse = getApplication().getMouse();
        sf::View& gameView = getApplication().getGameView();

        sf::Vector2f diff = gameView.getCenter() - curMouse;
        if (delta < 0)
            diff = -diff;

        ///\FIXME limit zoomFactor to the available zoom factor
        float worldDot = (mWorld.getSize().x);
        float cameraDot = (getApplication().getGameView().getSize().x);
        if (!((delta > 0 && cameraDot >= worldDot) || (delta < 0 && cameraDot <= 256)))
        {
            gameView.move(diff/zoomFactor);

            gameView.zoom(1 + delta / zoomFactor);

            sanitizeCamera();
        }
    }

    return false;
}
void GameState::update(float dt)
{
    auto list = mWorld.getAlive();

    if (list.empty())
    {
        mMoving = false;
        if (mMouseDrag)
        {
            sf::Vector2f curMouse = getApplication().getMouse();

            sf::Vector2f diff = mLastMouse - curMouse;
            curMouse += diff;
        
            getApplication().getGameView().move(diff);
            mLastMouse = curMouse;

            sanitizeCamera();
        }
    }
    else
    {
        mMoving = true;
        sf::Vector2f min(mWorld.getSize() * 1.1f), max(mWorld.getSize() * -1.1f);

        sf::Vector2f center;
        FOR_EACH (auto e, list)
        {
            auto& pos = e->getPosition();
            center += pos;
            float rad = e->getRadius() * 5.f;

            min.x = std::min(min.x, pos.x - rad);
            min.y = std::min(min.y, pos.y - rad);
            max.x = std::max(max.x, pos.x + rad);
            max.y = std::max(max.y, pos.y + rad);
        }

        center /= (float)list.size();
        
        sf::Vector2f target = max - min;
        sf::Vector2f current = getApplication().getGameView().getSize();

        if (current.x < current.y)
        {
            getApplication().getGameView().zoom((target.x / current.x));
            current = getApplication().getGameView().getSize();
            if (current.y < target.y)
                getApplication().getGameView().zoom(target.y / current.y);
        }
        else
        {
            getApplication().getGameView().zoom((target.y / current.y));
            current = getApplication().getGameView().getSize();
            if (current.x < target.x)
                getApplication().getGameView().zoom(target.x / current.x);
        }


        sf::Vector2f curPos = getApplication().getGameView().getCenter();
        getApplication().getGameView().move((center - curPos) / 4.f);
    }

    

    mWorld.update(dt);
}
void GameState::draw(sf::RenderTarget& target)
{
    mWorld.draw(target);
}
void GameState::drawUi(sf::RenderTarget& target)
{
    mWorld.drawUi(target);
}

void GameState::sanitizeCamera()
{
    sf::Vector2f worldSize = mWorld.getSize();
    sf::Vector2f viewSize = getApplication().getGameView().getSize();

    {
        sf::Vector2f halfWorld = worldSize / 2.f;
        sf::Vector2f halfView;// = viewSize / 2.f;
        sf::Vector2f curPos = getApplication().getGameView().getCenter();
        curPos.x = std::max(-halfWorld.x + halfView.x, std::min(curPos.x, halfWorld.x - halfView.x));
        curPos.y = std::max(-halfWorld.y + halfView.y, std::min(curPos.y, halfWorld.y - halfView.y));
        getApplication().getGameView().setCenter(curPos);
    }

    {
        float worldDot;<commit_msg>Always keep camera sane<commit_after>#include "GameState.hpp"
#include "Planet.hpp"
#include "Ship.hpp"
#include "Weapon.hpp"
#include "../Application.hpp"

#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/RenderTarget.hpp>

#include <unordered_map>
#include <functional>
#include <string>

GameState::GameState() : mMouseDrag(false), mMoving(false), mLoadState("Creating the universe")
{

}
GameState::~GameState()
{

}

bool GameState::load()
{
    static std::unordered_map<std::string, std::function<void()> > loadStates;
    if (loadStates.empty())
    {
        loadStates["Creating the universe"] = [&]() {
            static int stage = 0;
            switch (stage++)
            {
            case 0:
                mWorld.init();
                mWorld.setSize(sf::Vector2f(2048, 2048));
                break;

            case 1:
                mWorld.updateWalls();
                break;

            default:
                mLoadState = "Placing planets";
            }
        };
        loadStates["Placing planets"] = [&]() {
            static int totalPlanets = 0;
            
            if (totalPlanets++ > 9)
                mLoadState = "Adding retards";
            else
            {
                Game::Planet p;

                mWorld.addPlanet(p);
            }
        };
        loadStates["Adding retards"] = [&]() {
            static int totalRetards = 0;

            if (totalRetards++ > 4)
                mLoadState = "Giving them guns";
            else
            {
                Game::Ship s;

                mWorld.addShip(s);
            }
        };
        loadStates["Giving them guns"] = [&]() {
            static int scripts = 0;

            if (scripts++ > 0)
                mLoadState = "Finalizing";
            else
            {
                ///\TODO Load weapons from scripts.
            }
        };
        loadStates["Finalizing"] = [&]() { 
            static int finalizeWait = 0;

            if (finalizeWait++ > 0)
                mLoadState = "Reticulating splines";
        };
        loadStates["Reticulating splines"] = [&]() { 
            static int noWait = 0;

            if (noWait++ > 0)
                mLoadState = "Done";
        };
    }

    if (loadStates.count(mLoadState) == 0)
    {
        sanitizeCamera();
        return true;
    }

    loadStates[mLoadState]();
    return false;
}
void GameState::unload()
{

}

bool GameState::event(const sf::Event& ev)
{
    if (!mMoving)
    if (ev.type == sf::Event::MouseButtonPressed && ev.mouseButton.button == sf::Mouse::Left)
    {
        mMouseDrag = true;
        mLastMouse = getApplication().getMouse();
    }
    else if (ev.type == sf::Event::MouseButtonReleased && ev.mouseButton.button == sf::Mouse::Left)
        mMouseDrag = false;
    else if (ev.type == sf::Event::MouseButtonReleased && ev.mouseButton.button == sf::Mouse::Right)
    {
        sf::Vector2f mPos = getApplication().getMouse();
        auto& ships = mWorld.getShips();
        FOR_EACH(Game::Ship& s, ships)
        {
            auto pos = s.getPosition();

            float force = std::min(sqrt(((pos.x - mPos.x)*(pos.x - mPos.x)) + ((pos.y - mPos.y)*(pos.y - mPos.y))), 100.f);

            Game::Weapon fired(&s, atan2(mPos.y - pos.y, mPos.x - pos.x), force);

            mWorld.addWeapon(fired);
        }
    }
    else if (ev.type == sf::Event::MouseWheelMoved)
    {
        static float zoomFactor = 5.f;
        int delta = -ev.mouseWheel.delta;

        sf::Vector2f curMouse = getApplication().getMouse();
        sf::View& gameView = getApplication().getGameView();

        sf::Vector2f diff = gameView.getCenter() - curMouse;
        if (delta < 0)
            diff = -diff;

        ///\FIXME limit zoomFactor to the available zoom factor
        float worldDot = (mWorld.getSize().x);
        float cameraDot = (getApplication().getGameView().getSize().x);
        if (!((delta > 0 && cameraDot >= worldDot) || (delta < 0 && cameraDot <= 256)))
        {
            gameView.move(diff/zoomFactor);

            gameView.zoom(1 + delta / zoomFactor);

            sanitizeCamera();
        }
    }

    return false;
}
void GameState::update(float dt)
{
    auto list = mWorld.getAlive();

    if (list.empty())
    {
        mMoving = false;
        if (mMouseDrag)
        {
            sf::Vector2f curMouse = getApplication().getMouse();

            sf::Vector2f diff = mLastMouse - curMouse;
            curMouse += diff;
        
            getApplication().getGameView().move(diff);
            mLastMouse = curMouse;
        }
    }
    else
    {
        mMoving = true;
        sf::Vector2f min(mWorld.getSize() * 1.1f), max(mWorld.getSize() * -1.1f);

        sf::Vector2f center;
        FOR_EACH (auto e, list)
        {
            auto& pos = e->getPosition();
            center += pos;
            float rad = e->getRadius() * 5.f;

            min.x = std::min(min.x, pos.x - rad);
            min.y = std::min(min.y, pos.y - rad);
            max.x = std::max(max.x, pos.x + rad);
            max.y = std::max(max.y, pos.y + rad);
        }

        center /= (float)list.size();
        
        sf::Vector2f target = max - min;
        sf::Vector2f current = getApplication().getGameView().getSize();

        if (current.x < current.y)
        {
            getApplication().getGameView().zoom((target.x / current.x));
            current = getApplication().getGameView().getSize();
            if (current.y < target.y)
                getApplication().getGameView().zoom(target.y / current.y);
        }
        else
        {
            getApplication().getGameView().zoom((target.y / current.y));
            current = getApplication().getGameView().getSize();
            if (current.x < target.x)
                getApplication().getGameView().zoom(target.x / current.x);
        }


        sf::Vector2f curPos = getApplication().getGameView().getCenter();
        getApplication().getGameView().move((center - curPos) / 4.f);
    }

    sanitizeCamera();

    mWorld.update(dt);
}
void GameState::draw(sf::RenderTarget& target)
{
    mWorld.draw(target);
}
void GameState::drawUi(sf::RenderTarget& target)
{
    mWorld.drawUi(target);
}

void GameState::sanitizeCamera()
{
    sf::Vector2f worldSize = mWorld.getSize();
    sf::Vector2f viewSize = getApplication().getGameView().getSize();

    {
        sf::Vector2f halfWorld = worldSize / 2.f;
        sf::Vector2f halfView;// = viewSize / 2.f;
        sf::Vector2f curPos = getApplication().getGameView().getCenter();
        curPos.x = std::max(-halfWorld.x + halfView.x, std::min(curPos.x, halfWorld.x - halfView.x));
        curPos.y = std::max(-halfWorld.y + halfView.y, std::min(curPos.y, halfWorld.y - halfView.y));
        getApplication().getGameView().setCenter(curPos);
    }

    {
        float worldDot;
{'fraction_non_alphanumeric': 0.1494973043858371, 'fraction_numerical': 0.008451114672883578, 'mean_word_length': 1.844384583506009, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2612195', 'n_tokens_mistral': 4361, 'n_tokens_neox': 4180, 'n_words': 802}