diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index bd09c51097..1ed3b78286 100755 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -68,8 +68,6 @@ int CGUI::HandleEvent(const SDL_Event* ev) { int ret = EV_PASS; - // MT: If something's gone wrong, check this block... (added for hotkey support) - if( ev->type == SDL_GUIHOTKEYPRESS ) { const CStr& objectName = *( (CStr*)ev->user.code ); @@ -78,8 +76,6 @@ int CGUI::HandleEvent(const SDL_Event* ev) object->ScriptEvent( "press" ); } - // -- MT - if(ev->type == SDL_MOUSEMOTION) { // Yes the mouse position is stored as float to avoid diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index a91298f43e..549248f072 100755 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -35,9 +35,7 @@ IGUIObject::IGUIObject() : AddSetting(GUIST_bool, "hidden"); AddSetting(GUIST_CClientArea, "size"); AddSetting(GUIST_CStr, "style"); -// MT - temp tag AddSetting(GUIST_CStr, "hotkey" ); -// -- MT AddSetting(GUIST_float, "z"); AddSetting(GUIST_bool, "absolute"); AddSetting(GUIST_bool, "ghost"); diff --git a/source/gui/IGUIObject.h b/source/gui/IGUIObject.h index 5c21087504..a4ba84d41f 100755 --- a/source/gui/IGUIObject.h +++ b/source/gui/IGUIObject.h @@ -524,6 +524,7 @@ class CGUIDummyObject : public IGUIObject GUI_OBJECT(CGUIDummyObject) public: + virtual void HandleMessage(const SGUIMessage& UNUSEDPARAM(Message)) {} virtual void Draw() {} // Empty can never be hovered. It is only a category. diff --git a/source/lib/res/ogl_tex.cpp b/source/lib/res/ogl_tex.cpp index 8672c779e1..70210b071b 100755 --- a/source/lib/res/ogl_tex.cpp +++ b/source/lib/res/ogl_tex.cpp @@ -1,5 +1,7 @@ #include "precompiled.h" +#define CHEEZY_NOMIPMAP + #include "res.h" #include "ogl.h" #include "tex.h" @@ -331,6 +333,9 @@ int tex_upload(const Handle ht, int filter_ovr, int int_fmt_ovr, int fmt_ovr) if(int_fmt_ovr) int_fmt = int_fmt_ovr; if(fmt_ovr) fmt = fmt_ovr; +#ifdef CHEEZY_NOMIPMAP + filter = GL_NEAREST_MIPMAP_LINEAR; +#endif CHECK_ERR(tex_bind(ht)); // we know ht is valid (H_DEREF above), but tex_bind can // fail in debug builds if Tex.id isn't a valid texture name @@ -370,11 +375,13 @@ int tex_upload(const Handle ht, int filter_ovr, int int_fmt_ovr, int fmt_ovr) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } + glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, fmt, w, h, 0, tex_size, tex_data); } // normal else { + // manual mipmap gen via GLU (box filter) if(mipmap && !sgm_avl) gluBuild2DMipmaps(GL_TEXTURE_2D, int_fmt, w, h, fmt, GL_UNSIGNED_BYTE, tex_data); @@ -385,6 +392,7 @@ int tex_upload(const Handle ht, int filter_ovr, int int_fmt_ovr, int fmt_ovr) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, w, h, 0, fmt, GL_UNSIGNED_BYTE, tex_data); + } } diff --git a/source/lib/res/snd.cpp b/source/lib/res/snd.cpp index 342f3a2ba2..d7f96f878f 100755 --- a/source/lib/res/snd.cpp +++ b/source/lib/res/snd.cpp @@ -1414,7 +1414,6 @@ static void list_prune_removed() vsrcs.erase(new_end, vsrcs.end()); } - static void free(VSrc* vs) { snd_free(vs->hvs); diff --git a/source/main.cpp b/source/main.cpp index 17db80e883..87e10df076 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -56,6 +56,7 @@ #include "scripting/JSInterface_Selection.h" #include "scripting/JSInterface_Console.h" #include "scripting/JSCollection.h" +#include "scripting/DOMEvent.h" #include "gui/scripting/JSInterface_IGUIObject.h" #include "gui/scripting/JSInterface_GUITypes.h" @@ -105,7 +106,7 @@ static bool g_FixedFrameTiming=false; static bool g_VSync = false; static float g_LodBias = 0.0f; -CLightEnv g_LightEnv; +extern CLightEnv g_LightEnv; static bool g_EntGraph = false; @@ -117,8 +118,7 @@ extern int game_view_handler(const SDL_Event* ev); static CMusicPlayer MusicPlayer; CStr g_CursorName = "test"; - - +CStr g_ActiveProfile = "default"; extern int allow_reload(); extern int dir_add_watch(const char* const dir, bool watch_subdirs); @@ -534,6 +534,42 @@ static void InitDefaultGameAttributes() g_GameAttributes.SetValue("mapFile", L"test01.pmp"); } + +static void LoadProfile( CStr profile ) +{ + CStr filename = CStr( "profiles/" ) + profile + CStr( ".cfg" ); + g_ConfigDB.SetConfigFile( CFG_USER, true, filename ); + g_ConfigDB.Reload( CFG_USER ); +} + +// Fill in the globals from the config files. +static void LoadGlobals() +{ + CConfigValue *val; + + if ((val=g_ConfigDB.GetValue(CFG_SYSTEM, "profile"))) + val->GetString( g_ActiveProfile ); + + // Now load the profile before trying to retrieve the values of the rest of these. + + LoadProfile( g_ActiveProfile ); + + if ((val=g_ConfigDB.GetValue(CFG_USER, "xres"))) + val->GetInt(g_xres); + if ((val=g_ConfigDB.GetValue(CFG_USER, "yres"))) + val->GetInt(g_yres); + + if ((val=g_ConfigDB.GetValue(CFG_USER, "vsync"))) + val->GetBool(g_VSync); + if ((val=g_ConfigDB.GetValue(CFG_USER, "novbo"))) + val->GetBool(g_NoGLVBO); + if ((val=g_ConfigDB.GetValue(CFG_USER, "shadows"))) + val->GetBool(g_Shadows); + + LOG(NORMAL, LOG_CATEGORY, "g_x/yres is %dx%d", g_xres, g_yres); + LOG(NORMAL, LOG_CATEGORY, "Active profile is %s", g_ActiveProfile); +} + static void ParseArgs(int argc, char* argv[]) { for(int i = 1; i < argc; i++) @@ -558,7 +594,7 @@ static void ParseArgs(int argc, char* argv[]) if(equ) { *equ = 0; - g_ConfigDB.CreateValue(CFG_SYSTEM, arg) + g_ConfigDB.CreateValue(CFG_COMMAND, arg) ->m_String = (equ+1); } } @@ -585,45 +621,33 @@ static void ParseArgs(int argc, char* argv[]) break; case 'n': if(strncmp(name, "novbo", 5) == 0) - g_ConfigDB.CreateValue(CFG_SYSTEM, "novbo")->m_String="true"; + g_ConfigDB.CreateValue(CFG_COMMAND, "novbo")->m_String="true"; else if(strncmp(name, "nopbuffer", 9) == 0) g_NoPBuffer = true; break; case 's': if(strncmp(name, "shadows", 7) == 0) - g_ConfigDB.CreateValue(CFG_SYSTEM, "shadows")->m_String="true"; + g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String="true"; break; case 'v': - g_ConfigDB.CreateValue(CFG_SYSTEM, "vsync")->m_String="true"; + g_ConfigDB.CreateValue(CFG_COMMAND, "vsync")->m_String="true"; break; case 'x': if(strncmp(name, "xres=", 6) == 0) - g_ConfigDB.CreateValue(CFG_SYSTEM, "xres")->m_String=argv[i]+6; + g_ConfigDB.CreateValue(CFG_COMMAND, "xres")->m_String=argv[i]+6; break; case 'y': if(strncmp(name, "yres=", 6) == 0) - g_ConfigDB.CreateValue(CFG_SYSTEM, "yres")->m_String=argv[i]+6; + g_ConfigDB.CreateValue(CFG_COMMAND, "yres")->m_String=argv[i]+6; + break; + case 'p': + if(strncmp(name, "profile=", 8) == 0 ) + g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = argv[i]+9; break; } // switch } - CConfigValue *val; - if ((val=g_ConfigDB.GetValue(CFG_SYSTEM, "xres"))) - val->GetInt(g_xres); - if ((val=g_ConfigDB.GetValue(CFG_SYSTEM, "yres"))) - val->GetInt(g_yres); - - if ((val=g_ConfigDB.GetValue(CFG_SYSTEM, "vsync"))) - val->GetBool(g_VSync); - if ((val=g_ConfigDB.GetValue(CFG_SYSTEM, "novbo"))) - val->GetBool(g_NoGLVBO); - if ((val=g_ConfigDB.GetValue(CFG_SYSTEM, "shadows"))) - val->GetBool(g_Shadows); - - if((val = g_ConfigDB.GetValue(CFG_SYSTEM, "lodbias"))) - val->GetFloat(g_LodBias); - - LOG(NORMAL, LOG_CATEGORY, "g_x/yres is %dx%d", g_xres, g_yres); + } @@ -644,9 +668,9 @@ static void InitScripting() JSI_IGUIObject::init(); JSI_GUITypes::init(); JSI_Vector3D::init(); - // JSI_Selection::init(); EntityCollection::Init( "EntityCollection" ); CJSPropertyAccessor::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor is already being compiled for T = CEntity. + CScriptEvent::ScriptingInit(); JSI_Camera::init(); JSI_Console::init(); @@ -672,6 +696,7 @@ static void InitVfs(char* argv0) vfs_mount("", "mods/official", 0); vfs_mount("screenshots", "screenshots", 0); + vfs_mount("profiles", "profiles", 0 ); } static void psInit() @@ -851,21 +876,20 @@ PREVTSC=TSC; MICROLOG(L"init config"); new CConfigDB; + + g_ConfigDB.SetConfigFile(CFG_SYSTEM, false, "config/system.cfg"); g_ConfigDB.Reload(CFG_SYSTEM); g_ConfigDB.SetConfigFile(CFG_MOD, true, "config/mod.cfg"); // No point in reloading mod.cfg here - we haven't mounted mods yet - g_ConfigDB.SetConfigFile(CFG_USER, true, "config/user.cfg"); - // Same thing here; we haven't even started up yet - this will wait until - // the profile dir is VFS mounted (or we will do a new SetConfigFile with - // a generated profile path) - // We init the defaults here; command line options might want to override InitDefaultGameAttributes(); ParseArgs(argc, argv); + LoadGlobals(); // Collects information from system.cfg, the profile file, and any command-line overrides + // to fill in the globals. //g_xres = 800; //g_yres = 600; @@ -1137,7 +1161,6 @@ static void Frame() # define CUSTOM_EXCEPTION_HANDLER #endif - #ifdef CUSTOM_EXCEPTION_HANDLER #include #endif diff --git a/source/ps/Config.cpp b/source/ps/Config.cpp deleted file mode 100755 index a3d5cee409..0000000000 --- a/source/ps/Config.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// TODO: A few changes from VFS -> CFile usage if required. -// TODO: Optimizations, when we've decided what needs to be done. - -#include "precompiled.h" - -#if 0 - -#include "Config.h" -#include "res/res.h" - -using namespace std; - -DEFINE_ERROR( PS_FILE_NOT_FOUND, "A data file required by the engine could \ -not be found. Check that it exists within the game directory or archive tree." ); -DEFINE_ERROR( PS_FILE_LOAD_FAILURE, "One or more data files required by the \ -engine could not be loaded. These files may have been deleted or corrupted." ); -DEFINE_ERROR( PS_FILE_NODYNAMIC, "A data file was modified during execution, \ -but the engine cannot make one or more of these alterations while the game is \ -running." ); - -//-------------------------------------------------------- -// SConfigData: Internal file representation -//-------------------------------------------------------- - -SConfigData::SConfigData( CStr _Filename, void* _Data, LoaderFunction _DynamicLoader, bool _Static ) -{ - Filename = _Filename; - Data = _Data; - DynamicLoader = _DynamicLoader; - Static = _Static; - Timestamp = TIME_UNREGISTERED; -} - -//-------------------------------------------------------- -// CConfig: Dynamic Data Manager (singleton) -//-------------------------------------------------------- - -//-------------------------------------------------------- -// CConfig::CConfig() -//-------------------------------------------------------- - -CConfig::CConfig() -{ - Clear(); - Attach( NULL ); - i = m_FileList.begin(); -} - -//-------------------------------------------------------- -// CConfig::Register() -// -// Add a file to the registered list. -//-------------------------------------------------------- - -PS_RESULT CConfig::Register( CStr Filename, void* Data, LoaderFunction DynamicLoader, bool Static ) -{ - assert( DynamicLoader != NULL ); - - if( m_LogFile ) - { - CStr Report = _T( "Adding file: " ); - Report += Filename; - m_LogFile->WriteText( (const TCHAR*)Report ); - } - - // Might as well check we can find the thing. - // This could need changing if vfs_stat doesn't - // search archives... - - struct stat dy; - - if( vfs_stat( Filename, &dy ) ) - { - if( m_LogFile ) - { - CStr Error = _T( "File not found on: " ); - Error += Filename; - m_LogFile->WriteError( (const TCHAR*)Error ); - } - return( PS_FILE_NOT_FOUND ); - } - - m_FileList.push_back( SConfigData( Filename, Data, DynamicLoader, Static ) ); - - i = m_FileList.begin(); - - if( !Static ) - return( PS_OK ); - - // Load static files at the point of registration. - - PS_RESULT Result; - if( ( Result = DynamicLoader( Filename, Data ) ) != PS_OK ) - { - if( m_LogFile ) - { - CStr Error = _T( "Load failed on: " ); - Error += Filename; - Error += CStr( "Load function returned: " ); - Error += CStr( Result ); - m_LogFile->WriteError( (const TCHAR*)Error ); - } - } - return( Result ); -} - -//-------------------------------------------------------- -// CConfig::Update() -// -// Check timestamps of files and reload as required. -//-------------------------------------------------------- - -PS_RESULT CConfig::Update() -{ - int slice = 0; - int failed = 0; - struct stat FileInfo; - - for( slice = 0; ( i != m_FileList.end() ) && ( slice < CONFIG_SLICE ); i++ ) - { - // Ignore static files - - if( i->Static ) - continue; - slice++; - - // TODO: CFile change on following line. - - if( vfs_stat( i->Filename, &FileInfo ) ) - { - // We can't find the file. - // If VFS ends up implemented in such a way as vfs_stat doesn't - // search archives, the following code is needed... - /* - if( i->Timestamp ) - { - // And it's already been loaded once, don't do so again. - continue; - } - // == TIME_UNREGISTERED. Load it, and set the modified date - // to now so that if it does turn up later on with a time - // after the start of the program, it will get loaded. - i->Timestamp = time( NULL ); - */ - // Otherwise; - failed++; - if( m_LogFile ) - { - CStr Error = _T( "File not found on: " ); - Error += i->Filename; - m_LogFile->WriteError( (const TCHAR*)Error ); - } - continue; - } - else - { - if( i->Timestamp == FileInfo.st_mtime ) - { - // This file has the same modification time as it did last - // time we checked. - continue; - } - i->Timestamp = FileInfo.st_mtime; - } - // If we reach here, the file needs to be (re)loaded. - - // Note also that polling every frame via _stat() for a file which - // either does not exist (or exists only in an archive) could be a - // considerable waste of time, but if not done the game won't pick - // up on modified versions of archived files moved into the main - // directory trees. Also, alternatives to polling don't tend to be - // portable. - - slice--; - - // Reloaded files do not count against the slice quota. - - if( m_LogFile ) - { - CStr Report = _T( "Reloading file: " ); - Report += i->Filename; - m_LogFile->WriteText( (const TCHAR*)Report ); - } - - PS_RESULT Result; - if( ( Result = i->DynamicLoader( i->Filename, i->Data ) ) != PS_OK ) - { - if( m_LogFile ) - { - CStr Error = _T( "Load failed on: " ); - Error += CStr( i->Filename ); - Error += CStr( "Load function returned: " ); - Error += CStr( Result ); - m_LogFile->WriteError( (const TCHAR*)Error ); - } - failed++; - if( Result != PS_FILE_NODYNAMIC ) - return( PS_FILE_LOAD_FAILURE ); // Oops. Serious problem, bail. - } - } - if( i == m_FileList.end() ) i = m_FileList.begin(); - if( failed ) - return( PS_FILE_NODYNAMIC ); - return( PS_OK ); -} - -//-------------------------------------------------------- -// CConfig::ReloadAll() -// -// Reloads all files. -//-------------------------------------------------------- - -PS_RESULT CConfig::ReloadAll() -{ - // Mostly identical to Update(), above. - int failed = 0; - int notfound = 0; - struct stat FileInfo; - - for( i = m_FileList.begin(); i != m_FileList.end(); i++ ) - { - // TODO: CFile change on following line. - - if( vfs_stat( i->Filename, &FileInfo ) ) - { - // We can't find the file. - // Next block may need to be uncommented if VFS_stat - // doesn't search archives in the final ver. - /* - char filepath[PATH_MAX]; - if( vfs_realpath( i->Filename, filepath ) ) - { - // Oops. - notfound++; - if( m_LogFile ) - { - CStr Error = _T( "File not found on: " ); - Error += i->Filename; - m_LogFile->WriteError( (const TCHAR*)Error ); - } - continue; - } - i->Filename = CStr( filepath ); - i->Timestamp = time( NULL ); - */ - notfound++; - if( m_LogFile ) - { - CStr Error = _T( "File not found on: " ); - Error += i->Filename; - m_LogFile->WriteError( (const TCHAR*)Error ); - } - continue; - } - else - { - i->Timestamp = FileInfo.st_mtime; - } - - // And load them all again... - - if( m_LogFile ) - { - CStr Report = _T( "Reloading file: " ); - Report += i->Filename; - m_LogFile->WriteText( (const TCHAR*)Report ); - } - - PS_RESULT Result; - if( ( Result = i->DynamicLoader( i->Filename, i->Data ) ) != PS_OK ) - { - if( m_LogFile ) - { - CStr Error = _T( "Load failed on: " ); - Error += i->Filename; - Error += CStr( "Load function returned: " ); - Error += CStr( Result ); - m_LogFile->WriteError( (const TCHAR*)Error ); - } - failed++; - if( Result != PS_FILE_NODYNAMIC ) - return( PS_FILE_LOAD_FAILURE ); // Oops. Serious problem, bail. - } - } - - i = m_FileList.begin(); - - if( notfound ) - return( PS_FILE_NOT_FOUND ); - if( failed ) - return( PS_FILE_NODYNAMIC ); - return( PS_OK ); -} - -//-------------------------------------------------------- -// CConfig::Clear() -// -// Erases registered and static lists. -//-------------------------------------------------------- - -void CConfig::Clear() -{ - m_FileList.clear(); -} - -//-------------------------------------------------------- -// CConfig::Attach() -// -// Attaches (or detaches, with a NULL argument) a logfile class. -//-------------------------------------------------------- - -void CConfig::Attach( CLogFile* LogFile ) -{ - m_LogFile = LogFile; -} - -#endif diff --git a/source/ps/Config.h b/source/ps/Config.h deleted file mode 100755 index 1c93534cbd..0000000000 --- a/source/ps/Config.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - -Config.h - -CConfig dynamic data file manager class -Mark Thompson (mot20@cam.ac.uk) - ---Overview-- - -Maintains a list of data files in use by the engine; reloads any data file -altered during execution when Update() is called. - ---Usage-- - -Load files by calling CConfig::Register() for each. The files are not loaded -until Update() is called; do so at the end of the block. - -Update() compares the 'last-modified' timestamps of all registered files, -reloading all that have been altered since the last call (also any newly -registered). - -Loader functions passed to Register() must take a CStr argument for a -filename, a void* for additional data, and return PS_OK if successful. -They must also handle the case where modified data is being reloaded. Ideally, -they should release resources allocated to the old version and load the new, at -least functions must leave the system in a predictable state. (e.g. if graphics -files are changed, but the loader functions cannot reload them, they should -do nothing but return PS_FILE_NODYNAMIC) - ---Examples-- - -g_Config.Register( "gameParameters.dat", NULL, paramLoader ); -g_Config.Register( "graphicsParameters7.dat", (void*)7, gfxParamLoader ); -g_Config.Update(); - ---More info-- - -TDD at http://forums.wildfiregames.com/0ad - -*/ - -#ifndef CONFIG_INCLUDED -#define CONFIG_INCLUDED - -//-------------------------------------------------------- -// Includes / Compiler directives -//-------------------------------------------------------- - -#include - -#include "Prometheus.h" -#include "Singleton.h" -#include "CStr.h" -#include "LogFile.h" -#include "lib.h" - -#include - -//-------------------------------------------------------- -// Macros -//-------------------------------------------------------- - -// Get singleton -#define g_Config CConfig::GetSingleton() - -//Dummy timestamp value -#define TIME_UNREGISTERED 0 -#define ACCESS_EXISTS 0 -//The maximum number of files processed in one call to Update() -#define CONFIG_SLICE 100 - -//-------------------------------------------------------- -// Declarations -//-------------------------------------------------------- - -//Possible return codes -DECLARE_ERROR( PS_FILE_NOT_FOUND ); -DECLARE_ERROR( PS_FILE_LOAD_FAILURE ); -DECLARE_ERROR( PS_FILE_NODYNAMIC ); - -//Loader function -typedef PS_RESULT (*LoaderFunction)( CStr Filename, void* Data ); - -//Internal registration type -struct SConfigData -{ - CStr Filename; - LoaderFunction DynamicLoader; - void* Data; - bool Static; - time_t Timestamp; - SConfigData( CStr _Filename, void* _Data, LoaderFunction _DynamicLoader, bool _Static ); -}; - -class CConfig : public Singleton -{ -public: - CConfig(); - //Register a new file with it's associated loader function - PS_RESULT Register( CStr Filename, void* Data, LoaderFunction DynamicLoader, bool Static = false ); - //Check all registered files, reload as neccessary - PS_RESULT Update(); - //Force an update of all files in the registered and static lists. - PS_RESULT ReloadAll(); - //Erase the entire list of registered and static files - void Clear(); - //Attach or detach a logfile class. - void Attach( CLogFile* LogFile ); -private: - std::vector m_FileList; - std::vector::iterator i; - CLogFile* m_LogFile; -}; - -#endif diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp index fb8f42cd67..12fb4290e4 100755 --- a/source/ps/ConfigDB.cpp +++ b/source/ps/ConfigDB.cpp @@ -195,15 +195,6 @@ CConfigDB::CConfigDB() CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, CStr name) { - /* - assert(ns < CFG_LAST && ns >= 0); - - TConfigMap::iterator it=m_Map[ns].find(name); - if (it == m_Map[ns].end()) - return NULL; - else - return &(it->second[0] ); - */ CConfigValueSet* values = GetValues( ns, name ); if( !values ) return( NULL ); return &( (*values)[0] ); @@ -212,13 +203,20 @@ CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, CStr name) CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, CStr name ) { assert(ns < CFG_LAST && ns >= 0); - - TConfigMap::iterator it=m_Map[ns].find(name); - if (it == m_Map[ns].end()) - return NULL; - else - return &(it->second ); -} + + TConfigMap::iterator it = m_Map[CFG_COMMAND].find( name ); + if( it != m_Map[CFG_COMMAND].end() ) + return &( it->second ); + + for( int search_ns = ns; search_ns >= CFG_SYSTEM; search_ns-- ) + { + TConfigMap::iterator it = m_Map[search_ns].find(name); + if (it != m_Map[search_ns].end()) + return &( it->second ); + } + + return( NULL ); +} CConfigValue *CConfigDB::CreateValue(EConfigNamespace ns, CStr name) { diff --git a/source/ps/ConfigDB.h b/source/ps/ConfigDB.h index 24995b2f65..b4dcda1443 100755 --- a/source/ps/ConfigDB.h +++ b/source/ps/ConfigDB.h @@ -38,11 +38,15 @@ #include "CStr.h" #include "Singleton.h" +// Namespace priorities: User supersedes mod supersedes system. +// Command-line arguments override everything. + enum EConfigNamespace { CFG_SYSTEM, CFG_MOD, CFG_USER, + CFG_COMMAND, CFG_LAST }; @@ -63,16 +67,16 @@ public: CConfigDB(); // GetValue() - // Attempt to find a config variable with the given name in the specified - // namespace. + // Attempt to find a config variable with the given name; will search all + // namespaces from system up to the specified namespace. // // Returns a pointer to the config value structure for the variable, or // NULL if such a variable could not be found CConfigValue *GetValue(EConfigNamespace ns, CStr name); // GetValues() - // Attempt to retrieve a vector of values corresponding to the given setting - // in the specified namespace + // Attempt to retrieve a vector of values corresponding to the given setting; + // will search all namespaces from system up to the specified namespace. // // Returns a pointer to the vector, or NULL if the setting could not be found. CConfigValueSet *GetValues(EConfigNamespace ns, CStr name); diff --git a/source/ps/Font.cpp b/source/ps/Font.cpp index f5d106d5fb..4c65ca9ed2 100755 --- a/source/ps/Font.cpp +++ b/source/ps/Font.cpp @@ -24,7 +24,7 @@ CFont::CFont(const char* name) CStr fontName = "font."; fontName += name; // See if the config value can be loaded - CConfigValue* fontFilenameVar = g_ConfigDB.GetValue(CFG_SYSTEM, fontName); + CConfigValue* fontFilenameVar = g_ConfigDB.GetValue(CFG_USER, fontName); if (fontFilenameVar && fontFilenameVar->GetString(fontFilename)) { h = unifont_load(fontFilename.c_str()); diff --git a/source/ps/Hotkey.cpp b/source/ps/Hotkey.cpp index fbbbbb940d..6e476e0dd1 100755 --- a/source/ps/Hotkey.cpp +++ b/source/ps/Hotkey.cpp @@ -146,7 +146,7 @@ static GUIHotkeyMap guiHotkeyMap; void setBindings( const CStr& hotkeyName, int integerMapping = -1 ) { - CConfigValueSet* binding = g_ConfigDB.GetValues( CFG_SYSTEM, CStr( "hotkey." ) + hotkeyName ); + CConfigValueSet* binding = g_ConfigDB.GetValues( CFG_USER, CStr( "hotkey." ) + hotkeyName ); if( binding ) { int mapping; diff --git a/source/ps/Network/AllNetMessages.h b/source/ps/Network/AllNetMessages.h index 524c186d12..740628cbb1 100755 --- a/source/ps/Network/AllNetMessages.h +++ b/source/ps/Network/AllNetMessages.h @@ -59,8 +59,6 @@ enum ENetMessageType /* Game event messages */ - NMT_Event_IveGotAnInteger, - /** * One higher than the highest value of any message type */ diff --git a/source/ps/Parser.cpp b/source/ps/Parser.cpp index 4611028388..457f1e7bb6 100755 --- a/source/ps/Parser.cpp +++ b/source/ps/Parser.cpp @@ -191,6 +191,12 @@ bool CParserValue::GetString(std::string &ret) return true; } +bool CParserValue::GetString( CStr& ret ) +{ + ret = m_String; + return true; +} + // These macros include the IMPLEMENTATION of the // the function in the macro argument for CParserValue // They use GetDouble, and then type-cast it diff --git a/source/ps/Parser.h b/source/ps/Parser.h index 920cc48dc4..3acce8da9e 100755 --- a/source/ps/Parser.h +++ b/source/ps/Parser.h @@ -39,6 +39,8 @@ will exist, and it's up to the system to figure out which one acquired. #include #include +#include "CStr.h" + //------------------------------------------------- // Types //------------------------------------------------- @@ -76,6 +78,7 @@ public: // return is error status bool GetString(std::string &ret); + bool GetString( CStr& ret ); bool GetBool(bool &ret); bool GetChar(char &ret); // As number! otherwise use GetString make sure size=1 bool GetShort(short &ret); diff --git a/source/ps/World.cpp b/source/ps/World.cpp index fc3e0298fb..f8eb8bb4d5 100755 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -14,7 +14,7 @@ #define LOG_CATEGORY "world" -extern CLightEnv g_LightEnv; +CLightEnv g_LightEnv; void CWorld::Initialize(CGameAttributes *pAttribs) { diff --git a/source/scripting/DOMEvent.cpp b/source/scripting/DOMEvent.cpp new file mode 100755 index 0000000000..538ecf9ee2 --- /dev/null +++ b/source/scripting/DOMEvent.cpp @@ -0,0 +1,35 @@ +#include "precompiled.h" +#include "DOMEvent.h" +#include "timer.h" + +CScriptEvent::CScriptEvent( const CStrW& Type, bool Cancelable, unsigned int TypeCode ) +{ + m_Type = Type; m_TypeCode = TypeCode; m_Cancelable = Cancelable; m_Cancelled = false; m_Timestamp = (long)( get_time() * 1000.0 ); + AddReadOnlyProperty( L"type", &m_Type ); + AddReadOnlyProperty( L"cancelable", &m_Cancelable ); + AddReadOnlyProperty( L"timeStamp", &m_Timestamp ); +} + +void CScriptEvent::ScriptingInit() +{ + AddMethod( "toString", 0 ); + AddMethod( "preventDefault", 0 ); + + CJSObject::ScriptingInit( "Event" ); +} + +jsval CScriptEvent::PreventDefault( JSContext* cx, uintN argc, jsval* argv ) +{ + if( m_Cancelable ) + m_Cancelled = true; + return( JSVAL_VOID ); +} + +jsval CScriptEvent::ToString( JSContext* cx, uintN argc, jsval* argv ) +{ + utf16_t buffer[256]; + swprintf( buffer, 256, L"[object Event: %ls]", m_Type.c_str() ); + buffer[255] = 0; + return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, buffer ) ) ); +} + diff --git a/source/scripting/DOMEvent.h b/source/scripting/DOMEvent.h new file mode 100755 index 0000000000..2cacaa8f10 --- /dev/null +++ b/source/scripting/DOMEvent.h @@ -0,0 +1,60 @@ +// DOM-style event object +// +// Mark Thompson (mot20@cam.ac.uk / mark@wildfiregames.com) + +// Note: Cancellable? Cancelable? DOM says one l, OED says 2. JS interface uses 1. + +#ifndef DOMEVENT_INCLUDED +#define DOMEVENT_INCLUDED + +#include "ScriptableObject.h" + +class CScriptEvent : public CJSObject +{ +public: + enum EPhaseType + { + CAPTURING_PHASE = 1, + AT_TARGET = 2, + BUBBLING_PHASE = 3 + }; + + // Target (currently unused) + // EventTarget* m_Target; + + // Listening object currently being processed (currentky unused) + // EventTarget* m_CurrentTarget; + + // Phase type (currently unused) + // EPhaseType m_EventPhase; + + // Can bubble? (currently unused) + // bool m_Bubbles; + + // Can be cancelled (default actions prevented) + bool m_Cancelable; + + // Timestamp (milliseconds since epoch (start of game?)) + i32 m_Timestamp; + + // Event type string + CStrW m_Type; + + // Type code (to speed lookups) + unsigned int m_TypeCode; + + // Has been cancelled? + bool m_Cancelled; + +// -- + + jsval ToString( JSContext* cx, uintN argc, jsval* argv ); + jsval PreventDefault( JSContext* cx, uintN argc, jsval* argv ); + +public: + CScriptEvent( const CStrW& Type, bool Cancelable, unsigned int TypeCode = -1 ); + static void ScriptingInit(); +}; + +#endif + diff --git a/source/scripting/JSConversions.cpp b/source/scripting/JSConversions.cpp index 095f2d9ff8..4a68302f5a 100755 --- a/source/scripting/JSConversions.cpp +++ b/source/scripting/JSConversions.cpp @@ -71,9 +71,7 @@ template<> JSObject* ToScript( CVector3D* Native ) template<> jsval ToJSVal( CScriptObject& Native ) { - if( Native.Type == CScriptObject::FUNCTION ) - return( OBJECT_TO_JSVAL( JS_GetFunctionObject( Native.Function ) ) ); - return( JSVAL_NULL ); + return( OBJECT_TO_JSVAL( Native.GetFunctionObject() ) ); } template<> bool ToPrimitive( JSContext* cx, jsval v, CScriptObject& Storage ) diff --git a/source/scripting/JSConversions.h b/source/scripting/JSConversions.h index 653db16231..ceaf7cfd61 100755 --- a/source/scripting/JSConversions.h +++ b/source/scripting/JSConversions.h @@ -27,6 +27,8 @@ template T* ToNative( JSContext* cx, JSObject* obj ) template JSObject* ToScript( T* Native ) { + if( !Native ) + return( JSVAL_NULL ); return( Native->GetScript() ); } diff --git a/source/scripting/ScriptableObject.h b/source/scripting/ScriptableObject.h index 8e28d7a69f..5c04d4bd73 100755 --- a/source/scripting/ScriptableObject.h +++ b/source/scripting/ScriptableObject.h @@ -68,13 +68,13 @@ public: virtual void AddProperty( CStrW PropertyName, CStrW Value ) = 0; }; -template class CJSObject; +template class CJSObject; template class CJSPropertyAccessor { T* m_Owner; CStrW m_PropertyRoot; - template friend class CJSObject; + template friend class CJSObject; public: CJSPropertyAccessor( T* Owner, CStrW PropertyRoot ) @@ -129,16 +129,6 @@ public: return( JS_TRUE ); } - /* - static void JSFinalize( JSContext* cx, JSObject* obj ) - { - CJSPropertyAccessor* Instance = (CJSPropertyAccessor*)JS_GetPrivate( cx, obj ); - if( !Instance ) - return; - - if( Instance ) delete( Instance ); - } - */ static JSClass JSI_Class; static void ScriptingInit() { @@ -159,7 +149,7 @@ template JSClass CJSPropertyAccessor::JSI_Class = { }; -template class CJSProperty : public IJSProperty +template class CJSProperty : public IJSProperty { T* m_Data; @@ -172,14 +162,14 @@ template class CJSProperty : public IJSProperty IJSObject::NotifyFn m_Freshen; public: - CJSProperty( T* Data, IJSObject* Owner = NULL, bool AllowsInheritance = true, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL ) + CJSProperty( T* Data, IJSObject* Owner = NULL, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL ) { assert( !( !m_Owner && ( Freshen || Update ) ) ); // Bad programmer. m_Data = Data; m_Owner = Owner; + m_AllowsInheritance = AllowsInheritance; m_Update = Update; m_Freshen = Freshen; - m_AllowsInheritance = AllowsInheritance; m_Intrinsic = true; } jsval Get( JSContext* cx ) @@ -189,19 +179,22 @@ public: } void ImmediateCopy( IJSProperty* Copy ) { - *m_Data = *( ((CJSProperty*)Copy)->m_Data ); + *m_Data = *( ((CJSProperty*)Copy)->m_Data ); } void Set( JSContext* cx, jsval Value ) { - if( m_Freshen ) (m_Owner->*m_Freshen)(); - if( ToPrimitive( cx, Value, *m_Data ) ) - if( m_Update ) (m_Owner->*m_Update)(); + if( !ReadOnly ) // I think all our compilers are intelligent enough to optimize this away. + { + if( m_Freshen ) (m_Owner->*m_Freshen)(); + if( ToPrimitive( cx, Value, *m_Data ) ) + if( m_Update ) (m_Owner->*m_Update)(); + } } }; class CJSValProperty : public IJSProperty { - template friend class CJSObject; + template friend class CJSObject; jsval m_Data; JSObject* m_JSAccessor; @@ -264,7 +257,7 @@ public: } }; -template class CJSObject : public IJSObject +template class CJSObject : public IJSObject { JSObject* m_JS; public: @@ -273,37 +266,43 @@ public: void GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ); void SetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ) { - IJSProperty* prop = HasProperty( PropertyName ); - - if( prop ) + if( !ReadOnly ) { - // Already exists - prop->Set( cx, *vp ); - - if( prop->m_AllowsInheritance ) + IJSProperty* prop = HasProperty( PropertyName ); + + if( prop ) { - // Run along and update this property in any inheritors - InheritorsList UpdateSet( m_Inheritors ); - - while( !UpdateSet.empty() ) + // Already exists + prop->Set( cx, *vp ); + + if( AllowInheritance ) { - IJSObject* UpdateObj = UpdateSet.back(); - UpdateSet.pop_back(); - IJSProperty* UpdateProp = UpdateObj->m_Properties[PropertyName]; - if( UpdateProp->m_Inherited ) + if( prop->m_AllowsInheritance ) { - UpdateProp->Set( cx, *vp ); - InheritorsList::iterator it2; - for( it2 = UpdateObj->m_Inheritors.begin(); it2 != UpdateObj->m_Inheritors.end(); it2++ ) - UpdateSet.push_back( *it2 ); + // Run along and update this property in any inheritors + InheritorsList UpdateSet( m_Inheritors ); + + while( !UpdateSet.empty() ) + { + IJSObject* UpdateObj = UpdateSet.back(); + UpdateSet.pop_back(); + IJSProperty* UpdateProp = UpdateObj->m_Properties[PropertyName]; + if( UpdateProp->m_Inherited ) + { + UpdateProp->Set( cx, *vp ); + InheritorsList::iterator it2; + for( it2 = UpdateObj->m_Inheritors.begin(); it2 != UpdateObj->m_Inheritors.end(); it2++ ) + UpdateSet.push_back( *it2 ); + } + } } } } - } - else - { - // Need to add it - AddProperty( PropertyName, *vp ); + else + { + // Need to add it + AddProperty( PropertyName, *vp ); + } } } @@ -312,7 +311,7 @@ public: // static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { - CJSObject* Instance = ToNative( cx, obj ); + CJSObject* Instance = ToNative( cx, obj ); if( !Instance ) return( JS_TRUE ); @@ -324,7 +323,7 @@ public: } static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { - CJSObject* Instance = ToNative( cx, obj ); + CJSObject* Instance = ToNative( cx, obj ); if( !Instance ) return( JS_TRUE ); @@ -384,7 +383,7 @@ public: CJSValProperty* extProp = (CJSValProperty*)it->second; if( extProp->m_JSAccessor ) { - CJSPropertyAccessor< CJSObject >* accessor = (CJSPropertyAccessor< CJSObject >*)JS_GetPrivate( g_ScriptingHost.GetContext(), extProp->m_JSAccessor ); + CJSPropertyAccessor< CJSObject >* accessor = (CJSPropertyAccessor< CJSObject >*)JS_GetPrivate( g_ScriptingHost.GetContext(), extProp->m_JSAccessor ); assert( accessor ); delete( accessor ); JS_SetPrivate( g_ScriptingHost.GetContext(), extProp->m_JSAccessor, NULL ); @@ -393,37 +392,6 @@ public: } delete( it->second ); } - /* - ReferrersSet::iterator rit; - for( rit = m_Referring.begin(); rit != m_Referring.end(); rit++ ) - { - JSObject* ref = *rit; - if( JS_GetClass( ref ) == &JSI_class ) - { - // Reference to this object directly. - // Replace with null pointer. - - // - Make sure it refers to this object. - assert( JS_GetPrivate( g_ScriptingHost.GetContext(), ref ) == this ); - - JS_SetPrivate( g_ScriptingHost.GetContext(), ref, NULL ); - } - else - { - // Possibly just deallocate the property object? - - // - Nothing else it should be. - assert( JS_GetClass( ref ) == &CJSPropertyAccessor::JSI_Class ); - - CJSPropertyAccessor* Accessor = (CJSPropertyAccessor*)JS_GetPrivate( g_ScriptingHost.GetContext(), ref ); - - // - Make sure it refers to this object. - assert( Accessor->m_Owner == this ); - - Accessor->m_Owner = NULL; - } - } - */ if( m_JS ) { JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, NULL ); @@ -432,45 +400,51 @@ public: } void SetBase( IJSObject* Parent ) { - if( m_Parent ) + if( AllowInheritance ) { - // Remove this from the list of our parent's inheritors - InheritorsList::iterator it; - for( it = m_Parent->m_Inheritors.begin(); it != m_Parent->m_Inheritors.end(); it++ ) - if( (*it) == this ) - m_Parent->m_Inheritors.erase( it ); - // TODO: Remove any properties we were inheriting from this parent that we didn't specify ourselves - } - m_Parent = Parent; - if( m_Parent ) - { - // Place this in the list of our parent's inheritors - m_Parent->m_Inheritors.push_back( this ); - Rebuild(); + if( m_Parent ) + { + // Remove this from the list of our parent's inheritors + InheritorsList::iterator it; + for( it = m_Parent->m_Inheritors.begin(); it != m_Parent->m_Inheritors.end(); it++ ) + if( (*it) == this ) + m_Parent->m_Inheritors.erase( it ); + // TODO: Remove any properties we were inheriting from this parent that we didn't specify ourselves + } + m_Parent = Parent; + if( m_Parent ) + { + // Place this in the list of our parent's inheritors + m_Parent->m_Inheritors.push_back( this ); + Rebuild(); + } } } void Rebuild() { - PropertyTable::iterator it; - // For each property in the parent - for( it = m_Parent->m_Properties.begin(); it != m_Parent->m_Properties.end(); it++ ) + if( AllowInheritance ) { - if( !it->second->m_AllowsInheritance ) - continue; - PropertyTable::iterator cp; - // Attempt to locate it in this object - cp = m_Properties.find( it->first ); - if( cp != m_Properties.end() ) + PropertyTable::iterator it; + // For each property in the parent + for( it = m_Parent->m_Properties.begin(); it != m_Parent->m_Properties.end(); it++ ) { - if( cp->second->m_Inherited ) - cp->second->ImmediateCopy( it->second ); + if( !it->second->m_AllowsInheritance ) + continue; + PropertyTable::iterator cp; + // Attempt to locate it in this object + cp = m_Properties.find( it->first ); + if( cp != m_Properties.end() ) + { + if( cp->second->m_Inherited ) + cp->second->ImmediateCopy( it->second ); + } + else + m_Properties[it->first] = new CJSValProperty( it->second->Get(), true ); } - else - m_Properties[it->first] = new CJSValProperty( it->second->Get(), true ); + InheritorsList::iterator c; + for( c = m_Inheritors.begin(); c != m_Inheritors.end(); c++ ) + (*c)->Rebuild(); } - InheritorsList::iterator c; - for( c = m_Inheritors.begin(); c != m_Inheritors.end(); c++ ) - (*c)->Rebuild(); } IJSProperty* HasProperty( CStrW PropertyName ) { @@ -483,13 +457,16 @@ public: void ReplicateProperty( CStrW PropertyName, jsval Value ) { - m_Properties[PropertyName] = new CJSValProperty( Value, true ); - // Run through our descendants to add the property to all of them that don't - // already have it. - InheritorsList::iterator it; - for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ ) - if( !((*it)->HasProperty( PropertyName ) ) ) - (*it)->ReplicateProperty( PropertyName, Value ); + if( AllowInheritance ) + { + m_Properties[PropertyName] = new CJSValProperty( Value, true ); + // Run through our descendants to add the property to all of them that don't + // already have it. + InheritorsList::iterator it; + for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ ) + if( !((*it)->HasProperty( PropertyName ) ) ) + (*it)->ReplicateProperty( PropertyName, Value ); + } } void AddProperty( CStrW PropertyName, jsval Value ) @@ -497,12 +474,15 @@ public: assert( !HasProperty( PropertyName ) ); m_Properties[PropertyName] = new CJSValProperty( Value, false ); - // Run through our descendants to add the property to all of them that don't - // already have it. - InheritorsList::iterator it; - for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ ) - if( !((*it)->HasProperty( PropertyName ) ) ) - (*it)->ReplicateProperty( PropertyName, Value ); + if( AllowInheritance ) + { + // Run through our descendants to add the property to all of them that don't + // already have it. + InheritorsList::iterator it; + for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ ) + if( !((*it)->HasProperty( PropertyName ) ) ) + (*it)->ReplicateProperty( PropertyName, Value ); + } } void AddProperty( CStrW PropertyName, CStrW Value ) @@ -515,13 +495,18 @@ public: JSFunctionSpec FnInfo = { Name, CNativeFunction::JSFunction, MinArgs, 0, 0 }; T::m_Methods.push_back( FnInfo ); } - template void AddProperty( CStrW PropertyName, PropType* Native, bool AllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) + template void AddProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = AllowInheritance, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) { - m_Properties[PropertyName] = new CJSProperty( Native, this, AllowInheritance, Update, Refresh ); + m_Properties[PropertyName] = new CJSProperty( Native, this, PropAllowInheritance, Update, Refresh ); + } + template void AddReadOnlyProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = AllowInheritance, NotifyFn Update = NULL, NotifyFn Refresh = NULL ) + { + assert( !( PropAllowInheritance && !AllowInheritance ) ); + m_Properties[PropertyName] = new CJSProperty( Native, this, PropAllowInheritance, Update, Refresh ); } }; -template JSClass CJSObject::JSI_class = { +template JSClass CJSObject::JSI_class = { NULL, JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JSGetProperty, JSSetProperty, @@ -530,13 +515,13 @@ template JSClass CJSObject::JSI_class = { NULL, NULL, NULL, NULL }; -template JSPropertySpec CJSObject::JSI_props[] = { +template JSPropertySpec CJSObject::JSI_props[] = { { 0 }, }; -template std::vector CJSObject::m_Methods; +template std::vector CJSObject::m_Methods; -template void CJSObject::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ) +template void CJSObject::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ) { IJSProperty* Property = HasProperty( PropertyName ); if( Property ) @@ -550,7 +535,7 @@ template void CJSObject::GetProperty( JSContext* cx, CStrW Proper CJSValProperty* extProp = (CJSValProperty*)Property; if( !extProp->m_JSAccessor ) { - extProp->m_JSAccessor = CJSPropertyAccessor< CJSObject >::CreateAccessor( cx, this, PropertyName ); + extProp->m_JSAccessor = CJSPropertyAccessor< CJSObject >::CreateAccessor( cx, this, PropertyName ); JS_AddRoot( cx, extProp->m_JSAccessor ); } diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 5fd2cd26fa..c1be9d1492 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -20,6 +20,8 @@ CBaseEntity::CBaseEntity() for( int t = 0; t < EVENT_LAST; t++ ) AddProperty( EventNames[t], &m_EventHandlers[t] ); + m_base = NULL; + m_actorObject = NULL; m_bound_type = CBoundingObject::BOUND_NONE; m_bound_circle = NULL; @@ -165,7 +167,7 @@ bool CBaseEntity::loadXML( CStr filename ) { if( CStrW( EventNames[eventID] ) == EventName ) { - m_EventHandlers[eventID].CompileScript( CStrW( filename ) + L"::" + EventName + L" (" + CStrW( Child.getLineNumber() ) + L")", Code ); + m_EventHandlers[eventID].Compile( CStrW( filename ) + L"::" + EventName + L" (" + CStrW( Child.getLineNumber() ) + L")", Code ); HasProperty( EventName )->m_Inherited = false; break; } @@ -243,7 +245,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& void CBaseEntity::ScriptingInit() { AddMethod( "toString", 0 ); - CJSObject::ScriptingInit( "EntityTemplate" ); + CJSObject::ScriptingInit( "EntityTemplate" ); } // Script-bound functions diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index 66dac978b7..31a79bccad 100755 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -27,7 +27,7 @@ #include "ScriptObject.h" #include "Xeromyces.h" -class CBaseEntity : public CJSObject +class CBaseEntity : public CJSObject { public: CBaseEntity(); diff --git a/source/simulation/BaseEntityCollection.cpp b/source/simulation/BaseEntityCollection.cpp index 22a8589879..c54d888514 100755 --- a/source/simulation/BaseEntityCollection.cpp +++ b/source/simulation/BaseEntityCollection.cpp @@ -10,7 +10,7 @@ void CBaseEntityCollection::loadTemplates() { Handle handle; - vfsDirEnt type, file; + vfsDirEnt type; CStr basepath = "entities/"; CStr pathname; @@ -21,6 +21,7 @@ void CBaseEntityCollection::loadTemplates() if( maindir > 0 ) { + LoadDirectory( maindir, basepath ); while( !vfs_next_dirent( maindir, &type, "/" ) ) { pathname = basepath + type.name; @@ -31,17 +32,7 @@ void CBaseEntityCollection::loadTemplates() if( handle > 0 ) { - while( !vfs_next_dirent(handle, &file, ".xml") ) - { - CBaseEntity* newTemplate = new CBaseEntity(); - if( newTemplate->loadXML( pathname + file.name ) ) - { - addTemplate( newTemplate ); - LOG(NORMAL, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s%s\"", pathname.c_str(), file.name); - } - else - LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s%s\"", pathname.c_str(), file.name); - } + LoadDirectory( handle, pathname ); vfs_close_dir( handle ); } else @@ -75,6 +66,22 @@ void CBaseEntityCollection::loadTemplates() } +void CBaseEntityCollection::LoadDirectory( Handle directory, CStr pathname ) +{ + vfsDirEnt file; + while( !vfs_next_dirent( directory, &file, ".xml") ) + { + CBaseEntity* newTemplate = new CBaseEntity(); + if( newTemplate->loadXML( pathname + file.name ) ) + { + addTemplate( newTemplate ); + LOG(NORMAL, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s%s\"", pathname.c_str(), file.name); + } + else + LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s%s\"", pathname.c_str(), file.name); + } +} + void CBaseEntityCollection::addTemplate( CBaseEntity* temp ) { m_templates.push_back( temp ); diff --git a/source/simulation/BaseEntityCollection.h b/source/simulation/BaseEntityCollection.h index cf6da32167..fd01863dac 100755 --- a/source/simulation/BaseEntityCollection.h +++ b/source/simulation/BaseEntityCollection.h @@ -33,6 +33,7 @@ public: ~CBaseEntityCollection(); CBaseEntity* getTemplate( CStrW entityType ); void loadTemplates(); + void LoadDirectory( Handle directory, CStr pathname ); void addTemplate( CBaseEntity* temp ); CBaseEntity* getTemplateByActor( CObjectEntry* actor ); }; diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 8ef377af36..293a8f47af 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -22,7 +22,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) { m_position = position; m_orientation = orientation; - m_ahead.x = sin( m_orientation ); m_ahead.y = cos( m_orientation ); @@ -186,13 +185,19 @@ void CEntity::update( size_t timestep ) void CEntity::dispatch( const CMessage* msg ) { + switch( msg->type ) { case CMessage::EMSG_TICK: - m_EventHandlers[EVENT_TICK].Run( GetScript() ); + { + CEventTick Tick; + DispatchEvent( &Tick ); break; + } case CMessage::EMSG_INIT: - m_EventHandlers[EVENT_INITIALIZE].Run( GetScript() ); + { + CEventInitialize Init; + DispatchEvent( &Init ); if( m_base->m_Tag == CStrW( L"Prometheus Dude" ) ) { if( getCollisionObject( this ) ) @@ -220,6 +225,7 @@ void CEntity::dispatch( const CMessage* msg ) */ } break; + } case CMessage::EMSG_ORDER: CMessageOrder* m; m = (CMessageOrder*)msg; @@ -230,6 +236,12 @@ void CEntity::dispatch( const CMessage* msg ) } } +bool CEntity::DispatchEvent( CScriptEvent* evt ) +{ + m_EventHandlers[evt->m_TypeCode].DispatchEvent( GetScript(), evt ); + return( false ); +} + void CEntity::clearOrders() { m_orderQueue.clear(); @@ -512,7 +524,7 @@ void CEntity::ScriptingInit() AddMethod( "toString", 0 ); AddMethod( "order", 1 ); AddMethod( "orderQueued", 1 ); - CJSObject::ScriptingInit( "Entity", Construct, 2 ); + CJSObject::ScriptingInit( "Entity", Construct, 2 ); } // Script constructor diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index a08ae2cb1a..fc83b81457 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -47,7 +47,7 @@ class CEntityManager; -class CEntity : public CJSObject +class CEntity : public CJSObject { friend class CEntityManager; public: @@ -77,8 +77,23 @@ public: float m_graphics_orientation; //-- Scripts + + // EventListener adaptation? + //typedef std::vector ExtendedHandlerList; + //typedef STL_HASH_MAP ExtendedHandlerTable; + CScriptObject m_EventHandlers[EVENT_LAST]; + // EventListener adaptation? + /* + void AddListener( const CStrW& EventType, CScriptObject* Handler ) + { + m_EventHandlers[EventType].push_back( Handler ); + } + */ + + bool DispatchEvent( CScriptEvent* evt ); + CUnit* m_actor; bool m_moving; @@ -97,18 +112,28 @@ public: // Handle-to-self. HEntity me; + // Process an event void dispatch( const CMessage* msg ); + + // Updates gameplay information for the specified timestep void update( size_t timestep_millis ); + // Updates graphical information for a point between the last and current simulation frame; 0 < relativeoffset < 1. + void interpolate( float relativeoffset ); + + // Removes entity from the gameworld and deallocates it, but not neccessarily immediately. void kill(); - void interpolate( float relativeoffset ); void snapToGround(); void updateActorTransforms(); + + // Things like selection circles and debug info - possibly move to gui if/when it becomes responsible for (and capable of) it. void render(); void renderSelectionOutline( float alpha = 1.0f ); + // After a collision, recalc the path to the next fixed waypoint. void repath(); + // Reset properties after the entity-template we use changes. void loadBase(); void reorient(); // Orientation @@ -117,6 +142,7 @@ public: void checkGroup(); // Groups void checkExtant(); // Existance + // Returns whether the entity is capable of performing the given orderType on the target. bool acceptsOrder( int orderType, CEntity* orderTarget ); void clearOrders(); diff --git a/source/simulation/EntityManager.cpp b/source/simulation/EntityManager.cpp index c638a857ed..bde1329732 100755 --- a/source/simulation/EntityManager.cpp +++ b/source/simulation/EntityManager.cpp @@ -13,7 +13,7 @@ CEntityManager::CEntityManager() m_nextalloc = 0; m_extant = true; // Also load a couple of global entity settings - CConfigValue* cfg = g_ConfigDB.GetValue( CFG_SYSTEM, "selection.outline.quality" ); + CConfigValue* cfg = g_ConfigDB.GetValue( CFG_USER, "selection.outline.quality" ); if( cfg ) cfg->GetInt( SELECTION_SMOOTHNESS_UNIFIED ); if( SELECTION_SMOOTHNESS_UNIFIED < 0 ) SELECTION_SMOOTHNESS_UNIFIED = 0; SELECTION_CIRCLE_POINTS = 7 + 2 * SELECTION_SMOOTHNESS_UNIFIED; diff --git a/source/simulation/EventHandlers.h b/source/simulation/EventHandlers.h index 21d4318660..7f6961f9b3 100755 --- a/source/simulation/EventHandlers.h +++ b/source/simulation/EventHandlers.h @@ -5,6 +5,8 @@ #ifndef EVENT_HANDLERS_INCLUDED #define EVENT_HANDLERS_INCLUDED +#include "scripting/DOMEvent.h" + enum EEventType { EVENT_INITIALIZE, @@ -18,4 +20,14 @@ static const wchar_t* EventNames[] = /* EVENT_TICK */ L"onTick" }; +class CEventInitialize : public CScriptEvent +{ +public: CEventInitialize() : CScriptEvent( L"initialize", false, EVENT_INITIALIZE ) {} +}; + +class CEventTick : public CScriptEvent +{ +public: CEventTick() : CScriptEvent( L"tick", false, EVENT_TICK ) {} +}; + #endif \ No newline at end of file diff --git a/source/simulation/PathfindEngine.cpp b/source/simulation/PathfindEngine.cpp index 8e4719a041..01b5d92d4b 100755 --- a/source/simulation/PathfindEngine.cpp +++ b/source/simulation/PathfindEngine.cpp @@ -6,7 +6,7 @@ CPathfindEngine::CPathfindEngine() { - CConfigValue* sparseDepth = g_ConfigDB.GetValue( CFG_SYSTEM, "pathfind.sparse.recursiondepth" ); + CConfigValue* sparseDepth = g_ConfigDB.GetValue( CFG_USER, "pathfind.sparse.recursiondepth" ); if( sparseDepth ) sparseDepth->GetInt( SPF_RECURSION_DEPTH ); } diff --git a/source/simulation/ScriptObject.cpp b/source/simulation/ScriptObject.cpp index 154e087679..81de82b917 100755 --- a/source/simulation/ScriptObject.cpp +++ b/source/simulation/ScriptObject.cpp @@ -3,9 +3,7 @@ CScriptObject::CScriptObject() { - Type = UNDEFINED; Function = NULL; - Script = NULL; } CScriptObject::CScriptObject( JSFunction* _Function ) @@ -13,11 +11,6 @@ CScriptObject::CScriptObject( JSFunction* _Function ) SetFunction( _Function ); } -CScriptObject::CScriptObject( JSScript* _Script ) -{ - SetScript( _Script ); -} - CScriptObject::CScriptObject( jsval v ) { SetJSVal( v ); @@ -25,45 +18,36 @@ CScriptObject::CScriptObject( jsval v ) void CScriptObject::SetFunction( JSFunction* _Function ) { - Type = FUNCTION; Function = _Function; - Script = NULL; -} - -void CScriptObject::SetScript( JSScript* _Script ) -{ - Type = SCRIPT; - Function = NULL; - Script = _Script; } void CScriptObject::SetJSVal( jsval v ) { + CStrW Source; switch( JS_TypeOfValue( g_ScriptingHost.GetContext(), v ) ) { case JSTYPE_STRING: - { - CStrW Source = g_ScriptingHost.ValueToUCString( v ); - JSScript* Script = JS_CompileUCScript( g_ScriptingHost.GetContext(), JS_GetGlobalObject( g_ScriptingHost.GetContext() ), Source.c_str(), Source.Length(), "subset query script", 0 ); - SetScript( Script ); + Source = g_ScriptingHost.ValueToUCString( v ); + Compile( L"unknown", Source ); break; - } case JSTYPE_FUNCTION: - { - JSFunction* fn = JS_ValueToFunction( g_ScriptingHost.GetContext(), v ); - SetFunction( fn ); + SetFunction( JS_ValueToFunction( g_ScriptingHost.GetContext(), v ) ); break; - } default: - Type = UNDEFINED; Function = NULL; - Script = NULL; } } bool CScriptObject::Defined() { - return( Type != UNDEFINED ); + return( Function != NULL ); +} + +JSObject* CScriptObject::GetFunctionObject() +{ + if( Function ) + return( JS_GetFunctionObject( Function ) ); + return( NULL ); } // Executes a script attached to a JS object. @@ -71,17 +55,9 @@ bool CScriptObject::Defined() // otherwise true. Script return value is in rval. bool CScriptObject::Run( JSObject* Context, jsval* rval ) { - switch( Type ) - { - case UNDEFINED: + if( !Function ) return( false ); - case FUNCTION: - return( JS_TRUE == JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, 0, NULL, rval ) ); - case SCRIPT: - return( JS_TRUE == JS_ExecuteScript( g_ScriptingHost.GetContext(), Context, Script, rval ) ); - default: - return( false ); - } + return( JS_TRUE == JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, 0, NULL, rval ) ); } // This variant casts script return value to a boolean, and passes it back. @@ -92,9 +68,18 @@ bool CScriptObject::Run( JSObject* Context ) return( false ); return( g_ScriptingHost.ValueToBool( Temp ) ); } - -void CScriptObject::CompileScript( CStrW FileNameTag, CStrW Script ) + +// Treat this as an event handler and dispatch an event to it. +void CScriptObject::DispatchEvent( JSObject* Context, CScriptEvent* evt ) { - Type = FUNCTION; - Function = JS_CompileUCFunction( g_ScriptingHost.GetContext(), NULL, NULL, 0, NULL, Script, Script.Length(), (CStr)FileNameTag, 0 ); + jsval Temp; + jsval EventObject = OBJECT_TO_JSVAL( evt->GetScript() ); + if( Function ) + JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, 1, &EventObject, &Temp ); +} + +void CScriptObject::Compile( CStrW FileNameTag, CStrW FunctionBody ) +{ + const char* argnames[] = { "evt" }; + Function = JS_CompileUCFunction( g_ScriptingHost.GetContext(), NULL, NULL, 1, argnames, FunctionBody, FunctionBody.Length(), (CStr)FileNameTag, 0 ); } diff --git a/source/simulation/ScriptObject.h b/source/simulation/ScriptObject.h index cd766936c4..79deab0e1a 100755 --- a/source/simulation/ScriptObject.h +++ b/source/simulation/ScriptObject.h @@ -10,36 +10,36 @@ #include "scripting/ScriptingHost.h" #include "EntityHandles.h" #include "scripting/JSInterface_Entity.h" +#include "scripting/DOMEvent.h" class CScriptObject { -public: - enum EScriptType - { - UNDEFINED, - FUNCTION, - SCRIPT - } Type; - JSFunction* Function; - JSScript* Script; +public: CScriptObject(); CScriptObject( JSFunction* _Function ); - CScriptObject( JSScript* _Script ); CScriptObject( jsval v ); + + // Initialize in various ways: from a JS function, a string to be compiled, or a jsval containing either. void SetFunction( JSFunction* _Function ); - void SetScript( JSScript* _Script ); void SetJSVal( jsval v ); + void Compile( CStrW FileNameTag, CStrW FunctionBody ); + inline bool Defined(); + + // JSObject wrapping the function if it's defined, NULL if it isn't. + JSObject* GetFunctionObject(); + // Executes a script attached to a JS object. // Returns false if the script isn't defined, if the script can't be executed, // otherwise true. Script return value is in rval. bool Run( JSObject* Context, jsval* rval ); // This variant casts script return value to a boolean, and passes it back. bool Run( JSObject* Context ); - - void CompileScript( CStrW FileNameTag, CStrW Script ); + + // Treat this as an event handler and dispatch an event to it. + void DispatchEvent( JSObject* Context, CScriptEvent* evt ); }; #endif \ No newline at end of file diff --git a/source/simulation/Simulation.cpp b/source/simulation/Simulation.cpp index cb2d72d2f3..c35e3d2ff8 100755 --- a/source/simulation/Simulation.cpp +++ b/source/simulation/Simulation.cpp @@ -50,7 +50,6 @@ void CSimulation::Update(double frameTime) { // The desired sim frame rate can't be achieved. Settle for process & render // frames as fast as possible. - // g_Console->InsertMessage( L"Can't maintain %d FPS simulation rate!", SIM_FRAMERATE ); m_DeltaTime = 0.0; } } diff --git a/source/simulation/TurnManager.cpp b/source/simulation/TurnManager.cpp index a967be68a3..a2b4f1bcb8 100755 --- a/source/simulation/TurnManager.cpp +++ b/source/simulation/TurnManager.cpp @@ -13,7 +13,7 @@ CSinglePlayerTurnManager *g_SinglePlayerTurnManager=NULL; CTurnManager::CTurnManager() { for (int i=0;i<3;i++) - m_Batches[i].m_TurnLength=500; + m_Batches[i].m_TurnLength=40; } void CTurnManager::ClearBatch(uint batch)