00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00048
00049
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
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
00121 time_of_day tod = get_time_of_day(loc, for_turn);
00122
00123
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
00147
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
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
00234
00235
00236
00237
00238
00239
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
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 }