Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
594 lines
14 KiB
C++
594 lines
14 KiB
C++
#include "MW4Headers.hpp"
|
|
//상훈 앞
|
|
#include "MWMission.hpp"
|
|
#include "VehicleInterface.hpp"
|
|
#include "Narc.hpp"
|
|
#include "MWGUIManager.hpp"
|
|
#include "MWGame.hpp"
|
|
#include "gameinfo.hpp"
|
|
#include "AI_Statistics.hpp"
|
|
#include "AI_UserConstants.hpp"
|
|
#include "GameTypes.h"
|
|
#include "MWObject.hpp"
|
|
#include "mwguimanager.hpp"
|
|
#include "MWPlayer.hpp"
|
|
#include <Adept\Mission.hpp>
|
|
//상훈 뒤
|
|
|
|
#include "hudcomp.hpp"
|
|
#include "HUDComm.hpp"
|
|
#include "mwapplication.hpp"
|
|
#include "ai_groups.hpp"
|
|
#include "ai.hpp"
|
|
#include "lancemate.hpp"
|
|
#include "mech.hpp"
|
|
#include "..\missionlang\resource.h"
|
|
#include "mechlabheaders.h"
|
|
|
|
//상훈짱 begin
|
|
#include <windows.h>
|
|
#include <ddraw.h>
|
|
#include <d3d.h>
|
|
|
|
#include <GameOS\render.hpp>
|
|
|
|
//상훈짱 end
|
|
|
|
using namespace MechWarrior4;
|
|
|
|
const char* talker_suffixes[]={
|
|
"_IAN",
|
|
"_RAT",
|
|
"_CAS",
|
|
"_GON",
|
|
"_JEN",
|
|
"_TER",
|
|
"_DAM",
|
|
"_RES",
|
|
"_65C",
|
|
"_EV1",
|
|
"_EV2",
|
|
"_SAL",
|
|
"_REC",
|
|
"_SUP",
|
|
"_FO1",
|
|
"_FO2",
|
|
"_FO3",
|
|
"_FO4",
|
|
"_FO5",
|
|
"_FO6",
|
|
"_PI1",
|
|
"_PI2",
|
|
"_PI3",
|
|
"_PI4",
|
|
"_ART",
|
|
"_SHE",
|
|
"_BD1",
|
|
"_BD2",
|
|
"_FOX",
|
|
"_KIL",
|
|
"_SGT",
|
|
"_ROM",
|
|
"_XRY",
|
|
"_CCG",
|
|
"_ERL",
|
|
"_PA1",
|
|
"_PA2",
|
|
"_PA3",
|
|
"_PA4",
|
|
"_BRV",
|
|
"_CHL",
|
|
"_DEN",
|
|
"_RCG",
|
|
"_VRD",
|
|
"_VOR",
|
|
"_HQ1",
|
|
"_HQ2",
|
|
"_HQ3",
|
|
"_MED",
|
|
"_SFQ",
|
|
"_CJK",
|
|
"_ABC",
|
|
"_BRK",
|
|
"_CST",
|
|
"_ROL",
|
|
"_WIL",
|
|
"_EPS",
|
|
"_PET",
|
|
"_EP2",
|
|
"_BET"
|
|
};
|
|
|
|
|
|
HUDComm::HUDComm() :
|
|
m_CurAudio (NULL)
|
|
{
|
|
static Scalar realright[LastMechID+1] = {94,92,108,129,105,112,102,93,119,83,105,114,101,107,92,93,122,113,87,88,105 };
|
|
|
|
int i;
|
|
MWApplication *app;
|
|
// m_Lancemates.clear ();
|
|
m_LanceCommands.clear ();
|
|
m_AnimTime = 0;
|
|
m_AnimLoc = 0;
|
|
Lancemate_Line_Size = 15;
|
|
|
|
app = MWApplication::GetInstance ();
|
|
AddTexture ("hud\\hud5",0,4,123,41,130); // health bar
|
|
Location (Point3D (0,0,0.9f));
|
|
Color (0,125,0,250);
|
|
DeselectLancemate ();
|
|
|
|
for (i=0;i<=LastMechID;i++)
|
|
{
|
|
AddTexture ("hud\\hud5",10+i,62,71+(i*8.0f),realright[i],72+7+(i*8.0f));
|
|
}
|
|
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands[0]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND1));
|
|
m_LanceCommands[1]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND2));
|
|
m_LanceCommands[2]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND3));
|
|
m_LanceCommands[3]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND4));
|
|
m_LanceCommands[4]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND5));
|
|
m_LanceCommands[5]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND6));
|
|
m_LanceCommands[6]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND7));
|
|
m_LanceCommands[7]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND8));
|
|
m_LanceCommands[8]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND9));
|
|
|
|
m_LanceCommands[0]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[1]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[2]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[3]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[4]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[5]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[6]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[7]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[8]->Justification (HUDText::LEFT_ALIGN);
|
|
|
|
m_LanceCommands[0]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[1]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[2]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[3]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[4]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[5]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[6]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[7]->Color (MakeColor (0,225,0,230));
|
|
m_LanceCommands[8]->Color (MakeColor (0,225,0,230));
|
|
|
|
m_LanceCommands[0]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[1]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[2]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[3]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[4]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[5]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[6]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[7]->SetSize (HUDText::MEDIUM_SIZE);
|
|
m_LanceCommands[8]->SetSize (HUDText::MEDIUM_SIZE);
|
|
|
|
if(MWApplication::GetInstance()->networkingFlag)
|
|
{
|
|
m_LanceCommands.push_back (new HUDText ());
|
|
m_LanceCommands[9]->UpdateText (app->GetLocString (IDS_LANCEMATECOMMAND10));
|
|
m_LanceCommands[9]->Justification (HUDText::LEFT_ALIGN);
|
|
m_LanceCommands[9]->Color (MakeColor (0,125,0,230));
|
|
m_LanceCommands[9]->SetSize (HUDText::MEDIUM_SIZE);
|
|
}
|
|
// m_PlayingVideo = false;
|
|
}
|
|
|
|
HUDComm::~HUDComm()
|
|
{
|
|
stlport::vector<HUDText *>::iterator iter;
|
|
|
|
for (iter = m_LanceCommands.begin ();iter!= m_LanceCommands.end ();iter++)
|
|
{
|
|
delete (*iter);
|
|
(*iter) = NULL;
|
|
}
|
|
m_LanceCommands.clear ();
|
|
ClearLancemates ();
|
|
}
|
|
|
|
void HUDComm::ClearLancemates (void)
|
|
{
|
|
stlport::vector<HUDText *>::iterator iter;
|
|
for (iter = m_LanceMech.begin ();iter!= m_LanceMech.end ();iter++)
|
|
{
|
|
delete (*iter);
|
|
(*iter) = NULL;
|
|
}
|
|
for (iter = m_LanceName.begin ();iter!= m_LanceName.end ();iter++)
|
|
{
|
|
delete (*iter);
|
|
(*iter) = NULL;
|
|
}
|
|
// m_Lancemates.clear ();
|
|
m_LanceMech.clear ();
|
|
m_LanceName.clear ();
|
|
}
|
|
|
|
void HUDComm::Reset (void)
|
|
{
|
|
ClearLancemates ();
|
|
}
|
|
|
|
void HUDComm::SetupLancemates (void)
|
|
{
|
|
// HUDText *text;
|
|
ClearLancemates ();
|
|
#if 0
|
|
stlport::vector<MWObject *> lance;
|
|
stlport::vector<MWObject *>::iterator iter;
|
|
|
|
MW4AI::Groups::GetLancemates (lance);
|
|
for (iter = lance.begin ();iter != lance.end ();iter++)
|
|
{
|
|
Check_Object ((*iter)->GetAI ());
|
|
m_Lancemates.push_back ((*iter)->GetAI ());
|
|
|
|
AI *ai;
|
|
ai = (*iter)->GetAI ();
|
|
if (!ai)
|
|
continue;
|
|
LancematePlug *lance;
|
|
text = new HUDText ();
|
|
text->Color (0,255,0,250);
|
|
text->Justification (HUDText::LEFT_ALIGN);
|
|
text->Size (-10);
|
|
lance = ai->GetLancemate ();
|
|
if (!lance) // so some of the test missio
|
|
text->UpdateText ("Unknown");
|
|
else
|
|
text->UpdateText (lance->m_lancemateName);
|
|
|
|
m_LanceName.push_back (text);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void HUDComm::Update (Stuff::Time till)
|
|
{
|
|
if (m_AnimTime == 0)
|
|
m_AnimTime = till;
|
|
|
|
int size;
|
|
size = (int) m_Textures[0]->Size ().x;
|
|
while (m_AnimTime <= till)
|
|
{
|
|
m_AnimLoc++;
|
|
if (m_AnimLoc >= (size-1))
|
|
m_AnimLoc = 0;
|
|
m_AnimTime += 1.0/26.0;
|
|
}
|
|
|
|
#if 0
|
|
if (m_PlayingVideo)
|
|
{
|
|
while (m_VideoTime <= till)
|
|
{
|
|
m_VideoFrame++;
|
|
if (m_VideoFrame > 3)
|
|
m_VideoFrame = 0;
|
|
m_VideoTime += 1.0/1.0;
|
|
}
|
|
}
|
|
#endif
|
|
if (!m_CurAudio.GetCurrent ())
|
|
StopVideo ();
|
|
|
|
inherited::Update (till);
|
|
}
|
|
|
|
Scalar HUDComm::BottomY (void) const
|
|
{
|
|
Point3D loc;
|
|
int count;
|
|
int fred;
|
|
|
|
if (!m_Vehicle.GetCurrent ())
|
|
return 0;
|
|
|
|
stlport::vector<MWObject *> lance;
|
|
MW4AI::Groups::GetLancemates (lance);
|
|
|
|
count = lance.size ();
|
|
if (m_ActiveLancemate != -1)
|
|
count += m_LanceCommands.size ();
|
|
loc = Location ();
|
|
|
|
if (count)
|
|
{
|
|
DWORD x,y;
|
|
m_LanceCommands[0]->DrawSize (x,y);
|
|
fred = y + 8;
|
|
}
|
|
else
|
|
fred = 0;
|
|
|
|
return ((count * fred) + loc.y);
|
|
}
|
|
|
|
void HUDComm::PlayVideo (int person,AudioCommand *command)
|
|
{
|
|
m_WhoTalking = person;
|
|
if (command == m_CurAudio.GetCurrent ())
|
|
return;
|
|
else if (m_CurAudio.GetCurrent ())
|
|
m_CurAudio.Remove ();
|
|
if (person == -1)
|
|
{
|
|
StopVideo ();
|
|
return;
|
|
}
|
|
Verify (command);
|
|
m_CurAudio.Add (command);
|
|
/*
|
|
char buf[128];
|
|
Verify (person>=0);
|
|
Verify (person < (sizeof (talker_suffixes)/sizeof (const char *)));
|
|
strcpy (buf,"HUD\\speaker");
|
|
Str_Cat (buf,talker_suffixes[person],128);
|
|
AddTexture (buf,1,0,0,256,256);
|
|
m_Textures[1]->BlendMode (gos_BlendDecal);
|
|
m_Textures[1]->AlphaMode (gos_Alpha_OneZero);
|
|
m_PlayingVideo = true;
|
|
m_VideoTime = gos_GetElapsedTime ();
|
|
m_VideoFrame = 0;
|
|
*/
|
|
}
|
|
|
|
void HUDComm::StopVideo (void)
|
|
{
|
|
m_WhoTalking = -1;
|
|
if (m_CurAudio.GetCurrent ())
|
|
m_CurAudio.Remove ();
|
|
/*
|
|
m_PlayingVideo = false;
|
|
m_VideoFrame = 0;
|
|
*/
|
|
}
|
|
|
|
bool HUDComm::IsTalker (LancematePlug *plug)
|
|
{
|
|
if (m_WhoTalking == -1)
|
|
return false;
|
|
if (!plug)
|
|
return false;
|
|
if (!strncmp ((const char *) (plug->m_TalkerSuffix),talker_suffixes[m_WhoTalking],4))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void HUDComm::DrawImplementation(void)
|
|
{
|
|
if(!hsh_initialized){
|
|
int count,i;
|
|
Point3D loc,size;
|
|
Scalar yvalue;
|
|
HUDText *text;
|
|
Point3D videopos;
|
|
|
|
stlport::vector<MWObject *> lance;
|
|
|
|
MW4AI::Groups::GetLancemates (lance);
|
|
|
|
loc = Location ();
|
|
count = lance.size ();
|
|
// if (m_PlayingVideo)
|
|
// DeselectLancemate ();
|
|
|
|
if (m_ActiveLancemate != -1)
|
|
count += m_LanceCommands.size ();
|
|
if (count == 0)
|
|
return;
|
|
|
|
videopos.x = 5;
|
|
videopos.y = 5;
|
|
videopos.z = 0.9f;
|
|
if (count)
|
|
{
|
|
text = new HUDText ();
|
|
text->SetSize (HUDText::MEDIUM_SIZE);
|
|
Verify (lance[0]);
|
|
DWORD x=0,y=0;
|
|
if (!lance[0])
|
|
return;
|
|
{
|
|
AI *ai;
|
|
ai = lance[0]->GetAI ();
|
|
if (ai)
|
|
{
|
|
LancematePlug *lanceplug;
|
|
text->Color (0,255,0,250);
|
|
text->Justification (HUDText::LEFT_ALIGN);
|
|
lanceplug = ai->GetLancemate ();
|
|
if (!lanceplug) // so some of the test mission work
|
|
text->UpdateText (" ");
|
|
else
|
|
text->UpdateText (lanceplug->m_lancemateName);
|
|
}
|
|
else
|
|
text->UpdateText (" ");
|
|
text->DrawSize (x,y);
|
|
}
|
|
Lancemate_Line_Size = y + 4;
|
|
|
|
text->Color (0,255,0,250);
|
|
text->Justification (HUDText::LEFT_ALIGN);
|
|
|
|
Size (Point3D (192,(Scalar) (count*Lancemate_Line_Size),0.9f));
|
|
size = Size ();
|
|
|
|
DWORD bcolor = BrighterColor (Color ());
|
|
DrawRect (loc,size,MakeColor (5,15,5,200));
|
|
DrawSpecFrame (loc,size,bcolor);
|
|
|
|
loc.y += 2;
|
|
loc.x += 2;
|
|
yvalue = loc.y;
|
|
size.x -= 4;
|
|
Point3D r,s;
|
|
r.z = 0.0f;
|
|
s.z = 0.0f;
|
|
Point3D texsize;
|
|
texsize = m_Textures[0]->Size ();
|
|
Point3D rtl,rbr;
|
|
rtl.x = m_Textures[0]->Left ()*256.0f;
|
|
rtl.y = m_Textures[0]->Top ()*256.0f;
|
|
rbr.x = m_Textures[0]->Right ()*256.0f;
|
|
rbr.y = m_Textures[0]->Bottom ()*256.0f;
|
|
|
|
for (i=0;i<lance.size();i++,yvalue += Lancemate_Line_Size)
|
|
{
|
|
AI *ai;
|
|
ai = lance[i]->GetAI ();
|
|
if (!ai)
|
|
continue;
|
|
Mech *mech;
|
|
mech = Cast_Object (Mech *,ai->getEntity ());
|
|
|
|
LancematePlug *plug;
|
|
plug = ai->GetLancemate ();
|
|
if (!plug) // so some of the test missio
|
|
text->UpdateText (" ");
|
|
else
|
|
text->UpdateText (plug->m_lancemateName);
|
|
r.x = loc.x;
|
|
r.y = yvalue;
|
|
s.x = size.x;
|
|
s.y = Lancemate_Line_Size-2.0f;
|
|
|
|
if (IsTalker (plug))
|
|
{
|
|
DWORD mechcolor = MakeColor (0,0,255,200);
|
|
DrawRect (Point3D (r.x-1,r.y-1,0.9f),Point3D (s.x+3,s.y+1,0.9f),mechcolor);
|
|
}
|
|
else
|
|
{
|
|
if (lance[i]->IsDerivedFrom (Mech::DefaultData))
|
|
{
|
|
mech = Cast_Object (Mech *,lance[i]);
|
|
Scalar dam = mech->AverageDamage ();
|
|
DWORD mechcolor = MakeColor (0,0,0,250);
|
|
if (!mech->IsDestroyed ())
|
|
{
|
|
if (dam < 1.0f)
|
|
mechcolor = MakeColor (0,128,0,200);
|
|
else if (dam < 3.0f)
|
|
mechcolor = MakeColor (255,255,0,200);
|
|
else
|
|
mechcolor = MakeColor (255,0,0,200);
|
|
}
|
|
DrawRect (Point3D (r.x-1,r.y-1,0.9f),Point3D (s.x+3,s.y+1,0.9f),mechcolor);
|
|
}
|
|
else
|
|
DrawRect (Point3D (r.x-1,r.y-1,0.9f),Point3D (s.x+3,s.y+1,0.9f),MakeColor (5,150,5,200));
|
|
}
|
|
|
|
text->Draw (Point3D (r.x+4.0f,r.y+1.0f,0.9f));
|
|
|
|
if (lance[i]->IsDerivedFrom (Mech::DefaultData))
|
|
{
|
|
int mechid=-1;
|
|
mech = Cast_Object (Mech *,lance[i]);
|
|
Scalar dam = mech->AverageDamage ();
|
|
const Mech__GameModel *model = static_cast<const Mech__GameModel *> (mech->GetGameModel ());
|
|
mechid = model->mechID;
|
|
DWORD mechcolor = MakeColor (0,0,0,250);
|
|
if (!mech->IsDestroyed ())
|
|
{
|
|
if (dam < 1.0f)
|
|
mechcolor = MakeColor (0,250,0,250);
|
|
else if (dam < 3.0f)
|
|
mechcolor = MakeColor (255,255,0,250);
|
|
else
|
|
mechcolor = MakeColor (255,0,0,250);
|
|
}
|
|
Scalar tx,ty;
|
|
tx = r.x+(size.x/2.0f) - ((rbr.x-rtl.x)/2.0f);
|
|
ty = r.y+((Lancemate_Line_Size - texsize.y)/2.0f);
|
|
Min_Clamp (ty,r.y);
|
|
/*
|
|
m_Textures[0]->TopLeft (rtl.x,rtl.y);
|
|
m_Textures[0]->BottomRight (rbr.x-m_AnimLoc,rbr.y);
|
|
m_Textures[0]->Draw (Point3D (tx+m_AnimLoc,ty,0.9f),m_Textures[0]->Size (),mechcolor,HUDTexture::NO_FLIP,true);
|
|
|
|
m_Textures[0]->TopLeft (rbr.x-m_AnimLoc,rtl.y);
|
|
m_Textures[0]->BottomRight (rbr.x,rbr.y);
|
|
m_Textures[0]->Draw (Point3D (tx,ty,0.9f),m_Textures[0]->Size (),mechcolor,HUDTexture::NO_FLIP,true);
|
|
*/
|
|
|
|
if (mechid == 4) // easy fix for glitch in art
|
|
mechid = 5;
|
|
else if (mechid == 5)
|
|
mechid = 4;
|
|
|
|
Point3D namesize = m_Textures[10+mechid]->Size ();
|
|
ty = r.y+((Lancemate_Line_Size - namesize.y)/2.0f);
|
|
Min_Clamp (ty,r.y);
|
|
m_Textures[10+mechid]->Draw (Point3D (r.x+size.x - m_Textures[10+mechid]->Size().x,ty,0.9f),m_Textures[10+mechid]->Size (),MakeColor (255,255,255,255));
|
|
}
|
|
if (m_ActiveLancemate == (i+1))
|
|
DrawFrame (r,s,bcolor);
|
|
videopos.x = r.x+5;
|
|
videopos.y = r.y+5;
|
|
}
|
|
m_Textures[0]->TopLeft (rtl.x,rtl.y);
|
|
m_Textures[0]->BottomRight (rbr.x,rbr.y);
|
|
delete text;
|
|
if (m_ActiveLancemate != -1)
|
|
{
|
|
r.z = 0.0f;
|
|
for (i=0;i<m_LanceCommands.size();i++,yvalue += Lancemate_Line_Size)
|
|
{
|
|
r.x = loc.x;
|
|
r.y = yvalue;
|
|
s.x = size.x;
|
|
s.y = Lancemate_Line_Size-4.0f;
|
|
m_LanceCommands[i]->TopLeft (loc.x,loc.y);
|
|
m_LanceCommands[i]->BottomRight (r.x+size.x,r.y+size.y);
|
|
m_LanceCommands[i]->Draw (r);
|
|
}
|
|
}
|
|
}
|
|
#if 0
|
|
if (m_PlayingVideo)
|
|
{
|
|
|
|
switch (m_VideoFrame)
|
|
{
|
|
case 0:
|
|
m_Textures[1]->TopLeft (0,0);
|
|
m_Textures[1]->BottomRight (128,128);
|
|
break;
|
|
case 1:
|
|
m_Textures[1]->TopLeft (128,0);
|
|
m_Textures[1]->BottomRight (256,128);
|
|
break;
|
|
case 2:
|
|
m_Textures[1]->TopLeft (0,128);
|
|
m_Textures[1]->BottomRight (128,256);
|
|
break;
|
|
case 3:
|
|
m_Textures[1]->TopLeft (128,128);
|
|
m_Textures[1]->BottomRight (256,256);
|
|
break;
|
|
}
|
|
|
|
m_Textures[1]->Draw (videopos,m_Textures[1]->Size (),MakeColor (255,255,255,255));
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|