2015-05-01 07:50:34 -06:00
#include "global.h"
#include "ActorUtil.h"
#include "IniFile.h"
#include "RageFile.h"
#include "RageFileManager.h"
#include "RageLog.h"
#include "RageTypes.h"
#include "LuaManager.h"
#include "LuaBinding.h"
#include "XmlFile.h"
#include "XmlFileUtil.h"
2023-04-19 23:04:25 +02:00
#include <cstddef>
2015-05-01 07:50:34 -06:00
#include <map>
#include <set>
2023-04-19 23:04:25 +02:00
#include <vector>
2015-05-01 07:50:34 -06:00
#define TWEEN_QUEUE_MAX 50
RString unique_name ();
void convert_xmls_in_dir ( RString const & dirname );
void convert_xml_file ( RString const & fname , RString const & dirname );
RString maybe_conv_pos ( RString pos , RString ( * conv_func )( float p ));
RString add_extension_to_relative_path_from_found_file (
RString const & relative_path , RString const & found_file );
RString unique_name ( RString const & type )
{
static char const * name_chars = "abcdefghijklmnopqrstuvwxyz" ;
static int name_count = 0 ;
int curr_name = name_count ;
RString ret = "xtl_" + type + "_" ; // Minimize the chance of a name collision.
ret = ret + name_chars [ curr_name % 26 ];
while ( curr_name / 26 > 0 )
{
curr_name = curr_name / 26 ;
ret = ret + name_chars [ curr_name % 26 ];
}
++ name_count ;
return ret ;
}
void convert_xmls_in_dir ( RString const & dirname )
{
2022-07-10 18:28:56 +03:00
std :: vector < RString > listing ;
2015-05-01 07:50:34 -06:00
FILEMAN -> GetDirListing ( dirname , listing , false , true );
2022-07-10 18:28:56 +03:00
for ( std :: vector < RString >:: iterator curr_file = listing . begin ();
2015-05-01 07:50:34 -06:00
curr_file != listing . end (); ++ curr_file )
{
switch ( ActorUtil :: GetFileType ( * curr_file ))
{
case FT_Xml :
convert_xml_file ( * curr_file , dirname );
break ;
case FT_Directory :
convert_xmls_in_dir (( * curr_file ) + "/" );
break ;
default : // Ignore anything not xml or directory.
break ;
}
}
}
RString convert_xpos ( float x )
{
2019-06-22 12:35:38 -07:00
return "SCREEN_CENTER_X + " + std :: to_string ( x - 320.0f );
2015-05-01 07:50:34 -06:00
}
RString convert_ypos ( float y )
{
2019-06-22 12:35:38 -07:00
return "SCREEN_CENTER_Y + " + std :: to_string ( y - 240.0f );
2015-05-01 07:50:34 -06:00
}
RString maybe_conv_pos ( RString pos , RString ( * conv_func )( float p ))
{
float f ;
if ( pos >> f )
{
return conv_func ( f );
}
return pos ;
}
2023-04-19 23:04:25 +02:00
std :: size_t after_slash_or_zero ( RString const & s )
2015-05-01 07:50:34 -06:00
{
2023-04-19 23:04:25 +02:00
std :: size_t ret = s . rfind ( '/' );
2022-07-10 18:28:56 +03:00
if ( ret != std :: string :: npos )
2015-05-01 07:50:34 -06:00
{
return ret + 1 ;
}
return 0 ;
}
RString add_extension_to_relative_path_from_found_file (
RString const & relative_path , RString const & found_file )
{
2023-04-19 23:04:25 +02:00
std :: size_t rel_last_slash = after_slash_or_zero ( relative_path );
std :: size_t found_last_slash = after_slash_or_zero ( found_file );
2015-05-01 07:50:34 -06:00
return relative_path . Left ( rel_last_slash ) +
2022-07-10 18:28:56 +03:00
found_file . substr ( found_last_slash , std :: string :: npos );
2015-05-01 07:50:34 -06:00
}
2023-04-19 23:04:25 +02:00
bool verify_arg_count ( RString cmd , std :: vector < RString >& args , std :: size_t req )
2015-05-01 07:50:34 -06:00
{
if ( args . size () < req )
{
LuaHelpers :: ReportScriptError ( "Not enough args to " + cmd + " command." );
return false ;
}
return true ;
}
2022-07-10 18:28:56 +03:00
typedef void ( * arg_converter_t )( std :: vector < RString >& args );
2015-05-01 07:50:34 -06:00
2022-07-10 18:28:56 +03:00
std :: map < RString , arg_converter_t > arg_converters ;
2023-04-19 23:04:25 +02:00
std :: map < RString , std :: size_t > tween_counters ;
2022-07-10 18:28:56 +03:00
std :: set < RString > fields_that_are_strings ;
std :: map < RString , RString > chunks_to_replace ;
2015-05-01 07:50:34 -06:00
#define COMMON_ARG_VERIFY(count) if(!verify_arg_count(args[0], args, count)) return;
2022-07-10 18:28:56 +03:00
void x_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
float pos ;
if ( args [ 1 ] >> pos )
{
args [ 1 ] = convert_xpos ( pos );
}
}
2022-07-10 18:28:56 +03:00
void y_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
float pos ;
if ( args [ 1 ] >> pos )
{
args [ 1 ] = convert_ypos ( pos );
}
}
2022-07-10 18:28:56 +03:00
void string_arg_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
args [ 1 ] = " \" " + args [ 1 ] + " \" " ;
}
2022-07-10 18:28:56 +03:00
void lower_string_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
args [ 0 ]. MakeLower ();
}
2022-07-10 18:28:56 +03:00
void hidden_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
args [ 0 ] = "visible" ;
if ( args [ 1 ] == "1" )
{
2016-08-05 12:01:48 -06:00
args [ 1 ] = "false" ;
2015-05-01 07:50:34 -06:00
}
else
{
2016-08-05 12:01:48 -06:00
args [ 1 ] = "true" ;
2015-05-01 07:50:34 -06:00
}
}
2022-07-10 18:28:56 +03:00
void diffuse_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
RString retarg ;
2023-04-19 23:04:25 +02:00
for ( std :: size_t i = 1 ; i < args . size (); ++ i )
2015-05-01 07:50:34 -06:00
{
retarg += args [ i ];
if ( i < args . size () - 1 )
{
retarg += "," ;
}
}
args [ 1 ] = "color('" + retarg + "')" ;
args . resize ( 2 );
}
// Prototype for a function that is created by a macro in another translation unit and has no visible prototype, don't do this unless you have a good reason.
const RString & BlendModeToString ( BlendMode );
const RString & CullModeToString ( CullMode );
2022-07-10 18:28:56 +03:00
void blend_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
for ( int i = 0 ; i < NUM_BlendMode ; ++ i )
{
RString blend_str = BlendModeToString ( static_cast < BlendMode > ( i ));
blend_str . MakeLower ();
if ( args [ 1 ] == blend_str )
{
args [ 1 ] = " \" BlendMode_" + BlendModeToString ( static_cast < BlendMode > ( i )) + " \" " ;
break ;
}
}
}
2022-07-10 18:28:56 +03:00
void cull_conv ( std :: vector < RString >& args )
2015-05-01 07:50:34 -06:00
{
COMMON_ARG_VERIFY ( 2 );
for ( int i = 0 ; i < NUM_CullMode ; ++ i )
{
RString cull_str = CullModeToString ( static_cast < CullMode > ( i ));
cull_str . MakeLower ();
if ( args [ 1 ] == cull_str )
{
args [ 1 ] = " \" CullMode_" + CullModeToString ( static_cast < CullMode > ( i )) + " \" " ;
break ;
}
}
}
#undef COMMON_ARG_VERIFY
void init_parser_helpers ()
{
arg_converters [ "x" ] = & x_conv ;
arg_converters [ "y" ] = & y_conv ;
arg_converters [ "queuecommand" ] = & string_arg_conv ;
arg_converters [ "playcommand" ] = & string_arg_conv ;
arg_converters [ "effectclock" ] = & string_arg_conv ;
arg_converters [ "EffectMagnitude" ] = & lower_string_conv ;
arg_converters [ "ZoomToWidth" ] = & lower_string_conv ;
arg_converters [ "ZoomToHeight" ] = & lower_string_conv ;
arg_converters [ "blend" ] = & blend_conv ;
arg_converters [ "cullmode" ] = & cull_conv ;
arg_converters [ "hidden" ] = & hidden_conv ;
arg_converters [ "diffuse" ] = & diffuse_conv ;
arg_converters [ "effectcolor1" ] = & diffuse_conv ;
arg_converters [ "effectcolor2" ] = & diffuse_conv ;
tween_counters [ "sleep" ] = 2 ;
tween_counters [ "linear" ] = 1 ;
tween_counters [ "accelerate" ] = 1 ;
tween_counters [ "decelerate" ] = 1 ;
tween_counters [ "spring" ] = 1 ;
tween_counters [ "tween" ] = 1 ;
tween_counters [ "queuecommand" ] = 1 ;
fields_that_are_strings . insert ( "Texture" );
fields_that_are_strings . insert ( "Text" );
fields_that_are_strings . insert ( "AltText" );
fields_that_are_strings . insert ( "File" );
fields_that_are_strings . insert ( "Font" );
fields_that_are_strings . insert ( "Meshes" );
fields_that_are_strings . insert ( "Materials" );
fields_that_are_strings . insert ( "Bones" );
chunks_to_replace [ "hidden(0)" ] = "visible(true)" ;
chunks_to_replace [ "hidden(1)" ] = "visible(false)" ;
chunks_to_replace [ "effectdelay" ] = "effect_hold_at_full" ;
chunks_to_replace [ "IsPlayerEnabled(0)" ] = "IsPlayerEnabled(PLAYER_1)" ;
chunks_to_replace [ "IsPlayerEnabled(1)" ] = "IsPlayerEnabled(PLAYER_2)" ;
}
2015-05-08 23:55:38 -06:00
void convert_lua_chunk ( RString & chunk_text )
{
2022-07-10 18:28:56 +03:00
for ( std :: map < RString , RString >:: iterator chunk = chunks_to_replace . begin ();
2015-05-08 23:55:38 -06:00
chunk != chunks_to_replace . end (); ++ chunk )
{
chunk_text . Replace ( chunk -> first , chunk -> second );
}
}
2015-05-01 07:50:34 -06:00
// Conditions are mapped by condition string.
// So condition_set_t::iterator->first is the lua to execute for the
// condition, and condition_set_t::iterator->second is the name of the
// condition.
2022-07-10 18:28:56 +03:00
typedef std :: map < RString , RString > condition_set_t ;
typedef std :: map < RString , RString > field_cont_t ;
2015-05-01 07:50:34 -06:00
struct frame_t
{
int frame ;
float delay ;
frame_t () : frame ( 0 ), delay ( 0.0f ) {}
};
struct actor_template_t
{
RString type ;
field_cont_t fields ;
RString condition ;
RString name ;
2022-07-10 18:28:56 +03:00
std :: vector < frame_t > frames ;
std :: vector < actor_template_t > children ;
2015-05-01 07:50:34 -06:00
RString x ;
RString y ;
void make_space_for_frame ( int id );
void store_cmd ( RString const & cmd_name , RString const & full_cmd );
void store_field ( RString const & field_name , RString const & value , bool cmd_convert , RString const & pref = "" , RString const & suf = "" );
void store_field ( RString const & field_name , XNodeValue const * value , bool cmd_convert , RString const & pref = "" , RString const & suf = "" );
void rename_field ( RString const & old_name , RString const & new_name );
RString get_field ( RString const & field_name );
void load_frames_from_file ( RString const & fname , RString const & rel_path );
void load_model_from_file ( RString const & fname , RString const & rel_path );
void load_node ( XNode const & node , RString const & dirname , condition_set_t & conditions );
void output_to_file ( RageFile * file , RString const & indent );
};
void actor_template_t :: make_space_for_frame ( int id )
{
if ( id >= static_cast < int > ( frames . size ()))
{
frames . resize ( id + 1 );
}
}
void actor_template_t :: store_cmd ( RString const & cmd_name , RString const & full_cmd )
{
if ( full_cmd . Left ( 1 ) == "%" )
{
RString cmd_text = full_cmd . Right ( full_cmd . size () - 1 );
2015-05-08 23:55:38 -06:00
convert_lua_chunk ( cmd_text );
2015-05-01 07:50:34 -06:00
fields [ cmd_name ] = cmd_text ;
return ;
}
2022-07-10 18:28:56 +03:00
std :: vector < RString > cmds ;
2015-05-01 07:50:34 -06:00
split ( full_cmd , ";" , cmds , true );
2023-04-19 23:04:25 +02:00
std :: size_t queue_size = 0 ;
2015-05-01 07:50:34 -06:00
// If someone has a simfile that uses a playcommand that pushes tween
// states onto the queue, queue size counting will have to be made much
// more complex to prevent that from causing an overflow.
2022-07-10 18:28:56 +03:00
for ( std :: vector < RString >:: iterator cmd = cmds . begin (); cmd != cmds . end (); ++ cmd )
2015-05-01 07:50:34 -06:00
{
2022-07-10 18:28:56 +03:00
std :: vector < RString > args ;
2015-05-01 07:50:34 -06:00
split ( * cmd , "," , args , true );
if ( ! args . empty ())
{
2022-07-10 18:28:56 +03:00
for ( std :: vector < RString >:: iterator arg = args . begin (); arg != args . end (); ++ arg )
2015-05-01 07:50:34 -06:00
{
2023-04-19 23:04:25 +02:00
std :: size_t first_nonspace = 0 ;
std :: size_t last_nonspace = arg -> size ();
2015-05-01 07:50:34 -06:00
while (( * arg )[ first_nonspace ] == ' ' )
{
++ first_nonspace ;
}
while (( * arg )[ last_nonspace ] == ' ' )
{
-- last_nonspace ;
}
* arg = arg -> substr ( first_nonspace , last_nonspace - first_nonspace );
}
2022-07-10 18:28:56 +03:00
std :: map < RString , arg_converter_t >:: iterator conv = arg_converters . find ( args [ 0 ]);
2015-05-01 07:50:34 -06:00
if ( conv != arg_converters . end ())
{
conv -> second ( args );
}
2023-04-19 23:04:25 +02:00
std :: map < RString , std :: size_t >:: iterator counter = tween_counters . find ( args [ 0 ]);
2015-05-01 07:50:34 -06:00
if ( counter != tween_counters . end ())
{
queue_size += counter -> second ;
}
}
* cmd = join ( "," , args );
}
// This code is probably actually useless, OITG has the same tween queue size
// and the real reason I saw overflows in converted files was a bug in
// foreground loading that ran InitCommand twice. -Kyz
if ( queue_size >= TWEEN_QUEUE_MAX )
{
2023-04-19 23:04:25 +02:00
std :: size_t num_to_make = ( queue_size / TWEEN_QUEUE_MAX ) + 1 ;
std :: size_t states_per = ( queue_size / num_to_make ) + 1 ;
std :: size_t states_in_curr = 0 ;
2015-05-01 07:50:34 -06:00
RString this_name = cmd_name ;
2022-07-10 18:28:56 +03:00
std :: vector < RString > curr_cmd ;
for ( std :: vector < RString >:: iterator cmd = cmds . begin (); cmd != cmds . end (); ++ cmd )
2015-05-01 07:50:34 -06:00
{
curr_cmd . push_back ( * cmd );
2022-07-10 18:28:56 +03:00
std :: vector < RString > args ;
2015-05-01 07:50:34 -06:00
split ( * cmd , "," , args , true );
if ( ! args . empty ())
{
2023-04-19 23:04:25 +02:00
std :: map < RString , std :: size_t >:: iterator counter = tween_counters . find ( args [ 0 ]);
2015-05-01 07:50:34 -06:00
if ( counter != tween_counters . end ())
{
states_in_curr += counter -> second ;
if ( states_in_curr >= states_per - 1 )
{
RString next_name = unique_name ( "cmd" );
curr_cmd . push_back ( "queuecommand, \" " + next_name + " \" " );
fields [ this_name ] = "cmd(" + join ( ";" , curr_cmd ) + ")" ;
curr_cmd . clear ();
this_name = next_name ;
states_in_curr = 0 ;
}
}
}
}
if ( ! curr_cmd . empty ())
{
fields [ this_name ] = "cmd(" + join ( ";" , curr_cmd ) + ")" ;
}
}
else
{
fields [ cmd_name ] = "cmd(" + join ( ";" , cmds ) + ")" ;
}
}
void actor_template_t :: store_field ( RString const & field_name , RString const & value , bool cmd_convert , RString const & pref , RString const & suf )
{
// OITG apparently allowed "Oncommand" as valid.
if ( field_name . Right ( 7 ). MakeLower () != "command" )
{
cmd_convert = false ;
}
if ( cmd_convert )
{
RString real_field_name = field_name . Left ( field_name . size () - 7 ) + "Command" ;
store_cmd ( real_field_name , value );
}
else
{
fields [ field_name ] = pref + value + suf ;
}
2023-04-19 23:04:25 +02:00
2015-05-01 07:50:34 -06:00
}
void actor_template_t :: store_field ( RString const & field_name , XNodeValue const * value , bool cmd_convert , RString const & pref , RString const & suf )
{
RString val ;
value -> GetValue ( val );
store_field ( field_name , val , cmd_convert , pref , suf );
}
void actor_template_t :: rename_field ( RString const & old_name , RString const & new_name )
{
field_cont_t :: iterator old_field = fields . find ( old_name );
if ( old_field == fields . end ())
{
return ;
}
fields [ new_name ] = old_field -> second ;
fields . erase ( old_field );
}
RString actor_template_t :: get_field ( RString const & field_name )
{
field_cont_t :: iterator field = fields . find ( field_name );
if ( field == fields . end ())
{
return "" ;
}
return field -> second ;
}
void actor_template_t :: load_frames_from_file ( RString const & fname , RString const & rel_path )
{
IniFile ini ;
if ( ! ini . ReadFile ( fname ))
{
LOG -> Trace ( "Failed to read sprite file %s: %s" , fname . c_str (), ini . GetError (). c_str ());
return ;
}
XNode const * sprite_node = ini . GetChild ( "Sprite" );
2019-06-22 12:35:38 -07:00
if ( sprite_node != nullptr )
2015-05-01 07:50:34 -06:00
{
FOREACH_CONST_Attr ( sprite_node , attr )
{
// Frame and Delay fields have names of the form "Frame0000" where the
// "0000" part is the id of the frame.
RString field_type = attr -> first . Left ( 5 );
if ( field_type == "Frame" )
{
2021-02-15 20:36:51 +00:00
int id = StringToInt ( attr -> first . Right ( attr -> first . size () - 5 ));
2015-05-01 07:50:34 -06:00
make_space_for_frame ( id );
attr -> second -> GetValue ( frames [ id ]. frame );
}
else if ( field_type == "Delay" )
{
2021-02-15 20:36:51 +00:00
int id = StringToInt ( attr -> first . Right ( attr -> first . size () - 5 ));
2015-05-01 07:50:34 -06:00
make_space_for_frame ( id );
attr -> second -> GetValue ( frames [ id ]. delay );
}
else if ( field_type == "Textu" )
{
store_field ( "Texture" , attr -> second , false , rel_path , "" );
}
else
{
// Unrecognized, ignore.
}
}
}
}
void actor_template_t :: load_model_from_file ( RString const & fname , RString const & rel_path )
{
IniFile ini ;
if ( ! ini . ReadFile ( fname ))
{
LOG -> Trace ( "Failed to read model file %s: %s" , fname . c_str (), ini . GetError (). c_str ());
return ;
}
XNode const * model_node = ini . GetChild ( "Model" );
2019-06-22 12:35:38 -07:00
if ( model_node != nullptr )
2015-05-01 07:50:34 -06:00
{
FOREACH_CONST_Attr ( model_node , attr )
{
store_field ( attr -> first , attr -> second , false , rel_path , "" );
}
}
}
void actor_template_t :: load_node ( XNode const & node , RString const & dirname , condition_set_t & conditions )
{
type = node . GetName ();
bool type_set_by_automagic = false ;
2015-05-05 21:41:15 -06:00
#define set_type(auto_type) type_set_by_automagic= true; type= auto_type;
2015-05-01 07:50:34 -06:00
FOREACH_CONST_Attr ( & node , attr )
{
if ( attr -> first == "Name" )
{
attr -> second -> GetValue ( name );
}
else if ( attr -> first == "Condition" )
{
RString cond_str ;
attr -> second -> GetValue ( cond_str );
condition_set_t :: iterator cond = conditions . find ( cond_str );
if ( cond == conditions . end ())
{
condition = unique_name ( "cond" );
conditions [ cond_str ] = condition ;
}
else
{
condition = cond -> second ;
}
}
else if ( attr -> first == "Type" || attr -> first == "Class" )
{
if ( ! type_set_by_automagic )
{
attr -> second -> GetValue ( type );
}
}
else if ( attr -> first == "__TEXT__" )
{
// Ignore. This attribute seems to be put in by the xml parser, and
// not part of the actual xml code.
}
2015-05-05 21:41:15 -06:00
else if ( attr -> first == "Text" )
{
set_type ( "BitmapText" );
store_field ( attr -> first , attr -> second , true );
}
2015-05-01 07:50:34 -06:00
else if ( attr -> first == "File" )
{
RString relative_path ;
attr -> second -> GetValue ( relative_path );
RString sfname = dirname + relative_path ;
if ( FILEMAN -> IsADirectory ( sfname ))
{
2015-05-05 21:41:15 -06:00
set_type ( "LoadActor" );
2015-05-01 07:50:34 -06:00
store_field ( "File" , attr -> second , false );
}
else
{
2022-07-10 18:28:56 +03:00
std :: vector < RString > files_in_dir ;
2015-05-01 07:50:34 -06:00
FILEMAN -> GetDirListing ( sfname + "*" , files_in_dir , false , true );
int handled_level = 0 ;
RString found_file = "" ;
2022-07-10 18:28:56 +03:00
for ( std :: vector < RString >:: iterator file = files_in_dir . begin ();
2015-05-01 07:50:34 -06:00
file != files_in_dir . end () && handled_level < 2 ; ++ file )
{
RString extension = GetExtension ( * file );
FileType file_type = ActorUtil :: GetFileType ( * file );
RString this_relative =
add_extension_to_relative_path_from_found_file ( relative_path , * file );
switch ( file_type )
{
case FT_Xml :
this_relative = SetExtension ( this_relative , "lua" );
2022-11-08 06:59:56 -07:00
[[fallthrough]] ;
2015-05-01 07:50:34 -06:00
case FT_Lua :
2015-05-05 21:41:15 -06:00
set_type ( "LoadActor" );
2015-05-01 07:50:34 -06:00
store_field ( "File" , this_relative , false );
handled_level = 2 ;
break ;
case FT_Ini :
break ;
case FT_Bitmap :
case FT_Movie :
if ( handled_level < 2 )
{
2015-05-05 21:41:15 -06:00
set_type ( "Sprite" );
2015-05-01 07:50:34 -06:00
store_field ( "File" , this_relative , false );
handled_level = 1 ;
}
break ;
case FT_Sound :
2015-05-05 21:41:15 -06:00
set_type ( "ActorSound" );
2015-05-01 07:50:34 -06:00
store_field ( "File" , this_relative , false );
handled_level = 1 ;
break ;
case FT_Sprite :
2015-05-05 21:41:15 -06:00
set_type ( "Sprite" );
2015-05-01 07:50:34 -06:00
load_frames_from_file ( dirname + this_relative , Dirname ( relative_path ));
handled_level = 2 ;
break ;
case FT_Model :
2015-05-05 21:41:15 -06:00
set_type ( "Model" );
2015-05-01 07:50:34 -06:00
store_field ( "Meshes" , this_relative , false );
store_field ( "Materials" , this_relative , false );
store_field ( "Bones" , this_relative , false );
handled_level = 2 ;
break ;
2016-03-24 18:30:29 -04:00
default :
break ;
2015-05-01 07:50:34 -06:00
}
if ( ! handled_level )
{
if ( extension == "model" )
{
2015-05-05 21:41:15 -06:00
set_type ( "Model" );
2015-05-01 07:50:34 -06:00
load_model_from_file ( dirname + this_relative , Dirname ( relative_path ));
handled_level = 2 ;
}
}
}
if ( ! handled_level )
{
if ( ! files_in_dir . empty ())
{
RString this_relative =
add_extension_to_relative_path_from_found_file ( relative_path , files_in_dir [ 0 ]);
store_field ( "File" , this_relative , false );
}
else
{
store_field ( "File" , attr -> second , false );
}
}
}
}
else
{
store_field ( attr -> first , attr -> second , true );
}
}
if ( type == "BitmapText" )
{
rename_field ( "Texture" , "Font" );
rename_field ( "File" , "Font" );
}
if ( type == "Sprite" )
{
rename_field ( "File" , "Texture" );
}
XNode const * xren = node . GetChild ( "children" );
2019-06-22 12:35:38 -07:00
if ( xren != nullptr )
2015-05-01 07:50:34 -06:00
{
FOREACH_CONST_Child ( xren , child )
{
actor_template_t chill_plate ;
chill_plate . load_node ( * child , dirname , conditions );
children . push_back ( chill_plate );
}
}
if ( ! x . empty () || ! y . empty ())
{
RString pos_init = "xy," + x + "," + y ;
field_cont_t :: iterator init = fields . find ( "InitCommand" );
if ( init != fields . end ())
{
pos_init = pos_init + ";queuecommand,xtl_passed_initCommand" ;
fields [ "xtl_passed_initCommand" ] = init -> second ;
}
fields [ "InitCommand" ] = "cmd(" + pos_init + ")" ;
}
}
void actor_template_t :: output_to_file ( RageFile * file , RString const & indent )
{
if ( ! condition . empty ())
{
file -> Write ( indent + "optional_actor(" + condition + "_result, \n " );
}
if ( type == "LoadActor" )
{
file -> Write ( indent + "LoadActor('" + get_field ( "File" ) + "') .. { \n " );
}
else
{
file -> Write ( indent + "Def." + type + "{ \n " );
}
RString subindent = indent + " " ;
if ( name . empty ())
{
name = unique_name ( "actor" );
}
file -> Write ( subindent + "Name= \" " + name + " \" , \n " );
if ( ! frames . empty ())
{
file -> Write ( subindent + "Frames= { \n " );
RString frameindent = subindent + " " ;
2022-07-10 18:28:56 +03:00
for ( std :: vector < frame_t >:: iterator frame = frames . begin ();
2015-05-01 07:50:34 -06:00
frame != frames . end (); ++ frame )
{
2019-06-22 12:35:38 -07:00
file -> Write ( frameindent + "{Frame= " + std :: to_string ( frame -> frame ) +
", Delay= " + std :: to_string ( frame -> delay ) + "}, \n " );
2015-05-01 07:50:34 -06:00
}
file -> Write ( indent + "}, \n " );
}
for ( field_cont_t :: iterator field = fields . begin ();
field != fields . end (); ++ field )
{
2022-07-10 18:28:56 +03:00
std :: set < RString >:: iterator is_string = fields_that_are_strings . find ( field -> first );
2015-05-01 07:50:34 -06:00
if ( is_string != fields_that_are_strings . end ())
{
file -> Write ( subindent + field -> first + "= \" " + field -> second + " \" , \n " );
}
else
{
file -> Write ( subindent + field -> first + "= " + field -> second + ", \n " );
}
}
2022-07-10 18:28:56 +03:00
for ( std :: vector < actor_template_t >:: iterator child = children . begin ();
2015-05-01 07:50:34 -06:00
child != children . end (); ++ child )
{
child -> output_to_file ( file , subindent );
file -> Write ( ", \n " );
}
file -> Write ( indent + "}" );
if ( ! condition . empty ())
{
file -> Write ( ")" );
}
}
void convert_xml_file ( RString const & fname , RString const & dirname )
{
if ( arg_converters . empty ())
{
init_parser_helpers ();
}
LOG -> Trace ( "Beginning conversion of entry: %s" , fname . c_str ());
XNode xml ;
if ( ! XmlFileUtil :: LoadFromFileShowErrors ( xml , fname ))
{
LOG -> Trace ( "Error when loading xml." );
return ;
}
actor_template_t plate ;
condition_set_t conditions ;
plate . load_node ( xml , dirname , conditions );
RageFile * file = new RageFile ;
RString out_name = fname . Left ( fname . size () - 4 ) + ".lua" ;
if ( ! file -> Open ( out_name , RageFile :: WRITE ))
{
LOG -> Trace ( "Could not open %s: %s" , out_name . c_str (), file -> GetError (). c_str ());
return ;
}
LOG -> Trace ( "Saving conversion to: %s" , out_name . c_str ());
for ( condition_set_t :: iterator cond = conditions . begin ();
cond != conditions . end (); ++ cond )
{
2015-05-08 23:55:38 -06:00
RString cond_text = cond -> first ;
convert_lua_chunk ( cond_text );
file -> Write ( "local " + cond -> second + "_result= " + cond_text + " \n\n " );
2015-05-01 07:50:34 -06:00
}
if ( ! conditions . empty ())
{
file -> Write ( "local function optional_actor(cond, actor) \n "
" if cond then return actor end \n "
" return Def.Actor{} \n "
"end \n\n " );
}
file -> Write ( "return " );
plate . output_to_file ( file , "" );
file -> Write ( " \n " );
file -> Close ();
delete file ;
}
int LuaFunc_convert_xml_bgs ( lua_State * L );
int LuaFunc_convert_xml_bgs ( lua_State * L )
{
RString dir = SArg ( 1 );
2022-07-10 18:28:56 +03:00
std :: vector < RString > xml_list ;
2015-05-01 07:50:34 -06:00
convert_xmls_in_dir ( dir + "/" );
return 0 ;
}
LUAFUNC_REGISTER_COMMON ( convert_xml_bgs );
/*
* (c) 2014 Eric Reese
* All rights reserved.
2023-04-19 23:04:25 +02:00
*
2015-05-01 07:50:34 -06:00
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
2023-04-19 23:04:25 +02:00
*
2015-05-01 07:50:34 -06:00
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/