diff --git a/src/config/Config.cpp b/src/config/Config.cpp index f9686d27..56207a81 100644 --- a/src/config/Config.cpp +++ b/src/config/Config.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "Config.h" @@ -242,6 +243,32 @@ Config::Config( const int argc, const char* argv[] ) m_launch_flags |= LF_QUICKSTART_FACTION; } ); + m_parser->AddRule( + "mods", "MODS", "Comma-separated list of mods to load", AH( this ) { + std::stringstream ss( value ); + while ( ss.good() ) { + std::string mod_name; + getline( ss, mod_name, ',' ); + if ( !mod_name.empty() ) { + const auto mod_path = util::FS::GeneratePath( + { + m_data_path, + "mods", + mod_name + } + ); + if ( !util::FS::DirectoryExists( mod_path ) ) { + Error( "Mod path does not exist or is not a directory: " + mod_path ); + } + m_mod_paths.push_back( mod_path ); + } + } + if ( m_mod_paths.empty() ) { + Error( "No mod paths were defined" ); + } + m_launch_flags |= LF_MODS; + } + ); #ifdef DEBUG m_parser->AddRule( @@ -405,6 +432,10 @@ const std::string& Config::GetQuickstartFaction() const { return m_quickstart_faction; } +const std::vector< std::string >& Config::GetModPaths() const { + return m_mod_paths; +} + #ifdef DEBUG const bool Config::HasDebugFlag( const debug_flag_t flag ) const { diff --git a/src/config/Config.h b/src/config/Config.h index 6536d57f..49078888 100644 --- a/src/config/Config.h +++ b/src/config/Config.h @@ -39,6 +39,7 @@ CLASS( Config, common::Module ) LF_QUICKSTART_MAP_LIFEFORMS = 1 << 12, LF_QUICKSTART_MAP_CLOUDS = 1 << 13, LF_QUICKSTART_FACTION = 1 << 14, + LF_MODS = 1 << 15, }; #ifdef DEBUG @@ -81,6 +82,8 @@ CLASS( Config, common::Module ) const game::backend::settings::map_config_value_t GetQuickstartMapClouds() const; const std::string& GetQuickstartFaction() const; + const std::vector< std::string >& GetModPaths() const; + #ifdef DEBUG const bool HasDebugFlag( const debug_flag_t flag ) const; @@ -121,6 +124,8 @@ CLASS( Config, common::Module ) game::backend::settings::map_config_value_t m_quickstart_map_clouds = game::backend::settings::MAP_CONFIG_CLOUDS_AVERAGE; std::string m_quickstart_faction = ""; + std::vector< std::string > m_mod_paths = {}; + #ifdef DEBUG uint16_t m_debug_flags = DF_NONE; diff --git a/src/game/backend/Bindings.cpp b/src/game/backend/Bindings.cpp index 14160932..765fd477 100644 --- a/src/game/backend/Bindings.cpp +++ b/src/game/backend/Bindings.cpp @@ -53,7 +53,10 @@ void Bindings::AddToContext( gse::context::Context* ctx ) { } void Bindings::RunMainScript() { - m_gse->GetInclude( m_gse_context, m_si_internal, m_entry_script ); + m_gse->RunScript( m_gse_context, m_si_internal, m_entry_script ); + for ( const auto& mod_path : g_engine->GetConfig()->GetModPaths() ) { + m_gse->RunScript( m_gse_context, m_si_internal, util::FS::GeneratePath({ mod_path, "main" })); + } } void Bindings::RunMain() { diff --git a/src/game/backend/Game.cpp b/src/game/backend/Game.cpp index 7402b539..66c78ead 100644 --- a/src/game/backend/Game.cpp +++ b/src/game/backend/Game.cpp @@ -472,6 +472,10 @@ const size_t Game::GetSlotNum() const { WRAPIMPL_BEGIN( Game, CLASS_GAME ) WRAPIMPL_PROPS + { + "year", + VALUE( gse::type::Int, 2100/*tmp*/ + m_current_turn.GetId() ) + }, { "random", m_random->Wrap() diff --git a/src/game/backend/faction/FactionManager.cpp b/src/game/backend/faction/FactionManager.cpp index b2db7ada..a861936a 100644 --- a/src/game/backend/faction/FactionManager.cpp +++ b/src/game/backend/faction/FactionManager.cpp @@ -192,6 +192,18 @@ WRAPIMPL_BEGIN( FactionManager, CLASS_FM ) return faction->Wrap(); } ) }, + { + "remove", + NATIVE_CALL( this ) { + N_EXPECT_ARGS( 1 ); + N_GETVALUE( id, 0, String ); + if ( !Get( id ) ) { + GSE_ERROR( gse::EC.GAME_ERROR, "Unknown faction: " + id ); + } + Remove( id ); + return VALUE( gse::type::Undefined ); + } ) + }, }; WRAPIMPL_END_PTR( FactionManager ) diff --git a/src/gse/GSE.cpp b/src/gse/GSE.cpp index 951323e5..8c944efc 100644 --- a/src/gse/GSE.cpp +++ b/src/gse/GSE.cpp @@ -80,7 +80,7 @@ void GSE::Run() { Log( "GSE finished" ); } -const Value GSE::GetInclude( context::Context* ctx, const si_t& si, const std::string& path ) { +const Value GSE::RunScript( context::Context* ctx, const si_t& si, const std::string& path ) { const auto& it = m_include_cache.find( path ); if ( it != m_include_cache.end() ) { return it->second.result; diff --git a/src/gse/GSE.h b/src/gse/GSE.h index 7035c2c9..b4ea6829 100644 --- a/src/gse/GSE.h +++ b/src/gse/GSE.h @@ -52,7 +52,7 @@ CLASS( GSE, common::Class ) void AddModule( const std::string& path, type::Callable* module ); void Run(); - const Value GetInclude( context::Context* ctx, const si_t& si, const std::string& path ); + const Value RunScript( context::Context* ctx, const si_t& si, const std::string& path ); void SetGlobal( const std::string& identifier, Value variable ); const Value& GetGlobal( const std::string& identifier ); diff --git a/src/gse/builtins/Include.cpp b/src/gse/builtins/Include.cpp index dffd884a..8c19e9ff 100644 --- a/src/gse/builtins/Include.cpp +++ b/src/gse/builtins/Include.cpp @@ -18,7 +18,7 @@ void Include::AddToContext( context::Context* ctx ) { N_EXPECT_ARGS( 1 ); N_GETVALUE( path, 0, String ); const auto full_path = ctx->GetScriptInfo().directory + GSE::PATH_SEPARATOR + path; - return ctx->GetGSE()->GetInclude( ctx, call_si, full_path ); + return ctx->GetGSE()->RunScript( ctx, call_si, full_path ); } ) ); } diff --git a/src/gse/type/Object.cpp b/src/gse/type/Object.cpp index d60be887..68a54548 100644 --- a/src/gse/type/Object.cpp +++ b/src/gse/type/Object.cpp @@ -23,6 +23,10 @@ static const std::unordered_map< Object::object_class_t, std::string > s_object_ Object::CLASS_EXCEPTION, "#exception" }, + { + Object::CLASS_RANDOM, + "#random" + }, { Object::CLASS_COLOR, "#color" @@ -39,6 +43,14 @@ static const std::unordered_map< Object::object_class_t, std::string > s_object_ Object::CLASS_GAME, "#game" }, + { + Object::CLASS_RM, + "#rm" + }, + { + Object::CLASS_TM, + "#tm" + }, { Object::CLASS_TILE, "#tile" @@ -53,7 +65,11 @@ static const std::unordered_map< Object::object_class_t, std::string > s_object_ }, { Object::CLASS_FM, - "#factions" + "#fm" + }, + { + Object::CLASS_UM, + "#um" }, { Object::CLASS_UNITDEF, @@ -63,10 +79,22 @@ static const std::unordered_map< Object::object_class_t, std::string > s_object_ Object::CLASS_UNIT, "#unit" }, + { + Object::CLASS_BM, + "#bm" + }, { Object::CLASS_BASE, "#base" }, + { + Object::CLASS_BASE_POP, + "#basepop" + }, + { + Object::CLASS_AM, + "#am" + } }; const std::string& Object::GetClassString( const object_class_t object_class ) { const auto& it = s_object_class_str.find( object_class ); diff --git a/src/gse/type/Object.h b/src/gse/type/Object.h index 9739aa45..ae6b727a 100644 --- a/src/gse/type/Object.h +++ b/src/gse/type/Object.h @@ -32,7 +32,6 @@ class Object : public Type { CLASS_SYSTEM, CLASS_STATE, CLASS_GAME, - CLASS_MAP, CLASS_RM, CLASS_TM, CLASS_TILE, diff --git a/src/resource/ResourceManager.cpp b/src/resource/ResourceManager.cpp index d5f2c14a..6b9baabb 100644 --- a/src/resource/ResourceManager.cpp +++ b/src/resource/ResourceManager.cpp @@ -5,6 +5,9 @@ #include "util/FS.h" +#include "engine/Engine.h" +#include "config/Config.h" + namespace resource { ResourceManager::ResourceManager() @@ -369,8 +372,17 @@ const std::string& ResourceManager::GetCustomPath( const std::string& path ) { key.resize( path.length() ); std::transform( path.begin(), path.end(), key.begin(), ::tolower ); - // look in datadir - auto resolved_file = util::FS::GetExistingCaseSensitivePath( m_data_path, path ); + std::string resolved_file = ""; + + // look in mod dirs + for ( const auto& mod_path : g_engine->GetConfig()->GetModPaths() ) { + resolved_file = util::FS::GetExistingCaseSensitivePath( mod_path, path ); + } + + if ( resolved_file.empty() ) { + // look in datadir + resolved_file = util::FS::GetExistingCaseSensitivePath( m_data_path, path ); + } if ( resolved_file.empty() ) {