Fork Copy 1#include #include #include #include #include #include using namespace std; class Character { protected: string name; int hp, max_hp, atk, def; public: Character(const string& n, int h, int a, int d) : name(n), hp(h), max_hp(h), atk(a), def(d) {} virtual ~Character() = 0; virtual int getEffectiveDef() const { return def; } void takeDamage(int damage) { hp = max(0, hp - damage); } bool isDead() const { return hp <= 0; } string getName() const { return name; } int getHP() const { return hp; } int getMaxHP() const { return max_hp; } }; Character::~Character() {} class Player : public Character { private: bool is_defending; int heal_cooldown; public: Player(const string& n) : Character(n, 100, 15, 5), is_defending(false), heal_cooldown(0) {} int getEffectiveDef() const override { return is_defending ? def * 2 : def; } int getHealCooldown() const { return heal_cooldown; } string attack(Character* target) { int damage = max(1, atk - target->getEffectiveDef()); target->takeDamage(damage); return name + " attacks " + target->getName() + " for " + to_string(damage) + " damage!"; } string defend() { is_defending = true; return name + " defends, effective DEF increased to " + to_string(getEffectiveDef()); } string heal() { if (heal_cooldown > 0) { return "Heal is on cooldown for " + to_string(heal_cooldown) + " more turns!"; } int old_hp = hp; hp = min(max_hp, hp + 20); heal_cooldown = 3; return name + " heals for 20 HP (from " + to_string(old_hp) + " to " + to_string(hp) + ")."; } void endTurn() { if (heal_cooldown > 0) heal_cooldown--; is_defending = false; } }; class Enemy : public Character { public: Enemy(const string& n, int h, int a, int d) : Character(n, h, a, d) {} virtual string performAction(Character* target) = 0; }; class Wolf : public Enemy { public: Wolf() : Enemy("Wolf", 80, 20, 3) {} string performAction(Character* target) override { int damage = max(1, atk - target->getEffectiveDef()); target->takeDamage(damage); return name + " attacks " + target->getName() + " for " + to_string(damage) + " damage!"; } }; class Golem : public Enemy { private: int action_counter; public: Golem() : Enemy("Golem", 120, 10, 12), action_counter(0) {} string performAction(Character* target) override { action_counter++; if (action_counter % 3 == 0) { int damage = max(1, atk - target->getEffectiveDef()); target->takeDamage(damage); return name + " attacks " + target->getName() + " for " + to_string(damage) + " damage!"; } return name + " is preparing its attack..."; } }; class Slime : public Enemy { private: int action_counter; public: Slime() : Enemy("Slime", 80, 12, 2), action_counter(0) {} string performAction(Character* target) override { int damage = max(1, atk - target->getEffectiveDef()); target->takeDamage(damage); string result = name + " attacks " + target->getName() + " for " + to_string(damage) + " damage!"; action_counter++; if (action_counter % 3 == 0) { hp = min(max_hp, hp + 10); result += "\n" + name + " regenerates 10 HP, now at " + to_string(hp) + " HP."; } return result; } }; Enemy* generateRandomEnemy() { int r = rand() % 3; if (r == 0) return new Wolf(); else if (r == 1) return new Golem(); else return new Slime(); } int main() { srand(static_cast(time(nullptr))); // Khởi tạo SFML sf::RenderWindow window(sf::VideoMode(800, 600), "Turn-Based Combat Game"); window.setFramerateLimit(60); // Tải font chữ sf::Font font; if (!font.loadFromFile("arial.ttf")) { return 1; // Lỗi tải font } // Trạng thái nhập tên bool entering_name = true; string player_name = ""; sf::Text name_prompt("Enter your fighter's name:", font, 30); name_prompt.setPosition(200, 200); name_prompt.setFillColor(sf::Color::Black); sf::Text name_input("", font, 30); name_input.setPosition(200, 250); name_input.setFillColor(sf::Color::Black); sf::RectangleShape confirm_button(sf::Vector2f(150, 50)); confirm_button.setPosition(300, 350); confirm_button.setFillColor(sf::Color(255, 255, 100)); // Vàng nhạt sf::Text confirm_text("Confirm", font, 20); confirm_text.setPosition(320, 360); confirm_text.setFillColor(sf::Color::Black); // Nút chơi lại sf::RectangleShape play_again_button(sf::Vector2f(150, 50)); play_again_button.setPosition(300, 400); play_again_button.setFillColor(sf::Color(100, 255, 100)); // Xanh lá nhạt sf::Text play_again_text("Play Again", font, 20); play_again_text.setPosition(310, 410); play_again_text.setFillColor(sf::Color::Black); // Khởi tạo biến game Player* player = nullptr; Enemy* current_enemy = nullptr; int score = 0; bool game_over = false; string message = ""; // Tạo các nút hành động sf::RectangleShape attack_button(sf::Vector2f(100, 50)); attack_button.setPosition(50, 500); attack_button.setFillColor(sf::Color(255, 165, 0)); // Cam sf::RectangleShape defend_button(sf::Vector2f(100, 50)); defend_button.setPosition(200, 500); defend_button.setFillColor(sf::Color(100, 100, 255)); // Xanh dương nhạt sf::RectangleShape heal_button(sf::Vector2f(100, 50)); heal_button.setPosition(350, 500); heal_button.setFillColor(sf::Color(255, 182, 193)); // Hồng nhạt sf::Text attack_text("Attack", font, 20); attack_text.setPosition(60, 510); attack_text.setFillColor(sf::Color::Black); sf::Text defend_text("Defend", font, 20); defend_text.setPosition(210, 510); defend_text.setFillColor(sf::Color::Black); sf::Text heal_text("Heal", font, 20); heal_text.setPosition(360, 510); heal_text.setFillColor(sf::Color::Black); // Vòng lặp chính while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } if (entering_name) { if (event.type == sf::Event::TextEntered) { if (event.text.unicode == '\b' && !player_name.empty()) { player_name.pop_back(); } else if (event.text.unicode == '\r' || event.text.unicode == '\n') { if (!player_name.empty()) { entering_name = false; player = new Player(player_name); current_enemy = generateRandomEnemy(); message = "A wild " + current_enemy->getName() + " appears!"; heal_button.setFillColor(player->getHealCooldown() > 0 ? sf::Color(150, 150, 150) : sf::Color(255, 182, 193)); } } else if (event.text.unicode < 128) { player_name += static_cast(event.text.unicode); } name_input.setString(player_name); } if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { sf::Vector2f mouse_pos = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); if (confirm_button.getGlobalBounds().contains(mouse_pos) && !player_name.empty()) { entering_name = false; player = new Player(player_name); current_enemy = generateRandomEnemy(); message = "A wild " + current_enemy->getName() + " appears!"; heal_button.setFillColor(player->getHealCooldown() > 0 ? sf::Color(150, 150, 150) : sf::Color(255, 182, 193)); } } } else if (game_over) { if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { sf::Vector2f mouse_pos = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); if (play_again_button.getGlobalBounds().contains(mouse_pos)) { // Reset game delete player; delete current_enemy; player = nullptr; current_enemy = nullptr; score = 0; game_over = false; entering_name = true; player_name = ""; message = ""; name_input.setString(""); } } } else { if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { sf::Vector2f mouse_pos = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); string action_message; bool action_taken = false; if (attack_button.getGlobalBounds().contains(mouse_pos)) { action_message = player->attack(current_enemy); action_taken = true; } else if (defend_button.getGlobalBounds().contains(mouse_pos)) { action_message = player->defend(); action_taken = true; } else if (heal_button.getGlobalBounds().contains(mouse_pos)) { action_message = player->heal(); if (action_message.find("Heal is on cooldown") == string::npos) { action_taken = true; } } if (action_taken) { message = action_message; if (current_enemy->isDead()) { message += "\n" + current_enemy->getName() + " has been defeated!"; score++; delete current_enemy; current_enemy = generateRandomEnemy(); message += "\nA new " + current_enemy->getName() + " appears!"; } else { message += "\n" + current_enemy->performAction(player); } player->endTurn(); if (player->isDead()) { game_over = true; message = "Game Over! " + player->getName() + " has been defeated.\nTotal score: " + to_string(score); } } else { message = action_message; } heal_button.setFillColor(player->getHealCooldown() > 0 ? sf::Color(150, 150, 150) : sf::Color(255, 182, 193)); } } } window.clear(sf::Color(220, 220, 220)); // Xám nhạt if (entering_name) { window.draw(name_prompt); window.draw(name_input); window.draw(confirm_button); window.draw(confirm_text); } else { sf::RectangleShape player_hp_bar(sf::Vector2f(200 * (float)player->getHP() / player->getMaxHP(), 20)); player_hp_bar.setPosition(50, 50); player_hp_bar.setFillColor(sf::Color(100, 255, 100)); // Xanh lá nhạt sf::RectangleShape enemy_hp_bar(sf::Vector2f(200 * (float)current_enemy->getHP() / current_enemy->getMaxHP(), 20)); enemy_hp_bar.setPosition(550, 50); enemy_hp_bar.setFillColor(sf::Color(255, 100, 100)); // Đỏ nhạt sf::Text player_info(player->getName() + "\nHP: " + to_string(player->getHP()) + "/" + to_string(player->getMaxHP()), font, 20); player_info.setPosition(50, 80); player_info.setFillColor(sf::Color::Black); sf::Text enemy_info(current_enemy->getName() + "\nHP: " + to_string(current_enemy->getHP()) + "/" + to_string(current_enemy->getMaxHP()), font, 20); enemy_info.setPosition(550, 80); enemy_info.setFillColor(sf::Color::Black); sf::Text score_text("Score: " + to_string(score), font, 20); score_text.setPosition(50, 150); score_text.setFillColor(sf::Color::Black); sf::Text message_text(message, font, 20); message_text.setPosition(50, 200); message_text.setFillColor(sf::Color::Black); if (player->getHealCooldown() > 0) { sf::Text cooldown_text("Heal cooldown: " + to_string(player->getHealCooldown()) + " turns", font, 20); cooldown_text.setPosition(50, 400); cooldown_text.setFillColor(sf::Color::Black); window.draw(cooldown_text); } window.draw(player_hp_bar); window.draw(enemy_hp_bar); window.draw(player_info); window.draw(enemy_info); window.draw(score_text); window.draw(message_text); if (!game_over) { window.draw(attack_button); window.draw(defend_button); window.draw(heal_button); window.draw(attack_text); window.draw(defend_text); window.draw(heal_text); } else { window.draw(play_again_button); window.draw(play_again_text); } } window.display(); } delete player; delete current_enemy; return 0; }