move WML [kill] impl to lua
This commit is contained in:
parent
9922b98fa3
commit
75767d3a77
4 changed files with 168 additions and 145 deletions
|
@ -1376,6 +1376,10 @@ function wml_actions.inspect(cfg)
|
|||
wesnoth.gamestate_inspector(cfg)
|
||||
end
|
||||
|
||||
function wml_actions.kill(cfg)
|
||||
wesnoth.kill(cfg)
|
||||
end
|
||||
|
||||
function wml_actions.label(cfg)
|
||||
wesnoth.label(cfg)
|
||||
end
|
||||
|
|
|
@ -102,40 +102,6 @@ namespace { // advance declarations
|
|||
}
|
||||
|
||||
namespace { // Types
|
||||
|
||||
class recursion_preventer {
|
||||
typedef std::map<map_location, int> t_counter;
|
||||
static t_counter counter_;
|
||||
static const int max_recursion = 10;
|
||||
|
||||
map_location loc_;
|
||||
bool too_many_recursions_;
|
||||
|
||||
public:
|
||||
recursion_preventer(map_location& loc) :
|
||||
loc_(loc),
|
||||
too_many_recursions_(false)
|
||||
{
|
||||
t_counter::iterator inserted = counter_.insert(std::make_pair(loc_, 0)).first;
|
||||
++inserted->second;
|
||||
too_many_recursions_ = inserted->second >= max_recursion;
|
||||
}
|
||||
~recursion_preventer()
|
||||
{
|
||||
t_counter::iterator itor = counter_.find(loc_);
|
||||
if (--itor->second == 0)
|
||||
{
|
||||
counter_.erase(itor);
|
||||
}
|
||||
}
|
||||
bool too_many_recursions() const
|
||||
{
|
||||
return too_many_recursions_;
|
||||
}
|
||||
};
|
||||
recursion_preventer::t_counter recursion_preventer::counter_;
|
||||
typedef boost::scoped_ptr<recursion_preventer> recursion_preventer_ptr;
|
||||
|
||||
struct message_user_choice : mp_sync::user_choice
|
||||
{
|
||||
vconfig cfg;
|
||||
|
@ -733,117 +699,6 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg)
|
|||
}
|
||||
}
|
||||
|
||||
WML_HANDLER_FUNCTION(kill, event_info, cfg)
|
||||
{
|
||||
bool secondary_unit = cfg.has_child("secondary_unit");
|
||||
entity_location killer_loc(map_location(0, 0));
|
||||
if(cfg["fire_event"].to_bool() && secondary_unit)
|
||||
{
|
||||
secondary_unit = false;
|
||||
const unit_filter ufilt(cfg.child("secondary_unit"), resources::filter_con);
|
||||
for(unit_map::const_unit_iterator unit = resources::units->begin();
|
||||
unit != resources::units->end(); ++unit) {
|
||||
if ( ufilt( *unit) )
|
||||
{
|
||||
killer_loc = entity_location(*unit);
|
||||
secondary_unit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!secondary_unit) {
|
||||
WRN_NG << "failed to match [secondary_unit] in [kill] with a single on-board unit" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//Find all the dead units first, because firing events ruins unit_map iteration
|
||||
std::vector<unit *> dead_men_walking;
|
||||
const unit_filter ufilt(cfg, resources::filter_con);
|
||||
BOOST_FOREACH(unit & u, *resources::units){
|
||||
if ( ufilt(u) ) {
|
||||
dead_men_walking.push_back(&u);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(unit * un, dead_men_walking) {
|
||||
map_location loc(un->get_location());
|
||||
bool fire_event = false;
|
||||
entity_location death_loc(*un);
|
||||
if(!secondary_unit) {
|
||||
killer_loc = entity_location(*un);
|
||||
}
|
||||
|
||||
if (cfg["fire_event"].to_bool())
|
||||
{
|
||||
// Prevent infinite recursion of 'die' events
|
||||
fire_event = true;
|
||||
recursion_preventer_ptr recursion_prevent;
|
||||
|
||||
if (event_info.loc1 == death_loc && (event_info.name == "die" || event_info.name == "last breath"))
|
||||
{
|
||||
recursion_prevent.reset(new recursion_preventer(death_loc));
|
||||
|
||||
if(recursion_prevent->too_many_recursions())
|
||||
{
|
||||
fire_event = false;
|
||||
|
||||
ERR_NG << "tried to fire 'die' or 'last breath' event on primary_unit inside its own 'die' or 'last breath' event with 'first_time_only' set to false!" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fire_event) {
|
||||
resources::game_events->pump().fire("last breath", death_loc, killer_loc);
|
||||
}
|
||||
|
||||
// Visual consequences of the kill.
|
||||
if (cfg["animate"].to_bool()) {
|
||||
resources::screen->scroll_to_tile(loc);
|
||||
unit_map::iterator iun = resources::units->find(loc);
|
||||
if (iun != resources::units->end() && iun.valid()) {
|
||||
unit_display::unit_die(loc, *iun);
|
||||
}
|
||||
} else {
|
||||
// Make sure the unit gets (fully) cleaned off the screen.
|
||||
resources::screen->invalidate(loc);
|
||||
unit_map::iterator iun = resources::units->find(loc);
|
||||
if ( iun != resources::units->end() && iun.valid() )
|
||||
iun->anim_comp().invalidate(*resources::screen);
|
||||
}
|
||||
resources::screen->redraw_minimap();
|
||||
|
||||
if (fire_event) {
|
||||
resources::game_events->pump().fire("die", death_loc, killer_loc);
|
||||
unit_map::iterator iun = resources::units->find(death_loc);
|
||||
if ( death_loc.matches_unit(iun) ) {
|
||||
resources::units->erase(iun);
|
||||
}
|
||||
}
|
||||
else resources::units->erase(loc);
|
||||
}
|
||||
|
||||
// If the filter doesn't contain positional information,
|
||||
// then it may match units on all recall lists.
|
||||
t_string const& cfg_x = cfg["x"];
|
||||
t_string const& cfg_y = cfg["y"];
|
||||
if((cfg_x.empty() || cfg_x == "recall")
|
||||
&& (cfg_y.empty() || cfg_y == "recall"))
|
||||
{
|
||||
const unit_filter ufilt(cfg, resources::filter_con);
|
||||
//remove the unit from the corresponding team's recall list
|
||||
for(std::vector<team>::iterator pi = resources::teams->begin();
|
||||
pi!=resources::teams->end(); ++pi)
|
||||
{
|
||||
for(std::vector<unit_ptr>::iterator j = pi->recall_list().begin(); j != pi->recall_list().end();) { //TODO: This block is really messy, cleanup somehow...
|
||||
scoped_recall_unit auto_store("this_unit", pi->save_id(), j - pi->recall_list().begin());
|
||||
if (ufilt( *(*j), map_location() )) {
|
||||
j = pi->recall_list().erase(j);
|
||||
} else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WML_HANDLER_FUNCTION(lift_fog, /*event_info*/, cfg)
|
||||
{
|
||||
toggle_fog(true, cfg, !cfg["multiturn"].to_bool(false));
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "game_display.hpp" // for game_display
|
||||
#include "game_errors.hpp" // for game_error
|
||||
#include "game_events/conditional_wml.hpp" // for conditional_passed
|
||||
#include "game_events/entity_location.hpp"
|
||||
#include "game_events/manager.hpp" // for add_event_handler
|
||||
#include "game_events/pump.hpp" // for queued_event
|
||||
#include "game_preferences.hpp" // for encountered_units
|
||||
|
@ -90,6 +91,7 @@
|
|||
#include "tstring.hpp" // for t_string, operator+
|
||||
#include "unit.hpp" // for unit, intrusive_ptr_add_ref, etc
|
||||
#include "unit_animation_component.hpp" // for unit_animation_component
|
||||
#include "unit_display.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_map.hpp" // for unit_map, etc
|
||||
#include "unit_ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||
|
@ -2959,6 +2961,166 @@ int game_lua_kernel::intf_delay(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
namespace { // Types
|
||||
|
||||
class recursion_preventer {
|
||||
typedef std::map<map_location, int> t_counter;
|
||||
static t_counter counter_;
|
||||
static const int max_recursion = 10;
|
||||
|
||||
map_location loc_;
|
||||
bool too_many_recursions_;
|
||||
|
||||
public:
|
||||
recursion_preventer(map_location& loc) :
|
||||
loc_(loc),
|
||||
too_many_recursions_(false)
|
||||
{
|
||||
t_counter::iterator inserted = counter_.insert(std::make_pair(loc_, 0)).first;
|
||||
++inserted->second;
|
||||
too_many_recursions_ = inserted->second >= max_recursion;
|
||||
}
|
||||
~recursion_preventer()
|
||||
{
|
||||
t_counter::iterator itor = counter_.find(loc_);
|
||||
if (--itor->second == 0)
|
||||
{
|
||||
counter_.erase(itor);
|
||||
}
|
||||
}
|
||||
bool too_many_recursions() const
|
||||
{
|
||||
return too_many_recursions_;
|
||||
}
|
||||
};
|
||||
recursion_preventer::t_counter recursion_preventer::counter_;
|
||||
typedef boost::scoped_ptr<recursion_preventer> recursion_preventer_ptr;
|
||||
} // end anonymouse namespace (types)
|
||||
|
||||
int game_lua_kernel::intf_kill(lua_State *L)
|
||||
{
|
||||
vconfig cfg(luaW_checkvconfig(L, 1));
|
||||
|
||||
const game_events::queued_event &event_info = *queued_events_.top();
|
||||
|
||||
size_t number_killed = 0;
|
||||
|
||||
bool secondary_unit = cfg.has_child("secondary_unit");
|
||||
game_events::entity_location killer_loc(map_location(0, 0));
|
||||
if(cfg["fire_event"].to_bool() && secondary_unit)
|
||||
{
|
||||
secondary_unit = false;
|
||||
const unit_filter ufilt(cfg.child("secondary_unit"), &game_state_);
|
||||
for(unit_map::const_unit_iterator unit = units().begin(); unit; ++unit) {
|
||||
if ( ufilt( *unit) )
|
||||
{
|
||||
killer_loc = game_events::entity_location(*unit);
|
||||
secondary_unit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!secondary_unit) {
|
||||
WRN_LUA << "failed to match [secondary_unit] in [kill] with a single on-board unit" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//Find all the dead units first, because firing events ruins unit_map iteration
|
||||
std::vector<unit *> dead_men_walking;
|
||||
const unit_filter ufilt(cfg, &game_state_);
|
||||
BOOST_FOREACH(unit & u, units()){
|
||||
if ( ufilt(u) ) {
|
||||
dead_men_walking.push_back(&u);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(unit * un, dead_men_walking) {
|
||||
map_location loc(un->get_location());
|
||||
bool fire_event = false;
|
||||
game_events::entity_location death_loc(*un);
|
||||
if(!secondary_unit) {
|
||||
killer_loc = game_events::entity_location(*un);
|
||||
}
|
||||
|
||||
if (cfg["fire_event"].to_bool())
|
||||
{
|
||||
// Prevent infinite recursion of 'die' events
|
||||
fire_event = true;
|
||||
recursion_preventer_ptr recursion_prevent;
|
||||
|
||||
if (event_info.loc1 == death_loc && (event_info.name == "die" || event_info.name == "last breath"))
|
||||
{
|
||||
recursion_prevent.reset(new recursion_preventer(death_loc));
|
||||
|
||||
if(recursion_prevent->too_many_recursions())
|
||||
{
|
||||
fire_event = false;
|
||||
|
||||
ERR_LUA << "tried to fire 'die' or 'last breath' event on primary_unit inside its own 'die' or 'last breath' event with 'first_time_only' set to false!" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fire_event) {
|
||||
play_controller_.pump().fire("last breath", death_loc, killer_loc);
|
||||
}
|
||||
|
||||
// Visual consequences of the kill.
|
||||
if (game_display_) {
|
||||
if (cfg["animate"].to_bool()) {
|
||||
game_display_->scroll_to_tile(loc);
|
||||
if (unit_map::iterator iun = units().find(loc)) {
|
||||
unit_display::unit_die(loc, *iun);
|
||||
}
|
||||
} else {
|
||||
// Make sure the unit gets (fully) cleaned off the screen.
|
||||
game_display_->invalidate(loc);
|
||||
if (unit_map::iterator iun = units().find(loc)) {
|
||||
iun->anim_comp().invalidate(*game_display_);
|
||||
}
|
||||
}
|
||||
game_display_->redraw_minimap();
|
||||
}
|
||||
|
||||
if (fire_event) {
|
||||
play_controller_.pump().fire("die", death_loc, killer_loc);
|
||||
unit_map::iterator iun = units().find(death_loc);
|
||||
if ( death_loc.matches_unit(iun) ) {
|
||||
units().erase(iun);
|
||||
}
|
||||
}
|
||||
else units().erase(loc);
|
||||
|
||||
++number_killed;
|
||||
}
|
||||
|
||||
// If the filter doesn't contain positional information,
|
||||
// then it may match units on all recall lists.
|
||||
const config::attribute_value cfg_x = cfg["x"];
|
||||
const config::attribute_value cfg_y = cfg["y"];
|
||||
if((cfg_x.empty() || cfg_x == "recall")
|
||||
&& (cfg_y.empty() || cfg_y == "recall"))
|
||||
{
|
||||
const unit_filter ufilt(cfg, &game_state_);
|
||||
//remove the unit from the corresponding team's recall list
|
||||
for(std::vector<team>::iterator pi = teams().begin();
|
||||
pi!=teams().end(); ++pi)
|
||||
{
|
||||
for(std::vector<unit_ptr>::iterator j = pi->recall_list().begin(); j != pi->recall_list().end();) { //TODO: This block is really messy, cleanup somehow...
|
||||
scoped_recall_unit auto_store("this_unit", pi->save_id(), j - pi->recall_list().begin());
|
||||
if (ufilt( *(*j), map_location() )) {
|
||||
j = pi->recall_list().erase(j);
|
||||
++number_killed;
|
||||
} else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushinteger(L, number_killed);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int game_lua_kernel::intf_label(lua_State *L)
|
||||
{
|
||||
if (game_display_) {
|
||||
|
@ -3456,6 +3618,7 @@ game_lua_kernel::game_lua_kernel(const config &cfg, CVideo * video, game_state &
|
|||
{ "get_displayed_unit", boost::bind(&game_lua_kernel::intf_get_displayed_unit, this, _1) },
|
||||
{ "highlight_hex", boost::bind(&game_lua_kernel::intf_highlight_hex, this, _1) },
|
||||
{ "is_enemy", boost::bind(&game_lua_kernel::intf_is_enemy, this, _1) },
|
||||
{ "kill", boost::bind(&game_lua_kernel::intf_kill, this, _1) },
|
||||
{ "label", boost::bind(&game_lua_kernel::intf_label, this, _1) },
|
||||
{ "lock_view", boost::bind(&game_lua_kernel::intf_lock_view, this, _1) },
|
||||
{ "match_location", boost::bind(&game_lua_kernel::intf_match_location, this, _1) },
|
||||
|
|
|
@ -130,6 +130,7 @@ class game_lua_kernel : public lua_kernel_base
|
|||
int intf_remove_event(lua_State *L);
|
||||
int intf_color_adjust(lua_State *L);
|
||||
int intf_delay(lua_State *L);
|
||||
int intf_kill(lua_State *L);
|
||||
int intf_label(lua_State *L);
|
||||
int intf_redraw(lua_State *L);
|
||||
int intf_replace_schedule(lua_State *l);
|
||||
|
|
Loading…
Add table
Reference in a new issue