You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
591 lines
16 KiB
591 lines
16 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
|
|
#include "cbase.h" |
|
#include "c_tf_player.h" |
|
#include "iclientmode.h" |
|
#include "ienginevgui.h" |
|
#include <vgui/ILocalize.h> |
|
#include <vgui/ISurface.h> |
|
#include <vgui/IVGui.h> |
|
#include <vgui_controls/Label.h> |
|
#include <vgui_controls/EditablePanel.h> |
|
#include "tf_imagepanel.h" |
|
#include "tf_gamerules.h" |
|
#include "c_tf_team.h" |
|
#include "c_team_objectiveresource.h" |
|
#include "tf_hud_match_status.h" |
|
#include "tf_hud_teamgoal_tournament.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
using namespace vgui; |
|
|
|
void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); |
|
|
|
DECLARE_HUDELEMENT( CHudTeamGoalTournament ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CHudTeamGoalTournament::CHudTeamGoalTournament( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudTeamGoalTournament" ) |
|
{ |
|
Panel *pParent = g_pClientMode->GetViewport(); |
|
SetParent( pParent ); |
|
|
|
SetHiddenBits( HIDEHUD_MISCSTATUS ); |
|
|
|
m_flShowAt = -1.f; |
|
|
|
RegisterForRenderGroup( "commentary" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudTeamGoalTournament::LevelInit( void ) |
|
{ |
|
m_flShowAt = -1.f; |
|
|
|
ListenForGameEvent( "tournament_stateupdate" ); |
|
ListenForGameEvent( "teamplay_round_start" ); |
|
ListenForGameEvent( "competitive_state_changed" ); |
|
} |
|
C_TFTeam *GetTeamRoles( int iTeamRole ) |
|
{ |
|
for ( int i = LAST_SHARED_TEAM+1; i < GetNumberOfTeams(); i++ ) |
|
{ |
|
C_TFTeam *pTeam = GetGlobalTFTeam( i ); |
|
|
|
if ( pTeam ) |
|
{ |
|
if ( pTeam->GetRole() == iTeamRole ) |
|
{ |
|
return pTeam; |
|
} |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CHudTeamGoalTournament::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) |
|
{ |
|
if ( IsVisible() && TFGameRules() && TFGameRules()->IsInTournamentMode() && TFGameRules()->IsInStopWatch() ) |
|
{ |
|
if ( ( TFGameRules()->State_Get() == GR_STATE_PREROUND ) || TFGameRules()->InSetup() ) |
|
{ |
|
if ( down && ( keynum == KEY_F1 ) ) |
|
{ |
|
m_flShowAt = -1.f; |
|
return 0; |
|
} |
|
} |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudTeamGoalTournament::FireGameEvent( IGameEvent * event ) |
|
{ |
|
const char *pEventName = event->GetName(); |
|
|
|
if ( FStrEq( "tournament_stateupdate", pEventName ) ) |
|
{ |
|
m_flShowAt = -1.f; |
|
} |
|
else if ( FStrEq( "teamplay_round_start", pEventName ) ) |
|
{ |
|
if ( TFGameRules() && TFGameRules()->IsInTournamentMode() && TFGameRules()->IsInStopWatch() ) |
|
{ |
|
C_TFTeam *pAttacker = GetTeamRoles( TEAM_ROLE_ATTACKERS ); |
|
C_TFTeam *pDefender = GetTeamRoles( TEAM_ROLE_DEFENDERS ); |
|
|
|
if( !pAttacker || !pDefender ) |
|
return; |
|
|
|
if ( ( pAttacker->Get_Score() != 0 ) && ( pDefender->Get_Score() != 0 ) ) |
|
return; |
|
|
|
m_flShowAt = gpGlobals->curtime + 1.f; |
|
} |
|
} |
|
else if ( FStrEq( "competitive_state_changed", pEventName ) ) |
|
{ |
|
InvalidateLayout( false, true ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudTeamGoalTournament::ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
KeyValues *pConditions = NULL; |
|
if ( ShouldUseMatchHUD() ) |
|
{ |
|
pConditions = new KeyValues( "conditions" ); |
|
AddSubKeyNamed( pConditions, "if_comp" ); |
|
} |
|
|
|
// load control settings... |
|
LoadControlSettings( "resource/UI/HudTeamGoalTournament.res", NULL, NULL, pConditions ); |
|
|
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
if ( pConditions ) |
|
{ |
|
pConditions->deleteThis(); |
|
} |
|
|
|
m_cRegularColor = pScheme->GetColor( "TanLight", Color( 0, 0, 0 ) ); |
|
m_cHighlightColor = pScheme->GetColor( "GoalOrange", Color( 0, 0, 0 ) ); |
|
|
|
m_pStopWatchGoal = dynamic_cast<EditablePanel *>( FindChildByName( "HudStopWatchObjective" ) ); |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoalText = dynamic_cast<CExRichText *>( m_pStopWatchGoal->FindChildByName( "HudStopWatchObjectiveText1" ) ); |
|
} |
|
|
|
if ( m_pStopWatchGoalText ) |
|
{ |
|
m_pStopWatchGoalText->SetVisible( true ); |
|
m_pStopWatchGoalText->InsertColorChange( m_cRegularColor ); |
|
} |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoalText2 = dynamic_cast<CExRichText *>( m_pStopWatchGoal->FindChildByName( "HudStopWatchObjectiveText2" ) ); |
|
} |
|
|
|
if ( m_pStopWatchGoalText2 ) |
|
{ |
|
m_pStopWatchGoalText2->SetVisible( true ); |
|
m_pStopWatchGoalText2->InsertColorChange( m_cRegularColor ); |
|
} |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoalBGLarge = m_pStopWatchGoal->FindChildByName( "HudStopWatchObjectiveBG" ); |
|
m_pStopWatchGoalBGSmall = m_pStopWatchGoal->FindChildByName( "HudStopWatchObjectiveBGSmall" ); |
|
m_pStopWatchGoalDivider = m_pStopWatchGoal->FindChildByName( "HudStopWatchObjectiveShadedBar" ); |
|
} |
|
|
|
m_pStopWatchGoalArrow = FindChildByName( "HudStopWatchObjectiveArrow" ); |
|
} |
|
inline wchar_t *CloneWString( const wchar_t *str ); |
|
|
|
enum |
|
{ |
|
STOPWATCH_COLOR_NORMAL = 1, |
|
STOPWATCH_COLOR_SUB = 3, |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudTeamGoalTournament::SetVisible( bool bState ) |
|
{ |
|
if ( bState ) |
|
{ |
|
SetupStopWatchLabel(); |
|
} |
|
|
|
BaseClass::SetVisible( bState ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Prepares the string with the different colors |
|
// This is kinda nasty since I just copied this code from the chat |
|
// This should be abstracted and made all nice. |
|
//----------------------------------------------------------------------------- |
|
void CHudTeamGoalTournament::PrepareStopWatchString( wchar_t *pszString, CExRichText *pText ) |
|
{ |
|
if ( m_text ) |
|
{ |
|
delete[] m_text; |
|
m_text = NULL; |
|
} |
|
|
|
m_textRanges.RemoveAll(); |
|
|
|
m_text = CloneWString( pszString ); |
|
|
|
wchar_t *txt = m_text; |
|
int lineLen = wcslen( m_text ); |
|
|
|
TextRange range; |
|
range.start = 0; |
|
range.end = wcslen( m_text ); |
|
range.color = Color( 235, 226, 202 ); |
|
m_textRanges.AddToTail( range ); |
|
|
|
while ( txt && *txt ) |
|
{ |
|
switch ( *txt ) |
|
{ |
|
case STOPWATCH_COLOR_SUB: |
|
case STOPWATCH_COLOR_NORMAL: |
|
{ |
|
// save this start |
|
range.start = (txt-m_text) + 1; |
|
|
|
if ( *txt == STOPWATCH_COLOR_NORMAL ) |
|
range.color = m_cRegularColor; |
|
else |
|
range.color = m_cHighlightColor; |
|
|
|
range.end = lineLen; |
|
|
|
int count = m_textRanges.Count(); |
|
if ( count ) |
|
{ |
|
m_textRanges[count-1].end = range.start - 1; |
|
} |
|
|
|
m_textRanges.AddToTail( range ); |
|
} |
|
++txt; |
|
break; |
|
|
|
default: |
|
++txt; |
|
} |
|
} |
|
|
|
for ( int i=0; i<m_textRanges.Count(); ++i ) |
|
{ |
|
wchar_t * start = m_text + m_textRanges[i].start; |
|
if ( *start > 0 && *start < COLOR_MAX ) |
|
{ |
|
m_textRanges[i].start += 1; |
|
} |
|
} |
|
|
|
wchar_t wText[4096]; |
|
Color color; |
|
for ( int i=0; i<m_textRanges.Count(); ++i ) |
|
{ |
|
wchar_t * start = m_text + m_textRanges[i].start; |
|
int len = m_textRanges[i].end - m_textRanges[i].start + 1; |
|
if ( len > 1 ) |
|
{ |
|
wcsncpy( wText, start, len ); |
|
wText[len-1] = 0; |
|
color = m_textRanges[i].color; |
|
color[3] = 255; |
|
pText->InsertColorChange( color ); |
|
pText->InsertString( wText ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudTeamGoalTournament::SetupStopWatchLabel( void ) |
|
{ |
|
int iPoints = 0; |
|
|
|
if ( !TFGameRules() ) |
|
return; |
|
|
|
if ( !ObjectiveResource() ) |
|
return; |
|
|
|
C_TFTeam *pAttacker = GetTeamRoles( TEAM_ROLE_ATTACKERS ); |
|
C_TFTeam *pDefender = GetTeamRoles( TEAM_ROLE_DEFENDERS ); |
|
|
|
if( !pAttacker || !pDefender ) |
|
return; |
|
|
|
int iActiveTimer = ObjectiveResource()->GetStopWatchTimer(); |
|
|
|
CTeamRoundTimer *pTimer = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( iActiveTimer ) ); |
|
|
|
if ( !pTimer ) |
|
return; |
|
|
|
if ( !pTimer->IsWatchingTimeStamps() ) |
|
{ |
|
iPoints = pDefender->Get_Score(); |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoal->SetVisible( true ); |
|
} |
|
|
|
if ( m_pStopWatchGoalArrow ) |
|
{ |
|
m_pStopWatchGoalArrow->SetVisible( true ); |
|
} |
|
} |
|
else |
|
{ |
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoal->SetVisible( false ); |
|
} |
|
|
|
if ( m_pStopWatchGoalArrow ) |
|
{ |
|
m_pStopWatchGoalArrow->SetVisible( false ); |
|
} |
|
|
|
return; |
|
} |
|
|
|
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
|
|
if ( !pLocalPlayer ) |
|
return; |
|
|
|
wchar_t wzHelp[256]; |
|
|
|
C_TFTeam *pBlueTeam = GetGlobalTFTeam( TF_TEAM_BLUE ); |
|
const wchar_t *pBlueTeamName = pBlueTeam ? pBlueTeam->Get_Localized_Name() : L"BLU"; |
|
|
|
C_TFTeam *pRedTeam = GetGlobalTFTeam( TF_TEAM_RED ); |
|
const wchar_t *pRedTeamName = pRedTeam ? pRedTeam->Get_Localized_Name() : L"RED"; |
|
|
|
wchar_t wszAttackersName[MAX_TEAM_NAME_LENGTH]; |
|
wchar_t wszDefendersName[MAX_TEAM_NAME_LENGTH]; |
|
|
|
V_wcscpy_safe( wszAttackersName, ( pAttacker->GetTeamNumber() == TF_TEAM_BLUE ) ? pBlueTeamName : pRedTeamName ); |
|
V_wcscpy_safe( wszDefendersName, ( pDefender->GetTeamNumber() == TF_TEAM_BLUE ) ? pBlueTeamName : pRedTeamName ); |
|
|
|
#ifdef WIN32 |
|
#define INT_CHAR_FMT L"%d %s" |
|
#else |
|
#define INT_CHAR_FMT L"%d %S" |
|
#endif |
|
|
|
wchar_t wszPoints[256]; |
|
_snwprintf( wszPoints, ARRAYSIZE( wszPoints ), INT_CHAR_FMT, iPoints, iPoints == 1 ? g_pVGuiLocalize->Find( "Tournament_StopWatch_Point" ) : g_pVGuiLocalize->Find( "Tournament_StopWatch_Points" ) ); |
|
|
|
wchar_t wszTime[256]; |
|
wchar_t wszLabel[256]; |
|
|
|
int iMinutes = pTimer->GetTimeRemaining() / 60; |
|
int iSeconds = ((int)pTimer->GetTimeRemaining()) % 60; |
|
|
|
if ( iMinutes > 0 ) |
|
{ |
|
#ifdef WIN32 |
|
_snwprintf( wszTime, ARRAYSIZE( wszTime ) , L"%d %s %d %s", iMinutes, iMinutes == 1 ? g_pVGuiLocalize->Find( "Tournament_WinConditionsMinute" ) : g_pVGuiLocalize->Find( "Tournament_WinConditionsMinutes" ), iSeconds, iSeconds == 1 ? g_pVGuiLocalize->Find( "Tournament_WinConditionsSecond" ) : g_pVGuiLocalize->Find( "Tournament_WinConditionsSeconds" ) ); |
|
#else |
|
_snwprintf( wszTime, ARRAYSIZE( wszTime ) , L"%d %S %d %S", iMinutes, iMinutes == 1 ? g_pVGuiLocalize->Find( "Tournament_WinConditionsMinute" ) : g_pVGuiLocalize->Find( "Tournament_WinConditionsMinutes" ), iSeconds, iSeconds == 1 ? g_pVGuiLocalize->Find( "Tournament_WinConditionsSecond" ) : g_pVGuiLocalize->Find( "Tournament_WinConditionsSeconds" ) ); |
|
#endif |
|
} |
|
else |
|
{ |
|
_snwprintf( wszTime, ARRAYSIZE( wszTime ), INT_CHAR_FMT, iSeconds, iSeconds == 1 ? g_pVGuiLocalize->Find( "Tournament_WinConditionsSecond" ) : g_pVGuiLocalize->Find( "Tournament_WinConditionsSeconds" ) ); |
|
} |
|
|
|
if ( m_pStopWatchGoalText ) |
|
{ |
|
m_pStopWatchGoalText->SetText(""); |
|
} |
|
|
|
if ( m_pStopWatchGoalText2 ) |
|
{ |
|
m_pStopWatchGoalText2->SetText(""); |
|
} |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoal->SetDialogVariable( "objectivelabel", "" ); |
|
} |
|
|
|
if ( pLocalPlayer->GetTeam() == pDefender ) |
|
{ |
|
g_pVGuiLocalize->ConstructString_safe( wszLabel, g_pVGuiLocalize->Find( "Tournament_StopWatch_LabelDefender" ), 1, wszAttackersName ); |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoal->SetDialogVariable( "objectivelabel", wszLabel ); |
|
} |
|
} |
|
|
|
//Attackers capped something last round case |
|
if ( iPoints > 0 ) |
|
{ |
|
bool bCappedAllPoints = ( iPoints == ObjectiveResource()->GetNumControlPoints() ); |
|
|
|
g_pVGuiLocalize->ConstructString_safe( wzHelp, g_pVGuiLocalize->Find( bCappedAllPoints ? "Tournament_StopWatch_GoalTextPointsAndTimeAndClose" : "Tournament_StopWatch_GoalTextPointsAndTime" ), 5, wszDefendersName, wszPoints, wszTime, wszAttackersName, wszPoints ); |
|
|
|
if ( m_pStopWatchGoalText ) |
|
{ |
|
PrepareStopWatchString( wzHelp, m_pStopWatchGoalText ); |
|
} |
|
|
|
if ( bCappedAllPoints ) |
|
{ |
|
if ( m_pStopWatchGoalText2 ) |
|
{ |
|
m_pStopWatchGoalText2->SetVisible( false ); |
|
} |
|
|
|
if ( m_pStopWatchGoalBGLarge ) |
|
{ |
|
m_pStopWatchGoalBGLarge->SetVisible( false ); |
|
} |
|
|
|
if ( m_pStopWatchGoalBGSmall ) |
|
{ |
|
m_pStopWatchGoalBGSmall->SetVisible( true ); |
|
} |
|
|
|
if ( m_pStopWatchGoalDivider ) |
|
{ |
|
m_pStopWatchGoalDivider->SetVisible( false ); |
|
} |
|
} |
|
else |
|
{ |
|
if ( m_pStopWatchGoalText2 ) |
|
{ |
|
m_pStopWatchGoalText2->SetVisible( true ); |
|
} |
|
|
|
if ( m_pStopWatchGoalBGLarge ) |
|
{ |
|
m_pStopWatchGoalBGLarge->SetVisible( true ); |
|
} |
|
|
|
if ( m_pStopWatchGoalBGSmall ) |
|
{ |
|
m_pStopWatchGoalBGSmall->SetVisible( false ); |
|
} |
|
|
|
if ( m_pStopWatchGoalDivider ) |
|
{ |
|
m_pStopWatchGoalDivider->SetVisible( true ); |
|
} |
|
|
|
iPoints += 1; |
|
_snwprintf( wszPoints, ARRAYSIZE( wszPoints ), INT_CHAR_FMT, iPoints, iPoints == 1 ? g_pVGuiLocalize->Find( "Tournament_StopWatch_Point" ) : g_pVGuiLocalize->Find( "Tournament_StopWatch_Points" ) ); |
|
g_pVGuiLocalize->ConstructString_safe( wzHelp, g_pVGuiLocalize->Find( "Tournament_StopWatch_GoalTextPointsAndTime2" ), 4, wszAttackersName, wszDefendersName, wszAttackersName, wszPoints ); |
|
|
|
if ( m_pStopWatchGoalText2 ) |
|
{ |
|
PrepareStopWatchString( wzHelp, m_pStopWatchGoalText2 ); |
|
} |
|
} |
|
|
|
if ( pLocalPlayer->GetTeam() == pAttacker ) |
|
{ |
|
g_pVGuiLocalize->ConstructString_safe( wszLabel, g_pVGuiLocalize->Find( "Tournament_StopWatch_TimeVictory" ), 1, wszDefendersName ); |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoal->SetDialogVariable( "objectivelabel", wszLabel ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
if ( m_pStopWatchGoalText2 ) |
|
{ |
|
m_pStopWatchGoalText2->SetVisible( false ); |
|
} |
|
|
|
if ( m_pStopWatchGoalBGLarge ) |
|
{ |
|
m_pStopWatchGoalBGLarge->SetVisible( false ); |
|
} |
|
|
|
if ( m_pStopWatchGoalBGSmall ) |
|
{ |
|
m_pStopWatchGoalBGSmall->SetVisible( true ); |
|
} |
|
|
|
if ( m_pStopWatchGoalDivider ) |
|
{ |
|
m_pStopWatchGoalDivider->SetVisible( false ); |
|
} |
|
|
|
g_pVGuiLocalize->ConstructString_safe( wzHelp, g_pVGuiLocalize->Find( "Tournament_StopWatch_GoalTextPoints" ), 4, wszDefendersName, wszAttackersName ); |
|
|
|
|
|
if ( m_pStopWatchGoalText ) |
|
{ |
|
PrepareStopWatchString( wzHelp, m_pStopWatchGoalText ); |
|
} |
|
|
|
if ( pLocalPlayer->GetTeam() == pAttacker ) |
|
{ |
|
g_pVGuiLocalize->ConstructString_safe( wszLabel, g_pVGuiLocalize->Find( "Tournament_StopWatch_AttackerScore" ), 1, wszDefendersName ); |
|
|
|
if ( m_pStopWatchGoal ) |
|
{ |
|
m_pStopWatchGoal->SetDialogVariable( "objectivelabel", wszLabel ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CHudTeamGoalTournament::ShouldDraw( void ) |
|
{ |
|
if ( !TFGameRules() || |
|
!TFGameRules()->IsInTournamentMode() || |
|
!TFGameRules()->IsInStopWatch() || |
|
( ( TFGameRules()->State_Get() != GR_STATE_PREROUND ) && !TFGameRules()->InSetup() ) ) |
|
{ |
|
m_flShowAt = -1.f; |
|
return false; |
|
} |
|
|
|
if ( ObjectiveResource() ) |
|
{ |
|
int iActiveTimer = ObjectiveResource()->GetStopWatchTimer(); |
|
CTeamRoundTimer *pTimer = dynamic_cast<CTeamRoundTimer*>( ClientEntityList().GetEnt( iActiveTimer ) ); |
|
if ( pTimer && pTimer->IsWatchingTimeStamps() ) |
|
{ |
|
m_flShowAt = -1.f; |
|
return false; |
|
} |
|
} |
|
|
|
if ( ( m_flShowAt < 0 ) || ( m_flShowAt > gpGlobals->curtime ) ) |
|
{ |
|
return false; |
|
} |
|
|
|
// only show the panel for 15 seconds after it is first draws |
|
if ( gpGlobals->curtime - m_flShowAt > 15.f ) |
|
{ |
|
m_flShowAt = -1.f; |
|
return false; |
|
} |
|
|
|
C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
if ( pPlayer && pPlayer->IsAlive() && ( pPlayer->GetTeamNumber() >= FIRST_GAME_TEAM ) ) |
|
{ |
|
if ( CHudElement::ShouldDraw() ) |
|
{ |
|
CHudElement *pHudSwitch = gHUD.FindElement( "CHudTeamSwitch" ); |
|
if ( pHudSwitch && pHudSwitch->ShouldDraw() ) |
|
return false; |
|
|
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
}
|
|
|