Added automatically generated help for units, abilities and weapon specials.
The units and terrains the user has encountered are saved in the preferences file so that no spoilers will be shown.
This commit is contained in:
parent
8173bbf891
commit
05552caacb
9 changed files with 172 additions and 34 deletions
|
@ -1,7 +1,7 @@
|
|||
[help]
|
||||
[toplevel]
|
||||
#sections=introduction,gameplay,units,abilities,traits,weapon_specials
|
||||
sections=introduction,gameplay,traits
|
||||
sections=introduction,gameplay,units,abilities,traits,weapon_specials
|
||||
#sections=introduction,gameplay,traits
|
||||
topics=about
|
||||
[/toplevel]
|
||||
|
||||
|
|
|
@ -1278,7 +1278,9 @@ void advance_unit(const game_data& info,
|
|||
const unit& new_unit = get_advanced_unit(info,units,loc,advance_to);
|
||||
|
||||
statistics::advance_unit(new_unit);
|
||||
|
||||
preferences::encountered_units().insert(new_unit.type().name());
|
||||
std::cout << "Added '" << new_unit.type().name() << "' to encountered units" << std::endl;
|
||||
|
||||
units.erase(loc);
|
||||
units.insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
}
|
||||
|
|
|
@ -68,9 +68,6 @@ public:
|
|||
/// changed.
|
||||
void terrain_palette::adjust_size();
|
||||
|
||||
//void bg_backup();
|
||||
//void bg_restore();
|
||||
|
||||
private:
|
||||
void draw_old(bool);
|
||||
/// To be called when a mouse click occurs. Check if the coordinates
|
||||
|
@ -99,7 +96,6 @@ private:
|
|||
gui::button top_button_, bot_button_;
|
||||
size_t button_x_, top_button_y_, bot_button_y_;
|
||||
size_t nterrains_, terrain_start_;
|
||||
//surface_restorer restorer_;
|
||||
};
|
||||
|
||||
/// A bar where the brush is drawin
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "language.hpp"
|
||||
#include "log.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
|
@ -294,6 +295,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
const std::vector<std::string>& types = config::split(type);
|
||||
for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
|
||||
(*teams)[index].recruits().insert(*i);
|
||||
preferences::encountered_units().insert(*i);
|
||||
if(index == 0) {
|
||||
state_of_game->can_recruit.insert(*i);
|
||||
}
|
||||
|
@ -679,6 +681,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
|
||||
for(std::vector<gamemap::location>::const_iterator loc = locs.begin(); loc != locs.end(); ++loc) {
|
||||
const std::string& terrain_type = cfg["letter"];
|
||||
preferences::encountered_terrains().insert(terrain_type);
|
||||
if(terrain_type.size() > 0) {
|
||||
game_map->set_terrain(*loc,terrain_type[0]);
|
||||
}
|
||||
|
@ -691,6 +694,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
//if we should spawn a new unit on the map somewhere
|
||||
else if(cmd == "unit") {
|
||||
unit new_unit(*game_data_ptr,cfg);
|
||||
preferences::encountered_units().insert(new_unit.type().name());
|
||||
gamemap::location loc(cfg);
|
||||
|
||||
if(game_map->on_board(loc)) {
|
||||
|
|
101
src/help.cpp
101
src/help.cpp
|
@ -36,6 +36,7 @@
|
|||
namespace {
|
||||
const config *game_config = NULL;
|
||||
game_data *game_info = NULL;
|
||||
gamemap *map = NULL;
|
||||
// The default toplevel.
|
||||
help::section toplevel;
|
||||
// All sections and topics not referenced from the default toplevel.
|
||||
|
@ -137,9 +138,15 @@ namespace {
|
|||
|
||||
namespace help {
|
||||
|
||||
help_manager::help_manager(const config *cfg, game_data *gameinfo) {
|
||||
help_manager::help_manager(const config *cfg, game_data *gameinfo, gamemap *_map) {
|
||||
game_config = cfg == NULL ? &dummy_cfg : cfg;
|
||||
game_info = gameinfo;
|
||||
map = _map;
|
||||
}
|
||||
|
||||
void generate_contents() {
|
||||
toplevel.clear();
|
||||
hidden_sections.clear();
|
||||
if (game_config != NULL) {
|
||||
const config *help_config = game_config->child("help");
|
||||
if (help_config == NULL) {
|
||||
|
@ -203,6 +210,7 @@ help_manager::help_manager(const config *cfg, game_data *gameinfo) {
|
|||
help_manager::~help_manager() {
|
||||
game_config = NULL;
|
||||
game_info = NULL;
|
||||
map = NULL;
|
||||
toplevel.clear();
|
||||
hidden_sections.clear();
|
||||
}
|
||||
|
@ -385,22 +393,24 @@ std::vector<topic> generate_weapon_special_topics() {
|
|||
for (std::vector<attack_type>::const_iterator it = attacks.begin();
|
||||
it != attacks.end(); it++) {
|
||||
const std::string special = (*it).special();
|
||||
if (checked_specials.find(special) == checked_specials.end()) {
|
||||
std::string lang_special = string_table["weapon_special_" + special];
|
||||
if (lang_special == "") {
|
||||
lang_special = special;
|
||||
if (special != "") {
|
||||
if (checked_specials.find(special) == checked_specials.end()) {
|
||||
std::string lang_special = string_table["weapon_special_" + special];
|
||||
if (lang_special == "") {
|
||||
lang_special = special;
|
||||
}
|
||||
lang_special = cap(lang_special);
|
||||
std::string description
|
||||
= string_table["weapon_special_" + special + "_description"];
|
||||
const size_t colon_pos = description.find(':');
|
||||
if (colon_pos != std::string::npos) {
|
||||
// Remove the first colon and the following newline.
|
||||
description.erase(0, colon_pos + 2);
|
||||
}
|
||||
topic t(lang_special, "weaponspecial_" + special, description);
|
||||
topics.push_back(t);
|
||||
checked_specials.insert(special);
|
||||
}
|
||||
lang_special = cap(lang_special);
|
||||
std::string description
|
||||
= string_table["weapon_special_" + special + "_description"];
|
||||
const size_t colon_pos = description.find(':');
|
||||
if (colon_pos != std::string::npos) {
|
||||
// Remove the first colon and the following newline.
|
||||
description.erase(0, colon_pos + 2);
|
||||
}
|
||||
topic t(lang_special, "weaponspecial_" + special, description);
|
||||
topics.push_back(t);
|
||||
checked_specials.insert(special);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -470,12 +480,18 @@ std::vector<topic> generate_unit_topics() {
|
|||
}
|
||||
else if (desc_type == FULL_DESCRIPTION) {
|
||||
const std::string detailed_description = type.unit_description();
|
||||
const std::string normal_image = type.image();
|
||||
const unit_type *female_type = type.get_gender_unit_type(unit_race::FEMALE);
|
||||
const unit_type *male_type = type.get_gender_unit_type(unit_race::MALE);
|
||||
|
||||
// Show the unit's image and it's level.
|
||||
ss << "<img>src='" << normal_image << "' align=left float=no</img>"
|
||||
<< "<format>font_size=11 text='" << translate_string("level")
|
||||
<< " " << type.level() << "'</format>\n";
|
||||
if (male_type != NULL) {
|
||||
ss << "<img>src='" << male_type->image() << "'</img> ";
|
||||
}
|
||||
if (female_type != NULL && female_type != male_type) {
|
||||
ss << "<img>src='" << female_type->image() << "'</img> ";
|
||||
}
|
||||
ss << "<format>font_size=11 text=' " << translate_string("level")
|
||||
<< " " << type.level() << "'</format>\n";
|
||||
|
||||
// Print the units this unit can advance to. Cross reference
|
||||
// to the topics containing information about those units.
|
||||
|
@ -530,7 +546,8 @@ std::vector<topic> generate_unit_topics() {
|
|||
ss << translate_string("hp") << ": " << type.hitpoints() << jump_to(100)
|
||||
<< translate_string("moves") << ": " << type.movement() << jump_to(200)
|
||||
<< translate_string("alignment") << ": "
|
||||
<< type.alignment_description(type.alignment()) << jump_to(350);
|
||||
<< translate_string(type.alignment_description(type.alignment()))
|
||||
<< jump_to(350);
|
||||
if (type.experience_needed() != 500) {
|
||||
// 500 is apparently used when the units cannot advance.
|
||||
ss << translate_string("required_xp") << ": " << type.experience_needed();
|
||||
|
@ -608,6 +625,39 @@ std::vector<topic> generate_unit_topics() {
|
|||
<< " text='"<< resistance << "%'</format>\n";
|
||||
}
|
||||
|
||||
if (map != NULL) {
|
||||
// Print the terrain modifier table of the unit.
|
||||
ss << "\n<header>text='" << cap(translate_string("terrain_info"))
|
||||
<< "'</header>\n\n"
|
||||
<< bold(cap(translate_string("terrain"))) << jump_to(140)
|
||||
<< bold(cap(translate_string("movement"))) << jump_to(280)
|
||||
<< bold(cap(translate_string("defense"))) << "\n";
|
||||
for (std::set<std::string>::const_iterator terrain_it =
|
||||
preferences::encountered_terrains().begin();
|
||||
terrain_it != preferences::encountered_terrains().end();
|
||||
terrain_it++) {
|
||||
assert(terrain_it->size() > 0);
|
||||
const gamemap::TERRAIN terrain = (*terrain_it)[0];
|
||||
if (terrain == gamemap::FOGGED || terrain == gamemap::VOID_TERRAIN) {
|
||||
continue;
|
||||
}
|
||||
const terrain_type& info = map->get_terrain_info(terrain);
|
||||
if (!info.is_alias()) {
|
||||
const std::string& name = map->terrain_name(terrain);
|
||||
const std::string& lang_name = string_table[name];
|
||||
const int moves = movement_type.movement_cost(*map,terrain);
|
||||
std::stringstream str;
|
||||
ss << lang_name << jump_to(140);
|
||||
if(moves < 100)
|
||||
ss << moves;
|
||||
else
|
||||
ss << "--";
|
||||
const int defense =
|
||||
100 - movement_type.defense_modifier(*map,terrain);
|
||||
ss << jump_to(280) << defense << "%\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
|
@ -619,8 +669,12 @@ std::vector<topic> generate_unit_topics() {
|
|||
}
|
||||
|
||||
UNIT_DESCRIPTION_TYPE description_type(const unit_type &type) {
|
||||
// For now, until decision is made, show the full description for everything.
|
||||
return FULL_DESCRIPTION;
|
||||
const std::string id = type.name();
|
||||
const std::set<std::string> &encountered_units = preferences::encountered_units();
|
||||
if (encountered_units.find(id) != encountered_units.end()) {
|
||||
return FULL_DESCRIPTION;
|
||||
}
|
||||
return NO_DESCRIPTION;
|
||||
}
|
||||
|
||||
std::string generate_traits_text() {
|
||||
|
@ -2061,6 +2115,7 @@ void show_help(display &disp, const section &toplevel_sec, const std::string sho
|
|||
gui::draw_dialog(xloc, yloc, width, height, disp, translate_string("help_title"),
|
||||
NULL, &buttons_ptr, &restorer);
|
||||
|
||||
generate_contents();
|
||||
try {
|
||||
help_browser hb(disp, toplevel_sec);
|
||||
hb.set_location(xloc + left_padding, yloc + top_padding);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "config.hpp"
|
||||
#include "display.hpp"
|
||||
#include "font.hpp"
|
||||
#include "map.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
#include "unit_types.hpp"
|
||||
#include "widgets/button.hpp"
|
||||
|
@ -31,10 +32,14 @@
|
|||
namespace help {
|
||||
|
||||
struct help_manager {
|
||||
help_manager(const config *game_config, game_data *game_info);
|
||||
help_manager(const config *game_config, game_data *game_info, gamemap *map);
|
||||
~help_manager();
|
||||
};
|
||||
|
||||
/// Generate the help contents from the configurations given to the
|
||||
/// manager.
|
||||
void generate_contents();
|
||||
|
||||
struct section;
|
||||
|
||||
typedef std::vector<section *> section_list;
|
||||
|
|
|
@ -261,7 +261,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
|
|||
if(teams.size() == 1) {
|
||||
state_of_game.can_recruit = teams.back().recruits();
|
||||
}
|
||||
|
||||
|
||||
//if there are additional starting units on this side
|
||||
const config::child_list& starting_units = (*ui)->get_children("unit");
|
||||
for(config::child_list::const_iterator su = starting_units.begin();
|
||||
|
@ -281,8 +281,51 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
|
|||
std::cerr << "inserting unit for side " << new_unit.side() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add all recruitable units as encountered so that information
|
||||
// about them are displayed to the user in the help system.
|
||||
for (std::vector<team>::const_iterator help_team_it = teams.begin();
|
||||
help_team_it != teams.end(); help_team_it++) {
|
||||
std::cout << "Adding help units for team '" << help_team_it->name()
|
||||
<< "'" << std::endl;
|
||||
const std::set<std::string> &recruitable = help_team_it->recruits();
|
||||
std::set<std::string> &enc_units = preferences::encountered_units();
|
||||
std::cout << "Adding recruitable units: " << std::endl;
|
||||
for (std::set<std::string>::iterator it = recruitable.begin();
|
||||
it != recruitable.end(); it++) {
|
||||
std::cout << *it << std::endl;
|
||||
}
|
||||
std::cout << "Added all recruitable units" << std::endl;
|
||||
std::copy(recruitable.begin(), recruitable.end(),
|
||||
std::inserter(enc_units, enc_units.begin()));
|
||||
}
|
||||
|
||||
// Add all units that exist at the start to the encountered units so
|
||||
// that information about them are displayed to the user in the help
|
||||
// system.
|
||||
for (unit_map::const_iterator help_unit_it = units.begin();
|
||||
help_unit_it != units.end(); help_unit_it++) {
|
||||
const std::string name = help_unit_it->second.type().name();
|
||||
preferences::encountered_units().insert(name);
|
||||
}
|
||||
|
||||
// Add all units that are recallable as encountred units.
|
||||
for(std::vector<unit>::iterator help_recall_it = state_of_game.available_units.begin();
|
||||
help_recall_it != state_of_game.available_units.end(); help_recall_it++) {
|
||||
preferences::encountered_units().insert(help_recall_it->type().name());
|
||||
}
|
||||
|
||||
// Add all terrains on the map as encountered terrains.
|
||||
for (int map_x = 0; map_x < map.x(); map_x++) {
|
||||
for (int map_y = 0; map_y < map.y(); map_y++) {
|
||||
const gamemap::TERRAIN t = map.get_terrain(gamemap::location(map_x, map_y));
|
||||
std::string s;
|
||||
s += t;
|
||||
preferences::encountered_terrains().insert(s);
|
||||
}
|
||||
}
|
||||
std::cerr << "initialized teams... " << (SDL_GetTicks() - ticks) << "\n";
|
||||
|
||||
const config* theme_cfg = NULL;
|
||||
|
@ -344,7 +387,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
|
|||
|
||||
std::cerr << "initializing events manager... " << (SDL_GetTicks() - ticks) << "\n";
|
||||
|
||||
help::help_manager help_manager(&game_config, &gameinfo);
|
||||
help::help_manager help_manager(&game_config, &gameinfo, &map);
|
||||
|
||||
//find a list of 'items' (i.e. overlays) on the level, and add them
|
||||
const config::child_list& overlays = level->get_children("item");
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -44,6 +45,9 @@ bool message_private_on = true;
|
|||
|
||||
bool haloes = true;
|
||||
|
||||
std::set<std::string> encountered_units_set;
|
||||
std::set<std::string> encountered_terrains_set;
|
||||
|
||||
}
|
||||
|
||||
namespace preferences {
|
||||
|
@ -51,16 +55,33 @@ namespace preferences {
|
|||
manager::manager()
|
||||
{
|
||||
prefs.read(read_file(get_prefs_file()));
|
||||
|
||||
set_music_volume(music_volume());
|
||||
set_sound_volume(sound_volume());
|
||||
|
||||
set_colour_cursors(prefs["colour_cursors"] == "yes");
|
||||
set_show_haloes(prefs["show_haloes"] != "no");
|
||||
|
||||
std::vector<std::string> v;
|
||||
v = config::split(prefs["encountered_units"]);
|
||||
std::copy(v.begin(), v.end(),
|
||||
std::inserter(encountered_units_set, encountered_units_set.begin()));
|
||||
v = config::split(prefs["encountered_terrains"]);
|
||||
std::copy(v.begin(), v.end(),
|
||||
std::inserter(encountered_terrains_set, encountered_terrains_set.begin()));
|
||||
}
|
||||
|
||||
manager::~manager()
|
||||
{
|
||||
|
||||
std::vector<std::string> v;
|
||||
std::copy(encountered_units_set.begin(), encountered_units_set.end(), std::back_inserter(v));
|
||||
prefs["encountered_units"] = config::join(v);
|
||||
v.clear();
|
||||
std::copy(encountered_terrains_set.begin(), encountered_terrains_set.end(),
|
||||
std::back_inserter(v));
|
||||
prefs["encountered_terrains"] = config::join(v);
|
||||
encountered_units_set.clear();
|
||||
encountered_terrains_set.clear();
|
||||
try {
|
||||
write_file(get_prefs_file(),prefs.write());
|
||||
} catch(io_exception&) {
|
||||
|
@ -527,6 +548,14 @@ void set_show_haloes(bool value)
|
|||
prefs["show_haloes"] = value ? "yes" : "no";
|
||||
}
|
||||
|
||||
std::set<std::string> &encountered_units() {
|
||||
return encountered_units_set;
|
||||
}
|
||||
|
||||
std::set<std::string> &encountered_terrains() {
|
||||
return encountered_terrains_set;
|
||||
}
|
||||
|
||||
CACHE_SAVES_METHOD cache_saves()
|
||||
{
|
||||
if(prefs["cache_saves"] == "always") {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <set>
|
||||
|
||||
namespace preferences {
|
||||
|
||||
|
@ -109,6 +110,9 @@ namespace preferences {
|
|||
bool show_haloes();
|
||||
void set_show_haloes(bool value);
|
||||
|
||||
std::set<std::string> &encountered_units();
|
||||
std::set<std::string> &encountered_terrains();
|
||||
|
||||
enum CACHE_SAVES_METHOD { CACHE_SAVES_ASK, CACHE_SAVES_NEVER, CACHE_SAVES_ALWAYS };
|
||||
CACHE_SAVES_METHOD cache_saves();
|
||||
void set_cache_saves(CACHE_SAVES_METHOD method);
|
||||
|
|
Loading…
Add table
Reference in a new issue