added files forgotten in last commit
This commit is contained in:
parent
cb1f13e272
commit
a29e9379c6
4 changed files with 600 additions and 0 deletions
291
src/cavegen.cpp
Normal file
291
src/cavegen.cpp
Normal file
|
@ -0,0 +1,291 @@
|
|||
#include "cavegen.hpp"
|
||||
#include "pathfind.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
cave_map_generator::cave_map_generator(const config& cfg) : wall_('W'), clear_('u'), village_('D'), castle_('C'),
|
||||
cfg_(NULL), width_(50), height_(50)
|
||||
{
|
||||
cfg_ = cfg.find_child("map_generator","name",name());
|
||||
|
||||
if(cfg_ == NULL) {
|
||||
static const config default_cfg;
|
||||
cfg_ = &default_cfg;
|
||||
}
|
||||
|
||||
width_ = atoi((*cfg_)["map_width"].c_str());
|
||||
height_ = atoi((*cfg_)["map_height"].c_str());
|
||||
}
|
||||
|
||||
bool cave_map_generator::allow_user_config() const { return true; }
|
||||
|
||||
void cave_map_generator::user_config(display& disp) { return; }
|
||||
|
||||
std::string cave_map_generator::name() const { return "cave"; }
|
||||
|
||||
std::string cave_map_generator::create_map(const std::vector<std::string>& args)
|
||||
{
|
||||
const config res = create_scenario(args);
|
||||
return res["map_data"];
|
||||
}
|
||||
|
||||
config cave_map_generator::create_scenario(const std::vector<std::string>& args)
|
||||
{
|
||||
map_ = std::vector<std::vector<gamemap::TERRAIN> >(width_,std::vector<gamemap::TERRAIN>(height_,wall_));
|
||||
chambers_.clear();
|
||||
passages_.clear();
|
||||
res_.clear();
|
||||
|
||||
std::cerr << "creating scenario....\n";
|
||||
generate_chambers();
|
||||
|
||||
std::cerr << "placing chambers...\n";
|
||||
for(std::vector<chamber>::const_iterator c = chambers_.begin(); c != chambers_.end(); ++c) {
|
||||
place_chamber(*c);
|
||||
}
|
||||
|
||||
std::cerr << "placing passages...\n";
|
||||
|
||||
for(std::vector<passage>::const_iterator p = passages_.begin(); p != passages_.end(); ++p) {
|
||||
place_passage(*p);
|
||||
}
|
||||
|
||||
std::cerr << "outputting map....\n";
|
||||
std::stringstream out;
|
||||
for(size_t y = 0; y != height_; ++y) {
|
||||
for(size_t x = 0; x != width_; ++x) {
|
||||
out << map_[x][y];
|
||||
}
|
||||
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
res_["map_data"] = out.str();
|
||||
|
||||
std::cerr << "returning result...\n";
|
||||
|
||||
return res_;
|
||||
}
|
||||
|
||||
void cave_map_generator::build_chamber(gamemap::location loc, std::set<gamemap::location>& locs, size_t size, size_t jagged)
|
||||
{
|
||||
if(size == 0 || locs.count(loc) != 0 || !on_board(loc))
|
||||
return;
|
||||
|
||||
locs.insert(loc);
|
||||
|
||||
gamemap::location adj[6];
|
||||
get_adjacent_tiles(loc,adj);
|
||||
for(size_t n = 0; n != 6; ++n) {
|
||||
if((rand()%100) < (100-jagged)) {
|
||||
build_chamber(adj[n],locs,size-1,jagged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cave_map_generator::generate_chambers()
|
||||
{
|
||||
const config::child_list& chambers = cfg_->get_children("chamber");
|
||||
for(config::child_list::const_iterator i = chambers.begin(); i != chambers.end(); ++i) {
|
||||
//if there is only a chance of the chamber appearing, deal with that here.
|
||||
const std::string& chance = (**i)["chance"];
|
||||
if(chance != "" && (rand()%100) < atoi(chance.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& xpos = (**i)["x"];
|
||||
const std::string& ypos = (**i)["y"];
|
||||
|
||||
size_t min_xpos = 0, min_ypos = 0, max_xpos = width_, max_ypos = height_;
|
||||
|
||||
if(xpos != "") {
|
||||
const std::vector<std::string>& items = config::split(xpos,'-');
|
||||
if(items.empty() == false) {
|
||||
min_xpos = atoi(items.front().c_str()) - 1;
|
||||
max_xpos = atoi(items.back().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if(ypos != "") {
|
||||
const std::vector<std::string>& items = config::split(ypos,'-');
|
||||
if(items.empty() == false) {
|
||||
min_ypos = atoi(items.front().c_str()) - 1;
|
||||
max_ypos = atoi(items.back().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
const size_t x = min_xpos + (rand()%(max_xpos-min_xpos));
|
||||
const size_t y = min_ypos + (rand()%(max_ypos-min_ypos));
|
||||
|
||||
const std::string& size = (**i)["size"];
|
||||
size_t chamber_size = 3;
|
||||
if(size != "") {
|
||||
chamber_size = atoi(size.c_str());
|
||||
}
|
||||
|
||||
const std::string& jagged = (**i)["jagged"];
|
||||
size_t jagged_edges = 0;
|
||||
if(jagged != "") {
|
||||
jagged_edges = atoi(jagged.c_str());
|
||||
}
|
||||
|
||||
chamber new_chamber;
|
||||
new_chamber.center = gamemap::location(x,y);
|
||||
build_chamber(new_chamber.center,new_chamber.locs,chamber_size,jagged_edges);
|
||||
|
||||
new_chamber.items = (**i).child("items");
|
||||
|
||||
const std::string& id = (**i)["id"];
|
||||
if(id != "") {
|
||||
chamber_ids_[id] = chambers_.size();
|
||||
}
|
||||
|
||||
chambers_.push_back(new_chamber);
|
||||
|
||||
const config::child_list& passages = (**i).get_children("passage");
|
||||
for(config::child_list::const_iterator p = passages.begin(); p != passages.end(); ++p) {
|
||||
const std::string& dst = (**p)["destination"];
|
||||
|
||||
//find the destination of this passage
|
||||
const std::map<std::string,size_t>::const_iterator itor = chamber_ids_.find(dst);
|
||||
if(itor == chamber_ids_.end())
|
||||
continue;
|
||||
|
||||
assert(itor->second < chambers_.size());
|
||||
|
||||
passages_.push_back(passage(new_chamber.center,chambers_[itor->second].center,**p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cave_map_generator::place_chamber(const chamber& c)
|
||||
{
|
||||
for(std::set<gamemap::location>::const_iterator i = c.locs.begin(); i != c.locs.end(); ++i) {
|
||||
set_terrain(*i,clear_);
|
||||
}
|
||||
|
||||
if(c.items != NULL) {
|
||||
place_items(c,c.items->ordered_begin(),c.items->ordered_end());
|
||||
}
|
||||
}
|
||||
|
||||
void cave_map_generator::place_items(const chamber& c, config::all_children_iterator i1, config::all_children_iterator i2)
|
||||
{
|
||||
if(c.locs.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
while(i1 != i2) {
|
||||
const std::string& key = *(*i1).first;
|
||||
config cfg = *(*i1).second;
|
||||
if(cfg["same_location_as_previous"] != "yes") {
|
||||
index = rand()%c.locs.size();
|
||||
}
|
||||
|
||||
std::set<gamemap::location>::const_iterator loc = c.locs.begin();
|
||||
std::advance(loc,index);
|
||||
|
||||
char buf[50];
|
||||
sprintf(buf,"%d",loc->x+1);
|
||||
cfg.values["x"] = buf;
|
||||
|
||||
sprintf(buf,"%d",loc->y+1);
|
||||
cfg.values["y"] = buf;
|
||||
|
||||
//if this is a side, place a castle for the side
|
||||
if(key == "side" && cfg["no_castle"] != "yes") {
|
||||
place_castle(cfg["side"],*loc);
|
||||
}
|
||||
|
||||
res_.add_child(key,cfg);
|
||||
|
||||
++i1;
|
||||
}
|
||||
}
|
||||
|
||||
struct passage_path_calculator
|
||||
{
|
||||
passage_path_calculator(const std::vector<std::vector<gamemap::TERRAIN> >& mapdata, gamemap::TERRAIN wall, double laziness, size_t windiness)
|
||||
: map_(mapdata), wall_(wall), laziness_(laziness), windiness_(windiness)
|
||||
{}
|
||||
|
||||
double cost(const gamemap::location& loc, double so_far) const;
|
||||
private:
|
||||
const std::vector<std::vector<gamemap::TERRAIN> >& map_;
|
||||
gamemap::TERRAIN wall_;
|
||||
double laziness_;
|
||||
size_t windiness_;
|
||||
};
|
||||
|
||||
double passage_path_calculator::cost(const gamemap::location& loc, double so_far) const
|
||||
{
|
||||
if(loc.x < 0 || loc.y < 0 || size_t(loc.x) >= map_.size() || map_.empty() || size_t(loc.y) >= map_.front().size()) {
|
||||
return 100000.0;
|
||||
}
|
||||
|
||||
double res = 1.0;
|
||||
if(map_[loc.x][loc.y] == wall_) {
|
||||
res = laziness_;
|
||||
}
|
||||
|
||||
if(windiness_ > 1) {
|
||||
res *= double(rand()%windiness_);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void cave_map_generator::place_passage(const passage& p)
|
||||
{
|
||||
const std::string& chance = p.cfg["chance"];
|
||||
if(chance != "" && (rand()%100) < atoi(chance.c_str())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const size_t windiness = atoi(p.cfg["windiness"].c_str());
|
||||
const double laziness = maximum<double>(1.0,atof(p.cfg["laziness"].c_str()));
|
||||
|
||||
passage_path_calculator calc(map_,wall_,laziness,windiness);
|
||||
|
||||
const paths::route rt = a_star_search(p.src,p.dst,10000.0,calc);
|
||||
|
||||
const size_t width = maximum<size_t>(1,atoi(p.cfg["width"].c_str()));
|
||||
const size_t jagged = atoi(p.cfg["jagged"].c_str());
|
||||
|
||||
for(std::vector<gamemap::location>::const_iterator i = rt.steps.begin(); i != rt.steps.end(); ++i) {
|
||||
std::set<gamemap::location> locs;
|
||||
build_chamber(*i,locs,width,jagged);
|
||||
for(std::set<gamemap::location>::const_iterator j = locs.begin(); j != locs.end(); ++j) {
|
||||
set_terrain(*j,clear_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cave_map_generator::on_board(const gamemap::location& loc) const
|
||||
{
|
||||
return loc.x >= 0 && loc.y >= 0 && loc.x < width_ && loc.y < height_;
|
||||
}
|
||||
|
||||
void cave_map_generator::set_terrain(gamemap::location loc, gamemap::TERRAIN t)
|
||||
{
|
||||
if(on_board(loc)) {
|
||||
gamemap::TERRAIN& c = map_[loc.x][loc.y];
|
||||
if(c == clear_ || c == wall_) {
|
||||
c = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cave_map_generator::place_castle(const std::string& side, gamemap::location loc)
|
||||
{
|
||||
if(side != "") {
|
||||
set_terrain(loc,side[0]);
|
||||
}
|
||||
|
||||
gamemap::location adj[6];
|
||||
get_adjacent_tiles(loc,adj);
|
||||
for(size_t n = 0; n != 6; ++n) {
|
||||
set_terrain(adj[n],castle_);
|
||||
}
|
||||
}
|
59
src/cavegen.hpp
Normal file
59
src/cavegen.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef CAVEGEN_HPP_INCLUDED
|
||||
#define CAVEGEN_HPP_INCLUDED
|
||||
|
||||
#include "mapgen.hpp"
|
||||
|
||||
class cave_map_generator : public map_generator
|
||||
{
|
||||
public:
|
||||
cave_map_generator(const config& game_config);
|
||||
|
||||
bool allow_user_config() const;
|
||||
void user_config(display& disp);
|
||||
|
||||
std::string name() const;
|
||||
|
||||
std::string create_map(const std::vector<std::string>& args);
|
||||
config create_scenario(const std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
|
||||
struct chamber {
|
||||
gamemap::location center;
|
||||
std::set<gamemap::location> locs;
|
||||
config* items;
|
||||
};
|
||||
|
||||
struct passage {
|
||||
passage(gamemap::location s, gamemap::location d, const config& c)
|
||||
: src(s), dst(d), cfg(c)
|
||||
{}
|
||||
gamemap::location src, dst;
|
||||
config cfg;
|
||||
};
|
||||
|
||||
void generate_chambers();
|
||||
void build_chamber(gamemap::location loc, std::set<gamemap::location>& locs, size_t size, size_t jagged);
|
||||
|
||||
void place_chamber(const chamber& c);
|
||||
void place_items(const chamber& c, config::all_children_iterator i1, config::all_children_iterator i2);
|
||||
|
||||
void place_passage(const passage& p);
|
||||
|
||||
bool on_board(const gamemap::location& loc) const;
|
||||
void set_terrain(gamemap::location loc, gamemap::TERRAIN t);
|
||||
void place_castle(const std::string& side, gamemap::location loc);
|
||||
|
||||
gamemap::TERRAIN wall_, clear_, village_, castle_;
|
||||
std::vector<std::vector<gamemap::TERRAIN> > map_;
|
||||
|
||||
std::map<std::string,size_t> chamber_ids_;
|
||||
std::vector<chamber> chambers_;
|
||||
std::vector<passage> passages_;
|
||||
|
||||
config res_;
|
||||
const config* cfg_;
|
||||
size_t width_, height_;
|
||||
};
|
||||
|
||||
#endif
|
182
src/statistics.cpp
Normal file
182
src/statistics.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
#include "statistics.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef statistics::stats stats;
|
||||
|
||||
struct scenario_stats
|
||||
{
|
||||
scenario_stats(const std::string& name) : scenario_name(name)
|
||||
{}
|
||||
|
||||
std::vector<stats> team_stats;
|
||||
std::string scenario_name;
|
||||
};
|
||||
|
||||
std::vector<scenario_stats> master_stats;
|
||||
|
||||
stats& get_stats(int team)
|
||||
{
|
||||
if(master_stats.empty()) {
|
||||
master_stats.push_back(scenario_stats(""));
|
||||
}
|
||||
|
||||
std::vector<stats>& team_stats = master_stats.back().team_stats;
|
||||
const size_t index = size_t(team-1);
|
||||
if(index >= team_stats.size()) {
|
||||
team_stats.resize(index+1);
|
||||
}
|
||||
|
||||
return team_stats[index];
|
||||
}
|
||||
|
||||
void merge_str_int_map(stats::str_int_map& a, const stats::str_int_map& b)
|
||||
{
|
||||
for(stats::str_int_map::const_iterator i = b.begin(); i != b.end(); ++i) {
|
||||
a[i->first] += i->second;
|
||||
}
|
||||
}
|
||||
|
||||
void merge_battle_result_maps(stats::battle_result_map& a, const stats::battle_result_map& b)
|
||||
{
|
||||
for(stats::battle_result_map::const_iterator i = b.begin(); i != b.end(); ++i) {
|
||||
merge_str_int_map(a[i->first],i->second);
|
||||
}
|
||||
}
|
||||
|
||||
void merge_stats(stats& a, const stats& b)
|
||||
{
|
||||
merge_str_int_map(a.recruits,b.recruits);
|
||||
merge_str_int_map(a.recalls,b.recalls);
|
||||
merge_str_int_map(a.advanced_to,b.advanced_to);
|
||||
merge_str_int_map(a.deaths,b.deaths);
|
||||
merge_str_int_map(a.killed,b.killed);
|
||||
|
||||
merge_battle_result_maps(a.attacks,b.attacks);
|
||||
merge_battle_result_maps(a.defends,b.defends);
|
||||
|
||||
a.recruit_cost += b.recruit_cost;
|
||||
a.recall_cost += b.recall_cost;
|
||||
a.damage_inflicted += b.damage_inflicted;
|
||||
a.damage_taken += b.damage_taken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace statistics
|
||||
{
|
||||
|
||||
stats::stats() : recruit_cost(0), recall_cost(0), damage_inflicted(0), damage_taken(0)
|
||||
{}
|
||||
|
||||
scenario_context::scenario_context(const std::string& name)
|
||||
{
|
||||
master_stats.push_back(scenario_stats(name));
|
||||
}
|
||||
|
||||
scenario_context::~scenario_context()
|
||||
{
|
||||
}
|
||||
|
||||
attack_context::attack_context(const unit& a, const unit& d, const battle_stats& stats)
|
||||
: attacker_type(a.type().name()), defender_type(d.type().name()),
|
||||
bat_stats(stats), attacker_side(a.side()), defender_side(d.side())
|
||||
{
|
||||
}
|
||||
|
||||
attack_context::~attack_context()
|
||||
{
|
||||
attacker_stats().attacks[bat_stats.chance_to_hit_defender][attacker_res]++;
|
||||
defender_stats().defends[bat_stats.chance_to_hit_attacker][defender_res]++;
|
||||
}
|
||||
|
||||
stats& attack_context::attacker_stats()
|
||||
{
|
||||
return get_stats(attacker_side);
|
||||
}
|
||||
|
||||
stats& attack_context::defender_stats()
|
||||
{
|
||||
return get_stats(defender_side);
|
||||
}
|
||||
|
||||
void attack_context::attack_result(attack_context::ATTACK_RESULT res)
|
||||
{
|
||||
attacker_res.resize(attacker_res.size()+1);
|
||||
attacker_res[attacker_res.size()-1] = (res == MISSES ? '0' : '1');
|
||||
|
||||
attacker_stats().damage_inflicted += bat_stats.damage_defender_takes;
|
||||
defender_stats().damage_taken += bat_stats.damage_defender_takes;
|
||||
|
||||
if(res == KILLS) {
|
||||
attacker_stats().killed[defender_type]++;
|
||||
defender_stats().deaths[attacker_type]++;
|
||||
}
|
||||
}
|
||||
|
||||
void attack_context::defend_result(attack_context::ATTACK_RESULT res)
|
||||
{
|
||||
defender_res.resize(defender_res.size()+1);
|
||||
defender_res[defender_res.size()-1] = (res == MISSES ? '0' : '1');
|
||||
|
||||
attacker_stats().damage_taken += bat_stats.damage_attacker_takes;
|
||||
defender_stats().damage_inflicted += bat_stats.damage_defender_takes;
|
||||
|
||||
if(res == KILLS) {
|
||||
attacker_stats().deaths[defender_type]++;
|
||||
defender_stats().killed[attacker_type]++;
|
||||
}
|
||||
}
|
||||
|
||||
void recruit_unit(const unit& u)
|
||||
{
|
||||
stats& s = get_stats(u.side());
|
||||
s.recruits[u.type().name()]++;
|
||||
s.recruit_cost += u.type().cost();
|
||||
}
|
||||
|
||||
void recall_unit(const unit& u)
|
||||
{
|
||||
stats& s = get_stats(u.side());
|
||||
s.recalls[u.type().name()]++;
|
||||
s.recall_cost += u.type().cost();
|
||||
}
|
||||
|
||||
void advance_unit(const unit& u)
|
||||
{
|
||||
stats& s = get_stats(u.side());
|
||||
s.advanced_to[u.type().name()]++;
|
||||
}
|
||||
|
||||
std::vector<std::string> get_categories()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
res.push_back("all_statistics");
|
||||
for(std::vector<scenario_stats>::const_iterator i = master_stats.begin(); i != master_stats.end(); ++i) {
|
||||
res.push_back(i->scenario_name);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
stats calculate_stats(int category, int side)
|
||||
{
|
||||
if(category == 0) {
|
||||
stats res;
|
||||
for(int i = 1; i <= int(master_stats.size()); ++i) {
|
||||
merge_stats(res,calculate_stats(i,side));
|
||||
}
|
||||
|
||||
return res;
|
||||
} else {
|
||||
const size_t index = master_stats.size() - size_t(side);
|
||||
const size_t side_index = size_t(side) - 1;
|
||||
if(index < master_stats.size() && side_index < master_stats[index].team_stats.size()) {
|
||||
return master_stats[index].team_stats[side_index];
|
||||
} else {
|
||||
return stats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
68
src/statistics.hpp
Normal file
68
src/statistics.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef STATISTICS_HPP_INCLUDED
|
||||
#define STATISTICS_HPP_INCLUDED
|
||||
|
||||
#include "actions.hpp"
|
||||
#include "unit.hpp"
|
||||
|
||||
namespace statistics
|
||||
{
|
||||
struct stats
|
||||
{
|
||||
stats();
|
||||
|
||||
typedef std::map<std::string,int> str_int_map;
|
||||
str_int_map recruits, recalls, advanced_to, deaths, killed;
|
||||
int recruit_cost, recall_cost;
|
||||
|
||||
//a type that will map a string of hit/miss to the number of times
|
||||
//that sequence has occurred
|
||||
typedef str_int_map battle_sequence_frequency_map;
|
||||
|
||||
//a type that will map different % chances to hit to different results
|
||||
typedef std::map<int,battle_sequence_frequency_map> battle_result_map;
|
||||
|
||||
battle_result_map attacks, defends;
|
||||
|
||||
int damage_inflicted, damage_taken;
|
||||
};
|
||||
|
||||
struct scenario_context
|
||||
{
|
||||
scenario_context(const std::string& name);
|
||||
~scenario_context();
|
||||
};
|
||||
|
||||
struct attack_context
|
||||
{
|
||||
attack_context(const unit& a, const unit& d, const battle_stats& stats);
|
||||
~attack_context();
|
||||
|
||||
enum ATTACK_RESULT { MISSES, HITS, KILLS };
|
||||
|
||||
void attack_result(ATTACK_RESULT res);
|
||||
void defend_result(ATTACK_RESULT res);
|
||||
|
||||
private:
|
||||
|
||||
std::string attacker_type, defender_type;
|
||||
battle_stats bat_stats;
|
||||
int attacker_side, defender_side;
|
||||
std::string attacker_res, defender_res;
|
||||
|
||||
stats& attacker_stats();
|
||||
stats& defender_stats();
|
||||
};
|
||||
|
||||
void recruit_unit(const unit& u);
|
||||
void recall_unit(const unit& u);
|
||||
|
||||
void advance_unit(const unit& u);
|
||||
|
||||
config write_stats(int team);
|
||||
void read_stats(int team, const config& cfg);
|
||||
|
||||
std::vector<std::string> get_categories();
|
||||
stats calculate_stats(int category, int side);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue