Files @ r17613:a9b2554a5d79
Branch filter:

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

rubidium
(svn r22387) -Fix-ish [FS#4601]: Windows' recv seems to return "graceful closed" before having passed the remaining buffer which causes OpenTTD to think all connections are "incorrectly" terminated, i.e. without the "I'm leaving" packet from the client. So let the client wait a tiny bit after sending the "I'm leaving" packet and before gracefully closing the connection
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10723:2143de457ff9
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14377:f63ba65f9d57
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14377:f63ba65f9d57
r10712:3ee31720391b
r14202:008944a6e34c
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10696:8dfe83e30d01
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10723:2143de457ff9
r10730:c4f9653e3345
r10730:c4f9653e3345
r10723:2143de457ff9
r10723:2143de457ff9
r10723:2143de457ff9
r10723:2143de457ff9
r10723:2143de457ff9
r10723:2143de457ff9
r10723:2143de457ff9
r10723:2143de457ff9
r10730:c4f9653e3345
r10723:2143de457ff9
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10712:3ee31720391b
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10712:3ee31720391b
r10840:7a608f4ad153
r14202:008944a6e34c
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10730:c4f9653e3345
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10788:e413614a4b4e
r10840:7a608f4ad153
r10840:7a608f4ad153
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14187:fd7084a22bff
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14377:f63ba65f9d57
r10849:8e532db71075
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r14828:12f0b09ddc04
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14828:12f0b09ddc04
r14828:12f0b09ddc04
r10696:8dfe83e30d01
r14828:12f0b09ddc04
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14187:fd7084a22bff
r10696:8dfe83e30d01
r14187:fd7084a22bff
r10696:8dfe83e30d01
r16951:cc90f5512419
r10730:c4f9653e3345
r10730:c4f9653e3345
r16951:cc90f5512419
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10730:c4f9653e3345
r10724:cec22216aab8
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10724:cec22216aab8
r10730:c4f9653e3345
r10730:c4f9653e3345
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10840:7a608f4ad153
r10730:c4f9653e3345
r10730:c4f9653e3345
r10840:7a608f4ad153
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r10730:c4f9653e3345
r14187:fd7084a22bff
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14202:008944a6e34c
r14202:008944a6e34c
r14202:008944a6e34c
r14202:008944a6e34c
r14202:008944a6e34c
r14187:fd7084a22bff
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14187:fd7084a22bff
r10712:3ee31720391b
r10712:3ee31720391b
r10712:3ee31720391b
r10712:3ee31720391b
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14187:fd7084a22bff
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r14187:fd7084a22bff
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r11284:ee8c04942ac9
r10696:8dfe83e30d01
r11284:ee8c04942ac9
r11284:ee8c04942ac9
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10836:2daa1e2f98f5
r10836:2daa1e2f98f5
r10836:2daa1e2f98f5
r10696:8dfe83e30d01
/* $Id$ */

/*
 * This file is part of OpenTTD.
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 */

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

#include "../stdafx.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, bool force_exact_match, bool is_random_ai)
{
	free((void *)this->name);
	this->name = (name == NULL) ? NULL : strdup(name);
	this->info = (name == NULL) ? NULL : AI::FindInfo(this->name, version, force_exact_match);
	this->version = (info == NULL) ? -1 : info->GetVersion();
	this->is_random_ai = is_random_ai;
	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;
	this->is_random_ai = config->is_random_ai;

	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() const
{
	return this->info;
}

bool AIConfig::ResetInfo()
{
	this->info = AI::FindInfo(this->name, -1, false);
	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, AISettingSource source)
{
	AIConfig **config;
	if (source == AISS_FORCE_NEWGAME || (source == AISS_DEFAULT && _game_mode == GM_MENU)) {
		config = &_settings_newgame.ai_config[company];
	} else {
		config = &_settings_game.ai_config[company];
	}
	if (*config == NULL) *config = new AIConfig();
	return *config;
}

int AIConfig::GetSetting(const char *name) const
{
	SettingValueList::const_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() || GetGameSettings().difficulty.diff_level != 3) {
		if (this->info == NULL) {
			assert(strcmp("start_date", name) == 0);
			switch (GetGameSettings().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() const
{
	return this->info != NULL;
}

bool AIConfig::IsRandomAI() const
{
	return this->is_random_ai;
}

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

int AIConfig::GetVersion() const
{
	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) const
{
	string[0] = '\0';
	for (SettingValueList::const_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_t needed_size = strlen((*it).first) + 1 + strlen(no) + 1;
		/* If it doesn't fit, skip the next settings */
		if (size <= needed_size) break;
		size -= needed_size;

		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';
}