Files @ r11283:69678a6bd7ef
Branch filter:

Location: cpp/openttd-patchpack/source/src/ai/ai_config.cpp

truebrain
(svn r15637) -Fix: when you try to protect something from doing something it shouldn't be doing, make sure that the actions happening after that, doesn't start doing what it shouldn't be doing. This of course would only happen in rare corner cases.
/* $Id$ */

/** @file ai_config.cpp Implementation of AIConfig. */

#include "../stdafx.h"
#include "../openttd.h"
#include "../settings_type.h"
#include "../core/random_func.hpp"
#include "ai.hpp"
#include "ai_config.hpp"

void AIConfig::ChangeAI(const char *name, int version)
{
	free((void *)this->name);
	this->name = (name == NULL) ? NULL : strdup(name);
	this->info = (name == NULL) ? NULL : AI::FindInfo(this->name, version);
	this->version = (info == NULL) ? -1 : info->GetVersion();
	if (this->config_list != NULL) delete this->config_list;
	this->config_list = (info == NULL) ? NULL : new AIConfigItemList();
	if (this->config_list != NULL) this->config_list->push_back(_start_date_config);

	/* The special casing for start_date is here to ensure that the
	 *  start_date setting won't change even if you chose another AI. */
	int start_date = this->GetSetting("start_date");

	for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
		free((void*)(*it).first);
	}
	this->settings.clear();

	this->SetSetting("start_date", start_date);

	if (_game_mode == GM_NORMAL && this->info != NULL) {
		/* If we're in an existing game and the AI is changed, set all settings
		 *  for the AI that have the random flag to a random value. */
		for (AIConfigItemList::const_iterator it = this->info->GetConfigList()->begin(); it != this->info->GetConfigList()->end(); it++) {
			if ((*it).flags & AICONFIG_RANDOM) {
				this->SetSetting((*it).name, InteractiveRandomRange((*it).max_value - (*it).min_value) + (*it).min_value);
			}
		}
		this->AddRandomDeviation();
	}

}

AIConfig::AIConfig(const AIConfig *config)
{
	this->name = (config->name == NULL) ? NULL : strdup(config->name);
	this->info = config->info;
	this->version = config->version;
	this->config_list = NULL;

	for (SettingValueList::const_iterator it = config->settings.begin(); it != config->settings.end(); it++) {
		this->settings[strdup((*it).first)] = (*it).second;
	}
	this->AddRandomDeviation();
}

AIConfig::~AIConfig()
{
	free((void *)this->name);
	this->ResetSettings();
	if (this->config_list != NULL) delete this->config_list;
}

AIInfo *AIConfig::GetInfo()
{
	return this->info;
}

bool AIConfig::ResetInfo()
{
	this->info = AI::FindInfo(this->name, -1);
	return this->info != NULL;
}

const AIConfigItemList *AIConfig::GetConfigList()
{
	if (this->info != NULL) return this->info->GetConfigList();
	if (this->config_list == NULL) {
		this->config_list = new AIConfigItemList();
		this->config_list->push_back(_start_date_config);
	}
	return this->config_list;
}

AIConfig *AIConfig::GetConfig(CompanyID company, bool forceNewgameSetting)
{
	AIConfig **config;
	if (!forceNewgameSetting) {
		config = (_game_mode == GM_MENU) ? &_settings_newgame.ai_config[company] : &_settings_game.ai_config[company];
	} else {
		config = &_settings_newgame.ai_config[company];
	}
	if (*config == NULL) *config = new AIConfig();
	return *config;
}

int AIConfig::GetSetting(const char *name)
{
	SettingValueList::iterator it = this->settings.find(name);
	/* Return the default value if the setting is not set, or if we are in a not-custom difficult level */
	if (it == this->settings.end() || ((_game_mode == GM_MENU) ? _settings_newgame.difficulty.diff_level : _settings_game.difficulty.diff_level) != 3) {
		if (this->info == NULL) {
			assert(strcmp("start_date", name) == 0);
			switch ((_game_mode == GM_MENU) ? _settings_newgame.difficulty.diff_level : _settings_game.difficulty.diff_level) {
				case 0: return AI::START_NEXT_EASY;
				case 1: return AI::START_NEXT_MEDIUM;
				case 2: return AI::START_NEXT_HARD;
				case 3: return AI::START_NEXT_MEDIUM;
				default: NOT_REACHED();
			}
		}
		return this->info->GetSettingDefaultValue(name);
	}
	return (*it).second;
}

void AIConfig::SetSetting(const char *name, int value)
{
	/* You can only set ai specific settings if an AI is selected. */
	if (this->info == NULL && strcmp("start_date", name) != 0) return;

	if (this->info == NULL && strcmp("start_date", name) == 0) {
		value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX);
	} else {
		const AIConfigItem *config_item = this->info->GetConfigItem(name);
		if (config_item == NULL) return;

		value = Clamp(value, config_item->min_value, config_item->max_value);
	}

	SettingValueList::iterator it = this->settings.find(name);
	if (it != this->settings.end()) {
		(*it).second = value;
	} else {
		this->settings[strdup(name)] = value;
	}
}

void AIConfig::ResetSettings()
{
	for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
		free((void*)(*it).first);
	}
	this->settings.clear();
}

void AIConfig::AddRandomDeviation()
{
	for (AIConfigItemList::const_iterator it = this->GetConfigList()->begin(); it != this->GetConfigList()->end(); it++) {
		if ((*it).random_deviation != 0) {
			this->SetSetting((*it).name, InteractiveRandomRange((*it).random_deviation * 2) - (*it).random_deviation + this->GetSetting((*it).name));
		}
	}
}

bool AIConfig::HasAI()
{
	return this->info != NULL;
}

const char *AIConfig::GetName()
{
	return this->name;
}

int AIConfig::GetVersion()
{
	return this->version;
}

void AIConfig::StringToSettings(const char *value)
{
	char *value_copy = strdup(value);
	char *s = value_copy;

	while (s != NULL) {
		/* Analyze the string ('name=value,name=value\0') */
		char *item_name = s;
		s = strchr(s, '=');
		if (s == NULL) break;
		if (*s == '\0') break;
		*s = '\0';
		s++;

		char *item_value = s;
		s = strchr(s, ',');
		if (s != NULL) {
			*s = '\0';
			s++;
		}

		this->SetSetting(item_name, atoi(item_value));
	}
	free(value_copy);
}

void AIConfig::SettingsToString(char *string, size_t size)
{
	string[0] = '\0';
	for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
		char no[10];
		snprintf(no, sizeof(no), "%d", (*it).second);

		/* Check if the string would fit in the destination */
		size -= strlen((*it).first) - 1 - strlen(no) - 1;
		/* If it doesn't fit, skip the next settings */
		if (size <= 0) return;

		strcat(string, (*it).first);
		strcat(string, "=");
		strcat(string, no);
		strcat(string, ",");
	}
	/* Remove the last ',', but only if at least one setting was saved. */
	size_t len = strlen(string);
	if (len > 0) string[len - 1] = '\0';
}