mirror of
https://github.com/Motschen/Adventura.git
synced 2025-12-13 10:25:09 +01:00
feat: add final level and story
This commit is contained in:
1
COMPILE.txt
Normal file
1
COMPILE.txt
Normal file
@@ -0,0 +1 @@
|
||||
g++ -std=c++23 -Wall ./src/main.cpp -o ./build/testCompiled && ./build/testCompiled
|
||||
5
screens/help.txt
Normal file
5
screens/help.txt
Normal file
@@ -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
|
||||
6
screens/start.txt
Normal file
6
screens/start.txt
Normal file
@@ -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!
|
||||
@@ -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!
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
};
|
||||
21
src/main.cpp
21
src/main.cpp
@@ -2,6 +2,8 @@
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#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<string> 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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
o
|
||||
S /|\ O
|
||||
/ \
|
||||
Welt 1: Zuhause
|
||||
|
||||
|
||||
S O
|
||||
|
||||
--------- -------- -------
|
||||
H H
|
||||
H H
|
||||
|
||||
17
worlds/2.txt
17
worlds/2.txt
@@ -1,15 +1,16 @@
|
||||
Welt 2: Paul hat Pech
|
||||
NEIIIIN! Natuerlich ist die Bruecke genau jetzt kaputt!
|
||||
|
||||
S
|
||||
|
||||
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
|
||||
----------------------------------------
|
||||
-------- H 0 0 -----
|
||||
H H 0 0 0
|
||||
O H H 0 0 O 0
|
||||
H H 0^^^^^0 0
|
||||
--- xx x ------------------------------------------
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
Welt 4: In der Klemme
|
||||
|
||||
|
||||
S
|
||||
|
||||
o
|
||||
S /|\
|
||||
/ \
|
||||
---
|
||||
0
|
||||
0 x x
|
||||
|
||||
17
worlds/5.txt
Normal file
17
worlds/5.txt
Normal file
@@ -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-----------------------------------*******~~~~~
|
||||
Reference in New Issue
Block a user