<commit_before>#include <algorithm>
#include <cassert>
#include <cmath>

#include "SDL.h"

#include "GameData.h"
#include "../Assets/ExeStrings.h"
#include "../Assets/INFFile.h"
#include "../Assets/MIFFile.h"
#include "../Entities/Animation.h"
#include "../Entities/CharacterClass.h"
#include "../Entities/Doodad.h"
#include "../Entities/Entity.h"
#include "../Entities/EntityManager.h"
#include "../Entities/GenderName.h"
#include "../Entities/NonPlayer.h"
#include "../Entities/Player.h"
#include "../Interface/TextBox.h"
#include "../Math/Constants.h"
#include "../Math/Random.h"
#include "../Media/PaletteFile.h"
#include "../Media/PaletteName.h"
#include "../Media/TextureManager.h"
#include "../Rendering/Renderer.h"
#include "../Utilities/Debug.h"
#include "../Utilities/String.h"
#include "../World/ClimateType.h"
#include "../World/LocationType.h"
#include "../World/VoxelGrid.h"
#include "../World/VoxelType.h"
#include "../World/WeatherType.h"
#include "../World/WorldType.h"

// Arbitrary value for testing. One real second = six game minutes.
// The value used in Arena is one real second = twenty game seconds.
const double GameData::TIME_SCALE = static_cast<double>(Clock::SECONDS_IN_A_DAY) / 240.0;

GameData::GameData(Player &&player, WorldData &&worldData, const Location &location,
	const Date &date, const Clock &clock, double fogDistance)
	: player(std::move(player)), worldData(std::move(worldData)), location(location),
	date(date), clock(clock), triggerText(0.0, nullptr), actionText(0.0, nullptr),
	effectText(0.0, nullptr)
{
	DebugMention("Initializing.");

	this->fogDistance = fogDistance;
}

GameData::~GameData()
{
	DebugMention("Closing.");
}

std::vector<uint32_t> GameData::makeExteriorSkyPalette(WeatherType weatherType,
	TextureManager &textureManager)
{
	// Get the palette name for the given weather.
	const std::string paletteName = (weatherType == WeatherType::Clear) ?
		"DAYTIME.COL" : "DREARY.COL";

	// The palettes in the data files only cover half of the day, so some added
	// darkness is needed for the other half.
	const SDL_Surface *palette = textureManager.getSurface(paletteName);
	const uint32_t *pixels = static_cast<const uint32_t*>(palette->pixels);
	const int pixelCount = palette->w * palette->h;

	std::vector<uint32_t> fullPalette(pixelCount * 2);

	// Fill with darkness (the first color in the palette is the closest to night).
	const uint32_t darkness = pixels[0];
	std::fill(fullPalette.begin(), fullPalette.end(), darkness);

	// Copy the sky palette over the center of the full palette.
	std::copy(pixels, pixels + pixelCount, 
		fullPalette.data() + (fullPalette.size() / 4));

	return fullPalette;
}

double GameData::getFogDistanceFromWeather(WeatherType weatherType)
{
	// Arbitrary values, the distance at which fog is maximum.
	if (weatherType == WeatherType::Clear)
	{
		return 75.0;
	}
	else if (weatherType == WeatherType::Overcast)
	{
		return 25.0;
	}
	else if (weatherType == WeatherType::Rain)
	{
		return 35.0;
	}
	else if (weatherType == WeatherType::Snow)
	{
		return 15.0;
	}
	else
	{
		throw std::runtime_error("Bad weather type \"" +
			std::to_string(static_cast<int>(weatherType)) + "\".");
	}
}

void GameData::loadInterior(const MIFFile &mif, Double3 &playerPosition, WorldData &worldData,
	TextureManager &textureManager, Renderer &renderer)
{
	// Call interior WorldData loader.
	worldData = WorldData::loadInterior(mif);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set player starting position.
	const Double2 &startPoint = worldData.getStartPoints().front();
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Set interior sky palette.
	const auto &level = worldData.getLevels().at(worldData.getCurrentLevel());
	const uint32_t skyColor = level.getInteriorSkyColor();
	renderer.setSkyPalette(&skyColor, 1);

	// Arbitrary interior fog distance.
	renderer.setFogDistance(25.0);
}

