mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-30 16:55:28 +00:00
Applied patch #3297
This commit is contained in:
parent
1738722c2e
commit
bcaa7f4f2c
@ -14,7 +14,16 @@ The release team should empty this file after each release.
|
||||
CHANGES
|
||||
=======
|
||||
|
||||
[section="A Change"]
|
||||
[section="Multiplayer modifications"]
|
||||
Starting with this release, there's a new type of add-on, MP Modification, which allows alterations to the game play independently from eras and scenarios. Additionally, you can have any amount of modifications enabled at a time. You can access installed modifications with the "Modifications" button on the game creation screen. See [wiki]ModificationWML[/wiki] for details.
|
||||
[/section]
|
||||
|
||||
[section="Multiplayer option system"]
|
||||
Another improvement is the new option system. UMC authors now can have their add-ons display some configuration options on the game creation screen. The settings are translated into WML variables inside the add-on. The options for activated modifications, era or scenario are accessible through the "Options" button on the game creation screen. See [wiki]OptionWML[/wiki] for details.
|
||||
[/section]
|
||||
|
||||
[section="Multiplayer dependency system"]
|
||||
With a lot of new possibilities for conflicts between add-ons, there's now a dependency system for eras, scenarios and modifications, not to be confused with the already existing dependency management for whole add-ons. See the appopriate sections of [wiki]EraWML[/wiki], [wiki]ScenarioWML[/wiki] and [wiki]ModificationWML[/wiki] for details.
|
||||
[/section]
|
||||
|
||||
[section="Another Change"]
|
||||
|
@ -234,6 +234,8 @@ Version 1.11.0:
|
||||
* Changes to the time of day schedules of Fallenstar Lake and Silverhead
|
||||
Crossing
|
||||
* Random leader is default selection when picking faction
|
||||
* Added support for modification tags
|
||||
* Added support for dependencies between eras, scenarios and modifications
|
||||
* Music and sound effects:
|
||||
* Replaced some of the wolf hit sounds with lower-pitched ones
|
||||
* Terrain:
|
||||
|
220
data/gui/default/window/mp_create_game_choose_mods.cfg
Normal file
220
data/gui/default/window/mp_create_game_choose_mods.cfg
Normal file
@ -0,0 +1,220 @@
|
||||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Select the modifications to be active during the game
|
||||
###
|
||||
|
||||
[window]
|
||||
id = "mp_create_game_choose_mods"
|
||||
description = "Dialog for choosing modifications for MP games."
|
||||
|
||||
[resolution]
|
||||
definition = "default"
|
||||
|
||||
automatic_placement = "true"
|
||||
vertical_placement = "center"
|
||||
horizontal_placement = "center"
|
||||
|
||||
[linked_group]
|
||||
id = "checkbox"
|
||||
fixed_width = "true"
|
||||
[/linked_group]
|
||||
|
||||
[linked_group]
|
||||
id = "name"
|
||||
fixed_width = "true"
|
||||
[/linked_group]
|
||||
|
||||
[linked_group]
|
||||
id = "description"
|
||||
fixed_width = "true"
|
||||
[/linked_group]
|
||||
|
||||
[tooltip]
|
||||
id = "tooltip_large"
|
||||
[/tooltip]
|
||||
|
||||
[helptip]
|
||||
id = "tooltip_large"
|
||||
[/helptip]
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
[label]
|
||||
definition = "title"
|
||||
|
||||
label = _ "Choose Modifications"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
[label]
|
||||
definition = "default"
|
||||
id = "message"
|
||||
|
||||
label = _ "Enable the modifications you want to be active during the game."
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
horizontal_grow = "true"
|
||||
vertical_grow = "true"
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
||||
[listbox]
|
||||
id = "mod_list"
|
||||
definition = "default"
|
||||
|
||||
[list_definition]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
vertical_grow = "true"
|
||||
horizontal_grow = "true"
|
||||
[toggle_panel]
|
||||
definition = "default"
|
||||
[grid]
|
||||
[row]
|
||||
[column]
|
||||
grow_factor = 0
|
||||
horizontal_alignment = "left"
|
||||
border = "all"
|
||||
border_size = 5
|
||||
[toggle_button]
|
||||
id = "checkbox"
|
||||
definition = "default"
|
||||
linked_group = "checkbox"
|
||||
[/toggle_button]
|
||||
[/column]
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = "true"
|
||||
border = "all"
|
||||
border_size = 5
|
||||
[label]
|
||||
id = "name"
|
||||
definition = "default_large"
|
||||
linked_group = "name"
|
||||
[/label]
|
||||
[/column]
|
||||
[/row]
|
||||
[row]
|
||||
[column]
|
||||
grow_factor = 0
|
||||
horizontal_alignment = "left"
|
||||
border = "all"
|
||||
border_size = 5
|
||||
[spacer]
|
||||
[/spacer]
|
||||
[/column]
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_alignment = "left"
|
||||
border = "all"
|
||||
border_size = 5
|
||||
[label]
|
||||
id = "description"
|
||||
definition = "default"
|
||||
linked_group = "description"
|
||||
[/label]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
[/toggle_panel]
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/list_definition]
|
||||
|
||||
[/listbox]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[button]
|
||||
id = "ok"
|
||||
definition = "default"
|
||||
|
||||
label = _ "OK"
|
||||
[/button]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[button]
|
||||
id = "cancel"
|
||||
definition = "default"
|
||||
|
||||
label = _ "Cancel"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/resolution]
|
||||
|
||||
[/window]
|
||||
|
161
data/gui/default/window/mp_depcheck_confirm_change.cfg
Normal file
161
data/gui/default/window/mp_depcheck_confirm_change.cfg
Normal file
@ -0,0 +1,161 @@
|
||||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Prompts the user to confirm some changes required to satisfy
|
||||
### dependencies. Currently used for enabling/disabling modifications.
|
||||
###
|
||||
|
||||
[window]
|
||||
id = "mp_depcheck_confirm_change"
|
||||
description = "Enable/disable modifications"
|
||||
|
||||
[resolution]
|
||||
definition = "default"
|
||||
|
||||
automatic_placement = "true"
|
||||
vertical_placement = "center"
|
||||
horizontal_placement = "center"
|
||||
|
||||
[tooltip]
|
||||
id = "tooltip_large"
|
||||
[/tooltip]
|
||||
|
||||
[helptip]
|
||||
id = "tooltip_large"
|
||||
[/helptip]
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "title"
|
||||
label = _ "Confirmation requested"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "default"
|
||||
label = "text is set by C++"
|
||||
id = "message"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[scroll_label]
|
||||
id = "itemlist"
|
||||
label = "text set by c++"
|
||||
definition = "default"
|
||||
[/scroll_label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
label = _ "Would you like to apply the changes?"
|
||||
definition = "default"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 0
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "center"
|
||||
|
||||
[button]
|
||||
id = "ok"
|
||||
label = _ "Yes"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[button]
|
||||
id = "cancel"
|
||||
label = _ "No"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/resolution]
|
||||
|
||||
[/window]
|
164
data/gui/default/window/mp_depcheck_select_new.cfg
Normal file
164
data/gui/default/window/mp_depcheck_select_new.cfg
Normal file
@ -0,0 +1,164 @@
|
||||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Proposes a list of compaitble components if the currently selected
|
||||
### one is incompatible. Currently used for scenarios and eras.
|
||||
###
|
||||
|
||||
[window]
|
||||
id = "mp_depcheck_select_new"
|
||||
description = "Select new era or scenario"
|
||||
|
||||
[resolution]
|
||||
definition = "default"
|
||||
|
||||
automatic_placement = "true"
|
||||
horizontal_placement = "center"
|
||||
vertical_placement = "center"
|
||||
|
||||
[tooltip]
|
||||
id = "tooltip_large"
|
||||
[/tooltip]
|
||||
|
||||
[helptip]
|
||||
id = "tooltip_large"
|
||||
[/helptip]
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "title"
|
||||
label = _ "User interaction required"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
definition = "default"
|
||||
label = _ "User interaction required"
|
||||
id = "message"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = "true"
|
||||
vertical_grow = "true"
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
||||
[listbox]
|
||||
definition = "default"
|
||||
id = "itemlist"
|
||||
|
||||
[list_definition]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = "true"
|
||||
|
||||
[toggle_button]
|
||||
definition = "listbox_text"
|
||||
|
||||
return_value_id = "ok"
|
||||
[/toggle_button]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/list_definition]
|
||||
|
||||
[/listbox]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 0
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "center"
|
||||
|
||||
[button]
|
||||
id = "ok"
|
||||
label = _ "OK"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "right"
|
||||
|
||||
[button]
|
||||
id = "cancel"
|
||||
label = _ "Cancel"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/resolution]
|
||||
|
||||
[/window]
|
@ -44,6 +44,11 @@ Version 1.11.0+svn:
|
||||
in the Load Game dialog.
|
||||
* Fix OOS when dismissing a recall in a multiplayer campaign (bug #19924).
|
||||
|
||||
* Multiplayer
|
||||
* New add-on type: modifications
|
||||
* GUI2 configuration options for eras, scenarios and modifications
|
||||
* Dependency system for eras, scenarios and modifications
|
||||
|
||||
|
||||
Version 1.11.0:
|
||||
* Add-ons client:
|
||||
|
@ -721,7 +721,10 @@ set(wesnoth-main_SRC
|
||||
gui/dialogs/mp_cmd_wrapper.cpp
|
||||
gui/dialogs/mp_connect.cpp
|
||||
gui/dialogs/mp_create_game.cpp
|
||||
gui/dialogs/mp_create_game_choose_mods.cpp
|
||||
gui/dialogs/mp_create_game_set_password.cpp
|
||||
gui/dialogs/mp_depcheck_confirm_change.cpp
|
||||
gui/dialogs/mp_depcheck_select_new.cpp
|
||||
gui/dialogs/mp_host_game_prompt.cpp
|
||||
gui/dialogs/mp_login.cpp
|
||||
gui/dialogs/mp_method_selection.cpp
|
||||
@ -743,7 +746,9 @@ set(wesnoth-main_SRC
|
||||
menu_events.cpp
|
||||
mouse_events.cpp
|
||||
mouse_handler_base.cpp
|
||||
mp_depcheck.cpp
|
||||
mp_game_settings.cpp
|
||||
mp_options.cpp
|
||||
multiplayer.cpp
|
||||
multiplayer_connect.cpp
|
||||
multiplayer_create.cpp
|
||||
|
@ -62,7 +62,7 @@ if env["PLATFORM"] != "win32":
|
||||
|
||||
if env['default_prefs_file']:
|
||||
client_env.Append(CPPDEFINES = "DEFAULT_PREFS_PATH='\"$default_prefs_file\"'")
|
||||
|
||||
|
||||
game_config_env['default_prefs_file'] = env['default_prefs_file']
|
||||
game_config_env.Append(CPPDEFINES = "DEFAULT_PREFS_PATH='\"$default_prefs_file\"'")
|
||||
if not os.path.isabs(env['default_prefs_file']):
|
||||
@ -363,7 +363,10 @@ wesnoth_sources = Split("""
|
||||
gui/dialogs/mp_change_control.cpp
|
||||
gui/dialogs/mp_connect.cpp
|
||||
gui/dialogs/mp_create_game.cpp
|
||||
gui/dialogs/mp_create_game_choose_mods.cpp
|
||||
gui/dialogs/mp_create_game_set_password.cpp
|
||||
gui/dialogs/mp_depcheck_confirm_change.cpp
|
||||
gui/dialogs/mp_depcheck_select_new.cpp
|
||||
gui/dialogs/mp_host_game_prompt.cpp
|
||||
gui/dialogs/mp_login.cpp
|
||||
gui/dialogs/mp_method_selection.cpp
|
||||
@ -402,13 +405,13 @@ wesnoth_sources = Split("""
|
||||
gui/widgets/scrollbar_container.cpp
|
||||
gui/widgets/scrollbar_panel.cpp
|
||||
gui/widgets/settings.cpp
|
||||
gui/widgets/slider.cpp
|
||||
gui/widgets/slider.cpp
|
||||
gui/widgets/spacer.cpp
|
||||
gui/widgets/stacked_widget.cpp
|
||||
gui/widgets/text.cpp
|
||||
gui/widgets/text_box.cpp
|
||||
gui/widgets/toggle_button.cpp
|
||||
gui/widgets/toggle_panel.cpp
|
||||
gui/widgets/toggle_button.cpp
|
||||
gui/widgets/toggle_panel.cpp
|
||||
gui/widgets/tree_view.cpp
|
||||
gui/widgets/tree_view_node.cpp
|
||||
gui/widgets/vertical_scrollbar.cpp
|
||||
@ -423,7 +426,9 @@ wesnoth_sources = Split("""
|
||||
menu_events.cpp
|
||||
mouse_events.cpp
|
||||
mouse_handler_base.cpp
|
||||
mp_depcheck.cpp
|
||||
mp_game_settings.cpp
|
||||
mp_options.cpp
|
||||
multiplayer.cpp
|
||||
multiplayer_connect.cpp
|
||||
multiplayer_create.cpp
|
||||
|
@ -53,6 +53,12 @@ std::set<std::string> ignores;
|
||||
bool friends_initialized = false;
|
||||
bool ignores_initialized = false;
|
||||
|
||||
std::vector<std::string> mp_modifications;
|
||||
bool modifications_initialized = false;
|
||||
|
||||
config option_values;
|
||||
bool options_initialized = false;
|
||||
|
||||
bool authenticated = false;
|
||||
|
||||
const char WRAP_CHAR = '@';
|
||||
@ -77,10 +83,17 @@ std::string parse_wrapped_credentials_field(const std::string& raw)
|
||||
return raw.substr(1, raw.length() - 2);
|
||||
}
|
||||
|
||||
void initialize_modifications()
|
||||
{
|
||||
mp_modifications = utils::split(preferences::get("modifications"), ',');
|
||||
modifications_initialized = true;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
namespace preferences {
|
||||
|
||||
|
||||
manager::manager() :
|
||||
base()
|
||||
{
|
||||
@ -580,6 +593,32 @@ void set_turns(int value)
|
||||
preferences::set("mp_turns", value);
|
||||
}
|
||||
|
||||
const config& options()
|
||||
{
|
||||
if (options_initialized) {
|
||||
return option_values;
|
||||
}
|
||||
|
||||
if (!preferences::get_child("options")) {
|
||||
// It may be an invalid config, which would cause problems in
|
||||
// multiplayer_create, so let's replace it with an empty but valid
|
||||
// config
|
||||
option_values = config();
|
||||
} else {
|
||||
option_values = preferences::get_child("options");
|
||||
}
|
||||
|
||||
options_initialized = true;
|
||||
|
||||
return option_values;
|
||||
}
|
||||
|
||||
void set_options(const config& values)
|
||||
{
|
||||
preferences::set_child("options", values);
|
||||
options_initialized = false;
|
||||
}
|
||||
|
||||
bool skip_mp_replay()
|
||||
{
|
||||
return preferences::get("skip_mp_replay", false);
|
||||
@ -694,6 +733,20 @@ void set_map(int value)
|
||||
preferences::set("mp_map", value);
|
||||
}
|
||||
|
||||
const std::vector<std::string>& modifications()
|
||||
{
|
||||
if (!modifications_initialized)
|
||||
initialize_modifications();
|
||||
|
||||
return mp_modifications;
|
||||
}
|
||||
|
||||
void set_modifications(const std::vector<std::string>& value)
|
||||
{
|
||||
preferences::set("modifications", utils::join(value, ","));
|
||||
modifications_initialized = false;
|
||||
}
|
||||
|
||||
bool show_ai_moves()
|
||||
{
|
||||
return preferences::get("show_ai_moves", true);
|
||||
|
@ -23,6 +23,7 @@ class unit_map;
|
||||
#include "preferences.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace preferences {
|
||||
|
||||
@ -143,6 +144,9 @@ namespace preferences {
|
||||
int turns();
|
||||
void set_turns(int value);
|
||||
|
||||
const config& options();
|
||||
void set_options(const config& values);
|
||||
|
||||
bool skip_mp_replay();
|
||||
void set_skip_mp_replay(bool value);
|
||||
|
||||
@ -172,6 +176,9 @@ namespace preferences {
|
||||
int map();
|
||||
void set_map(int value);
|
||||
|
||||
const std::vector<std::string>& modifications();
|
||||
void set_modifications(const std::vector<std::string>& value);
|
||||
|
||||
bool show_ai_moves();
|
||||
void set_show_ai_moves(bool value);
|
||||
|
||||
|
114
src/gui/dialogs/mp_create_game_choose_mods.cpp
Normal file
114
src/gui/dialogs/mp_create_game_choose_mods.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/dialogs/mp_create_game_choose_mods.hpp"
|
||||
|
||||
#include "game_preferences.hpp"
|
||||
#include "gui/dialogs/field.hpp"
|
||||
#include "gui/dialogs/helper.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/toggle_button.hpp"
|
||||
#include "../../settings.hpp"
|
||||
#include "gettext.hpp"
|
||||
|
||||
namespace gui2 {
|
||||
|
||||
/*WIKI
|
||||
* @page = GUIWindowDefinitionWML
|
||||
* @order = 2_mp_create_game_choose_mods
|
||||
*
|
||||
* == Create Game: Choose Modifications ==
|
||||
*
|
||||
* The dialog for selecting modifications.
|
||||
*
|
||||
* @begin{table}{dialog_widgets}
|
||||
*
|
||||
* mod_list & & listbox & m &
|
||||
* displays the list of the available modifications $
|
||||
*
|
||||
* -checkbox & & toggle_button & o &
|
||||
* enable/disable a modification $
|
||||
*
|
||||
* -name & & label & o &
|
||||
* displays the modification's name $
|
||||
*
|
||||
* -description & & label & o &
|
||||
* displays the modification's description $
|
||||
*
|
||||
* ok & & button & m &
|
||||
* closes the dialog, applies changes $
|
||||
*
|
||||
* cancel & & button & m &
|
||||
* closes the dialog, discards changes $
|
||||
*
|
||||
* @end{table}
|
||||
*/
|
||||
|
||||
REGISTER_DIALOG(mp_create_game_choose_mods)
|
||||
|
||||
tmp_create_game_choose_mods::tmp_create_game_choose_mods
|
||||
(const config& game_cfg,
|
||||
std::vector<std::string>& result)
|
||||
: result_(result)
|
||||
, game_cfg_(game_cfg)
|
||||
{
|
||||
}
|
||||
|
||||
void tmp_create_game_choose_mods::pre_show(CVideo &/*video*/, twindow &window)
|
||||
{
|
||||
mod_list_ = find_widget<tlistbox>(&window, "mod_list", false, true);
|
||||
std::vector<string_map>::iterator mod_itor;
|
||||
|
||||
BOOST_FOREACH (const config& mod, game_cfg_.child_range("modification")) {
|
||||
|
||||
string_map column;
|
||||
std::map<std::string, string_map> item;
|
||||
column["label"] = mod["name"];
|
||||
item.insert(std::make_pair("name", column));
|
||||
column["label"] = mod["description"];
|
||||
item.insert(std::make_pair("description", column));
|
||||
|
||||
mod_list_->add_row(item);
|
||||
|
||||
tgrid *grid = mod_list_->get_row_grid(mod_list_->get_item_count()-1);
|
||||
ttoggle_button &checkbox =
|
||||
find_widget<ttoggle_button>(grid, "checkbox", false);
|
||||
|
||||
checkbox.set_value(std::find( result_.begin(), result_.end(),
|
||||
mod["id"]) != result_.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tmp_create_game_choose_mods::post_show(twindow& /*window*/)
|
||||
{
|
||||
if (get_retval() == twindow::OK) {
|
||||
result_.clear();
|
||||
|
||||
for(unsigned int i = 0; i < mod_list_->get_item_count(); i++) {
|
||||
const tgrid *grid = mod_list_->get_row_grid(i);
|
||||
const ttoggle_button &checkbox =
|
||||
find_widget<const ttoggle_button>(grid, "checkbox", false);
|
||||
|
||||
if (checkbox.get_value()) {
|
||||
result_.push_back(game_cfg_.child("modification", i)["id"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
|
67
src/gui/dialogs/mp_create_game_choose_mods.hpp
Normal file
67
src/gui/dialogs/mp_create_game_choose_mods.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 GUI_DIALOGS_MP_CREATE_GAME_CHOOSE_MODS_HPP_INCLUDED
|
||||
#define GUI_DIALOGS_MP_CREATE_GAME_CHOOSE_MODS_HPP_INCLUDED
|
||||
|
||||
#include "gui/dialogs/dialog.hpp"
|
||||
#include "gui/widgets/listbox.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class config;
|
||||
|
||||
namespace gui2 {
|
||||
|
||||
class tmp_create_game_choose_mods : public tdialog
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param game_cfg the config which contains the information for the
|
||||
* modifications
|
||||
* @param result [in] the list of the currently activated modifications
|
||||
* @param result [out] the list of all activated modifications
|
||||
*/
|
||||
tmp_create_game_choose_mods(const config& game_cfg,
|
||||
std::vector<std::string>& result);
|
||||
|
||||
private:
|
||||
|
||||
/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
|
||||
virtual const std::string& window_id() const;
|
||||
|
||||
/** Inherited from tdialog */
|
||||
void pre_show(CVideo &video, twindow &window);
|
||||
|
||||
/** Inherited from tdialog */
|
||||
void post_show(twindow &window);
|
||||
|
||||
/** a reference to the variable the result should be written into */
|
||||
std::vector<std::string>& result_;
|
||||
|
||||
/** a reference to the config which contains the info about modifications*/
|
||||
const config& game_cfg_;
|
||||
|
||||
/** a pointer to the listbox which displays the items */
|
||||
gui2::tlistbox *mod_list_;
|
||||
};
|
||||
|
||||
} // namespace gui2
|
||||
|
||||
#endif
|
77
src/gui/dialogs/mp_depcheck_confirm_change.cpp
Normal file
77
src/gui/dialogs/mp_depcheck_confirm_change.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/dialogs/mp_depcheck_confirm_change.hpp"
|
||||
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
#include "gettext.hpp"
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
/*WIKI
|
||||
* @page = GUIWindowDefinitionWML
|
||||
* @order = 2_mp_depcheck_confirm_change
|
||||
*
|
||||
* == MP Dependency Check: Confirm Change ==
|
||||
*
|
||||
* Asks the user to confirm a change required to proceed. Currently used
|
||||
* for enabling/disabling modifications
|
||||
*
|
||||
* @begin{table}{dialog_widgets}
|
||||
*
|
||||
* message & & label & m &
|
||||
* displays the details of the required changes $
|
||||
*
|
||||
* itemlist & & scroll_label & m &
|
||||
* displays the list of affected items $
|
||||
*
|
||||
* cancel & & button & m &
|
||||
* refuse to apply changes $
|
||||
*
|
||||
* ok & & button & m &
|
||||
* agree to apply changes $
|
||||
*
|
||||
* @end{table}
|
||||
*/
|
||||
|
||||
REGISTER_DIALOG(mp_depcheck_confirm_change)
|
||||
|
||||
tmp_depcheck_confirm_change::tmp_depcheck_confirm_change
|
||||
(bool action,
|
||||
const std::vector<std::string>& mods,
|
||||
const std::string& requester)
|
||||
{
|
||||
utils::string_map symbols;
|
||||
symbols["requester"] = requester;
|
||||
std::string message;
|
||||
if (action) {
|
||||
message = vgettext("$requester requires the following modifications to be enabled:", symbols);
|
||||
} else {
|
||||
message = vgettext("$requester requires the following modifications to be disabled:", symbols);
|
||||
}
|
||||
|
||||
std::string list = "\t";
|
||||
list += utils::join(mods, "\n\t");
|
||||
|
||||
register_label("message", false, message);
|
||||
|
||||
register_label("itemlist", false, list);
|
||||
}
|
||||
|
||||
}
|
51
src/gui/dialogs/mp_depcheck_confirm_change.hpp
Normal file
51
src/gui/dialogs/mp_depcheck_confirm_change.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 GUI_DIALOGS_MP_DEPCHECK_CONFIRM_CHANGE_HPP_INCLUDED
|
||||
#define GUI_DIALOGS_MP_DEPCHECK_CONFIRM_CHANGE_HPP_INCLUDED
|
||||
|
||||
#include "gui/dialogs/dialog.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
class tmp_depcheck_confirm_change
|
||||
: public tdialog
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param action true if the listed modifications are to be enabled,
|
||||
* false if they're to be disabled
|
||||
* @param mods the names of the affected modifications
|
||||
* @param requester the name of the component which requests the change
|
||||
*
|
||||
*/
|
||||
tmp_depcheck_confirm_change(bool action,
|
||||
const std::vector<std::string>& mods,
|
||||
const std::string& requester );
|
||||
|
||||
protected:
|
||||
|
||||
/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
|
||||
virtual const std::string& window_id() const;
|
||||
|
||||
};
|
||||
|
||||
} //namespace gui2
|
||||
|
||||
#endif
|
110
src/gui/dialogs/mp_depcheck_select_new.cpp
Normal file
110
src/gui/dialogs/mp_depcheck_select_new.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/dialogs/mp_depcheck_select_new.hpp"
|
||||
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "gui/widgets/listbox.hpp"
|
||||
#include "gettext.hpp"
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
/*WIKI
|
||||
* @page = GUIWindowDefinitionWML
|
||||
* @order = 2_mp_depcheck_select_new
|
||||
*
|
||||
* == MP Dependency Check: Select New ==
|
||||
*
|
||||
* Offers a list of compatible items if a currently selected one is
|
||||
* incompatible. Currently used for switching era or map.
|
||||
*
|
||||
* @begin{table}{dialog_widgets}
|
||||
*
|
||||
* message & & label & m &
|
||||
* displays the details of the required changes $
|
||||
*
|
||||
* itemlist & & listbox & m &
|
||||
* displays the available items to choose from $
|
||||
*
|
||||
* cancel & & button & m &
|
||||
* refuse to apply any changes $
|
||||
*
|
||||
* ok & & button & m &
|
||||
* select the chosen item $
|
||||
*
|
||||
* @end{table}
|
||||
*
|
||||
*/
|
||||
|
||||
REGISTER_DIALOG(mp_depcheck_select_new)
|
||||
|
||||
tmp_depcheck_select_new::tmp_depcheck_select_new
|
||||
( mp::depcheck::component_type name,
|
||||
const std::vector<std::string>& items )
|
||||
: items_(items)
|
||||
, result_(-1)
|
||||
{
|
||||
|
||||
std::string message;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case mp::depcheck::SCENARIO:
|
||||
message = _( "The currently chosen scenario " \
|
||||
"is not compatible with your setup." \
|
||||
"\nPlease select a compatible one.");
|
||||
break;
|
||||
case mp::depcheck::ERA:
|
||||
message = _( "The currently chosen era " \
|
||||
"is not compatible with your setup." \
|
||||
"\nPlease select a compatible one.");
|
||||
break;
|
||||
case mp::depcheck::MODIFICATION:
|
||||
//currently this can't happen, but be prepared for anything...
|
||||
message = _( "The currently chosen modification " \
|
||||
"is not compatible with your setup." \
|
||||
"\nPlease select a compatible one.");
|
||||
}
|
||||
|
||||
register_label("message", false, message);
|
||||
|
||||
}
|
||||
|
||||
void tmp_depcheck_select_new::pre_show(CVideo& /*video*/, twindow& window)
|
||||
{
|
||||
tlistbox& listbox = find_widget<tlistbox>(&window, "itemlist", false);
|
||||
|
||||
BOOST_FOREACH(const std::string& item, items_) {
|
||||
string_map current;
|
||||
current.insert(std::make_pair("label", item));
|
||||
|
||||
listbox.add_row(current);
|
||||
}
|
||||
|
||||
listbox.select_row(0);
|
||||
}
|
||||
|
||||
void tmp_depcheck_select_new::post_show(twindow& window)
|
||||
{
|
||||
if (get_retval() == twindow::OK) {
|
||||
tlistbox& listbox = find_widget<tlistbox>(&window, "itemlist", false);
|
||||
result_ = listbox.get_selected_row();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
66
src/gui/dialogs/mp_depcheck_select_new.hpp
Normal file
66
src/gui/dialogs/mp_depcheck_select_new.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 GUI_DIALOGS_MP_DEPCHECK_SELECT_NEW_HPP_INCLUDED
|
||||
#define GUI_DIALOGS_MP_DEPCHECK_SELECT_NEW_HPP_INCLUDED
|
||||
|
||||
#include "gui/dialogs/dialog.hpp"
|
||||
#include "mp_depcheck.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
class tmp_depcheck_select_new
|
||||
: public tdialog
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param name the type of which we want to select a new item
|
||||
* @param options the names of the components which can be choosed
|
||||
*/
|
||||
tmp_depcheck_select_new(mp::depcheck::component_type name,
|
||||
const std::vector<std::string>& options);
|
||||
|
||||
/**
|
||||
* Returns the selected item.
|
||||
*
|
||||
* @return the index of the selected item, or -1 if none was selected
|
||||
* (the dialog was closed with the cancel button)
|
||||
*/
|
||||
int result() const { return result_; }
|
||||
|
||||
protected:
|
||||
/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
|
||||
virtual const std::string& window_id() const;
|
||||
|
||||
/** Inherited from tdialog */
|
||||
virtual void pre_show(CVideo& video, twindow& window);
|
||||
|
||||
/** Inherited from tdialog */
|
||||
virtual void post_show(twindow& window);
|
||||
|
||||
private:
|
||||
/** the options available */
|
||||
std::vector<std::string> items_;
|
||||
|
||||
/** the index of the selected item */
|
||||
int result_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
719
src/mp_depcheck.cpp
Normal file
719
src/mp_depcheck.cpp
Normal file
@ -0,0 +1,719 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 "mp_depcheck.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "formula_string_utils.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include "gui/dialogs/mp_depcheck_confirm_change.hpp"
|
||||
#include "gui/dialogs/mp_depcheck_select_new.hpp"
|
||||
#include "gui/dialogs/message.hpp"
|
||||
|
||||
static lg::log_domain log_mp_create_depcheck("mp/create/depcheck");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp_create_depcheck)
|
||||
|
||||
namespace {
|
||||
//helper function
|
||||
void copy_keys(config& out,
|
||||
const config& in,
|
||||
const std::string& type,
|
||||
bool copy_force_key=false)
|
||||
{
|
||||
if (in.has_attribute("allow_" + type)) {
|
||||
out["allow_" + type] = in["allow_" + type];
|
||||
} else if (in.has_attribute("disallow_" + type)) {
|
||||
out["disallow_" + type] = in["disallow_" + type];
|
||||
}
|
||||
|
||||
if (in.has_attribute("ignore_incompatible_" + type)) {
|
||||
out["ignore_incompatible_" + type] = in["ignore_incompatible_" + type];
|
||||
}
|
||||
|
||||
if (copy_force_key) {
|
||||
if (in.has_attribute("force_" + type)) {
|
||||
out["force_" + type] = in["force_" + type];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//helper function
|
||||
inline bool contains(const std::vector<std::string>& container,
|
||||
const std::string& value)
|
||||
{
|
||||
return std::find(container.begin(), container.end(), value)
|
||||
!= container.end();
|
||||
}
|
||||
|
||||
} //anonymous namespace
|
||||
|
||||
namespace mp
|
||||
{
|
||||
|
||||
namespace depcheck
|
||||
{
|
||||
|
||||
manager::manager(const config& gamecfg, CVideo& video)
|
||||
: video_(video)
|
||||
, depinfo_()
|
||||
, era_()
|
||||
, scenario_()
|
||||
, mods_()
|
||||
, prev_era_()
|
||||
, prev_scenario_()
|
||||
, prev_mods_()
|
||||
{
|
||||
DBG_MP << "Initializing the dependency manager" << std::endl;
|
||||
BOOST_FOREACH (const config& cfg, gamecfg.child_range("modification")) {
|
||||
config info;
|
||||
info["id"] = cfg["id"];
|
||||
info["name"] = cfg["name"];
|
||||
|
||||
copy_keys(info, cfg, "scenario");
|
||||
copy_keys(info, cfg, "era");
|
||||
copy_keys(info, cfg, "modification");
|
||||
|
||||
depinfo_.add_child("modification", info);
|
||||
}
|
||||
|
||||
BOOST_FOREACH (const config& cfg, gamecfg.child_range("era")) {
|
||||
config info;
|
||||
info["id"] = cfg["id"];
|
||||
info["name"] = cfg["name"];
|
||||
|
||||
copy_keys(info, cfg, "scenario");
|
||||
copy_keys(info, cfg, "modification", true);
|
||||
|
||||
depinfo_.add_child("era", info);
|
||||
}
|
||||
|
||||
BOOST_FOREACH (const config& cfg, gamecfg.child_range("multiplayer")) {
|
||||
config info;
|
||||
info["id"] = cfg["id"];
|
||||
info["name"] = cfg["name"];
|
||||
|
||||
copy_keys(info, cfg, "era");
|
||||
copy_keys(info, cfg, "modification", true);
|
||||
|
||||
depinfo_.add_child("scenario", info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void manager::save_state()
|
||||
{
|
||||
DBG_MP << "Saving current state" << std::endl;
|
||||
prev_era_ = era_;
|
||||
prev_scenario_ = scenario_;
|
||||
prev_mods_ = mods_;
|
||||
}
|
||||
|
||||
void manager::revert()
|
||||
{
|
||||
DBG_MP << "Restoring previous state" << std::endl;
|
||||
era_ = prev_era_;
|
||||
scenario_ = prev_scenario_;
|
||||
mods_ = prev_mods_;
|
||||
}
|
||||
|
||||
bool manager::exists(const elem& e) const
|
||||
{
|
||||
BOOST_FOREACH (const config& cfg, depinfo_.child_range(e.type)) {
|
||||
if (cfg["id"] == e.id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
manager::get_required_not_installed(const elem& e) const
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::vector<std::string> items = get_required(e);
|
||||
|
||||
BOOST_FOREACH (const std::string& str, items) {
|
||||
if (!exists(elem(str, "modification"))) {
|
||||
result.push_back(str);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> manager::get_required(const elem& e) const
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
if (e.type == "modification") {
|
||||
return result;
|
||||
}
|
||||
|
||||
config data = depinfo_.find_child(e.type, "id", e.id);
|
||||
|
||||
if (data.has_attribute("force_modification")) {
|
||||
result = utils::split(data["force_modification"], ',');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> manager::get_required_not_enabled(const elem& e) const
|
||||
{
|
||||
std::vector<std::string> required = get_required(e);
|
||||
std::vector<std::string> result;
|
||||
|
||||
BOOST_FOREACH (std::string str, required) {
|
||||
if (!contains(mods_, str)) {
|
||||
result.push_back(str);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> manager::get_conflicting_enabled(const elem& e) const
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
BOOST_FOREACH(const std::string& mod, mods_) {
|
||||
if (conflicts(elem(mod, "modification"), e)) {
|
||||
result.push_back(mod);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool manager::conflicts(const elem& elem1, const elem& elem2, bool directonly) const
|
||||
{
|
||||
if (elem1 == elem2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We ignore inexistent elements at this point, they will generate
|
||||
// errors in change_era()/change_scenario() anyways.
|
||||
if (!exists(elem1) || !exists(elem2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config data1 = depinfo_.find_child(elem1.type, "id", elem1.id);
|
||||
config data2 = depinfo_.find_child(elem2.type, "id", elem2.id);
|
||||
|
||||
// Whether we should skip the check entirely
|
||||
if (data1.has_attribute("ignore_incompatible_" + elem2.type)) {
|
||||
std::vector<std::string> ignored =
|
||||
utils::split(data1["ignore_incompatible_" + elem2.type]);
|
||||
|
||||
if (contains(ignored, elem2.id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data2.has_attribute("ignore_incompatible_" + elem1.type)) {
|
||||
std::vector<std::string> ignored =
|
||||
utils::split(data2["ignore_incompatible_" + elem1.type]);
|
||||
|
||||
if (contains(ignored, elem1.id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Checking for direct conflicts between elem1 and elem2
|
||||
if (data1.has_attribute("allow_" + elem2.type)) {
|
||||
std::vector<std::string> allowed =
|
||||
utils::split(data1["allow_" + elem2.type]);
|
||||
|
||||
result = !contains(allowed, elem2.id) && !requires(elem1, elem2);
|
||||
} else if (data1.has_attribute("disallow_" + elem2.type)) {
|
||||
std::vector<std::string> disallowed =
|
||||
utils::split(data1["disallow_" + elem2.type]);
|
||||
|
||||
result = contains(disallowed, elem2.id);
|
||||
}
|
||||
|
||||
if (data2.has_attribute("allow_" + elem1.type)) {
|
||||
std::vector<std::string> allowed =
|
||||
utils::split(data2["allow_" + elem1.type]);
|
||||
|
||||
result = result || (!contains(allowed, elem1.id) && !requires(elem2, elem1));
|
||||
} else if (data2.has_attribute("disallow_" + elem1.type)) {
|
||||
std::vector<std::string> disallowed =
|
||||
utils::split(data2["disallow_" + elem1.type]);
|
||||
|
||||
result = result || contains(disallowed, elem1.id);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checking for indirect conflicts (i.e. conflicts between dependencies)
|
||||
if (!directonly) {
|
||||
std::vector<std::string> req1 = get_required(elem1),
|
||||
req2 = get_required(elem2);
|
||||
|
||||
BOOST_FOREACH (const std::string& s, req1) {
|
||||
elem m(s, "modification");
|
||||
|
||||
if (conflicts(elem2, m, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH (const std::string& s, req2) {
|
||||
elem m(s, "modification");
|
||||
|
||||
if (conflicts(elem1, m, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH (const std::string& id1, req1) {
|
||||
elem m1(id1, "modification");
|
||||
|
||||
BOOST_FOREACH (const std::string& id2, req2) {
|
||||
elem m2(id2, "modification");
|
||||
|
||||
if (conflicts(m1, m2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool manager::requires(const elem& elem1, const elem& elem2) const
|
||||
{
|
||||
if (elem2.type != "modification") {
|
||||
return false;
|
||||
}
|
||||
|
||||
config data = depinfo_.find_child(elem1.type, "id", elem1.id);
|
||||
|
||||
if (data.has_attribute("force_modification")) {
|
||||
std::vector<std::string> required =
|
||||
utils::split(data["force_modification"]);
|
||||
|
||||
return contains(required, elem2.id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void manager::try_era(const std::string& id, bool force)
|
||||
{
|
||||
save_state();
|
||||
|
||||
if (force) {
|
||||
era_ = id;
|
||||
} else if (!change_era(id)) {
|
||||
revert();
|
||||
}
|
||||
}
|
||||
|
||||
void manager::try_scenario(const std::string& id, bool force)
|
||||
{
|
||||
save_state();
|
||||
|
||||
if (force) {
|
||||
scenario_ = id;
|
||||
} else if (!change_scenario(id)) {
|
||||
revert();
|
||||
}
|
||||
}
|
||||
|
||||
void manager::try_modifications(const std::vector<std::string>& ids, bool force)
|
||||
{
|
||||
save_state();
|
||||
|
||||
if (force) {
|
||||
mods_ = ids;
|
||||
} else if (!change_modifications(ids)) {
|
||||
revert();
|
||||
}
|
||||
}
|
||||
|
||||
void manager::try_era_by_index(int index, bool force)
|
||||
{
|
||||
try_era(depinfo_.child("era", index)["id"], force);
|
||||
}
|
||||
|
||||
void manager::try_scenario_by_index(int index, bool force)
|
||||
{
|
||||
try_scenario(depinfo_.child("scenario", index - 1)["id"], force);
|
||||
}
|
||||
|
||||
int manager::get_era_index() const
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
BOOST_FOREACH (const config& i, depinfo_.child_range("era"))
|
||||
{
|
||||
if (i["id"] == era_) {
|
||||
return result;
|
||||
}
|
||||
result++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int manager::get_scenario_index() const
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
BOOST_FOREACH (const config& i, depinfo_.child_range("scenario"))
|
||||
{
|
||||
if (i["id"] == scenario_) {
|
||||
return result;
|
||||
}
|
||||
result++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bool manager::enable_mods_dialog(const std::vector<std::string>& mods)
|
||||
{
|
||||
std::vector<std::string> items;
|
||||
BOOST_FOREACH (const std::string& mod, mods) {
|
||||
items.push_back(depinfo_.find_child("modification", "id", mod)["name"]);
|
||||
}
|
||||
|
||||
gui2::tmp_depcheck_confirm_change dialog(true, items, _("A component"));
|
||||
return dialog.show(video_);
|
||||
}
|
||||
|
||||
bool manager::disable_mods_dialog(const std::vector<std::string>& mods)
|
||||
{
|
||||
std::vector<std::string> items;
|
||||
BOOST_FOREACH (const std::string& mod, mods) {
|
||||
items.push_back(depinfo_.find_child("modification", "id", mod)["name"]);
|
||||
}
|
||||
|
||||
gui2::tmp_depcheck_confirm_change dialog(false, items, _("A component"));
|
||||
return dialog.show(video_);
|
||||
}
|
||||
|
||||
std::string manager::change_era_dialog(const std::vector<std::string>& eras)
|
||||
{
|
||||
std::vector<std::string> items;
|
||||
BOOST_FOREACH(const std::string& era, eras) {
|
||||
items.push_back(depinfo_.find_child("era", "id", era)["name"]);
|
||||
}
|
||||
|
||||
gui2::tmp_depcheck_select_new dialog(ERA, items);
|
||||
|
||||
if (dialog.show(video_)) {
|
||||
return eras[dialog.result()];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string
|
||||
manager::change_scenario_dialog(const std::vector<std::string>& scenarios)
|
||||
{
|
||||
std::vector<std::string> items;
|
||||
BOOST_FOREACH (const std::string& scenario, scenarios) {
|
||||
items.push_back(depinfo_.find_child("scenario", "id", scenario)["name"]);
|
||||
}
|
||||
|
||||
gui2::tmp_depcheck_select_new dialog(SCENARIO, items);
|
||||
if (dialog.show(video_)) {
|
||||
return scenarios[dialog.result()];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void manager::failure_dialog(const std::string& msg)
|
||||
{
|
||||
gui2::show_message
|
||||
(video_, _("Failed to resolve dependencies"), msg, _("OK"));
|
||||
}
|
||||
|
||||
|
||||
void manager::insert_element(component_type type, const config& data, int index)
|
||||
{
|
||||
std::string type_str;
|
||||
switch (type) {
|
||||
case ERA:
|
||||
type_str = "era";
|
||||
break;
|
||||
case SCENARIO:
|
||||
type_str = "scenario";
|
||||
break;
|
||||
case MODIFICATION:
|
||||
type_str = "modification";
|
||||
}
|
||||
|
||||
depinfo_.add_child_at(type_str, data, index);
|
||||
}
|
||||
|
||||
bool manager::change_scenario(const std::string& id)
|
||||
{
|
||||
// Checking for missing dependencies
|
||||
if (!get_required_not_installed(elem(id, "scenario")).empty()) {
|
||||
std::string msg =
|
||||
_("Scenario can't be activated. Some dependencies are missing: ");
|
||||
|
||||
msg +=
|
||||
utils::join(get_required_not_installed(elem(id, "scenario")), ", ");
|
||||
|
||||
failure_dialog(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
scenario_ = id;
|
||||
|
||||
elem scen = elem(id, "scenario");
|
||||
|
||||
// Firstly, we check if we have to enable/disable any mods
|
||||
std::vector<std::string> req = get_required_not_enabled(scen);
|
||||
std::vector<std::string> con = get_conflicting_enabled(scen);
|
||||
|
||||
if (!req.empty()) {
|
||||
if (!enable_mods_dialog(req)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!con.empty()) {
|
||||
if (!disable_mods_dialog(con)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> newmods = req;
|
||||
BOOST_FOREACH (const std::string& i, mods_) {
|
||||
if (!contains(con, i)) {
|
||||
newmods.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mods_ = newmods;
|
||||
|
||||
// Now checking if the currently selected era conflicts the scenario
|
||||
// and changing era if necessary
|
||||
if (!conflicts(scen, elem(era_, "era"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> compatible;
|
||||
BOOST_FOREACH (const config& i, depinfo_.child_range("era")) {
|
||||
if (!conflicts(scen, elem(i["id"], "era"))) {
|
||||
compatible.push_back(i["id"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!compatible.empty()) {
|
||||
era_ = change_era_dialog(compatible);
|
||||
} else {
|
||||
failure_dialog(_("No compatible eras found."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (era_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return change_era(era_);
|
||||
}
|
||||
|
||||
bool manager::change_era(const std::string& id)
|
||||
{
|
||||
// Checking for missing dependenciess
|
||||
if (!get_required_not_installed(elem(id, "era")).empty()) {
|
||||
std::string msg =
|
||||
_("Era can't be activated. Some dependencies are missing: ");
|
||||
|
||||
msg += utils::join(get_required_not_installed(elem(id, "era")), ", ");
|
||||
failure_dialog(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
era_ = id;
|
||||
|
||||
elem era = elem(id, "era");
|
||||
|
||||
std::vector<std::string> req = get_required_not_enabled(era);
|
||||
std::vector<std::string> con = get_conflicting_enabled(era);
|
||||
|
||||
// Firstly, we check if we have to enable/disable any mods
|
||||
if (!req.empty()) {
|
||||
if (!enable_mods_dialog(req)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!con.empty()) {
|
||||
if (!disable_mods_dialog(con)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> newmods = req;
|
||||
BOOST_FOREACH (const std::string& i, mods_) {
|
||||
if (!contains(con, i)) {
|
||||
newmods.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
mods_ = newmods;
|
||||
|
||||
// Now checking if the currently selected scenarop conflicts the era
|
||||
// and changing scenario if necessary
|
||||
if (!conflicts(era, elem(scenario_, "scenario"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> compatible;
|
||||
BOOST_FOREACH (const config& i, depinfo_.child_range("scenario")) {
|
||||
if (!conflicts(era, elem(i["id"], "scenario"))) {
|
||||
compatible.push_back(i["id"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!compatible.empty()) {
|
||||
scenario_ = change_scenario_dialog(compatible);
|
||||
} else {
|
||||
failure_dialog(_("No compatible scenarios found."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scenario_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return change_scenario(scenario_);
|
||||
}
|
||||
|
||||
bool manager::change_modifications
|
||||
(const std::vector<std::string>& modifications)
|
||||
{
|
||||
// Checking if the selected combination of mods is valid at all
|
||||
std::vector<std::string> filtered;
|
||||
BOOST_FOREACH (const std::string& i, modifications) {
|
||||
bool ok = true;
|
||||
elem ei(i, "modification");
|
||||
BOOST_FOREACH (const std::string& j, filtered) {
|
||||
ok = ok && !conflicts(ei, elem(j, "modification"));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
filtered.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (filtered.size() != modifications.size()) {
|
||||
failure_dialog(_("Not all of the chosen modifications are compatible." \
|
||||
" Some of them will be disabled."));
|
||||
}
|
||||
|
||||
mods_ = filtered;
|
||||
|
||||
// Checking if the currently selected era is compatible with the set
|
||||
// modifications, and changing era if necessary
|
||||
std::vector<std::string> compatible;
|
||||
BOOST_FOREACH (const config& c, depinfo_.child_range("era")) {
|
||||
elem era(c["id"], "era");
|
||||
bool ok = true;
|
||||
BOOST_FOREACH (const std::string& s, mods_) {
|
||||
ok = ok && !conflicts(era, elem(s, "modification"));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
compatible.push_back(era.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!contains(compatible, era_)) {
|
||||
if (!compatible.empty()) {
|
||||
era_ = change_era_dialog(compatible);
|
||||
} else {
|
||||
failure_dialog(_("No compatible eras found."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (era_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!change_era(era_)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!change_era(era_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
compatible.clear();
|
||||
|
||||
// Checking if the currently selected scenario is compatible with
|
||||
// the set modifications, and changing scenario if necessary
|
||||
BOOST_FOREACH (const config& c, depinfo_.child_range("scenario")) {
|
||||
elem scen(c["id"], "scenario");
|
||||
bool ok = true;
|
||||
BOOST_FOREACH (const std::string& s, mods_) {
|
||||
ok = ok && !conflicts(scen, elem(s, "modification"));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
compatible.push_back(scen.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!contains(compatible, scenario_)) {
|
||||
if (!compatible.empty()) {
|
||||
scenario_ = change_scenario_dialog(compatible);
|
||||
} else {
|
||||
failure_dialog(_("No compatible scenarios found."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scenario_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return change_scenario(scenario_);
|
||||
} else {
|
||||
if (!change_scenario(scenario_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} //namespace depcheck
|
||||
|
||||
} //namespace mp
|
337
src/mp_depcheck.hpp
Normal file
337
src/mp_depcheck.hpp
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 MP_DEPCHECK_HPP_INCLUDED
|
||||
#define MP_DEPCHECK_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "config.hpp"
|
||||
#include "game_display.hpp"
|
||||
|
||||
namespace mp
|
||||
{
|
||||
|
||||
namespace depcheck
|
||||
{
|
||||
|
||||
enum component_type
|
||||
{
|
||||
ERA,
|
||||
SCENARIO,
|
||||
MODIFICATION
|
||||
};
|
||||
|
||||
/**
|
||||
* Note to all triers:
|
||||
* It's not guaranteed that the specified component will be selected
|
||||
* (if the user denies to perform dependency resolution, all changes
|
||||
* will be reverted). Consequently, it's essential to check the
|
||||
* selected values after calling any trier.
|
||||
*
|
||||
* Note to ctor & insert_element:
|
||||
* Please note that the ctor collects data for scenario elements from
|
||||
* "multiplayer" nodes, while insert_element from "scenario" nodes.
|
||||
*/
|
||||
class manager
|
||||
{
|
||||
public:
|
||||
manager(const config& gamecfg, CVideo& video);
|
||||
|
||||
/**
|
||||
* Tries to set the selected era
|
||||
*
|
||||
* @param id the id of the era
|
||||
* @param force whether to skip dependency check
|
||||
*/
|
||||
void try_era(const std::string& id, bool force = false);
|
||||
|
||||
/**
|
||||
* Tries to set the selected scenario
|
||||
*
|
||||
* @param id the id of the scenario
|
||||
* @param force whether to skip dependency check
|
||||
*/
|
||||
void try_scenario(const std::string& id, bool force = false);
|
||||
|
||||
/**
|
||||
* Tries to set the enabled modifications
|
||||
*
|
||||
* @param ids the ids of the modifications
|
||||
* @param force whether to skip dependency check
|
||||
*/
|
||||
void try_modifications(const std::vector<std::string>& ids,
|
||||
bool force = false );
|
||||
|
||||
/**
|
||||
* Tries to set the selected era
|
||||
*
|
||||
* @param index the index of the era
|
||||
* @param force whether to skip dependency check
|
||||
*/
|
||||
void try_era_by_index(int index, bool force = false);
|
||||
|
||||
/**
|
||||
* Tries to set the selected scenario
|
||||
*
|
||||
* @param index the index of the scenario
|
||||
* @param force whether to skip dependency check
|
||||
*/
|
||||
void try_scenario_by_index(int index, bool force = false);
|
||||
|
||||
/**
|
||||
* Returns the selected era
|
||||
*
|
||||
* @return the id of the era
|
||||
*/
|
||||
const std::string& get_era() const { return era_; }
|
||||
|
||||
/**
|
||||
* Returns the selected scenario
|
||||
*
|
||||
* @return the id of the scenario
|
||||
*/
|
||||
const std::string& get_scenario() const { return scenario_; }
|
||||
|
||||
/**
|
||||
* Returns the enabled modifications
|
||||
*
|
||||
* @return the ids of the modifications
|
||||
*/
|
||||
const std::vector<std::string>& get_modifications() const { return mods_; }
|
||||
|
||||
/**
|
||||
* Returns the selected era
|
||||
*
|
||||
* @return the index of the era
|
||||
*/
|
||||
int get_era_index() const;
|
||||
|
||||
/**
|
||||
* Returns the selected scenario
|
||||
*
|
||||
* @return the index of the scenario
|
||||
*/
|
||||
int get_scenario_index() const;
|
||||
|
||||
/**
|
||||
* Adds a new element to the manager's database
|
||||
*
|
||||
* @param type the type of the element
|
||||
* @param data a config object containing the dependency info for the
|
||||
* element
|
||||
* @param index where to insert the element
|
||||
*/
|
||||
void insert_element(component_type type, const config& data, int index = 0);
|
||||
|
||||
private:
|
||||
|
||||
/** represents a component (era, modification or scenario)*/
|
||||
struct elem {
|
||||
elem(const std::string& _id, const std::string& _type)
|
||||
: id(_id)
|
||||
, type(_type)
|
||||
{}
|
||||
|
||||
std::string id;
|
||||
std::string type;
|
||||
|
||||
bool operator ==(const elem& e) const
|
||||
{ return id == e.id && type == e.type; }
|
||||
|
||||
bool operator !=(const elem& e) const { return !(*this == e); }
|
||||
};
|
||||
|
||||
/** the screen to display dialogs on */
|
||||
CVideo& video_;
|
||||
|
||||
/** holds all required info about the components and their dependencies */
|
||||
config depinfo_;
|
||||
|
||||
/** the id of the currently selected era */
|
||||
std::string era_;
|
||||
|
||||
/** the id of the currently selected scenario */
|
||||
std::string scenario_;
|
||||
|
||||
/** the ids of the currently selected modifications */
|
||||
std::vector<std::string> mods_;
|
||||
|
||||
/** used by save_state() and revert() to backup/restore era_ */
|
||||
std::string prev_era_;
|
||||
|
||||
/** used by save_state() and revert() to backup/restore scenario_ */
|
||||
std::string prev_scenario_;
|
||||
|
||||
/** used by save_state() and revert() to backup/restore mods_ */
|
||||
std::vector<std::string> prev_mods_;
|
||||
|
||||
/** saves the current values of era_, scenarios_ and mods_ */
|
||||
void save_state();
|
||||
|
||||
/** restores the lastly saved values of era_, scenarios_ and mods_ */
|
||||
void revert();
|
||||
|
||||
/**
|
||||
* Attempts to change the selected scenario.
|
||||
*
|
||||
* @param id the scenario's id
|
||||
* @return true if the selection was changed; false if not
|
||||
*/
|
||||
bool change_scenario(const std::string& id);
|
||||
|
||||
/**
|
||||
* Attempts to change the selected era.
|
||||
*
|
||||
* @param id the era's id
|
||||
* @return true if the selection was changed; false if not
|
||||
*/
|
||||
bool change_era(const std::string& id);
|
||||
|
||||
/**
|
||||
* Attempts to change the selected modifications.
|
||||
*
|
||||
* @param modifications the list of the modifications' ids
|
||||
* @return true if the selection was changed; false if not
|
||||
*/
|
||||
bool change_modifications(const std::vector<std::string>& modifications);
|
||||
|
||||
/**
|
||||
* Decides if two components are conflicting or not
|
||||
*
|
||||
* @param elem1 the first component
|
||||
* @param elem2 the second component
|
||||
* @param directonly whether the function should ignore any possible
|
||||
* conflicts between the components' dependencies.
|
||||
*
|
||||
* @return true if e1 and e2 conflict, false if not
|
||||
*/
|
||||
bool conflicts(const elem& elem1, const elem& elem2, bool directonly=false) const;
|
||||
|
||||
/**
|
||||
* Decides whether e1 requires e2
|
||||
*
|
||||
* @param elem1 a component; by definition, passing a modification here
|
||||
* makes no sense
|
||||
* @param elem2 another component; by definition, passing anything else
|
||||
* than a modification here makes no sense
|
||||
*
|
||||
* @return true if e2 is required by e1, false if not
|
||||
*/
|
||||
bool requires(const elem& elem1, const elem& elem2) const;
|
||||
|
||||
/**
|
||||
* Get the list of modifications required by a certain component
|
||||
*
|
||||
* @param e the component
|
||||
*
|
||||
* @return the list of the modifications' ids
|
||||
*/
|
||||
std::vector<std::string> get_required(const elem& e) const;
|
||||
|
||||
/**
|
||||
* Get the list of modifications which are required by a certain
|
||||
* component, but aren't currently enabled
|
||||
*
|
||||
* @param e the component
|
||||
*
|
||||
* @return the list of the modifications' ids
|
||||
*/
|
||||
std::vector<std::string> get_required_not_enabled(const elem& e) const;
|
||||
|
||||
/**
|
||||
* Get the list of modifications which are conflicting a certain
|
||||
* component and are currently enabled
|
||||
*
|
||||
* @param e the component
|
||||
*
|
||||
* @return the list of the modifications' ids
|
||||
*/
|
||||
std::vector<std::string> get_conflicting_enabled(const elem& e) const;
|
||||
|
||||
/**
|
||||
* Get the list of modifications which are required by a certain
|
||||
* component, but currently unavailable on the computer
|
||||
*
|
||||
* @param e the component
|
||||
*
|
||||
* @return the list of the modifications' ids
|
||||
*/
|
||||
std::vector<std::string> get_required_not_installed(const elem& e) const;
|
||||
|
||||
/**
|
||||
* Display a dialog requesting confirmation for enabling some
|
||||
* modifications
|
||||
*
|
||||
* @param mods the list of modifications to be enabled
|
||||
*
|
||||
* @return true, if the user accepted the change, false if not
|
||||
*/
|
||||
bool enable_mods_dialog(const std::vector<std::string>& mods);
|
||||
|
||||
/**
|
||||
* Display a dialog requesting confirmation for disabling some
|
||||
* modifications
|
||||
*
|
||||
* @param mods the list of modifications to be disabled
|
||||
*
|
||||
* @return true, if the user accepted the change, false if not
|
||||
*/
|
||||
bool disable_mods_dialog(const std::vector<std::string>& mods);
|
||||
|
||||
/**
|
||||
* Display a dialog requesting the user to select a new era
|
||||
*
|
||||
* @param eras the possible options (ids)
|
||||
*
|
||||
* @return the selected era's id or empty string if the user
|
||||
* refused to select any
|
||||
*/
|
||||
std::string change_era_dialog(const std::vector<std::string>& eras);
|
||||
|
||||
/**
|
||||
* Display a dialog requesting the user to select a new scenario
|
||||
*
|
||||
* @param scenarios the possible options (ids)
|
||||
*
|
||||
* @return the selected scenario's id or empty string if the user
|
||||
* refused to select any
|
||||
*/
|
||||
std::string change_scenario_dialog
|
||||
(const std::vector<std::string>& scenarios);
|
||||
|
||||
/**
|
||||
* Shows an error message
|
||||
*
|
||||
* @param msg the message to be displayed
|
||||
*/
|
||||
void failure_dialog(const std::string& msg);
|
||||
|
||||
/**
|
||||
* Decides whether a certain component is installed or not
|
||||
*
|
||||
* @param e the component
|
||||
*
|
||||
* @return true if the component exists false if not
|
||||
*/
|
||||
bool exists(const elem& e) const;
|
||||
|
||||
};
|
||||
|
||||
} //namespace depcheck
|
||||
|
||||
} //namespace mp
|
||||
|
||||
#endif
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "mp_game_settings.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
|
||||
mp_game_settings::mp_game_settings() :
|
||||
savegame_config(),
|
||||
@ -28,6 +29,7 @@ mp_game_settings::mp_game_settings() :
|
||||
hash(),
|
||||
mp_era(),
|
||||
mp_scenario(),
|
||||
active_mods(),
|
||||
village_gold(0),
|
||||
village_support(1),
|
||||
xp_modifier(0),
|
||||
@ -45,6 +47,7 @@ mp_game_settings::mp_game_settings() :
|
||||
share_view(false),
|
||||
share_maps(false),
|
||||
saved_game(false),
|
||||
options(),
|
||||
scenario_data()
|
||||
|
||||
{ reset(); }
|
||||
@ -56,6 +59,7 @@ mp_game_settings::mp_game_settings(const config& cfg) :
|
||||
hash(),
|
||||
mp_era(),
|
||||
mp_scenario(),
|
||||
active_mods(),
|
||||
village_gold(0),
|
||||
village_support(1),
|
||||
xp_modifier(0),
|
||||
@ -73,6 +77,7 @@ mp_game_settings::mp_game_settings(const config& cfg) :
|
||||
share_view(false),
|
||||
share_maps(false),
|
||||
saved_game(false),
|
||||
options(),
|
||||
scenario_data()
|
||||
{
|
||||
set_from_config(cfg);
|
||||
@ -85,6 +90,7 @@ mp_game_settings::mp_game_settings(const mp_game_settings& settings)
|
||||
, hash(settings.hash)
|
||||
, mp_era(settings.mp_era)
|
||||
, mp_scenario(settings.mp_scenario)
|
||||
, active_mods(settings.active_mods)
|
||||
, village_gold(settings.village_gold)
|
||||
, village_support(settings.village_support)
|
||||
, xp_modifier(settings.xp_modifier)
|
||||
@ -102,6 +108,7 @@ mp_game_settings::mp_game_settings(const mp_game_settings& settings)
|
||||
, share_view(settings.share_view)
|
||||
, share_maps(settings.share_maps)
|
||||
, saved_game(settings.saved_game)
|
||||
, options(settings.options)
|
||||
, scenario_data(settings.scenario_data)
|
||||
{
|
||||
}
|
||||
@ -116,6 +123,7 @@ void mp_game_settings::set_from_config(const config& game_cfg)
|
||||
hash = cfg["hash"].str();
|
||||
mp_era = cfg["mp_era"].str();
|
||||
mp_scenario = cfg["mp_scenario"].str();
|
||||
active_mods = utils::split(cfg["active_mods"], ',');
|
||||
xp_modifier = cfg["experience_modifier"];
|
||||
use_map_settings = cfg["mp_use_map_settings"].to_bool();
|
||||
fog_game = cfg["mp_fog"].to_bool();
|
||||
@ -130,6 +138,7 @@ void mp_game_settings::set_from_config(const config& game_cfg)
|
||||
allow_observers = cfg["observer"].to_bool();
|
||||
shuffle_sides = cfg["shuffle_sides"].to_bool();
|
||||
saved_game = cfg["savegame"].to_bool();
|
||||
options = cfg.child_or_empty("options");
|
||||
}
|
||||
|
||||
void mp_game_settings::reset()
|
||||
@ -139,6 +148,7 @@ void mp_game_settings::reset()
|
||||
hash = "";
|
||||
mp_era = "";
|
||||
mp_scenario = "";
|
||||
active_mods.clear();
|
||||
village_gold = 0;
|
||||
village_support = 1;
|
||||
xp_modifier = 0;
|
||||
@ -148,6 +158,7 @@ void mp_game_settings::reset()
|
||||
mp_countdown_action_bonus=0;
|
||||
mp_countdown=false;
|
||||
use_map_settings = random_start_time = fog_game = shroud_game = allow_observers = shuffle_sides = share_view = share_maps = false;
|
||||
options.clear();
|
||||
|
||||
scenario_data.clear();
|
||||
}
|
||||
@ -160,6 +171,7 @@ config mp_game_settings::to_config() const
|
||||
cfg["hash"] = hash;
|
||||
cfg["mp_era"] = mp_era;
|
||||
cfg["mp_scenario"] = mp_scenario;
|
||||
cfg["active_mods"] = utils::join(active_mods, ",");
|
||||
cfg["experience_modifier"] = xp_modifier;
|
||||
cfg["mp_countdown"] = mp_countdown;
|
||||
cfg["mp_countdown_init_time"] = mp_countdown_init_time;
|
||||
@ -174,6 +186,7 @@ config mp_game_settings::to_config() const
|
||||
cfg["observer"] = allow_observers;
|
||||
cfg["shuffle_sides"] = shuffle_sides;
|
||||
cfg["savegame"] = saved_game;
|
||||
cfg.add_child("options", options);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ struct mp_game_settings : public savegame::savegame_config
|
||||
std::string hash;
|
||||
std::string mp_era;
|
||||
std::string mp_scenario;
|
||||
std::vector<std::string> active_mods;
|
||||
|
||||
int village_gold;
|
||||
int village_support;
|
||||
@ -59,6 +60,8 @@ struct mp_game_settings : public savegame::savegame_config
|
||||
|
||||
bool saved_game;
|
||||
|
||||
config options;
|
||||
|
||||
/**
|
||||
* If the game is to be randomly generated, the map generator
|
||||
* will create the scenario data in this variable
|
||||
|
632
src/mp_options.cpp
Normal file
632
src/mp_options.cpp
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 "mp_options.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/auxiliary/window_builder.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/slider.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
#include "gui/widgets/toggle_button.hpp"
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
static lg::log_domain log_mp_create_options("mp/create/options");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp_create_options)
|
||||
|
||||
namespace mp
|
||||
{
|
||||
|
||||
namespace options
|
||||
{
|
||||
|
||||
config to_event(const config& cfg)
|
||||
{
|
||||
config result;
|
||||
|
||||
if (!cfg) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result["name"] = "prestart";
|
||||
|
||||
BOOST_FOREACH (const config& c, cfg.child_range("option")) {
|
||||
config ev;
|
||||
ev["name"] = c["id"];
|
||||
ev["value"] = c["value"];
|
||||
result.add_child("set_variable", ev);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void manager::init_info(const config& cfg, const std::string& key)
|
||||
{
|
||||
BOOST_FOREACH (const config& comp, cfg.child_range(key)) {
|
||||
config entry;
|
||||
entry["id"] = comp["id"];
|
||||
entry["name"] = comp["name"];
|
||||
|
||||
if (comp.has_child("options")) {
|
||||
const config& options = comp.child("options");
|
||||
|
||||
BOOST_FOREACH (const config::any_child& c,
|
||||
options.all_children_range()) {
|
||||
entry.add_child(c.key, c.cfg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We need to store components even if they don't have any options in
|
||||
// order to have set_xxx_by_index work properly
|
||||
options_info_.add_child(key, entry);
|
||||
}
|
||||
}
|
||||
|
||||
manager::manager(const config& gamecfg, CVideo& video, const config& values)
|
||||
: options_info_()
|
||||
, values_(values)
|
||||
, video_(video)
|
||||
, era_()
|
||||
, scenario_()
|
||||
, modifications_()
|
||||
{
|
||||
DBG_MP << "Initializing the options manager" << std::endl;
|
||||
init_info(gamecfg, "modification");
|
||||
init_info(gamecfg, "era");
|
||||
init_info(gamecfg, "multiplayer");
|
||||
|
||||
BOOST_FOREACH (const config::any_child& i,
|
||||
options_info_.all_children_range())
|
||||
{
|
||||
BOOST_FOREACH (const config::any_child& j, i.cfg.all_children_range())
|
||||
{
|
||||
if (is_valid_option(j.key, j.cfg)) {
|
||||
config& value = get_value_cfg(j.cfg["id"]);
|
||||
value["value"] = get_stored_value(j.cfg["id"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void manager::set_values(const config& c)
|
||||
{
|
||||
values_ = c;
|
||||
}
|
||||
|
||||
void manager::set_era(const std::string& era)
|
||||
{
|
||||
era_ = era;
|
||||
}
|
||||
|
||||
void manager::set_era_by_index(int index)
|
||||
{
|
||||
era_ = options_info_.child("era", index)["id"].str();
|
||||
}
|
||||
|
||||
void manager::set_scenario(const std::string& scenario)
|
||||
{
|
||||
scenario_ = scenario;
|
||||
}
|
||||
|
||||
void manager::set_scenario_by_index(int index)
|
||||
{
|
||||
scenario_ = options_info_.child("multiplayer", index - 1)["id"].str();
|
||||
}
|
||||
|
||||
void manager::set_modifications(const std::vector<std::string>& modifications)
|
||||
{
|
||||
modifications_ = modifications;
|
||||
}
|
||||
|
||||
void manager::insert_element(elem_type type, const config& data, int pos)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SCENARIO:
|
||||
options_info_.add_child_at("multiplayer", data, pos);
|
||||
break;
|
||||
case ERA:
|
||||
options_info_.add_child_at("era", data, pos);
|
||||
break;
|
||||
case MODIFICATION:
|
||||
options_info_.add_child_at("modification", data, pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void manager::show_dialog()
|
||||
{
|
||||
DBG_MP << "Building the options dialog" << std::endl;
|
||||
// Constructing the dialog
|
||||
config dialog_cfg;
|
||||
|
||||
dialog_cfg.add_child("resolution");
|
||||
dialog_cfg["definition"] = "default";
|
||||
dialog_cfg["automatic_placement"] = true;
|
||||
dialog_cfg["vertical_placement"] = "center";
|
||||
dialog_cfg["horizontal_placement"] = "center";
|
||||
dialog_cfg.add_child("helptip")["id"] = "tooltip_large";
|
||||
dialog_cfg.add_child("tooltip")["id"] = "tooltip_large";
|
||||
|
||||
config& grid = dialog_cfg.add_child("grid");
|
||||
|
||||
// Adding widgets for available options
|
||||
add_widgets(options_info_.find_child("era", "id", era_), grid);
|
||||
add_widgets(options_info_.find_child("multiplayer", "id", scenario_), grid);
|
||||
|
||||
for (unsigned i = 0; i<modifications_.size(); i++) {
|
||||
add_widgets(
|
||||
options_info_.find_child("modification", "id", modifications_[i]),
|
||||
grid);
|
||||
}
|
||||
|
||||
if (grid.ordered_begin() == grid.ordered_end()) {
|
||||
// No widgets were actually added, we've got nothing to show
|
||||
gui2::show_transient_message(video_, "", _(
|
||||
"None of the selected modifications, era or scenario provide " \
|
||||
"configuration options."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Dialog buttons
|
||||
config& row = grid.add_child("row");
|
||||
row["grow_factor"] = 0;
|
||||
|
||||
config& column = row.add_child("column");
|
||||
column["grow_factor"] = 1;
|
||||
column["border"] = "all";
|
||||
column["border_size"] = 5;
|
||||
column["horizontal_alignment"] = "right";
|
||||
|
||||
config& widget_grid = column.add_child("grid");
|
||||
|
||||
config& widget_row = widget_grid.add_child("row");
|
||||
widget_row["grow_factor"] = 0;
|
||||
|
||||
config& defaults_column = widget_row.add_child("column");
|
||||
defaults_column["grow_factor"] = 0;
|
||||
defaults_column["border"] = "all";
|
||||
defaults_column["border_size"] = 5;
|
||||
defaults_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& ok_column = widget_row.add_child("column");
|
||||
ok_column["grow_factor"] = 0;
|
||||
ok_column["border"] = "all";
|
||||
ok_column["border_size"] = 5;
|
||||
ok_column["horizontal_alignment"] = "right";
|
||||
|
||||
config& cancel_column = widget_row.add_child("column");
|
||||
cancel_column["grow_factor"] = 0;
|
||||
cancel_column["border"] = "all";
|
||||
cancel_column["border_size"] = 5;
|
||||
cancel_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& defaults_button = defaults_column.add_child("button");
|
||||
defaults_button["definition"] = "default";
|
||||
defaults_button["label"] = _("Restore defaults");
|
||||
defaults_button["id"] = "restore_defaults";
|
||||
|
||||
config& ok_button = ok_column.add_child("button");
|
||||
ok_button["definition"] = "default";
|
||||
ok_button["label"] = _("OK");
|
||||
ok_button["id"] = "ok";
|
||||
|
||||
config& cancel_button = cancel_column.add_child("button");
|
||||
cancel_button["definition"] = "default";
|
||||
cancel_button["label"] = _("Cancel");
|
||||
cancel_button["id"] = "cancel";
|
||||
|
||||
// Building the window
|
||||
gui2::twindow_builder::tresolution resolution(dialog_cfg);
|
||||
gui2::twindow* window = gui2::build(video_, &resolution);
|
||||
|
||||
__tmp_set_checkbox_defaults(window);
|
||||
|
||||
gui2::tbutton* button = gui2::find_widget<gui2::tbutton>
|
||||
(window, "restore_defaults", false, true);
|
||||
|
||||
// Callbacks (well, one callback)
|
||||
button->connect_click_handler(boost::bind(restore_defaults, this, window));
|
||||
|
||||
// Show window
|
||||
DBG_MP << "Showing the dialog" << std::endl;
|
||||
if (window->show() == gui2::twindow::CANCEL) {
|
||||
DBG_MP << "User cancelled changes" << std::endl;
|
||||
delete window;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Saving the results
|
||||
DBG_MP << "User accepted changes, saving values" << std::endl;
|
||||
extract_values("era", era_, window);
|
||||
extract_values("multiplayer", scenario_, window);
|
||||
for (unsigned i = 0; i<modifications_.size(); i++) {
|
||||
extract_values("modification", modifications_[i], window);
|
||||
}
|
||||
|
||||
delete window;
|
||||
}
|
||||
|
||||
void manager::add_widgets(const config& data, config& grid) const
|
||||
{
|
||||
if (!data.has_child("entry") &&
|
||||
!data.has_child("slider") &&
|
||||
!data.has_child("checkbox"))
|
||||
{
|
||||
//Don't display the title if there're no options at all
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// The title for this section
|
||||
config& row = grid.add_child("row");
|
||||
row["grow_factor"] = 0;
|
||||
config& column = row.add_child("column");
|
||||
column["grow_factor"] = 1;
|
||||
column["border"] = "all";
|
||||
column["border_size"] = 5;
|
||||
column["horizontal_alignment"] = "left";
|
||||
config& caption = column.add_child("label");
|
||||
caption["definition"] = "title";
|
||||
caption["label"] = data["name"];
|
||||
}
|
||||
|
||||
// Adding the widgets
|
||||
BOOST_FOREACH (const config::any_child& c, data.all_children_range()) {
|
||||
if (!is_valid_option(c.key, c.cfg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
config& row = grid.add_child("row");
|
||||
row["grow_factor"] = 0;
|
||||
config& column = row.add_child("column");
|
||||
column["grow_factor"] = 1;
|
||||
column["border"] = "all";
|
||||
column["border_size"] = 5;
|
||||
column["horizontal_alignment"] = "left";
|
||||
|
||||
if (c.key == "entry") {
|
||||
add_entry(c.cfg, column);
|
||||
} else if (c.key == "slider") {
|
||||
add_slider(c.cfg, column);
|
||||
} else if (c.key == "checkbox") {
|
||||
add_checkbox(c.cfg, column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void manager::add_entry(const config& data, config& column) const
|
||||
{
|
||||
config& grid = column.add_child("grid");
|
||||
config& row = grid.add_child("row");
|
||||
row["grow_factor"] = 0;
|
||||
|
||||
config& label_column = row.add_child("column");
|
||||
label_column["grow_factor"] = 0;
|
||||
label_column["border"] = "all";
|
||||
label_column["border_size"] = 5;
|
||||
label_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& entry_column = row.add_child("column");
|
||||
entry_column["grow_factor"] = 0;
|
||||
entry_column["border"] = "all";
|
||||
entry_column["border_size"] = 5;
|
||||
entry_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& label = label_column.add_child("label");
|
||||
label["definition"] = "default";
|
||||
label["label"] = data["description"];
|
||||
|
||||
config& entry = entry_column.add_child("text_box");
|
||||
entry["id"] = data["id"];
|
||||
entry["definition"] = "default";
|
||||
entry["label"] = get_stored_value(data["id"]);
|
||||
}
|
||||
|
||||
void manager::add_slider(const config& data, config& column) const
|
||||
{
|
||||
config& grid = column.add_child("grid");
|
||||
config& row = grid.add_child("row");
|
||||
row["grow_factor"] = 0;
|
||||
|
||||
config& label_column = row.add_child("column");
|
||||
label_column["grow_factor"] = 0;
|
||||
label_column["border"] = "all";
|
||||
label_column["border_size"] = 5;
|
||||
label_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& slider_column = row.add_child("column");
|
||||
slider_column["grow_factor"] = 0;
|
||||
slider_column["border"] = "all";
|
||||
slider_column["border_size"] = 5;
|
||||
slider_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& label = label_column.add_child("label");
|
||||
label["definition"] = "default";
|
||||
label["label"] = data["description"];
|
||||
|
||||
config& slider = slider_column.add_child("slider");
|
||||
slider["id"] = data["id"];
|
||||
slider["definition"] = "default";
|
||||
slider["minimum_value"] = data["min_value"];
|
||||
slider["maximum_value"] = data["max_value"];
|
||||
slider["step_size"] = data["step"].to_int() ? data["step"].to_int() : 1;
|
||||
|
||||
// This seems to misbehave when step_size isn't 1, apparently a bug
|
||||
// with the slider widget itself.
|
||||
slider["value"] = get_stored_value(data["id"]);
|
||||
}
|
||||
|
||||
void manager::add_checkbox(const config& data, config& column) const
|
||||
{
|
||||
config& grid = column.add_child("grid");
|
||||
config& row = grid.add_child("row");
|
||||
row["grow_factor"] = 0;
|
||||
|
||||
config& box_column = row.add_child("column");
|
||||
box_column["grow_factor"] = 0;
|
||||
box_column["border"] = "all";
|
||||
box_column["border_size"] = 5;
|
||||
box_column["horizontal_alignment"] = "left";
|
||||
|
||||
config& checkbox = box_column.add_child("toggle_button");
|
||||
checkbox["id"] = data["id"];
|
||||
checkbox["definition"] = "default";
|
||||
checkbox["label"] = data["description"];
|
||||
}
|
||||
|
||||
config& manager::get_value_cfg(const std::string& id)
|
||||
{
|
||||
{
|
||||
const manager* m = this;
|
||||
config& value_cfg = const_cast<config&>(m->get_value_cfg(id));
|
||||
if (!value_cfg.empty()) {
|
||||
return value_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
config::any_child info = get_option_parent(id);
|
||||
config* parent_cfg;
|
||||
if (!values_.find_child(info.key, "id", info.cfg["id"])) {
|
||||
parent_cfg = &values_.add_child(info.key);
|
||||
(*parent_cfg)["id"] = info.cfg["id"];
|
||||
} else {
|
||||
parent_cfg = &values_.find_child(info.key, "id", info.cfg["id"]);
|
||||
}
|
||||
|
||||
config& value_cfg = parent_cfg->add_child("option");
|
||||
value_cfg["id"] = id;
|
||||
|
||||
return value_cfg;
|
||||
}
|
||||
|
||||
const config& manager::get_value_cfg(const std::string& id) const
|
||||
{
|
||||
static const config empty;
|
||||
|
||||
BOOST_FOREACH (const config::any_child& i, values_.all_children_range()) {
|
||||
BOOST_FOREACH (const config& j, i.cfg.child_range("option")) {
|
||||
if (j["id"] == id) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
config::any_child manager::get_option_parent(const std::string& id) const
|
||||
{
|
||||
static const config empty;
|
||||
static const std::string empty_key = "";
|
||||
static config::any_child not_found(&empty_key, &empty);
|
||||
|
||||
BOOST_FOREACH (const config::any_child& i,
|
||||
options_info_.all_children_range()) {
|
||||
BOOST_FOREACH (const config::any_child& j, i.cfg.all_children_range()) {
|
||||
if (j.cfg["id"] == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return not_found;
|
||||
}
|
||||
|
||||
const config& manager::get_option_info_cfg(const std::string& id) const
|
||||
{
|
||||
static const config empty;
|
||||
|
||||
BOOST_FOREACH (const config::any_child& i,
|
||||
options_info_.all_children_range()) {
|
||||
BOOST_FOREACH (const config::any_child& j, i.cfg.all_children_range()) {
|
||||
if (j.cfg["id"] == id) {
|
||||
return j.cfg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
config::attribute_value manager::get_stored_value(const std::string& id) const
|
||||
{
|
||||
const config& valcfg = get_value_cfg(id);
|
||||
|
||||
if (!valcfg["value"].empty()) {
|
||||
// There's a saved value for this option
|
||||
return valcfg["value"];
|
||||
}
|
||||
|
||||
// Fall back to the option's default
|
||||
return get_default_value(id);
|
||||
}
|
||||
|
||||
config::attribute_value manager::get_default_value(const std::string& id) const
|
||||
{
|
||||
const config& optinfo = get_option_info_cfg(id);
|
||||
|
||||
return optinfo["default"];
|
||||
}
|
||||
|
||||
int manager::get_slider_value(const std::string& id, gui2::twindow* win) const
|
||||
{
|
||||
gui2::tslider* widget =
|
||||
gui2::find_widget<gui2::tslider>(win, id, false, true);
|
||||
|
||||
return widget->get_value();
|
||||
}
|
||||
|
||||
bool manager::get_checkbox_value
|
||||
(const std::string& id, gui2::twindow* win) const
|
||||
{
|
||||
gui2::ttoggle_button* widget =
|
||||
gui2::find_widget<gui2::ttoggle_button>(win, id, false, true);
|
||||
|
||||
return widget->get_value();
|
||||
}
|
||||
|
||||
std::string manager::get_entry_value(const std::string& id,
|
||||
gui2::twindow* window) const
|
||||
{
|
||||
gui2::ttext_box* widget =
|
||||
gui2::find_widget<gui2::ttext_box>(window, id, false, true);
|
||||
|
||||
return widget->text();
|
||||
}
|
||||
|
||||
void manager::set_slider_value(int val, const std::string& id,
|
||||
gui2::twindow* win) const
|
||||
{
|
||||
gui2::tslider* widget =
|
||||
gui2::find_widget<gui2::tslider>(win, id, false, true);
|
||||
|
||||
widget->set_value(val);
|
||||
}
|
||||
|
||||
void manager::set_checkbox_value(bool val, const std::string& id,
|
||||
gui2::twindow* win) const
|
||||
{
|
||||
gui2::ttoggle_button* widget =
|
||||
gui2::find_widget<gui2::ttoggle_button>(win, id, false, true);
|
||||
|
||||
widget->set_value(val);
|
||||
}
|
||||
|
||||
void manager::set_entry_value(const std::string& val, const std::string& id,
|
||||
gui2::twindow* win) const
|
||||
{
|
||||
gui2::ttext_box* widget =
|
||||
gui2::find_widget<gui2::ttext_box>(win, id, false, true);
|
||||
|
||||
widget->set_value(val);
|
||||
}
|
||||
|
||||
void manager::extract_values(const std::string& key, const std::string& id,
|
||||
gui2::twindow* window)
|
||||
{
|
||||
BOOST_FOREACH (const config::any_child& c,
|
||||
options_info_.find_child(key, "id", id).all_children_range())
|
||||
{
|
||||
if (!is_valid_option(c.key, c.cfg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
config& out = get_value_cfg(c.cfg["id"].str());
|
||||
|
||||
if (c.key == "entry") {
|
||||
out["value"] = get_entry_value(c.cfg["id"], window);
|
||||
} else if (c.key == "slider") {
|
||||
out["value"] = get_slider_value(c.cfg["id"], window);
|
||||
} else if (c.key == "checkbox") {
|
||||
out["value"] = get_checkbox_value(c.cfg["id"], window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool manager::is_valid_option(const std::string& key, const config& option)
|
||||
{
|
||||
return (key == "slider" || key == "entry" || key == "checkbox") &&
|
||||
(!option["id"].empty());
|
||||
}
|
||||
|
||||
void manager::restore_defaults(manager* m, gui2::twindow* w)
|
||||
{
|
||||
const config& era = m->options_info_.find_child("era", "id", m->era_);
|
||||
restore_defaults_for_component(era, m, w);
|
||||
|
||||
const config& scen = m->options_info_.find_child("multiplayer", "id",
|
||||
m->scenario_);
|
||||
restore_defaults_for_component(scen, m, w);
|
||||
|
||||
BOOST_FOREACH (const std::string& id, m->modifications_) {
|
||||
const config& mod = m->options_info_.find_child("modification", "id",
|
||||
id);
|
||||
restore_defaults_for_component(mod, m, w);
|
||||
}
|
||||
}
|
||||
|
||||
void manager::restore_defaults_for_component(const config& c, manager* m,
|
||||
gui2::twindow* w)
|
||||
{
|
||||
BOOST_FOREACH (const config::any_child& i, c.all_children_range()) {
|
||||
if (!is_valid_option(i.key, i.cfg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string id = i.cfg["id"].str();
|
||||
|
||||
if (i.key == "entry") {
|
||||
m->set_entry_value(m->get_default_value(id).str(), id, w);
|
||||
} else if (i.key == "checkbox") {
|
||||
m->set_checkbox_value(m->get_default_value(id).to_bool(), id, w);
|
||||
} else if (i.key == "slider") {
|
||||
m->set_slider_value(m->get_default_value(id).to_int(), id, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void manager::__tmp_set_checkbox_defaults(gui2::twindow* window) const
|
||||
{
|
||||
BOOST_FOREACH (const config::any_child& i,
|
||||
options_info_.all_children_range())
|
||||
{
|
||||
BOOST_FOREACH (const config& j, i.cfg.child_range("checkbox"))
|
||||
{
|
||||
if (!is_valid_option("checkbox", j)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gui2::ttoggle_button* button;
|
||||
button = gui2::find_widget<gui2::ttoggle_button>
|
||||
(window, j["id"].str(), false, false);
|
||||
|
||||
if (button) {
|
||||
button->set_value(get_stored_value(j["id"]).to_bool());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace options
|
||||
|
||||
} // namespace mp
|
||||
|
370
src/mp_options.hpp
Normal file
370
src/mp_options.hpp
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@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 MP_OPTIONS_HPP_INCLUDED
|
||||
#define MP_OPTIONS_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "config.hpp"
|
||||
#include "video.hpp"
|
||||
#include "gui/widgets/widget.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
|
||||
namespace mp
|
||||
{
|
||||
|
||||
namespace options
|
||||
{
|
||||
|
||||
config to_event(const config& options);
|
||||
|
||||
// TODO: there's an identical enum in mp_depcheck.hpp, maybe we should factor
|
||||
// out?
|
||||
enum elem_type
|
||||
{
|
||||
SCENARIO,
|
||||
ERA,
|
||||
MODIFICATION
|
||||
};
|
||||
|
||||
class manager
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param gamecfg The config object holding all eras, scenarios
|
||||
* and modifications.
|
||||
*
|
||||
* @param video The screen to display the dialog on.
|
||||
*
|
||||
* @param initial_values The initial values for each option.
|
||||
*/
|
||||
manager(const config& gamecfg, CVideo& video, const config& initial_values);
|
||||
|
||||
/**
|
||||
* Set the current values the options. This overrides ALL previously set
|
||||
* values, even if a not all options are provided a new value for.
|
||||
*
|
||||
* @param values The new values for each option.
|
||||
*/
|
||||
void set_values(const config& values);
|
||||
|
||||
/**
|
||||
* Sets the selected era. Whenever show_dialog is called, only
|
||||
* options for the selected era will be displayed.
|
||||
*
|
||||
* @param id The era's id.
|
||||
*/
|
||||
void set_era(const std::string& id);
|
||||
|
||||
/**
|
||||
* Sets the selected era. Whenever show_dialog is called, only
|
||||
* options for the selected era will be displayed.
|
||||
*
|
||||
* @param index The era's index.
|
||||
*/
|
||||
void set_era_by_index(int index);
|
||||
|
||||
/**
|
||||
* Sets the selected scenario. Whenever show_dialog is called, only
|
||||
* options for the selected scenario will be displayed.
|
||||
*
|
||||
* @param id The scenario's id.
|
||||
*/
|
||||
void set_scenario(const std::string& id);
|
||||
|
||||
/**
|
||||
* Sets the selected scenario. Whenever show_dialog is called, only
|
||||
* options for the selected scenario will be displayed.
|
||||
*
|
||||
* @param index The scenario's index.
|
||||
*/
|
||||
void set_scenario_by_index(int index);
|
||||
|
||||
/**
|
||||
* Sets the activated modifications. Whenever show_dialog is called, only
|
||||
* options for the activated modifications will be displayed.
|
||||
*
|
||||
* @param ids The ids of the modifications
|
||||
*/
|
||||
void set_modifications(const std::vector<std::string>& ids);
|
||||
|
||||
/**
|
||||
* Add options information of an era/scenario/modification not yet in the
|
||||
* database.
|
||||
*
|
||||
* @param type The type of the element,
|
||||
*
|
||||
* @param data The config object which holds the
|
||||
* information about the element's options in
|
||||
* an [options] child.
|
||||
*
|
||||
* @param pos The position to insert the element into.
|
||||
*/
|
||||
void insert_element(elem_type type, const config& data, int pos);
|
||||
|
||||
/**
|
||||
* Shows the options dialog and saves the selected values.
|
||||
*/
|
||||
void show_dialog();
|
||||
|
||||
/**
|
||||
* Returns the the values for each option.
|
||||
*
|
||||
* @return A config containing the values.
|
||||
*/
|
||||
const config& get_values() const { return values_; }
|
||||
|
||||
private:
|
||||
/** Stores needed info about each element and their configuration options */
|
||||
config options_info_;
|
||||
|
||||
/** Stores the selected values for each option */
|
||||
config values_;
|
||||
|
||||
/** The screen to display the dialog on */
|
||||
CVideo &video_;
|
||||
|
||||
/** The id of the selected era */
|
||||
std::string era_;
|
||||
|
||||
/** The id of the selected scenario */
|
||||
std::string scenario_;
|
||||
|
||||
/** The ids of the selected modifications */
|
||||
std::vector<std::string> modifications_;
|
||||
|
||||
/**
|
||||
* Adds the necessary information about the specified component
|
||||
* to options_info_.
|
||||
*
|
||||
* @param cfg The component's data.
|
||||
* @param key The component's type.
|
||||
*/
|
||||
void init_info(const config& cfg, const std::string& key);
|
||||
|
||||
/**
|
||||
* Creates a widget layout based on an [options] section.
|
||||
*
|
||||
* @param data The [options] section.
|
||||
* @param grid The grid to create the layout in.
|
||||
*/
|
||||
void add_widgets(const config& data, config& grid) const;
|
||||
|
||||
/**
|
||||
* Creates a slider widget.
|
||||
*
|
||||
* @param data A [slider] config.
|
||||
* @param column The grid cell to add the widget into.
|
||||
*/
|
||||
void add_slider(const config& data, config& column) const;
|
||||
|
||||
/**
|
||||
* Creates a checkbox (toggle button) widget.
|
||||
*
|
||||
* @param data A [checkbox] config.
|
||||
* @param column The grid cell to add the widget into.
|
||||
*/
|
||||
void add_checkbox(const config& data, config& column) const;
|
||||
|
||||
/**
|
||||
* @todo Implement this function (along with a combo box widget, preferably)
|
||||
*
|
||||
* Creates a combo box widget.
|
||||
*
|
||||
* @param data A [combobox] config.
|
||||
* @param column The grid cell to add the widget into.
|
||||
*/
|
||||
void add_combobox(const config& data, config& column) const;
|
||||
|
||||
/**
|
||||
* Creates a text entry widget.
|
||||
*
|
||||
* @param data An [entry] config.
|
||||
* @param column The grid cell to add the widget into.
|
||||
*/
|
||||
void add_entry(const config& data, config& column) const;
|
||||
|
||||
/**
|
||||
* Returns the node which holds the selected value of an option. If that
|
||||
* node is not yet created, the function creates it.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return A reference to the config which the value
|
||||
* for this option should be written into.
|
||||
*/
|
||||
config& get_value_cfg(const std::string& id);
|
||||
|
||||
/**
|
||||
* Returns the node which holds the selected value of an option. If that
|
||||
* node is not yet created, the function returns an empty config.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return A reference to the config which the value
|
||||
* for this option should be written into or
|
||||
* an empty config if that doesn't exist.
|
||||
*/
|
||||
const config& get_value_cfg(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Returns the information about an option.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return The config object which contains the
|
||||
* settings of the option, or an empty config
|
||||
* if the option was not found.
|
||||
*/
|
||||
const config& get_option_info_cfg(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Finds the parent node of an options.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return A config::any_child object containing the
|
||||
* key and the data of the parent node, or ""
|
||||
* for the key and an empty config if the
|
||||
* option was not found.
|
||||
*/
|
||||
config::any_child get_option_parent(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Retrieves the saved value for a certain option, or the default, if
|
||||
* there's no such.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return The value saved in values_ for this option
|
||||
* or its specified default value if a saved
|
||||
* value can't be found.
|
||||
*/
|
||||
config::attribute_value get_stored_value(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Retrieves the default value for a certain option.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return The default value for this option.
|
||||
*/
|
||||
config::attribute_value get_default_value(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Gets the current value of a slider widget.
|
||||
*
|
||||
* @param id The id of the widget.
|
||||
* @param win The window to find the widget in.
|
||||
*
|
||||
* @return The integer currently set on the slider.
|
||||
*/
|
||||
int get_slider_value(const std::string& id, gui2::twindow* win) const;
|
||||
|
||||
/**
|
||||
* Gets the current value of a checkbox widget.
|
||||
*
|
||||
* @param id The id of the widget.
|
||||
* @param win The window to find the widget in.
|
||||
*
|
||||
* @return True if the box is checked, false if not.
|
||||
*/
|
||||
bool get_checkbox_value(const std::string& id, gui2::twindow* win) const;
|
||||
|
||||
/**
|
||||
* Gets the current value of a text_box widget.
|
||||
*
|
||||
* @param id The id of the widget.
|
||||
* @param win The window to find the widget in.
|
||||
*
|
||||
* @return The text written in the widget.
|
||||
*/
|
||||
std::string get_entry_value(const std::string& id,
|
||||
gui2::twindow* win) const;
|
||||
|
||||
void set_slider_value(int val, const std::string& id,
|
||||
gui2::twindow* win) const;
|
||||
|
||||
void set_checkbox_value(bool val, const std::string& id,
|
||||
gui2::twindow* win) const;
|
||||
|
||||
void set_entry_value(const std::string& val, const std::string& id,
|
||||
gui2::twindow* win) const;
|
||||
|
||||
/**
|
||||
* Writes all the values for the options of a certain component from a
|
||||
* specified window into values_.
|
||||
*
|
||||
* @param key The component's type.
|
||||
* @param id The component's id.
|
||||
* @param window The window.
|
||||
*/
|
||||
void extract_values(const std::string& key, const std::string& id,
|
||||
gui2::twindow* window);
|
||||
|
||||
/**
|
||||
* Decides whether a config is a sane option node or not.
|
||||
* A valid option node:
|
||||
* - Must have an id field.
|
||||
* - Its key must be "slider", "entry" or "checkbox"
|
||||
*
|
||||
* @param key The option's key.
|
||||
* @param option The option's data.
|
||||
*
|
||||
* @return True if the option is valid, false if not.
|
||||
*/
|
||||
static bool is_valid_option(const std::string& key, const config& option);
|
||||
|
||||
/**
|
||||
* Restores every widget's value to its default for a window.
|
||||
*
|
||||
* @param m A pointer to the manager which generated
|
||||
* the window.
|
||||
* @param w A pointer to the window itself.
|
||||
*/
|
||||
static void restore_defaults(manager* m, gui2::twindow* w);
|
||||
|
||||
/**
|
||||
* Finds the widgets representing the options of a certain component in a
|
||||
* window (era, scenario or modification) and sets their value to their
|
||||
* defaults.
|
||||
*
|
||||
* @param comp The config of the component.
|
||||
* @param m A pointer to the manager which generated
|
||||
* the window.
|
||||
* @param w A pointer to the window.
|
||||
*/
|
||||
static void restore_defaults_for_component(const config& comp, manager* m,
|
||||
gui2::twindow* w);
|
||||
|
||||
/**
|
||||
* @todo Implement a way to initialize the checkbox via WML and then
|
||||
* remove this function altogether.
|
||||
*
|
||||
* Sets the default states for all checkbox widgets inside a window. All
|
||||
* required data is fetched from values_ and options_info_.
|
||||
*
|
||||
* @param window The window.
|
||||
*/
|
||||
void __tmp_set_checkbox_defaults(gui2::twindow* window) const;
|
||||
};
|
||||
|
||||
} // namespace options
|
||||
|
||||
} // namespace mp
|
||||
#endif
|
@ -36,6 +36,7 @@
|
||||
#include "formula_string_utils.hpp"
|
||||
#include "tod_manager.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "mp_options.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
@ -1642,6 +1643,10 @@ void connect::load_game()
|
||||
level_["turns"] = num_turns_;
|
||||
level_.add_child("multiplayer", params_.to_config());
|
||||
|
||||
// Convert options to events
|
||||
level_.add_child_at("event", mp::options::to_event(params_.options
|
||||
.find_child("multiplayer", "id", params_.mp_scenario)), 0);
|
||||
|
||||
params_.hash = level_.hash();
|
||||
level_["next_underlying_unit_id"] = 0;
|
||||
n_unit::id_manager::instance().clear();
|
||||
@ -1690,7 +1695,22 @@ void connect::load_game()
|
||||
BOOST_FOREACH(const config &e, era_cfg.child_range("multiplayer_side")) {
|
||||
era_sides_.push_back(&e);
|
||||
}
|
||||
level_.add_child("era", era_cfg);
|
||||
config& cfg = level_.add_child("era", era_cfg);
|
||||
|
||||
// Convert options to event
|
||||
cfg.add_child_at("event", mp::options::to_event
|
||||
(params_.options.find_child("era", "id", era)), 0);
|
||||
}
|
||||
|
||||
// Add modifications
|
||||
const std::vector<std::string>& mods = params_.active_mods;
|
||||
for (unsigned i = 0; i<mods.size(); i++) {
|
||||
config& cfg = level_.add_child("modification",
|
||||
game_config().find_child("modification", "id", mods[i]));
|
||||
|
||||
// Convert options to event
|
||||
cfg.add_child_at("event", mp::options::to_event
|
||||
(params_.options.find_child("modification", "id", mods[i])), 0);
|
||||
}
|
||||
|
||||
gold_title_label_.hide(params_.saved_game);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "map_exception.hpp"
|
||||
#include "map_create.hpp"
|
||||
#include "gui/dialogs/message.hpp"
|
||||
#include "gui/dialogs/mp_create_game_choose_mods.hpp"
|
||||
#include "gui/dialogs/mp_create_game_set_password.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "minimap.hpp"
|
||||
@ -58,11 +59,13 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
|
||||
|
||||
local_players_only_(local_players_only),
|
||||
tooltip_manager_(disp.video()),
|
||||
era_selection_(-1),
|
||||
map_selection_(-1),
|
||||
mp_countdown_init_time_(270),
|
||||
mp_countdown_reservoir_time_(330),
|
||||
user_maps_(),
|
||||
map_options_(),
|
||||
available_mods_(),
|
||||
map_index_(),
|
||||
|
||||
maps_menu_(disp.video(), std::vector<std::string>()),
|
||||
@ -94,11 +97,13 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
|
||||
shroud_game_(disp.video(), _("Shroud"), gui::button::TYPE_CHECK),
|
||||
observers_game_(disp.video(), _("Observers"), gui::button::TYPE_CHECK),
|
||||
shuffle_sides_(disp.video(), _("Shuffle sides"), gui::button::TYPE_CHECK),
|
||||
options_(disp.video(), _("Options...")),
|
||||
cancel_game_(disp.video(), _("Cancel")),
|
||||
launch_game_(disp.video(), _("OK")),
|
||||
regenerate_map_(disp.video(), _("Regenerate")),
|
||||
generator_settings_(disp.video(), _("Settings...")),
|
||||
password_button_(disp.video(), _("Set Password...")),
|
||||
choose_mods_(disp.video(), _("Modifications...")),
|
||||
era_combo_(disp, std::vector<std::string>()),
|
||||
vision_combo_(disp, std::vector<std::string>()),
|
||||
name_entry_(disp.video(), 32),
|
||||
@ -106,7 +111,9 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
|
||||
minimap_rect_(null_rect),
|
||||
generator_(NULL),
|
||||
num_turns_(0),
|
||||
parameters_()
|
||||
parameters_(),
|
||||
dependency_manager_(cfg, disp.video()),
|
||||
options_manager_(cfg, disp.video(), preferences::options())
|
||||
{
|
||||
// Build the list of scenarios to play
|
||||
|
||||
@ -127,6 +134,22 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
|
||||
{
|
||||
menu_help_str = help_sep + user_maps_[i];
|
||||
map_options_.push_back(user_maps_[i] + menu_help_str);
|
||||
|
||||
// Since user maps are treated as scenarios,
|
||||
// some dependency info is required
|
||||
config depinfo;
|
||||
|
||||
depinfo["id"] = user_maps_[i];
|
||||
depinfo["name"] = user_maps_[i];
|
||||
|
||||
dependency_manager_.insert_element(depcheck::SCENARIO, depinfo, i);
|
||||
|
||||
// Same with options
|
||||
// FIXME: options::elem_type duplicates depcheck::component_type
|
||||
// Perhaps they should me merged?
|
||||
config optinfo = depinfo;
|
||||
|
||||
options_manager_.insert_element(options::SCENARIO, optinfo, i);
|
||||
}
|
||||
|
||||
// Standard maps
|
||||
@ -145,8 +168,11 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
|
||||
|
||||
// Create the scenarios menu
|
||||
maps_menu_.set_items(map_options_);
|
||||
if (size_t(preferences::map()) < map_options_.size())
|
||||
if (size_t(preferences::map()) < map_options_.size()) {
|
||||
maps_menu_.move_selection(preferences::map());
|
||||
dependency_manager_.try_scenario_by_index(preferences::map(), true);
|
||||
options_manager_.set_scenario_by_index(preferences::map());
|
||||
}
|
||||
maps_menu_.set_numeric_keypress_selection(false);
|
||||
|
||||
turns_slider_.set_min(settings::turns_min);
|
||||
@ -238,9 +264,25 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
|
||||
if (size_t(preferences::era()) < eras.size()) {
|
||||
era_combo_.set_selected(preferences::era());
|
||||
} else {
|
||||
era_combo_.set_selected(0);
|
||||
era_combo_.set_selected(preferences::era());
|
||||
}
|
||||
|
||||
dependency_manager_.try_era_by_index(era_selection_, true);
|
||||
options_manager_.set_era_by_index(era_selection_);
|
||||
|
||||
// Available modifications
|
||||
BOOST_FOREACH (const config& mod, cfg.child_range("modification")) {
|
||||
available_mods_.add_child("modification", mod);
|
||||
}
|
||||
|
||||
BOOST_FOREACH (const std::string& str, preferences::modifications()) {
|
||||
if (cfg.find_child("modification", "id", str))
|
||||
parameters_.active_mods.push_back(str);
|
||||
}
|
||||
|
||||
dependency_manager_.try_modifications(parameters_.active_mods, true);
|
||||
options_manager_.set_modifications(parameters_.active_mods);
|
||||
|
||||
|
||||
utils::string_map i18n_symbols;
|
||||
i18n_symbols["login"] = preferences::login();
|
||||
@ -271,8 +313,10 @@ create::~create()
|
||||
preferences::set_countdown_turn_bonus(parameters_.mp_countdown_turn_bonus);
|
||||
preferences::set_countdown_reservoir_time(parameters_.mp_countdown_reservoir_time);
|
||||
preferences::set_countdown_action_bonus(parameters_.mp_countdown_action_bonus);
|
||||
preferences::set_era(era_combo_.selected()); /** @todo FIXME: may be broken if new eras are added. */
|
||||
preferences::set_era(era_selection_); /** @todo FIXME: may be broken if new eras are added. */
|
||||
preferences::set_map(map_selection_);
|
||||
preferences::set_modifications(parameters_.active_mods);
|
||||
preferences::set_options(parameters_.options);
|
||||
|
||||
// When using map settings, the following variables are determined by the map,
|
||||
// so don't store them as the new preferences.
|
||||
@ -334,6 +378,7 @@ mp_game_settings& create::get_parameters()
|
||||
parameters_.shuffle_sides = shuffle_sides_.checked();
|
||||
parameters_.share_view = vision_combo_.selected() == 0;
|
||||
parameters_.share_maps = vision_combo_.selected() == 1;
|
||||
parameters_.options = options_manager_.get_values();
|
||||
|
||||
return parameters_;
|
||||
}
|
||||
@ -368,12 +413,35 @@ void create::process_event()
|
||||
}
|
||||
}
|
||||
|
||||
if(options_.pressed()) {
|
||||
options_manager_.show_dialog();
|
||||
}
|
||||
|
||||
if(password_button_.pressed()) {
|
||||
gui2::tmp_create_game_set_password::execute(
|
||||
parameters_.password
|
||||
, disp_.video());
|
||||
}
|
||||
|
||||
if(choose_mods_.pressed()) {
|
||||
if (available_mods_.empty()) {
|
||||
gui2::show_transient_message(disp_.video(), "",
|
||||
_( "There are no modifications currently installed." \
|
||||
" To download modifications, connect to the add-ons server" \
|
||||
" by choosing the 'Add-ons' option on the main screen." ));
|
||||
} else {
|
||||
|
||||
gui2::tmp_create_game_choose_mods
|
||||
dialog(available_mods_, parameters_.active_mods);
|
||||
|
||||
dialog.show(disp_.video());
|
||||
|
||||
dependency_manager_.try_modifications(parameters_.active_mods);
|
||||
options_manager_.set_modifications(parameters_.active_mods);
|
||||
synchronize_selections();
|
||||
}
|
||||
}
|
||||
|
||||
// Turns per game
|
||||
const int cur_turns = turns_slider_.value();
|
||||
|
||||
@ -446,9 +514,24 @@ void create::process_event()
|
||||
|
||||
xp_modifier_label_.set_text(buf.str());
|
||||
|
||||
bool era_changed = era_selection_ != era_combo_.selected();
|
||||
era_selection_ = era_combo_.selected();
|
||||
|
||||
if (era_changed) {
|
||||
dependency_manager_.try_era_by_index(era_selection_);
|
||||
options_manager_.set_era_by_index(era_selection_);
|
||||
synchronize_selections();
|
||||
}
|
||||
|
||||
bool map_changed = map_selection_ != maps_menu_.selection();
|
||||
map_selection_ = maps_menu_.selection();
|
||||
|
||||
if (map_changed) {
|
||||
dependency_manager_.try_scenario_by_index(map_selection_);
|
||||
options_manager_.set_scenario_by_index(map_selection_);
|
||||
synchronize_selections();
|
||||
}
|
||||
|
||||
if(map_changed) {
|
||||
generator_.assign(NULL);
|
||||
|
||||
@ -757,6 +840,8 @@ void create::layout_children(const SDL_Rect& rect)
|
||||
ypos += era_label_.height() + border_size;
|
||||
era_combo_.set_location(xpos, ypos);
|
||||
ypos += era_combo_.height() + border_size;
|
||||
choose_mods_.set_location(xpos, ypos);
|
||||
ypos += choose_mods_.height() + border_size;
|
||||
if(!local_players_only_) {
|
||||
password_button_.set_location(xpos, ypos);
|
||||
ypos += password_button_.height() + border_size;
|
||||
@ -857,6 +942,28 @@ void create::layout_children(const SDL_Rect& rect)
|
||||
ca.y + ca.h - right_button->height());
|
||||
left_button->set_location(right_button->location().x - left_button->width() -
|
||||
gui::ButtonHPadding, ca.y + ca.h - left_button->height());
|
||||
|
||||
options_.set_location(left_button->location().x - options_.width() -
|
||||
gui::ButtonHPadding, ca.y + ca.h - options_.height());
|
||||
}
|
||||
|
||||
void create::synchronize_selections()
|
||||
{
|
||||
DBG_MP << "Synchronizing with the dependency manager" << std::endl;
|
||||
if (era_selection_ != dependency_manager_.get_era_index()) {
|
||||
era_combo_.set_selected(dependency_manager_.get_era_index());
|
||||
process_event();
|
||||
}
|
||||
|
||||
if (map_selection_ != dependency_manager_.get_scenario_index()) {
|
||||
maps_menu_.move_selection(dependency_manager_.get_scenario_index());
|
||||
process_event();
|
||||
}
|
||||
|
||||
parameters_.active_mods = dependency_manager_.get_modifications();
|
||||
options_manager_.set_modifications(dependency_manager_.get_modifications());
|
||||
options_manager_.set_era(dependency_manager_.get_era());
|
||||
options_manager_.set_scenario(dependency_manager_.get_scenario());
|
||||
}
|
||||
|
||||
} // namespace mp
|
||||
|
@ -18,7 +18,9 @@
|
||||
#ifndef MULTIPLAYER_CREATE_HPP_INCLUDED
|
||||
#define MULTIPLAYER_CREATE_HPP_INCLUDED
|
||||
|
||||
#include "mp_depcheck.hpp"
|
||||
#include "mp_game_settings.hpp"
|
||||
#include "mp_options.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
#include "widgets/combo.hpp"
|
||||
@ -43,9 +45,12 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
void synchronize_selections();
|
||||
|
||||
bool local_players_only_;
|
||||
|
||||
tooltips::manager tooltip_manager_;
|
||||
int era_selection_;
|
||||
int map_selection_;
|
||||
int mp_countdown_init_time_;
|
||||
int mp_countdown_reservoir_time_;
|
||||
@ -53,6 +58,7 @@ private:
|
||||
|
||||
std::vector<std::string> user_maps_;
|
||||
std::vector<std::string> map_options_;
|
||||
config available_mods_;
|
||||
|
||||
/**
|
||||
* Due to maps not available the index of the selected map and mp scenarios
|
||||
@ -91,11 +97,13 @@ private:
|
||||
gui::button shroud_game_;
|
||||
gui::button observers_game_;
|
||||
gui::button shuffle_sides_;
|
||||
gui::button options_;
|
||||
gui::button cancel_game_;
|
||||
gui::button launch_game_;
|
||||
gui::button regenerate_map_;
|
||||
gui::button generator_settings_;
|
||||
gui::button password_button_;
|
||||
gui::button choose_mods_;
|
||||
|
||||
gui::combo era_combo_;
|
||||
gui::combo vision_combo_;
|
||||
@ -108,6 +116,9 @@ private:
|
||||
|
||||
int num_turns_;
|
||||
mp_game_settings parameters_;
|
||||
|
||||
depcheck::manager dependency_manager_;
|
||||
options::manager options_manager_;
|
||||
};
|
||||
|
||||
} // end namespace mp
|
||||
|
@ -159,6 +159,9 @@ void gamebrowser::draw_row(const size_t index, const SDL_Rect& item_rect, ROW_TY
|
||||
font_color = font::DISABLED_COLOR;
|
||||
no_era_string = _(" (Unknown Era)");
|
||||
}
|
||||
if(!game.have_all_mods && font_color != font::BAD_COLOR) {
|
||||
font_color = font::DISABLED_COLOR;
|
||||
}
|
||||
|
||||
const surface status_text(font::get_rendered_text(game.status,
|
||||
font::SIZE_NORMAL, font_color));
|
||||
@ -179,7 +182,7 @@ void gamebrowser::draw_row(const size_t index, const SDL_Rect& item_rect, ROW_TY
|
||||
}
|
||||
|
||||
// Second line
|
||||
ypos = item_rect.y + item_rect.h/2;
|
||||
ypos = item_rect.y + item_rect.h/3 + margin_;
|
||||
|
||||
// Draw map info
|
||||
const surface map_info_surf(font::get_rendered_text(
|
||||
@ -191,6 +194,18 @@ void gamebrowser::draw_row(const size_t index, const SDL_Rect& item_rect, ROW_TY
|
||||
}
|
||||
|
||||
// Third line
|
||||
ypos = item_rect.y + 2*item_rect.h/3 - margin_;
|
||||
|
||||
// Draw modifications info
|
||||
const surface mod_info_surf(font::get_rendered_text(
|
||||
font::make_text_ellipsis(game.mod_info, font::SIZE_NORMAL,
|
||||
(item_rect.x + item_rect.w) - xpos - margin_),
|
||||
font::SIZE_NORMAL, font::NORMAL_COLOR));
|
||||
if(mod_info_surf) {
|
||||
video().blit_surface(xpos, ypos - mod_info_surf->h/2, mod_info_surf);
|
||||
}
|
||||
|
||||
// Fourth line
|
||||
ypos = item_rect.y + item_rect.h - margin_;
|
||||
|
||||
// Draw observer icon
|
||||
@ -525,6 +540,32 @@ void gamebrowser::set_game_items(const config& cfg, const config& game_config)
|
||||
games_.back().map_info += _("Unknown scenario");
|
||||
verified = false;
|
||||
}
|
||||
|
||||
games_.back().mod_info += "Modifications: ";
|
||||
|
||||
if (!game.child_or_empty("modification").empty()) {
|
||||
games_.back().have_all_mods = true;
|
||||
BOOST_FOREACH (const config& m, game.child_range("modification")) {
|
||||
const config& mod_cfg = game_config.find_child("modification", "id", m["id"]);
|
||||
if (mod_cfg) {
|
||||
games_.back().mod_info += mod_cfg["name"].str();
|
||||
games_.back().mod_info += ", ";
|
||||
} else {
|
||||
games_.back().mod_info += m["id"].str();
|
||||
if (m["require_modification"].to_bool(false)) {
|
||||
games_.back().have_all_mods = false;
|
||||
games_.back().mod_info += _(" (missing)");
|
||||
}
|
||||
games_.back().mod_info += ", ";
|
||||
}
|
||||
}
|
||||
games_.back().mod_info.erase(games_.back().mod_info.size()-2, 2);
|
||||
} else {
|
||||
games_.back().mod_info += "none";
|
||||
games_.back().have_all_mods = true;
|
||||
}
|
||||
|
||||
|
||||
if (games_.back().reloaded) {
|
||||
games_.back().map_info += " — ";
|
||||
games_.back().map_info += _("Reloaded game");
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
name(),
|
||||
map_info(),
|
||||
map_info_size(),
|
||||
mod_info(),
|
||||
gold(),
|
||||
xp(),
|
||||
vision(),
|
||||
@ -60,7 +61,8 @@ public:
|
||||
use_map_settings(false),
|
||||
verified(false),
|
||||
password_required(false),
|
||||
have_era(false)
|
||||
have_era(false),
|
||||
have_all_mods(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -70,6 +72,7 @@ public:
|
||||
std::string name;
|
||||
std::string map_info;
|
||||
std::string map_info_size;
|
||||
std::string mod_info;
|
||||
std::string gold;
|
||||
std::string xp;
|
||||
std::string vision;
|
||||
@ -87,6 +90,7 @@ public:
|
||||
bool verified;
|
||||
bool password_required;
|
||||
bool have_era;
|
||||
bool have_all_mods;
|
||||
};
|
||||
gamebrowser(CVideo& video, const config &map_hashes);
|
||||
void scroll(unsigned int pos);
|
||||
@ -100,9 +104,9 @@ public:
|
||||
SDL_Rect get_item_rect(size_t index) const;
|
||||
bool empty() const { return games_.empty(); }
|
||||
bool selection_is_joinable() const
|
||||
{ return empty() ? false : (games_[selected_].vacant_slots > 0 && !games_[selected_].started && games_[selected_].have_era); }
|
||||
{ return empty() ? false : (games_[selected_].vacant_slots > 0 && !games_[selected_].started && games_[selected_].have_era && games_[selected_].have_all_mods); }
|
||||
// Moderators may observe any game.
|
||||
bool selection_is_observable() const { return empty() ? false : (games_[selected_].observers && games_[selected_].have_era) || preferences::is_authenticated(); }
|
||||
bool selection_is_observable() const { return empty() ? false : (games_[selected_].observers && games_[selected_].have_era && games_[selected_].have_all_mods) || preferences::is_authenticated(); }
|
||||
bool selected() const { return double_clicked_ && !empty(); }
|
||||
void reset_selection() { double_clicked_ = false; }
|
||||
int selection() const { return selected_; }
|
||||
|
@ -282,11 +282,17 @@ void play_controller::init(CVideo& video){
|
||||
browse_ = true;
|
||||
|
||||
init_managers();
|
||||
// add era events for MP game
|
||||
// add era & mod events for MP game
|
||||
if (const config &era_cfg = level_.child("era")) {
|
||||
game_events::add_events(era_cfg.child_range("event"), "era_events");
|
||||
}
|
||||
|
||||
if (level_.child_or_empty("modification")) {
|
||||
BOOST_FOREACH (const config& mod_cfg, level_.child_range("modification")) {
|
||||
game_events::add_events(mod_cfg.child_range("event"),
|
||||
"mod_" + mod_cfg["id"].str() + "_events");
|
||||
}
|
||||
}
|
||||
loadscreen::global_loadscreen->start_stage("start game");
|
||||
loadscreen_manager->reset();
|
||||
}
|
||||
|
@ -4026,9 +4026,9 @@ void LuaKernel::initialize()
|
||||
|
||||
static char const *handled_file_tags[] = {
|
||||
"color_palette", "color_range", "era", "event", "generator",
|
||||
"label", "lua", "map", "menu_item", "music", "side", "sound_source", "story",
|
||||
"terrain_graphics", "time", "time_area", "tunnel", "variables", "endlevel",
|
||||
"display",
|
||||
"label", "lua", "map", "menu_item", "modification", "music", "options",
|
||||
"side", "sound_source", "story","terrain_graphics", "time", "time_area",
|
||||
"tunnel", "variables", "endlevel", "display",
|
||||
//TODO: These are only needed for MP campaigns and only for subsequent scenarios, see bug #18883
|
||||
"snapshot", "multiplayer", "replay_start"
|
||||
};
|
||||
|
@ -2404,6 +2404,7 @@ void server::process_data_game(const network::connection sock,
|
||||
rooms_.lobby().send_server_message("The scenario data is missing the [multiplayer] tag which contains the game settings. Game aborted.", sock);
|
||||
return;
|
||||
}
|
||||
|
||||
g->set_description(&desc);
|
||||
desc.set_attr_dup("id", lexical_cast<std::string>(g->id()).c_str());
|
||||
} else {
|
||||
@ -2428,6 +2429,14 @@ void server::process_data_game(const network::connection sock,
|
||||
}
|
||||
}
|
||||
|
||||
const simple_wml::node::child_list& mlist = data.children("modification");
|
||||
BOOST_FOREACH (const simple_wml::node* m, mlist) {
|
||||
desc.add_child_at("modification", 0);
|
||||
desc.child("modification")->set_attr_dup("id", m->attr("id"));
|
||||
if (m->attr("require_modification").to_bool(false))
|
||||
desc.child("modification")->set_attr("require_modification", "yes");
|
||||
}
|
||||
|
||||
// Record the full scenario in g->level()
|
||||
g->level().swap(data);
|
||||
// The host already put himself in the scenario so we just need
|
||||
@ -2497,6 +2506,7 @@ void server::process_data_game(const network::connection sock,
|
||||
rooms_.lobby().send_server_message("The scenario data is missing the [multiplayer] tag which contains the game settings. Game aborted.", sock);
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is no shroud, then tell players in the lobby
|
||||
// what the map looks like.
|
||||
const simple_wml::node& s = g->level().root();
|
||||
|
@ -242,6 +242,10 @@ public:
|
||||
return root().child(name);
|
||||
}
|
||||
|
||||
const node::child_list& children(const char* name) const {
|
||||
return root().children(name);
|
||||
}
|
||||
|
||||
node& set_attr(const char* key, const char* value) {
|
||||
return root().set_attr(key, value);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user