Added possibility to use per fight EV statistics proposed by maboul
Fixed possible cause for client disconnects when having bad connection Cleaned up game config reading code minor code cleanups
This commit is contained in:
parent
9adac709e8
commit
859958b006
8 changed files with 168 additions and 91 deletions
|
@ -57,6 +57,7 @@ opts.AddOptions(
|
|||
BoolOption('profile', 'Set to build for profiling', False),
|
||||
('program_suffix', 'suffix to append to names of installed programs',""),
|
||||
BoolOption('python', 'Enable in-game python extensions.', True),
|
||||
BoolOption('maboul_stats', 'Enable alternative excpeted damage calculations', False),
|
||||
BoolOption('raw_sockets', 'Set to use raw receiving sockets in the multiplayer network layer rather than the SDL_net facilities', False),
|
||||
('server_gid', 'group id of the user who runs wesnothd', ""),
|
||||
('server_uid', 'user id of the user who runs wesnothd', ""),
|
||||
|
@ -239,6 +240,9 @@ if env['internal_data']:
|
|||
if env['python']:
|
||||
env.Append(CPPDEFINES = "HAVE_PYTHON")
|
||||
|
||||
if env['maboul_stats']:
|
||||
env.Append(CPPDEFINES = "MABOUL_STATS")
|
||||
|
||||
if sys.platform != "win32":
|
||||
if env['prefsdir']:
|
||||
env.Append(CPPDEFINES = "PREFERENCES_DIR='\"%s\"'" % env['prefsdir'] )
|
||||
|
|
|
@ -41,8 +41,9 @@ Version 1.5.0+svn:
|
|||
* fixed multiplayer_connect to handle leave_game command from server
|
||||
* improved reloading of game configs after installing or removing addons
|
||||
* fixed threading bug in upload_logs
|
||||
* dissallow_observers is forced on if side has controller=null
|
||||
* dissallow_observers is on as default if side has controller=null
|
||||
* Fixed null-pointer reference in network code
|
||||
* Added possibility to use per fight EV statistics proposed by maboul
|
||||
* Removed bug introduced in 1.5.0 that allowed use of :debug commands during
|
||||
network play
|
||||
* added some includes to fix compilation problems with Sun Studio 12
|
||||
|
|
|
@ -917,6 +917,19 @@ attack::attack(game_display& gui, const gamemap& map,
|
|||
DBG_NG << "getting attack statistics\n";
|
||||
statistics::attack_context attack_stats(a_->second, d_->second, a_stats_->chance_to_hit, d_stats_->chance_to_hit);
|
||||
|
||||
#ifdef MABOUL_STATS
|
||||
{
|
||||
// Calculate stats for battle
|
||||
combatant attacker(bc_->get_attacker_stats());
|
||||
combatant defender(bc_->get_defender_stats());
|
||||
attacker.fight(defender);
|
||||
const double attacker_inflict = static_cast<double>(d_->second.hitpoints()) - defender.average_hp();
|
||||
const double defender_inflict = static_cast<double>(a_->second.hitpoints()) - attacker.average_hp();
|
||||
|
||||
attack_stats.attack_excepted_damage(attacker_inflict,defender_inflict);
|
||||
}
|
||||
#endif
|
||||
|
||||
orig_attacks_ = a_stats_->num_blows;
|
||||
orig_defends_ = d_stats_->num_blows;
|
||||
n_attacks_ = orig_attacks_;
|
||||
|
@ -1010,10 +1023,13 @@ attack::attack(game_display& gui, const gamemap& map,
|
|||
*a_stats_->weapon,d_stats_->weapon,
|
||||
abs_n_attack_,float_text,a_stats_->drains,"");
|
||||
}
|
||||
|
||||
const int drains_damage = a_stats_->drains ? damage_defender_takes / 2 : 0;
|
||||
const int damage_done = minimum<int>(d_->second.hitpoints(), damage_defender_takes);
|
||||
bool dies = d_->second.take_hit(damage_defender_takes);
|
||||
LOG_NG << "defender took " << damage_defender_takes << (dies ? " and died" : "") << "\n";
|
||||
attack_stats.attack_result(hits ? (dies ? statistics::attack_context::KILLS : statistics::attack_context::HITS)
|
||||
: statistics::attack_context::MISSES, attacker_damage_);
|
||||
: statistics::attack_context::MISSES, damage_done,drains_damage);
|
||||
|
||||
if(ran_results == NULL) {
|
||||
log_scope2(engine, "setting random results");
|
||||
|
@ -1261,6 +1277,8 @@ attack::attack(game_display& gui, const gamemap& map,
|
|||
*d_stats_->weapon,a_stats_->weapon,
|
||||
abs_n_defend_,float_text,d_stats_->drains,"");
|
||||
}
|
||||
const int drains_damage = d_stats_->drains ? damage_attacker_takes / 2 : 0;
|
||||
const int damage_done = minimum<int>(a_->second.hitpoints(), damage_attacker_takes);
|
||||
bool dies = a_->second.take_hit(damage_attacker_takes);
|
||||
LOG_NG << "attacker took " << damage_attacker_takes << (dies ? " and died" : "") << "\n";
|
||||
if(dies) {
|
||||
|
@ -1305,7 +1323,7 @@ attack::attack(game_display& gui, const gamemap& map,
|
|||
refresh_bc();
|
||||
}
|
||||
attack_stats.defend_result(hits ? (dies ? statistics::attack_context::KILLS : statistics::attack_context::HITS)
|
||||
: statistics::attack_context::MISSES, defender_damage_);
|
||||
: statistics::attack_context::MISSES, damage_done, drains_damage);
|
||||
if(hits || dies){
|
||||
int amount_drained = d_stats_->drains ? defender_damage_ / 2 : 0;
|
||||
|
||||
|
|
181
src/game.cpp
181
src/game.cpp
|
@ -117,6 +117,7 @@ public:
|
|||
void reset_game_cfg();
|
||||
void reset_defines_map();
|
||||
void reload_changed_game_config();
|
||||
void read_configs(std::string&);
|
||||
|
||||
bool is_loading() const;
|
||||
bool load_game();
|
||||
|
@ -1751,6 +1752,91 @@ void game_controller::show_upload_begging()
|
|||
disp().redraw_everything();
|
||||
}
|
||||
|
||||
|
||||
void game_controller::read_configs(std::string& error_log)
|
||||
{
|
||||
preproc_map defines_map(defines_map_);
|
||||
|
||||
std::string user_error_log;
|
||||
//read the file and then write to the cache
|
||||
scoped_istream stream = preprocess_file("data/", &defines_map, &error_log);
|
||||
|
||||
//reset the parse counter before reading the game files
|
||||
if (loadscreen::global_loadscreen) {
|
||||
loadscreen::global_loadscreen->parser_counter = 0;
|
||||
}
|
||||
|
||||
read(game_config_, *stream, &error_log);
|
||||
|
||||
//load usermade add-ons
|
||||
const std::string user_campaign_dir = get_user_data_dir() + "/data/campaigns/";
|
||||
std::vector<std::string> user_campaigns, error_campaigns;
|
||||
get_files_in_dir(user_campaign_dir,NULL,&user_campaigns,ENTIRE_FILE_PATH);
|
||||
for(std::vector<std::string>::const_iterator uc = user_campaigns.begin(); uc != user_campaigns.end(); ++uc) {
|
||||
std::string oldstyle_cfg = *uc + ".cfg";
|
||||
std::string main_cfg = *uc + "/_main.cfg";
|
||||
std::string toplevel;
|
||||
if (file_exists(oldstyle_cfg))
|
||||
toplevel = oldstyle_cfg;
|
||||
else if (file_exists(main_cfg))
|
||||
toplevel = main_cfg;
|
||||
else
|
||||
continue;
|
||||
|
||||
try {
|
||||
preproc_map user_defines_map(defines_map);
|
||||
scoped_istream stream = preprocess_file(toplevel, &user_defines_map);
|
||||
|
||||
std::string campaign_error_log;
|
||||
|
||||
config user_campaign_cfg;
|
||||
read(user_campaign_cfg,*stream,&campaign_error_log);
|
||||
|
||||
if(campaign_error_log.empty()) {
|
||||
game_config_.append(user_campaign_cfg);
|
||||
} else {
|
||||
user_error_log += campaign_error_log;
|
||||
error_campaigns.push_back(*uc);
|
||||
}
|
||||
} catch(config::error& err) {
|
||||
ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
|
||||
error_campaigns.push_back(*uc);
|
||||
|
||||
user_error_log += err.message + "\n";
|
||||
} catch(preproc_config::error&) {
|
||||
ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
|
||||
error_campaigns.push_back(*uc);
|
||||
//no need to modify the error log here, already done by the preprocessor
|
||||
|
||||
} catch(io_exception&) {
|
||||
ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
|
||||
error_campaigns.push_back(*uc);
|
||||
}
|
||||
}
|
||||
|
||||
if(error_campaigns.empty() == false) {
|
||||
std::stringstream msg;
|
||||
msg << _n("The following add-on had errors and could not be loaded:",
|
||||
"The following add-ons had errors and could not be loaded:",
|
||||
error_campaigns.size());
|
||||
for(std::vector<std::string>::const_iterator i = error_campaigns.begin(); i != error_campaigns.end(); ++i) {
|
||||
msg << "\n" << *i;
|
||||
}
|
||||
|
||||
msg << "\n" << _("ERROR DETAILS:") << "\n" << font::nullify_markup(user_error_log);
|
||||
|
||||
gui::show_error_message(disp(),msg.str());
|
||||
}
|
||||
|
||||
game_config_.merge_children("units");
|
||||
|
||||
config& hashes = game_config_.add_child("multiplayer_hashes");
|
||||
for(config::child_list::const_iterator ch = game_config_.get_children("multiplayer").begin(); ch != game_config_.get_children("multiplayer").end(); ++ch) {
|
||||
hashes[(**ch)["id"]] = (*ch)->hash();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//this function reads the game configuration, searching for valid cached copies first
|
||||
void game_controller::read_game_cfg(bool use_cache)
|
||||
{
|
||||
|
@ -1816,86 +1902,10 @@ void game_controller::read_game_cfg(bool use_cache)
|
|||
|
||||
LOG_CONFIG << "no valid cache found. Writing cache to '" << fname << " with defines_map "<< str.str() << "'\n";
|
||||
DBG_CONFIG << ((use_cache && file_exists(fname)) ? "yes":"no ") << " " << dir_checksum.modified << "==" << data_tree_checksum().modified << " " << dir_checksum.nfiles << "==" << data_tree_checksum().nfiles << " " << dir_checksum.sum_size << "==" << data_tree_checksum().sum_size << "\n";
|
||||
preproc_map defines_map(defines_map_);
|
||||
|
||||
std::string error_log, user_error_log;
|
||||
std::string error_log;
|
||||
|
||||
//read the file and then write to the cache
|
||||
scoped_istream stream = preprocess_file("data/", &defines_map, &error_log);
|
||||
|
||||
//reset the parse counter before reading the game files
|
||||
if (loadscreen::global_loadscreen) {
|
||||
loadscreen::global_loadscreen->parser_counter = 0;
|
||||
}
|
||||
|
||||
read(game_config_, *stream, &error_log);
|
||||
|
||||
//load usermade add-ons
|
||||
const std::string user_campaign_dir = get_user_data_dir() + "/data/campaigns/";
|
||||
std::vector<std::string> user_campaigns, error_campaigns;
|
||||
get_files_in_dir(user_campaign_dir,NULL,&user_campaigns,ENTIRE_FILE_PATH);
|
||||
for(std::vector<std::string>::const_iterator uc = user_campaigns.begin(); uc != user_campaigns.end(); ++uc) {
|
||||
std::string oldstyle_cfg = *uc + ".cfg";
|
||||
std::string main_cfg = *uc + "/_main.cfg";
|
||||
std::string toplevel;
|
||||
if (file_exists(oldstyle_cfg))
|
||||
toplevel = oldstyle_cfg;
|
||||
else if (file_exists(main_cfg))
|
||||
toplevel = main_cfg;
|
||||
else
|
||||
continue;
|
||||
|
||||
try {
|
||||
preproc_map user_defines_map(defines_map);
|
||||
scoped_istream stream = preprocess_file(toplevel, &user_defines_map);
|
||||
|
||||
std::string campaign_error_log;
|
||||
|
||||
config user_campaign_cfg;
|
||||
read(user_campaign_cfg,*stream,&campaign_error_log);
|
||||
|
||||
if(campaign_error_log.empty()) {
|
||||
game_config_.append(user_campaign_cfg);
|
||||
} else {
|
||||
user_error_log += campaign_error_log;
|
||||
error_campaigns.push_back(*uc);
|
||||
}
|
||||
} catch(config::error& err) {
|
||||
ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
|
||||
error_campaigns.push_back(*uc);
|
||||
|
||||
user_error_log += err.message + "\n";
|
||||
} catch(preproc_config::error&) {
|
||||
ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
|
||||
error_campaigns.push_back(*uc);
|
||||
//no need to modify the error log here, already done by the preprocessor
|
||||
|
||||
} catch(io_exception&) {
|
||||
ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
|
||||
error_campaigns.push_back(*uc);
|
||||
}
|
||||
}
|
||||
|
||||
if(error_campaigns.empty() == false) {
|
||||
std::stringstream msg;
|
||||
msg << _n("The following add-on had errors and could not be loaded:",
|
||||
"The following add-ons had errors and could not be loaded:",
|
||||
error_campaigns.size());
|
||||
for(std::vector<std::string>::const_iterator i = error_campaigns.begin(); i != error_campaigns.end(); ++i) {
|
||||
msg << "\n" << *i;
|
||||
}
|
||||
|
||||
msg << "\n" << _("ERROR DETAILS:") << "\n" << font::nullify_markup(user_error_log);
|
||||
|
||||
gui::show_error_message(disp(),msg.str());
|
||||
}
|
||||
|
||||
game_config_.merge_children("units");
|
||||
|
||||
config& hashes = game_config_.add_child("multiplayer_hashes");
|
||||
for(config::child_list::const_iterator ch = game_config_.get_children("multiplayer").begin(); ch != game_config_.get_children("multiplayer").end(); ++ch) {
|
||||
hashes[(**ch)["id"]] = (*ch)->hash();
|
||||
}
|
||||
read_configs(error_log);
|
||||
|
||||
if(!error_log.empty()) {
|
||||
gui::show_error_message(disp(),
|
||||
|
@ -1915,15 +1925,22 @@ void game_controller::read_game_cfg(bool use_cache)
|
|||
}
|
||||
}
|
||||
|
||||
set_unit_data();
|
||||
set_unit_data();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_CONFIG << "caching cannot be done. Reading file\n";
|
||||
preproc_map defines_map(defines_map_);
|
||||
scoped_istream stream = preprocess_file("data/", &defines_map);
|
||||
read(game_config_, *stream);
|
||||
|
||||
std::string error_log;
|
||||
|
||||
read_configs(error_log);
|
||||
if(!error_log.empty()) {
|
||||
gui::show_error_message(disp(),
|
||||
_("Warning: Errors occurred while loading game configuration files: '") +
|
||||
font::nullify_markup(error_log));
|
||||
|
||||
}
|
||||
set_unit_data();
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ int receive_bytes(TCPsocket s, char* buf, size_t nbytes)
|
|||
}
|
||||
|
||||
bool receive_with_timeout(TCPsocket s, char* buf, size_t nbytes,
|
||||
bool update_stats=false, int timeout_ms=10000)
|
||||
bool update_stats=false, int timeout_ms=60000)
|
||||
{
|
||||
int startTicks = SDL_GetTicks();
|
||||
int time_used = 0;
|
||||
|
|
|
@ -398,7 +398,24 @@ stats& attack_context::defender_stats()
|
|||
return get_stats(defender_side);
|
||||
}
|
||||
|
||||
void attack_context::attack_result(attack_context::ATTACK_RESULT res, int damage)
|
||||
#ifdef MABOUL_STATS
|
||||
void attack_context::attack_excepted_damage(double attacker_inflict, double defender_inflict)
|
||||
{
|
||||
attacker_inflict *= 100.0;
|
||||
defender_inflict *= 100.0;
|
||||
attacker_stats().expected_damage_inflicted += attacker_inflict;
|
||||
attacker_stats().expected_damage_taken += defender_inflict;
|
||||
defender_stats().expected_damage_inflicted += defender_inflict;
|
||||
defender_stats().expected_damage_taken += attacker_inflict;
|
||||
attacker_stats().turn_expected_damage_inflicted += attacker_inflict;
|
||||
attacker_stats().turn_expected_damage_taken += defender_inflict;
|
||||
defender_stats().turn_expected_damage_inflicted += defender_inflict;
|
||||
defender_stats().turn_expected_damage_taken += attacker_inflict;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void attack_context::attack_result(attack_context::ATTACK_RESULT res, int damage, int drain)
|
||||
{
|
||||
if(stats_disabled > 0)
|
||||
return;
|
||||
|
@ -406,16 +423,24 @@ void attack_context::attack_result(attack_context::ATTACK_RESULT res, int damage
|
|||
push_back(attacker_res,(res == MISSES ? '0' : '1'));
|
||||
|
||||
if(res != MISSES) {
|
||||
#ifdef MABOUL_STATS
|
||||
attacker_stats().damage_taken -= drain;
|
||||
defender_stats().damage_inflicted -= drain;
|
||||
attacker_stats().turn_damage_taken -= drain;
|
||||
defender_stats().turn_damage_inflicted -= drain;
|
||||
#endif
|
||||
attacker_stats().damage_inflicted += damage;
|
||||
defender_stats().damage_taken += damage;
|
||||
attacker_stats().turn_damage_inflicted += damage;
|
||||
defender_stats().turn_damage_taken += damage;
|
||||
}
|
||||
#ifndef MABOUL_STATS
|
||||
const int exp_damage = damage * chance_to_hit_defender;
|
||||
attacker_stats().expected_damage_inflicted += exp_damage;
|
||||
defender_stats().expected_damage_taken += exp_damage;
|
||||
attacker_stats().turn_expected_damage_inflicted += exp_damage;
|
||||
defender_stats().turn_expected_damage_taken += exp_damage;
|
||||
#endif
|
||||
|
||||
if(res == KILLS) {
|
||||
attacker_stats().killed[defender_type]++;
|
||||
|
@ -423,24 +448,33 @@ void attack_context::attack_result(attack_context::ATTACK_RESULT res, int damage
|
|||
}
|
||||
}
|
||||
|
||||
void attack_context::defend_result(attack_context::ATTACK_RESULT res, int damage)
|
||||
void attack_context::defend_result(attack_context::ATTACK_RESULT res, int damage, int drain)
|
||||
{
|
||||
if(stats_disabled > 0)
|
||||
return;
|
||||
|
||||
push_back(defender_res,(res == MISSES ? '0' : '1'));
|
||||
|
||||
|
||||
if(res != MISSES) {
|
||||
#ifdef MABOUL_STATS
|
||||
defender_stats().damage_taken -= drain;
|
||||
attacker_stats().damage_inflicted -= drain;
|
||||
defender_stats().turn_damage_taken -= drain;
|
||||
attacker_stats().turn_damage_inflicted -= drain;
|
||||
#endif
|
||||
attacker_stats().damage_taken += damage;
|
||||
defender_stats().damage_inflicted += damage;
|
||||
attacker_stats().turn_damage_taken += damage;
|
||||
defender_stats().turn_damage_inflicted += damage;
|
||||
}
|
||||
#ifndef MABOUL_STATS
|
||||
const int exp_damage = damage * chance_to_hit_attacker;
|
||||
attacker_stats().expected_damage_taken += exp_damage;
|
||||
defender_stats().expected_damage_inflicted += exp_damage;
|
||||
attacker_stats().turn_expected_damage_taken += exp_damage;
|
||||
defender_stats().turn_expected_damage_inflicted += exp_damage;
|
||||
#endif
|
||||
|
||||
if(res == KILLS) {
|
||||
attacker_stats().deaths[attacker_type]++;
|
||||
|
|
|
@ -85,8 +85,11 @@ namespace statistics
|
|||
|
||||
enum ATTACK_RESULT { MISSES, HITS, KILLS };
|
||||
|
||||
void attack_result(ATTACK_RESULT res, int damage);
|
||||
void defend_result(ATTACK_RESULT res, int damage);
|
||||
#ifdef MABOUL_STATS
|
||||
void attack_excepted_damage(double attacker_inflict, double defender_inflict);
|
||||
#endif
|
||||
void attack_result(ATTACK_RESULT res, int damage, int drain);
|
||||
void defend_result(ATTACK_RESULT res, int damage, int drain);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ team::team_info::team_info(const config& cfg) :
|
|||
if(village_income.empty())
|
||||
income_per_village = game_config::village_income;
|
||||
else
|
||||
income_per_village = atoi(village_income.c_str());
|
||||
income_per_village = lexical_cast_default<int>(village_income, game_config::village_income);
|
||||
|
||||
const std::string& enemies_list = cfg["enemy"];
|
||||
if(!enemies_list.empty()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue