Merge pull request #216 from Rift-Walker/scenario_era_mod_defines_mergable

Add define functionality to scenarios, eras, and mods
This commit is contained in:
Alexander van Gessel 2014-06-25 09:20:38 +02:00
commit 5ca7121822
14 changed files with 157 additions and 12 deletions

View file

@ -87,6 +87,7 @@ Version 1.13.0-dev:
* Added support for [elseif] tags inside [if]
* Schema validator messages now conform better to the new WML
parser/preprocessor diagnostics format introduced in version 1.11.10.
* Added define= functionality to scenarios, eras, and modifications.
* Miscellaneous and bug fixes:
* replace 'fight_on_without_leader'=yes/no with defeat_condition=no_leader/
no_units/always/never which allows the wml developer to decide when a side

View file

@ -1174,6 +1174,10 @@
email = "greywhind_AT_users.sourceforge.net"
wikiuser = "Greywhind"
[/entry]
[entry]
name = "Nathan Walker (RiftWalker)"
email = "nathan.b.walker@vanderbilt.edu"
[/entry]
[entry]
name = "Oleg Tsarev"
email = "zabivator@gmail.com"

View file

@ -10,7 +10,9 @@ Note: You need to use the default map settings for the scenario to work right."
experience_modifier="100"
map_data="{multiplayer/maps/Dark_Forecast.map}"
victory_when_enemies_defeated=no
define=MULTIPLAYER_2P_DARK_FORECAST_LOAD
#ifdef MULTIPLAYER_2P_DARK_FORECAST_LOAD
#define RANDOMIZE NUMBER
{VARIABLE_OP random rand 1..{NUMBER}}
#enddef
@ -1006,6 +1008,7 @@ Note: You need to use the default map settings for the scenario to work right."
{FIRST_WATCH}
{SECOND_WATCH}
#endif
[side]
side=1
team_name="revolt"
@ -1015,6 +1018,7 @@ Note: You need to use the default map settings for the scenario to work right."
no_leader=yes
controller="ai"
village_gold=1
#ifdef MULTIPLAYER_2P_DARK_FORECAST_LOAD
[unit]
type=Ancient Lich
canrecruit=yes
@ -1033,6 +1037,7 @@ Note: You need to use the default map settings for the scenario to work right."
[/object]
[/modifications]
[/unit]
#endif
[/side]
[side]
@ -1088,6 +1093,7 @@ Note: You need to use the default map settings for the scenario to work right."
share_view="yes"
[/side]
#ifdef MULTIPLAYER_2P_DARK_FORECAST_LOAD
[event]
name=prestart
{SET_TIMID_AI_AND_BOLD_AI 2 1}
@ -1406,4 +1412,5 @@ The weather will also change randomly, affecting the layout of the map.
#undef WEATHER_ALERT
#undef ADJUST_WEATHER
#undef INIT_WEATHER
#endif
[/multiplayer]

View file

@ -1,5 +1,6 @@
#textdomain wesnoth-multiplayer
#ifdef MULTIPLAYER_HORNSHARK_ISLAND_LOAD
#define MODIFY_BOWMAN X Y
[object]
silent=yes
@ -18,6 +19,7 @@
[/effect]
[/object]
#enddef
#endif
[multiplayer]
id=multiplayer_Hornshark_Island
@ -26,10 +28,13 @@
description= _ "Players must forge strange alliances with the local inhabitants, in order to survive on this most unusual of islands. Designed by Doc Paterson."
map_data="{multiplayer/maps/2p_Hornshark_Island.map}"
random_start_time="no"
define=MULTIPLAYER_HORNSHARK_ISLAND_LOAD
#ifdef MULTIPLAYER_HORNSHARK_ISLAND_LOAD
{DEFAULT_SCHEDULE_MORNING}
{DEFAULT_MUSIC_PLAYLIST}
#endif
[side]
[ai]
@ -56,6 +61,7 @@
fog=yes
[/side]
#ifdef MULTIPLAYER_HORNSHARK_ISLAND_LOAD
[event]
name=prestart
@ -1011,4 +1017,5 @@
{MODIFY_BOWMAN 1 1}
{MODIFY_BOWMAN 28 24}
[/event]
#endif
[/multiplayer]

View file

