The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
3  Copyright (C) 2009 - 2016 by Ignacio R. Morelle <[email protected]>
4  Part of the Battle for Wesnoth Project http://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  * Storyscreen controller (implementation).
19  */
20 
21 #include "global.hpp"
23 #include "storyscreen/part.hpp"
24 #include "storyscreen/render.hpp"
25 
26 #include "asserts.hpp"
27 #include "variable.hpp"
28 
30 #include "game_events/manager.hpp"
31 #include "game_events/pump.hpp"
32 #include "game_data.hpp"
33 #include "gettext.hpp"
34 #include "intro.hpp"
35 #include "log.hpp"
36 #include "resources.hpp"
37 #include "widgets/button.hpp"
38 
39 static lg::log_domain log_engine("engine");
40 #define ERR_NG LOG_STREAM(err, log_engine)
41 #define LOG_NG LOG_STREAM(info, log_engine)
42 
43 namespace storyscreen {
44 
45 controller::controller(CVideo& video, const vconfig& data, const std::string& scenario_name,
46  int segment_index)
47  : video_(video)
48  , evt_context_()
49  , scenario_name_(scenario_name)
50  , segment_index_(segment_index)
51  , parts_()
52 {
53  ASSERT_LOG(resources::gamedata != nullptr, "Ouch: gamedata is nullptr when initializing storyscreen controller");
54  resolve_wml(data);
55 }
56 
58 {
60  {
61  // i->first and i->second are goddamn temporaries; do not make references
62  const std::string key = i->first;
63  const vconfig node = i->second;
64 
65  if(key == "part" && !node.empty()) {
66  part_pointer_type const story_part(new part(node));
67  // Use scenario name as part title if the WML doesn't supply a custom one.
68  if((*story_part).show_title() && (*story_part).title().empty()) {
69  (*story_part).set_title( scenario_name_ );
70  }
71  parts_.push_back(story_part);
72  }
73  // [if]
74  else if(key == "if") {
75  // check if the [if] tag has a [then] child;
76  // if we try to execute a non-existing [then], we get a segfault
78  if (node.has_child("then")) {
79  resolve_wml(node.child("then"));
80  }
81  }
82  // condition not passed, check [elseif] and [else]
83  else {
84  // get all [elseif] children and set a flag
85  vconfig::child_list elseif_children = node.get_children("elseif");
86  bool elseif_flag = false;
87  // for each [elseif]: test if it has a [then] child
88  // if the condition matches, execute [then] and raise flag
89  for (vconfig::child_list::const_iterator elseif = elseif_children.begin(); elseif != elseif_children.end(); ++elseif) {
90  if (game_events::conditional_passed(*elseif)) {
91  if (elseif->has_child("then")) {
92  resolve_wml(elseif->child("then"));
93  }
94  elseif_flag = true;
95  break;
96  }
97  }
98  // if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
99  if (node.has_child("else") && !elseif_flag) {
100  resolve_wml(node.child("else"));
101  }
102  }
103  }
104  // [switch]
105  else if(key == "switch") {
106  const std::string var_name = node["variable"];
107  const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
108  bool case_not_found = true;
109 
110  for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
111  if(j->first != "case") continue;
112 
113  // Enter all matching cases.
114  const std::string var_expected_value = (j->second)["value"];
115  if(var_actual_value == var_expected_value) {
116  case_not_found = false;
117  resolve_wml(j->second);
118  }
119  }
120 
121  if(case_not_found) {
122  for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
123  if(j->first != "else") continue;
124 
125  // Enter all elses.
126  resolve_wml(j->second);
127  }
128  }
129  }
130  // [deprecated_message]
131  else if(key == "deprecated_message") {
132  // Won't appear until the scenario start event finishes.
133  lg::wml_error() << node["message"] << '\n';
134  }
135  // [wml_message]
136  else if(key == "wml_message") {
137  // As with [deprecated_message],
138  // it won't appear until the scenario start event is complete.
139  resources::game_events->pump().put_wml_message(node["logger"], node["message"], node["in_chat"].to_bool(false));
140  }
141  }
142 }
143 
145 {
146 
147  if(parts_.empty()) {
148  LOG_NG << "no storyscreen parts to show\n";
149  return NEXT;
150  }
151 
152  gui::button back_button (video_, "", gui::button::TYPE_PRESS, "button_normal/button_small_H22"
153  , gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_left");
154  gui::button next_button (video_, "", gui::button::TYPE_PRESS, "button_normal/button_small_H22"
155  , gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_right");
156  gui::button play_button (video_, _("Skip"));
157 
158  // Build renderer cache unless built for a low-memory environment;
159  // caching the scaled backgrounds can take over a decent amount of memory.
160 #ifndef LOW_MEM
161  std::vector< render_pointer_type > uis_;
162  for(part_pointer_type p : parts_) {
163  ASSERT_LOG( p != nullptr, "Ouch: hit nullptr storyscreen part in collection" );
164  render_pointer_type const rpt(new part_ui(*p, video_, next_button, back_button, play_button));
165  uis_.push_back(rpt);
166  }
167 #endif
168 
169  size_t k = 0;
170  switch(startpos) {
171  case START_BEGINNING:
172  break;
173  case START_END:
174  k = parts_.size() -1;
175  break;
176  default:
177  assert(false);
178  break;
179  }
180 
181  while(k < parts_.size()) {
182 #ifndef LOW_MEM
183  part_ui &render_interface = *uis_[k];
184 #else
185  part_ui render_interface(*parts_[k], video_, next_button, back_button, play_button);
186 #endif
187 
188  LOG_NG << "displaying storyscreen part " << k+1 << " of " << parts_.size() << '\n';
189 
190  back_button.enable(segment_index_ != 0 || k != 0);
191 
192  switch(render_interface.show()) {
193  case part_ui::NEXT:
194  ++k;
195  break;
196  case part_ui::BACK:
197  if(k > 0) {
198  --k;
199  }
200  else if(segment_index_ > 0) {
201  return BACK;
202  }
203  break;
204  case part_ui::QUIT:
205  return QUIT;
206  }
207  }
208  return NEXT;
209 }
210 
211 } // end namespace storyscreen
-file gamestatus.hpp
#define LOG_NG
Definition: controller.cpp:41
Storyscreen parts and floating images representation.
std::vector< part_pointer_type > parts_
Definition: controller.hpp:68
The user pressed the go-next button.
Definition: render.hpp:48
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:243
Definition: video.hpp:58
all_children_iterator ordered_end() const
Definition: variable.cpp:403
virtual void enable(bool new_val=true)
Definition: button.cpp:386
void resolve_wml(const vconfig &cfg)
Definition: controller.cpp:57
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
game_data * gamedata
Definition: resources.cpp:22
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
static lg::log_domain log_engine("engine")
The user pressed the go-back button.
Definition: render.hpp:49
virtual config::attribute_value get_variable_const(const std::string &varname) const
returns a blank attribute value if varname is no valid variable name.
Definition: game_data.cpp:75
child_list get_children(const std::string &key) const
Definition: variable.cpp:181
Storyscreen parts rendering interface.
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:270
Storyscreen part user interface.
Definition: render.hpp:43
The user selected quit.
Definition: render.hpp:50
GLfloat GLfloat p
Definition: glew.h:12766
game_events::manager * game_events
Definition: resources.cpp:24
Represents and contains information about a single storyscreen part.
Definition: part.hpp:244
Define conditionals for the game's events mechanism, a.k.a.
#define ASSERT_LOG(a, b)
Definition: asserts.hpp:49
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:262
RESULT show()
Render and display the storyscreen, process and return user input.
Definition: render.cpp:965
bool empty() const
Definition: variable.hpp:93
Define the game's event mechanism.
size_t i
Definition: function.cpp:1057
controller(CVideo &video, const vconfig &data, const std::string &scenario_name, int segment_index)
Definition: controller.cpp:45
game_events::t_pump & pump()
Definition: manager.cpp:194
bool conditional_passed(const vconfig &cond)
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
Standard logging facilities (interface).
std::vector< vconfig > child_list
Definition: variable.hpp:71
Storyscreen controller (interface).
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:458
GLsizei const GLcharARB ** string
Definition: glew.h:4503
std::string scenario_name_
Definition: controller.hpp:64
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:398
STORY_RESULT show(START_POSITION startpos=START_BEGINNING)
Display all story screen parts in a first..last sequence.
Definition: controller.cpp:144