00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019 #include "actions.hpp"
00020 #include "construct_dialog.hpp"
00021 #include "game_display.hpp"
00022 #include "dialogs.hpp"
00023 #include "game_errors.hpp"
00024 #include "game_events.hpp"
00025 #include "image.hpp"
00026 #include "language.hpp"
00027 #include "log.hpp"
00028 #include "map.hpp"
00029 #include "menu_events.hpp"
00030 #include "game_preferences.hpp"
00031 #include "replay.hpp"
00032 #include "SDL_timer.h"
00033 #include "sound.hpp"
00034 #include "team.hpp"
00035 #include "terrain_filter.hpp"
00036 #include "unit_display.hpp"
00037 #include "util.hpp"
00038 #include "gettext.hpp"
00039 #include "serialization/string_utils.hpp"
00040 #include "wml_exception.hpp"
00041 #include "foreach.hpp"
00042
00043 #include <cassert>
00044 #include <cstdlib>
00045 #include <deque>
00046 #include <iostream>
00047 #include <iterator>
00048 #include <set>
00049 #include <string>
00050
00051 #define DBG_NG LOG_STREAM(debug, engine)
00052 #define LOG_NG LOG_STREAM(info, engine)
00053 #define WRN_NG LOG_STREAM(warn, engine)
00054 #define ERR_NG LOG_STREAM(err, engine)
00055 #define DBG_DP LOG_STREAM(debug, display)
00056 #define LOG_DP LOG_STREAM(info, display)
00057 #define ERR_CF LOG_STREAM(err, config)
00058
00059 #define LOG_NO LOG_STREAM(info, notifs)
00060 #define WRN_NO LOG_STREAM(warn, notifs)
00061 #define ERR_NO LOG_STREAM(err, notifs)
00062
00063 namespace {
00064
00065 game_display* screen = NULL;
00066 soundsource::manager* soundsources = NULL;
00067 gamemap* game_map = NULL;
00068 unit_map* units = NULL;
00069 std::vector<team>* teams = NULL;
00070 game_state* state_of_game = NULL;
00071 gamestatus* status_ptr = NULL;
00072 int floating_label = 0;
00073 Uint32 unit_mutations = 0;
00074
00075 class event_handler;
00076 std::vector< event_handler > new_handlers;
00077 typedef std::pair< std::string, config* > wmi_command_change;
00078 std::vector< wmi_command_change > wmi_command_changes;
00079
00080 const gui::msecs prevent_misclick_duration = 10;
00081 const gui::msecs average_frame_time = 30;
00082
00083 class wml_event_dialog : public gui::message_dialog {
00084 public:
00085 wml_event_dialog(game_display &disp, const std::string& title="", const std::string& message="", const gui::DIALOG_TYPE type=gui::MESSAGE)
00086 : message_dialog(disp, title, message, type)
00087 {}
00088 void action(gui::dialog_process_info &info) {
00089 if(result() == gui::CLOSE_DIALOG && !info.key_down && info.key[SDLK_ESCAPE]) {
00090 set_result(gui::ESCAPE_DIALOG);
00091 }
00092 }
00093 };
00094
00095 }
00096
00097 #ifdef _MSC_VER
00098
00099 #if _MSC_VER < 1300
00100 #ifndef GETLINE_PATCHED
00101 #pragma message("warning: the std::getline implementation in your compiler might be broken.")
00102 #pragma message(" http://support.microsoft.com/default.aspx?scid=kb;EN-US;q240015")
00103 #endif
00104 #endif
00105 #endif
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 static void show_wml_errors()
00117 {
00118
00119
00120 std::map<std::string, int> messages;
00121 while(true) {
00122 std::string msg;
00123 std::getline(lg::wml_error, msg);
00124
00125 if(lg::wml_error.eof()) {
00126 break;
00127 }
00128
00129 if(msg == "") {
00130 continue;
00131 }
00132
00133 if(messages.find(msg) == messages.end()) {
00134 messages[msg] = 1;
00135 } else {
00136 messages[msg]++;
00137 }
00138 }
00139
00140 lg::wml_error.clear();
00141
00142
00143 std::string caption = "Deprecated WML found";
00144 for(std::map<std::string, int>::const_iterator itor = messages.begin();
00145 itor != messages.end(); ++itor) {
00146
00147 std::stringstream msg;
00148 msg << itor->first;
00149 if(itor->second > 1) {
00150 msg << " (" << itor->second << ")";
00151 }
00152
00153 screen->add_chat_message(time(NULL), caption, 0, msg.str(),
00154 game_display::MESSAGE_PUBLIC, false);
00155 std::cerr << caption << ": " << msg.str() << '\n';
00156 }
00157 }
00158
00159 namespace game_events {
00160
00161 static bool unit_matches_filter(const unit& u, const vconfig filter,const gamemap::location& loc);
00162 static bool matches_special_filter(const config* cfg, const vconfig filter);
00163
00164 game_state* get_state_of_game()
00165 {
00166 return state_of_game;
00167 }
00168
00169 static bool internal_conditional_passed(const unit_map* units,
00170 const vconfig cond, bool& backwards_compat)
00171 {
00172
00173
00174
00175 const vconfig::child_list& have_unit = cond.get_children("have_unit");
00176 backwards_compat = backwards_compat && have_unit.empty();
00177 for(vconfig::child_list::const_iterator u = have_unit.begin(); u != have_unit.end(); ++u) {
00178
00179 if(units == NULL)
00180 return false;
00181
00182 unit_map::const_iterator itor;
00183 for(itor = units->begin(); itor != units->end(); ++itor) {
00184 if(itor->second.hitpoints() > 0 && game_events::unit_matches_filter(itor, *u)) {
00185 break;
00186 }
00187 }
00188
00189 if(itor == units->end()) {
00190 return false;
00191 }
00192 }
00193
00194
00195
00196 const vconfig::child_list& have_location = cond.get_children("have_location");
00197 backwards_compat = backwards_compat && have_location.empty();
00198 for(vconfig::child_list::const_iterator v = have_location.begin(); v != have_location.end(); ++v) {
00199 std::set<gamemap::location> res;
00200 assert(game_map != NULL && units != NULL && status_ptr != NULL);
00201 terrain_filter(*v, *game_map, *status_ptr, *units).get_locations(res);
00202 if(res.empty()) {
00203 return false;
00204 }
00205 }
00206
00207
00208
00209 const vconfig::child_list& variables = cond.get_children("variable");
00210 backwards_compat = backwards_compat && variables.empty();
00211 for(vconfig::child_list::const_iterator var = variables.begin(); var != variables.end(); ++var) {
00212 const vconfig& values = *var;
00213
00214 const std::string name = values["name"];
00215 assert(state_of_game != NULL);
00216 const std::string& value = state_of_game->get_variable_const(name);
00217
00218 const double num_value = atof(value.c_str());
00219
00220 const std::string equals = values["equals"];
00221 if(values.get_attribute("equals") != "" && value != equals) {
00222 return false;
00223 }
00224
00225 const std::string numerical_equals = values["numerical_equals"];
00226 if(values.get_attribute("numerical_equals") != "" && atof(numerical_equals.c_str()) != num_value){
00227 return false;
00228 }
00229
00230 const std::string not_equals = values["not_equals"];
00231 if(values.get_attribute("not_equals") != "" && not_equals == value) {
00232 return false;
00233 }
00234
00235 const std::string numerical_not_equals = values["numerical_not_equals"];
00236 if(values.get_attribute("numerical_not_equals") != "" && atof(numerical_not_equals.c_str()) == num_value){
00237 return false;
00238 }
00239
00240 const std::string greater_than = values["greater_than"];
00241 if(values.get_attribute("greater_than") != "" && atof(greater_than.c_str()) >= num_value){
00242 return false;
00243 }
00244
00245 const std::string less_than = values["less_than"];
00246 if(values.get_attribute("less_than") != "" && atof(less_than.c_str()) <= num_value){
00247 return false;
00248 }
00249
00250 const std::string greater_than_equal_to = values["greater_than_equal_to"];
00251 if(values.get_attribute("greater_than_equal_to") != "" && atof(greater_than_equal_to.c_str()) > num_value){
00252 return false;
00253 }
00254
00255 const std::string less_than_equal_to = values["less_than_equal_to"];
00256 if(values.get_attribute("less_than_equal_to") != "" && atof(less_than_equal_to.c_str()) < num_value) {
00257 return false;
00258 }
00259 const std::string boolean_equals = values["boolean_equals"];
00260 if(values.get_attribute("boolean_equals") != ""
00261 && (utils::string_bool(value) != utils::string_bool(boolean_equals))) {
00262 return false;
00263 }
00264 const std::string boolean_not_equals = values["boolean_not_equals"];
00265 if(values.get_attribute("boolean_not_equals") != ""
00266 && (utils::string_bool(value) == utils::string_bool(boolean_not_equals))) {
00267 return false;
00268 }
00269 const std::string contains = values["contains"];
00270 if(values.get_attribute("contains") != "" && value.find(contains) == std::string::npos) {
00271 return false;
00272 }
00273 }
00274 return true;
00275 }
00276
00277 bool conditional_passed(const unit_map* units,
00278 const vconfig cond, bool backwards_compat)
00279 {
00280 bool allow_backwards_compat = backwards_compat = backwards_compat &&
00281 utils::string_bool(cond["backwards_compat"],true);
00282 bool matches = internal_conditional_passed(units, cond, allow_backwards_compat);
00283
00284
00285 int or_count = 0;
00286 vconfig::all_children_iterator cond_i = cond.ordered_begin();
00287 vconfig::all_children_iterator cond_end = cond.ordered_end();
00288 while(cond_i != cond_end)
00289 {
00290 const std::string& cond_name = cond_i.get_key();
00291 const vconfig& cond_filter = cond_i.get_child();
00292
00293
00294 if(cond_name == "and")
00295 {
00296 matches = matches && conditional_passed(units, cond_filter, backwards_compat);
00297 backwards_compat = false;
00298 }
00299
00300 else if(cond_name == "or")
00301 {
00302 matches = matches || conditional_passed(units, cond_filter, backwards_compat);
00303 ++or_count;
00304 }
00305
00306 else if(cond_name == "not")
00307 {
00308 matches = matches && !conditional_passed(units, cond_filter, backwards_compat);
00309 backwards_compat = false;
00310 }
00311 ++cond_i;
00312 }
00313
00314 if(matches && or_count > 1 && allow_backwards_compat)
00315 {
00316 lg::wml_error << "possible deprecated [or] syntax: now forcing re-interpretation\n";
00317
00318
00319 const vconfig::child_list& orcfgs = cond.get_children("or");
00320 for(unsigned int i=0; i < orcfgs.size(); ++i) {
00321 if(conditional_passed(units, orcfgs[i])) {
00322 return true;
00323 }
00324 }
00325 return false;
00326 }
00327 return matches;
00328 }
00329
00330 }
00331
00332 namespace {
00333
00334 std::set<std::string> used_items;
00335
00336 }
00337
00338 static bool events_init() { return screen != NULL; }
00339
00340 namespace {
00341
00342 struct queued_event {
00343 queued_event(const std::string& name, const game_events::entity_location& loc1,
00344 const game_events::entity_location& loc2,
00345 const config& data)
00346 : name(name), loc1(loc1), loc2(loc2),data(data) {}
00347
00348 std::string name;
00349 game_events::entity_location loc1;
00350 game_events::entity_location loc2;
00351 config data;
00352 };
00353
00354 std::deque<queued_event> events_queue;
00355
00356 class event_handler
00357 {
00358 public:
00359 event_handler(const vconfig& cfg) :
00360 names_(utils::split(cfg["name"])),
00361 first_time_only_(utils::string_bool(cfg["first_time_only"],true)),
00362 disabled_(false),rebuild_screen_(false),
00363 cfg_(cfg)
00364 {}
00365
00366 void write(config& cfg) const
00367 {
00368 if(disabled_)
00369 return;
00370
00371 cfg = cfg_.get_config();
00372 }
00373
00374 const std::vector< std::string >& names() const { return names_; }
00375
00376 bool first_time_only() const { return first_time_only_; }
00377
00378 void disable() { disabled_ = true; }
00379 bool disabled() const { return disabled_; }
00380
00381 bool is_menu_item() const {
00382 assert(state_of_game != NULL);
00383 std::map<std::string, wml_menu_item *>::iterator itor = state_of_game->wml_menu_items.begin();
00384 while(itor != state_of_game->wml_menu_items.end()) {
00385 if(&cfg_.get_config() == &itor->second->command) {
00386 return true;
00387 }
00388 ++itor;
00389 }
00390 return false;
00391 }
00392
00393 const vconfig::child_list first_arg_filters()
00394 {
00395 return cfg_.get_children("filter");
00396 }
00397 const vconfig::child_list first_special_filters()
00398 {
00399 vconfig::child_list kids;
00400 kids = cfg_.get_children("filter_attack");
00401
00402 if (!kids.empty())
00403 return kids;
00404 else
00405 return cfg_.get_children("special_filter");
00406
00407 }
00408
00409 const vconfig::child_list second_arg_filters()
00410 {
00411 return cfg_.get_children("filter_second");
00412 }
00413 const vconfig::child_list second_special_filters()
00414 {
00415 vconfig::child_list kids;
00416 kids = cfg_.get_children("filter_second_attack");
00417
00418 if (!kids.empty())
00419 return kids;
00420 else
00421 return cfg_.get_children("special_filter_second");
00422 }
00423
00424 bool handle_event(const queued_event& event_info,
00425 const vconfig cfg = vconfig());
00426
00427 bool& rebuild_screen() {return rebuild_screen_;}
00428
00429 private:
00430 void handle_event_command(const queued_event& event_info, const std::string& cmd, const vconfig cfg, bool& mutated, bool& skip_messages);
00431
00432 std::vector< std::string > names_;
00433 bool first_time_only_;
00434 bool disabled_;
00435 bool rebuild_screen_;
00436 vconfig cfg_;
00437 };
00438
00439 }
00440
00441 static gamemap::location cfg_to_loc(const vconfig& cfg,int defaultx = 0, int defaulty = 0)
00442 {
00443 int x = lexical_cast_default(cfg["x"], defaultx) - 1;
00444 int y = lexical_cast_default(cfg["y"], defaulty) - 1;
00445
00446 return gamemap::location(x, y);
00447 }
00448
00449 static std::vector<gamemap::location> multiple_locs(const vconfig cfg)
00450 {
00451 return parse_location_range(cfg["x"],cfg["y"]);
00452 }
00453
00454 namespace {
00455
00456 std::multimap<std::string,event_handler> events_map;
00457
00458
00459 void event_handler::handle_event_command(const queued_event& event_info,
00460 const std::string& cmd, const vconfig cfg, bool& mutated, bool& skip_messages)
00461 {
00462 log_scope2(engine, "handle_event_command");
00463 LOG_NG << "handling command: '" << cmd << "'\n";
00464
00465
00466 if(cmd == "command") {
00467 if(!handle_event(event_info, cfg)) {
00468 mutated = false;
00469 }
00470 }
00471
00472
00473 else if(cmd == "allow_undo") {
00474 mutated = false;
00475 }
00476
00477 else if(cmd == "remove_shroud" || cmd == "place_shroud") {
00478 const bool remove = cmd == "remove_shroud";
00479
00480 std::string side = cfg["side"];
00481 assert(state_of_game != NULL);
00482 const int side_num = lexical_cast_default<int>(side,1);
00483 const size_t index = side_num-1;
00484
00485 if(index < teams->size()) {
00486 const std::vector<gamemap::location>& locs = multiple_locs(cfg);
00487 for(std::vector<gamemap::location>::const_iterator j = locs.begin(); j != locs.end(); ++j) {
00488 if(remove) {
00489 (*teams)[index].clear_shroud(*j);
00490 } else {
00491 (*teams)[index].place_shroud(*j);
00492 }
00493 }
00494 }
00495
00496 screen->labels().recalculate_shroud();
00497 screen->invalidate_all();
00498 }
00499
00500
00501
00502 else if(cmd == "teleport") {
00503
00504 unit_map::iterator u = units->find(event_info.loc1);
00505
00506
00507 const vconfig filter = cfg.child("filter");
00508 if(!filter.null()) {
00509 for(u = units->begin(); u != units->end(); ++u){
00510 if(game_events::unit_matches_filter(u, filter))
00511 break;
00512 }
00513 }
00514
00515
00516 if(u != units->end()) {
00517 const gamemap::location dst = cfg_to_loc(cfg);
00518 if(dst != u->first && game_map->on_board(dst)) {
00519 const gamemap::location vacant_dst = find_vacant_tile(*game_map,*units,dst);
00520 if(game_map->on_board(vacant_dst)) {
00521 const int side = u->second.side();
00522
00523 screen->invalidate(u->first);
00524 std::pair<gamemap::location,unit> *up = units->extract(u->first);
00525 up->first = vacant_dst;
00526 units->add(up);
00527 unit_mutations++;
00528 if(game_map->is_village(vacant_dst)) {
00529 get_village(vacant_dst, *screen,*teams,side-1,*units);
00530 }
00531
00532 if(utils::string_bool(cfg["clear_shroud"],true)) {
00533 clear_shroud(*screen,*game_map,*units,*teams,side-1);
00534 }
00535
00536 screen->invalidate(dst);
00537 screen->draw();
00538 }
00539 }
00540 }
00541 }
00542
00543
00544 else if(cmd == "unstone") {
00545 const vconfig filter = cfg.child("filter");
00546
00547 std::vector<bool> clear_fog_side(teams->size(),false);
00548
00549 for(unit_map::iterator i = units->begin(); i != units->end(); ++i) {
00550 if(utils::string_bool(i->second.get_state("stoned"))) {
00551 if(filter.null() || game_events::unit_matches_filter(i, filter)) {
00552 i->second.set_state("stoned","");
00553 clear_fog_side[i->second.side()-1] = true;
00554 }
00555 }
00556 }
00557
00558 for (size_t side = 0; side != teams->size(); side++) {
00559 if (clear_fog_side[side] && (*teams)[side].auto_shroud_updates()) {
00560 clear_shroud(*screen,*game_map,*units,*teams,side);
00561 }
00562 }
00563 }
00564
00565
00566 else if(cmd == "allow_recruit") {
00567 std::string side = cfg["side"];
00568 assert(state_of_game != NULL);
00569 const int side_num = lexical_cast_default<int>(side,1);
00570 const size_t index = side_num-1;
00571
00572 if(index >= teams->size())
00573 return;
00574
00575 const std::string type = cfg["type"];
00576
00577 const std::vector<std::string>& types = utils::split(type);
00578 for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
00579 (*teams)[index].recruits().insert(*i);
00580 preferences::encountered_units().insert(*i);
00581
00582 player_info *player=state_of_game->get_player((*teams)[index].save_id());
00583 if(player) {
00584 player->can_recruit.insert(*i);
00585 }
00586 }
00587 }
00588
00589
00590 else if(cmd == "disallow_recruit") {
00591 std::string side = cfg["side"];
00592 assert(state_of_game != NULL);
00593 const int side_num = lexical_cast_default<int>(side,1);
00594 const size_t index = side_num-1;
00595
00596 if(index >= teams->size())
00597 return;
00598
00599 const std::string type = cfg["type"];
00600 const std::vector<std::string>& types = utils::split(type);
00601 for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
00602 (*teams)[index].recruits().erase(*i);
00603
00604 player_info *player=state_of_game->get_player((*teams)[index].save_id());
00605 if(player) {
00606 player->can_recruit.erase(*i);
00607 }
00608 }
00609 }
00610
00611 else if(cmd == "set_recruit") {
00612 std::string side = cfg["side"];
00613 assert(state_of_game != NULL);
00614 const int side_num = lexical_cast_default<int>(side,1);
00615 const size_t index = side_num-1;
00616
00617 if(index >= teams->size())
00618 return;
00619
00620 std::vector<std::string> recruit = utils::split(cfg["recruit"]);
00621 if(recruit.size() == 1 && recruit.back() == "")
00622 recruit.clear();
00623
00624 std::set<std::string>& can_recruit = (*teams)[index].recruits();
00625 can_recruit.clear();
00626 std::copy(recruit.begin(),recruit.end(),std::inserter(can_recruit,can_recruit.end()));
00627
00628 player_info *player=state_of_game->get_player((*teams)[index].save_id());
00629 if(player) {
00630 player->can_recruit = can_recruit;
00631 }
00632 }
00633
00634 else if(cmd == "music") {
00635 sound::play_music_config(cfg.get_parsed_config());
00636 }
00637
00638 else if(cmd == "sound") {
00639 std::string sound = cfg["name"];
00640 const int repeats = lexical_cast_default<int>(cfg["repeat"], 0);
00641 assert(state_of_game != NULL);
00642 sound::play_sound(sound, sound::SOUND_FX, repeats);
00643 }
00644
00645 else if(cmd == "colour_adjust") {
00646 std::string red = cfg["red"];
00647 std::string green = cfg["green"];
00648 std::string blue = cfg["blue"];
00649 assert(state_of_game != NULL);
00650 const int r = atoi(red.c_str());
00651 const int g = atoi(green.c_str());
00652 const int b = atoi(blue.c_str());
00653 screen->adjust_colours(r,g,b);
00654 screen->invalidate_all();
00655 screen->draw(true,true);
00656 }
00657
00658 else if(cmd == "delay") {
00659 std::string delay_string = cfg["time"];
00660 assert(state_of_game != NULL);
00661 const int delay_time = atoi(delay_string.c_str());
00662 screen->delay(delay_time);
00663 }
00664
00665 else if(cmd == "scroll") {
00666 std::string x = cfg["x"];
00667 std::string y = cfg["y"];
00668 assert(state_of_game != NULL);
00669 const int xoff = atoi(x.c_str());
00670 const int yoff = atoi(y.c_str());
00671 screen->scroll(xoff,yoff);
00672 screen->draw(true,true);
00673 }
00674
00675 else if(cmd == "scroll_to") {
00676 assert(state_of_game != NULL);
00677 const gamemap::location loc = cfg_to_loc(cfg);
00678 std::string check_fogged = cfg["check_fogged"];
00679 screen->scroll_to_tile(loc,game_display::SCROLL,utils::string_bool(check_fogged,false));
00680 }
00681
00682 else if(cmd == "scroll_to_unit") {
00683 unit_map::const_iterator u;
00684 for(u = units->begin(); u != units->end(); ++u){
00685 if(game_events::unit_matches_filter(u,cfg))
00686 break;
00687 }
00688 std::string check_fogged = cfg["check_fogged"];
00689 if(u != units->end()) {
00690 screen->scroll_to_tile(u->first,game_display::SCROLL,utils::string_bool(check_fogged,false));
00691 }
00692 }
00693
00694
00695 else if(cmd == "gold") {
00696 std::string side = cfg["side"];
00697 std::string amount = cfg["amount"];
00698 assert(state_of_game != NULL);
00699 const int side_num = lexical_cast_default<int>(side,1);
00700 const int amount_num = atoi(amount.c_str());
00701 const size_t team_index = side_num-1;
00702 if(team_index < teams->size()) {
00703 (*teams)[team_index].spend_gold(-amount_num);
00704 }
00705 }
00706
00707
00708 else if(cmd == "modify_side") {
00709 std::string side = cfg["side"];
00710 std::string income = cfg["income"];
00711 std::string name = cfg["name"];
00712 std::string team_name = cfg["team_name"];
00713 std::string user_team_name = cfg["user_team_name"];
00714 std::string gold = cfg["gold"];
00715 std::string controller = cfg["controller"];
00716 std::string recruit_str = cfg["recruit"];
00717 std::string fog = cfg["fog"];
00718 std::string shroud = cfg["shroud"];
00719 std::string shroud_data = cfg["shroud_data"];
00720 std::string village_gold = cfg["village_gold"];
00721 const config::child_list& ai = cfg.get_parsed_config().get_children("ai");
00722
00723
00724
00725 assert(state_of_game != NULL);
00726 const int side_num = lexical_cast_default<int>(side,1);
00727 const size_t team_index = side_num-1;
00728
00729 if(team_index < teams->size()) {
00730 LOG_NG << "modifying side: " << side_num << "\n";
00731 if(!team_name.empty()) {
00732 LOG_NG << "change side's team to team_name '" << team_name << "'\n";
00733 (*teams)[team_index].change_team(team_name,
00734 user_team_name);
00735 }
00736
00737 if (!recruit_str.empty()) {
00738 std::vector<std::string> recruit = utils::split(recruit_str);
00739 if (recruit.size() == 1 && recruit.back() == "")
00740 recruit.clear();
00741
00742 std::set<std::string>& rlist_set = (*teams)[team_index].recruits();
00743 rlist_set.clear();
00744
00745 std::copy( recruit.begin(), recruit.end(), std::inserter(rlist_set,rlist_set.end()) );
00746 player_info *player = state_of_game->get_player((*teams)[team_index].save_id());
00747
00748 if (player) player->can_recruit = rlist_set;
00749 }
00750
00751 if(!income.empty()) {
00752 (*teams)[team_index].set_income(lexical_cast_default<int>(income));
00753 }
00754
00755 if(!gold.empty()) {
00756 (*teams)[team_index].spend_gold((*teams)[team_index].gold()-lexical_cast_default<int>(gold));
00757 }
00758
00759 if(!controller.empty()) {
00760 (*teams)[team_index].change_controller(controller);
00761 }
00762
00763 if (!shroud.empty()) {
00764 (*teams)[team_index].set_shroud( utils::string_bool(shroud, true) );
00765 }
00766
00767 if (!shroud_data.empty()) {
00768 (*teams)[team_index].merge_shroud_map_data(shroud_data);
00769 }
00770
00771 if (!fog.empty()) {
00772 (*teams)[team_index].set_fog( utils::string_bool(fog, true) );
00773 }
00774
00775 if (!village_gold.empty()) {
00776 (*teams)[team_index].set_village_gold(lexical_cast_default<int>(village_gold));
00777 }
00778
00779 if (!ai.empty()) {
00780 (*teams)[team_index].set_ai_parameters(ai);
00781 }
00782 }
00783 }
00784
00785 else if(cmd == "store_side" || cmd == "store_gold") {
00786 t_string *gold_store;
00787 std::string side = cfg["side"];
00788 std::string var_name = cfg["variable"];
00789 if(var_name.empty()) {
00790 var_name = cmd.substr(cmd.find_first_of('_') + 1);
00791 }
00792 assert(state_of_game != NULL);
00793 const int side_num = lexical_cast_default<int>(side,1);
00794 const size_t team_index = side_num-1;
00795 if(team_index < teams->size()) {
00796 if(cmd == "store_side") {
00797 config side_data;
00798 (*teams)[team_index].write(side_data);
00799 state_of_game->get_variable(var_name+".controller") = side_data["controller"];
00800 state_of_game->get_variable(var_name+".recruit") = side_data["recruit"];
00801 state_of_game->get_variable(var_name+".fog") = side_data["fog"];
00802 state_of_game->get_variable(var_name+".shroud") = side_data["shroud"];
00803
00804 state_of_game->get_variable(var_name+".income") = lexical_cast_default<std::string>((*teams)[team_index].income(),"");
00805 state_of_game->get_variable(var_name+".village_gold") = lexical_cast_default<std::string>((*teams)[team_index].village_gold(),"");
00806 state_of_game->get_variable(var_name+".name") = (*teams)[team_index].name();
00807 state_of_game->get_variable(var_name+".team_name") = (*teams)[team_index].team_name();
00808 state_of_game->get_variable(var_name+".user_team_name") = (*teams)[team_index].user_team_name();
00809 state_of_game->get_variable(var_name+".colour") = (*teams)[team_index].map_colour_to();
00810
00811 gold_store = &state_of_game->get_variable(var_name+".gold");
00812 } else {
00813 gold_store = &state_of_game->get_variable(var_name);
00814 }
00815 *gold_store = lexical_cast_default<std::string>((*teams)[team_index].gold(),"");
00816 }
00817 }
00818 else if(cmd == "modify_turns") {
00819 std::string value = cfg["value"];
00820 std::string add = cfg["add"];
00821 assert(state_of_game != NULL);
00822 assert(status_ptr != NULL);
00823 if(add != "") {
00824 status_ptr->modify_turns(add);
00825 } else {
00826 status_ptr->add_turns(-status_ptr->number_of_turns());
00827 status_ptr->add_turns(lexical_cast_default<int>(value,50));
00828 }
00829 }
00830 else if(cmd == "store_turns") {
00831 std::string var_name = cfg["variable"];
00832 if(var_name.empty()) {
00833 var_name = cmd.substr(cmd.find_first_of('_') + 1);
00834 }
00835 assert(state_of_game != NULL);
00836 assert(status_ptr != NULL);
00837 int turns = status_ptr->number_of_turns();
00838 state_of_game->get_variable(var_name) = lexical_cast_default<std::string>(turns,"");
00839 }
00840
00841
00842
00843 else if(cmd == "move_unit_fake") {
00844 std::string type = cfg["type"];
00845 std::string side = cfg["side"];
00846 std::string x = cfg["x"];
00847 std::string y = cfg["y"];
00848 std::string variation = cfg["variation"];
00849 assert(state_of_game != NULL);
00850
00851 size_t side_num = lexical_cast_default<int>(side,1)-1;
00852 if (side_num >= teams->size()) side_num = 0;
00853
00854 const unit_race::GENDER gender = string_gender(cfg["gender"]);
00855 const unit_type_data::unit_type_map::const_iterator itor = unit_type_data::types().find(type);
00856 if(itor != unit_type_data::types().end()) {
00857 assert(units != NULL);
00858 assert(game_map != NULL);
00859 assert(status_ptr != NULL);
00860 unit dummy_unit(units,game_map,status_ptr,teams,&itor->second,side_num+1,false,true,gender,variation);
00861 const std::vector<std::string> xvals = utils::split(x);
00862 const std::vector<std::string> yvals = utils::split(y);
00863 std::vector<gamemap::location> path;
00864 gamemap::location src;
00865 gamemap::location dst;
00866 for(size_t i = 0; i != minimum(xvals.size(),yvals.size()); ++i) {
00867 if(i==0){
00868 src.x = atoi(xvals[i].c_str())-1;
00869 src.y = atoi(yvals[i].c_str())-1;
00870 if (!game_map->on_board(src)) {
00871 ERR_CF << "invalid move_unit_fake source: " << src << '\n';
00872 break;
00873 }
00874 continue;
00875 }
00876 shortest_path_calculator calc(dummy_unit,
00877 (*teams)[side_num],
00878 *units,
00879 *teams,
00880 *game_map);
00881
00882 dst.x = atoi(xvals[i].c_str())-1;
00883 dst.y = atoi(yvals[i].c_str())-1;
00884 if (!game_map->on_board(dst)) {
00885 ERR_CF << "invalid move_unit_fake destination: " << dst << '\n';
00886 break;
00887 }
00888
00889 paths::route route = a_star_search(src, dst, 10000, &calc,
00890 game_map->w(), game_map->h());
00891
00892 if (route.steps.size() == 0) {
00893 WRN_NG << "Could not find move_unit_fake route from " << src << " to " << dst << ": ignoring complexities\n";
00894 emergency_path_calculator calc(dummy_unit, *game_map);
00895
00896 route = a_star_search(src, dst, 10000, &calc,
00897 game_map->w(), game_map->h());
00898 assert(route.steps.size() > 0);
00899 }
00900 unit_display::move_unit(route.steps, dummy_unit, *teams);
00901
00902 src = dst;
00903 }
00904 }
00905 }
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 else if(cmd == "objectives") {
00940 const std::string win_str = "@";
00941 const std::string lose_str = "#";
00942
00943 assert(state_of_game != NULL);
00944 const t_string summary = cfg["summary"];
00945 const t_string note = cfg["note"];
00946 std::string side = cfg["side"];
00947 bool silent = utils::string_bool(cfg["silent"]);
00948 const size_t side_num = lexical_cast_default<size_t>(side,0);
00949
00950 if(side_num != 0 && (side_num - 1) >= teams->size()) {
00951 ERR_NG << "Invalid side: " << cfg["side"] << " in objectives event\n";
00952 return;
00953 }
00954
00955 t_string win_string = cfg["victory_string"];
00956 if(win_string.empty())
00957 win_string = t_string(N_("Victory:"), "wesnoth");
00958 t_string lose_string = cfg["defeat_string"];
00959 if(lose_string.empty())
00960 lose_string = t_string(N_("Defeat:"), "wesnoth");
00961
00962 t_string win_objectives;
00963 t_string lose_objectives;
00964
00965 const vconfig::child_list objectives = cfg.get_children("objective");
00966 for(vconfig::child_list::const_iterator obj_it = objectives.begin();
00967 obj_it != objectives.end(); ++obj_it) {
00968
00969 t_string description = (*obj_it)["description"];
00970 std::string condition = (*obj_it)["condition"];
00971 LOG_NG << condition << " objective: " << description << "\n";
00972 if(condition == "win") {
00973 win_objectives += "\n";
00974 win_objectives += win_str;
00975 win_objectives += description;
00976 } else if(condition == "lose") {
00977 lose_objectives += "\n";
00978 lose_objectives += lose_str;
00979 lose_objectives += description;
00980 } else {
00981 ERR_NG << "unknown condition '" << condition << "', ignoring\n";
00982 }
00983 }
00984
00985 t_string objs;
00986 if(!summary.empty())
00987 objs += "*" + summary + "\n";
00988 if(!win_objectives.empty()) {
00989 objs += "*" + win_string + "\n";
00990 objs += win_objectives + "\n";
00991 }
00992 if(!lose_objectives.empty()) {
00993 objs += "*" + lose_string + "\n";
00994 objs += lose_objectives + "\n";
00995 }
00996 if(!note.empty())
00997 objs += note + "\n";
00998
00999 if(side_num == 0) {
01000 for(std::vector<team>::iterator itor = teams->begin();
01001 itor != teams->end(); ++itor) {
01002
01003 itor->set_objectives(objs, silent);
01004 }
01005 } else {
01006 (*teams)[side_num - 1].set_objectives(objs, silent);
01007 }
01008 }
01009
01010
01011
01012 else if(cmd == "set_variable") {
01013 assert(state_of_game != NULL);
01014
01015 const std::string name = cfg["name"];
01016 t_string& var = state_of_game->get_variable(name);
01017
01018 const t_string& literal = cfg.get_attribute("literal");
01019 if(literal.empty() == false) {
01020 var = literal;
01021 }
01022
01023 const t_string value = cfg["value"];
01024 if(value.empty() == false) {
01025 var = value;
01026 }
01027
01028 const t_string format = cfg["format"];
01029 if(format.empty() == false) {
01030 var = format;
01031 }
01032
01033 const std::string to_variable = cfg["to_variable"];
01034 if(to_variable.empty() == false) {
01035 var = state_of_game->get_variable(to_variable);
01036 }
01037
01038 const std::string add = cfg["add"];
01039 if(add.empty() == false) {
01040 int value = int(atof(var.c_str()));
01041 value += atoi(add.c_str());
01042 char buf[50];
01043 snprintf(buf,sizeof(buf),"%d",value);
01044 var = buf;
01045 }
01046
01047 const std::string multiply = cfg["multiply"];
01048 if(multiply.empty() == false) {
01049 int value = int(atof(var.c_str()));
01050 value = int(double(value) * atof(multiply.c_str()));
01051 char buf[50];
01052 snprintf(buf,sizeof(buf),"%d",value);
01053 var = buf;
01054 }
01055
01056 const std::string divide = cfg["divide"];
01057 if(divide.empty() == false) {
01058 int value = int(atof(var.c_str()));
01059 double divider = atof(divide.c_str());
01060 if (divider == 0) {
01061 ERR_NG << "division by zero on variable " << name << "\n";
01062 return;
01063 } else {
01064 value = int(double(value) / divider);
01065 char buf[50];
01066 snprintf(buf,sizeof(buf),"%d",value);
01067 var = buf;
01068 }
01069 }
01070
01071 const std::string modulo = cfg["modulo"];
01072 if(modulo.empty() == false) {
01073 int value = atoi(var.c_str());
01074 int divider = atoi(modulo.c_str());
01075 if (divider == 0) {
01076 ERR_NG << "division by zero on variable " << name << "\n";
01077 return;
01078 } else {
01079 value %= divider;
01080 var = str_cast(value);
01081 }
01082 }
01083
01084 const t_string string_length_target = cfg["string_length"];
01085 if(string_length_target.empty() == false) {
01086 const int value = string_length_target.str().length();
01087 var = str_cast(value);
01088 }
01089
01090
01091
01092 const std::string time = cfg["time"];
01093 if(time == "stamp") {
01094 char buf[50];
01095 snprintf(buf,sizeof(buf),"%d",SDL_GetTicks());
01096 var = buf;
01097 }
01098
01099
01100
01101
01102
01103
01104 const std::string random = cfg["random"];
01105 if(random.empty() == false) {
01106
01107
01108
01109
01110
01111
01112 std::string random_value;
01113
01114 if(get_replay_source().at_end()) {
01115 std::string word;
01116 std::vector<std::string> words;
01117 std::vector<std::pair<long,long> > ranges;
01118 int num_choices = 0;
01119 std::string::size_type pos = 0, pos2 = std::string::npos;
01120 std::stringstream ss(std::stringstream::in|std::stringstream::out);
01121 while (pos2 != random.length()) {
01122 pos = pos2+1;
01123 pos2 = random.find(",", pos);
01124
01125 if (pos2 == std::string::npos)
01126 pos2 = random.length();
01127
01128 word = random.substr(pos, pos2-pos);
01129 words.push_back(word);
01130 std::string::size_type tmp = word.find("..");
01131
01132
01133 if (tmp == std::string::npos) {
01134
01135 ranges.push_back(std::pair<int, int>(0,0));
01136 num_choices += 1;
01137 }
01138 else {
01139
01140 const std::string first = word.substr(0, tmp);
01141 const std::string second = word.substr(tmp+2,
01142 random.length());
01143
01144 long low, high;
01145 ss << first + " " + second;
01146 ss >> low;
01147 ss >> high;
01148 ss.clear();
01149
01150 if (low > high) {
01151 tmp = low;
01152 low = high;
01153 high = tmp;
01154 }
01155 ranges.push_back(std::pair<long, long>(low,high));
01156 num_choices += (high - low) + 1;
01157 }
01158 }
01159
01160 int choice = get_random() % num_choices;
01161 int tmp = 0;
01162 for(size_t i = 0; i < ranges.size(); i++) {
01163 tmp += (ranges[i].second - ranges[i].first) + 1;
01164 if (tmp > choice) {
01165 if (ranges[i].first == 0 && ranges[i].second == 0) {
01166 random_value = words[i];
01167 }
01168 else {
01169 tmp = (ranges[i].second - (tmp - choice)) + 1;
01170 ss << tmp;
01171 ss >> random_value;
01172 }
01173 break;
01174 }
01175 }
01176 recorder.set_random_value(random_value.c_str());
01177 }
01178
01179
01180 else {
01181 const config* const action = get_replay_source().get_next_action();
01182 if(action == NULL || action->get_children("random_number").empty()) {
01183 replay::throw_error("random_number expected but none found\n");
01184 }
01185
01186 const std::string& val = (*(action->get_children("random_number").front()))["value"];
01187 random_value = val;
01188 }
01189 var = random_value;
01190 }
01191
01192
01193 const std::string rand = cfg["rand"];
01194 if(rand.empty() == false) {
01195 assert(state_of_game);
01196
01197 std::string random_value;
01198
01199 std::string word;
01200 std::vector<std::string> words;
01201 std::vector<std::pair<long,long> > ranges;
01202 int num_choices = 0;
01203 std::string::size_type pos = 0, pos2 = std::string::npos;
01204 std::stringstream ss(std::stringstream::in|std::stringstream::out);
01205 while (pos2 != rand.length()) {
01206 pos = pos2+1;
01207 pos2 = rand.find(",", pos);
01208
01209 if (pos2 == std::string::npos)
01210 pos2 = rand.length();
01211
01212 word = rand.substr(pos, pos2-pos);
01213 words.push_back(word);
01214 std::string::size_type tmp = word.find("..");
01215
01216
01217 if (tmp == std::string::npos) {
01218
01219 ranges.push_back(std::pair<int, int>(0,0));
01220 num_choices += 1;
01221 }
01222 else {
01223
01224 const std::string first = word.substr(0, tmp);
01225 const std::string second = word.substr(tmp+2,
01226 rand.length());
01227
01228 long low, high;
01229 ss << first + " " + second;
01230 ss >> low;
01231 ss >> high;
01232 ss.clear();
01233
01234 if (low > high) {
01235 tmp = low;
01236 low = high;
01237 high = tmp;
01238 }
01239 ranges.push_back(std::pair<long, long>(low,high));
01240 num_choices += (high - low) + 1;
01241 }
01242 }
01243
01244 int choice = state_of_game->rng().get_random() % num_choices;
01245 int tmp = 0;
01246 for(size_t i = 0; i < ranges.size(); i++) {
01247 tmp += (ranges[i].second - ranges[i].first) + 1;
01248 if (tmp > choice) {
01249 if (ranges[i].first == 0 && ranges[i].second == 0) {
01250 random_value = words[i];
01251 }
01252 else {
01253 tmp = (ranges[i].second - (tmp - choice)) + 1;
01254 ss << tmp;
01255 ss >> random_value;
01256 }
01257 break;
01258 }
01259 }
01260
01261 var = random_value;
01262 }
01263
01264
01265 const vconfig::child_list join_elements = cfg.get_children("join");
01266 if(!join_elements.empty())
01267 {
01268 const vconfig join_element=join_elements.front();
01269
01270 std::string array_name=join_element["variable"];
01271 std::string separator=join_element["separator"];
01272 std::string key_name=join_element["key"];
01273
01274 if(key_name.empty())
01275 {
01276 key_name="value";
01277 }
01278
01279 bool remove_empty=utils::string_bool(join_element["remove_empty"]);
01280
01281 variable_info::array_range array=state_of_game->get_variable_cfgs(array_name);
01282
01283 std::string joined_string;
01284 std::string current_string;
01285
01286 for(std::vector<config*>::iterator i=array.first; i!=array.second; ++i)
01287 {
01288 current_string=(**i)[key_name];
01289 if(remove_empty && current_string.empty())
01290 {
01291 continue;
01292 }
01293
01294 joined_string+=current_string;
01295 if(i+1!=array.second)
01296 {
01297 joined_string+=separator;
01298 }
01299 }
01300
01301 var=joined_string;
01302 }
01303
01304 }
01305
01306 else if(cmd == "set_variables")
01307 {
01308 assert(state_of_game != NULL);
01309
01310 const std::string name = cfg["name"];
01311
01312 std::string mode = cfg["mode"];
01313 if(mode!="append"&&mode!="merge")
01314 {
01315 mode="replace";
01316 }
01317
01318 const t_string to_variable = cfg["to_variable"];
01319 const vconfig::child_list values = cfg.get_children("value");
01320 const vconfig::child_list literals = cfg.get_children("literal");
01321 const vconfig::child_list split_elements = cfg.get_children("split");
01322
01323 std::vector<config> data;
01324
01325 if(!to_variable.empty())
01326 {
01327 variable_info::array_range range = state_of_game->get_variable_cfgs(to_variable);
01328 for( ; range.first != range.second; ++range.first)
01329 {
01330 data.push_back(**range.first);
01331 }
01332 } else if(!values.empty()) {
01333 for(vconfig::child_list::const_iterator i=values.begin(); i!=values.end(); ++i)
01334 {
01335 data.push_back((*i).get_parsed_config());
01336 }
01337 } else if(!literals.empty()) {
01338 for(vconfig::child_list::const_iterator i=literals.begin(); i!=literals.end(); ++i)
01339 {
01340 data.push_back(i->get_config());
01341 }
01342 } else if(!split_elements.empty()) {
01343 const vconfig split_element=split_elements.front();
01344
01345 std::string split_string=split_element["list"];
01346 std::string separator_string=split_element["separator"];
01347 std::string key_name=split_element["key"];
01348 if(key_name.empty())
01349 {
01350 key_name="value";
01351 }
01352
01353 bool remove_empty=utils::string_bool(split_element["remove_empty"]);
01354
01355 char* separator = separator_string.empty() ? NULL : &separator_string[0];
01356
01357 std::vector<std::string> split_vector;
01358
01359
01360 if(separator == NULL)
01361 {
01362 for(std::string::iterator i=split_string.begin(); i!=split_string.end(); ++i)
01363 {
01364 split_vector.push_back(&*i);
01365 }
01366 }
01367 else {
01368 split_vector=utils::split(split_string, *separator, remove_empty ? utils::REMOVE_EMPTY | utils::STRIP_SPACES : utils::STRIP_SPACES);
01369 }
01370
01371 state_of_game->clear_variable_cfg(name);
01372 for(std::vector<std::string>::iterator i=split_vector.begin(); i!=split_vector.end(); ++i)
01373 {
01374 config item = config();
01375 item[key_name]=*i;
01376 data.push_back(item);
01377 }
01378 }
01379
01380 if(!data.empty())
01381 {
01382 if(mode == "replace")
01383 {
01384 state_of_game->clear_variable_cfg(name);
01385 }
01386 if(mode == "merge")
01387 {
01388 variable_info::array_range target = state_of_game->get_variable_cfgs(name);
01389 std::vector<config>::iterator i=data.begin();
01390 config::child_list::iterator j=target.first;
01391 while(i!=data.end())
01392 {
01393 if(j!=target.second)
01394 {
01395 (*j)->merge_with(*i);
01396 ++j;
01397 } else {
01398 state_of_game->add_variable_cfg(name, *i);
01399 }
01400 ++i;
01401 }
01402 } else {
01403 for(std::vector<config>::iterator i=data.begin(); i!=data.end(); ++i)
01404 {
01405 state_of_game->add_variable_cfg(name, *i);
01406 }
01407 }
01408 return;
01409 }
01410 }
01411
01412
01413 else if(cmd == "if" || cmd == "while") {
01414 log_scope(cmd);
01415 const size_t max_iterations = (cmd == "if" ? 1 : game_config::max_loop);
01416 const std::string pass = (cmd == "if" ? "then" : "do");
01417 const std::string fail = (cmd == "if" ? "else" : "");
01418 for(size_t i = 0; i != max_iterations; ++i) {
01419 const std::string type = game_events::conditional_passed(
01420 units,cfg) ? pass : fail;
01421
01422 if(type == "") {
01423 break;
01424 }
01425
01426
01427
01428 const vconfig::child_list commands = cfg.get_children(type);
01429 for(vconfig::child_list::const_iterator cmd = commands.begin();
01430 cmd != commands.end(); ++cmd) {
01431 if(!handle_event(event_info, *cmd)) {
01432 mutated = false;
01433 }
01434 }
01435 }
01436 }
01437
01438 else if(cmd == "switch") {
01439 assert(state_of_game != NULL);
01440
01441 const std::string var_name = cfg["variable"];
01442 const std::string& var = state_of_game->get_variable_const(var_name);
01443
01444 bool not_found = true;
01445 const vconfig::child_list& cases = cfg.get_children("case");
01446
01447 for(vconfig::child_list::const_iterator c = cases.begin(); c != cases.end(); ++c) {
01448 const std::string value = (*c)["value"];
01449 if (var == value) {
01450 not_found = false;
01451 if(!handle_event(event_info, *c)) {
01452 mutated = false;
01453 }
01454 }
01455 }
01456 if (not_found) {
01457
01458 const vconfig::child_list elses = cfg.get_children("else");
01459 for(vconfig::child_list::const_iterator e = elses.begin(); e != elses.end(); ++e) {
01460 if(!handle_event(event_info, *e)) {
01461 mutated = false;
01462 }
01463 }
01464 }
01465 }
01466
01467 else if(cmd == "role") {
01468
01469
01470 std::vector<std::string> types = utils::split(cfg["type"]);
01471 if (types.size() == 0) types.push_back("");
01472
01473 std::vector<std::string> sides = utils::split(cfg["side"]);
01474
01475
01476
01477 std::vector<std::string>::iterator ti;
01478 for(ti = types.begin(); ti != types.end(); ++ti) {
01479 config item = cfg.get_config();
01480 item["type"] = *ti;
01481 item["role"] = "";
01482 vconfig filter(&item);
01483
01484 unit_map::iterator itor;
01485 for(itor = units->begin(); itor != units->end(); ++itor) {
01486 if(game_events::unit_matches_filter(itor, filter)) {
01487 itor->second.assign_role(cfg["role"]);
01488 break;
01489 }
01490 }
01491
01492 if(itor != units->end())
01493 break;
01494
01495 bool found = false;
01496
01497 if(sides.empty() == false) {
01498 std::vector<std::string>::const_iterator si;
01499 for(si = sides.begin(); si != sides.end(); ++si) {
01500 int side_num = lexical_cast_default<int>(*si,1);
01501 const std::string player_id = (*teams)[side_num-1].save_id();
01502 player_info* player=state_of_game->get_player(player_id);
01503
01504 if(!player)
01505 continue;
01506
01507
01508 std::vector<unit>::iterator ui;
01509 for(ui = player->available_units.begin();
01510 ui != player->available_units.end(); ++ui) {
01511 ui->set_game_context(units,game_map,status_ptr,teams);
01512 scoped_recall_unit auto_store("this_unit", player_id,
01513 (ui - player->available_units.begin()));
01514 if(game_events::unit_matches_filter(*ui, filter,gamemap::location())) {
01515 ui->assign_role(cfg["role"]);
01516 found=true;
01517 break;
01518 }
01519 }
01520 }
01521 } else {
01522 std::map<std::string, player_info>::iterator pi;
01523 for(pi=state_of_game->players.begin();
01524 pi!=state_of_game->players.end(); ++pi) {
01525 std::vector<unit>::iterator ui;
01526
01527 for(ui = pi->second.available_units.begin();
01528 ui != pi->second.available_units.end(); ++ui) {
01529 ui->set_game_context(units,game_map,status_ptr,teams);
01530 scoped_recall_unit auto_store("this_unit", pi->first,
01531 (ui - pi->second.available_units.begin()));
01532 if(game_events::unit_matches_filter(*ui, filter,gamemap::location())) {
01533 ui->assign_role(cfg["role"]);
01534 found=true;
01535 break;
01536 }
01537 }
01538 }
01539 }
01540
01541
01542 if (found) break;
01543 }
01544 }
01545
01546 else if(cmd == "removeitem") {
01547 std::string img = cfg["image"];
01548 assert(state_of_game != NULL);
01549 gamemap::location loc = cfg_to_loc(cfg);
01550
01551 if(!loc.valid()) {
01552 loc = event_info.loc1;
01553 }
01554
01555 if(!img.empty()) {
01556 screen->remove_single_overlay(loc, img);
01557 }
01558 else {
01559 screen->remove_overlay(loc);
01560 }
01561 }
01562
01563 else if(cmd == "unit_overlay") {
01564 std::string img = cfg["image"];
01565 assert(state_of_game != NULL);
01566 for(unit_map::iterator itor = units->begin(); itor != units->end(); ++itor) {
01567 if(game_events::unit_matches_filter(itor,cfg)) {
01568 itor->second.add_overlay(img);
01569 break;
01570 }
01571 }
01572 }
01573
01574 else if(cmd == "remove_unit_overlay") {
01575 std::string img = cfg["image"];
01576 assert(state_of_game != NULL);
01577 for(unit_map::iterator itor = units->begin(); itor != units->end(); ++itor) {
01578 if(game_events::unit_matches_filter(itor,cfg)) {
01579 itor->second.remove_overlay(img);
01580 break;
01581 }
01582 }
01583 }
01584
01585
01586 else if(cmd == "hide_unit") {
01587 const gamemap::location loc = cfg_to_loc(cfg);
01588 unit_map::iterator u = units->find(loc);
01589 if(u != units->end()) {
01590 u->second.set_hidden(true);
01591 screen->invalidate(loc);
01592 screen->draw();
01593 }
01594 }
01595
01596 else if(cmd == "unhide_unit") {
01597 const gamemap::location loc = cfg_to_loc(cfg);
01598 unit_map::iterator u;
01599
01600 for(u = units->begin(); u != units->end() ; u++) {
01601 u->second.set_hidden(false);
01602 screen->invalidate(loc);
01603 screen->draw();
01604 }
01605 }
01606
01607
01608 else if(cmd == "item") {
01609 gamemap::location loc = cfg_to_loc(cfg);
01610 std::string img = cfg["image"];
01611 std::string halo = cfg["halo"];
01612 assert(state_of_game != NULL);
01613 if(!img.empty() || !halo.empty()) {
01614 screen->add_overlay(loc,img,halo);
01615 screen->invalidate(loc);
01616 screen->draw();
01617 }
01618 }
01619
01620 else if(cmd == "sound_source") {
01621 std::string sounds = cfg["sounds"];
01622 std::string id = cfg["id"];
01623 std::string delay = cfg["delay"];
01624 std::string chance = cfg["chance"];
01625 std::string play_fogged = cfg["check_fogged"];
01626 std::string x = cfg["x"];
01627 std::string y = cfg["y"];
01628 std::string loop = cfg["loop"];
01629 std::string full_range = cfg["full_range"];
01630 std::string fade_range = cfg["fade_range"];
01631
01632 assert(state_of_game != NULL);
01633
01634 if(!sounds.empty() && !delay.empty() && !chance.empty()) {
01635 const std::vector<std::string>& vx = utils::split(x);
01636 const std::vector<std::string>& vy = utils::split(y);
01637
01638 if(vx.size() != vy.size()) {
01639 lg::wml_error << "invalid number of sound source location coordinates";
01640 return;
01641 }
01642
01643 soundsource::sourcespec spec(id, sounds, lexical_cast_default<int>(delay, 1000), lexical_cast_default<int>(chance, 100));
01644
01645 spec.loop(lexical_cast_default<int>(loop, 0));
01646
01647 if(!full_range.empty()) {
01648 spec.full_range(lexical_cast<int>(full_range));
01649 }
01650
01651 if(!fade_range.empty()) {
01652 spec.fade_range(lexical_cast<int>(fade_range));
01653 }
01654
01655 if(play_fogged.empty()) {
01656 spec.check_fog(true);
01657 } else {
01658 spec.check_fog(utils::string_bool(play_fogged));
01659 }
01660
01661 for(unsigned int i = 0; i < minimum(vx.size(), vy.size()); ++i) {
01662 gamemap::location loc(lexical_cast<int>(vx[i]), lexical_cast<int>(vy[i]));
01663 spec.location(loc);
01664 }
01665
01666 soundsources->add(spec);
01667 }
01668 }
01669
01670 else if(cmd == "remove_sound_source") {
01671 soundsources->remove(cfg["id"]);
01672 }
01673
01674
01675 else if(cmd == "terrain") {
01676 const std::vector<gamemap::location> locs = multiple_locs(cfg);
01677
01678 std::string terrain_type = cfg["terrain"];
01679
01680 if (terrain_type.empty())
01681 terrain_type = cfg["letter"];
01682 assert(state_of_game != NULL);
01683
01684 t_translation::t_terrain terrain = t_translation::read_terrain_code(terrain_type);
01685
01686 if(terrain != t_translation::NONE_TERRAIN) {
01687
01688 gamemap::tmerge_mode mode = gamemap::BOTH;
01689 if (cfg["layer"] == "base") {
01690 mode = gamemap::BASE;
01691 }
01692 else if (cfg["layer"] == "overlay") {
01693 mode = gamemap::OVERLAY;
01694 }
01695
01696 for(std::vector<gamemap::location>::const_iterator loc = locs.begin(); loc != locs.end(); ++loc) {
01697 const t_translation::t_terrain old_terrain = game_map->get_terrain(*loc);
01698 const t_translation::t_terrain new_terrain = game_map->merge_terrains(old_terrain, terrain, mode, utils::string_bool(cfg["replace_if_failed"]) );
01699 if (new_terrain != t_translation::NONE_TERRAIN) {
01700
01701 preferences::encountered_terrains().insert(new_terrain);
01702 const bool old_village = game_map->is_village(*loc);
01703 const bool new_village = game_map->is_village(new_terrain);
01704
01705 if(old_village && !new_village) {
01706 int owner = village_owner(*loc, *teams);
01707 if(owner != -1) {
01708 (*teams)[owner].lose_village(*loc);
01709 }
01710 }
01711
01712 game_map->set_terrain(*loc, new_terrain);
01713
01714 const t_translation::t_list underlaying_list = game_map->underlying_union_terrain(*loc);
01715 for (t_translation::t_list::const_iterator ut = underlaying_list.begin(); ut != underlaying_list.end(); ut++) {
01716 preferences::encountered_terrains().insert(*ut);
01717 };
01718 }
01719 }
01720 rebuild_screen_ = true;
01721 }
01722 }
01723
01724
01725 else if(cmd == "terrain_mask") {
01726 gamemap::location loc = cfg_to_loc(cfg, 1, 1);
01727
01728 gamemap mask(*game_map);
01729
01730 try {
01731 mask.read(cfg["mask"]);
01732 } catch(gamemap::incorrect_format_exception&) {
01733 ERR_NG << "terrain mask is in the incorrect format, and couldn't be applied\n";
01734 return;
01735 } catch(twml_exception& e) {
01736 e.show(*screen);
01737 return;
01738 }
01739
01740 game_map->overlay(mask, cfg.get_parsed_config(), loc.x, loc.y);
01741 rebuild_screen_ = true;
01742 }
01743
01744
01745 else if(cmd == "unit") {
01746 assert(units != NULL);
01747 assert(game_map != NULL);
01748 assert(status_ptr != NULL);
01749 assert(state_of_game != NULL);
01750 unit new_unit(units,game_map,status_ptr,teams,cfg.get_parsed_config(),true, state_of_game);
01751 preferences::encountered_units().insert(new_unit.type_id());
01752 gamemap::location loc = cfg_to_loc(cfg);
01753
01754 if(game_map->on_board(loc)) {
01755 loc = find_vacant_tile(*game_map,*units,loc);
01756 const bool show = screen != NULL && !screen->fogged(loc);
01757 const bool animate = show && utils::string_bool(cfg["animate"], false);
01758
01759 units->erase(loc);
01760 units->add(new std::pair<gamemap::location,unit>(loc,new_unit));
01761 unit_mutations++;
01762 if(game_map->is_village(loc)) {
01763 get_village(loc,*screen,*teams,new_unit.side()-1,*units);
01764 }
01765
01766 screen->invalidate(loc);
01767
01768 unit_map::iterator un = units->find(loc);
01769
01770 if(animate) {
01771 unit_display::unit_recruited(loc);
01772 }
01773 else if(show) {
01774 screen->draw();
01775 }
01776 } else {
01777 player_info* const player = state_of_game->get_player((*teams)[new_unit.side()-1].save_id());
01778
01779 if(player != NULL) {
01780 player->available_units.push_back(new_unit);
01781 } else {
01782 ERR_NG << "Cannot create unit: location (" << loc.x << "," << loc.y <<") is not on the map, and player "
01783 << new_unit.side() << " has no recall list.\n";
01784 }
01785 }
01786 }
01787
01788
01789 else if(cmd == "recall") {
01790 LOG_NG << "recalling unit...\n";
01791 bool unit_recalled = false;
01792 config temp_config(cfg.get_config());
01793
01794
01795
01796 temp_config["x"] = "";
01797 temp_config["y"] = "";
01798 vconfig unit_filter(&temp_config);
01799 for(int index = 0; !unit_recalled && index < int(teams->size()); ++index) {
01800 LOG_NG << "for side " << index << "...\n";
01801 const std::string player_id = (*teams)[index].save_id();
01802 player_info* const player = state_of_game->get_player(player_id);
01803
01804 if(player == NULL) {
01805 ERR_NG << "player not found!\n";
01806 continue;
01807 }
01808
01809 std::vector<unit>& avail = player->available_units;
01810
01811 for(std::vector<unit>::iterator u = avail.begin(); u != avail.end(); ++u) {
01812 DBG_NG << "checking unit against filter...\n";
01813 u->set_game_context(units,game_map,status_ptr,teams);
01814 scoped_recall_unit auto_store("this_unit", player_id, u - avail.begin());
01815 if(game_events::unit_matches_filter(*u, unit_filter, gamemap::location())) {
01816 gamemap::location loc = cfg_to_loc(cfg);
01817 unit to_recruit(*u);
01818 avail.erase(u);
01819 unit_mutations++;
01820 recruit_unit(*game_map,index+1,*units,to_recruit,loc,true,utils::string_bool(cfg["show"],true),false,true,true);
01821 unit_recalled = true;
01822 break;
01823 }
01824 }
01825 }
01826 } else if(cmd == "object") {
01827 const vconfig filter = cfg.child("filter");
01828
01829 std::string id = cfg["id"];
01830 assert(state_of_game != NULL);
01831
01832
01833 if(id != "" && used_items.count(id))
01834 return;
01835
01836 std::string image = cfg["image"];
01837 std::string caption = cfg["name"];
01838 std::string text;
01839
01840 gamemap::location loc;
01841 if(!filter.null()) {
01842 for(unit_map::const_iterator u = units->begin(); u != units->end(); ++u) {
01843 if(game_events::unit_matches_filter(u, filter)) {
01844 loc = u->first;
01845 break;
01846 }
01847 }
01848 }
01849
01850 if(loc.valid() == false) {
01851 loc = event_info.loc1;
01852 }
01853
01854 const unit_map::iterator u = units->find(loc);
01855
01856 std::string command_type = "then";
01857
01858 if(u != units->end() && (filter.null() || game_events::unit_matches_filter(u, filter))) {
01859 text = cfg["description"];
01860
01861 u->second.add_modification("object", cfg.get_parsed_config());
01862
01863 screen->select_hex(event_info.loc1);
01864 screen->invalidate_unit();
01865
01866
01867 used_items.insert(id);
01868 } else {
01869 text = cfg["cannot_use_message"];
01870 command_type = "else";
01871 }
01872
01873 if(!utils::string_bool(cfg["silent"])) {
01874 surface surface(NULL);
01875
01876 if(image.empty() == false) {
01877 surface.assign(image::get_image(image));
01878 }
01879
01880
01881 screen->draw();
01882
01883 try {
01884 const std::string duration_str = cfg["duration"];
01885 const unsigned int lifetime = average_frame_time
01886 * lexical_cast_default<unsigned int>(duration_str, prevent_misclick_duration);
01887
01888 wml_event_dialog to_show(*screen,((surface.null())? caption : ""),text);
01889 if(!surface.null()) {
01890 to_show.set_image(surface, caption);
01891 }
01892 to_show.layout();
01893 to_show.show(lifetime);
01894 } catch(utils::invalid_utf8_exception&) {
01895
01896 }
01897 }
01898
01899 const vconfig::child_list commands = cfg.get_children(command_type);
01900 for(vconfig::child_list::const_iterator cmd = commands.begin();
01901 cmd != commands.end(); ++cmd) {
01902 if(!handle_event(event_info, *cmd)) {
01903 mutated = false;
01904 }
01905 }
01906 }
01907
01908
01909 else if(cmd == "print") {
01910 std::string text = cfg["text"];
01911 std::string size_str = cfg["size"];
01912 std::string duration_str = cfg["duration"];
01913 std::string red_str = cfg["red"];
01914 std::string green_str = cfg["green"];
01915 std::string blue_str = cfg["blue"];
01916
01917 assert(state_of_game != NULL);
01918 const int size = lexical_cast_default<int>(size_str,font::SIZE_SMALL);
01919 const int lifetime = lexical_cast_default<int>(duration_str,50);
01920 const int red = lexical_cast_default<int>(red_str,0);
01921 const int green = lexical_cast_default<int>(green_str,0);
01922 const int blue = lexical_cast_default<int>(blue_str,0);
01923
01924 SDL_Color colour = {red,green,blue,255};
01925
01926
01927 if (floating_label)
01928 font::remove_floating_label(floating_label);
01929
01930 const std::string& msg = text;
01931 if(msg != "") {
01932 const SDL_Rect rect = screen->map_outside_area();
01933 floating_label = font::add_floating_label(msg,size,colour,
01934 rect.w/2,rect.h/2,0.0,0.0,lifetime,rect,font::CENTER_ALIGN);
01935 }
01936 }
01937
01938 else if(cmd == "deprecated_message") {
01939
01940 const std::string message = cfg["message"];
01941 lg::wml_error << message << '\n';
01942 }
01943
01944 else if(cmd == "debug_message") {
01945 const std::string log_level = cfg["logger"];
01946 const std::string log_message = cfg["message"];
01947 if (log_level == "err" || log_level == "error")
01948 ERR_NO << log_message << "\n";
01949 else if (log_level == "warn" || log_level == "wrn" || log_level == "warning")
01950 WRN_NO << log_message << "\n";
01951 else
01952 LOG_NO << log_message << "\n";
01953 }
01954
01955
01956 else if(cmd == "message") {
01957
01958 const vconfig::child_list menu_items = cfg.get_children("option");
01959
01960 const vconfig::child_list text_input_elements = cfg.get_children("text_input");
01961 const bool has_text_input = (text_input_elements.size() == 1);
01962
01963 bool has_input= (has_text_input || !menu_items.empty() );
01964
01965 if (skip_messages && !has_input ) {
01966 return;
01967 }
01968
01969
01970 std::string side_for_raw = cfg["side_for"];
01971 bool side_for_show = true;
01972 if (!side_for_raw.empty())
01973 {
01974
01975 assert(state_of_game != 0);
01976 side_for_show = false;
01977
01978 std::vector<std::string> side_for =
01979 utils::split(side_for_raw, ',', utils::STRIP_SPACES | utils::REMOVE_EMPTY);
01980 std::vector<std::string>::iterator itSide;
01981 size_t side;
01982
01983
01984 for (itSide = side_for.begin(); itSide != side_for.end(); ++itSide)
01985 {
01986 side = lexical_cast_default<size_t>(*itSide);
01987
01988
01989 if (side > 0
01990 && side <= teams->size()
01991 && (*teams)[side-1].is_human())
01992 {
01993 side_for_show = true;
01994 break;
01995 }
01996 }
01997 if (!side_for_show)
01998 {
01999 DBG_NG << "player isn't controlling side which should get message\n";
02000 }
02001 }
02002 unit_map::iterator speaker = units->end();
02003
02004 std::string speaker_str = cfg["speaker"];
02005 assert(state_of_game != NULL);
02006 if(speaker_str == "unit") {
02007 speaker = units->find(event_info.loc1);
02008 } else if(speaker_str == "second_unit") {
02009 speaker = units->find(event_info.loc2);
02010 } else if(speaker_str != "narrator") {
02011 for(speaker = units->begin(); speaker != units->end(); ++speaker){
02012 if(game_events::unit_matches_filter(speaker,cfg))
02013 break;
02014 }
02015 }
02016
02017 if(speaker == units->end() && speaker_str != "narrator") {
02018
02019
02020 WRN_NG << "cannot show message\n";
02021 return;
02022 }
02023
02024 if(speaker != units->end()) {
02025 LOG_NG << "set speaker to '" << speaker->second.name() << "'\n";
02026 } else {
02027 LOG_NG << "no speaker\n";
02028 }
02029
02030 std::string sfx = cfg["sound"];
02031 if(sfx != "") {
02032 sound::play_sound(sfx);
02033 }
02034
02035 std::string image = cfg["image"];
02036 std::string caption = cfg["caption"];
02037
02038 if(speaker != units->end()) {
02039 LOG_DP << "scrolling to speaker..\n";
02040 screen->highlight_hex(speaker->first);
02041 const int offset_from_center = maximum<int>(0, speaker->first.y - 1);
02042 screen->scroll_to_tile(gamemap::location(speaker->first.x,offset_from_center));
02043 screen->highlight_hex(speaker->first);
02044
02045 if(image.empty()) {
02046 image = speaker->second.profile();
02047 if(image == speaker->second.absolute_image()) {
02048 std::stringstream ss;
02049
02050 #ifdef LOW_MEM
02051 ss << image;
02052 #else
02053 ss << image << speaker->second.image_mods();
02054 #endif
02055
02056 image = ss.str();
02057 }
02058 }
02059
02060 if(caption.empty()) {
02061 caption = speaker->second.name();
02062 if(caption.empty()) {
02063 caption = speaker->second.type_name();
02064 }
02065 }
02066 LOG_DP << "done scrolling to speaker...\n";
02067 } else {
02068 screen->highlight_hex(gamemap::location::null_location);
02069 }
02070 screen->draw(false);
02071
02072 std::vector<std::string> options;
02073 std::vector<vconfig::child_list> option_events;
02074
02075 for(vconfig::child_list::const_iterator mi = menu_items.begin();
02076 mi != menu_items.end(); ++mi) {
02077 std::string msg_str = (*mi)["message"];
02078 if(!(*mi).has_child("show_if")
02079 || game_events::conditional_passed(units,(*mi).child("show_if"))) {
02080 options.push_back(msg_str);
02081 option_events.push_back((*mi).get_children("command"));
02082 }
02083 }
02084
02085 if(text_input_elements.size()>1) {
02086 lg::wml_error << "too many text_input tags, only one accepted\n";
02087 }
02088
02089 const vconfig text_input_element = has_text_input ?
02090 text_input_elements.front() : vconfig();
02091
02092 surface surface(NULL);
02093 if(image.empty() == false) {
02094 surface.assign(image::get_image(image));
02095 }
02096
02097 int option_chosen = -1;
02098 std::string text_input_result;
02099
02100 DBG_DP << "showing dialog...\n";
02101
02102
02103
02104 if(get_replay_source().at_end() || (options.empty() && !has_text_input) ) {
02105
02106 if (side_for_show && !get_replay_source().is_skipping())
02107 {
02108 const t_string msg = cfg["message"];
02109 const std::string duration_str = cfg["duration"];
02110 const unsigned int lifetime = average_frame_time * lexical_cast_default<unsigned int>(duration_str, prevent_misclick_duration);
02111 const SDL_Rect& map_area = screen->map_outside_area();
02112
02113 try {
02114 wml_event_dialog to_show(*screen, ((surface.null())? caption : ""),
02115 msg, ((options.empty()&& !has_text_input)? gui::MESSAGE : gui::OK_ONLY));
02116 if(!surface.null()) {
02117 to_show.set_image(surface, caption);
02118 }
02119 if(!options.empty()) {
02120 to_show.set_menu(options);
02121 }
02122 if(has_text_input) {
02123 std::string text_input_label=text_input_element["label"];
02124 std::string text_input_content=text_input_element["text"];
02125 std::string max_size_str=text_input_element["max_length"];
02126 int input_max_size=lexical_cast_default<int>(max_size_str, 256);
02127 if(input_max_size>1024||input_max_size<1){
02128 lg::wml_error << "invalid maximum size for input "<<input_max_size<<"\n";
02129 input_max_size=256;
02130 }
02131 to_show.set_textbox(text_input_label, text_input_content, input_max_size);
02132 }
02133 gui::dialog::dimension_measurements dim = to_show.layout();
02134 to_show.get_menu().set_width( dim.menu_width );
02135 to_show.get_menu().set_max_width( dim.menu_width );
02136 to_show.get_menu().wrap_words();
02137 static const int dialog_top_offset = 26;
02138 to_show.layout(-1, map_area.y + dialog_top_offset);
02139 option_chosen = to_show.show(lifetime);
02140 if(has_text_input) {
02141 text_input_result=to_show.textbox_text();
02142 }
02143 LOG_DP << "showed dialog...\n";
02144
02145 if (option_chosen == gui::ESCAPE_DIALOG) {
02146 skip_messages = true;
02147 }
02148
02149 if(!options.empty()) {
02150 recorder.choose_option(option_chosen);
02151 }
02152 if(has_text_input) {
02153 recorder.text_input(text_input_result);
02154 }
02155 } catch(utils::invalid_utf8_exception&) {
02156
02157 }
02158 }
02159
02160
02161 } else {
02162
02163 const t_string& side_str = state_of_game->get_variable("side_number");
02164 const int side = lexical_cast_default<int>(side_str.base_str(), -1);
02165
02166
02167
02168 if(!options.empty()) {
02169 do_replay_handle(*screen,*game_map,*units,*teams,
02170 side ,*status_ptr,*state_of_game,std::string("choose"));
02171 const config* action = get_replay_source().get_next_action();
02172 if(action == NULL || action->get_children("choose").empty()) {
02173 replay::throw_error("choice expected but none found\n");
02174 }
02175 const std::string& val = (*(action->get_children("choose").front()))["value"];
02176 option_chosen = atol(val.c_str());
02177 }
02178 if(has_text_input) {
02179 do_replay_handle(*screen,*game_map,*units,*teams,
02180 side ,*status_ptr,*state_of_game,std::string("input"));
02181 const config* action = get_replay_source().get_next_action();
02182 if(action == NULL || action->get_children("input").empty()) {
02183 replay::throw_error("input expected but none found\n");
02184 }
02185 text_input_result = (*(action->get_children("input").front()))["text"];
02186 }
02187 }
02188
02189
02190 if(options.empty() == false) {
02191 if(size_t(option_chosen) >= menu_items.size()) {
02192 std::stringstream errbuf;
02193 errbuf << "invalid choice (" << option_chosen
02194 << ") was specified, choice 0 to " << (menu_items.size() - 1)
02195 << " was expected.\n";
02196 replay::throw_error(errbuf.str());
02197 }
02198
02199 vconfig::child_list events = option_events[option_chosen];
02200 for(vconfig::child_list::const_iterator itor = events.begin();
02201 itor != events.end(); ++itor) {
02202 if(!handle_event(event_info, *itor)) {
02203 mutated = false;
02204 }
02205 }
02206 }
02207 if(has_text_input) {
02208 std::string variable_name=text_input_element["variable"];
02209 if(variable_name.empty())
02210 variable_name="input";
02211 state_of_game->set_variable(variable_name, text_input_result);
02212 }
02213 }
02214
02215 else if(cmd == "kill") {
02216
02217 for(gamemap::location loc(0,0); loc.x < game_map->w(); ++loc.x) {
02218 for(loc.y = 0; loc.y < game_map->h(); ++loc.y) {
02219 unit_map::iterator un = units->find(loc);
02220 if(un != units->end() && game_events::unit_matches_filter(un,cfg)) {
02221 if(utils::string_bool(cfg["animate"])) {
02222 screen->scroll_to_tile(loc);
02223 unit_display::unit_die(loc, un->second);
02224 }
02225 if(utils::string_bool(cfg["fire_event"])) {
02226 game_events::entity_location death_loc(un);
02227 game_events::fire("die", death_loc, death_loc);
02228 un = units->find(death_loc);
02229 if(un != units->end() && death_loc.matches_unit(un->second)) {
02230 units->erase(un);
02231 unit_mutations++;
02232 }
02233 } else {
02234 units->erase(un);
02235 unit_mutations++;
02236 }
02237 }
02238 }
02239 }
02240
02241
02242
02243 if(cfg["x"].empty() && cfg["y"].empty()) {
02244 std::map<std::string, player_info>& players=state_of_game->players;
02245
02246 for(std::map<std::string, player_info>::iterator pi = players.begin();
02247 pi!=players.end(); ++pi)
02248 {
02249 std::vector<unit>& avail_units = pi->second.available_units;
02250 for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
02251 j->set_game_context(units,game_map,status_ptr,teams);
02252 scoped_recall_unit auto_store("this_unit", pi->first, j - avail_units.begin());
02253 if(game_events::unit_matches_filter(*j, cfg,gamemap::location())) {
02254 j = avail_units.erase(j);
02255 } else {
02256 ++j;
02257 }
02258 }
02259 }
02260 }
02261 }
02262
02263
02264 else if(cmd == "event") {
02265 new_handlers.push_back(event_handler(cfg));
02266 }
02267
02268
02269 else if(cmd == "fire_event") {
02270 gamemap::location loc1,loc2;
02271 config data;
02272 if (cfg.has_child("primary_unit")) {
02273 vconfig u = cfg.child("primary_unit");
02274 if (u.has_attribute("x") && u.has_attribute("y"))
02275 loc1 = cfg_to_loc(u);
02276 if (u.has_attribute("weapon")) {
02277 config& f = data.add_child("first");
02278 f["weapon"] = u.get_attribute("weapon");
02279 }
02280 }
02281 if (cfg.has_child("secondary_unit")) {
02282 vconfig u = cfg.child("secondary_unit");
02283 if (u.has_attribute("x") && u.has_attribute("y"))
02284 loc2 = cfg_to_loc(u);
02285 if (u.has_attribute("weapon")) {
02286 config& s = data.add_child("second");
02287 s["weapon"] = u.get_attribute("weapon");
02288 }
02289 }
02290 game_events::fire(cfg["name"],loc1,loc2,data);
02291 }
02292
02293
02294 else if(cmd == "set_menu_item") {
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314 std::string id = cfg["id"];
02315 wml_menu_item*& mref = state_of_game->wml_menu_items[id];
02316 if(mref == NULL) {
02317 mref = new wml_menu_item(id);
02318 }
02319 if(cfg.has_attribute("image")) {
02320 mref->image = cfg["image"];
02321 }
02322 if(cfg.has_attribute("description")) {
02323 mref->description = cfg["description"];
02324 }
02325 if(cfg.has_attribute("needs_select")) {
02326 mref->needs_select = utils::string_bool(cfg["needs_select"], false);
02327 }
02328 if(cfg.has_child("show_if")) {
02329 mref->show_if = cfg.child("show_if").get_config();
02330 }
02331 if(cfg.has_child("filter_location")) {
02332 mref->filter_location = cfg.child("filter_location").get_config();
02333 }
02334 if(cfg.has_child("command")) {
02335 config* new_command = new config(cfg.child("command").get_config());
02336 wmi_command_changes.push_back(wmi_command_change(id, new_command));
02337 }
02338 }
02339
02340
02341 else if(cmd == "store_unit") {
02342 const config empty_filter;
02343 vconfig filter = cfg.child("filter");
02344 if(filter.null())
02345 filter = &empty_filter;
02346
02347 std::string variable = cfg["variable"];
02348 if(variable.empty()) {
02349 variable="unit";
02350 }
02351 const std::string mode = cfg["mode"];
02352 config to_store;
02353 variable_info varinfo(variable, true, variable_info::TYPE_ARRAY);
02354
02355 const bool kill_units = utils::string_bool(cfg["kill"]);
02356
02357 for(unit_map::iterator i = units->begin(); i != units->end();) {
02358 if(game_events::unit_matches_filter(i,filter) == false) {
02359 ++i;
02360 continue;
02361 }
02362
02363 config& data = to_store.add_child(varinfo.key);
02364 i->first.write(data);
02365 i->second.write(data);
02366
02367 if(kill_units) {
02368 units->erase(i++);
02369 unit_mutations++;
02370 } else {
02371 ++i;
02372 }
02373 }
02374
02375 if(filter["x"].empty() && filter["y"].empty()) {
02376 std::map<std::string, player_info>& players = state_of_game->players;
02377
02378 for(std::map<std::string, player_info>::iterator pi = players.begin();
02379 pi!=players.end(); ++pi) {
02380 std::vector<unit>& avail_units = pi->second.available_units;
02381 for(std::vector<unit>::iterator j = avail_units.begin(); j != avail_units.end();) {
02382 j->set_game_context(units,game_map,status_ptr,teams);
02383 scoped_recall_unit auto_store("this_unit", pi->first, j - avail_units.begin());
02384 if(game_events::unit_matches_filter(*j, filter,gamemap::location()) == false) {
02385 ++j;
02386 continue;
02387 }
02388 config& data = to_store.add_child(varinfo.key);
02389 j->write(data);
02390 data["x"] = "recall";
02391 data["y"] = "recall";
02392
02393 if(kill_units) {
02394 j = avail_units.erase(j);
02395 } else {
02396 ++j;
02397 }
02398 }
02399 }
02400 }
02401 if(mode != "append") {
02402 varinfo.vars->clear_children(varinfo.key);
02403 }
02404 varinfo.vars->append(to_store);
02405 }
02406
02407 else if(cmd == "unstore_unit") {
02408 assert(state_of_game != NULL);
02409 const config& var = state_of_game->get_variable_cfg(cfg["variable"]);
02410
02411 try {
02412 assert(units != NULL);
02413 assert(game_map != NULL);
02414 assert(status_ptr != NULL);
02415 const unit u(units,game_map,status_ptr,teams,var, false);
02416
02417 preferences::encountered_units().insert(u.type_id());
02418 gamemap::location loc(var, game_events::get_state_of_game());
02419 if(loc.valid()) {
02420 if(utils::string_bool(cfg["find_vacant"])) {
02421 loc = find_vacant_tile(*game_map,*units,loc);
02422 }
02423
02424 units->erase(loc);
02425 units->add(new std::pair<gamemap::location,unit>(loc,u));
02426 unit_mutations++;
02427
02428 std::string text = cfg["text"];
02429 if(!text.empty())
02430 {
02431
02432 std::string red_str = cfg["red"];
02433 std::string green_str = cfg["green"];
02434 std::string blue_str = cfg["blue"];
02435 const int red = lexical_cast_default<int>(red_str,0);
02436 const int green = lexical_cast_default<int>(green_str,0);
02437 const int blue = lexical_cast_default<int>(blue_str,0);
02438 {
02439 screen->float_label(loc,text,red,green,blue);
02440 }
02441 }
02442
02443 if(utils::string_bool(cfg["advance"], true) && get_replay_source().at_end()) {
02444
02445
02446
02447 const t_string& side_str = state_of_game->get_variable("side_number");
02448 const int side = lexical_cast_default<int>(side_str.base_str(), -1);
02449
02450
02451 const bool sel = (side == static_cast<int>(u.side())
02452 && (*teams)[side-1].is_human());
02453
02454
02455 dialogs::advance_unit(*game_map, *units, loc, *screen, !sel, true);
02456 }
02457
02458 } else {
02459 player_info *player=state_of_game->get_player((*teams)[u.side()-1].save_id());
02460
02461 if(player) {
02462
02463
02464
02465
02466
02467
02468 if(player->available_units.size() > 1) {
02469 std::vector<std::string> desciptions;
02470 for(std::vector<unit>::const_iterator citor =
02471 player->available_units.begin();
02472 citor != player->available_units.end(); ++citor) {
02473
02474 const std::string desciption =
02475 citor->underlying_id();
02476 if(std::find(desciptions.begin(), desciptions.end(),
02477 desciption) != desciptions.end()) {
02478
02479 lg::wml_error << "Recall list has duplicate unit "
02480 "description '" << desciption
02481 << "' unstore_unit may not work as expected.\n";
02482 } else {
02483 desciptions.push_back(desciption);
02484 }
02485 }
02486 }
02487
02488
02489
02490
02491
02492 const std::string key = u.underlying_id();
02493 for(std::vector<unit>::iterator itor =
02494 player->available_units.begin();
02495 itor != player->available_units.end(); ++itor) {
02496
02497 LOG_NG << "Replaced unit '"
02498 << key << "' on the recall list\n";
02499 if(itor->underlying_id() == key) {
02500 player->available_units.erase(itor);
02501 break;
02502 }
02503 }
02504 player->available_units.push_back(u);
02505 } else {
02506 ERR_NG << "Cannot unstore unit: no recall list for player " << u.side()
02507 << " and the map location is invalid.\n";
02508 }
02509 }
02510
02511
02512
02513 if(u.can_recruit()) {
02514 (*teams)[u.side() - 1].no_leader() = false;
02515 }
02516
02517 } catch(game::load_game_failed& e) {
02518 ERR_NG << "could not de-serialize unit: '" << e.message << "'\n";
02519 }
02520 }
02521
02522 else if (cmd == "store_map_dimensions") {
02523 std::string variable = cfg["variable"];
02524 if (variable.empty()) {
02525 variable="map_size";
02526 }
02527 assert(state_of_game != NULL);
02528 state_of_game->get_variable(variable + ".width") = str_cast<int>(game_map->w());
02529 state_of_game->get_variable(variable + ".height") = str_cast<int>(game_map->h());
02530 }
02531
02532 else if(cmd == "store_starting_location") {
02533 std::string side = cfg["side"];
02534 std::string variable = cfg["variable"];
02535 if (variable.empty()) {
02536 variable="location";
02537 }
02538 assert(state_of_game != NULL);
02539 const int side_num = lexical_cast_default<int>(side,1);
02540
02541 const gamemap::location& loc = game_map->starting_position(side_num);
02542 assert(state_of_game != NULL);
02543 config &loc_store = state_of_game->get_variable_cfg(variable);
02544 loc_store.clear();
02545 loc.write(loc_store);
02546 game_map->write_terrain(loc, loc_store);
02547 if (game_map->is_village(loc)) {
02548 std::stringstream sd;
02549 int side = village_owner(loc,*teams) + 1;
02550 sd << side;
02551 loc_store["owner_side"]= sd.str();
02552 }
02553 }
02554
02555
02556
02557
02558
02559
02560
02561 else if(cmd == "store_villages" ) {
02562 log_scope("store_villages");
02563 std::string variable = cfg["variable"];
02564 if (variable.empty()) {
02565 variable="location";
02566 }
02567 config to_store;
02568 variable_info varinfo(variable, true, variable_info::TYPE_ARRAY);
02569
02570 std::vector<gamemap::location> locs = game_map->villages();
02571
02572 for(std::vector<gamemap::location>::const_iterator j = locs.begin(); j != locs.end(); ++j) {
02573 bool matches = false;
02574 if(cfg.has_attribute("side")) {
02575 lg::wml_error << "side key is no longer accepted in [store_villages],"
02576 << " use owner_side instead.\n";
02577 config temp_cfg(cfg.get_config());
02578 temp_cfg["owner_side"] = temp_cfg["side"];
02579 temp_cfg["side"] = "";
02580 matches = terrain_filter(&temp_cfg, *game_map, *status_ptr, *units).match(*j);
02581 } else {
02582 matches = terrain_filter(cfg, *game_map, *status_ptr, *units).match(*j);
02583 }
02584 if(matches) {
02585 config &loc_store = to_store.add_child(varinfo.key);
02586 j->write(loc_store);
02587 game_map->write_terrain(*j, loc_store);
02588 std::stringstream sd;
02589 int side = village_owner(*j,*teams) + 1;
02590 sd << side;
02591 loc_store["owner_side"]= sd.str();
02592 }
02593 }
02594 varinfo.vars->clear_children(varinfo.key);
02595 varinfo.vars->append(to_store);
02596 }
02597
02598 else if(cmd == "store_locations" ) {
02599 log_scope("store_locations");
02600 std::string variable = cfg["variable"];
02601 if (variable.empty()) {
02602 variable="location";
02603 }
02604
02605 std::set<gamemap::location> res;
02606 terrain_filter filter(cfg, *game_map, *status_ptr, *units);
02607 filter.restrict(game_config::max_loop);
02608 filter.get_locations(res);
02609
02610 state_of_game->clear_variable_cfg(variable);
02611 for(std::set<gamemap::location>::const_iterator j = res.begin(); j != res.end(); ++j) {
02612 config &loc_store = state_of_game->add_variable_cfg(variable);
02613 j->write(loc_store);
02614 game_map->write_terrain(*j, loc_store);
02615 if (game_map->is_village(*j)) {
02616 std::stringstream sd;
02617 int side = village_owner(*j,*teams) + 1;
02618 sd << side;
02619 loc_store["owner_side"]= sd.str();
02620 }
02621 }
02622 }
02623
02624
02625 else if(cmd == "capture_village") {
02626 std::string side = cfg["side"];
02627 assert(state_of_game != NULL);
02628 const int side_num = lexical_cast_default<int>(side);
02629
02630
02631 const size_t team_num = size_t(side_num-1);
02632
02633 const std::vector<gamemap::location> locs(multiple_locs(cfg));
02634
02635 for(std::vector<gamemap::location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
02636 if(game_map->is_village(*i)) {
02637 get_village(*i,*screen,*teams,team_num,*units);
02638 }
02639 }
02640 }
02641
02642
02643 else if(cmd == "clear_variable") {
02644 const std::string name = cfg["name"];
02645 std::vector<std::string> vars_to_clear =
02646 utils::split(name, ',', utils::STRIP_SPACES | utils::REMOVE_EMPTY);
02647 foreach(const std::string& var, vars_to_clear) {
02648 state_of_game->clear_variable(var);
02649 }
02650 }
02651
02652 else if(cmd == "endlevel") {
02653
02654
02655
02656
02657 unit_map::iterator u = units->begin();
02658 while(u != units->end()) {
02659 if(u->second.hitpoints() <= 0) {
02660 units->erase(u++);
02661 ++unit_mutations;
02662 } else {
02663 ++u;
02664 }
02665 }
02666
02667 const std::string next_scenario = cfg["next_scenario"];
02668 if(next_scenario.empty() == false) {
02669 state_of_game->next_scenario = next_scenario;
02670 }
02671
02672 const std::string result = cfg["result"].base_str();
02673 if(result.empty() || result == "victory") {
02674 const bool bonus = utils::string_bool(cfg["bonus"],true);
02675 const int carry_over = lexical_cast_default<int>
02676 (cfg["carryover_percentage"],
02677 game_config::gold_carryover_percentage);
02678 const bool gold_add = utils::string_bool(cfg["carryover_add"],
02679 game_config::gold_carryover_add);
02680
02681 throw end_level_exception(VICTORY, carry_over, gold_add, bonus);
02682 } else if(result == "continue") {
02683 throw end_level_exception(LEVEL_CONTINUE);
02684 } else if(result == "continue_no_save") {
02685 throw end_level_exception(LEVEL_CONTINUE_NO_SAVE);
02686 } else {
02687 LOG_NG << "throwing event defeat...\n";
02688 throw end_level_exception(DEFEAT);
02689 }
02690 }
02691
02692 else if(cmd == "redraw") {
02693 std::string side = cfg["side"];
02694 assert(state_of_game != NULL);
02695 if(side != "") {
02696 const int side_num = lexical_cast_default<int>(side);
02697 clear_shroud(*screen,*game_map,*units,*teams,side_num-1);
02698 screen->recalculate_minimap();
02699 }
02700 if(rebuild_screen_) {
02701 rebuild_screen_ = false;
02702 screen->recalculate_minimap();
02703 screen->rebuild_all();
02704 }
02705 screen->invalidate_all();
02706 screen->draw(true,true);
02707 }
02708
02709 else if(cmd == "animate_unit") {
02710
02711 unit_map::iterator u = units->find(event_info.loc1);
02712
02713
02714
02715 vconfig filter = cfg.child("filter");
02716 if(!filter.null()) {
02717 for(u = units->begin(); u != units->end(); ++u){
02718 if(game_events::unit_matches_filter(u, filter))
02719 break;
02720 }
02721 }
02722
02723
02724 if(u != units->end() && ! screen->fogged(u->first)) {
02725 attack_type *primary = NULL;
02726 attack_type *secondary = NULL;
02727 Uint32 text_color = 0;
02728 unit_animation::hit_type hits= unit_animation::INVALID;
02729 std::vector<attack_type> attacks = u->second.attacks();
02730 std::vector<attack_type>::iterator itor;
02731
02732 filter = cfg.child("primary_attack");
02733 if(!filter.null()) {
02734 for(itor = attacks.begin(); itor != attacks.end(); ++itor){
02735 if(itor->matches_filter(filter.get_parsed_config())) {
02736 primary = &*itor;
02737 break;
02738 }
02739 }
02740 }
02741
02742 filter = cfg.child("secondary_attack");
02743 if(!filter.null()) {
02744 for(itor = attacks.begin(); itor != attacks.end(); ++itor){
02745 if(itor->matches_filter(filter.get_parsed_config())) {
02746 secondary = &*itor;
02747 break;
02748 }
02749 }
02750 }
02751
02752 if(cfg["hit"] == "yes" || cfg["hit"] == "hit") {
02753 hits = unit_animation::HIT;
02754 }
02755 if(cfg["hit"] == "no" || cfg["hit"] == "miss") {
02756 hits = unit_animation::MISS;
02757 }
02758 if( cfg["hit"] == "kill" ) {
02759 hits = unit_animation::KILL;
02760 }
02761 std::vector<std::string> tmp_string_vect=utils::split(cfg["text_color"]);
02762 if(tmp_string_vect.size() ==3) text_color = display::rgb(atoi(tmp_string_vect[0].c_str()),atoi(tmp_string_vect[1].c_str()),atoi(tmp_string_vect[2].c_str()));
02763 screen->scroll_to_tile(u->first);
02764 unit_animator animator;
02765 animator.add_animation(&u->second,cfg["flag"],u->first,lexical_cast_default<int>(cfg["value"]),utils::string_bool(cfg["with_bars"]),
02766 false,cfg["text"],text_color, hits,primary,secondary,0);
02767 animator.start_animations();
02768 animator.wait_for_end();
02769 u->second.set_standing(u->first);
02770 screen->invalidate(u->first);
02771 screen->draw();
02772 events::pump();
02773 }
02774 } else if(cmd == "label") {
02775
02776 terrain_label label(screen->labels(),
02777 cfg.get_config(),
02778 game_events::get_state_of_game());
02779
02780 screen->labels().set_label(label.location(),
02781 label.text(),
02782 label.team_name(),
02783 label.colour());
02784 }
02785
02786 else if(cmd== "heal_unit") {
02787
02788 const bool animated = utils::string_bool(cfg["animate"],false);
02789
02790 const vconfig healed_filter = cfg.child("filter");
02791 unit_map::iterator u;
02792
02793 if (healed_filter.null()) {
02794
02795 u = units->find(event_info.loc1);
02796 }
02797 else {
02798 for(u = units->begin(); u != units->end(); ++u) {
02799 if(game_events::unit_matches_filter(u, healed_filter))
02800 break;
02801 }
02802 }
02803
02804 const vconfig healers_filter = cfg.child("secondary_unit_filter");
02805 unit_map::iterator v;
02806 std::vector<unit_map::iterator> healers;
02807
02808 if (!healers_filter.null()) {
02809 for(v = units->begin(); v != units->end(); ++v) {
02810 if(game_events::unit_matches_filter(v, healers_filter) &&
02811 v->second.has_ability_type("heals")) {
02812 healers.push_back(v);
02813 }
02814 }
02815 }
02816
02817
02818 if(u != units->end()) {
02819 int amount = lexical_cast_default<int>(cfg["amount"],0);
02820 int real_amount = u->second.hitpoints();
02821 u->second.heal(amount);
02822 real_amount = u->second.hitpoints() - real_amount;
02823
02824 if (animated) {
02825 unit_display::unit_healing(u->second,u->first,
02826 healers,
02827 real_amount);
02828 }
02829
02830 state_of_game->set_variable("heal_amount",
02831 str_cast<int>(real_amount));
02832 }
02833 }
02834
02835 DBG_NG << "done handling command...\n";
02836 }
02837
02838 static void commit_new_handlers() {
02839
02840 while(new_handlers.size() > 0) {
02841 event_handler& new_handler = new_handlers.back();
02842 std::vector<std::string> names = new_handler.names();
02843 std::vector<std::string>::iterator iter,end;
02844 for (iter = names.begin(),end = names.end();
02845 iter != end; ++iter) {
02846 events_map.insert(std::pair<std::string,event_handler>(*iter,new_handler));
02847 LOG_NG << "spawning new handler for event " << *iter << "\n";
02848 }
02849
02850 new_handlers.pop_back();
02851 }
02852 }
02853
02854 static void commit_wmi_commands() {
02855
02856 while(wmi_command_changes.size() > 0) {
02857 wmi_command_change wcc = wmi_command_changes.back();
02858 wml_menu_item*& mref = state_of_game->wml_menu_items[wcc.first];
02859 const bool no_current_handler = mref->command.empty();
02860 mref->command = *(wcc.second);
02861 if(no_current_handler) {
02862 if(!mref->command.empty()) {
02863 mref->command["name"] = mref->name;
02864 mref->command["first_time_only"] = "no";
02865 event_handler new_handler(&mref->command);
02866 std::vector<std::string> names = new_handler.names();
02867 std::vector<std::string>::iterator iter,end;
02868 for (iter = names.begin(),end = names.end();
02869 iter != end; ++iter) {
02870 events_map.insert(std::pair<std::string,event_handler>(*iter, new_handler));
02871 }
02872 }
02873 } else if(mref->command.empty()) {
02874 mref->command["name"] = mref->name;
02875 mref->command["first_time_only"] = "no";
02876 mref->command.add_child("allow_undo");
02877 }
02878 LOG_NG << "setting command for " << mref->name << "\n";
02879 LOG_NG << *wcc.second;
02880 delete wcc.second;
02881 wmi_command_changes.pop_back();
02882 }
02883 }
02884
02885 bool event_handler::handle_event(const queued_event& event_info, const vconfig conf)
02886 {
02887 if (first_time_only_)
02888 {
02889 disable();
02890 }
02891 bool mutated = true;
02892 bool skip_messages = false;
02893
02894 vconfig cfg = conf;
02895 if(cfg.null()) {
02896 cfg = cfg_;
02897 }
02898 for(vconfig::all_children_iterator i = cfg.ordered_begin();
02899 i != cfg.ordered_end(); ++i) {
02900
02901
02902 handle_event_command(event_info, i.get_key(), i.get_child(), mutated, skip_messages);
02903 }
02904
02905
02906 sound::commit_music_changes();
02907
02908 return mutated;
02909 }
02910
02911 }
02912
02913 static bool process_event(event_handler& handler, const queued_event& ev)
02914 {
02915 if(handler.disabled())
02916 return false;
02917
02918 unit_map::iterator unit1 = units->find(ev.loc1);
02919 unit_map::iterator unit2 = units->find(ev.loc2);
02920 bool filtered_unit1 = false, filtered_unit2 = false;
02921 scoped_xy_unit first_unit("unit", ev.loc1.x, ev.loc1.y, *units);
02922 scoped_xy_unit second_unit("second_unit", ev.loc2.x, ev.loc2.y, *units);
02923
02924 const vconfig::child_list first_filters = handler.first_arg_filters();
02925 vconfig::child_list::const_iterator ffi;
02926 for(ffi = first_filters.begin();
02927 ffi != first_filters.end(); ++ffi) {
02928
02929 if(unit1 == units->end() || !game_events::unit_matches_filter(unit1,*ffi)) {
02930 return false;
02931 }
02932 if(!ffi->empty()) {
02933 filtered_unit1 = true;
02934 }
02935 }
02936 bool special_matches = false;
02937 const vconfig::child_list first_special_filters = handler.first_special_filters();
02938 special_matches = first_special_filters.size() ? false : true;
02939 for(ffi = first_special_filters.begin();
02940 ffi != first_special_filters.end(); ++ffi) {
02941
02942 if(unit1 != units->end() && game_events::matches_special_filter(ev.data.child("first"),*ffi)) {
02943 special_matches = true;
02944 }
02945 if(!ffi->empty()) {
02946 filtered_unit1 = true;
02947 }
02948 }
02949 if(!special_matches) {
02950 return false;
02951 }
02952
02953 const vconfig::child_list second_filters = handler.second_arg_filters();
02954 for(vconfig::child_list::const_iterator sfi = second_filters.begin();
02955 sfi != second_filters.end(); ++sfi) {
02956 if(unit2 == units->end() || !game_events::unit_matches_filter(unit2,*sfi)) {
02957 return false;
02958 }
02959 if(!sfi->empty()) {
02960 filtered_unit2 = true;
02961 }
02962 }
02963 const vconfig::child_list second_special_filters = handler.second_special_filters();
02964 special_matches = second_special_filters.size() ? false : true;
02965 for(ffi = second_special_filters.begin();
02966 ffi != second_special_filters.end(); ++ffi) {
02967
02968 if(unit2 != units->end() && game_events::matches_special_filter(ev.data.child("second"),*ffi)) {
02969 special_matches = true;
02970 }
02971 if(!ffi->empty()) {
02972 filtered_unit2 = true;
02973 }
02974 }
02975 if(!special_matches) {
02976 return false;
02977 }
02978 if(ev.loc1.requires_unit() && filtered_unit1
02979 && (unit1 == units->end() || !ev.loc1.matches_unit(unit1->second))) {
02980
02981 return false;
02982 }
02983 if(ev.loc2.requires_unit() && filtered_unit2
02984 && (unit2 == units->end() || !ev.loc2.matches_unit(unit2->second))) {
02985
02986 return false;
02987 }
02988
02989
02990 const bool res = handler.handle_event(ev);
02991 if(ev.name == "select") {
02992 state_of_game->last_selected = ev.loc1;
02993 }
02994
02995 if(handler.rebuild_screen()) {
02996 handler.rebuild_screen() = false;
02997 screen->recalculate_minimap();
02998 screen->invalidate_all();
02999 screen->rebuild_all();
03000 }
03001
03002
03003 return res;
03004 }
03005
03006 namespace game_events {
03007
03008 bool matches_special_filter(const config* cfg, const vconfig filter)
03009 {
03010
03011
03012
03013 if(!cfg) {
03014 return false;
03015 }
03016 bool matches = true;
03017 if(filter["weapon"] != "") {
03018 if(filter["weapon"] != (*cfg)["weapon"]) {
03019 matches = false;
03020 }
03021 }
03022
03023
03024 vconfig::all_children_iterator cond_i = filter.ordered_begin();
03025 vconfig::all_children_iterator cond_end = filter.ordered_end();
03026 while(cond_i != cond_end)
03027 {
03028 const std::string& cond_name = cond_i.get_key();
03029 const vconfig& cond_filter = cond_i.get_child();
03030
03031
03032 if(cond_name == "and")
03033 {
03034 matches = matches && matches_special_filter(cfg, cond_filter);
03035 }
03036
03037 else if(cond_name == "or")
03038 {
03039 matches = matches || matches_special_filter(cfg, cond_filter);
03040 }
03041
03042 else if(cond_name == "not")
03043 {
03044 matches = matches && !matches_special_filter(cfg, cond_filter);
03045 }
03046 ++cond_i;
03047 }
03048 return matches;
03049 }
03050
03051 bool unit_matches_filter(const unit& u, const vconfig filter,const gamemap::location& loc)
03052 {
03053 return u.matches_filter(filter,loc);
03054 }
03055
03056 bool unit_matches_filter(unit_map::const_iterator itor, const vconfig filter)
03057 {
03058 return itor->second.matches_filter(filter,itor->first);
03059 }
03060
03061 static config::child_list unit_wml_configs;
03062 static std::set<std::string> unit_wml_ids;
03063
03064 manager::manager(const config& cfg, game_display& gui_, gamemap& map_,
03065 soundsource::manager& sndsources_,
03066 unit_map& units_,
03067 std::vector<team>& teams_,
03068 game_state& state_of_game_, gamestatus& status) :
03069 variable_manager(&state_of_game_)
03070 {
03071 const config::child_list& events_list = cfg.get_children("event");
03072 for(config::child_list::const_iterator i = events_list.begin();
03073 i != events_list.end(); ++i) {
03074 event_handler new_handler(*i);
03075 std::vector<std::string> names = new_handler.names();
03076 std::vector<std::string>::iterator iter,end;
03077 for (iter = names.begin(),end = names.end();
03078 iter != end; ++iter) {
03079 events_map.insert(std::pair<std::string,event_handler>(*iter, new_handler));
03080 }
03081 }
03082 std::vector<std::string> unit_ids = utils::split(cfg["unit_wml_ids"]);
03083 for(std::vector<std::string>::const_iterator id_it = unit_ids.begin(); id_it != unit_ids.end(); ++id_it) {
03084 unit_wml_ids.insert(*id_it);
03085 }
03086
03087 teams = &teams_;
03088 screen = &gui_;
03089 soundsources = &sndsources_;
03090 game_map = &map_;
03091 units = &units_;
03092 state_of_game = &state_of_game_;
03093 status_ptr = &status;
03094
03095 used_items.clear();
03096
03097 const std::string used = cfg["used_items"];
03098 if(!used.empty()) {
03099 const std::vector<std::string>& v = utils::split(used);
03100 for(std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i) {
03101 used_items.insert(*i);
03102 }
03103 }
03104 int wmi_count = 0;
03105 std::map<std::string, wml_menu_item *>::iterator itor = state_of_game->wml_menu_items.begin();
03106 while(itor != state_of_game->wml_menu_items.end()) {
03107 if(!itor->second->command.empty()) {
03108 event_handler new_handler(&itor->second->command);
03109 std::vector<std::string> names = new_handler.names();
03110 std::vector<std::string>::iterator iter,end;
03111 for (iter = names.begin(),end = names.end();
03112 iter != end; ++iter) {
03113 events_map.insert(std::pair<std::string,event_handler>(*iter, new_handler));
03114 }
03115 }
03116 ++itor;
03117 ++wmi_count;
03118 }
03119 if(wmi_count > 0) {
03120 LOG_NG << wmi_count << " WML menu items found, loaded." << std::endl;
03121 }
03122 }
03123
03124 void write_events(config& cfg)
03125 {
03126 for(std::multimap<std::string,event_handler>::const_iterator i = events_map.begin(); i != events_map.end(); ++i) {
03127 if(!i->second.disabled() && !i->second.is_menu_item()) {
03128 i->second.write(cfg.add_child("event"));
03129 }
03130 }
03131
03132 std::stringstream used;
03133 std::set<std::string>::const_iterator u;
03134 for(u = used_items.begin(); u != used_items.end(); ++u) {
03135 if(u != used_items.begin())
03136 used << ",";
03137
03138 used << *u;
03139 }
03140
03141 cfg["used_items"] = used.str();
03142 std::stringstream ids;
03143 for(u = unit_wml_ids.begin(); u != unit_wml_ids.end(); ++u) {
03144 if(u != unit_wml_ids.begin())
03145 ids << ",";
03146
03147 ids << *u;
03148 }
03149
03150 cfg["unit_wml_ids"] = ids.str();
03151
03152 if(screen != NULL)
03153 screen->write_overlays(cfg);
03154 }
03155
03156 manager::~manager() {
03157 events_queue.clear();
03158 events_map.clear();
03159 screen = NULL;
03160 game_map = NULL;
03161 units = NULL;
03162 state_of_game = NULL;
03163 status_ptr = NULL;
03164 for(config::child_list::iterator d = unit_wml_configs.begin(); d != unit_wml_configs.end(); ++d) {
03165 delete *d;
03166 }
03167 unit_wml_configs.clear();
03168 unit_wml_ids.clear();
03169 }
03170
03171 void raise(const std::string& event,
03172 const entity_location& loc1,
03173 const entity_location& loc2,
03174 const config& data)
03175 {
03176 if(!events_init())
03177 return;
03178
03179 events_queue.push_back(queued_event(event,loc1,loc2,data));
03180 }
03181
03182 bool fire(const std::string& event,
03183 const entity_location& loc1,
03184 const entity_location& loc2,
03185 const config& data)
03186 {
03187 raise(event,loc1,loc2,data);
03188 return pump();
03189 }
03190
03191 void add_events(const config::child_list& cfgs,const std::string& id)
03192 {
03193 if(std::find(unit_wml_ids.begin(),unit_wml_ids.end(),id) == unit_wml_ids.end()) {
03194 unit_wml_ids.insert(id);
03195 for(config::child_list::const_iterator new_ev = cfgs.begin(); new_ev != cfgs.end(); ++ new_ev) {
03196 unit_wml_configs.push_back(new config(**new_ev));
03197 event_handler new_handler(&(*unit_wml_configs.back()));
03198 std::vector<std::string> names = new_handler.names();
03199 std::vector<std::string>::iterator iter,end;
03200 for (iter = names.begin(),end = names.end();
03201 iter != end; ++iter) {
03202 events_map.insert(std::pair<std::string,event_handler>(*iter, new_handler));
03203 }
03204 }
03205 }
03206 }
03207
03208 bool pump()
03209 {
03210 if(!events_init())
03211 return false;
03212
03213 bool result = false;
03214
03215 while(events_queue.empty() == false) {
03216 queued_event ev = events_queue.front();
03217 events_queue.pop_front();
03218 const std::string& event_name = ev.name;
03219 typedef std::multimap<std::string,event_handler>::iterator itor;
03220
03221
03222
03223 unit::clear_status_caches();
03224
03225
03226 std::pair<itor,itor> i = events_map.equal_range(event_name);
03227
03228
03229 if(i.first != i.second && state_of_game != NULL) {
03230 char buf[50];
03231 snprintf(buf,sizeof(buf),"%d",ev.loc1.x+1);
03232 state_of_game->set_variable("x1", buf);
03233
03234 snprintf(buf,sizeof(buf),"%d",ev.loc1.y+1);
03235 state_of_game->set_variable("y1", buf);
03236
03237 snprintf(buf,sizeof(buf),"%d",ev.loc2.x+1);
03238 state_of_game->set_variable("x2", buf);
03239
03240 snprintf(buf,sizeof(buf),"%d",ev.loc2.y+1);
03241 state_of_game->set_variable("y2", buf);
03242 }
03243
03244 while(i.first != i.second) {
03245 LOG_NG << "processing event '" << event_name << "'\n";
03246 event_handler& handler = i.first->second;
03247 if(process_event(handler, ev))
03248 result = true;
03249 ++i.first;
03250 }
03251
03252 commit_wmi_commands();
03253 commit_new_handlers();
03254
03255
03256 if(! screen->video().update_locked()) {
03257 show_wml_errors();
03258 }
03259 }
03260
03261 return result;
03262 }
03263
03264 Uint32 mutations() {
03265 return unit_mutations;
03266 }
03267
03268 entity_location::entity_location(gamemap::location loc, const std::string& id)
03269 : location(loc), id_(id)
03270 {}
03271
03272 entity_location::entity_location(unit_map::iterator itor)
03273 : location(itor->first), id_(itor->second.underlying_id())
03274 {}
03275
03276 bool entity_location::matches_unit(const unit& u) const
03277 {
03278 return id_ == u.underlying_id();
03279 }
03280
03281 bool entity_location::requires_unit() const
03282 {
03283 return !id_.empty();
03284 }
03285
03286 }
03287
03288