diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03126d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +*.o \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d449d3e..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next -paragraph) shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF -OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/flag.txt b/flag.txt new file mode 100644 index 0000000..c580b24 --- /dev/null +++ b/flag.txt @@ -0,0 +1 @@ +slashroot{n0b0dy_3xpEc7_th3_sp4n1sh_Inqu15it10n} diff --git a/lib/Character.cpp b/lib/Character.cpp new file mode 100644 index 0000000..c2488c1 --- /dev/null +++ b/lib/Character.cpp @@ -0,0 +1,152 @@ +#include "Character.hpp" + +std::vector Character::playerNames = { + "Abby", + "John", + "Adam", + "Johny", + "Christo", + "Greg", +}; + +Character::Character(const char *n, int l, int e, int h, int m, int a, int d) +{ + this->name = n; + this->level = l; + this->experience = e; + this->maxHP = h; + this->curHP = maxHP; + this->maxMP = m; + this->curMP = maxMP; + this->atk = a; + this->def = d; +} + +const char *Character::getName() +{ + return this->name; +} + +int Character::getLevel() +{ + return this->level; +} + +int Character::getExperience() +{ + return this->experience; +} + +int Character::getMaxHP() +{ + return this->maxHP; +} + +int Character::getCurHP() +{ + return this->curHP; +} + +int Character::getMaxMP() +{ + return this->maxMP; +} + +int Character::getCurMP() +{ + return this->curMP; +} + +int Character::getAtk() +{ + return this->atk; +} + +int Character::getDef() +{ + return this->def; +} + +void Character::levelUp() +{ + if ((this->level <= maxLevel) && this->readytoLevelUp()) + { + this->level++; + this->maxHP += 10; + this->maxMP += 5; + } + + this->curHP = this->maxHP; + this->curMP = this->maxMP; +} + +void Character::restoreHP(int n) +{ + this->curHP += n; + if (this->curHP > this->maxHP) + { + this->curHP = this->maxHP; + } +} + +void Character::restoreMP(int n) +{ + this->curMP += n; + if (this->curMP > this->maxMP) + { + this->curMP = this->maxMP; + } +} + +void Character::reduceHP(int n) +{ + this->curHP -= n; +} + +void Character::reduceMP(int n) +{ + this->curMP -= n; +} + +std::vector Character::Enemies = { + new Character("Red Mage", 1, 1, 10, 5, 1, 1), + new Character("Green Mage", 2, 3, 20, 10, 1, 1), + new Character("Blue Mage", 3, 7, 40, 25, 1, 1), + new Character("White Mage", 4, 11, 80, 40, 1, 1), + new Character("Black Mage", 5, 16, 160, 80, 1, 1), +}; + +bool Character::isAlive() +{ + return this->curHP > 0; +} + +int Character::toNextLevel() +{ + return (this->level <= maxLevel) ? ((this->level + 1) * (this->level + 1)) - this->getExperience() : 999999; +} + +bool Character::readytoLevelUp() +{ + return (this->toNextLevel() <= 0); +} + +void Character::increaseExperience(int n) +{ + this->experience += n; + if (this->experience > maxEperience) + { + this->experience = maxEperience; + } +} + +bool Character::canCastSpell(Spell *s) +{ + return this->curMP >= s->getCost(); +} + +void Character::castSpell(Spell *s, Character *t) +{ + this->reduceMP(s->getCost()); + t->reduceHP(s->getAmount()); +} diff --git a/lib/Character.hpp b/lib/Character.hpp new file mode 100644 index 0000000..393e2f0 --- /dev/null +++ b/lib/Character.hpp @@ -0,0 +1,55 @@ +#ifndef SPELL_WARZ_CHARACTER_HPP +#define SPELL_WARZ_CHARACTER_HPP 1 + +#include + +#include "Spell.hpp" + +class Character +{ +protected: + static const int maxLevel = 100; + static const int maxEperience = 999999999; + const char *name; + + int level; + int experience; + int maxHP; + int curHP; + int maxMP; + int curMP; + int atk; + int def; + +public: + static std::vector Enemies; + static std::vector playerNames; + + Character(const char *, int, int, int, int, int, int); + + void restoreHP(int); + void restoreMP(int); + void reduceHP(int); + void reduceMP(int); + + void castSpell(Spell *, Character *); + bool canCastSpell(Spell *); + + const char *getName(); + int getLevel(); + int getExperience(); + int getMaxHP(); + int getCurHP(); + int getMaxMP(); + int getCurMP(); + int getAtk(); + int getDef(); + int toNextLevel(); + + bool readytoLevelUp(); + bool isAlive(); + void levelUp(); + void increaseExperience(int n); +}; + +#endif \ No newline at end of file diff --git a/lib/Spell.cpp b/lib/Spell.cpp new file mode 100644 index 0000000..13e11be --- /dev/null +++ b/lib/Spell.cpp @@ -0,0 +1,40 @@ +#include "Spell.hpp" + +Spell::Spell(const char *n, int t, int a, int c) +{ + this->name = n; + this->type = t; + this->amount = a; + this->cost = c; +} + +int Spell::getType() +{ + return this->type; +} + +int Spell::getAmount() +{ + return this->amount; +} + +int Spell::getCost() +{ + return this->cost; +} + +const char *Spell::getName() +{ + return this->name; +} + +std::vector Spell::Book = { + new Spell("Spanish Inquisition", 1, 111111, 0), + new Spell("Mana Bolt", 1, 5, 1), + new Spell("Flame Bolt", 1, 8, 2), + new Spell("Mana Flare", 1, 10, 3), + new Spell("Ice Spear", 1, 13, 4), + new Spell("Mana Misile", 1, 15, 5), + new Spell("Thunder Strike", 1, 18, 6), + new Spell("Mana Blast", 1, 20, 7), +}; \ No newline at end of file diff --git a/lib/Spell.hpp b/lib/Spell.hpp new file mode 100644 index 0000000..61865a0 --- /dev/null +++ b/lib/Spell.hpp @@ -0,0 +1,27 @@ +#ifndef SPELL_WARZ_SPELL_CPP +#define SPELL_WARZ_SPELL_CPP 1 + +#include + +class Spell +{ +protected: + const char *name; + + int type; + int amount; + int cost; + +public: + int TYPE_RESTORATION = 0; + int TYPE_DESTRUCTION = 1; + static std::vector Book; + + Spell(const char *, int, int, int); + int getType(); + int getAmount(); + int getCost(); + const char *getName(); +}; + +#endif \ No newline at end of file diff --git a/main b/main new file mode 100755 index 0000000..34e9ed1 Binary files /dev/null and b/main differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..9981f4d --- /dev/null +++ b/main.cpp @@ -0,0 +1,378 @@ + +#include +#include +#include +#include +#include + +#include "lib/Character.hpp" +#include "lib/Spell.hpp" + +#define INTERVAL 1000 +#define FLAG_INTERVAL 250 + +void sleep(int ms) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + +int strlen(const char *msg) +{ + int i = 0; + while (msg[i] != '\x00') + { + i++; + } + return i; +} + +int getLowest(int a, int b) +{ + return (a < b) ? a : b; +} + +int getHighest(int a, int b) +{ + return (a > b) ? a : b; +} + +void intervalPrint(const char *msg, int interval = 1000, int len = 0) +{ + if (len <= 0) + { + len = strlen(msg); + } + + for (int i = 0; i < len; i++) + { + std::cout << msg[i] << std::flush; + std::this_thread::sleep_for(std::chrono::milliseconds(interval)); + } + std::cout << std::endl; +} +void intervalPrint(std::string &msg, int interval = 1000, int len = 0) +{ + if (len <= 0) + { + len = msg.length(); + } + + for (int i = 0; i < len; i++) + { + std::cout << msg.at(i) << std::flush; + std::this_thread::sleep_for(std::chrono::milliseconds(interval)); + } + std::cout << std::endl; +} + +int getNumber(const char *prompt, int min, int max) +{ + int tmp = 0; + std::cout << prompt; + while (!(std::cin >> tmp) && (tmp >= min && tmp <= max)) + { + if (std::cin.eofbit) + { + exit(1); + } + std::cin.get(); + std::cin.clear(); + std::cin.ignore(4096, '\x00'); + // std::cin.ignore(4096, '\n'); + std::cout << prompt; + } + return tmp; +} + +Character *chooseEnemy() +{ + std::cout << "List of challenger:" << std::endl; + for (int i = 0; i < Character::Enemies.size(); i++) + { + std::cout << "[" << i << "] " << Character::Enemies[i]->getName() << std::endl; + } + + int choice = 0; + do + { + choice = getNumber("Choose your enemy: ", 0, Character::Enemies.size()); + } while (!(choice >= 0 && choice < Character::Enemies.size())); + return Character::Enemies[choice]; +} + +Character *generatePlayer() +{ + Character *tmp = new Character( + Character::playerNames[std::rand() % Character::playerNames.size()], + 1, + 1, + 100, + 50, + 1, + 1); + + return tmp; +} + +std::string loadFlag() +{ + std::string tmp; + std::ifstream flagFile("flag.txt"); + if (flagFile.is_open()) + { + flagFile >> tmp; + } + return tmp; +} + +void printCharacterInfo(Character *c) +{ + std::cout << "Name : " << c->getName() << std::endl + << "HP : " << c->getCurHP() << "/" << c->getMaxHP() << std::endl + << "MP : " << c->getCurMP() << "/" << c->getMaxMP() << std::endl; +} + +void printCharacterFullInfo(Character *c) +{ + std::cout << "Name : " << c->getName() << std::endl + << "Level: " << c->getLevel() << std::endl + << "Exp : " << c->getExperience() << " | next: " << c->toNextLevel() << std::endl + << "HP : " << c->getCurHP() << "/" << c->getMaxHP() << std::endl + << "MP : " << c->getCurMP() << "/" << c->getMaxMP() << std::endl; +} + +Character *startBattle(Character *p1, Character *p2) +{ + int maxTurn = 1000; + int turn = 0; + std::cout << "===== BATTLE START ======" << std::endl; + while ((p1->isAlive() && p2->isAlive()) && (++turn <= maxTurn)) + { + std::cout << "== Turn " << turn << " ==" << std::endl; + std::cout << "Player =====" << std::endl; + printCharacterInfo(p1); + + std::cout << "Enemy ======" << std::endl; + printCharacterInfo(p2); + + std::cout << "===== Spell Books =====" << std::endl; + for (int i = 1; i <= p1->getLevel() && i < Spell::Book.size(); i++) + { + std::cout << "[" << i << "] " << Spell::Book[i]->getName() << std::endl; + } + + int p1Choice = getNumber("Choose your spell: ", 0, getLowest(p1->getLevel(), Spell::Book.size() - 1)); + int p2Choice = (std::rand() % getLowest(p2->getLevel(), Spell::Book.size() - 1)) + 1; + + Spell *p1Spell = Spell::Book[p1Choice]; + Spell *p2Spell = Spell::Book[p2Choice]; + + if (p1->canCastSpell(p1Spell)) + { + p1->castSpell(p1Spell, p2); + std::cout << p1->getName() << " cast " << p1Spell->getName() << std::endl; + sleep(INTERVAL); + std::cout << p2->getName() << " took " << p1Spell->getAmount() << " damage" << std::endl; + sleep(INTERVAL); + } + else + { + std::cout << p1->getName() << " failed to cast " << p1Spell->getName() << std::endl; + sleep(INTERVAL); + std::cout << p1->getName() << " does not have enough MP to cast it!" << std::endl; + sleep(INTERVAL); + } + + if (p2->canCastSpell(p2Spell)) + { + p2->castSpell(p2Spell, p1); + std::cout << p2->getName() << " cast " << p2Spell->getName() << std::endl; + sleep(INTERVAL); + std::cout << p1->getName() << " took " << p2Spell->getAmount() << " damage" << std::endl; + sleep(INTERVAL); + } + else + { + std::cout << p2->getName() << " failed to cast " << p2Spell->getName() << std::endl; + sleep(INTERVAL); + std::cout << p2->getName() << " does not have enough MP to cast it!" << std::endl; + sleep(INTERVAL); + } + } + + Character *winner; + + if (turn >= maxTurn) + { + std::cout << "The battle took too long, a winner has to be decided." << std::endl; + winner = (p1->getCurHP() > p2->getCurHP()) ? p1 : p2; + } + else + { + winner = (p1->isAlive()) ? p1 : p2; + } + + return winner; +} + +int main() +{ + std::srand(std::time(0)); + std::string flag = loadFlag(); + Character *player = generatePlayer(); + Character *archMage = new Character("Arch-Mage", 999, 999999, 999999, 999999, 1, 1); + + std::cout << "Welcome to SpellWarz!" << std::endl; + sleep(INTERVAL); + std::cout << "You are a young mage named '" << player->getName() << "'" << std::endl; + sleep(INTERVAL); + std::cout << "Here's your flag: "; + + intervalPrint(flag, FLAG_INTERVAL, 10); + + std::cout << "Oh no!" << std::endl; + sleep(INTERVAL); + std::cout << "The Arch-Mage took your flag!" << std::endl; + sleep(INTERVAL); + std::cout << "He said you are not worthy of it," << std::endl; + sleep(INTERVAL); + std::cout << "defeat him to get it back!" << std::endl; + sleep(INTERVAL); + + while (player->isAlive()) + { + std::cout << "========================================" << std::endl; + printCharacterFullInfo(player); + + std::cout << "========================================" << std::endl + << "[1] Sleep" << std::endl + << "[2] Meditate" << std::endl + << "[3] Spar with other mages" << std::endl + << "[4] Search info about Arch-Mage" << std::endl + << "[5] Challenge the Arch-Mage" << std::endl + << "[0] Give up on life" << std::endl; + + int choice = getNumber("Choose your action: ", 0, 5); + std::cout << "========================================" << std::endl; + + if (choice == 0) + { + std::cout << "Farewell young mage, see you in the afterlife..." << std::endl; + player->reduceHP(player->getMaxHP()); + } + if (choice == 1) + { + std::cout << "You take a rest in your dormitory..." << std::endl; + sleep(INTERVAL); + std::cout << "You recovered to full HP and MP" << std::endl; + sleep(INTERVAL); + player->restoreHP(player->getMaxHP()); + player->restoreMP(player->getMaxMP()); + } + if (choice == 2) + { + int tmp; + tmp = (rand() % 10) + 1; + std::cout << "You meditate on your mana..." << std::endl; + sleep(INTERVAL); + std::cout << "And got " << tmp << " experience!" << std::endl; + sleep(INTERVAL); + player->increaseExperience(tmp); + if (player->readytoLevelUp()) + { + std::cout << "Congratulations, you leveled up!" << std::endl; + while (player->readytoLevelUp()) + { + player->levelUp(); + } + sleep(200); + } + } + if (choice == 3) + { + Character *enemy = new Character(*chooseEnemy()); + Character *winner = startBattle(player, enemy); + if (winner == player) + { + std::cout << "You win! You got " << enemy->getExperience() << "exp" << std::endl; + sleep(INTERVAL); + player->increaseExperience(enemy->getExperience()); + if (player->readytoLevelUp()) + { + std::cout << "Congratulations, you leveled up!" << std::endl; + while (player->readytoLevelUp()) + { + player->levelUp(); + } + sleep(200); + } + } + else + { + while (!player->isAlive()) + { + player->restoreHP(1); + } + std::cout << "You lose the fight, it was a fair fight." << std::endl; + sleep(INTERVAL); + } + } + if (choice == 4) + { + std::cout << "You are searching info about the Arch-Mage..." << std::endl; + sleep(INTERVAL); + std::cout << "Here's some info about the Arch-Mage:" << std::endl; + printCharacterFullInfo(archMage); + } + if (choice == 5) + { + if (archMage->isAlive()) + { + std::cout << "You are challenging the Arch-Mage" << std::endl; + sleep(INTERVAL); + std::cout << "Arch-Mage: "; + sleep(INTERVAL); + intervalPrint("so you have come to challenge me. Prepare to die!", 200); + + Character *winner = startBattle(player, archMage); + if (winner == player) + { + std::cout << "You win! You got " << archMage->getExperience() << "exp" << std::endl; + player->increaseExperience(archMage->getExperience()); + sleep(INTERVAL); + if (player->readytoLevelUp()) + { + std::cout << "Congratulations, you leveled up!" << std::endl; + while (player->readytoLevelUp()) + { + player->levelUp(); + } + sleep(200); + } + std::cout << "You did a good job! Now you are the Arch-Mage!" << std::endl; + sleep(INTERVAL); + std::cout << "Here's the flag the previous Arch-Mage took from you: " << std::endl; + sleep(INTERVAL); + intervalPrint(flag, FLAG_INTERVAL); + } + else + { + std::cout << "You lose the fight..." << std::endl; + sleep(INTERVAL); + std::cout << "Unfortunately, the Arch-Mage was serious about this fight..." << std::endl; + sleep(INTERVAL); + std::cout << "You were killed in battle..." << std::endl; + intervalPrint("GAME OVER", 250); + } + } + else + { + std::cout << "You are the Arch-Mage now." << std::endl; + sleep(INTERVAL); + std::cout << "Here's your flag:"; + sleep(INTERVAL); + intervalPrint(flag, FLAG_INTERVAL); + } + } + } +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..9e6122e --- /dev/null +++ b/makefile @@ -0,0 +1,18 @@ +CC = g++ + +Spell.o: lib/Spell.cpp lib/Spell.hpp + g++ -c lib/Spell.cpp -o Spell.o + +Character.o: lib/Character.cpp lib/Character.hpp + g++ -c lib/Character.cpp -o Character.o + +main: Spell.o Character.o main.cpp lib/Character.hpp lib/Spell.hpp + g++ main.cpp -o main Spell.o Character.o + +clean: Spell.o Character.o + rm Spell.o Character.o + +striped: Spell.o Character.o main.cpp lib/Character.hpp lib/Spell.hpp + g++ -s main.cpp -o main Spell.o Character.o + +all: Spell.o Character.o main \ No newline at end of file