tod_manager.cpp

Go to the documentation of this file.
00001 /*
00002    Copyright (C) 2009 - 2012 by Eugen Jiresch
00003    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013  */
00014 
00015 #include "foreach.hpp"
00016 #include "tod_manager.hpp"
00017 #include "wml_exception.hpp"
00018 #include "gettext.hpp"
00019 #include "formula_string_utils.hpp"
00020 #include "gamestatus.hpp"
00021 #include "log.hpp"
00022 #include "map.hpp"
00023 #include "play_controller.hpp"
00024 #include "resources.hpp"
00025 #include "unit.hpp"
00026 #include "unit_abilities.hpp"
00027 
00028 static lg::log_domain log_engine("engine");
00029 #define LOG_NG LOG_STREAM(info, log_engine)
00030 
00031 tod_manager::tod_manager(const config& scenario_cfg, const int num_turns):
00032     savegame_config(),
00033     currentTime_(0),
00034     times_(),
00035     areas_(),
00036     turn_(1),
00037     num_turns_(num_turns)
00038 {
00039     const config::attribute_value& turn_at = scenario_cfg["turn_at"];
00040     if(!turn_at.blank()) {
00041         turn_ = turn_at.to_int(1);
00042     }
00043 
00044     time_of_day::parse_times(scenario_cfg,times_);
00045 
00046     currentTime_ = get_start_ToD(scenario_cfg);
00047     //TODO:
00048     //Very bad, since we're pretending to not modify the cfg. Needed to transfer the result
00049     //to the network clients in a mp game, otherwise we have OOS.
00050     config& non_const_config = const_cast<config&>(scenario_cfg);
00051     non_const_config["current_tod"] = currentTime_;
00052 }
00053 
00054 tod_manager& tod_manager::operator=(const tod_manager& manager)
00055 {
00056     if(this == &manager) {
00057         return *this;
00058     }
00059 
00060     currentTime_ = manager.currentTime_;
00061     times_ = manager.times_;
00062     areas_ = manager.areas_;
00063 
00064     turn_ = manager.turn_;
00065     num_turns_ = manager.num_turns_;
00066 
00067     return *this;
00068 }
00069 
00070 config tod_manager::to_config() const
00071 {
00072     config cfg;
00073     cfg["turn_at"] = turn_;
00074     cfg["turns"] = num_turns_;
00075     cfg["current_tod"] = currentTime_;
00076 
00077     std::vector<time_of_day>::const_iterator t;
00078     for(t = times_.begin(); t != times_.end(); ++t) {
00079         t->write(cfg.add_child("time"));
00080     }
00081     for(std::vector<area_time_of_day>::const_iterator i = areas_.begin(); i != areas_.end(); ++i) {
00082         config& area = cfg.add_child("time_area");
00083         // if no ranges, then use hexes to generate ranges
00084         if(i->xsrc.empty() && i->ysrc.empty()) {
00085             write_location_range(i->hexes, area);
00086         } else {
00087             area["x"] = i->xsrc;
00088             area["y"] = i->ysrc;
00089         }
00090         for(t = i->times.begin(); t != i->times.end(); ++t) {
00091             t->write(area.add_child("time"));
00092         }
00093         area["current_time"] = i->currentTime;
00094     }
00095     return cfg;
00096 }
00097 
00098 const time_of_day& tod_manager::get_previous_time_of_day() const
00099 {
00100     return get_time_of_day_turn(times_, turn_ - 1, currentTime_);
00101 }
00102 
00103 const time_of_day& tod_manager::get_time_of_day(const map_location& loc, int n_turn) const
00104 {
00105     if(n_turn == 0)
00106         n_turn = turn_;
00107 
00108     for (std::vector<area_time_of_day>::const_reverse_iterator
00109          i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i)
00110     {
00111         if (i->hexes.find(loc) != i->hexes.end())
00112             return get_time_of_day_turn(i->times, n_turn, i->currentTime);
00113     }
00114 
00115     return get_time_of_day_turn(times_, n_turn, currentTime_);
00116 }
00117 
00118 const time_of_day tod_manager::get_illuminated_time_of_day(const map_location& loc, int for_turn) const
00119 {
00120     // get ToD ignoring illumination
00121     time_of_day tod = get_time_of_day(loc, for_turn);
00122 
00123     // now add illumination
00124     const gamemap& map = *resources::game_map;
00125     const unit_map& units = *resources::units;
00126     int light_modif =  map.get_terrain_info(map.get_terrain(loc)).light_modification();
00127 
00128     int light = tod.lawful_bonus + light_modif;
00129     int illum_light = light;
00130 
00131     if(loc.valid()) {
00132         map_location locs[7];
00133         locs[0] = loc;
00134         get_adjacent_tiles(loc,locs+1);
00135 
00136         for(int i = 0; i != 7; ++i) {
00137             const unit_map::const_iterator itor = units.find(locs[i]);
00138             if(itor != units.end() &&
00139                 itor->get_ability_bool("illuminates") &&
00140                 !itor->incapacitated())
00141             {
00142                 unit_ability_list illum = itor->get_abilities("illuminates");
00143                 unit_abilities::effect illum_effect(illum, light, false);
00144 
00145                 illum_light = light + illum_effect.get_composite_value();
00146                 //max_value and min_value control the final result
00147                 //unless ToD + terrain effect is stronger
00148                 int max = std::max(light, illum.highest("max_value").first);
00149                 int min = std::min(light, illum.lowest("min_value").first);
00150                 if(illum_light > max) {
00151                     illum_light = max;
00152                 } else if (illum_light < min) {
00153                     illum_light = min;
00154                 }
00155 
00156             }
00157         }
00158     }
00159 
00160     tod.bonus_modified = illum_light - tod.lawful_bonus;
00161     tod.lawful_bonus = illum_light;
00162 
00163     return tod;
00164 }
00165 
00166 
00167 bool tod_manager::is_start_ToD(const std::string& random_start_time)
00168 {
00169     return !random_start_time.empty()
00170         && utils::string_bool(random_start_time, true);
00171 }
00172 
00173 void tod_manager::replace_schedule(const config& time_cfg)
00174 {
00175     times_.clear();
00176     time_of_day::parse_times(time_cfg,times_);
00177     currentTime_ = 0;
00178 }
00179 
00180 void tod_manager::add_time_area(const config& cfg)
00181 {
00182     areas_.push_back(area_time_of_day());
00183     area_time_of_day &area = areas_.back();
00184     area.id = cfg["id"].str();
00185     area.xsrc = cfg["x"].str();
00186     area.ysrc = cfg["y"].str();
00187     area.currentTime = cfg["current_time"].to_int(0);
00188     std::vector<map_location> const& locs = parse_location_range(area.xsrc, area.ysrc, true);
00189     std::copy(locs.begin(), locs.end(), std::inserter(area.hexes, area.hexes.end()));
00190     time_of_day::parse_times(cfg, area.times);
00191 }
00192 
00193 void tod_manager::add_time_area(const std::string& id, const std::set<map_location>& locs,
00194         const config& time_cfg)
00195 {
00196     areas_.push_back(area_time_of_day());
00197     area_time_of_day& area = areas_.back();
00198     area.id = id;
00199     area.hexes = locs;
00200     time_of_day::parse_times(time_cfg, area.times);
00201 }
00202 
00203 void tod_manager::remove_time_area(const std::string& area_id)
00204 {
00205     if(area_id.empty()) {
00206         areas_.clear();
00207     } else {
00208         // search for all time areas that match the id.
00209         std::vector<area_time_of_day>::iterator i = areas_.begin();
00210         while(i != areas_.end()) {
00211             if((*i).id == area_id) {
00212                 i = areas_.erase(i);
00213             } else {
00214                 ++i;
00215             }
00216         }
00217     }
00218 }
00219 
00220 int tod_manager::get_start_ToD(const config &level) const
00221 {
00222     const config::attribute_value& current_tod = level["current_tod"];
00223     if (!current_tod.blank())
00224     {
00225         return calculate_current_time(times_.size(), turn_, current_tod.to_int(0), true);
00226     }
00227 
00228     const int default_result = calculate_current_time(times_.size(), turn_, currentTime_);
00229 
00230     const config::attribute_value& cfg_random_start_time = level["random_start_time"];
00231     if(!cfg_random_start_time.blank()) {
00232         const std::string& random_start_time = cfg_random_start_time.str();
00233         //TODO:
00234         //Here there is danger of OOS (bug #15948)
00235         //But this randomization is needed on the other hand to make the "random start time" option
00236         //in the mp game selection screen work.
00237 
00238         //process the random_start_time string, which can be boolean yes/no true/false or a
00239         //comma-separated string of integers >= 1 referring to the times_ array indices
00240         const std::vector<std::string>& random_start_time_strings = utils::split(random_start_time);
00241         const int random_index = calculate_current_time(random_start_time_strings.size(), turn_, rand(), true);
00242         const int given_current_time = lexical_cast_default<int, std::string>(random_start_time_strings[random_index], 0) - 1;
00243         if(given_current_time >= 0) return calculate_current_time(times_.size(), turn_, given_current_time, true);
00244         if(cfg_random_start_time.to_bool(false)) return calculate_current_time(times_.size(), turn_, rand(), true);
00245     }
00246 
00247     return default_result;
00248 }
00249 
00250 const time_of_day& tod_manager::get_time_of_day_turn(const std::vector<time_of_day>& times, int nturn, const int current_time) const
00251 {
00252     const int time = calculate_current_time(times.size(), nturn, current_time);
00253     return times[time];
00254 }
00255 
00256 void tod_manager::modify_turns(const std::string& mod)
00257 {
00258     num_turns_ = std::max<int>(utils::apply_modifier(num_turns_,mod,0),-1);
00259 }
00260 void tod_manager::set_number_of_turns(int num)
00261 {
00262     num_turns_ = std::max<int>(num, -1);
00263 }
00264 
00265 void tod_manager::set_turn(const int num, const bool increase_limit_if_needed)
00266 {
00267     const int new_turn = std::max<int>(num, 1);
00268     LOG_NG << "changing current turn number from " << turn_ << " to " << new_turn << '\n';
00269     // Correct ToD
00270     set_new_current_times(new_turn);
00271 
00272     if(increase_limit_if_needed && (new_turn > num_turns_) && num_turns_ != -1) {
00273         set_number_of_turns(new_turn);
00274     }
00275     turn_ = new_turn;
00276     resources::state_of_game->get_variable("turn_number") = new_turn;
00277 }
00278 
00279 void tod_manager::set_new_current_times(const int new_current_turn_number)
00280 {
00281     currentTime_ = calculate_current_time(times_.size(), new_current_turn_number, currentTime_);
00282     foreach(area_time_of_day& area, areas_) {
00283         area.currentTime = calculate_current_time(
00284             area.times.size(),
00285             new_current_turn_number,
00286             area.currentTime);
00287     }
00288 }
00289 
00290 int tod_manager::calculate_current_time(
00291     const int number_of_times,
00292     const int for_turn_number,
00293     const int current_time,
00294     const bool only_to_allowed_range) const
00295 {
00296     int new_current_time = 0;
00297     if(only_to_allowed_range) new_current_time = current_time % number_of_times;
00298     else new_current_time = (current_time + for_turn_number - turn_) % number_of_times;
00299     while(new_current_time < 0) { new_current_time += number_of_times; }
00300     return new_current_time;
00301 }
00302 
00303 bool tod_manager::next_turn()
00304 {
00305     set_turn(turn_ + 1, false);
00306     return is_time_left();
00307 }
00308 
00309 
00310 bool tod_manager::is_time_left()
00311 {
00312     return num_turns_ == -1 || turn_ <= num_turns_;
00313 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:12 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs