From 275a73851ce33fe3dce8973e5ebe2164e7eef841 Mon Sep 17 00:00:00 2001 From: Matei Date: Tue, 16 May 2006 04:41:37 +0000 Subject: [PATCH] # Added sky box as well as repair, heal and trample actions. Closes #31, #32, #37. Refs #46. This was SVN commit r3865. --- source/graphics/GameView.cpp | 2 + source/graphics/ObjectBase.h | 2 +- source/ps/CConsole.cpp | 24 +++- source/ps/GameSetup/Config.cpp | 2 +- source/renderer/Renderer.cpp | 16 +++ source/renderer/Renderer.h | 13 ++ source/renderer/SkyManager.cpp | 220 +++++++++++++++++++++++++++++ source/renderer/SkyManager.h | 66 +++++++++ source/scripting/ScriptGlue.cpp | 17 ++- source/scripting/ScriptingHost.cpp | 4 +- source/simulation/Aura.cpp | 47 +++++- source/simulation/Aura.h | 7 +- source/simulation/Entity.cpp | 39 ++--- source/simulation/Entity.h | 1 + 14 files changed, 416 insertions(+), 44 deletions(-) create mode 100644 source/renderer/SkyManager.cpp create mode 100644 source/renderer/SkyManager.h diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 3b2b1d414b..b892c5dcd8 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -28,6 +28,7 @@ #include "ps/LoaderThunks.h" #include "ps/Globals.h" #include "renderer/WaterManager.h" +#include "renderer/SkyManager.h" #include "Quaternion.h" #include "Unit.h" @@ -257,6 +258,7 @@ void CGameView::RegisterInit(CGameAttributes *pAttribs) RegMemFun(g_ObjMan.GetSingletonPtr(), &CObjectManager::LoadObjects, L"LoadObjects", 1); RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadAlphaMaps, L"LoadAlphaMaps", 5); RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); + RegMemFun(g_Renderer.GetSingletonPtr()->GetSkyManager(), &SkyManager::LoadSkyTextures, L"LoadSkyTextures", 15); } diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h index e35bfaa866..cfcf8cf019 100644 --- a/source/graphics/ObjectBase.h +++ b/source/graphics/ObjectBase.h @@ -15,7 +15,7 @@ public: struct Anim { // constructor - Anim() : m_Speed(1), m_ActionPos(0.0), m_ActionPos2(0.0) {} + Anim() : m_Speed(1), m_ActionPos(0.5), m_ActionPos2(0.0) {} // name of the animation - "Idle", "Run", etc CStr m_AnimName; diff --git a/source/ps/CConsole.cpp b/source/ps/CConsole.cpp index 86a34c4ca7..9f0ce4883c 100644 --- a/source/ps/CConsole.cpp +++ b/source/ps/CConsole.cpp @@ -338,14 +338,28 @@ void CConsole::InsertChar(const int szChar, const wchar_t cooked ) if (IsEmpty() || IsEOB()) return; if (m_iBufferPos == m_iBufferLength-1) + { m_szBuffer[m_iBufferPos] = '\0'; - else{ - for(int j=m_iBufferPos; jUseHistoryFile(base+"/settings/history", max_history_lines); } diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index dcbafc0dcb..138500020f 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -59,6 +59,7 @@ #include "renderer/TerrainRenderer.h" #include "renderer/TransparencyRenderer.h" #include "renderer/WaterManager.h" +#include "renderer/SkyManager.h" #define LOG_CATEGORY "graphics" @@ -209,6 +210,9 @@ struct CRendererInternals /// Water manager WaterManager waterManager; + /// Sky manager + SkyManager skyManager; + /// Terrain renderer TerrainRenderer* terrainRenderer; @@ -315,6 +319,7 @@ CRenderer::CRenderer() { m = new CRendererInternals; m_WaterManager = &m->waterManager; + m_SkyManager = &m->skyManager; g_ProfileViewer.AddRootTable(&m->profileTable); @@ -959,6 +964,17 @@ void CRenderer::FlushFrame() oglCheck(); + // render sky; this is done before everything so that + // (a) we can use a box around the camera instead of placing it "infinitely far away" + // (we just disable depth write so that this doesn't affect future rendering) + // (b) transparent objects properly overlap the sky + if (m_SkyManager->m_RenderSky) + { + MICROLOG(L"render sky"); + m->skyManager.RenderSky(); + oglCheck(); + } + // render submitted patches and models MICROLOG(L"render patches"); RenderPatches(); diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index a017e8029e..94323c3590 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -39,6 +39,7 @@ class CTerrain; class RenderPathVertexShader; class WaterManager; +class SkyManager; // rendering modes @@ -277,6 +278,13 @@ public: */ WaterManager* GetWaterManager() { return m_WaterManager; } + /** + * GetWaterManager: Return the renderer's sky manager. + * + * @return the SkyManager object used by the renderer + */ + SkyManager* GetSkyManager() { return m_SkyManager; } + /** * SetFastPlayerColor: Tell the renderer which path to take for * player colored models. Both paths should provide the same visual @@ -400,6 +408,11 @@ protected: */ WaterManager* m_WaterManager; + /** + * m_SkyManager: the SkyManager object used for sky textures and settings + */ + SkyManager* m_SkyManager; + /** * m_SortAllTransparent: If true, all transparent models are * rendered using the TransparencyRenderer which performs sorting. diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp new file mode 100644 index 0000000000..77c6d2a351 --- /dev/null +++ b/source/renderer/SkyManager.cpp @@ -0,0 +1,220 @@ +/** + * ========================================================================= + * File : SkyManager.cpp + * Project : Pyrogenesis + * Description : Sky settings, texture management and rendering. + * + * @author Matei Zaharia + * ========================================================================= + */ + +#include "precompiled.h" + +#include "lib/timer.h" +#include "lib/res/file/vfs.h" +#include "lib/res/graphics/tex.h" +#include "lib/res/graphics/ogl_tex.h" + +#include "ps/CLogger.h" +#include "ps/Loader.h" + +#include "renderer/SkyManager.h" +#include "renderer/Renderer.h" + +#include "graphics/Camera.h" + +#define LOG_CATEGORY "graphics" + + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SkyManager implementation + + +/////////////////////////////////////////////////////////////////// +// Construction/Destruction +SkyManager::SkyManager() +{ + // water + m_RenderSky = true; + + for (uint i = 0; i < ARRAY_SIZE(m_SkyTexture); i++) + m_SkyTexture[i] = 0; + + cur_loading_tex = 0; +} + +SkyManager::~SkyManager() +{ + // Cleanup if the caller messed up + UnloadSkyTextures(); +} + + +/////////////////////////////////////////////////////////////////// +// Progressive load of sky textures +int SkyManager::LoadSkyTextures() +{ + // Note: this must be kept in sync with the IMG_ constants in SkyManager.h + static const char* IMAGE_NAMES[6] = { + "front", + "back", + "right", + "left", + "top", + "bottom" + }; + + const uint num_textures = ARRAY_SIZE(m_SkyTexture); + + // yield after this time is reached. balances increased progress bar + // smoothness vs. slowing down loading. + const double end_time = get_time() + 100e-3; + + while (cur_loading_tex < num_textures) + { + char filename[PATH_MAX]; + // TODO: add a member variable and setter for this. (can't make this + // a parameter because this function is called via delay-load code) + static const char* const set_name = "day1"; + snprintf(filename, ARRAY_SIZE(filename), "art/textures/skies/%s/%s.dds", set_name, IMAGE_NAMES[cur_loading_tex]); + Handle ht = ogl_tex_load(filename); + if (ht <= 0) + { + LOG(ERROR, LOG_CATEGORY, "SkyManager::LoadSkyTextures failed on \"%s\"", filename); + return ht; + } + ogl_tex_set_wrap(ht, GL_CLAMP_TO_EDGE); + m_SkyTexture[cur_loading_tex] = ht; + RETURN_ERR(ogl_tex_upload(ht)); + + cur_loading_tex++; + LDR_CHECK_TIMEOUT(cur_loading_tex, num_textures); + } + + return 0; +} + + +/////////////////////////////////////////////////////////////////// +// Unload sky textures +void SkyManager::UnloadSkyTextures() +{ + for(uint i = 0; i < ARRAY_SIZE(m_SkyTexture); i++) + { + ogl_tex_free(m_SkyTexture[i]); + m_SkyTexture[i] = 0; + } + cur_loading_tex = 0; // so they will be reloaded if LoadWaterTextures is called again +} + + +/////////////////////////////////////////////////////////////////// +// Render sky +void SkyManager::RenderSky() +{ + // Draw the sky as a small box around the camera position, with depth write enabled. + // This will be done before anything else is drawn so we'll be overlapped by everything else. + + // Note: The coordinates for this were set up through a rather cumbersome trial-and-error + // process - there might be a smarter way to do it, but this seems to work. + + glDepthMask( GL_FALSE ); + + pglActiveTextureARB(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + // Translate so we are at the camera in the X and Z directions, + // but put the horizon at Y=0 so it looks right when the camera is higher + const CCamera& camera = g_Renderer.GetViewCamera(); + CVector3D pos = camera.m_Orientation.GetTranslation(); + glTranslatef( pos.X, 0.0f, pos.Z ); + + // Distance to draw the faces at + const float D = 2000.0; + + // Front face (positive Z) + ogl_tex_bind( m_SkyTexture[IMG_FRONT] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0, 1 ); + glVertex3f( -D, -D, +D ); + glTexCoord2f( 1, 1 ); + glVertex3f( +D, -D, +D ); + glTexCoord2f( 1, 0 ); + glVertex3f( +D, +D, +D ); + glTexCoord2f( 0, 0 ); + glVertex3f( -D, +D, +D ); + glEnd(); + + // Back face (negative Z) + ogl_tex_bind( m_SkyTexture[IMG_BACK] ); + glBegin( GL_QUADS ); + glTexCoord2f( 1, 1 ); + glVertex3f( -D, -D, -D ); + glTexCoord2f( 1, 0 ); + glVertex3f( -D, +D, -D ); + glTexCoord2f( 0, 0 ); + glVertex3f( +D, +D, -D ); + glTexCoord2f( 0, 1 ); + glVertex3f( +D, -D, -D ); + glEnd(); + + // Right face (negative X) + ogl_tex_bind( m_SkyTexture[IMG_RIGHT] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0, 1 ); + glVertex3f( -D, -D, -D ); + glTexCoord2f( 1, 1 ); + glVertex3f( -D, -D, +D ); + glTexCoord2f( 1, 0 ); + glVertex3f( -D, +D, +D ); + glTexCoord2f( 0, 0 ); + glVertex3f( -D, +D, -D ); + glEnd(); + + // Left face (positive X) + ogl_tex_bind( m_SkyTexture[IMG_LEFT] ); + glBegin( GL_QUADS ); + glTexCoord2f( 1, 1 ); + glVertex3f( +D, -D, -D ); + glTexCoord2f( 1, 0 ); + glVertex3f( +D, +D, -D ); + glTexCoord2f( 0, 0 ); + glVertex3f( +D, +D, +D ); + glTexCoord2f( 0, 1 ); + glVertex3f( +D, -D, +D ); + glEnd(); + + // Top face (positive Y) + ogl_tex_bind( m_SkyTexture[IMG_TOP] ); + glBegin( GL_QUADS ); + glTexCoord2f( 1, 0 ); + glVertex3f( +D, +D, -D ); + glTexCoord2f( 0, 0 ); + glVertex3f( -D, +D, -D ); + glTexCoord2f( 0, 1 ); + glVertex3f( -D, +D, +D ); + glTexCoord2f( 1, 1 ); + glVertex3f( +D, +D, +D ); + glEnd(); + + // Bottom face (negative Y) + // Note: These texcoords not be completely correct (haven't had a good texture to test with) + ogl_tex_bind( m_SkyTexture[IMG_BOTTOM] ); + glBegin( GL_QUADS ); + glTexCoord2f( 1, 0 ); + glVertex3f( +D, -D, -D ); + glTexCoord2f( 1, 1 ); + glVertex3f( +D, -D, +D ); + glTexCoord2f( 0, 1 ); + glVertex3f( -D, -D, +D ); + glTexCoord2f( 0, 0 ); + glVertex3f( -D, -D, -D ); + glEnd(); + + glPopMatrix(); + + glDepthMask( GL_TRUE ); +} diff --git a/source/renderer/SkyManager.h b/source/renderer/SkyManager.h new file mode 100644 index 0000000000..4fef45fd96 --- /dev/null +++ b/source/renderer/SkyManager.h @@ -0,0 +1,66 @@ +/** + * ========================================================================= + * File : SkyManager.h + * Project : Pyrogenesis + * Description : Sky settings and texture management + * + * @author Matei Zaharia + * ========================================================================= + */ + +#ifndef SKYMANAGER_H +#define SKYMANAGER_H + +#include "ps/Overlay.h" + +/** + * Class SkyManager: Maintain sky settings and textures, and render the sky. + */ +class SkyManager +{ +public: + Handle m_SkyTexture[6]; + + // Indices into m_SkyTexture + // Note: these must be kept in sync with the string constants in LoadSkyTextures; + // perhaps there is a more clever way to do that. + static const int IMG_FRONT = 0; + static const int IMG_BACK = 1; + static const int IMG_RIGHT = 2; + static const int IMG_LEFT = 3; + static const int IMG_TOP = 4; + static const int IMG_BOTTOM = 5; + + bool m_RenderSky; + +public: + SkyManager(); + ~SkyManager(); + + /** + * LoadSkyTextures: Load sky textures from within the + * progressive load framework. + * + * @return 0 if loading has completed, a value from 1 to 100 (in percent of completion) + * if more textures need to be loaded and a negative error value on failure. + */ + int LoadSkyTextures(); + + /** + * UnloadSkyTextures: Free any loaded sky textures and reset the internal state + * so that another call to LoadSkyTextures will begin progressive loading. + */ + void UnloadSkyTextures(); + + /** + * RenderSky: Render the sky. + */ + void RenderSky(); + +private: + /// State of progressive loading (in # of loaded textures) + uint cur_loading_tex; +}; + + +#endif // SKYMANAGER_H diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 793e7be256..d579f128db 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -42,6 +42,7 @@ #include "graphics/scripting/JSInterface_LightEnv.h" #include "scripting/JSConversions.h" #include "renderer/WaterManager.h" +#include "renderer/SkyManager.h" #include "simulation/FormationManager.h" #ifndef NO_GUI @@ -896,7 +897,8 @@ JSBool getGlobal( JSContext* cx, JSObject* globalObject, uint argc, jsval* argv, return( JS_TRUE ); } -// Activates the building placement cursor for placing a building. +// Activates the building placement cursor for placing a building. The currently selected units +// are then ordered to construct the building if it is placed. // params: templateName - the name of the entity to place. // returns: true if cursor was activated, false if cursor was already active. JSBool startPlacing( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval ) @@ -919,11 +921,19 @@ JSBool startPlacing( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, j return( JS_TRUE ); } +// Toggles drawing the sky +JSBool toggleSky( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval ) +{ + REQUIRE_NO_PARAMS( toggleSky ); + g_Renderer.GetSkyManager()->m_RenderSky = !g_Renderer.GetSkyManager()->m_RenderSky; + *rval = JSVAL_VOID; + return( JS_TRUE ); +} + // Toggles drawing the water plane JSBool toggleWater( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval ) { REQUIRE_NO_PARAMS( toggleWater ); - debug_printf("Toggling water!\n"); g_Renderer.GetWaterManager()->m_RenderWater = !g_Renderer.GetWaterManager()->m_RenderWater; *rval = JSVAL_VOID; return( JS_TRUE ); @@ -1129,6 +1139,9 @@ JSFunctionSpec ScriptFunctionTable[] = // Camera JS_FUNC(setCameraTarget, setCameraTarget, 1) + // Sky + JS_FUNC(toggleSky, toggleSky, 0) + // Water JS_FUNC(toggleWater, toggleWater, 0) JS_FUNC(setWaterHeight, setWaterHeight, 1) diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index c939d574a7..72f1ba35a8 100644 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -119,7 +119,7 @@ void ScriptingHost::RunScript(const CStr& filename, JSObject* globalObject) throw PSERROR_Scripting_LoadFile_OpenFailed(); const char* script = (const char*)buf; - RunMemScript(script, size, fn, 0, globalObject); + RunMemScript(script, size, fn, 1, globalObject); (void)file_buf_free(buf); } @@ -147,7 +147,7 @@ jsval ScriptingHost::ExecuteScript(const CStrW& script, const CStrW& calledFrom, char* asciiName = new char[len + 1]; wcstombs( asciiName, calledFrom, len + 1 ); - JSBool ok = JS_EvaluateUCScript(m_Context, contextObject ? contextObject : m_GlobalObject, script.utf16().c_str(), (int)script.Length(), asciiName, 0, &rval); + JSBool ok = JS_EvaluateUCScript(m_Context, contextObject ? contextObject : m_GlobalObject, script.utf16().c_str(), (int)script.Length(), asciiName, 1, &rval); delete[]( asciiName ); diff --git a/source/simulation/Aura.cpp b/source/simulation/Aura.cpp index a1ad87206d..569dc6bee8 100644 --- a/source/simulation/Aura.cpp +++ b/source/simulation/Aura.cpp @@ -5,8 +5,9 @@ using namespace std; -CAura::CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, JSObject* handler ) - : m_cx(cx), m_source(source), m_name(name), m_radius(radius), m_handler(handler) +CAura::CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, size_t tickRate, JSObject* handler ) + : m_cx(cx), m_source(source), m_name(name), m_radius(radius), m_handler(handler), + m_tickRate(tickRate), m_tickCyclePos(0) { JS_AddRoot( m_cx, &m_handler ); // don't GC it so we can call it later } @@ -16,7 +17,7 @@ CAura::~CAura() JS_RemoveRoot( m_cx, &m_handler ); } -void CAura::Update( size_t UNUSED(timestep) ) +void CAura::Update( size_t timestep ) { vector inRange; CVector3D pos = m_source->m_position; @@ -51,10 +52,12 @@ void CAura::Update( size_t UNUSED(timestep) ) jsval rval; jsval argv[1]; + // Call onEnter on any new unit that has entered the aura CStrW enterName = L"onEnter"; jsval enterFunction; utf16string enterName16 = enterName.utf16(); - if( JS_GetUCProperty( m_cx, m_handler, enterName16.c_str(), enterName16.length(), &enterFunction ) ) + if( JS_GetUCProperty( m_cx, m_handler, enterName16.c_str(), enterName16.length(), &enterFunction ) + && enterFunction != JSVAL_VOID) { back_insert_iterator > ins( entered ); set_difference( curInfluenced.begin(), curInfluenced.end(), @@ -68,10 +71,12 @@ void CAura::Update( size_t UNUSED(timestep) ) } } + // Call onExit on any unit that has exited the aura CStrW exitName = L"onExit"; jsval exitFunction; utf16string exitName16 = exitName.utf16(); - if( JS_GetUCProperty( m_cx, m_handler, exitName16.c_str(), exitName16.length(), &exitFunction ) ) + if( JS_GetUCProperty( m_cx, m_handler, exitName16.c_str(), exitName16.length(), &exitFunction ) + && exitFunction != JSVAL_VOID ) { back_insert_iterator > ins( exited ); set_difference( prevInfluenced.begin(), prevInfluenced.end(), @@ -84,6 +89,28 @@ void CAura::Update( size_t UNUSED(timestep) ) (*it)->m_aurasInfluencingMe.erase( this ); } } + + m_tickCyclePos += timestep; + + if( m_tickRate > 0 && m_tickCyclePos > m_tickRate ) + { + // It's time to tick; call OnTick on any unit that is in the aura + CStrW tickName = L"onTick"; + jsval tickFunction; + utf16string tickName16 = tickName.utf16(); + if( JS_GetUCProperty( m_cx, m_handler, tickName16.c_str(), tickName16.length(), &tickFunction ) + && tickFunction != JSVAL_VOID ) + { + for( vector::iterator it = curInfluenced.begin(); it != curInfluenced.end(); it++ ) + { + argv[0] = OBJECT_TO_JSVAL( (*it)->GetScript() ); + JS_CallFunctionValue( m_cx, m_handler, tickFunction, 1, argv, &rval ); + } + } + + // Reset cycle pos + m_tickCyclePos %= m_tickRate; + } } void CAura::RemoveAll() @@ -93,8 +120,10 @@ void CAura::RemoveAll() CStrW exitName = L"onExit"; jsval exitFunction; utf16string exitName16 = exitName.utf16(); - if( JS_GetUCProperty( m_cx, m_handler, exitName16.c_str(), exitName16.length(), &exitFunction ) ) + if( JS_GetUCProperty( m_cx, m_handler, exitName16.c_str(), exitName16.length(), &exitFunction ) + && exitFunction != JSVAL_VOID ) { + // Call the exit function on everything in our influence for( vector::iterator it = m_influenced.begin(); it != m_influenced.end(); it++ ) { CEntity* ent = *it; @@ -116,10 +145,14 @@ void CAura::Remove( CEntity* ent ) CStrW exitName = L"onExit"; jsval exitFunction; utf16string exitName16 = exitName.utf16(); - if( JS_GetUCProperty( m_cx, m_handler, exitName16.c_str(), exitName16.length(), &exitFunction ) ) + if( JS_GetUCProperty( m_cx, m_handler, exitName16.c_str(), exitName16.length(), &exitFunction ) + && exitFunction != JSVAL_VOID ) { + // Call the exit function on it argv[0] = OBJECT_TO_JSVAL( ent->GetScript() ); JS_CallFunctionValue( m_cx, m_handler, exitFunction, 1, argv, &rval ); + + // Remove it from the m_influenced array for( size_t i=0; i < m_influenced.size(); i++ ) { if( ((CEntity*) m_influenced[i]) == ent ) diff --git a/source/simulation/Aura.h b/source/simulation/Aura.h index bccc14d1a5..e37643b5c3 100644 --- a/source/simulation/Aura.h +++ b/source/simulation/Aura.h @@ -10,11 +10,13 @@ public: JSContext* m_cx; CEntity* m_source; CStrW m_name; - float m_radius; + float m_radius; // In graphics units + size_t m_tickRate; // In milliseconds JSObject* m_handler; std::vector m_influenced; + size_t m_tickCyclePos; // Add time to this until it's time to tick again - CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, JSObject* handler ); + CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, size_t tickRate, JSObject* handler ); ~CAura(); // Remove all entities from under our influence; this isn't done in the destructor since @@ -27,6 +29,7 @@ public: // notify its auras to remove it before it dies (so they can still access its data). void Remove( CEntity* ent ); + // Called to update the aura each simulation frame. void Update( size_t timestep ); }; diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 5ae7f1d4d5..c010fc3d86 100644 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -98,6 +98,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons AddProperty( L"traits.vision.los", &m_los ); AddProperty( L"traits.vision.permanent", &m_permanent ); AddProperty( L"last_combat_time", &m_lastCombatTime ); + AddProperty( L"last_run_time", &m_lastRunTime ); AddProperty( L"building", &m_building ); m_productionQueue = new CProductionQueue( this ); @@ -157,6 +158,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons m_frameCheck = 0; m_lastCombatTime = 0; + m_lastRunTime = 0; m_currentNotification = 0; m_currentRequest = 0; m_destroyNotifiers = true; @@ -422,8 +424,13 @@ void CEntity::update( size_t timestep ) PROFILE_START( "state processing" ); + if( m_isRunning ) + { + m_lastRunTime = g_Game->GetTime(); + } + while( !m_orderQueue.empty() ) - { + { CEntityOrder* current = &m_orderQueue.front(); if( current->m_type != m_lastState ) @@ -524,28 +531,11 @@ void CEntity::update( size_t timestep ) m_isRunning = false; m_shouldRun = false; } - else - { - // If the front order is not a movement order, stop running - switch(m_orderQueue.front().m_type) - { - case CEntityOrder::ORDER_GOTO_NOPATHING: - case CEntityOrder::ORDER_GOTO_COLLISION: - case CEntityOrder::ORDER_GOTO_SMOOTHED: - case CEntityOrder::ORDER_GOTO_WAYPOINT: - case CEntityOrder::ORDER_GOTO_WAYPOINT_CONTACT: - case CEntityOrder::ORDER_GOTO: - case CEntityOrder::ORDER_RUN: - break; - default: - m_isRunning = false; - //m_shouldRun = false; - break; - } - } PROFILE_END( "state processing" ); + // If we get to here, it means we're idle or dead (no orders); update the animation + if( m_actor ) { PROFILE( "animation updates" ); @@ -1811,18 +1801,19 @@ jsval CEntity::GetSpawnPoint( JSContext* UNUSED(cx), uintN argc, jsval* argv ) jsval CEntity::AddAura( JSContext* cx, uintN argc, jsval* argv ) { - debug_assert( argc >= 3 ); - debug_assert( JSVAL_IS_OBJECT(argv[2]) ); + debug_assert( argc >= 4 ); + debug_assert( JSVAL_IS_OBJECT(argv[3]) ); CStrW name = ToPrimitive( argv[0] ); float radius = ToPrimitive( argv[1] ); - JSObject* handler = JSVAL_TO_OBJECT( argv[2] ); + size_t tickRate = max( 0, ToPrimitive( argv[2] ) ); // since it's a size_t we don't want it to be negative + JSObject* handler = JSVAL_TO_OBJECT( argv[3] ); if( m_auras[name] ) { delete m_auras[name]; } - m_auras[name] = new CAura( cx, this, name, radius, handler ); + m_auras[name] = new CAura( cx, this, name, radius, tickRate, handler ); return JSVAL_VOID; } diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index 39be057aec..67b5022ef5 100644 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -111,6 +111,7 @@ public: int m_frameCheck; //counts the frame float m_lastCombatTime; + float m_lastRunTime; // Building to convert to if this is a foundation, or "" otherwise CStrW m_building;