Skip to content

Commit

Permalink
support [time_area] with no specific time schedule
Browse files Browse the repository at this point in the history
now the c++ code does no longer add a dummy time when
there are no times defines for an [time_area]. this is
in particular useful when one wants to define areas in
the map editor that is then used ingame for example in
filters.
We should consider renamaing [time_area] to just [area]
[time_area]s that don't define their own times schedule
are now ignored during tod calculation.
  • Loading branch information
gfgtdf committed Feb 21, 2020
1 parent b72ec6e commit ebbecb3
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 76 deletions.
15 changes: 0 additions & 15 deletions src/play_controller.cpp
Expand Up @@ -722,21 +722,6 @@ const team& play_controller::current_team() const
return gamestate().board_.get_team(current_side());
}

/// @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
static int modulo(int num, int mod, int min)
{
assert(mod > 0);
int n = (num - min) % mod;
if (n < 0)
n += mod;
//n is now in [0, mod)
n = n + min;
return n;
// the following properties are easy to verify:
// 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
// 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
}

bool play_controller::is_team_visible(int team_num, bool observer) const
{
const team& t = gamestate().board_.get_team(team_num);
Expand Down
5 changes: 5 additions & 0 deletions src/scripting/game_lua_kernel.cpp
Expand Up @@ -3788,6 +3788,11 @@ int game_lua_kernel::intf_set_time_of_day(lua_State * L)
return luaL_argerror(L, 1, "invalid time of day ID");
}
}

if(new_time == 0 && num_times == 0) {
//ignore this case, because we don't want code like set_current_time(get_current_time()) to fail if num_times is 0.
return 0;
}
if(new_time < 0 || new_time >= num_times) {
return luaL_argerror(L, 1, "invalid time of day index");
}
Expand Down
6 changes: 0 additions & 6 deletions src/time_of_day.cpp
Expand Up @@ -72,10 +72,4 @@ void time_of_day::parse_times(const config& cfg, std::vector<time_of_day>& times
for(const config &t : cfg.child_range("time")) {
times.push_back(time_of_day(t));
}

if(times.empty())
{
// Make sure we have at least default time
times.push_back(time_of_day());
}
}
115 changes: 66 additions & 49 deletions src/tod_manager.cpp
Expand Up @@ -57,8 +57,8 @@ tod_manager::tod_manager(const config& scenario_cfg):
liminal_bonus_ = scenario_cfg["liminal_bonus"].to_int(liminal_bonus_);
has_cfg_liminal_bonus_ = true;
}
//We need to call parse_times before calculate_current_time because otherwise the first parameter will always be 0.
currentTime_ = calculate_current_time(times_.size(), turn_, scenario_cfg["current_time"].to_int(0), true);
//We need to call parse_times before fix_time_index because otherwise the first parameter will always be 0.
currentTime_ = fix_time_index(times_.size(), scenario_cfg["current_time"].to_int(0));

}

Expand Down Expand Up @@ -117,12 +117,12 @@ void tod_manager::resolve_random(randomness::rng& r)
if(!output.empty())
{
int chosen = output[r.next_random() % output.size()];
currentTime_ = calculate_current_time(times_.size(), turn_, chosen, true);
currentTime_ = fix_time_index(times_.size(), chosen);
r.next_random();
}
else if (random_tod_.to_bool(false))
{
currentTime_ = calculate_current_time(times_.size(), turn_, r.next_random(), true);
currentTime_ = fix_time_index(times_.size(), r.next_random());
}
random_tod_ = false;
}
Expand All @@ -138,10 +138,7 @@ config tod_manager::to_config() const
cfg["liminal_bonus"] = liminal_bonus_;

for(const time_of_day& tod : times_) {
// Don't write the stub default ToD if it happens to be present.
if(tod.id != "nulltod") {
tod.write(cfg.add_child("time"));
}
tod.write(cfg.add_child("time"));
}

for(const area_time_of_day& a_tod : areas_) {
Expand Down Expand Up @@ -172,6 +169,12 @@ config tod_manager::to_config() const
return cfg;
}

static const time_of_day& dummytime()
{
static time_of_day* pdummy = new time_of_day();
return *pdummy;
}

