|
@ -0,0 +1,378 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
#include <thread>
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
|
#include <random>
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
|
|
|
|
#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); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |