// Return random between 0 and range-1 int ARandomDebug(int range, int line, char *file) { #ifndef NDEBUG BamDebug.Out("#%d@%d ARand(%d)l%d %s\n", bGlobal.randGenCalls, ATicks(), range, line, file); bGlobal.randGenCalls++; return bGlobal.randGen.GetNumber(range); #else range = range; line = line; file = file; APanic("ARandomDebug() called w/ #NDEBUG!\n"); return(0); #endif }
int main(int argc, char** argv) { char mess[100], *string1; uint16 saverResult; int loop1, loop2, framesRun, framesPerSec = 0; bool fWaitToSend; BAM_WorldEnderPopup *pWEPop; FILE *pFile; // Nothing *pNothing1 = new Nothing; // NothingMore *pNothingMore1 = new NothingMore; // Dummy *pDummy1 = new Dummy(0x1234); // pNothing1->SetValue(0x1234); // pNothingMore1->SetValue(0x5678); // pDummy1->SetValue(0x90ab); // Unit *pUnit = new Unit(TRUE); // Unit unit1(TRUE); /* Jay - here's the code for the test case you said you wanted to try next: pFile = fopen("unit1.dat", "wb"); fwrite(&unit1, 1, sizeof(unit1), pFile); fclose(pFile); */ /* pFile = fopen("unit1.dat", "rb"); fread(&unit1, 1, sizeof(unit1), pFile); fclose(pFile); */ time_t startTime, timeDif, lastTime; time(&startTime); lastTime = startTime; // disable critical error handler _harderr(critical_error_handler); AInitializePlatform(); #ifndef NDEBUG printf("\n\n&ReportFreeMem==0x%08X\n", (int)ReportFreeMem); #endif #ifdef OS_DOS printf("\nBLOOD & MAGIC Copyright (C) 1996 by Tachyon Studios Inc..\n"); printf("Developed by Tachyon Studios for Interplay Productions.\n"); printf("BLOOD & MAGIC, FORGOTTEN REALMS and the TSR LOGO are Trademarks\n"); printf("owned by TSR, Inc and are used under license.\n"); printf("\nCompiled %s %s\n", __DATE__, __TIME__); printf("%dk free after platform initialization\n", AAvailMem() / 1024); if(AAvailMem() < MIN_MEM_REQ) { printf("\nWARNING: Free XMS memory is low (<%dk)!\nBAM may not run reliably\n", MIN_MEM_REQ / 1000); sleep(4); } #endif // short-circuit any command line args // argc = 1; if(argc > 1 && (!memcmp(argv[1], "?", 2) || !memcmp(argv[1], "-HELP", 6))) { // printf("Format: BAM [mapNum] [-NOINTRO] [-NOFOG] [-SIDEx] [-NOWIN] [-NET] [-SHOWOFF]\n"); return(0); } // if the seed is the same, the sequence will repeat. cool! // ASeedRandom(41); // for repeatability of bugs // ASeedRandom2(41); // for repeatability of bugs ASeedRandom(startTime); // for genuine randomness ASeedRandom2(startTime); // for genuine randomness // If you ever don't want to see unfreed memory, like for demos, // then uncomment this. // extern bool fPrintUnfreedPtrs; // fPrintUnfreedPtrs = FALSE; TRACK_MEM("Mono"); pMono = new Mono; // if we really must allocate this on the fly instead of // having it global, then we must tell the memmgr not to save it. ASetSaveStatus(AGetGrip(pMono), FALSE); // also, we don't want this to be purged on a restore. ASetPurgeStatus(AGetGrip(pMono), FALSE); pMono->SetWindow(0, 7, 79, 12); pMono->Clear(); pMono->Out("Monochrome output initialized\n"); #ifndef NDBEUG pMono->Out("&ReportFreeMem==0x%08X\n", (int)ReportFreeMem); sleep(4); #endif pMono->Out("EventMgr initializing\n"); TRACK_MEM("EventMgr"); new EventMgr; // we are going to update ticks when we want to. AAutoUpdateTicks(FALSE); pMono->Out("ContextMgr initializing\n"); TRACK_MEM("ContextMgr"); new ContextMgr; pMono->Out("ResMgr initializing\n"); TRACK_MEM("ResMgr"); new ResourceMgr(TRUE); // NOTE - IT IS HIGHLY RECOMMENDED THAT YOU INIT THE SOUND MANAGER // BEFORE THE GRAPH MANAGER. If you don't, streamed sounds will // stop and start during restore because of the busy loop in graph // manager that happens when the palette fades up. pMono->Out("SoundMgr initializing\n"); TRACK_MEM("SndMgr"); new SoundMgr; pSoundMgr->Init(); // BUGBUG! If we bind w/ DOS4GW/Pro we will crash here! //setup smacker sound stuff SmackSoundUseSOS3((u16)pSoundMgr->hDigiDriverHandle,0); pMono->Out("GraphMgr initializing\n"); TRACK_MEM("GraphMgr"); pGraphMgr = new GraphicsMgr(MODEX_320X400); pMono->Out("%dk free after platform initialization\n", AAvailMem() / 1024); // Debugger debug1, debug2; // debug1.OpenWindow(0, 0, 79, 10); // debug2.OpenWindow(40, 11, 79, 21); // for(loop1 = 0; loop1 < 25; loop1++) // { // pMono->Out("\n%d", loop1); // } // sleep(2); TRACK_MEM("FontMgr"); pFontMgr = new FontMgr; // default font pFontMgr->SetRes(9050); // default font color pFontMgr->ForeColor(TEXT_DEFAULT); pFontMgr->colors[FNT_BACK_COLOR] = CI_SKIP; #ifdef OS_MAC // #include "menubar.hpp" // DS9MenuBar* pMenuBar; // TRACK_MEM("menuBar"); pMenuBar = new DS9MenuBar; TRACK_MEM("Mouse"); new Mouse; #else TRACK_MEM("Mouse"); new MouseInt; #endif if(pMouse->hideCount == 999) { // init error ShutDownSoundMgr(); APrintUnfreedPtrs(FALSE); exit(1); } pMouse->Init(0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1); pMouse->SetRes(RES_ANIM, POINTER_RES, 1); pMouse->Hide(); //let bamroom show it at room change time. // this is our global data saver AtSave(GlobalSave); // create the application instance TRACK_MEM("BAM App"); pBam = new BAM_Application; bGlobal.gBam = pBam->gSelf; pBam->msgMask = E_MOUSE_DOWN | E_MOUSE_UP | E_KEY_DOWN; // command-line options parsed here memcpy(pBam->scenarioName, "9110", 5); // default scenario pBam->fNoIntro = FALSE; pBam->fDefaultScenario = FALSE; pBam->fUseFog = TRUE; pBam->fUseWinLose = TRUE; pBam->playerSide = SIDE1; pBam->fMapEdit = FALSE; pBam->playerTypes[SIDE0] = PLAYER_NONE; pBam->playerTypes[SIDE1] = PLAYER_LOCAL; pBam->playerTypes[SIDE2] = PLAYER_NONE; pBam->playerTypes[SIDE3] = PLAYER_NONE; pBam->playerTypes[SIDE4] = PLAYER_NONE; { FILE *pPentiumFile; pPentiumFile = fopen("PENTIUM.VAN", "rb"); if(pPentiumFile) { fclose(pPentiumFile); fPentium = TRUE; } } for(loop1 = 1; loop1 < argc; loop1++) { strcpy(mess, argv[loop1]); string1 = mess; do { *string1 = (char) toupper(*string1); string1++; } while(*string1); if(mess[0] == '-') { // #ifdef ENABLE_EDITOR // if(!memcmp(mess, "-EDIT", 5)) // turn on edit mode // pBam->fMapEdit = TRUE; // #endif if(!memcmp(mess, "-NOINTRO", 9)) // turn off opening cinematic pBam->fNoIntro = TRUE; else if(!memcmp(mess, "-NOWIN", 6)) // turn on win/lose conditions pBam->fUseWinLose = FALSE; else if(!memcmp(mess, "-NOFOG", 6)) // turn off fog pBam->fUseFog = FALSE; else if(!memcmp(mess, "-NET", 4)) // network play { pBam->fNetworkTest = TRUE; bGlobal.storyLine = NETGAME; ASeedRandom(42); // need sync'ed RNGs } else if(!memcmp(mess, "-PENTIUM", 8)) { fPentium = TRUE; } else if(!memcmp(mess, "-MUSIC", 6)) { bGlobal.altMusicNum = atoi(mess + 6); } else if(!memcmp(mess, "-AIUNITS", 8)) { bGlobal.aiUnitMultiplier = atoi(mess + 8); } else if(!memcmp(mess, "-AI", 3)) { bGlobal.aiOveride = atoi(mess + 3); } else if(!memcmp(mess, "-FRENCH", 7)) { SetLanguage(LANG_FRENCH); } else if(!memcmp(mess, "-GERMAN", 7)) { SetLanguage(LANG_GERMAN); } else if(!memcmp(mess, "-ENGLISH", 8)) { SetLanguage(LANG_ENGLISH); } else if(!memcmp(mess, "-SHOWOFF", 8)) // storefront demo mode { bGlobal.storyLine = SHOW_OFF; } else if(!memcmp(mess, "-HACKRES", 8)) // allow single resource replacement { pResMgr->fSearchStuffsFirst = FALSE; } else if(!memcmp(mess, "-SIDE", 5)) // set player side (1 or 2) { switch(mess[5]) { case '0': pBam->playerSide = SIDE0; pBam->playerTypes[SIDE1] = PLAYER_NONE; pBam->playerTypes[SIDE2] = PLAYER_NONE; break; case '1': pBam->playerSide = SIDE1; pBam->playerTypes[SIDE1] = PLAYER_LOCAL; pBam->playerTypes[SIDE2] = PLAYER_NONE; break; case '2': pBam->playerSide = SIDE2; pBam->playerTypes[SIDE1] = PLAYER_NONE; pBam->playerTypes[SIDE2] = PLAYER_LOCAL; break; default: pMono->Out("Invalid option to command line arg -SIDEx\n"); break; } } } else if(atoi(argv[loop1])) { memcpy(pBam->scenarioName, argv[loop1], 8); pBam->fDefaultScenario = TRUE; } } #ifdef ENABLE_EDITOR if(pBam->fMapEdit) // if editor mode, then turn off fog pBam->fUseFog = FALSE; pBam->fShowTileNums = TRUE; #endif // initialize game start, pBam->Activate(TRUE); pContextMgr->msgMask = E_MOUSE_DOWN | E_MOUSE_UP | E_KEY_DOWN; #ifdef COUNT_FRAMES FrameCounter fps; #endif // COUNT_FRAMES TRACK_MEM("TCommMgr"); new TCommMgr; if(pBam->fNetworkTest) // if set up network from command line { // TNetwork *pComm; // TModem *pComm; TComm::ERROR errVal; int int1; // pMono->Out("New TCommMgr\n"); // TRACK_MEM("TCommMgr"); pCommMgr = new TCommMgr; //it isn't an object -no gSelf TRACK_MEM("TNetwork"); pComm = new TNetwork; // pComm = new TModem; // ((TModem*) pComm)->SetPort(3); // ((TModem*) pComm)->SetBaud(19200); #ifdef OS_MAC int commInitArg = 0; // ignored by DOS/TIGRE // player 1 is caller, player two is listener // at least for now, using command line args to specify direction if (pBam->playerTypes[SIDE1] == PLAYER_LOCAL) { commInitArg = TCommMacintosh::kATalkCaller; } else { commInitArg = TCommMacintosh::kATalkListener; } pCommMgr->Init(pComm, commInitArg); #else pCommMgr->SetUserAbortFn ((pIntFnInt) CycleConnection); pCommMgr->Init(pComm); #endif pMono->Out("Attempting connection...\n"); int1 = (int)pCommMgr->Connect(); errVal = (TComm::ERROR)int1; if(errVal != TComm::ALL_OK) { pMono->Out("Main() - error, commMgr->Connect() failed\n"); sleep(1); pBam->fNetworkTest = FALSE; } else { pMono->Out("Main() - connection established\n"); pBam->playerTypes[(pBam->playerSide == SIDE1)? SIDE2: SIDE1] = pCommMgr->GetUserID(); pMono->Out("User ID==%d\n", pCommMgr->GetUserID()); // sleep(2); } } pMono->Out("TIGRE engine initialized\n"); ReportFreeMem(); // side1 and side2 MUST have a player setting of some kind if(pBam->playerTypes[SIDE1] == PLAYER_NONE) pBam->playerTypes[SIDE1] = PLAYER_COMPUTER; if(pBam->playerTypes[SIDE2] == PLAYER_NONE) pBam->playerTypes[SIDE2] = PLAYER_COMPUTER; // initial room if(pBam->fDefaultScenario) { SetDefaults(pBam->scenarioName); bGlobal.roomMgr.NewRoom(BR_WORLD); // skip everything, go to game } else if(bGlobal.storyLine == SHOW_OFF) { bGlobal.roomMgr.NewRoom(BR_WORLD); // skip everything, go to game } else if(pBam->fNoIntro) bGlobal.roomMgr.NewRoom(BR_MENU); // skip intro, go to story selector else bGlobal.roomMgr.NewRoom(BR_CINE); // skip nothing bGlobal.roomMgr.CheckRoomChange(); #ifdef OS_MAC #include "menubar.hpp" DS9MenuBar *pMenuBar; TRACK_MEM("menuBar"); MenuBar.Init(); #endif ticks_t currTicks = ATicks(); int snapShot = 0; // anti-piracy stuff pFile = fopen("HMICARDS.386", "rb"); if(!pFile) bGlobal.antiPiracyCrashFlag &= 0xFFFFF0FF; else { for(loop1 = 0; loop1 < 5; loop1++) { char string1[128]; unsigned long lineCheck1, lineCheck2; fread(string1, 32, 1, pFile); // camoflage string fread(string1, 128, 1, pFile); // encrypted string fread(&lineCheck1, sizeof(lineCheck1), 1, pFile); // line checksum // verify checksum for(lineCheck2 = 0, loop2 = 0; loop2 < 128; loop2++) lineCheck2 = lineCheck2 + string1[loop2]; lineCheck2 ^= 0xF61E22C9; if(lineCheck1 != lineCheck2) { // failure - set the delayed crash flag fclose(pFile); bGlobal.antiPiracyCrashFlag &= 0xFFFFF0FF; } } fclose(pFile); } //======================================================================= //MAIN GAME LOOP //======================================================================= ReportFreeMem(); enum timerTags {TIMER_CYC_PER_FRAME = 0, TIMER_UPDATE_TICKS, TIMER_CONTEXT_CYCLE, TIMER_ANIMATE, TIMER_SYNC_SEND, TIMER_SYNC_RECV, TIMER_MAX}; DebugTimer timers[TIMER_MAX]; while (!pContextMgr->fQuitting) { #ifndef NDEBUG timers[TIMER_CYC_PER_FRAME].Start(); #endif #ifdef DEBUG_BIG_NET pMono->Out("main loop().."); #endif // our own exceptional ptrs pBam = ADerefAs(BAM_Application, bGlobal.gBam); if (bGlobal.gWorld) { pWorld = ADerefAs(World, bGlobal.gWorld); } else { pWorld = NULL; } #ifdef DEBUG_BIG_NET pMono->Out("roomMgr.cycle().."); #endif bGlobal.roomMgr.Cycle(); //fps.Count(); #ifdef DEBUG_BIG_NET pMono->Out("memMgr.cycle().."); #endif pMemMgr->Cycle(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER // // MDB - Modified the mouse interrupt handler. // MouseHandler( FALSE ); #endif #ifndef NDEBUG //mem_check(); #endif #ifdef DEBUG_BIG_NET pMono->Out("roomMgr.CheckRoomChange().."); #endif bGlobal.roomMgr.CheckRoomChange(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER // // MDB - Modified the mouse interrupt handler. // MouseHandler( FALSE ); #endif //if snap is on lets handle tick updates ourself if(bGlobal.gSnap && pSnap->snapOn) { //if snap just toggled on if(!snapShot) { snapShot++; currTicks = ATicks(); } else { currTicks += 2; } ASetTicks(currTicks); } else { snapShot = 0; //reset #ifdef DEBUG_BIG_NET pMono->Out("EventMgr->Publish().."); #endif // add local actions to actionPool2 pEventMgr->PublishNext(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER // // MDB - Modified the mouse interrupt handler. // MouseHandler( FALSE ); #endif if(pWorld) { // wait for next tick to occur, because otherwise there's no point. // note: UpdateTicks() cannot be trusted to change, in case of Pause() currTicks = ATicks(); // #ifndef NDEBUG // BamDebug.Out("main() - update tick counter (curr=%d)\n", // currTicks); // #endif #ifndef NDEBUG timers[TIMER_UPDATE_TICKS].Start(); #endif UpdateTicks(); // did the tick counter fail to increment? if(ATicks() == currTicks) { // loop on clock() delta, then resume. A tick will have changed by // then or else we're in Pause() mode, so who cares. clock_t currClock = clock(); while(currClock == clock()) { #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif }; // try again - if it fails again, assume Pause() and don't worry UpdateTicks(); } // if we skipped over a tick somehow.. if(ATicks() > currTicks + 1) { // #ifndef NDEBUG // BamDebug.Out("main() WARNING: ATicks() advanced by %d! - retarding\n", // ATicks() - currTicks); // #endif // dont allow the tick counter to increment by more than 1 // tick per frame, or we may get out of sync with the // remote machine ASetTicks(currTicks + 1); } #ifndef NDEBUG timers[TIMER_UPDATE_TICKS].Stop(); #endif // #ifndef NDEBUG // BamDebug.Out("ATicks() == %d\n", ATicks()); // #endif // sync1 - send actionPool2 to remote #ifndef NDEBUG timers[TIMER_SYNC_SEND].Start(); #endif fWaitToSend = FALSE; if(pCommMgr && pCommMgr->totalPacketsWaiting) fWaitToSend = TRUE; if(!pWorld->SyncSend()) { #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif //pWorld->AITakeOver(); if(!pBam->fWorldEnderPopupExists) { TRACK_MEM("BAM_WorldEnderPopup"); pWEPop = new BAM_WorldEnderPopup; pWEPop->Setup(); pBam->fWorldEnderPopupExists = TRUE; } } #ifndef NDEBUG timers[TIMER_SYNC_SEND].Stop(); #endif // process actionPool1 pWorld->ProcessActions(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif } else { #ifndef NDEBUG timers[TIMER_UPDATE_TICKS].Start(); #endif UpdateTicks(); #ifndef NDEBUG timers[TIMER_UPDATE_TICKS].Stop(); #endif } if(bGlobal.storyLine == NETGAME && !bGlobal.netDisconnect) { pCommMgr->EnQueueData(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif } } #ifdef DEBUG_BIG_NET pMono->Out("contextMgr.cycle().."); #endif #ifndef NDEBUG timers[TIMER_CONTEXT_CYCLE].Start(); #endif pContextMgr->Cycle(); #ifndef NDEBUG timers[TIMER_CONTEXT_CYCLE].Stop(); #endif #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif if(bGlobal.storyLine == NETGAME && !bGlobal.netDisconnect) { pCommMgr->EnQueueData(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif } #ifdef DEBUG_BIG_NET pMono->Out("GraphMgr->Animate().."); #endif #ifndef NDEBUG timers[TIMER_ANIMATE].Start(); #endif pGraphMgr->Animate(); #ifndef NDEBUG timers[TIMER_ANIMATE].Stop(); #endif #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif if(bGlobal.storyLine == NETGAME && !bGlobal.netDisconnect) { pCommMgr->EnQueueData(); #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif } #ifdef DEBUG_BIG_NET pMono->Out("soundMgr.cycle().."); #endif pSoundMgr->Cycle(); // current frame now done // gather cmds from remote for next frame, then prepare to run it if(pWorld) { pWorld->currFrame++; // sync2 - add remote actions to local actions in actionPool2 #ifndef NDEBUG timers[TIMER_SYNC_RECV].Start(); #endif if(!pWorld->SyncReceive()) { #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif //pWorld->AITakeOver(); if(!pBam->fWorldEnderPopupExists) { TRACK_MEM("BAM_WorldEnderPopup"); pWEPop = new BAM_WorldEnderPopup; pWEPop->Setup(); pBam->fWorldEnderPopupExists = TRUE; } } // sync3 - swap action pools pWorld->SwapActionPools(); #ifndef NDEBUG timers[TIMER_SYNC_RECV].Stop(); #endif } if(bGlobal.gSnap && pSnap->snapOn) { pSnap->SnapScreen(); } if(netRestoreNum || netSaveNum) { //this means we're in a netgame save or restore //we don't run the eventmgr to keep both sides in sync //and we set the restore number here, after the context cycle, //to insure the otherside has had time to be notified of this if(netRestoreNum) restoreNum = netRestoreNum; //our one net save game if(netSaveNum) { saveNum = netSaveNum; netSerialNum = ARandom(99999); sprintf(saveMessage,"%d",netSerialNum); } } if (saveNum) { pMemMgr->Dump((uint16) (100 + saveNum), "Save Dump", TRUE); saverResult = saveMgr.Save((uint16) saveNum, bGlobal.versionNum, bGlobal.versionSubNum, bGlobal.buildID, saveMessage); if (saverResult) { sprintf(mess, "save failed. error #%d", saverResult); APanic(mess); } netSaveNum = 0; //reset this after save saveNum = 0; } if (restoreNum) { saverResult = saveMgr.Restore((uint16) restoreNum, bGlobal.versionNum, bGlobal.versionSubNum, bGlobal.buildID); if (saverResult) { // sprintf(mess, "restore failed. error #%d", saverResult); BamDebug.Out("Restore failed! Error %d\n", saverResult); // APanic(mess); } pMemMgr->Dump((uint16) (200 + restoreNum), "Restore Dump", TRUE); netRestoreNum = 0; //reset this after restore restoreNum = 0; bGlobal.roomMgr.Cycle(); // frantic temporary debugging measure pBam = ADerefAs(BAM_Application, bGlobal.gBam); if (bGlobal.gWorld) { pWorld = ADerefAs(World, bGlobal.gWorld); pWorld->Save(AFTER_RESTORE); } else { pWorld = NULL; } bGlobal.roomMgr.Cycle(); pMemMgr->Cycle(); pSoundMgr->Cycle(); if(pWorld) { pBam->fPauseWorld = TRUE; //force ResumeTicks() to be called in PauseWorld pWorld->Pause(FALSE, TRUE); pBam->PauseWorld(); } else bGlobal.roomMgr.curRoom->Pause(FALSE, TRUE); #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif } if(pWorld) if(pBam->fPauseWorld != pWorld->fIsPaused) pBam->PauseWorld(); #ifdef DEBUG_BIG_NET pMono->Out("main loop() done\n"); #endif #ifndef NDEBUG timers[TIMER_CYC_PER_FRAME].Stop(); #endif #ifndef NDEBUG pMono->SaveWindow(); pMono->Goto(24, 1); pMono->Out("CpF%5d UTick%5d CmC%5d GmA%5d Tx%4d:%dp@%4db]%c Rx[%4d]", timers[TIMER_CYC_PER_FRAME].duration, timers[TIMER_UPDATE_TICKS].duration, timers[TIMER_CONTEXT_CYCLE].duration, timers[TIMER_ANIMATE].duration, timers[TIMER_SYNC_SEND].duration, pCommMgr->pComm->totalPacketsSent, pCommMgr->pComm->totalBytesSent, fWaitToSend? 'W': 'w', timers[TIMER_SYNC_RECV].duration); pMono->Goto(25, 1); time(&timeDif); if(timeDif != lastTime) { lastTime = timeDif; framesPerSec = AMin(framesRun, 99); framesRun = 0; } else framesRun++; timeDif -= startTime; pMono->Out("%05dkt %05dkl %02d:%02d:%02d %2dFPS", pMemMgr->AvailMem() / 1024, pMemMgr->LargestAlloc() / 1024, timeDif / 3600, (timeDif / 60) % 60, timeDif % 60, framesPerSec); if(pWorld) { pMono->Goto(25, 32); pMono->Out("r%d g%d 0x%08x", pWorld->tileResNum, ALoad(RES_TILELIB, pWorld->tileResNum), AGetResData(ALoad(RES_TILELIB, pWorld->tileResNum))); } pCommMgr->pComm->totalBytesSent = 0; pCommMgr->pComm->totalPacketsSent = 0; pMono->RestoreWindow(); #endif #ifndef OLD_MOUSE_INTERRUPT_HANDLER MouseHandler( FALSE ); #endif } //=================================== LoadExitQuote(); //=================================== // get rid of our current room bGlobal.roomMgr.DeleteCurRoom(); // shut down communications if(pCommMgr) { pCommMgr->Disconnect(); pCommMgr->DiscardData(); delete pCommMgr; //its destructor will delete pComm pCommMgr = NULL; } if(bGlobal.gSnap) ADelete(bGlobal.gSnap); ADelete(bGlobal.gBam); // all actors should be removed from graphmgr, do one more // animate to clear lists. pGraphMgr->Animate(); ADelete(pContextMgr->gSelf); // TSound exitSound; // exitSound.Play(667); // while(exitSound.IsPlaying()) // pSoundMgr->Cycle(); // storm the office! kill all managers! ADelete(pGraphMgr->gSelf); ADelete(pFontMgr->gSelf); ADelete(pSoundMgr->gSelf); ADelete(pResMgr->gSelf); ADelete(pEventMgr->gSelf); ADelete(pMouse->gSelf); delete pMono; // DESTROY_MGR_CAREFUL(GraphicsMgr, pGraphMgr); // DESTROY_MGR_CAREFUL(Mono, pMono); // DESTROY_MGR_CAREFUL(FontMgr, pFontMgr); // DESTROY_MGR_CAREFUL(SoundMgr, pSoundMgr); // DESTROY_MGR(pResMgr); // DESTROY_MGR(pContextMgr); // DESTROY_MGR_CAREFUL(EventMgr, pEventMgr); #ifdef INTERACTIVE_DEMO DPMI dpmi; char *pScreen = (char *)dpmi.RealToProtected(0xB8000000); // kludge - remove "Installer" from data for(loop1 = 0; loop1 < 9; loop1++) MSG_DEMO_ENGL[86 + loop1 * 2] = ' '; memcpy(pScreen, (char *)MSG_DEMO_ENGL, 4000); while(!kbhit()); getch(); #endif system("mode co80"); // yeah, mega-cheesy I know. It's a bug patch. -Van printf("\n%s\n",exitMessage); printf("%s\n",exitAuthor); return 0; }