mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-30 00:58:29 +00:00

[[The Wesnoth repository started off as CVS in September 2003 on SourceForge. In September 2005 it was converted to Subversion using cvs2svn and hosted at Gna!; the last CVS commit corresponded to Subversion r8374. In March 2013 it was converted to git by ESR using reposurgeon 2.30; the last Subversion commit was r56594. In the process, several small, abandoned experimental branches were removed. For all branches known to have been merged to trunk merge points were found and patched in. Comments have been massaged into git summary + body form; revision references have been lifted to action stamps. Conversion comments are, like this one, enclosed in double square brackets. Typos in change comments have often been quietly fixed. Some abbreviations (notably for mainline campaign names) have been made more uniform than they were in the Subversion comments. Infix "::" to mark a campaign-scenario pair (as in "HttT::12" has sometimes been inserted for clarity and to shorten summary lines. Two branches, website/ and resources/, have been merged to trunk, where their history now appears as that of those two top-level directories rather than as separate branches. Subversion property settings, and the commits in the Subversion history that manipulated them, are almost all gone. A few have been translated to .gitignore files and setting of executable bits. There are a few committers that we have been unable to identify. These are: uso zas uid65860 uid66289 uid67456 uid68698 uid68803 uid68842 uid68850 uid68852 uid69097 uid69206 The uid names seem to have been mechanically generated from Wesnoth forum postings. Committer lines for all of these have been left without a domain name in the email address.]]
740 lines
20 KiB
C++
740 lines
20 KiB
C++
/*
|
|
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
|
|
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
#include "game_events.hpp"
|
|
#include "menu.hpp"
|
|
#include "language.hpp"
|
|
#include "playlevel.hpp"
|
|
#include "replay.hpp"
|
|
|
|
#include <cstdlib>
|
|
#include <deque>
|
|
#include <iostream>
|
|
#include <set>
|
|
#include <string>
|
|
|
|
namespace game_events {
|
|
|
|
bool conditional_passed(game_state& state_of_game,
|
|
const std::map<gamemap::location,unit>* units,
|
|
config& cond)
|
|
{
|
|
//if the if statement requires we have a certain unit, then
|
|
//check for that.
|
|
std::vector<config*>& have_unit = cond.children["have_unit"];
|
|
|
|
for(std::vector<config*>::iterator u = have_unit.begin();
|
|
u != have_unit.end(); ++u) {
|
|
|
|
if(units == NULL)
|
|
return false;
|
|
|
|
std::map<gamemap::location,unit>::const_iterator itor;
|
|
for(itor = units->begin(); itor != units->end(); ++itor) {
|
|
if(itor->second.matches_filter(**u)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(itor == units->end()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//check against each variable statement to see if the variable
|
|
//matches the conditions or not
|
|
std::vector<config*>& variables = cond.children["variable"];
|
|
for(std::vector<config*>::iterator var = variables.begin();
|
|
var != variables.end(); ++var) {
|
|
std::map<std::string,std::string>& values = (*var)->values;
|
|
std::map<std::string,std::string>& vars = state_of_game.variables;
|
|
const std::string& name = values["name"];
|
|
|
|
//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.find("not_equals") == values.end() &&
|
|
values.find("numerical_not_equals") == values.end()) {
|
|
return false;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
const std::string& value = vars[name];
|
|
const double num_value = atof(value.c_str());
|
|
|
|
std::map<std::string,std::string>::iterator itor;
|
|
|
|
itor = values.find("equals");
|
|
if(itor != values.end() && itor->second != value) {
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("numerical_equals");
|
|
if(itor != values.end() && atof(itor->second.c_str()) != num_value){
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("not_equals");
|
|
if(itor != values.end() && itor->second == value) {
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("numerical_not_equals");
|
|
if(itor != values.end() && atof(itor->second.c_str()) == num_value){
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("greater_than");
|
|
if(itor != values.end() && atof(itor->second.c_str()) >= num_value){
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("less_than");
|
|
if(itor != values.end() && atof(itor->second.c_str()) <= num_value){
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("greater_than_equal_to");
|
|
if(itor != values.end() && atof(itor->second.c_str()) > num_value){
|
|
return false;
|
|
}
|
|
|
|
itor = values.find("less_than_equal_to");
|
|
if(itor != values.end() && atof(itor->second.c_str()) < num_value){
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} //end namespace game_events
|
|
|
|
namespace {
|
|
|
|
display* screen = NULL;
|
|
gamemap* game_map = NULL;
|
|
std::map<gamemap::location,unit>* units = NULL;
|
|
game_state* state_of_game = NULL;
|
|
game_data* game_data_ptr = NULL;
|
|
|
|
bool events_init() { return screen != NULL; }
|
|
|
|
struct queued_event {
|
|
queued_event(const std::string& name, const gamemap::location& loc1,
|
|
const gamemap::location& loc2)
|
|
: name(name), loc1(loc1), loc2(loc2) {}
|
|
|
|
std::string name;
|
|
gamemap::location loc1;
|
|
gamemap::location loc2;
|
|
};
|
|
|
|
std::deque<queued_event> events_queue;
|
|
|
|
class event_handler
|
|
{
|
|
public:
|
|
event_handler(config* cfg) : name_(cfg->values["name"]),
|
|
first_time_only_(cfg->values["first_time_only"] != "no"),
|
|
disabled_(false),
|
|
cfg_(cfg)
|
|
{}
|
|
|
|
const std::string& name() const { return name_; }
|
|
|
|
bool first_time_only() const { return first_time_only_; }
|
|
|
|
void disable() { disabled_ = true; }
|
|
bool disabled() const { return disabled_; }
|
|
|
|
std::vector<config*>& first_arg_filters() {
|
|
return cfg_->children["filter"];
|
|
}
|
|
|
|
std::vector<config*>& second_arg_filters() {
|
|
return cfg_->children["filter_second"];
|
|
}
|
|
|
|
void handle_event(const queued_event& event_info, config* cfg=NULL);
|
|
|
|
private:
|
|
std::string name_;
|
|
bool first_time_only_;
|
|
bool disabled_;
|
|
config* cfg_;
|
|
};
|
|
|
|
std::multimap<std::string,event_handler> events_map;
|
|
|
|
void event_handler::handle_event(const queued_event& event_info, config* cfg)
|
|
{
|
|
if(cfg == NULL)
|
|
cfg = cfg_;
|
|
|
|
//sub commands that need to be handled in a guaranteed ordering
|
|
std::vector<config*>& commands = cfg->children["command"];
|
|
for(std::vector<config*>::iterator cmd = commands.begin();
|
|
cmd != commands.end(); ++cmd) {
|
|
handle_event(event_info,*cmd);
|
|
}
|
|
|
|
//setting a variable
|
|
std::vector<config*>& set_vars = cfg->children["set_variable"];
|
|
for(std::vector<config*>::iterator var = set_vars.begin();
|
|
var != set_vars.end(); ++var) {
|
|
std::map<std::string,std::string>& vals = (*var)->values;
|
|
const std::string& name = vals["name"];
|
|
const std::string& value = vals["value"];
|
|
if(value.empty() == false) {
|
|
state_of_game->variables[name] = value;
|
|
}
|
|
|
|
const std::string& add = vals["add"];
|
|
if(add.empty() == false) {
|
|
double value = atof(state_of_game->variables[name].c_str());
|
|
value += atof(add.c_str());
|
|
char buf[50];
|
|
sprintf(buf,"%f",value);
|
|
state_of_game->variables[name] = buf;
|
|
}
|
|
|
|
const std::string& multiply = vals["multiply"];
|
|
if(multiply.empty() == false) {
|
|
double value = atof(state_of_game->variables[name].c_str());
|
|
value *= atof(multiply.c_str());
|
|
char buf[50];
|
|
sprintf(buf,"%f",value);
|
|
state_of_game->variables[name] = buf;
|
|
}
|
|
}
|
|
|
|
//conditional statements
|
|
std::vector<config*>& conditionals = cfg->children["if"];
|
|
for(std::vector<config*>::iterator cond = conditionals.begin();
|
|
cond != conditionals.end(); ++cond) {
|
|
const std::string type = game_events::conditional_passed(
|
|
*state_of_game,units,**cond) ? "then":"else";
|
|
|
|
//if the if statement passed, then execute all 'then' statements,
|
|
//otherwise execute 'else' statements
|
|
std::vector<config*>& commands = cfg->children[type];
|
|
for(std::vector<config*>::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
|
|
std::vector<config*>& assign_role = cfg->children["role"];
|
|
for(std::vector<config*>::iterator rl = assign_role.begin();
|
|
rl != assign_role.end(); ++rl) {
|
|
|
|
//get a list of the types this unit can be
|
|
std::vector<std::string> types = config::split((*rl)->values["type"]);
|
|
|
|
//iterate over all the types, and for each type, try to find
|
|
//a unit that matches
|
|
std::vector<std::string>::iterator ti;
|
|
for(ti = types.begin(); ti != types.end(); ++ti) {
|
|
config cfg;
|
|
cfg.values["type"] = *ti;
|
|
|
|
std::map<gamemap::location,unit>::iterator itor;
|
|
for(itor = units->begin(); itor != units->end(); ++itor) {
|
|
if(itor->second.matches_filter(cfg)) {
|
|
itor->second.assign_role((*rl)->values["role"]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(itor != units->end())
|
|
break;
|
|
|
|
std::vector<unit>::iterator ui;
|
|
//iterate over the units, and try to find one that matches
|
|
for(ui = state_of_game->available_units.begin();
|
|
ui != state_of_game->available_units.end(); ++ui) {
|
|
if(ui->matches_filter(cfg)) {
|
|
ui->assign_role((*rl)->values["role"]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//if we found a unit, we don't have to keep going.
|
|
if(ui != state_of_game->available_units.end())
|
|
break;
|
|
}
|
|
|
|
//if we found a unit in the current type, we don't have to
|
|
//look through any more types
|
|
if(ti != types.end())
|
|
break;
|
|
}
|
|
|
|
std::vector<config*>& remove_overlays = cfg->children["removeitem"];
|
|
for(std::vector<config*>::iterator rm = remove_overlays.begin();
|
|
rm != remove_overlays.end(); ++rm) {
|
|
gamemap::location loc(**rm);
|
|
if(!loc.valid()) {
|
|
loc = event_info.loc1;
|
|
}
|
|
|
|
screen->remove_overlay(loc);
|
|
}
|
|
|
|
//adding new items
|
|
std::vector<config*>& add_overlays = cfg->children["item"];
|
|
for(std::vector<config*>::iterator ni = add_overlays.begin();
|
|
ni != add_overlays.end(); ++ni) {
|
|
gamemap::location loc(**ni);
|
|
const std::string& img = (*ni)->values["image"];
|
|
if(!img.empty())
|
|
screen->add_overlay(loc,img);
|
|
}
|
|
|
|
//changing the terrain
|
|
std::vector<config*>& terrain_changes = cfg->children["terrain"];
|
|
for(std::vector<config*>::iterator tc = terrain_changes.begin();
|
|
tc != terrain_changes.end(); ++tc) {
|
|
gamemap::location loc(**tc);
|
|
const std::string& terrain_type = (*tc)->values["letter"];
|
|
if(terrain_type.size() > 0) {
|
|
game_map->set_terrain(loc,terrain_type[0]);
|
|
screen->recalculate_minimap();
|
|
screen->invalidate_all();
|
|
}
|
|
}
|
|
|
|
//if we should spawn a new unit on the map somewhere
|
|
std::vector<config*>& new_units = cfg->children["unit"];
|
|
for(std::vector<config*>::iterator ui = new_units.begin();
|
|
ui != new_units.end(); ++ui) {
|
|
unit new_unit(*game_data_ptr,**ui);
|
|
gamemap::location loc(**ui);
|
|
|
|
if(game_map->on_board(loc)) {
|
|
loc = find_vacant_tile(*game_map,*units,loc);
|
|
units->insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
|
} else {
|
|
state_of_game->available_units.push_back(new_unit);
|
|
}
|
|
}
|
|
|
|
//if we should recall units that match a certain description
|
|
std::vector<config*>& recalls = cfg->children["recall"];
|
|
for(std::vector<config*>::iterator ir = recalls.begin();
|
|
ir != recalls.end(); ++ir) {
|
|
std::vector<unit>& avail = state_of_game->available_units;
|
|
for(std::vector<unit>::iterator u = avail.begin();
|
|
u != avail.end(); ++u) {
|
|
if(u->matches_filter(**ir)) {
|
|
recruit_unit(*game_map,1,*units,*u,gamemap::location(),screen);
|
|
u = avail.erase(u);
|
|
if(u == avail.end())
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<config*>& objects = cfg->children["object"];
|
|
for(std::vector<config*>::iterator obj = objects.begin();
|
|
obj != objects.end(); ++obj) {
|
|
std::map<std::string,std::string>& values = (*obj)->values;
|
|
|
|
//if this item has already been used
|
|
if(values["used"].empty() == false)
|
|
continue;
|
|
|
|
const std::string& id = values["id"];
|
|
|
|
const std::string image = values["image"];
|
|
std::string caption = values["name"];
|
|
|
|
const std::string& caption_lang = string_table[id + "_name"];
|
|
if(caption_lang.empty() == false)
|
|
caption = caption_lang;
|
|
|
|
const std::map<gamemap::location,unit>::iterator u =
|
|
units->find(event_info.loc1);
|
|
|
|
if(u == units->end())
|
|
continue;
|
|
|
|
std::string text;
|
|
|
|
std::vector<config*>& filters = (*obj)->children["filter"];
|
|
|
|
if(filters.empty() || u->second.matches_filter(*filters[0])) {
|
|
const std::string& lang = string_table[id];
|
|
if(!lang.empty())
|
|
text = lang;
|
|
else
|
|
text = values["description"];
|
|
|
|
u->second.add_modification("object",**obj);
|
|
screen->remove_overlay(event_info.loc1);
|
|
screen->select_hex(event_info.loc1);
|
|
screen->invalidate_unit();
|
|
|
|
//mark that this item won't be used again
|
|
values["used"] = "true";
|
|
} else {
|
|
const std::string& lang = string_table[id + "_cannot_use"];
|
|
if(!lang.empty())
|
|
text = lang;
|
|
else
|
|
text = values["cannot_use_message"];
|
|
}
|
|
|
|
|
|
SDL_Surface* surface = NULL;
|
|
if(image.empty() == false) {
|
|
surface = screen->getImage(image,display::UNSCALED);
|
|
}
|
|
|
|
gui::show_dialog(*screen,surface,caption,text);
|
|
|
|
//this will redraw the unit, with its new stats
|
|
screen->draw();
|
|
}
|
|
|
|
std::vector<config*>& messages = cfg->children["message"];
|
|
for(std::vector<config*>::iterator msg = messages.begin();
|
|
msg != messages.end(); ++msg) {
|
|
std::map<std::string,std::string>& values = (*msg)->values;
|
|
std::map<gamemap::location,unit>::iterator speaker = units->end();
|
|
if(values["speaker"] == "unit") {
|
|
speaker = units->find(event_info.loc1);
|
|
} else if(values["speaker"] == "second_unit") {
|
|
speaker = units->find(event_info.loc2);
|
|
} else if(values["speaker"] != "narrator") {
|
|
for(speaker = units->begin(); speaker != units->end();
|
|
++speaker){
|
|
if(speaker->second.matches_filter(**msg))
|
|
break;
|
|
}
|
|
|
|
if(speaker == units->end()) {
|
|
//no matching unit found, so the dialog can't come up
|
|
//continue onto the next message
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const std::string& id = values["id"];
|
|
|
|
std::string image = (*msg)->values["image"];
|
|
std::string caption;
|
|
|
|
const std::string& lang_caption = string_table[id + "_caption"];
|
|
if(!lang_caption.empty())
|
|
caption = lang_caption;
|
|
else
|
|
caption = (*msg)->values["caption"];
|
|
|
|
if(speaker != units->end()) {
|
|
screen->highlight_hex(speaker->first);
|
|
screen->scroll_to_tile(speaker->first.x,speaker->first.y);
|
|
|
|
if(image.empty()) {
|
|
image = speaker->second.type().image_profile();
|
|
}
|
|
|
|
if(caption.empty()) {
|
|
caption = speaker->second.description();
|
|
if(caption.empty()) {
|
|
caption = speaker->second.type().language_name();
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> options;
|
|
std::vector<std::vector<config*>*> option_events;
|
|
|
|
std::vector<config*>& menu_items = (*msg)->children["option"];
|
|
for(std::vector<config*>::iterator mi = menu_items.begin();
|
|
mi != menu_items.end(); ++mi) {
|
|
const std::string& lang_msg = string_table[(*mi)->values["id"]];
|
|
const std::string& msg = lang_msg.empty() ?
|
|
(*mi)->values["message"] : lang_msg;
|
|
options.push_back(msg);
|
|
option_events.push_back(&(*mi)->children["command"]);
|
|
}
|
|
|
|
SDL_Surface* surface = NULL;
|
|
if(image.empty() == false) {
|
|
surface = screen->getImage(image,display::UNSCALED);
|
|
}
|
|
|
|
const std::string& lang_message = string_table[id];
|
|
int option_chosen = gui::show_dialog(*screen,surface,caption,
|
|
lang_message.empty() ? values["message"] : lang_message,
|
|
options.empty() ? gui::MESSAGE : gui::OK_ONLY,
|
|
options.empty() ? NULL : &options);
|
|
|
|
if(screen->update_locked() && options.empty() == false) {
|
|
config* const cfg = recorder.get_next_action();
|
|
if(cfg == NULL || cfg->children["choose"].empty()) {
|
|
std::cerr << "choice expected but none found\n";
|
|
throw replay::error();
|
|
}
|
|
|
|
const std::string& val =
|
|
cfg->children["choose"].front()->values["value"];
|
|
option_chosen = atol(val.c_str());
|
|
|
|
} else if(options.empty() == false) {
|
|
recorder.choose_option(option_chosen);
|
|
}
|
|
|
|
if(options.empty() == false) {
|
|
assert(option_chosen >= 0 && option_chosen < menu_items.size());
|
|
std::vector<config*>& events = *option_events[option_chosen];
|
|
for(std::vector<config*>::iterator ev = events.begin();
|
|
ev != events.end(); ++ev) {
|
|
handle_event(event_info,*ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<config*>& dead_units = cfg->children["kill"];
|
|
for(std::vector<config*>::iterator du = dead_units.begin();
|
|
du != dead_units.end(); ++du) {
|
|
|
|
for(std::map<gamemap::location,unit>::iterator i = units->begin();
|
|
i != units->end(); ++i) {
|
|
while(i->second.matches_filter(**du) && i != units->end()) {
|
|
units->erase(i);
|
|
i = units->begin();
|
|
}
|
|
}
|
|
|
|
std::vector<unit>& avail_units = state_of_game->available_units;
|
|
for(std::vector<unit>::iterator j = avail_units.begin();
|
|
j != avail_units.end(); ++j) {
|
|
while(j->matches_filter(**du) && j != avail_units.end()) {
|
|
j = avail_units.erase(j);
|
|
}
|
|
}
|
|
}
|
|
|
|
//adding of new events
|
|
std::vector<config*>& new_events = cfg->children["event"];
|
|
for(std::vector<config*>::iterator ne = new_events.begin();
|
|
ne != new_events.end(); ++ne) {
|
|
event_handler new_handler(*ne);
|
|
events_map.insert(std::pair<std::string,event_handler>(
|
|
new_handler.name(),new_handler));
|
|
}
|
|
|
|
std::vector<config*>& end_level = cfg->children["endlevel"];
|
|
if(end_level.empty() == false) {
|
|
config* const end_info = end_level[0];
|
|
const std::string& result = end_info->values["result"];
|
|
if(result.size() == 0 || result == "victory") {
|
|
const bool bonus = (end_info->values["bonus"] == "yes");
|
|
throw end_level_exception(VICTORY,bonus);
|
|
} else {
|
|
throw end_level_exception(DEFEAT);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool filter_loc_impl(const gamemap::location& loc, const std::string& xloc,
|
|
const std::string& yloc)
|
|
{
|
|
if(std::find(xloc.begin(),xloc.end(),',') != xloc.end()) {
|
|
std::vector<std::string> xlocs = config::split(xloc);
|
|
std::vector<std::string> ylocs = config::split(yloc);
|
|
|
|
const int size = xlocs.size() < ylocs.size()?xlocs.size():ylocs.size();
|
|
for(int i = 0; i != size; ++i) {
|
|
if(filter_loc_impl(loc,xlocs[i],ylocs[i]))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if(!xloc.empty()) {
|
|
const std::string::const_iterator dash =
|
|
std::find(xloc.begin(),xloc.end(),'-');
|
|
|
|
if(dash != xloc.end()) {
|
|
const std::string beg(xloc.begin(),dash);
|
|
const std::string end(dash+1,xloc.end());
|
|
|
|
const int bot = atoi(beg.c_str()) - 1;
|
|
const int top = atoi(end.c_str()) - 1;
|
|
|
|
if(loc.x < bot || loc.x > top)
|
|
return false;
|
|
} else {
|
|
const int xval = atoi(xloc.c_str()) - 1;
|
|
if(xval != loc.x)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(!yloc.empty()) {
|
|
const std::string::const_iterator dash =
|
|
std::find(yloc.begin(),yloc.end(),'-');
|
|
|
|
if(dash != yloc.end()) {
|
|
const std::string beg(yloc.begin(),dash);
|
|
const std::string end(dash+1,yloc.end());
|
|
|
|
const int bot = atoi(beg.c_str()) - 1;
|
|
const int top = atoi(end.c_str()) - 1;
|
|
|
|
if(loc.y < bot || loc.y > top)
|
|
return false;
|
|
} else {
|
|
const int yval = atoi(yloc.c_str()) - 1;
|
|
if(yval != loc.y)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool filter_loc(const gamemap::location& loc, config& cfg)
|
|
{
|
|
const std::string& xloc = cfg.values["x"];
|
|
const std::string& yloc = cfg.values["y"];
|
|
|
|
return filter_loc_impl(loc,xloc,yloc);
|
|
}
|
|
|
|
bool process_event(event_handler& handler, const queued_event& ev)
|
|
{
|
|
if(handler.disabled())
|
|
return false;
|
|
|
|
std::map<gamemap::location,unit>::iterator unit1 = units->find(ev.loc1);
|
|
std::map<gamemap::location,unit>::iterator unit2 = units->find(ev.loc2);
|
|
|
|
std::vector<config*>& first_filters = handler.first_arg_filters();
|
|
for(std::vector<config*>::iterator ffi = first_filters.begin();
|
|
ffi != first_filters.end(); ++ffi) {
|
|
if(!filter_loc(ev.loc1,**ffi))
|
|
return false;
|
|
|
|
if(unit1 != units->end() && !unit1->second.matches_filter(**ffi)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::vector<config*>& second_filters = handler.second_arg_filters();
|
|
for(std::vector<config*>::iterator sfi = second_filters.begin();
|
|
sfi != second_filters.end(); ++sfi) {
|
|
if(!filter_loc(ev.loc2,**sfi))
|
|
return false;
|
|
|
|
if(unit2 != units->end() && !unit2->second.matches_filter(**sfi)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//the event hasn't been filtered out, so execute the handler
|
|
handler.handle_event(ev);
|
|
|
|
if(handler.first_time_only())
|
|
handler.disable();
|
|
|
|
return true;
|
|
}
|
|
|
|
} //end anonymous namespace
|
|
|
|
namespace game_events {
|
|
|
|
manager::manager(config& cfg, display& gui_, gamemap& map_,
|
|
std::map<gamemap::location,unit>& units_,
|
|
game_state& state_of_game_, game_data& game_data_)
|
|
{
|
|
std::vector<config*>& events_list = cfg.children["event"];
|
|
for(std::vector<config*>::iterator i = events_list.begin();
|
|
i != events_list.end(); ++i) {
|
|
event_handler new_handler(*i);
|
|
events_map.insert(std::pair<std::string,event_handler>(
|
|
new_handler.name(), new_handler));
|
|
}
|
|
|
|
screen = &gui_;
|
|
game_map = &map_;
|
|
units = &units_;
|
|
state_of_game = &state_of_game_;
|
|
game_data_ptr = &game_data_;
|
|
}
|
|
|
|
manager::~manager() {
|
|
events_queue.clear();
|
|
events_map.clear();
|
|
screen = NULL;
|
|
game_map = NULL;
|
|
units = NULL;
|
|
state_of_game = NULL;
|
|
game_data_ptr = NULL;
|
|
}
|
|
|
|
void raise(const std::string& event,
|
|
const gamemap::location& loc1,
|
|
const gamemap::location& loc2)
|
|
{
|
|
if(!events_init())
|
|
return;
|
|
|
|
events_queue.push_back(queued_event(event,loc1,loc2));
|
|
}
|
|
|
|
bool fire(const std::string& event,
|
|
const gamemap::location& loc1,
|
|
const gamemap::location& loc2)
|
|
{
|
|
raise(event,loc1,loc2);
|
|
return pump();
|
|
}
|
|
|
|
bool pump()
|
|
{
|
|
if(!events_init())
|
|
return false;
|
|
|
|
bool result = false;
|
|
|
|
while(events_queue.empty() == false) {
|
|
queued_event ev = events_queue.front();
|
|
events_queue.pop_front(); //pop now for exception safety
|
|
const std::string& event_name = ev.name;
|
|
typedef std::multimap<std::string,event_handler>::iterator itor;
|
|
|
|
//find all handlers for this event in the map
|
|
std::pair<itor,itor> i = events_map.equal_range(event_name);
|
|
|
|
while(i.first != i.second) {
|
|
event_handler& handler = i.first->second;
|
|
if(process_event(handler, ev))
|
|
result = true;
|
|
++i.first;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
} //end namespace game_events
|