2014-10-14 13:11:37 +00:00
/*
* This file is part of the Colobot : Gold Edition source code
2015-08-22 14:40:02 +00:00
* Copyright ( C ) 2001 - 2015 , Daniel Roux , EPSITEC SA & TerranovaTeam
* http : //epsitec.ch; http://colobot.info; http://github.com/colobot
2014-10-14 13:11:37 +00:00
*
* This program 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 , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program 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 this program . If not , see http : //gnu.org/licenses
*/
2012-06-26 20:23:05 +00:00
2012-09-10 21:29:38 +00:00
# include "script/script.h"
2012-06-26 20:23:05 +00:00
2014-12-20 17:45:46 +00:00
# include "common/restext.h"
# include "common/stringutils.h"
2014-12-20 17:03:49 +00:00
2015-08-02 11:09:48 +00:00
# include "common/resources/inputstream.h"
# include "common/resources/outputstream.h"
# include "common/resources/resourcemanager.h"
2014-12-20 17:45:46 +00:00
# include "graphics/engine/engine.h"
# include "graphics/engine/text.h"
2014-12-20 17:03:49 +00:00
2015-08-13 09:47:32 +00:00
# include "level/robotmain.h"
2015-07-12 11:46:25 +00:00
# include "object/old_object.h"
2014-12-20 17:03:49 +00:00
2014-12-20 17:45:46 +00:00
# include "script/cbottoken.h"
2014-12-20 17:03:49 +00:00
2015-08-02 11:09:48 +00:00
# include "ui/displaytext.h"
2015-08-10 11:46:39 +00:00
2015-08-06 11:25:24 +00:00
# include "ui/controls/edit.h"
# include "ui/controls/interface.h"
# include "ui/controls/list.h"
2014-12-20 17:03:49 +00:00
2015-11-22 17:29:25 +00:00
# include "CBot/CBot.h"
2014-12-20 17:03:49 +00:00
2014-12-20 17:45:46 +00:00
const int CBOT_IPF = 100 ; // CBOT: default number of instructions / frame
2012-06-26 20:23:05 +00:00
// Object's constructor.
2015-08-10 11:46:39 +00:00
CScript : : CScript ( COldObject * object )
2012-06-26 20:23:05 +00:00
{
2015-08-11 15:51:39 +00:00
assert ( object - > Implements ( ObjectInterfaceType : : Programmable ) ) ;
2015-08-10 11:46:39 +00:00
m_object = object ;
assert ( m_object - > Implements ( ObjectInterfaceType : : TaskExecutor ) ) ;
m_taskExecutor = dynamic_cast < CTaskExecutorObject * > ( m_object ) ;
2013-02-16 21:37:43 +00:00
m_engine = Gfx : : CEngine : : GetInstancePointer ( ) ;
m_main = CRobotMain : : GetInstancePointer ( ) ;
m_terrain = m_main - > GetTerrain ( ) ;
m_water = m_engine - > GetWater ( ) ;
2015-08-10 11:46:39 +00:00
m_interface = m_main - > GetInterface ( ) ;
2015-07-12 11:46:25 +00:00
2012-06-26 20:23:05 +00:00
m_ipf = CBOT_IPF ;
m_errMode = ERM_STOP ;
m_len = 0 ;
m_bRun = false ;
m_bStepMode = false ;
m_bCompile = false ;
m_title [ 0 ] = 0 ;
2014-11-10 21:42:05 +00:00
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
m_cursor1 = 0 ;
m_cursor2 = 0 ;
m_filename [ 0 ] = 0 ;
}
// Object's destructor.
CScript : : ~ CScript ( )
{
m_len = 0 ;
}
// Gives the script editable block of text.
2012-09-18 20:33:28 +00:00
void CScript : : PutScript ( Ui : : CEdit * edit , const char * name )
2012-06-26 20:23:05 +00:00
{
2012-12-28 12:37:08 +00:00
if ( m_script = = nullptr )
2012-06-26 20:23:05 +00:00
{
New ( edit , name ) ;
}
else
{
2015-08-14 21:11:24 +00:00
edit - > SetText ( m_script . get ( ) ) ;
2012-06-26 20:23:05 +00:00
edit - > SetCursor ( m_cursor2 , m_cursor1 ) ;
edit - > ShowSelect ( ) ;
}
2015-07-15 17:08:45 +00:00
m_interface - > SetFocus ( edit ) ;
2012-06-26 20:23:05 +00:00
}
// The script takes a paved text.
2012-09-10 21:29:38 +00:00
bool CScript : : GetScript ( Ui : : CEdit * edit )
2012-06-26 20:23:05 +00:00
{
2015-08-14 21:11:24 +00:00
int len = edit - > GetTextLength ( ) ;
m_script = MakeUniqueArray < char > ( len + 1 ) ;
2012-06-26 20:23:05 +00:00
2015-08-14 21:11:24 +00:00
edit - > GetText ( m_script . get ( ) , len + 1 ) ;
2012-06-26 20:23:05 +00:00
edit - > GetCursor ( m_cursor2 , m_cursor1 ) ;
2015-08-14 21:11:24 +00:00
m_len = strlen ( m_script . get ( ) ) ;
2012-06-26 20:23:05 +00:00
if ( ! CheckToken ( ) )
{
edit - > SetCursor ( m_cursor2 , m_cursor1 ) ;
edit - > ShowSelect ( ) ;
2015-07-15 17:08:45 +00:00
m_interface - > SetFocus ( edit ) ;
2012-06-26 20:23:05 +00:00
return false ;
}
if ( ! Compile ( ) )
{
edit - > SetCursor ( m_cursor2 , m_cursor1 ) ;
edit - > ShowSelect ( ) ;
2015-07-15 17:08:45 +00:00
m_interface - > SetFocus ( edit ) ;
2012-06-26 20:23:05 +00:00
return false ;
}
return true ;
}
// Indicates whether a program is compiled correctly.
2012-09-10 21:29:38 +00:00
bool CScript : : GetCompile ( )
2012-06-26 20:23:05 +00:00
{
return m_bCompile ;
}
// Indicates whether the program is empty.
bool CScript : : IsEmpty ( )
{
2015-08-14 21:11:24 +00:00
for ( int i = 0 ; i < m_len ; i + + )
2012-06-26 20:23:05 +00:00
{
if ( m_script [ i ] ! = ' ' & &
m_script [ i ] ! = ' \n ' ) return false ;
}
return true ;
}
// Checks if a program does not contain the prohibited instructions
// and if it contains well at least once every mandatory instructions.
bool CScript : : CheckToken ( )
{
2012-09-10 21:29:38 +00:00
if ( ! m_object - > GetCheckToken ( ) ) return true ;
2012-06-26 20:23:05 +00:00
2015-12-21 20:35:20 +00:00
m_error = CBotNoErr ;
2012-06-26 20:23:05 +00:00
m_title [ 0 ] = 0 ;
2014-11-10 21:42:05 +00:00
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
m_token [ 0 ] = 0 ;
m_bCompile = false ;
2015-12-23 15:46:41 +00:00
std : : vector < bool > used ( m_main - > GetObligatoryToken ( ) , false ) ;
2012-06-26 20:23:05 +00:00
2015-12-23 15:46:41 +00:00
auto tokens = CBotToken : : CompileTokens ( m_script . get ( ) ) ;
CBotToken * bt = tokens . get ( ) ;
2015-08-17 20:40:52 +00:00
while ( bt ! = nullptr )
2012-06-26 20:23:05 +00:00
{
2015-12-23 15:46:41 +00:00
std : : string token = bt - > GetString ( ) ;
int cursor1 = bt - > GetStart ( ) ;
int cursor2 = bt - > GetEnd ( ) ;
2012-06-26 20:23:05 +00:00
2015-12-23 15:46:41 +00:00
int i = m_main - > IsObligatoryToken ( token . c_str ( ) ) ;
2012-06-26 20:23:05 +00:00
if ( i ! = - 1 )
{
2015-12-23 15:46:41 +00:00
used [ i ] = true ; // token used
2012-06-26 20:23:05 +00:00
}
2015-12-20 15:19:10 +00:00
if ( ! m_main - > IsProhibitedToken ( token . c_str ( ) ) )
2012-06-26 20:23:05 +00:00
{
2015-12-21 20:35:20 +00:00
m_error = static_cast < CBotError > ( ERR_PROHIBITEDTOKEN ) ;
2012-06-26 20:23:05 +00:00
m_cursor1 = cursor1 ;
m_cursor2 = cursor2 ;
2014-11-10 21:42:05 +00:00
strcpy ( m_title , " <prohibited> " ) ;
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
return false ;
}
2012-09-10 21:29:38 +00:00
bt = bt - > GetNext ( ) ;
2012-06-26 20:23:05 +00:00
}
// At least once every obligatory instruction?
2015-12-23 15:46:41 +00:00
for ( unsigned int i = 0 ; i < used . size ( ) ; i + + )
2012-06-26 20:23:05 +00:00
{
2015-12-23 15:46:41 +00:00
if ( ! used [ i ] ) // token not used?
2012-06-26 20:23:05 +00:00
{
2012-09-10 21:29:38 +00:00
strcpy ( m_token , m_main - > GetObligatoryToken ( i ) ) ;
2015-12-21 20:35:20 +00:00
m_error = static_cast < CBotError > ( ERR_OBLIGATORYTOKEN ) ;
2014-11-10 21:42:05 +00:00
strcpy ( m_title , " <obligatory> " ) ;
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
return false ;
}
}
return true ;
}
// Compile the script of a paved text.
bool CScript : : Compile ( )
{
2015-12-20 15:19:10 +00:00
std : : vector < std : : string > functionList ;
2012-06-26 20:23:05 +00:00
int i ;
2015-12-20 15:19:10 +00:00
std : : string p ;
2012-06-26 20:23:05 +00:00
2015-12-21 20:35:20 +00:00
m_error = CBotNoErr ;
2012-06-26 20:23:05 +00:00
m_cursor1 = 0 ;
m_cursor2 = 0 ;
m_title [ 0 ] = 0 ;
2014-11-10 21:42:05 +00:00
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
m_bCompile = false ;
if ( IsEmpty ( ) ) // program exist?
{
2015-08-14 21:11:24 +00:00
m_botProg . reset ( ) ;
2012-06-26 20:23:05 +00:00
return true ;
}
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr )
2012-06-26 20:23:05 +00:00
{
2015-08-14 21:11:24 +00:00
m_botProg = MakeUnique < CBotProgram > ( m_object - > GetBotVar ( ) ) ;
2012-06-26 20:23:05 +00:00
}
2015-12-20 13:49:30 +00:00
if ( m_botProg - > Compile ( m_script . get ( ) , functionList , this ) )
2012-06-26 20:23:05 +00:00
{
2015-12-20 13:49:30 +00:00
if ( functionList . empty ( ) )
2012-06-26 20:23:05 +00:00
{
2013-05-19 15:03:55 +00:00
strcpy ( m_title , " <extern missing> " ) ;
2014-11-10 21:42:05 +00:00
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
}
else
{
2015-12-20 13:49:30 +00:00
p = functionList [ 0 ] ;
2012-06-26 20:23:05 +00:00
i = 0 ;
2014-11-10 21:42:05 +00:00
bool titleDone = false ;
2012-06-26 20:23:05 +00:00
while ( true )
{
if ( p [ i ] = = 0 | | p [ i ] = = ' ( ' ) break ;
2014-11-10 21:42:05 +00:00
if ( i > = 20 & & ! titleDone )
2012-06-26 20:23:05 +00:00
{
2014-11-10 21:42:05 +00:00
m_title [ i + 0 ] = ' . ' ;
m_title [ i + 1 ] = ' . ' ;
m_title [ i + 2 ] = ' . ' ;
m_title [ i + 3 ] = 0 ;
titleDone = true ;
2012-06-26 20:23:05 +00:00
}
2014-11-10 21:42:05 +00:00
if ( ! titleDone )
m_title [ i ] = p [ i ] ;
m_mainFunction [ i ] = p [ i ] ;
2012-06-26 20:23:05 +00:00
i + + ;
}
2014-11-10 21:42:05 +00:00
if ( ! titleDone )
m_title [ i ] = 0 ;
m_mainFunction [ i ] = p [ i ] ;
2012-06-26 20:23:05 +00:00
}
m_bCompile = true ;
return true ;
}
else
{
m_botProg - > GetError ( m_error , m_cursor1 , m_cursor2 ) ;
if ( m_cursor1 < 0 | | m_cursor1 > m_len | |
m_cursor2 < 0 | | m_cursor2 > m_len )
{
m_cursor1 = 0 ;
m_cursor2 = 0 ;
}
if ( m_error = = 0 )
{
m_cursor1 = m_cursor2 = 0 ;
}
2013-05-19 15:03:55 +00:00
strcpy ( m_title , " <error> " ) ;
2014-11-10 21:42:05 +00:00
m_mainFunction [ 0 ] = 0 ;
2012-06-26 20:23:05 +00:00
return false ;
}
}
// Returns the title of the script.
void CScript : : GetTitle ( char * buffer )
{
strcpy ( buffer , m_title ) ;
}
// Choice of mode of execution.
void CScript : : SetStepMode ( bool bStep )
{
m_bStepMode = bStep ;
}
2015-08-31 19:47:55 +00:00
bool CScript : : GetStepMode ( )
{
return m_bStepMode ;
}
2012-06-26 20:23:05 +00:00
// Runs the program from the beginning.
bool CScript : : Run ( )
{
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr ) return false ;
2012-12-28 12:37:08 +00:00
if ( m_script = = nullptr | | m_len = = 0 ) return false ;
2014-11-10 21:42:05 +00:00
if ( m_mainFunction [ 0 ] = = 0 ) return false ;
2015-07-12 11:46:25 +00:00
2014-11-10 21:42:05 +00:00
if ( ! m_botProg - > Start ( m_mainFunction ) ) return false ;
2012-06-26 20:23:05 +00:00
m_bRun = true ;
m_bContinue = false ;
m_ipf = CBOT_IPF ;
m_errMode = ERM_STOP ;
if ( m_bStepMode ) // step by step mode?
{
2015-08-10 11:46:39 +00:00
Step ( ) ;
2012-06-26 20:23:05 +00:00
}
return true ;
}
// Continues the execution of current program.
// Returns true when execution is finished.
2015-08-10 11:46:39 +00:00
bool CScript : : Continue ( )
2012-06-26 20:23:05 +00:00
{
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr ) return true ;
2012-06-26 20:23:05 +00:00
if ( ! m_bRun ) return true ;
if ( m_bStepMode ) // step by step mode?
{
if ( m_bContinue ) // instuction "move", "goto", etc. ?
{
2015-08-11 15:51:39 +00:00
if ( m_botProg - > Run ( this , 0 ) )
2012-06-26 20:23:05 +00:00
{
m_botProg - > GetError ( m_error , m_cursor1 , m_cursor2 ) ;
if ( m_cursor1 < 0 | | m_cursor1 > m_len | |
m_cursor2 < 0 | | m_cursor2 > m_len )
{
m_cursor1 = 0 ;
m_cursor2 = 0 ;
}
if ( m_error = = 0 )
{
m_cursor1 = m_cursor2 = 0 ;
}
m_bRun = false ;
if ( m_error ! = 0 & & m_errMode = = ERM_STOP )
{
2013-12-02 23:11:26 +00:00
std : : string s ;
2012-06-26 20:23:05 +00:00
GetError ( s ) ;
2013-12-02 23:11:26 +00:00
m_main - > GetDisplayText ( ) - > DisplayText ( s . c_str ( ) , m_object , 10.0f , Ui : : TT_ERROR ) ;
2012-06-26 20:23:05 +00:00
}
return true ;
}
}
return false ;
}
2015-08-11 15:51:39 +00:00
if ( m_botProg - > Run ( this , m_ipf ) )
2012-06-26 20:23:05 +00:00
{
m_botProg - > GetError ( m_error , m_cursor1 , m_cursor2 ) ;
if ( m_cursor1 < 0 | | m_cursor1 > m_len | |
m_cursor2 < 0 | | m_cursor2 > m_len )
{
m_cursor1 = 0 ;
m_cursor2 = 0 ;
}
if ( m_error = = 0 )
{
m_cursor1 = m_cursor2 = 0 ;
}
m_bRun = false ;
if ( m_error ! = 0 & & m_errMode = = ERM_STOP )
{
2013-12-02 23:11:26 +00:00
std : : string s ;
2012-06-26 20:23:05 +00:00
GetError ( s ) ;
2013-12-02 23:11:26 +00:00
m_main - > GetDisplayText ( ) - > DisplayText ( s . c_str ( ) , m_object , 10.0f , Ui : : TT_ERROR ) ;
2012-06-26 20:23:05 +00:00
}
return true ;
}
return false ;
}
// Continues the execution of current program.
// Returns true when execution is finished.
2015-08-10 11:46:39 +00:00
bool CScript : : Step ( )
2012-06-26 20:23:05 +00:00
{
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr ) return true ;
2012-06-26 20:23:05 +00:00
if ( ! m_bRun ) return true ;
if ( ! m_bStepMode ) return false ;
2015-08-11 15:51:39 +00:00
if ( m_botProg - > Run ( this , 0 ) ) // step mode
2012-06-26 20:23:05 +00:00
{
m_botProg - > GetError ( m_error , m_cursor1 , m_cursor2 ) ;
if ( m_cursor1 < 0 | | m_cursor1 > m_len | |
m_cursor2 < 0 | | m_cursor2 > m_len )
{
m_cursor1 = 0 ;
m_cursor2 = 0 ;
}
if ( m_error = = 0 )
{
m_cursor1 = m_cursor2 = 0 ;
}
m_bRun = false ;
if ( m_error ! = 0 & & m_errMode = = ERM_STOP )
{
2013-12-02 23:11:26 +00:00
std : : string s ;
2012-06-26 20:23:05 +00:00
GetError ( s ) ;
2013-12-02 23:11:26 +00:00
m_main - > GetDisplayText ( ) - > DisplayText ( s . c_str ( ) , m_object , 10.0f , Ui : : TT_ERROR ) ;
2012-06-26 20:23:05 +00:00
}
return true ;
}
return false ;
}
// Stops the program.
void CScript : : Stop ( )
{
if ( ! m_bRun ) return ;
2015-08-12 14:54:44 +00:00
m_taskExecutor - > StopForegroundTask ( ) ;
2015-08-14 21:11:24 +00:00
if ( m_botProg ! = nullptr )
2012-06-26 20:23:05 +00:00
{
m_botProg - > Stop ( ) ;
}
m_bRun = false ;
}
// Indicates whether the program runs.
bool CScript : : IsRunning ( )
{
return m_bRun ;
}
// Indicates whether the program continues a step.
bool CScript : : IsContinue ( )
{
return m_bContinue ;
}
// Gives the position of the cursor during the execution.
bool CScript : : GetCursor ( int & cursor1 , int & cursor2 )
{
2015-12-20 15:19:10 +00:00
std : : string funcName ;
2012-06-26 20:23:05 +00:00
cursor1 = cursor2 = 0 ;
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr ) return false ;
2012-06-26 20:23:05 +00:00
if ( ! m_bRun ) return false ;
m_botProg - > GetRunPos ( funcName , cursor1 , cursor2 ) ;
if ( cursor1 < 0 | | cursor1 > m_len | |
cursor2 < 0 | | cursor2 > m_len )
{
cursor1 = 0 ;
cursor2 = 0 ;
}
return true ;
}
// Put of the variables in a list.
2012-09-10 21:29:38 +00:00
void PutList ( const char * baseName , bool bArray , CBotVar * var , Ui : : CList * list , int & rankList )
2012-06-26 20:23:05 +00:00
{
CBotVar * svar , * pStatic ;
char varName [ 100 ] ;
char buffer [ 100 ] ;
2015-12-20 15:19:10 +00:00
std : : string p ;
2012-06-26 20:23:05 +00:00
int index , type ;
2015-08-17 20:40:52 +00:00
if ( var = = nullptr & & baseName [ 0 ] ! = 0 )
2012-06-26 20:23:05 +00:00
{
sprintf ( buffer , " %s = null; " , baseName ) ;
2013-05-26 15:45:15 +00:00
list - > SetItemName ( rankList + + , buffer ) ;
2012-06-26 20:23:05 +00:00
return ;
}
index = 0 ;
2015-08-17 20:40:52 +00:00
while ( var ! = nullptr )
2012-06-26 20:23:05 +00:00
{
2015-08-16 10:43:42 +00:00
var - > Maj ( nullptr , false ) ;
2012-09-10 21:29:38 +00:00
pStatic = var - > GetStaticVar ( ) ; // finds the static element
2012-06-26 20:23:05 +00:00
2015-12-20 15:19:10 +00:00
p = pStatic - > GetName ( ) ; // variable name
2012-06-26 20:23:05 +00:00
//? if ( strcmp(p, "this") == 0 )
//? {
2012-09-10 21:29:38 +00:00
//? var = var->GetNext();
2012-06-26 20:23:05 +00:00
//? continue;
//? }
if ( baseName [ 0 ] = = 0 )
{
2015-12-20 15:19:10 +00:00
sprintf ( varName , " %s " , p . c_str ( ) ) ;
2012-06-26 20:23:05 +00:00
}
else
{
if ( bArray )
{
sprintf ( varName , " %s[%d] " , baseName , index ) ;
}
else
{
2015-12-20 15:19:10 +00:00
sprintf ( varName , " %s.%s " , baseName , p . c_str ( ) ) ;
2012-06-26 20:23:05 +00:00
}
}
2012-09-10 21:29:38 +00:00
type = pStatic - > GetType ( ) ;
2012-06-26 20:23:05 +00:00
if ( type < CBotTypBoolean )
{
2015-12-20 15:19:10 +00:00
p = pStatic - > GetValString ( ) ;
sprintf ( buffer , " %s = %s; " , varName , p . c_str ( ) ) ;
2013-05-26 15:45:15 +00:00
list - > SetItemName ( rankList + + , buffer ) ;
2012-06-26 20:23:05 +00:00
}
else if ( type = = CBotTypString )
{
2015-12-20 15:19:10 +00:00
p = pStatic - > GetValString ( ) ;
sprintf ( buffer , " %s = \" %s \" ; " , varName , p . c_str ( ) ) ;
2013-05-26 15:45:15 +00:00
list - > SetItemName ( rankList + + , buffer ) ;
2012-06-26 20:23:05 +00:00
}
else if ( type = = CBotTypArrayPointer )
{
2012-09-10 21:29:38 +00:00
svar = pStatic - > GetItemList ( ) ;
2012-06-26 20:23:05 +00:00
PutList ( varName , true , svar , list , rankList ) ;
}
else if ( type = = CBotTypClass | |
type = = CBotTypPointer )
{
2012-09-10 21:29:38 +00:00
svar = pStatic - > GetItemList ( ) ;
2012-06-26 20:23:05 +00:00
PutList ( varName , false , svar , list , rankList ) ;
}
else
{
sprintf ( buffer , " %s = ?; " , varName ) ;
2013-05-26 15:45:15 +00:00
list - > SetItemName ( rankList + + , buffer ) ;
2012-06-26 20:23:05 +00:00
}
index + + ;
2012-09-10 21:29:38 +00:00
var = var - > GetNext ( ) ;
2012-06-26 20:23:05 +00:00
}
}
// Fills a list with variables.
2012-09-10 21:29:38 +00:00
void CScript : : UpdateList ( Ui : : CList * list )
2012-06-26 20:23:05 +00:00
{
CBotVar * var ;
2015-12-20 15:19:10 +00:00
std : : string progName , funcName ;
2012-06-26 20:23:05 +00:00
int total , select , level , cursor1 , cursor2 , rank ;
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr ) return ;
2012-06-26 20:23:05 +00:00
2012-09-10 21:29:38 +00:00
total = list - > GetTotal ( ) ;
select = list - > GetSelect ( ) ;
2012-06-26 20:23:05 +00:00
list - > Flush ( ) ; // empty list
m_botProg - > GetRunPos ( progName , cursor1 , cursor2 ) ;
2015-12-20 15:19:10 +00:00
if ( progName . empty ( ) ) return ;
2012-06-26 20:23:05 +00:00
level = 0 ;
rank = 0 ;
while ( true )
{
2012-09-10 21:29:38 +00:00
var = m_botProg - > GetStackVars ( funcName , level - - ) ;
2012-06-26 20:23:05 +00:00
if ( funcName ! = progName ) break ;
PutList ( " " , false , var , list , rank ) ;
}
2012-09-10 21:29:38 +00:00
if ( total = = list - > GetTotal ( ) ) // same total?
2012-06-26 20:23:05 +00:00
{
list - > SetSelect ( select ) ;
}
list - > SetTooltip ( " " ) ;
2012-09-10 21:29:38 +00:00
list - > SetState ( Ui : : STATE_ENABLE ) ;
2012-06-26 20:23:05 +00:00
}
// Colorize the text according to syntax.
2015-08-18 18:28:12 +00:00
void CScript : : ColorizeScript ( Ui : : CEdit * edit , int rangeStart , int rangeEnd )
2012-06-26 20:23:05 +00:00
{
2015-08-18 18:28:12 +00:00
if ( rangeEnd > edit - > GetMaxChar ( ) )
rangeEnd = edit - > GetMaxChar ( ) ;
2012-06-26 20:23:05 +00:00
2015-08-18 18:28:12 +00:00
edit - > SetFormat ( rangeStart , rangeEnd , Gfx : : FONT_HIGHLIGHT_COMMENT ) ; // anything not processed is a comment
2012-06-26 20:23:05 +00:00
2015-08-25 09:22:02 +00:00
// NOTE: Images are registered as index in some array, and that can be 0 which normally ends the string!
std : : string text = std : : string ( edit - > GetText ( ) , edit - > GetMaxChar ( ) ) ;
2015-08-18 18:28:12 +00:00
text = text . substr ( rangeStart , rangeEnd - rangeStart ) ;
2015-12-23 15:46:41 +00:00
auto tokens = CBotToken : : CompileTokens ( text . c_str ( ) ) ;
CBotToken * bt = tokens . get ( ) ;
2015-08-17 20:40:52 +00:00
while ( bt ! = nullptr )
2012-06-26 20:23:05 +00:00
{
2015-12-20 15:19:10 +00:00
std : : string token = bt - > GetString ( ) ;
2015-08-18 18:28:12 +00:00
int type = bt - > GetType ( ) ;
2012-06-26 20:23:05 +00:00
2015-08-18 18:28:12 +00:00
int cursor1 = bt - > GetStart ( ) ;
int cursor2 = bt - > GetEnd ( ) ;
2015-08-18 14:00:44 +00:00
if ( cursor1 < 0 | | cursor2 < 0 | | cursor1 = = cursor2 | | type = = 0 ) { bt = bt - > GetNext ( ) ; continue ; } // seems to be a bug in CBot engine (how does it even still work? D:)
2015-08-18 18:28:12 +00:00
cursor1 + = rangeStart ;
cursor2 + = rangeStart ;
Gfx : : FontHighlight color = Gfx : : FONT_HIGHLIGHT_NONE ;
2015-12-20 15:19:10 +00:00
if ( ( type = = TokenTypVar | | ( type > = TokenKeyWord & & type < TokenKeyWord + 100 ) ) & & IsType ( token . c_str ( ) ) ) // types (basic types are TokenKeyWord, classes are TokenTypVar)
2015-08-18 14:00:44 +00:00
{
color = Gfx : : FONT_HIGHLIGHT_TYPE ;
}
2015-12-20 15:19:10 +00:00
else if ( type = = TokenTypVar & & IsFunction ( token . c_str ( ) ) ) // functions
2012-06-26 20:23:05 +00:00
{
2012-09-10 21:29:38 +00:00
color = Gfx : : FONT_HIGHLIGHT_TOKEN ;
2012-06-26 20:23:05 +00:00
}
2015-12-20 15:19:10 +00:00
else if ( type = = TokenTypVar & & ( token = = " this " | | token = = " super " ) ) // this, super
2015-08-18 14:00:44 +00:00
{
color = Gfx : : FONT_HIGHLIGHT_THIS ;
}
else if ( type > = TokenKeyWord & & type < TokenKeyWord + 100 ) // builtin keywords
{
color = Gfx : : FONT_HIGHLIGHT_KEYWORD ;
}
else if ( type > = TokenKeyVal & & type < TokenKeyVal + 100 ) // true, false, null, nan
2012-06-26 20:23:05 +00:00
{
2012-09-10 21:29:38 +00:00
color = Gfx : : FONT_HIGHLIGHT_CONST ;
2012-06-26 20:23:05 +00:00
}
2015-08-18 14:00:44 +00:00
else if ( type = = TokenTypDef ) // constants (object types etc.)
2012-06-26 20:23:05 +00:00
{
2015-08-18 14:00:44 +00:00
color = Gfx : : FONT_HIGHLIGHT_CONST ;
2012-06-26 20:23:05 +00:00
}
2015-08-18 14:00:44 +00:00
else if ( type = = TokenTypString | | type = = TokenTypNum ) // string literals and numbers
2012-06-26 20:23:05 +00:00
{
2015-08-18 14:00:44 +00:00
color = Gfx : : FONT_HIGHLIGHT_STRING ;
2012-06-26 20:23:05 +00:00
}
2015-08-18 14:00:44 +00:00
assert ( cursor1 < cursor2 ) ;
edit - > SetFormat ( cursor1 , cursor2 , color ) ;
2012-06-26 20:23:05 +00:00
2012-09-10 21:29:38 +00:00
bt = bt - > GetNext ( ) ;
2012-06-26 20:23:05 +00:00
}
}
// Seeks a token at random in a script.
// Returns the index of the start of the token found, or -1.
2012-09-10 21:29:38 +00:00
int SearchToken ( char * script , const char * token )
2012-06-26 20:23:05 +00:00
{
int lScript , lToken , i , iFound ;
int found [ 100 ] ;
char * p ;
lScript = strlen ( script ) ;
lToken = strlen ( token ) ;
iFound = 0 ;
for ( i = 0 ; i < lScript - lToken ; i + + )
{
p = strstr ( script + i , token ) ;
2015-08-17 20:40:52 +00:00
if ( p ! = nullptr )
2012-06-26 20:23:05 +00:00
{
found [ iFound + + ] = p - script ;
if ( iFound > = 100 ) break ;
}
}
if ( iFound = = 0 ) return - 1 ;
return found [ rand ( ) % iFound ] ;
}
// Removes a token in a script.
void DeleteToken ( char * script , int pos , int len )
{
while ( true )
{
script [ pos ] = script [ pos + len ] ;
if ( script [ pos + + ] = = 0 ) break ;
}
}
// Inserts a token in a script.
2012-09-10 21:29:38 +00:00
void InsertToken ( char * script , int pos , const char * token )
2012-06-26 20:23:05 +00:00
{
int lScript , lToken , i ;
lScript = strlen ( script ) ;
lToken = strlen ( token ) ;
for ( i = lScript ; i > = pos ; i - - )
{
script [ i + lToken ] = script [ i ] ;
}
memcpy ( script + pos , token , lToken ) ;
}
// Introduces a virus into a program.
bool CScript : : IntroduceVirus ( )
{
2015-08-06 20:50:22 +00:00
if ( m_script = = nullptr ) return false ;
2012-06-26 20:23:05 +00:00
2012-09-10 21:29:38 +00:00
const char * names [ 11 * 2 ] =
2012-06-26 20:23:05 +00:00
{
" == " , " != " ,
" != " , " == " ,
" > " , " < " ,
" < " , " > " ,
" true " , " false " ,
" false " , " true " ,
" grab " , " drop " ,
" drop " , " grab " ,
" InFront " , " Behind " ,
" Behind " , " EnergyCell " ,
" EnergyCell " , " InFront " ,
} ;
2015-08-06 20:50:22 +00:00
int iFound = 0 ;
int found [ 11 * 2 ] ;
for ( int i = 0 ; i < 11 ; i + + )
2012-06-26 20:23:05 +00:00
{
2015-08-14 21:11:24 +00:00
int start = SearchToken ( m_script . get ( ) , names [ i * 2 ] ) ;
2012-06-26 20:23:05 +00:00
if ( start ! = - 1 )
{
found [ iFound + + ] = i * 2 ;
found [ iFound + + ] = start ;
}
}
if ( iFound = = 0 ) return false ;
2015-08-06 20:50:22 +00:00
int i = ( rand ( ) % ( iFound / 2 ) ) * 2 ;
int start = found [ i + 1 ] ;
2012-06-26 20:23:05 +00:00
i = found [ i + 0 ] ;
2015-08-14 21:11:24 +00:00
auto newScript = MakeUniqueArray < char > ( m_len + strlen ( names [ i + 1 ] ) + 1 ) ;
strcpy ( newScript . get ( ) , m_script . get ( ) ) ;
m_script = std : : move ( newScript ) ;
2012-06-26 20:23:05 +00:00
2015-08-14 21:11:24 +00:00
DeleteToken ( m_script . get ( ) , start , strlen ( names [ i ] ) ) ;
InsertToken ( m_script . get ( ) , start , names [ i + 1 ] ) ;
m_len = strlen ( m_script . get ( ) ) ;
2012-06-26 20:23:05 +00:00
Compile ( ) ; // recompile with the virus
return true ;
}
// Returns the number of the error.
2012-09-10 21:29:38 +00:00
int CScript : : GetError ( )
2012-06-26 20:23:05 +00:00
{
return m_error ;
}
// Returns the text of the error.
2013-12-02 23:11:26 +00:00
void CScript : : GetError ( std : : string & error )
2012-06-26 20:23:05 +00:00
{
if ( m_error = = 0 )
{
2013-12-02 23:11:26 +00:00
error . clear ( ) ;
2012-06-26 20:23:05 +00:00
}
else
{
2015-12-21 20:35:20 +00:00
if ( m_error = = static_cast < CBotError > ( ERR_OBLIGATORYTOKEN ) )
2012-06-26 20:23:05 +00:00
{
2013-12-02 23:11:26 +00:00
std : : string s ;
2012-06-26 20:23:05 +00:00
GetResource ( RES_ERR , m_error , s ) ;
2013-12-02 23:11:26 +00:00
error = StrUtils : : Format ( s . c_str ( ) , m_token ) ;
2012-06-26 20:23:05 +00:00
}
else if ( m_error < 1000 )
{
2013-12-02 23:11:26 +00:00
GetResource ( RES_ERR , m_error , error ) ;
2012-06-26 20:23:05 +00:00
}
else
{
2013-12-02 23:11:26 +00:00
GetResource ( RES_CBOT , m_error , error ) ;
2012-06-26 20:23:05 +00:00
}
}
}
// New program.
2012-09-18 20:33:28 +00:00
void CScript : : New ( Ui : : CEdit * edit , const char * name )
2012-06-26 20:23:05 +00:00
{
char res [ 100 ] ;
char text [ 100 ] ;
char script [ 500 ] ;
char buffer [ 500 ] ;
int cursor1 , cursor2 , len , i , j ;
2013-12-02 23:11:26 +00:00
std : : string resStr ;
GetResource ( RES_TEXT , RT_SCRIPT_NEW , resStr ) ;
strcpy ( res , resStr . c_str ( ) ) ;
2012-06-26 20:23:05 +00:00
if ( name [ 0 ] = = 0 ) strcpy ( text , res ) ;
else strcpy ( text , name ) ;
sprintf ( script , " extern void object::%s() \n { \n \t \n \t \n \t \n } \n " , text ) ;
edit - > SetText ( script , false ) ;
if ( strcmp ( text , res ) = = 0 )
{
cursor1 = 20 ;
cursor2 = 20 + strlen ( text ) ; // update "New"
}
else
{
2012-09-10 21:29:38 +00:00
if ( edit - > GetAutoIndent ( ) )
2012-06-26 20:23:05 +00:00
{
cursor1 = 20 + strlen ( text ) + 6 ;
cursor2 = cursor1 ; // cursor in { }
}
else
{
cursor1 = 20 + strlen ( text ) + 8 ;
cursor2 = cursor1 ; // cursor in { }
}
}
edit - > SetCursor ( cursor2 , cursor1 ) ;
edit - > ShowSelect ( ) ;
2015-07-15 17:08:45 +00:00
m_interface - > SetFocus ( edit ) ;
2012-06-26 21:01:17 +00:00
2015-10-01 17:37:31 +00:00
std : : string sf = m_main - > GetScriptFile ( ) ;
if ( ! sf . empty ( ) ) // Load an empty program specific?
2012-06-26 20:23:05 +00:00
{
2014-06-22 19:30:23 +00:00
CInputStream stream ;
2015-10-01 17:37:31 +00:00
stream . open ( sf ) ;
2014-06-22 19:30:23 +00:00
if ( stream . is_open ( ) )
2012-06-26 20:23:05 +00:00
{
2014-06-22 19:30:23 +00:00
len = stream . size ( ) ;
2012-06-26 20:23:05 +00:00
if ( len > 500 - 1 ) len = 500 - 1 ;
2014-06-22 19:30:23 +00:00
stream . read ( buffer , len ) ;
2012-06-26 20:23:05 +00:00
buffer [ len ] = 0 ;
2014-06-22 19:30:23 +00:00
stream . close ( ) ;
2012-06-26 20:23:05 +00:00
cursor1 = 0 ;
i = 0 ;
j = 0 ;
while ( true )
{
if ( buffer [ i ] = = 0 ) break ;
if ( buffer [ i ] = = ' \r ' )
{
i + + ;
continue ;
}
2012-09-10 21:29:38 +00:00
if ( buffer [ i ] = = ' \t ' & & edit - > GetAutoIndent ( ) )
2012-06-26 20:23:05 +00:00
{
i + + ;
continue ;
}
if ( buffer [ i + 0 ] = = ' % ' & &
buffer [ i + 1 ] = = ' s ' )
{
strcpy ( script + j , text ) ;
j + = strlen ( text ) ;
i + = 2 ;
continue ;
}
if ( buffer [ i ] = = ' # ' )
{
cursor1 = j ;
i + + ;
continue ;
}
script [ j + + ] = buffer [ i + + ] ;
}
script [ j ] = 0 ;
edit - > SetText ( script , false ) ;
cursor2 = cursor1 ;
edit - > SetCursor ( cursor2 , cursor1 ) ;
edit - > ShowSelect ( ) ;
2015-07-15 17:08:45 +00:00
m_interface - > SetFocus ( edit ) ;
2012-06-26 20:23:05 +00:00
}
}
ColorizeScript ( edit ) ;
}
// Provided a script for all parts.
2013-05-19 14:25:53 +00:00
bool CScript : : SendScript ( const char * text )
2012-06-26 20:23:05 +00:00
{
2013-05-19 14:25:53 +00:00
/*m_len = strlen(text);
2012-12-28 12:37:08 +00:00
m_script = new char [ m_len + 1 ] ;
2012-06-26 20:23:05 +00:00
strcpy ( m_script , text ) ;
if ( ! CheckToken ( ) ) return false ;
2013-05-19 14:25:53 +00:00
if ( ! Compile ( ) ) return false ; */
Ui : : CEdit * edit = m_interface - > CreateEdit ( Math : : Point ( 0.0f , 0.0f ) , Math : : Point ( 0.0f , 0.0f ) , 0 , EVENT_EDIT9 ) ;
edit - > SetMaxChar ( Ui : : EDITSTUDIOMAX ) ;
edit - > SetAutoIndent ( m_engine - > GetEditIndentMode ( ) ) ;
edit - > SetText ( text , true ) ;
GetScript ( edit ) ;
m_interface - > DeleteControl ( EVENT_EDIT9 ) ;
2012-06-26 20:23:05 +00:00
return true ;
}
// Reads a script as a text file.
2012-09-15 16:50:51 +00:00
bool CScript : : ReadScript ( const char * filename )
2012-06-26 20:23:05 +00:00
{
2012-09-10 21:29:38 +00:00
Ui : : CEdit * edit ;
2012-06-26 20:23:05 +00:00
2014-06-22 19:30:23 +00:00
if ( ! CResourceManager : : Exists ( filename ) ) return false ;
2012-06-26 20:23:05 +00:00
2015-08-14 21:11:24 +00:00
m_script . reset ( ) ;
2012-06-26 20:23:05 +00:00
edit = m_interface - > CreateEdit ( Math : : Point ( 0.0f , 0.0f ) , Math : : Point ( 0.0f , 0.0f ) , 0 , EVENT_EDIT9 ) ;
2012-09-10 21:29:38 +00:00
edit - > SetMaxChar ( Ui : : EDITSTUDIOMAX ) ;
edit - > SetAutoIndent ( m_engine - > GetEditIndentMode ( ) ) ;
2014-06-20 21:41:38 +00:00
edit - > ReadText ( filename ) ;
2012-06-26 20:23:05 +00:00
GetScript ( edit ) ;
m_interface - > DeleteControl ( EVENT_EDIT9 ) ;
return true ;
}
// Writes a script as a text file.
2012-09-15 16:50:51 +00:00
bool CScript : : WriteScript ( const char * filename )
2012-06-26 20:23:05 +00:00
{
2012-12-28 12:37:08 +00:00
if ( m_script = = nullptr )
2012-06-26 20:23:05 +00:00
{
2015-03-29 12:21:02 +00:00
CResourceManager : : Remove ( filename ) ;
2012-06-26 20:23:05 +00:00
return false ;
}
2015-08-14 21:11:24 +00:00
Ui : : CEdit * edit = m_interface - > CreateEdit ( Math : : Point ( 0.0f , 0.0f ) , Math : : Point ( 0.0f , 0.0f ) , 0 , EVENT_EDIT9 ) ;
2012-09-10 21:29:38 +00:00
edit - > SetMaxChar ( Ui : : EDITSTUDIOMAX ) ;
edit - > SetAutoIndent ( m_engine - > GetEditIndentMode ( ) ) ;
2015-08-14 21:11:24 +00:00
edit - > SetText ( m_script . get ( ) ) ;
2014-06-20 21:41:38 +00:00
edit - > WriteText ( filename ) ;
2012-06-26 20:23:05 +00:00
m_interface - > DeleteControl ( EVENT_EDIT9 ) ;
return true ;
}
// Reads a stack of script by execution as a file.
bool CScript : : ReadStack ( FILE * file )
{
int nb ;
fRead ( & nb , sizeof ( int ) , 1 , file ) ;
fRead ( & m_ipf , sizeof ( int ) , 1 , file ) ;
fRead ( & m_errMode , sizeof ( int ) , 1 , file ) ;
2015-08-14 21:11:24 +00:00
if ( m_botProg = = nullptr ) return false ;
2012-06-26 20:23:05 +00:00
if ( ! m_botProg - > RestoreState ( file ) ) return false ;
2012-06-26 21:01:17 +00:00
2012-06-26 20:23:05 +00:00
m_bRun = true ;
m_bContinue = false ;
return true ;
}
// Writes a stack of script by execution as a file.
bool CScript : : WriteStack ( FILE * file )
{
int nb ;
nb = 2 ;
fWrite ( & nb , sizeof ( int ) , 1 , file ) ;
fWrite ( & m_ipf , sizeof ( int ) , 1 , file ) ;
fWrite ( & m_errMode , sizeof ( int ) , 1 , file ) ;
return m_botProg - > SaveState ( file ) ;
}
// Compares two scripts.
bool CScript : : Compare ( CScript * other )
{
if ( m_len ! = other - > m_len ) return false ;
2015-08-14 21:11:24 +00:00
return ( strcmp ( m_script . get ( ) , other - > m_script . get ( ) ) = = 0 ) ;
2012-06-26 20:23:05 +00:00
}
// Management of the file name when the script is saved.
void CScript : : SetFilename ( char * filename )
{
strcpy ( m_filename , filename ) ;
}
2012-09-10 21:29:38 +00:00
char * CScript : : GetFilename ( )
2012-06-26 20:23:05 +00:00
{
return m_filename ;
}