@ -6,7 +6,9 @@
description= _ "This 4p survival scenario allows you to construct buildings and terraform the land. Use map settings. The recommended starting gold is 100."
experience_modifier=70%
turns=unlimited
define=MULTIPLAYER_A_NEW_LAND_LOAD
#ifdef MULTIPLAYER_A_NEW_LAND_LOAD
{DEFAULT_SCHEDULE}
{DEFAULT_MUSIC_PLAYLIST}
# ------------------------------------------------------
@ -36,6 +38,7 @@
[/objective]
[/objectives]
[/event]
#endif
# ------------------------------------------------------
# Side Definitions
@ -120,6 +123,7 @@
income_lock=yes
type=Death Knight
allow_player=no
#ifdef MULTIPLAYER_A_NEW_LAND_LOAD
[modifications]
{MOVEMENT_RESTRICTION flat shallow_water}
[/modifications]
@ -130,6 +134,7 @@
[village]
x,y=10,25
[/village]
#endif
[/side]
[side]
@ -147,6 +152,7 @@
income_lock=yes
type=Orcish Sovereign
allow_player=no
#ifdef MULTIPLAYER_A_NEW_LAND_LOAD
[modifications]
{MOVEMENT_RESTRICTION flat shallow_water}
[/modifications]
@ -157,6 +163,7 @@
[village]
x,y=50,25
[/village]
#endif
[/side]
[side]
@ -174,6 +181,7 @@
income_lock=yes
type=Orcish Sovereign
allow_player=no
#ifdef MULTIPLAYER_A_NEW_LAND_LOAD
[modifications]
{MOVEMENT_RESTRICTION flat shallow_water}
[/modifications]
@ -184,6 +192,7 @@
[village]
x,y=10,30
[/village]
#endif
[/side]
[side]
@ -201,6 +210,7 @@
income_lock=yes
type=Death Knight
allow_player=no
#ifdef MULTIPLAYER_A_NEW_LAND_LOAD
[modifications]
{MOVEMENT_RESTRICTION flat shallow_water}
[/modifications]
@ -211,6 +221,7 @@
[village]
x,y=50,30
[/village]
#endif
[/side]
# This side is for trapped units. It is allied to the AI so they don't attack it.
@ -233,6 +244,7 @@
[/ai]
[/side]
#ifdef MULTIPLAYER_A_NEW_LAND_LOAD
# ------------------------------------------------------
# ANL Building Logic
# ------------------------------------------------------
@ -840,4 +852,5 @@
type=Necrophage,Bone Shooter,Revenant
[/allow_recruit]
[/event]
#endif
[/multiplayer]

View file

@ -49,6 +49,7 @@ _s , _s , _s , _s , _s , _s
_s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s
_s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s , _s
#enddef
#ifdef 6P_TEAM_SURVIVAL_LOAD
#define TS_WALL_MASK_NORTH
usage=mask
@ -311,6 +312,7 @@ usage=mask
{TS_SPAWN2 "Goblin Rouser"}{TS_SPAWN2 "Goblin Spearman"}{TS_SPAWN2 "Goblin Spearman"}{TS_SPAWN2 "Goblin Spearman"}{TS_SPAWN2 "Goblin Spearman"}{TS_SPAWN2 "Goblin Spearman"}{TS_SPAWN2 "Goblin Spearman"}
[/event]
#enddef
#endif
[multiplayer]
id=multiplayer_6p_Team_Survival
@ -321,9 +323,12 @@ usage=mask
turns=32
victory_when_enemies_defeated=yes
random_start_time="no"
define=6P_TEAM_SURVIVAL_LOAD
#ifdef 6P_TEAM_SURVIVAL_LOAD
{DEFAULT_MUSIC_PLAYLIST}
{DEFAULT_SCHEDULE}
#endif
[side]
user_team_name=_ "Attacker"
@ -420,6 +425,7 @@ usage=mask
[/ai]
[/side]
#ifdef 6P_TEAM_SURVIVAL_LOAD
[event]
name=prestart
@ -600,9 +606,11 @@ usage=mask
image=portraits/undead/transparent/spectre.png
[/message]
[/event]
#endif
[/multiplayer]
#undef TS_MAP_DATA
#ifdef 6P_TEAM_SURVIVAL_LOAD
#undef TS_WALL_MASK_NORTH
#undef TS_WALL_MASK_NORTH_EAST
#undef TS_WALL_MASK_NORTH_WEST
@ -622,3 +630,4 @@ usage=mask
#undef TS_LAKE_SPAWN
#undef TS_HOME_SPAWN
#undef TS_SPAWNS
#endif

View file

