00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "global.hpp"
00022 #include "config.hpp"
00023
00024 #include "gamestatus.hpp"
00025
00026 #include "actions.hpp"
00027 #include "filesystem.hpp"
00028 #include "foreach.hpp"
00029 #include "gettext.hpp"
00030 #include "log.hpp"
00031 #include "game_preferences.hpp"
00032 #include "replay.hpp"
00033 #include "resources.hpp"
00034 #include "statistics.hpp"
00035 #include "team.hpp"
00036 #include "unit.hpp"
00037 #include "unit_id.hpp"
00038 #include "wesconfig.h"
00039 #include "wml_exception.hpp"
00040 #include "formula_string_utils.hpp"
00041 #include "map.hpp"
00042 #include "pathfind/pathfind.hpp"
00043 #include "whiteboard/side_actions.hpp"
00044
00045 #include <boost/bind.hpp>
00046
00047 #ifndef _MSC_VER
00048 #include <sys/time.h>
00049 #endif
00050
00051 static lg::log_domain log_engine("engine");
00052 #define ERR_NG LOG_STREAM(err, log_engine)
00053 #define WRN_NG LOG_STREAM(warn, log_engine)
00054 #define LOG_NG LOG_STREAM(info, log_engine)
00055 #define DBG_NG LOG_STREAM(debug, log_engine)
00056
00057 static lg::log_domain log_engine_tc("engine/team_construction");
00058 #define ERR_NG_TC LOG_STREAM(err, log_engine_tc)
00059 #define WRN_NG_TC LOG_STREAM(warn, log_engine_tc)
00060 #define LOG_NG_TC LOG_STREAM(info, log_engine_tc)
00061 #define DBG_NG_TC LOG_STREAM(debug, log_engine_tc)
00062
00063 game_classification::game_classification():
00064 savegame_config(),
00065 label(),
00066 parent(),
00067 version(),
00068 campaign_type(),
00069 campaign_define(),
00070 campaign_xtra_defines(),
00071 campaign(),
00072 history(),
00073 abbrev(),
00074 scenario(),
00075 next_scenario(),
00076 completion(),
00077 end_credits(true),
00078 end_text(),
00079 end_text_duration(),
00080 difficulty("NORMAL")
00081 {}
00082
00083 game_classification::game_classification(const config& cfg):
00084 savegame_config(),
00085 label(cfg["label"]),
00086 parent(cfg["parent"]),
00087 version(cfg["version"]),
00088 campaign_type(cfg["campaign_type"].empty() ? "scenario" : cfg["campaign_type"].str()),
00089 campaign_define(cfg["campaign_define"]),
00090 campaign_xtra_defines(utils::split(cfg["campaign_extra_defines"])),
00091 campaign(cfg["campaign"]),
00092 history(cfg["history"]),
00093 abbrev(cfg["abbrev"]),
00094 scenario(cfg["scenario"]),
00095 next_scenario(cfg["next_scenario"]),
00096 completion(cfg["completion"]),
00097 end_credits(cfg["end_credits"].to_bool(true)),
00098 end_text(cfg["end_text"]),
00099 end_text_duration(cfg["end_text_duration"]),
00100 difficulty(cfg["difficulty"].empty() ? "NORMAL" : cfg["difficulty"].str())
00101 {}
00102
00103 game_classification::game_classification(const game_classification& gc):
00104 savegame_config(),
00105 label(gc.label),
00106 parent(gc.parent),
00107 version(gc.version),
00108 campaign_type(gc.campaign_type),
00109 campaign_define(gc.campaign_define),
00110 campaign_xtra_defines(gc.campaign_xtra_defines),
00111 campaign(gc.campaign),
00112 history(gc.history),
00113 abbrev(gc.abbrev),
00114 scenario(gc.scenario),
00115 next_scenario(gc.next_scenario),
00116 completion(gc.completion),
00117 end_credits(gc.end_credits),
00118 end_text(gc.end_text),
00119 end_text_duration(gc.end_text_duration),
00120 difficulty(gc.difficulty)
00121 {
00122 }
00123
00124 config game_classification::to_config() const
00125 {
00126 config cfg;
00127
00128 cfg["label"] = label;
00129 cfg["parent"] = parent;
00130 cfg["version"] = game_config::version;
00131 cfg["campaign_type"] = campaign_type;
00132 cfg["campaign_define"] = campaign_define;
00133 cfg["campaign_extra_defines"] = utils::join(campaign_xtra_defines);
00134 cfg["campaign"] = campaign;
00135 cfg["history"] = history;
00136 cfg["abbrev"] = abbrev;
00137 cfg["scenario"] = scenario;
00138 cfg["next_scenario"] = next_scenario;
00139 cfg["completion"] = completion;
00140 cfg["end_credits"] = end_credits;
00141 cfg["end_text"] = end_text;
00142 cfg["end_text_duration"] = str_cast<unsigned int>(end_text_duration);
00143 cfg["difficulty"] = difficulty;
00144
00145 return cfg;
00146 }
00147
00148 game_state::game_state() :
00149 scoped_variables(),
00150 wml_menu_items(),
00151 replay_data(),
00152 starting_pos(),
00153 snapshot(),
00154 last_selected(map_location::null_location),
00155 rng_(),
00156 variables_(),
00157 temporaries_(),
00158 generator_setter_(&recorder),
00159 classification_(),
00160 mp_settings_(),
00161 phase_(INITIAL),
00162 can_end_turn_(true)
00163 {}
00164
00165 void write_players(game_state& gamestate, config& cfg, const bool use_snapshot, const bool merge_side)
00166 {
00167
00168
00169 config::child_itors player_cfg = cfg.child_range("player");
00170 if (player_cfg.first != player_cfg.second)
00171 return;
00172
00173 config *source = NULL;
00174 if (use_snapshot) {
00175 source = &gamestate.snapshot;
00176 } else {
00177 source = &gamestate.starting_pos;
00178 }
00179
00180 if (merge_side) {
00181
00182 std::vector<std::string> tags;
00183 tags.push_back("side");
00184 tags.push_back("player");
00185
00186 foreach (const std::string& side_tag, tags)
00187 {
00188 foreach (config &carryover_side, source->child_range(side_tag))
00189 {
00190 config *scenario_side = NULL;
00191
00192
00193 if (config& c = cfg.find_child("side", "save_id", carryover_side["save_id"])) {
00194 scenario_side = &c;
00195 } else if (config& c = cfg.find_child("side", "id", carryover_side["save_id"])) {
00196 scenario_side = &c;
00197 }
00198
00199 if (scenario_side == NULL) {
00200
00201 cfg.add_child("player", carryover_side);
00202 continue;
00203 }
00204
00205
00206
00207
00208 int ngold = (*scenario_side)["gold"].to_int(100);
00209 int player_gold = carryover_side["gold"];
00210 if (carryover_side["gold_add"].to_bool()) {
00211 ngold += player_gold;
00212 } else if (player_gold >= ngold) {
00213 ngold = player_gold;
00214 }
00215 carryover_side["gold"] = str_cast(ngold);
00216 if (const config::attribute_value *v = scenario_side->get("gold_add")) {
00217 carryover_side["gold_add"] = *v;
00218 }
00219
00220 (*scenario_side)["save_id"] = carryover_side["save_id"];
00221 (*scenario_side)["gold"] = ngold;
00222 (*scenario_side)["gold_add"] = carryover_side["gold_add"];
00223 if (const config::attribute_value *v = carryover_side.get("previous_recruits")) {
00224 (*scenario_side)["previous_recruits"] = *v;
00225 } else {
00226 (*scenario_side)["previous_recruits"] = carryover_side["can_recruit"];
00227 }
00228 (*scenario_side)["name"] = carryover_side["name"];
00229 (*scenario_side)["current_player"] = carryover_side["current_player"];
00230
00231 (*scenario_side)["color"] = carryover_side["color"];
00232
00233
00234 foreach (const config &u, carryover_side.child_range("unit")) {
00235 scenario_side->add_child("unit", u);
00236 }
00237 }
00238 }
00239 } else {
00240 foreach(const config &snapshot_side, source->child_range("side")) {
00241
00242 cfg.add_child("player", snapshot_side);
00243 }
00244 }
00245 }
00246
00247 game_state::game_state(const config& cfg, bool show_replay) :
00248 scoped_variables(),
00249 wml_menu_items(),
00250 replay_data(),
00251 starting_pos(),
00252 snapshot(),
00253 last_selected(map_location::null_location),
00254 rng_(cfg),
00255 variables_(),
00256 temporaries_(),
00257 generator_setter_(&recorder),
00258 classification_(cfg),
00259 mp_settings_(cfg),
00260 phase_(INITIAL),
00261 can_end_turn_(true)
00262 {
00263 n_unit::id_manager::instance().set_save_id(cfg["next_underlying_unit_id"]);
00264 log_scope("read_game");
00265
00266 const config &snapshot = cfg.child("snapshot");
00267 const config &replay_start = cfg.child("replay_start");
00268
00269 bool load_snapshot = !show_replay && snapshot && !snapshot.empty();
00270
00271 if (load_snapshot) {
00272 this->snapshot = snapshot;
00273
00274 rng_.seed_random(snapshot["random_calls"]);
00275 } else {
00276 assert(replay_start);
00277 }
00278
00279 can_end_turn_ = cfg["can_end_turn"].to_bool(true);
00280
00281 LOG_NG << "scenario: '" << classification_.scenario << "'\n";
00282 LOG_NG << "next_scenario: '" << classification_.next_scenario << "'\n";
00283
00284
00285
00286 if (load_snapshot) {
00287 if (const config &vars = snapshot.child("variables")) {
00288 set_variables(vars);
00289 } else if (const config &vars = cfg.child("variables")) {
00290 set_variables(vars);
00291 }
00292 }
00293 else if (const config &vars = replay_start.child("variables")) {
00294 set_variables(vars);
00295 }
00296 else if (const config &vars = cfg.child("variables")) {
00297 set_variables(vars);
00298 }
00299 set_menu_items(cfg.child_range("menu_item"));
00300
00301 if (const config &replay = cfg.child("replay")) {
00302 replay_data = replay;
00303 }
00304
00305 if (replay_start) {
00306 starting_pos = replay_start;
00307
00308
00309
00310
00311
00312
00313 if(!starting_pos.empty()) {
00314 foreach (const config &p, cfg.child_range("player")) {
00315 config& cfg_player = starting_pos.add_child("player");
00316 cfg_player.merge_with(p);
00317 }
00318 }
00319 }
00320
00321 if (const config &stats = cfg.child("statistics")) {
00322 statistics::fresh_stats();
00323 statistics::read_stats(stats);
00324 }
00325 }
00326
00327 void game_state::write_snapshot(config& cfg) const
00328 {
00329 log_scope("write_game");
00330 cfg["label"] = classification_.label;
00331 cfg["history"] = classification_.history;
00332 cfg["abbrev"] = classification_.abbrev;
00333 cfg["version"] = game_config::version;
00334
00335 cfg["scenario"] = classification_.scenario;
00336 cfg["next_scenario"] = classification_.next_scenario;
00337
00338 cfg["completion"] = classification_.completion;
00339
00340 cfg["campaign"] = classification_.campaign;
00341 cfg["campaign_type"] = classification_.campaign_type;
00342 cfg["difficulty"] = classification_.difficulty;
00343
00344 cfg["campaign_define"] = classification_.campaign_define;
00345 cfg["campaign_extra_defines"] = utils::join(classification_.campaign_xtra_defines);
00346 cfg["next_underlying_unit_id"] = str_cast(n_unit::id_manager::instance().get_save_id());
00347 cfg["can_end_turn"] = can_end_turn_;
00348
00349 cfg["random_seed"] = rng_.get_random_seed();
00350 cfg["random_calls"] = rng_.get_random_calls();
00351
00352 cfg["end_credits"] = classification_.end_credits;
00353 cfg["end_text"] = classification_.end_text;
00354 cfg["end_text_duration"] = str_cast<unsigned int>(classification_.end_text_duration);
00355
00356 cfg.add_child("variables", variables_);
00357
00358 for(std::map<std::string, wml_menu_item *>::const_iterator j=wml_menu_items.begin();
00359 j!=wml_menu_items.end(); ++j) {
00360 config new_cfg;
00361 new_cfg["id"]=j->first;
00362 new_cfg["image"]=j->second->image;
00363 new_cfg["description"]=j->second->description;
00364 new_cfg["needs_select"] = j->second->needs_select;
00365 if(!j->second->show_if.empty())
00366 new_cfg.add_child("show_if", j->second->show_if);
00367 if(!j->second->filter_location.empty())
00368 new_cfg.add_child("filter_location", j->second->filter_location);
00369 if(!j->second->command.empty())
00370 new_cfg.add_child("command", j->second->command);
00371 cfg.add_child("menu_item", new_cfg);
00372 }
00373 }
00374
00375 void extract_summary_from_config(config& cfg_save, config& cfg_summary)
00376 {
00377 const config &cfg_snapshot = cfg_save.child("snapshot");
00378 const config &cfg_replay_start = cfg_save.child("replay_start");
00379
00380 const config &cfg_replay = cfg_save.child("replay");
00381 const bool has_replay = cfg_replay && !cfg_replay.empty();
00382 const bool has_snapshot = cfg_snapshot && cfg_snapshot.child("side");
00383
00384 cfg_summary["replay"] = has_replay;
00385 cfg_summary["snapshot"] = has_snapshot;
00386
00387 cfg_summary["label"] = cfg_save["label"];
00388 cfg_summary["parent"] = cfg_save["parent"];
00389 cfg_summary["campaign_type"] = cfg_save["campaign_type"];
00390 cfg_summary["scenario"] = cfg_save["scenario"];
00391 cfg_summary["campaign"] = cfg_save["campaign"];
00392 cfg_summary["difficulty"] = cfg_save["difficulty"];
00393 cfg_summary["version"] = cfg_save["version"];
00394 cfg_summary["corrupt"] = "";
00395
00396 if(has_snapshot) {
00397 cfg_summary["turn"] = cfg_snapshot["turn_at"];
00398 if (cfg_snapshot["turns"] != "-1") {
00399 cfg_summary["turn"] = cfg_summary["turn"].str() + "/" + cfg_snapshot["turns"].str();
00400 }
00401 }
00402
00403
00404
00405
00406 std::string leader;
00407 std::string leader_image;
00408
00409
00410
00411
00412
00413
00414
00415
00416 bool shrouded = false;
00417
00418
00419
00420 if (const config &snapshot = *(has_snapshot ? &cfg_snapshot : &cfg_replay_start))
00421 {
00422 foreach (const config &side, snapshot.child_range("side"))
00423 {
00424 if (side["controller"] != "human") {
00425 continue;
00426 }
00427
00428 if (side["shroud"].to_bool()) {
00429 shrouded = true;
00430 }
00431
00432 if (side["canrecruit"].to_bool())
00433 {
00434 leader = side["id"].str();
00435 leader_image = side["image"].str();
00436 break;
00437 }
00438
00439 foreach (const config &u, side.child_range("unit"))
00440 {
00441 if (u["canrecruit"].to_bool()) {
00442 leader = u["id"].str();
00443 leader_image = u["image"].str();
00444 break;
00445 }
00446 }
00447 }
00448 }
00449
00450
00451 cfg_summary["leader"] = leader;
00452
00453
00454
00455 cfg_summary["leader_image"] = get_independent_image_path(leader_image);
00456
00457 if(!shrouded) {
00458 if(has_snapshot) {
00459 if (!cfg_snapshot.find_child("side", "shroud", "yes")) {
00460 cfg_summary.add_child("map", cfg_snapshot.child_or_empty("map"));
00461 }
00462 } else if(has_replay) {
00463 if (!cfg_replay_start.find_child("side","shroud","yes")) {
00464 cfg_summary.add_child("map", cfg_replay_start.child_or_empty("map"));
00465 }
00466 }
00467 }
00468 }
00469
00470 config::attribute_value &game_state::get_variable(const std::string& key)
00471 {
00472 return variable_info(key, true, variable_info::TYPE_SCALAR).as_scalar();
00473 }
00474
00475 config::attribute_value game_state::get_variable_const(const std::string &key) const
00476 {
00477 variable_info to_get(key, false, variable_info::TYPE_SCALAR);
00478 if (!to_get.is_valid)
00479 {
00480 config::attribute_value &to_return = temporaries_[key];
00481 if (key.size() > 7 && key.substr(key.size() - 7) == ".length") {
00482
00483 to_return = 0;
00484 }
00485 return to_return;
00486 }
00487 return to_get.as_scalar();
00488 }
00489
00490 config& game_state::get_variable_cfg(const std::string& key)
00491 {
00492 return variable_info(key, true, variable_info::TYPE_CONTAINER).as_container();
00493 }
00494
00495 void game_state::set_variable(const std::string& key, const t_string& value)
00496 {
00497 get_variable(key) = value;
00498 }
00499
00500 config& game_state::add_variable_cfg(const std::string& key, const config& value)
00501 {
00502 variable_info to_add(key, true, variable_info::TYPE_ARRAY);
00503 return to_add.vars->add_child(to_add.key, value);
00504 }
00505
00506 void game_state::clear_variable_cfg(const std::string& varname)
00507 {
00508 variable_info to_clear(varname, false, variable_info::TYPE_CONTAINER);
00509 if(!to_clear.is_valid) return;
00510 if(to_clear.explicit_index) {
00511 to_clear.vars->remove_child(to_clear.key, to_clear.index);
00512 } else {
00513 to_clear.vars->clear_children(to_clear.key);
00514 }
00515 }
00516
00517 void game_state::clear_variable(const std::string& varname)
00518 {
00519 variable_info to_clear(varname, false);
00520 if(!to_clear.is_valid) return;
00521 if(to_clear.explicit_index) {
00522 to_clear.vars->remove_child(to_clear.key, to_clear.index);
00523 } else {
00524 to_clear.vars->clear_children(to_clear.key);
00525 to_clear.vars->remove_attribute(to_clear.key);
00526 }
00527 }
00528
00529 static void clear_wmi(std::map<std::string, wml_menu_item *> &gs_wmi)
00530 {
00531 for (std::map<std::string, wml_menu_item *>::iterator i = gs_wmi.begin(),
00532 i_end = gs_wmi.end(); i != i_end; ++i)
00533 {
00534 delete i->second;
00535 }
00536 gs_wmi.clear();
00537 }
00538
00539 game_state::game_state(const game_state& state) :
00540 variable_set(),
00541 scoped_variables(state.scoped_variables),
00542 wml_menu_items(),
00543 replay_data(state.replay_data),
00544 starting_pos(state.starting_pos),
00545 snapshot(state.snapshot),
00546 last_selected(state.last_selected),
00547 rng_(state.rng_),
00548 variables_(state.variables_),
00549 temporaries_(),
00550 generator_setter_(state.generator_setter_),
00551 classification_(state.classification_),
00552 mp_settings_(state.mp_settings_),
00553 phase_(state.phase_),
00554 can_end_turn_(state.can_end_turn_)
00555 {
00556 clear_wmi(wml_menu_items);
00557 std::map<std::string, wml_menu_item*>::const_iterator itor;
00558 for (itor = state.wml_menu_items.begin(); itor != state.wml_menu_items.end(); ++itor) {
00559 wml_menu_item*& mref = wml_menu_items[itor->first];
00560 mref = new wml_menu_item(*(itor->second));
00561 }
00562 }
00563
00564 game_state& game_state::operator=(const game_state& state)
00565 {
00566
00567 if (this != &state) {
00568 this->~game_state();
00569 new (this) game_state(state) ;
00570 }
00571 return *this ;
00572 }
00573
00574 game_state::~game_state() {
00575 clear_wmi(wml_menu_items);
00576 }
00577
00578 void game_state::set_variables(const config& vars) {
00579 variables_ = vars;
00580 }
00581
00582
00583 class team_builder {
00584 public:
00585 team_builder(const config& side_cfg,
00586 const std::string &save_id, std::vector<team>& teams,
00587 const config& level, gamemap& map, unit_map& units,
00588 bool snapshot, const config &starting_pos)
00589 : gold_info_ngold_(0)
00590 , gold_info_add_(false)
00591 , leader_configs_()
00592 , level_(level)
00593 , map_(map)
00594 , player_cfg_(NULL)
00595 , player_exists_(false)
00596 , save_id_(save_id)
00597 , seen_ids_()
00598 , side_(0)
00599 , side_cfg_(side_cfg)
00600 , snapshot_(snapshot)
00601 , starting_pos_(starting_pos)
00602 , t_(NULL)
00603 , teams_(teams)
00604 , unit_configs_()
00605 , units_(units)
00606 {
00607 }
00608
00609 void build_team_stage_one()
00610 {
00611
00612 init();
00613
00614
00615 gold();
00616
00617
00618 new_team();
00619
00620 assert(t_!=NULL);
00621
00622
00623 objectives();
00624
00625
00626 previous_recruits();
00627
00628
00629 leader();
00630
00631
00632 prepare_units();
00633
00634 }
00635
00636
00637 void build_team_stage_two()
00638 {
00639
00640
00641 place_units();
00642
00643 }
00644
00645 protected:
00646
00647 static const std::string default_gold_qty_;
00648
00649 int gold_info_ngold_;
00650 bool gold_info_add_;
00651 std::deque<config> leader_configs_;
00652 const config &level_;
00653 gamemap &map_;
00654 const config *player_cfg_;
00655 bool player_exists_;
00656 const std::string save_id_;
00657 std::set<std::string> seen_ids_;
00658 int side_;
00659 const config &side_cfg_;
00660 bool snapshot_;
00661 const config &starting_pos_;
00662 team *t_;
00663 std::vector<team> &teams_;
00664 std::vector<const config*> unit_configs_;
00665 unit_map &units_;
00666
00667
00668 void log_step(const char *s) const
00669 {
00670 LOG_NG_TC << "team "<<side_<<" construction: "<< s << std::endl;
00671 }
00672
00673
00674 void init()
00675 {
00676 side_ = side_cfg_["side"].to_int(1);
00677 if (unsigned(side_ - 1) >= teams_.size() || teams_[side_ - 1].side() != 0)
00678 throw config::error("Invalid side number.");
00679 t_ = &teams_[side_ - 1];
00680
00681 log_step("init");
00682
00683 player_cfg_ = NULL;
00684
00685 player_exists_ = false;
00686
00687 if(map_.empty()) {
00688 throw game::load_game_failed("Map not found");
00689 }
00690
00691 if(side_cfg_["controller"] == "human" ||
00692 side_cfg_["controller"] == "network" ||
00693 side_cfg_["controller"] == "network_ai" ||
00694 side_cfg_["controller"] == "human_ai" ||
00695 side_cfg_["persistent"].to_bool())
00696 {
00697 player_exists_ = true;
00698
00699
00700
00701
00702 if (snapshot_) {
00703 if (const config &c = level_.find_child("player","save_id",save_id_)) {
00704 player_cfg_ = &c;
00705 }
00706 } else {
00707
00708 if (const config &c = starting_pos_.find_child("player","save_id",save_id_)) {
00709 player_cfg_ = &c;
00710 } else if (const config &c = starting_pos_.find_child("side","save_id",save_id_)) {
00711 player_cfg_ = &c;
00712 player_exists_ = false;
00713 } else {
00714 player_cfg_ = NULL;
00715 player_exists_ = false;
00716 }
00717 }
00718 }
00719
00720 DBG_NG_TC << "save id: "<< save_id_ <<std::endl;
00721 DBG_NG_TC << "snapshot: "<< (player_exists_ ? "true" : "false") <<std::endl;
00722 DBG_NG_TC << "player_cfg: "<< (player_cfg_==NULL ? "is null" : "is not null") <<std::endl;
00723 DBG_NG_TC << "player_exists: "<< (player_exists_ ? "true" : "false") <<std::endl;
00724
00725 unit_configs_.clear();
00726 seen_ids_.clear();
00727
00728 }
00729
00730 bool use_player_cfg() const
00731 {
00732 return (player_cfg_ != NULL) && (!snapshot_);
00733 }
00734
00735 void gold()
00736 {
00737 log_step("gold");
00738
00739 std::string gold = side_cfg_["gold"];
00740 if(gold.empty()) {
00741 gold = default_gold_qty_;
00742 }
00743
00744 DBG_NG_TC << "found gold: '" << gold << "'\n";
00745
00746 gold_info_ngold_ = lexical_cast_default<int>(gold);
00747
00748
00749
00750
00751
00752
00753
00754
00755 gold_info_add_ = side_cfg_["gold_add"].to_bool();
00756
00757 if (use_player_cfg()) {
00758 try {
00759 int player_gold = (*player_cfg_)["gold"];
00760 if (!player_exists_) {
00761
00762 gold_info_ngold_ = player_gold;
00763 gold_info_add_ = (*player_cfg_)["gold_add"].to_bool();
00764 } else if ((*player_cfg_)["gold_add"].to_bool()) {
00765 gold_info_ngold_ += player_gold;
00766 gold_info_add_ = true;
00767 } else if(player_gold >= gold_info_ngold_) {
00768 gold_info_ngold_ = player_gold;
00769 }
00770 } catch (config::error&) {
00771 ERR_NG_TC << "player tag for " << save_id_ << " does not have gold information\n";
00772 }
00773 }
00774
00775 DBG_NG_TC << "set gold to '" << gold_info_ngold_ << "'\n";
00776 DBG_NG_TC << "set gold add flag to '" << gold_info_add_ << "'\n";
00777 }
00778
00779
00780 void new_team()
00781 {
00782 log_step("new team");
00783 t_->build(side_cfg_, map_, gold_info_ngold_);
00784 t_->set_gold_add(gold_info_add_);
00785 }
00786
00787
00788 void objectives()
00789 {
00790 log_step("objectives");
00791
00792
00793 if (t_->objectives().empty())
00794 t_->set_objectives(level_["objectives"], false);
00795 }
00796
00797
00798 void previous_recruits()
00799 {
00800 log_step("previous recruits");
00801
00802
00803 if (!player_cfg_) return;
00804 if (const config::attribute_value *v = player_cfg_->get("previous_recruits")) {
00805 foreach (const std::string &rec, utils::split(*v)) {
00806 DBG_NG_TC << "adding previous recruit: " << rec << '\n';
00807 t_->add_recruit(rec);
00808 }
00809 }
00810 }
00811
00812
00813
00814
00815 void handle_unit(const config &u, const char *origin)
00816 {
00817 DBG_NG_TC
00818 << "unit from "<<origin
00819 << ": type=["<<u["type"]
00820 << "] id=["<<u["id"]
00821 << "] placement=["<<u["placement"]
00822 << "] x=["<<u["x"]
00823 << "] y=["<<u["y"]
00824 <<"]"<< std::endl;
00825 const std::string &id = u["id"];
00826 if (!id.empty()) {
00827 if ( seen_ids_.find(id)!=seen_ids_.end() ) {
00828
00829 config u_tmp = u;
00830 u_tmp["side"] = str_cast(side_);
00831 unit new_unit(u_tmp, true);
00832 t_->recall_list().push_back(new_unit);
00833 } else {
00834
00835 unit_configs_.push_back(&u);
00836 seen_ids_.insert(id);
00837 }
00838
00839 } else {
00840 unit_configs_.push_back(&u);
00841 }
00842 }
00843
00844 void handle_leader(const config &leader)
00845 {
00846 leader_configs_.push_back(leader);
00847
00848 config::attribute_value &a1 = leader_configs_.back()["canrecruit"];
00849 if (a1.blank()) a1 = true;
00850 config::attribute_value &a2 = leader_configs_.back()["placement"];
00851 if (a2.blank()) a2 = "map,leader";
00852
00853 handle_unit(leader_configs_.back(), "leader_cfg");
00854 }
00855
00856 void leader()
00857 {
00858 log_step("leader");
00859
00860
00861
00862
00863
00864
00865 if (!side_cfg_["no_leader"].to_bool() && side_cfg_["controller"] != "null") {
00866 if (side_cfg_["type"] == "random") {
00867 std::vector<std::string> types = utils::split(side_cfg_["random_leader"]);
00868 if (types.empty())
00869 types = utils::split(side_cfg_["leader"]);
00870 if (types.empty()) {
00871 utils::string_map i18n_symbols;
00872 i18n_symbols["faction"] = side_cfg_["name"];
00873 throw config::error(vgettext("Unable to find a leader type for faction $faction", i18n_symbols));
00874 }
00875 const int choice = rand() % types.size();
00876 config leader = side_cfg_;
00877 leader["type"] = types[choice];
00878 handle_leader(leader);
00879 } else
00880 handle_leader(side_cfg_);
00881 }
00882 foreach (const config &l, side_cfg_.child_range("leader")) {
00883 handle_leader(l);
00884 }
00885 }
00886
00887
00888 void prepare_units()
00889 {
00890 log_step("prepare units");
00891 if (use_player_cfg()) {
00892
00893
00894
00895
00896 foreach(const config &u, (*player_cfg_).child_range("unit")) {
00897 handle_unit(u,"player_cfg");
00898 }
00899
00900 } else {
00901
00902 foreach (const config &su, side_cfg_.child_range("unit")) {
00903 handle_unit(su, "side_cfg");
00904 }
00905 }
00906 }
00907
00908
00909 void place_units()
00910 {
00911 static char const *side_attrs[] = {
00912 "income", "team_name", "user_team_name", "save_id",
00913 "current_player", "countdown_time", "action_bonus_count",
00914 "flag", "flag_icon", "objectives", "objectives_changed",
00915 "disallow_observers", "allow_player", "no_leader",
00916 "hidden", "music", "color", "ai_config", "gold",
00917 "start_gold", "team_rgb", "village_gold", "recall_cost",
00918 "controller", "persistent", "share_view",
00919 "share_maps", "recruit", "fog", "shroud", "shroud_data",
00920 "scroll_to_leader",
00921
00922 "income_lock", "gold_lock", "color_lock", "team_lock", "leader",
00923 "random_leader", "terrain_liked",
00924 "allow_changes", "faction_name", "user_description", "faction" };
00925
00926 log_step("place units");
00927 foreach (const config *u, unit_configs_) {
00928 unit_creator uc(*t_,map_.starting_position(side_));
00929 uc
00930 .allow_add_to_recall(true)
00931 .allow_discover(true)
00932 .allow_get_village(true)
00933 .allow_invalidate(false)
00934 .allow_rename_side(true)
00935 .allow_show(false);
00936
00937 config cfg = *u;
00938 foreach (const char *attr, side_attrs) {
00939 cfg.remove_attribute(attr);
00940 }
00941 uc.add_unit(cfg);
00942
00943 }
00944
00945
00946 unit_map::iterator u = resources::units->find_first_leader(t_->side());
00947 if ((u != resources::units->end()) && t_->current_player().empty())
00948 t_->set_current_player(u->name());
00949
00950 }
00951
00952 };
00953
00954 const std::string team_builder::default_gold_qty_ = "100";
00955
00956
00957 team_builder_ptr game_state::create_team_builder(const config& side_cfg,
00958 std::string save_id, std::vector<team>& teams,
00959 const config& level, gamemap& map, unit_map& units,
00960 bool snapshot)
00961 {
00962 return team_builder_ptr(new team_builder(side_cfg,save_id,teams,level,map,units,snapshot,starting_pos));
00963 }
00964
00965 void game_state::build_team_stage_one(team_builder_ptr tb_ptr)
00966 {
00967 tb_ptr->build_team_stage_one();
00968 }
00969
00970 void game_state::build_team_stage_two(team_builder_ptr tb_ptr)
00971 {
00972 tb_ptr->build_team_stage_two();
00973 }
00974
00975 void game_state::set_menu_items(const config::const_child_itors &menu_items)
00976 {
00977 clear_wmi(wml_menu_items);
00978 foreach (const config &item, menu_items)
00979 {
00980 std::string id = item["id"];
00981 wml_menu_item*& mref = wml_menu_items[id];
00982 if(mref == NULL) {
00983 mref = new wml_menu_item(id, &item);
00984 } else {
00985 WRN_NG << "duplicate menu item (" << id << ") while loading gamestate\n";
00986 }
00987 }
00988 }
00989
00990 void game_state::write_config(config_writer& out, bool write_variables) const
00991 {
00992 out.write(classification_.to_config());
00993 if (classification_.campaign_type == "multiplayer")
00994 out.write_child("multiplayer", mp_settings_.to_config());
00995 out.write_key_val("random_seed", lexical_cast<std::string>(rng_.get_random_seed()));
00996 out.write_key_val("random_calls", lexical_cast<std::string>(rng_.get_random_calls()));
00997 if (write_variables) {
00998 out.write_child("variables", variables_);
00999 }
01000
01001 for(std::map<std::string, wml_menu_item *>::const_iterator j = wml_menu_items.begin();
01002 j != wml_menu_items.end(); ++j) {
01003 out.open_child("menu_item");
01004 out.write_key_val("id", j->first);
01005 out.write_key_val("image", j->second->image);
01006 out.write_key_val("description", j->second->description);
01007 out.write_key_val("needs_select", (j->second->needs_select) ? "yes" : "no");
01008 if(!j->second->show_if.empty())
01009 out.write_child("show_if", j->second->show_if);
01010 if(!j->second->filter_location.empty())
01011 out.write_child("filter_location", j->second->filter_location);
01012 if(!j->second->command.empty())
01013 out.write_child("command", j->second->command);
01014 out.close_child("menu_item");
01015 }
01016
01017 if (!replay_data.child("replay")) {
01018 out.write_child("replay", replay_data);
01019 }
01020
01021 out.write_child("replay_start",starting_pos);
01022 }
01023
01024 wml_menu_item::wml_menu_item(const std::string& id, const config* cfg) :
01025 name(),
01026 event_id(id),
01027 image(),
01028 description(),
01029 needs_select(false),
01030 show_if(),
01031 filter_location(),
01032 command()
01033
01034 {
01035 std::stringstream temp;
01036 temp << "menu item";
01037 if(!id.empty()) {
01038 temp << ' ' << id;
01039 }
01040 name = temp.str();
01041 if(cfg != NULL) {
01042 image = (*cfg)["image"].str();
01043 description = (*cfg)["description"];
01044 needs_select = (*cfg)["needs_select"].to_bool();
01045 if (const config &c = cfg->child("show_if")) show_if = c;
01046 if (const config &c = cfg->child("filter_location")) filter_location = c;
01047 if (const config &c = cfg->child("command")) command = c;
01048 }
01049 }