Logo Search packages:      
Sourcecode: wesnoth version File versions

reports.cpp

#include "global.hpp"

#include "actions.hpp"
#include "font.hpp"
#include "game_config.hpp"
#include "gamestatus.hpp"
#include "gettext.hpp"
#include "language.hpp"
#include "reports.hpp"
#include "wassert.hpp"

#include <map>
#include <set>
#include <sstream>

namespace {
      const std::string report_names[] = { "unit_description", "unit_type", "unit_level",
            "unit_traits","unit_status","unit_alignment","unit_abilities","unit_hp","unit_xp",
            "unit_moves","unit_weapons","unit_image","unit_profile","time_of_day",
            "turn","gold","villages","num_units","upkeep", "expenses",
             "income", "terrain", "position", "side_playing", "observers", "selected_terrain",
             "edit_left_button_function"};
      std::map<reports::TYPE, std::string> report_contents;
}

namespace reports {

const std::string& report_name(TYPE type)
{
      wassert(sizeof(report_names)/sizeof(*report_names) == NUM_REPORTS);
      wassert(type < NUM_REPORTS);

      return report_names[type];
}

void report::add_text(std::stringstream& text, std::stringstream& tooltip) {
      add_text(text.str(), tooltip.str());
      // Clear the streams
      text.str("");
      tooltip.str("");
}

void report::add_text(const std::string& text, const std::string& tooltip) {
      this->push_back(element(text,"",tooltip));
}

void report::add_image(std::stringstream& image, std::stringstream& tooltip) {
      add_image(image.str(), tooltip.str());
      // Clear the streams
      image.str("");
      tooltip.str("");
}

void report::add_image(const std::string& image, const std::string& tooltip) {
      this->push_back(element("",image,tooltip));
}

report generate_report(TYPE type, const gamemap& map, const unit_map& units,
                       const std::vector<team>& teams, const team& current_team,
                       int current_side, int playing_side,
                       const gamemap::location& loc, const gamemap::location& mouseover,
                       const gamestatus& status, const std::set<std::string>& observers)
{
      unit_map::const_iterator u = units.end();
      
      if(int(type) >= int(UNIT_REPORTS_BEGIN) && int(type) < int(UNIT_REPORTS_END) || type == POSITION) {

            if(!current_team.fogged(mouseover.x,mouseover.y)) {
                  u = find_visible_unit(units,mouseover,
                              map,
                              status.get_time_of_day().lawful_bonus,
                              teams,current_team);
            }

            if(u == units.end()) {
                  if(!current_team.fogged(loc.x,loc.y)) {
                        u = find_visible_unit(units,loc,
                                    map,
                                    status.get_time_of_day().lawful_bonus,
                                    teams,current_team);
                  }

                  if(u == units.end() && type != POSITION) {
                        return report();
                  }
            }
      }

      std::stringstream str;

      switch(type) {
      case UNIT_DESCRIPTION:
            return report(u->second.description());
      case UNIT_TYPE:
            return report(u->second.type().language_name(),"",u->second.unit_description());
      case UNIT_LEVEL:
            str << u->second.type().level();
            break;
      case UNIT_TRAITS:
            return report(u->second.traits_description(),"",u->second.modification_description("trait"));
      case UNIT_STATUS: {
            std::stringstream unit_status;
            std::stringstream tooltip;
            report res;

            if(map.on_board(loc) && u->second.invisible(map.underlying_terrain(map[loc.x][loc.y]),status.get_time_of_day().lawful_bonus,loc,units,teams)) {
                  unit_status << "misc/invisible.png";
                  tooltip << _("invisible: ") << _("This unit is invisible. It cannot be seen or attacked by enemy units.");
                  res.add_image(unit_status,tooltip);
            }
            if(u->second.has_flag("slowed")) {
                  unit_status << "misc/slowed.png";
                  tooltip << _("slowed: ") << _("This unit has been slowed. It moves at half normal speed and receives one less attack than normal in combat.");
                  res.add_image(unit_status,tooltip);
            }
            if(u->second.has_flag("poisoned")) {
                  unit_status << "misc/poisoned.png";
                  tooltip << _("poisoned: ") << _("This unit is poisoned. It will lose 8 HP every turn until it can seek a cure to the poison in a village or from a friendly unit with the 'cures' ability.\n\
\n\
Units cannot be killed by poison alone. The poison will not reduce it below 1 HP.");
                  res.add_image(unit_status,tooltip);
            }
            if(u->second.has_flag("stone")) {
                  unit_status << "misc/stone.png";
                  tooltip << _("stone: ") << _("This unit has been turned to stone. It may not move or attack.");
                  res.add_image(unit_status,tooltip);
            }

            return res;
      }
      case UNIT_ALIGNMENT: {
            const std::string& align = unit_type::alignment_description(u->second.type().alignment());
            const std::string& align_id = unit_type::alignment_id(u->second.type().alignment());
            return report(align, "", string_table[align_id + "_description"]);
      }
      case UNIT_ABILITIES: {
            report res;
            std::stringstream tooltip;
            const std::vector<std::string>& abilities = u->second.type().abilities();
            for(std::vector<std::string>::const_iterator i = abilities.begin(); i != abilities.end(); ++i) {
                  str << gettext(i->c_str());
                  if(i+1 != abilities.end())
                        str << ",";

                  tooltip << string_table[*i + "_description"];
                  res.add_text(str,tooltip);
            }

            return res;
      }
      case UNIT_HP:
            if(u->second.hitpoints() <= u->second.max_hitpoints()/3)
                  str << font::BAD_TEXT;
            else if(u->second.hitpoints() > 2*(u->second.max_hitpoints()/3))
                  str << font::GOOD_TEXT;

            str << u->second.hitpoints()
                << "/" << u->second.max_hitpoints() << "\n";

            break;
      case UNIT_XP:
            if(u->second.can_advance() == false) {
                  str << u->second.experience() << "/-";
            } else {
                  //if killing a unit of the same level as us lets us advance, display in 'good' colour
                  if(u->second.max_experience() - u->second.experience() <= game_config::kill_experience*u->second.type().level()) {
                        str << font::GOOD_TEXT;
                  }

                  str << u->second.experience() << "/" << u->second.max_experience();
            }

            break;
      case UNIT_MOVES:
            str << u->second.movement_left() << "/" << u->second.total_movement();
            break;
      case UNIT_WEAPONS: {
            report res;
            std::stringstream tooltip;
            
            const size_t team_index = u->second.side()-1;
            if(team_index >= teams.size()) {
                  std::cerr << "illegal team index in reporting: " << team_index << "\n";
                  return res;
            }

            const std::vector<attack_type>& attacks = u->second.attacks();
            for(std::vector<attack_type>::const_iterator at_it = attacks.begin();
                at_it != attacks.end(); ++at_it) {
                  const std::string& lang_weapon = gettext(at_it->name().c_str());
                  const std::string& lang_type = gettext(at_it->type().c_str());
                  
                  str << lang_weapon << " (" << lang_type << ")\n";

                  tooltip << lang_weapon << " (" << lang_type << ")\n";

                  //find all the unit types on the map, and show this weapon's bonus against all the different units
                  std::set<const unit_type*> seen_units;
                  std::map<int,std::vector<std::string> > resistances;
                  for(unit_map::const_iterator u_it = units.begin(); u_it != units.end(); ++u_it) {
                        if(teams[team_index].is_enemy(u_it->second.side()) && !current_team.fogged(u_it->first.x,u_it->first.y) &&
                           seen_units.count(&u_it->second.type()) == 0) {
                              seen_units.insert(&u_it->second.type());
                              const int resistance = u_it->second.type().movement_type().resistance_against(*at_it) - 100;
                              resistances[resistance].push_back(u_it->second.type().language_name());
                        }
                  }

                  for(std::map<int,std::vector<std::string> >::reverse_iterator resist = resistances.rbegin(); resist != resistances.rend(); ++resist) {
                        std::sort(resist->second.begin(),resist->second.end());
                        tooltip << (resist->first >= 0 ? "+" : "") << resist->first << "% " << _("vs") << " ";
                        for(std::vector<std::string>::const_iterator i = resist->second.begin(); i != resist->second.end(); ++i) {
                              if(i != resist->second.begin()) {
                                    tooltip << ",";
                              }

                              tooltip << *i;
                        }

                        tooltip << "\n";
                  }

                  res.add_text(str,tooltip);
                  
                  if (!at_it->special().empty()) {
                        str << gettext(at_it->special().c_str()) << "\n";
                        tooltip << string_table["weapon_special_" + at_it->special() + "_description"];
                        res.add_text(str,tooltip);
                  }
                  
                  str << at_it->damage() << "-" << at_it->num_attacks() << " -- "
                    << (at_it->range() == attack_type::SHORT_RANGE ?
                        _("melee") :
                              _("ranged"));
                  tooltip << at_it->damage() << " " << _("damage") << ", "
                              << at_it->num_attacks() << " " << _("attacks");
                  
                  str << "\n";
                  res.add_text(str,tooltip);
            }

            return res;
      }
      case UNIT_IMAGE:
            return report("",u->second.type().image(),"");
      case UNIT_PROFILE:
            return report("",u->second.type().image_profile(),"");
      case TIME_OF_DAY: {
            const time_of_day& tod = timeofday_at(status,units,mouseover);
            std::stringstream tooltip;
            
            tooltip << tod.name << "\n"
                    << _("Lawful units: ")
                        << (tod.lawful_bonus > 0 ? "+" : "") << tod.lawful_bonus << "%\n"
                        << _("Neutral units: ") << "0%\n"
                        << _("Chaotic units: ")
                        << (tod.lawful_bonus < 0 ? "+" : "") << (tod.lawful_bonus*-1) << "%";
            
            return report("",tod.image,tooltip.str());
      }
      case TURN:
            str << status.turn();

            if(status.number_of_turns() != -1) {
                  str << "/" << status.number_of_turns();
            }

            str << "\n";
            break;
      case GOLD:
            str << (current_team.gold() < 0 ? font::BAD_TEXT : font::NULL_MARKUP) << current_team.gold();
            break;
      case VILLAGES: {
            const team_data data = calculate_team_data(current_team,current_side,units);
            str << data.villages;

            break;
      }
      case NUM_UNITS: {
            str << team_units(units,current_side);
            break;
      }
      case UPKEEP: {
            const team_data data = calculate_team_data(current_team,current_side,units);
            str << data.expenses << " (" << data.upkeep << ")";
            break;
      }
      case EXPENSES: {
            const team_data data = calculate_team_data(current_team,current_side,units);
            str << data.expenses;
            break;
      }
      case INCOME: {
            const team_data data = calculate_team_data(current_team,current_side,units);
            str << (data.net_income < 0 ? font::BAD_TEXT : font::NULL_MARKUP) << data.net_income;
            break;
      }
      case TERRAIN: {
            if(!map.on_board(mouseover) || current_team.shrouded(mouseover.x,mouseover.y))
                  break;

            const gamemap::TERRAIN terrain = map.get_terrain(mouseover);
            const std::string& underlying = map.underlying_terrain(terrain);

            if(map.is_village(mouseover)) {
                  const int owner = village_owner(mouseover,teams)+1;
                  if(owner == 0 || current_team.fogged(mouseover.x,mouseover.y)) {
                        str << _("Village");
                  } else if(owner == current_side) {
                        str << _("Owned village");
                  } else if(current_team.is_enemy(owner)) {
                        str << _("Enemy village");
                  } else {
                        str << _("Allied village");
                  }

                  str << " ";
            } else {
                  str << map.get_terrain_info(terrain).name();
            }

            if(underlying.size() != 1 || underlying[0] != terrain) {
                  str << " (";
                  
                  for(std::string::const_iterator i = underlying.begin(); i != underlying.end(); ++i) {
                        str << map.get_terrain_info(*i).name();
                        if(i+1 != underlying.end()) {
                              str << ",";
                        }
                  }

                  str << ")";
            }

            break;
      }
      case POSITION: {
            if(!map.on_board(mouseover)) {
                  break;
            }

            str << (mouseover.x+1) << ", " << (mouseover.y+1);

            if(u == units.end() || current_team.shrouded(mouseover.x,mouseover.y))
                  break;

            const gamemap::TERRAIN terrain = map[mouseover.x][mouseover.y];

            const int move_cost = u->second.movement_cost(map,terrain);
            const int defense = 100 - u->second.defense_modifier(map,terrain);

            if(move_cost > 10) {
                  str << " (-)";
            } else {
                  str << " (" << defense << "%," << move_cost << ")";
            }

            break;      
      }

      case SIDE_PLAYING: {
            char buf[50];
            sprintf(buf,"terrain/flag-team%d-1.png",team::get_side_colour_index(playing_side));

            u = find_leader(units,playing_side);
            return report("",buf,u != units.end() ? u->second.description() : "");
      }

      case OBSERVERS: {
            if(observers.empty()) {
                  return report();
            }

            str << _("Observers:") << "\n";

            for(std::set<std::string>::const_iterator i = observers.begin(); i != observers.end(); ++i) {
                  str << *i << "\n";
            }

            return report("",game_config::observer_image,str.str());
      }
      case SELECTED_TERRAIN: {
            std::map<TYPE, std::string>::const_iterator it =
                  report_contents.find(SELECTED_TERRAIN);
            if (it != report_contents.end()) {
                  return report(it->second);
            }
            else {
                  return report();
            }
      }
      case EDIT_LEFT_BUTTON_FUNCTION: {
            std::map<TYPE, std::string>::const_iterator it =
                  report_contents.find(EDIT_LEFT_BUTTON_FUNCTION);
            if (it != report_contents.end()) {
                  return report(it->second);
            }
            else {
                  return report();
            }
      }
      default:
            wassert(false);
            break;
      }
      return report(str.str());
}
      
      
void set_report_content(const TYPE which_report, const std::string &content) {
      report_contents[which_report] = content;
}
      

}

Generated by  Doxygen 1.6.0   Back to index