added [store_unit], [unstore_unit], and [while] tags to WML

This commit is contained in:
Dave White 2004-04-30 04:57:12 +00:00
parent 8f27ecf3e9
commit db0492bf45
12 changed files with 357 additions and 158 deletions

View file

@ -1621,7 +1621,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
symbols["enemies"] = lexical_cast<std::string>(nenemies);
std::cerr << "formatting string...\n";
const std::string message = config::interpolate_variables_into_string(string_table[msg_id],symbols);
const std::string message = config::interpolate_variables_into_string(string_table[msg_id],&symbols);
std::cerr << "displaying label...\n";
font::add_floating_label(message,24,font::BAD_COLOUR,

View file

@ -275,28 +275,39 @@ class ai : public ai_interface {
public:
ai(ai_interface::info& info);
virtual ~ai() {}
void play_turn();
virtual void play_turn();
private:
virtual int choose_weapon(const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain);
void do_move();
struct target {
target(const location& pos, double val) : loc(pos), value(val)
{}
location loc;
double value;
};
bool do_combat(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
bool get_villages(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader);
bool get_healing(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
bool retreat_units(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader);
bool move_to_targets(std::map<gamemap::location,paths>& possible_moves, move_map& srcdst, move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader);
protected:
bool should_retreat(const gamemap::location& loc, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc) const;
virtual void do_move();
void do_recruitment();
virtual bool do_combat(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
virtual bool get_villages(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader);
virtual bool get_healing(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
virtual bool retreat_units(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader);
virtual bool move_to_targets(std::map<gamemap::location,paths>& possible_moves, move_map& srcdst, move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader);
void move_leader_to_keep(const move_map& enemy_dstsrc);
void move_leader_after_recruit(const move_map& enemy_dstsrc);
void leader_attack();
virtual bool should_retreat(const gamemap::location& loc, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc) const;
bool recruit_usage(const std::string& usage);
virtual void do_recruitment();
virtual void move_leader_to_keep(const move_map& enemy_dstsrc);
virtual void move_leader_after_recruit(const move_map& enemy_dstsrc);
virtual void leader_attack();
virtual bool recruit_usage(const std::string& usage);
struct attack_analysis
{
@ -345,7 +356,7 @@ private:
bool leader_threat;
};
void do_attack_analysis(
virtual void do_attack_analysis(
const location& loc,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc,
@ -356,32 +367,20 @@ private:
);
double power_projection(const gamemap::location& loc, const move_map& srcdst, const move_map& dstsrc, bool use_terrain=true) const;
virtual double power_projection(const gamemap::location& loc, const move_map& srcdst, const move_map& dstsrc, bool use_terrain=true) const;
public:
int choose_weapon(const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain);
struct target {
target(const location& pos, double val) : loc(pos), value(val)
{}
location loc;
double value;
};
private:
std::vector<attack_analysis> analyze_targets(
virtual std::vector<attack_analysis> analyze_targets(
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc
);
std::vector<target> find_targets(unit_map::const_iterator leader, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
virtual std::vector<target> find_targets(unit_map::const_iterator leader, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
std::pair<location,location> choose_move(std::vector<target>& targets,const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
virtual std::pair<location,location> choose_move(std::vector<target>& targets,const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
//function which rates the value of moving onto certain terrain for a unit
int rate_terrain(const unit& u, const location& loc);
virtual int rate_terrain(const unit& u, const location& loc);
display& disp_;
const gamemap& map_;
@ -396,28 +395,28 @@ private:
//function which will analyze all the units that this side can recruit and rate
//their movement types. Ratings will be placed in 'unit_movement_scores_', with
//lower scores being better, and the lowest possible rating being '10'.
void analyze_potential_recruit_movements();
virtual void analyze_potential_recruit_movements();
std::map<std::string,int> unit_movement_scores_;
std::set<std::string> not_recommended_units_;
virtual std::map<std::string,int> unit_movement_scores_;
virtual std::set<std::string> not_recommended_units_;
//function which will analyze all the units that this side can recruit and rate
//their fighting suitability against enemy units. Ratings will be placed in
//'unit_combat_scores_' with a '0' rating indicating that the unit is 'average'
//against enemy units, negative ratings meaning they are poorly suited, and
//positive ratings meaning they are well suited
void analyze_potential_recruit_combat();
virtual void analyze_potential_recruit_combat();
std::map<std::string,int> unit_combat_scores_;
//function which rates two unit types for their suitability against each other.
//returns 0 if the units are equally matched, a positive number if a is suited
//against b, and a negative number if b is suited against a.
int compare_unit_types(const unit_type& a, const unit_type& b) const;
virtual int compare_unit_types(const unit_type& a, const unit_type& b) const;
//function which calculates the average resistance unit type a has against
//the attacks of unit type b.
int average_resistance_against(const unit_type& a, const unit_type& b) const;
virtual int average_resistance_against(const unit_type& a, const unit_type& b) const;
};
#endif

View file

@ -1055,14 +1055,20 @@ std::string& config::operator[](const std::string& key)
}
const std::string& config::operator[](const std::string& key) const
{
const std::string& str = get_attribute(key);
//see if the value is a variable
if(str != "" && str[0] == '$') {
return game_events::get_variable(std::string(str.begin()+1,str.end()));
} else {
return str;
}
}
const std::string& config::get_attribute(const std::string& key) const
{
const string_map::const_iterator i = values.find(key);
if(i != values.end()) {
//see if the value is a variable
if(i->second[0] == '$') {
return game_events::get_variable(std::string(i->second.begin()+1,i->second.end()));
}
return i->second;
} else {
static const std::string empty_string;
@ -1251,10 +1257,10 @@ namespace {
bool not_id(char c)
{
return !isalpha(c);
return !isalpha(c) && c != '.';
}
void do_interpolation(std::string& res, size_t npos, const string_map& m)
void do_interpolation(std::string& res, size_t npos, const string_map* m)
{
const std::string::iterator i = std::find(res.begin()+npos,res.end(),'$');
if(i == res.end() || i+1 == res.end()) {
@ -1268,9 +1274,13 @@ void do_interpolation(std::string& res, size_t npos, const string_map& m)
const std::string key(i+1,end);
res.erase(i,end);
const string_map::const_iterator itor = m.find(key);
if(itor != m.end()) {
res.insert(npos-1,itor->second);
if(m != NULL) {
const string_map::const_iterator itor = m->find(key);
if(itor != m->end()) {
res.insert(npos-1,itor->second);
}
} else {
res.insert(npos-1,game_events::get_variable(key));
}
do_interpolation(res,npos,m);
@ -1278,7 +1288,7 @@ void do_interpolation(std::string& res, size_t npos, const string_map& m)
}
std::string config::interpolate_variables_into_string(const std::string& str, const string_map& symbols)
std::string config::interpolate_variables_into_string(const std::string& str, const string_map* symbols)
{
std::string res = str;
do_interpolation(res,0,symbols);

View file

@ -142,6 +142,8 @@ struct config
std::string& operator[](const std::string& key);
const std::string& operator[](const std::string& key) const;
const std::string& get_attribute(const std::string& key) const;
config* find_child(const std::string& key, const std::string& name,
const std::string& value);
const config* find_child(const std::string& key, const std::string& name,
@ -159,7 +161,10 @@ struct config
static std::string& strip(std::string& str);
static bool has_value(const std::string& values, const std::string& val);
static std::string interpolate_variables_into_string(const std::string& str, const string_map& symbols);
//function which will interpolate variables, starting with '$' in the string 'str' with
//the equivalent symbols in the given symbol table. If 'symbols' is NULL, then game event
//variables will be used instead
static std::string interpolate_variables_into_string(const std::string& str, const string_map* symbols=NULL);
void clear();
bool empty() const;
@ -238,20 +243,4 @@ private:
const std::string name_, value_;
};
//an object which wraps around a config object and interpolates
//variables into all strings it returns
struct config_interpolater {
config_interpolater(const config& cfg, const string_map& m) : cfg_(cfg), map_(m)
{}
std::string operator[](const std::string& str) const
{
return config::interpolate_variables_into_string(cfg_[str],map_);
}
private:
const config& cfg_;
const string_map& map_;
};
#endif

View file

@ -72,66 +72,54 @@ bool conditional_passed(game_state& state_of_game,
const config::child_list& variables = cond.get_children("variable");
for(config::child_list::const_iterator var = variables.begin();
var != variables.end(); ++var) {
const string_map& values = (*var)->values;
string_map& vars = state_of_game.variables;
const config& values = **var;
string_map::const_iterator itor = values.find("name");
if(itor == values.end())
return false;
const std::string& name = values["name"];
const std::string& value = game_events::get_variable(name);
const std::string& name = itor->second;
//if we don't have a record of the variable, then the statement
//is not true, unless it's a not equals statement, in which it's
//automatically true
if(vars.find(name) == vars.end()) {
if(values.count("not_equals") == 0 && values.count("numerical_not_equals") == 0) {
return false;
}
continue;
}
const std::string& value = vars[name];
const double num_value = atof(value.c_str());
itor = values.find("equals");
if(itor != values.end() && itor->second != value) {
const std::string& equals = values["equals"];
if(equals != "" && value != equals) {
return false;
}
itor = values.find("numerical_equals");
if(itor != values.end() && atof(itor->second.c_str()) != num_value){
const std::string& numerical_equals = values["numerical_equals"];
if(numerical_equals != "" && atof(numerical_equals.c_str()) != num_value){
return false;
}
itor = values.find("not_equals");
if(itor != values.end() && itor->second == value) {
const std::string& not_equals = values["not_equals"];
if(not_equals != "" && not_equals == value) {
return false;
}
itor = values.find("numerical_not_equals");
if(itor != values.end() && atof(itor->second.c_str()) == num_value){
const std::string& numerical_not_equals = values["numerical_not_equals"];
if(numerical_not_equals != "" && atof(numerical_not_equals.c_str()) == num_value){
return false;
}
itor = values.find("greater_than");
if(itor != values.end() && atof(itor->second.c_str()) >= num_value){
const std::string& greater_than = values["greater_than"];
if(greater_than != "" && atof(greater_than.c_str()) >= num_value){
return false;
}
itor = values.find("less_than");
if(itor != values.end() && atof(itor->second.c_str()) <= num_value){
const std::string& less_than = values["less_than"];
std::cerr << num_value << " < '" << less_than << "' ?\n";
if(less_than != "" && atof(less_than.c_str()) <= num_value){
std::cerr << "no\n";
return false;
}
itor = values.find("greater_than_equal_to");
if(itor != values.end() && atof(itor->second.c_str()) > num_value){
std::cerr << "yes\n";
const std::string& greater_than_equal_to = values["greater_than_equal_to"];
if(greater_than_equal_to != "" && atof(greater_than_equal_to.c_str()) > num_value){
return false;
}
itor = values.find("less_than_equal_to");
if(itor != values.end() && atof(itor->second.c_str()) < num_value){
const std::string& less_than_equal_to = values["less_than_equal_to"];
if(less_than_equal_to != "" && atof(less_than_equal_to.c_str()) < num_value) {
return false;
}
}
@ -446,28 +434,38 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
//setting a variable
else if(cmd == "set_variable") {
const std::string& name = cfg["name"];
const std::string& value = config::interpolate_variables_into_string(cfg["value"],state_of_game->variables);
std::cerr << "setting variable\n";
const std::string& name = config::interpolate_variables_into_string(cfg.get_attribute("name"));
std::cerr << "name: '" << name << "'\n";
std::string& var = game_events::get_variable(name);
std::cerr << "got variable...\n";
const std::string& value = cfg["value"];
if(value.empty() == false) {
state_of_game->variables[name] = value;
var = value;
}
const std::string& add = config::interpolate_variables_into_string(cfg["add"],state_of_game->variables);;
const std::string& format = config::interpolate_variables_into_string(cfg.get_attribute("format"));
if(format.empty() == false) {
var = format;
}
const std::string& add = cfg["add"];
if(add.empty() == false) {
double value = atof(state_of_game->variables[name].c_str());
value += atof(add.c_str());
int value = atof(var.c_str());
value += atoi(add.c_str());
char buf[50];
sprintf(buf,"%f",value);
state_of_game->variables[name] = buf;
sprintf(buf,"%d",value);
var = buf;
}
const std::string& multiply = config::interpolate_variables_into_string(cfg["multiply"],state_of_game->variables);;
const std::string& multiply = cfg["multiply"];
if(multiply.empty() == false) {
double value = atof(state_of_game->variables[name].c_str());
value *= atof(multiply.c_str());
int value = atof(var.c_str());
value = int(double(value) * atof(multiply.c_str()));
char buf[50];
sprintf(buf,"%f",value);
state_of_game->variables[name] = buf;
sprintf(buf,"%d",value);
std::cerr << "'" << var << "' * '" << multiply << "' = '" << buf << "'\n";
var = buf;
}
// random generation works as follows:
@ -475,7 +473,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
// Each element in the list will be considered a separate choice,
// unless it contains "..". In this case, it must be a numerical
// range. (i.e. -1..-10, 0..100, -10..10, etc)
const std::string& random = config::interpolate_variables_into_string(cfg["random"],state_of_game->variables);;
const std::string& random = cfg["random"];
if(random.empty() == false) {
std::string random_value, word;
std::vector<std::string> words;
@ -539,25 +537,33 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
}
}
std::cerr << "(" << choice << ")" << random_value << " ";
state_of_game->variables[name] = random_value;
var = random_value;
}
}
//conditional statements
else if(cmd == "if") {
const std::string type = game_events::conditional_passed(
*state_of_game,units,cfg) ? "then":"else";
else if(cmd == "if" || cmd == "while") {
const size_t max_iterations = (cmd == "if" ? 1 : 1024);
const std::string pass = (cmd == "if" ? "then" : "do");
const std::string fail = (cmd == "if" ? "else" : "");
for(size_t i = 0; i != max_iterations; ++i) {
const std::string type = game_events::conditional_passed(
*state_of_game,units,cfg) ? pass : fail;
//if the if statement passed, then execute all 'then' statements,
//otherwise execute 'else' statements
const config::child_list& commands = cfg.get_children(type);
for(config::child_list::const_iterator cmd = commands.begin();
cmd != commands.end(); ++cmd) {
handle_event(event_info,*cmd);
if(type == "") {
break;
}
//if the if statement passed, then execute all 'then' statements,
//otherwise execute 'else' statements
const config::child_list& commands = cfg.get_children(type);
for(config::child_list::const_iterator cmd = commands.begin();
cmd != commands.end(); ++cmd) {
handle_event(event_info,*cmd);
}
}
}
//if we are assigning a role to a unit from the available units list
else if(cmd == "role") {
//get a list of the types this unit can be
@ -687,16 +693,25 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
if(caption_lang.empty() == false)
caption = caption_lang;
const std::map<gamemap::location,unit>::iterator u = units->find(event_info.loc1);
std::string text;
const config* filter = cfg.child("filter");
gamemap::location loc;
if(filter != NULL) {
loc = gamemap::location(*filter);
}
if(loc.valid() == false) {
loc = event_info.loc1;
}
const unit_map::iterator u = units->find(loc);
if(u == units->end())
return rval;
std::string text;
const config::child_list& filters = cfg.get_children("filter");
if(filters.empty() || u->second.matches_filter(*filters.front())) {
if(filter == NULL || u->second.matches_filter(*filter)) {
const std::string& lang = string_table[id];
if(!lang.empty())
text = lang;
@ -827,7 +842,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
//if we're not replaying, or if we are replaying and there is no choice
//to be made, show the dialog.
if(recorder.at_end() || options.empty()) {
const std::string msg = config::interpolate_variables_into_string(lang_message.empty() ? cfg["message"] : lang_message,state_of_game->variables);
const std::string msg = config::interpolate_variables_into_string(lang_message.empty() ? cfg["message"] : lang_message);
option_chosen = gui::show_dialog(*screen,surface,caption,msg,
options.empty() ? gui::MESSAGE : gui::OK_ONLY,
options.empty() ? NULL : &options);
@ -870,7 +885,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
else if(cmd == "kill") {
for(std::map<gamemap::location,unit>::iterator un = units->begin(); un != units->end();) {
for(unit_map::iterator un = units->begin(); un != units->end();) {
if(game_events::unit_matches_filter(un,cfg)) {
if(cfg["animate"] == "yes") {
screen->scroll_to_tile(un->first.x,un->first.y,display::WARP);
@ -881,15 +896,18 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
} else {
++un;
}
}
std::vector<unit>& avail_units = state_of_game->available_units;
for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
if(j->matches_filter(cfg)) {
j = avail_units.erase(j);
} else {
++j;
//if the filter doesn't contain positional information, then it may match
//units on the recall list.
if(cfg["x"].empty() && cfg["y"].empty()) {
std::vector<unit>& avail_units = state_of_game->available_units;
for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
if(j->matches_filter(cfg)) {
j = avail_units.erase(j);
} else {
++j;
}
}
}
}
@ -900,6 +918,79 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
events_map.insert(std::pair<std::string,event_handler>(new_handler.name(),new_handler));
}
//unit serialization to and from variables
else if(cmd == "store_unit") {
const config empty_filter;
const config* filter_ptr = cfg.child("filter");
const config& filter = filter_ptr != NULL ? *filter_ptr : empty_filter;
const std::string& variable = cfg["variable"];
config& vars = state_of_game->variables;
vars.clear_children(variable);
const bool kill_units = cfg["kill"] == "yes";
for(unit_map::iterator i = units->begin(); i != units->end();) {
if(game_events::unit_matches_filter(i,filter) == false) {
++i;
continue;
}
config& data = vars.add_child(variable);
i->first.write(data);
i->second.write(data);
if(kill_units) {
units->erase(i++);
} else {
++i;
}
}
if(filter["x"].empty() && filter["y"].empty()) {
std::vector<unit>& avail_units = state_of_game->available_units;
for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
if(j->matches_filter(filter) == false) {
++j;
continue;
}
config& data = vars.add_child(variable);
j->write(data);
data["x"] = "recall";
data["y"] = "recall";
if(kill_units) {
j = avail_units.erase(j);
} else {
++j;
}
}
}
}
else if(cmd == "unstore_unit") {
const config& var = game_events::get_variable_cfg(config::interpolate_variables_into_string(cfg.get_attribute("variable")));
try {
const unit u(*game_data_ptr,var);
gamemap::location loc(var);
if(loc.valid()) {
if(cfg["find_vacant"] == "yes") {
loc = find_vacant_tile(*game_map,*units,loc);
}
units->erase(loc);
units->insert(std::pair<gamemap::location,unit>(loc,u));
} else {
state_of_game->available_units.push_back(u);
}
} catch(gamestatus::load_game_failed& e) {
std::cerr << "could not de-serialize unit: '" << e.message << "'\n";
}
}
else if(cmd == "endlevel") {
const std::string& next_scenario = cfg["next_scenario"];
if(next_scenario.empty() == false) {
@ -1049,6 +1140,71 @@ bool process_event(event_handler& handler, const queued_event& ev)
return true;
}
void get_variable_internal(const std::string& key, config& cfg,
std::string** varout, config** cfgout)
{
//we get the variable from the [variables] section of the game state. Variables may
//be in the format
const std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
if(itor != key.end()) {
std::string element(key.begin(),itor);
const std::string sub_key(itor+1,key.end());
size_t index = 0;
const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
const bool explicit_index = index_start != element.end();
if(explicit_index) {
const std::string::iterator index_end = std::find(index_start,element.end(),']');
const std::string index_str(index_start+1,index_end);
index = size_t(atoi(index_str.c_str()));
if(index > 1024) {
std::cerr << "ERROR: index greater than 1024: truncated\n";
index = 1024;
}
element = std::string(element.begin(),index_start);
}
const config::child_list& items = cfg.get_children(element);
//special case -- '.length' on an array returns the size of the array
if(explicit_index == false && sub_key == "length") {
if(items.empty()) {
if(varout != NULL) {
static std::string zero_str;
zero_str = "0";
*varout = &zero_str;
}
} else {
char buf[50];
sprintf(buf,"%d",minimum<int>(1024,int(items.size())));
((*items.back())["__length"] = buf);
if(varout != NULL) {
*varout = &(*items.back())["__length"];
}
}
return;
}
while(cfg.get_children(element).size() <= index) {
std::cerr << "element '" << element << "', " << index << " not found -- adding\n";
cfg.add_child(element);
}
if(cfgout != NULL) {
*cfgout = cfg.get_children(element)[index];
}
get_variable_internal(sub_key,*cfg.get_children(element)[index],varout,cfgout);
} else {
if(varout != NULL) {
*varout = &cfg[key];
}
}
}
} //end anonymous namespace
namespace game_events {
@ -1058,18 +1214,32 @@ bool unit_matches_filter(unit_map::const_iterator itor, const config& filter)
return filter_loc(itor->first,filter) && itor->second.matches_filter(filter);
}
const std::string& get_variable(const std::string& key)
std::string& get_variable(const std::string& key)
{
static const std::string empty_string;
if(state_of_game != NULL) {
const string_map::const_iterator i = state_of_game->variables.find(key);
if(i != state_of_game->variables.end())
return i->second;
else
return empty_string;
} else {
return empty_string;
std::string* res = NULL;
get_variable_internal(key,state_of_game->variables,&res,NULL);
if(res != NULL) {
return *res;
}
}
static std::string empty_string;
return empty_string;
}
config& get_variable_cfg(const std::string& key)
{
if(state_of_game != NULL) {
config* res = NULL;
get_variable_internal(key + ".",state_of_game->variables,NULL,&res);
if(res != NULL) {
return *res;
}
}
static config empty_cfg;
return empty_cfg;
}
void set_variable(const std::string& key, const std::string& value)
@ -1177,6 +1347,22 @@ bool pump()
//find all handlers for this event in the map
std::pair<itor,itor> i = events_map.equal_range(event_name);
//set the variables for the event
if(i.first != i.second && state_of_game != NULL) {
char buf[50];
sprintf(buf,"%d",ev.loc1.x+1);
state_of_game->variables["x1"] = buf;
sprintf(buf,"%d",ev.loc1.y+1);
state_of_game->variables["y1"] = buf;
sprintf(buf,"%d",ev.loc2.x+1);
state_of_game->variables["x2"] = buf;
sprintf(buf,"%d",ev.loc2.y+1);
state_of_game->variables["y2"] = buf;
}
while(i.first != i.second) {
std::cerr << "processing event '" << event_name << "'\n";
event_handler& handler = i.first->second;

View file

@ -34,7 +34,8 @@
namespace game_events
{
const std::string& get_variable(const std::string& varname);
std::string& get_variable(const std::string& varname);
config& get_variable_cfg(const std::string& varname);
void set_variable(const std::string& varname, const std::string& value);

View file

@ -215,7 +215,7 @@ game_state read_game(game_data& data, const config* cfg)
const config* const vars = cfg->child("variables");
if(vars != NULL) {
res.variables = vars->values;
res.variables = *vars;
}
const config* const replay = cfg->child("replay");
@ -271,7 +271,7 @@ void write_game(const game_state& game, config& cfg)
cfg["difficulty"] = game.difficulty;
cfg.add_child("variables").values = game.variables;
cfg.add_child("variables",game.variables);
for(std::vector<unit>::const_iterator i = game.available_units.begin();
i != game.available_units.end(); ++i) {

View file

@ -115,7 +115,7 @@ struct game_state
std::string scenario; //the scenario being played
int gold; //amount of gold the player has saved
std::vector<unit> available_units; //units the player may recall
std::map<std::string,std::string> variables; //variables that have been set
config variables; //variables that have been set
std::string difficulty; //the difficulty level the game is being played on.
std::set<std::string> can_recruit; //units the player has the ability to recruit

View file

@ -57,7 +57,7 @@ public:
location() : x(-1), y(-1) {}
location(int x, int y) : x(x), y(y) {}
location(const config& cfg);
explicit location(const config& cfg);
void write(config& cfg) const;

View file

@ -1647,7 +1647,7 @@ gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_se
if(message != "") {
string_map symbols;
symbols["noun"] = string_table[u.type().gender() == unit_race::MALE ? "noun_male" : "noun_female"];
message = config::interpolate_variables_into_string(message,symbols);
message = config::interpolate_variables_into_string(message,&symbols);
const int res = gui::show_dialog(disp_,NULL,"",message,gui::YES_NO);
if(res != 0) {

View file

@ -567,10 +567,19 @@ void unit::read(game_data& data, const config& cfg)
const config* const status_flags = cfg.child("status");
if(status_flags != NULL) {
for(string_map::const_iterator i = status_flags->values.begin(); i != status_flags->values.end(); ++i) {
statusFlags_.insert(i->first);
if(i->second == "on") {
statusFlags_.insert(i->first);
}
}
}
const config* const variables = cfg.child("variables");
if(variables != NULL) {
variables_ = *variables;
} else {
variables_.clear();
}
const config* const modifications = cfg.child("modifications");
if(modifications != NULL) {
modifications_ = *modifications;
@ -624,6 +633,8 @@ void unit::write(config& cfg) const
status_flags[*st] = "on";
}
cfg.add_child("variables",variables_);
cfg.add_child("status",status_flags);
cfg["user_description"] = description_;

View file

@ -166,6 +166,9 @@ private:
std::set<std::string> statusFlags_;
//this field stores user-variables associated with the unit
config variables_;
std::vector<attack_type> attacks_;
std::vector<attack_type> backupAttacks_;