const time_of_day& tod_manager::get_previous_time_of_day() const
{
return get_time_of_day_turn(times_, turn_ - 1, currentTime_);
Expand Down Expand Up @@ -202,7 +205,7 @@ const std::vector<time_of_day>& tod_manager::times(const map_location& loc) cons
for ( std::vector<area_time_of_day>::const_reverse_iterator
i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
{
if (i->hexes.find(loc) != i->hexes.end())
if (i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
return i->times;
}
}
Expand All @@ -220,7 +223,7 @@ const time_of_day& tod_manager::get_time_of_day(const map_location& loc, int n_t
for ( std::vector<area_time_of_day>::const_reverse_iterator
i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
{
if (i->hexes.find(loc) != i->hexes.end())
if (i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
return get_time_of_day_turn(i->times, n_turn, i->currentTime);
}
}
Expand Down Expand Up @@ -299,32 +302,23 @@ bool tod_manager::is_start_ToD(const std::string& random_start_time)

void tod_manager::replace_schedule(const config& time_cfg)
{
int bonus = times_[currentTime_].lawful_bonus;
times_.clear();
time_of_day::parse_times(time_cfg,times_);
currentTime_ = time_cfg["current_time"].to_int(0);
if (bonus != times_[currentTime_].lawful_bonus) {
has_tod_bonus_changed_ = true;
}
std::vector<time_of_day> new_scedule;
time_of_day::parse_times(time_cfg, new_scedule);
replace_schedule(new_scedule);
}

void tod_manager::replace_schedule(const std::vector<time_of_day>& schedule)
{
int bonus = times_[currentTime_].lawful_bonus;
times_ = schedule;

if(schedule.empty()) {
// Make sure that there is at least one ToD
times_.emplace_back();
if(times_.empty() || schedule.empty() || times_[currentTime_].lawful_bonus != schedule.front().lawful_bonus) {
has_tod_bonus_changed_ = true;
}

times_ = schedule;
currentTime_ = 0;
if (bonus != times_[currentTime_].lawful_bonus) {
has_tod_bonus_changed_ = true;
}
}

void tod_manager::replace_area_locations(int area_index, const std::set<map_location>& locs) {
void tod_manager::replace_area_locations(int area_index, const std::set<map_location>& locs)
{
assert(area_index < static_cast<int>(areas_.size()));
areas_[area_index].hexes = locs;
has_tod_bonus_changed_ = true;
Expand All @@ -334,12 +328,20 @@ void tod_manager::replace_local_schedule(const std::vector<time_of_day>& schedul
{
assert(area_index < static_cast<int>(areas_.size()));
area_time_of_day& area = areas_[area_index];
int bonus = area.times[area.currentTime].lawful_bonus;
area.times = schedule;
area.currentTime = 0;
if (bonus != area.times[area.currentTime].lawful_bonus) {

if(area.times.empty() || schedule.empty())
{
//If one of those is empty then their 'prievious' time of day might depend on other areas_,
//its better to just assume the illimination has changes than to do the explicit computation.
has_tod_bonus_changed_ = true;
}
else if(area.times[area.currentTime].lawful_bonus != schedule.front().lawful_bonus)
{
// the current illimination on these tiles has changes.
has_tod_bonus_changed_ = true;
}
area.times = schedule;
area.currentTime = 0;
}

void tod_manager::set_area_id(int area_index, const std::string& id) {
Expand Down Expand Up @@ -424,7 +426,10 @@ void tod_manager::remove_time_area(int area_index)

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
{
const int time = calculate_current_time(times.size(), nturn, current_time);
if(times.empty()) {
return dummytime();
}
const int time = calculate_time_index_at_turn(times.size(), nturn, current_time);
return times[time];
}

Expand Down Expand Up @@ -484,52 +489,64 @@ void tod_manager::set_turn_by_wml(const int num, game_data* vars, const bool inc
set_turn(num, vars, increase_limit_if_needed);
update_server_information();
}

void tod_manager::set_new_current_times(const int new_current_turn_number)
{
set_current_time(calculate_current_time(times_.size(), new_current_turn_number, currentTime_));
set_current_time(calculate_time_index_at_turn(times_.size(), new_current_turn_number, currentTime_));
for (area_time_of_day& area : areas_) {
set_current_time(calculate_current_time(
set_current_time(calculate_time_index_at_turn(
area.times.size(),
new_current_turn_number,
area.currentTime),
area);
}
}

int tod_manager::calculate_current_time(
const int number_of_times,
const int for_turn_number,
const int current_time,
const bool only_to_allowed_range) const
int tod_manager::fix_time_index(
int number_of_times,
int time)
{
if (number_of_times == 0) return 0;
int new_current_time = 0;
if(only_to_allowed_range) new_current_time = current_time % number_of_times;
else new_current_time = (current_time + for_turn_number - turn_) % number_of_times;
while(new_current_time < 0) { new_current_time += number_of_times; }
return new_current_time;
return modulo(time, number_of_times);
}

void tod_manager::set_current_time(int time) {
if (times_[time].lawful_bonus != times_[currentTime_].lawful_bonus) {
int tod_manager::calculate_time_index_at_turn(
int number_of_times,
int for_turn_number,
int current_time) const
{
if (number_of_times == 0) return 0;
return modulo(current_time + for_turn_number - turn_, number_of_times);
}

void tod_manager::set_current_time(int time)
{
if (!times_.empty() && times_[time].lawful_bonus != times_[currentTime_].lawful_bonus) {
has_tod_bonus_changed_ = true;
}
currentTime_ = time;
}

void tod_manager::set_current_time(int time, int area_index) {
void tod_manager::set_current_time(int time, int area_index)
{
assert(area_index < static_cast<int>(areas_.size()));
set_current_time(time, areas_[area_index]);
}

void tod_manager::set_current_time(int time, const std::string& area_id) {
void tod_manager::set_current_time(int time, const std::string& area_id)
{
for (area_time_of_day& area : areas_) {
if (area.id == area_id)
set_current_time(time, area);
}
}

void tod_manager::set_current_time(int time, area_time_of_day& area) {
void tod_manager::set_current_time(int time, area_time_of_day& area)
{
if(time == 0 && area.times.empty()) {
//this case is okay, don't fail from the assertion below.
return;
}
assert(time < static_cast<int>(area.times.size()) );
if (area.times[time].lawful_bonus != area.times[area.currentTime].lawful_bonus) {
has_tod_bonus_changed_ = true;
Expand Down
19 changes: 13 additions & 6 deletions src/tod_manager.hpp
Expand Up @@ -195,11 +195,19 @@ class tod_manager
* for_turn_number: for which current turn
* current_time: the main or time area's current time
*/
int calculate_current_time(
const int number_of_times,
const int for_turn_number,
const int current_time,
const bool only_to_allowed_range = false) const;
static int fix_time_index(
int number_of_times,
int time);
/**
* Computes for the main time or a time area the index of its times where we're currently at.
* number_of_times: size of that main time or time area's times vector
* for_turn_number: for which current turn
* current_time: the main or time area's current time
*/
int calculate_time_index_at_turn(
int number_of_times,
int for_turn_number,
int current_time) const;
/**
* Computes the maximum absolute value of lawful_bonus in the schedule.
*/
Expand All @@ -211,7 +219,6 @@ class tod_manager
*/
void set_new_current_times(const int new_current_turn_number);


struct area_time_of_day {
area_time_of_day() :
xsrc(),
Expand Down
20 changes: 20 additions & 0 deletions src/utils/math.hpp
Expand Up @@ -26,6 +26,7 @@
#include <limits>
#include <vector>
#include <algorithm>
#include <cassert>

template<typename T>
inline bool is_even(T num) { return num % 2 == 0; }
Expand All @@ -52,6 +53,25 @@ inline int bounded_add(int base, int increment, int max_sum, int min_sum = 0)
}
}


/**
* @returns: the number n in [min, min+mod ) so that (n - num) is a multiple of mod.
*/
template<typename T>
inline T modulo(T num, int mod, T min = 0)
{
assert(mod > 0);
T n = (num - min) % mod;
if (n < 0)
n += mod;
//n is now in [0, mod)
n = n + min;
return n;
// the following properties are easy to verify:
// 1) For all m: modulo(num, mod, min) == modulo(num + mod*m, mod, min)
// 2) For all 0 <= m < mod: modulo(min + m, mod, min) == min + m
}

/**
* round (base_damage * bonus / divisor) to the closest integer,
* but up or down towards base_damage
Expand Down

0 comments on commit ebbecb3

Please sign in to comment.