void GameData::loadPremadeCity(const MIFFile &mif, ClimateType climateType,
	WeatherType weatherType, Double3 &playerPosition, WorldData &worldData,
	TextureManager &textureManager, Renderer &renderer)
{
	// Call premade WorldData loader.
	worldData = WorldData::loadPremadeCity(mif, climateType, weatherType);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set player starting position.
	const Double2 &startPoint = worldData.getStartPoints().front();
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Regular sky palette based on weather.
	const std::vector<uint32_t> skyPalette =
		GameData::makeExteriorSkyPalette(weatherType, textureManager);
	renderer.setSkyPalette(skyPalette.data(), static_cast<int>(skyPalette.size()));
	
	const double fogDistance = GameData::getFogDistanceFromWeather(weatherType);
	renderer.setFogDistance(fogDistance);
}

void GameData::loadCity(const MIFFile &mif, WeatherType weatherType, Double3 &playerPosition,
	WorldData &worldData, TextureManager &textureManager, Renderer &renderer)
{
	// Call random city WorldData loader.
	worldData = WorldData::loadCity(mif, weatherType);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set player starting position.
	const Double2 &startPoint = worldData.getStartPoints().front();
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Regular sky palette based on weather.
	const std::vector<uint32_t> skyPalette =
		GameData::makeExteriorSkyPalette(weatherType, textureManager);
	renderer.setSkyPalette(skyPalette.data(), static_cast<int>(skyPalette.size()));

	const double fogDistance = GameData::getFogDistanceFromWeather(weatherType);
	renderer.setFogDistance(fogDistance);
}

void GameData::loadWilderness(int rmdTR, int rmdTL, int rmdBR, int rmdBL, ClimateType climateType,
	WeatherType weatherType, Double3 &playerPosition, WorldData &worldData,
	TextureManager &textureManager, Renderer &renderer)
{
	// Call wilderness WorldData loader.
	worldData = WorldData::loadWilderness(rmdTR, rmdTL, rmdBR, rmdBL, climateType, weatherType);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set arbitrary player starting position (no starting point in WILD.MIF).
	const Double2 startPoint(1.50, 1.50);
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Regular sky palette based on weather.
	const std::vector<uint32_t> skyPalette =
		GameData::makeExteriorSkyPalette(weatherType, textureManager);
	renderer.setSkyPalette(skyPalette.data(), static_cast<int>(skyPalette.size()));

	const double fogDistance = GameData::getFogDistanceFromWeather(weatherType);
	renderer.setFogDistance(fogDistance);
}

