diff --git a/src/game_events/wmi_container.cpp b/src/game_events/wmi_container.cpp index 1f34e6de7ae..770e37e2f1e 100644 --- a/src/game_events/wmi_container.cpp +++ b/src/game_events/wmi_container.cpp @@ -23,7 +23,10 @@ #include "menu_item.hpp" #include "../config.hpp" +#include "../gamestatus.hpp" #include "../log.hpp" +#include "../map_location.hpp" +#include "../resources.hpp" #include @@ -31,6 +34,8 @@ static lg::log_domain log_engine("engine"); #define WRN_NG LOG_STREAM(warn, log_engine) #define LOG_NG LOG_STREAM(info, log_engine) +static const size_t MAX_WML_COMMANDS = 7; + // This file is in the game_events namespace. namespace game_events @@ -101,6 +106,31 @@ wmi_container::size_type wmi_container::erase(const std::string & id) return 1; // Erased one item. } +/** + * Fires the menu item with the given @a id. + * @returns true if a matching item was found (even if it could not be fired). + * NOTE: The return value could be altered if it is decided that + * play_controller::execute_command() needs something different. + */ +bool wmi_container::fire_item(const std::string & id, const map_location & hex) const +{ + // Does this item exist? + const_iterator iter = find(id); + if ( iter == end() ) + return false; + + // Prepare for can show(). + resources::gamedata->get_variable("x1") = hex.x + 1; + resources::gamedata->get_variable("y1") = hex.y + 1; + scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, *resources::units); + + // Can this item be shown? + if ( iter->can_show(hex) ) + iter->fire_event(hex); + + return true; +} + /** * Returns an item with the given id. * If one does not already exist, one will be created. @@ -122,6 +152,45 @@ wml_menu_item & wmi_container::get_item(const std::string& id) return *add_it->second; } +/** + * Returns the menu items that can be shown for the given location. + * The number of items returned is limited by MAX_WML_COMMANDS. + * @param[out] items Pointers to applicable menu items will be pushed onto @a items. + * @param[out] descriptions Menu item descriptions will be pushed onto @descriptions (in the same order as @a items). + */ +void wmi_container::get_items(const map_location& hex, + std::vector & items, + std::vector & descriptions) const +{ + size_t item_count = 0; + + if ( empty() ) + // Nothing to do (skip setting game variables). + return; + + // Prepare for can show(). + resources::gamedata->get_variable("x1") = hex.x + 1; + resources::gamedata->get_variable("y1") = hex.y + 1; + scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, *resources::units); + + // Check each menu item. + BOOST_FOREACH( const wml_menu_item & item, *this ) + { + // Can this item be shown? + if ( item.use_wml_menu() && item.can_show(hex) ) + { + // Include this item. + items.push_back(&item); + // Prevent accidental hotkey binding by appending a space + descriptions.push_back(item.description().str() + ' '); + + // Limit how many items can be returned. + if ( ++item_count >= MAX_WML_COMMANDS ) + return; + } + } +} + /** * Initializes the implicit event handlers for inlined [command]s. */ diff --git a/src/game_events/wmi_container.hpp b/src/game_events/wmi_container.hpp index 4c6afe59c68..0c9e8c6b4bc 100644 --- a/src/game_events/wmi_container.hpp +++ b/src/game_events/wmi_container.hpp @@ -23,8 +23,10 @@ #include "iterator.hpp" #include +#include class config; +struct map_location; class vconfig; @@ -72,6 +74,12 @@ public: /// Erases the item with the provided @a id. size_type erase(const std::string & id); + /// Fires the menu item with the given @a id. + bool fire_item(const std::string & id, const map_location & hex) const; + /// Returns the menu items that can be shown for the given location. + void get_items(const map_location& hex, + std::vector & items, + std::vector & descriptions) const; /// Initializes the implicit event handlers for inlined [command]s. void init_handlers() const; void to_config(config& cfg); diff --git a/src/play_controller.cpp b/src/play_controller.cpp index d0c798e0ede..1fddde37c57 100644 --- a/src/play_controller.cpp +++ b/src/play_controller.cpp @@ -821,21 +821,10 @@ bool play_controller::execute_command(const hotkey::hotkey_command& cmd, int ind if(command == hotkey::HOTKEY_WML && cmd.command.compare(0, prefixlen, wml_menu_hotkey_prefix) == 0) { std::string name = cmd.command.substr(prefixlen); - game_events::wmi_container& gs_wmi = gamedata_.get_wml_menu_items(); - game_events::wmi_container::iterator iter = gs_wmi.find(name); - if(iter != gs_wmi.end()) - { - //copied from expand_wml_commands - const map_location& hex = mouse_handler_.get_last_hex(); - gamedata_.get_variable("x1") = hex.x + 1; - gamedata_.get_variable("y1") = hex.y + 1; - scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, units_); + const map_location& hex = mouse_handler_.get_last_hex(); - if (iter->can_show(hex)) - { - iter->fire_event(mouse_handler_.get_last_hex()); - } - } + gamedata_.get_wml_menu_items().fire_item(name, hex); + /// @todo Shouldn't the function return at this point? } return command_executor::execute_command(cmd, index); } @@ -1185,32 +1174,18 @@ void play_controller::expand_wml_commands(std::vector& items) wml_commands_.clear(); for (unsigned int i = 0; i < items.size(); ++i) { if (items[i] == "wml") { - items.erase(items.begin() + i); - const game_events::wmi_container & gs_wmi = gamedata_.get_wml_menu_items(); - if(gs_wmi.empty()) - break; std::vector newitems; - const map_location& hex = mouse_handler_.get_last_hex(); - gamedata_.get_variable("x1") = hex.x + 1; - gamedata_.get_variable("y1") = hex.y + 1; - scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, units_); - - for ( game_events::wmi_container::const_iterator itor = gs_wmi.begin(); - itor != gs_wmi.end() && newitems.size() < MAX_WML_COMMANDS; - ++itor) - { - const game_events::wml_menu_item & item = *itor; - if ( item.use_wml_menu() && item.can_show(hex) ) - { - wml_commands_.push_back(&item); - // Prevent accidental hotkey binding by appending a space - newitems.push_back(item.description().str() + ' '); - } - } + // Replace this placeholder entry with available menu items. + items.erase(items.begin() + i); + gamedata_.get_wml_menu_items().get_items(mouse_handler_.get_last_hex(), + wml_commands_, newitems); items.insert(items.begin()+i, newitems.begin(), newitems.end()); + // End the "for" loop. break; } + // Pad the commands with NULL (keeps the indices of items and + // wml_commands_ synced). wml_commands_.push_back(NULL); } } diff --git a/src/play_controller.hpp b/src/play_controller.hpp index fffffcc20bf..1a4abed80fd 100644 --- a/src/play_controller.hpp +++ b/src/play_controller.hpp @@ -267,7 +267,6 @@ private: void expand_wml_commands(std::vector& items); std::vector wml_commands_; - static const size_t MAX_WML_COMMANDS = 7; bool victory_when_enemies_defeated_; bool remove_from_carryover_on_leaders_loss_;