From eaa645442cdf7af0f440aeab2d1b7375e8b559b7 Mon Sep 17 00:00:00 2001 From: Matthew Sekirin Date: Wed, 8 Dec 2021 14:38:33 -0500 Subject: [PATCH] Splitting factory into generalcreator and spawncreator --- Makefile | 3 +- cc3k.cc | 48 ++-- cc3k.h | 6 +- creator.cc | 168 +++++++++++ creator.h | 31 +++ defaultlevel.cc | 463 ------------------------------- enemy/enemy.h | 10 + generalcreator.cc | 6 + generalcreator.h | 30 ++ levelcreator.cc | 207 ++++++++++++++ defaultlevel.h => levelcreator.h | 18 +- localizedcreator.cc | 6 + localizedcreator.h | 21 ++ spawncreator.cc | 75 +++++ spawncreator.h | 26 ++ 15 files changed, 617 insertions(+), 501 deletions(-) create mode 100644 creator.cc create mode 100644 creator.h delete mode 100644 defaultlevel.cc create mode 100644 generalcreator.cc create mode 100644 generalcreator.h create mode 100644 levelcreator.cc rename defaultlevel.h => levelcreator.h (58%) create mode 100644 localizedcreator.cc create mode 100644 localizedcreator.h create mode 100644 spawncreator.cc create mode 100644 spawncreator.h diff --git a/Makefile b/Makefile index d4e0f9b..e360b2c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ CXX= g++ CXXFLAGS=-std=c++14 -g -MMD -OBJECTS=main.o cc3k.o floor.o level.o defaultlevel.o stairway.o cell.o entity.o character.o \ +OBJECTS=main.o cc3k.o floor.o stairway.o cell.o entity.o character.o \ + creator.o generalcreator.o localizedcreator.o levelcreator.o spawncreator.o \ utils/message.o utils/color.o \ player/player.o player/drow.o player/goblin.o player/shade.o player/troll.o player/vampire.o \ treasure/gold.o treasure/smallPile.o treasure/normalPile.o treasure/merchantHoard.o treasure/dragonHoard.o \ diff --git a/cc3k.cc b/cc3k.cc index 86cddd0..bd83ae2 100644 --- a/cc3k.cc +++ b/cc3k.cc @@ -1,6 +1,7 @@ #include "cc3k.h" -#include "level.h" -#include "defaultlevel.h" +#include "creator.h" +#include "levelcreator.h" +#include "spawncreator.h" #include "player/player.h" #include "player/drow.h" @@ -50,7 +51,8 @@ using namespace std; CC3K::CC3K() : levelNum{1}, theFloor{make_shared()}, - theLevel{make_shared(theFloor, *this)}, + levelCreator{make_shared(theFloor, *this)}, + spawnCreator{make_shared(theFloor, *this)}, theStairway{nullptr}, playerGold{0}, startingRace{Player::RaceTypes::SHADE}, stopEnemies{false}, isHostileMerchants{false}, isCustom{false} { @@ -142,58 +144,58 @@ void CC3K::loadCustomLevel(int customLevelNum) { switch (customLevelRaw[i][j]) { - // Spawn RH + // Spawn RH: case '0': { - thePotions.push_back(theLevel->spawnPotionAt(Potion::PotionTypes::RESTOREHEALTH, j, i)); + thePotions.push_back(spawnCreator->createPotionAt(Potion::PotionTypes::RESTOREHEALTH, j, i)); break; } // Spawn BA case '1': { - thePotions.push_back(theLevel->spawnPotionAt(Potion::PotionTypes::BOOSTATK, j, i)); + thePotions.push_back(spawnCreator->createPotionAt(Potion::PotionTypes::BOOSTATK, j, i)); break; } // Spawn BD case '2': { - thePotions.push_back(theLevel->spawnPotionAt(Potion::PotionTypes::BOOSTDEF, j, i)); + thePotions.push_back(spawnCreator->createPotionAt(Potion::PotionTypes::BOOSTDEF, j, i)); break; } // Spawn PH case '3': { - thePotions.push_back(theLevel->spawnPotionAt(Potion::PotionTypes::POISONHEALTH, j, i)); + thePotions.push_back(spawnCreator->createPotionAt(Potion::PotionTypes::POISONHEALTH, j, i)); break; } // Spawn WA case '4': { - thePotions.push_back(theLevel->spawnPotionAt(Potion::PotionTypes::WOUNDATK, j, i)); + thePotions.push_back(spawnCreator->createPotionAt(Potion::PotionTypes::WOUNDATK, j, i)); break; } // Spawn WD case '5': { - thePotions.push_back(theLevel->spawnPotionAt(Potion::PotionTypes::WOUNDDEF, j, i)); + thePotions.push_back(spawnCreator->createPotionAt(Potion::PotionTypes::WOUNDDEF, j, i)); break; } // Spawn Normal gold pile case '6': { - theGold.push_back(theLevel->spawnGoldAt(Gold::GoldTypes::MEDIUM, j, i, nullptr)); + theGold.push_back(spawnCreator->createGoldAt(Gold::GoldTypes::MEDIUM, j, i, nullptr)); break; } // Spawn small hoard case '7': { - theGold.push_back(theLevel->spawnGoldAt(Gold::GoldTypes::SMALL, j, i, nullptr)); + theGold.push_back(spawnCreator->createGoldAt(Gold::GoldTypes::SMALL, j, i, nullptr)); break; } // Spawn merchant hoard case '8': { - theGold.push_back(theLevel->spawnGoldAt(Gold::GoldTypes::MERCHANT_HOARD, j, i, nullptr)); + theGold.push_back(spawnCreator->createGoldAt(Gold::GoldTypes::MERCHANT_HOARD, j, i, nullptr)); break; } @@ -210,7 +212,7 @@ void CC3K::loadCustomLevel(int customLevelNum) { auto dragon = make_shared(nullptr); - theGold.push_back(theLevel->spawnGoldAt(Gold::GoldTypes::DRAGON_HOARD, j, i, dragon)); + theGold.push_back(spawnCreator->createGoldAt(Gold::GoldTypes::DRAGON_HOARD, j, i, dragon)); if (dragon) { theEnemies.push_back(dragon); @@ -230,15 +232,15 @@ void CC3K::loadCustomLevel(int customLevelNum) // Generate enemies for (int i = 0; i < NUM_ENEMIES; i++) { - theEnemies.push_back(theLevel->generateEnemy(isHostileMerchants)); + theEnemies.push_back(levelCreator->generateEnemy(isHostileMerchants)); } // Place the player at a random chamber - theLevel->placePlayer(thePlayer); + levelCreator->placePlayer(thePlayer); // Generate stairway int chamberPlayer = theFloor->chamberAt(thePlayer); - theStairway = theLevel->generateStairway(chamberPlayer); + theStairway = levelCreator->generateStairway(chamberPlayer); } void CC3K::newGame() @@ -247,7 +249,7 @@ void CC3K::newGame() // Generate the player messages.emplace_back("Player character has spawned. ", Color::GREEN); - thePlayer = theLevel->generatePlayer(startingRace); + thePlayer = levelCreator->generatePlayer(startingRace); // Generate the level newLevel(); @@ -290,23 +292,23 @@ void CC3K::newLevel() thePlayer->applyPermanentPotions(); // Place the player at a random chamber - theLevel->placePlayer(thePlayer); + levelCreator->placePlayer(thePlayer); // Generate stairway int chamberPlayer = theFloor->chamberAt(thePlayer); - theStairway = theLevel->generateStairway(chamberPlayer); + theStairway = levelCreator->generateStairway(chamberPlayer); // Generate potions for (int i = 0; i < NUM_POTIONS; i++) { - thePotions.push_back(theLevel->generatePotion()); + thePotions.push_back(levelCreator->generatePotion()); } // Generate gold for (int i = 0; i < NUM_GOLD; i++) { auto newDragon = make_shared(nullptr); - shared_ptr newGold = theLevel->generateGold(newDragon); + shared_ptr newGold = levelCreator->generateGold(newDragon); theGold.push_back(newGold); if (newDragon->getHoard()) { @@ -317,7 +319,7 @@ void CC3K::newLevel() // Generate enemies for (int i = 0; i < NUM_ENEMIES; i++) { - theEnemies.push_back(theLevel->generateEnemy(isHostileMerchants)); + theEnemies.push_back(levelCreator->generateEnemy(isHostileMerchants)); } } diff --git a/cc3k.h b/cc3k.h index c75d5e7..70121c8 100644 --- a/cc3k.h +++ b/cc3k.h @@ -13,12 +13,14 @@ #include "display/subject.h" #include "utils/message.h" -class Level; +class GeneralCreator; +class LocalizedCreator; class CC3K : public Subject { int levelNum; std::shared_ptr theFloor; - std::shared_ptr theLevel; + std::shared_ptr levelCreator; + std::shared_ptr spawnCreator; std::vector observers; std::shared_ptr theStairway; diff --git a/creator.cc b/creator.cc new file mode 100644 index 0000000..6eee615 --- /dev/null +++ b/creator.cc @@ -0,0 +1,168 @@ +#include "creator.h" + +#include "floor.h" + +#include "player/player.h" +#include "player/drow.h" +#include "player/shade.h" +#include "player/goblin.h" +#include "player/troll.h" +#include "player/vampire.h" + +#include "enemy/enemy.h" +#include "enemy/orc.h" +#include "enemy/human.h" +#include "enemy/dwarf.h" +#include "enemy/halfling.h" +#include "enemy/elf.h" +#include "enemy/merchant.h" + +#include "potion/potion.h" +#include "potion/restoreHealth.h" +#include "potion/poisonHealth.h" +#include "potion/boostAtk.h" +#include "potion/woundAtk.h" +#include "potion/boostDef.h" +#include "potion/woundDef.h" + +#include "treasure/gold.h" +#include "treasure/smallPile.h" +#include "treasure/normalPile.h" +#include "treasure/merchantHoard.h" + +#include "stairway.h" + +using namespace std; + + +Creator::Creator(shared_ptr floorMap): theFloor{floorMap} {} + +Creator::~Creator() {}; + +// requires: sum of numbers in typeWeightings equals totalWeight +int Creator::getRandomType(vector typeWeightings, int totalWeight) { + int sum = rand() % totalWeight + 1; + int index = 0; + while (sum > typeWeightings[index]) { + sum -= typeWeightings[index]; + index++; + } + + return index + 1; +} + +std::shared_ptr Creator::createPlayer(int playerType) { + switch (playerType) + { + case (Player::RaceTypes::SHADE): + { + return make_shared(); + } + case (Player::RaceTypes::DROW): + { + return make_shared(); + } + case (Player::RaceTypes::VAMPIRE): + { + return make_shared(); + } + case (Player::RaceTypes::GOBLIN): + { + return make_shared(); + } + case (Player::RaceTypes::TROLL): + { + return make_shared(); + } + } + + return nullptr; +} + +std::shared_ptr Creator::createStairway() { + return make_shared(); +} + +std::shared_ptr Creator::createPotion(int potionType) { + switch (potionType) + { + case Potion::PotionTypes::RESTOREHEALTH: + { + return make_shared(); + } + case Potion::PotionTypes::POISONHEALTH: + { + return make_shared(); + } + case Potion::PotionTypes::BOOSTATK: + { + return make_shared(); + } + case Potion::PotionTypes::WOUNDATK: + { + return make_shared(); + } + case Potion::PotionTypes::BOOSTDEF: + { + return make_shared(); + } + case Potion::PotionTypes::WOUNDDEF: + { + return make_shared(); + } + } + + return nullptr; +} + +// dragon and dragon hoard are not included +std::shared_ptr Creator::createGold(int goldType) { + switch (goldType) + { + case Gold::GoldTypes::SMALL: + { + return make_shared(); + } + case Gold::GoldTypes::MEDIUM: + { + return make_shared(); + } + case Gold::GoldTypes::MERCHANT_HOARD: + { + return make_shared(); + } + } + + return nullptr; +} +std::shared_ptr Creator::createEnemy(int enemyType, bool hostileMerchants) { + switch (enemyType) + { + case Enemy::EnemyTypes::HUMAN: + { + return make_shared(); + } + case Enemy::EnemyTypes::DWARF: + { + return make_shared(); + } + case Enemy::EnemyTypes::HALFING: + { + return make_shared(); + } + case Enemy::EnemyTypes::ELF: + { + return make_shared(); + } + case Enemy::EnemyTypes::ORC: + { + return make_shared(); + } + case Enemy::EnemyTypes::MERCHANT: + { + return make_shared(hostileMerchants); + } + } + + return nullptr; +} diff --git a/creator.h b/creator.h new file mode 100644 index 0000000..8a0701f --- /dev/null +++ b/creator.h @@ -0,0 +1,31 @@ +#ifndef CREATOR_H_ +#define CREATOR_H_ + +#include +#include + +class Floor; +class Player; +class Stairway; +class Potion; +class Gold; +class Enemy; +class Dragon; + +class Creator { +protected: + std::shared_ptr theFloor; + + int getRandomType(std::vector typeWeightings, int totalWeight); + std::shared_ptr createPlayer(int playerType); + std::shared_ptr createStairway(); + std::shared_ptr createPotion(int potionType); + std::shared_ptr createGold(int goldType); + std::shared_ptr createEnemy(int enemyType, bool hostileMerchants); +public: + Creator(std::shared_ptr floorMap); + virtual ~Creator() = 0; + +}; + +#endif /* CREATOR_H_ */ diff --git a/defaultlevel.cc b/defaultlevel.cc deleted file mode 100644 index 9541359..0000000 --- a/defaultlevel.cc +++ /dev/null @@ -1,463 +0,0 @@ -#include "defaultlevel.h" - -#include "cc3k.h" - -#include - -#include "player/player.h" -#include "player/drow.h" -#include "player/shade.h" -#include "player/goblin.h" -#include "player/troll.h" -#include "player/vampire.h" - -#include "enemy/enemy.h" -#include "enemy/orc.h" -#include "enemy/human.h" -#include "enemy/dragon.h" -#include "enemy/dwarf.h" -#include "enemy/halfling.h" -#include "enemy/elf.h" -#include "enemy/merchant.h" - -#include "potion/restoreHealth.h" -#include "potion/poisonHealth.h" -#include "potion/boostAtk.h" -#include "potion/woundAtk.h" -#include "potion/boostDef.h" -#include "potion/woundDef.h" - -#include "treasure/gold.h" -#include "treasure/smallPile.h" -#include "treasure/normalPile.h" -#include "treasure/dragonHoard.h" -#include "treasure/merchantHoard.h" - -#include "stairway.h" -#include "floor.h" - -using namespace std; - -DefaultLevel::DefaultLevel(shared_ptr floorMap, const CC3K &game) - : Level{floorMap}, game{game} {} - -/* - * Generates a player according to startingRace. - */ -shared_ptr DefaultLevel::generatePlayer(int startingRace) -{ - shared_ptr newPlayer; - switch (startingRace) - { - case (Player::RaceTypes::SHADE): - { - newPlayer = make_shared(); - break; - } - case (Player::RaceTypes::DROW): - { - newPlayer = make_shared(); - break; - } - case (Player::RaceTypes::VAMPIRE): - { - newPlayer = make_shared(); - break; - } - case (Player::RaceTypes::GOBLIN): - { - newPlayer = make_shared(); - break; - } - case (Player::RaceTypes::TROLL): - { - newPlayer = make_shared(); - break; - } - } - placePlayer(newPlayer); - - return newPlayer; -} - -shared_ptr DefaultLevel::generateStairway(int playerChamberNum) -{ - // Assumption: only the player has been generated at this point - // Thus we only need to check collision with player - shared_ptr newStairway = make_shared(); - - while (true) - { - // Generate a random chamber number (to ensure each chamber has equal probability) - // Ensure it is NOT EQUAL to player chamber - int targetChamberNum = theFloor->getRandomChamberNum(); - - while (targetChamberNum == playerChamberNum) - { - targetChamberNum = theFloor->getRandomChamberNum(); - } - - // Get random coordinates and a random chamber number - int randX = theFloor->getRandomX(); - int randY = theFloor->getRandomY(); - int chamberNum = theFloor->chamberAt(randX, randY); - - // Check that chamber is not same as the chamber that player spawned in - if (!game.isOccupied(randX, randY) && (chamberNum == targetChamberNum) && (chamberNum != playerChamberNum)) - { - newStairway->setX(randX); - newStairway->setY(randY); - return newStairway; - } - } -} - -shared_ptr DefaultLevel::generatePotion() -{ - // Generate a random potion type - int potionType = rand() % Potion::NUM_POTION_TYPES + 1; - - auto newPotion = make_shared(); - - switch (potionType) - { - case Potion::PotionTypes::RESTOREHEALTH: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::POISONHEALTH: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::BOOSTATK: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::WOUNDATK: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::BOOSTDEF: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::WOUNDDEF: - { - newPotion = make_shared(); - break; - } - } - - while (true) - { - // Generate a random chamber number (to ensure each chamber has equal probability) - int targetChamberNum = theFloor->getRandomChamberNum(); - - // Get random coordinates and its associated chamber - int randX = theFloor->getRandomX(); - int randY = theFloor->getRandomY(); - int chamberNum = theFloor->chamberAt(randX, randY); - - if ((chamberNum == targetChamberNum) && !(game.isOccupied(randX, randY))) - { - newPotion->setX(randX); - newPotion->setY(randY); - return newPotion; - } - } - return nullptr; -} - -shared_ptr DefaultLevel::generateGold(shared_ptr dragonEnemy) -{ - // Generate a number from 1-8 - // For the desired probability distribution - // 5/8 normal, 1/8 dragon, 1/4 small hoard - int goldType = rand() % 8 + 1; - - auto newGold = make_shared("", 0); - - // If we are spawning a dragonhoard - bool isDragonHoard = false; - - // 5/8 probability normal - if (goldType <= 5) - { - newGold = make_shared(); - } - // 1/8 probability dragon - else if (goldType <= 6) - { - // Spawn a dragon later - isDragonHoard = true; - } - // 1/4 probability small - else - { - newGold = make_shared(); - } - - while (true) - { - // Generate a random chamber number (to ensure each chamber has equal probability) - int targetChamberNum = theFloor->getRandomChamberNum(); - - // Get random coordinates and its associated chamber - int randX = theFloor->getRandomX(); - int randY = theFloor->getRandomY(); - int chamberNum = theFloor->chamberAt(randX, randY); - if (chamberNum == targetChamberNum && !(game.isOccupied(randX, randY))) - { - if (isDragonHoard) - { - // Generate random coordinates for the dragon - auto dragonGold = make_shared(); - - // Generate a dragon with the associated dragon hoard - auto dragon = make_shared(dragonGold); - - // Generate the coordinates for the dragon - - // Generate a dx and dy either -1 or 1 - int dY = rand() % 2 ? -1 : 1; - int dX = rand() % 2 ? -1 : 1; - - int dragonX = dX + randX; - int dragonY = dY + randY; - - // Set the coordinates for gold and dragon - dragonGold->setX(randX); - dragonGold->setY(randY); - - int dragonChamberNum = theFloor->chamberAt(dragonX, dragonY); - - if (dragonChamberNum == targetChamberNum && !(game.isOccupied(dragonX, dragonY))) - { - dragonEnemy->setX(dragonX); - dragonEnemy->setY(dragonY); - dragonEnemy->setHoard(dragonGold); - - return dragonGold; - } - } - else - { - newGold->setX(randX); - newGold->setY(randY); - dragonEnemy->setHoard(nullptr); - return newGold; - } - // If generation fails, we do nothing - } - } - return nullptr; -} - -shared_ptr DefaultLevel::generateEnemy(bool hostileMerchants) -{ - // Generate a number from 1-18 - // For the desired probability distribution - int enemyType = rand() % 18 + 1; - - auto newEnemy = make_shared(0, 0, 0, false, 'E', ""); - - // Cumulative probability - // 2/9 human - if (enemyType <= 4) - { - newEnemy = make_shared(); - } - // - else if (enemyType <= 7) - { - newEnemy = make_shared(); - } - else if (enemyType <= 12) - { - newEnemy = make_shared(); - } - else if (enemyType <= 14) - { - newEnemy = make_shared(); - } - else if (enemyType <= 16) - { - newEnemy = make_shared(); - } - else if (enemyType <= 18) - { - newEnemy = make_shared(hostileMerchants); - } - else - { - cerr << "Error generating enemy" << endl; - } - - while (true) - { - // Generate a random chamber number (to ensure each chamber has equal probability) - int targetChamberNum = theFloor->getRandomChamberNum(); - - // Get random coordinates and its associated chamber - int randX = theFloor->getRandomX(); - int randY = theFloor->getRandomY(); - int chamberNum = theFloor->chamberAt(randX, randY); - - if (chamberNum == targetChamberNum && !(game.isOccupied(randX, randY))) - { - newEnemy->setX(randX); - newEnemy->setY(randY); - - return newEnemy; - } - } - return nullptr; -} - -void DefaultLevel::placePlayer(shared_ptr thePlayer) -{ - while (true) - { - int targetChamberNum = theFloor->getRandomChamberNum(); // select a random chamber number - // Get random coordinates - int randX = theFloor->getRandomX(); - int randY = theFloor->getRandomY(); - int chamberNum = theFloor->chamberAt(randX, randY); - - // Check the chamber - if (!game.isOccupied(randX, randY) && chamberNum == targetChamberNum) - { - thePlayer->setX(randX); - thePlayer->setY(randY); - break; - } - } -} - -shared_ptr DefaultLevel::spawnPotionAt(int potionType, int x, int y) -{ - - auto newPotion = make_shared(); - - switch (potionType) - { - case Potion::PotionTypes::RESTOREHEALTH: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::POISONHEALTH: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::BOOSTATK: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::WOUNDATK: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::BOOSTDEF: - { - newPotion = make_shared(); - break; - } - case Potion::PotionTypes::WOUNDDEF: - { - newPotion = make_shared(); - break; - } - } - - newPotion->setX(x); - newPotion->setY(y); - return newPotion; -} -shared_ptr DefaultLevel::spawnGoldAt(int goldType, int x, int y, std::shared_ptr dragon) -{ - - auto newGold = make_shared("", 0); - switch (goldType) - { - case Gold::GoldTypes::SMALL: - { - newGold = make_shared(); - break; - } - case Gold::GoldTypes::MEDIUM: - { - newGold = make_shared(); - break; - } - case Gold::GoldTypes::MERCHANT_HOARD: - { - newGold = make_shared(); - break; - } - case Gold::GoldTypes::DRAGON_HOARD: - { - int numAttempts = 0; - while (true) - { - - - auto dragonGold = make_shared(); - auto theDragon = make_shared(dragonGold); - - dragonGold->setX(x); - dragonGold->setY(y); - - // Generate a dx and dy either -1 or 1 - int dY = rand() % 2 ? -1 : 1; - int dX = rand() % 2 ? -1 : 1; - - int dragonX; - int dragonY; - // Too many failed generation attempts, just spawn somewhere - if (numAttempts > 10) - { - dragonX = theFloor->getRandomX(); - dragonY = theFloor->getRandomY(); - } - else { - dragonX = dX + x; - dragonY = dY + y; - - } - - - - // Set the coordinates for gold and dragon - if (!(game.isOccupied(dragonX, dragonY)) && theFloor->chamberAt(dragonX, dragonY) == theFloor->chamberAt(x, y) && dragon != nullptr) - { - dragon->setHoard(dragonGold); - dragon->setX(dragonX); - dragon->setY(dragonY); - return dragonGold; - - } - - // Requirement: to call spawnGoldAt with dragon hoard requires with an associated dragon - if (dragon == nullptr) - { - return nullptr; - } - - } - } - } - - newGold->setX(x); - newGold->setY(y); - - return newGold; -} diff --git a/enemy/enemy.h b/enemy/enemy.h index c171fd0..84398c0 100644 --- a/enemy/enemy.h +++ b/enemy/enemy.h @@ -12,5 +12,15 @@ class Enemy : public Character { virtual int attack(std::shared_ptr defender); virtual bool inRange(std::shared_ptr defender); // virtual void move(int dx, int dy); + + enum EnemyTypes { + HUMAN = 1, + DWARF, + HALFING, + ELF, + ORC, + MERCHANT, + DRAGON + }; }; #endif diff --git a/generalcreator.cc b/generalcreator.cc new file mode 100644 index 0000000..c8cd003 --- /dev/null +++ b/generalcreator.cc @@ -0,0 +1,6 @@ +#include "generalcreator.h" +using namespace std; + +GeneralCreator::GeneralCreator(shared_ptr floorMap): Creator{floorMap} {} + +GeneralCreator::~GeneralCreator() {}; diff --git a/generalcreator.h b/generalcreator.h new file mode 100644 index 0000000..a78e239 --- /dev/null +++ b/generalcreator.h @@ -0,0 +1,30 @@ +#ifndef GENERALCREATOR_H_ +#define GENERALCREATOR_H_ + +#include +#include "creator.h" + +class Floor; +class Player; +class Stairway; +class Potion; +class Gold; +class Enemy; +class Dragon; + +class GeneralCreator: public Creator { +public: + GeneralCreator(std::shared_ptr floorMap); + + virtual std::shared_ptr generatePlayer(int startingRace) = 0; + virtual std::shared_ptr generateStairway(int playerChamberNum) = 0; + virtual std::shared_ptr generatePotion() = 0; + virtual std::shared_ptr generateGold(std::shared_ptr dragonEnemy) = 0; + virtual std::shared_ptr generateEnemy(bool hostileMerchants) = 0; + + virtual void placePlayer(std::shared_ptr thePlayer) = 0; + + virtual ~GeneralCreator() = 0; +}; + +#endif /*GENERALCREATOR_H_ */ diff --git a/levelcreator.cc b/levelcreator.cc new file mode 100644 index 0000000..27a164a --- /dev/null +++ b/levelcreator.cc @@ -0,0 +1,207 @@ +#include "levelcreator.h" + +#include "cc3k.h" + +#include + +#include "player/player.h" +#include "enemy/enemy.h" +#include "enemy/dragon.h" +#include "potion/potion.h" +#include "treasure/gold.h" +#include "treasure/dragonHoard.h" + +#include "stairway.h" +#include "floor.h" + +using namespace std; + +LevelCreator::LevelCreator(shared_ptr floorMap, const CC3K &game) + : GeneralCreator{floorMap}, game{game} {} + +/* + * Generates a player according to startingRace. + */ +shared_ptr LevelCreator::generatePlayer(int startingRace) +{ + shared_ptr newPlayer = createPlayer(startingRace); + placePlayer(newPlayer); + + return newPlayer; +} + +shared_ptr LevelCreator::generateStairway(int playerChamberNum) +{ + // Assumption: only the player has been generated at this point + // Thus we only need to check collision with player + shared_ptr newStairway = createStairway(); + + while (true) + { + // Generate a random chamber number (to ensure each chamber has equal probability) + // Ensure it is NOT EQUAL to player chamber + int targetChamberNum = theFloor->getRandomChamberNum(); + + while (targetChamberNum == playerChamberNum) + { + targetChamberNum = theFloor->getRandomChamberNum(); + } + + // Get random coordinates and a random chamber number + int randX = theFloor->getRandomX(); + int randY = theFloor->getRandomY(); + int chamberNum = theFloor->chamberAt(randX, randY); + + // Check that chamber is not same as the chamber that player spawned in + if (!game.isOccupied(randX, randY) && (chamberNum == targetChamberNum) && (chamberNum != playerChamberNum)) + { + newStairway->setX(randX); + newStairway->setY(randY); + return newStairway; + } + } +} + +shared_ptr LevelCreator::generatePotion() +{ + // Generate a random potion type + int potionType = rand() % Potion::NUM_POTION_TYPES + 1; + + shared_ptr newPotion = createPotion(potionType); + while (true) + { + // Generate a random chamber number (to ensure each chamber has equal probability) + int targetChamberNum = theFloor->getRandomChamberNum(); + + // Get random coordinates and its associated chamber + int randX = theFloor->getRandomX(); + int randY = theFloor->getRandomY(); + int chamberNum = theFloor->chamberAt(randX, randY); + + if ((chamberNum == targetChamberNum) && !(game.isOccupied(randX, randY))) + { + newPotion->setX(randX); + newPotion->setY(randY); + return newPotion; + } + } + return nullptr; +} + +shared_ptr LevelCreator::generateGold(shared_ptr dragonEnemy) +{ + bool isDragonHoard = false; // if we are spawning a dragonhoard + std::shared_ptr newGold = nullptr; + int goldType = getRandomType({5, 1, 2}, 8); + if (goldType == 2) + { + isDragonHoard = true; + } + else + { + newGold = createGold(goldType); + } + + while (true) + { + // Generate a random chamber number (to ensure each chamber has equal probability) + int targetChamberNum = theFloor->getRandomChamberNum(); + + // Get random coordinates and its associated chamber + int randX = theFloor->getRandomX(); + int randY = theFloor->getRandomY(); + int chamberNum = theFloor->chamberAt(randX, randY); + if ((chamberNum == targetChamberNum) && !game.isOccupied(randX, randY)) + { + if (isDragonHoard) + { + // Generate random coordinates for the dragon + auto dragonGold = make_shared(); + + // Generate a dragon with the associated dragon hoard + auto dragon = make_shared(dragonGold); + + // Generate the coordinates for the dragon + + // Generate a dx and dy either -1 or 1 + int dY = rand() % 2 ? -1 : 1; + int dX = rand() % 2 ? -1 : 1; + + int dragonX = dX + randX; + int dragonY = dY + randY; + + // Set the coordinates for gold and dragon + dragonGold->setX(randX); + dragonGold->setY(randY); + + int dragonChamberNum = theFloor->chamberAt(dragonX, dragonY); + + if (dragonChamberNum == targetChamberNum && !game.isOccupied(dragonX, dragonY)) + { + dragonEnemy->setX(dragonX); + dragonEnemy->setY(dragonY); + dragonEnemy->setHoard(dragonGold); + + return dragonGold; + } + } + else + { + newGold->setX(randX); + newGold->setY(randY); + dragonEnemy->setHoard(nullptr); + return newGold; + } + // If generation fails, we do nothing + } + } + return nullptr; +} + +shared_ptr LevelCreator::generateEnemy(bool hostileMerchants) +{ + shared_ptr newEnemy = nullptr; + int enemyType = getRandomType({4, 3, 5, 2, 2, 2}, 18); + newEnemy = createEnemy(enemyType, hostileMerchants); + + while (true) + { + // Generate a random chamber number (to ensure each chamber has equal probability) + int targetChamberNum = theFloor->getRandomChamberNum(); + + // Get random coordinates and its associated chamber + int randX = theFloor->getRandomX(); + int randY = theFloor->getRandomY(); + int chamberNum = theFloor->chamberAt(randX, randY); + + if (chamberNum == targetChamberNum && !game.isOccupied(randX, randY)) + { + newEnemy->setX(randX); + newEnemy->setY(randY); + + return newEnemy; + } + } + return nullptr; +} + +void LevelCreator::placePlayer(shared_ptr thePlayer) +{ + while (true) + { + int targetChamberNum = theFloor->getRandomChamberNum(); // select a random chamber number + // Get random coordinates + int randX = theFloor->getRandomX(); + int randY = theFloor->getRandomY(); + int chamberNum = theFloor->chamberAt(randX, randY); + + // Check the chamber + if (!game.isOccupied(randX, randY) && chamberNum == targetChamberNum) + { + thePlayer->setX(randX); + thePlayer->setY(randY); + break; + } + } +} + diff --git a/defaultlevel.h b/levelcreator.h similarity index 58% rename from defaultlevel.h rename to levelcreator.h index d002863..48fb001 100644 --- a/defaultlevel.h +++ b/levelcreator.h @@ -1,9 +1,8 @@ -#ifndef DEFAULTLEVEL_H_ -#define DEFAULTLEVEL_H_ +#ifndef LEVELCREATOR_H_ +#define LEVELCREATOR_H_ #include - -#include "level.h" +#include "generalcreator.h" class CC3K; class Floor; @@ -14,11 +13,11 @@ class Gold; class Enemy; class Dragon; -class DefaultLevel: public Level { +class LevelCreator: public GeneralCreator { const CC3K &game; public: - DefaultLevel(std::shared_ptr floorMap, const CC3K &game); + LevelCreator(std::shared_ptr floorMap, const CC3K &game); std::shared_ptr generatePlayer(int startingRace) override; std::shared_ptr generateStairway(int playerChamberNum) override; @@ -26,11 +25,6 @@ class DefaultLevel: public Level { std::shared_ptr generateGold(std::shared_ptr dragonEnemy) override; std::shared_ptr generateEnemy(bool hostileMerchants) override; void placePlayer(std::shared_ptr thePlayer) override; - - // Helper functions for parsing custom levels - std::shared_ptr spawnPotionAt(int potionType, int x, int y); - std::shared_ptr spawnGoldAt(int goldType, int x, int y, std::shared_ptr dragon); - }; -#endif /* DEFAULTLEVEL_H_ */ +#endif /* LEVELCREATOR_H_ */ diff --git a/localizedcreator.cc b/localizedcreator.cc new file mode 100644 index 0000000..5910ce1 --- /dev/null +++ b/localizedcreator.cc @@ -0,0 +1,6 @@ +#include "localizedcreator.h" +using namespace std; + +LocalizedCreator::LocalizedCreator(shared_ptr floorMap): Creator{floorMap} {} + +LocalizedCreator::~LocalizedCreator() {}; diff --git a/localizedcreator.h b/localizedcreator.h new file mode 100644 index 0000000..525475a --- /dev/null +++ b/localizedcreator.h @@ -0,0 +1,21 @@ +#ifndef LOCALIZEDCREATOR_H_ +#define LOCALIZEDCREATOR_H_ + +#include +#include "creator.h" + +class Potion; +class Gold; +class Dragon; + +class LocalizedCreator: public Creator { +public: + LocalizedCreator(std::shared_ptr floorMap); + virtual std::shared_ptr createPotionAt(int potionType, int x, int y) = 0; + virtual std::shared_ptr createGoldAt(int goldType, int x, int y, std::shared_ptr dragon) = 0; + // add remaining ones + + virtual ~LocalizedCreator() = 0; +}; + +#endif /* LOCALIZEDCREATOR_H_ */ diff --git a/spawncreator.cc b/spawncreator.cc new file mode 100644 index 0000000..2ab7c7d --- /dev/null +++ b/spawncreator.cc @@ -0,0 +1,75 @@ +#include "spawncreator.h" + +#include "cc3k.h" +#include "floor.h" + +#include "potion/potion.h" +#include "treasure/gold.h" +#include "treasure/dragonHoard.h" +#include "enemy/dragon.h" + +using namespace std; + +SpawnCreator::SpawnCreator(shared_ptr floorMap, const CC3K &game) + : LocalizedCreator{floorMap}, game{game} {} +SpawnCreator::~SpawnCreator() {}; + +shared_ptr SpawnCreator::createPotionAt(int potionType, int x, int y) { + shared_ptr newPotion = createPotion(potionType); + + newPotion->setX(x); + newPotion->setY(y); + return newPotion; +} + +shared_ptr SpawnCreator::createGoldAt(int goldType, int x, int y, std::shared_ptr dragon) { + + shared_ptr newGold = nullptr; + if (goldType == Gold::GoldTypes::DRAGON_HOARD) + { + if (dragon == nullptr) { + throw invalid_argument("argument DragonHoard for gold_type requires an associated dragon"); + } + int numAttempts = 0; // may fail due to associated dragon + while (true) + { + auto dragonGold = make_shared(); + auto theDragon = make_shared(dragonGold); + + dragonGold->setX(x); + dragonGold->setY(y); + + // Generate a dx and dy either -1 or 1 + int dY = rand() % 2 ? -1 : 1; + int dX = rand() % 2 ? -1 : 1; + + int dragonX; + int dragonY; + // Too many failed generation attempts, just spawn somewhere + if (numAttempts > 10) + { + dragonX = theFloor->getRandomX(); + dragonY = theFloor->getRandomY(); + } + else { + dragonX = dX + x; + dragonY = dY + y; + + } + + // Set the coordinates for gold and dragon + if (!(game.isOccupied(dragonX, dragonY)) && theFloor->chamberAt(dragonX, dragonY) == theFloor->chamberAt(x, y) && dragon != nullptr) + { + dragon->setHoard(dragonGold); + dragon->setX(dragonX); + dragon->setY(dragonY); + return dragonGold; + } + } + } + createGold(goldType); + + newGold->setX(x); + newGold->setY(y); + return newGold; +} diff --git a/spawncreator.h b/spawncreator.h new file mode 100644 index 0000000..e1f941d --- /dev/null +++ b/spawncreator.h @@ -0,0 +1,26 @@ +#ifndef SPAWNCREATOR_H_ +#define SPAWNCREATOR_H_ + +#include +#include "localizedcreator.h" + +class CC3K; +class Floor; +class Potion; +class Gold; +class Dragon; + +class SpawnCreator: public LocalizedCreator { + const CC3K &game; +public: + SpawnCreator(std::shared_ptr floorMap, const CC3K &game); + + std::shared_ptr createPotionAt(int potionType, int x, int y) override; + std::shared_ptr createGoldAt(int goldType, int x, int y, std::shared_ptr dragon) override; + + ~SpawnCreator(); +}; + + + +#endif /* FACTORIES_SPAWNCREATOR_H_ */