This commit is contained in:
ln-zookeeper 2015-12-16 11:59:59 +02:00
commit 3c091dbe7d
18 changed files with 149 additions and 124 deletions

View file

@ -6,6 +6,7 @@ Version 1.13.2+dev:
in a couple of places so Wesnoth does not quit on startup when trying to
relocate the log file to a path with Unicode characters (bug #22897,
definitely fixed this time).
* Fix bug #23108: exclude aborted attacks from statistics
Version 1.13.2:
* Add-ons client:

View file

@ -27,17 +27,6 @@
[event]
name=prestart
#ifdef DEBUG_MODE
[set_menu_item]
description="let kalenz arrive" #wmllint: ignore
[command]
[fire_event]
name=kalenz_arrives
[/fire_event]
[/command]
[/set_menu_item]
#endif
[replace_map]
x=9-53
y=9-53

View file

@ -1299,6 +1299,9 @@
name = "Paŭlo Ebermann (Pauxlo)"
wikiuser = "Pauxlo"
[/entry]
[entry]
name = "Peter Elmers"
[/entry]
[entry]
name = "Peter Mawhorter (solsword)"
wikiuser = "solsword"

View file

@ -10,17 +10,15 @@
#enddef
#define COLOR_HEAL
green=255
color="0,255,0"
#enddef
#define COLOR_HARM
red=255
color="255,0,0"
#enddef
#define COLOR_WHITE
red=255
green=255
blue=255
color="255,255,255"
#enddef
#define IS_HERO

View file

