282 lines
8.4 KiB
C++
282 lines
8.4 KiB
C++
#include "level.h"
|
|
|
|
#include "constants.h"
|
|
|
|
level::level(character *player, RNG *rng, const feature enabled_features):
|
|
enabled_features{enabled_features}, map{player, rng, enabled_features},
|
|
player{player} {
|
|
auto tiles = map.get_room_list();
|
|
|
|
for (size_t i = 0; i < tiles.size(); ++i)
|
|
remove_from_list(tiles[i], player->get_pos());
|
|
|
|
for (size_t i = 0; i < tiles.size(); ++i)
|
|
remove_from_list(tiles[i], map.get_down_stairs());
|
|
|
|
if (enabled_features & FEATURE_REVISIT)
|
|
for (size_t i = 0; i < tiles.size(); ++i)
|
|
remove_from_list(tiles[i], map.get_up_stairs());
|
|
|
|
gen_potions(rng, tiles);
|
|
gen_gold(rng, tiles);
|
|
gen_enemies(rng, tiles);
|
|
}
|
|
|
|
level::level(const std::string &map_data, character *player, RNG *rng,
|
|
const feature enabled_features):
|
|
enabled_features{enabled_features},
|
|
map{player, map_data, rng, enabled_features}, player{player} {
|
|
auto tiles = map.get_room_list();
|
|
|
|
for (size_t i = 0; i < tiles.size(); ++i)
|
|
remove_from_list(tiles[i], player->get_pos());
|
|
|
|
for (size_t i = 0; i < tiles.size(); ++i)
|
|
remove_from_list(tiles[i], map.get_down_stairs());
|
|
|
|
if (enabled_features & FEATURE_REVISIT)
|
|
for (size_t i = 0; i < tiles.size(); ++i)
|
|
remove_from_list(tiles[i], map.get_up_stairs());
|
|
|
|
gen_potions(rng, tiles);
|
|
gen_gold(rng, tiles);
|
|
gen_enemies(rng, tiles);
|
|
}
|
|
|
|
gold_list level::dragon_hoard() {
|
|
gold_list result;
|
|
|
|
for (auto g : glist)
|
|
if (g.amount == GOLD_DRAGON)
|
|
result.push_back({g.amount, g.pos});
|
|
return result;
|
|
}
|
|
|
|
void level::gen_enemies(RNG *rng, std::vector<position_list> &tiles) {
|
|
auto dhoard = dragon_hoard();
|
|
int cnt = enabled_features & FEATURE_EXTRA_STUFF ?
|
|
rng->rand_between(MIN_ENEMIE_CNT, MAX_ENEMIE_CNT + 1) :
|
|
MIN_ENEMIE_CNT + dhoard.size();
|
|
|
|
elist.reserve(cnt);
|
|
pelist.reserve(cnt);
|
|
|
|
for (size_t i = 0; i < dhoard.size(); ++i) {
|
|
position_list spots;
|
|
|
|
for (int dir = 0; dir < DIRECTION_CNT; ++dir) {
|
|
position tmp = dhoard[i].pos + MOVE[dir];
|
|
|
|
if (map.which_room(tmp) != -1)
|
|
spots.push_back(dhoard[i].pos + MOVE[dir]);
|
|
}
|
|
|
|
auto pos = spots.size() ? rng->get_rand_in_vector(spots) :
|
|
dhoard[i].pos;
|
|
pelist.push_back(new_dragon(rng, pos, dhoard[i].pos,
|
|
enabled_features,
|
|
map.which_room(dhoard[i].pos)));
|
|
int room = map.which_room(pos);
|
|
remove_from_list(tiles[room], pos);
|
|
|
|
if (!tiles[room].size())
|
|
tiles.erase(tiles.begin() + room);
|
|
|
|
elist.push_back(pelist[i].get());
|
|
}
|
|
|
|
|
|
for (int i = dhoard.size(); i < cnt; ++i) {
|
|
auto p = get_rand_pos(rng, tiles);
|
|
pelist.push_back(new_enemy(rng, p, enabled_features,
|
|
map.which_room(p)));
|
|
elist.push_back(pelist[i].get());
|
|
}
|
|
}
|
|
|
|
position level::get_rand_pos(RNG *rng, std::vector<position_list> &tiles) {
|
|
int room;
|
|
position pos;
|
|
room = rng->rand_under(tiles.size());
|
|
|
|
pos = rng->get_rand_in_vector(tiles[room]);
|
|
remove_from_list(tiles[room], pos);
|
|
|
|
if (!tiles[room].size())
|
|
tiles.erase(tiles.begin() + room);
|
|
|
|
return pos;
|
|
}
|
|
|
|
void level::add_gold(gold g) {
|
|
glist.push_back(g);
|
|
}
|
|
|
|
void level::gen_gold(RNG *rng, std::vector<position_list> &tiles) {
|
|
glist.reserve(GOLD_CNT);
|
|
|
|
for (int i = 0; i < GOLD_CNT; ++i)
|
|
glist.push_back({rand_gold_pile(rng), get_rand_pos(rng, tiles)});
|
|
}
|
|
|
|
void level::gen_potions(RNG *rng, std::vector<position_list> &tiles) {
|
|
int cnt;
|
|
int max_type;
|
|
|
|
if (enabled_features & FEATURE_EXTRA_STUFF) {
|
|
cnt = rng->rand_between(MIN_POTION_CNT, MAX_POTION_CNT + 1);
|
|
max_type = POTION_TYPE_CNT;
|
|
} else {
|
|
cnt = MIN_POTION_CNT;
|
|
max_type = DEFAULT_POTION_TYPE_CNT;
|
|
}
|
|
|
|
plist.reserve(cnt);
|
|
pplist.reserve(cnt);
|
|
|
|
for (int i = 0; i < cnt; ++i) {
|
|
pplist.push_back(new_potion((potion_type)rng->rand_under(max_type),
|
|
get_rand_pos(rng, tiles)));
|
|
plist.push_back(pplist[i].get());
|
|
}
|
|
}
|
|
|
|
void level::print(output *out) const {
|
|
map.print(out);
|
|
|
|
for (size_t i = 0; i < plist.size(); ++i)
|
|
plist[i]->print(out);
|
|
|
|
for (size_t i = 0; i < glist.size(); ++i)
|
|
out->print_char(glist[i].pos, 'G', COLOR_PAIR(COLOR_YELLOW));
|
|
|
|
for (size_t i = 0; i < elist.size(); ++i)
|
|
elist[i]->print(out);
|
|
}
|
|
|
|
bool level::is_available(const position &pos, bool is_player) const {
|
|
if (!map.is_available(pos))
|
|
return false;
|
|
|
|
if (player->get_pos() == pos)
|
|
return false;
|
|
|
|
for (size_t i = 0; i < elist.size(); ++i)
|
|
if (pos == elist[i]->get_pos())
|
|
return false;
|
|
|
|
if (!(enabled_features & FEATURE_WALK_OVER))
|
|
for (size_t i = 0; i < plist.size(); ++i)
|
|
if (pos == plist[i]->get_pos())
|
|
return false;
|
|
|
|
if (!(enabled_features & FEATURE_WALK_OVER) && !is_player)
|
|
for (size_t i = 0; i < glist.size(); ++i)
|
|
if (pos == glist[i].pos)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool level::is_available_all(const position &pos) const {
|
|
if (!map.is_available(pos))
|
|
return false;
|
|
|
|
if (!(enabled_features & FEATURE_DOORS) &&
|
|
map.which_room(pos) == -1)
|
|
return false;
|
|
|
|
if (player->get_pos() == pos)
|
|
return false;
|
|
|
|
for (size_t i = 0; i < elist.size(); ++i)
|
|
if (pos == elist[i]->get_pos())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < plist.size(); ++i)
|
|
if (pos == plist[i]->get_pos())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < glist.size(); ++i)
|
|
if (pos == glist[i].pos)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int level::get_room(const position &pos) const {
|
|
return map.which_room(pos);
|
|
}
|
|
|
|
position_list level::get_available_around(const position &pos) const {
|
|
position_list result;
|
|
|
|
for (int i = 0; i < DIRECTION_CNT; ++i)
|
|
if (is_available(pos + MOVE[i]))
|
|
result.push_back(pos + MOVE[i]);
|
|
|
|
return result;
|
|
}
|
|
|
|
position_list level::get_available_around_all(const position &pos) const {
|
|
position_list result;
|
|
|
|
for (int i = 0; i < DIRECTION_CNT; ++i)
|
|
if (is_available_all(pos + MOVE[i]))
|
|
result.push_back(pos + MOVE[i]);
|
|
|
|
return result;
|
|
}
|
|
|
|
position level::get_up_stairs() const {
|
|
return map.get_up_stairs();
|
|
}
|
|
|
|
position level::get_down_stairs() const {
|
|
return map.get_down_stairs();
|
|
}
|
|
|
|
const enemy_list &level::get_elist() {
|
|
return elist;
|
|
}
|
|
|
|
const potion_list &level::get_plist() {
|
|
return plist;
|
|
}
|
|
|
|
gold_list &level::get_glist() {
|
|
return glist;
|
|
}
|
|
|
|
std::unique_ptr<potion> level::detach_potion(size_t idx) {
|
|
if (idx >= plist.size())
|
|
return nullptr;
|
|
|
|
auto tmp = std::move(pplist[idx]);
|
|
plist.erase(plist.begin() + idx);
|
|
pplist.erase(pplist.begin() + idx);
|
|
return tmp;
|
|
}
|
|
|
|
void level::erase_enemy(character *ch) {
|
|
if (ch == nullptr)
|
|
return;
|
|
|
|
for (size_t i = 0; i < elist.size(); ++i)
|
|
if (elist[i] == ch) {
|
|
elist.erase(elist.begin() + i);
|
|
pelist.erase(pelist.begin() + i);
|
|
}
|
|
}
|
|
|
|
size_t level::what_is_at(const position &pos) const {
|
|
if (!map.is_available(pos))
|
|
return WHAT_WALL;
|
|
|
|
for (size_t i = 0; i < plist.size(); ++i)
|
|
if (plist[i]->get_pos() == pos)
|
|
return WHAT_ENEMY | i;
|
|
|
|
return WHAT_SPACE;
|
|
}
|