502 lines
14 KiB
C++
502 lines
14 KiB
C++
|
|
/// 2011.02.08 - prodongi
|
|
|
|
#include "stdafx.h"
|
|
#include "KUIControlStatic.h"
|
|
#include "KUIControlGauge.h"
|
|
#include "CreatureBase.h"
|
|
#include "SGameManager.h"
|
|
#include "CharacterInfo/SUICharacterInfoWnd.h"
|
|
#include "CharacterInfo/SUICharacterInfoSubBasicWnd.h"
|
|
#include "CharacterInfo/SUICharacterInfoSubAddedWnd.h"
|
|
#include "SUIDisplayInfo.h"
|
|
#include "SGameMessage.h"
|
|
//#include "SGameMessageUI.h"
|
|
#include "SJobDB.h"
|
|
#include "SStringDB.h"
|
|
#include "SSummonSlotMgr.h"
|
|
#include "SPlayerInfoMgr.h"
|
|
#include "SMessengerMgr.h"
|
|
#include "SChatType.h"
|
|
#include "SUISysMsgDefine.h"
|
|
#include "SDebug_Util.h"
|
|
//#include "SUIUtil.h"
|
|
#include "KUITabControl.h"
|
|
#include "Arena\\ArenaSystem.h"
|
|
#include "SGameSystem.h"
|
|
|
|
extern SGameSystem* g_pCurrentGameSystem;
|
|
|
|
|
|
namespace
|
|
{
|
|
// const int c_nSysMenu = 56; // 왼쪽 메뉴 바 width
|
|
const DWORD c_dwGaugeFillTime = 1000;
|
|
};
|
|
|
|
SUICharacterInfoWnd::SUICharacterInfoWnd( SGameManager* pGameManager, SUIDisplayInfo* pDisplayInfo )
|
|
: SUIWnd( pGameManager ), m_pDisplayInfo(pDisplayInfo), m_curSubWnd(SUB_BASIC)
|
|
{
|
|
};
|
|
|
|
SUIWnd* SUICharacterInfoWnd::CreateWnd(const char *szFile, KUIWndManager *pWndManager, KPoint kPos, int nWindowID)
|
|
{
|
|
SUIWnd::CreateWnd(szFile, pWndManager, kPos, nWindowID);
|
|
|
|
/// create sub windows
|
|
createSubWnd<SUICharacterInfoSubBasicWnd>(pWndManager, SUB_BASIC, "window_player_character_info_sub_basic.nui", SIMSG_TOGGLE_UIWINDOW::UIWINDOW_CHARINFO_SUB_BASIC);
|
|
createSubWnd<SUICharacterInfoSubAddedWnd>(pWndManager, SUB_ADDED, "window_player_character_info_sub_added.nui", SIMSG_TOGGLE_UIWINDOW::UIWINDOW_CHARINFO_SUB_ADDED);
|
|
|
|
return this;
|
|
}
|
|
|
|
bool SUICharacterInfoWnd::InitControls( KPoint kPos )
|
|
{
|
|
SetCustomMovingRect( GetChild("titlebar")->GetRect() ); // 타이틀 바 선택 영역, 이동위해 클릭 Area
|
|
|
|
return SUIWnd::InitControls( kPos );
|
|
}
|
|
|
|
bool SUICharacterInfoWnd::InitData( bool bReload )
|
|
{
|
|
refreshGuildName();
|
|
initFrameHeightData();
|
|
|
|
return SUIWnd::InitData(bReload);
|
|
}
|
|
void SUICharacterInfoWnd::OnNotifyUIWindowOpen( bool bOpen, bool bLimitWnd )
|
|
{
|
|
SUIWnd::OnNotifyUIWindowOpen(bOpen);
|
|
|
|
if( bOpen )
|
|
{
|
|
m_pGameManager->StartSound( "ui_popup_window01.wav" );
|
|
setCurSubWnd(m_curSubWnd);
|
|
m_subWnd[SUB_BASIC]->refreshExpand(true);
|
|
m_subWnd[SUB_ADDED]->refreshAll();
|
|
}
|
|
}
|
|
void SUICharacterInfoWnd::PumpUpMessage( LPCSTR lpszControlID, DWORD nMessage, DWORD lparam, DWORD wparam )
|
|
{
|
|
switch( nMessage )
|
|
{
|
|
case KUI_MESSAGE::KBUTTON_CLICK:
|
|
{
|
|
if( ::_stricmp( lpszControlID, "button_close" ) == 0 )
|
|
{
|
|
m_pGameManager->PostMsgAtDynamic( new SIMSG_SHOW_UIWINDOW( SIMSG_TOGGLE_UIWINDOW::UIWINDOW_CHARINFO, false) );
|
|
}
|
|
if (_stricmp(lpszControlID, "tab_basic_01") == 0)
|
|
{
|
|
setCurSubWnd(SUB_BASIC);
|
|
}
|
|
else if (_stricmp(lpszControlID, "tab_added_01") == 0)
|
|
{
|
|
setCurSubWnd(SUB_ADDED);
|
|
}
|
|
else if (_stricmp(lpszControlID, "button_equip") == 0)
|
|
{
|
|
/// 장비창에서 y축 위치를 장비창의 높이만큼 빼주기 때문에(왜 이런가??), 여시서는 bottom을 넣어준다(+2는 임시,,,)
|
|
m_pGameManager->PostMsgAtDynamic( new SIMSG_UI_MOVE( SIMSG_TOGGLE_UIWINDOW::UIWINDOW_EQUIPMENT, GetBoundingRect().right-1, GetBoundingRect().bottom + 2) );
|
|
m_pGameManager->PostMsgAtDynamic( new SIMSG_TOGGLE_UIWINDOW( SIMSG_TOGGLE_UIWINDOW::UIWINDOW_EQUIPMENT));
|
|
}
|
|
}
|
|
break;
|
|
case KUI_MESSAGE::KGENWND_MOVE: // 윈도우 이동
|
|
{
|
|
LimitMoveWnd(); // 게임 외부로 나가지 못하게 제한
|
|
}
|
|
break;
|
|
}
|
|
|
|
SUIWnd::PumpUpMessage( lpszControlID, nMessage, lparam, wparam );
|
|
}
|
|
|
|
void SUICharacterInfoWnd::ProcMsgAtStatic( SGameMessage* pMsg )
|
|
{
|
|
switch( pMsg->nType )
|
|
{
|
|
case MSG_CHANGE_NAME :
|
|
{
|
|
refreshJobName();
|
|
}
|
|
break;
|
|
|
|
case IMSG_UI_SEND_DATA:
|
|
{
|
|
SIMSG_UI_SEND_DATA *pData = (SIMSG_UI_SEND_DATA *)pMsg;
|
|
|
|
if( pData->m_strString == "guild_update" )
|
|
{
|
|
pMsg->bUse = true;
|
|
|
|
refreshGuildName();
|
|
}
|
|
else if( pData->m_dwData == IMSG_GUILD_ICON || pData->m_dwData == IMSG_GUILD_ICON_REFRESH )
|
|
{
|
|
pMsg->bUse = true;
|
|
|
|
if( m_GuildMgr.GetGuildID() == (int)pData->m_nNumber.getAmount() )
|
|
{
|
|
refreshGuildMark(pData->m_strText);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IMSG_GUILD_ICON_DESTROY :
|
|
{
|
|
pMsg->bUse = true;
|
|
refreshGuildMark("");
|
|
}
|
|
break;
|
|
case IMSG_GUILD_ICON_LEAVE :
|
|
{
|
|
pMsg->bUse = true;
|
|
refreshGuildMark("");
|
|
}
|
|
case MSG_LOGIN:
|
|
{
|
|
SMSG_LOGIN* pLoginMsg = dynamicCast<SMSG_LOGIN*>(pMsg);
|
|
refreshHP( pLoginMsg->hp, pLoginMsg->max_hp );
|
|
refreshMP( pLoginMsg->mp, pLoginMsg->max_mp );
|
|
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case IMSG_UI_TARGET_STAT:
|
|
{
|
|
SIMSG_UI_TARGET_STAT* pUISyncMsg = dynamicCast<SIMSG_UI_TARGET_STAT*>(pMsg);
|
|
|
|
SPlayerInfo & info = m_PlayerInfoMgr.GetPlayerInfo();
|
|
|
|
if( pUISyncMsg->handle != m_PlayerInfoMgr.GetPlayerHandle() )
|
|
return;
|
|
|
|
if( pUISyncMsg->m_nMode == SIMSG_UI_TARGET_STAT::USE_DEF ||
|
|
pUISyncMsg->m_nMode == SIMSG_UI_TARGET_STAT::USE_HPMP )
|
|
{
|
|
refreshHP ( pUISyncMsg->m_nVar1, pUISyncMsg->m_nVar3 );
|
|
refreshMP ( pUISyncMsg->m_nVar2, pUISyncMsg->m_nVar4 );
|
|
}
|
|
else if( pUISyncMsg->m_nMode == SIMSG_UI_TARGET_STAT::USE_EXP )
|
|
{
|
|
refreshExp ();
|
|
}
|
|
}
|
|
break;
|
|
case IMSG_UI_FOCUS:
|
|
{
|
|
m_pManager->SetFocus(this);
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case MSG_PROPERTY:
|
|
{
|
|
SMSG_PROPERTY* pPropertyMsg = (SMSG_PROPERTY*)pMsg;
|
|
switch( pPropertyMsg->nPropertyType )
|
|
{
|
|
case SMSG_PROPERTY::PROPERTY_JOB_LEVEL:
|
|
case SMSG_PROPERTY::PROPERTY_NAME:
|
|
case SMSG_PROPERTY::PROPERTY_LEVEL:
|
|
case SMSG_PROPERTY::PROPERTY_JOB: refreshJobName(); break;
|
|
case SMSG_PROPERTY::PROPERTY_EXP:
|
|
case SMSG_PROPERTY::PROPERTY_JP: refreshExp(); break;
|
|
case SMSG_PROPERTY::PROPERTY_PK_COUNT:
|
|
case SMSG_PROPERTY::PROPERTY_DK_COUNT:
|
|
case SMSG_PROPERTY::PROPERTY_MORAL: m_subWnd[SUB_ADDED]->refreshPropensity(); break;
|
|
}
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case MSG_STATUS_CHANGE:
|
|
{
|
|
m_subWnd[SUB_ADDED]->refreshPropensity();
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case IMSG_INSTANCE_GAME_SCORE:
|
|
{
|
|
m_subWnd[SUB_ADDED]->refreshGameScore((SMSG_INSTANCE_GAME_SCORE *)pMsg);
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case MSG_INSTANCE_GAME_SCORE_REQUEST:
|
|
{
|
|
SMSG_INSTANCE_GAME_SCORE_REQUEST* msg = dynamicCast<SMSG_INSTANCE_GAME_SCORE_REQUEST*>(pMsg);
|
|
if (msg)
|
|
{
|
|
if (msg->activeAddedWnd)
|
|
{
|
|
if (SUB_ADDED != m_curSubWnd)
|
|
{
|
|
setCurSubWnd(SUB_ADDED, true);
|
|
}
|
|
else
|
|
{
|
|
m_subWnd[SUB_ADDED]->refreshGameScore(NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_subWnd[SUB_ADDED]->refreshGameScore(NULL);
|
|
}
|
|
}
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case MSG_LEVEL_UPDATE:
|
|
{
|
|
refreshJobName();
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case MSG_STAT_INFO:
|
|
{
|
|
SMSG_STAT_INFO* pStatInfoMsg = (SMSG_STAT_INFO*)pMsg;
|
|
|
|
if( pStatInfoMsg->type == TS_SC_STAT_INFO::TOTAL )
|
|
{
|
|
refreshBaseStat();
|
|
refreshBattleStat();
|
|
}
|
|
else if( pStatInfoMsg->type == TS_SC_STAT_INFO::BY_ITEM )
|
|
{
|
|
refreshBaseStat();
|
|
refreshBattleStat();
|
|
|
|
refreshBaseItemStat( pStatInfoMsg->stat );
|
|
refreshBattleItemStat( pStatInfoMsg->attribute );
|
|
}
|
|
|
|
pMsg->bUse = true;
|
|
}
|
|
break;
|
|
case IMSG_UI_TITLE_SET_MAIN: // 2012. 5. 21 - marine 주 호칭 이름 갱신
|
|
{
|
|
SIMSG_UI_TITLE_SET_MAIN *pTitle = dynamicCast<SIMSG_UI_TITLE_SET_MAIN *>(pMsg);
|
|
GetChild("character_title_text")->SetCaption(CStringUtil::StringFormat("<font:font_01><#7b2e00><vcenter><hcenter><size:9>%s",pTitle->strName.c_str()).c_str());
|
|
}
|
|
break;
|
|
case MSG_BATTLE_ARENA_BATTLE_INFO:
|
|
case MSG_BATTLE_ARENA_LEAVE:
|
|
updateName();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshHP( int nHP, int nMaxHP )
|
|
{
|
|
int nPer = static_cast<int>(m_pDisplayInfo->GetPercent( nHP, nMaxHP ));
|
|
|
|
/// 2011.07.22 - prodongi
|
|
SetChildCaption( "static_hp_value" , CStringUtil::StringFormat( "<font:font_01><b><hcenter><vcenter><size:8>%d / %d", nHP, nMaxHP ).c_str() );
|
|
SetChildCaption( "static_hp_percent", CStringUtil::StringFormat( "<font:font_01><size:8><left><#ffffff><shadow>%d%s", nPer, "%" ).c_str() );
|
|
|
|
KUIControlGauge* pGaugeHP = dynamicCast<KUIControlGauge*>(GetChild( "gauge_hp" ));
|
|
if( pGaugeHP )
|
|
{
|
|
m_pDisplayInfo->RefreshGaugeAndStatic( pGaugeHP, nHP, nMaxHP, nPer, c_dwGaugeFillTime );
|
|
|
|
// 게이지 남은 양에 따라 텍스처 바꿔줌 // 2012.02.03 - servantes
|
|
setHPGaugeTexture( nPer, pGaugeHP, 11 );
|
|
}
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshMP( int nMP, int nMaxMP )
|
|
{
|
|
int nPer = static_cast<int>(m_pDisplayInfo->GetPercent( nMP, nMaxMP ));
|
|
|
|
/// 2011.07.22 - prodongi
|
|
SetChildCaption( "static_mp_value" , CStringUtil::StringFormat( "<font:font_01><b><hcenter><vcenter><size:8>%d / %d", nMP, nMaxMP ).c_str() );
|
|
SetChildCaption( "static_mp_percent", CStringUtil::StringFormat( "<font:font_01><size:8><left><#ffffff><shadow>%d%s", nPer, "%" ).c_str() );
|
|
|
|
KUIControlGauge* pGaugeMP = dynamicCast<KUIControlGauge*>(GetChild( "gauge_mp" ));
|
|
if( pGaugeMP )
|
|
m_pDisplayInfo->RefreshGaugeAndStatic( pGaugeMP, nMP, nMaxMP, nPer, c_dwGaugeFillTime );
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshJP()
|
|
{
|
|
SPlayerInfo & info = m_PlayerInfoMgr.GetPlayerInfo();
|
|
|
|
std::string jpStr;
|
|
jpToString(info.GetJP(), jpStr);
|
|
|
|
SetChildCaption( "mainframe_jp" , CStringUtil::StringFormat("<font:font_01><size:9><left>%s", jpStr.c_str()).c_str());
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshExp()
|
|
{
|
|
SPlayerInfo & info = m_PlayerInfoMgr.GetPlayerInfo();
|
|
|
|
refreshJP();
|
|
|
|
double fPer = ((double)(info.GetCurExp())/info.GetMaxExp())*100.f;
|
|
|
|
/// 2011.07.22 - prodongi
|
|
SetChildCaption( "static_exp_value" , CStringUtil::StringFormat( "<font:font_01><b><hcenter><vcenter><size:8>%I64d / %I64d", info.GetCurExp(), info.GetMaxExp() ).c_str() );
|
|
SetChildCaption( "static_exp_percent", CStringUtil::StringFormat( "<font:font_01><size:8><left><#ffffff><shadow>%02.02f%s", fPer, "%" ).c_str() );
|
|
|
|
KUIControlGauge* pGauge = dynamicCast<KUIControlGauge*>(GetChild( "gauge_exp" ));
|
|
if( pGauge )
|
|
m_pDisplayInfo->RefreshGaugeAndStaticByPercentage( pGauge, (int)fPer, 0 ); // #2.3.1.31
|
|
}
|
|
|
|
// 잡
|
|
void SUICharacterInfoWnd::refreshJobName()
|
|
{
|
|
SPlayerInfo & info = m_PlayerInfoMgr.GetPlayerInfo();
|
|
|
|
SetChildCaption( "static_lv_value" , CStringUtil::StringFormat( "<font:font_01><size:9><left>%d", info.GetLevel() ).c_str() );
|
|
SetChildCaption( "mainframe_jlv_number", CStringUtil::StringFormat( "<font:font_01><size:9><left>%d", info.GetJLv() ).c_str() );
|
|
refreshJP();
|
|
updateName();
|
|
|
|
SetChildCaption( "character_jobname_text", CStringUtil::StringFormat( "<font:font_01><hcenter><#ffffff><size:9><vcenter>%s", info.GetJobName() ).c_str() );
|
|
/// 칭호는 아직 작업 전이므로 빈 공백으로 해 놓는다
|
|
SetChildCaption( "character_title_text", CStringUtil::StringFormat( "<font:font_01><#7b2e00><vcenter><hcenter><size:9>%s", "" ).c_str());
|
|
|
|
//EXP
|
|
refreshExp();
|
|
|
|
// 잡 아이콘
|
|
KUIControlIconStatic* pJobIcon = dynamicCast<KUIControlIconStatic*>(GetChild( "character_job_icon" ));
|
|
if( pJobIcon )
|
|
{
|
|
pJobIcon->SetIcon( c_szDEF_SPR_NAME, GetJobDB().GetJobIconName(info.GetJobID()) );
|
|
pJobIcon->SetTooltip(NULL);
|
|
}
|
|
}
|
|
// 길드
|
|
void SUICharacterInfoWnd::refreshGuildName()
|
|
{
|
|
SetChildCaption( "character_placeguildname_text", CStringUtil::StringFormat( "<font:font_01><vcenter><hcenter><size:9>%s", m_GuildMgr.GetGuildName() ).c_str() );
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshGuildMark(std::string const& iconName)
|
|
{
|
|
KUIControlIconStatic* wnd = dynamicCast<KUIControlIconStatic*>(GetChild("character_guild_icon"));
|
|
|
|
if (iconName.empty())
|
|
{
|
|
wnd->SetIcon("ui_frame.spr", "common_mark_icon_none");
|
|
}
|
|
else
|
|
{
|
|
wnd->SetIcon("ui_frame.spr", iconName.c_str());
|
|
}
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshBaseStat()
|
|
{
|
|
m_subWnd[SUB_BASIC]->refreshBaseStat();
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshBaseItemStat(CreatureStat const& stat)
|
|
{
|
|
m_subWnd[SUB_BASIC]->refreshBaseItemStat(stat);
|
|
}
|
|
|
|
void SUICharacterInfoWnd::refreshBattleStat()
|
|
{
|
|
m_subWnd[SUB_BASIC]->refreshBattleStat();
|
|
}
|
|
void SUICharacterInfoWnd::refreshBattleItemStat(CreatureAttribute const& attribute)
|
|
{
|
|
m_subWnd[SUB_BASIC]->refreshBattleItemStat(attribute);
|
|
}
|
|
|
|
void SUICharacterInfoWnd::setCurSubWnd(int type, bool updateHead)
|
|
{
|
|
m_subWnd[SUB_BASIC]->SetShow(false);
|
|
m_subWnd[SUB_ADDED]->SetShow(false);
|
|
|
|
/// 2011.05.26 - prodongi
|
|
if (updateHead && m_curSubWnd != type)
|
|
{
|
|
KUITabControlSheet* tabSheet = dynamicCast<KUITabControlSheet*>(GetChild("tab_character_01"));
|
|
if (tabSheet) tabSheet->SetSelectHead((DWORD)type);
|
|
}
|
|
|
|
m_curSubWnd = type;
|
|
m_subWnd[type]->SetShow(true);
|
|
|
|
///
|
|
if (SUB_BASIC == type)
|
|
{
|
|
SetChildAsTop("tab_added_01");
|
|
SetChildAsTop("window_player_character_info_sub_basic");
|
|
SetChildAsTop("tab_basic_01");
|
|
|
|
setExpand(m_subWnd[SUB_BASIC]->isExpand());
|
|
}
|
|
else if (SUB_ADDED == type)
|
|
{
|
|
SetChildAsTop("tab_basic_01");
|
|
SetChildAsTop("window_player_character_info_sub_added");
|
|
SetChildAsTop("tab_added_01");
|
|
|
|
setExpand(m_subWnd[SUB_ADDED]->isExpand());
|
|
|
|
m_pGameManager->PostMsgAtDynamic( new SMSG_INSTANCE_GAME_SCORE_REQUEST() );
|
|
}
|
|
}
|
|
|
|
void SUICharacterInfoWnd::setExpand(bool expand)
|
|
{
|
|
KRect r;
|
|
int fhType = (!expand) ? FH_ORI : FH_EXPAND;
|
|
sFrameHeight fh;
|
|
memcpy(&fh, m_frameHeight + fhType, sizeof (fh));
|
|
|
|
KUIWnd* wnd;
|
|
|
|
/// inframe
|
|
wnd = GetChild("inframe");
|
|
r = wnd->GetRect();
|
|
r.bottom = r.top + fh.m_in;
|
|
wnd->Resize(r);
|
|
|
|
/// outframe
|
|
wnd = GetChild("outframe");
|
|
r = wnd->GetRect();
|
|
r.bottom = r.top + fh.m_out - 2; /// 왜 -2만큼 해야 이미지가 안 짤리는지 잘 모르겠음,,,
|
|
wnd->Resize(r);
|
|
|
|
/// wnd
|
|
r = GetRect();
|
|
r.bottom = r.top + fh.m_wnd;
|
|
Resize(r);
|
|
|
|
if (expand)
|
|
LimitMoveWnd();
|
|
}
|
|
|
|
void SUICharacterInfoWnd::initFrameHeightData()
|
|
{
|
|
KUIWnd* wnd;
|
|
|
|
wnd = GetChild("inframe");
|
|
m_frameHeight[FH_ORI].m_in = wnd->GetRect().GetHeight();
|
|
wnd = GetChild("outframe");
|
|
m_frameHeight[FH_ORI].m_out = wnd->GetRect().GetHeight();
|
|
m_frameHeight[FH_ORI].m_wnd = GetRect().GetHeight();
|
|
|
|
wnd = GetChild("inframe_01");
|
|
m_frameHeight[FH_EXPAND].m_in = wnd->GetRect().GetHeight();
|
|
wnd = GetChild("outframe_01");
|
|
m_frameHeight[FH_EXPAND].m_out = wnd->GetRect().GetHeight();
|
|
m_frameHeight[FH_EXPAND].m_wnd = GetRect().GetHeight() + (m_frameHeight[FH_EXPAND].m_out - m_frameHeight[FH_ORI].m_out);
|
|
}
|
|
|
|
void SUICharacterInfoWnd::updateName()
|
|
{
|
|
sArenaSystem* arenaSystem = g_pCurrentGameSystem->getArenaSystem();
|
|
SetName(arenaSystem->getPlayerName(&m_PlayerInfoMgr));
|
|
}
|
|
|
|
void SUICharacterInfoWnd::SetName(char const* name)
|
|
{
|
|
SetChildCaption( "static_character_name", CStringUtil::StringFormat( "<font:font_01><left><size:9><#ffffff><hcenter>%s", name ).c_str() );
|
|
}
|