@ -725,6 +725,12 @@ namespace {
std::string dump();
};
/**
* Used in perform_hit to confirm a replay is in sync.
* Check OOS_error_ after this method, true if error detected.
*/
void check_replay_attack_result(bool, int, int, config, unit_info&);
void unit_killed(unit_info &, unit_info &,
const battle_context_unit_stats *&, const battle_context_unit_stats *&,
bool);
@ -901,7 +907,6 @@ namespace {
resources::gamedata->get_variable("damage_inflicted") = damage;
}
// Make sure that if we're serializing a game here,
// we got the same results as the game did originally.
const config local_results = config_of("chance", attacker.cth_)("hits", hits)("damage", damage);
@ -909,62 +914,18 @@ namespace {
bool equals_replay = checkup_instance->local_checkup(local_results, replay_results);
if (!equals_replay)
{
int results_chance = replay_results["chance"];
bool results_hits = replay_results["hits"].to_bool();
int results_damage = replay_results["damage"];
/*
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< " replay data differs from local calculated data:"
<< " chance to hit in data source: " << results_chance
<< " chance to hit in calculated: " << attacker.cth_
<< " chance to hit in data source: " << results_chance
<< " chance to hit in calculated: " << attacker.cth_
;
attacker.cth_ = results_chance;
hits = results_hits;
damage = results_damage;
OOS_error_ = true;
*/
if (results_chance != attacker.cth_)
{
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< ": chance to hit is inconsistent. Data source: "
<< results_chance << "; Calculation: " << attacker.cth_
<< " (over-riding game calculations with data source results)\n";
attacker.cth_ = results_chance;
OOS_error_ = true;
}
if (results_hits != hits)
{
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< ": the data source says the hit was "
<< (results_hits ? "successful" : "unsuccessful")
<< ", while in-game calculations say the hit was "
<< (hits ? "successful" : "unsuccessful")
<< " random number: " << ran_num << " = "
<< (ran_num % 100) << "/" << results_chance
<< " (over-riding game calculations with data source results)\n";
hits = results_hits;
OOS_error_ = true;
}
if (results_damage != damage)
{
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< ": the data source says the hit did " << results_damage
<< " damage, while in-game calculations show the hit doing "
<< damage
<< " damage (over-riding game calculations with data source results)\n";
damage = results_damage;
OOS_error_ = true;
}
check_replay_attack_result(hits, ran_num, damage, replay_results, attacker);
}
// can do no more damage than the defender has hitpoints
int damage_done = std::min<int>(defender.get_unit().hitpoints(), attacker.damage_);
// expected damage = damage potential * chance to hit (as a percentage)
double expected_damage = damage_done*attacker.cth_*0.01;
if (attacker_turn) {
stats.attack_expected_damage(expected_damage, 0);
} else {
stats.attack_expected_damage(0, expected_damage);
}
int drains_damage = 0;
if (hits && attacker_stats->drains) {
@ -1262,17 +1223,6 @@ namespace {
DBG_NG << "getting attack statistics\n";
statistics::attack_context attack_stats(a_.get_unit(), d_.get_unit(), a_stats_->chance_to_hit, d_stats_->chance_to_hit);
{
// Calculate stats for battle
combatant attacker(bc_->get_attacker_stats());
combatant defender(bc_->get_defender_stats());
attacker.fight(defender,false);
const double attacker_inflict = static_cast<double>(d_.get_unit().hitpoints()) - defender.average_hp();
const double defender_inflict = static_cast<double>(a_.get_unit().hitpoints()) - attacker.average_hp();
attack_stats.attack_expected_damage(attacker_inflict,defender_inflict);
}
a_.orig_attacks_ = a_stats_->num_blows;
d_.orig_attacks_ = d_stats_->num_blows;
a_.n_attacks_ = a_.orig_attacks_;
@ -1301,7 +1251,10 @@ namespace {
++abs_n_attack_;
if (a_.n_attacks_ > 0 && !defender_strikes_first) {
if (!perform_hit(true, attack_stats)) break;
if (!perform_hit(true, attack_stats)) {
DBG_NG << "broke from attack loop on attacker turn\n";
break;
}
}
// If the defender got to strike first, they use it up here.
@ -1309,7 +1262,10 @@ namespace {
++abs_n_defend_;
if (d_.n_attacks_ > 0) {
if (!perform_hit(false, attack_stats)) break;
if (!perform_hit(false, attack_stats)) {
DBG_NG << "broke from attack loop on defender turn\n";
break;
}
}
// Continue the fight to death; if one of the units got petrified,
@ -1365,8 +1321,63 @@ namespace {
}
}
} //end anonymous namespace
void attack::check_replay_attack_result(bool hits, int ran_num, int damage,
config replay_results, unit_info& attacker)
{
int results_chance = replay_results["chance"];
bool results_hits = replay_results["hits"].to_bool();
int results_damage = replay_results["damage"];
/*
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< " replay data differs from local calculated data:"
<< " chance to hit in data source: " << results_chance
<< " chance to hit in calculated: " << attacker.cth_
<< " chance to hit in data source: " << results_chance
<< " chance to hit in calculated: " << attacker.cth_
;
attacker.cth_ = results_chance;
hits = results_hits;
damage = results_damage;
OOS_error_ = true;
*/
if (results_chance != attacker.cth_)
{
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< ": chance to hit is inconsistent. Data source: "
<< results_chance << "; Calculation: " << attacker.cth_
<< " (over-riding game calculations with data source results)\n";
attacker.cth_ = results_chance;
OOS_error_ = true;
}
if (results_hits != hits)
{
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< ": the data source says the hit was "
<< (results_hits ? "successful" : "unsuccessful")
<< ", while in-game calculations say the hit was "
<< (hits ? "successful" : "unsuccessful")
<< " random number: " << ran_num << " = "
<< (ran_num % 100) << "/" << results_chance
<< " (over-riding game calculations with data source results)\n";
hits = results_hits;
OOS_error_ = true;
}
if (results_damage != damage)
{
errbuf_ << "SYNC: In attack " << a_.dump() << " vs " << d_.dump()
<< ": the data source says the hit did " << results_damage
<< " damage, while in-game calculations show the hit doing "
<< damage
<< " damage (over-riding game calculations with data source results)\n";
damage = results_damage;
OOS_error_ = true;
}
}
} //end anonymous namespace
void attack_unit(const map_location &attacker, const map_location &defender,
int attack_with, int defend_with, bool update_display)
@ -1376,7 +1387,6 @@ void attack_unit(const map_location &attacker, const map_location &defender,
}
namespace
{
class unit_advancement_choice : public mp_sync::user_choice

View file

@ -261,7 +261,7 @@ private:
}
void display_float(const map_location& location, const std::string& text) const{
game_display::get_singleton()->float_label(location,text,255,0,0);
game_display::get_singleton()->float_label(location, text, create_color(255,0,0));
}
};

View file

@ -728,8 +728,7 @@ void game_display::set_route(const pathfind::marked_route *route)
invalidate_route();
}
void game_display::float_label(const map_location& loc, const std::string& text,
int red, int green, int blue)
void game_display::float_label(const map_location& loc, const std::string& text, const SDL_Color& color)
{
if(preferences::show_floating_labels() == false || fogged(loc)) {
return;
@ -737,7 +736,6 @@ void game_display::float_label(const map_location& loc, const std::string& text,
font::floating_label flabel(text);
flabel.set_font_size(font::SIZE_XLARGE);
const SDL_Color color = create_color(red, green, blue);
flabel.set_color(color);
flabel.set_position(get_location_x(loc)+zoom_/2, get_location_y(loc));
flabel.set_move(0, -2 * turbo_speed());

View file

@ -116,8 +116,7 @@ public:
void set_route(const pathfind::marked_route *route);
/** Function to float a label above a tile */
void float_label(const map_location& loc, const std::string& text,
int red, int green, int blue);
void float_label(const map_location& loc, const std::string& text, const SDL_Color& color);
/** Draws the movement info (turns available) for a given location. */
void draw_movement_info(const map_location& loc);

View file

@ -84,6 +84,7 @@ static lg::log_domain log_display("display");
static lg::log_domain log_wml("wml");
#define LOG_WML LOG_STREAM(info, log_wml)
#define WRN_WML LOG_STREAM(warn, log_wml)
#define ERR_WML LOG_STREAM(err, log_wml)
static lg::log_domain log_config("config");
@ -1342,7 +1343,15 @@ WML_HANDLER_FUNCTION(unstore_unit, /*event_info*/, cfg)
if(!text.empty() && !controller->is_skipping_replay())
{
// Print floating label
resources::screen->float_label(loc, text, cfg["red"], cfg["green"], cfg["blue"]);
SDL_Color color = font::LABEL_COLOR;
if(!cfg["color"].empty()) {
color = string_to_color(cfg["color"]);
} else if(cfg.has_attribute("red") || cfg.has_attribute("green") || cfg.has_attribute("blue")) {
color = create_color(cfg["red"], cfg["green"], cfg["blue"]);
}
resources::screen->float_label(loc, text, color);
}
if(advance) {
advance_unit_at(advance_unit_params(loc)

View file

@ -991,11 +991,7 @@ config side_engine::new_config() const
// Save default "recruit" so that correct faction lists would be
// initialized by flg_manager when the new side config is sent over network.
// In case recruit list was empty, set a flag to indicate that.
res["default_recruit"] = cfg_["recruit"].str();
if (res["default_recruit"].empty()) {
res["no_recruit"] = true;
}
// If the user is allowed to change type, faction, leader etc,
// then import their new values in the config.

View file

@ -578,27 +578,30 @@ void create_engine::prepare_for_campaign(const std::string& difficulty)
*
* @param set_value Preselected difficulty number. The default -1 launches the gui.
* @return Selected difficulty. Returns "FAIL" if set_value is invalid,
* and "CANCEL" if the gui is cancelled.
* and "CANCEL" if the gui is canceled.
*/
std::string create_engine::select_campaign_difficulty(int set_value)
{
// Verify the existence of difficulties
std::vector<std::string> difficulties;
BOOST_FOREACH(const config &d, current_level().data().child_range("difficulty"))
{
difficulties.push_back(d["define"]);
}
if(difficulties.empty()) {
difficulties = utils::split(current_level().data()["difficulties"]);
}
// No difficulties found. Exit
if(difficulties.empty()) {
return "";
}
// A specific difficulty value was passed
// Use a minimilistic interface to get the specified define
if(set_value != -1) {
std::vector<std::string> difficulties =
utils::split(current_level().data()["difficulties"]);
if(difficulties.empty()) {
BOOST_FOREACH(const config &d, current_level().data().child_range("difficulty"))
{
difficulties.push_back(d["define"]);
}
}
if(difficulties.empty()) {
return "";
}
if (set_value > static_cast<int>(difficulties.size())) {
std::cerr << "incorrect difficulty number: [" <<
set_value << "]. maximum is [" << difficulties.size() << "].\n";
@ -613,6 +616,8 @@ std::string create_engine::select_campaign_difficulty(int set_value)
}
// If not, let the user pick one from the prompt
// We don't pass the difficulties vector here because additional data is required
// to constrict the dialog
gui2::tcampaign_difficulty dlg(current_level().data());
dlg.show(disp_.video());

View file

@ -625,7 +625,7 @@ void flg_manager::set_current_gender(const std::string& gender)
std::vector<std::string> flg_manager::get_original_recruits(const config& cfg)
{
if (cfg["no_recruit"].to_bool()) {
if (cfg["default_recruit"].empty()) {
return std::vector<std::string>();
}
const config::attribute_value& cfg_default_recruit = cfg["default_recruit"];

View file

@ -288,7 +288,7 @@ void help_text_area::handle_format_cfg(const config &cfg)
bool bold = cfg["bold"].to_bool();
bool italic = cfg["italic"].to_bool();
int font_size = cfg["font_size"].to_int(normal_font_size);
SDL_Color color = string_to_color(cfg["color"]);
SDL_Color color = help::string_to_color(cfg["color"]);
add_text_item(text, "", false, font_size, bold, italic, color);
}

View file

@ -398,11 +398,9 @@ void terrain_label::read(const config &cfg)
tmp_color = utils::interpolate_variables_into_string(tmp_color, vs);
if(!tmp_color.empty()) {
std::vector<Uint32> temp_rgb;
if(string2rgb(tmp_color, temp_rgb) && !temp_rgb.empty()) {
color = int_to_color(temp_rgb[0]);
}
color = string_to_color(tmp_color);
}
color_ = color;
}

View file

@ -2255,7 +2255,14 @@ int game_lua_kernel::intf_print(lua_State *L) {
int size = cfg["size"].to_int(font::SIZE_SMALL);
int lifetime = cfg["duration"].to_int(50);
SDL_Color color = create_color(cfg["red"], cfg["green"], cfg["blue"]);
SDL_Color color = font::LABEL_COLOR;
if(!cfg["color"].empty()) {
color = string_to_color(cfg["color"]);
} else if(cfg.has_attribute("red") || cfg.has_attribute("green") || cfg.has_attribute("blue")) {
color = create_color(cfg["red"], cfg["green"], cfg["blue"]);
}
const SDL_Rect& rect = game_display_->map_outside_area();
@ -2517,8 +2524,7 @@ int game_lua_kernel::intf_float_label(lua_State *L)
t_string text = luaW_checktstring(L, 3);
if (game_display_) {
game_display_->float_label(loc, text, font::LABEL_COLOR.r,
font::LABEL_COLOR.g, font::LABEL_COLOR.b);
game_display_->float_label(loc, text, font::LABEL_COLOR);
}
return 0;
}

View file

@ -18,6 +18,7 @@
*/
#include "global.hpp"
#include "color_range.hpp"
#include "sdl/utils.hpp"
#include "sdl/alpha.hpp"
@ -75,6 +76,18 @@ SDL_Color int_to_color(const Uint32 rgb)
return result;
}
SDL_Color string_to_color(const std::string& color_string)
{
SDL_Color color;
std::vector<Uint32> temp_rgb;
if(string2rgb(color_string, temp_rgb) && !temp_rgb.empty()) {
color = int_to_color(temp_rgb[0]);
}
return color;
}
SDL_Color create_color(const unsigned char red
, unsigned char green
, unsigned char blue

View file

@ -432,8 +432,10 @@ SDL_Rect get_non_transparent_portion(const surface &surf);
bool operator==(const SDL_Color& a, const SDL_Color& b);
bool operator!=(const SDL_Color& a, const SDL_Color& b);
SDL_Color inverse(const SDL_Color& color);
SDL_Color int_to_color(const Uint32 rgb);
SDL_Color string_to_color(const std::string& color_string);
SDL_Color create_color(const unsigned char red
, unsigned char green

View file

@ -649,10 +649,8 @@ void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of
sound::play_sound(current_data.sound);
}
if(!current_data.text.empty() ) {
game_display::get_singleton()->float_label(src,current_data.text,
(current_data.text_color & 0x00FF0000) >> 16,
(current_data.text_color & 0x0000FF00) >> 8,
(current_data.text_color & 0x000000FF) >> 0);
game_display::get_singleton()->float_label(src, current_data.text,
int_to_color(current_data.text_color));
}
}
image::locator image_loc;