The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
handlers.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * The structure that tracks WML event handlers.
18  * (Typically, handlers are defined by [event] tags.)
19  */
20 
21 #include "game_events/handlers.hpp"
24 #include "game_events/pump.hpp"
25 
26 #include "formula/string_utils.hpp"
27 #include "game_data.hpp"
28 #include "log.hpp"
29 #include "reports.hpp"
32 #include "sound.hpp"
33 #include "soundsource.hpp"
34 
35 #include <iostream>
36 
37 static lg::log_domain log_engine("engine");
38 #define DBG_NG LOG_STREAM(debug, log_engine)
39 #define LOG_NG LOG_STREAM(info, log_engine)
40 #define WRN_NG LOG_STREAM(warn, log_engine)
41 
42 static lg::log_domain log_event_handler("event_handler");
43 #define DBG_EH LOG_STREAM(debug, log_event_handler)
44 
45 // This file is in the game_events namespace.
46 namespace game_events
47 {
48 /* ** handler_list::iterator ** */
49 
50 /**
51  * Dereference.
52  * If the current element has become invalid, we will increment first.
53  */
55 {
56  // Check for an available handler.
57  while(iter_.derefable()) {
58  // Handler still accessible?
59  if(handler_ptr lock = iter_->lock()) {
60  return lock;
61  } else {
62  // Remove the now-defunct entry.
64  }
65  }
66 
67  // End of the list.
68  return handler_ptr();
69 }
70 
71 /* ** event_handler ** */
72 
73 event_handler::event_handler(const config& cfg, bool imi, handler_vec::size_type index, manager& man)
74  : first_time_only_(cfg["first_time_only"].to_bool(true))
75  , is_menu_item_(imi)
76  , index_(index)
77  , man_(&man)
78  , cfg_(cfg)
79 {
80 }
81 
82 /**
83  * Disables *this, removing it from the game.
84  * (Technically, the handler is only removed once no one is hanging on to a
85  * handler_ptr to *this. So be careful how long they persist.)
86  *
87  * WARNING: *this may be destroyed at the end of this call, unless
88  * the caller maintains a handler_ptr to this.
89  */
91 {
92  assert(man_);
93  assert(man_->event_handlers_);
94 
95  // Handlers must have an index after they're created.
96  assert(index_ < man_->event_handlers_->size());
97 
98  // Disable this handler.
99  (*man_->event_handlers_)[index_].reset();
100 }
101 
102 /**
103  * Handles the queued event, according to our WML instructions.
104  * WARNING: *this may be destroyed at the end of this call, unless
105  * the caller maintains a handler_ptr to this.
106  *
107  * @param[in] event_info Information about the event that needs handling.
108  * @param[in,out] handler_p The caller's smart pointer to *this. It may be
109  * reset() during processing.
110  */
111 void event_handler::handle_event(const queued_event& event_info, handler_ptr& handler_p, game_lua_kernel& lk)
112 {
113  // We will need our config after possibly self-destructing. Make a copy now.
114  // TODO: instead of copying possibly huge config objects we should use shared things and only increase a refcount
115  // here.
116  vconfig vcfg(cfg_, true);
117 
118  if(is_menu_item_) {
119  DBG_NG << cfg_["name"] << " will now invoke the following command(s):\n" << cfg_;
120  }
121 
122  if(first_time_only_) {
123  // Disable this handler.
124  disable();
125 
126  // Also remove our caller's hold on us.
127  handler_p.reset();
128  }
129  // *WARNING*: At this point, dereferencing this could be a memory violation!
130 
131  lk.run_wml_action("command", vcfg, event_info);
133 }
134 
136 {
137  const std::string my_names = !gd
138  ? cfg_["name"].str()
140 
141  std::string::const_iterator
142  itor, it_begin = my_names.begin(),
143  it_end = my_names.end(),
144  match_it = name.begin(),
145  match_begin = name.begin(),
146  match_end = name.end();
147 
148  int skip_count = 0;
149  for(itor = it_begin; itor != it_end; ++itor) {
150  bool do_eat = false, do_skip = false;
151 
152  switch(*itor) {
153  case ',':
154  if(itor - it_begin - skip_count == match_it - match_begin && match_it == match_end) {
155  return true;
156  }
157  it_begin = itor + 1;
158  match_it = match_begin;
159  skip_count = 0;
160  continue;
161  case '\f':
162  case '\n':
163  case '\r':
164  case '\t':
165  case '\v':
166  do_skip = (match_it == match_begin || match_it == match_end);
167  break;
168  case ' ':
169  do_skip = (match_it == match_begin || match_it == match_end);
170  FALLTHROUGH;
171  case '_':
172  do_eat = (match_it != match_end && (*match_it == ' ' || *match_it == '_'));
173  break;
174  default:
175  do_eat = (match_it != match_end && *match_it == *itor);
176  break;
177  }
178 
179  if(do_eat) {
180  ++match_it;
181  } else if(do_skip) {
182  ++skip_count;
183  } else {
184  itor = std::find(itor, it_end, ',');
185  if(itor == it_end) {
186  return false;
187  }
188  it_begin = itor + 1;
189  match_it = match_begin;
190  skip_count = 0;
191  }
192  }
193 
194  if(itor - it_begin - skip_count == match_it - match_begin && match_it == match_end) {
195  return true;
196  }
197 
198  return false;
199 }
200 
201 } // end namespace game_events
handler_ptr operator*()
Dereference.
Definition: handlers.cpp:54
std::vector< char_t > string
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
bool run_wml_action(const std::string &, vconfig const &, game_events::queued_event const &)
Runs a command from an event handler.
bool matches_name(const std::string &name, const game_data *data) const
Definition: handlers.cpp:135
void handle_event(const queued_event &event_info, handler_ptr &handler_p, game_lua_kernel &)
Handles the queued event, according to our WML instructions.
Definition: handlers.cpp:111
#define DBG_NG
Definition: handlers.cpp:38
static lg::log_domain log_engine("engine")
const std::unique_ptr< event_handlers > event_handlers_
Definition: manager.hpp:105
handler_vec::size_type index_
Definition: handlers.hpp:78
Domain specific events.
Definition: action_wml.cpp:88
void disable()
Disables *this, removing it from the game.
Definition: handlers.cpp:90
list_t::iterator iter_
The current element.
Definition: handlers.hpp:115
static iterator erase(const iterator &pos)
static lg::log_domain log_event_handler("event_handler")
Define the game's event mechanism.
std::shared_ptr< event_handler > handler_ptr
Shared pointer to handler objects.
Definition: handlers.hpp:40
The game event manager loads the scenario configuration object, and ensures that events are handled a...
Definition: manager.hpp:45
Define the handlers for the game's events mechanism.
bool find(E event, F functor)
Tests whether an event handler is available.
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Standard logging facilities (interface).
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
void commit_music_changes()
Definition: sound.cpp:769
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
event_handler(const config &cfg, bool is_menu_item, handler_vec::size_type index, manager &)
Definition: handlers.cpp:73