added [store_unit], [unstore_unit], and [while] tags to WML
This commit is contained in:
parent
8f27ecf3e9
commit
db0492bf45
12 changed files with 357 additions and 158 deletions
|
@ -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,
|
||||
|
|
75
src/ai.hpp
75
src/ai.hpp
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
13
src/unit.cpp
13
src/unit.cpp
|
@ -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_;
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue