// // Created by Zoe Roux on 6/11/21. // #include "System/Event/EventSystem.hpp" #include "Component/Renderer/Drawable2DComponent.hpp" #include "System/Lobby/LobbySystem.hpp" #include "Component/Controllable/ControllableComponent.hpp" #include "Component/Speed/SpeedComponent.hpp" #include "System/MenuControllable/MenuControllableSystem.hpp" #include "Component/Tag/TagComponent.hpp" #include #include #include #include #include "Component/IAControllable/IAControllableComponent.hpp" #include #include #include #include #include #include "Component/Color/ColorComponent.hpp" #include "Component/Stat/StatComponent.hpp" #include "Component/Bonus/PlayerBonusComponent.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; namespace RAY2D = RAY::Drawables::Drawables2D; namespace BBM { std::array LobbySystem::colors = { "blue", "red", "green", // "purple", TODO MISSING ICONS // "cyan", "yellow" }; std::array LobbySystem::_rayColors = { BLUE, RED, GREEN, // PURPLE, // SKYBLUE, YELLOW }; LobbySystem::LobbySystem(WAL::Wal &wal) : System(wal) {} void LobbySystem::_nextColor(WAL::ViewEntity &entity) { auto &lobby = entity.get(); if (lobby.color != -1) this->_colorTaken[lobby.color] = false; do { lobby.color++; if (lobby.color >= static_cast(this->_colorTaken.size())) lobby.color = 0; } while (this->_colorTaken[lobby.color]); this->_colorTaken[lobby.color] = true; entity.get().drawable = std::make_shared("assets/player/icons/" + colors[lobby.color] + ".png"); lobby.coloredTile.getComponent().drawable->setColor(_rayColors[lobby.color]); } void LobbySystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) { auto &lobby = entity.get(); auto lastTick = std::chrono::steady_clock::now(); if (lastTick - lobby.lastInput < std::chrono::milliseconds(150)) return; if (lobby.layout == ControllableComponent::NONE) { for (auto &[_, ctrl] : this->_wal.getScene()->view()) { auto &controller = ctrl; if (controller.bomb && this->_canJoin()) { if (std::any_of(this->getView().begin(), this->getView().end(), [&controller](WAL::ViewEntity &view) { return view.get().layout == controller.layout; })) return; lobby.lastInput = lastTick; lobby.color = -1; this->_nextColor(entity); lobby.layout = controller.layout; controller.bomb = false; return; } } } for (auto &[_, controller] : this->_wal.getScene()->view()) { if (controller.layout != lobby.layout) continue; if (controller.bomb && !lobby.ready && this->_canJoin()) { lobby.ready = true; lobby.lastInput = lastTick; controller.bomb = false; this->_wal.getSystem().now = lastTick; auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); if (texture) texture->use("assets/player/icons/ready.png"); } if (controller.secondary) { lobby.lastInput = lastTick; this->_nextColor(entity); } } } bool LobbySystem::_canJoin() { auto *button = this->_wal.getSystem().currentButton; if (!button) return true; return button->hasComponent>(); } void LobbySystem::addAI() { for (auto entity : this->getView()) { auto &lobby = entity.get(); if (lobby.layout != ControllableComponent::NONE) continue; lobby.color = -1; this->_nextColor(entity); lobby.layout = ControllableComponent::AI; lobby.ready = true; auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); if (texture) texture->use("assets/player/icons/ai.png"); return; } } void LobbySystem::removeAI() { std::optional> last; for (auto &entity : this->getView()) { auto &lobby = entity.get(); if (lobby.layout == ControllableComponent::AI) last.emplace(entity); } if (!last) return; auto &entity = *last; auto &lobby = entity.get(); auto &drawable = entity.get(); this->_colorTaken[lobby.color] = false; lobby.color = -1; lobby.layout = ControllableComponent::NONE; lobby.ready = false; drawable.drawable = std::make_shared("assets/player/icons/none.png"); lobby.coloredTile.getComponent().drawable->setColor(RAY::Color(0, 0, 0, 0)); auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); if (texture) texture->unload(); } void LobbySystem::onSelfUpdate(std::chrono::nanoseconds) { auto &view = this->_wal.getScene()->view, Drawable2DComponent>(); if (view.size() == 0) return; auto *texture = dynamic_cast(view.front().get().drawable.get()); if (!texture) return; if (playersAreReady(*this->_wal.getScene())) texture->setColor(WHITE); else texture->setColor(GRAY); } bool LobbySystem::playersAreReady(WAL::Scene &scene) { auto &lobby = scene.view(); long playerCount = std::count_if(lobby.begin(), lobby.end(), [](WAL::ViewEntity &entity) { auto &lobbyPlayer = entity.get(); return lobbyPlayer.layout != ControllableComponent::NONE; }); if (playerCount <= 1) return false; return std::all_of(lobby.begin(), lobby.end(), [](WAL::ViewEntity &entity) { auto &lobbyPlayer = entity.get(); return lobbyPlayer.ready || lobbyPlayer.layout == ControllableComponent::NONE; }); } void LobbySystem::addController(WAL::Entity &player, ControllableComponent::Layout layout) { switch (layout) { case ControllableComponent::KEYBOARD_0: case ControllableComponent::KEYBOARD_1: player.addComponent(layout); break; case ControllableComponent::GAMEPAD_0: player.addComponent(0); break; case ControllableComponent::GAMEPAD_1: player.addComponent(1); break; case ControllableComponent::GAMEPAD_2: player.addComponent(2); break; case ControllableComponent::GAMEPAD_3: player.addComponent(3); break; case ControllableComponent::AI: player.addComponent("./assets/ai_scripts/john.lua"); break; default: throw std::runtime_error("Invalid controller for a player."); } player.getComponent().layout = layout; } void LobbySystem::createTile(const std::shared_ptr& scene, WAL::Entity &player, int color, int playerCount) { std::string texturePath = "assets/player/ui/" + colors[color] + ".png"; int x = (playerCount % 2 == 0) ? 1920 - 10 - 320 : 10; int y = (playerCount % 3 != 0) ? 1080 - 10 - 248 : 10; scene->addEntity("player color tile") .addComponent(x, y - 2, 0) .addComponent(x, y, 320, 248, RAY::Color(_rayColors[color]).setA(150)); scene->addEntity("player ui tile") .addComponent(x, y, 0) .addComponent(texturePath); scene->addEntity("player hide fireup") .addComponent(x + 220, y + 35, 0) .addComponent("", 20, x, y, WHITE) .addComponent([&player](Drawable2DComponent &drawable) { const BombHolderComponent *bonus = player.tryGetComponent(); if (!bonus) return; auto *text = dynamic_cast(drawable.drawable.get()); if (!text) return; text->setText(std::to_string(static_cast(bonus->explosionRadius))); }); scene->addEntity("player hide bomb-up") .addComponent(x + 220, y + 77, 0) .addComponent("", 20, x, y, WHITE) .addComponent([&player](Drawable2DComponent &drawable) { const BombHolderComponent *bonus = player.tryGetComponent(); if (!bonus) return; auto *text = dynamic_cast(drawable.drawable.get()); if (!text) return; text->setText(std::to_string(bonus->bombCount) + " / " + std::to_string(bonus->maxBombCount)); }); scene->addEntity("player hide speedup") .addComponent(x + 220, y + 122, 0) .addComponent("", 20, x, y, WHITE) .addComponent([&player](Drawable2DComponent &drawable) { auto *speed = player.tryGetComponent(); if (!speed) return; auto *text = dynamic_cast(drawable.drawable.get()); if (!text) return; text->setText(std::to_string(static_cast(speed->speed * 100))); }); scene->addEntity("player hide wall") .addComponent(x + 220, y + 161, 0) .addComponent("", 20, x, y, WHITE) .addComponent([&player](Drawable2DComponent &drawable) { const PlayerBonusComponent *bonus = player.tryGetComponent(); if (!bonus) return; auto *text = dynamic_cast(drawable.drawable.get()); if (!text) return; text->setText(bonus->isNoClipOn ? "YES" : "NO"); }); } void LobbySystem::switchToGame(WAL::Wal &wal) { auto scene = Runner::loadGameScene(); int mapWidth = Runner::mapWidth; int mapHeight = Runner::mapHeight; int playerCount = 0; for (auto &[_, lobby] : wal.getScene()->view()) { if (lobby.layout == ControllableComponent::NONE) continue; auto &player = Runner::createPlayer(*scene); player.getComponent().position = Vector3f(mapWidth * (playerCount % 2), (Runner::hasHeights ? 1.01 : 0), mapHeight * (!(playerCount % 3))); auto *model = dynamic_cast(player.getComponent().drawable.get()); model->setTextureToMaterial(MAP_DIFFUSE, "assets/player/textures/" + colors[lobby.color] + ".png"); addController(player, lobby.layout); createTile(scene, player, lobby.color, playerCount); playerCount++; } Runner::gameState.loadedScenes[GameState::SceneID::GameScene] = scene; MapGenerator::loadMap(Runner::mapWidth, Runner::mapHeight, MapGenerator::createMap(Runner::mapWidth, Runner::mapHeight, Runner::hasHeights), scene); Runner::gameState.nextScene = BBM::GameState::SceneID::GameScene; wal.getSystem().unloadLobby(); } void LobbySystem::unloadLobby() { this->_colorTaken.fill(false); for (auto &[_, lobby, drawable] : this->getView()) { lobby.layout = ControllableComponent::NONE; lobby.ready = false; lobby.color = -1; drawable.drawable = std::make_shared("assets/player/icons/none.png"); lobby.coloredTile.getComponent().drawable->setColor(RAY::Color(0, 0, 0, 0)); auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); if (texture) texture->unload(); } } }