diff --git a/assets/imgs/deathCountBG.png b/assets/imgs/deathCountBG.png new file mode 100644 index 00000000..40fedb85 Binary files /dev/null and b/assets/imgs/deathCountBG.png differ diff --git a/assets/imgs/defeat.png b/assets/imgs/defeat.png new file mode 100644 index 00000000..8100c5df Binary files /dev/null and b/assets/imgs/defeat.png differ diff --git a/assets/imgs/destroyedSkull.png b/assets/imgs/destroyedSkull.png new file mode 100644 index 00000000..c32f2ec3 Binary files /dev/null and b/assets/imgs/destroyedSkull.png differ diff --git a/assets/imgs/exitBG.png b/assets/imgs/exitBG.png new file mode 100644 index 00000000..4fd4133a Binary files /dev/null and b/assets/imgs/exitBG.png differ diff --git a/assets/imgs/exitDMBG.png b/assets/imgs/exitDMBG.png new file mode 100644 index 00000000..8bf16cc6 Binary files /dev/null and b/assets/imgs/exitDMBG.png differ diff --git a/assets/imgs/helpBG.png b/assets/imgs/helpBG.png new file mode 100644 index 00000000..8d888792 Binary files /dev/null and b/assets/imgs/helpBG.png differ diff --git a/assets/imgs/helpDMBG.png b/assets/imgs/helpDMBG.png new file mode 100644 index 00000000..be2adc51 Binary files /dev/null and b/assets/imgs/helpDMBG.png differ diff --git a/assets/imgs/lobbyButton.png b/assets/imgs/lobbyButton.png new file mode 100644 index 00000000..a521ac8e Binary files /dev/null and b/assets/imgs/lobbyButton.png differ diff --git a/assets/imgs/mirror.png b/assets/imgs/mirror.png new file mode 100644 index 00000000..1f3d0104 Binary files /dev/null and b/assets/imgs/mirror.png differ diff --git a/assets/imgs/normalSkull.png b/assets/imgs/normalSkull.png new file mode 100644 index 00000000..cfc6697b Binary files /dev/null and b/assets/imgs/normalSkull.png differ diff --git a/assets/imgs/victory.png b/assets/imgs/victory.png new file mode 100644 index 00000000..6725c739 Binary files /dev/null and b/assets/imgs/victory.png differ diff --git a/config.json b/config.json index d6f31c9f..8f2544e5 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "game": { "maze": { "directory": "maps", - "procedural": true, + "procedural": false, "maze_file": "test/itemRoom.maze" } }, @@ -20,8 +20,9 @@ "client": { "default_name": "Conan O'Brien", "lobby_discovery": true, - "fullscreen": false, + "fullscreen": true, "draw_bboxes": false, - "fps_counter": true + "fps_counter": true, + "presentation": true } } diff --git a/include/client/gui/img/img.hpp b/include/client/gui/img/img.hpp index de6d6c47..a282d6ff 100644 --- a/include/client/gui/img/img.hpp +++ b/include/client/gui/img/img.hpp @@ -63,6 +63,16 @@ enum class ImgID { DMCD_10, DMCD_9, DMCD_8, DMCD_7, DMCD_6, DMCD_5, DMCD_4, DMCD_3, DMCD_2, DMCD_1, DMCD_Selected_10, DMCD_Selected_9, DMCD_Selected_8, DMCD_Selected_7, DMCD_Selected_6, DMCD_Selected_5, DMCD_Selected_4, DMCD_Selected_3, DMCD_Selected_2, DMCD_Selected_1, + Skull, + DestroyedSkull, + SkullBG, + HelpBG, + HelpDMBG, + ExitBG, + ExitDMBG, + LobbyButton, + Victory, + Defeat, Blank, }; @@ -87,6 +97,8 @@ enum class ImgID { ImgID::DMCD_5, ImgID::DMCD_4, ImgID::DMCD_3, ImgID::DMCD_2, ImgID::DMCD_1, \ ImgID::DMCD_Selected_10, ImgID::DMCD_Selected_9, ImgID::DMCD_Selected_8, ImgID::DMCD_Selected_7, ImgID::DMCD_Selected_6, \ ImgID::DMCD_Selected_5, ImgID::DMCD_Selected_4, ImgID::DMCD_Selected_3, ImgID::DMCD_Selected_2, ImgID::DMCD_Selected_1, \ + ImgID::Skull, ImgID::DestroyedSkull, ImgID::SkullBG, ImgID::HelpBG, ImgID::HelpDMBG, \ + ImgID::ExitBG, ImgID::ExitDMBG, ImgID::LobbyButton, ImgID::Victory, ImgID::Defeat, \ } /** diff --git a/include/server/game/constants.hpp b/include/server/game/constants.hpp index 2d7d78df..cb66f02b 100644 --- a/include/server/game/constants.hpp +++ b/include/server/game/constants.hpp @@ -4,16 +4,9 @@ #include #include -#define NUM_PLAYERS 4 -#define MAX_ENTITIES 1000 -#define MAX_COMPONENTS 32 -#define MAX_WALLS 1000 -#define MAX_TRAPS 10 -#define MAX_SPELLS 4 - - /* ServerGameState Constants */ #define MAX_ENEMY_VALUE 500 +#define NUM_PLAYERS 4 /* Maze Constants */ #define MAX_MAZE_COLUMNS 10000 @@ -98,7 +91,7 @@ /* DM Constants */ #define MAX_TRAPS 10 -#define TRAP_INVENTORY_SIZE 10 +#define TRAP_INVENTORY_SIZE 6 #define TRAP_TIME 10 #define TRAP_COOL_DOWN 5 #define ITEM_SPAWN_PROB 0.1 diff --git a/include/server/game/servergamestate.hpp b/include/server/game/servergamestate.hpp index 773ed116..4ad88b69 100644 --- a/include/server/game/servergamestate.hpp +++ b/include/server/game/servergamestate.hpp @@ -371,11 +371,15 @@ class ServerGameState { * cell * @param cell is a single cell of the maze's grid where a wall + torch * should be placed + * @param orb_pos position of the orb so that we can calculate the distance + * for coloring purposes + * @param exit_pos position of the exit so that we can calculate the distance + * for coloring purposes * @param cellType determines which direction the torch should face. * This means that only TorchUp, TorchDown, TorchRight, and TorchLeft * are acceptable values of cellType */ - void spawnTorch(GridCell *cell); + void spawnTorch(GridCell *cell, glm::vec3 orb_pos, glm::vec3 exit_pos); /** * @brief helper function to spawn a fireball trap diff --git a/include/server/game/torchlight.hpp b/include/server/game/torchlight.hpp index 6fc20ffb..0c862ebd 100644 --- a/include/server/game/torchlight.hpp +++ b/include/server/game/torchlight.hpp @@ -35,8 +35,10 @@ class Torchlight : public Object { /** * Creates a torchight with default lighting properties. * @param corner Corner position of the surface + * @param dist_orb distance to orb, to see if it should be shaded blue + * @param dist_exit distance to the exit, to see if it should be shaded white */ - explicit Torchlight(glm::vec3 corner); + explicit Torchlight(glm::vec3 corner, float dist_orb, float dist_exit); /** * @param corner Corner position of the surface diff --git a/include/shared/utilities/config.hpp b/include/shared/utilities/config.hpp index 91179aeb..d94d7ee4 100644 --- a/include/shared/utilities/config.hpp +++ b/include/shared/utilities/config.hpp @@ -62,6 +62,7 @@ struct GameConfig { bool fullscreen; bool draw_bboxes; bool fps_counter; + bool presentation; } client; /** diff --git a/src/client/gui/gui.cpp b/src/client/gui/gui.cpp index 5681a1fd..8543fdb6 100644 --- a/src/client/gui/gui.cpp +++ b/src/client/gui/gui.cpp @@ -272,7 +272,7 @@ void GUI::_layoutTitleScreen() { ); exit_text->addOnHover([this](widget::Handle handle) { auto widget = this->borrowWidget(handle); - widget->changeColor(font::Color::YELLOW); + widget->changeColor(font::Color::RED); }); exit_text->addOnClick([this](widget::Handle handle) { glfwSetWindowShouldClose(this->client->getWindow(), GL_TRUE); @@ -932,6 +932,19 @@ void GUI::_sharedGameHUD() { // Add controls Help if (this->controlDisplayed) { + auto controlBG = widget::Flexbox::make( + glm::vec2(WINDOW_WIDTH - font::getRelativePixels(360), FRAC_WINDOW_HEIGHT(1, 2) - font::getRelativePixels(10)), + glm::vec2(0.0f, 0.0f), + widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::LEFT, font::getRelativePixels(10)) + ); + if (!is_dm.value()) { + controlBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::HelpBG), 2)); + } + else { + controlBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::HelpDMBG), 2)); + } + this->addWidget(std::move(controlBG)); + auto controlsFlex = widget::Flexbox::make( glm::vec2(WINDOW_WIDTH - font::getRelativePixels(350), FRAC_WINDOW_HEIGHT(1, 2)), glm::vec2(0.0f, 0.0f), @@ -1122,12 +1135,11 @@ void GUI::_sharedGameHUD() { } } - // TODO Need to arrange auto txtHeight = font::getRelativePixels(145.0); auto flexHeight = font::getRelativePixels(45.0); - - if (!this->config.client.fullscreen) { - txtHeight -= font::getRelativePixels(10); + if(this->config.client.presentation){ + txtHeight += font::getRelativePixels(80.0); + flexHeight += font::getRelativePixels(85.0); } // Item Description Background @@ -1150,6 +1162,10 @@ void GUI::_sharedGameHUD() { this->addWidget(std::move(itemBGFlex)); } + if (!is_dm.value()) { + txtHeight -= font::getRelativePixels(2.0); + } + // Text for item description auto item_txt = widget::CenterText::make( itemString, @@ -1438,10 +1454,14 @@ void GUI::_sharedGameHUD() { this->addWidget(std::move(itemflex)); + auto barHeight = font::getRelativePixels(5.0); + if (this->config.client.presentation) { + barHeight += font::getRelativePixels(90.0); + } if (!is_dm.value()) { // Flexbox for the health bar auto healthflex = widget::Flexbox::make( - glm::vec2(0.0f, 5.0f), + glm::vec2(0.0f, barHeight), glm::vec2(WINDOW_WIDTH, 0.0f), widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) ); @@ -1449,7 +1469,7 @@ void GUI::_sharedGameHUD() { this->addWidget(std::move(healthflex)); auto healthtickflex = widget::Flexbox::make( - glm::vec2(0.0f, 5.0f), + glm::vec2(0.0f, barHeight), glm::vec2(WINDOW_WIDTH, 0.0f), widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) ); @@ -1467,7 +1487,7 @@ void GUI::_sharedGameHUD() { else { // Flexbox for the mana bar for DM auto manaflex = widget::Flexbox::make( - glm::vec2(0.0f, 5.0f), + glm::vec2(0.0f, barHeight), glm::vec2(WINDOW_WIDTH, 0.0f), widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) ); @@ -1475,7 +1495,7 @@ void GUI::_sharedGameHUD() { this->addWidget(std::move(manaflex)); auto manatickflex = widget::Flexbox::make( - glm::vec2(0.0f, 5.0f), + glm::vec2(0.0f, barHeight), glm::vec2(WINDOW_WIDTH, 0.0f), widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) ); @@ -1511,15 +1531,19 @@ void GUI::_layoutGameHUD() { auto self = client->gameState.objects.at(*self_eid); + auto eventBGHeight = 0; + auto eventTxtHeight = font::getRelativePixels(25); + if (this->config.client.presentation) { + eventBGHeight += font::getRelativePixels(85.0); + eventTxtHeight += font::getRelativePixels(85.0); + } + auto matchPhaseBGFlex = widget::Flexbox::make( - glm::vec2(font::getRelativePixels(5), 0), + glm::vec2(font::getRelativePixels(5), eventBGHeight), glm::vec2(0, 0), widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::LEFT, font::getRelativePixels(10)) ); - auto bgSize = 2; - if (!this->config.client.fullscreen) { - bgSize = 2.5; - } + auto bgSize = 2.5; if (!is_dm.value()) { matchPhaseBGFlex->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::EventBG), bgSize)); } @@ -1529,7 +1553,7 @@ void GUI::_layoutGameHUD() { this->addWidget(std::move(matchPhaseBGFlex)); auto matchPhaseFlex = widget::Flexbox::make( - glm::vec2(font::getRelativePixels(25), font::getRelativePixels(25)), + glm::vec2(font::getRelativePixels(25), eventTxtHeight), glm::vec2(0, 0), widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::LEFT, font::getRelativePixels(7)) ); @@ -1646,45 +1670,63 @@ void GUI::_layoutGameHUD() { this->addWidget(std::move(matchPhaseFlex)); // Show death or timer on the top - auto death_timeflex = widget::Flexbox::make( - glm::vec2(0, WINDOW_HEIGHT - (font::getRelativePixels(50))), + auto death_flexBG = widget::Flexbox::make( + glm::vec2(0, WINDOW_HEIGHT - (font::getRelativePixels(100))), glm::vec2(WINDOW_WIDTH, 0), - widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::CENTER, 0.0f) + widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) ); + death_flexBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::SkullBG), 2)); + this->addWidget(std::move(death_flexBG)); // Add timer string if (client->gameState.matchPhase == MatchPhase::RelayRace) { - std::string timerString = "Time Left: "; - auto timerSeconds = client->gameState.relay_finish_time - getSecSinceEpoch(); - timerString += std::to_string(timerSeconds); + auto remainingTime = client->gameState.relay_finish_time - std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + int min = (int) remainingTime / 60; + int sec = remainingTime % 60; - timerString += (timerSeconds > 1) ? " seconds" : " second"; + auto timeFlex = widget::Flexbox::make( + glm::vec2(0, WINDOW_HEIGHT - (font::getRelativePixels(70))), + glm::vec2(WINDOW_WIDTH, 0), + widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) + ); - death_timeflex->push(widget::DynText::make( + std::string timerString = std::to_string(min) + "min " + std::to_string(sec) + "sec "; + + float time_frac = remainingTime / 300.0f; + glm::vec3 close_color = font::getRGB(font::Color::GREEN); + glm::vec3 far_color = font::getRGB(font::Color::RED); + glm::vec3 color = ((1- time_frac) * far_color) + (time_frac * close_color); + + timeFlex->push(widget::DynText::make( timerString, fonts, - widget::DynText::Options(font::Font::TEXT, font::Size::MEDIUM, font::Color::RED) + widget::DynText::Options(font::Font::TEXT, font::Size::MEDIUM, color) )); + this->addWidget(std::move(timeFlex)); } else { - // Add player deaths string - std::string playerDeathsString = std::to_string(client->gameState.numPlayerDeaths) - + " / " + std::to_string(PLAYER_DEATHS_TO_RELAY_RACE) - + " Player Deaths"; - - death_timeflex->push(widget::DynText::make( - playerDeathsString, - fonts, - widget::DynText::Options(font::Font::TEXT, font::Size::MEDIUM, font::Color::RED) - )); + auto death_flex = widget::Flexbox::make( + glm::vec2(0, WINDOW_HEIGHT - (font::getRelativePixels(95))), + glm::vec2(WINDOW_WIDTH, 0), + widget::Flexbox::Options(widget::Dir::HORIZONTAL, widget::Align::CENTER, 0.0f) + ); + for(int i = 0; i < PLAYER_DEATHS_TO_RELAY_RACE; i++){ + if(PLAYER_DEATHS_TO_RELAY_RACE - client->gameState.numPlayerDeaths > i){ + death_flex->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::Skull), 2)); + } else { + death_flex->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::DestroyedSkull), 2)); + } + } + this->addWidget(std::move(death_flex)); } - this->addWidget(std::move(death_timeflex)); - - auto txtHeight = font::getRelativePixels(170); - if (!this->config.client.fullscreen) { - txtHeight -= font::getRelativePixels(14); + auto txtHeight = font::getRelativePixels(163); + auto bartxtHeight = font::getRelativePixels(13); + if (this->config.client.presentation) { + txtHeight += font::getRelativePixels(80.0); + bartxtHeight += font::getRelativePixels(90.0); } + if (is_dm.has_value() && is_dm.value()) { // add some DM specific stuff in here auto traps_placed_txt = widget::CenterText::make( @@ -1703,7 +1745,7 @@ void GUI::_layoutGameHUD() { font::Size::SMALL, font::Color::WHITE, fonts, - font::getRelativePixels(13) + bartxtHeight ); this->addWidget(std::move(mana_txt)); @@ -1731,7 +1773,7 @@ void GUI::_layoutGameHUD() { font::Size::SMALL, font::Color::WHITE, fonts, - font::getRelativePixels(13) + bartxtHeight ); this->addWidget(std::move(health_txt)); @@ -1770,8 +1812,13 @@ void GUI::_layoutGameHUD() { } this->addWidget(std::move(durationFlex)); + auto compassHeight = font::getRelativePixels(10); + if (this->config.client.presentation) { + compassHeight += font::getRelativePixels(85.0); + } + auto compassFlex = widget::Flexbox::make( - glm::vec2(WINDOW_WIDTH - font::getRelativePixelsHorizontal(700), font::getRelativePixels(10)), + glm::vec2(WINDOW_WIDTH - font::getRelativePixelsHorizontal(700), compassHeight), glm::vec2(0.0f, 0.0f), widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::LEFT, font::getRelativePixels(5)) ); @@ -1815,7 +1862,7 @@ void GUI::_layoutGameHUD() { this->addWidget(std::move(compassFlex)); auto needleFlex = widget::Flexbox::make( - glm::vec2(WINDOW_WIDTH - font::getRelativePixelsHorizontal(700), font::getRelativePixels(10)), + glm::vec2(WINDOW_WIDTH - font::getRelativePixelsHorizontal(700), compassHeight), glm::vec2(0.0f, 0.0f), widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::LEFT, font::getRelativePixels(5)) ); @@ -1863,14 +1910,34 @@ void GUI::_layoutGameHUD() { } void GUI::_layoutGameEscMenu() { + auto self_eid = client->session->getInfo().client_eid; + auto is_dm = client->session->getInfo().is_dungeon_master; + + auto exitBG = widget::Flexbox::make( + glm::vec2(font::getRelativePixels(2), FRAC_WINDOW_HEIGHT(1, 2) - font::getRelativePixels(15)), + glm::vec2(WINDOW_WIDTH, 0.0f), + widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::CENTER, 0.0f) + ); + if(!is_dm.value()){ + exitBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::ExitBG), 2)); + } else { + exitBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::ExitDMBG), 2)); + } + + exitBG->addOnClick([this](widget::Handle handle) { + glfwSetWindowShouldClose(this->client->getWindow(), GL_TRUE); + }); + + this->addWidget(std::move(exitBG)); + auto exit_game_txt = widget::DynText::make( - "(Exit Game)", + "Exit Game", fonts, widget::DynText::Options(font::Font::MENU, font::Size::MEDIUM, font::Color::WHITE) ); exit_game_txt->addOnHover([this](widget::Handle handle) { auto widget = this->borrowWidget(handle); - widget->changeColor(font::Color::RED); + widget->changeColor(font::Color::YELLOW); }); exit_game_txt->addOnClick([this](widget::Handle handle) { glfwSetWindowShouldClose(this->client->getWindow(), GL_TRUE); @@ -1931,6 +1998,21 @@ void GUI::_layoutResultsScreen() { std::string result_string = won ? "Victory" : "Defeat"; + auto victoryBG = widget::Flexbox::make( + glm::vec2(font::getRelativePixels(2), FRAC_WINDOW_HEIGHT(1, 2) - font::getRelativePixels(55)), + glm::vec2(WINDOW_WIDTH, 0.0f), + widget::Flexbox::Options(widget::Dir::VERTICAL, widget::Align::CENTER, 0.0f) + ); + + if (won) { + victoryBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::Victory), 2)); + } + else { + victoryBG->push(widget::StaticImg::make(glm::vec2(0.0f), images.getImg(img::ImgID::Defeat), 2)); + } + + this->addWidget(std::move(victoryBG)); + this->addWidget(widget::CenterText::make( result_string, font::Font::MENU, diff --git a/src/client/gui/imgs/img.cpp b/src/client/gui/imgs/img.cpp index a4f30cf1..82b8447a 100644 --- a/src/client/gui/imgs/img.cpp +++ b/src/client/gui/imgs/img.cpp @@ -17,8 +17,7 @@ std::string getImgFilepath(ImgID img) { case ImgID::FireSpell: return (img_root / "fire_wand.png").string(); case ImgID::HealSpell: return (img_root / "heal_wand.png").string(); case ImgID::Orb: return (img_root / "orb.png").string(); - // TODO: Replace mirror image with an image of an actual mirror - case ImgID::Mirror: return (img_root / "orb.png").string(); + case ImgID::Mirror: return (img_root / "mirror.png").string(); case ImgID::Scroll: return (img_root / "scroll.png").string(); case ImgID::Crosshair: return (img_root / "crosshair046.png").string(); case ImgID::Dagger: return (img_root / "weapon_dagger.png").string(); @@ -83,6 +82,16 @@ std::string getImgFilepath(ImgID img) { case ImgID::FloorSpikeTrap: return (img_root / "floorspiketrap.png").string(); case ImgID::ArrowTrap: return (img_root / "arrowtrap.png").string(); case ImgID::SpikeTrap: return (img_root / "spiketrap.png").string(); + case ImgID::Skull: return (img_root / "normalSkull.png").string(); + case ImgID::DestroyedSkull: return (img_root / "destroyedSkull.png").string(); + case ImgID::SkullBG: return (img_root / "deathCountBG.png").string(); + case ImgID::HelpBG: return (img_root / "helpBG.png").string(); + case ImgID::HelpDMBG: return (img_root / "helpDMBG.png").string(); + case ImgID::ExitBG: return (img_root / "exitBG.png").string(); + case ImgID::ExitDMBG: return (img_root / "exitDMBG.png").string(); + case ImgID::LobbyButton: return (img_root / "lobbyButton.png").string(); + case ImgID::Victory: return (img_root / "victory.png").string(); + case ImgID::Defeat: return (img_root / "defeat.png").string(); } } } diff --git a/src/server/game/servergamestate.cpp b/src/server/game/servergamestate.cpp index db2597c8..deede8dd 100644 --- a/src/server/game/servergamestate.cpp +++ b/src/server/game/servergamestate.cpp @@ -1270,6 +1270,16 @@ void ServerGameState::handleDeaths() { // Player died - increment number of player deaths this->numPlayerDeaths++; + if (numPlayerDeaths < PLAYER_DEATHS_TO_RELAY_RACE) { + this->soundTable().addNewSoundSource(SoundSource( + ServerSFX::Thunder, + player->physics.shared.getCenterPosition(), + DEFAULT_VOLUME, + FAR_DIST, + FAR_ATTEN + )); + } + if (numPlayerDeaths == PLAYER_DEATHS_TO_RELAY_RACE) { this->transitionToRelayRace(); } @@ -1865,6 +1875,29 @@ void ServerGameState::loadMaze(const Grid& grid) { } } + std::optional orb_pos; + std::optional exit_pos; + // go through and mark distance to orb and exit + for (int c = 0; c < this->grid.getColumns(); c++) { + for (int r = 0; r < this->grid.getRows(); r++) { + CellType type = this->grid.getCell(c, r)->type; + if (type == CellType::Orb || type == CellType::Exit) { + glm::vec3 corner(c * Grid::grid_cell_width, 0.0f, r * Grid::grid_cell_width); + + if (type == CellType::Orb) { + orb_pos = corner; + } else { + exit_pos = corner; + } + + } + } + + if (orb_pos.has_value() && exit_pos.has_value()) { + break; // early exit, not really needed though probably + } + } + // create multiple floor and ceiling objects to populate the size of the entire maze. // currently doing this to stretch out the floor texture by the desired factor. here // in the maze generation we can have a lot of control over how frequently the floor texture @@ -2097,7 +2130,10 @@ void ServerGameState::loadMaze(const Grid& grid) { case CellType::TorchDown: case CellType::TorchRight: case CellType::TorchLeft: { - this->spawnTorch(cell); + // if no orb or exit in maze then just tell it that they are very far off so not + // considered in color calculations + const glm::vec3 FAR_OFF_POS(10000, 10000, 10000); + this->spawnTorch(cell, orb_pos.value_or(FAR_OFF_POS), exit_pos.value_or(FAR_OFF_POS)); this->spawnWall(cell, col, row, internal_walls.contains(glm::ivec2(col, row))); break; } @@ -2227,7 +2263,7 @@ void ServerGameState::spawnWall(GridCell* cell, int col, int row, bool is_intern } } -void ServerGameState::spawnTorch(GridCell *cell) { +void ServerGameState::spawnTorch(GridCell *cell, glm::vec3 orb_pos, glm::vec3 exit_pos) { glm::vec3 dimensions = Object::models.at(ModelType::Torchlight); glm::vec3 corner( cell->x * this->grid.grid_cell_width, @@ -2235,6 +2271,9 @@ void ServerGameState::spawnTorch(GridCell *cell) { cell->y * this->grid.grid_cell_width ); + float orb_dist = glm::distance(corner, orb_pos); + float exit_dist = glm::distance(corner, exit_pos); + switch (cell->type) { case CellType::TorchDown: { corner.x += (this->grid.grid_cell_width / 2.0f) - (dimensions.x / 2.0f); @@ -2271,7 +2310,7 @@ void ServerGameState::spawnTorch(GridCell *cell) { true )); - this->objects.createObject(new Torchlight(corner)); + this->objects.createObject(new Torchlight(corner, orb_dist, exit_dist)); } Trap* ServerGameState::spawnFireballTrap(GridCell *cell) { diff --git a/src/server/game/torchlight.cpp b/src/server/game/torchlight.cpp index 0792dee5..53ca6163 100644 --- a/src/server/game/torchlight.cpp +++ b/src/server/game/torchlight.cpp @@ -5,6 +5,7 @@ #include "server/game/object.hpp" #include "shared/game/sharedobject.hpp" #include "shared/utilities/rng.hpp" +#include "server/game/grid.hpp" SharedObject Torchlight::toShared() { auto so = Object::toShared(); @@ -20,34 +21,83 @@ SharedObject Torchlight::toShared() { } Torchlight::Torchlight( - glm::vec3 corner): + glm::vec3 corner, float dist_orb, float dist_exit): Object(ObjectType::Torchlight, Physics(false, Collider::Box, corner, glm::vec3(0.0f), glm::vec3(1.0f)), ModelType::Torchlight) { - // for amber orange lights - this->properties = TorchlightProperties { - .flickering = true, - .min_intensity = 0.3f, - .max_intensity = 1.0f, - .ambient_color = glm::vec3(0.05f, 0.05f, 0.05f), - .diffuse_color = glm::vec3(1.0f, 0.5f, 0.03f), - .specular_color = glm::vec3(0.5f, 0.25f, 0.015f), - .attenuation_linear = 0.07f, - .attenuation_quadratic = 0.017f + const float MIN_ORB_DIST = Grid::grid_cell_width * 60.0f; + const float MIN_EXIT_DIST = Grid::grid_cell_width * 60.0f; // min distance to start shade white + + const float AMBER_MIN_INTENSITY = 0.3f; + const float AMBER_MAX_INTENSITY = 1.0f; + const glm::vec3 AMBER_AMBIENT(0.05f, 0.05f, 0.05f); + const glm::vec3 AMBER_DIFFUSE(1.0f, 0.5f, 0.03f); + const glm::vec3 AMBER_SPECULAR(0.5f, 0.25f, 0.015f); + + const float BLUE_MIN_INTENSITY = 0.1f; + const float BLUE_MAX_INTENSITY = 0.5f; + const glm::vec3 BLUE_AMBIENT(0.0f, 0.75f, 0.67f); + const glm::vec3 BLUE_DIFFUSE(0.0f, 0.75f, 0.67f); + const glm::vec3 BLUE_SPECULAR(0.0f, 0.35, 0.33f); + + const float WHITE_MIN_INTENSITY = 0.1f; + const float WHITE_MAX_INTENSITY = 0.3f; + const glm::vec3 WHITE_AMBIENT(1.05f, 1.05f, 1.05f); + const glm::vec3 WHITE_DIFFUSE(1.0f, 1.0f, 1.0f); + const glm::vec3 WHITE_SPECULAR(0.5f, 0.5f, 0.5f); + + const float ATTEN_LINEAR = 0.07f; + const float ATTEN_QUAD = 0.017f; + + // higher intensity takes you closer to color2 + const auto interpolateColor = [](float intensity, glm::vec3 color1, glm::vec3 color2) { + return color1 + intensity * (color2 - color1); }; + + if (dist_orb < MIN_ORB_DIST) { + // the closer you get, the higher the factor to make it more white is multiplied + const float blue_intensity = (MIN_ORB_DIST - dist_orb) / MIN_ORB_DIST; + + // close to orb, so shade blue + this->properties = TorchlightProperties { + .flickering = true, + .min_intensity = BLUE_MIN_INTENSITY, + .max_intensity = BLUE_MAX_INTENSITY, + .ambient_color = interpolateColor(blue_intensity, AMBER_AMBIENT, BLUE_DIFFUSE), + .diffuse_color = interpolateColor(blue_intensity, AMBER_DIFFUSE, BLUE_DIFFUSE), + .specular_color = interpolateColor(blue_intensity, AMBER_SPECULAR, BLUE_SPECULAR), + .attenuation_linear = ATTEN_LINEAR, + .attenuation_quadratic = ATTEN_QUAD + }; + } else if (dist_exit < MIN_EXIT_DIST) { + const float white_intensity = (MIN_EXIT_DIST - dist_exit) / MIN_EXIT_DIST; + // close to exit, so shade white + // TEMP: still amber + this->properties = TorchlightProperties { + .flickering = true, + .min_intensity = WHITE_MIN_INTENSITY, + .max_intensity = WHITE_MAX_INTENSITY, + .ambient_color = interpolateColor(white_intensity, AMBER_AMBIENT, WHITE_AMBIENT), + .diffuse_color = interpolateColor(white_intensity, AMBER_DIFFUSE, WHITE_DIFFUSE), + .specular_color = interpolateColor(white_intensity, AMBER_SPECULAR, WHITE_SPECULAR), + .attenuation_linear = ATTEN_LINEAR, + .attenuation_quadratic = ATTEN_QUAD + }; + } else { + // shade normal amber + this->properties = TorchlightProperties { + .flickering = true, + .min_intensity = AMBER_MIN_INTENSITY, + .max_intensity = AMBER_MAX_INTENSITY, + .ambient_color = AMBER_AMBIENT, + .diffuse_color = AMBER_DIFFUSE, + .specular_color = AMBER_SPECULAR, + .attenuation_linear = ATTEN_LINEAR, + .attenuation_quadratic = ATTEN_QUAD + }; + } - // for blue lights - // this->properties = TorchlightProperties { - // .flickering = true, - // .min_intensity = 0.1f, - // .max_intensity = 0.5f, - // .ambient_color = glm::vec3(0.0f, 0.75f, 0.67f), - // .diffuse_color = glm::vec3(0.0f, 0.75f, 0.67f), - // .specular_color = glm::vec3(0.0f, 0.35f, 0.33f), - // .attenuation_linear = 0.07f, - // .attenuation_quadratic = 0.017f - // }; init(); } diff --git a/src/shared/utilities/config.cpp b/src/shared/utilities/config.cpp index 1dad4042..881be0de 100644 --- a/src/shared/utilities/config.cpp +++ b/src/shared/utilities/config.cpp @@ -59,7 +59,8 @@ GameConfig GameConfig::parse(int argc, char** argv) { // cppcheck-suppress const .lobby_discovery = json.at("client").at("lobby_discovery"), .fullscreen = json.at("client").at("fullscreen"), .draw_bboxes = json.at("client").at("draw_bboxes"), - .fps_counter = json.at("client").at("fps_counter") + .fps_counter = json.at("client").at("fps_counter"), + .presentation = json.at("client").at("presentation") } }; } catch (nlohmann::json::exception& ex) { @@ -91,7 +92,10 @@ GameConfig getDefaultConfig() { .client = { .default_name = "Player", .lobby_discovery = false, - .fullscreen = false + .fullscreen = false, + .draw_bboxes = false, + .fps_counter = false, + .presentation = false } }; } \ No newline at end of file