Storyscreen: split common WML parsing code into a helper class
This commit is contained in:
parent
3ff2816fee
commit
e97b992393
8 changed files with 200 additions and 198 deletions
|
@ -1042,6 +1042,8 @@
|
|||
<Unit filename="../../src/statistics.hpp" />
|
||||
<Unit filename="../../src/storyscreen/controller.cpp" />
|
||||
<Unit filename="../../src/storyscreen/controller.hpp" />
|
||||
<Unit filename="../../src/storyscreen/parser.cpp" />
|
||||
<Unit filename="../../src/storyscreen/parser.hpp" />
|
||||
<Unit filename="../../src/storyscreen/part.cpp" />
|
||||
<Unit filename="../../src/storyscreen/part.hpp" />
|
||||
<Unit filename="../../src/synced_checkup.cpp" />
|
||||
|
|
|
@ -359,6 +359,7 @@ settings.cpp
|
|||
side_filter.cpp
|
||||
statistics.cpp
|
||||
storyscreen/controller.cpp
|
||||
storyscreen/parser.cpp
|
||||
storyscreen/part.cpp
|
||||
synced_checkup.cpp
|
||||
synced_commands.cpp
|
||||
|
|
|
@ -21,11 +21,6 @@
|
|||
#include "storyscreen/controller.hpp"
|
||||
#include "storyscreen/part.hpp"
|
||||
|
||||
#include "game_data.hpp"
|
||||
#include "game_events/conditional_wml.hpp"
|
||||
#include "game_events/manager.hpp"
|
||||
#include "game_events/pump.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "variable.hpp"
|
||||
|
@ -46,98 +41,16 @@ controller::controller(const vconfig& data, const std::string& scenario_name)
|
|||
resolve_wml(data);
|
||||
}
|
||||
|
||||
void controller::resolve_wml(const vconfig& cfg)
|
||||
void controller::resolve_wml_helper(const std::string& key, const vconfig& node)
|
||||
{
|
||||
for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++i) {
|
||||
// i->first and i->second are goddamn temporaries; do not make references
|
||||
const std::string key = i->first;
|
||||
const vconfig node = i->second;
|
||||
|
||||
if(key == "part" && !node.empty()) {
|
||||
part_pointer_type const story_part(new part(node));
|
||||
// Use scenario name as part title if the WML doesn't supply a custom one.
|
||||
if((*story_part).show_title() && (*story_part).title().empty()) {
|
||||
(*story_part).set_title(scenario_name_);
|
||||
}
|
||||
|
||||
parts_.push_back(story_part);
|
||||
if(key == "part" && !node.empty()) {
|
||||
part_pointer_type const story_part(new part(node));
|
||||
// Use scenario name as part title if the WML doesn't supply a custom one.
|
||||
if((*story_part).show_title() && (*story_part).title().empty()) {
|
||||
(*story_part).set_title(scenario_name_);
|
||||
}
|
||||
// [if]
|
||||
else if(key == "if") {
|
||||
// check if the [if] tag has a [then] child;
|
||||
// if we try to execute a non-existing [then], we get a segfault
|
||||
if(game_events::conditional_passed(node)) {
|
||||
if(node.has_child("then")) {
|
||||
resolve_wml(node.child("then"));
|
||||
}
|
||||
}
|
||||
// condition not passed, check [elseif] and [else]
|
||||
else {
|
||||
// get all [elseif] children and set a flag
|
||||
vconfig::child_list elseif_children = node.get_children("elseif");
|
||||
bool elseif_flag = false;
|
||||
// for each [elseif]: test if it has a [then] child
|
||||
// if the condition matches, execute [then] and raise flag
|
||||
for(vconfig::child_list::const_iterator elseif = elseif_children.begin();
|
||||
elseif != elseif_children.end(); ++elseif) {
|
||||
if(game_events::conditional_passed(*elseif)) {
|
||||
if(elseif->has_child("then")) {
|
||||
resolve_wml(elseif->child("then"));
|
||||
}
|
||||
|
||||
elseif_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
|
||||
if(node.has_child("else") && !elseif_flag) {
|
||||
resolve_wml(node.child("else"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// [switch]
|
||||
else if(key == "switch") {
|
||||
const std::string var_name = node["variable"];
|
||||
const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
|
||||
bool case_not_found = true;
|
||||
|
||||
for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
|
||||
if(j->first != "case") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enter all matching cases.
|
||||
const std::string var_expected_value = (j->second)["value"];
|
||||
if(var_actual_value == var_expected_value) {
|
||||
case_not_found = false;
|
||||
resolve_wml(j->second);
|
||||
}
|
||||
}
|
||||
|
||||
if(case_not_found) {
|
||||
for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
|
||||
if(j->first != "else") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enter all elses.
|
||||
resolve_wml(j->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
// [deprecated_message]
|
||||
else if(key == "deprecated_message") {
|
||||
// Won't appear until the scenario start event finishes.
|
||||
lg::wml_error() << node["message"] << '\n';
|
||||
}
|
||||
// [wml_message]
|
||||
else if(key == "wml_message") {
|
||||
// As with [deprecated_message],
|
||||
// it won't appear until the scenario start event is complete.
|
||||
resources::game_events->pump().put_wml_message(
|
||||
node["logger"], node["message"], node["in_chat"].to_bool(false));
|
||||
}
|
||||
parts_.push_back(story_part);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,18 +21,17 @@
|
|||
#define STORYSCREEN_CONTROLLER_HPP_INCLUDED
|
||||
|
||||
#include "events.hpp"
|
||||
#include "storyscreen/parser.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class vconfig;
|
||||
|
||||
namespace storyscreen
|
||||
{
|
||||
class part;
|
||||
class floating_image;
|
||||
|
||||
class controller
|
||||
class controller : private story_parser
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<part> part_pointer_type;
|
||||
|
@ -50,8 +49,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Executes WML flow instructions and inserts parts.
|
||||
void resolve_wml(const vconfig& cfg);
|
||||
/** Inherited from story_parser. */
|
||||
virtual void resolve_wml_helper(const std::string& key, const vconfig& node) override;
|
||||
|
||||
std::string scenario_name_;
|
||||
|
||||
|
|
118
src/storyscreen/parser.cpp
Normal file
118
src/storyscreen/parser.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright (C) 2009 - 2017 by Ignacio R. Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "storyscreen/parser.hpp"
|
||||
|
||||
#include "game_data.hpp"
|
||||
#include "game_events/conditional_wml.hpp"
|
||||
#include "game_events/manager.hpp"
|
||||
#include "game_events/pump.hpp"
|
||||
#include "log.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
namespace storyscreen
|
||||
{
|
||||
|
||||
void story_parser::resolve_wml(const vconfig& cfg)
|
||||
{
|
||||
// Execution flow/branching/[image]
|
||||
for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++i) {
|
||||
// i->first and i->second are goddamn temporaries; do not make references
|
||||
const std::string key = i->first;
|
||||
const vconfig node = i->second;
|
||||
|
||||
// Execute any special actions derived classes provide.
|
||||
resolve_wml_helper(key, node);
|
||||
|
||||
// [if]
|
||||
if(key == "if") {
|
||||
// check if the [if] tag has a [then] child;
|
||||
// if we try to execute a non-existing [then], we get a segfault
|
||||
if(game_events::conditional_passed(node)) {
|
||||
if(node.has_child("then")) {
|
||||
resolve_wml(node.child("then"));
|
||||
}
|
||||
}
|
||||
// condition not passed, check [elseif] and [else]
|
||||
else {
|
||||
// get all [elseif] children and set a flag
|
||||
vconfig::child_list elseif_children = node.get_children("elseif");
|
||||
bool elseif_flag = false;
|
||||
// for each [elseif]: test if it has a [then] child
|
||||
// if the condition matches, execute [then] and raise flag
|
||||
for(vconfig::child_list::const_iterator elseif = elseif_children.begin();
|
||||
elseif != elseif_children.end(); ++elseif) {
|
||||
if(game_events::conditional_passed(*elseif)) {
|
||||
if(elseif->has_child("then")) {
|
||||
resolve_wml(elseif->child("then"));
|
||||
}
|
||||
|
||||
elseif_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
|
||||
if(node.has_child("else") && !elseif_flag) {
|
||||
resolve_wml(node.child("else"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// [switch]
|
||||
else if(key == "switch") {
|
||||
const std::string var_name = node["variable"];
|
||||
const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
|
||||
bool case_not_found = true;
|
||||
|
||||
for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
|
||||
if(j->first != "case") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enter all matching cases.
|
||||
const std::string var_expected_value = (j->second)["value"];
|
||||
if(var_actual_value == var_expected_value) {
|
||||
case_not_found = false;
|
||||
resolve_wml(j->second);
|
||||
}
|
||||
}
|
||||
|
||||
if(case_not_found) {
|
||||
for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
|
||||
if(j->first != "else") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enter all elses.
|
||||
resolve_wml(j->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
// [deprecated_message]
|
||||
else if(key == "deprecated_message") {
|
||||
// Won't appear until the scenario start event finishes.
|
||||
lg::wml_error() << node["message"] << '\n';
|
||||
}
|
||||
// [wml_message]
|
||||
else if(key == "wml_message") {
|
||||
// As with [deprecated_message],
|
||||
// it won't appear until the scenario start event is complete.
|
||||
resources::game_events->pump().put_wml_message(
|
||||
node["logger"], node["message"], node["in_chat"].to_bool(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace storyscreen
|
48
src/storyscreen/parser.hpp
Normal file
48
src/storyscreen/parser.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright (C) 2009 - 2017 by Ignacio R. Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef STORYSCREEN_PARSER_HPP_INCLUDED
|
||||
#define STORYSCREEN_PARSER_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
class vconfig;
|
||||
|
||||
namespace storyscreen
|
||||
{
|
||||
|
||||
/**
|
||||
* Small helper class to encapsulate the common logic for parsing storyscreen WML.
|
||||
*/
|
||||
class story_parser
|
||||
{
|
||||
public:
|
||||
story_parser() = default;
|
||||
|
||||
story_parser(const story_parser&) = delete;
|
||||
operator=(const story_parser&) = delete;
|
||||
|
||||
/** Takes care of initializing and branching properties. */
|
||||
virtual void resolve_wml(const vconfig& cfg);
|
||||
|
||||
/**
|
||||
* May be implemented by derived classes to perform additional actions
|
||||
* When executing @ref resolve_wml.
|
||||
*/
|
||||
virtual void resolve_wml_helper(const std::string& key, const vconfig& node) = 0;
|
||||
};
|
||||
|
||||
} // namespace storyscreen
|
||||
|
||||
#endif
|
|
@ -20,13 +20,6 @@
|
|||
#include "storyscreen/part.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "game_data.hpp"
|
||||
#include "game_events/conditional_wml.hpp"
|
||||
#include "game_events/manager.hpp"
|
||||
#include "game_events/pump.hpp"
|
||||
#include "log.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
namespace storyscreen
|
||||
|
@ -246,96 +239,19 @@ void part::resolve_wml(const vconfig& cfg)
|
|||
sound_ = cfg["sound"].str();
|
||||
}
|
||||
|
||||
// Execution flow/branching/[image]
|
||||
for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++i) {
|
||||
// i->first and i->second are goddamn temporaries; do not make references
|
||||
const std::string key = i->first;
|
||||
const vconfig node = i->second;
|
||||
// Inherited
|
||||
story_parser::resolve_wml(cfg);
|
||||
}
|
||||
|
||||
// [background_layer]
|
||||
if(key == "background_layer") {
|
||||
background_layers_.push_back(node.get_parsed_config());
|
||||
}
|
||||
// [image]
|
||||
else if(key == "image") {
|
||||
floating_images_.push_back(node.get_parsed_config());
|
||||
}
|
||||
// [if]
|
||||
else if(key == "if") {
|
||||
// check if the [if] tag has a [then] child;
|
||||
// if we try to execute a non-existing [then], we get a segfault
|
||||
if(game_events::conditional_passed(node)) {
|
||||
if(node.has_child("then")) {
|
||||
resolve_wml(node.child("then"));
|
||||
}
|
||||
}
|
||||
// condition not passed, check [elseif] and [else]
|
||||
else {
|
||||
// get all [elseif] children and set a flag
|
||||
vconfig::child_list elseif_children = node.get_children("elseif");
|
||||
bool elseif_flag = false;
|
||||
// for each [elseif]: test if it has a [then] child
|
||||
// if the condition matches, execute [then] and raise flag
|
||||
for(vconfig::child_list::const_iterator elseif = elseif_children.begin();
|
||||
elseif != elseif_children.end(); ++elseif) {
|
||||
if(game_events::conditional_passed(*elseif)) {
|
||||
if(elseif->has_child("then")) {
|
||||
resolve_wml(elseif->child("then"));
|
||||
}
|
||||
|
||||
elseif_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
|
||||
if(node.has_child("else") && !elseif_flag) {
|
||||
resolve_wml(node.child("else"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// [switch]
|
||||
else if(key == "switch") {
|
||||
const std::string var_name = node["variable"];
|
||||
const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
|
||||
bool case_not_found = true;
|
||||
|
||||
for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
|
||||
if(j->first != "case") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enter all matching cases.
|
||||
const std::string var_expected_value = (j->second)["value"];
|
||||
if(var_actual_value == var_expected_value) {
|
||||
case_not_found = false;
|
||||
resolve_wml(j->second);
|
||||
}
|
||||
}
|
||||
|
||||
if(case_not_found) {
|
||||
for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
|
||||
if(j->first != "else") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enter all elses.
|
||||
resolve_wml(j->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
// [deprecated_message]
|
||||
else if(key == "deprecated_message") {
|
||||
// Won't appear until the scenario start event finishes.
|
||||
lg::wml_error() << node["message"] << '\n';
|
||||
}
|
||||
// [wml_message]
|
||||
else if(key == "wml_message") {
|
||||
// As with [deprecated_message],
|
||||
// it won't appear until the scenario start event is complete.
|
||||
resources::game_events->pump().put_wml_message(
|
||||
node["logger"], node["message"], node["in_chat"].to_bool(false));
|
||||
}
|
||||
void part::resolve_wml_helper(const std::string& key, const vconfig& node)
|
||||
{
|
||||
// [background_layer]
|
||||
if(key == "background_layer") {
|
||||
background_layers_.push_back(node.get_parsed_config());
|
||||
}
|
||||
// [image]
|
||||
else if(key == "image") {
|
||||
floating_images_.push_back(node.get_parsed_config());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#ifndef STORYSCREEN_PART_HPP_INCLUDED
|
||||
#define STORYSCREEN_PART_HPP_INCLUDED
|
||||
|
||||
#include "storyscreen/parser.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
@ -220,7 +222,7 @@ private:
|
|||
/**
|
||||
* Represents and contains information about a single storyscreen part.
|
||||
*/
|
||||
class part
|
||||
class part : private story_parser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
@ -333,8 +335,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
/** Takes care of initializing and branching properties. */
|
||||
void resolve_wml(const vconfig& cfg);
|
||||
/** Inherited from story_parser. */
|
||||
virtual void resolve_wml(const vconfig& cfg) override;
|
||||
|
||||
/** Inherited from story_parser. */
|
||||
virtual void resolve_wml_helper(const std::string& key, const vconfig& node) override;
|
||||
|
||||
static BLOCK_LOCATION string_tblock_loc(const std::string& s);
|
||||
static TEXT_ALIGNMENT string_title_align(const std::string& s);
|
||||
|
|
Loading…
Add table
Reference in a new issue