diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index ac03805d03..704dcdc222 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -195,6 +195,10 @@ void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjec const std::vector& units=pUnitMan->GetUnits(); for (uint i=0;iGetEntity(); + if( ent && !ent->m_visible ) + continue; + int status = losMgr->GetUnitStatus(units[i], g_Game->GetLocalPlayer()); CModel* model = units[i]->GetModel(); diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index 77eb7d2daf..22dc7c8dfa 100644 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -16,6 +16,7 @@ #include "SkeletonAnimDef.h" #include "SkeletonAnimManager.h" #include "MeshManager.h" +#include "ObjectEntry.h" #include "lib/res/graphics/ogl_tex.h" #include "lib/res/h_mgr.h" #include "ps/Profile.h" @@ -500,6 +501,8 @@ void CModel::SetPlayerColor(CColor& colour) void CModel::SetShadingColor(CColor& colour) { m_ShadingColor = colour; - for (std::vector::iterator it = m_Props.begin(); it != m_Props.end(); ++it) + for( std::vector::iterator it = m_Props.begin(); it != m_Props.end(); ++it ) + { it->m_Model->SetShadingColor(colour); + } } diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp index fc36172e25..874ba003ab 100644 --- a/source/graphics/UnitManager.cpp +++ b/source/graphics/UnitManager.cpp @@ -17,6 +17,7 @@ #include "ps/CConsole.h" #include "ObjectManager.h" #include "ObjectEntry.h" +#include "simulation/Entity.h" #include "simulation/LOSManager.h" #include "simulation/TerritoryManager.h" @@ -96,6 +97,10 @@ CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) con CUnit* unit = m_Units[i]; float tmin, tmax; + CEntity* ent = unit->GetEntity(); + if( ent && !ent->m_visible ) + continue; + if (unit->GetModel()->GetBounds().RayIntersect(origin, dir, tmin, tmax) && losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN) { diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index e75a691998..ef8e6b5953 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -332,16 +332,6 @@ void Render() glDisable( GL_DEPTH_TEST ); PROFILE_END( "render selection" ); - PROFILE_START( "render building placement cursor" ); - if( g_BuildingPlacer.m_active ) - { - //glEnable( GL_DEPTH_TEST ); - g_BuildingPlacer.render(); - //glDisable( GL_DEPTH_TEST ); - } - PROFILE_END( "render building placement cursor" ); - - PROFILE_START( "render health bars" ); pglActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D); diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index 47adf97eaa..02229fed96 100644 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -1310,29 +1310,29 @@ bool CBuildingPlacer::activate(CStrW& templateName) m_totalTime = 0; m_valid = false; - CBaseEntity* base = g_EntityTemplateCollection.getTemplate( m_templateName ); + m_template = g_EntityTemplateCollection.getTemplate( m_templateName ); - if( !base ) + if( !m_template ) { deactivate(); return false; } // m_actor - CStr actorName ( base->m_actorName ); // convert CStrW->CStr8 + CStr actorName ( m_template->m_actorName ); // convert CStrW->CStr8 std::set selections; m_actor = g_UnitMan.CreateUnit( actorName, 0, selections ); m_actor->SetPlayerID(g_Game->GetLocalPlayer()->GetPlayerID()); // m_bounds - if( base->m_bound_type == CBoundingObject::BOUND_CIRCLE ) + if( m_template->m_bound_type == CBoundingObject::BOUND_CIRCLE ) { - m_bounds = new CBoundingCircle( 0, 0, base->m_bound_circle ); + m_bounds = new CBoundingCircle( 0, 0, m_template->m_bound_circle ); } - else if( base->m_bound_type == CBoundingObject::BOUND_OABB ) + else if( m_template->m_bound_type == CBoundingObject::BOUND_OABB ) { - m_bounds = new CBoundingBox( 0, 0, CVector2D(1, 0), base->m_bound_box ); + m_bounds = new CBoundingBox( 0, 0, CVector2D(1, 0), m_template->m_bound_box ); } return true; @@ -1341,7 +1341,8 @@ bool CBuildingPlacer::activate(CStrW& templateName) void CBuildingPlacer::mousePressed() { CCamera &g_Camera=*g_Game->GetView()->GetCamera(); - clickPos = g_Camera.GetWorldCoordinates(); + if( m_template->m_socket == L"" ) + clickPos = g_Camera.GetWorldCoordinates(); m_clicked = true; } @@ -1349,12 +1350,9 @@ void CBuildingPlacer::mouseReleased() { deactivate(); // do it first in case we fail for any reason - if(m_valid) + if( m_valid ) { - //HEntity ent = g_EntityManager.createFoundation( m_templateName, clickPos, m_angle ); - //ent->SetPlayer(g_Game->GetLocalPlayer()); - - // Issue a command accross the network + // issue a place object command accross the network CPlaceObject *msg = new CPlaceObject(); msg->m_Entities = g_Selection.m_selected; msg->m_Template = m_templateName; @@ -1383,8 +1381,9 @@ void CBuildingPlacer::update( float timeStep ) m_totalTime += timeStep; - if(m_clicked) + if( m_clicked && m_template->m_socket == L"" ) { + // Rotate object m_timeSinceClick += timeStep; CCamera &g_Camera=*g_Game->GetView()->GetCamera(); CVector3D mousePos = g_Camera.GetWorldCoordinates(); @@ -1404,7 +1403,7 @@ void CBuildingPlacer::update( float timeStep ) } CVector3D pos; - if(m_clicked) + if( m_clicked ) { pos = clickPos; } @@ -1414,6 +1413,23 @@ void CBuildingPlacer::update( float timeStep ) pos = g_Camera.GetWorldCoordinates(); } + bool onSocket = false; + if( m_template->m_socket != L"" ) + { + // If we're on a socket of our type, remember that and snap ourselves to it + m_bounds->setPosition(pos.X, pos.Z); // first, move bounds to mouse pos + CEntity* ent = getCollisionEntity( m_bounds, 0, L"" ); // now, check what we intersect + if( ent && ent->m_classes.IsMember( m_template->m_socket ) ) // if it's a socket, snap to it + { + onSocket = true; + m_angle = atan2f( ent->m_ahead.x, ent->m_ahead.y ); + pos = ent->m_position; + clickPos = ent->m_position; + } + } + + // Set position and angle to the location we decided on + CMatrix3D m; float s = sin( m_angle ); float c = cos( m_angle ); @@ -1425,52 +1441,33 @@ void CBuildingPlacer::update( float timeStep ) m_bounds->setPosition(pos.X, pos.Z); - if(m_bounds->m_type == CBoundingObject::BOUND_OABB) + if( m_bounds->m_type == CBoundingObject::BOUND_OABB ) { CBoundingBox* box = (CBoundingBox*) m_bounds; - box->setOrientation(m_angle); + box->setOrientation( m_angle ); } + // It's valid to place the object here if the position is on the map and it's + // unobstructed by anything except possibly our socket (which we find out by + // by passing an ignoreClass to getCollisionObject); also, if we are a + // socketted object, we check that we are in fact on a socket, using onSocket. + CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain(); - m_valid = pTerrain->isOnMap(pos.X, pos.Z) && getCollisionObject(m_bounds)==0; + m_valid = pTerrain->isOnMap( pos.X, pos.Z ) + && ( m_template->m_socket == L"" || onSocket ) + && ( getCollisionObject( m_bounds, 0, m_template->m_socket ) == 0 ); + + // Flash our actor red if the position is invalid. CColor col; - if(m_valid) + if( m_valid ) { col = CColor(1.0f, 1.0f, 1.0f, 1.0f); } else { - float add = (sin(4*PI*m_totalTime) + 1.0f) * 0.08f; - col = CColor(1.4f+add, 0.4f+add, 0.4f+add, 1.0f); + float add = ( sin(4*PI*m_totalTime) + 1.0f ) * 0.08f; + col = CColor( 1.4f+add, 0.4f+add, 0.4f+add, 1.0f ); } - m_actor->GetModel()->SetShadingColor(col); -} - -void CBuildingPlacer::render() -{ - // do nothing special - our CUnit will get rendered by the UnitManager - - /*if(!m_active) - return; - - CVector3D pos; - if(m_clicked) - { - pos = clickPos; - } - else - { - CCamera &g_Camera=*g_Game->GetView()->GetCamera(); - pos = g_Camera.GetWorldCoordinates(); - } - - glBegin(GL_LINE_STRIP); - glColor3f(1,1,1); - glVertex3f(pos.X, pos.Y+6, pos.Z); - glColor3f(1,1,1); - glVertex3f(pos.X, pos.Y, pos.Z); - glColor3f(1,1,1); - glVertex3f(pos.X + 3*sin(m_angle), pos.Y, pos.Z + 3*cos(m_angle)); - glEnd();*/ + m_actor->GetModel()->SetShadingColor( col ); } diff --git a/source/ps/Interact.h b/source/ps/Interact.h index 431779c9db..53c0475aa2 100644 --- a/source/ps/Interact.h +++ b/source/ps/Interact.h @@ -16,6 +16,7 @@ class CVector3D; class CUnit; +class CBaseEntity; class CBoundingObject; #define MAX_BOOKMARKS 10 @@ -154,6 +155,7 @@ struct CBuildingPlacer : public Singleton } CStrW m_templateName; + CBaseEntity* m_template; bool m_active; bool m_clicked; bool m_dragged; @@ -170,7 +172,6 @@ struct CBuildingPlacer : public Singleton void mousePressed(); void mouseReleased(); void update( float timeStep ); - void render(); }; bool isMouseoverType( CEntity* ev, void* userdata ); diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index ce90940c5b..58456f78ca 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -282,8 +282,8 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv CNetMessage* msg = CNetMessage::CommandFromJSArgs(msgEntities, cx, argc-1, argv+1); if (!msg) { - return JS_TRUE; delete msg; + return JS_TRUE; } messages.push_back(msg); diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 358f40eabe..84a6c8e46d 100644 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -69,6 +69,7 @@ CBaseEntity::CBaseEntity( CPlayer* player ) AddProperty( L"traits.vision.permanent", &m_permanent ); AddProperty( L"traits.is_territory_centre", &m_isTerritoryCentre ); AddProperty( L"traits.foundation", &m_foundation ); + AddProperty( L"traits.socket", &m_socket ); for( int t = 0; t < EVENT_LAST; t++ ) { @@ -80,6 +81,7 @@ CBaseEntity::CBaseEntity( CPlayer* player ) m_speed = m_turningRadius = 0.0f; m_extant = true; m_foundation = CStrW(); + m_socket = CStrW(); m_passThroughAllies = false; m_sectorDivs = 4; diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index 0f85c45818..5026ea7ac9 100644 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -116,6 +116,9 @@ public: // Foundation entity, or "" for none CStrW m_foundation; + // Socket entity that we can be built on, or "" for free placement + CStrW m_socket; + float m_speed; float m_runSpeed; float m_runRegenRate; diff --git a/source/simulation/Collision.cpp b/source/simulation/Collision.cpp index 7f15ee3964..048e010127 100644 --- a/source/simulation/Collision.cpp +++ b/source/simulation/Collision.cpp @@ -45,7 +45,7 @@ CEntity* GetCollisionObject( float x, float y ) return( NULL ); } -CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player ) +CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player, CStrW ignoreClass ) { std::vector entities; g_EntityManager.GetInRange( bounds->m_pos.x, bounds->m_pos.y, COLLISION_RANGE, entities ); @@ -55,9 +55,13 @@ CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player ) { if( !(*it)->m_bounds ) continue; if( (*it)->m_bounds == bounds ) continue; + /* If the unit is marked to ignore ally collisions, and the player parameter is passed in and the same player as the unit, then ignore the (potential) collision */ if( player && (*it)->m_passThroughAllies && (*it)->m_player == player ) continue; + + if( (*it)->m_classes.IsMember( ignoreClass ) ) continue; + if( bounds->intersects( (*it)->m_bounds ) ) { CBoundingObject* obj = (*it)->m_bounds; @@ -68,6 +72,32 @@ CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player ) return( NULL ); } +CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player, CStrW ignoreClass ) +{ + std::vector entities; + g_EntityManager.GetInRange( bounds->m_pos.x, bounds->m_pos.y, COLLISION_RANGE, entities ); + std::vector::iterator it; + + for( it = entities.begin(); it != entities.end(); it++ ) + { + if( !(*it)->m_bounds ) continue; + if( (*it)->m_bounds == bounds ) continue; + + /* If the unit is marked to ignore ally collisions, and the player parameter + is passed in and the same player as the unit, then ignore the (potential) collision */ + if( player && (*it)->m_passThroughAllies && (*it)->m_player == player ) continue; + + if( (*it)->m_classes.IsMember( ignoreClass ) ) continue; + + if( bounds->intersects( (*it)->m_bounds ) ) + { + return (*it); + } + } + + return( NULL ); +} + HEntity getCollisionObject( CEntity* entity ) { #ifndef NDEBUG diff --git a/source/simulation/Collision.h b/source/simulation/Collision.h index ceaaa8d03b..d9d7c0e3a1 100644 --- a/source/simulation/Collision.h +++ b/source/simulation/Collision.h @@ -34,7 +34,8 @@ typedef std::vector RayIntersects; HEntity getCollisionObject( CEntity* entity ); HEntity getCollisionObject( CEntity* entity, float x, float y ); -CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player=0 ); +CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player=0, CStrW ignoreClass=L"" ); +CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player=0, CStrW ignoreClass=L"" ); CBoundingObject* getContainingObject( const CVector2D& point ); CEntity* GetCollisionObject( float x, float y ); // Point collision 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 98b044667e..eddc28dba1 100644 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -106,6 +106,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons AddProperty( L"last_combat_time", &m_lastCombatTime ); AddProperty( L"last_run_time", &m_lastRunTime ); AddProperty( L"building", &m_building ); + AddProperty( L"visible", &m_visible ); m_productionQueue = new CProductionQueue( this ); AddProperty( L"production_queue", m_productionQueue ); @@ -168,6 +169,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons m_building = building; + m_visible = true; + m_associatedTerritory = 0; m_player = g_Game->GetPlayer( 0 ); @@ -243,6 +246,13 @@ void CEntity::loadBase() // Make sure the actor has the right player colour m_actor->SetPlayerID( m_player->GetPlayerID() ); } + + // Re-enter all our auras so they can take into account our new traits + for( AuraSet::iterator it = m_aurasInfluencingMe.begin(); + it != m_aurasInfluencingMe.end(); it++ ) + { + (*it)->Remove( this ); + } } void CEntity::initAttributes(const CEntity* _this) @@ -340,6 +350,10 @@ void CEntity::SetPlayer(CPlayer *pPlayer) // Store the ID of the player in the associated model if( m_actor ) m_actor->SetPlayerID( m_player->GetPlayerID() ); + + // If we're a territory centre, change the territory's owner + if( m_associatedTerritory ) + m_associatedTerritory->owner = pPlayer; } void CEntity::updateActorTransforms() @@ -909,8 +923,13 @@ void CEntity::teleport() void CEntity::playerChanged() { + // Set actor player colour if( m_actor ) m_actor->SetPlayerID( m_player->GetPlayerID() ); + + // If we're a territory centre, change the territory's owner + if( m_associatedTerritory ) + m_associatedTerritory->owner = m_player; } void CEntity::checkSelection() @@ -992,6 +1011,8 @@ void CEntity::invalidateActor() void CEntity::render() { + if( !m_visible ) return; + if( !m_orderQueue.empty() ) { std::deque::iterator it; @@ -1120,15 +1141,17 @@ int CEntity::findSector( int divs, float angle, float maxAngle, bool negative ) } void CEntity::renderSelectionOutline( float alpha ) { - if( !m_bounds ) + if( !m_bounds || !m_visible ) return; - if( getCollisionObject( this ) ) - glColor4f( 1.0f, 0.5f, 0.5f, alpha ); + if( getCollisionObject( m_bounds, m_player, m_base->m_socket ) ) + { + glColor4f( 1.0f, 0.5f, 0.5f, alpha ); // We're colliding with another unit; colour outline pink + } else { const SPlayerColour& col = m_player->GetColour(); - glColor3f( col.r, col.g, col.b ); + glColor3f( col.r, col.g, col.b ); // Colour outline with player colour } glBegin( GL_LINE_LOOP ); @@ -1229,7 +1252,10 @@ CVector2D CEntity::getScreenCoords( float height ) return CVector2D( sx, sy ); } void CEntity::renderBarBorders() -{ +{ + if( !m_visible ) + return; + if ( m_staminaBarHeight >= 0 && g_Selection.m_unitUITextures.find(m_healthBorderName) != g_Selection.m_unitUITextures.end() ) { @@ -1275,7 +1301,7 @@ void CEntity::renderBarBorders() } void CEntity::renderHealthBar() { - if( !m_bounds ) + if( !m_bounds || !m_visible ) return; if( m_healthBarHeight < 0 ) return; // negative bar height means don't display health bar @@ -1312,7 +1338,7 @@ void CEntity::renderHealthBar() void CEntity::renderStaminaBar() { - if( !m_bounds ) + if( !m_bounds || !m_visible ) return; if( m_staminaBarHeight < 0 ) return; // negative bar height means don't display stamina bar @@ -1346,7 +1372,7 @@ void CEntity::renderStaminaBar() } void CEntity::renderRank() { - if( !m_bounds ) + if( !m_bounds || !m_visible ) return; if( m_rankHeight < 0 ) return; // negative height means don't display rank @@ -1385,6 +1411,9 @@ void CEntity::renderRank() } void CEntity::renderRallyPoint() { + if( !m_visible ) + return; + if ( !m_hasRallyPoint || g_Selection.m_unitUITextures.find(m_rallyTexture) == g_Selection.m_unitUITextures.end() ) { diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index ee294e5f2f..e23e86ca48 100644 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -105,6 +105,9 @@ public: // If this unit is still active in the gameworld - i.e. not a corpse. bool m_extant; + // If this is false, the unit will not be drawn and cannot be interacted with using the mouse. + bool m_visible; + bool m_isRunning; //is it actually running bool m_shouldRun; //if run was issued, it will remain true until it is stopped bool m_triggerRun; //used in SetRun, corrects 1 frame stamina imbalance diff --git a/source/simulation/TerritoryManager.cpp b/source/simulation/TerritoryManager.cpp index 4d0e782aeb..3a64dcca84 100644 --- a/source/simulation/TerritoryManager.cpp +++ b/source/simulation/TerritoryManager.cpp @@ -73,7 +73,7 @@ void CTerritoryManager::Recalculate() boundary.push_back( CVector2D(mapSize, mapSize) ); boundary.push_back( CVector2D(mapSize, 0) ); - CTerritory* ter = new CTerritory( g_Game->GetPlayer(0), 0, boundary ); + CTerritory* ter = new CTerritory( g_Game->GetPlayer(0), HEntity(), boundary ); m_Territories.push_back(ter); @@ -93,7 +93,7 @@ void CTerritoryManager::Recalculate() std::vector boundary; CalculateBoundary( centres, i, boundary ); - CTerritory* ter = new CTerritory( centres[i]->GetPlayer(), centres[i], boundary ); + CTerritory* ter = new CTerritory( centres[i]->GetPlayer(), centres[i]->me, boundary ); centres[i]->m_associatedTerritory = ter; m_Territories.push_back(ter); @@ -201,6 +201,4 @@ void CTerritoryManager::CalculateBoundary( std::vector& centres, size_ boundary = newBoundary; } } - - debug_printf("Created a boundary polygon with %d edges around index %d\n", boundary.size(), myIndex); } diff --git a/source/simulation/TerritoryManager.h b/source/simulation/TerritoryManager.h index 8b25dfb386..570247380d 100644 --- a/source/simulation/TerritoryManager.h +++ b/source/simulation/TerritoryManager.h @@ -24,10 +24,10 @@ class CTerritory { public: CPlayer* owner; // owner of the territory, or Gaia for none - CEntity* centre; // centre object of this territory + HEntity centre; // centre object of this territory std::vector boundary; // boundary polygon, in map coordinates - CTerritory(CPlayer* owner_, CEntity* centre_, std::vector boundary_) + CTerritory(CPlayer* owner_, HEntity centre_, std::vector boundary_) : owner(owner_), centre(centre_), boundary(boundary_) {} };