From 7bb08ed447167a1fed14f91bd6af862e9b9d7cb3 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 29 Aug 2013 21:39:18 +0200 Subject: [PATCH] Added random weapons for enemies, also added setFirst/SecondWeapon to Character. --- res/yaml/enemy.yaml | 2 -- res/yaml/player.yaml | 2 -- src/Game.cpp | 4 ++-- src/generator/Generator.cpp | 27 +++++++++++++----------- src/generator/Generator.h | 2 +- src/sprites/Enemy.cpp | 33 +++++++++++++++++++++++++++++- src/sprites/Enemy.h | 4 ++-- src/sprites/Player.cpp | 3 +++ src/sprites/abstract/Character.cpp | 31 +++++++++++++++++++++++----- src/sprites/abstract/Character.h | 2 ++ src/sprites/items/Weapon.cpp | 25 ++++++++++++++++++++++ src/sprites/items/Weapon.h | 12 +++++++++++ src/util/Loader.h | 4 ++-- src/util/ResourceManager.h | 4 ++-- 14 files changed, 124 insertions(+), 31 deletions(-) diff --git a/res/yaml/enemy.yaml b/res/yaml/enemy.yaml index a5b958b..323baa5 100644 --- a/res/yaml/enemy.yaml +++ b/res/yaml/enemy.yaml @@ -5,6 +5,4 @@ health: 100 speed: 100 radius: 25 size: [50, 50] -first_weapon: pistol.yaml -second_weapon: knife.yaml faction: 1 \ No newline at end of file diff --git a/res/yaml/player.yaml b/res/yaml/player.yaml index e049589..a301a4c 100644 --- a/res/yaml/player.yaml +++ b/res/yaml/player.yaml @@ -5,6 +5,4 @@ health: 100 speed: 100 radius: 25 size: [50, 50] -first_weapon: pistol.yaml -second_weapon: knife.yaml faction: 0 \ No newline at end of file diff --git a/src/Game.cpp b/src/Game.cpp index 68c6060..1f166b2 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -55,8 +55,8 @@ Game::Game(tgui::Window& window) : } void Game::initPlayer() { - mPlayer = std::shared_ptr < Player - > (new Player(mWorld, mPathfinder, mGenerator.getPlayerSpawn())); + mPlayer = std::shared_ptr(new Player(mWorld, mPathfinder, + mGenerator.getPlayerSpawn())); mPlayer->setLeftGadget(std::shared_ptr < Gadget > (new Heal())); mPlayer->setRightGadget(std::shared_ptr < Gadget > (new Shield())); mWorld.insertCharacter(mPlayer); diff --git a/src/generator/Generator.cpp b/src/generator/Generator.cpp index 75e9484..dd405f0 100644 --- a/src/generator/Generator.cpp +++ b/src/generator/Generator.cpp @@ -65,10 +65,11 @@ Generator::generateCurrentAreaIfNeeded(const Vector2f& playerPosition) { Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2, Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE)); generateTiles(area); - for (const auto& enemyPosition : getEnemySpawns(area)) { - float distance = thor::length(enemyPosition - playerPosition); + for (const auto& enemy : getEnemySpawns(area)) { + float distance = thor::length(enemy.first - playerPosition); if (distance > Character::VISION_DISTANCE) - mWorld.insertCharacter(std::shared_ptr(new Enemy(mWorld, mPathfinder, enemyPosition))); + mWorld.insertCharacter(std::shared_ptr(new Enemy( + mWorld, mPathfinder, enemy.first, enemy.second))); } } if (mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) { @@ -258,23 +259,25 @@ Generator::generateTiles(const sf::IntRect& area) { * Returns coordinates where enemies should spawn. * * @param area Area for which enemy spawns should be returned. + * @return Pairs of spawn points together with seeds. */ -std::vector +std::vector > Generator::getEnemySpawns(const sf::IntRect& area) { - auto compare = [](const Vector2f& a, const Vector2f& b) { - return a.x < b.x || (a.x == b.x && a.y < b.y); - }; - std::set ret(compare); + std::vector > spawns; for (int x = area.left; x < area.left + area.width; x++) { for (int y = area.top; y < area.top + area.height; y++) { - if (mCharacterNoise.getNoise(x, y) < -0.85f) { + float noise = mCharacterNoise.getNoise(x, y); + if (noise <= -0.85f) { Vector2i tilePosition = findClosestFloor(Vector2i(x, y)); - ret.insert(Vector2f(tilePosition.x * Tile::TILE_SIZE.x, - tilePosition.y * Tile::TILE_SIZE.y)); + // Bad way to get a pseudo random, but deterministic value. + // Just using noise would be better, but that is not uniformly distributed. + int seed = ((int) noise * 100000) xor x xor y; + spawns.push_back(std::make_pair(Vector2f(tilePosition.x * Tile::TILE_SIZE.x, + tilePosition.y * Tile::TILE_SIZE.y), seed)); } } } - return std::vector(ret.begin(), ret.end()); + return spawns; } /** diff --git a/src/generator/Generator.h b/src/generator/Generator.h index 4f77a64..805daf9 100644 --- a/src/generator/Generator.h +++ b/src/generator/Generator.h @@ -25,7 +25,7 @@ public: explicit Generator(World& world, Pathfinder& pathfinder); void generateCurrentAreaIfNeeded(const Vector2f& position); Vector2f getPlayerSpawn() const; - std::vector getEnemySpawns(const sf::IntRect& area); + std::vector > getEnemySpawns(const sf::IntRect& area); private: typedef std::map > array; diff --git a/src/sprites/Enemy.cpp b/src/sprites/Enemy.cpp index aa844b7..eac7ca0 100644 --- a/src/sprites/Enemy.cpp +++ b/src/sprites/Enemy.cpp @@ -9,12 +9,43 @@ #include +#include "items/Heal.h" +#include "items/Shield.h" +#include "items/Weapon.h" #include "../util/Yaml.h" +/** + * Determines items used by this enemy using seed. + * + * @param seed Random value to seed random number generator. + */ Enemy::Enemy(World& world, Pathfinder& pathfinder, - const Vector2f& position) : + const Vector2f& position, float seed) : Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("enemy.yaml"), world, pathfinder) { + std::ranlux24_base generator(seed); + + // Select primary weapon. + switch (std::uniform_int_distribution(0, 4)(generator)) { + case 0: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::ASSAULT_RIFLE)); break; + case 1: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::AUTO_SHOTGUN)); break; + case 2: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::HMG)); break; + case 3: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::RIFLE)); break; + case 4: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::SHOTGUN)); break; + } + + // Select secondary weapon. + switch (std::uniform_int_distribution(0, 1)(generator)) { + case 0: setSecondWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::PISTOL)); + case 1: setSecondWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::KNIFE)); + } + + // Select gadget. + switch (std::uniform_int_distribution(0, 1)(generator)) { + case 0: setLeftGadget(std::shared_ptr(new Heal())); + case 1: setLeftGadget(std::shared_ptr(new Shield())); + } + } void diff --git a/src/sprites/Enemy.h b/src/sprites/Enemy.h index 0381795..6f1f633 100644 --- a/src/sprites/Enemy.h +++ b/src/sprites/Enemy.h @@ -8,14 +8,14 @@ #ifndef DG_ENEMY_H_ #define DG_ENEMY_H -#include "../sprites/abstract/Character.h" +#include "abstract/Character.h" class World; class Enemy : public Character { public: explicit Enemy(World& world, Pathfinder& pathfinder, - const Vector2f& position); + const Vector2f& position, float seed); private: virtual void onThink(int elapsed) override; diff --git a/src/sprites/Player.cpp b/src/sprites/Player.cpp index 7ca50c7..cfb8d71 100644 --- a/src/sprites/Player.cpp +++ b/src/sprites/Player.cpp @@ -9,6 +9,7 @@ #include +#include "items/Weapon.h" #include "../util/Yaml.h" /** @@ -19,6 +20,8 @@ Player::Player(World& world, Pathfinder& pathfinder, Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("player.yaml"), world, pathfinder), mDirection(0) { + setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::PISTOL)); + setSecondWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::KNIFE)); } Vector2f diff --git a/src/sprites/abstract/Character.cpp b/src/sprites/abstract/Character.cpp index b7c913b..4e743e9 100644 --- a/src/sprites/abstract/Character.cpp +++ b/src/sprites/abstract/Character.cpp @@ -32,10 +32,6 @@ Character::Character(const Vector2f& position, Category category, mMaxHealth(config.get("health", 100)), mCurrentHealth(mMaxHealth), mMovementSpeed(config.get("speed", 0.0f)), - mFirstWeapon(new Weapon(world, *this, - Yaml(config.get("first_weapon", std::string())))), - mSecondWeapon(new Weapon(world, *this, - Yaml(config.get("second_weapon", std::string())))), mActiveWeapon(mFirstWeapon), mLastPosition(getPosition()), mFaction((Faction) config.get("faction", 1)) { @@ -48,12 +44,13 @@ Character::~Character() { * Subtracts health from Actor. Calls onDeath() when health reaches zero and marks * object for deletion. * - * @param damage Amount of health to subtract. + * @param damage Amount of damage taken. */ void Character::onDamage(int damage) { mCurrentHealth -= damage; + if (mCurrentHealth > mMaxHealth) mCurrentHealth = mMaxHealth; @@ -232,11 +229,35 @@ Character::selectSecondWeapon() { mActiveWeapon = mSecondWeapon; } +/** + * Returns current player health. + */ int Character::getHealth() const { return mCurrentHealth; } +/** + * Sets first weapon to weapon, also replacing active weapon if first weapon + * is active. + */ +void +Character::setFirstWeapon(std::shared_ptr weapon) { + if (mFirstWeapon == mActiveWeapon) + mActiveWeapon = weapon; + mFirstWeapon = weapon; +} + +/** + * Sets second weapon to weapon, also replacing active weapon if second weapon + * is active. + */ +void +Character::setSecondWeapon(std::shared_ptr weapon) { + if (mSecondWeapon == mActiveWeapon) + mActiveWeapon = weapon; + mSecondWeapon = weapon; +} void Character::setLeftGadget(std::shared_ptr gadget) { diff --git a/src/sprites/abstract/Character.h b/src/sprites/abstract/Character.h index 0dcee7a..1d35600 100644 --- a/src/sprites/abstract/Character.h +++ b/src/sprites/abstract/Character.h @@ -59,6 +59,8 @@ protected: void selectFirstWeapon(); void selectSecondWeapon(); int getHealth() const; + void setFirstWeapon(std::shared_ptr weapon); + void setSecondWeapon(std::shared_ptr weapon); void setLeftGadget(std::shared_ptr gadget); void setRightGadget(std::shared_ptr gadget); void useLeftGadget(); diff --git a/src/sprites/items/Weapon.cpp b/src/sprites/items/Weapon.cpp index e1098ac..4c28e03 100755 --- a/src/sprites/items/Weapon.cpp +++ b/src/sprites/items/Weapon.cpp @@ -38,6 +38,31 @@ Weapon::Weapon(World& world, Character& holder, const Yaml& config) : mRequiresAmmo(!config.get("requires_no_ammo", false)) { } +/** + * Constructs a new instance of the given weapon type and returns it as a + * smart pointer. + */ +std::shared_ptr +Weapon::getWeapon(World& world, Character& holder, WeaponType type) { + switch (type) { + case WeaponType::KNIFE: + return std::shared_ptr(new Weapon(world, holder, Yaml("knife.yaml"))); + case WeaponType::PISTOL: + return std::shared_ptr(new Weapon(world, holder, Yaml("pistol.yaml"))); + case WeaponType::ASSAULT_RIFLE: + return std::shared_ptr(new Weapon(world, holder, Yaml("assault_rifle.yaml"))); + case WeaponType::SHOTGUN: + return std::shared_ptr(new Weapon(world, holder, Yaml("shotgun.yaml"))); + case WeaponType::AUTO_SHOTGUN: + return std::shared_ptr(new Weapon(world, holder, Yaml("auto_shotgun.yaml"))); + case WeaponType::RIFLE: + return std::shared_ptr(new Weapon(world, holder, Yaml("rifle.yaml"))); + case WeaponType::HMG: + return std::shared_ptr(new Weapon(world, holder, Yaml("hmg.yaml"))); + default: return std::shared_ptr(); + } +} + /** * Pull the trigger. */ diff --git a/src/sprites/items/Weapon.h b/src/sprites/items/Weapon.h index 1f30c72..749b2ec 100755 --- a/src/sprites/items/Weapon.h +++ b/src/sprites/items/Weapon.h @@ -24,8 +24,20 @@ class Particle; class Yaml; class Weapon : public Item { +public: + enum class WeaponType { + KNIFE, + PISTOL, + ASSAULT_RIFLE, + SHOTGUN, + AUTO_SHOTGUN, + RIFLE, + HMG + }; + public: explicit Weapon(World& world, Character& holder, const Yaml& config); + static std::shared_ptr getWeapon(World& world, Character& holder, WeaponType type); void pullTrigger(); void releaseTrigger(); diff --git a/src/util/Loader.h b/src/util/Loader.h index bcf717a..c0c129b 100755 --- a/src/util/Loader.h +++ b/src/util/Loader.h @@ -9,8 +9,8 @@ #define DG_LOADER_H_ #include - -#include "../util/Singleton.h" + +#include "Singleton.h" /** * This class allows to set default resource folders and subfolders, which means that these diff --git a/src/util/ResourceManager.h b/src/util/ResourceManager.h index c5514ab..278d228 100644 --- a/src/util/ResourceManager.h +++ b/src/util/ResourceManager.h @@ -7,8 +7,8 @@ #ifndef DG_RESOURCEMANAGER_H_ #define DG_RESOURCEMANAGER_H_ - -#include "../util/Singleton.h" + +#include "Singleton.h" /** * Loads and manages all resources by providing Singleton access to