@ -34,6 +34,9 @@ game_classification::game_classification():
campaign_type(),
campaign_define(),
campaign_xtra_defines(),
scenario_define(),
era_define(),
mod_defines(),
campaign(),
abbrev(),
completion(),
@ -51,6 +54,9 @@ game_classification::game_classification(const config& cfg):
campaign_type(lexical_cast_default<game_classification::CAMPAIGN_TYPE> (cfg["campaign_type"].str(), game_classification::SCENARIO)),
campaign_define(cfg["campaign_define"]),
campaign_xtra_defines(utils::split(cfg["campaign_extra_defines"])),
scenario_define(cfg["scenario_define"]),
era_define(cfg["era_define"]),
mod_defines(utils::split(cfg["mod_defines"])),
campaign(cfg["campaign"]),
abbrev(cfg["abbrev"]),
completion(cfg["completion"]),
@ -68,6 +74,9 @@ game_classification::game_classification(const game_classification& gc):
campaign_type(gc.campaign_type),
campaign_define(gc.campaign_define),
campaign_xtra_defines(gc.campaign_xtra_defines),
scenario_define(gc.scenario_define),
era_define(gc.era_define),
mod_defines(gc.mod_defines),
campaign(gc.campaign),
abbrev(gc.abbrev),
completion(gc.completion),
@ -88,6 +97,9 @@ config game_classification::to_config() const
cfg["campaign_type"] = lexical_cast<std::string> (campaign_type);
cfg["campaign_define"] = campaign_define;
cfg["campaign_extra_defines"] = utils::join(campaign_xtra_defines);
cfg["scenario_define"] = scenario_define;
cfg["era_define"] = era_define;
cfg["mod_defines"] = utils::join(mod_defines);
cfg["campaign"] = campaign;
cfg["abbrev"] = abbrev;
cfg["completion"] = completion;

View file

@ -43,6 +43,9 @@ public:
CAMPAIGN_TYPE campaign_type;
std::string campaign_define; /**< If there is a define the campaign uses to customize data */
std::vector<std::string> campaign_xtra_defines; /**< more customization of data */
std::string scenario_define; /**< If there is a define the scenario uses to customize data */
std::string era_define; /**< If there is a define the era uses to customize data */
std::vector<std::string> mod_defines; /**< If there are defines the modifications use to customize data */
std::string campaign; /**< the campaign being played */

View file

