Integrated medium cover activities into standoffs and beyond

This commit is contained in:
Blixibon 2021-10-27 23:49:22 -05:00
parent 833f0b0823
commit 26c05ee685
7 changed files with 284 additions and 52 deletions

View File

@ -6509,7 +6509,7 @@ CAI_BaseNPC *CAI_BaseNPC::CreateCustomTarget( const Vector &vecOrigin, float dur
//-----------------------------------------------------------------------------
Activity CAI_BaseNPC::TranslateCrouchActivity( Activity eNewActivity )
{
if (CapabilitiesGet() & bits_CAP_DUCK)
if (CapabilitiesGet() & bits_CAP_DUCK && CanTranslateCrouchActivity())
{
// ========================================================================
// The main issue with cover hint nodes is that crouch activities are not translated at the right time
@ -6541,10 +6541,18 @@ Activity CAI_BaseNPC::TranslateCrouchActivity( Activity eNewActivity )
CAI_Hint *pHint = GetHintNode();
if (pHint)
{
if (pHint->HintType() == HINT_TACTICAL_COVER_LOW || pHint->HintType() == HINT_TACTICAL_COVER_MED)
if (pHint->HintType() == HINT_TACTICAL_COVER_LOW)
{
nCoverActivity = ACT_RANGE_ATTACK1_LOW;
}
else if (pHint->HintType() == HINT_TACTICAL_COVER_MED)
{
#ifdef EXPANDED_HL2_COVER_ACTIVITIES
nCoverActivity = ACT_RANGE_ATTACK1_MED;
#else
nCoverActivity = ACT_RANGE_ATTACK1_LOW;
#endif
}
}
}
}
@ -6586,21 +6594,30 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity )
//if (eNewActivity == ACT_DROP_WEAPON)
// return TranslateActivity(ACT_IDLE);
// ---------------------------------------------
// Accounts for certain act busy activities that aren't on all NPCs.
if (eNewActivity == ACT_BUSY_QUEUE || eNewActivity == ACT_BUSY_STAND)
return TranslateActivity(ACT_IDLE);
// ---------------------------------------------
if (eNewActivity == ACT_WALK_ANGRY)
return TranslateActivity(ACT_WALK);
// ---------------------------------------------
// If one climbing animation isn't available, use the other
if (eNewActivity == ACT_CLIMB_DOWN)
return ACT_CLIMB_UP;
else if (eNewActivity == ACT_CLIMB_UP)
return ACT_CLIMB_DOWN;
// GetCoverActivity() should have this covered.
// ---------------------------------------------
if (eNewActivity == ACT_COVER_MED)
eNewActivity = ACT_COVER_LOW;
//if (eNewActivity == ACT_COVER)
// return TranslateActivity(ACT_IDLE);
@ -9137,27 +9154,45 @@ Activity CAI_BaseNPC::GetCoverActivity( CAI_Hint *pHint )
switch (pHint->HintType())
{
case HINT_TACTICAL_COVER_MED:
#ifndef MAPBASE // I know what you're thinking, but ACT_COVER_MED is pretty much deprecated at this point anyway.
{
nCoverActivity = ACT_COVER_MED;
#ifdef MAPBASE
// Some NPCs lack ACT_COVER_MED, but could easily use ACT_COVER_LOW.
if (SelectWeightedSequence(nCoverActivity) == ACTIVITY_NOT_AVAILABLE)
nCoverActivity = ACT_COVER_LOW;
#endif
// NPCs which lack ACT_COVER_MED should fall through to HINT_TACTICAL_COVER_LOW
if (SelectWeightedSequence( ACT_COVER_MED ) != ACTIVITY_NOT_AVAILABLE)
{
nCoverActivity = ACT_COVER_MED;
}
#else
nCoverActivity = ACT_COVER_MED;
break;
}
#endif
}
case HINT_TACTICAL_COVER_LOW:
{
#ifdef MAPBASE
if (pHint->HintActivityName() != NULL_STRING)
nCoverActivity = (Activity)CAI_BaseNPC::GetActivityID( STRING(pHint->HintActivityName()) );
else
#endif
// Make sure nCoverActivity wasn't already assigned above, then fall through to HINT_TACTICAL_COVER_CUSTOM
if (nCoverActivity == ACT_INVALID)
nCoverActivity = ACT_COVER_LOW;
#else
nCoverActivity = ACT_COVER_LOW;
break;
#endif
}
#ifdef MAPBASE
case HINT_TACTICAL_COVER_CUSTOM:
{
if (pHint->HintActivityName() != NULL_STRING)
{
nCoverActivity = (Activity)CAI_BaseNPC::GetActivityID( STRING(pHint->HintActivityName()) );
if (nCoverActivity == ACT_INVALID)
{
m_iszSceneCustomMoveSeq = pHint->HintActivityName();
nCoverActivity = ACT_SCRIPT_CUSTOM_MOVE;
}
}
break;
}
#endif
}
}
@ -15985,6 +16020,26 @@ bool CAI_BaseNPC::CouldShootIfCrouching( CBaseEntity *pTarget )
return bResult;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Check if this position will block our line of sight if aiming low.
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::CouldShootIfCrouchingAt( const Vector &vecPosition, const Vector &vecForward, const Vector &vecRight, float flDist )
{
Vector vGunPos = vecPosition;
vGunPos += (GetCrouchGunOffset() + vecRight * 8);
trace_t tr;
AI_TraceLOS( vGunPos, vGunPos + (vecForward * flDist), this, &tr );
if (tr.fraction != 1.0)
{
return false;
}
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------

View File

@ -998,6 +998,7 @@ public:
Activity NPC_TranslateActivity( Activity eNewActivity );
#ifdef MAPBASE
Activity TranslateCrouchActivity( Activity baseAct );
virtual bool CanTranslateCrouchActivity( void ) { return true; }
virtual Activity NPC_BackupActivity( Activity eNewActivity );
#endif
Activity GetActivity( void ) { return m_Activity; }
@ -2207,6 +2208,10 @@ public:
inline void ForceCrouch( void );
inline void ClearForceCrouch( void );
#ifdef MAPBASE
bool CouldShootIfCrouchingAt( const Vector &vecPosition, const Vector &vecForward, const Vector &vecRight, float flDist = 48.0f );
#endif
protected:
virtual bool Crouch( void );
virtual bool Stand( void );

View File

@ -420,6 +420,24 @@ bool CAI_BehaviorBase::CanUnholsterWeapon( void )
return m_pBackBridge->BackBridge_CanUnholsterWeapon();
}
//-------------------------------------
bool CAI_BehaviorBase::ShouldPickADeathPose( void )
{
Assert( m_pBackBridge != NULL );
return m_pBackBridge->BackBridge_ShouldPickADeathPose();
}
//-------------------------------------
bool CAI_BehaviorBase::CanTranslateCrouchActivity( void )
{
Assert( m_pBackBridge != NULL );
return m_pBackBridge->BackBridge_CanTranslateCrouchActivity();
}
#endif
//-------------------------------------

