#include "CResFile.h" #include "GlobalFunc.h" #include "T2BitImage.h" #include "T2CtrlPalette.h" #include "T2DateTime.h" #include "T2Dialog.h" #include "T2DlgItem.h" #include "T2DLL.h" #include "T2EquipPtrList.h" #include "T2FireBurning.h" #include "T2FloorInfo.h" #include "T2ImageObj.h" #include "T2MainWindow.h" #include "T2People.h" #include "T2PeoplePtrList.h" #include "T2RegistedTenantDB.h" #include "T2Settlement.h" #include "T2SoundPlayer.h" #include "T2Sprite.h" #include "T2Tenant.h" #include "T2ToolWindow.h" #include "T2TowerDoc.h" #include "T2TowerEvent.h" #include "T2TowerMainView.h" #include "T2TowerMessage.h" #include "T2WorldDef.h" #include "UT2Coordinate.h" #include "UT2Utils.h" T2FireBurning::T2FireBurning(T2TowerEvent* inTowerEvent, CResFile* inResFile, int inSubID) : T2EventItem(inTowerEvent, inResFile, inSubID) { mFightAction = kFireFightNull; mFireArray = NULL; mHelicopter = NULL; mAttach = NULL; mImage = NULL; mImageObj = NULL; *inResFile >> mHelicopterPrice; *inResFile >> m40; if (inResFile->IsBinaryMode()) { int tmp; for (int i = 0; i < m40; i++) *inResFile >> tmp; } mPeopleList = new T2PeoplePtrList; } /*virtual*/ T2FireBurning::~T2FireBurning() { if (mStatus == kFireBurningStatus1) StopEvent(mTowerEvent->mDocument); delete mPeopleList; } /*virtual*/ BOOL T2FireBurning::Start(T2TowerDoc* inDoc) { BOOL started = false; CPoint pt; T2Tenant *theTenant; if (IsBreakoutFire(inDoc, pt, theTenant)) { mStatus = kFireBurningStatus1; StartEvent(inDoc, pt, theTenant); inDoc->towerDoc_vf2B0(true); switch (mFightAction) { case kFireFightHelicopter: { CString text = LoadStringTable(GetWorldModuleHandle(), 8100, 1); DoAlert(inDoc, text, 0); inDoc->DoPay(mHelicopterPrice, kFundGroup2); inDoc->SetDrawSpeed(25); Sounds->Play("FIREBURNING:HELI", SoundMask_10, SoundFlags_10 | SoundFlags_10000, NULL, PlayMode_3, 100); break; } case kFireFightFireman: inDoc->SetDrawSpeed(25); break; } mTimePassed = 0; started = true; } return started; } /*virtual*/ int T2FireBurning::Exec(T2TowerDoc* inDoc) { CString str; switch (mStatus) { case kFireBurningStatus1: if (mFightAction != kFireFightNull) { if (mHelicopter) mHelicopter->Move(inDoc); mTimePassed++; IdleEvent(inDoc); T2DateTime *theNow = inDoc->GetNow(); if (!mFireArray || mFireArray->GetCount() == 0 || theNow->GetRawMinutes() == mEndTime) mStatus = kFireBurningStatus2; } return IsExclusive() ? 1 : 0; case kFireBurningStatus2: StopEvent(inDoc); str = LoadStringTable(GetWorldModuleHandle(), 8100, 2); DoAlert(inDoc, str, 0); return 3; } return 0; } /*virtual*/ void T2FireBurning::StartEvent(T2TowerDoc* inTowerDoc, POINT inPt, const T2Tenant* inTenant) { T2FloorInfo *theFloorInfo = inTowerDoc->GetFloorInfo(); mFightAction = kFireFightNull; mFireArray = new LArray; inTowerDoc->SetViewMode(kInView); inTowerDoc->SetDrawSpeed(25); inTowerDoc->SetFireBurning(true); inTowerDoc->towerDoc_vf1A0(true); inTowerDoc->towerDoc_vf2A0()->EnableIcon(false); inTowerDoc->GetMainView()->HideToolSprite(); inTowerDoc->BreakoutEmergency(); Sounds->FadeOut(); Sounds->AddSound("FIREBURNING:", SoundPriority_1, 8100, GetWorldModuleHandle()); Sounds->AddSound("FIREBURNING:HELI", SoundPriority_1, 8101, GetWorldModuleHandle()); Sounds->AddSound("FIREBURNING:FIRE", SoundPriority_1, 8102, GetWorldModuleHandle()); Sounds->Play("FIREBURNING:", SoundMask_10, SoundFlags_10 | SoundFlags_10000, NULL, PlayMode_0, 100); CString dialogText; dialogText.Format("%d", inTowerDoc->GetFloorInfo()->UnitToFloor(inPt.y)); dialogText += LoadStringTable(GetWorldModuleHandle(), 8100, 3); DoDialog(inTowerDoc, 8100, 5100, 3, dialogText); if (!mImage) mImage = new T2BitImage(inTowerDoc->mWorldDef->mModuleHandle, 5000, true); if (!mImageObj) { mImageObj = new T2ImageObj; mImageObj->AddObject(inTowerDoc->mWorldDef->mModuleHandle, 5000, mImage); SIZE size; mImageObj->GetObjectSize(mImageObj->FindObject("FIRE", 0), &size); mFireWidth = size.cx / 8; } MakeFire(inPt, inTowerDoc); // should this be called theView? as per Mac asserts T2TowerMainView *theTowerMainView = inTowerDoc->GetMainView(); CRect area; inTenant->GetEquipArea(area); theTowerMainView->CenterOnRect(area); T2_MAIN_WINDOW->mCtrlPalette->vf108(0); Sounds->Play("FIREBURNING:FIRE", SoundMask_10, SoundFlags_10 | SoundFlags_10000, NULL, PlayMode_3, 100); dialogText = LoadStringTable(GetWorldModuleHandle(), 8100, 4); switch (DoDialog(inTowerDoc, 8110, 5101, 1, dialogText)) { case 8114: mHelicopter = new T2Helicopter(inTowerDoc, inTenant); mFightAction = kFireFightHelicopter; break; case 8115: CallFireman(inTowerDoc, inTenant); mFightAction = kFireFightFireman; break; case 8116: mFightAction = kFireFightDoNothing; break; } mAttach = new T2FireAttach(this, 0, true); theTowerMainView->AddAttachment(mAttach, NULL, true); if (mFightAction == kFireFightHelicopter) theTowerMainView->SetTimer(100, 55, NULL); } /*virtual*/ void T2FireBurning::SetupDialog(T2Dialog* inDialog) { if (inDialog->mTemplate.resID == 8100) return; ((T2DlgItem *) inDialog->GetDlgItem(8114))->AddListener(inDialog); ((T2DlgItem *) inDialog->GetDlgItem(8115))->AddListener(inDialog); ((T2DlgItem *) inDialog->GetDlgItem(8116))->AddListener(inDialog); } /*virtual*/ unsigned int T2FireBurning::DialogHook(T2EventDialog* inDialog, unsigned int inResult, T2TowerDoc* inDoc) { CString theString; T2TowerMessage *theTowerMsg = inDoc->mTowerMessage; T2FloorInfo *theFloorInfo; T2Tenant *theTenant; switch (inResult) { case 8114: if (inDoc->GetCurrentFunds() < mHelicopterPrice) { theString = LoadStringTable(GetWorldModuleHandle(), 8100, 5); DoAlert(inDoc, theString, 9000); inResult = 0; } break; case 8115: theFloorInfo = inDoc->GetFloorInfo(); theTenant = theFloorInfo ? theFloorInfo->GetTenantByPID('KEBI') : NULL; if (!theTenant) { theString = LoadStringTable(GetWorldModuleHandle(), 8100, 6); DoAlert(inDoc, theString, 9000); inResult = 0; } break; } return inResult; } /*virtual*/ void T2FireBurning::IdleEvent(T2TowerDoc* inDoc) { if (mFireArray) { if (mFightAction == kFireFightFireman) { T2Fire *fire = NULL; if (mFireArray->GetCount() > 0) mFireArray->FetchItemAt(mFireArray->GetCount(), &fire); LArrayIterator iterator(*mPeopleList); T2People *people; while (iterator.Next(&people)) { if (people->GetStatus() == kStatus15) { if (fire) { people->SetDestination(fire->GetArsonTenant()->GetEquipID()); people->ChangeStyle(kPeopleStyle2); people->ChangeStatus(kStatus3); } else { people->ChangeStyle(kPeopleStyle1); } } } } T2Fire *theFire; int index = 1; while (mFireArray->FetchItemAt(index, &theFire)) { BOOL flag = false; if ((mTimePassed % 1) == 0) flag = theFire->Move(); if (!flag && mFightAction == kFireFightFireman && theFire->ExtinguishByFireman(inDoc, mPeopleList)) { flag = true; Extinguish(theFire); } if (!flag) index++; } } } /*virtual*/ void T2FireBurning::StopEvent(T2TowerDoc* inDoc) { T2TowerMainView *theView = inDoc->GetMainView(); theView->KillTimer(100); if (mFireArray) { LArrayIterator iterator(*mFireArray); T2Fire *theFire; while (iterator.Next(&theFire)) delete theFire; delete mFireArray; mFireArray = NULL; delete mImageObj; mImageObj = NULL; delete mImage; mImage = NULL; } if (mHelicopter) { delete mHelicopter; mHelicopter = NULL; } if (theView && mAttach) { theView->RemoveAttachment(mAttach); delete mAttach; mAttach = NULL; theView->Invalidate(true); theView->tmv_vf120(); } mStatus = kFireBurningStatus0; mFightAction = kFireFightNull; LArrayIterator iterator(*mPeopleList); T2People *theFireman; while (iterator.Next(&theFireman)) { theFireman->ChangeStyle(kPeopleStyle1); theFireman->SetReturnToDestination(); theFireman->SetStatus(kStatus3); theFireman->ClearSpecialFlag(kSpecialFlag20 | kSpecialFlag40); theFireman->ClearColor(); } mPeopleList->RemoveItemsAt(mPeopleList->GetCount(), 1); inDoc->towerDoc_vf2B0(false); Sounds->Stop("FIREBURNING:"); Sounds->Stop("FIREBURNING:HELI"); Sounds->Stop("FIREBURNING:FIRE"); Sounds->DeleteSound("FIREBURNING:"); Sounds->DeleteSound("FIREBURNING:HELI"); Sounds->DeleteSound("FIREBURNING:FIRE"); Sounds->FadeIn(); inDoc->towerDoc_vf1A0(false); inDoc->SetFireBurning(false); if (inDoc->GetMainView()) inDoc->GetMainView()->UnhideToolSprite(); if (inDoc->towerDoc_vf2A0()) inDoc->towerDoc_vf2A0()->EnableIcon(true); } BOOL T2FireBurning::MakeFire(POINT inPt, T2TowerDoc* inDoc) { BOOL createdFire = false; T2FloorInfo *theFloorInfo = inDoc->GetFloorInfo(); T2Tenant *theTenant = theFloorInfo->GetTenant(inPt.y, inPt.x); if (theTenant && !theTenant->IsFire() && !theTenant->IsFireproof()) { CRect rect; if (AdjustFirePos(theFloorInfo, inPt, rect)) { for (unsigned int i = 0; i < 2; i++) { T2Fire *theFire = new T2Fire(rect.TopLeft(), inDoc, i ? -1 : 1, mImageObj); mFireArray->Add(&theFire); } for (int h = rect.left; h < rect.right; h++) { T2Tenant *tenant = theFloorInfo->GetTenant(rect.top, h); if (tenant && !tenant->IsFireproof() && !tenant->IsFire()) tenant->BurntDown(inDoc); } createdFire = true; } } return createdFire; } BOOL T2FireBurning::AdjustFirePos(T2FloorInfo* inFloorInfo, POINT& inPt, RECT& outRect) const { BOOL success = false; int distance = mFireWidth / 2; SetRect(&outRect, inPt.x - distance, inPt.y, inPt.x + distance, inPt.y + 1); int dir = 0; for (unsigned int i = 0; i <= distance; i++) { if (inFloorInfo->GetTenant(outRect.top, outRect.left)) { if (inFloorInfo->GetTenant(outRect.top, outRect.right - 1)) { if (inFloorInfo->IsAllTenant(outRect)) { success = true; break; } break; } if (dir <= 0) { dir = -1; OffsetRect(&outRect, dir, 0); } else { break; } } else if (inFloorInfo->GetTenant(outRect.top, outRect.right - 1)) { if (dir >= 0) { dir = 1; OffsetRect(&outRect, dir, 0); } else { break; } } } return success; } void T2FireBurning::Extinguish(T2Fire* inFire) { mFireArray->Remove(&inFire); T2People *theFireman = inFire->GetFireman(); if (theFireman) { theFireman->ChangeStyle(kPeopleStyle1); theFireman->ChangeStatus(kStatus15); mPeopleList->InsertItemsAt(1, 1, &theFireman); } delete inFire; } BOOL T2FireBurning::DoExtinguish(CPoint& inPt) { LArrayIterator iterator(*mFireArray); CRect rect; T2Fire *theFire; while (iterator.Next(&theFire)) { if (theFire->HitTest(inPt, rect)) { Extinguish(theFire); return true; } } return false; } void T2FireBurning::CallFireman(T2TowerDoc* inDoc, const T2Tenant* inTenant) { T2RegistedTenantDB *theDB = inDoc->GetRegistedTenantDB(); T2EquipPtrList *theList = theDB->GetList(kTenantRegistID5); if (theList) { LArrayIterator iterator(*theList); unsigned int numFiremen = 0; unsigned int nowMinutes = inDoc->GetNow()->GetRawMinutes(); T2Tenant *theFireStation; while (numFiremen < 6 && iterator.Next(&theFireStation)) { while (numFiremen < 6 && theFireStation->GetFirstPeople()) { T2People *thePeople = theFireStation->GetFirstPeople(); thePeople->ChangeStyle(kPeopleStyle2); thePeople->SetSpecialFlag(kSpecialFlag20 | kSpecialFlag40); thePeople->SetReturn(theFireStation->GetEquipID()); thePeople->SetDestination(inTenant->GetEquipID()); thePeople->mColor = 11; theFireStation->PushOutPeople(inDoc, thePeople); mPeopleList->InsertItemsAt(1, 1, &thePeople); numFiremen++; } } } } BOOL T2FireBurning::IsBreakoutFire(const T2TowerDoc* inDoc, POINT& outPt, T2Tenant*& outTenant) const { BOOL done = false; T2FloorInfo *theFloorInfo = inDoc->GetFloorInfo(); unsigned int curAttempt = 0; unsigned int numAttempt = mForceStart ? 100000 : 100; while (!done && curAttempt < numAttempt) { curAttempt++; POINT pt; pt.x = UT2Utils::Randomize(theFloorInfo->GetHRange()); pt.y = UT2Utils::Randomize(theFloorInfo->GetGroundLine() - 2); T2Tenant *theTn = theFloorInfo->GetTenant(pt.y, pt.x); if (theTn && !theTn->IsFire() && !theTn->IsFireproof()) { RECT rect; rect.left = pt.x - (mFireWidth / 2 + 1); rect.top = pt.y; rect.right = pt.x + (mFireWidth / 2 + 1); rect.bottom = pt.y + 1; if (theFloorInfo->IsAllTenant(rect)) { outPt = pt; outTenant = theTn; done = true; } } } return done; } T2Fire::T2Fire(POINT& inPt, T2TowerDoc* inDoc, int inVar, T2ImageObj* inImageObj) { CRect junkRect; CRect theRect; inImageObj->GetObjectImage(inImageObj->FindObject("FIRE", 0), theRect); theRect.OffsetRect(-theRect.left, -theRect.top); x0 = 0; x4 = 0; mDocument = inDoc; xC = inVar; x18 = (theRect.right - theRect.left) / 2; x1C = (theRect.right - theRect.left) / 8; mSprite = &mDocument->mSprite; mArsonTenant = NULL; mFireman = NULL; for (unsigned int h = 0; h < x1C; h++) { T2Tenant *theTenant = inDoc->GetFloorInfo()->GetTenant(inPt.y, inPt.x + h); if (theTenant && !theTenant->IsFireproof() && !theTenant->IsFire()) { if (xC > 0) { if (mArsonTenant != theTenant) mArsonTenant = theTenant; } else { if (mArsonTenant == NULL) mArsonTenant = theTenant; } } } if (mSprite) { mFireSpriteID = mSprite->NewSprite(*inImageObj, "FIRE", T2Sprite::ELayer_4); POINT spritePt = inPt; UT2Coordinate::UnitToQD(spritePt, 0, true); mSprite->MoveSprite(mFireSpriteID, spritePt); mSprite->ShowSprite(mFireSpriteID, true); } } T2Fire::~T2Fire() { if (mSprite) { mSprite->ShowSprite(mFireSpriteID, false); mSprite->DeleteSprite(mFireSpriteID); } } void T2Fire::SetFireman(T2People* inPeople) { mFireman = inPeople; mFireman->SetDestination(mArsonTenant->GetEquipID()); mFireman->ChangeStyle(kPeopleStyle2); mFireman->ChangeStatus(kStatus3); } BOOL T2Fire::Move() { BOOL done = false; mSprite->ChangePattern(mFireSpriteID, x0 % 4); CRect rect; mSprite->GetSpriteRect(mFireSpriteID, rect); CPoint p = rect.TopLeft(); if (x4 == 0) { p.x = (xC > 0) ? (rect.right + 1) : (rect.left - 1); UT2Coordinate::QDToUnit(p, 0); T2Tenant *theTenant = mDocument->GetFloorInfo()->GetTenant(p.y, p.x); if (theTenant && !theTenant->IsFireproof() && (!theTenant->IsFire() || mArsonTenant == theTenant)) { p.y = rect.top; p.x = rect.left + xC; mSprite->MoveSprite(mFireSpriteID, p); theTenant->SetStatus(kTenantStatus10000); mArsonTenant = theTenant; } else { x4 = 1; } } else { x4++; T2TowerMainView *theView = mDocument->GetMainView(); if (theView) { CRect unitRect = rect; UT2Coordinate::QDToUnit(unitRect.TopLeft(), 0); UT2Coordinate::QDToUnit(unitRect.BottomRight(), 0); unitRect.right++; theView->InvalUnitRect(unitRect, true); } } if (x18 != 0) { x0++; if ((x0 % x18) == 0) { T2FireBurning *theFireBurning = mDocument->mWorldDef->GetFireBurning(); p.y = rect.top; p.x = rect.left + x18; p.x = (xC > 0) ? rect.left : rect.right; UT2Coordinate::QDToUnit(p, 0); p.y--; for (unsigned int i = 0; i < x1C; i++) { if (theFireBurning->MakeFire(p, mDocument)) break; if (x4 == 0) break; p.x += xC; } if (x4 > x18) { theFireBurning->Extinguish(this); done = true; } } } return done; } BOOL T2Fire::HitTest(CPoint& inPt, CRect& outRect) { CRect rect; mSprite->GetSpriteRect(mFireSpriteID, rect); BOOL success = rect.PtInRect(inPt); if (success) outRect = rect; return success; } BOOL T2Fire::ExtinguishByFireman(T2TowerDoc* inDoc, T2PeoplePtrList* inPeopleList) { BOOL result = false; if (!mFireman) { T2People *fireman; if (inPeopleList->FetchItemAt(1, &fireman)) { inPeopleList->Remove(&fireman); SetFireman(fireman); } } else { if (mFireman->GetWalkStyle() != 2) { switch (mFireman->GetStatus()) { case kStatus14: case kStatus15: { CRect rect; mSprite->GetSpriteRect(mFireSpriteID, rect); CPoint theFirePos = rect.TopLeft(); // should this be theFirePt? as per Mac asserts theFirePos.x += rect.Width() / 2; UT2Coordinate::QDToUnit(theFirePos, 0); CPoint theFiremanPos = mFireman->GetCurPosition(); if (theFiremanPos.x != theFirePos.x) { if (mFireman->GetCurrDestPos().x != theFirePos.x) { mFireman->SetCurrDestPos(theFirePos); switch (mFireman->GetDirection()) { case 0: if (theFiremanPos.x > theFirePos.x) mFireman->FlipDirection(); break; case 1: if (theFiremanPos.x < theFirePos.x) mFireman->FlipDirection(); break; } mFireman->SetStatus(kStatus14); } } else { if (x4 < (x18 - 4) || x4 == 0) { x4 = x18 - 4; if (x4 <= 0) x4 = 1; } mFireman->SetStatus(kStatus15); mFireman->ChangeWalkStyle(2); } } } } else { if (x4 > x18) result = true; } } return result; } T2Helicopter::T2Helicopter(T2TowerDoc* inDoc, const T2Tenant* inTenant) { mDocument = inDoc; mSprite = &mDocument->mSprite; mHeliSpriteID = 0; mWaterSpriteID = 0; mTimePassed = 0; mSpeed = 1; mWaterVisible = false; mImage = new T2BitImage(mDocument->mWorldDef->mModuleHandle, 5001, true); mImageObj = new T2ImageObj; mImageObj->AddObject(inDoc->mWorldDef->mModuleHandle, 5001, mImage); mHeliSpriteID = mSprite->NewSprite(*mImageObj, "HELI", T2Sprite::ELayer_4); mWaterSpriteID = mSprite->NewSprite(*mImageObj, "WATER", T2Sprite::ELayer_4); if (inTenant) { CRect unitRect, qdRect; inTenant->GetEquipArea(unitRect); unitRect.top -= 5; unitRect.left += 10; UT2Coordinate::UnitToQD(unitRect, qdRect, 0, true); mSprite->MoveSprite(mHeliSpriteID, qdRect.TopLeft()); mSprite->ShowSprite(mHeliSpriteID, true); } } T2Helicopter::~T2Helicopter() { mDocument->mSprite.DeleteSprite(mHeliSpriteID); mDocument->mSprite.DeleteSprite(mWaterSpriteID); delete mImage; delete mImageObj; } void T2Helicopter::Move(T2TowerDoc* inDoc) { T2TowerMainView *theMainView = inDoc->GetMainView(); CRect rect; CPoint cursorPt, p; GetCursorPos(&cursorPt); theMainView->ScreenToClient(&cursorPt); cursorPt += theMainView->mScrollOffset; UT2Coordinate::QDToUnit(cursorPt, mDocument->GetZoomLevel()); cursorPt.y -= 1; cursorPt.x += 1; UT2Coordinate::UnitToQD(cursorPt, 0, true); cursorPt.y -= 4; mSprite->GetSpriteRect(mHeliSpriteID, rect); p = rect.TopLeft(); float h = cursorPt.x - p.x; float v = cursorPt.y - p.y; float dst = sqrt(h * h + v * v); if (dst < 36.0f) mSpeed -= (mSpeed > 1); else mSpeed += (mSpeed < 8); float ratio = dst / mSpeed; if (ratio > 1.0) { p.x += (int) (h / ratio); p.y += (int) (v / ratio); } else { p.y--; p.x++; } mTimePassed++; mSprite->ChangePattern(mHeliSpriteID, mTimePassed & 1); mSprite->MoveSprite(mHeliSpriteID, p); if (GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) < 0) { p.y += rect.Height(); mSprite->GetSpriteRect(mWaterSpriteID, rect); p.x -= rect.Width(); mSprite->ChangePattern(mWaterSpriteID, mTimePassed & 1); mSprite->MoveSprite(mWaterSpriteID, p); if (!mWaterVisible) { mSprite->ShowSprite(mWaterSpriteID, true); mWaterVisible = true; } p.y += rect.Height(); T2FireBurning *theFireBurning = mDocument->mWorldDef->GetFireBurning(); theFireBurning->DoExtinguish(p); } else if (mWaterVisible) { p.x = p.y = 0; mSprite->MoveSprite(mWaterSpriteID, p); mSprite->ShowSprite(mWaterSpriteID, false); mWaterVisible = false; } } T2FireAttach::T2FireAttach(T2EventItem* inOwner, unsigned int inMessage, BOOL inExecuteHost) : LAttachment(inMessage, inExecuteHost) { mOwner = inOwner; } /*virtual*/ T2FireAttach::~T2FireAttach() { } /*virtual*/ void T2FireAttach::ExecuteSelf(unsigned int inMessage, void* ioData) { MSG *pMsg; BOOL newExecuteHost = true; if (mOwner->mStatus != 0) { switch (inMessage) { case WM_SETCURSOR: pMsg = (MSG *) ioData; if (LOWORD(pMsg->lParam) == HTCLIENT) { SetCursor(LoadCursor(NULL, IDC_ARROW)); newExecuteHost = false; } break; case WM_LBUTTONDOWN: newExecuteHost = false; break; case WM_TIMER: pMsg = (MSG *) ioData; if (pMsg->wParam == 100) newExecuteHost = false; break; } } SetExecuteHost(newExecuteHost); }