std::unique_ptr<GameData> GameData::createDefault(const std::string &playerName,
	GenderName gender, int raceID, const CharacterClass &charClass, int portraitID,
	const ExeStrings &exeStrings, TextureManager &textureManager, Renderer &renderer)
{
	// Create some dummy data for the test world.

	// Some arbitrary player values.
	const Double3 position = Double3(1.50, 1.70, 12.50);
	const Double3 direction = Double3(1.0, 0.0, 0.0).normalized();
	const Double3 velocity = Double3::Zero;
	const double maxWalkSpeed = 2.0;
	const double maxRunSpeed = 8.0;
	const int weaponID = [&charClass]()
	{
		// Pick a random weapon available to the player's class for testing.
		std::vector<int> weapons = charClass.getAllowedWeapons();

		// Remove bows for now (16 and 17).
		weapons.erase(std::remove(weapons.begin(), weapons.end(), 16), weapons.end());
		weapons.erase(std::remove(weapons.begin(), weapons.end(), 17), weapons.end());<commit_msg>Put player in center of wilderness for convenience.<commit_after>#include <algorithm>
#include <cassert>
#include <cmath>

#include "SDL.h"

#include "GameData.h"
#include "../Assets/ExeStrings.h"
#include "../Assets/INFFile.h"
#include "../Assets/MIFFile.h"
#include "../Entities/Animation.h"
#include "../Entities/CharacterClass.h"
#include "../Entities/Doodad.h"
#include "../Entities/Entity.h"
#include "../Entities/EntityManager.h"
#include "../Entities/GenderName.h"
#include "../Entities/NonPlayer.h"
#include "../Entities/Player.h"
#include "../Interface/TextBox.h"
#include "../Math/Constants.h"
#include "../Math/Random.h"
#include "../Media/PaletteFile.h"
#include "../Media/PaletteName.h"
#include "../Media/TextureManager.h"
#include "../Rendering/Renderer.h"
#include "../Utilities/Debug.h"
#include "../Utilities/String.h"
#include "../World/ClimateType.h"
#include "../World/LocationType.h"
#include "../World/VoxelGrid.h"
#include "../World/VoxelType.h"
#include "../World/WeatherType.h"
#include "../World/WorldType.h"

// Arbitrary value for testing. One real second = six game minutes.
// The value used in Arena is one real second = twenty game seconds.
const double GameData::TIME_SCALE = static_cast<double>(Clock::SECONDS_IN_A_DAY) / 240.0;

GameData::GameData(Player &&player, WorldData &&worldData, const Location &location,
	const Date &date, const Clock &clock, double fogDistance)
	: player(std::move(player)), worldData(std::move(worldData)), location(location),
	date(date), clock(clock), triggerText(0.0, nullptr), actionText(0.0, nullptr),
	effectText(0.0, nullptr)
{
	DebugMention("Initializing.");

	this->fogDistance = fogDistance;
}

GameData::~GameData()
{
	DebugMention("Closing.");
}

std::vector<uint32_t> GameData::makeExteriorSkyPalette(WeatherType weatherType,
	TextureManager &textureManager)
{
	// Get the palette name for the given weather.
	const std::string paletteName = (weatherType == WeatherType::Clear) ?
		"DAYTIME.COL" : "DREARY.COL";

	// The palettes in the data files only cover half of the day, so some added
	// darkness is needed for the other half.
	const SDL_Surface *palette = textureManager.getSurface(paletteName);
	const uint32_t *pixels = static_cast<const uint32_t*>(palette->pixels);
	const int pixelCount = palette->w * palette->h;

	std::vector<uint32_t> fullPalette(pixelCount * 2);

	// Fill with darkness (the first color in the palette is the closest to night).
	const uint32_t darkness = pixels[0];
	std::fill(fullPalette.begin(), fullPalette.end(), darkness);

	// Copy the sky palette over the center of the full palette.
	std::copy(pixels, pixels + pixelCount, 
		fullPalette.data() + (fullPalette.size() / 4));

	return fullPalette;
}

double GameData::getFogDistanceFromWeather(WeatherType weatherType)
{
	// Arbitrary values, the distance at which fog is maximum.
	if (weatherType == WeatherType::Clear)
	{
		return 75.0;
	}
	else if (weatherType == WeatherType::Overcast)
	{
		return 25.0;
	}
	else if (weatherType == WeatherType::Rain)
	{
		return 35.0;
	}
	else if (weatherType == WeatherType::Snow)
	{
		return 15.0;
	}
	else
	{
		throw std::runtime_error("Bad weather type \"" +
			std::to_string(static_cast<int>(weatherType)) + "\".");
	}
}

void GameData::loadInterior(const MIFFile &mif, Double3 &playerPosition, WorldData &worldData,
	TextureManager &textureManager, Renderer &renderer)
{
	// Call interior WorldData loader.
	worldData = WorldData::loadInterior(mif);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set player starting position.
	const Double2 &startPoint = worldData.getStartPoints().front();
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Set interior sky palette.
	const auto &level = worldData.getLevels().at(worldData.getCurrentLevel());
	const uint32_t skyColor = level.getInteriorSkyColor();
	renderer.setSkyPalette(&skyColor, 1);

	// Arbitrary interior fog distance.
	renderer.setFogDistance(25.0);
}

void GameData::loadPremadeCity(const MIFFile &mif, ClimateType climateType,
	WeatherType weatherType, Double3 &playerPosition, WorldData &worldData,
	TextureManager &textureManager, Renderer &renderer)
{
	// Call premade WorldData loader.
	worldData = WorldData::loadPremadeCity(mif, climateType, weatherType);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set player starting position.
	const Double2 &startPoint = worldData.getStartPoints().front();
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Regular sky palette based on weather.
	const std::vector<uint32_t> skyPalette =
		GameData::makeExteriorSkyPalette(weatherType, textureManager);
	renderer.setSkyPalette(skyPalette.data(), static_cast<int>(skyPalette.size()));
	
	const double fogDistance = GameData::getFogDistanceFromWeather(weatherType);
	renderer.setFogDistance(fogDistance);
}

void GameData::loadCity(const MIFFile &mif, WeatherType weatherType, Double3 &playerPosition,
	WorldData &worldData, TextureManager &textureManager, Renderer &renderer)
{
	// Call random city WorldData loader.
	worldData = WorldData::loadCity(mif, weatherType);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set player starting position.
	const Double2 &startPoint = worldData.getStartPoints().front();
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Regular sky palette based on weather.
	const std::vector<uint32_t> skyPalette =
		GameData::makeExteriorSkyPalette(weatherType, textureManager);
	renderer.setSkyPalette(skyPalette.data(), static_cast<int>(skyPalette.size()));

	const double fogDistance = GameData::getFogDistanceFromWeather(weatherType);
	renderer.setFogDistance(fogDistance);
}

void GameData::loadWilderness(int rmdTR, int rmdTL, int rmdBR, int rmdBL, ClimateType climateType,
	WeatherType weatherType, Double3 &playerPosition, WorldData &worldData,
	TextureManager &textureManager, Renderer &renderer)
{
	// Call wilderness WorldData loader.
	worldData = WorldData::loadWilderness(rmdTR, rmdTL, rmdBR, rmdBL, climateType, weatherType);
	worldData.setLevelActive(worldData.getCurrentLevel(), textureManager, renderer);

	// Set arbitrary player starting position (no starting point in WILD.MIF).
	const Double2 startPoint(63.50, 63.50);
	playerPosition = Double3(startPoint.x, playerPosition.y, startPoint.y);

	// Regular sky palette based on weather.
	const std::vector<uint32_t> skyPalette =
		GameData::makeExteriorSkyPalette(weatherType, textureManager);
	renderer.setSkyPalette(skyPalette.data(), static_cast<int>(skyPalette.size()));

	const double fogDistance = GameData::getFogDistanceFromWeather(weatherType);
	renderer.setFogDistance(fogDistance);
}

std::unique_ptr<GameData> GameData::createDefault(const std::string &playerName,
	GenderName gender, int raceID, const CharacterClass &charClass, int portraitID,
	const ExeStrings &exeStrings, TextureManager &textureManager, Renderer &renderer)
{
	// Create some dummy data for the test world.

	// Some arbitrary player values.
	const Double3 position = Double3(1.50, 1.70, 12.50);
	const Double3 direction = Double3(1.0, 0.0, 0.0).normalized();
	const Double3 velocity = Double3::Zero;
	const double maxWalkSpeed = 2.0;
	const double maxRunSpeed = 8.0;
	const int weaponID = [&charClass]()
	{
		// Pick a random weapon available to the player's class for testing.
		std::vector<int> weapons = charClass.getAllowedWeapons();

		// Remove bows for now (16 and 17).
		weapons.erase(std::remove(weapons.begin(), weapons.end(), 16), weapons.end());
		weapons.erase(std::remove(weapons.begin(), weapons.end(), 17), weapons.end());
{'fraction_non_alphanumeric': 0.13370273794002607, 'fraction_numerical': 0.01303780964797914, 'mean_word_length': 5.6153514445881845, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3932434', 'n_tokens_mistral': 5065, 'n_tokens_neox': 4839, 'n_words': 1174}