added files forgotten in last commit

This commit is contained in:
Dave White 2004-03-21 19:33:35 +00:00
parent cb1f13e272
commit a29e9379c6
4 changed files with 600 additions and 0 deletions

291
src/cavegen.cpp Normal file
View 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
View 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
View 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
View 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