diff --git a/ASCII-G.vcxproj b/ASCII-G.vcxproj index 23bb508..a433f61 100644 --- a/ASCII-G.vcxproj +++ b/ASCII-G.vcxproj @@ -1,4 +1,4 @@ - + @@ -123,6 +123,7 @@ + @@ -130,6 +131,7 @@ + diff --git a/ASCII-G.vcxproj.filters b/ASCII-G.vcxproj.filters index 0b563bd..52d2269 100644 --- a/ASCII-G.vcxproj.filters +++ b/ASCII-G.vcxproj.filters @@ -24,13 +24,19 @@ Исходные файлы + + Исходные файлы + + + Файлы заголовков + - Исходные файлы + Файлы заголовков - Исходные файлы + Файлы заголовков \ No newline at end of file diff --git a/data/locations/location_1.txt b/data/locations/location_1.txt new file mode 100644 index 0000000..26a2980 --- /dev/null +++ b/data/locations/location_1.txt @@ -0,0 +1,21 @@ +ID=1 +TITLE=Entrance Hall +WIDTH=10 +HEIGHT=6 +START_X=1 +START_Y=1 +NORTH=0 +SOUTH=2 +WEST=0 +EAST=0 +RIDDLE_TYPE=1 +RIDDLE_TEXT=What gets bigger when you take something away? +RIDDLE_ANSWER=hole +MAP_BEGIN +########## +#@.......# +#....C...# +#........# +#......D.# +########## +MAP_END \ No newline at end of file diff --git a/data/locations/location_2.txt b/data/locations/location_2.txt new file mode 100644 index 0000000..d6b500a --- /dev/null +++ b/data/locations/location_2.txt @@ -0,0 +1,21 @@ +ID=2 +TITLE=Old Corridor +WIDTH=10 +HEIGHT=6 +START_X=1 +START_Y=1 +NORTH=1 +SOUTH=3 +WEST=0 +EAST=0 +RIDDLE_TYPE=2 +RIDDLE_TEXT=Decode this word: MBHJD. Each letter is shifted by one. +RIDDLE_ANSWER=magic +MAP_BEGIN +########## +#@.......# +#..E.....# +#........# +#......D.# +########## +MAP_END \ No newline at end of file diff --git a/data/locations/location_3.txt b/data/locations/location_3.txt new file mode 100644 index 0000000..1bae725 --- /dev/null +++ b/data/locations/location_3.txt @@ -0,0 +1,21 @@ +ID=3 +TITLE=Guard Room +WIDTH=10 +HEIGHT=6 +START_X=1 +START_Y=1 +NORTH=2 +SOUTH=4 +WEST=0 +EAST=0 +RIDDLE_TYPE=3 +RIDDLE_TEXT=Continue the sequence: 2 4 8 16 +RIDDLE_ANSWER=32 +MAP_BEGIN +########## +#@.......# +#....N...# +#........# +#......D.# +########## +MAP_END \ No newline at end of file diff --git a/data/locations/location_4.txt b/data/locations/location_4.txt new file mode 100644 index 0000000..aca674e --- /dev/null +++ b/data/locations/location_4.txt @@ -0,0 +1,21 @@ +ID=4 +TITLE=Library +WIDTH=10 +HEIGHT=6 +START_X=1 +START_Y=1 +NORTH=3 +SOUTH=5 +WEST=0 +EAST=0 +RIDDLE_TYPE=4 +RIDDLE_TEXT=Where is knowledge usually stored? +RIDDLE_ANSWER=book +MAP_BEGIN +########## +#@.......# +#....C...# +#..E.....# +#......D.# +########## +MAP_END \ No newline at end of file diff --git a/data/locations/location_5.txt b/data/locations/location_5.txt new file mode 100644 index 0000000..471f11d --- /dev/null +++ b/data/locations/location_5.txt @@ -0,0 +1,21 @@ +ID=5 +TITLE=Final Gate +WIDTH=10 +HEIGHT=6 +START_X=1 +START_Y=1 +NORTH=4 +SOUTH=0 +WEST=0 +EAST=0 +RIDDLE_TYPE=5 +RIDDLE_TEXT=What key opens no door? +RIDDLE_ANSWER=keyboard +MAP_BEGIN +########## +#@.......# +#....E...# +#....C...# +#......D.# +########## +MAP_END \ No newline at end of file diff --git a/include/game.h b/include/game.h index 3021646..609eac8 100644 --- a/include/game.h +++ b/include/game.h @@ -1,5 +1,7 @@ -#include "player.h" #pragma once +#include "player.h" +#include "location.h" +#include class Game { public: @@ -7,11 +9,20 @@ public: private: bool isRunning = true; + Player player; + std::vector locations; void showMainMenu(); - void processCommand(); - void render(); -}; -#pragma once + void loadLocations(); + Location* getCurrentLocation(); + + void render(); + void processCommand(); + + void movePlayer(int dx, int dy); + void handleTile(char tile); + + bool solveRiddle(Location& location); +}; \ No newline at end of file diff --git a/include/location.h b/include/location.h new file mode 100644 index 0000000..e2c9f4e --- /dev/null +++ b/include/location.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include + +struct Point { + int x = 0; + int y = 0; +}; + +struct Chest { + Point pos; + int gold = 0; + bool opened = false; +}; + +struct Enemy { + Point pos; + std::string type; + int hp = 50; +}; + +struct NPC { + Point pos; + std::string name; +}; + +struct Riddle { + int type = 0; + std::string text; + std::string answer; + bool isSolved = false; +}; + +class Location { +public: + int id = 0; + std::string title; + + int width = 0; + int height = 0; + + int north = 0; + int south = 0; + int west = 0; + int east = 0; + + Point startPosition; + Riddle riddle; + + std::vector map; + std::vector chests; + std::vector enemies; + std::vector npcs; + + bool loadFromFile(const std::string& path); + + void draw(const Point& playerPosition) const; + + bool isWalkable(int x, int y) const; + char getTile(int x, int y) const; +}; \ No newline at end of file diff --git a/include/player.h b/include/player.h index ca7350c..15f23ec 100644 --- a/include/player.h +++ b/include/player.h @@ -1,20 +1,24 @@ #pragma once #include #include +#include "location.h" class Player { public: std::string name = "Character Name"; + int hp = 100; - int atk = 1; + int atk = 10; int gold = 0; + int currentLocation = 1; + Point position; + int weaponId = 101; std::vector items; - Player() {}; - Player(std::string _name); - void showStats(); -}; + Player() = default; + Player(std::string name); -#pragma once + void showStats() const; +}; \ No newline at end of file diff --git a/location.cpp b/location.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/location.h b/location.h deleted file mode 100644 index 49a3aa9..0000000 --- a/location.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -class Location { -public: - std::string title; - int id; - int sizeX; - int sizeY; - int gold = 0; - - Location() {}; - Location(std::string _name); - void showStats(); -}; - -#pragma once diff --git a/src/game.cpp b/src/game.cpp index 9750835..4d907a4 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,16 +1,40 @@ #include "../include/game.h" -#include "../include/player.h" #include #include void Game::run() { + loadLocations(); showMainMenu(); + while (isRunning) { render(); processCommand(); } } +void Game::loadLocations() { + locations.clear(); + + for (int i = 1; i <= 5; i++) { + Location location; + std::string path = "data/locations/location_" + std::to_string(i) + ".txt"; + + if (location.loadFromFile(path)) { + locations.push_back(location); + } + } +} + +Location* Game::getCurrentLocation() { + for (auto& location : locations) { + if (location.id == player.currentLocation) { + return &location; + } + } + + return nullptr; +} + void Game::showMainMenu() { while (true) { std::cout << "=== ASCII-G - The Cookies Edition ===\n"; @@ -22,47 +46,61 @@ void Game::showMainMenu() { std::string str; std::getline(std::cin, str); - if (str.length() != 1) { - std::cout << "It seems you've tried to input more than 1 digit... Don't do this please.\n"; - continue; - } - - char select = str[0]; - - if (select == '1') { + if (str == "1") { std::string name; + std::cout << ">>> Enter your character name: "; std::getline(std::cin, name); - if (name == "") { - std::cout << ">>> Empty name? Damn... let's call you Zero!\n"; + + if (name.empty()) { player = Player("Zero"); } else { player = Player(name); } - std::cout << ">>> Created new character " << player.name << "!"; + + Location* location = getCurrentLocation(); + + if (location != nullptr) { + player.position = location->startPosition; + } + + std::cout << ">>> Created new character " << player.name << "!\n"; break; } - else if (select == '2') { - std::cout << ">>> I can't do this... yet."; + else if (str == "2") { + std::cout << ">>> Load system is not ready yet.\n"; } - else if (select == '3') { + else if (str == "3") { isRunning = false; break; } else { - std::cout << ">>> I can't do this... yet? Let's try again!"; + std::cout << ">>> Unknown menu option.\n"; } } } void Game::render() { - std::cout << "\n\n=== ASCII-G - The Cookies Edition ===\n"; - std::cout << "Commands: stats, exit\n"; + Location* location = getCurrentLocation(); + + if (location == nullptr) { + std::cout << "Current location not found.\n"; + isRunning = false; + return; + } + + location->draw(player.position); + + std::cout << "\nCommands:\n"; + std::cout << "WASD - move\n"; + std::cout << "stats - show stats\n"; + std::cout << "exit - exit game\n"; } void Game::processCommand() { std::string command; + std::cout << "> "; std::cin >> command; @@ -72,7 +110,117 @@ void Game::processCommand() { else if (command == "stats") { player.showStats(); } + else if (command == "w" || command == "W") { + movePlayer(0, -1); + } + else if (command == "s" || command == "S") { + movePlayer(0, 1); + } + else if (command == "a" || command == "A") { + movePlayer(-1, 0); + } + else if (command == "d" || command == "D") { + movePlayer(1, 0); + } else { std::cout << "Unknown command.\n"; } +} + +void Game::movePlayer(int dx, int dy) { + Location* location = getCurrentLocation(); + + if (location == nullptr) { + return; + } + + int newX = player.position.x + dx; + int newY = player.position.y + dy; + + if (!location->isWalkable(newX, newY)) { + std::cout << "You hit the wall.\n"; + return; + } + + char tile = location->getTile(newX, newY); + + player.position.x = newX; + player.position.y = newY; + + handleTile(tile); +} + +void Game::handleTile(char tile) { + Location* location = getCurrentLocation(); + + if (location == nullptr) { + return; + } + + if (tile == 'C') { + std::cout << "You found a chest. For now it gives you 25 gold.\n"; + player.gold += 25; + } + else if (tile == 'E') { + std::cout << "Enemy encountered. Combat will be added later.\n"; + } + else if (tile == 'N') { + std::cout << "NPC: Hello, traveler.\n"; + } + else if (tile == 'D') { + if (!location->riddle.isSolved) { + bool solved = solveRiddle(*location); + + if (!solved) { + player.hp -= 10; + std::cout << "Wrong answer. You lost 10 HP.\n"; + return; + } + } + + if (location->south != 0) { + player.currentLocation = location->south; + } + else if (location->east != 0) { + player.currentLocation = location->east; + } + else if (location->north != 0) { + player.currentLocation = location->north; + } + else if (location->west != 0) { + player.currentLocation = location->west; + } + else { + std::cout << "There is no exit from this door.\n"; + return; + } + + Location* newLocation = getCurrentLocation(); + + if (newLocation != nullptr) { + player.position = newLocation->startPosition; + std::cout << "You entered: " << newLocation->title << "\n"; + } + } +} + +bool Game::solveRiddle(Location& location) { + if (location.riddle.text.empty()) { + return true; + } + + std::cout << "\nRiddle:\n"; + std::cout << location.riddle.text << "\n"; + std::cout << "Answer: "; + + std::string answer; + std::cin >> answer; + + if (answer == location.riddle.answer) { + std::cout << "Correct.\n"; + location.riddle.isSolved = true; + return true; + } + + return false; } \ No newline at end of file diff --git a/src/location.cpp b/src/location.cpp new file mode 100644 index 0000000..b468753 --- /dev/null +++ b/src/location.cpp @@ -0,0 +1,127 @@ +#include "../include/location.h" +#include +#include +#include + +bool Location::loadFromFile(const std::string& path) { + std::ifstream file(path); + + if (!file.is_open()) { + std::cout << "Cannot open location file: " << path << "\n"; + return false; + } + + std::string line; + bool readingMap = false; + + while (std::getline(file, line)) { + if (line.empty()) { + continue; + } + + if (line == "MAP_BEGIN") { + readingMap = true; + continue; + } + + if (line == "MAP_END") { + readingMap = false; + continue; + } + + if (readingMap) { + map.push_back(line); + continue; + } + + size_t pos = line.find('='); + if (pos == std::string::npos) { + continue; + } + + std::string key = line.substr(0, pos); + std::string value = line.substr(pos + 1); + + if (key == "ID") id = std::stoi(value); + else if (key == "TITLE") title = value; + else if (key == "WIDTH") width = std::stoi(value); + else if (key == "HEIGHT") height = std::stoi(value); + else if (key == "START_X") startPosition.x = std::stoi(value); + else if (key == "START_Y") startPosition.y = std::stoi(value); + else if (key == "NORTH") north = std::stoi(value); + else if (key == "SOUTH") south = std::stoi(value); + else if (key == "WEST") west = std::stoi(value); + else if (key == "EAST") east = std::stoi(value); + else if (key == "RIDDLE_TYPE") riddle.type = std::stoi(value); + else if (key == "RIDDLE_TEXT") riddle.text = value; + else if (key == "RIDDLE_ANSWER") riddle.answer = value; + } + + for (int y = 0; y < map.size(); y++) { + for (int x = 0; x < map[y].size(); x++) { + char tile = map[y][x]; + + if (tile == 'C') { + Chest chest; + chest.pos = { x, y }; + chest.gold = 25; + chests.push_back(chest); + } + else if (tile == 'E') { + Enemy enemy; + enemy.pos = { x, y }; + enemy.type = "Goblin"; + enemy.hp = 50; + enemies.push_back(enemy); + } + else if (tile == 'N') { + NPC npc; + npc.pos = { x, y }; + npc.name = "Stranger"; + npcs.push_back(npc); + } + } + } + + return true; +} + +void Location::draw(const Point& playerPosition) const { + std::cout << "\n=== " << title << " ===\n"; + + for (int y = 0; y < map.size(); y++) { + for (int x = 0; x < map[y].size(); x++) { + if (playerPosition.x == x && playerPosition.y == y) { + std::cout << '@'; + } + else { + char tile = map[y][x]; + + if (tile == '@') { + std::cout << '.'; + } + else { + std::cout << tile; + } + } + } + + std::cout << "\n"; + } +} + +bool Location::isWalkable(int x, int y) const { + if (y < 0 || y >= map.size()) return false; + if (x < 0 || x >= map[y].size()) return false; + + char tile = map[y][x]; + + return tile != '#'; +} + +char Location::getTile(int x, int y) const { + if (y < 0 || y >= map.size()) return '#'; + if (x < 0 || x >= map[y].size()) return '#'; + + return map[y][x]; +} \ No newline at end of file diff --git a/src/player.cpp b/src/player.cpp index 8c360d8..f07fef3 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1,17 +1,19 @@ #include "../include/player.h" #include -Player::Player(std::string _name) -{ - this->name = _name; +Player::Player(std::string name) { + this->name = name; hp = 100; atk = 10; gold = 0; + currentLocation = 1; } -void Player::showStats() { - std::cout << "\n === " << this->name << "'s STATS ==="; - std::cout << "\nHP : " << this->hp; - std::cout << "\nATK : " << this->atk; - std::cout << "\nGOLD : " << this->gold; +void Player::showStats() const { + std::cout << "\n=== " << name << "'s STATS ==="; + std::cout << "\nHP: " << hp; + std::cout << "\nATK: " << atk; + std::cout << "\nGOLD: " << gold; + std::cout << "\nLOCATION: " << currentLocation; + std::cout << "\nPOSITION: " << position.x << ", " << position.y << "\n"; } \ No newline at end of file