Author: suokko
Date: Wed Jun 25 13:28:04 2008
New Revision: 27502

URL: http://svn.gna.org/viewcvs/wesnoth?rev=27502&view=rev
Log:
Added recursion preventarion to [kill] fire_event=yes [/kill] (bug: 11207)

Modified:
    trunk/changelog
    trunk/src/game_events.cpp

Modified: trunk/changelog
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/changelog?rev=27502&r1=27501&r2=27502&view=diff
==============================================================================
--- trunk/changelog (original)
+++ trunk/changelog Wed Jun 25 13:28:04 2008
@@ -6,6 +6,7 @@
    * rewrote the textbox history saving of the new widget library. This rewrite
      is incompatible with the old version, but since the library is still in
      development, no compatibility layer has been added.
+   * Added recursion preventarion to [kill] fire_event=yes [/kill]
 
 Version 1.5.1:
  * campaigns:

Modified: trunk/src/game_events.cpp
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/src/game_events.cpp?rev=27502&r1=27501&r2=27502&view=diff
==============================================================================
--- trunk/src/game_events.cpp (original)
+++ trunk/src/game_events.cpp Wed Jun 25 13:28:04 2008
@@ -49,6 +49,8 @@
 #include <iterator>
 #include <set>
 #include <string>
+
+#include <boost/scoped_ptr.hpp>
 
 #define DBG_NG LOG_STREAM(debug, engine)
 #define LOG_NG LOG_STREAM(info, engine)
@@ -1905,6 +1907,42 @@
                else
                        LOG_NO << log_message << "\n";
        }
+
+
+       typedef std::map<gamemap::location, int> recursion_counter;
+       
+       class recursion_preventer {
+               static recursion_counter counter_;
+               static const int max_recursion = 10;
+               gamemap::location loc_;
+               bool too_many_recursions_;
+
+               public:
+               recursion_preventer(gamemap::location& loc) : loc_(loc)
+               {
+                       const int nill = 0;
+                       recursion_counter::iterator inserted = 
counter_.insert(std::make_pair(loc_, nill)).first;
+                       ++inserted->second;
+                       too_many_recursions_ = inserted->second >= 
max_recursion;
+               }
+               ~recursion_preventer()
+               {
+                       recursion_counter::iterator itor = counter_.find(loc_);
+                       if (--itor->second == 0)
+                       {
+                               counter_.erase(itor);
+                       }
+               }
+               bool too_many_recursions() const
+               {
+                       return too_many_recursions_;
+               }
+       };
+
+       recursion_counter recursion_preventer::counter_ = recursion_counter();
+
+       typedef boost::scoped_ptr<recursion_preventer> recursion_preventer_ptr;
+
        WML_HANDLER_FUNCTION(kill,handler,event_info,cfg)
        {
                // Use (x,y) iteration, because firing events ruins unit_map 
iteration
@@ -1919,11 +1957,21 @@
                                        
if(utils::string_bool(cfg["fire_event"])) {
                                                game_events::entity_location 
death_loc(un);
                                                // Prevent infinite recursion 
of 'die' events
+                                               bool fire_event = true;
+                                               recursion_preventer_ptr 
recursion_prevent;
+                                               
                                                if (event_info.loc1 == 
death_loc && event_info.name == "die" && !handler.first_time_only())
                                                {
-                                                       ERR_NG << "tried to 
fire 'die' event on primary_unit inside its own 'die' event with 
'first_time_only' set to false!\n";
+                                                       
recursion_prevent.reset(new recursion_preventer(death_loc));
+
+                                                       
if(recursion_prevent->too_many_recursions())
+                                                       {
+                                                               fire_event = 
false;
+
+                                                               ERR_NG << 
"tried to fire 'die' event on primary_unit inside its own 'die' event with 
'first_time_only' set to false!\n";
+                                                       }
                                                }
-                                               else
+                                               if (fire_event)
                                                {
                                                        
game_events::fire("die", death_loc, death_loc);
                                                        un = 
units->find(death_loc);


_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits

Reply via email to