From befae8627d8ae18e34d04739d39a52ea529deda8 Mon Sep 17 00:00:00 2001 From: MarkT Date: Fri, 23 Jul 2004 10:56:52 +0000 Subject: [PATCH] Changed hotkey handling for groups and bookmarks; small pathfinding fixes. This was SVN commit r809. --- source/graphics/HFTracer.cpp | 4 +- source/graphics/Terrain.cpp | 21 ++++ source/graphics/Terrain.h | 12 ++ source/ps/Hotkey.cpp | 59 +++++++++- source/ps/Hotkey.h | 31 ++++- source/ps/Interact.cpp | 104 +++++++++-------- source/ps/Vector2D.h | 2 +- source/ps/scripting/JSInterface_Selection.cpp | 2 +- source/scripting/ScriptingHost.cpp | 6 +- source/simulation/BaseEntity.cpp | 16 +-- source/simulation/BaseEntity.h | 1 + source/simulation/BoundingObjects.cpp | 4 - source/simulation/BoundingObjects.h | 3 +- source/simulation/Collision.cpp | 21 ++++ source/simulation/Collision.h | 1 + source/simulation/Entity.cpp | 98 +++++----------- source/simulation/Entity.h | 4 +- source/simulation/EntityHandles.cpp | 3 + source/simulation/EntityManager.cpp | 2 +- source/simulation/EntityStateProcessing.cpp | 110 +++++++++++++++--- source/simulation/PathfindEngine.cpp | 8 ++ source/simulation/PathfindEngine.h | 1 + source/simulation/PathfindSparse.cpp | 48 ++++++-- source/simulation/PathfindSparse.h | 5 +- 24 files changed, 391 insertions(+), 175 deletions(-) diff --git a/source/graphics/HFTracer.cpp b/source/graphics/HFTracer.cpp index 69519f006a..27ab6a32c1 100755 --- a/source/graphics/HFTracer.cpp +++ b/source/graphics/HFTracer.cpp @@ -156,11 +156,11 @@ bool CHFTracer::RayIntersect(CVector3D& origin,CVector3D& dir,int& x,int& z,CVec // catch travelling off the map if( ( cx < 0 ) && ( sx < 0 ) ) return( false ); - if( ( cx >= m_MapSize ) && ( sx > 0 ) ) + if( ( cx >= (int)m_MapSize ) && ( sx > 0 ) ) return( false ); if( ( cz < 0 ) && ( sz < 0 ) ) return( false ); - if( ( cz >= m_MapSize ) && ( sz > 0 ) ) + if( ( cz >= (int)m_MapSize ) && ( sz > 0 ) ) return( false ); } diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp index 96e818d2fb..73d91d994e 100755 --- a/source/graphics/Terrain.cpp +++ b/source/graphics/Terrain.cpp @@ -150,6 +150,27 @@ CMiniPatch* CTerrain::GetTile(int32_t x,int32_t z) return &patch->m_MiniPatches[z%PATCH_SIZE][x%PATCH_SIZE]; } +float CTerrain::getExactGroundLevel( float x, float y ) const +{ + x /= (float)CELL_SIZE; + y /= (float)CELL_SIZE; + + int xi = (int)floor( x ); + int yi = (int)floor( y ); + float xf = x - (float)xi; + float yf = y - (float)yi; + + assert( isOnMap( x, y ) ); + + if( !isOnMap( x, y ) ) + return 0.0f; + + float h00 = m_Heightmap[yi*m_MapSize + xi]; + float h01 = m_Heightmap[yi*m_MapSize + xi + m_MapSize]; + float h10 = m_Heightmap[yi*m_MapSize + xi + 1]; + float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1]; + return( HEIGHT_SCALE * ( ( 1 - yf ) * ( ( 1 - xf ) * h00 + xf * h10 ) + yf * ( ( 1 - xf ) * h01 + xf * h11 ) ) ); +} /////////////////////////////////////////////////////////////////////////////// // Resize: resize this terrain to the given size (in patches per side) diff --git a/source/graphics/Terrain.h b/source/graphics/Terrain.h index 5a25dd5e22..9c11337058 100755 --- a/source/graphics/Terrain.h +++ b/source/graphics/Terrain.h @@ -12,6 +12,7 @@ #include "Patch.h" #include "Vector3D.h" +#include "Vector2D.h" /////////////////////////////////////////////////////////////////////////////// // CTerrain: main terrain class; contains the heightmap describing elevation @@ -29,6 +30,17 @@ public: // return number of patches along edge of the terrain u32 GetPatchesPerSide() { return m_MapSizePatches; } + inline bool isOnMap( float x, float y ) const + { + return( ( x >= 0.0f ) && ( x <= (float)m_MapSize ) && ( y >= 0.0f ) && ( y <= (float)m_MapSize ) ); + } + inline bool isOnMap( const CVector2D& v ) const + { + return( ( v.x >= 0.0f ) && ( v.x <= (float)m_MapSize ) && ( v.y >= 0.0f ) && ( v.y <= (float)m_MapSize ) ); + } + float getExactGroundLevel( float x, float y ) const ; + inline float getExactGroundLevel( const CVector2D& v ) const { return( getExactGroundLevel( v.x, v.y ) ); } + // resize this terrain such that each side has given number of patches void Resize(u32 size); diff --git a/source/ps/Hotkey.cpp b/source/ps/Hotkey.cpp index 52ca81ce95..0c78d5dbb0 100755 --- a/source/ps/Hotkey.cpp +++ b/source/ps/Hotkey.cpp @@ -57,12 +57,41 @@ static SHotkeyInfo hotkeyInfo[] = { HOTKEY_CAMERA_PAN_RIGHT, "camera.pan.right", SDLK_RIGHT, 0 }, { HOTKEY_CAMERA_PAN_FORWARD, "camera.pan.forward", SDLK_UP, 0 }, { HOTKEY_CAMERA_PAN_BACKWARD, "camera.pan.backward", SDLK_DOWN, 0 }, - { HOTKEY_CAMERA_BOOKMARK_MODIFIER, "camera.bookmark.modifier", 0, 0 }, + { HOTKEY_CAMERA_BOOKMARK_0, "camera.bookmark.0", SDLK_F5, 0, }, + { HOTKEY_CAMERA_BOOKMARK_1, "camera.bookmark.1", SDLK_F6, 0, }, + { HOTKEY_CAMERA_BOOKMARK_2, "camera.bookmark.2", SDLK_F7, 0, }, + { HOTKEY_CAMERA_BOOKMARK_3, "camera.bookmark.3", SDLK_F8, 0, }, + { HOTKEY_CAMERA_BOOKMARK_4, "camera.bookmark.4", 0, 0, }, + { HOTKEY_CAMERA_BOOKMARK_5, "camera.bookmark.5", 0, 0, }, + { HOTKEY_CAMERA_BOOKMARK_6, "camera.bookmark.6", 0, 0, }, + { HOTKEY_CAMERA_BOOKMARK_7, "camera.bookmark.7", 0, 0, }, + { HOTKEY_CAMERA_BOOKMARK_8, "camera.bookmark.8", 0, 0, }, + { HOTKEY_CAMERA_BOOKMARK_9, "camera.bookmark.9", 0, 0, }, { HOTKEY_CAMERA_BOOKMARK_SAVE, "camera.bookmark.save", 0, 0 }, { HOTKEY_CAMERA_BOOKMARK_SNAP, "camera.bookmark.snap", 0, 0 }, { HOTKEY_CONSOLE_TOGGLE, "console.toggle", SDLK_F1, 0 }, { HOTKEY_SELECTION_ADD, "selection.add", SDLK_LSHIFT, SDLK_RSHIFT }, { HOTKEY_SELECTION_REMOVE, "selection.remove", SDLK_LCTRL, SDLK_RCTRL }, + { HOTKEY_SELECTION_GROUP_0, "selection.group.0", SDLK_0, 0, }, + { HOTKEY_SELECTION_GROUP_1, "selection.group.1", SDLK_1, 0, }, + { HOTKEY_SELECTION_GROUP_2, "selection.group.2", SDLK_2, 0, }, + { HOTKEY_SELECTION_GROUP_3, "selection.group.3", SDLK_3, 0, }, + { HOTKEY_SELECTION_GROUP_4, "selection.group.4", SDLK_4, 0, }, + { HOTKEY_SELECTION_GROUP_5, "selection.group.5", SDLK_5, 0, }, + { HOTKEY_SELECTION_GROUP_6, "selection.group.6", SDLK_6, 0, }, + { HOTKEY_SELECTION_GROUP_7, "selection.group.7", SDLK_7, 0, }, + { HOTKEY_SELECTION_GROUP_8, "selection.group.8", SDLK_8, 0, }, + { HOTKEY_SELECTION_GROUP_9, "selection.group.9", SDLK_9, 0, }, + { HOTKEY_SELECTION_GROUP_10, "selection.group.10", 0, 0, }, + { HOTKEY_SELECTION_GROUP_11, "selection.group.11", 0, 0, }, + { HOTKEY_SELECTION_GROUP_12, "selection.group.12", 0, 0, }, + { HOTKEY_SELECTION_GROUP_13, "selection.group.13", 0, 0, }, + { HOTKEY_SELECTION_GROUP_14, "selection.group.14", 0, 0, }, + { HOTKEY_SELECTION_GROUP_15, "selection.group.15", 0, 0, }, + { HOTKEY_SELECTION_GROUP_16, "selection.group.16", 0, 0, }, + { HOTKEY_SELECTION_GROUP_17, "selection.group.17", 0, 0, }, + { HOTKEY_SELECTION_GROUP_18, "selection.group.18", 0, 0, }, + { HOTKEY_SELECTION_GROUP_19, "selection.group.19", 0, 0, }, { HOTKEY_SELECTION_GROUP_ADD, "selection.group.add", SDLK_LSHIFT, SDLK_RSHIFT }, { HOTKEY_SELECTION_GROUP_SAVE, "selection.group.save", SDLK_LCTRL, SDLK_RCTRL }, { HOTKEY_SELECTION_GROUP_SNAP, "selection.group.snap", SDLK_LALT, SDLK_RALT }, @@ -228,9 +257,22 @@ int hotkeyInputHandler( const SDL_Event* ev ) SDL_Event hotkeyNotification; + // Here's an interesting bit: + // If you have an event bound to, say, 'F', and another to, say, 'Ctrl+F', pressing + // 'F' while control is down will fire off both. + + // To avoid this, set the modifier keys for /all/ events this key would trigger + // (Ctrl, for example, is both group-save and bookmark-save) + // but only send a HotkeyDown event for the event whos bindings most precisely + // match the conditions (i.e. the event with the highest number of auxiliary + // keys, providing they're all down) + if( ( ev->type == SDL_KEYDOWN ) || ( ev->type == SDL_MOUSEBUTTONDOWN ) ) { // SDL-events bit + + int closestMap = -1, closestMapMatch; + for( it = hotkeyMap[keycode].begin(); it < hotkeyMap[keycode].end(); it++ ) { // Check to see if all auxiliary keys are down @@ -253,11 +295,20 @@ int hotkeyInputHandler( const SDL_Event* ev ) if( accept ) { hotkeys[it->mapsTo] = true; - hotkeyNotification.type = SDL_HOTKEYDOWN; - hotkeyNotification.user.code = it->mapsTo; - SDL_PushEvent( &hotkeyNotification ); + if( ( closestMap == -1 ) || ( it->requires.size() > closestMapMatch ) ) + { + closestMap = it->mapsTo; + closestMapMatch = it->requires.size(); + } } } + + if( closestMap != -1 ) + { + hotkeyNotification.type = SDL_HOTKEYDOWN; + hotkeyNotification.user.code = closestMap; + SDL_PushEvent( &hotkeyNotification ); + } // GUI bit... could do with some optimization later. for( itGUI = hotkeyMapGUI[keycode].begin(); itGUI != hotkeyMapGUI[keycode].end(); itGUI++ ) { diff --git a/source/ps/Hotkey.h b/source/ps/Hotkey.h index 1b73f7160a..972175add4 100755 --- a/source/ps/Hotkey.h +++ b/source/ps/Hotkey.h @@ -42,12 +42,41 @@ enum HOTKEY_CAMERA_PAN_RIGHT, HOTKEY_CAMERA_PAN_FORWARD, HOTKEY_CAMERA_PAN_BACKWARD, - HOTKEY_CAMERA_BOOKMARK_MODIFIER, + HOTKEY_CAMERA_BOOKMARK_0, + HOTKEY_CAMERA_BOOKMARK_1, + HOTKEY_CAMERA_BOOKMARK_2, + HOTKEY_CAMERA_BOOKMARK_3, + HOTKEY_CAMERA_BOOKMARK_4, + HOTKEY_CAMERA_BOOKMARK_5, + HOTKEY_CAMERA_BOOKMARK_6, + HOTKEY_CAMERA_BOOKMARK_7, + HOTKEY_CAMERA_BOOKMARK_8, + HOTKEY_CAMERA_BOOKMARK_9, HOTKEY_CAMERA_BOOKMARK_SAVE, HOTKEY_CAMERA_BOOKMARK_SNAP, HOTKEY_CONSOLE_TOGGLE, HOTKEY_SELECTION_ADD, HOTKEY_SELECTION_REMOVE, + HOTKEY_SELECTION_GROUP_0, + HOTKEY_SELECTION_GROUP_1, + HOTKEY_SELECTION_GROUP_2, + HOTKEY_SELECTION_GROUP_3, + HOTKEY_SELECTION_GROUP_4, + HOTKEY_SELECTION_GROUP_5, + HOTKEY_SELECTION_GROUP_6, + HOTKEY_SELECTION_GROUP_7, + HOTKEY_SELECTION_GROUP_8, + HOTKEY_SELECTION_GROUP_9, + HOTKEY_SELECTION_GROUP_10, + HOTKEY_SELECTION_GROUP_11, + HOTKEY_SELECTION_GROUP_12, + HOTKEY_SELECTION_GROUP_13, + HOTKEY_SELECTION_GROUP_14, + HOTKEY_SELECTION_GROUP_15, + HOTKEY_SELECTION_GROUP_16, + HOTKEY_SELECTION_GROUP_17, + HOTKEY_SELECTION_GROUP_18, + HOTKEY_SELECTION_GROUP_19, HOTKEY_SELECTION_GROUP_ADD, HOTKEY_SELECTION_GROUP_SAVE, HOTKEY_SELECTION_GROUP_SNAP, diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index cf436e41b6..343d139cf0 100755 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -72,10 +72,8 @@ void CSelectedEntities::renderOverlays() glLoadIdentity(); float x, y; CVector3D labelpos = (*it)->m_graphics_position - g_Camera.m_Orientation.GetLeft() * (*it)->m_bounds->m_radius; - labelpos.X += (*it)->m_bounds->m_offset.x; - labelpos.Z += (*it)->m_bounds->m_offset.y; #ifdef SELECTION_TERRAIN_CONFORMANCE - labelpos.Y = (*it)->getExactGroundLevel( labelpos.X, labelpos.Z ); + labelpos.Y = g_Terrain.getExactGroundLevel( labelpos.X, labelpos.Z ); #endif g_Camera.GetScreenCoordinates( labelpos, x, y ); glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); @@ -98,10 +96,8 @@ void CSelectedEntities::renderOverlays() glLoadIdentity(); float x, y; CVector3D labelpos = (*it)->m_graphics_position - g_Camera.m_Orientation.GetLeft() * (*it)->m_bounds->m_radius; - labelpos.X += (*it)->m_bounds->m_offset.x; - labelpos.Z += (*it)->m_bounds->m_offset.y; #ifdef SELECTION_TERRAIN_CONFORMANCE - labelpos.Y = (*it)->getExactGroundLevel( labelpos.X, labelpos.Z ); + labelpos.Y = g_Terrain.getExactGroundLevel( labelpos.X, labelpos.Z ); #endif g_Camera.GetScreenCoordinates( labelpos, x, y ); glColor4f( 1.0f, 1.0f, 1.0f, 0.5f ); @@ -178,11 +174,7 @@ CVector3D CSelectedEntities::getSelectionPosition() CVector3D avg; std::vector::iterator it; for( it = m_selected.begin(); it < m_selected.end(); it++ ) - { avg += (*it)->m_graphics_position; - avg.X += (*it)->m_bounds->m_offset.x; - avg.Z += (*it)->m_bounds->m_offset.y; - } return( avg * ( 1.0f / m_selected.size() ) ); } @@ -303,11 +295,7 @@ CVector3D CSelectedEntities::getGroupPosition( u8 groupid ) CVector3D avg; std::vector::iterator it; for( it = m_groups[groupid].begin(); it < m_groups[groupid].end(); it++ ) - { avg += (*it)->m_graphics_position; - avg.X += (*it)->m_bounds->m_offset.x; - avg.Z += (*it)->m_bounds->m_offset.y; - } return( avg * ( 1.0f / m_groups[groupid].size() ) ); } @@ -382,7 +370,7 @@ bool CSelectedEntities::isContextValid( int contextOrder ) void CSelectedEntities::contextOrder( bool pushQueue ) { std::vector::iterator it; - CEntityOrder context; + CEntityOrder context, contextRandomized; (int&)context.m_type = m_contextOrder; CVector3D origin, dir; g_Camera.BuildCameraRay( origin, dir ); @@ -404,9 +392,32 @@ void CSelectedEntities::contextOrder( bool pushQueue ) break; } + // Location randomizer, for group orders... + // Having the group turn up at the destination with /some/ sort of cohesion is good + // but tasking them all to the exact same point will leave them brawling for it + // at the other end (it shouldn't, but the PASAP pathfinder is too simplistic) + + // Task them all to a point within a radius of the target, radius depends upon + // the number of units in the group. + + float radius = 2.0f * sqrt( (float)m_selected.size() ); // A decent enough approximation + float _t, _x, _y; + for( it = m_selected.begin(); it < m_selected.end(); it++ ) if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) ) - g_Scheduler.pushFrame( ORDER_DELAY, (*it)->me, new CMessageOrder( context, pushQueue ) ); + { + contextRandomized = context; + do + { + _x = (float)( rand() % 20000 ) / 10000.0f - 1.0f; + _y = (float)( rand() % 20000 ) / 10000.0f - 1.0f; + } + while( ( _x * _x ) + ( _y * _y ) > 1.0f ); + + contextRandomized.m_data[0].location.x += _x * radius; + contextRandomized.m_data[0].location.y += _y * radius; + g_Scheduler.pushFrame( ORDER_DELAY, (*it)->me, new CMessageOrder( contextRandomized, pushQueue ) ); + } } @@ -459,8 +470,6 @@ void CMouseoverEntities::update( float timestep ) for( it = onscreen->begin(); it < onscreen->end(); it++ ) { CVector3D worldspace = (*it)->m_graphics_position; - worldspace.X += (*it)->m_bounds->m_offset.x; - worldspace.Z += (*it)->m_bounds->m_offset.y; float x, y; @@ -634,10 +643,8 @@ void CMouseoverEntities::renderOverlays() glLoadIdentity(); float x, y; CVector3D labelpos = it->entity->m_graphics_position - g_Camera.m_Orientation.GetLeft() * it->entity->m_bounds->m_radius; - labelpos.X += it->entity->m_bounds->m_offset.x; - labelpos.Z += it->entity->m_bounds->m_offset.y; #ifdef SELECTION_TERRAIN_CONFORMANCE - labelpos.Y = it->entity->getExactGroundLevel( labelpos.X, labelpos.Z ); + labelpos.Y = g_Terrain.getExactGroundLevel( labelpos.X, labelpos.Z ); #endif g_Camera.GetScreenCoordinates( labelpos, x, y ); glColor4f( 1.0f, 1.0f, 1.0f, it->fade ); @@ -672,15 +679,28 @@ int interactInputHandler( const SDL_Event* ev ) static bool button_down = false; switch( ev->type ) - { - case SDL_KEYDOWN: - if( ( ev->key.keysym.sym >= SDLK_0 ) && ( ev->key.keysym.sym <= SDLK_9 ) ) + { + case SDL_HOTKEYDOWN: + switch( ev->user.code ) { - u8 id = ev->key.keysym.sym - SDLK_0; - // This competes with the camera bookmarks for the top-row number keys - // Find out which this is, and act accordingly - if( !hotkeys[HOTKEY_CAMERA_BOOKMARK_MODIFIER] ) + case HOTKEY_HIGHLIGHTALL: + g_Mouseover.m_viewall = true; + break; + case HOTKEY_SELECTION_SNAP: + if( g_Selection.m_selected.size() ) + setCameraTarget( g_Selection.getSelectionPosition() ); + break; + case HOTKEY_CONTEXTORDER_NEXT: + g_Selection.nextContext(); + break; + case HOTKEY_CONTEXTORDER_PREVIOUS: + g_Selection.previousContext(); + break; + default: + if( ( ev->user.code >= HOTKEY_SELECTION_GROUP_0 ) && ( ev->key.keysym.sym <= HOTKEY_SELECTION_GROUP_19 ) ) { + u8 id = ev->user.code - HOTKEY_SELECTION_GROUP_0; + if( hotkeys[HOTKEY_SELECTION_GROUP_ADD] ) { g_Selection.addGroup( id ); @@ -702,13 +722,15 @@ int interactInputHandler( const SDL_Event* ev ) else g_Selection.loadGroup( id ); } + return( EV_HANDLED ); } - else + else if( ( ev->user.code >= HOTKEY_CAMERA_BOOKMARK_0 ) && ( ev->user.code <= HOTKEY_CAMERA_BOOKMARK_9 ) ) { + u8 id = ev->user.code - HOTKEY_CAMERA_BOOKMARK_0; if( hotkeys[HOTKEY_CAMERA_BOOKMARK_SAVE] ) { // Attempt to track the ground we're looking at - CHFTracer tracer( g_Terrain.GetHeightMap(), g_Terrain.GetVerticesPerSide(), CELL_SIZE, HEIGHT_SCALE ); int x, z; + CHFTracer tracer( g_Terrain.GetHeightMap(), g_Terrain.GetVerticesPerSide(), (float)CELL_SIZE, (float)HEIGHT_SCALE ); int x, z; CVector3D origin, dir, delta, currentTarget; origin = g_Camera.m_Orientation.GetTranslation(); dir = g_Camera.m_Orientation.GetIn(); @@ -736,26 +758,8 @@ int interactInputHandler( const SDL_Event* ev ) if( bookmarkInUse[id] ) setCameraTarget( cameraBookmarks[id] ); } + return( EV_HANDLED ); } - } - break; - case SDL_HOTKEYDOWN: - switch( ev->user.code ) - { - case HOTKEY_HIGHLIGHTALL: - g_Mouseover.m_viewall = true; - break; - case HOTKEY_SELECTION_SNAP: - if( g_Selection.m_selected.size() ) - setCameraTarget( g_Selection.getSelectionPosition() ); - break; - case HOTKEY_CONTEXTORDER_NEXT: - g_Selection.nextContext(); - break; - case HOTKEY_CONTEXTORDER_PREVIOUS: - g_Selection.previousContext(); - break; - default: return( EV_PASS ); } return( EV_HANDLED ); @@ -879,7 +883,7 @@ void setCameraTarget( const CVector3D& target ) // the difference beteen that position and the camera point, and restoring // that difference to our new target) - CHFTracer tracer( g_Terrain.GetHeightMap(), g_Terrain.GetVerticesPerSide(), CELL_SIZE, HEIGHT_SCALE ); int x, z; + CHFTracer tracer( g_Terrain.GetHeightMap(), g_Terrain.GetVerticesPerSide(), (float)CELL_SIZE, (float)HEIGHT_SCALE ); int x, z; CVector3D origin, dir, currentTarget; origin = g_Camera.m_Orientation.GetTranslation(); dir = g_Camera.m_Orientation.GetIn(); diff --git a/source/ps/Vector2D.h b/source/ps/Vector2D.h index 3b7f650362..ac73a5ef48 100755 --- a/source/ps/Vector2D.h +++ b/source/ps/Vector2D.h @@ -14,7 +14,7 @@ class CVector2D public: float x; float y; - CVector2D() {} + CVector2D() { x = 0.0f; y = 0.0f; } CVector2D( float _x, float _y ) { x = _x; y = _y; diff --git a/source/ps/scripting/JSInterface_Selection.cpp b/source/ps/scripting/JSInterface_Selection.cpp index b6cd81599c..078b0eb038 100755 --- a/source/ps/scripting/JSInterface_Selection.cpp +++ b/source/ps/scripting/JSInterface_Selection.cpp @@ -106,7 +106,7 @@ JSBool JSI_Selection::isValidContextOrder( JSContext* context, JSObject* obj, un JSBool JSI_Selection::getContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp ) { - *vp = g_Selection.m_contextOrder; + *vp = INT_TO_JSVAL( g_Selection.m_contextOrder ); return( JS_TRUE ); } diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index 434922d0a0..8513a46f26 100755 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -312,13 +312,13 @@ void ScriptingHost::ErrorReporter(JSContext * context, const char * message, JSE if (g_Console) { - g_Console->InsertMessage( L"%hs (%d)", report->filename, report->lineno ); if (message) { - g_Console->InsertMessage( L"%hs", message ); + g_Console->InsertMessage( L"JavaScript Error (%hs, line %d): %hs", report->filename, report->lineno, message ); } else - g_Console->InsertMessage( L"No error message available" ); + g_Console->InsertMessage( L"JavaScript Error (%hs, line %d): No error message available", report->filename, report->lineno ); + } if (report->filename != NULL) diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index b1a50a014a..98d3255253 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -48,7 +48,7 @@ bool CBaseEntity::loadXML( CStr filename ) EL(turningradius); EL(size); EL(footprint); - EL(boundsoffset); + EL(graphicsoffset); AT(radius); AT(width); AT(height); @@ -103,21 +103,13 @@ bool CBaseEntity::loadXML( CStr filename ) m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() ); m_bound_type = CBoundingObject::BOUND_OABB; } - else if (ChildName == el_boundsoffset) + else if (ChildName == el_graphicsoffset) { CStr x (Child.getAttributes().getNamedItem(at_x)); CStr y (Child.getAttributes().getNamedItem(at_y)); - if( !m_bound_circle ) - m_bound_circle = new CBoundingCircle(); - if( !m_bound_box ) - m_bound_box = new CBoundingBox(); - - m_bound_circle->m_offset.x = x.ToFloat(); - m_bound_circle->m_offset.y = y.ToFloat(); - m_bound_box->m_offset.x = x.ToFloat(); - m_bound_box->m_offset.y = y.ToFloat(); - + m_graphicsOffset.x = x.ToFloat(); + m_graphicsOffset.y = y.ToFloat(); } } diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index 8322b820c2..82dc7a48cd 100755 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -40,6 +40,7 @@ public: CBoundingCircle* m_bound_circle; CBoundingBox* m_bound_box; CBoundingObject::EBoundingType m_bound_type; + CVector2D m_graphicsOffset; CProperty_float m_speed; CProperty_float m_turningRadius; diff --git a/source/simulation/BoundingObjects.cpp b/source/simulation/BoundingObjects.cpp index 840161daa4..c1167d69ee 100755 --- a/source/simulation/BoundingObjects.cpp +++ b/source/simulation/BoundingObjects.cpp @@ -40,7 +40,6 @@ CBoundingCircle::CBoundingCircle( float x, float y, float radius ) CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy ) { m_type = BOUND_CIRCLE; - m_offset = copy->m_offset; setPosition( x, y ); setRadius( copy->m_radius ); } @@ -48,7 +47,6 @@ CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy ) void CBoundingObject::setPosition( float x, float y ) { m_pos.x = x; m_pos.y = y; - m_pos += m_offset; } void CBoundingCircle::setRadius( float radius ) @@ -95,7 +93,6 @@ CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, float width, f CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, CBoundingBox* copy ) { m_type = BOUND_OABB; - m_offset = copy->m_offset; setPosition( x, y ); setDimensions( copy->getWidth(), copy->getHeight() ); setOrientation( u ); @@ -112,7 +109,6 @@ CBoundingBox::CBoundingBox( float x, float y, float orientation, float width, fl CBoundingBox::CBoundingBox( float x, float y, float orientation, CBoundingBox* copy ) { m_type = BOUND_OABB; - m_offset = copy->m_offset; setPosition( x, y ); setDimensions( copy->getWidth(), copy->getHeight() ); setOrientation( orientation ); diff --git a/source/simulation/BoundingObjects.h b/source/simulation/BoundingObjects.h index 3cb7621be0..b8007b6e40 100755 --- a/source/simulation/BoundingObjects.h +++ b/source/simulation/BoundingObjects.h @@ -18,7 +18,7 @@ class CBoundingCircle; class CBoundingObject { public: - CBoundingObject() { m_offset.x = 0; m_offset.y = 0; } + CBoundingObject() {} enum EBoundingType { BOUND_CIRCLE, @@ -26,7 +26,6 @@ public: }; EBoundingType m_type; CVector2D m_pos; - CVector2D m_offset; float m_radius; void setPosition( float x, float y ); bool intersects( CBoundingObject* obj ); diff --git a/source/simulation/Collision.cpp b/source/simulation/Collision.cpp index 57426b00e1..ada13fe206 100755 --- a/source/simulation/Collision.cpp +++ b/source/simulation/Collision.cpp @@ -23,6 +23,27 @@ CBoundingObject* getContainingObject( const CVector2D& point ) return( NULL ); } +CBoundingObject* getCollisionObject( CBoundingObject* bounds ) +{ + std::vector* entities = g_EntityManager.getExtant(); + std::vector::iterator it; + + for( it = entities->begin(); it != entities->end(); it++ ) + { + assert( (*it)->m_bounds ); + if( (*it)->m_bounds == bounds ) continue; + if( bounds->intersects( (*it)->m_bounds ) ) + { + CBoundingObject* obj = (*it)->m_bounds; + delete( entities ); + return( obj ); + } + } + + delete( entities ); + return( NULL ); +} + HEntity getCollisionObject( CEntity* entity ) { assert( entity->m_bounds ); diff --git a/source/simulation/Collision.h b/source/simulation/Collision.h index f671e3945b..f37c4819aa 100755 --- a/source/simulation/Collision.h +++ b/source/simulation/Collision.h @@ -29,6 +29,7 @@ struct rayIntersectionResults HEntity getCollisionObject( CEntity* entity ); HEntity getCollisionObject( CEntity* entity, float x, float y ); +CBoundingObject* getCollisionObject( CBoundingObject* bounds ); CBoundingObject* getContainingObject( const CVector2D& point ); bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results ); diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 4deb4fe876..20ce2db358 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -20,7 +20,7 @@ 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 ); @@ -41,8 +41,18 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) m_base = base; loadBase(); + + // Nasty hackish correction for models that are off-centre. + // Bad artist. No cookie. + + m_position.X += m_graphicsOffset.x; + m_position.Z += m_graphicsOffset.y; + if( m_bounds ) + m_bounds->setPosition( m_position.X, m_position.Z ); - // We can now freely admit that this exists. + m_position_previous = m_position; + m_orientation_previous = m_orientation; + m_extant = true; m_extant_mirror = true; @@ -88,6 +98,8 @@ void CEntity::loadBase() m_base->m_inheritors.push_back( this ); rebuild(); + m_graphicsOffset = m_base->m_graphicsOffset; + if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE ) { m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle ); @@ -96,6 +108,9 @@ void CEntity::loadBase() { m_bounds = new CBoundingBox( m_position.X, m_position.Z, m_ahead, m_base->m_bound_box ); } + + + } void CEntity::kill() @@ -130,65 +145,17 @@ void CEntity::updateActorTransforms() float s = sin( m_graphics_orientation ); float c = cos( m_graphics_orientation ); - m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = m_graphics_position.X; + m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = m_graphics_position.X - m_graphicsOffset.x; m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = m_graphics_position.Y; - m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = m_graphics_position.Z; + m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = m_graphics_position.Z - m_graphicsOffset.y; m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f; m_actor->GetModel()->SetTransform( m ); } -float CEntity::getExactGroundLevel( float x, float y ) -{ - x /= 4.0f; - y /= 4.0f; - - int xi = (int)floor( x ); - int yi = (int)floor( y ); - float xf = x - (float)xi; - float yf = y - (float)yi; - - u16* heightmap = g_Terrain.GetHeightMap(); - unsigned long mapsize = g_Terrain.GetVerticesPerSide(); - - assert( ( xi >= 0 ) && ( xi < (int)mapsize ) && ( yi >= 0 ) && ( yi < (int)mapsize ) ); - - // In non-debug builds, do something nicer than crashing - if (! ( ( xi >= 0 ) && ( xi < (int)mapsize ) && ( yi >= 0 ) && ( yi < (int)mapsize ) ) ) - { - return 0.0f; - } - - float h00 = heightmap[yi*mapsize + xi]; - float h01 = heightmap[yi*mapsize + xi + mapsize]; - float h10 = heightmap[yi*mapsize + xi + 1]; - float h11 = heightmap[yi*mapsize + xi + mapsize + 1]; - - /* - if( xf < ( 1.0f - yf ) ) - { - return( HEIGHT_SCALE * ( ( 1 - xf - yf ) * h00 + xf * h10 + yf * h01 ) ); - } - else - return( HEIGHT_SCALE * ( ( xf + yf - 1 ) * h11 + ( 1 - xf ) * h01 + ( 1 - yf ) * h10 ) ); - */ - - /* - if( xf > yf ) - { - return( HEIGHT_SCALE * ( ( 1 - xf ) * h00 + ( xf - yf ) * h10 + yf * h11 ) ); - } - else - return( HEIGHT_SCALE * ( ( 1 - yf ) * h00 + ( yf - xf ) * h01 + xf * h11 ) ); - */ - - return( HEIGHT_SCALE * ( ( 1 - yf ) * ( ( 1 - xf ) * h00 + xf * h10 ) + yf * ( ( 1 - xf ) * h01 + xf * h11 ) ) ); - -} - void CEntity::snapToGround() { - m_graphics_position.Y = getExactGroundLevel( m_graphics_position.X, m_graphics_position.Z ); + m_graphics_position.Y = g_Terrain.getExactGroundLevel( m_graphics_position.X, m_graphics_position.Z ); } void CEntity::update( float timestep ) @@ -417,11 +384,11 @@ void CEntity::render() glEnd(); glBegin( GL_LINES ); glColor3f( 1.0f, 0.0f, 0.0f ); - glVertex3f( x0 + fwd.x * r.distance, getExactGroundLevel( x0 + fwd.x * r.distance, y0 + fwd.y * r.distance ) + 0.25f, y0 + fwd.y * r.distance ); - glVertex3f( r.position.x, getExactGroundLevel( r.position.x, r.position.y ) + 0.25f, r.position.y ); + glVertex3f( x0 + fwd.x * r.distance, g_Terrain.getExactGroundLevel( x0 + fwd.x * r.distance, y0 + fwd.y * r.distance ) + 0.25f, y0 + fwd.y * r.distance ); + glVertex3f( r.position.x, g_Terrain.getExactGroundLevel( r.position.x, r.position.y ) + 0.25f, r.position.y ); glEnd(); glBegin( GL_LINE_STRIP ); - glVertex3f( x0, getExactGroundLevel( x0, y0 ), y0 ); + glVertex3f( x0, g_Terrain.getExactGroundLevel( x0, y0 ), y0 ); } switch( it->m_type ) { @@ -438,7 +405,7 @@ void CEntity::render() continue; } - glVertex3f( x, getExactGroundLevel( x, y ) + 0.25f, y ); + glVertex3f( x, g_Terrain.getExactGroundLevel( x, y ) + 0.25f, y ); } glEnd(); @@ -447,7 +414,7 @@ void CEntity::render() glColor3f( 1.0f, 1.0f, 1.0f ); if( getCollisionObject( this ) ) glColor3f( 0.5f, 0.5f, 1.0f ); - m_bounds->render( getExactGroundLevel( m_position.X, m_position.Z ) + 0.25f ); //m_position.Y + 0.25f ); + m_bounds->render( g_Terrain.getExactGroundLevel( m_position.X, m_position.Z ) + 0.25f ); //m_position.Y + 0.25f ); } void CEntity::renderSelectionOutline( float alpha ) @@ -455,12 +422,11 @@ void CEntity::renderSelectionOutline( float alpha ) if( !m_bounds ) return; glColor4f( 1.0f, 1.0f, 1.0f, alpha ); + if( getCollisionObject( this ) ) glColor4f( 1.0f, 0.5f, 0.5f, alpha ); glBegin( GL_LINE_LOOP ); CVector3D pos = m_graphics_position; - pos.X += m_bounds->m_offset.x; - pos.Z += m_bounds->m_offset.y; switch( m_bounds->m_type ) { @@ -473,7 +439,7 @@ void CEntity::renderSelectionOutline( float alpha ) float x = pos.X + radius * sin( ang ); float y = pos.Z + radius * cos( ang ); #ifdef SELECTION_TERRAIN_CONFORMANCE - glVertex3f( x, getExactGroundLevel( x, y ) + 0.25f, y ); + glVertex3f( x, g_Terrain.getExactGroundLevel( x, y ) + 0.25f, y ); #else glVertex3f( x, pos.Y + 0.25f, y ); #endif @@ -497,29 +463,29 @@ void CEntity::renderSelectionOutline( float alpha ) for( int i = SELECTION_BOX_POINTS; i > -SELECTION_BOX_POINTS; i-- ) { p = q + u * h + v * ( w * (float)i / (float)SELECTION_BOX_POINTS ); - glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); + glVertex3f( p.x, g_Terrain.getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } for( int i = SELECTION_BOX_POINTS; i > -SELECTION_BOX_POINTS; i-- ) { p = q + u * ( h * (float)i / (float)SELECTION_BOX_POINTS ) - v * w; - glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); + glVertex3f( p.x, g_Terrain.getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } for( int i = -SELECTION_BOX_POINTS; i < SELECTION_BOX_POINTS; i++ ) { p = q - u * h + v * ( w * (float)i / (float)SELECTION_BOX_POINTS ); - glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); + glVertex3f( p.x, g_Terrain.getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } for( int i = -SELECTION_BOX_POINTS; i < SELECTION_BOX_POINTS; i++ ) { p = q + u * ( h * (float)i / (float)SELECTION_BOX_POINTS ) + v * w; - glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); + glVertex3f( p.x, g_Terrain.getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } #else p = q + u * h + v * w; - glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); + glVertex3f( p.x, g_Terrain.getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); p = q + u * h - v * w; glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index 1ce6d5312b..febee27292 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -61,12 +61,13 @@ public: u8 m_grouped; CProperty_i32 m_grouped_mirror; - //-- Interpolated property CVector3D m_position; CVector3D m_position_previous; CProperty_CVector3D m_graphics_position; + CVector2D m_graphicsOffset; + CBoundingObject* m_bounds; float m_targetorientation; CVector2D m_ahead; @@ -98,7 +99,6 @@ public: void kill(); void interpolate( float relativeoffset ); - float getExactGroundLevel( float x, float y ); void snapToGround(); void updateActorTransforms(); void render(); diff --git a/source/simulation/EntityHandles.cpp b/source/simulation/EntityHandles.cpp index c9a0c68061..1b9e5ba7a8 100755 --- a/source/simulation/EntityHandles.cpp +++ b/source/simulation/EntityHandles.cpp @@ -47,7 +47,10 @@ bool HEntity::operator ==( const HEntity& test ) const void HEntity::addRef() { if( m_handle != INVALID_HANDLE ) + { + assert( m_handle < 4096 ); g_EntityManager.m_entities[m_handle].m_refcount++; + } } void HEntity::decRef() diff --git a/source/simulation/EntityManager.cpp b/source/simulation/EntityManager.cpp index 6e18400dc7..9fd9917568 100755 --- a/source/simulation/EntityManager.cpp +++ b/source/simulation/EntityManager.cpp @@ -6,7 +6,7 @@ int SELECTION_CIRCLE_POINTS; int SELECTION_BOX_POINTS; -int SELECTION_SMOOTHNESS_UNIFIED; +int SELECTION_SMOOTHNESS_UNIFIED = 9; CEntityManager::CEntityManager() { diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index 9b7f8e1a36..3f5cdb5fd3 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -7,6 +7,9 @@ #include "Collision.h" #include "PathfindEngine.h" +#include "Terrain.h" + +extern CTerrain g_Terrain; bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep ) { @@ -43,6 +46,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep ) // making the paths we calculate useless. // It's also painful trying to watch two entities resolve their // collision when they're both bound by turning constraints. + m_ahead = delta / len; m_orientation = atan2( m_ahead.x, m_ahead.y ); } @@ -84,42 +88,75 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep ) delta = m_ahead * scale; + // What would happen if we moved forward a little? + m_position.X += delta.x; m_position.Z += delta.y; + m_bounds->setPosition( m_position.X, m_position.Z ); HEntity collide = getCollisionObject( this ); if( collide ) { - // Hit something. Is it our destination? + // We'd hit something. Let's not. + m_position.X -= delta.x; + m_position.Z -= delta.y; + m_bounds->m_pos -= delta; + + // Is it too late to avoid the collision? + + if( collide->m_bounds->intersects( m_bounds ) ) + { + // Yes. Oh dear. That can't be good. + // This really shouldn't happen in the current build. + + assert( false && "Overlapping objects" ); + + // Erm... do nothing? + + return( false ); + } + + // No. Is our destination within the obstacle? if( collide->m_bounds->contains( current->m_data[0].location ) ) { + // Yes? All well and good, then. Stop here. m_orderQueue.pop_front(); return( false ); } - // No? Take a step back. - m_position.X -= delta.x; - m_position.Z -= delta.y; + // No. Are we nearing our destination, do we wish to stop there, and is it obstructed? - m_bounds->setPosition( m_position.X, m_position.Z ); - - // Are we still hitting it? - if( collide->m_bounds->intersects( m_bounds ) ) + if( ( m_orderQueue.size() == 1 ) && ( len <= 10.0f ) ) { - // Oh dear. Most likely explanation is that this unit was created - // within the bounding area of another entity. - // Try a little boost of speed, to help resolve the situation more quickly. + CBoundingCircle destinationObs( current->m_data[0].location.x, current->m_data[0].location.y, m_bounds->m_radius ); + if( getCollisionObject( &destinationObs ) ) + { + // Yes. (Chances are a bunch of units were tasked to the same destination) + // Here's a wierd idea: (I hope it works) + // Spiral round the destination until a free point is found. + float r = 0.0f, theta = 0.0f, delta; + float interval = destinationObs.m_radius; + float _x = current->m_data[0].location.x, _y = current->m_data[0].location.y; + + while( true ) + { + delta = interval / r; + theta += delta; + r += ( interval * delta ) / ( 2 * PI ); + destinationObs.setPosition( _x + r * cosf( theta ), _y + r * sinf( theta ) ); + if( !getCollisionObject( &destinationObs ) ) break; + } + + // Reset our destination + current->m_data[0].location.x = _x; + current->m_data[0].location.y = _y; - // This really shouldn't happen in the current build. - - m_position.X += delta.x * 2.0f; - m_position.Z += delta.y * 2.0f; - m_bounds->setPosition( m_position.X, m_position.Z ); - return( false ); + return( false ); + } } - + // No? Path around it. CEntityOrder avoidance; @@ -128,6 +165,9 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep ) right.x = m_ahead.y; right.y = -m_ahead.x; CVector2D avoidancePosition; + // Which is the shortest diversion, going left or right? + // (Weight a little towards the right, to stop both units dodging the same way) + if( ( collide->m_bounds->m_pos - m_bounds->m_pos ).dot( right ) < 1 ) { // Turn right. @@ -139,6 +179,8 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep ) avoidancePosition = collide->m_bounds->m_pos - right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f ); } + // Create a short path representing this detour + avoidance.m_data[0].location = avoidancePosition; if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION ) m_orderQueue.pop_front(); @@ -147,6 +189,27 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep ) } + // Will we step off the map? + if( !g_Terrain.isOnMap( m_position.X, m_position.Z ) ) + { + // Yes. That's not a particularly good idea, either. + + m_position.X -= delta.x; + m_position.Z -= delta.y; + m_bounds->setPosition( m_position.X, m_position.Z ); + + // All things being equal, we should only get here while on a collision path + // (No destination could be off the map) + + assert( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION ); + + // Just stop here, repath if necessary. + + m_orderQueue.pop_front(); + } + + // No. I suppose it's OK to go there, then. *disappointed* + return( false ); } @@ -155,13 +218,19 @@ bool CEntity::processGoto( CEntityOrder* current, float timestep ) CVector2D pos( m_position.X, m_position.Z ); CVector2D path_to = current->m_data[0].location; m_orderQueue.pop_front(); + + // Let's just check we're going somewhere... if( ( path_to - pos ).length() < 0.1f ) return( false ); + if( m_actor->GetModel()->GetAnimation() != m_actor->GetObject()->m_WalkAnim ) { m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim ); m_actor->GetModel()->Update( ( rand() * 1000.0f ) / 1000.0f ); } + + // The pathfinder will push its result back into this unit's queue. + g_Pathfinder.requestPath( me, path_to ); return( true ); } @@ -170,6 +239,11 @@ bool CEntity::processPatrol( CEntityOrder* current, float timestep ) { CEntityOrder this_segment; CEntityOrder repeat_patrol; + + // Duplicate the patrol order, push one copy onto the start of our order queue + // (that's the path we'll be taking next) and one copy onto the end of the + // queue (to keep us patrolling) + this_segment.m_type = CEntityOrder::ORDER_GOTO; this_segment.m_data[0] = current->m_data[0]; repeat_patrol.m_type = CEntityOrder::ORDER_PATROL; diff --git a/source/simulation/PathfindEngine.cpp b/source/simulation/PathfindEngine.cpp index 2b63f50433..8e4719a041 100755 --- a/source/simulation/PathfindEngine.cpp +++ b/source/simulation/PathfindEngine.cpp @@ -2,6 +2,14 @@ #include "PathfindEngine.h" #include "PathfindSparse.h" +#include "ConfigDB.h" + +CPathfindEngine::CPathfindEngine() +{ + CConfigValue* sparseDepth = g_ConfigDB.GetValue( CFG_SYSTEM, "pathfind.sparse.recursiondepth" ); + if( sparseDepth ) + sparseDepth->GetInt( SPF_RECURSION_DEPTH ); +} void CPathfindEngine::requestPath( HEntity entity, const CVector2D& destination ) { diff --git a/source/simulation/PathfindEngine.h b/source/simulation/PathfindEngine.h index ac6d558406..dc633daabf 100755 --- a/source/simulation/PathfindEngine.h +++ b/source/simulation/PathfindEngine.h @@ -20,6 +20,7 @@ class CPathfindEngine : public Singleton { public: + CPathfindEngine(); void requestPath( HEntity entity, const CVector2D& destination ); }; diff --git a/source/simulation/PathfindSparse.cpp b/source/simulation/PathfindSparse.cpp index d5f8e4d657..e1a80c51f3 100755 --- a/source/simulation/PathfindSparse.cpp +++ b/source/simulation/PathfindSparse.cpp @@ -1,10 +1,14 @@ #include "precompiled.h" #include "PathfindSparse.h" +#include "Terrain.h" -sparsePathTree::sparsePathTree( const CVector2D& _from, const CVector2D& _to, HEntity _entity, CBoundingObject* _destinationCollisionObject ) +int SPF_RECURSION_DEPTH = 10; + +sparsePathTree::sparsePathTree( const CVector2D& _from, const CVector2D& _to, HEntity _entity, CBoundingObject* _destinationCollisionObject, int _recursionDepth ) { from = _from; to = _to; + recursionDepth = _recursionDepth; entity = _entity; destinationCollisionObject = _destinationCollisionObject; leftPre = NULL; leftPost = NULL; @@ -26,6 +30,13 @@ bool sparsePathTree::slice() { if( type == SPF_OPEN_UNVISITED ) { + if( !recursionDepth ) + { + // Too deep. + type = SPF_IMPOSSIBLE; + return( true ); + } + rayIntersectionResults r; CVector2D forward = to - from; @@ -75,15 +86,16 @@ bool sparsePathTree::slice() if( r.closestApproach < 0 ) favourLeft = true; + // First we path to the left... - leftPre = new sparsePathTree( from, left, entity, destinationCollisionObject ); - leftPost = new sparsePathTree( left, to, entity, destinationCollisionObject ); + leftPre = new sparsePathTree( from, left, entity, destinationCollisionObject, recursionDepth - 1 ); + leftPost = new sparsePathTree( left, to, entity, destinationCollisionObject, recursionDepth - 1 ); // Then we path to the right... - rightPre = new sparsePathTree( from, right, entity, destinationCollisionObject ); - rightPost = new sparsePathTree( right, to, entity, destinationCollisionObject ); + rightPre = new sparsePathTree( from, right, entity, destinationCollisionObject, recursionDepth - 1 ); + rightPost = new sparsePathTree( right, to, entity, destinationCollisionObject, recursionDepth - 1 ); // If anybody reaches this point and is thinking: // @@ -91,6 +103,28 @@ bool sparsePathTree::slice() // // Let me know. + // Check that the subwaypoints are on the map... + if( !g_Terrain.isOnMap( left ) ) + { + // Shut that path down + leftPre->type = SPF_IMPOSSIBLE; + leftPost->type = SPF_IMPOSSIBLE; + } + + if( !g_Terrain.isOnMap( right ) ) + { + // Shut that path down + rightPre->type = SPF_IMPOSSIBLE; + rightPost->type = SPF_IMPOSSIBLE; + } + + if( ( leftPre->type == SPF_IMPOSSIBLE ) && ( rightPre->type == SPF_IMPOSSIBLE ) ) + { + // It's unlikely, but I suppose it /might/ happen + type = SPF_IMPOSSIBLE; + return( true ); + } + type = SPF_OPEN_PROCESSING; return( true ); @@ -193,10 +227,10 @@ void pathSparse( HEntity entity, CVector2D destination ) // Sanity check: if( source.length() < 0.01f ) return; - sparsePathTree sparseEngine( source, destination, entity, getContainingObject( destination ) ); + sparsePathTree sparseEngine( source, destination, entity, getContainingObject( destination ), SPF_RECURSION_DEPTH ); while( sparseEngine.type & sparsePathTree::SPF_OPEN ) sparseEngine.slice(); - assert( sparseEngine.type & sparsePathTree::SPF_SOLVED ); // Shouldn't be any impossible cases yet. + // assert( sparseEngine.type & sparsePathTree::SPF_SOLVED ); // Shouldn't be any impossible cases yet. if( sparseEngine.type & sparsePathTree::SPF_SOLVED ) { diff --git a/source/simulation/PathfindSparse.h b/source/simulation/PathfindSparse.h index 9bdcae4590..f9ff4bbf19 100755 --- a/source/simulation/PathfindSparse.h +++ b/source/simulation/PathfindSparse.h @@ -38,6 +38,7 @@ struct sparsePathTree SPF_OPEN = 4, SPF_SOLVED = 2 } type; + int recursionDepth; HEntity entity; CBoundingObject* destinationCollisionObject; CVector2D from; @@ -59,12 +60,14 @@ struct sparsePathTree sparsePathTree* subtrees[4]; }; unsigned short nextSubtree; - sparsePathTree( const CVector2D& from, const CVector2D& to, HEntity entity, CBoundingObject* destinationCollisionObject ); + sparsePathTree( const CVector2D& from, const CVector2D& to, HEntity entity, CBoundingObject* destinationCollisionObject, int _recursionDepth ); ~sparsePathTree(); bool slice(); void pushResults( std::vector& nodelist ); }; +extern int SPF_RECURSION_DEPTH; + void nodeSmooth( HEntity entity, std::vector& nodelist ); void pathSparse( HEntity entity, CVector2D destination ); bool pathSparseRecursive( HEntity entity, CVector2D from, CVector2D to, CBoundingObject* destinationCollisionObject );