diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index a43b9e7f91..cdf06aabcb 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -112,6 +112,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) m_frameCheck = 0; m_lastCombatTime = 0; + m_currentNotification = 0; + m_currentListener = NULL; m_grouped = -1; @@ -623,24 +625,38 @@ void CEntity::clearOrders() void CEntity::pushOrder( CEntityOrder& order ) { - if( acceptsOrder( order.m_type, order.m_data[0].entity ) ) + //Replace acceptsOrder because we need the notification data after the order is pushed + CEventPrepareOrder evt( order.m_data[0].entity, order.m_type, order.m_data[1].data ); + if( DispatchEvent(&evt) ) { m_orderQueue.push_back( order ); + CheckListeners( evt.m_notifyType, evt.m_notifySource ); } } -bool CEntity::acceptsOrder( int orderType, CEntity* orderTarget ) +bool CEntity::acceptsOrder( int orderType, CEntity* orderTarget, int action ) { - CEventPrepareOrder evt( orderTarget, orderType ); - return( DispatchEvent( &evt ) ); + CEventPrepareOrder evt( orderTarget, orderType, action ); + return ( DispatchEvent(&evt) ); } -void CEntity::DispatchNotification( CEntityOrder order, uint type ) +void CEntity::DispatchNotification( CEntityOrder order, int type ) { CEventNotification evt( order, type ); DispatchEvent( &evt ); } +void CEntity::DestroyListeners( CEntity* target ) +{ + if (target->m_listeners.empty()) + return; + for ( size_t i=0; i < target->m_listeners.size(); i++) + { + if ( target->m_listeners[i].m_sender == this ) + target->m_listeners.erase(target->m_listeners.begin() + i); + } + +} void CEntity::repath() { @@ -1051,6 +1067,7 @@ void CEntity::ScriptingInit() AddMethod( "toString", 0 ); AddMethod( "order", 1 ); AddMethod( "orderQueued", 1 ); + AddMethod( "terminateOrder", 1 ); AddMethod( "kill", 0 ); AddMethod( "isIdle", 0 ); AddMethod( "hasClass", 1 ); @@ -1058,8 +1075,8 @@ void CEntity::ScriptingInit() AddMethod( "addAura", 3 ); AddMethod( "removeAura", 1 ); AddMethod( "setActionParams", 5 ); - AddMethod( "checkListeners", 1 ); - AddMethod( "requestNotification", 3 ); + AddMethod( "forceCheckListeners", 2 ); + AddMethod( "requestNotification", 3 ); AddMethod( "triggerRun", 1 ); AddMethod( "setRun", 1 ); AddMethod( "getRunState", 0 ); @@ -1192,6 +1209,13 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued ) } if ( orderCode == CEntityOrder::ORDER_RUN ) m_triggerRun = true; + //It's not a notification order + if ( argc == 3 ) + { + if ( m_currentListener ) + DestroyListeners( m_currentListener ); + m_currentListener = NULL; + } break; case CEntityOrder::ORDER_GENERIC: @@ -1216,6 +1240,13 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued ) JS_ReportError( cx, "Invalid generic order type" ); return( false ); } + //It's not a notification order + if ( argc == 3 ) + { + if ( m_currentListener ) + DestroyListeners( m_currentListener ); + m_currentListener = NULL; + } break; default: JS_ReportError( cx, "Invalid order type" ); @@ -1472,43 +1503,81 @@ jsval CEntity::SetActionParams( JSContext* UNUSED(cx), uintN argc, jsval* argv ) return JSVAL_VOID; } -jsval CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv ) +bool CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv ) { if( argc < 3 ) { JS_ReportError( cx, "Too few parameters" ); return( false ); } + CEntityListener notify; - notify.m_sender = this; //(Convert from int to enum) CEntity *target = ToNative( argv[0] ); - *( (uint*) &(notify.m_type) ) = ToPrimitive( argv[1] ); - - bool destroy = ToPrimitive( argv[2] ); - - std::deque::iterator it = target->m_listeners.begin(); - for ( ; it != target->m_listeners.end(); it++) - { - if ( destroy && it->m_sender == this ) - target->m_listeners.erase(it); - } + if (target == this) + return false; + *( (int*) &(notify.m_type) ) = ToPrimitive( argv[1] ); + + //Clean up old requests + if ( ToPrimitive( argv[2] ) && !target->m_listeners.empty() ) + DestroyListeners( target ); + + if ( target != m_currentListener && m_currentListener ) + DestroyListeners( m_currentListener ); + + m_currentListener = target; + + //If our target isn't stationary and it's doing something we want to follow, send notification + int result = target->m_currentNotification & notify.m_type; + if ( result && !target->m_orderQueue.empty() ) + { + CEntityOrder order = target->m_orderQueue.front(); + switch( result ) + { + case CEntityListener::NOTIFY_GOTO: + case CEntityListener::NOTIFY_RUN: + DispatchNotification( order, result ); + break; + + case CEntityListener::NOTIFY_HEAL: + case CEntityListener::NOTIFY_ATTACK: + case CEntityListener::NOTIFY_GATHER: + case CEntityListener::NOTIFY_DAMAGE: + if( argc < 2 ) + { + JS_ReportError( cx, "Too few parameters" ); + } + + DispatchNotification( order, result ); + break; + default: + JS_ReportError( cx, "Invalid order type" ); + break; + } + target->m_listeners.push_back( notify ); + return true; + } + target->m_listeners.push_back( notify ); - return JSVAL_VOID; + return false; } -jsval CEntity::CheckListeners( JSContext *cx, uintN argc, jsval* argv ) +bool CEntity::ForceCheckListeners( JSContext *cx, uintN argc, jsval* argv ) { - if( argc < 1 ) + if( argc < 2 ) { JS_ReportError( cx, "Too few parameters" ); - return( false ); + return false; } int type = ToPrimitive( argv[0] ); //notify code - CEntityOrder order = this->m_orderQueue.front(); - CEntity* target; + m_currentNotification = type; + + CEntity *target = ToNative( argv[1] ); + if ( target->m_orderQueue.empty() ) + return false; + CEntityOrder order = target->m_orderQueue.front(); for (size_t i=0; iDispatchNotification( order, result ); - break; - + case CEntityListener::NOTIFY_GOTO: + case CEntityListener::NOTIFY_RUN: case CEntityListener::NOTIFY_HEAL: case CEntityListener::NOTIFY_ATTACK: case CEntityListener::NOTIFY_GATHER: case CEntityListener::NOTIFY_DAMAGE: - if( argc < 2 ) - { - JS_ReportError( cx, "Too few parameters" ); - continue; - } - target = ToNative( argv[1] ); - order.m_data[0].entity = target->me; - - m_listeners[i].m_sender->DispatchNotification( order, result ); - break; + m_listeners[i].m_sender->DispatchNotification( order, result ); - default: + default: JS_ReportError( cx, "Invalid order type" ); continue; } } } - return JSVAL_VOID; + return true; +} +void CEntity::CheckListeners( int type, CEntity *target) +{ + m_currentNotification = type; + + debug_assert(target); + if ( target->m_orderQueue.empty() ) + return; + + CEntityOrder order = target->m_orderQueue.front(); + for (size_t i=0; iDispatchNotification( order, result ); + break; + default: + debug_warn("Invalid notification: CheckListeners()"); + continue; + } + } + } } jsval CEntity::TriggerRun( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index c5a417a347..bda819f6ed 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -174,6 +174,8 @@ public: std::deque m_orderQueue; std::deque m_listeners; + int m_currentNotification; + CEntity* m_currentListener; private: CEntity( CBaseEntity* base, CVector3D position, float orientation ); @@ -261,12 +263,13 @@ public: void checkExtant(); // Existence // Returns whether the entity is capable of performing the given orderType on the target. - bool acceptsOrder( int orderType, CEntity* orderTarget ); + bool acceptsOrder( int orderType, CEntity* orderTarget, int action ); void clearOrders(); void pushOrder( CEntityOrder& order ); - void DispatchNotification( CEntityOrder order,uint type ); + void DispatchNotification( CEntityOrder order, int type ); + void DestroyListeners( CEntity* target ); // Script constructor @@ -288,8 +291,10 @@ public: jsval IsRunning( JSContext* cx, uintN argc, jsval* argv ); jsval GetRunState( JSContext* cx, uintN argc, jsval* argv ); - jsval RequestNotification( JSContext* cx, uintN argc, jsval* argv ); - jsval CheckListeners( JSContext* cx, uintN argc, jsval* argv ); + bool RequestNotification( JSContext* cx, uintN argc, jsval* argv ); + //Just in case we want to explicitly check the listeners without waiting for the order to be pushed + bool ForceCheckListeners( JSContext* cx, uintN argc, jsval* argv ); + void CheckListeners( int type, CEntity *target ); bool Order( JSContext* cx, uintN argc, jsval* argv, bool Queued ); inline bool OrderSingle( JSContext* cx, uintN argc, jsval* argv ) @@ -311,6 +316,14 @@ public: debug_assert( argc >= 1 ); return( m_classes.IsMember( ToPrimitive( cx, argv[0] ) ) ); } + jsval TerminateOrder( JSContext* cx, uintN argc, jsval* argv ) + { + debug_assert( argc >= 1); + if ( ToPrimitive( argv[0] ) ) + m_orderQueue.clear(); + else + m_orderQueue.pop_front(); + } static void ScriptingInit(); diff --git a/source/simulation/EntityOrders.h b/source/simulation/EntityOrders.h index d0581b4c1c..9da8535074 100755 --- a/source/simulation/EntityOrders.h +++ b/source/simulation/EntityOrders.h @@ -85,6 +85,7 @@ public: ORDER_PATH_END_MARKER, ORDER_GENERIC, ORDER_GENERIC_NOPATHING, + ORDER_NOTIFY_REQUEST, ORDER_LAST } m_type; SOrderData m_data[ORDER_MAX_DATA]; diff --git a/source/simulation/EventHandlers.cpp b/source/simulation/EventHandlers.cpp index a55a84d58c..9de5fc8be1 100755 --- a/source/simulation/EventHandlers.cpp +++ b/source/simulation/EventHandlers.cpp @@ -39,12 +39,16 @@ CEventTargetChanged::CEventTargetChanged( CEntity* target ) : CScriptEvent( L"ta AddLocalProperty( L"secondaryAction", &m_secondaryAction ); } -CEventPrepareOrder::CEventPrepareOrder( CEntity* target, int orderType ) : CScriptEvent( L"prepareOrder", EVENT_PREPARE_ORDER, true ) +CEventPrepareOrder::CEventPrepareOrder( CEntity* target, int orderType, int action ) : CScriptEvent( L"prepareOrder", EVENT_PREPARE_ORDER, true ) { m_target = target; m_orderType = orderType; + m_action = action; AddLocalProperty( L"target", &m_target, true ); AddLocalProperty( L"orderType", &m_orderType, true ); + AddLocalProperty( L"action", &m_action ); + AddLocalProperty( L"notifyType", &m_notifyType ); + AddLocalProperty( L"notifySource", &m_notifySource ); } CEventOrderTransition::CEventOrderTransition( int orderPrevious, int orderCurrent, CEntity*& target, CVector3D& worldPosition ) : CScriptEvent( L"orderTransition", EVENT_ORDER_TRANSITION, true ) @@ -58,16 +62,14 @@ CEventOrderTransition::CEventOrderTransition( int orderPrevious, int orderCurren AddLocalProperty( L"target", m_target ); AddLocalProperty( L"position", m_worldPosition ); } -CEventNotification::CEventNotification( CEntityOrder order, uint type ) : CScriptEvent( L"notification", EVENT_NOTIFICATION, true ) +CEventNotification::CEventNotification( CEntityOrder order, int notifyType ) : CScriptEvent( L"notification", EVENT_NOTIFICATION, true ) { - m_type = type; + m_notifyType = notifyType; m_target = order.m_data[0].entity; - m_data = (uint) order.m_data[1].data; CVector3D convert( order.m_data[0].location.x, 0.0f, order.m_data[0].location.y ); m_location = convert; - AddLocalProperty( L"type", &m_type ); + AddLocalProperty( L"notifyType", &m_notifyType ); AddLocalProperty( L"target", &m_target ); - AddLocalProperty( L"data", &m_data ); AddLocalProperty( L"location", &m_location ); } diff --git a/source/simulation/EventHandlers.h b/source/simulation/EventHandlers.h index ec7835f411..76ddb6c9e4 100755 --- a/source/simulation/EventHandlers.h +++ b/source/simulation/EventHandlers.h @@ -47,7 +47,10 @@ class CEventPrepareOrder : public CScriptEvent CEntity* m_target; int m_orderType; public: - CEventPrepareOrder( CEntity* target, int orderType ); + CEntity* m_notifySource; + int m_notifyType; + int m_action; + CEventPrepareOrder( CEntity* target, int orderType, int action ); }; class CEventOrderTransition : public CScriptEvent @@ -63,11 +66,11 @@ class CEventNotification : public CScriptEvent { //Same as CEntityOrder data for support of all orders CEntity* m_target; - uint m_data; //u64 is unsupported...will this work? - uint m_type; + int m_action; //u64 is unsupported...will this work? + int m_notifyType; CVector3D m_location; //No real use for y, but CVector2D unsupported public: - CEventNotification( CEntityOrder order, uint type ); + CEventNotification( CEntityOrder order, int notifyType ); }; #endif diff --git a/source/simulation/Simulation.cpp b/source/simulation/Simulation.cpp index 7731392cbb..71bc460a8d 100755 --- a/source/simulation/Simulation.cpp +++ b/source/simulation/Simulation.cpp @@ -260,6 +260,9 @@ uint CSimulation::TranslateMessage(CNetMessage* pMsg, uint clientMask, void* UNU case NMT_Generic: ENTITY_ENTITY_INT(CGeneric, ORDER_GENERIC); break; + case NMT_NotifyRequest: + ENTITY_ENTITY_INT(CNotifyRequest, ORDER_NOTIFY_REQUEST); + break; } return clientMask;