@ -374,6 +374,10 @@ void game_config_manager::load_game_config_for_game(
!classification.difficulty.empty());
game_config::scoped_preproc_define campaign(classification.campaign_define,
!classification.campaign_define.empty());
game_config::scoped_preproc_define scenario(classification.scenario_define,
!classification.scenario_define.empty());
game_config::scoped_preproc_define era(classification.era_define,
!classification.era_define.empty());
game_config::scoped_preproc_define multiplayer("MULTIPLAYER",
classification.campaign_type == game_classification::MULTIPLAYER);
@ -385,6 +389,13 @@ void game_config_manager::load_game_config_for_game(
(new game_config::scoped_preproc_define(extra_define));
extra_defines.push_back(new_define);
}
std::deque<define> modification_defines;
BOOST_FOREACH(const std::string& mod_define,
classification.mod_defines) {
define new_define
(new game_config::scoped_preproc_define(mod_define, !mod_define.empty()));
modification_defines.push_back(new_define);
}
try{
load_game_config(NO_FORCE_RELOAD, &classification);

View file

@ -41,6 +41,8 @@
#include "settings.hpp"
#include "sound.hpp"
#include "unit_id.hpp"
#include "resources.hpp"
#include "game_config_manager.hpp"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
@ -785,13 +787,34 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
// None of the other parameters need to be set, as their creation values above are good enough for CL mode.
// In particular, we do not want to use the preferences values.
// Override era, faction (side) and scenario if set on the commandline
if (cmdline_opts.multiplayer_era) parameters.mp_era = *cmdline_opts.multiplayer_era;
const config &era_cfg = game_config.find_child("era", "id", parameters.mp_era);
if (!era_cfg) {
std::cerr << "Could not find era '" << parameters.mp_era << "'\n";
return;
// scope for config objects that will become invalid after reload
{
// Override era, faction (side) and scenario if set on the commandline
if (cmdline_opts.multiplayer_era)
parameters.mp_era = *cmdline_opts.multiplayer_era;
const config& era_cfg_preload = game_config.find_child("era", "id", parameters.mp_era);
if (!era_cfg_preload) {
std::cerr << "Could not find era '" << parameters.mp_era << "'\n";
return;
}
if (cmdline_opts.multiplayer_scenario)
parameters.name = *cmdline_opts.multiplayer_scenario;
const config &level_preload = game_config.find_child("multiplayer", "id", parameters.name);
if (!level_preload) {
std::cerr << "Could not find scenario '" << parameters.name << "'\n";
return;
}
game_classification classification;
classification.campaign_type = game_classification::MULTIPLAYER;
classification.scenario_define = level_preload["define"].str();
classification.era_define = era_cfg_preload["define"].str();
resources::config_manager->load_game_config_for_game(classification);
}
const config& era_cfg = resources::config_manager->game_config().find_child("era", "id", parameters.mp_era);
const config& level = resources::config_manager->game_config().find_child("multiplayer", "id", parameters.name);
if (cmdline_opts.multiplayer_side) {
for(std::vector<boost::tuple<unsigned int, std::string> >::const_iterator
@ -805,12 +828,6 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
}
}
if (cmdline_opts.multiplayer_scenario) parameters.name = *cmdline_opts.multiplayer_scenario;
const config &level = game_config.find_child("multiplayer", "id", parameters.name);
if (!level) {
std::cerr << "Could not find scenario '" << parameters.name << "'\n";
return;
}
// Should the map be randomly generated?
if (level["map_generation"].empty()) {

View file

@ -223,6 +223,9 @@ void create::process_event()
if (launch_game_.pressed() || levels_menu_.double_clicked()) {
if (engine_.current_level().can_launch_game()) {
engine_.prepare_for_era_and_mods();
if (engine_.current_level_type() == level::CAMPAIGN ||
engine_.current_level_type() == level::SP_CAMPAIGN) {
@ -232,6 +235,8 @@ void create::process_event()
}
engine_.prepare_for_campaign(difficulty);
} else {
engine_.prepare_for_scenario();
}
engine_.prepare_for_new_level();

View file

@ -412,6 +412,34 @@ void create_engine::prepare_for_new_level()
state_.mp_settings().hash = current_level().data().hash();
}
void create_engine::prepare_for_era_and_mods()
{
state_.classification().era_define =
resources::config_manager->game_config().find_child(
"era", "id", get_parameters().mp_era)["define"].str();
BOOST_FOREACH(const std::string& mod_id, get_parameters().active_mods) {
state_.classification().mod_defines.push_back(
resources::config_manager->game_config().find_child(
"modification", "id", mod_id)["define"].str());
}
}
void create_engine::prepare_for_scenario()
{
DBG_MP << "preparing data for scenario by reloading game config\n";
state_.classification().scenario_define =
current_level().data()["define"].str();
resources::config_manager->
load_game_config_for_game(state_.classification());
current_level().set_data(
resources::config_manager->game_config().find_child(
lexical_cast<std::string> (game_classification::MULTIPLAYER),
"id", current_level().data()["id"]));
}
void create_engine::prepare_for_campaign(const std::string& difficulty)
{
DBG_MP << "preparing data for campaign by reloading game config\n";

View file

@ -180,6 +180,8 @@ public:
void init_generated_level_data();
void prepare_for_new_level();
void prepare_for_era_and_mods();
void prepare_for_scenario();
void prepare_for_campaign(const std::string& difficulty);
void prepare_for_saved_game();

View file

@ -237,6 +237,14 @@ void wait::join_game(bool observe)
const config* campaign = &resources::config_manager->
game_config().find_child("campaign", "id",
level_.child("multiplayer")["mp_campaign"]);
const config* scenario = &resources::config_manager->
game_config().find_child("multiplayer", "id",
level_.child(lexical_cast<std::string>(game_classification::MULTIPLAYER))["id"]);
const config* era = &resources::config_manager->
game_config().find_child("era", "id", level_.child("era")["id"]);
if (*campaign) {
state_.classification().difficulty =
level_.child("multiplayer")["difficulty_define"].str();
@ -246,6 +254,24 @@ void wait::join_game(bool observe)
utils::split((*campaign)["extra_defines"]);
}
if (*scenario)
state_.classification().scenario_define =
(*scenario)["define"].str();
if (*era)
state_.classification().era_define =
(*era)["define"].str();
BOOST_FOREACH(const config& mod, level_.child_range("modification")) {
const config* modification = &resources::config_manager->
game_config().find_child("modification", "id", mod["id"]);
if (*modification) {
state_.classification().mod_defines.push_back(
(*modification)["define"].str());
}
}
// Make sure that we have the same config as host, if possible.
resources::config_manager->
load_game_config_for_game(state_.classification());