The Battle for Wesnoth  1.17.0-dev
pump.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2021
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Handles the current state of WML-events. This includes raising and firing,
19  * as well as tracking the context for event firing.
20  */
21 
22 #include "game_events/pump.hpp"
24 #include "game_events/handlers.hpp"
25 
26 #include "display_chat_manager.hpp"
27 #include "game_config.hpp"
28 #include "gettext.hpp"
29 #include "log.hpp"
30 #include "play_controller.hpp"
31 #include "resources.hpp"
33 #include "side_filter.hpp"
34 #include "units/map.hpp"
35 #include "units/unit.hpp"
36 #include "variable.hpp"
37 #include "whiteboard/manager.hpp"
38 
39 #include <iomanip>
40 #include <iostream>
41 
42 static lg::log_domain log_engine("engine");
43 #define DBG_NG LOG_STREAM(debug, log_engine)
44 #define LOG_NG LOG_STREAM(info, log_engine)
45 #define ERR_NG LOG_STREAM(err, log_engine)
46 
47 static lg::log_domain log_wml("wml");
48 #define DBG_WML LOG_STREAM(debug, log_wml)
49 #define LOG_WML LOG_STREAM(info, log_wml)
50 #define WRN_WML LOG_STREAM(warn, log_wml)
51 #define ERR_WML LOG_STREAM(err, log_wml)
52 
53 static lg::log_domain log_event_handler("event_handler");
54 #define DBG_EH LOG_STREAM(debug, log_event_handler)
55 
56 // This file is in the game_events namespace.
57 namespace game_events
58 {
59 namespace context
60 {
61 /** State when processing a particular flight of events or commands. */
62 struct state
63 {
67 
68  explicit state(bool s, bool m = true)
69  : undo_disabled(m)
70  , action_canceled(false)
71  , skip_messages(s)
72  {
73  }
74 };
75 
76 class scoped
77 {
78 public:
79  scoped(std::stack<context::state>& contexts, bool m = true);
80  ~scoped();
81 
82 private:
83  std::stack<context::state>& contexts_;
84 };
85 }
86 
87 struct pump_impl
88 {
89  std::vector<queued_event> events_queue;
90 
91  std::stringstream wml_messages_stream;
92 
93  std::stack<context::state> contexts_;
94 
95  unsigned instance_count;
96 
98 
100  : events_queue()
101  , wml_messages_stream()
102  , contexts_()
103  , instance_count(0)
104  , my_manager(&man)
105  {
106  contexts_.emplace(false);
107  }
108 };
109 
110 namespace
111 { // Types
112 class pump_manager
113 {
114 public:
115  pump_manager(pump_impl&);
116  ~pump_manager();
117 
118  /** Allows iteration through the queued events. */
119  queued_event& next()
120  {
121  return queue_[pumped_count_++];
122  }
123  /** Indicates the iteration is over. */
124  bool done() const
125  {
126  return pumped_count_ >= queue_.size();
127  }
128 
129  unsigned count() const
130  {
131  return impl_.instance_count;
132  }
133 
134 private:
135  pump_impl& impl_;
136  int x1_, x2_, y1_, y2_;
137 
138  /**
139  * Tracks the events to process.
140  * This isolates these events from any events that might be generated during the processing.
141  */
142  std::vector<queued_event> queue_;
143 
144  /** Tracks how many events have been processed. */
145  std::size_t pumped_count_;
146 };
147 } // end anonymous namespace (types)
148 
149 namespace
150 { // Support functions
151 
152 pump_manager::pump_manager(pump_impl& impl)
153  : impl_(impl)
154  , x1_(resources::gamedata->get_variable("x1"))
155  , x2_(resources::gamedata->get_variable("x2"))
156  , y1_(resources::gamedata->get_variable("y1"))
157  , y2_(resources::gamedata->get_variable("y2"))
158  , queue_()
159  , pumped_count_(0) // Filled later with a swap().
160 {
161  queue_.swap(impl_.events_queue);
162  ++impl_.instance_count;
163 }
164 
165 pump_manager::~pump_manager()
166 {
167  --impl_.instance_count;
168 
169  // Not sure what the correct thing to do is here. In princple,
170  // discarding all events (i.e. clearing events_queue) seems like
171  // the right thing to do in the face of an exception. However, the
172  // previous functionality preserved the queue, so for now we will
173  // restore it.
174  if(!done()) {
175  // The remaining events get inserted at the beginning of events_queue.
176  std::vector<queued_event> temp;
177  impl_.events_queue.swap(temp);
178  impl_.events_queue.insert(impl_.events_queue.end(), queue_.begin() + pumped_count_, queue_.end());
179  impl_.events_queue.insert(impl_.events_queue.end(), temp.begin(), temp.end());
180  }
181 
182  // Restore the old values of the game variables.
187 }
188 }
189 
190 /**
191  * Returns true iff the given event passes all its filters.
192  */
194 {
195  const unit_map& units = resources::gameboard->units();
196  unit_map::const_iterator unit1 = units.find(ev.loc1);
197  unit_map::const_iterator unit2 = units.find(ev.loc2);
198  vconfig filters(handler.get_config());
199 
200  for(const vconfig& condition : filters.get_children("filter_condition")) {
201  if(!conditional_passed(condition)) {
202  return false;
203  }
204  }
205 
206  for(const vconfig& f : filters.get_children("filter_side")) {
207  side_filter ssf(f, &resources::controller->gamestate());
209  return false;
210  }
211 
212  for(const vconfig& f : filters.get_children("filter")) {
213  if(!ev.loc1.matches_unit_filter(unit1, f)) {
214  return false;
215  }
216  }
217 
218  vconfig::child_list special_filters = filters.get_children("filter_attack");
219  bool special_matches = special_filters.empty();
220  if(!special_matches && unit1 != units.end()) {
221  const bool matches_unit = ev.loc1.matches_unit(unit1);
222  const config& attack = ev.data.child("first");
223  for(const vconfig& f : special_filters) {
224  if(f.empty()) {
225  special_matches = true;
226  } else if(!matches_unit) {
227  return false;
228  }
229 
230  special_matches = special_matches || matches_special_filter(attack, f);
231  }
232  }
233 
234  if(!special_matches) {
235  return false;
236  }
237 
238  for(const vconfig& f : filters.get_children("filter_second")) {
239  if(!ev.loc2.matches_unit_filter(unit2, f)) {
240  return false;
241  }
242  }
243 
244  special_filters = filters.get_children("filter_second_attack");
245  special_matches = special_filters.empty();
246  if(!special_matches && unit2 != units.end()) {
247  const bool matches_unit = ev.loc2.matches_unit(unit2);
248  const config& attack = ev.data.child("second");
249  for(const vconfig& f : special_filters) {
250  if(f.empty()) {
251  special_matches = true;
252  } else if(!matches_unit) {
253  return false;
254  }
255 
256  special_matches = special_matches || matches_special_filter(attack, f);
257  }
258  }
259 
260  if(!special_matches) {
261  return false;
262  }
263 
264  // All filters passed.
265  return true;
266 }
267 
268 /**
269  * Processes an event through a single event handler.
270  * This includes checking event filters, but not checking that the event
271  * name matches.
272  *
273  * @param[in,out] handler_p The handler to offer the event to.
274  * This may be reset during processing.
275  * @param[in] ev The event information.
276  */
278 {
279  DBG_EH << "processing event " << ev.name << " with id=" << ev.id << "\n";
280 
281  // We currently never pass a null pointer to this function, but to
282  // guard against future modifications:
283  if(!handler_p) {
284  return;
285  }
286 
287  unit_map& units = resources::gameboard->units();
288  scoped_xy_unit first_unit("unit", ev.loc1, units);
289  scoped_xy_unit second_unit("second_unit", ev.loc2, units);
290  scoped_weapon_info first_weapon("weapon", ev.data.child("first"));
291  scoped_weapon_info second_weapon("second_weapon", ev.data.child("second"));
292 
293  if(!filter_event(*handler_p, ev)) {
294  return;
295  }
296 
297  // The event hasn't been filtered out, so execute the handler.
298  context::scoped evc(impl_->contexts_);
299  assert(resources::lua_kernel != nullptr);
300  handler_p->handle_event(ev, *resources::lua_kernel);
301  // NOTE: handler_p may be null at this point!
302 
303  if(ev.name == "select") {
305  }
306 
307  if(game_display::get_singleton() != nullptr) {
309  }
310 }
311 
312 /**
313  * Helper function for show_wml_messages(), which gathers
314  * the messages from a stringstream.
315  */
316 void wml_event_pump::fill_wml_messages_map(std::map<std::string, int>& msg_map, std::stringstream& source)
317 {
318  while(true) {
319  std::string msg;
320  std::getline(source, msg);
321 
322  if(source.eof()) {
323  break;
324  }
325 
326  if(msg.empty()) {
327  continue;
328  }
329 
330  if(msg_map.find(msg) == msg_map.end()) {
331  msg_map[msg] = 1;
332  } else {
333  msg_map[msg]++;
334  }
335  }
336 
337  // Make sure the eof flag is cleared otherwise no new messages are shown
338  source.clear();
339 }
340 
341 /**
342  * Shows a summary of messages/errors generated so far by WML.
343  * Identical messages are shown once, with (between parentheses)
344  * the number of times that message was encountered.
345  * The order in which the messages are shown does not need
346  * to be the order in which these messages are encountered.
347  *
348  * @param source The source to be parsed before being displayed.
349  * @param caption The text to display before each message parsed from @a source.
350  */
351 void wml_event_pump::show_wml_messages(std::stringstream& source, const std::string& caption)
352 {
353  // Get all unique messages in messages,
354  // with the number of encounters for these messages
355  std::map<std::string, int> messages;
356  fill_wml_messages_map(messages, source);
357 
358  // Show the messages collected
359  for(std::map<std::string, int>::const_iterator itor = messages.begin(); itor != messages.end(); ++itor) {
360  std::stringstream msg;
361  msg << itor->first;
362  if(itor->second > 1) {
363  msg << " (" << itor->second << ")";
364  }
365 
367  std::time(nullptr), caption, 0, msg.str(), events::chat_handler::MESSAGE_PUBLIC, false);
368  }
369 }
370 
371 /**
372  * Shows a summary of the errors encountered in WML so far,
373  * to avoid a lot of the same messages to be shown.
374  * Identical messages are shown once, with (between parentheses)
375  * the number of times that message was encountered.
376  * The order in which the messages are shown does not need
377  * to be the order in which these messages are encountered.
378  * Messages are always written to std::cerr.
379  */
381 {
382  show_wml_messages(lg::log_to_chat(), "");
383 }
384 
385 /**
386  * Shows a summary of the messages generated so far by WML.
387  * Identical messages are shown once, with (between parentheses)
388  * the number of times that message was encountered.
389  * The order in which the messages are shown does not need
390  * to be the order in which these messages are encountered.
391  */
393 {
394  show_wml_messages(impl_->wml_messages_stream, "WML: ");
395 }
396 
398  lg::logger& logger, const std::string& prefix, const std::string& message, bool in_chat)
399 {
400  FORCE_LOG_TO(logger, log_wml) << message << std::endl;
401  if(in_chat) {
402  impl_->wml_messages_stream << prefix << message << std::endl;
403  }
404 }
405 
406 context::scoped::scoped(std::stack<context::state>& contexts, bool m)
407  : contexts_(contexts)
408 {
409  // The default context at least should always be on the stack
410  assert(contexts_.size() > 0);
411 
412  bool skip_messages = (contexts_.size() > 1) && contexts_.top().skip_messages;
413  contexts_.emplace(skip_messages, m);
414 }
415 
417 {
418  assert(contexts_.size() > 1);
419  bool undo_disabled = contexts_.top().undo_disabled;
420  bool action_canceled = contexts_.top().action_canceled;
421 
422  contexts_.pop();
423  contexts_.top().undo_disabled |= undo_disabled;
424  contexts_.top().action_canceled |= action_canceled;
425 }
426 
428 {
429  assert(impl_->contexts_.size() > 0);
430  return impl_->contexts_.top().undo_disabled;
431 }
432 
434 {
435  assert(impl_->contexts_.size() > 0);
436  impl_->contexts_.top().undo_disabled = b;
437 }
438 
440 {
441  assert(impl_->contexts_.size() > 0);
442  return impl_->contexts_.top().action_canceled;
443 }
444 
446 {
447  assert(impl_->contexts_.size() > 0);
448  impl_->contexts_.top().action_canceled = true;
449 }
450 
451 
453 {
454  assert(impl_->contexts_.size() > 0);
455  return impl_->contexts_.top().skip_messages;
456 }
457 
459 {
460  assert(impl_->contexts_.size() > 0);
461  impl_->contexts_.top().skip_messages = b;
462 }
463 
464 /**
465  * Helper function which determines whether a wml_message text can
466  * really be pushed into the wml_messages_stream, and does it.
467  */
468 void wml_event_pump::put_wml_message(const std::string& logger, const std::string& message, bool in_chat)
469 {
470  if(logger == "err" || logger == "error") {
471  put_wml_message(lg::err(), _("Error: "), message, in_chat);
472  } else if(logger == "warn" || logger == "wrn" || logger == "warning") {
473  put_wml_message(lg::warn(), _("Warning: "), message, in_chat);
474  } else if((logger == "debug" || logger == "dbg") && !lg::debug().dont_log(log_wml)) {
475  put_wml_message(lg::debug(), _("Debug: "), message, in_chat);
476  } else if(!lg::info().dont_log(log_wml)) {
477  put_wml_message(lg::info(), _("Info: "), message, in_chat);
478  }
479 }
480 
482  const std::string& event, const entity_location& loc1, const entity_location& loc2, const config& data)
483 {
484  raise(event, loc1, loc2, data);
485  return (*this)();
486 }
487 
488 pump_result_t wml_event_pump::fire(const std::string& event,
489  const std::string& id,
490  const entity_location& loc1,
491  const entity_location& loc2,
492  const config& data)
493 {
494  raise(event, id, loc1, loc2, data);
495  return (*this)();
496 }
497 
498 void wml_event_pump::raise(const std::string& event,
499  const std::string& id,
500  const entity_location& loc1,
501  const entity_location& loc2,
502  const config& data)
503 {
504  if(game_display::get_singleton() == nullptr)
505  return;
506 
507  DBG_EH << "raising event name=" << event << ", id=" << id << "\n";
508 
509  impl_->events_queue.emplace_back(event, id, loc1, loc2, data);
510 }
511 
513 {
514  // Quick aborts:
515  if(game_display::get_singleton() == nullptr) {
516  return pump_result_t();
517  }
518 
519  assert(resources::lua_kernel != nullptr);
520  if(impl_->events_queue.empty()) {
521  DBG_EH << "Processing queued events, but none found.\n";
522  return pump_result_t();
523  }
524 
525  if(impl_->instance_count >= game_config::max_loop) {
526  ERR_NG << "game_events pump waiting to process new events because "
527  << "recursion level would exceed maximum: " << game_config::max_loop << '\n';
528  return pump_result_t();
529  }
530 
531  if(!lg::debug().dont_log(log_event_handler)) {
532  std::stringstream ss;
533  for(const queued_event& ev : impl_->events_queue) {
534  ss << "name=" << ev.name << ", "
535  << "id=" << ev.id << "; ";
536  }
537  DBG_EH << "processing queued events: " << ss.str() << "\n";
538  }
539 
540  // Ensure the whiteboard doesn't attempt to build its future unit map
541  // while events are being processed.
542  wb::real_map real_unit_map;
543 
544  pump_manager pump_instance(*impl_);
545  context::scoped evc(impl_->contexts_, false);
546  // Loop through the events we need to process.
547  while(!pump_instance.done()) {
548  queued_event& ev = pump_instance.next();
549 
550  if(ev.name.empty() && ev.id.empty()) {
551  continue;
552  }
553 
554  const std::string& event_name = ev.name;
555  const std::string& event_id = ev.id;
556 
557  // Clear the unit cache, since the best clearing time is hard to figure out
558  // due to status changes by WML. Every event will flush the cache.
560 
561  { // Block for context::scoped
562  context::scoped inner_evc(impl_->contexts_, false);
564  }
565 
566  assert(impl_->my_manager);
567 
572 
573  if(event_id.empty()) {
574  // Handle events of this name.
575  impl_->my_manager->execute_on_events(event_name, [&](game_events::manager&, handler_ptr& ptr) {
576  DBG_EH << "processing event " << event_name << " with id=" << ptr->get_config()["id"] << "\n";
577 
578  // Let this handler process our event.
579  process_event(ptr, ev);
580  });
581  } else {
582  // Get the handler directly via ID
583  handler_ptr cur_handler = impl_->my_manager->get_event_handler_by_id(event_id);
584 
585  if(cur_handler) {
586  DBG_EH << "processing event " << event_name << " with id=" << cur_handler->get_config()["id"] << "\n";
587  process_event(cur_handler, ev);
588  }
589  }
590 
591  // Flush messages when finished iterating over event_handlers.
592  flush_messages();
593  }
594 
595  // Notify the whiteboard of any event.
596  // This is used to track when moves, recruits, etc. happen.
597  resources::whiteboard->on_gamestate_change();
598 
599  return std::tuple(undo_disabled(), action_canceled());
600 }
601 
603 {
604  // Dialogs can only be shown if the display is not locked
605  if(game_display::get_singleton() && !CVideo::get_singleton().update_locked()) {
606  show_wml_errors();
607  show_wml_messages();
608  }
609 }
610 
612  : impl_(new pump_impl(man))
613 {
614 }
615 
617 {
618 }
619 
620 } // end namespace game_events
play_controller * controller
Definition: resources.cpp:22
manager * my_manager
Definition: pump.cpp:97
int x2_
Definition: pump.cpp:136
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
std::vector< queued_event > queue_
Tracks the events to process.
Definition: pump.cpp:142
unit_iterator end()
Definition: map.hpp:429
entity_location loc2
Definition: pump.hpp:66
State when processing a particular flight of events or commands.
Definition: pump.cpp:62
map_location last_selected
the last location where a select event fired.
Definition: game_data.hpp:92
#define ERR_NG
Definition: pump.cpp:45
bool matches_unit_filter(const unit_map::const_iterator &un_it, const vconfig &filter) const
Determines if un_it matches filter.
wml_event_pump(manager &)
Definition: pump.cpp:611
virtual const unit_map & units() const override
Definition: game_board.hpp:112
logger & info()
Definition: log.cpp:89
std::stringstream wml_messages_stream
Definition: pump.cpp:91
const map_location & filter_loc() const
int wml_x() const
Definition: location.hpp:153
static CVideo & get_singleton()
Definition: video.hpp:49
std::string name
Definition: pump.hpp:63
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
scoped(std::stack< context::state > &contexts, bool m=true)
Definition: pump.cpp:406
bool action_canceled()
Returns whether or not wml wants to abort the currently executed user action.
Definition: pump.cpp:439
static std::string _(const char *str)
Definition: gettext.hpp:93
const std::size_t max_loop
The maximum number of hexes on a map and items in an array and also used as maximum in wml loops...
Definition: game_config.cpp:93
game_data * gamedata
Definition: resources.cpp:23
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
Definition: game_data.cpp:63
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
#define b
int x1_
Definition: pump.cpp:136
int y2_
Definition: pump.cpp:136
static lg::log_domain log_engine("engine")
static void clear_status_caches()
Clear this unit status cache for all units.
Definition: unit.cpp:673
child_list get_children(const std::string &key) const
Definition: variable.cpp:226
const config & get_config() const
Definition: handlers.hpp:69
bool matches_unit(const unit_map::const_iterator &un_it) const
Determines if un_it matches (using underlying ID) the unit that was supplied when this was constructe...
int wml_y() const
Definition: location.hpp:154
void show_wml_messages()
Shows a summary of the messages generated so far by WML.
Definition: pump.cpp:392
pump_impl(manager &man)
Definition: pump.cpp:99
game_board * gameboard
Definition: resources.cpp:21
std::vector< queued_event > events_queue
Definition: pump.cpp:89
void flush_messages()
Flushes WML messages and errors.
Definition: pump.cpp:602
bool run_event(const game_events::queued_event &)
Executes the game_events.on_event function.
void show_wml_errors()
Shows a summary of the errors encountered in WML so far, to avoid a lot of the same messages to be sh...
Definition: pump.cpp:380
logger & debug()
Definition: log.cpp:95
static lg::log_domain log_event_handler("event_handler")
Domain specific events.
Definition: action_wml.cpp:87
int y1_
Definition: pump.cpp:136
unit_iterator find(std::size_t id)
Definition: map.cpp:310
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:34
state(bool s, bool m=true)
Definition: pump.cpp:68
Define conditionals for the game&#39;s events mechanism, a.k.a.
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
#define FORCE_LOG_TO(logger, domain)
Definition: log.hpp:231
std::size_t pumped_count_
Tracks how many events have been processed.
Definition: pump.cpp:145
void put_wml_message(const std::string &logger, const std::string &message, bool in_chat)
Helper function which determines whether a wml_message text can really be pushed into the wml_message...
Definition: pump.cpp:468
logger & err()
Definition: log.cpp:77
void raise(const std::string &event, const std::string &id, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Definition: pump.cpp:498
bool undo_disabled()
Context: The general environment within which events are processed.
Definition: pump.cpp:427
bool matches_special_filter(const config &cfg, const vconfig &filter)
void set_action_canceled()
Sets whether or not wml wants to abort the currently executed user action.
Definition: pump.cpp:445
static map_location::DIRECTION s
pump_result_t operator()()
Definition: pump.cpp:512
pump_impl & impl_
Definition: pump.cpp:135
Define the game&#39;s event mechanism.
#define DBG_EH
Definition: pump.cpp:54
The game event manager loads the scenario configuration object, and ensures that events are handled a...
Definition: manager.hpp:44
static lg::log_domain log_wml("wml")
void process_event(handler_ptr &handler_p, const queued_event &ev)
Processes an event through a single event handler.
Definition: pump.cpp:277
pump_result_t fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
Definition: pump.cpp:481
entity_location loc1
Definition: pump.hpp:65
#define next(ls)
Definition: llex.cpp:32
display_chat_manager & get_chat_manager()
bool conditional_passed(const vconfig &cond)
bool match(const team &t) const
Define the handlers for the game&#39;s events mechanism.
logger & warn()
Definition: log.cpp:83
#define f
unsigned instance_count
Definition: pump.cpp:95
bool filter_event(const event_handler &handler, const queued_event &ev)
Returns true iff the given event passes all its filters.
Definition: pump.cpp:193
void set_undo_disabled(bool mutated)
[allow_undo] implementation
Definition: pump.cpp:433
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
Standard logging facilities (interface).
int current_side() const
Returns the number of the side whose turn it is.
game_lua_kernel * lua_kernel
Definition: resources.cpp:26
Container associating units to locations.
Definition: map.hpp:98
void fill_wml_messages_map(std::map< std::string, int > &msg_map, std::stringstream &source)
Helper function for show_wml_messages(), which gathers the messages from a stringstream.
Definition: pump.cpp:316
std::stack< context::state > contexts_
Definition: pump.cpp:93
std::stack< context::state > & contexts_
Definition: pump.cpp:83
std::vector< vconfig > child_list
Definition: variable.hpp:78
std::shared_ptr< event_handler > handler_ptr
Definition: fwd.hpp:25
std::tuple< bool, bool > pump_result_t
Definition: fwd.hpp:29
Ensures that the real unit map is active for the duration of the struct&#39;s life.
Definition: manager.hpp:283
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition: log.cpp:289
static game_display * get_singleton()
bool maybe_rebuild()
Rebuilds the screen if needs_rebuild(true) was previously called, and resets the flag.
bool context_skip_messages()
Returns whether or not we are skipping messages.
Definition: pump.cpp:452