Added patch by Brilliand for bug #2851
(Ghast and Necrophage double feeding) 1. Added event ids to prevent duplicates 2. Added event deletion via ids.
This commit is contained in:
parent
d8a87d0335
commit
aead1784f1
4 changed files with 105 additions and 59 deletions
|
@ -99,6 +99,8 @@ Version 1.9.8+svn:
|
|||
* Increased the swamp defense from 10% to 20%
|
||||
* Decreased the hill defense from 60% to 50%
|
||||
* WML engine:
|
||||
* Added [event]id= support (to protect against duplicates)
|
||||
* Added [event]delete=true support (to remove events that have an id set)
|
||||
* Implemented sub= and divide= for abilities and weapon specials
|
||||
(patch #2857)
|
||||
* new attribute replay_save= in [end_level]. Defaults to yes, allows
|
||||
|
|
|
@ -893,6 +893,9 @@
|
|||
[entry]
|
||||
name = "Ben Anderman (crimson_penguin)"
|
||||
comment = "unit list"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Brilliand"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Burkay Özdemir (Velory)"
|
||||
|
|
|
@ -527,18 +527,9 @@ Enemy units cannot see this unit while it is in deep water, except if they have
|
|||
This unit gains 1 hitpoint added to its maximum whenever it kills a living unit."
|
||||
[/dummy] # a hack to please wmlxgettext (using a bug in wmlxgettext!): dummy tag start: [abilities]
|
||||
[/abilities]
|
||||
|
||||
# NOTE: the purpose of the unit.variables.killed_by_feeding variable is to
|
||||
# prevent multiple instances of feeding stacking with each other: the first
|
||||
# event will not trigger for units marked as already having been killed by
|
||||
# feeding on this turn. The turn number is included in the variable value in
|
||||
# order to decrease the chances of feeding not working on a unit as a result of
|
||||
# a scenario event storing it upon death and bringing it back later, in which
|
||||
# case the variable could still be intact. However, this doesn't work in every
|
||||
# imaginable situation and therefore a better fix is still needed eventually.
|
||||
|
||||
[event]
|
||||
name=last breath
|
||||
id=ability_feeding_die
|
||||
name=die
|
||||
first_time_only=no
|
||||
|
||||
[filter]
|
||||
|
@ -548,14 +539,6 @@ This unit gains 1 hitpoint added to its maximum whenever it kills a living unit.
|
|||
not_living="yes"
|
||||
[/status]
|
||||
[/filter_wml]
|
||||
|
||||
[or]
|
||||
[filter_wml]
|
||||
[variables]
|
||||
killed_by_feeding="on_turn_$turn_number"
|
||||
[/variables]
|
||||
[/filter_wml]
|
||||
[/or]
|
||||
[/not]
|
||||
[/filter]
|
||||
|
||||
|
@ -563,13 +546,6 @@ This unit gains 1 hitpoint added to its maximum whenever it kills a living unit.
|
|||
ability=feeding
|
||||
[/filter_second]
|
||||
|
||||
{VARIABLE unit.variables.killed_by_feeding "on_turn_$turn_number"}
|
||||
|
||||
[unstore_unit]
|
||||
variable=unit
|
||||
find_vacant=no
|
||||
[/unstore_unit]
|
||||
|
||||
[unstore_unit]
|
||||
variable=second_unit
|
||||
{COLOR_HEAL}
|
||||
|
@ -592,25 +568,6 @@ This unit gains 1 hitpoint added to its maximum whenever it kills a living unit.
|
|||
[/effect]
|
||||
[/object]
|
||||
[/event]
|
||||
[event]
|
||||
name=die
|
||||
first_time_only=no
|
||||
|
||||
[filter]
|
||||
[filter_wml]
|
||||
[variables]
|
||||
killed_by_feeding="on_turn_$turn_number"
|
||||
[/variables]
|
||||
[/filter_wml]
|
||||
[/filter]
|
||||
|
||||
{CLEAR_VARIABLE unit.variables.killed_by_feeding}
|
||||
|
||||
[unstore_unit]
|
||||
variable=unit
|
||||
find_vacant=no
|
||||
[/unstore_unit]
|
||||
[/event]
|
||||
[+abilities] # a hack to please wmlxgettext (using a bug in wmlxgettext!): dummy tag end: [/abilities]
|
||||
#enddef
|
||||
# wmllint: unbalanced-off
|
||||
|
|
|
@ -123,7 +123,6 @@ namespace {
|
|||
bool manager_running = false;
|
||||
int floating_label = 0;
|
||||
|
||||
std::vector< game_events::event_handler > new_handlers;
|
||||
typedef std::pair< std::string, config* > wmi_command_change;
|
||||
std::vector< wmi_command_change > wmi_command_changes;
|
||||
|
||||
|
@ -570,7 +569,92 @@ static map_location cfg_to_loc(const vconfig& cfg,int defaultx = 0, int defaulty
|
|||
|
||||
namespace {
|
||||
|
||||
std::vector<game_events::event_handler> event_handlers;
|
||||
class t_event_handlers : public std::vector<game_events::event_handler> {
|
||||
private:
|
||||
std::vector<game_events::event_handler> insert_buffer;
|
||||
std::set<std::string> remove_buffer;
|
||||
bool buffering;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Adds an event handler. An event with a nonempty ID will not
|
||||
* be added if an event with that ID already exists. This method
|
||||
* respects this class's buffering functionality.
|
||||
*/
|
||||
void add_event_handler(game_events::event_handler const & new_handler) {
|
||||
if(buffering) {
|
||||
insert_buffer.push_back(new_handler);
|
||||
} else {
|
||||
const config & cfg = new_handler.get_config();
|
||||
std::string id = cfg["id"];
|
||||
if(id != "") {
|
||||
for(std::vector<game_events::event_handler>::iterator i = begin(); i < end(); i++) {
|
||||
const config & temp_config = (*i).get_config();
|
||||
if(id == temp_config["id"])
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->push_back(new_handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event handler, identified by its ID. Events with
|
||||
* empty IDs cannot be removed. This method respects this class's
|
||||
* buffering functionality.
|
||||
*/
|
||||
void remove_event_handler(std::string const & id) {
|
||||
if(id == "")
|
||||
return;
|
||||
|
||||
if(buffering)
|
||||
remove_buffer.insert(id);
|
||||
|
||||
std::vector<game_events::event_handler> &temp = buffering ? insert_buffer : *this;
|
||||
|
||||
std::vector<game_events::event_handler>::iterator i = temp.begin();
|
||||
while(i < temp.end()) {
|
||||
const config & temp_config = (*i).get_config();
|
||||
std::string event_id = temp_config["id"];
|
||||
if(event_id != "" && event_id == id)
|
||||
i = temp.erase(i);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts buffering. While buffering, any calls to add_event_handler
|
||||
* and remove_event_handler will not take effect until commit_buffer
|
||||
* is called. This function is idempotent - starting a buffer
|
||||
* when already buffering will not start a second buffer.
|
||||
*/
|
||||
void start_buffer() {
|
||||
buffering = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops buffering and commits all changes.
|
||||
*/
|
||||
void commit_buffer() {
|
||||
if(!buffering)
|
||||
return;
|
||||
|
||||
buffering = false;
|
||||
|
||||
// Commit any event removals
|
||||
for(std::set<std::string>::iterator i = remove_buffer.begin(); i != remove_buffer.end(); i++)
|
||||
remove_event_handler(*i);
|
||||
remove_buffer.clear();
|
||||
|
||||
// Commit any spawned events-within-events
|
||||
for(std::vector<game_events::event_handler>::iterator i = insert_buffer.begin(); i != insert_buffer.end(); i++)
|
||||
add_event_handler(*i);
|
||||
insert_buffer.clear();
|
||||
}
|
||||
};
|
||||
|
||||
t_event_handlers event_handlers;
|
||||
|
||||
} // end anonymous namespace (4)
|
||||
|
||||
|
@ -2693,10 +2777,12 @@ WML_HANDLER_FUNCTION(disallow_end_turn, /*event_info*/, /*cfg*/)
|
|||
// Adding new events
|
||||
WML_HANDLER_FUNCTION(event, /*event_info*/, cfg)
|
||||
{
|
||||
if (!cfg["delayed_variable_substitution"].to_bool(true)) {
|
||||
new_handlers.push_back(game_events::event_handler(cfg.get_parsed_config()));
|
||||
if (cfg["remove"].to_bool(false)) {
|
||||
event_handlers.remove_event_handler(cfg["id"]);
|
||||
} else if (!cfg["delayed_variable_substitution"].to_bool(true)) {
|
||||
event_handlers.add_event_handler(game_events::event_handler(cfg.get_parsed_config()));
|
||||
} else {
|
||||
new_handlers.push_back(game_events::event_handler(cfg.get_config()));
|
||||
event_handlers.add_event_handler(game_events::event_handler(cfg.get_config()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2767,10 +2853,7 @@ WML_HANDLER_FUNCTION(clear_global_variable,/**/,pcfg)
|
|||
|
||||
static void commit_new_handlers() {
|
||||
// Commit any spawned events-within-events
|
||||
while(new_handlers.size() > 0) {
|
||||
event_handlers.push_back(new_handlers.back());
|
||||
new_handlers.pop_back();
|
||||
}
|
||||
event_handlers.commit_buffer();
|
||||
}
|
||||
static void commit_wmi_commands() {
|
||||
// Commit WML Menu Item command changes
|
||||
|
@ -2797,7 +2880,7 @@ static void commit_wmi_commands() {
|
|||
}
|
||||
} else if(!is_empty_command) {
|
||||
LOG_NG << "setting command for " << mref->name << " to:\n" << *wcc.second;
|
||||
event_handlers.push_back(game_events::event_handler(mref->command, true));
|
||||
event_handlers.add_event_handler(game_events::event_handler(mref->command, true));
|
||||
}
|
||||
|
||||
delete wcc.second;
|
||||
|
@ -3068,7 +3151,7 @@ namespace game_events {
|
|||
{
|
||||
assert(!manager_running);
|
||||
foreach (const config &ev, cfg.child_range("event")) {
|
||||
event_handlers.push_back(game_events::event_handler(ev));
|
||||
event_handlers.add_event_handler(game_events::event_handler(ev));
|
||||
}
|
||||
foreach (const std::string &id, utils::split(cfg["unit_wml_ids"])) {
|
||||
unit_wml_ids.insert(id);
|
||||
|
@ -3092,7 +3175,7 @@ namespace game_events {
|
|||
typedef std::pair<std::string, wml_menu_item *> item;
|
||||
foreach (const item &itor, resources::state_of_game->wml_menu_items) {
|
||||
if (!itor.second->command.empty()) {
|
||||
event_handlers.push_back(game_events::event_handler(itor.second->command, true));
|
||||
event_handlers.add_event_handler(game_events::event_handler(itor.second->command, true));
|
||||
}
|
||||
++wmi_count;
|
||||
}
|
||||
|
@ -3176,8 +3259,7 @@ namespace game_events {
|
|||
if(std::find(unit_wml_ids.begin(),unit_wml_ids.end(),id) == unit_wml_ids.end()) {
|
||||
unit_wml_ids.insert(id);
|
||||
foreach (const config &new_ev, cfgs) {
|
||||
std::vector<game_events::event_handler> &temp = (pump_manager::count()) ? new_handlers : event_handlers;
|
||||
temp.push_back(game_events::event_handler(new_ev));
|
||||
event_handlers.add_event_handler(game_events::event_handler(new_ev));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3208,6 +3290,8 @@ namespace game_events {
|
|||
return false;
|
||||
}
|
||||
|
||||
event_handlers.start_buffer();
|
||||
|
||||
bool result = false;
|
||||
while(events_queue.empty() == false) {
|
||||
game_events::queued_event ev = events_queue.front();
|
||||
|
|
Loading…
Add table
Reference in a new issue