From 2b396ccb577435c97d742a696ad68eb9f7b05597 Mon Sep 17 00:00:00 2001 From: MarkT Date: Mon, 2 Aug 2004 23:14:54 +0000 Subject: [PATCH] Minor improvements to some simulation code. This was SVN commit r887. --- source/graphics/Camera.cpp | 59 ++- source/graphics/Camera.h | 16 +- source/graphics/GameView.cpp | 106 +++-- source/graphics/GameView.h | 1 + source/graphics/Terrain.cpp | 18 + .../graphics/scripting/JSInterface_Camera.cpp | 266 +++++++++++++ .../graphics/scripting/JSInterface_Camera.h | 65 ++++ source/lib/sysdep/win/win.cpp | 8 +- source/lib/sysdep/win/wsdl.cpp | 7 +- source/main.cpp | 6 + .../maths/scripting/JSInterface_Vector3D.cpp | 46 ++- source/maths/scripting/JSInterface_Vector3D.h | 12 +- source/ps/CConsole.cpp | 52 ++- source/ps/CConsole.h | 4 + source/ps/Config.cpp | 2 - source/ps/Config.h | 3 +- source/ps/Hotkey.cpp | 165 ++++++-- source/ps/Hotkey.h | 3 + source/ps/Interact.cpp | 193 +++++---- source/ps/Interact.h | 28 +- source/ps/KeyName.cpp | 29 +- source/ps/Vector2D.h | 11 +- source/ps/scripting/JSInterface_Console.cpp | 102 +++++ source/ps/scripting/JSInterface_Console.h | 30 ++ source/ps/scripting/JSInterface_Selection.cpp | 265 +++++++++++-- source/ps/scripting/JSInterface_Selection.h | 30 +- source/scripting/ScriptGlue.cpp | 56 ++- source/scripting/ScriptGlue.h | 1 - source/scripting/ScriptingHost.h | 11 +- source/simulation/BaseEntity.cpp | 24 +- source/simulation/BaseEntity.h | 8 +- source/simulation/BaseEntityCollection.cpp | 55 ++- source/simulation/BaseEntityCollection.h | 2 +- source/simulation/Collision.cpp | 5 +- source/simulation/Entity.cpp | 48 +-- source/simulation/Entity.h | 20 +- source/simulation/EntityManager.cpp | 2 +- source/simulation/EntityManager.h | 2 +- source/simulation/EntityProperties.cpp | 368 ++++-------------- source/simulation/EntityProperties.h | 212 +++++----- source/simulation/EntityStateProcessing.cpp | 82 ++-- .../scripting/JSInterface_BaseEntity.cpp | 12 +- .../scripting/JSInterface_BaseEntity.h | 2 - .../scripting/JSInterface_Entity.cpp | 25 +- .../simulation/scripting/JSInterface_Entity.h | 4 - source/workspaces/premake/premake.lua | 1 + 46 files changed, 1589 insertions(+), 878 deletions(-) create mode 100755 source/graphics/scripting/JSInterface_Camera.cpp create mode 100755 source/graphics/scripting/JSInterface_Camera.h create mode 100755 source/ps/scripting/JSInterface_Console.cpp create mode 100755 source/ps/scripting/JSInterface_Console.h diff --git a/source/graphics/Camera.cpp b/source/graphics/Camera.cpp index 8e14d6d58a..8785523e8a 100755 --- a/source/graphics/Camera.cpp +++ b/source/graphics/Camera.cpp @@ -14,6 +14,8 @@ #include "Camera.h" #include "Renderer.h" +#include "HFTracer.h" +#include "Game.h" CCamera::CCamera () { @@ -187,14 +189,57 @@ void CCamera::GetScreenCoordinates( const CVector3D& world, float& x, float& y ) y = ( 1 - y ) * 0.5f * g_Renderer.GetHeight(); } +CVector3D CCamera::GetWorldCoordinates( int px, int py ) +{ + CHFTracer tracer( g_Game->GetWorld()->GetTerrain() ); int x, z; + + CVector3D origin, dir, delta, currentTarget; + + BuildCameraRay( px, py, origin, dir ); + + if( tracer.RayIntersect( origin, dir, x, z, currentTarget ) ) + return( currentTarget ); + + // Off the edge of the world? + // Work out where it /would/ hit, if the map were extended out to infinity with average height. + + return( origin + dir * ( ( 50.0f - origin.Y ) / dir.Y ) ); +} + +CVector3D CCamera::GetFocus() +{ + // Basically the same as GetWorldCoordinates + + CHFTracer tracer( g_Game->GetWorld()->GetTerrain() ); int x, z; + + CVector3D origin, dir, delta, currentTarget; + + origin = m_Orientation.GetTranslation(); + dir = m_Orientation.GetIn(); + + if( tracer.RayIntersect( origin, dir, x, z, currentTarget ) ) + return( currentTarget ); + + // Off the edge of the world? + // Work out where it /would/ hit, if the map were extended out to infinity with average height. + + return( origin + dir * ( ( 50.0f - origin.Y ) / dir.Y ) ); +} + void CCamera::LookAt( const CVector3D& camera, const CVector3D& target, const CVector3D& up ) { CVector3D delta = target - camera; - delta.Normalize(); - CVector3D s = delta.Cross( up ); - CVector3D u = s.Cross( delta ); - m_Orientation._11 = -s.X; m_Orientation._12 = up.X; m_Orientation._13 = delta.X; m_Orientation._14 = camera.X; - m_Orientation._21 = -s.Y; m_Orientation._22 = up.Y; m_Orientation._23 = delta.Y; m_Orientation._24 = camera.Y; - m_Orientation._31 = -s.Z; m_Orientation._32 = up.Z; m_Orientation._33 = delta.Z; m_Orientation._34 = camera.Z; - m_Orientation._41 = 0.0f; m_Orientation._42 = 0.0f; m_Orientation._43 = 0.0f; m_Orientation._44 = 1.0f; + LookAlong( camera, delta, up ); +} + +void CCamera::LookAlong( CVector3D camera, CVector3D orientation, CVector3D up ) +{ + orientation.Normalize(); + up.Normalize(); + CVector3D s = orientation.Cross( up ); + // CVector3D u = s.Cross( orientation ); + m_Orientation._11 = -s.X; m_Orientation._12 = up.X; m_Orientation._13 = orientation.X; m_Orientation._14 = camera.X; + m_Orientation._21 = -s.Y; m_Orientation._22 = up.Y; m_Orientation._23 = orientation.Y; m_Orientation._24 = camera.Y; + m_Orientation._31 = -s.Z; m_Orientation._32 = up.Z; m_Orientation._33 = orientation.Z; m_Orientation._34 = camera.Z; + m_Orientation._41 = 0.0f; m_Orientation._42 = 0.0f; m_Orientation._43 = 0.0f; m_Orientation._44 = 1.0f; } \ No newline at end of file diff --git a/source/graphics/Camera.h b/source/graphics/Camera.h index 355588e926..33bc243064 100755 --- a/source/graphics/Camera.h +++ b/source/graphics/Camera.h @@ -70,10 +70,22 @@ class CCamera BuildCameraRay( mouse_x, mouse_y, origin, dir ); } +// General helpers that seem to fit here + +// Get the screen-space coordinates corresponding to a given world-space position void GetScreenCoordinates( const CVector3D& world, float& x, float& y ); - // Build an orientation matrix from camera position, camera target, and up-vector - void LookAt( const CVector3D& camera, const CVector3D& target, const CVector3D& up ); +// Get the point on the terrain corresponding to pixel (px,py) (or the mouse coordinates) + CVector3D GetWorldCoordinates( int px, int py ); + CVector3D GetWorldCoordinates() { return( GetWorldCoordinates( mouse_x, mouse_y ) ); } +// Get the point on the terrain the camera is pointing towards + CVector3D GetFocus(); + + // Build an orientation matrix from camera position, camera focus point, and up-vector + void LookAt( const CVector3D& camera, const CVector3D& orientation, const CVector3D& up ); + + // Build an orientation matrix from camera position, camera orientation, and up-vector + void LookAlong( CVector3D camera, CVector3D focus, CVector3D up ); public: //This is the orientation matrix. The inverse of this diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 5709b180b7..641b76b997 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -26,6 +26,10 @@ extern bool g_active; extern CLightEnv g_LightEnv; +CVector3D cameraBookmarks[10]; +bool bookmarkInUse[10] = { false, false, false, false, false, false, false, false, false, false }; +i8 currentBookmark = -1; + CGameView::CGameView(CGame *pGame): m_pGame(pGame), m_pWorld(pGame->GetWorld()), @@ -189,19 +193,28 @@ void CGameView::ResetCamera() m_Camera.m_Orientation.Translate (100, 150, -100); } +void CGameView::ResetCameraOrientation() +{ + + CVector3D origin = m_Camera.m_Orientation.GetTranslation(); + CVector3D dir = m_Camera.m_Orientation.GetIn(); + + CVector3D target = origin + dir * ( ( 50.0f - origin.Y ) / dir.Y ); + + target -= CVector3D( -22.474480f, 50.0f, 22.474480f ); + + m_Camera.SetProjection (1, 5000, DEGTORAD(20)); + m_Camera.m_Orientation.SetXRotation(DEGTORAD(30)); + m_Camera.m_Orientation.RotateY(DEGTORAD(-45)); + + target += CVector3D( 100.0f, 150.0f, -100.0f ); + + m_Camera.m_Orientation.Translate( target ); +} + void CGameView::RotateAboutTarget() { - CTerrain *pTerrain=m_pWorld->GetTerrain(); - - int x, z; - CHFTracer tracer( pTerrain ); - CVector3D origin, dir; - origin = m_Camera.m_Orientation.GetTranslation(); - dir = m_Camera.m_Orientation.GetIn(); - m_Camera.BuildCameraRay( origin, dir ); - - if( !tracer.RayIntersect( origin, dir, x, z, m_CameraPivot ) ) - m_CameraPivot = origin - dir * ( origin.Y / dir.Y ); + m_CameraPivot = m_Camera.GetWorldCoordinates(); } void CGameView::Update(float DeltaTime) @@ -215,7 +228,7 @@ void CGameView::Update(float DeltaTime) #define CAMERASTYLE 2 // 0 = old style, 1 = relatively new style, 2 = newest style -#if CAMERASTYLE == 2 +// #if CAMERASTYLE == 2 // This could be rewritten much more reliably, so it doesn't e.g. accidentally tilt // the camera, assuming we know exactly what limits the camera should have. @@ -239,10 +252,6 @@ void CGameView::Update(float DeltaTime) forwards_horizontal.Y = 0.0f; forwards_horizontal.Normalize(); - /* - if ((mouseButtons[SDL_BUTTON_MIDDLE] && (keys[SDLK_LCTRL] || keys[SDLK_RCTRL])) - || (mouseButtons[SDL_BUTTON_LEFT] && mouseButtons[SDL_BUTTON_RIGHT]) ) - */ if( hotkeys[HOTKEY_CAMERA_ROTATE] ) { // Ctrl + middle-drag or left-and-right-drag to rotate view @@ -352,6 +361,8 @@ void CGameView::Update(float DeltaTime) zoom_delta *= zoom_proportion; } +/* +Just commented out to make it more obvious it's not in use. #elif CAMERASTYLE == 1 @@ -437,7 +448,7 @@ void CGameView::Update(float DeltaTime) to be completely wrong. sticking with the FOV hack for now. if anyone sees what's wrong, or knows how to correctly implement zoom, please put this code out of its misery :) - */ + *//* // RC - added ScEd style zoom in and out (actually moving camera, rather than fudging fov) float dir=0; @@ -463,6 +474,7 @@ void CGameView::Update(float DeltaTime) } } #endif // CAMERASTYLE +*/ m_Camera.UpdateFrustum (); } @@ -482,17 +494,8 @@ void CGameView::SetCameraTarget( const CVector3D& target ) // the difference beteen that position and the camera point, and restoring // that difference to our new target) - CHFTracer tracer( m_pWorld->GetTerrain() ); - int x, z; - CVector3D origin, dir, currentTarget; - origin = m_Camera.m_Orientation.GetTranslation(); - dir = m_Camera.m_Orientation.GetIn(); - if( tracer.RayIntersect( origin, dir, x, z, currentTarget ) ) - { - m_CameraDelta = target - currentTarget; - } - else - m_CameraDelta = ( target - dir * 160.0f ) - origin; + CVector3D CurrentTarget = m_Camera.GetFocus(); + m_CameraDelta = target - CurrentTarget; } void CGameView::PopCameraTarget() @@ -523,16 +526,59 @@ int game_view_handler(const SDL_Event* ev) } return( EV_HANDLED ); - case HOTKEY_CAMERA_RESET: + case HOTKEY_CAMERA_RESET_ORIGIN: pView->ResetCamera(); return( EV_HANDLED ); + case HOTKEY_CAMERA_RESET: + pView->ResetCameraOrientation(); + return( EV_HANDLED ); + case HOTKEY_CAMERA_ROTATE_ABOUT_TARGET: pView->RotateAboutTarget(); return( EV_HANDLED ); - } + default: + if( ( ev->user.code >= HOTKEY_CAMERA_BOOKMARK_0 ) && ( ev->user.code <= HOTKEY_CAMERA_BOOKMARK_9 ) ) + { + // The above test limits it to 10 bookmarks, so don't worry about overflowing + i8 id = (i8)( ev->user.code - HOTKEY_CAMERA_BOOKMARK_0 ); + + if( hotkeys[HOTKEY_CAMERA_BOOKMARK_SAVE] ) + { + // Attempt to track the ground we're looking at + cameraBookmarks[id] = pView->GetCamera()->GetFocus(); + bookmarkInUse[id] = true; + } + else if( hotkeys[HOTKEY_CAMERA_BOOKMARK_SNAP] ) + { + if( bookmarkInUse[id] && ( currentBookmark == -1 ) ) + { + pView->PushCameraTarget( cameraBookmarks[id] ); + currentBookmark = id; + } + } + else + { + if( bookmarkInUse[id] ) + pView->SetCameraTarget( cameraBookmarks[id] ); + } + return( EV_HANDLED ); + } + } + case SDL_HOTKEYUP: + switch( ev->user.code ) + { + case HOTKEY_CAMERA_BOOKMARK_SNAP: + if( currentBookmark != -1 ) + pView->PopCameraTarget(); + currentBookmark = -1; + break; + default: + return( EV_PASS ); + } + return( EV_HANDLED ); } return EV_PASS; diff --git a/source/graphics/GameView.h b/source/graphics/GameView.h index 7c3c0ff69c..f18f561a40 100755 --- a/source/graphics/GameView.h +++ b/source/graphics/GameView.h @@ -69,6 +69,7 @@ public: // Camera Control Functions (used by input handler) void ResetCamera(); + void ResetCameraOrientation(); void RotateAboutTarget(); void PushCameraTarget( const CVector3D& target ); diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp index 73d91d994e..737c407c4d 100755 --- a/source/graphics/Terrain.cpp +++ b/source/graphics/Terrain.cpp @@ -160,10 +160,28 @@ float CTerrain::getExactGroundLevel( float x, float y ) const float xf = x - (float)xi; float yf = y - (float)yi; + if( xi < 0 ) + { + xi = 0; xf = 0.0f; + } + if( xi >= m_MapSize ) + { + xi = m_MapSize - 1; xf = 1.0f; + } + if( yi < 0 ) + { + yi = 0; yf = 0.0f; + } + if( yi >= m_MapSize ) + { + yi = m_MapSize - 1; yf = 1.0f; + } + /* 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]; diff --git a/source/graphics/scripting/JSInterface_Camera.cpp b/source/graphics/scripting/JSInterface_Camera.cpp new file mode 100755 index 0000000000..d20ab970f9 --- /dev/null +++ b/source/graphics/scripting/JSInterface_Camera.cpp @@ -0,0 +1,266 @@ +#include "precompiled.h" + +#include "JSInterface_Camera.h" +#include "scripting/JSInterface_Vector3D.h" +#include "Camera.h" +#include "Vector3D.h" +#include "Matrix3D.h" +#include "Terrain.h" +#include "Game.h" + +JSClass JSI_Camera::JSI_class = { + "Camera", JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, + JSI_Camera::getProperty, JSI_Camera::setProperty, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JSI_Camera::finalize, + NULL, NULL, NULL, NULL +}; + +JSPropertySpec JSI_Camera::JSI_props[] = +{ + { "position", JSI_Camera::vector_position, JSPROP_ENUMERATE }, + { "orientation", JSI_Camera::vector_orientation, JSPROP_ENUMERATE }, + { "up", JSI_Camera::vector_up, JSPROP_ENUMERATE }, + { 0 }, +}; + +JSFunctionSpec JSI_Camera::JSI_methods[] = +{ + { "lookAt", JSI_Camera::lookAt, 2, 0, 0 }, + { "getFocus", JSI_Camera::getFocus, 0, 0, 0 }, + { 0 } +}; + +void JSI_Camera::init() +{ + g_ScriptingHost.DefineCustomObjectType( &JSI_class, JSI_Camera::construct, 0, JSI_props, JSI_methods, NULL, NULL ); +} + +JSI_Camera::Camera_Info::Camera_Info() +{ + CMatrix3D orient; + orient.SetXRotation( DEGTORAD( 30 ) ); + orient.RotateY( DEGTORAD( -45 ) ); + orient.Translate( 100, 150, -100 ); + + Camera_Info( orient.GetTranslation(), orient.GetIn(), orient.GetUp() ); +} + +JSI_Camera::Camera_Info::Camera_Info( const CVector3D& _position ) +{ + Camera_Info(); + position = _position; +} + +JSI_Camera::Camera_Info::Camera_Info( const CVector3D& _position, const CVector3D& _orientation ) +{ + Camera_Info( _position, _orientation, CVector3D( 0.0f, 1.0f, 0.0f ) ); +} + +JSI_Camera::Camera_Info::Camera_Info( const CVector3D& _position, const CVector3D& _orientation, const CVector3D& _up ) +{ + position = _position; + orientation = _orientation; + up = _up; + copy = NULL; +} + +JSI_Camera::Camera_Info::Camera_Info( CCamera* _copy ) +{ + copy = _copy; + position = copy->m_Orientation.GetTranslation(); + orientation = copy->m_Orientation.GetIn(); + up = copy->m_Orientation.GetUp(); +} + +void JSI_Camera::Camera_Info::update() +{ + if( copy ) + copy->LookAlong( position, orientation, up ); +} + +JSBool JSI_Camera::getCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + JSObject* camera = JS_NewObject( cx, &JSI_Camera::JSI_class, NULL, NULL ); + JS_SetPrivate( cx, camera, new Camera_Info( g_Game->GetView()->GetCamera() ) ); + *vp = OBJECT_TO_JSVAL( camera ); + return( JS_TRUE ); +} + +JSBool JSI_Camera::setCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + JSObject* camera = JSVAL_TO_OBJECT( *vp ); + Camera_Info* cameraInfo; + if( !JSVAL_IS_OBJECT( *vp ) || !( cameraInfo = (Camera_Info*)JS_GetInstancePrivate( cx, camera, &JSI_Camera::JSI_class, NULL ) ) ) + { + JS_ReportError( cx, "[Camera] Invalid object" ); + } + else + g_Game->GetView()->GetCamera()->LookAlong( cameraInfo->position, cameraInfo->orientation, cameraInfo->up ); + return( JS_TRUE ); +} + +JSBool JSI_Camera::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj ); + if( !cameraInfo ) + { + JS_ReportError( cx, "[Camera] Invalid Reference" ); + return( JS_TRUE ); + } + + CVector3D* d; + + switch( g_ScriptingHost.ValueToInt( id ) ) + { + case vector_position: d = &cameraInfo->position; break; + case vector_orientation: d = &cameraInfo->orientation; break; + case vector_up: d = &cameraInfo->up; break; + default: return( JS_FALSE ); + } + + JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL ); + JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( d, cameraInfo, ( void( IBoundPropertyOwner::* )() )&Camera_Info::update ) ); + *vp = OBJECT_TO_JSVAL( vector3d ); + return( JS_TRUE ); +} + +JSBool JSI_Camera::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj ); + if( !cameraInfo ) + { + JS_ReportError( cx, "[Camera] Invalid reference" ); + return( JS_TRUE ); + } + + JSObject* vector3d = JSVAL_TO_OBJECT( *vp ); + JSI_Vector3D::Vector3D_Info* v = NULL; + + if( JSVAL_IS_OBJECT( *vp ) && ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), vector3d, &JSI_Vector3D::JSI_class, NULL ) ) ) + { + switch( g_ScriptingHost.ValueToInt( id ) ) + { + case vector_position: cameraInfo->position = *( v->vector ); break; + case vector_orientation: cameraInfo->orientation = *( v->vector ); break; + case vector_up: cameraInfo->up = *( v->vector ); break; + } + + cameraInfo->update(); + } + + return( JS_TRUE ); +} + +JSBool JSI_Camera::lookAt( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ) +{ + assert( argc >= 2 ); + + JSI_Vector3D::Vector3D_Info* v = NULL; + Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj ); + +#define GETVECTOR( jv ) ( ( JSVAL_IS_OBJECT( jv ) && ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), JSVAL_TO_OBJECT( jv ), &JSI_Vector3D::JSI_class, NULL ) ) ) ? *(v->vector) : CVector3D() ) + + if( argc <= 3 ) + { + cameraInfo->position = GETVECTOR( argv[0] ); + cameraInfo->orientation = ( GETVECTOR( argv[1] ) - GETVECTOR( argv[0] ) ); + cameraInfo->orientation.Normalize(); + } + else + { + JS_ReportError( cx, "[Camera] Too many arguments to lookAt" ); + *rval = JSVAL_FALSE; + return( JS_TRUE ); + } + + if( argc == 2 ) + { + cameraInfo->up = CVector3D( 0.0f, 1.0f, 0.0f ); + } + else if( argc == 3 ) + { + cameraInfo->up = GETVECTOR( argv[2] ); + } + +#undef GETVECTOR + + cameraInfo->update(); + + *rval = JSVAL_TRUE; + return( JS_TRUE ); +} + +JSBool JSI_Camera::getFocus( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) +{ + // Largely copied from the equivalent method in CCamera + + Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj ); + + CHFTracer tracer( g_Game->GetWorld()->GetTerrain() ); int x, z; + + CVector3D currentTarget; + + if( !tracer.RayIntersect( cameraInfo->position, cameraInfo->orientation, x, z, currentTarget ) ) + { + // Off the edge of the world? + // Work out where it /would/ hit, if the map were extended out to infinity with average height. + + currentTarget = cameraInfo->position + cameraInfo->orientation * ( ( 50.0f - cameraInfo->position.Y ) / cameraInfo->orientation.Y ); + } + + JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL ); + JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( currentTarget ) ); + *rval = OBJECT_TO_JSVAL( vector3d ); + return( JS_TRUE ); +} + +JSBool JSI_Camera::construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) +{ + JSI_Vector3D::Vector3D_Info* v = NULL; + + JSObject* camera = JS_NewObject( cx, &JSI_Camera::JSI_class, NULL, NULL ); + +#define GETVECTOR( jv ) ( ( JSVAL_IS_OBJECT( jv ) && ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), JSVAL_TO_OBJECT( jv ), &JSI_Vector3D::JSI_class, NULL ) ) ) ? *(v->vector) : CVector3D() ) + + if( argc == 0 ) + { + JS_SetPrivate( cx, camera, new Camera_Info() ); + } + else if( argc == 1 ) + { + JS_SetPrivate( cx, camera, new Camera_Info( GETVECTOR( argv[0] ) ) ); + } + else if( argc == 2 ) + { + JS_SetPrivate( cx, camera, new Camera_Info( GETVECTOR( argv[0] ), GETVECTOR( argv[1] ) ) ); + } + else if( argc == 3 ) + { + JS_SetPrivate( cx, camera, new Camera_Info( GETVECTOR( argv[0] ), GETVECTOR( argv[1] ), GETVECTOR( argv[2] ) ) ); + } + else + { + JS_ReportError( cx, "[Camera] Too many arguments to constructor" ); + *rval = JSVAL_NULL; + return( JS_TRUE ); + } + +#undef GET_VECTOR + + *rval = OBJECT_TO_JSVAL( camera ); + return( JS_TRUE ); +} + +void JSI_Camera::finalize( JSContext* cx, JSObject* obj ) +{ + delete( (Camera_Info*)JS_GetPrivate( cx, obj ) ); +} + diff --git a/source/graphics/scripting/JSInterface_Camera.h b/source/graphics/scripting/JSInterface_Camera.h new file mode 100755 index 0000000000..1863066fa1 --- /dev/null +++ b/source/graphics/scripting/JSInterface_Camera.h @@ -0,0 +1,65 @@ +// JSInterface_Camera.h +// +// A JavaScript wrapper around a camera object. +// +// Usage: When manipulating objects of type 'Camera' in JavaScript +// +// Mark Thompson (mot20@cam.ac.uk / mark@wildfiregames.com) + +#include "scripting/ScriptingHost.h" +#include "EntityProperties.h" + +#include "Vector3D.h" +#include "Camera.h" +#include "HFTracer.h" + +#ifndef JSI_CAMERA_INCLUDED +#define JSI_CAMERA_INCLUDED + +namespace JSI_Camera +{ + enum + { + vector_position, + vector_orientation, + vector_up + }; + + enum + { + lookat + }; + + struct Camera_Info : public IBoundPropertyOwner + { + CVector3D position; + CVector3D orientation; + CVector3D up; + CCamera* copy; + Camera_Info(); // Create a camera set to the initial view + Camera_Info( const CVector3D& _position ); + Camera_Info( const CVector3D& _position, const CVector3D& _orientation ); + Camera_Info( const CVector3D& _position, const CVector3D& _orientation, const CVector3D& _up ); + Camera_Info( CCamera* copy ); + void update(); + }; + extern JSClass JSI_class; + extern JSPropertySpec JSI_props[]; + extern JSFunctionSpec JSI_methods[]; + + JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + + JSBool getCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool setCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + + JSBool construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); + void finalize( JSContext* cx, JSObject* obj ); + + JSBool lookAt( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); + JSBool getFocus( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); + + void init(); +}; + +#endif \ No newline at end of file diff --git a/source/lib/sysdep/win/win.cpp b/source/lib/sysdep/win/win.cpp index 8fe26b2140..48210a971a 100755 --- a/source/lib/sysdep/win/win.cpp +++ b/source/lib/sysdep/win/win.cpp @@ -27,6 +27,8 @@ #include // __argc #include +extern HWND hWnd; + void sle(int x) { SetLastError((DWORD)x); @@ -120,10 +122,12 @@ int clipboard_set(const wchar_t* text) { int err = -1; - if(!OpenClipboard(0)) + if(!OpenClipboard( hWnd )) return err; EmptyClipboard(); + err = 0; + const size_t len = wcslen(text); HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (len+1) * sizeof(wchar_t)); @@ -137,7 +141,7 @@ int clipboard_set(const wchar_t* text) GlobalUnlock(hMem); - if(SetClipboardData(CF_TEXT, hMem) != 0) + if(SetClipboardData(CF_UNICODETEXT, hMem) != 0) err = 0; // success } diff --git a/source/lib/sysdep/win/wsdl.cpp b/source/lib/sysdep/win/wsdl.cpp index 7264c4bed0..ca967dd5e0 100755 --- a/source/lib/sysdep/win/wsdl.cpp +++ b/source/lib/sysdep/win/wsdl.cpp @@ -72,8 +72,9 @@ static HINSTANCE hInst = 0; // app instance. // returned by GetModuleHandle and used in kbd hook and window creation. -static HWND hWnd = (HWND)INVALID_HANDLE_VALUE; - // make available to the app for ShowWindow calls, etc.? + +HWND hWnd = (HWND)INVALID_HANDLE_VALUE; /* make available to the app for ShowWindow calls, etc.? */ + /* MT: Yes, please. Clipboard calls need it, at least. */ static DEVMODE dm; /* current video mode */ static HDC hDC; @@ -350,7 +351,7 @@ return_char: sdl_btn = (msg.wParam & BIT(31))? SDL_BUTTON_WHEELUP : SDL_BUTTON_WHEELDOWN; break; // event filled in mouse code below default: - if( msg.message >= WM_APP && msg.message < 0xC000 ) + if( ( msg.message >= WM_APP ) && ( msg.message < 0xC000 ) ) // 0xC000 = maximum application message { assert( SDL_USEREVENT+(msg.message-WM_APP) <= 0xff && "Message too far above WM_APP"); ev->type = (u8)(SDL_USEREVENT+(msg.message-WM_APP)); diff --git a/source/main.cpp b/source/main.cpp index 655c7be378..2007b53c21 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -46,6 +46,9 @@ #include "scripting/JSInterface_Entity.h" #include "scripting/JSInterface_BaseEntity.h" #include "scripting/JSInterface_Vector3D.h" +#include "scripting/JSInterface_Camera.h" +#include "scripting/JSInterface_Selection.h" +#include "scripting/JSInterface_Console.h" #include "gui/scripting/JSInterface_IGUIObject.h" #include "gui/scripting/JSInterface_GUITypes.h" @@ -578,6 +581,9 @@ static void InitScripting() JSI_IGUIObject::init(); JSI_GUITypes::init(); JSI_Vector3D::init(); + JSI_Selection::init(); + JSI_Camera::init(); + JSI_Console::init(); } diff --git a/source/maths/scripting/JSInterface_Vector3D.cpp b/source/maths/scripting/JSInterface_Vector3D.cpp index f351890fa8..1397e8a6d9 100755 --- a/source/maths/scripting/JSInterface_Vector3D.cpp +++ b/source/maths/scripting/JSInterface_Vector3D.cpp @@ -42,18 +42,24 @@ JSI_Vector3D::Vector3D_Info::Vector3D_Info( float x, float y, float z ) vector = new CVector3D( x, y, z ); } -JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner ) +JSI_Vector3D::Vector3D_Info::Vector3D_Info( const CVector3D& copy ) +{ + owner = NULL; + vector = new CVector3D( copy.X, copy.Y, copy.Z ); +} + +JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IBoundPropertyOwner* _owner ) { owner = _owner; updateFn = NULL; - vector = copy; + vector = attach; } -JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner, void( IPropertyOwner::*_updateFn )(void) ) +JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IBoundPropertyOwner* _owner, void( IBoundPropertyOwner::*_updateFn )(void) ) { owner = _owner; updateFn = _updateFn; - vector = copy; + vector = attach; } JSI_Vector3D::Vector3D_Info::~Vector3D_Info() @@ -97,31 +103,28 @@ JSBool JSI_Vector3D::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* } CVector3D* vectorData = vectorInfo->vector; - try + + switch( g_ScriptingHost.ValueToInt( id ) ) { - switch( g_ScriptingHost.ValueToInt( id ) ) - { - case component_x: vectorData->X = (float)g_ScriptingHost.ValueToDouble( *vp ); break; - case component_y: vectorData->Y = (float)g_ScriptingHost.ValueToDouble( *vp ); break; - case component_z: vectorData->Z = (float)g_ScriptingHost.ValueToDouble( *vp ); break; - } - } - catch (PSERROR_Scripting_ConversionFailed) - { - JS_ReportError( cx, "Invalid parameter value for Vector3D" ); - return( JS_TRUE ); + case component_x: vectorData->X = (float)g_ScriptingHost.ValueToDouble( *vp ); break; + case component_y: vectorData->Y = (float)g_ScriptingHost.ValueToDouble( *vp ); break; + case component_z: vectorData->Z = (float)g_ScriptingHost.ValueToDouble( *vp ); break; } + if( vectorInfo->owner && vectorInfo->updateFn ) ( (vectorInfo->owner)->*(vectorInfo->updateFn) )(); return( JS_TRUE ); } -JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSEDPARAM(rval) ) +JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) { + JSObject* vector = JS_NewObject( cx, &JSI_Vector3D::JSI_class, NULL, NULL ); + if( argc == 0 ) { - JS_SetPrivate( cx, obj, new Vector3D_Info() ); + JS_SetPrivate( cx, vector, new Vector3D_Info() ); + *rval = OBJECT_TO_JSVAL( vector ); return( JS_TRUE ); } else if( argc == 3 ) @@ -131,19 +134,22 @@ JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* obj, uintN argc, jsval* float x = (float)g_ScriptingHost.ValueToDouble( argv[0] ); float y = (float)g_ScriptingHost.ValueToDouble( argv[1] ); float z = (float)g_ScriptingHost.ValueToDouble( argv[2] ); - JS_SetPrivate( cx, obj, new Vector3D_Info( x, y, z ) ); + JS_SetPrivate( cx, vector, new Vector3D_Info( x, y, z ) ); + *rval = OBJECT_TO_JSVAL( vector ); return( JS_TRUE ); } catch (PSERROR_Scripting_ConversionFailed) { // Invalid input (i.e. can't be coerced into doubles) - fail JS_ReportError( cx, "Invalid parameters to Vector3D constructor" ); - return( JS_TRUE ); + *rval = JSVAL_NULL; + return( JS_FALSE ); } } else { JS_ReportError( cx, "Invalid number of parameters to Vector3D constructor" ); + *rval = JSVAL_NULL; return( JS_FALSE ); } } diff --git a/source/maths/scripting/JSInterface_Vector3D.h b/source/maths/scripting/JSInterface_Vector3D.h index 9693b880c3..5d7f747927 100755 --- a/source/maths/scripting/JSInterface_Vector3D.h +++ b/source/maths/scripting/JSInterface_Vector3D.h @@ -1,6 +1,5 @@ // JSInterface_Entity.h // -// Last modified: 03 June 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com // // A JavaScript class representing a Prometheus CVector3D object. // @@ -14,7 +13,7 @@ #ifndef JSI_VECTOR3_INCLUDED #define JSI_VECTOR3_INCLUDED -class IPropertyOwner; +class IBoundPropertyOwner; namespace JSI_Vector3D { @@ -27,13 +26,14 @@ namespace JSI_Vector3D JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ); struct Vector3D_Info { - IPropertyOwner* owner; - void ( IPropertyOwner::*updateFn )(); + IBoundPropertyOwner* owner; + void ( IBoundPropertyOwner::*updateFn )(); CVector3D* vector; Vector3D_Info(); Vector3D_Info( float x, float y, float z ); - Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner ); - Vector3D_Info( CVector3D* copy, IPropertyOwner* _owner, void (IPropertyOwner::*_updateFn)() ); + Vector3D_Info( const CVector3D& copy ); + Vector3D_Info( CVector3D* attach, IBoundPropertyOwner* _owner ); + Vector3D_Info( CVector3D* attach, IBoundPropertyOwner* _owner, void (IBoundPropertyOwner::*_updateFn)() ); ~Vector3D_Info(); }; extern JSClass JSI_class; diff --git a/source/ps/CConsole.cpp b/source/ps/CConsole.cpp index 222c0ccb32..b723ce1186 100755 --- a/source/ps/CConsole.cpp +++ b/source/ps/CConsole.cpp @@ -7,9 +7,10 @@ #include "sysdep/sysdep.h" #include "input.h" #include "Hotkey.h" - #include "scripting/ScriptingHost.h" +extern bool keys[SDLK_LAST]; + CConsole::CConsole() { @@ -52,6 +53,12 @@ void CConsole::ToggleVisible() m_bVisible = !m_bVisible; } +void CConsole::SetVisible( bool visible ) +{ + if( visible != m_bVisible ) + m_bToggle = true; + m_bVisible = visible; +} void CConsole::FlushBuffer(void) { @@ -411,6 +418,11 @@ void CConsole::InsertMessage(const wchar_t* szMessage, ...) delete[] szBuffer; } +const wchar_t* CConsole::GetBuffer() +{ + m_szBuffer[m_iBufferLength] = 0; + return( m_szBuffer ); +} void CConsole::SetBuffer(const wchar_t* szMessage, ...) { @@ -521,6 +533,21 @@ int conInputHandler(const SDL_Event* ev) g_Console->ToggleVisible(); return( EV_HANDLED ); } + else if( ev->user.code == HOTKEY_CONSOLE_COPY ) + { + clipboard_set( g_Console->GetBuffer() ); + } + else if( ev->user.code == HOTKEY_CONSOLE_PASTE ) + { + wchar_t* text = clipboard_get(); + if(text) + { + for(wchar_t* c = text; *c; c++) + g_Console->InsertChar(0, *c); + + clipboard_free(text); + } + } } if( ev->type != SDL_KEYDOWN) @@ -531,20 +558,15 @@ int conInputHandler(const SDL_Event* ev) if(!g_Console->IsActive()) return EV_PASS; - // paste from clipboard - if(sym == SDLK_INSERT) - { - wchar_t* text = clipboard_get(); - if(text) - { - for(wchar_t* c = text; *c; c++) - g_Console->InsertChar(0, *c); - - clipboard_free(text); - } - } - else + // Stop unprintable characters (ctrl+, alt+ and escape), + // also prevent ` and/or ~ appearing in console every time it's toggled. + // MT: Is this safe? Does any valid character require a ctrl+ or alt+ + // key combination? + if( ( ev->key.keysym.sym != SDLK_ESCAPE ) && + !keys[SDLK_LCTRL] && !keys[SDLK_RCTRL] && + !keys[SDLK_LALT] && !keys[SDLK_RALT] && + !hotkeys[HOTKEY_CONSOLE_TOGGLE] ) g_Console->InsertChar(sym, (wchar_t)ev->key.keysym.unicode ); - return EV_HANDLED; + return EV_PASS; } diff --git a/source/ps/CConsole.h b/source/ps/CConsole.h index 2ea56d4731..18bb1efe86 100755 --- a/source/ps/CConsole.h +++ b/source/ps/CConsole.h @@ -80,6 +80,7 @@ public: void SetSize(float X = 300, float Y = 0, float W = 800, float H = 600); void ToggleVisible(); + void SetVisible( bool visible ); void Update(float DeltaTime); @@ -89,6 +90,9 @@ public: void InsertChar(const int szChar, const wchar_t cooked); void SetBuffer(const wchar_t* szMessage, ...); + + // Only returns a pointer to the buffer; copy out of here if you want to keep it. + const wchar_t* GetBuffer(); void FlushBuffer(); void RegisterFunc(fptr F, const wchar_t* szName); diff --git a/source/ps/Config.cpp b/source/ps/Config.cpp index d39875157a..a3d5cee409 100755 --- a/source/ps/Config.cpp +++ b/source/ps/Config.cpp @@ -1,5 +1,3 @@ -// Last modified: 22 November 2003 (Mark Thompson) - // TODO: A few changes from VFS -> CFile usage if required. // TODO: Optimizations, when we've decided what needs to be done. diff --git a/source/ps/Config.h b/source/ps/Config.h index c9820d066c..1c93534cbd 100755 --- a/source/ps/Config.h +++ b/source/ps/Config.h @@ -1,11 +1,10 @@ /* + Config.h CConfig dynamic data file manager class Mark Thompson (mot20@cam.ac.uk) -Last modified: 22 November 2003 (Mark Thompson) - --Overview-- Maintains a list of data files in use by the engine; reloads any data file diff --git a/source/ps/Hotkey.cpp b/source/ps/Hotkey.cpp index cb6b7b0eeb..13413f0006 100755 --- a/source/ps/Hotkey.cpp +++ b/source/ps/Hotkey.cpp @@ -9,6 +9,7 @@ extern CConsole* g_Console; extern bool keys[SDLK_LAST]; extern bool mouseButtons[5]; +bool unified[5]; /* SDL-type */ @@ -20,8 +21,10 @@ struct SHotkeyMapping typedef std::vector KeyMapping; +const int HK_MAX_KEYCODES = SDLK_LAST + 10; + // A mapping of keycodes onto sets of SDL event codes -static KeyMapping hotkeyMap[SDLK_LAST + 5]; +static KeyMapping hotkeyMap[HK_MAX_KEYCODES]; // An array of the status of virtual keys bool hotkeys[HOTKEY_LAST]; @@ -33,6 +36,13 @@ const int MOUSE_MIDDLE = SDLK_LAST + SDL_BUTTON_MIDDLE; const int MOUSE_WHEELUP = SDLK_LAST + SDL_BUTTON_WHEELUP; const int MOUSE_WHEELDOWN = SDLK_LAST + SDL_BUTTON_WHEELDOWN; +// 'Keycodes' for the unified modifier keys +const int UNIFIED_SHIFT = MOUSE_WHEELDOWN + 1; +const int UNIFIED_CTRL = MOUSE_WHEELDOWN + 2; +const int UNIFIED_ALT = MOUSE_WHEELDOWN + 3; +const int UNIFIED_META = MOUSE_WHEELDOWN + 4; +const int UNIFIED_SUPER = MOUSE_WHEELDOWN + 5; + struct SHotkeyInfo { int code; @@ -40,12 +50,17 @@ struct SHotkeyInfo int defaultmapping1, defaultmapping2; }; +// Will phase out the default shortcuts at sometime in the near future +// (or, failing that, will update them so they can do the tricky stuff +// the config file can. + static SHotkeyInfo hotkeyInfo[] = { { HOTKEY_EXIT, "exit", SDLK_ESCAPE, 0 }, { HOTKEY_SCREENSHOT, "screenshot", SDLK_PRINT, 0 }, { HOTKEY_WIREFRAME, "wireframe", SDLK_w, 0 }, - { HOTKEY_CAMERA_RESET, "camera.reset", SDLK_h, 0 }, + { HOTKEY_CAMERA_RESET, "camera.reset", 0, 0 }, + { HOTKEY_CAMERA_RESET_ORIGIN, "camera.reset.origin", SDLK_h, 0 }, { HOTKEY_CAMERA_ZOOM_IN, "camera.zoom.in", SDLK_PLUS, SDLK_KP_PLUS }, { HOTKEY_CAMERA_ZOOM_OUT, "camera.zoom.out", SDLK_MINUS, SDLK_KP_MINUS }, { HOTKEY_CAMERA_ZOOM_WHEEL_IN, "camera.zoom.wheel.in", MOUSE_WHEELUP, 0 }, @@ -70,6 +85,8 @@ static SHotkeyInfo hotkeyInfo[] = { 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_CONSOLE_COPY, "console.copy", 0, 0 }, + { HOTKEY_CONSOLE_PASTE, "console.paste", 0, 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, }, @@ -117,7 +134,7 @@ struct SHotkeyMappingGUI typedef std::vector GuiMapping; // A mapping of keycodes onto sets of hotkey name strings (e.g. '[hotkey.]camera.reset') -static GuiMapping hotkeyMapGUI[SDLK_LAST + 5]; +static GuiMapping hotkeyMapGUI[HK_MAX_KEYCODES]; typedef std::vector GUIObjectList; // A list of GUI objects typedef std::map GUIHotkeyMap; // A mapping of name strings to lists of GUI objects that they trigger @@ -189,6 +206,7 @@ void setBindings( const CStr& hotkeyName, int integerMapping = -1 ) bindCode.requires.push_back( *itKey2 ); } } + hotkeyMapGUI[*itKey].push_back( bindName ); if( integerMapping != -1 ) hotkeyMap[*itKey].push_back( bindCode ); @@ -246,13 +264,55 @@ int hotkeyInputHandler( const SDL_Event* ev ) return( EV_PASS ); } - // Inhibit the dispatch of hotkey events caused by printable or control keys - // while the console is up. + // Somewhat hackish: + // Create phantom 'unified-modifier' events when left- or right- modifier keys are pressed + // Just send them to this handler; don't let the imaginary event codes leak back to real SDL. - if( g_Console->IsActive() && ( + SDL_Event phantom; + phantom.type = ( ( ev->type == SDL_KEYDOWN ) || ( ev->type == SDL_MOUSEBUTTONDOWN ) ) ? SDL_KEYDOWN : SDL_KEYUP; + if( ( keycode == SDLK_LSHIFT ) || ( keycode == SDLK_RSHIFT ) ) + { + (int&)phantom.key.keysym.sym = UNIFIED_SHIFT; + unified[0] = ( phantom.type == SDL_KEYDOWN ); + hotkeyInputHandler( &phantom ); + } + else if( ( keycode == SDLK_LCTRL ) || ( keycode == SDLK_RCTRL ) ) + { + (int&)phantom.key.keysym.sym = UNIFIED_CTRL; + unified[1] = ( phantom.type == SDL_KEYDOWN ); + hotkeyInputHandler( &phantom ); + } + else if( ( keycode == SDLK_LALT ) || ( keycode == SDLK_RALT ) ) + { + (int&)phantom.key.keysym.sym = UNIFIED_ALT; + unified[2] = ( phantom.type == SDL_KEYDOWN ); + hotkeyInputHandler( &phantom ); + } + else if( ( keycode == SDLK_LMETA ) || ( keycode == SDLK_RMETA ) ) + { + (int&)phantom.key.keysym.sym = UNIFIED_META; + unified[3] = ( phantom.type == SDL_KEYDOWN ); + hotkeyInputHandler( &phantom ); + } + else if( ( keycode == SDLK_LSUPER ) || ( keycode == SDLK_RSUPER ) ) + { + (int&)phantom.key.keysym.sym = UNIFIED_SUPER; + unified[4] = ( phantom.type == SDL_KEYDOWN ); + hotkeyInputHandler( &phantom ); + } + + // Inhibit the dispatch of hotkey events caused by printable or control keys + // while the console is up. (But allow multiple-key - 'Ctrl+F' events, and whatever + // key toggles the console.) + + bool consoleCapture = false, isCapturable; + + if( g_Console->IsActive() && ( ( keycode == 8 ) || ( keycode == 9 ) || ( keycode == 13 ) || /* Editing */ - ( ( keycode >= 32 ) && ( keycode < 282 ) ) ) ) /* Printable (<128), 'World' (<256) */ - return( EV_PASS ); /* Numeric keypad (<273) and Navigation (<282) */ + ( ( keycode >= 32 ) && ( keycode < 273 ) ) || /* Printable (<128), 'World' (<256) */ + ( ( keycode >= 273 ) && ( keycode < 282 ) && /* Numeric keypad (<273), navigation */ + ( keycode != SDLK_INSERT ) ) ) ) /* keys (<282) except insert */ + consoleCapture = true; std::vector::iterator it; std::vector::iterator itGUI; @@ -261,26 +321,28 @@ int hotkeyInputHandler( const SDL_Event* ev ) // 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. + // 'F' while control is down would normally 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 + // but only send a HotkeyDown event for the event with bindings most precisely + // matching 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; + unsigned int closestMap; + size_t closestMapMatch = 0; for( it = hotkeyMap[keycode].begin(); it < hotkeyMap[keycode].end(); it++ ) { // Check to see if all auxiliary keys are down - + std::vector::iterator itKey; bool accept = true; + isCapturable = true; for( itKey = it->requires.begin(); itKey != it->requires.end(); itKey++ ) { @@ -288,36 +350,51 @@ int hotkeyInputHandler( const SDL_Event* ev ) { if( !keys[*itKey] ) accept = false; } - else + else if( *itKey < UNIFIED_SHIFT ) { if( !mouseButtons[(*itKey)-SDLK_LAST] ) accept = false; } + else + if( !unified[(*itKey)-UNIFIED_SHIFT] ) accept = false; + + // If this event requires a multiple keypress (with the exception + // of shift+key combinations) the console won't inhibit it. + if( ( *itKey != SDLK_RSHIFT ) && ( *itKey != SDLK_LSHIFT ) ) + isCapturable = false; } - if( accept ) + if( it->mapsTo == HOTKEY_CONSOLE_TOGGLE ) isCapturable = false; // Because that would be silly. + + if( accept && !( isCapturable && consoleCapture ) ) { hotkeys[it->mapsTo] = true; - if( ( closestMap == -1 ) || ( it->requires.size() > (size_t)closestMapMatch ) ) + if( it->requires.size() >= closestMapMatch ) { + // Only if it's a more precise match, and it either isn't capturable or the console won't capture it. closestMap = it->mapsTo; - closestMapMatch = (int)it->requires.size(); + closestMapMatch = it->requires.size() + 1; } } } - if( closestMap != -1 ) + if( closestMapMatch ) { hotkeyNotification.type = SDL_HOTKEYDOWN; hotkeyNotification.user.code = closestMap; SDL_PushEvent( &hotkeyNotification ); } // GUI bit... could do with some optimization later. + + CStr closestMapName = -1; + closestMapMatch = 0; + for( itGUI = hotkeyMapGUI[keycode].begin(); itGUI != hotkeyMapGUI[keycode].end(); itGUI++ ) { // Check to see if all auxiliary keys are down std::vector::iterator itKey; bool accept = true; + isCapturable = true; for( itKey = itGUI->requires.begin(); itKey != itGUI->requires.end(); itKey++ ) { @@ -325,31 +402,47 @@ int hotkeyInputHandler( const SDL_Event* ev ) { if( !keys[*itKey] ) accept = false; } - else + else if( *itKey < UNIFIED_SHIFT ) { if( !mouseButtons[(*itKey)-SDLK_LAST] ) accept = false; } + else + if( !unified[(*itKey)-UNIFIED_SHIFT] ) accept = false; + + // If this event requires a multiple keypress (with the exception + // of shift+key combinations) the console won't inhibit it. + if( ( *itKey != SDLK_RSHIFT ) && ( *itKey != SDLK_LSHIFT ) ) + isCapturable = false; } - if( accept ) + if( accept && !( isCapturable && consoleCapture ) ) { - // GUI-objects bit - // This fragment is an obvious candidate for rewriting when speed becomes an issue. - GUIHotkeyMap::iterator map_it; - GUIObjectList::iterator obj_it; - map_it = guiHotkeyMap.find( itGUI->mapsTo ); - if( map_it != guiHotkeyMap.end() ) + if( itGUI->requires.size() >= closestMapMatch ) { - GUIObjectList& targets = map_it->second; - for( obj_it = targets.begin(); obj_it != targets.end(); obj_it++ ) - { - hotkeyNotification.type = SDL_GUIHOTKEYPRESS; - hotkeyNotification.user.code = (intptr_t)&(*obj_it); - SDL_PushEvent( &hotkeyNotification ); - } - } + closestMapName = itGUI->mapsTo; + closestMapMatch = itGUI->requires.size() + 1; + } } } + // GUI-objects bit + // This fragment is an obvious candidate for rewriting when speed becomes an issue. + + if( closestMapMatch ) + { + GUIHotkeyMap::iterator map_it; + GUIObjectList::iterator obj_it; + map_it = guiHotkeyMap.find( closestMapName ); + if( map_it != guiHotkeyMap.end() ) + { + GUIObjectList& targets = map_it->second; + for( obj_it = targets.begin(); obj_it != targets.end(); obj_it++ ) + { + hotkeyNotification.type = SDL_GUIHOTKEYPRESS; + hotkeyNotification.user.code = (intptr_t)&(*obj_it); + SDL_PushEvent( &hotkeyNotification ); + } + } + } } else { @@ -366,10 +459,12 @@ int hotkeyInputHandler( const SDL_Event* ev ) { if( !keys[*itKey] ) accept = false; } - else + else if( *itKey < UNIFIED_SHIFT ) { if( !mouseButtons[(*itKey)-SDLK_LAST] ) accept = false; } + else + if( !unified[(*itKey)-UNIFIED_SHIFT] ) accept = false; } if( accept ) diff --git a/source/ps/Hotkey.h b/source/ps/Hotkey.h index fde2621b42..9ad79217de 100755 --- a/source/ps/Hotkey.h +++ b/source/ps/Hotkey.h @@ -31,6 +31,7 @@ enum HOTKEY_SCREENSHOT, HOTKEY_WIREFRAME, HOTKEY_CAMERA_RESET, + HOTKEY_CAMERA_RESET_ORIGIN, HOTKEY_CAMERA_ZOOM_IN, HOTKEY_CAMERA_ZOOM_OUT, HOTKEY_CAMERA_ZOOM_WHEEL_IN, @@ -55,6 +56,8 @@ enum HOTKEY_CAMERA_BOOKMARK_SAVE, HOTKEY_CAMERA_BOOKMARK_SNAP, HOTKEY_CONSOLE_TOGGLE, + HOTKEY_CONSOLE_COPY, + HOTKEY_CONSOLE_PASTE, HOTKEY_SELECTION_ADD, HOTKEY_SELECTION_REMOVE, HOTKEY_SELECTION_GROUP_0, diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index 6203e84afc..990046c0dd 100755 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -16,13 +16,9 @@ extern bool keys[SDLK_LAST]; static const float SELECT_DBLCLICK_RATE = 0.5f; static const int ORDER_DELAY = 5; -CVector3D cameraBookmarks[10]; -bool bookmarkInUse[10] = { false, false, false, false, false, false, false, false, false, false }; -u8 currentBookmark = 255; - void CSelectedEntities::addSelection( CEntity* entity ) { - m_group = 255; + m_group = -1; assert( !isSelected( entity ) ); m_selected.push_back( entity ); entity->m_selected = true; @@ -30,7 +26,7 @@ void CSelectedEntities::addSelection( CEntity* entity ) void CSelectedEntities::removeSelection( CEntity* entity ) { - m_group = 255; + m_group = -1; assert( isSelected( entity ) ); entity->m_selected = false; std::vector::iterator it; @@ -50,7 +46,7 @@ void CSelectedEntities::renderSelectionOutlines() for( it = m_selected.begin(); it < m_selected.end(); it++ ) (*it)->renderSelectionOutline(); - if( m_group_highlight != 255 ) + if( m_group_highlight != -1 ) { glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_BLEND ); @@ -73,7 +69,7 @@ void CSelectedEntities::renderOverlays() std::vector::iterator it; for( it = m_selected.begin(); it < m_selected.end(); it++ ) { - if( (*it)->m_grouped != 255 ) + if( (*it)->m_grouped != -1 ) { assert( (*it)->m_bounds ); @@ -91,7 +87,7 @@ void CSelectedEntities::renderOverlays() } } - if( m_group_highlight != 255 ) + if( m_group_highlight != -1 ) { glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_BLEND ); @@ -137,14 +133,14 @@ void CSelectedEntities::renderOverlays() void CSelectedEntities::setSelection( CEntity* entity ) { - m_group = 255; + m_group = -1; clearSelection(); m_selected.push_back( entity ); } void CSelectedEntities::clearSelection() { - m_group = 255; + m_group = -1; std::vector::iterator it; for( it = m_selected.begin(); it < m_selected.end(); it++ ) (*it)->m_selected = false; @@ -186,21 +182,19 @@ CVector3D CSelectedEntities::getSelectionPosition() return( avg * ( 1.0f / m_selected.size() ) ); } -void CSelectedEntities::saveGroup( u8 groupid ) +void CSelectedEntities::saveGroup( i8 groupid ) { std::vector::iterator it; // Clear all entities in the group... for( it = m_groups[groupid].begin(); it < m_groups[groupid].end(); it++ ) - { - (*it)->m_grouped = 255; - (*it)->m_grouped_mirror = 0; - } + (*it)->m_grouped = -1; + m_groups[groupid].clear(); // Remove selected entities from each group they're in, and flag them as // members of the new group for( it = m_selected.begin(); it < m_selected.end(); it++ ) { - if( (*it)->m_grouped < 255 ) + if( (*it)->m_grouped != -1 ) { std::vector& group = m_groups[(*it)->m_grouped]; std::vector::iterator it2; @@ -214,7 +208,6 @@ void CSelectedEntities::saveGroup( u8 groupid ) } } (*it)->m_grouped = groupid; - (*it)->m_grouped_mirror = ( groupid != 0 ) ? groupid : 10; } // Copy the group across m_groups[groupid] = m_selected; @@ -222,7 +215,31 @@ void CSelectedEntities::saveGroup( u8 groupid ) m_group = groupid; } -void CSelectedEntities::loadGroup( u8 groupid ) +void CSelectedEntities::addToGroup( i8 groupid, CEntity* entity ) +{ + std::vector::iterator it; + + // Remove selected entities from each group they're in, and flag them as + // members of the new group + if( entity->m_grouped != -1 ) + { + std::vector& group = m_groups[(*it)->m_grouped]; + std::vector::iterator it2; + for( it2 = group.begin(); it2 < group.end(); it2++ ) + { + if( (*it2) == entity ) + { + group.erase( it2 ); + break; + } + } + } + entity->m_grouped = groupid; + + m_groups[groupid].push_back( entity ); +} + +void CSelectedEntities::loadGroup( i8 groupid ) { clearSelection(); m_selected = m_groups[groupid]; @@ -232,7 +249,7 @@ void CSelectedEntities::loadGroup( u8 groupid ) m_group = groupid; } -void CSelectedEntities::addGroup( u8 groupid ) +void CSelectedEntities::addGroup( i8 groupid ) { std::vector::iterator it; for( it = m_groups[groupid].begin(); it < m_groups[groupid].end(); it++ ) @@ -244,11 +261,11 @@ void CSelectedEntities::addGroup( u8 groupid ) (*it)->m_selected = true; } -void CSelectedEntities::changeGroup( CEntity* entity, u8 groupid ) +void CSelectedEntities::changeGroup( CEntity* entity, i8 groupid ) { // Remove from current group u8 current = entity->m_grouped; - if( current != 255 ) + if( current != -1 ) { std::vector::iterator it; for( it = m_groups[current].begin(); it < m_groups[current].end(); it++ ) @@ -260,7 +277,7 @@ void CSelectedEntities::changeGroup( CEntity* entity, u8 groupid ) } } } - if( groupid != 255 ) + if( groupid != -1 ) m_groups[groupid].push_back( entity ); entity->m_grouped = groupid; } @@ -276,9 +293,9 @@ bool CSelectedEntities::isSelected( CEntity* entity ) return( false ); } -void CSelectedEntities::highlightGroup( u8 groupid ) +void CSelectedEntities::highlightGroup( i8 groupid ) { - if( m_group_highlight != 255 ) + if( m_group_highlight != -1 ) return; if( !getGroupCount( groupid ) ) return; @@ -288,17 +305,19 @@ void CSelectedEntities::highlightGroup( u8 groupid ) void CSelectedEntities::highlightNone() { - if( m_group_highlight != 255 ) + + if( m_group_highlight != -1 ) g_Game->GetView()->PopCameraTarget(); - m_group_highlight = 255; + m_group_highlight = -1; + } -int CSelectedEntities::getGroupCount( u8 groupid ) +int CSelectedEntities::getGroupCount( i8 groupid ) { return( (int)m_groups[groupid].size() ); } -CVector3D CSelectedEntities::getGroupPosition( u8 groupid ) +CVector3D CSelectedEntities::getGroupPosition( i8 groupid ) { CVector3D avg; std::vector::iterator it; @@ -319,8 +338,10 @@ void CSelectedEntities::update() } m_contextOrder = -1; } - if( ( m_group_highlight != 255 ) && getGroupCount( m_group_highlight ) ) + + if( ( m_group_highlight != -1 ) && getGroupCount( m_group_highlight ) ) g_Game->GetView()->SetCameraTarget( getGroupPosition( m_group_highlight ) ); + } void CSelectedEntities::setContext( int contextOrder ) @@ -367,6 +388,10 @@ bool CSelectedEntities::isContextValid( int contextOrder ) { if( contextOrder == -1 ) return( false ); + // Can't order anything off the map + if( !g_Game->GetWorld()->GetTerrain()->isOnMap( g_Mouseover.m_worldposition ) ) + return( false ); + // Check to see if any member of the selection supports this order type. std::vector::iterator it; for( it = m_selected.begin(); it < m_selected.end(); it++ ) @@ -383,20 +408,12 @@ void CSelectedEntities::contextOrder( bool pushQueue ) std::vector::iterator it; CEntityOrder context, contextRandomized; (int&)context.m_type = m_contextOrder; - CVector3D origin, dir; - pCamera->BuildCameraRay( origin, dir ); switch( m_contextOrder ) { case CEntityOrder::ORDER_GOTO: case CEntityOrder::ORDER_PATROL: - { - CHFTracer maptracer( pTerrain ); - int x, y; CVector3D ipt; - maptracer.RayIntersect( origin, dir, x, y, ipt ); - context.m_data[0].location.x = ipt.X; - context.m_data[0].location.y = ipt.Z; - } + context.m_data[0].location = g_Mouseover.m_worldposition; break; default: @@ -411,9 +428,11 @@ void CSelectedEntities::contextOrder( bool pushQueue ) // 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 radius = 2.0f * sqrt( (float)m_selected.size() - 1 ); // A decent enough approximation + float _x, _y; + for( it = m_selected.begin(); it < m_selected.end(); it++ ) if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) ) { @@ -427,6 +446,18 @@ void CSelectedEntities::contextOrder( bool pushQueue ) contextRandomized.m_data[0].location.x += _x * radius; contextRandomized.m_data[0].location.y += _y * radius; + + // Clamp it to within the map, just in case. + float mapsize = (float)g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide(); + if( contextRandomized.m_data[0].location.x < 0.0f ) + contextRandomized.m_data[0].location.x = 0.0f; + if( contextRandomized.m_data[0].location.x >= mapsize ) + contextRandomized.m_data[0].location.x = mapsize; + if( contextRandomized.m_data[0].location.y < 0.0f ) + contextRandomized.m_data[0].location.y = 0.0f; + if( contextRandomized.m_data[0].location.y >= mapsize ) + contextRandomized.m_data[0].location.y = mapsize; + g_Scheduler.pushFrame( ORDER_DELAY, (*it)->me, new CMessageOrder( contextRandomized, pushQueue ) ); } @@ -443,6 +474,9 @@ void CMouseoverEntities::update( float timestep ) CUnit* hit = g_UnitMan.PickUnit( origin, dir ); m_target = NULL; + + m_worldposition = pCamera->GetWorldCoordinates(); + if( hit ) m_target = hit->GetEntity(); if( m_viewall ) @@ -652,7 +686,7 @@ void CMouseoverEntities::renderOverlays() std::vector::iterator it; for( it = m_mouseover.begin(); it < m_mouseover.end(); it++ ) { - if( it->entity->m_grouped != 255 ) + if( it->entity->m_grouped != -1 ) { assert( it->entity->m_bounds ); glPushMatrix(); @@ -720,7 +754,8 @@ int interactInputHandler( const SDL_Event* ev ) if( ( ev->user.code >= HOTKEY_SELECTION_GROUP_0 ) && ( ev->user.code <= HOTKEY_SELECTION_GROUP_19 ) ) { // The above test limits it to 20 groups, so don't worry about overflowing - u8 id = (u8)( ev->user.code - HOTKEY_SELECTION_GROUP_0 ); + + i8 id = (i8)( ev->user.code - HOTKEY_SELECTION_GROUP_0 ); if( hotkeys[HOTKEY_SELECTION_GROUP_ADD] ) { @@ -745,44 +780,7 @@ int interactInputHandler( const SDL_Event* ev ) } return( EV_HANDLED ); } - else if( ( ev->user.code >= HOTKEY_CAMERA_BOOKMARK_0 ) && ( ev->user.code <= HOTKEY_CAMERA_BOOKMARK_9 ) ) - { - // The above test limits it to 10 bookmarks, so don't worry about overflowing - u8 id = (u8)( ev->user.code - HOTKEY_CAMERA_BOOKMARK_0 ); - if( hotkeys[HOTKEY_CAMERA_BOOKMARK_SAVE] ) - { - // Attempt to track the ground we're looking at - CHFTracer tracer( pTerrain ); - int x, z; - CVector3D origin, dir, delta, currentTarget; - origin = pCamera->m_Orientation.GetTranslation(); - dir = pCamera->m_Orientation.GetIn(); - if( tracer.RayIntersect( origin, dir, x, z, currentTarget ) ) - { - cameraBookmarks[id] = currentTarget; - } - else - { - // Placing a bookmark off the map? If you say so, guv'nor. - cameraBookmarks[id] = pCamera->m_Orientation.GetTranslation() + pCamera->m_Orientation.GetIn() * 160.0f; - } - bookmarkInUse[id] = true; - } - else if( hotkeys[HOTKEY_CAMERA_BOOKMARK_SNAP] ) - { - if( bookmarkInUse[id] && ( currentBookmark == 255 ) ) - { - pView->PushCameraTarget( cameraBookmarks[id] ); - currentBookmark = id; - } - } - else - { - if( bookmarkInUse[id] ) - pView->SetCameraTarget( cameraBookmarks[id] ); - } - return( EV_HANDLED ); - } + return( EV_PASS ); } return( EV_HANDLED ); @@ -790,17 +788,14 @@ int interactInputHandler( const SDL_Event* ev ) switch( ev->user.code ) { case HOTKEY_SELECTION_GROUP_SNAP: - if( g_Selection.m_group_highlight != 255 ) + if( g_Selection.m_group_highlight != -1 ) g_Selection.highlightNone(); break; - case HOTKEY_CAMERA_BOOKMARK_SNAP: - if( currentBookmark != 255 ) - pView->PopCameraTarget(); - currentBookmark = 255; - break; case HOTKEY_HIGHLIGHTALL: g_Mouseover.m_viewall = false; break; + default: + return( EV_PASS ); } return( EV_HANDLED ); case SDL_MOUSEBUTTONUP: @@ -892,3 +887,29 @@ bool isMouseoverType( CEntity* ev ) } return( false ); } + +/* +void pushCameraTarget( const CVector3D& target ) +{ + // Save the current position + cameraTargets.push_back( g_Camera.m_Orientation.GetTranslation() ); + // And set the camera + setCameraTarget( target ); +} + +void setCameraTarget( const CVector3D& target ) +{ + // Maintain the same orientation and level of zoom, if we can + // (do this by working out the point the camera is looking at, saving + // the difference beteen that position and the camera point, and restoring + // that difference to our new target) + + cameraDelta = target - g_Camera.GetFocus(); +} + +void popCameraTarget() +{ + cameraDelta = cameraTargets.back() - g_Camera.m_Orientation.GetTranslation(); + cameraTargets.pop_back(); +} +*/ \ No newline at end of file diff --git a/source/ps/Interact.h b/source/ps/Interact.h index 9a34b9e314..2dbbfd20a8 100755 --- a/source/ps/Interact.h +++ b/source/ps/Interact.h @@ -14,15 +14,18 @@ #include "Scheduler.h" #include "Camera.h" +#define MAX_BOOKMARKS 10 +#define MAX_GROUPS 20 + // CSelectedEntities: the singleton containing entities currently selected on the local machine. // (including group allocations on the local machine) struct CSelectedEntities : public Singleton { - CSelectedEntities() { clearSelection(); m_group = 255; m_group_highlight = 255; m_contextOrder = -1; } + CSelectedEntities() { clearSelection(); m_group = -1; m_group_highlight = -1; m_contextOrder = -1; } std::vector m_selected; - std::vector m_groups[10]; - u8 m_group, m_group_highlight; + std::vector m_groups[MAX_GROUPS]; + i8 m_group, m_group_highlight; int m_contextOrder; void addSelection( CEntity* entity ); @@ -33,14 +36,15 @@ struct CSelectedEntities : public Singleton bool isSelected( CEntity* entity ); CVector3D getSelectionPosition(); - void saveGroup( u8 groupid ); - void loadGroup( u8 groupid ); - void addGroup( u8 groupid ); - void changeGroup( CEntity* entity, u8 groupid ); - void highlightGroup( u8 groupid ); + void addToGroup( i8 groupid, CEntity* entity ); + void saveGroup( i8 groupid ); + void loadGroup( i8 groupid ); + void addGroup( i8 groupid ); + void changeGroup( CEntity* entity, i8 groupid ); + void highlightGroup( i8 groupid ); void highlightNone(); - int getGroupCount( u8 groupid ); - CVector3D getGroupPosition( u8 groupid ); + int getGroupCount( i8 groupid ); + CVector3D getGroupPosition( i8 groupid ); void update(); bool isContextValid( int contextOrder ); @@ -69,6 +73,7 @@ struct CMouseoverEntities : public Singleton float m_fadeinrate; float m_fadeoutrate; float m_fademaximum; + CVector2D m_worldposition; CEntity* m_target; bool m_bandbox, m_viewall; @@ -81,7 +86,8 @@ struct CMouseoverEntities : public Singleton m_fadeinrate = 1.0f; m_fadeoutrate = 2.0f; m_fademaximum = 0.5f; - m_mouseover.clear(); + m_mouseover.clear(); + m_target = NULL; } std::vector m_mouseover; void update( float timestep ); diff --git a/source/ps/KeyName.cpp b/source/ps/KeyName.cpp index 03afd89df1..4b2b30e66e 100755 --- a/source/ps/KeyName.cpp +++ b/source/ps/KeyName.cpp @@ -13,6 +13,20 @@ struct SKeycodeMapping const char* altkeyname; }; +// 'Keycodes' for the mouse buttons +const int MOUSE_LEFT = SDLK_LAST + SDL_BUTTON_LEFT; +const int MOUSE_RIGHT = SDLK_LAST + SDL_BUTTON_RIGHT; +const int MOUSE_MIDDLE = SDLK_LAST + SDL_BUTTON_MIDDLE; +const int MOUSE_WHEELUP = SDLK_LAST + SDL_BUTTON_WHEELUP; +const int MOUSE_WHEELDOWN = SDLK_LAST + SDL_BUTTON_WHEELDOWN; + +// 'Keycodes' for the unified modifier keys +const int UNIFIED_SHIFT = MOUSE_WHEELDOWN + 1; +const int UNIFIED_CTRL = MOUSE_WHEELDOWN + 2; +const int UNIFIED_ALT = MOUSE_WHEELDOWN + 3; +const int UNIFIED_META = MOUSE_WHEELDOWN + 4; +const int UNIFIED_SUPER = MOUSE_WHEELDOWN + 5; + // You can use either key name in the config file... static SKeycodeMapping keycodeMapping[] = @@ -255,11 +269,16 @@ static SKeycodeMapping keycodeMapping[] = { SDLK_POWER, "Power", 0 }, // ? { SDLK_EURO, "Euro", 0 }, { SDLK_UNDO, "Undo", 0 }, // ? - { SDLK_LAST + SDL_BUTTON_LEFT, "Left Mouse Button", "MouseLeft" }, - { SDLK_LAST + SDL_BUTTON_RIGHT, "Right Mouse Button", "MouseRight" }, - { SDLK_LAST + SDL_BUTTON_MIDDLE, "Middle Mouse Button", "MouseMiddle" }, - { SDLK_LAST + SDL_BUTTON_WHEELUP, "Mouse Wheel Up", "WheelUp" }, - { SDLK_LAST + SDL_BUTTON_WHEELDOWN, "Mouse Wheel Down", "WheelDown" }, + { MOUSE_LEFT, "Left Mouse Button", "MouseLeft" }, + { MOUSE_RIGHT, "Right Mouse Button", "MouseRight" }, + { MOUSE_MIDDLE, "Middle Mouse Button", "MouseMiddle" }, + { MOUSE_WHEELUP, "Mouse Wheel Up", "WheelUp" }, + { MOUSE_WHEELDOWN, "Mouse Wheel Down", "WheelDown" }, + { UNIFIED_SHIFT, "Shift", "AnyShift" }, + { UNIFIED_CTRL, "Ctrl", "AnyCtrl" }, + { UNIFIED_ALT, "Alt", "AnyAlt" }, + { UNIFIED_META, "Meta", "AnyMeta" }, + { UNIFIED_SUPER, "Super", "AnyWindows" }, { 0, 0, 0 }, }; diff --git a/source/ps/Vector2D.h b/source/ps/Vector2D.h index ac73a5ef48..c02fcabfc4 100755 --- a/source/ps/Vector2D.h +++ b/source/ps/Vector2D.h @@ -1,6 +1,6 @@ // Vector2D.h // -// Last modified: 26 May 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com +// Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com // // 2-dimensional vector class, primarily for use by simulation code. @@ -8,17 +8,22 @@ #define VECTOR_2D_INCLUDED #include "math.h" +#include "Vector3D.h" class CVector2D { public: float x; float y; - CVector2D() { x = 0.0f; y = 0.0f; } - CVector2D( float _x, float _y ) + inline CVector2D() { x = 0.0f; y = 0.0f; } + inline CVector2D( float _x, float _y ) { x = _x; y = _y; } + inline CVector2D( const CVector3D& v3 ) // This is done an awful lot. + { + x = v3.X; y = v3.Z; + } static inline float dot( const CVector2D& u, const CVector2D& v ) { return( u.x * v.x + u.y * v.y ); diff --git a/source/ps/scripting/JSInterface_Console.cpp b/source/ps/scripting/JSInterface_Console.cpp new file mode 100755 index 0000000000..bf7bd8812f --- /dev/null +++ b/source/ps/scripting/JSInterface_Console.cpp @@ -0,0 +1,102 @@ +// JavaScript interface to native code selection and group objects + +// Mark Thompson (mot20@cam.ac.uk / mark@wildfiregames.com) + +#include "precompiled.h" +#include "JSInterface_Console.h" +#include "CConsole.h" + +extern CConsole* g_Console; + +JSClass JSI_Console::JSI_class = +{ + "Console", 0, + JS_PropertyStub, JS_PropertyStub, + JSI_Console::getProperty, JSI_Console::setProperty, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JS_FinalizeStub, + NULL, NULL, NULL, NULL +}; + +JSPropertySpec JSI_Console::JSI_props[] = +{ + { "visible", JSI_Console::console_visible, JSPROP_ENUMERATE }, + { 0 } +}; + +JSFunctionSpec JSI_Console::JSI_methods[] = +{ + { "write", JSI_Console::writeConsole, 1, 0, 0 }, + { 0 }, +}; + +JSBool JSI_Console::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + int i = JSVAL_TO_INT( id ); + + switch( i ) + { + case console_visible: + *vp = BOOLEAN_TO_JSVAL( g_Console->IsActive() ); return( JS_TRUE ); + default: + *vp = JSVAL_NULL; return( JS_TRUE ); + } +} + +JSBool JSI_Console::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + int i = JSVAL_TO_INT( id ); + + switch( i ) + { + case console_visible: + try + { + g_Console->SetVisible( g_ScriptingHost.ValueToBool( *vp ) ); + return( JS_TRUE ); + } + catch( PSERROR_Scripting_ConversionFailed ) + { + return( JS_TRUE ); + } + default: + return( JS_TRUE ); + } +} + +void JSI_Console::init() +{ + g_ScriptingHost.DefineCustomObjectType( &JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL ); +} + +JSBool JSI_Console::getConsole( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + JSObject* console = JS_NewObject( cx, &JSI_Console::JSI_class, NULL, NULL ); + *vp = OBJECT_TO_JSVAL( console ); + return( JS_TRUE ); +} + +JSBool JSI_Console::writeConsole( JSContext* UNUSEDPARAM(context), JSObject* UNUSEDPARAM(globalObject), unsigned int argc, jsval* argv, jsval* UNUSEDPARAM(rval) ) +{ + assert( argc >= 1 ); + CStr output; + for( unsigned int i = 0; i < argc; i++ ) + { + try + { + CStr arg = g_ScriptingHost.ValueToString( argv[0] ); + output += arg; + } + catch( PSERROR_Scripting_ConversionFailed ) + { + } + } + g_Console->InsertMessage( L"%hs", (const char*)output ); + return( JS_TRUE ); +} \ No newline at end of file diff --git a/source/ps/scripting/JSInterface_Console.h b/source/ps/scripting/JSInterface_Console.h new file mode 100755 index 0000000000..3d42cbef58 --- /dev/null +++ b/source/ps/scripting/JSInterface_Console.h @@ -0,0 +1,30 @@ +// JSInterface_Console.h +// +// The JavaScript wrapper around the console system + +#include "scripting/ScriptingHost.h" + +#ifndef JSI_CONSOLE_INCLUDED +#define JSI_CONSOLE_INCLUDED + +namespace JSI_Console +{ + enum + { + console_visible + }; + extern JSClass JSI_class; + extern JSPropertySpec JSI_props[]; + extern JSFunctionSpec JSI_methods[]; + + JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + + JSBool getConsole( JSContext* context, JSObject* obj, jsval id, jsval* vp ); + + void init(); + + JSBool writeConsole( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); +}; + +#endif \ No newline at end of file diff --git a/source/ps/scripting/JSInterface_Selection.cpp b/source/ps/scripting/JSInterface_Selection.cpp index 078b0eb038..76bfc0d950 100755 --- a/source/ps/scripting/JSInterface_Selection.cpp +++ b/source/ps/scripting/JSInterface_Selection.cpp @@ -6,72 +6,201 @@ #include "JSInterface_Selection.h" #include "Interact.h" -JSBool JSI_Selected::getProperty( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ) +JSClass JSI_Selection::JSI_class = { - if( g_Selection.m_selected.size() ) + "EntityCollection", JSCLASS_HAS_PRIVATE, + JSI_Selection::addProperty, JSI_Selection::removeProperty, + JSI_Selection::getProperty, JSI_Selection::setProperty, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, JSI_Selection::finalize, + NULL, NULL, NULL, NULL +}; + +JSPropertySpec JSI_Selection::JSI_props[] = +{ + { 0 } +}; + +JSFunctionSpec JSI_Selection::JSI_methods[] = +{ + { "toString", JSI_Selection::toString, 0, 0, 0 }, + { 0 }, +}; + +JSBool JSI_Selection::addProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + int i = JSVAL_TO_INT( id ); + std::vector* set = (std::vector*)JS_GetPrivate( cx, obj ); + + // Invalid index and/or value is not an object. + + if( !set || !JSVAL_IS_OBJECT( *vp ) || ( i < 0 ) ) + return( JS_TRUE ); + + HEntity* e = (HEntity*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( *vp ), &JSI_Entity::JSI_class, NULL ); + + // Value is not an entity. + if( !e ) + return( JS_TRUE ); + + if( i >= (int)set->capacity() ) set->resize( i + 1 ); + + // Add to set. + set->insert( set->begin() + id, *e ); + return( JS_TRUE ); +} + +JSBool JSI_Selection::removeProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) { - JSObject* entity = JS_NewObject( context, &JSI_Entity::JSI_class, NULL, NULL ); - JS_SetPrivate( context, entity, new HEntity( g_Selection.m_selected[0]->me ) ); - *vp = OBJECT_TO_JSVAL( entity ); + *vp = JSVAL_TRUE; return( JS_TRUE ); } - else + + int i = JSVAL_TO_INT( id ); + std::vector* set = (std::vector*)JS_GetPrivate( cx, obj ); + + // Invalid index and/or value is not an object. + + if( !set || !JSVAL_IS_OBJECT( *vp ) || ( i < 0 ) || ( i >= (int)set->size() ) ) + { + *vp = JSVAL_TRUE; + return( JS_TRUE ); + } + + // Remove from set. + set->erase( set->begin() + id ); + + *vp = JSVAL_TRUE; + return( JS_TRUE ); +} + +JSBool JSI_Selection::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) +{ + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + int i = JSVAL_TO_INT( id ); + std::vector* set = (std::vector*)JS_GetPrivate( cx, obj ); + + // Invalid index and/or value is not an object. + + if( !set || ( i < 0 ) || ( i >= (int)set->size() ) ) { *vp = JSVAL_NULL; return( JS_TRUE ); } -} -JSBool JSI_Selected::setProperty( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ) -{ - g_Selection.clearSelection(); - JSObject* selection = JSVAL_TO_OBJECT( *vp ); - HEntity* entity = NULL; - if( JSVAL_IS_OBJECT( *vp ) && ( entity = (HEntity*)JS_GetInstancePrivate( context, selection, &JSI_Entity::JSI_class, NULL ) ) ) - { - g_Selection.addSelection( *entity ); - } - else - JS_ReportError( context, "[Entity] Invalid reference" ); + // Retrieve from set. + JSObject* e = JS_NewObject( cx, &JSI_Entity::JSI_class, NULL, NULL ); + JS_SetPrivate( cx, e, new HEntity( set->at( i ) ) ); + + *vp = OBJECT_TO_JSVAL( e ); return( JS_TRUE ); } -JSBool JSI_Selection::getProperty( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ) +JSBool JSI_Selection::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { - JSObject* selectionArray = JS_NewArrayObject( context, 0, NULL ); - std::vector::iterator it; int i; - for( it = g_Selection.m_selected.begin(), i = 0; it < g_Selection.m_selected.end(); it++, i++ ) + if( !JSVAL_IS_INT( id ) ) + return( JS_TRUE ); + + int i = JSVAL_TO_INT( id ); + std::vector* set = (std::vector*)JS_GetPrivate( cx, obj ); + + // Invalid index and/or value is not an object. + + if( !set || !JSVAL_IS_OBJECT( *vp ) || ( i < 0 ) || ( i >= (int)set->size() ) ) + return( JS_TRUE ); + + HEntity* e = (HEntity*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( *vp ), &JSI_Entity::JSI_class, NULL ); + + // Value is not an entity. + if( !e ) { - JSObject* entity = JS_NewObject( context, &JSI_Entity::JSI_class, NULL, NULL ); - JS_SetPrivate( context, entity, new HEntity( (*it)->me ) ); - jsval j = OBJECT_TO_JSVAL( entity ); - JS_SetElement( context, selectionArray, i, &j ); + JSObject* c = JS_NewObject( cx, &JSI_Entity::JSI_class, NULL, NULL ); + JS_SetPrivate( cx, c, new HEntity( set->at( i ) ) ); + + *vp = OBJECT_TO_JSVAL( e ); + return( JS_TRUE ); } - // Also throw in the check/get/set context orders here. + + // Write into set. + set->at( id ) = *e; + + return( JS_TRUE ); +} + +void JSI_Selection::finalize( JSContext* cx, JSObject* obj ) +{ + std::vector* set = (std::vector*)JS_GetPrivate( cx, obj ); + if( set ) + delete( set ); +} + +void JSI_Selection::init() +{ + g_ScriptingHost.DefineCustomObjectType( &JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL ); +} + +JSBool JSI_Selection::toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) +{ + std::vector* set = (std::vector*)JS_GetPrivate( cx, obj ); + + wchar_t buffer[256]; + _snwprintf( buffer, 256, L"[object EntityCollection: %d entities]", set->size() ); + buffer[255] = 0; + *rval = STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, buffer ) ); + return( JS_TRUE ); +} + +JSBool JSI_Selection::getSelection( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ) +{ + std::vector* set = new std::vector; + std::vector::iterator it; + + for( it = g_Selection.m_selected.begin(); it != g_Selection.m_selected.end(); it++ ) + set->push_back( (*it)->me ); + + JSObject* selectionArray = JS_NewObject( context, &JSI_Selection::JSI_class, NULL, NULL ); + JS_SetPrivate( context, selectionArray, set ); + JS_DefineFunction( context, selectionArray, "isOrderTypeValid", JSI_Selection::isValidContextOrder, 1, 0 ); JS_DefineProperty( context, selectionArray, "orderType", INT_TO_JSVAL( g_Selection.m_contextOrder ), - JSI_Selection::getContextOrder, JSI_Selection::setContextOrder, 0 ); + JSI_Selection::getContextOrder, JSI_Selection::setContextOrder, 0 ); + *vp = OBJECT_TO_JSVAL( selectionArray ); return( JS_TRUE ); } -JSBool JSI_Selection::setProperty( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ) +JSBool JSI_Selection::setSelection( JSContext* context, JSObject* globalObject, jsval id, jsval* vp ) { - g_Selection.clearSelection(); + if( !JSVAL_IS_OBJECT( *vp ) ) + { + JS_ReportError( context, "Not a valid EntityCollection" ); + *vp = JSVAL_NULL; + return( JS_TRUE ); + } JSObject* selectionArray = JSVAL_TO_OBJECT( *vp ); - if( JSVAL_IS_NULL( *vp ) || !JSVAL_IS_OBJECT( *vp ) || !JS_IsArrayObject( context, selectionArray ) ) + + std::vector* set = (std::vector*)JS_GetInstancePrivate( context, JSVAL_TO_OBJECT( *vp ), &JSI_Selection::JSI_class, NULL ); + + if( !set ) { - JS_ReportError( context, "Not an array" ); + JS_ReportError( context, "Not a valid EntityCollection" ); + *vp = JSVAL_NULL; return( JS_TRUE ); } - jsuint selectionCount; - if( !JS_GetArrayLength( context, selectionArray, &selectionCount ) ) - { - JS_ReportError( context, "Not an array" ); - return( JS_TRUE ); - } - for( jsuint i = 0; i < selectionCount; i++ ) - { + + g_Selection.clearSelection(); + std::vector::iterator it; + + for( it = set->begin(); it < set->end(); it++ ) + g_Selection.addSelection( &(**it) ); +/* old-style load from array, here for reference jsval entry; JS_GetElement( context, selectionArray, i, &entry ); JSObject* selection = JSVAL_TO_OBJECT( entry ); @@ -82,10 +211,64 @@ JSBool JSI_Selection::setProperty( JSContext* context, JSObject* globalObject, j } else JS_ReportError( context, "[Entity] Invalid reference" ); - } +*/ + return( JS_TRUE ); } +JSBool JSI_Selection::getGroups( JSContext* context, JSObject* obj, jsval id, jsval* vp ) +{ + JSObject* groupsArray = JS_NewArrayObject( context, 0, NULL ); + + for( i8 groupId = 0; groupId < MAX_GROUPS; groupId++ ) + { + JSObject* group = JS_NewObject( context, &JSI_Selection::JSI_class, NULL, NULL ); + + std::vector* set = new std::vector; + std::vector::iterator it; + + for( it = g_Selection.m_groups[groupId].begin(); it < g_Selection.m_groups[groupId].end(); it++ ) + set->push_back( (*it)->me ); + + JS_SetPrivate( context, group, set ); + + jsval v = OBJECT_TO_JSVAL( group ); + JS_SetElement( context, groupsArray, groupId, &v ); + } + + *vp = OBJECT_TO_JSVAL( groupsArray ); + return( JS_TRUE ); +} + +JSBool JSI_Selection::setGroups( JSContext* context, JSObject* obj, jsval id, jsval* vp ) +{ + JSObject* groupsArray; + if( !JSVAL_IS_OBJECT( *vp ) || !JS_IsArrayObject( context, groupsArray = JSVAL_TO_OBJECT( *vp ) ) ) + { + JS_ReportError( context, "Not a valid group array" ); + *vp = JSVAL_NULL; + return( JS_TRUE ); + } + for( i8 groupId = 0; groupId < MAX_GROUPS; groupId++ ) + { + jsval v; + if( JS_GetElement( context, groupsArray, groupId, &v ) && JSVAL_IS_OBJECT( v ) ) + { + JSObject* group = JSVAL_TO_OBJECT( v ); + std::vector* set = (std::vector*)JS_GetInstancePrivate( context, group, &JSI_Selection::JSI_class, NULL ); + if( set ) + { + g_Selection.m_groups[groupId].clear(); + std::vector::iterator it; + + for( it = set->begin(); it < set->end(); it++ ) + g_Selection.addToGroup( groupId, &(**it) ); + } + } + } + return( JS_TRUE ); + } + JSBool JSI_Selection::isValidContextOrder( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ) { assert( argc >= 1 ); diff --git a/source/ps/scripting/JSInterface_Selection.h b/source/ps/scripting/JSInterface_Selection.h index 220426c192..cd91f74d44 100755 --- a/source/ps/scripting/JSInterface_Selection.h +++ b/source/ps/scripting/JSInterface_Selection.h @@ -1,18 +1,32 @@ +// JSInterface_Selection.h +// +// The JavaScript wrapper around collections of entities +// (notably the selection and groups objects) + #include "scripting/ScriptingHost.h" #ifndef JSI_SELECTION_INCLUDED #define JSI_SELECTION_INCLUDED -namespace JSI_Selected -{ - JSBool getProperty( JSContext* context, JSObject* objt, jsval id, jsval* vp ); - JSBool setProperty( JSContext* context, JSObject* obj, jsval id, jsval* vp ); -}; - namespace JSI_Selection { - JSBool getProperty( JSContext* context, JSObject* obj, jsval id, jsval* vp ); - JSBool setProperty( JSContext* context, JSObject* obj, jsval id, jsval* vp ); + JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ); + extern JSClass JSI_class; + extern JSPropertySpec JSI_props[]; + extern JSFunctionSpec JSI_methods[]; + JSBool addProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool removeProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + + void init(); + void finalize( JSContext* cx, JSObject* obj ); + + JSBool getSelection( JSContext* context, JSObject* obj, jsval id, jsval* vp ); + JSBool setSelection( JSContext* context, JSObject* obj, jsval id, jsval* vp ); + JSBool getGroups( JSContext* context, JSObject* obj, jsval id, jsval* vp ); + JSBool setGroups( JSContext* context, JSObject* obj, jsval id, jsval* vp ); + JSBool isValidContextOrder( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); JSBool getContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp ); JSBool setContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp ); diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 77ca6c4d77..bdc7d703fd 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -14,6 +14,8 @@ #include "scripting/JSInterface_Vector3D.h" #include "gui/scripting/JSInterface_IGUIObject.h" #include "scripting/JSInterface_Selection.h" +#include "scripting/JSInterface_Camera.h" +#include "scripting/JSInterface_Console.h" extern CConsole* g_Console; @@ -27,8 +29,8 @@ extern CConsole* g_Console; JSFunctionSpec ScriptFunctionTable[] = { - {"WriteLog", WriteLog, 1, 0, 0}, - {"writeConsole", writeConsole, 1, 0, 0 }, + {"writeLog", WriteLog, 1, 0, 0}, + {"writeConsole", JSI_Console::writeConsole, 1, 0, 0 }, // Keep this variant available for now. {"getEntityByHandle", getEntityByHandle, 1, 0, 0 }, {"getEntityTemplate", getEntityTemplate, 1, 0, 0 }, {"setTimeout", setTimeout, 2, 0, 0 }, @@ -45,14 +47,18 @@ JSFunctionSpec ScriptFunctionTable[] = enum ScriptGlobalTinyIDs { - GLOBAL_SELECTED, - GLOBAL_SELECTIONARRAY + GLOBAL_SELECTION, + GLOBAL_GROUPSARRAY, + GLOBAL_CAMERA, + GLOBAL_CONSOLE, }; JSPropertySpec ScriptGlobalTable[] = { - { "selected", GLOBAL_SELECTED, JSPROP_PERMANENT, JSI_Selected::getProperty, JSI_Selected::setProperty }, - { "selection", GLOBAL_SELECTIONARRAY, JSPROP_PERMANENT, JSI_Selection::getProperty, JSI_Selection::setProperty }, + { "selection", GLOBAL_SELECTION, JSPROP_PERMANENT, JSI_Selection::getSelection, JSI_Selection::setSelection }, + { "groups", GLOBAL_GROUPSARRAY, JSPROP_PERMANENT, JSI_Selection::getGroups, JSI_Selection::setGroups }, + { "camera", GLOBAL_CAMERA, JSPROP_PERMANENT, JSI_Camera::getCamera, JSI_Camera::setCamera }, + { "console", GLOBAL_CONSOLE, JSPROP_PERMANENT | JSPROP_READONLY, JSI_Console::getConsole, NULL }, { 0, 0, 0, 0, 0 }, }; @@ -62,40 +68,28 @@ JSBool WriteLog(JSContext* context, JSObject* UNUSEDPARAM(globalObject), unsigne if (argc < 1) return JS_FALSE; + CStr logMessage; + for (int i = 0; i < (int)argc; i++) { - if (JSVAL_IS_INT(argv[i])) + try { - printf("%d", JSVAL_TO_INT(argv[i])); + CStr arg = g_ScriptingHost.ValueToString( argv[i] ); + logMessage += arg; } - - if (JSVAL_IS_DOUBLE(argv[i])) + catch( PSERROR_Scripting_ConversionFailed ) { - double d = g_ScriptingHost.ValueToDouble(argv[i]); - printf("%e", d); - } - - if (JSVAL_IS_STRING(argv[i])) - { - JSString * str = JS_ValueToString(context, argv[i]); - char * chars = JS_GetStringBytes(str); - printf(chars); + // Do nothing. } } - printf("\n"); + // We should perhaps unicodify (?) the logger at some point. + + LOG( NORMAL, logMessage ); return JS_TRUE; } -JSBool writeConsole( JSContext* UNUSEDPARAM(context), JSObject* UNUSEDPARAM(globalObject), unsigned int argc, jsval* argv, jsval* UNUSEDPARAM(rval) ) -{ - assert( argc >= 1 ); - CStr output = g_ScriptingHost.ValueToString( argv[0] ); - g_Console->InsertMessage( L"%hs", (const char*)output ); - return( JS_TRUE ); -} - JSBool getEntityByHandle( JSContext* context, JSObject* UNUSEDPARAM(globalObject), unsigned int argc, jsval* argv, jsval* rval ) { assert( argc >= 1 ); @@ -126,10 +120,10 @@ JSBool getEntityByHandle( JSContext* context, JSObject* UNUSEDPARAM(globalObject JSBool getEntityTemplate( JSContext* context, JSObject* UNUSEDPARAM(globalObject), unsigned int argc, jsval* argv, jsval* rval ) { assert( argc >= 1 ); - CStr templateName; + CStrW templateName; try { - templateName = g_ScriptingHost.ValueToString( argv[0] ); + templateName = g_ScriptingHost.ValueToUCString( argv[0] ); } catch( PSERROR_Scripting_ConversionFailed ) { @@ -141,7 +135,7 @@ JSBool getEntityTemplate( JSContext* context, JSObject* UNUSEDPARAM(globalObject if( !v ) { *rval = JSVAL_NULL; - JS_ReportError( context, "No such template: %s", (const char*)templateName ); + JS_ReportError( context, "No such template: %ls", (const wchar_t*)templateName ); return( JS_TRUE ); } JSObject* baseEntity = JS_NewObject( context, &JSI_BaseEntity::JSI_class, NULL, NULL ); diff --git a/source/scripting/ScriptGlue.h b/source/scripting/ScriptGlue.h index be6ab28801..9ed6e118e0 100755 --- a/source/scripting/ScriptGlue.h +++ b/source/scripting/ScriptGlue.h @@ -7,7 +7,6 @@ // Functions to be called from Javascript: JSBool WriteLog(JSContext * context, JSObject * globalObject, unsigned int argc, jsval *argv, jsval *rval); -JSBool writeConsole( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval ); JSBool getEntityByHandle( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval ); JSBool getEntityTemplate( JSContext* context, JSObject* globalObject, unsigned int argc, jsval* argv, jsval* rval ); diff --git a/source/scripting/ScriptingHost.h b/source/scripting/ScriptingHost.h index 3a58c96675..a4d51e90ee 100755 --- a/source/scripting/ScriptingHost.h +++ b/source/scripting/ScriptingHost.h @@ -75,7 +75,6 @@ private: JSErrorReport m_ErrorReport; - //std::vector < DelayedScriptExecutor > m_DelayedScripts; std::map < std::string, CustomType > m_CustomObjectTypes; void _CollectGarbage(); @@ -85,6 +84,8 @@ public: ScriptingHost(); ~ScriptingHost(); + // Helpers: + JSContext* getContext(); void LoadScriptFromDisk(const std::string & fileName); @@ -114,14 +115,6 @@ public: CStrW ValueToUCString( const jsval value ); double ValueToDouble(const jsval value); - /* - All herald the new way of doing this! - - void Tick(float timeElapsed); - - void AddDelayedScript(const std::string & functionName, float delaySeconds); - */ - static void ErrorReporter(JSContext * context, const char * message, JSErrorReport * report); }; diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index a9d91be7b6..1f978b8afd 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -9,10 +9,10 @@ CBaseEntity::CBaseEntity() { m_base = NULL; - m_base.associate( this, "super" ); - m_name.associate( this, "name" ); - m_speed.associate( this, "speed" ); - m_turningRadius.associate( this, "turningRadius" ); + m_base.associate( this, L"super" ); + m_name.associate( this, L"name" ); + m_speed.associate( this, L"speed" ); + m_turningRadius.associate( this, L"turningRadius" ); m_bound_circle = NULL; m_bound_box = NULL; @@ -66,7 +66,7 @@ bool CBaseEntity::loadXML( CStr filename ) if (ChildName == el_name) { - m_name = (CStr)Child.getText(); + m_name = (CStrW)Child.getText(); } else if (ChildName == el_actor) { @@ -74,17 +74,17 @@ bool CBaseEntity::loadXML( CStr filename ) } else if (ChildName == el_speed) { - m_speed = CStr(Child.getText()).ToFloat(); + m_speed = CStrW(Child.getText()).ToFloat(); } else if (ChildName == el_turningradius) { - m_turningRadius = CStr(Child.getText()).ToFloat(); + m_turningRadius = CStrW(Child.getText()).ToFloat(); } else if (ChildName == el_size) { if( !m_bound_circle ) m_bound_circle = new CBoundingCircle(); - CStr radius (Child.getAttributes().getNamedItem(at_radius)); + CStrW radius (Child.getAttributes().getNamedItem(at_radius)); m_bound_circle->setRadius( radius.ToFloat() ); m_bound_type = CBoundingObject::BOUND_CIRCLE; } @@ -92,16 +92,16 @@ bool CBaseEntity::loadXML( CStr filename ) { if( !m_bound_box ) m_bound_box = new CBoundingBox(); - CStr width (Child.getAttributes().getNamedItem(at_width)); - CStr height (Child.getAttributes().getNamedItem(at_height)); + CStrW width (Child.getAttributes().getNamedItem(at_width)); + CStrW height (Child.getAttributes().getNamedItem(at_height)); m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() ); m_bound_type = CBoundingObject::BOUND_OABB; } else if (ChildName == el_graphicsoffset) { - CStr x (Child.getAttributes().getNamedItem(at_x)); - CStr y (Child.getAttributes().getNamedItem(at_y)); + CStrW x (Child.getAttributes().getNamedItem(at_x)); + CStrW y (Child.getAttributes().getNamedItem(at_y)); m_graphicsOffset.x = x.ToFloat(); m_graphicsOffset.y = y.ToFloat(); diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index 82dc7a48cd..a7479b4d48 100755 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -24,7 +24,7 @@ #include "EntityProperties.h" #include "BoundingObjects.h" -class CBaseEntity : public IPropertyOwner +class CBaseEntity : public IBoundPropertyOwner { public: CBaseEntity(); @@ -36,14 +36,14 @@ public: CObjectEntry* m_actorObject; - CProperty_CStr m_name; + CBoundObjectProperty m_name; CBoundingCircle* m_bound_circle; CBoundingBox* m_bound_box; CBoundingObject::EBoundingType m_bound_type; CVector2D m_graphicsOffset; - CProperty_float m_speed; - CProperty_float m_turningRadius; + CBoundProperty m_speed; + CBoundProperty m_turningRadius; }; #endif diff --git a/source/simulation/BaseEntityCollection.cpp b/source/simulation/BaseEntityCollection.cpp index 2fedc52be6..05ff5a0fe8 100755 --- a/source/simulation/BaseEntityCollection.cpp +++ b/source/simulation/BaseEntityCollection.cpp @@ -1,5 +1,3 @@ -// Last modified: May 15 2004, Mark Thompson (mark@wildfiregames.com) - #include "precompiled.h" #include "BaseEntityCollection.h" @@ -10,31 +8,50 @@ void CBaseEntityCollection::loadTemplates() { Handle handle; - vfsDirEnt dent; + vfsDirEnt type, file; - CStr pathname = "entities/templates/"; - handle=vfs_open_dir(pathname.c_str()); - if (handle > 0) + CStr basepath = "entities/"; + CStr pathname; + + // Iterate through all subdirectories + + Handle maindir = vfs_open_dir( basepath ); + + if( maindir > 0 ) { - while (vfs_next_dirent(handle, &dent, ".xml") == 0) + while( !vfs_next_dirent( maindir, &type, "/" ) ) { - CBaseEntity* newTemplate = new CBaseEntity(); - if( newTemplate->loadXML( pathname + dent.name ) ) + pathname = basepath + type.name; + + handle = vfs_open_dir( pathname ); + + pathname += "/"; + + if( handle > 0 ) { - addTemplate( newTemplate ); - LOG(NORMAL, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s%s\"", pathname.c_str(), dent.name); + while( !vfs_next_dirent(handle, &file, ".xml") ) + { + CBaseEntity* newTemplate = new CBaseEntity(); + if( newTemplate->loadXML( pathname + file.name ) ) + { + addTemplate( newTemplate ); + LOG(NORMAL, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s%s\"", pathname.c_str(), file.name); + } + else + LOG(ERROR, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s%s\"", pathname.c_str(), file.name); + } + vfs_close_dir( handle ); } else - LOG(ERROR, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s%s\"", pathname.c_str(), dent.name); - + { + LOG(ERROR, "CBaseEntityCollection::loadTemplates(): Failed to enumerate entity template directory"); + return; + } } - vfs_close_dir(handle); + vfs_close_dir( maindir ); } else - { - LOG(ERROR, "CBaseEntityCollection::loadTemplates(): Failed to enumerate entity template directory"); - return; - } + LOG(ERROR, "CBaseEntityCollection::loadTemplates(): Unable to open directory entities/"); } void CBaseEntityCollection::addTemplate( CBaseEntity* temp ) @@ -42,7 +59,7 @@ void CBaseEntityCollection::addTemplate( CBaseEntity* temp ) m_templates.push_back( temp ); } -CBaseEntity* CBaseEntityCollection::getTemplate( CStr name ) +CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name ) { for( u16 t = 0; t < m_templates.size(); t++ ) if( m_templates[t]->m_name == name ) return( m_templates[t] ); diff --git a/source/simulation/BaseEntityCollection.h b/source/simulation/BaseEntityCollection.h index 133c7067d8..66d1a4ccde 100755 --- a/source/simulation/BaseEntityCollection.h +++ b/source/simulation/BaseEntityCollection.h @@ -31,7 +31,7 @@ class CBaseEntityCollection : public Singleton std::vector m_templates; public: ~CBaseEntityCollection(); - CBaseEntity* getTemplate( CStr entityType ); + CBaseEntity* getTemplate( CStrW entityType ); void loadTemplates(); void addTemplate( CBaseEntity* temp ); CBaseEntity* getTemplateByActor( CObjectEntry* actor ); diff --git a/source/simulation/Collision.cpp b/source/simulation/Collision.cpp index ada13fe206..3a13cec3db 100755 --- a/source/simulation/Collision.cpp +++ b/source/simulation/Collision.cpp @@ -93,9 +93,8 @@ bool getRayIntersection( const CVector2D& source, const CVector2D& forward, cons { assert( (*it)->m_bounds ); if( (*it)->m_bounds == destinationCollisionObject ) continue; - // HACK: - // if( (*it)->m_bounds->m_type == CBoundingObject::BOUND_OABB ) continue; - if( (*it)->m_speed ) continue; + + if( (*it)->m_moving ) continue; CBoundingObject* obj = (*it)->m_bounds; delta = obj->m_pos - source; closestApproach = delta.dot( right ); diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 4c41f51fda..403d981a5a 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -24,19 +24,20 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) m_ahead.x = sin( m_orientation ); m_ahead.y = cos( m_orientation ); - m_base.associate( this, "template", ( void( IPropertyOwner::* )() )&CEntity::loadBase ); - m_name.associate( this, "name" ); - m_speed.associate( this, "speed" ); - m_selected.associate( this, "selected", ( void( IPropertyOwner::* )() )&CEntity::checkSelection ); - m_grouped_mirror.associate( this, "group", ( void( IPropertyOwner::* )() )&CEntity::checkGroup ); - m_extant_mirror.associate( this, "extant", ( void( IPropertyOwner::* )() )&CEntity::checkExtant ); - m_turningRadius.associate( this, "turningRadius" ); - m_graphics_position.associate( this, "position", ( void( IPropertyOwner::* )() )&CEntity::teleport ); - m_graphics_orientation.associate( this, "orientation", ( void( IPropertyOwner::* )() )&CEntity::reorient ); + m_base.associate( this, L"template", ( void( IBoundPropertyOwner::* )() )&CEntity::loadBase ); + m_name.associate( this, L"name" ); + m_speed.associate( this, L"speed" ); + m_selected.associate( this, L"selected", ( void( IBoundPropertyOwner::* )() )&CEntity::checkSelection ); + m_grouped.associate( this, L"group", ( void( IBoundPropertyOwner::* )() )&CEntity::checkGroup ); + m_extant_mirror.associate( this, L"extant", ( void( IBoundPropertyOwner::* )() )&CEntity::checkExtant ); + m_turningRadius.associate( this, L"turningRadius" ); + m_graphics_position.associate( this, L"position", ( void( IBoundPropertyOwner::* )() )&CEntity::teleport ); + m_graphics_orientation.associate( this, L"orientation", ( void( IBoundPropertyOwner::* )() )&CEntity::reorient ); // Set our parent unit and build us an actor. m_actor = NULL; m_bounds = NULL; + m_moving = false; m_base = base; @@ -57,8 +58,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) m_extant_mirror = true; m_selected = false; - m_grouped = 255; - m_grouped_mirror = 0; + m_grouped = -1; } CEntity::~CEntity() @@ -135,7 +135,7 @@ void CEntity::kill() bool isWaypoint( CEntity* e ) { - return( e->m_base->m_name == CStr( "Waypoint" ) ); + return( e->m_base->m_name == CStrW( L"House" ) ); } void CEntity::updateActorTransforms() @@ -186,8 +186,12 @@ void CEntity::update( size_t timestep ) assert( 0 && "Invalid entity order" ); } } - if( m_actor->GetModel()->GetAnimation() != m_actor->GetObject()->m_IdleAnim ) + + if( m_moving ) + { m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_IdleAnim ); + m_moving = false; + } } void CEntity::dispatch( const CMessage* msg ) @@ -197,7 +201,7 @@ void CEntity::dispatch( const CMessage* msg ) case CMessage::EMSG_TICK: break; case CMessage::EMSG_INIT: - if( m_base->m_name == CStr( "Prometheus Dude" ) ) + if( m_base->m_name == CStrW( L"Prometheus Dude" ) ) { if( getCollisionObject( this ) ) { @@ -303,19 +307,9 @@ void CEntity::checkSelection() void CEntity::checkGroup() { - if( m_grouped != m_grouped_mirror ) - { - if( ( m_grouped_mirror >= 0 ) && ( m_grouped_mirror <= 10 ) ) - { - u8 newgroup = m_grouped_mirror; - if( newgroup == 0 ) newgroup = 255; - if( newgroup == 10 ) newgroup = 0; - - g_Selection.changeGroup( this, newgroup ); - } - else - m_grouped_mirror = m_grouped; - } + g_Selection.changeGroup( this, -1 ); // Ungroup + if( ( m_grouped >= 0 ) && ( m_grouped < MAX_GROUPS ) ) + g_Selection.changeGroup( this, m_grouped ); } void CEntity::checkExtant() diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index 906c310a65..34668887ff 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -46,25 +46,24 @@ class CEntityManager; -class CEntity : public IPropertyOwner +class CEntity : public IBoundPropertyOwner { friend class CEntityManager; public: // Intrinsic properties - CProperty_CStr m_name; - CProperty_float m_speed; - CProperty_float m_turningRadius; - CProperty_bool m_selected; + CBoundObjectProperty m_name; + CBoundProperty m_speed; + CBoundProperty m_turningRadius; + CBoundProperty m_selected; + CBoundProperty m_grouped; bool m_extant; // Don't want JS to have direct write-access to these. (Things that should be done might not be) - CProperty_bool m_extant_mirror; // plus this way limits the number of nasty semantics to work around. - u8 m_grouped; - CProperty_i32 m_grouped_mirror; + CBoundProperty m_extant_mirror; // plus this way limits the number of nasty semantics to work around. //-- Interpolated property CVector3D m_position; CVector3D m_position_previous; - CProperty_CVector3D m_graphics_position; + CBoundObjectProperty m_graphics_position; CVector2D m_graphicsOffset; @@ -75,9 +74,10 @@ public: //-- Interpolated property float m_orientation; float m_orientation_previous; - CProperty_float m_graphics_orientation; + CBoundProperty m_graphics_orientation; CUnit* m_actor; + bool m_moving; std::deque m_orderQueue; diff --git a/source/simulation/EntityManager.cpp b/source/simulation/EntityManager.cpp index a99d71f6bb..fd091b8aad 100755 --- a/source/simulation/EntityManager.cpp +++ b/source/simulation/EntityManager.cpp @@ -38,7 +38,7 @@ HEntity CEntityManager::create( CBaseEntity* base, CVector3D position, float ori return( HEntity( m_nextalloc++ ) ); } -HEntity CEntityManager::create( CStr templatename, CVector3D position, float orientation ) +HEntity CEntityManager::create( CStrW templatename, CVector3D position, float orientation ) { CBaseEntity* templateobj = g_EntityTemplateCollection.getTemplate( templatename ); return( create( templateobj, position, orientation ) ); diff --git a/source/simulation/EntityManager.h b/source/simulation/EntityManager.h index 68f4f4de44..774fa3d272 100755 --- a/source/simulation/EntityManager.h +++ b/source/simulation/EntityManager.h @@ -42,7 +42,7 @@ public: CEntityManager(); ~CEntityManager(); HEntity create( CBaseEntity* base, CVector3D position, float orientation ); - HEntity create( CStr templatename, CVector3D position, float orientation ); + HEntity create( CStrW templatename, CVector3D position, float orientation ); HEntity* getByHandle( u16 index ); void updateAll( size_t timestep ); void interpolateAll( float relativeoffset ); diff --git a/source/simulation/EntityProperties.cpp b/source/simulation/EntityProperties.cpp index 4018612226..f37297d9bc 100755 --- a/source/simulation/EntityProperties.cpp +++ b/source/simulation/EntityProperties.cpp @@ -6,312 +6,124 @@ #undef new // to avoid confusing warnings -void CProperty::associate( IPropertyOwner* owner, const CStr& name ) +void IBoundProperty::associate( IBoundPropertyOwner* owner, const CStrW& name ) { m_owner = owner; owner->m_properties[name] = this; m_updateFn = NULL; } -void CProperty::associate( IPropertyOwner* owner, const CStr& name, void (IPropertyOwner::*updateFn)() ) +void IBoundProperty::associate( IBoundPropertyOwner* owner, const CStrW& name, void (IBoundPropertyOwner::*updateFn)() ) { m_owner = owner; owner->m_properties[name] = this; m_updateFn = updateFn; } -CProperty& CProperty::operator=( jsval value ) +void IBoundProperty::fromjsval( const jsval value ) { set( value ); - return( *this ); + if( m_updateFn ) + (m_owner->*m_updateFn)(); } -CProperty_i32::CProperty_i32() -{ - modifier = NULL; -} +// --- -CProperty_i32::~CProperty_i32() -{ - if( modifier ) - delete( modifier ); -} -CProperty_i32& CProperty_i32::operator =( i32 value ) -{ - if( !modifier ) - modifier = new SProperty_NumericModifier(); - *modifier = (float)value; - data = value; - return( *this ); -} -void CProperty_i32::set( jsval value ) +// --- + +void CBoundProperty::set( const jsval value ) { - if( !modifier ) - modifier = new SProperty_NumericModifier(); try { - *modifier = (float)g_ScriptingHost.ValueToInt( value ); - } - catch( PSERROR_Scripting_ConversionFailed ) - { - *modifier = 0; - } -} - -bool CProperty_i32::rebuild( CProperty* parent, bool triggerFn ) -{ - CProperty_i32* _parent = (CProperty_i32*)parent; - i32 newvalue = 0; - if( _parent ) - newvalue = *_parent; - if( modifier ) - { - newvalue = (i32)(newvalue * modifier->multiplicative); - newvalue += (i32)modifier->additive; - } - if( data == newvalue ) - return( false ); // No change. - data = newvalue; - if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); - return( true ); -} - -inline CProperty_i32::operator i32() -{ - return( data ); -} - -jsval CProperty_i32::tojsval() -{ - return( INT_TO_JSVAL( data ) ); -} - -CProperty_bool::CProperty_bool() -{ - modifier = NULL; -} - -CProperty_bool::~CProperty_bool() -{ - if( modifier ) - delete( modifier ); -} - -CProperty_bool& CProperty_bool::operator=( const bool value ) -{ - if( !modifier ) - modifier = new SProperty_BooleanModifier(); - *modifier = value; - data = value; - return( *this ); -} - -void CProperty_bool::set( jsval value ) -{ - if( !modifier ) - modifier = new SProperty_BooleanModifier(); - try - { - *modifier = g_ScriptingHost.ValueToBool( value ); + m_data = g_ScriptingHost.ValueToInt( value ); + m_inherited = false; } catch( ... ) { - *modifier = false; } } -bool CProperty_bool::rebuild( CProperty* parent, bool triggerFn ) +jsval CBoundProperty::tojsval() { - CProperty_bool* _parent = (CProperty_bool*)parent; - bool newvalue = false; - if( _parent ) - newvalue = *_parent; - if( modifier ) - newvalue = modifier->replacement; - if( data == newvalue ) - return( false ); // No change. - data = newvalue; - if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); - return( true ); + return( INT_TO_JSVAL( m_data ) ); } -inline CProperty_bool::operator bool() +void CBoundProperty::set( const jsval value ) { - return( data ); -} - -jsval CProperty_bool::tojsval() -{ - return( BOOLEAN_TO_JSVAL( data ) ); -} - -CProperty_float::CProperty_float() -{ - modifier = NULL; -} - -CProperty_float::~CProperty_float() -{ - if( modifier ) - delete modifier; -} - -CProperty_float& CProperty_float::operator =( const float& value ) -{ - if( !modifier ) - modifier = new SProperty_NumericModifier(); - *modifier = value; - data = value; - return( *this ); -} - -void CProperty_float::set( const jsval value ) -{ - if( !modifier ) - modifier = new SProperty_NumericModifier(); try { - *modifier = (float)g_ScriptingHost.ValueToDouble( value ); + m_data = g_ScriptingHost.ValueToBool( value ); + m_inherited = false; } - catch( PSERROR_Scripting_ConversionFailed ) + catch( ... ) { - *modifier = 0.0f; } } -bool CProperty_float::rebuild( CProperty* parent, bool triggerFn ) +jsval CBoundProperty::tojsval() { - CProperty_float* _parent = (CProperty_float*)parent; - float newvalue = 0; - if( _parent ) - newvalue = *_parent; - if( modifier ) - { - newvalue *= modifier->multiplicative; - newvalue += modifier->additive; - } - if( data == newvalue ) - return( false ); // No change. - data = newvalue; - if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); - return( true ); + return( BOOLEAN_TO_JSVAL( m_data ) ); } -CProperty_float::operator float() +void CBoundProperty::set( const jsval value ) { - return( data ); -} - -jsval CProperty_float::tojsval() -{ - return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), (jsdouble)data ) ) ); -} - -CProperty_float::operator bool() -{ - return( data != 0.0f); -} - -float CProperty_float::operator+( float value ) -{ - return( data + value ); -} - -float CProperty_float::operator-( float value ) -{ - return( data - value ); -} - -float CProperty_float::operator*( float value ) -{ - return( data * value ); -} - -float CProperty_float::operator/( float value ) -{ - return( data / value ); -} - -bool CProperty_float::operator<( float value ) -{ - return( data < value ); -} - -bool CProperty_float::operator>( float value ) -{ - return( data > value ); -} - -bool CProperty_float::operator==( float value ) -{ - return( data == value ); -} - -CProperty_CStr::CProperty_CStr() -{ - modifier = NULL; -} - -CProperty_CStr::~CProperty_CStr() -{ - if( modifier ) - delete( modifier ); -} - -CProperty_CStr& CProperty_CStr::operator=( const CStr& value ) -{ - if( !modifier ) - modifier = new SProperty_StringModifier(); - *modifier = value; - m_String = value; - return( *this ); -} - -void CProperty_CStr::set( jsval value ) -{ - if( !modifier ) - modifier = new SProperty_StringModifier(); try { - *modifier = g_ScriptingHost.ValueToString( value ); + m_data = (float)g_ScriptingHost.ValueToDouble( value ); + m_inherited = false; } - catch( PSERROR_Scripting_ConversionFailed ) + catch( ... ) { - *modifier = CStr(); - m_String.clear(); } } -bool CProperty_CStr::rebuild( CProperty* parent, bool triggerFn ) +jsval CBoundProperty::tojsval() { - CProperty_CStr* _parent = (CProperty_CStr*)parent; - CStr newvalue = ""; - if( _parent ) - newvalue = *_parent; - if( modifier ) - newvalue = modifier->replacement; - - if( *this == newvalue ) - return( false ); // No change. - m_String = newvalue; - if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); - return( true ); + return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), (jsdouble)m_data ) ) ); } -jsval CProperty_CStr::tojsval() +void CBoundObjectProperty::set( const jsval value ) +{ + try + { + m_String = g_ScriptingHost.ValueToString( value ); + m_inherited = false; + } + catch( ... ) + { + } +} + +jsval CBoundObjectProperty::tojsval() { return( STRING_TO_JSVAL( JS_NewStringCopyZ( g_ScriptingHost.getContext(), m_String.c_str() ) ) ); } -CProperty_CVector3D& CProperty_CVector3D::operator =( const CVector3D& value ) +void CBoundObjectProperty::set( const jsval value ) { - *( (CVector3D*)this ) = value; - return( *this ); + try + { + *this = g_ScriptingHost.ValueToUCString( value ); + m_inherited = false; + } + catch( ... ) + { + } } -void CProperty_CVector3D::set( jsval value ) +jsval CBoundObjectProperty::tojsval() +{ + return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( g_ScriptingHost.getContext(), m_String.c_str() ) ) ); +} + +CBoundObjectProperty::CBoundObjectProperty() +{ + m_inherited = false; +} + +void CBoundObjectProperty::set( const jsval value ) { JSObject* vector3d = JSVAL_TO_OBJECT( value ); JSI_Vector3D::Vector3D_Info* v = NULL; @@ -321,6 +133,7 @@ void CProperty_CVector3D::set( jsval value ) X = copy->X; Y = copy->Y; Z = copy->Z; + m_inherited = false; } else { @@ -328,75 +141,42 @@ void CProperty_CVector3D::set( jsval value ) } } -bool CProperty_CVector3D::rebuild( CProperty* parent, bool triggerFn ) -{ - if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); - return( false ); // Vector properties aren't inheritable. -} - -jsval CProperty_CVector3D::tojsval() +jsval CBoundObjectProperty::tojsval() { JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL ); JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( this, m_owner, m_updateFn ) ); return( OBJECT_TO_JSVAL( vector3d ) ); } -CProperty_CBaseEntityPtr& CProperty_CBaseEntityPtr::operator =( CBaseEntity* value ) +bool CBoundObjectProperty::rebuild( IBoundProperty* parent, bool triggerFn ) { - data = value; - return( *this ); + return( false ); } -void CProperty_CBaseEntityPtr::set( jsval value ) +void CBoundProperty::set( const jsval value ) { JSObject* baseEntity = JSVAL_TO_OBJECT( value ); CBaseEntity* base = NULL; if( JSVAL_IS_OBJECT( value ) && ( base = (CBaseEntity*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), baseEntity, &JSI_BaseEntity::JSI_class, NULL ) ) ) { - data = base; + m_data = base; } else JS_ReportError( g_ScriptingHost.getContext(), "[BaseEntity] Invalid reference" ); - } -bool CProperty_CBaseEntityPtr::rebuild( CProperty* parent, bool triggerFn ) -{ - if( triggerFn && m_updateFn ) (m_owner->*m_updateFn)(); - return( false ); // CBaseEntity* properties aren't inheritable. -} - -jsval CProperty_CBaseEntityPtr::tojsval() +jsval CBoundProperty::tojsval() { JSObject* baseEntity = JS_NewObject( g_ScriptingHost.getContext(), &JSI_BaseEntity::JSI_class, NULL, NULL ); - JS_SetPrivate( g_ScriptingHost.getContext(), baseEntity, data ); + JS_SetPrivate( g_ScriptingHost.getContext(), baseEntity, m_data ); return( OBJECT_TO_JSVAL( baseEntity ) ); } -CProperty_CBaseEntityPtr::operator bool() -{ - return( data != NULL ); -} -CProperty_CBaseEntityPtr::operator CBaseEntity*() +void IBoundPropertyOwner::rebuild( CStrW propertyName ) { - return( data ); -} - -CBaseEntity& CProperty_CBaseEntityPtr::operator *() const -{ - return( *data ); -} - -CBaseEntity* CProperty_CBaseEntityPtr::operator ->() const -{ - return( data ); -} - -void IPropertyOwner::rebuild( CStr propertyName ) -{ - CProperty* thisProperty = m_properties[propertyName]; - CProperty* baseProperty = NULL; + IBoundProperty* thisProperty = m_properties[propertyName]; + IBoundProperty* baseProperty = NULL; if( m_base ) { if( m_base->m_properties.find( propertyName ) != m_base->m_properties.end() ) @@ -404,20 +184,20 @@ void IPropertyOwner::rebuild( CStr propertyName ) } if( thisProperty->rebuild( baseProperty ) ) { - std::vector::iterator it; + std::vector::iterator it; for( it = m_inheritors.begin(); it != m_inheritors.end(); it++ ) (*it)->rebuild( propertyName ); } } -void IPropertyOwner::rebuild() +void IBoundPropertyOwner::rebuild() { - STL_HASH_MAP::iterator property; + STL_HASH_MAP::iterator property; if( m_base ) { for( property = m_properties.begin(); property != m_properties.end(); property++ ) { - CProperty* baseProperty = NULL; + IBoundProperty* baseProperty = NULL; if( m_base->m_properties.find( property->first ) != m_base->m_properties.end() ) baseProperty = m_base->m_properties[property->first]; (property->second)->rebuild( baseProperty, false ); @@ -429,7 +209,7 @@ void IPropertyOwner::rebuild() (property->second)->rebuild( NULL, false ); } - std::vector::iterator it; + std::vector::iterator it; for( it = m_inheritors.begin(); it != m_inheritors.end(); it++ ) (*it)->rebuild(); diff --git a/source/simulation/EntityProperties.h b/source/simulation/EntityProperties.h index 440d486541..8c48d2851b 100755 --- a/source/simulation/EntityProperties.h +++ b/source/simulation/EntityProperties.h @@ -4,8 +4,7 @@ // // Extended properties table, primarily intended for data-inheritable properties and those defined by JavaScript functions. // -// Usage: Nothing yet. -// These properties will be accessed via functions in CEntity/CBaseEntity +// Usage: These properties are accessed via functions in CEntity/CBaseEntity // // TODO: Fix the silent failures of the conversion functions: need to work out what to do in these cases. @@ -38,165 +37,128 @@ #endif -class IPropertyOwner; +class IBoundPropertyOwner; class CBaseEntity; -class CProperty; -struct SProperty_NumericModifier; -struct SProperty_StringModifier; -struct SProperty_BooleanModifier; +class CBoundPropertyModifier; -// Property abstract. +// Property interface -class CProperty +class IBoundProperty { protected: - IPropertyOwner* m_owner; - void (IPropertyOwner::*m_updateFn)(); + IBoundPropertyOwner* m_owner; + void (IBoundPropertyOwner::*m_updateFn)(); virtual void set( const jsval value ) = 0; public: - CProperty& operator=( const jsval value ); + void fromjsval( const jsval value ); virtual jsval tojsval() = 0; - virtual bool rebuild( CProperty* parent, bool triggerFn = true ) = 0; // Returns true if the rebuild changed the value of this property. - void associate( IPropertyOwner* owner, const CStr& name ); - void associate( IPropertyOwner* owner, const CStr& name, void (IPropertyOwner::*updateFn)() ); + virtual bool rebuild( IBoundProperty* parent, bool triggerFn = true ) = 0; // Returns true if the rebuild changed the value of this property. + void associate( IBoundPropertyOwner* owner, const CStrW& name ); + void associate( IBoundPropertyOwner* owner, const CStrW& name, void (IBoundPropertyOwner::*updateFn)() ); }; -// Integer specialization +// Specialize at least: +// - jsval conversion functions (set, tojsval) -class CProperty_i32 : public CProperty +// Generic primitive one: + +template class CBoundProperty : public IBoundProperty { - i32 data; - SProperty_NumericModifier* modifier; + T m_data; + bool m_inherited; + void (IBoundPropertyOwner::*m_updateFn)(); + public: - CProperty_i32(); - ~CProperty_i32(); + CBoundProperty() { m_inherited = true; } + CBoundProperty( const T& copy ) { m_inherited = false; m_data = copy; } + operator T&() { return( m_data ); } + operator const T&() const { return( m_data ); } + T& operator=( const T& copy ) { m_inherited = false; return( m_data = copy ); } + void set( const jsval value ); jsval tojsval(); - bool rebuild( CProperty* parent, bool triggerFn = true ); - CProperty_i32& operator=( const i32 value ); - operator i32(); + bool rebuild( IBoundProperty* parent, bool triggerFn = true ) + { + if( m_inherited && parent ) + { + *this = *( (CBoundProperty*)parent ); + if( triggerFn && m_updateFn ) + (m_owner->*m_updateFn)(); + } + return( !m_inherited ); + } }; -// Boolean specialization +// Generic class one: -class CProperty_bool : public CProperty +template class CBoundObjectProperty : public IBoundProperty, public T { - bool data; - SProperty_BooleanModifier* modifier; + bool m_inherited; + void (IBoundPropertyOwner::*m_updateFn)(); + public: - CProperty_bool(); - ~CProperty_bool(); + CBoundObjectProperty() { m_inherited = true; } + CBoundObjectProperty( const T& copy ) : T( copy ) { m_inherited = false; } + void set( const jsval value ); jsval tojsval(); - bool rebuild( CProperty* parent, bool triggerFn = true ); - CProperty_bool& operator=( const bool value ); - operator bool(); + bool rebuild( IBoundProperty* parent, bool triggerFn = true ) + { + if( m_inherited && parent ) + { + *this = *( (CBoundObjectProperty*)parent ); + if( triggerFn && m_updateFn ) + (m_owner->*m_updateFn)(); + } + return( !m_inherited ); + } }; -// Floating-point specialization +// And an explicit one: -class CProperty_float : public CProperty +template<> class CBoundProperty : public IBoundProperty { - float data; - SProperty_NumericModifier* modifier; + CBaseEntity* m_data; + void (IBoundPropertyOwner::*m_updateFn)(); + public: - CProperty_float(); - ~CProperty_float(); + CBoundProperty() { m_data = NULL; } + CBoundProperty( CBaseEntity* copy ) { m_data = copy; } + + operator CBaseEntity*&() { return( m_data ); } + operator CBaseEntity*() const { return( m_data ); } + CBaseEntity*& operator=( CBaseEntity* copy ) { return( m_data = copy ); } + +// Standard pointerish things + + CBaseEntity& operator*() { return( *m_data ); } + CBaseEntity* operator->() { return( m_data ); } + + /* + CBoundProperty( uintptr_t ptr ) { m_data = (CBaseEntity*)ptr; } + CBaseEntity*& operator=( uintptr_t ptr ) { m_data = (CBaseEntity*)ptr; } + operator uintptr_t() { return( (uintptr_t)m_data ); } + */ + void set( const jsval value ); jsval tojsval(); - bool rebuild( CProperty* parent, bool triggerFn = true ); - CProperty_float& operator=( const float& value ); - operator float(); - operator bool(); - float operator+( float value ); - float operator-( float value ); - float operator*( float value ); - float operator/( float value ); - bool operator<( float value ); - bool operator>( float value ); - bool operator==( float value ); -}; - -// String specialization - -class CProperty_CStr : public CProperty, public CStr -{ - SProperty_StringModifier* modifier; -public: - CProperty_CStr(); - ~CProperty_CStr(); - void set( const jsval value ); - jsval tojsval(); - bool rebuild( CProperty* parent, bool triggerFn = true ); - CProperty_CStr& operator=( const CStr& value ); -}; - -// 3-Vector specialization - -class CProperty_CVector3D : public CProperty, public CVector3D -{ -public: - void set( const jsval value ); - jsval tojsval(); - bool rebuild( CProperty* parent, bool triggerFn = true ); - CProperty_CVector3D& operator=( const CVector3D& value ); -}; - -// CBaseEntity* specialization - -class CProperty_CBaseEntityPtr : public CProperty -{ - CBaseEntity* data; -public: - void set( const jsval value ); - jsval tojsval(); - bool rebuild( CProperty* parent, bool triggerFn = true ); - operator CBaseEntity*(); - operator bool(); - CBaseEntity& operator*() const; - CBaseEntity* operator->() const; - CProperty_CBaseEntityPtr& operator=( CBaseEntity* value ); + bool rebuild( IBoundProperty* parent, bool triggerFn = true ) + { + return( false ); // Can't inherit a CBaseEntity* + } }; // e.g. Entities and their templates. -class IPropertyOwner + +class IBoundPropertyOwner { public: - CProperty_CBaseEntityPtr m_base; - STL_HASH_MAP m_properties; - std::vector m_inheritors; - void rebuild( CStr propName ); // Recursively rebuild just the named property over the inheritance tree. + CBoundProperty m_base; + STL_HASH_MAP m_properties; + std::vector m_inheritors; + void rebuild( CStrW propName ); // Recursively rebuild just the named property over the inheritance tree. void rebuild(); // Recursively rebuild everything over the inheritance tree. }; -struct SProperty_NumericModifier -{ - float multiplicative; - float additive; - void operator=( float value ) - { - multiplicative = 0.0f; - additive = value; - } -}; - -struct SProperty_StringModifier -{ - CStr replacement; - void operator=( const CStr& value ) - { - replacement = value; - } -}; - -struct SProperty_BooleanModifier -{ - bool replacement; - void operator=( const bool value ) - { - replacement = value; - } -}; - #endif diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index eecaea200b..287d4e2f63 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -21,8 +21,6 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli float len = delta.length(); - // ... 'Are we there yet?' ... - if( len < 0.1f ) { if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION ) @@ -37,8 +35,31 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli // Curve smoothing. // Here there be trig. - if( current->m_type != CEntityOrder::ORDER_GOTO_SMOOTHED ) + float scale = m_speed * timestep; + + // Note: Easy optimization: flag somewhere that this unit + // is already pointing the right way, and don't do this + // trig every time. + + 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; + + if( fabs( deltatheta ) > 0.01f ) { + float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep; + if( deltatheta > 0 ) + { + m_orientation = m_orientation + MIN( deltatheta, maxTurningSpeed ); + } + else + m_orientation = m_orientation + MAX( deltatheta, -maxTurningSpeed ); + + m_ahead.x = sin( m_orientation ); + m_ahead.y = cos( m_orientation ); + // We can only really attempt to smooth paths the pathfinder // has flagged for us. If the turning-radius calculations are // applied to other types of waypoint, wierdness happens. @@ -48,43 +69,28 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli // 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. + + // So, as a compromise for the look of the thing, we'll just turn in + // place until we're looking the right way. At least, that's what + // seems logical. But in most cases that looks worse. So actually, + // let's not. - m_ahead = delta / len; - m_orientation = atan2( m_ahead.x, m_ahead.y ); + + if( current->m_type != CEntityOrder::ORDER_GOTO_SMOOTHED ) + m_orientation = m_targetorientation; + } else { - 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; - - if( fabs( deltatheta ) > 0.01f ) - { - float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep; - if( deltatheta > 0 ) - { - m_orientation = m_orientation + MIN( deltatheta, maxTurningSpeed ); - } - else - m_orientation = m_orientation + MAX( deltatheta, -maxTurningSpeed ); - - m_ahead.x = sin( m_orientation ); - m_ahead.y = cos( m_orientation ); - } - else - { - m_ahead = delta / len; - m_orientation = atan2( m_ahead.x, m_ahead.y ); - } + m_ahead = delta / len; + m_orientation = m_targetorientation; } + + if( m_bounds->m_type == CBoundingObject::BOUND_OABB ) ((CBoundingBox*)m_bounds)->setOrientation( m_ahead ); - float scale = m_speed * timestep; - if( scale > len ) scale = len; @@ -138,8 +144,8 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli // 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 r = interval, theta = 0.0f, delta; float _x = current->m_data[0].location.x, _y = current->m_data[0].location.y; while( true ) @@ -152,8 +158,8 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli } // Reset our destination - current->m_data[0].location.x = _x; - current->m_data[0].location.y = _y; + current->m_data[0].location.x = _x + r * cosf( theta ); + current->m_data[0].location.y = _y + r * sinf( theta ); return( false ); } @@ -201,9 +207,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli 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 ); + // (No destination should be off the map) // Just stop here, repath if necessary. @@ -227,15 +231,17 @@ bool CEntity::processGoto( CEntityOrder* current, size_t timestep_millis ) if( ( path_to - pos ).length() < 0.1f ) return( false ); - if( m_actor->GetModel()->GetAnimation() != m_actor->GetObject()->m_WalkAnim ) + if( !m_moving ) { m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim ); m_actor->GetModel()->Update( ( rand() * 1000.0f ) / 1000.0f ); + m_moving = true; } // The pathfinder will push its result back into this unit's queue. g_Pathfinder.requestPath( me, path_to ); + return( true ); } diff --git a/source/simulation/scripting/JSInterface_BaseEntity.cpp b/source/simulation/scripting/JSInterface_BaseEntity.cpp index 212d8359e7..41aa859213 100755 --- a/source/simulation/scripting/JSInterface_BaseEntity.cpp +++ b/source/simulation/scripting/JSInterface_BaseEntity.cpp @@ -27,7 +27,7 @@ JSFunctionSpec JSI_BaseEntity::JSI_methods[] = JSBool JSI_BaseEntity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { CBaseEntity* e = (CBaseEntity*)JS_GetPrivate( cx, obj ); - CStr propName = g_ScriptingHost.ValueToString( id ); + CStrW propName = g_ScriptingHost.ValueToUCString( id ); if( e->m_properties.find( propName ) != e->m_properties.end() ) { @@ -35,7 +35,7 @@ JSBool JSI_BaseEntity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsva return( JS_TRUE ); } else - JS_ReportError( cx, "No such property on %s: %s", (const char*)e->m_name, (const char*)propName ); + JS_ReportError( cx, "No such property on %ls: %ls", (const wchar_t*)e->m_name, (const wchar_t*)propName ); return( JS_TRUE ); } @@ -43,16 +43,16 @@ JSBool JSI_BaseEntity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsva JSBool JSI_BaseEntity::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { CBaseEntity* e = (CBaseEntity*)JS_GetPrivate( cx, obj ); - CStr propName = g_ScriptingHost.ValueToString( id ); + CStrW propName = g_ScriptingHost.ValueToUCString( id ); if( e->m_properties.find( propName ) != e->m_properties.end() ) { - *(e->m_properties[propName]) = *vp; + e->m_properties[propName]->fromjsval( *vp ); e->rebuild( propName ); return( JS_TRUE ); } else - JS_ReportError( cx, "No such property on %s: %s", (const char*)e->m_name, (const char*)propName ); + JS_ReportError( cx, "No such property on %ls: %ls", (const wchar_t*)e->m_name, (const wchar_t*)propName ); return( JS_TRUE ); } @@ -67,7 +67,7 @@ JSBool JSI_BaseEntity::toString( JSContext* cx, JSObject* obj, uintN UNUSEDPARAM CBaseEntity* e = (CBaseEntity*)JS_GetPrivate( cx, obj ); char buffer[256]; - snprintf( buffer, 256, "[object EntityTemplate: %s]", (const TCHAR*)e->m_name ); + snprintf( buffer, 256, "[object EntityTemplate: %ls]", (const wchar_t*)e->m_name ); buffer[255] = 0; *rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) ); return( JS_TRUE ); diff --git a/source/simulation/scripting/JSInterface_BaseEntity.h b/source/simulation/scripting/JSInterface_BaseEntity.h index f1098ef75a..f6f4a2379d 100755 --- a/source/simulation/scripting/JSInterface_BaseEntity.h +++ b/source/simulation/scripting/JSInterface_BaseEntity.h @@ -1,6 +1,4 @@ // JSInterface_BaseEntity.h -// -// Last modified: 08 June 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com // // An interface between CBaseEntity and the JavaScript class EntityTemplate // diff --git a/source/simulation/scripting/JSInterface_Entity.cpp b/source/simulation/scripting/JSInterface_Entity.cpp index 5fa0addd9a..9c3b4ba972 100755 --- a/source/simulation/scripting/JSInterface_Entity.cpp +++ b/source/simulation/scripting/JSInterface_Entity.cpp @@ -37,7 +37,7 @@ JSBool JSI_Entity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* v *vp = JSVAL_NULL; return( JS_TRUE ); } - CStr propName = g_ScriptingHost.ValueToString( id ); + CStrW propName = g_ScriptingHost.ValueToUCString( id ); if( (*e)->m_properties.find( propName ) != (*e)->m_properties.end() ) { @@ -45,40 +45,40 @@ JSBool JSI_Entity::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* v return( JS_TRUE ); } else - JS_ReportError( cx, "No such property on %s: %s", (const char*)((*e)->m_name), (const char*)propName ); + JS_ReportError( cx, "No such property on %ls: %ls", (const wchar_t*)((*e)->m_name), (const wchar_t*)propName ); return( JS_TRUE ); } JSBool JSI_Entity::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ) { HEntity* e = (HEntity*)JS_GetPrivate( cx, obj ); - CStr propName = g_ScriptingHost.ValueToString( id ); + CStrW propName = g_ScriptingHost.ValueToUCString( id ); if( (*e)->m_properties.find( propName ) != (*e)->m_properties.end() ) { - *((*e)->m_properties[propName]) = *vp; + (*e)->m_properties[propName]->fromjsval( *vp ); (*e)->rebuild( propName ); return( JS_TRUE ); } else - JS_ReportError( cx, "No such property on %s: %s", (const char*)((*e)->m_name), (const char*)propName ); + JS_ReportError( cx, "No such property on %ls: %ls", (const wchar_t*)((*e)->m_name), (const wchar_t*)propName ); return( JS_TRUE ); } -JSBool JSI_Entity::construct( JSContext* cx, JSObject* UNUSEDPARAM(obj), unsigned int argc, jsval* argv, jsval* rval ) +JSBool JSI_Entity::construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ) { assert( argc >= 2 ); CBaseEntity* baseEntity = NULL; CVector3D position; float orientation = 0.0f; JSObject* jsBaseEntity = JSVAL_TO_OBJECT( argv[0] ); - CStr templateName; + CStrW templateName; if( !JSVAL_IS_OBJECT( argv[0] ) || !( baseEntity = (CBaseEntity*)JS_GetInstancePrivate( cx, jsBaseEntity, &JSI_BaseEntity::JSI_class, NULL ) ) ) { try { - templateName = g_ScriptingHost.ValueToString( argv[0] ); + templateName = g_ScriptingHost.ValueToUCString( argv[0] ); } catch( PSERROR_Scripting_ConversionFailed ) { @@ -91,7 +91,7 @@ JSBool JSI_Entity::construct( JSContext* cx, JSObject* UNUSEDPARAM(obj), unsigne if( !baseEntity ) { *rval = JSVAL_NULL; - JS_ReportError( cx, "No such template: %s", (const char*)templateName ); + JS_ReportError( cx, "No such template: %ls", (const wchar_t*)templateName ); return( JS_TRUE ); } JSI_Vector3D::Vector3D_Info* jsVector3D = NULL; @@ -107,6 +107,7 @@ JSBool JSI_Entity::construct( JSContext* cx, JSObject* UNUSEDPARAM(obj), unsigne } catch( PSERROR_Scripting_ConversionFailed ) { + // TODO: Net-safe random for this parameter. orientation = 0.0f; } } @@ -134,9 +135,9 @@ JSBool JSI_Entity::toString( JSContext* cx, JSObject* obj, uintN argc, jsval* ar { HEntity* e = (HEntity*)JS_GetPrivate( cx, obj ); - char buffer[256]; - snprintf( buffer, 256, "[object Entity: \"%s\" (%s)]", (const TCHAR*)(*e)->m_name, (const TCHAR*)(*e)->m_base->m_name ); + wchar_t buffer[256]; + _snwprintf( buffer, 256, L"[object Entity: \"%ls\" (%ls)]", (const wchar_t*)(*e)->m_name, (const wchar_t*)(*e)->m_base->m_name ); buffer[255] = 0; - *rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) ); + *rval = STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, buffer ) ); return( JS_TRUE ); } diff --git a/source/simulation/scripting/JSInterface_Entity.h b/source/simulation/scripting/JSInterface_Entity.h index 0c5b535c09..c16c86ac38 100755 --- a/source/simulation/scripting/JSInterface_Entity.h +++ b/source/simulation/scripting/JSInterface_Entity.h @@ -1,7 +1,5 @@ // JSInterface_Entity.h // -// Last modified: 03 June 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com -// // The interface layer between JavaScript code and the actual CEntity object. // // Usage: Used when manipulating objects of class 'Entity' in JavaScript. @@ -19,8 +17,6 @@ namespace JSI_Entity extern JSClass JSI_class; extern JSPropertySpec JSI_props[]; extern JSFunctionSpec JSI_methods[]; - JSBool addProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); - JSBool delProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); JSBool construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); diff --git a/source/workspaces/premake/premake.lua b/source/workspaces/premake/premake.lua index 173ebb67a4..6c0928d9e0 100755 --- a/source/workspaces/premake/premake.lua +++ b/source/workspaces/premake/premake.lua @@ -36,6 +36,7 @@ package.files = { -- graphics/ { sourcesfromdirs( "../../graphics") }, + { sourcesfromdirs( "../../graphics/scripting" ) }, -- maths/ { sourcesfromdirs( "../../maths") },