package org.mafagafogigante.dungeon.world;
import org.mafagafogigante.dungeon.date.Date;
import org.mafagafogigante.dungeon.date.Duration;
import org.mafagafogigante.dungeon.game.Random;
import org.mafagafogigante.dungeon.util.CircularList;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
/**
* An object that represents the weather of the world.
*/
public class Weather implements Serializable {
// Eight hours.
private static final Duration UPDATE_INTERVAL = new Duration(new Date(1, 1, 1, 1, 1, 1), new Date(1, 1, 1, 9, 1, 1));
// The probability of a trend (weather getting lighter or heavier) being followed.
private static final double TREND_FORCE = 0.6;
private CircularList<WeatherCondition> conditionHistory = new CircularList<>(2);
private Date lastWeatherUpdate;
/**
* Constructs a new Weather starting at the specified date.
*/
public Weather(@NotNull Date date) {
this.lastWeatherUpdate = date;
rollNewCondition(date);
}
public WeatherCondition getCurrentCondition(Date date) {
refresh(date);
return conditionHistory.get(0);
}
/**
* Refreshes the current condition if enough time has passed. If not enough time has passed, a call is a no-op.
*/
private void refresh(@NotNull Date date) {
if (new Duration(lastWeatherUpdate, date).compareTo(UPDATE_INTERVAL) >= 0) {
rollNewCondition(date);
}
}
/**
* Randomly selects a new WeatherCondition and adds it to the condition history.
*/
private void rollNewCondition(@NotNull Date date) {
if (conditionHistory.isEmpty()) {
conditionHistory.add(Random.select(Arrays.asList(WeatherCondition.values())));
} else {
final WeatherCondition lastCondition = conditionHistory.get(0);
if (conditionHistory.size() == 1) {
final List<WeatherCondition> list = Arrays.asList(lastCondition.getLighter(), lastCondition.getHeavier());
conditionHistory.add(Random.select(list));
} else { // WeatherCondition history has at least two conditions.
final WeatherCondition semiLastCondition = conditionHistory.get(1);
// Try to force change in the same way so that extremes are more common.
if (semiLastCondition.isLighterThan(lastCondition)) {
conditionHistory.add(Random.roll(TREND_FORCE) ? lastCondition.getHeavier() : lastCondition.getLighter());
} else if (semiLastCondition.isHeavierThan(lastCondition)) {
conditionHistory.add(Random.roll(TREND_FORCE) ? lastCondition.getLighter() : lastCondition.getHeavier());
} else { // The condition did not change, ensure change.
// If an extreme condition follows the trend, it doesn't change, so conditions may not change.
if (lastCondition.getLighter() == lastCondition) {
conditionHistory.add(lastCondition.getHeavier());
} else {
conditionHistory.add(lastCondition.getLighter());
}
}
}
}
lastWeatherUpdate = date;
}
}