2004-05-22 01:46:16 +02:00
|
|
|
// Last modified: May 15 2004, Mark Thompson (mark@wildfiregames.com)
|
|
|
|
|
2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
#include "Entity.h"
|
|
|
|
#include "EntityManager.h"
|
|
|
|
#include "BaseEntityCollection.h"
|
|
|
|
|
2004-05-26 22:57:25 +02:00
|
|
|
#include "Renderer.h"
|
|
|
|
#include "Model.h"
|
|
|
|
#include "Terrain.h"
|
2004-07-20 21:30:35 +02:00
|
|
|
#include "Interact.h"
|
2004-05-22 01:46:16 +02:00
|
|
|
|
2004-05-28 04:57:50 +02:00
|
|
|
#include "Collision.h"
|
2004-06-11 00:24:03 +02:00
|
|
|
#include "PathfindEngine.h"
|
2004-05-28 04:57:50 +02:00
|
|
|
|
2004-07-31 17:57:18 +02:00
|
|
|
#include "Game.h"
|
2004-07-20 21:30:35 +02:00
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
#include "scripting/JSInterface_Vector3D.h"
|
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
|
|
|
{
|
2004-06-11 00:24:03 +02:00
|
|
|
m_position = position;
|
|
|
|
m_orientation = orientation;
|
2004-07-23 12:56:52 +02:00
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
m_ahead.x = sin( m_orientation );
|
|
|
|
m_ahead.y = cos( m_orientation );
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
AddProperty( L"template", (CBaseEntity**)&m_base, false, (NotifyFn)loadBase );
|
|
|
|
AddProperty( L"actions.move.speed", &m_speed );
|
|
|
|
AddProperty( L"selected", &m_selected, false, (NotifyFn)checkSelection );
|
|
|
|
AddProperty( L"group", &m_grouped, false, (NotifyFn)checkGroup );
|
|
|
|
AddProperty( L"extant", &m_extant, false, (NotifyFn)checkExtant );
|
|
|
|
AddProperty( L"actions.move.turningradius", &m_turningRadius );
|
|
|
|
AddProperty( L"position", &m_graphics_position, false, (NotifyFn)teleport );
|
|
|
|
AddProperty( L"orientation", &m_graphics_orientation, false, (NotifyFn)reorient );
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
|
|
|
|
for( int t = 0; t < EVENT_LAST; t++ )
|
|
|
|
AddProperty( EventNames[t], &m_EventHandlers[t] );
|
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
// Set our parent unit and build us an actor.
|
2004-06-11 00:24:03 +02:00
|
|
|
m_actor = NULL;
|
|
|
|
m_bounds = NULL;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2004-08-03 01:14:54 +02:00
|
|
|
m_moving = false;
|
2004-05-22 01:46:16 +02:00
|
|
|
|
|
|
|
m_base = base;
|
2004-06-11 00:24:03 +02:00
|
|
|
|
|
|
|
loadBase();
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2004-07-23 12:56:52 +02:00
|
|
|
if( m_bounds )
|
|
|
|
m_bounds->setPosition( m_position.X, m_position.Z );
|
2004-07-20 21:30:35 +02:00
|
|
|
|
2004-07-23 12:56:52 +02:00
|
|
|
m_position_previous = m_position;
|
|
|
|
m_orientation_previous = m_orientation;
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
m_graphics_position = m_position;
|
|
|
|
m_graphics_orientation = m_orientation;
|
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
m_extant = true;
|
|
|
|
m_extant_mirror = true;
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
m_selected = false;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2004-08-03 01:14:54 +02:00
|
|
|
m_grouped = -1;
|
2004-06-11 00:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CEntity::~CEntity()
|
|
|
|
{
|
|
|
|
if( m_actor )
|
|
|
|
{
|
|
|
|
g_UnitMan.RemoveUnit( m_actor );
|
|
|
|
delete( m_actor );
|
|
|
|
}
|
|
|
|
if( m_bounds ) delete( m_bounds );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::loadBase()
|
|
|
|
{
|
|
|
|
if( m_actor )
|
|
|
|
{
|
|
|
|
g_UnitMan.RemoveUnit( m_actor );
|
|
|
|
delete( m_actor );
|
|
|
|
}
|
|
|
|
if( m_bounds )
|
|
|
|
{
|
|
|
|
delete( m_bounds );
|
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
m_actor = new CUnit( m_base->m_actorObject, m_base->m_actorObject->m_Model->Clone(), this );
|
2004-06-03 04:20:48 +02:00
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
// Register the actor with the renderer.
|
|
|
|
|
|
|
|
g_UnitMan.AddUnit( m_actor );
|
|
|
|
|
|
|
|
// Set up our instance data
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
SetBase( m_base );
|
2004-07-23 12:56:52 +02:00
|
|
|
|
2004-05-26 22:57:25 +02:00
|
|
|
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
|
|
|
|
{
|
2004-06-03 04:20:48 +02:00
|
|
|
m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle );
|
2004-05-26 22:57:25 +02:00
|
|
|
}
|
|
|
|
else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB )
|
|
|
|
{
|
|
|
|
m_bounds = new CBoundingBox( m_position.X, m_position.Z, m_ahead, m_base->m_bound_box );
|
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
void CEntity::kill()
|
|
|
|
{
|
2004-10-07 21:23:35 +02:00
|
|
|
g_Selection.removeAll( me );
|
2004-07-21 14:29:32 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
if( m_bounds ) delete( m_bounds );
|
|
|
|
m_bounds = NULL;
|
|
|
|
|
|
|
|
m_extant = false;
|
|
|
|
m_extant_mirror = false;
|
|
|
|
|
|
|
|
if( m_actor )
|
|
|
|
{
|
|
|
|
g_UnitMan.RemoveUnit( m_actor );
|
|
|
|
delete( m_actor );
|
2004-07-21 14:29:32 +02:00
|
|
|
m_actor = NULL;
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
2004-07-21 14:29:32 +02:00
|
|
|
me = HEntity(); // will deallocate the entity, assuming nobody else has a reference to it
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
void CEntity::updateActorTransforms()
|
|
|
|
{
|
|
|
|
CMatrix3D m;
|
2004-05-26 22:57:25 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
float s = sin( m_graphics_orientation );
|
|
|
|
float c = cos( m_graphics_orientation );
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = m_graphics_position.X;
|
2004-07-20 21:30:35 +02:00
|
|
|
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = m_graphics_position.Y;
|
2004-10-07 21:23:35 +02:00
|
|
|
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = m_graphics_position.Z;
|
2004-07-20 21:30:35 +02:00
|
|
|
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
|
2004-05-26 22:57:25 +02:00
|
|
|
|
2004-05-29 22:58:11 +02:00
|
|
|
m_actor->GetModel()->SetTransform( m );
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::snapToGround()
|
|
|
|
{
|
2004-07-31 17:57:18 +02:00
|
|
|
CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
|
|
|
|
|
|
|
|
m_graphics_position.Y = pTerrain->getExactGroundLevel( m_graphics_position.X, m_graphics_position.Z );
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
2004-07-27 23:00:53 +02:00
|
|
|
void CEntity::update( size_t timestep )
|
2004-05-22 01:46:16 +02:00
|
|
|
{
|
2004-07-20 21:30:35 +02:00
|
|
|
m_position_previous = m_position;
|
|
|
|
m_orientation_previous = m_orientation;
|
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
while( !m_orderQueue.empty() )
|
|
|
|
{
|
|
|
|
CEntityOrder* current = &m_orderQueue.front();
|
|
|
|
|
|
|
|
switch( current->m_type )
|
|
|
|
{
|
|
|
|
case CEntityOrder::ORDER_GOTO_NOPATHING:
|
2004-05-26 22:57:25 +02:00
|
|
|
case CEntityOrder::ORDER_GOTO_COLLISION:
|
2004-06-03 04:20:48 +02:00
|
|
|
case CEntityOrder::ORDER_GOTO_SMOOTHED:
|
2004-05-28 04:57:50 +02:00
|
|
|
if( processGotoNoPathing( current, timestep ) ) break;
|
|
|
|
return;
|
2004-05-22 01:46:16 +02:00
|
|
|
case CEntityOrder::ORDER_GOTO:
|
2004-05-28 04:57:50 +02:00
|
|
|
if( processGoto( current, timestep ) ) break;
|
|
|
|
return;
|
2004-05-22 01:46:16 +02:00
|
|
|
case CEntityOrder::ORDER_PATROL:
|
2004-05-28 04:57:50 +02:00
|
|
|
if( processPatrol( current, timestep ) ) break;
|
|
|
|
return;
|
2004-05-22 01:46:16 +02:00
|
|
|
default:
|
|
|
|
assert( 0 && "Invalid entity order" );
|
|
|
|
}
|
|
|
|
}
|
2004-08-03 01:14:54 +02:00
|
|
|
|
|
|
|
if( m_moving )
|
|
|
|
{
|
2004-05-29 22:58:11 +02:00
|
|
|
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_IdleAnim );
|
2004-08-03 01:14:54 +02:00
|
|
|
m_moving = false;
|
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
void CEntity::dispatch( const CMessage* msg )
|
2004-05-22 01:46:16 +02:00
|
|
|
{
|
|
|
|
switch( msg->type )
|
|
|
|
{
|
|
|
|
case CMessage::EMSG_TICK:
|
2004-10-07 21:23:35 +02:00
|
|
|
m_EventHandlers[EVENT_TICK].Run( GetScript() );
|
2004-05-22 01:46:16 +02:00
|
|
|
break;
|
|
|
|
case CMessage::EMSG_INIT:
|
2004-10-07 21:23:35 +02:00
|
|
|
m_EventHandlers[EVENT_INITIALIZE].Run( GetScript() );
|
|
|
|
if( m_base->m_Tag == CStrW( L"Prometheus Dude" ) )
|
2004-05-22 01:46:16 +02:00
|
|
|
{
|
2004-05-29 05:32:33 +02:00
|
|
|
if( getCollisionObject( this ) )
|
|
|
|
{
|
|
|
|
// Prometheus telefragging. (Appeared inside another object)
|
2004-07-20 21:30:35 +02:00
|
|
|
kill();
|
2004-05-29 05:32:33 +02:00
|
|
|
return;
|
|
|
|
}
|
2004-10-07 21:23:35 +02:00
|
|
|
/*
|
2004-05-22 01:46:16 +02:00
|
|
|
std::vector<HEntity>* waypoints = g_EntityManager.matches( isWaypoint );
|
|
|
|
while( !waypoints->empty() )
|
|
|
|
{
|
|
|
|
CEntityOrder patrol;
|
2004-05-24 23:01:50 +02:00
|
|
|
size_t id = rand() % waypoints->size();
|
2004-05-22 01:46:16 +02:00
|
|
|
std::vector<HEntity>::iterator it = waypoints->begin();
|
|
|
|
it += id;
|
|
|
|
HEntity waypoint = *it;
|
|
|
|
patrol.m_type = CEntityOrder::ORDER_PATROL;
|
|
|
|
patrol.m_data[0].location.x = waypoint->m_position.X;
|
|
|
|
patrol.m_data[0].location.y = waypoint->m_position.Z;
|
|
|
|
pushOrder( patrol );
|
|
|
|
waypoints->erase( it );
|
|
|
|
}
|
2004-05-26 22:57:25 +02:00
|
|
|
delete( waypoints );
|
2004-10-07 21:23:35 +02:00
|
|
|
*/
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
break;
|
2004-07-20 21:30:35 +02:00
|
|
|
case CMessage::EMSG_ORDER:
|
|
|
|
CMessageOrder* m;
|
|
|
|
m = (CMessageOrder*)msg;
|
|
|
|
if( !m->queue )
|
|
|
|
clearOrders();
|
|
|
|
pushOrder( m->order );
|
|
|
|
break;
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
}
|
2004-07-20 21:30:35 +02:00
|
|
|
|
|
|
|
void CEntity::clearOrders()
|
|
|
|
{
|
|
|
|
m_orderQueue.clear();
|
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
|
|
|
|
void CEntity::pushOrder( CEntityOrder& order )
|
|
|
|
{
|
|
|
|
m_orderQueue.push_back( order );
|
|
|
|
}
|
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
bool CEntity::acceptsOrder( int orderType, CEntity* orderTarget )
|
|
|
|
{
|
|
|
|
// Hardcoding...
|
|
|
|
switch( orderType )
|
|
|
|
{
|
|
|
|
case CEntityOrder::ORDER_GOTO:
|
|
|
|
case CEntityOrder::ORDER_PATROL:
|
|
|
|
return( m_speed > 0.0f );
|
|
|
|
}
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
void CEntity::repath()
|
|
|
|
{
|
|
|
|
CVector2D destination;
|
|
|
|
if( m_orderQueue.empty() ) return;
|
|
|
|
|
|
|
|
while( !m_orderQueue.empty() &&
|
|
|
|
( ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
|
|
|
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
|
|
|
|
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_SMOOTHED ) ) )
|
|
|
|
{
|
|
|
|
destination = m_orderQueue.front().m_data[0].location;
|
|
|
|
m_orderQueue.pop_front();
|
|
|
|
}
|
|
|
|
g_Pathfinder.requestPath( me, destination );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::reorient()
|
|
|
|
{
|
2004-07-20 21:30:35 +02:00
|
|
|
m_orientation = m_graphics_orientation;
|
2004-06-11 00:24:03 +02:00
|
|
|
m_ahead.x = sin( m_orientation );
|
|
|
|
m_ahead.y = cos( m_orientation );
|
|
|
|
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
|
|
|
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
|
|
|
|
updateActorTransforms();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::teleport()
|
|
|
|
{
|
2004-07-20 21:30:35 +02:00
|
|
|
m_position = m_graphics_position;
|
2004-06-11 00:24:03 +02:00
|
|
|
m_bounds->setPosition( m_position.X, m_position.Z );
|
|
|
|
repath();
|
|
|
|
}
|
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
void CEntity::checkSelection()
|
|
|
|
{
|
|
|
|
if( m_selected )
|
|
|
|
{
|
2004-10-07 21:23:35 +02:00
|
|
|
if( !g_Selection.isSelected( me ) )
|
|
|
|
g_Selection.addSelection( me );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-10-07 21:23:35 +02:00
|
|
|
if( g_Selection.isSelected( me ) )
|
|
|
|
g_Selection.removeSelection( me );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::checkGroup()
|
2004-05-22 01:46:16 +02:00
|
|
|
{
|
2004-10-07 21:23:35 +02:00
|
|
|
g_Selection.changeGroup( me, -1 ); // Ungroup
|
2004-08-03 01:14:54 +02:00
|
|
|
if( ( m_grouped >= 0 ) && ( m_grouped < MAX_GROUPS ) )
|
2004-10-07 21:23:35 +02:00
|
|
|
g_Selection.changeGroup( me, m_grouped );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::checkExtant()
|
|
|
|
{
|
|
|
|
if( m_extant && !( (bool)m_extant_mirror ) )
|
|
|
|
kill();
|
|
|
|
// Sorry. Dead stuff stays dead.
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::interpolate( float relativeoffset )
|
|
|
|
{
|
|
|
|
m_graphics_position = Interpolate<CVector3D>( m_position_previous, m_position, relativeoffset );
|
2004-05-29 05:32:33 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
// Avoid wraparound glitches for interpolating angles.
|
|
|
|
while( m_orientation < m_orientation_previous - PI )
|
|
|
|
m_orientation_previous -= 2 * PI;
|
|
|
|
while( m_orientation > m_orientation_previous + PI )
|
|
|
|
m_orientation_previous += 2 * PI;
|
|
|
|
|
|
|
|
m_graphics_orientation = Interpolate<float>( m_orientation_previous, m_orientation, relativeoffset );
|
|
|
|
snapToGround();
|
|
|
|
updateActorTransforms();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CEntity::render()
|
|
|
|
{
|
2004-07-31 17:57:18 +02:00
|
|
|
CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
|
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
if( !m_orderQueue.empty() )
|
|
|
|
{
|
2004-06-03 04:20:48 +02:00
|
|
|
std::deque<CEntityOrder>::iterator it;
|
|
|
|
CBoundingObject* destinationCollisionObject;
|
|
|
|
float x0, y0, x, y;
|
|
|
|
|
|
|
|
x = m_orderQueue.front().m_data[0].location.x;
|
|
|
|
y = m_orderQueue.front().m_data[0].location.y;
|
|
|
|
|
|
|
|
for( it = m_orderQueue.begin(); it < m_orderQueue.end(); it++ )
|
|
|
|
{
|
|
|
|
if( it->m_type == CEntityOrder::ORDER_PATROL )
|
|
|
|
break;
|
|
|
|
x = it->m_data[0].location.x;
|
|
|
|
y = it->m_data[0].location.y;
|
|
|
|
}
|
|
|
|
destinationCollisionObject = getContainingObject( CVector2D( x, y ) );
|
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
glShadeModel( GL_FLAT );
|
|
|
|
glBegin( GL_LINE_STRIP );
|
|
|
|
|
2004-06-03 04:20:48 +02:00
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
|
2004-06-03 04:20:48 +02:00
|
|
|
glVertex3f( m_position.X, m_position.Y + 0.25f, m_position.Z );
|
2004-05-29 05:32:33 +02:00
|
|
|
|
2004-06-03 04:20:48 +02:00
|
|
|
|
|
|
|
x = m_position.X;
|
|
|
|
y = m_position.Z;
|
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
for( it = m_orderQueue.begin(); it < m_orderQueue.end(); it++ )
|
|
|
|
{
|
2004-06-03 04:20:48 +02:00
|
|
|
x0 = x; y0 = y;
|
|
|
|
x = it->m_data[0].location.x;
|
|
|
|
y = it->m_data[0].location.y;
|
|
|
|
rayIntersectionResults r;
|
|
|
|
CVector2D fwd( x - x0, y - y0 );
|
|
|
|
float l = fwd.length();
|
|
|
|
fwd = fwd.normalize();
|
|
|
|
CVector2D rgt = fwd.beta();
|
|
|
|
if( getRayIntersection( CVector2D( x0, y0 ), fwd, rgt, l, m_bounds->m_radius, destinationCollisionObject, &r ) )
|
|
|
|
{
|
|
|
|
glEnd();
|
|
|
|
glBegin( GL_LINES );
|
|
|
|
glColor3f( 1.0f, 0.0f, 0.0f );
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( x0 + fwd.x * r.distance, pTerrain->getExactGroundLevel( x0 + fwd.x * r.distance, y0 + fwd.y * r.distance ) + 0.25f, y0 + fwd.y * r.distance );
|
|
|
|
glVertex3f( r.position.x, pTerrain->getExactGroundLevel( r.position.x, r.position.y ) + 0.25f, r.position.y );
|
2004-06-03 04:20:48 +02:00
|
|
|
glEnd();
|
|
|
|
glBegin( GL_LINE_STRIP );
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( x0, pTerrain->getExactGroundLevel( x0, y0 ), y0 );
|
2004-06-03 04:20:48 +02:00
|
|
|
}
|
2004-05-29 05:32:33 +02:00
|
|
|
switch( it->m_type )
|
|
|
|
{
|
|
|
|
case CEntityOrder::ORDER_GOTO:
|
|
|
|
glColor3f( 1.0f, 0.0f, 0.0f ); break;
|
|
|
|
case CEntityOrder::ORDER_GOTO_COLLISION:
|
|
|
|
glColor3f( 1.0f, 0.5f, 0.5f ); break;
|
|
|
|
case CEntityOrder::ORDER_GOTO_NOPATHING:
|
2004-06-03 04:20:48 +02:00
|
|
|
case CEntityOrder::ORDER_GOTO_SMOOTHED:
|
2004-05-29 05:32:33 +02:00
|
|
|
glColor3f( 0.5f, 0.5f, 0.5f ); break;
|
2004-06-03 04:20:48 +02:00
|
|
|
case CEntityOrder::ORDER_PATROL:
|
|
|
|
glColor3f( 0.0f, 1.0f, 0.0f ); break;
|
2004-05-29 05:32:33 +02:00
|
|
|
default:
|
2004-06-03 04:20:48 +02:00
|
|
|
continue;
|
2004-05-29 05:32:33 +02:00
|
|
|
}
|
2004-06-03 04:20:48 +02:00
|
|
|
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( x, pTerrain->getExactGroundLevel( x, y ) + 0.25f, y );
|
2004-05-29 05:32:33 +02:00
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
glEnd();
|
|
|
|
glShadeModel( GL_SMOOTH );
|
|
|
|
}
|
|
|
|
|
2004-05-26 22:57:25 +02:00
|
|
|
glColor3f( 1.0f, 1.0f, 1.0f );
|
2004-05-28 04:57:50 +02:00
|
|
|
if( getCollisionObject( this ) ) glColor3f( 0.5f, 0.5f, 1.0f );
|
2004-07-31 17:57:18 +02:00
|
|
|
m_bounds->render( pTerrain->getExactGroundLevel( m_position.X, m_position.Z ) + 0.25f ); //m_position.Y + 0.25f );
|
2004-05-26 22:57:25 +02:00
|
|
|
}
|
2004-05-22 01:46:16 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
void CEntity::renderSelectionOutline( float alpha )
|
2004-05-26 22:57:25 +02:00
|
|
|
{
|
2004-07-31 17:57:18 +02:00
|
|
|
CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
|
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
if( !m_bounds ) return;
|
|
|
|
|
|
|
|
glColor4f( 1.0f, 1.0f, 1.0f, alpha );
|
2004-07-23 12:56:52 +02:00
|
|
|
if( getCollisionObject( this ) ) glColor4f( 1.0f, 0.5f, 0.5f, alpha );
|
2004-07-20 21:30:35 +02:00
|
|
|
|
|
|
|
glBegin( GL_LINE_LOOP );
|
|
|
|
|
|
|
|
CVector3D pos = m_graphics_position;
|
|
|
|
|
|
|
|
switch( m_bounds->m_type )
|
|
|
|
{
|
|
|
|
case CBoundingObject::BOUND_CIRCLE:
|
|
|
|
{
|
|
|
|
float radius = ((CBoundingCircle*)m_bounds)->m_radius;
|
|
|
|
for( int i = 0; i < SELECTION_CIRCLE_POINTS; i++ )
|
|
|
|
{
|
|
|
|
float ang = i * 2 * PI / (float)SELECTION_CIRCLE_POINTS;
|
|
|
|
float x = pos.X + radius * sin( ang );
|
|
|
|
float y = pos.Z + radius * cos( ang );
|
|
|
|
#ifdef SELECTION_TERRAIN_CONFORMANCE
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( x, pTerrain->getExactGroundLevel( x, y ) + 0.25f, y );
|
2004-07-20 21:30:35 +02:00
|
|
|
#else
|
|
|
|
glVertex3f( x, pos.Y + 0.25f, y );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBoundingObject::BOUND_OABB:
|
|
|
|
{
|
|
|
|
CVector2D p, q;
|
|
|
|
CVector2D u, v;
|
|
|
|
q.x = pos.X; q.y = pos.Z;
|
|
|
|
float h = ((CBoundingBox*)m_bounds)->m_h;
|
|
|
|
float w = ((CBoundingBox*)m_bounds)->m_w;
|
|
|
|
|
|
|
|
u.x = sin( m_graphics_orientation );
|
|
|
|
u.y = cos( m_graphics_orientation );
|
|
|
|
v.x = u.y;
|
|
|
|
v.y = -u.x;
|
|
|
|
|
|
|
|
#ifdef SELECTION_TERRAIN_CONFORMANCE
|
|
|
|
for( int i = SELECTION_BOX_POINTS; i > -SELECTION_BOX_POINTS; i-- )
|
|
|
|
{
|
|
|
|
p = q + u * h + v * ( w * (float)i / (float)SELECTION_BOX_POINTS );
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = SELECTION_BOX_POINTS; i > -SELECTION_BOX_POINTS; i-- )
|
|
|
|
{
|
|
|
|
p = q + u * ( h * (float)i / (float)SELECTION_BOX_POINTS ) - v * w;
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = -SELECTION_BOX_POINTS; i < SELECTION_BOX_POINTS; i++ )
|
|
|
|
{
|
|
|
|
p = q - u * h + v * ( w * (float)i / (float)SELECTION_BOX_POINTS );
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = -SELECTION_BOX_POINTS; i < SELECTION_BOX_POINTS; i++ )
|
|
|
|
{
|
|
|
|
p = q + u * ( h * (float)i / (float)SELECTION_BOX_POINTS ) + v * w;
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
2004-07-20 21:30:35 +02:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
p = q + u * h + v * w;
|
2004-07-31 17:57:18 +02:00
|
|
|
glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
2004-07-20 21:30:35 +02:00
|
|
|
|
|
|
|
p = q + u * h - v * w;
|
|
|
|
glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
|
|
|
|
|
|
|
p = q - u * h + v * w;
|
|
|
|
glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
|
|
|
|
|
|
|
p = q + u * h + v * w;
|
|
|
|
glVertex3f( p.x, getExactGroundLevel( p.x, p.y ) + 0.25f, p.y );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
|
2004-06-03 15:27:01 +02:00
|
|
|
}
|
2004-10-07 21:23:35 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Scripting interface
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Scripting initialization
|
|
|
|
|
|
|
|
void CEntity::ScriptingInit()
|
|
|
|
{
|
|
|
|
AddMethod<jsval, ToString>( "toString", 0 );
|
|
|
|
AddMethod<bool, OrderSingle>( "order", 1 );
|
|
|
|
AddMethod<bool, OrderQueued>( "orderQueued", 1 );
|
|
|
|
CJSObject<CEntity>::ScriptingInit( "Entity", Construct, 2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Script constructor
|
|
|
|
|
|
|
|
JSBool CEntity::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] );
|
|
|
|
CStrW templateName;
|
|
|
|
|
|
|
|
if( !JSVAL_IS_OBJECT( argv[0] ) || !( baseEntity = ToNative<CBaseEntity>( cx, jsBaseEntity ) ) )
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
templateName = g_ScriptingHost.ValueToUCString( argv[0] );
|
|
|
|
}
|
|
|
|
catch( PSERROR_Scripting_ConversionFailed )
|
|
|
|
{
|
|
|
|
*rval = JSVAL_NULL;
|
|
|
|
JS_ReportError( cx, "Invalid template identifier" );
|
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
baseEntity = g_EntityTemplateCollection.getTemplate( templateName );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !baseEntity )
|
|
|
|
{
|
|
|
|
*rval = JSVAL_NULL;
|
2004-10-07 22:02:58 +02:00
|
|
|
JS_ReportError( cx, "No such template: %s", CStr8(templateName).c_str() );
|
2004-10-07 21:23:35 +02:00
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
JSI_Vector3D::Vector3D_Info* jsVector3D = NULL;
|
|
|
|
if( JSVAL_IS_OBJECT( argv[1] ) && ( jsVector3D = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( argv[1] ), &JSI_Vector3D::JSI_class, NULL ) ) )
|
|
|
|
{
|
|
|
|
position = *( jsVector3D->vector );
|
|
|
|
}
|
|
|
|
if( argc >= 3 )
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
orientation = (float)g_ScriptingHost.ValueToDouble( argv[2] );
|
|
|
|
}
|
|
|
|
catch( PSERROR_Scripting_ConversionFailed )
|
|
|
|
{
|
|
|
|
// TODO: Net-safe random for this parameter.
|
|
|
|
orientation = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HEntity handle = g_EntityManager.create( baseEntity, position, orientation );
|
|
|
|
|
|
|
|
CMessage message( CMessage::EMSG_INIT );
|
|
|
|
handle->dispatch( &message );
|
|
|
|
|
|
|
|
*rval = ToJSVal<CEntity>( *handle );
|
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Script-bound methods
|
|
|
|
|
|
|
|
jsval CEntity::ToString( JSContext* cx, uintN argc, jsval* argv )
|
|
|
|
{
|
|
|
|
utf16_t buffer[256];
|
|
|
|
swprintf( buffer, 256, L"[object Entity: %ls]", m_base->m_Tag.c_str() );
|
|
|
|
buffer[255] = 0;
|
|
|
|
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( cx, buffer ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
|
|
|
|
{
|
|
|
|
// This needs to be sorted (uses Scheduler rather than network messaging)
|
|
|
|
assert( argc >= 1 );
|
|
|
|
|
|
|
|
int orderCode;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
orderCode = g_ScriptingHost.ValueToInt( argv[0] );
|
|
|
|
}
|
|
|
|
catch( PSERROR_Scripting_ConversionFailed )
|
|
|
|
{
|
|
|
|
JS_ReportError( cx, "Invalid order type" );
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
CEntityOrder newOrder;
|
|
|
|
|
|
|
|
(int&)newOrder.m_type = orderCode;
|
|
|
|
|
|
|
|
switch( orderCode )
|
|
|
|
{
|
|
|
|
case CEntityOrder::ORDER_GOTO:
|
|
|
|
case CEntityOrder::ORDER_PATROL:
|
|
|
|
if( argc < 3 )
|
|
|
|
{
|
|
|
|
JS_ReportError( cx, "Too few parameters" );
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
2004-10-07 22:02:58 +02:00
|
|
|
newOrder.m_data[0].location.x = (float)g_ScriptingHost.ValueToDouble( argv[1] );
|
|
|
|
newOrder.m_data[0].location.y = (float)g_ScriptingHost.ValueToDouble( argv[2] );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
|
|
|
catch( PSERROR_Scripting_ConversionFailed )
|
|
|
|
{
|
|
|
|
JS_ReportError( cx, "Invalid location" );
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
g_Scheduler.pushFrame( ORDER_DELAY, me, new CMessageOrder( newOrder, Queued ) );
|
|
|
|
return( true );
|
|
|
|
default:
|
|
|
|
JS_ReportError( cx, "Invalid order type" );
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
}
|
2004-07-20 21:30:35 +02:00
|
|
|
|