View File

@ -132,6 +132,8 @@ public:
void BridgeHandleAnimEvent( animevent_t *pEvent );
#ifdef MAPBASE
bool BridgeCanUnholsterWeapon( void );
bool BridgeShouldPickADeathPose( void );
bool BridgeCanTranslateCrouchActivity( void );
#endif
virtual void GatherConditions();
@ -220,6 +222,8 @@ protected:
virtual void HandleAnimEvent( animevent_t *pEvent );
#ifdef MAPBASE
virtual bool CanUnholsterWeapon( void );
virtual bool ShouldPickADeathPose( void );
virtual bool CanTranslateCrouchActivity( void );
#endif
virtual bool ShouldAlwaysThink();
@ -370,6 +374,9 @@ public:
#ifdef MAPBASE
// For func_tank behavior
virtual bool BackBridge_CanUnholsterWeapon( void ) = 0;
virtual bool BackBridge_ShouldPickADeathPose( void ) = 0;
virtual bool BackBridge_CanTranslateCrouchActivity( void ) = 0;
#endif
//-------------------------------------
@ -470,6 +477,8 @@ public:
void HandleAnimEvent( animevent_t *pEvent );
#ifdef MAPBASE
bool CanUnholsterWeapon( void );
bool ShouldPickADeathPose( void );
bool CanTranslateCrouchActivity( void );
#endif
bool ShouldAlwaysThink();
@ -534,6 +543,9 @@ private:
#ifdef MAPBASE
// For func_tank behavior
bool BackBridge_CanUnholsterWeapon( void );
bool BackBridge_ShouldPickADeathPose( void );
bool BackBridge_CanTranslateCrouchActivity( void );
#endif
CAI_BehaviorBase **AccessBehaviors();
@ -913,6 +925,20 @@ inline bool CAI_BehaviorBase::BridgeCanUnholsterWeapon( void )
{
return CanUnholsterWeapon();
}
//-----------------------------------------------------------------------------
inline bool CAI_BehaviorBase::BridgeShouldPickADeathPose( void )
{
return ShouldPickADeathPose();
}
//-----------------------------------------------------------------------------
inline bool CAI_BehaviorBase::BridgeCanTranslateCrouchActivity( void )
{
return CanTranslateCrouchActivity();
}
#endif
//-----------------------------------------------------------------------------
@ -1498,6 +1524,22 @@ inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_CanUnholsterWeapon( void )
{
return BaseClass::CanUnholsterWeapon();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_ShouldPickADeathPose( void )
{
return BaseClass::ShouldPickADeathPose();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_CanTranslateCrouchActivity( void )
{
return BaseClass::CanTranslateCrouchActivity();
}
#endif
//-------------------------------------
@ -1914,6 +1956,28 @@ inline bool CAI_BehaviorHost<BASE_NPC>::CanUnholsterWeapon( void )
return BaseClass::CanUnholsterWeapon();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::ShouldPickADeathPose( void )
{
if (m_pCurBehavior)
return m_pCurBehavior->BridgeShouldPickADeathPose();
return BaseClass::ShouldPickADeathPose();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::CanTranslateCrouchActivity( void )
{
if (m_pCurBehavior)
return m_pCurBehavior->BridgeCanTranslateCrouchActivity();
return BaseClass::CanTranslateCrouchActivity();
}
#endif
//-------------------------------------

View File

@ -535,10 +535,11 @@ int CAI_StandoffBehavior::SelectScheduleCheckCover( void )
{
StandoffMsg( "Regulated to not shoot\n" );
#ifdef MAPBASE
if ( GetHintType() == HINT_TACTICAL_COVER_LOW || GetHintType() == HINT_TACTICAL_COVER_MED )
#else
if ( GetHintType() == HINT_TACTICAL_COVER_LOW )
if ( GetHintType() == HINT_TACTICAL_COVER_MED || GetCoverActivity() == ACT_COVER_MED )
SetPosture( AIP_CROUCHING_MED );
else
#endif
if ( GetHintType() == HINT_TACTICAL_COVER_LOW )
SetPosture( AIP_CROUCHING );
else
SetPosture( AIP_STANDING );
@ -557,7 +558,11 @@ int CAI_StandoffBehavior::SelectScheduleEstablishAim( void )
{
if ( HasCondition( COND_ENEMY_OCCLUDED ) )
{
#ifdef EXPANDED_HL2_COVER_ACTIVITIES
if ( GetPosture() == AIP_CROUCHING || GetPosture() == AIP_CROUCHING_MED )
#else
if ( GetPosture() == AIP_CROUCHING )
#endif
{
// force a stand up, just in case
GetOuter()->SpeakSentence( STANDOFF_SENTENCE_STAND_CHECK_TARGET );
@ -668,6 +673,15 @@ Activity CAI_MappedActivityBehavior_Temporary::GetMappedActivity( AI_Posture_t p
{
if ( posture != AIP_STANDING )
{
#ifdef EXPANDED_HL2_COVER_ACTIVITIES
// See UpdateTranslateActivityMap() for more information on what this is for
if ( posture == AIP_CROUCHING_MED )
{
if (activity != ACT_RANGE_ATTACK1)
posture = AIP_CROUCHING;
}
#endif
unsigned short iActivityTranslation = m_ActivityMap.Find( MAKE_ACTMAP_KEY( posture, activity ) );
if ( iActivityTranslation != m_ActivityMap.InvalidIndex() )
{
@ -685,10 +699,28 @@ Activity CAI_StandoffBehavior::NPC_TranslateActivity( Activity activity )
Activity coverActivity = GetCoverActivity();
if ( coverActivity != ACT_INVALID )
{
#ifdef MAPBASE
if ( GetPosture() == AIP_STANDING )
{
if ( coverActivity == ACT_COVER_LOW )
SetPosture( AIP_CROUCHING );
else if ( coverActivity == ACT_COVER_MED )
{
SetPosture( AIP_CROUCHING_MED );
coverActivity = ACT_COVER_LOW;
}
}
else if (coverActivity == ACT_COVER_MED)
coverActivity = ACT_COVER_LOW;
if ( activity == ACT_IDLE )
activity = coverActivity;
#else
if (activity == ACT_IDLE)
activity = coverActivity;
if ( GetPosture() == AIP_STANDING && coverActivity == ACT_COVER_LOW )
SetPosture( AIP_CROUCHING );
#endif
}
Activity result = GetMappedActivity( GetPosture(), activity );
@ -1089,12 +1121,25 @@ void CAI_StandoffBehavior::UnlockHintNode()
Activity CAI_StandoffBehavior::GetCoverActivity()
{
#ifdef MAPBASE
// This does two things:
// A. Allows medium cover nodes to be used, kind of.
// B. GetCoverActivity() already checks everything we checked here.
Activity coveract = GetOuter()->GetCoverActivity( GetHintNode() );
return coveract == ACT_IDLE ? ACT_INVALID : coveract;
#ifdef EXPANDED_HL2_COVER_ACTIVITIES
// GetCoverActivity() already checks everything we checked here.
Activity coverActivity = GetOuter()->GetCoverActivity( GetHintNode() );
if (coverActivity == ACT_COVER_LOW)
{
// Check if this node will block our line of sight if aiming low.
Vector vHintPos, vHintForward, vHintRight;
GetHintNode()->GetPosition( GetHullType(), &vHintPos );
vHintForward = GetHintNode()->GetDirection();
GetHintNode()->GetVectors( NULL, &vHintRight, NULL );
if (GetOuter()->CouldShootIfCrouchingAt( vHintPos, vHintForward, vHintRight ))
{
coverActivity = ACT_COVER_MED;
}
}
return coverActivity == ACT_IDLE ? ACT_INVALID : coverActivity;
#else
CAI_Hint *pHintNode = GetHintNode();
if ( pHintNode && pHintNode->HintType() == HINT_TACTICAL_COVER_LOW )
@ -1112,6 +1157,14 @@ struct AI_ActivityMapping_t
Activity activity;
const char * pszWeapon;
Activity translation;
#ifdef MAPBASE
Activity backup;
AI_ActivityMapping_t( AI_Posture_t _p, Activity _a, const char *_w, Activity _t, Activity _b = ACT_INVALID )
{
posture = _p; activity = _a; pszWeapon = _w; translation = _t; backup = _b;
}
#endif
};
void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap()
@ -1125,15 +1178,60 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap()
{ AIP_CROUCHING, ACT_WALK_AIM, NULL, ACT_WALK_CROUCH_AIM, },
{ AIP_CROUCHING, ACT_RUN_AIM, NULL, ACT_RUN_CROUCH_AIM, },
{ AIP_CROUCHING, ACT_RELOAD, NULL, ACT_RELOAD_LOW, },
#ifdef MAPBASE
{ AIP_CROUCHING, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_LOW, },
{ AIP_CROUCHING, ACT_COVER_MED, NULL, ACT_COVER_LOW, },
#else
{ AIP_CROUCHING, ACT_RANGE_ATTACK_SMG1, NULL, ACT_RANGE_ATTACK_SMG1_LOW, },
{ AIP_CROUCHING, ACT_RANGE_ATTACK_AR2, NULL, ACT_RANGE_ATTACK_AR2_LOW, },
#endif
#ifdef EXPANDED_HL2_COVER_ACTIVITIES
//
// ============ Really long explanation that should be in a wiki/documentation article somewhere ~ Blixibon, 10/27/2021 ============
//
// Standoff behavior assumes low attack animations allow NPCs to see over barricades, with ACT_COVER_LOW being their "safely in cover" animation.
// This is why AIP_CROUCHING translates ACT_RANGE_ATTACK1 to its low animation, but translates ACT_IDLE_ANGRY to ACT_COVER_LOW instead of ACT_RANGE_AIM_LOW,
// as this would ideally allow NPCs to pop in and out of cover to shoot.
// This is also why AIP_PEEKING translates ACT_COVER_LOW to ACT_RANGE_AIM_LOW, as it's supposed to force the NPC to peek over their cover.
//
// However, this assumption mainly just applies to metrocops. Citizens' low attacking animations crouch low to the ground (which isn't effective for
// shooting over most barricades) and, while they do have a distinct ACT_COVER_LOW animation with transitions, they are close enough together that popping
// in and out of cover is redundant in most cases. Meanwhile, Combine soldiers have identical ACT_COVER_LOW and ACT_RANGE_AIM_LOW animations, which means
// they do not pop in and out of cover and AIP_PEEKING does nothing. This may be the reason why Combine soldiers occasionally get stuck in cover after a fight.
//
// -------------------------------------------------------------
//
// As part of Mapbase v7.0's NPC activity overhaul, a new "medium cover" activity set has been added. Metrocops' previous "low cover" animation set (which, as
// mentioned before, is different from that of other NPCs) has been retroactively changed to use "medium cover". This was done for a few reasons unrelated to
// standoff behavior, but the important point is that these activities indicate a new cover height. This means we can use them to give standoff behavior more leeway
// for judging which animations to use in various levels of cover.
//
// Standoff behavior can use "medium cover" animations in cover which is too high for the "low" animations, and when the medium cover animations are not available,
// it simply falls back to the "standing" animations, thus resolving the issue with other NPCs not peeking in and out of cover without requiring new medium cover
// animations.
//
// In Mapbase, this is done by changing AIP_PEEKING to use the medium cover animations and adding a new alternate crouching posture posture called "AIP_CROUCHING_MED",
// which only uses the medium cover attack activity and otherwise automatically falls back to AIP_CROUCHING. AIP_CROUCHING_MED is automatically set if the NPC cannot
// get LOS from a regular crouching position.
//
{ AIP_CROUCHING_MED, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_MED, },
//----
{ AIP_PEEKING, ACT_IDLE, NULL, ACT_RANGE_AIM_MED, },
{ AIP_PEEKING, ACT_IDLE_ANGRY, NULL, ACT_RANGE_AIM_MED, },
{ AIP_PEEKING, ACT_COVER_LOW, NULL, ACT_RANGE_AIM_MED, ACT_IDLE_ANGRY },
{ AIP_PEEKING, ACT_COVER_MED, NULL, ACT_RANGE_AIM_MED, ACT_IDLE_ANGRY },
{ AIP_PEEKING, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_MED, },
{ AIP_PEEKING, ACT_RELOAD, NULL, ACT_RELOAD_LOW, },
#else
//----
{ AIP_PEEKING, ACT_IDLE, NULL, ACT_RANGE_AIM_LOW, },
{ AIP_PEEKING, ACT_IDLE_ANGRY, NULL, ACT_RANGE_AIM_LOW, },
{ AIP_PEEKING, ACT_COVER_LOW, NULL, ACT_RANGE_AIM_LOW, },
{ AIP_PEEKING, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_LOW, },
{ AIP_PEEKING, ACT_RELOAD, NULL, ACT_RELOAD_LOW, },
#endif
};
m_ActivityMap.RemoveAll();
@ -1145,7 +1243,7 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap()
if ( !mappings[i].pszWeapon || stricmp( mappings[i].pszWeapon, pszWeaponClass ) == 0 )
{
#ifdef MAPBASE
// Check backup activity
// Check NPC backup activity
if ( HaveSequenceForActivity( mappings[i].translation ) || HaveSequenceForActivity( GetOuter()->Weapon_TranslateActivity( mappings[i].translation ) ) || HaveSequenceForActivity( GetOuter()->Weapon_BackupActivity( mappings[i].translation ) ) )
#else
if ( HaveSequenceForActivity( mappings[i].translation ) || HaveSequenceForActivity( GetOuter()->Weapon_TranslateActivity( mappings[i].translation ) ) )
@ -1154,6 +1252,14 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap()
Assert( m_ActivityMap.Find( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ) ) == m_ActivityMap.InvalidIndex() );
m_ActivityMap.Insert( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ), mappings[i].translation );
}
#ifdef MAPBASE
// Check activity map backup activity
else if ( mappings[i].backup != ACT_INVALID && HaveSequenceForActivity( mappings[i].backup ) )
{
Assert( m_ActivityMap.Find( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ) ) == m_ActivityMap.InvalidIndex() );
m_ActivityMap.Insert( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ), mappings[i].backup );
}
#endif
}
}
}

View File

@ -51,6 +51,9 @@ enum AI_Posture_t
AIP_INDIFFERENT,
AIP_STANDING,
AIP_CROUCHING,
#ifdef EXPANDED_HL2_COVER_ACTIVITIES
AIP_CROUCHING_MED, // See UpdateTranslateActivityMap() for more information on what this is for
#endif
AIP_PEEKING,
};
@ -149,6 +152,14 @@ protected:
// Standoff overrides base AI crouch handling
bool IsCrouching( void ) { return false; }
#ifdef MAPBASE
// Standoff overrides base cover activity translation
bool CanTranslateCrouchActivity( void ) { return false; }
// Don't do death poses while crouching
bool ShouldPickADeathPose( void ) { return (GetPosture() != AIP_CROUCHING && GetPosture() != AIP_PEEKING) && BaseClass::ShouldPickADeathPose(); }
#endif
private:

View File

@ -4536,34 +4536,7 @@ int CNPC_MetroPolice::SelectBehaviorOverrideSchedule()
//-----------------------------------------------------------------------------
bool CNPC_MetroPolice::IsCrouchedActivity( Activity activity )
{
Activity realActivity = TranslateActivity(activity);
switch ( realActivity )
{
case ACT_RELOAD_LOW:
case ACT_COVER_LOW:
case ACT_COVER_PISTOL_LOW:
case ACT_COVER_SMG1_LOW:
case ACT_RELOAD_SMG1_LOW:
//case ACT_RELOAD_AR2_LOW:
case ACT_RELOAD_PISTOL_LOW:
case ACT_RELOAD_SHOTGUN_LOW:
// These animations aren't actually "low" on metrocops
//case ACT_RANGE_AIM_LOW:
//case ACT_RANGE_AIM_AR2_LOW:
//case ACT_RANGE_AIM_SMG1_LOW:
//case ACT_RANGE_AIM_PISTOL_LOW:
//case ACT_RANGE_ATTACK1_LOW:
//case ACT_RANGE_ATTACK_AR2_LOW:
//case ACT_RANGE_ATTACK_SMG1_LOW:
//case ACT_RANGE_ATTACK_PISTOL_LOW:
//case ACT_RANGE_ATTACK2_LOW:
return true;
}
return false;
return BaseClass::IsCrouchedActivity( activity );
}
//-----------------------------------------------------------------------------