diff --git a/source/main.cpp b/source/main.cpp index 9c94096b4b..e00d13b61e 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -214,6 +214,7 @@ static void Frame() // TODO Where does GameView end and other things begin? g_Mouseover.update( TimeSinceLastFrame ); g_Selection.update(); + g_BuildingPlacer.update( TimeSinceLastFrame ); PROFILE_END( "selection and interaction ui" ); PROFILE_START( "sound update" ); diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 3d527475f6..882b848247 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -244,10 +244,21 @@ void Render() } PROFILE_START( "render selection" ); + glEnable( GL_DEPTH_TEST ); g_Mouseover.renderSelectionOutlines(); g_Selection.renderSelectionOutlines(); + 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" ); + glPopAttrib(); } else @@ -790,6 +801,7 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui) new CPathfindEngine; new CSelectedEntities; new CMouseoverEntities; + new CBuildingPlacer; new CSessionManager; diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index 58cb28e57d..c70e56a0bb 100755 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -14,6 +14,7 @@ #include "BoundingObjects.h" #include "Unit.h" #include "Model.h" +#include "simulation/BaseEntityCollection.h" #include "scripting/GameEvents.h" extern CConsole* g_Console; @@ -748,6 +749,12 @@ void MouseButtonUpHandler(const SDL_Event *ev, int clicks) switch( ev->button.button ) { case SDL_BUTTON_LEFT: + if( g_BuildingPlacer.m_active ) + { + g_BuildingPlacer.mouseReleased(); + break; + } + if (customSelectionMode) break; @@ -777,6 +784,12 @@ void MouseButtonUpHandler(const SDL_Event *ev, int clicks) else g_Mouseover.setSelection(); break; + case SDL_BUTTON_RIGHT: + if( g_BuildingPlacer.m_active ) + { + g_BuildingPlacer.cancel(); + break; + } } } @@ -904,11 +917,15 @@ int interactInputHandler( const SDL_Event* ev ) button_down_x = ev->button.x; button_down_y = ev->button.y; button_down_time = get_time(); + if( g_BuildingPlacer.m_active ) + { + g_BuildingPlacer.mousePressed(); + } break; } break; case SDL_MOUSEMOTION: - if( !g_Mouseover.isBandbox() && button_down ) + if( !g_Mouseover.isBandbox() && button_down && !g_BuildingPlacer.m_active ) { int deltax = ev->motion.x - button_down_x; int deltay = ev->motion.y - button_down_y; @@ -953,3 +970,97 @@ void ResetInteraction() { customSelectionMode = false; } + + +bool CBuildingPlacer::activate(CStrW& templateName) +{ + if(m_active) + { + return false; + } + + m_templateName = templateName; + m_active = true; + m_clicked = false; + m_dragged = false; + m_angle = 0; + m_timeSinceClick = 0; + //g_Console->InsertMessage( L"BuildingPlacer: Activated with %ls", m_templateName.c_str() ); + return true; +} + +void CBuildingPlacer::mousePressed() +{ + CCamera &g_Camera=*g_Game->GetView()->GetCamera(); + clickPos = g_Camera.GetWorldCoordinates(); + m_clicked = true; + //g_Console->InsertMessage( L"BuildingPlacer: Clicked (%f, %f, %f)", clickPos.X, clickPos.Y, clickPos.Z ); +} + +void CBuildingPlacer::mouseReleased() +{ + m_active = false; // do it first in case we fail + CBaseEntity* baseEntity = g_EntityTemplateCollection.getTemplate( m_templateName ); + //g_Console->InsertMessage( L"BuildingPlacer: Created %ls at (%f, %f, %f) [%f]", + // m_templateName.c_str(), clickPos.X, clickPos.Y, clickPos.Z, m_angle ); + HEntity ent = g_EntityManager.create( baseEntity, clickPos, m_angle ); + ent->SetPlayer(g_Game->GetLocalPlayer()); +} + +void CBuildingPlacer::cancel() +{ + //g_Console->InsertMessage( L"BuildingPlacer: Cancelled"); + m_active = false; +} + +void CBuildingPlacer::update( float timeStep ) +{ + if(!m_active) + return; + + if(m_clicked) + { + m_timeSinceClick += timeStep; + CCamera &g_Camera=*g_Game->GetView()->GetCamera(); + CVector3D pos = g_Camera.GetWorldCoordinates(); + CVector3D dif = pos - clickPos; + float x = dif.X, z = dif.Z; + if(x*x + z*z < 3*3) { + if(m_dragged || m_timeSinceClick > 0.2f) + { + m_angle += timeStep * PI; + } + } + else + { + m_dragged = true; + m_angle = atan2(x, z); + } + } +} + +void CBuildingPlacer::render() +{ + 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(); +} \ No newline at end of file diff --git a/source/ps/Interact.h b/source/ps/Interact.h index 32ee751ca7..712433e652 100755 --- a/source/ps/Interact.h +++ b/source/ps/Interact.h @@ -113,6 +113,29 @@ struct CMouseoverEntities : public Singleton void stopBandbox(); }; +struct CBuildingPlacer : public Singleton +{ + CBuildingPlacer() + { + m_active = false; + } + + CStrW m_templateName; + bool m_active; + bool m_clicked; + bool m_dragged; + float m_angle; + float m_timeSinceClick; + CVector3D clickPos; + + bool activate( CStrW& templateName ); + void mousePressed(); + void mouseReleased(); + void cancel(); + void update( float timeStep ); + void render(); +}; + bool isMouseoverType( CEntity* ev, void* userdata ); bool isOnScreen( CEntity* ev, void* userdata ); @@ -123,4 +146,5 @@ int interactInputHandler( const SDL_Event* ev ); #define g_Selection CSelectedEntities::GetSingleton() #define g_Mouseover CMouseoverEntities::GetSingleton() +#define g_BuildingPlacer CBuildingPlacer::GetSingleton() diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index f9390191e2..abe5d89a62 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -741,6 +741,33 @@ JSBool getGlobal( JSContext* cx, JSObject* globalObject, uint argc, jsval* argv, return( JS_TRUE ); } +// Activates the building placement cursor for placing a building. +// 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* globalObject, uint argc, jsval* argv, jsval* rval ) +{ + CStrW name; + if(argc == 0) { + name = L"hele_ho"; // save some typing during testing + } + else { + try + { + name = g_ScriptingHost.ValueToUCString( argv[0] ); + } + catch( PSERROR_Scripting_ConversionFailed ) + { + *rval = JSVAL_NULL; + JS_ReportError( cx, "Invalid template name argument" ); + return( JS_TRUE ); + } + } + + *rval = g_BuildingPlacer.activate(name) ? JS_TRUE : JS_FALSE; + + return( JS_TRUE ); +} + //----------------------------------------------------------------------------- // function table @@ -765,6 +792,7 @@ JSFunctionSpec ScriptFunctionTable[] = JS_FUNC(getEntityByHandle, getEntityByHandle, 1) JS_FUNC(getEntityTemplate, getEntityTemplate, 1) JS_FUNC(issueCommand, issueCommand, 2) + JS_FUNC(startPlacing, startPlacing, 1) // Camera JS_FUNC(setCameraTarget, setCameraTarget, 1) diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 3be0dd2d67..fc2cd9cc35 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -664,7 +664,7 @@ void CEntity::renderSelectionOutline( float alpha ) const SPlayerColour& col = m_player->GetColour(); glColor3f( col.r, col.g, col.b ); } - + glBegin( GL_LINE_LOOP ); CVector3D pos = m_graphics_position;