diff --git a/docs/JSReg.rtf b/docs/JSReg.rtf new file mode 100644 index 0000000000..78847fb341 Binary files /dev/null and b/docs/JSReg.rtf differ diff --git a/source/graphics/CinemaTrack.h b/source/graphics/CinemaTrack.h index 62d0a404d5..66da50f633 100644 --- a/source/graphics/CinemaTrack.h +++ b/source/graphics/CinemaTrack.h @@ -19,8 +19,6 @@ #include "CStr.h" #include "NUSpline.h" -#include -#include /* Andrew (aka pyrolink) diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 66e70820ab..a375ff4a25 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -390,8 +390,6 @@ void CGameView::CameraLock(float x, float y, float z, bool smooth) m_ViewCamera.m_Orientation.Translate(x, y, z); m_ViewCamera.m_Orientation._24=height; } - - } } diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp index 515b9ac465..c7dfd396b4 100755 --- a/source/graphics/Terrain.cpp +++ b/source/graphics/Terrain.cpp @@ -53,8 +53,6 @@ bool CTerrain::Initialize(u32 size,const u16* data) // store terrain size m_MapSize=(size*PATCH_SIZE)+1; m_MapSizePatches=size; -// WaterManager *WaterMgr = g_Renderer.GetWaterManager(); -// WaterMgr->InitWave(); // allocate data for new terrain m_Heightmap=new u16[m_MapSize*m_MapSize]; m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches]; @@ -204,10 +202,166 @@ float CTerrain::getSlope(float x, float z) const float h01 = m_Heightmap[zi*m_MapSize + xi + m_MapSize]; float h10 = m_Heightmap[zi*m_MapSize + xi + 1]; float h11 = m_Heightmap[zi*m_MapSize + xi + m_MapSize + 1]; - + + //Difference of highest point from lowest point return MAX(MAX(h00, h01), MAX(h10, h11)) - MIN(MIN(h00, h01), MIN(h10, h11)); } +float CTerrain::getSlopeAngle( float x, float y ) const +{ + float fCell = (float)CELL_SIZE; + x /= fCell; + y /= fCell; + int xi = (int)floor(x); + int yi = (int)floor(y); + + //Keep it in bounds + if (xi < 0) + xi = 0; + else if (xi >= (int)m_MapSize-1) + xi = m_MapSize - 2; + if (yi < 0) + yi = 0; + else if (yi >= (int)m_MapSize-1) + yi = m_MapSize - 2; + + float h00 = m_Heightmap[yi*m_MapSize + xi] * HEIGHT_SCALE; + float h01 = m_Heightmap[yi*m_MapSize + xi + m_MapSize] * HEIGHT_SCALE; + float h10 = m_Heightmap[yi*m_MapSize + xi + 1] * HEIGHT_SCALE; + float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1] * HEIGHT_SCALE; + + CVector3D flat, elevated; + float low, high; + + if ( h00 < h01 && h00 < h10 && h00 < h11 ) + low = h00; + else if ( h01 < h10 && h01 < h11 ) + low = h01; + else if ( h10 < h11 ) + low = h10; + else + low = h11; + + //Find correct vector representing the flat version of the vector from low to high points + if ( h00 > h01 && h00 > h10 && h00 > h11 ) + { + high = h00; + if ( low == h10 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + else if ( low == h01 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + else if ( low == h11 ) + flat = CVector3D( fCell, 0.0f, fCell ); + } + else if ( h01 > h10 && h01 > h11 ) + { + high = h01; + if ( low == h00 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + else if ( low == h01 ) + flat = CVector3D( fCell, 0.0f, fCell ); + else if ( low == h11 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + } + else if ( h10 > h11 ) + { + high = h10; + if ( low == h00 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + else if ( low == h01 ) + flat = CVector3D( fCell, 0.0f, fCell ); + else if ( low == h11 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + } + else + { + high = h11; + if ( low == h10 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + else if ( low == h01 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + else if ( low == h00 ) + flat = CVector3D( fCell, 0.0f, fCell ); + } + elevated = flat; + elevated.Y = high - low; + elevated.Normalize(); + flat.Normalize(); + return acosf( flat.Dot( elevated ) ); +} +float CTerrain::getSlopeAngleFace(float x, float y, float orientation) const +{ + bool right; //true means use 0,0 and 1,1; false means use 1,0 and 0,1 + bool invert; + float top, bottom; + x /= (float)CELL_SIZE; + y /= (float)CELL_SIZE; + int xi = (int)floor(x); + int yi = (int)floor(y); + CVector3D flat( (float)CELL_SIZE, 0.0f, (float)CELL_SIZE ); + CVector3D elevated=flat; + + float a0 = DEGTORAD(0.0f); + float a90 = DEGTORAD(90.0f); + float a180 = DEGTORAD(180.0f); + float neg = DEGTORAD(-90.0f); + float a45 = DEGTORAD(45.0f); + float a135 = DEGTORAD(135.0f); + + //Find which side it's facing; use that and the opposite + if ( orientation > 0.0f && orientation < DEGTORAD(90.0f) ) + right = true; + else if ( orientation > DEGTORAD(90.0f) && orientation < DEGTORAD(180.0f) ) + right = false; + else if ( orientation < DEGTORAD(-180.0f) && orientation > DEGTORAD(-90.0f) ) + right = true; + else + right = false; + + //Keep it in bounds + if (xi < 0) + xi = 0; + else if (xi >= (int)m_MapSize-1) + xi = m_MapSize - 2; + if (yi < 0) + yi = 0; + else if (yi >= (int)m_MapSize-1) + yi = m_MapSize - 2; + + if ( right ) + { + bottom = m_Heightmap[yi*m_MapSize + xi]*HEIGHT_SCALE; + top = m_Heightmap[yi*m_MapSize+m_MapSize + xi + 1]*HEIGHT_SCALE; + if ( (orientation > DEGTORAD(-45.0f) && orientation < 0.0f) || + (orientation < DEGTORAD(135.0f) && orientation > 0.0f) ) + elevated.Y = top-bottom; + else + elevated.Y = bottom-top; + } + else + { + bottom = m_Heightmap[yi*m_MapSize + xi + 1]*HEIGHT_SCALE; + top = m_Heightmap[yi*m_MapSize+m_MapSize + xi]*HEIGHT_SCALE; + if ( (orientation > DEGTORAD(-135.0f) && orientation < 0.0f) || + (orientation < DEGTORAD(45.0f) && orientation > 0.0f) ) + elevated.Y = top-bottom; + else + elevated.Y = bottom-top; + } + if ( elevated.Y > 0.0f ) + invert=false; + else + invert=true; + elevated.Y = fabs(elevated.Y); + elevated.Normalize(); + flat.Normalize(); + float ret = elevated.Dot(flat); + + if (invert) + return -acosf(ret); + return acosf(ret); + +} float CTerrain::getExactGroundLevel(float x, float z) const { diff --git a/source/graphics/Terrain.h b/source/graphics/Terrain.h index 4c71fd8d17..34bef90890 100755 --- a/source/graphics/Terrain.h +++ b/source/graphics/Terrain.h @@ -45,7 +45,9 @@ public: inline float getExactGroundLevel(const CVector2D& v) const { return getExactGroundLevel(v.x, v.y); } float getSlope(float x, float z) const ; - + float getSlopeAngle( float x, float y) const; //In radians + //Same as above, but picks the two vertices that the unit is facing (front+back) for slope + float getSlopeAngleFace(float x, float y, float orientation) const; // resize this terrain such that each side has given number of patches void Resize(u32 size); diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 4429db6505..106cba9296 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -49,6 +49,8 @@ CBaseEntity::CBaseEntity() AddProperty( L"traits.stamina.border_name", &m_staminaBorderName ); AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs ); AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty ); + AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch ); + AddProperty( L"traits.pitch.min_actor", &m_minActorPitch ); AddProperty( L"traits.rank.width", &m_rankWidth ); AddProperty( L"traits.rank.height", &m_rankHeight ); AddProperty( L"traits.rank.name", &m_rankName ); diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index 9b3ebfa1e2..e1dbdf3737 100755 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -113,6 +113,9 @@ public: int m_sectorDivs; float m_sectorPenalty; + float m_maxActorPitch; + float m_minActorPitch; + float m_turningRadius; CScriptObject m_EventHandlers[EVENT_LAST]; diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index dd76e07d4f..652e574f92 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -79,6 +79,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons AddProperty( L"traits.stamina.border_name", &m_staminaBorderName ); AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs); AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty ); + AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch ); + AddProperty( L"traits.pitch.min_actor", &m_minActorPitch ); AddProperty( L"traits.rank.width", &m_rankWidth ); AddProperty( L"traits.rank.height", &m_rankHeight ); AddProperty( L"traits.rank.name", &m_rankName ); @@ -101,10 +103,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons AddHandler( t, &m_EventHandlers[t] ); } -// FIXME: janwas: this was uninitialized, which leads to disaster if -// its value happens to be positive. -// setting to what seems to be a reasonable default. - m_sectorDivs = 4; if ( m_sectorDivs >= 0 ) { m_sectorAngles.resize(m_sectorDivs); @@ -143,6 +141,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons m_graphics_orientation = m_orientation; m_actor_transform_valid = false; + m_pitchOrientation = m_pitchOrientation_previous = m_graphics_pitchOrientation = 0.0f; m_destroyed = false; m_selected = false; @@ -158,7 +157,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons m_currentRequest = 0; m_destroyNotifiers = true; - m_formationSlot = -1; + m_formationSlot = -1; m_formation = -1; m_grouped = -1; @@ -277,29 +276,22 @@ void CEntity::SetPlayer(CPlayer *pPlayer) void CEntity::updateActorTransforms() { CMatrix3D m; + CMatrix3D mX; + float Cos = cosf( m_graphics_orientation ); + float Sin = sinf( m_graphics_orientation ); - 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._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._41 = 0.0f; - m._42 = 0.0f; - m._43 = 0.0f; - m._44 = 1.0f; + m._11=-Cos; m._12=0.0f; m._13=-Sin; m._14=0.0f; + m._21=0.0f; m._22=1.0f; m._23=0.0f; m._24=0.0f; + m._31=Sin; m._32=0.0f; m._33=-Cos; m._34=0.0f; + m._41=0.0f; m._42=0.0f; m._43=0.0f; m._44=1.0f; + + mX.SetXRotation( m_graphics_pitchOrientation ); + mX = m*mX; + mX.Translate(m_graphics_position); + //m.RotateX(m_graphics_pitchOrientation); if( m_actor ) - m_actor->GetModel()->SetTransform( m ); + m_actor->GetModel()->SetTransform( mX ); } void CEntity::snapToGround() @@ -382,7 +374,8 @@ void CEntity::update( size_t timestep ) { m_position_previous = m_position; m_orientation_previous = m_orientation; - + m_pitchOrientation_previous = m_pitchOrientation; + CalculateRun( timestep ); CalculateHealth( timestep ); @@ -809,6 +802,7 @@ void CEntity::repath() void CEntity::reorient() { m_orientation = m_graphics_orientation; + m_pitchOrientation = m_graphics_pitchOrientation; m_ahead.x = sin( m_orientation ); m_ahead.y = cos( m_orientation ); if( m_bounds->m_type == CBoundingObject::BOUND_OABB ) @@ -855,7 +849,8 @@ void CEntity::interpolate( float relativeoffset ) { CVector3D old_graphics_position = m_graphics_position; float old_graphics_orientation = m_graphics_orientation; - + float old_graphics_pitchOrientation = m_graphics_pitchOrientation; + m_graphics_position = Interpolate( m_position_previous, m_position, relativeoffset ); // Avoid wraparound glitches for interpolating angles. @@ -864,7 +859,13 @@ void CEntity::interpolate( float relativeoffset ) while( m_orientation > m_orientation_previous + PI ) m_orientation_previous += 2 * PI; + while( m_pitchOrientation < m_pitchOrientation_previous - PI ) + m_pitchOrientation_previous -= 2 * PI; + while( m_pitchOrientation > m_pitchOrientation_previous + PI ) + m_pitchOrientation_previous += 2 * PI; + m_graphics_orientation = Interpolate( m_orientation_previous, m_orientation, relativeoffset ); + m_graphics_pitchOrientation = Interpolate( m_pitchOrientation_previous, m_pitchOrientation, relativeoffset ); // Mark the actor transform data as invalid if the entity has moved since // the last call to 'interpolate'. @@ -872,10 +873,13 @@ void CEntity::interpolate( float relativeoffset ) // calling snapToGround, which is slow. TODO: This may need to be adjusted to // handle flying units or moving terrain. if( m_graphics_orientation != old_graphics_orientation || - m_graphics_position.X != old_graphics_position.X || - m_graphics_position.Z != old_graphics_position.Z ) + m_graphics_position.X != old_graphics_position.X || + m_graphics_position.Z != old_graphics_position.Z || + m_graphics_pitchOrientation != old_graphics_pitchOrientation + ) + { m_actor_transform_valid = false; - + } // Update the actor transform data when necessary. if( !m_actor_transform_valid ) { diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index f3a6dcc2fc..5f4308cec3 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -79,6 +79,9 @@ public: float m_runRegenRate; float m_runDecayRate; + float m_maxActorPitch; + float m_minActorPitch; + float m_healthRegenRate; float m_healthRegenStart; float m_healthDecayRate; @@ -168,6 +171,10 @@ public: float m_orientation; float m_orientation_previous; float m_graphics_orientation; + + float m_pitchOrientation; + float m_pitchOrientation_previous; + float m_graphics_pitchOrientation; // If the actor's current transform data is valid (i.e. the entity hasn't // moved since it was last calculated, and the terrain hasn't been changed). diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index efb5df8a31..be68eb1534 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -89,13 +89,11 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis, float scale = processChooseMovement( len ) * timestep; - // Note: Easy optimization: flag somewhere that this unit // is already pointing the way, and don't do this // trig every time.right m_targetorientation = atan2( delta.x, delta.y ); - float deltatheta = m_targetorientation - (float)m_orientation; while( deltatheta > PI ) deltatheta -= 2 * PI; while( deltatheta < -PI ) deltatheta += 2 * PI; @@ -136,6 +134,12 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis, m_ahead = delta / len; m_orientation = m_targetorientation; } + + float targetpitch = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( m_position.X, m_position.Z, m_orientation ); + while( targetpitch > PI ) targetpitch -= 2 * PI; + while( targetpitch < -PI ) targetpitch += 2 * PI; + m_pitchOrientation = clamp( targetpitch, m_minActorPitch, m_maxActorPitch ); + if( m_bounds && m_bounds->m_type == CBoundingObject::BOUND_OABB ) ((CBoundingBox*)m_bounds)->setOrientation( m_ahead );