# Updates to the order system, including shift-click queueing.

This was SVN commit r4240.
This commit is contained in:
Matei 2006-08-25 04:24:06 +00:00
parent 01b02d145d
commit 6732af1ba9
11 changed files with 80 additions and 47 deletions

View File

@ -430,8 +430,8 @@ void CGameView::Update(float DeltaTime)
{
if(!m_TrackManager.Update(DeltaTime))
ResetCamera();
return;
}
return;
}
float delta = powf( m_ViewSnapSmoothness, DeltaTime );

View File

@ -620,3 +620,9 @@ bool keyRespondsTo( int hotkey, int sdlkey )
return true;
return false;
}
// Returns true if one of the key combinations for the given hotkey is pressed
bool isKeyDown( const CStr& keyname )
{
return hotkeys[getKeyCode(keyname)];
}

View File

@ -1382,6 +1382,7 @@ void CBuildingPlacer::mouseReleased()
{
// issue a place object command accross the network
CPlaceObject *msg = new CPlaceObject();
msg->m_IsQueued = hotkeys[HOTKEY_ORDER_QUEUE];
msg->m_Entities = g_Selection.m_selected;
msg->m_Template = m_templateName;
msg->m_X = (u32) (clickPos.X * 1000);

View File

@ -288,6 +288,7 @@ void initKeyNameMap()
SKeycodeMapping* it = keycodeMapping;
while( it->keycode != 0 )
{
debug_printf("adding key %s\n", it->keyname);
keymap.insert( std::pair<CStr,int>( CStr( it->keyname ).LowerCase(), it->keycode ) );
if( it->altkeyname )
keymap.insert( std::pair<CStr,int>( CStr( it->altkeyname ).LowerCase(), it->keycode ) );

View File

@ -210,6 +210,7 @@ END_NMT_CLASS()
START_NMT_CLASS(CNetCommand, NMT_NONE)
NMT_FIELD(CEntityList, m_Entities)
NMT_FIELD_INT(m_IsQueued, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(NetCommand, Goto)

View File

@ -89,7 +89,7 @@ void CNetMessage::ScriptingInit()
def(NMT_FormationGeneric);
}
CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSContext *cx, uintN argc, jsval *argv)
CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSContext *cx, uintN argc, jsval *argv, bool isQueued)
{
debug_assert(argc >= 1);
@ -160,6 +160,7 @@ CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSConte
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_IsQueued = isQueued; \
msg->m_Entities = entities; \
ReadPosition(msg, m_Target); \
return msg; \
@ -169,6 +170,7 @@ CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSConte
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_IsQueued = isQueued; \
msg->m_Entities = entities; \
ReadEntity(msg, m_Target); \
return msg; \
@ -178,6 +180,7 @@ CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSConte
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_IsQueued = isQueued; \
msg->m_Entities = entities; \
ReadEntity(msg, m_Target); \
ReadInt(msg, m_Action); \
@ -188,6 +191,7 @@ CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSConte
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_IsQueued = isQueued; \
msg->m_Entities = entities; \
ReadInt(msg, m_Type); \
ReadString(msg, m_Name); \
@ -198,6 +202,7 @@ CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSConte
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_IsQueued = isQueued; \
msg->m_Entities = entities; \
ReadString(msg, m_Template); \
ReadInt(msg, m_X); \

View File

@ -74,7 +74,7 @@ public:
*/
static void ScriptingInit();
static CNetCommand *CommandFromJSArgs(const CEntityList &entities, JSContext* cx, uintN argc, jsval* argv);
static CNetCommand *CommandFromJSArgs(const CEntityList &entities, JSContext* cx, uintN argc, jsval* argv, bool isQueued);
//These can create a net message without JS args
static CNetMessage *CreatePositionMessage( const CEntityList& entities, const int type, CVector2D pos );

View File

@ -26,6 +26,7 @@
#include "ps/Network/Client.h"
#include "ps/Network/Server.h"
#include "ps/i18n.h"
#include "ps/Hotkey.h"
#include "ps/scripting/JSCollection.h"
#include "ps/scripting/JSInterface_Console.h"
#include "ps/scripting/JSInterface_Selection.h"
@ -206,10 +207,10 @@ void CreateFormationMessage( std::vector<CNetMessage*>& msgList, CNetMessage* ms
// returns: command in serialized form [string]
JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval )
{
// at least one for target object, and then 1 or more for the CommandFromJSArgs
JSU_REQUIRE_MIN_PARAMS(2);
// at least one for target object, one for isQueued, and then 1 or more for the CommandFromJSArgs
JSU_REQUIRE_MIN_PARAMS(3);
debug_assert(JSVAL_IS_OBJECT(argv[0]));
JSU_ASSERT(JSVAL_IS_OBJECT(argv[0]), "Argument 0 must be an entity collection.");
*rval = JSVAL_NULL;
CEntityList entities, msgEntities;
@ -221,6 +222,8 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
msgEntities = entities;
std::map<int, CEntityList> entityStore;
bool isQueued = ToPrimitive<bool>(argv[1]);
//Destroy old notifiers if we're explicitly being reassigned
for ( size_t i=0; i < entities.size(); i++)
@ -248,7 +251,7 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
else
msgEntities.push_back( entities[i] );
}
CNetMessage* msg = CNetMessage::CommandFromJSArgs(msgEntities, cx, argc-1, argv+1);
CNetMessage* msg = CNetMessage::CommandFromJSArgs(msgEntities, cx, argc-2, argv+2, isQueued);
if (!msg)
{
delete msg;
@ -310,6 +313,17 @@ JSBool isFormationLocked( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval
*rval = entity->GetFormation()->IsLocked() ? JS_TRUE : JS_FALSE;
return JS_TRUE;
}
// Get the state of a given hotkey (from the hotkeys file)
JSBool isOrderQueued( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_NO_PARAMS();
*rval = ToJSVal(hotkeys[HOTKEY_ORDER_QUEUE]);
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// Techs
//-----------------------------------------------------------------------------
@ -1364,6 +1378,7 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC(setCursor, setCursor, 1)
JS_FUNC(getCursorName, getCursorName, 0)
JS_FUNC(getFPS, getFPS, 0)
JS_FUNC(isOrderQueued, isOrderQueued, 1)
// Miscellany
JS_FUNC(v3dist, v3dist, 2)

View File

@ -91,7 +91,7 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
float len = delta.length();
if( len < 0.1f )
if( len < 0.01f )
return( ALREADY_AT_DESTINATION );
// Curve smoothing.
@ -271,7 +271,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli
case COLLISION_OVERLAPPING_OBJECTS:
return( false );
case COLLISION_WITH_DESTINATION:
// We're here...
// We're as close as we can get...
m_orderQueue.pop_front();
//entf_clear(ENTF_IS_RUNNING);
//entf_clear(ENTF_SHOULD_RUN);

View File

@ -24,7 +24,7 @@ void CPathfindEngine::requestPath( HEntity entity, const CVector2D& destination
entity->m_orderQueue.push_front( waypoint );
}
void CPathfindEngine::requestLowLevelPath( HEntity entity, const CVector2D& destination, bool contact, float radius )
void CPathfindEngine::requestLowLevelPath( HEntity entity, const CVector2D& destination, bool UNUSED(contact), float radius )
{
PROFILE_START("Pathfinding");
@ -35,45 +35,42 @@ void CPathfindEngine::requestLowLevelPath( HEntity entity, const CVector2D& dest
std::vector<CVector2D> path = mLowPathfinder.getLastPath();
if( path.size() > 0 )
{
std::vector<CVector2D>::iterator it;
// Push the path onto the front of our order queue in reverse order,
// so that we run through it before continuing other orders.
CEntityOrder node;
for( it = path.begin(); (it+1) != path.end(); it++ )
{
if ( !contact )
{
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
}
else
{
// TODO: Is this right?
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
}
node.m_data[0].location = *it;
entity->m_orderQueue.push_back(node);
}
// Hack to make pathfinding slightly more precise:
// If the radius was 0, make the final node be exactly at the destination
// (otherwise, go to wherever the pathfinder tells us since we just want to be in range)
CVector2D finalDest = (radius==0 ? destination : (*it));
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
CVector2D finalDest = (radius==0 ? destination : path[path.size()-1]);
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER; // push end marker (used as a sentinel when repathing)
node.m_data[0].location = finalDest;
entity->m_orderQueue.push_back(node);
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
entity->m_orderQueue.push_front(node);
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING; // push final goto step
node.m_data[0].location = finalDest;
entity->m_orderQueue.push_back(node);
entity->m_orderQueue.push_front(node);
for( int i = ((int) path.size()) - 2; i >= 0; i-- )
{
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING; // TODO: For non-contact paths, do we want some other order type?
node.m_data[0].location = path[i];
entity->m_orderQueue.push_front(node);
}
}
else {
// Hack to make pathfinding slightly more precise:
// If radius = 0, we are still moving within the same tile, so add a GOTO order anyway
// If radius = 0, we have an empty path but the user still wants us to move
// within the same tile, so add a GOTO order anyway
if(radius == 0)
{
CEntityOrder node;
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
node.m_data[0].location = destination;
entity->m_orderQueue.push_back(node);
node.m_type = CEntityOrder::ORDER_PATH_END_MARKER;
node.m_data[0].location = destination;
entity->m_orderQueue.push_back(node);
entity->m_orderQueue.push_front(node);
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
node.m_data[0].location = destination;
entity->m_orderQueue.push_front(node);
}
}
}

View File

@ -148,7 +148,7 @@ void CSimulation::Simulate()
// Task them all to a point within a radius of the target, radius depends upon
// the number of units in the group.
void RandomizeLocations(CEntityOrder order, const vector <HEntity> &entities, bool clearQueue)
void RandomizeLocations(CEntityOrder order, const vector <HEntity> &entities, bool isQueued)
{
vector<HEntity>::const_iterator it;
float radius = 2.0f * sqrt( (float)entities.size() - 1 );
@ -181,14 +181,14 @@ void RandomizeLocations(CEntityOrder order, const vector <HEntity> &entities, bo
if( randomizedOrder.m_data[0].location.y >= mapsize )
randomizedOrder.m_data[0].location.y = mapsize;
if( clearQueue )
if( !isQueued )
(*it)->clearOrders();
(*it)->pushOrder( randomizedOrder );
}
}
void FormationLocations(CEntityOrder order, const vector <HEntity> &entities, bool clearQueue)
void FormationLocations(CEntityOrder order, const vector <HEntity> &entities, bool isQueued)
{
CVector2D upvec(0.0f, 1.0f);
vector<HEntity>::const_iterator it = entities.begin();
@ -223,20 +223,20 @@ void FormationLocations(CEntityOrder order, const vector <HEntity> &entities, bo
if( orderCopy.m_data[0].location.y >= mapsize )
orderCopy.m_data[0].location.y = mapsize;
if( clearQueue )
if( !isQueued )
(*it)->clearOrders();
(*it)->pushOrder( orderCopy );
}
}
void QueueOrder(CEntityOrder order, const vector <HEntity> &entities, bool clearQueue)
void QueueOrder(CEntityOrder order, const vector <HEntity> &entities, bool isQueued)
{
vector<HEntity>::const_iterator it;
for (it = entities.begin(); it < entities.end(); it++)
{
if( clearQueue )
if( !isQueued )
(*it)->clearOrders();
(*it)->pushOrder( order );
@ -246,46 +246,51 @@ void QueueOrder(CEntityOrder order, const vector <HEntity> &entities, bool clear
uint CSimulation::TranslateMessage(CNetMessage* pMsg, uint clientMask, void* UNUSED(userdata))
{
CEntityOrder order;
bool clearQueue = true;
bool isQueued = true;
#define ENTITY_POSITION(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].location.x=(float)msg->m_TargetX; \
order.m_data[0].location.y=(float)msg->m_TargetY; \
RandomizeLocations(order, msg->m_Entities, clearQueue); \
RandomizeLocations(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_POSITION_FORM(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].location.x=(float)msg->m_TargetX; \
order.m_data[0].location.y=(float)msg->m_TargetY; \
FormationLocations(order, msg->m_Entities, clearQueue); \
FormationLocations(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_ENTITY(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].entity=msg->m_Target; \
QueueOrder(order, msg->m_Entities, clearQueue); \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_ENTITY_INT(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].entity=msg->m_Target; \
order.m_data[1].data=msg->m_Action; \
QueueOrder(order, msg->m_Entities, clearQueue); \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_INT_STRING(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].string=msg->m_Name; \
order.m_data[1].data=msg->m_Type; \
QueueOrder(order, msg->m_Entities, clearQueue); \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
switch (pMsg->GetType())
@ -293,6 +298,7 @@ uint CSimulation::TranslateMessage(CNetMessage* pMsg, uint clientMask, void* UNU
case NMT_AddWaypoint:
{
CAddWaypoint *msg=(CAddWaypoint *)pMsg;
isQueued = msg->m_IsQueued != 0;
order.m_type=CEntityOrder::ORDER_LAST;
order.m_data[0].location.x=(float)msg->m_TargetX;
order.m_data[0].location.y=(float)msg->m_TargetY;
@ -351,6 +357,7 @@ uint CSimulation::TranslateMessage(CNetMessage* pMsg, uint clientMask, void* UNU
case NMT_PlaceObject:
{
CPlaceObject *msg = (CPlaceObject *) pMsg;
isQueued = msg->m_IsQueued != 0;
// Figure out the player
CPlayer* player = 0;