2009-01-12 17:11:45 +00:00
/* $Id$ */
2009-08-21 20:21:05 +00:00
/*
* 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/>.
*/
2009-01-12 17:11:45 +00:00
/** @file ai_info.cpp Implementation of AIFileInfo */
# include "../stdafx.h"
# include <squirrel.h>
# include "../script/squirrel.hpp"
# include "../script/squirrel_helper.hpp"
# include "ai_info.hpp"
# include "ai_scanner.hpp"
# include "../settings_type.h"
# include "../openttd.h"
2009-08-18 18:51:42 +00:00
# include "../debug.h"
2009-09-22 11:10:04 +00:00
# include "../rev.h"
2009-01-12 17:11:45 +00:00
2009-01-20 16:49:10 +00:00
AIConfigItem _start_date_config = {
" start_date " ,
" The amount of days after the start of the last AI, this AI will start (give or take). " ,
AI : : START_NEXT_MIN ,
AI : : START_NEXT_MAX ,
AI : : START_NEXT_MEDIUM ,
AI : : START_NEXT_EASY ,
AI : : START_NEXT_MEDIUM ,
AI : : START_NEXT_HARD ,
AI : : START_NEXT_DEVIATION ,
30 ,
2009-02-06 10:31:05 +00:00
AICONFIG_NONE ,
NULL
2009-01-20 16:49:10 +00:00
} ;
2009-01-15 18:15:12 +00:00
AILibrary : : ~ AILibrary ( )
{
free ( ( void * ) this - > category ) ;
}
2009-03-15 22:41:57 +00:00
/* static */ SQInteger AIFileInfo : : Constructor ( HSQUIRRELVM vm , AIFileInfo * info )
2009-01-12 17:11:45 +00:00
{
2009-03-16 14:40:32 +00:00
SQInteger res = ScriptFileInfo : : Constructor ( vm , info ) ;
if ( res ! = 0 ) return res ;
2009-01-12 17:11:45 +00:00
info - > base = ( ( AIScanner * ) Squirrel : : GetGlobalPointer ( vm ) ) ;
2009-02-13 01:44:56 +00:00
2009-01-12 17:11:45 +00:00
return 0 ;
}
2009-08-18 18:51:42 +00:00
static bool CheckAPIVersion ( const char * api_version )
{
2009-12-23 23:09:47 +00:00
return strcmp ( api_version , " 0.7 " ) = = 0 | | strcmp ( api_version , " 1.0 " ) = = 0 ;
2009-08-18 18:51:42 +00:00
}
2009-01-12 17:11:45 +00:00
/* static */ SQInteger AIInfo : : Constructor ( HSQUIRRELVM vm )
{
/* Get the AIInfo */
2009-02-13 18:43:56 +00:00
SQUserPointer instance = NULL ;
if ( SQ_FAILED ( sq_getinstanceup ( vm , 2 , & instance , 0 ) ) | | instance = = NULL ) return sq_throwerror ( vm , _SC ( " Pass an instance of a child class of AIInfo to RegisterAI " ) ) ;
2009-01-12 17:11:45 +00:00
AIInfo * info = ( AIInfo * ) instance ;
2009-03-15 22:41:57 +00:00
SQInteger res = AIFileInfo : : Constructor ( vm , info ) ;
2009-01-12 17:11:45 +00:00
if ( res ! = 0 ) return res ;
2009-01-20 16:49:10 +00:00
AIConfigItem config = _start_date_config ;
config . name = strdup ( config . name ) ;
config . description = strdup ( config . description ) ;
2009-01-12 17:11:45 +00:00
info - > config_list . push_back ( config ) ;
/* Check if we have settings */
if ( info - > engine - > MethodExists ( * info - > SQ_instance , " GetSettings " ) ) {
2009-02-13 17:17:34 +00:00
if ( ! info - > GetSettings ( ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
}
2009-02-13 01:44:56 +00:00
if ( info - > engine - > MethodExists ( * info - > SQ_instance , " MinVersionToLoad " ) ) {
2009-02-13 17:17:34 +00:00
if ( ! info - > engine - > CallIntegerMethod ( * info - > SQ_instance , " MinVersionToLoad " , & info - > min_loadable_version ) ) return SQ_ERROR ;
2009-02-13 01:44:56 +00:00
} else {
info - > min_loadable_version = info - > GetVersion ( ) ;
}
2009-04-21 19:13:32 +00:00
/* When there is an UseAsRandomAI function, call it. */
if ( info - > engine - > MethodExists ( * info - > SQ_instance , " UseAsRandomAI " ) ) {
if ( ! info - > engine - > CallBoolMethod ( * info - > SQ_instance , " UseAsRandomAI " , & info - > use_as_random ) ) return SQ_ERROR ;
} else {
info - > use_as_random = true ;
}
2009-08-18 18:51:42 +00:00
/* Try to get the API version the AI is written for. */
if ( info - > engine - > MethodExists ( * info - > SQ_instance , " GetAPIVersion " ) ) {
if ( ! info - > engine - > CallStringMethodStrdup ( * info - > SQ_instance , " GetAPIVersion " , & info - > api_version ) ) return SQ_ERROR ;
if ( ! CheckAPIVersion ( info - > api_version ) ) {
DEBUG ( ai , 1 , " Loading info.nut from (%s.%d): GetAPIVersion returned invalid version " , info - > GetName ( ) , info - > GetVersion ( ) ) ;
return SQ_ERROR ;
}
} else {
info - > api_version = strdup ( " 0.7 " ) ;
}
2009-01-12 17:11:45 +00:00
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
sq_setinstanceup ( vm , 2 , NULL ) ;
/* Register the AI to the base system */
info - > base - > RegisterAI ( info ) ;
return 0 ;
}
/* static */ SQInteger AIInfo : : DummyConstructor ( HSQUIRRELVM vm )
{
/* Get the AIInfo */
SQUserPointer instance ;
sq_getinstanceup ( vm , 2 , & instance , 0 ) ;
AIInfo * info = ( AIInfo * ) instance ;
2009-08-18 18:51:42 +00:00
info - > api_version = NULL ;
2009-01-12 17:11:45 +00:00
2009-03-15 22:41:57 +00:00
SQInteger res = AIFileInfo : : Constructor ( vm , info ) ;
2009-01-12 17:11:45 +00:00
if ( res ! = 0 ) return res ;
2009-09-22 11:10:04 +00:00
char buf [ 8 ] ;
seprintf ( buf , lastof ( buf ) , " %d.%d " , GB ( _openttd_newgrf_version , 28 , 4 ) , GB ( _openttd_newgrf_version , 24 , 4 ) ) ;
info - > api_version = strdup ( buf ) ;
2009-01-12 17:11:45 +00:00
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
sq_setinstanceup ( vm , 2 , NULL ) ;
/* Register the AI to the base system */
info - > base - > SetDummyAI ( info ) ;
return 0 ;
}
2009-03-15 22:41:57 +00:00
bool AIInfo : : GetSettings ( )
{
return this - > engine - > CallMethod ( * this - > SQ_instance , " GetSettings " , NULL , - 1 ) ;
}
2009-12-06 20:22:21 +00:00
AIInfo : : AIInfo ( ) :
min_loadable_version ( 0 ) ,
use_as_random ( false ) ,
api_version ( NULL )
{
}
2009-01-12 17:11:45 +00:00
AIInfo : : ~ AIInfo ( )
{
/* Free all allocated strings */
for ( AIConfigItemList : : iterator it = this - > config_list . begin ( ) ; it ! = this - > config_list . end ( ) ; it + + ) {
2009-05-24 20:29:04 +00:00
free ( ( void * ) ( * it ) . name ) ;
free ( ( void * ) ( * it ) . description ) ;
2009-02-06 00:25:37 +00:00
if ( it - > labels ! = NULL ) {
for ( LabelMapping : : iterator it2 = ( * it ) . labels - > Begin ( ) ; it2 ! = ( * it ) . labels - > End ( ) ; it2 + + ) {
free ( it2 - > second ) ;
}
delete it - > labels ;
}
2009-01-12 17:11:45 +00:00
}
this - > config_list . clear ( ) ;
2009-08-18 18:51:42 +00:00
free ( ( void * ) this - > api_version ) ;
2009-01-12 17:11:45 +00:00
}
2009-02-13 02:11:54 +00:00
bool AIInfo : : CanLoadFromVersion ( int version ) const
2009-02-13 01:44:56 +00:00
{
if ( version = = - 1 ) return true ;
return version > = this - > min_loadable_version & & version < = this - > GetVersion ( ) ;
}
2009-01-12 17:11:45 +00:00
SQInteger AIInfo : : AddSetting ( HSQUIRRELVM vm )
{
AIConfigItem config ;
memset ( & config , 0 , sizeof ( config ) ) ;
2009-01-13 01:51:39 +00:00
config . max_value = 1 ;
2009-01-13 18:26:58 +00:00
config . step_size = 1 ;
2009-01-13 01:52:32 +00:00
uint items = 0 ;
2009-01-12 17:11:45 +00:00
/* Read the table, and find all properties we care about */
sq_pushnull ( vm ) ;
while ( SQ_SUCCEEDED ( sq_next ( vm , - 2 ) ) ) {
const SQChar * sqkey ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getstring ( vm , - 2 , & sqkey ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
const char * key = FS2OTTD ( sqkey ) ;
if ( strcmp ( key , " name " ) = = 0 ) {
const SQChar * sqvalue ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getstring ( vm , - 1 , & sqvalue ) ) ) return SQ_ERROR ;
2009-07-04 13:55:28 +00:00
char * name = strdup ( FS2OTTD ( sqvalue ) ) ;
2009-01-12 17:11:45 +00:00
char * s ;
/* Don't allow '=' and ',' in configure setting names, as we need those
* 2 chars to nicely store the settings as a string . */
2009-07-04 13:55:28 +00:00
while ( ( s = strchr ( name , ' = ' ) ) ! = NULL ) * s = ' _ ' ;
while ( ( s = strchr ( name , ' , ' ) ) ! = NULL ) * s = ' _ ' ;
config . name = name ;
2009-01-12 17:11:45 +00:00
items | = 0x001 ;
} else if ( strcmp ( key , " description " ) = = 0 ) {
const SQChar * sqdescription ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getstring ( vm , - 1 , & sqdescription ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . description = strdup ( FS2OTTD ( sqdescription ) ) ;
items | = 0x002 ;
} else if ( strcmp ( key , " min_value " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . min_value = res ;
items | = 0x004 ;
} else if ( strcmp ( key , " max_value " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . max_value = res ;
items | = 0x008 ;
} else if ( strcmp ( key , " easy_value " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . easy_value = res ;
items | = 0x010 ;
} else if ( strcmp ( key , " medium_value " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . medium_value = res ;
items | = 0x020 ;
} else if ( strcmp ( key , " hard_value " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . hard_value = res ;
items | = 0x040 ;
2009-08-20 10:23:39 +00:00
} else if ( strcmp ( key , " random_deviation " ) = = 0 ) {
2009-01-13 16:53:03 +00:00
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-13 16:53:03 +00:00
config . random_deviation = res ;
items | = 0x200 ;
2009-01-12 17:11:45 +00:00
} else if ( strcmp ( key , " custom_value " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . custom_value = res ;
items | = 0x080 ;
2009-01-13 18:26:58 +00:00
} else if ( strcmp ( key , " step_size " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-13 18:26:58 +00:00
config . step_size = res ;
2009-01-12 17:11:45 +00:00
} else if ( strcmp ( key , " flags " ) = = 0 ) {
SQInteger res ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getinteger ( vm , - 1 , & res ) ) ) return SQ_ERROR ;
2009-01-12 17:11:45 +00:00
config . flags = ( AIConfigFlags ) res ;
items | = 0x100 ;
} else {
char error [ 1024 ] ;
snprintf ( error , sizeof ( error ) , " unknown setting property '%s' " , key ) ;
this - > engine - > ThrowError ( error ) ;
return SQ_ERROR ;
}
sq_pop ( vm , 2 ) ;
}
sq_pop ( vm , 1 ) ;
2009-01-13 16:53:03 +00:00
/* Don't allow both random_deviation and AICONFIG_RANDOM to
* be set for the same config item . */
if ( ( items & 0x200 ) ! = 0 & & ( config . flags & AICONFIG_RANDOM ) ! = 0 ) {
char error [ 1024 ] ;
snprintf ( error , sizeof ( error ) , " Setting both random_deviation and AICONFIG_RANDOM is not allowed " ) ;
this - > engine - > ThrowError ( error ) ;
return SQ_ERROR ;
}
/* Reset the bit for random_deviation as it's optional. */
items & = ~ 0x200 ;
2009-01-12 17:11:45 +00:00
/* Make sure all properties are defined */
2009-01-13 01:51:39 +00:00
uint mask = ( config . flags & AICONFIG_BOOLEAN ) ? 0x1F3 : 0x1FF ;
if ( items ! = mask ) {
2009-01-12 17:11:45 +00:00
char error [ 1024 ] ;
2009-01-13 01:51:39 +00:00
snprintf ( error , sizeof ( error ) , " please define all properties of a setting (min/max not allowed for booleans) " ) ;
2009-01-12 17:11:45 +00:00
this - > engine - > ThrowError ( error ) ;
return SQ_ERROR ;
}
this - > config_list . push_back ( config ) ;
return 0 ;
}
2009-02-06 00:25:37 +00:00
SQInteger AIInfo : : AddLabels ( HSQUIRRELVM vm )
{
const SQChar * sq_setting_name ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getstring ( vm , - 2 , & sq_setting_name ) ) ) return SQ_ERROR ;
2009-02-06 00:25:37 +00:00
const char * setting_name = FS2OTTD ( sq_setting_name ) ;
AIConfigItem * config = NULL ;
for ( AIConfigItemList : : iterator it = this - > config_list . begin ( ) ; it ! = this - > config_list . end ( ) ; it + + ) {
if ( strcmp ( ( * it ) . name , setting_name ) = = 0 ) config = & ( * it ) ;
}
if ( config = = NULL ) {
char error [ 1024 ] ;
snprintf ( error , sizeof ( error ) , " Trying to add labels for non-defined setting '%s' " , setting_name ) ;
this - > engine - > ThrowError ( error ) ;
return SQ_ERROR ;
}
if ( config - > labels ! = NULL ) return SQ_ERROR ;
config - > labels = new LabelMapping ;
/* Read the table and find all labels */
sq_pushnull ( vm ) ;
while ( SQ_SUCCEEDED ( sq_next ( vm , - 2 ) ) ) {
const SQChar * sq_key ;
const SQChar * sq_label ;
2009-02-13 18:43:56 +00:00
if ( SQ_FAILED ( sq_getstring ( vm , - 2 , & sq_key ) ) ) return SQ_ERROR ;
if ( SQ_FAILED ( sq_getstring ( vm , - 1 , & sq_label ) ) ) return SQ_ERROR ;
2009-02-06 00:25:37 +00:00
/* Because squirrel doesn't support identifiers starting with a digit,
* we skip the first character . */
const char * key_string = FS2OTTD ( sq_key ) ;
int key = atoi ( key_string + 1 ) ;
const char * label = FS2OTTD ( sq_label ) ;
if ( config - > labels - > Find ( key ) = = config - > labels - > End ( ) ) config - > labels - > Insert ( key , strdup ( label ) ) ;
sq_pop ( vm , 2 ) ;
}
sq_pop ( vm , 1 ) ;
return 0 ;
}
2009-02-13 02:11:54 +00:00
const AIConfigItemList * AIInfo : : GetConfigList ( ) const
2009-01-12 17:11:45 +00:00
{
return & this - > config_list ;
}
2009-02-13 02:11:54 +00:00
const AIConfigItem * AIInfo : : GetConfigItem ( const char * name ) const
2009-01-13 13:09:49 +00:00
{
2009-02-13 02:11:54 +00:00
for ( AIConfigItemList : : const_iterator it = this - > config_list . begin ( ) ; it ! = this - > config_list . end ( ) ; it + + ) {
2009-01-13 13:09:49 +00:00
if ( strcmp ( ( * it ) . name , name ) = = 0 ) return & ( * it ) ;
}
return NULL ;
}
2009-02-13 02:11:54 +00:00
int AIInfo : : GetSettingDefaultValue ( const char * name ) const
2009-01-12 17:11:45 +00:00
{
2009-02-13 02:11:54 +00:00
for ( AIConfigItemList : : const_iterator it = this - > config_list . begin ( ) ; it ! = this - > config_list . end ( ) ; it + + ) {
2009-01-12 17:11:45 +00:00
if ( strcmp ( ( * it ) . name , name ) ! = 0 ) continue ;
/* The default value depends on the difficulty level */
switch ( ( _game_mode = = GM_MENU ) ? _settings_newgame . difficulty . diff_level : _settings_game . difficulty . diff_level ) {
case 0 : return ( * it ) . easy_value ;
case 1 : return ( * it ) . medium_value ;
case 2 : return ( * it ) . hard_value ;
case 3 : return ( * it ) . custom_value ;
default : NOT_REACHED ( ) ;
}
}
/* There is no such setting */
return - 1 ;
}
/* static */ SQInteger AILibrary : : Constructor ( HSQUIRRELVM vm )
{
/* Create a new AIFileInfo */
AILibrary * library = new AILibrary ( ) ;
2009-03-15 22:41:57 +00:00
SQInteger res = AIFileInfo : : Constructor ( vm , library ) ;
2009-01-17 14:54:24 +00:00
if ( res ! = 0 ) {
delete library ;
return res ;
}
2009-01-12 17:11:45 +00:00
2009-02-13 01:44:56 +00:00
/* Cache the category */
2009-03-15 22:41:57 +00:00
if ( ! library - > CheckMethod ( " GetCategory " ) | | ! library - > engine - > CallStringMethodStrdup ( * library - > SQ_instance , " GetCategory " , & library - > category ) ) {
2009-02-13 17:17:34 +00:00
delete library ;
return SQ_ERROR ;
}
2009-02-13 01:44:56 +00:00
2009-01-12 17:11:45 +00:00
/* Register the Library to the base system */
library - > base - > RegisterLibrary ( library ) ;
return 0 ;
}
/* static */ SQInteger AILibrary : : Import ( HSQUIRRELVM vm )
{
SQConvert : : SQAutoFreePointers ptr ;
const char * library = GetParam ( SQConvert : : ForceType < const char * > ( ) , vm , 2 , & ptr ) ;
const char * class_name = GetParam ( SQConvert : : ForceType < const char * > ( ) , vm , 3 , & ptr ) ;
int version = GetParam ( SQConvert : : ForceType < int > ( ) , vm , 4 , & ptr ) ;
if ( ! AI : : ImportLibrary ( library , class_name , version , vm ) ) return - 1 ;
return 1 ;
}