From 246d0ace73523844972693d9923446d54d1b238c Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Wed, 22 Jan 2025 15:54:06 +0100 Subject: [PATCH] feat: add final level and story --- COMPILE.txt | 1 + screens/help.txt | 5 +++++ screens/start.txt | 6 ++++++ screens/victory.txt | 3 +++ src/blockRegistry.hpp | 5 +++-- src/blockSettings.hpp | 44 +++++++++++++++-------------------------- src/elementPos.hpp | 26 ------------------------ src/main.cpp | 21 +++++++++++++++++--- src/movementHandler.hpp | 28 ++++++++++++++++++-------- src/world.hpp | 2 +- worlds/1.txt | 8 +++++--- worlds/2.txt | 31 +++++++++++++++-------------- worlds/3.txt | 9 +++++---- worlds/4.txt | 7 ++++--- worlds/5.txt | 17 ++++++++++++++++ 15 files changed, 120 insertions(+), 93 deletions(-) create mode 100644 COMPILE.txt create mode 100644 screens/help.txt create mode 100644 screens/start.txt delete mode 100644 src/elementPos.hpp create mode 100644 worlds/5.txt diff --git a/COMPILE.txt b/COMPILE.txt new file mode 100644 index 0000000..3754a16 --- /dev/null +++ b/COMPILE.txt @@ -0,0 +1 @@ +g++ -std=c++23 -Wall ./src/main.cpp -o ./build/testCompiled && ./build/testCompiled \ No newline at end of file diff --git a/screens/help.txt b/screens/help.txt new file mode 100644 index 0000000..67ecada --- /dev/null +++ b/screens/help.txt @@ -0,0 +1,5 @@ +Welcome to Adventura v1.0 by Martin Prokoph! + +No Arguments: Play through all levels inside the world folder (in alphabetical order) +--level, -l: Load (only) the specified level +--help, -h: Show this screen \ No newline at end of file diff --git a/screens/start.txt b/screens/start.txt new file mode 100644 index 0000000..c3fd76b --- /dev/null +++ b/screens/start.txt @@ -0,0 +1,6 @@ + o Das ist Paul. + /|\ Er wurde von seinen Freundinnen und Freunden zu einer Beachparty eingeladen. + / \ Da er (wieder einmal) verschlafen hat, muss er zu Fuß gehen. + + Steuere Paul, indem du eine der Tasten WASD und danach jeweils Enter drückst. + Probiere es jetzt aus! \ No newline at end of file diff --git a/screens/victory.txt b/screens/victory.txt index 0c3d9e7..4ee8d67 100644 --- a/screens/victory.txt +++ b/screens/victory.txt @@ -3,3 +3,6 @@ │ G E W O N N E N ! ▙▟ │ │ Yay :) ▟▙ │ └────────────────────────────┘ + +Paul ist bei der Beachparty angekommen und kann +alle mit seinem abenteuerlichen Weg beeindrucken! \ No newline at end of file diff --git a/src/blockRegistry.hpp b/src/blockRegistry.hpp index 235797c..5c3961f 100644 --- a/src/blockRegistry.hpp +++ b/src/blockRegistry.hpp @@ -14,9 +14,10 @@ public: Block LADDER = Block(Identifier("adventura", "ladder"), 'H', Color::BRIGHT_MAGENTA, BlockSettingsBuilder().climbableFromBottom().climbableFromTop().build()); Block START = Block(Identifier("adventura", "start"), 'S', BlockSettingsBuilder().nonSolid().build()); Block GOAL = Block(Identifier("adventura", "goal"), 'O', Color::BRIGHT_GREEN, BlockSettingsBuilder().nonSolid().build()); - Block WALL = Block(Identifier("adventura", "wall"), '0', Color::BRIGHT_BLACK, BlockSettingsBuilder().collidable().build()); + Block WALL = Block(Identifier("adventura", "wall"), '0', BlockSettingsBuilder().collidable().build()); Block SPIKE = Block(Identifier("adventura", "spike"), '^', Color::BRIGHT_RED, BlockSettingsBuilder().lethal().build()); Block BOX = Block(Identifier("adventura", "box"), 'x', Color::BRIGHT_CYAN, BlockSettingsBuilder().pushable().collidable().gravity().build()); + Block SAND = Block(Identifier("adventura", "sand"), '*', Color::BRIGHT_YELLOW, BlockSettingsBuilder().brittle().gravity().build()); BlockRegistry() { registerBlock(AIR); @@ -28,13 +29,13 @@ public: registerBlock(WALL); registerBlock(SPIKE); registerBlock(BOX); + registerBlock(SAND); } const Block getByEncoding(char encoding) { for (Block block : registeredBlocks) { if (block.getEncoding() == encoding) return block; } - if (encoding == '/' || encoding == '\\' || encoding == '|' || encoding == 'o') return AIR; // The static player defined in the level should not be part of the world return Block(Identifier("decoration", string(1, encoding)), encoding, BlockSettingsBuilder().nonSolid().build()); // Keep other characters as decoration } diff --git a/src/blockSettings.hpp b/src/blockSettings.hpp index 7ea2687..38371b2 100644 --- a/src/blockSettings.hpp +++ b/src/blockSettings.hpp @@ -16,6 +16,9 @@ class BlockSettings { bool isLethal() { return isLethal_; } + bool isBrittle() { + return isBrittle_; + } bool isClimbableFromTop() { return isClimbableFromTop_; } @@ -23,27 +26,7 @@ class BlockSettings { return isClimbableFromBottom_; } - void setSolid(bool isSolid) { - this->isSolid_ = isSolid; - } - void setPushable(bool isMovable) { - this->isPushable_ = isMovable; - } - void setCollision(bool hasCollision) { - this->hasCollision_ = hasCollision; - } - void setGravity(bool hasGravity) { - this->hasGravity_ = hasGravity; - } - void setLethal(bool isLethal) { - this->isLethal_ = isLethal; - } - void setClimbableFromTop(bool isClimbableFromTop) { - this->isClimbableFromTop_ = isClimbableFromTop; - } - void setClimbableFromBottom(bool isClimbableFromBottom) { - this->isClimbableFromBottom_ = isClimbableFromBottom; - } + friend class BlockSettingsBuilder; private: bool isSolid_ = true; @@ -51,37 +34,42 @@ class BlockSettings { bool isClimbableFromTop_ = false; bool isClimbableFromBottom_ = false; bool isLethal_ = false; + bool isBrittle_ = false; bool hasCollision_ = false; bool hasGravity_ = false; }; class BlockSettingsBuilder { public: BlockSettingsBuilder nonSolid() { - blockSettings.setSolid(false); + blockSettings.isSolid_ = false; return *this; } BlockSettingsBuilder pushable() { - blockSettings.setPushable(true); + blockSettings.isPushable_ = true; return *this; } BlockSettingsBuilder collidable() { - blockSettings.setCollision(true); + blockSettings.hasCollision_ = true; return *this; } BlockSettingsBuilder gravity() { - blockSettings.setGravity(true); + blockSettings.hasGravity_ = true; return *this; } BlockSettingsBuilder lethal() { - blockSettings.setLethal(true); + blockSettings.isLethal_ = true; + return *this; + } + BlockSettingsBuilder brittle() { + blockSettings.isBrittle_ = true; return *this; } BlockSettingsBuilder climbableFromTop() { - blockSettings.setClimbableFromTop(true); + blockSettings.isClimbableFromTop_ = true; return *this; } BlockSettingsBuilder climbableFromBottom() { - blockSettings.setClimbableFromBottom(true); + blockSettings.isClimbableFromBottom_ = true; return *this; } BlockSettings build() { diff --git a/src/elementPos.hpp b/src/elementPos.hpp deleted file mode 100644 index 4e123d8..0000000 --- a/src/elementPos.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -class Pos { -protected: - int x; - int y; -public: - Pos(int x, int y) { - this->x = x; - this->y = y; - } - int getX() { - return x; - } - int getY() { - return y; - } - bool isNegative() { - return x < 0 || y < 0; - } - Pos operator+(Pos offset) { - return Pos(this->getX() + offset.getX(), this->getY() + offset.getY()); - } - Pos operator-(Pos offset) { - return Pos(this->getX() - offset.getX(), this->getY() - offset.getY()); - } -}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 2587762..bf402e7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include "world.hpp" #include "player.hpp" @@ -28,10 +30,21 @@ bool startWorld(string worldFile); */ int main(int argc, char *argv[]) { if (argc > 1) { - if (!startWorld("./worlds/" + string(argv[1]))) return 0; + for (int i = 1; i < argc; i++) { + string arg = string(argv[i]); + if (arg == "-h" || arg == "--help") { + printFile("./screens/help.txt", Color::BRIGHT_BLUE); + return 0; + } + if ((arg == "-l" || arg == "--level") && argc > i + 1 && !startWorld("./worlds/" + string(argv[i+1]))) return 0; + } + } else { + printFile("./screens/start.txt", Color::BRIGHT_YELLOW); + waitForInput(); vector worlds; + // Iterate over all files in the worlds directory for (auto & entry : fs::directory_iterator("./worlds")) { worlds.push_back(entry.path()); } @@ -39,9 +52,11 @@ int main(int argc, char *argv[]) { std::sort( worlds.begin(), worlds.end(), [](string a, string b) { return a < b; }); + // Load every world in order for (const auto & world : worlds) if (!startWorld(world)) return 0; } + // Print the victory screen once all levels have been completed printFile("./screens/victory.txt", Color::BRIGHT_GREEN); return 0; @@ -69,6 +84,7 @@ bool startWorld(string worldFile) { if (!player.isAlive()) printFile("./screens/death.txt", Color::BRIGHT_RED); return player.hasReachedGoal(); } + /** * Move the console cursor up by one line. * Used to overwrite the previous line. @@ -87,9 +103,7 @@ void jumpBackOneLine() { * @param world Reference to the World object representing the game's world. * @param player Reference to the Player object representing the player's state. */ - void redraw(World &world, Player &player) { - //std::this_thread::sleep_for(std::chrono::seconds(1)); for (unsigned int y = 0; y <= world.getMaxY()+1; y++) { jumpBackOneLine(); } @@ -119,6 +133,7 @@ void render(World &world, Player &player) { cout << endl; } } + /** * Prints the content of a file line by line onto the console, * in the specified color. diff --git a/src/movementHandler.hpp b/src/movementHandler.hpp index 94b774c..f115052 100644 --- a/src/movementHandler.hpp +++ b/src/movementHandler.hpp @@ -5,7 +5,13 @@ bool tryWalk(World& world, Player& player, bool left); bool tryGoDown(World& world, Player& player); bool tryGoUp(World& world, Player& player); -bool tryPushBlock(BlockPos& blockPos, World& world, bool left); +void tryPushBlock(BlockPos& blockPos, World& world, bool left); +void tryBlockGravity(BlockPos& blockPos, World& world); + +void waitForInput() { + char lastChar = ' '; + while (lastChar == ' ') cin >> lastChar; +} /** * Processes the player's input and attempts to move the player in the game world @@ -54,11 +60,13 @@ bool onInput(char lastChar, World& world, Player& player) { * @return true if the player's position was successfully updated, false otherwise. */ bool tryWalk(World& world, Player& player, bool left) { - BlockPos neighbourPosTorso = player.getPos()+(left ? BlockPos(-1, 0) : BlockPos(1, 0)); - BlockPos neighbourPosFeet = player.getPos()+(left ? BlockPos(-1, 1) : BlockPos(1, 1)); + BlockPos playerPos = player.getPos(); + BlockPos neighbourPosTorso = playerPos+(left ? BlockPos(-1, 0) : BlockPos(1, 0)); + BlockPos neighbourPosFeet = playerPos+(left ? BlockPos(-1, 1) : BlockPos(1, 1)); tryPushBlock(neighbourPosFeet, world, left); if (!world.getBlockAt(neighbourPosFeet).getSettings().hasCollision()) { player.setPos(neighbourPosTorso); + tryBlockGravity(playerPos, world); return true; } else if (world.getBlockAt(neighbourPosFeet).getSettings().hasCollision() && !world.getBlockAt(neighbourPosTorso).getSettings().isSolid()) { @@ -103,17 +111,21 @@ bool tryGoUp(World& world, Player& player) { } return false; } -bool tryPushBlock(BlockPos& blockPos, World& world, bool left) { +void tryPushBlock(BlockPos& blockPos, World& world, bool left) { BlockPos neighbourBlockPos = blockPos+(left ? BlockPos(-1, 0) : BlockPos(1, 0)); if (world.getBlockAt(blockPos).getSettings().isPushable()) { if (world.getBlockAt(neighbourBlockPos).getSettings().isPushable()) { - tryPushBlock(neighbourBlockPos, world, left); + tryPushBlock(neighbourBlockPos, world, left); // If multiple boxes are next to each other, handle the furthest one first } - if (world.getBlockAt(neighbourBlockPos) == world.getBlockRegistry().AIR) { + if (world.getBlockAt(neighbourBlockPos) == world.getBlockRegistry().AIR) { // Push the box by swapping the blocks world.setBlockAt(neighbourBlockPos, world.getBlockAt(blockPos)); world.setBlockAt(blockPos, world.getBlockRegistry().AIR); - return true; } } - return false; +} +void tryBlockGravity(BlockPos& playerPos, World& world) { + if (world.getBlockAt(playerPos.add(0, 2)).getSettings().hasGravity() && world.getBlockAt(playerPos.add(0, 3)) == world.getBlockRegistry().AIR) { + world.setBlockAt(playerPos.add(0, 3), world.getBlockAt(playerPos.add(0, 2))); + world.setBlockAt(playerPos.add(0, 2), world.getBlockRegistry().AIR); + } } \ No newline at end of file diff --git a/src/world.hpp b/src/world.hpp index f9e1e32..33d03cf 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -34,7 +34,7 @@ public: for (unsigned int y = 0; y < file.size(); y++) { for (unsigned int x = 0; x < file.at(y).size(); x++) { setBlockAt(BlockPos(x, y), blockRegistry.getByEncoding(file.at(y).at(x))); - if (file.at(y).at(x) == '|') startPos = BlockPos(x, y); + if (file.at(y).at(x) == 'S') startPos = BlockPos(x+3, y); if (x > maxX) maxX = x; } if (y > maxY) maxY = y; diff --git a/worlds/1.txt b/worlds/1.txt index d6da200..8cff519 100644 --- a/worlds/1.txt +++ b/worlds/1.txt @@ -1,6 +1,8 @@ - o -S /|\ O - / \ +Welt 1: Zuhause + + +S O + --------- -------- ------- H H H H diff --git a/worlds/2.txt b/worlds/2.txt index 7328ded..e7a51ec 100644 --- a/worlds/2.txt +++ b/worlds/2.txt @@ -1,15 +1,16 @@ - - - o - S /|\ - / \ -------------- ----------- - H H - H H - H H - H --------- ------- --------- H 0 0 - H H 0 0 - H H 0 0 O - H H 0^^^^^0 - ---------------------------------------- \ No newline at end of file +Welt 2: Paul hat Pech + NEIIIIN! Natuerlich ist die Bruecke genau jetzt kaputt! + + S + + ------------- ----------- + H H + H H + H H + H --------- ------- + -------- H 0 0 ----- + H H 0 0 0 + O H H 0 0 O 0 + H H 0^^^^^0 0 +--- xx x ------------------------------------------ + ~~~~~~~~~~ diff --git a/worlds/3.txt b/worlds/3.txt index 9d0f384..823976d 100644 --- a/worlds/3.txt +++ b/worlds/3.txt @@ -1,12 +1,13 @@ - +Welt 3: Der alte Tunnel + ---------------------- 00 00 00 --------- -0 o 00------ O -0 S /|\ 00 0 -0 / \ 00 0 --------------- +0 00------ O +0 S 00 0 +0 00 0 --------------- ---------------- 0 H 0 0 H 0 0 H 0 diff --git a/worlds/4.txt b/worlds/4.txt index d8ce5c9..6735422 100644 --- a/worlds/4.txt +++ b/worlds/4.txt @@ -1,7 +1,8 @@ +Welt 4: In der Klemme - o -S /|\ - / \ + +S + --- 0 0 x x diff --git a/worlds/5.txt b/worlds/5.txt new file mode 100644 index 0000000..66c9a6b --- /dev/null +++ b/worlds/5.txt @@ -0,0 +1,17 @@ +Welt 5: Die Beachparty + + + 0***************0 + 0 0 x + -------^^^^^^^^^^^^^^^^^^^------------ + H ---------------- + H H + H 0 H +S H 0 H + H 0 H +----------********~------- -------------------- H + H ^ 0000 + H 00 0 \u/ p 6 + H 00 0 | O \|/ /0\ + H 00 0~~~~~/~\~~~~~~~~~~~~~/~\~~~~/~\~~~~~~~~~~~~~~~~ + -------------------------***************00 0-----------------------------------*******~~~~~ \ No newline at end of file