#include "builddefines.h" #ifdef JA2EDITOR #include #include "Font Control.h" #include "renderworld.h" #include "Render Dirty.h" #include "LoadScreen.h" #include "selectwin.h" #include "EditorDefines.h" #include "messagebox.h" #include "Text Input.h" #include "Soldier Create.h" #include "Soldier Init List.h" #include "EditorBuildings.h" #include "Editor Taskbar Utils.h" #include "Editor Undo.h" #include "editscreen.h" #include "strategicmap.h" #include "Editor Modes.h" #include "Map Information.h" #include "Sys Globals.h" #include "Sector Summary.h" #include "newsmooth.h" #include "Simple Render Utils.h" #include "Animated ProgressBar.h" #include "EditorMercs.h" #include "lighting.h" #include "EditorMapInfo.h" #include "environment.h" #include "edit_sys.h" #include "EditorItems.h" #include "english.h" #include "gameloop.h" #include "message.h" #include "pits.h" #include "Item Statistics.h" #include "Scheduling.h" #include "MessageBoxScreen.h" #include //dnl ch37 110909 #include "Exit Grids.h"//dnl ch86 190214 //=========================================================================== BOOLEAN gfErrorCatch = FALSE; CHAR16 gzErrorCatchString[ 256 ] = L""; INT32 giErrorCatchMessageBox = 0; extern void RemoveMercsInSector(); enum{ DIALOG_NONE, DIALOG_SAVE, DIALOG_LOAD, DIALOG_CANCEL, DIALOG_DELETE }; extern UINT16 Counter; //Hook into the text input code. These callbacks help give back control, so we //can use the dialog interface in conjunction with the void FDlgOkCallback( GUI_BUTTON *butn, INT32 reason ); void FDlgCancelCallback( GUI_BUTTON *butn, INT32 reason ); void FDlgUpCallback( GUI_BUTTON *butn, INT32 reason ); void FDlgDwnCallback( GUI_BUTTON *butn, INT32 reason ); void FDlgNamesCallback( GUI_BUTTON *butn, INT32 reason ); void UpdateWorldInfoCallback( GUI_BUTTON *b, INT32 reason ); void FileDialogModeCallback( UINT8 ubID, BOOLEAN fEntering ); UINT32 ProcessLoadSaveScreenMessageBoxResult(); BOOLEAN RemoveFromFDlgList( FDLG_LIST **head, FDLG_LIST *node ); void DrawFileDialog(); void HandleMainKeyEvents( InputAtom *pEvent ); void HandleMouseWheelEvents(void);//dnl ch36 150909 void SetTopFileToLetter( UINT16 usLetter ); INT32 iTotalFiles; INT32 iTopFileShown; INT32 iCurrFileShown; INT32 iLastFileClicked; INT32 iLastClickTime; CHAR8 gzProfileName[FILENAME_BUFLEN];//dnl ch81 021213 CHAR16 gzFilename[FILENAME_BUFLEN];//dnl ch39 190909 extern INT16 gsSelSectorX; extern INT16 gsSelSectorY; FDLG_LIST *FileList = NULL; INT32 iFDlgState = DIALOG_NONE; BOOLEAN gfDestroyFDlg = FALSE; INT32 iFileDlgButtons[7]; BOOLEAN gfLoadError; BOOLEAN gfReadOnly; BOOLEAN gfFileExists; BOOLEAN gfIllegalName; BOOLEAN gfDeleteFile; BOOLEAN gfNoFiles; BOOLEAN gfSaveError;//dnl ch37 200909 CHAR16 zOrigName[60]; GETFILESTRUCT FileInfo; BOOLEAN fEnteringLoadSaveScreen = TRUE; BOOLEAN gfPassedSaveCheck = FALSE; MOUSE_REGION BlanketRegion; CHAR8 gszCurrFilename[80]; enum{ IOSTATUS_NONE, INITIATE_MAP_SAVE, SAVING_MAP, INITIATE_MAP_LOAD, LOADING_MAP }; INT8 gbCurrentFileIOStatus; //1 init saving message, 2 save, 3 init loading message, 4 load, 0 none UINT32 ProcessFileIO(); //BOOLEAN fSavingFile; extern UINT16 gusLightLevel, gusSavedLightLevel; UINT32 LoadSaveScreenInit(void) { gfUpdateSummaryInfo = TRUE; fEnteringLoadSaveScreen = TRUE; return TRUE; } UINT32 LoadSaveScreenShutdown(void) { return TRUE; } void LoadSaveScreenEntry() { fEnteringLoadSaveScreen = FALSE; gbCurrentFileIOStatus = IOSTATUS_NONE; gfReadOnly = FALSE; gfFileExists = FALSE; gfLoadError = FALSE; gfIllegalName = FALSE; gfDeleteFile = FALSE; gfNoFiles = FALSE; gfSaveError = FALSE;//dnl ch37 200909 RestoreBackgroundRects();//dnl ch86 210214 // setup filename dialog box // (*.dat and *.map) as file filter // If user clicks on a filename in the window, then turn off string focus and re-init the string with the new name. // If user hits ENTER or presses OK, then continue with the file loading/saving if(FileList) { TrashFDlgList(FileList); FileList = NULL; } iTopFileShown = iTotalFiles = 0; gzProfileName[0] = 0;//dnl ch81 021213 FDLG_LIST* TempFileList = NULL; vfs::CProfileStack* st = getVFS()->getProfileStack(); vfs::CProfileStack::Iterator it = st->begin(); while(!it.end()) { TempFileList = NULL; vfs::CVirtualProfile* prof = it.value(); memset(&FileInfo, 0, sizeof(GETFILESTRUCT)); strcpy(FileInfo.zFileName, "< "); // Cut filename off if it's too long for the buffer if (strlen(prof->cName.utf8().c_str()) > FILENAME_BUFLEN-4) { strncpy(FileInfo.zFileName+1, prof->cName.utf8().c_str(), FILENAME_BUFLEN-4); } else { strcat(FileInfo.zFileName, prof->cName.utf8().c_str()); } strcat(FileInfo.zFileName, " >"); FileInfo.zFileName[FILENAME_BUFLEN] = 0; FileInfo.uiFileAttribs = FILE_IS_DIRECTORY; if(iCurrentAction == ACTION_SAVE_MAP && prof->cWritable == false) { it.next(); continue; } TempFileList = AddToFDlgList(TempFileList, &FileInfo); iTotalFiles++; vfs::CVirtualProfile::FileIterator fit = prof->files(L"MAPS/*"); while(!fit.end()) { vfs::String fname = fit.value()->getName().c_str(); memset(&FileInfo, 0, sizeof(GETFILESTRUCT)); strcpy(FileInfo.zFileName, fname.utf8().c_str()); FileInfo.uiFileSize = fname.length(); FileInfo.uiFileAttribs = (fit.value()->implementsWritable() ? FILE_IS_NORMAL : FILE_IS_READONLY); if(strlen(FileInfo.zFileName) < FILENAME_BUFLEN) { TempFileList = AddToFDlgList(TempFileList, &FileInfo); iTotalFiles++; } fit.next(); } if(TempFileList) { while(TempFileList->pPrev) TempFileList = TempFileList->pPrev; if(FileList) { while(FileList->pNext) FileList = FileList->pNext; FileList->pNext = TempFileList; TempFileList->pPrev = FileList; } else FileList = TempFileList; } it.next(); } while(FileList->pPrev) FileList = FileList->pPrev; swprintf( zOrigName, L"%s Map (*.dat)", iCurrentAction == ACTION_SAVE_MAP ? L"Save" : L"Load" ); swprintf( gzFilename, L"%S", gubFilename ); CreateFileDialog( zOrigName ); if( !iTotalFiles ) { gfNoFiles = TRUE; if( iCurrentAction == ACTION_LOAD_MAP ) DisableButton( iFileDlgButtons[0] ); } iLastFileClicked = -1; iLastClickTime = 0; } UINT32 ProcessLoadSaveScreenMessageBoxResult() { FDLG_LIST *curr, *temp; gfRenderWorld = TRUE; RemoveMessageBox(); if( gfIllegalName ) { fEnteringLoadSaveScreen = TRUE; RemoveFileDialog(); MarkWorldDirty(); return gfMessageBoxResult ? LOADSAVE_SCREEN : EDIT_SCREEN; } if( gfDeleteFile ) { if( gfMessageBoxResult ) { //delete file INT32 x; curr = FileList; for( x = 0; x < iCurrFileShown && x < iTotalFiles && curr; x++ ) { curr = curr->pNext; } if( curr ) { if( gfReadOnly ) { // Other call sites have replaced this with FileDelete(); for VFS, should we do the same here? //FileClearAttributes( gszCurrFilename ); gfReadOnly = FALSE; } FileDelete( gszCurrFilename ); //File is deleted so redo the text fields so they show the //next file in the list. temp = curr->pNext; if( !temp ) temp = curr->pPrev; if( !temp ) wcscpy( gzFilename, L"" ); else swprintf( gzFilename, L"%S", temp->FileInfo.zFileName ); if( ValidFilename() ) { SetInputFieldStringWith16BitString( 0, gzFilename ); } else { SetInputFieldStringWith16BitString( 0, L"" ); wcscpy( gzFilename, L"" ); } RemoveFromFDlgList( &FileList, curr ); iTotalFiles--; if( !iTotalFiles ) { gfNoFiles = TRUE; if( iCurrentAction == ACTION_LOAD_MAP ) DisableButton( iFileDlgButtons[0] ); } if( iCurrFileShown >= iTotalFiles ) iCurrFileShown--; if( iCurrFileShown < iTopFileShown ) iTopFileShown -= 8; if( iTopFileShown < 0 ) iTopFileShown = 0; } } MarkWorldDirty(); RenderWorld(); gfDeleteFile = FALSE; iFDlgState = DIALOG_NONE; return LOADSAVE_SCREEN; } if(gfLoadError || gfSaveError)//dnl ch37 200909 { MarkWorldDirty(); RenderWorld(); fEnteringLoadSaveScreen = TRUE; return(gfMessageBoxResult ? LOADSAVE_SCREEN : EDIT_SCREEN); } if( gfReadOnly ) { //file is readonly. Result will determine if the file dialog stays up. fEnteringLoadSaveScreen = TRUE; RemoveFileDialog(); return gfMessageBoxResult ? LOADSAVE_SCREEN : EDIT_SCREEN; } if( gfFileExists ) { if( gfMessageBoxResult ) { //okay to overwrite file RemoveFileDialog(); gbCurrentFileIOStatus = INITIATE_MAP_SAVE; return LOADSAVE_SCREEN; } fEnteringLoadSaveScreen = TRUE; RemoveFileDialog(); return(LOADSAVE_SCREEN);//dnl ch36 210909 } // Assert( 0 ); return LOADSAVE_SCREEN; } UINT32 LoadSaveScreenHandle(void) { FDLG_LIST *FListNode; INT32 x; InputAtom DialogEvent; if( fEnteringLoadSaveScreen ) { LoadSaveScreenEntry(); } if( gbCurrentFileIOStatus ) //loading or saving map { UINT32 uiScreen; uiScreen = ProcessFileIO(); if( uiScreen == EDIT_SCREEN && gbCurrentFileIOStatus == LOADING_MAP ) RemoveProgressBar( 0 ); return uiScreen; } if( gubMessageBoxStatus ) { if( MessageBoxHandled() ) return ProcessLoadSaveScreenMessageBoxResult(); return LOADSAVE_SCREEN; } //handle all key input. while( DequeueEvent(&DialogEvent) ) { if( !HandleTextInput(&DialogEvent) && (DialogEvent.usEvent == KEY_DOWN || DialogEvent.usEvent == KEY_REPEAT) ) { HandleMainKeyEvents( &DialogEvent ); } } HandleMouseWheelEvents();//dnl ch36 150909 DrawFileDialog(); // Skip to first filename to show FListNode = FileList; for(x=0;xpNext; } // Show up to 8 filenames in the window SetFont( FONT12POINT1 ); if( gfNoFiles ) { SetFontForeground( FONT_LTRED ); SetFontBackground( 142 ); mprintf( iScreenWidthOffset + 226, iScreenHeightOffset + 126, L"NO FILES IN \\MAPS DIRECTORY" ); } else for(x=iTopFileShown;x<(iTopFileShown+8) && xFileInfo.zFileName); FListNode = FListNode->pNext; } RenderAllTextFields(); InvalidateScreen(); ExecuteBaseDirtyRectQueue(); EndFrameBufferRender(); switch( iFDlgState ) { case DIALOG_CANCEL: RemoveFileDialog(); fEnteringLoadSaveScreen = TRUE; return EDIT_SCREEN; case DIALOG_DELETE: sprintf( gszCurrFilename, "MAPS\\%S", gzFilename ); if( GetFileFirst(gszCurrFilename, &FileInfo) ) { CHAR16 str[40]; if( FileInfo.uiFileAttribs & (FILE_IS_READONLY|FILE_IS_HIDDEN|FILE_IS_SYSTEM) ) { swprintf( str, L" Delete READ-ONLY file %s? ", gzFilename ); gfReadOnly = TRUE; } else swprintf( str, L" Delete file %s? ", gzFilename ); gfDeleteFile = TRUE; CreateMessageBox( str ); } return LOADSAVE_SCREEN; case DIALOG_SAVE://dnl ch37 230909 { if(!ExtractFilenameFromFields()) { CreateMessageBox(L" Illegal filename. Try another filename? "); gfIllegalName = TRUE; iFDlgState = DIALOG_NONE; return(LOADSAVE_SCREEN); } sprintf(gszCurrFilename, "MAPS\\%S", gzFilename); gfFileExists = FALSE; gfReadOnly = TRUE; vfs::CProfileStack* st = getVFS()->getProfileStack(); vfs::CProfileStack::Iterator it = st->begin(); while(!it.end()) { vfs::CVirtualProfile* prof = it.value(); if(prof->cWritable == true) { gfReadOnly = FALSE; vfs::Path const& path = gszCurrFilename; vfs::IBaseFile *file = prof->getFile(path); if(file) { gfFileExists = TRUE; if(file->implementsWritable() == false) gfReadOnly = TRUE; } break; } it.next(); } if(gfReadOnly) { CreateMessageBox(L" File is read only! Choose a different name? "); return( LOADSAVE_SCREEN); } else if(gfFileExists) { CreateMessageBox(L" File exists, Overwrite? "); return(LOADSAVE_SCREEN); } RemoveFileDialog(); gbCurrentFileIOStatus = INITIATE_MAP_SAVE; return(LOADSAVE_SCREEN); } case DIALOG_LOAD: if( !ExtractFilenameFromFields() ) { CreateMessageBox( L" Illegal filename. Try another filename? " ); gfIllegalName = TRUE; iFDlgState = DIALOG_NONE; return LOADSAVE_SCREEN; } RemoveFileDialog(); CreateProgressBar( 0, iScreenWidthOffset + 118, iScreenHeightOffset + 183, iScreenWidthOffset + 522, iScreenHeightOffset + 202 ); DefineProgressBarPanel( 0, 65, 79, 94, iScreenWidthOffset + 100, iScreenHeightOffset + 155, iScreenWidthOffset + 540, iScreenHeightOffset + 235 ); swprintf( zOrigName, L"Loading map: %s", gzFilename ); SetProgressBarTitle( 0, zOrigName, BLOCKFONT2, FONT_RED, FONT_NEARBLACK ); gbCurrentFileIOStatus = INITIATE_MAP_LOAD; return LOADSAVE_SCREEN ; default: iFDlgState = DIALOG_NONE; } iFDlgState = DIALOG_NONE; return LOADSAVE_SCREEN ; } void CreateFileDialog( STR16 zTitle ) { iFDlgState = DIALOG_NONE; DisableEditorTaskbar(); MSYS_DefineRegion( &BlanketRegion, 0, 0, gsVIEWPORT_END_X, gsVIEWPORT_END_Y, MSYS_PRIORITY_HIGH - 5, 0, 0, 0 ); //Okay and cancel buttons iFileDlgButtons[0] = CreateTextButton( L"Okay", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT, iScreenWidthOffset + 354, iScreenHeightOffset + 225, 50, 30, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, FDlgOkCallback ); iFileDlgButtons[1] = CreateTextButton( L"Cancel", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT, iScreenWidthOffset + 406, iScreenHeightOffset + 225, 50, 30, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, FDlgCancelCallback ); //dnl ch36 150909 Scroll buttons iFileDlgButtons[2] = CreateSimpleButton(iScreenWidthOffset+426, iScreenHeightOffset+92-19, "EDITOR//uparrow.sti", BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, FDlgUpCallback); iFileDlgButtons[3] = CreateSimpleButton(iScreenWidthOffset+426, iScreenHeightOffset+182-19, "EDITOR//downarrow.sti", BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, FDlgDwnCallback); //File list window iFileDlgButtons[4] = CreateHotSpot( (iScreenWidthOffset + 179+4), (iScreenHeightOffset + 69+3), (179+4+240), (69+120+3), MSYS_PRIORITY_HIGH-1, BUTTON_NO_CALLBACK, FDlgNamesCallback); //Title button iFileDlgButtons[5] = CreateTextButton(zTitle, GetHugeFont(), FONT_LTKHAKI, FONT_DKKHAKI, BUTTON_USE_DEFAULT,iScreenWidthOffset + 179, iScreenHeightOffset + 39,281,30,BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH-2,BUTTON_NO_CALLBACK,BUTTON_NO_CALLBACK); DisableButton(iFileDlgButtons[5]); SpecifyDisabledButtonStyle( iFileDlgButtons[5], DISABLED_STYLE_NONE ); iFileDlgButtons[6] = -1; if( iCurrentAction == ACTION_SAVE_MAP ) { //checkboxes //The update world info checkbox iFileDlgButtons[6] = CreateCheckBoxButton( iScreenWidthOffset + 183, iScreenHeightOffset + 229, "EDITOR//smcheckbox.sti", MSYS_PRIORITY_HIGH, UpdateWorldInfoCallback ); if( gfUpdateSummaryInfo ) ButtonList[ iFileDlgButtons[6] ]->uiFlags |= BUTTON_CLICKED_ON; } //Add the text input fields InitTextInputModeWithScheme( DEFAULT_SCHEME ); //dnl ch36 150909 field 1 (filename) AddTextInputField(iScreenWidthOffset+183, iScreenHeightOffset+195, 240, 20, MSYS_PRIORITY_HIGH, gzFilename, (FILENAME_BUFLEN-1), INPUTTYPE_EXCLUSIVE_DOSFILENAME); //field 2 -- user field that allows mouse/key interaction with the filename list AddUserInputField( FileDialogModeCallback ); } void UpdateWorldInfoCallback( GUI_BUTTON *b, INT32 reason ) { if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) gfUpdateSummaryInfo = b->uiFlags & BUTTON_CLICKED_ON ? TRUE : FALSE; } //This is a hook into the text input code. This callback is called whenever the user is currently //editing text, and presses Tab to transfer to the file dialog mode. When this happens, we set the text //field to the currently selected file in the list which is already know. void FileDialogModeCallback( UINT8 ubID, BOOLEAN fEntering ) { INT32 x; FDLG_LIST *FListNode; if( fEntering ) { // Skip to first filename FListNode = FileList; for(x=0;xpNext; } // Find the already selected filename for(x = iTopFileShown; x < iTopFileShown + 8 && x < iTotalFiles && FListNode != NULL; x++ ) { if( iCurrFileShown == (x-iTopFileShown) ) { FListNode->FileInfo.zFileName[30] = 0; SetInputFieldStringWith8BitString( 0, FListNode->FileInfo.zFileName ); return; } FListNode = FListNode->pNext; } } } void RemoveFileDialog(void) { INT32 x; MSYS_RemoveRegion( &BlanketRegion ); for(x=0; x<6; x++) { RemoveButton(iFileDlgButtons[x]); } if( iFileDlgButtons[6] != -1 ) { RemoveButton( iFileDlgButtons[6] ); } TrashFDlgList( FileList ); FileList = NULL; InvalidateScreen( ); EnableEditorTaskbar(); KillTextInputMode(); MarkWorldDirty(); RenderWorld(); EndFrameBufferRender(); } void DrawFileDialog(void) { //dnl ch36 150909 ColorFillVideoSurfaceArea(FRAME_BUFFER, iScreenWidthOffset+179, iScreenHeightOffset+69, iScreenWidthOffset+179+281, iScreenHeightOffset+261, Get16BPPColor(FROMRGB(136, 138, 135))); ColorFillVideoSurfaceArea(FRAME_BUFFER, iScreenWidthOffset+180, iScreenHeightOffset+70, iScreenWidthOffset+179+281, iScreenHeightOffset+261, Get16BPPColor(FROMRGB(24, 61, 81))); ColorFillVideoSurfaceArea(FRAME_BUFFER, iScreenWidthOffset+180, iScreenHeightOffset+70, iScreenWidthOffset+179+280, iScreenHeightOffset+260, Get16BPPColor(FROMRGB(65, 79, 94))); ColorFillVideoSurfaceArea(FRAME_BUFFER, iScreenWidthOffset+179+4, iScreenHeightOffset+69+3, iScreenWidthOffset+179+4+240, iScreenHeightOffset+69+123, Get16BPPColor(FROMRGB(24, 61, 81))); ColorFillVideoSurfaceArea(FRAME_BUFFER, iScreenWidthOffset+179+5, iScreenHeightOffset+69+4, iScreenWidthOffset+179+4+240, iScreenHeightOffset+69+123, Get16BPPColor(FROMRGB(136, 138, 135))); ColorFillVideoSurfaceArea(FRAME_BUFFER, iScreenWidthOffset+179+5, iScreenHeightOffset+69+4, iScreenWidthOffset+179+3+240, iScreenHeightOffset+69+122, Get16BPPColor(FROMRGB(250, 240, 188))); MarkButtonsDirty(); RenderButtons(); //RenderButtonsFastHelp();//dnl ch86 210214 disable this because of sticky tooltip from taskbar SetFont( FONT10ARIAL ); SetFontForeground( FONT_LTKHAKI ); SetFontShadow( FONT_DKKHAKI ); SetFontBackground( FONT_BLACK ); mprintf( iScreenWidthOffset + 183, iScreenHeightOffset + 217, L"Filename" ); if( iFileDlgButtons[6] != -1 ) { mprintf( iScreenWidthOffset + 200, iScreenHeightOffset + 231, L"Update world info" ); } } //The callback calls this function passing the relative y position of where //the user clicked on the hot spot. void SelectFileDialogYPos( UINT16 usRelativeYPos ) { INT16 sSelName; INT32 x; FDLG_LIST *FListNode; sSelName = usRelativeYPos / 15; //This is a field in the text editmode, but clicked via mouse. SetActiveField( 1 ); // Skip to first filename FListNode = FileList; for(x=0;xpNext; } for(x=iTopFileShown;x<(iTopFileShown+8) && xFileInfo.zFileName[30] = 0; swprintf( gzFilename, L"%S", FListNode->FileInfo.zFileName ); if( ValidFilename() ) { SetInputFieldStringWith16BitString( 0, gzFilename ); } else { SetInputFieldStringWith16BitString( 0, L"" ); wcscpy( gzFilename, L"" ); } RenderInactiveTextField( 0 ); //Calculate and process any double clicking... iCurrClickTime = GetJA2Clock(); if( iCurrClickTime - iLastClickTime < 400 && x == iLastFileClicked ) { //Considered a double click, so activate load/save this filename. gfDestroyFDlg = TRUE; iFDlgState = iCurrentAction == ACTION_SAVE_MAP ? DIALOG_SAVE : DIALOG_LOAD; } iLastClickTime = iCurrClickTime; iLastFileClicked = x; //dnl ch81 021213 gzProfileName[0] = 0; while(FListNode = FListNode->pPrev) { if(FListNode->FileInfo.zFileName[0] == '<') { strcpy(gzProfileName, &FListNode->FileInfo.zFileName[2]); gzProfileName[strlen(gzProfileName)-2] = 0; break; } } break; } FListNode = FListNode->pNext; } } FDLG_LIST *AddToFDlgList(FDLG_LIST *pList, GETFILESTRUCT *pInfo) { FDLG_LIST *pNode; // Add to start of list if ( pList == NULL ) { pNode = (FDLG_LIST *)MemAlloc( sizeof(FDLG_LIST) ); pNode->FileInfo = *pInfo; pNode->pPrev = pNode->pNext = NULL; return(pNode); } // Add and sort alphabetically without regard to case -- function limited to 10 chars comparison if ( _stricmp(pList->FileInfo.zFileName, pInfo->zFileName ) > 0 ) { // pInfo is smaller than pList (i.e. Insert before) pNode = (FDLG_LIST *)MemAlloc( sizeof(FDLG_LIST) ); pNode->FileInfo = *pInfo; pNode->pNext = pList; pNode->pPrev = pList->pPrev; pList->pPrev = pNode; return(pNode); } else { pList->pNext = AddToFDlgList( pList->pNext, pInfo ); pList->pNext->pPrev = pList; } return(pList); } BOOLEAN RemoveFromFDlgList( FDLG_LIST **head, FDLG_LIST *node ) { FDLG_LIST *curr; curr = *head; while( curr ) { if( curr == node ) { if( *head == node ) *head = (*head)->pNext; if( curr->pPrev ) curr->pPrev->pNext = curr->pNext; if( curr->pNext ) curr->pNext->pPrev = curr->pPrev; MemFree( node ); node = NULL; return TRUE; } curr = curr->pNext; } return FALSE; //wasn't deleted } void TrashFDlgList(FDLG_LIST *pList) { FDLG_LIST *pNode; while(pList)//dnl ch49 061009 Rewind, just to be sure { if(pList->pPrev) pList = pList->pPrev; else break; } while(pList != NULL) { pNode = pList; pList = pList->pNext; MemFree(pNode); } } void SetTopFileToLetter( UINT16 usLetter ) { UINT32 x; FDLG_LIST *curr; FDLG_LIST *prev; UINT16 usNodeLetter; // Skip to first filename x = 0; curr = prev = FileList; while( curr ) { usNodeLetter = curr->FileInfo.zFileName[0]; //first letter of filename. if( usNodeLetter < 'a' ) usNodeLetter += 32; //convert uppercase to lower case A=65, a=97 if( usLetter <= usNodeLetter ) break; prev = curr; curr = curr->pNext; x++; } if( FileList ) { iCurrFileShown = x; iTopFileShown = x; if( iTopFileShown > iTotalFiles - 7 ) iTopFileShown = iTotalFiles - 7; SetInputFieldStringWith8BitString( 0, prev->FileInfo.zFileName ); } } void HandleMainKeyEvents( InputAtom *pEvent ) { INT32 iPrevFileShown = iCurrFileShown; //Replace Alt-x press with ESC. if( pEvent->usKeyState & ALT_DOWN && pEvent->usParam == 'x' ) pEvent->usParam = ESC; switch( pEvent->usParam ) { case ENTER: if( gfNoFiles && iCurrentAction == ACTION_LOAD_MAP ) break; gfDestroyFDlg = TRUE; iFDlgState = iCurrentAction == ACTION_SAVE_MAP ? DIALOG_SAVE : DIALOG_LOAD; break; case ESC: gfDestroyFDlg = TRUE; iFDlgState = DIALOG_CANCEL; break; case PGUP: if( iTopFileShown > 7 ) { iTopFileShown -= 7; iCurrFileShown -= 7; } else { iTopFileShown = 0; iCurrFileShown = 0; } break; case PGDN: iTopFileShown += 7; iCurrFileShown += 7; if( iTopFileShown > iTotalFiles-7 ) iTopFileShown = iTotalFiles - 7; if( iCurrFileShown >= iTotalFiles ) iCurrFileShown = iTotalFiles - 1; break; case UPARROW: if( iCurrFileShown > 0 ) iCurrFileShown--; if( iTopFileShown > iCurrFileShown ) iTopFileShown = iCurrFileShown; break; case DNARROW: iCurrFileShown++; if( iCurrFileShown >= iTotalFiles ) iCurrFileShown = iTotalFiles - 1; else if( iTopFileShown < iCurrFileShown-7 ) iTopFileShown++; else if( iTopFileShown > iCurrFileShown )//dnl ch84 290114 iTopFileShown = iCurrFileShown; break; case HOME: case CTRL_HOME: iTopFileShown = 0; iCurrFileShown = 0; break; case END: case CTRL_END: iTopFileShown = iTotalFiles-7; iCurrFileShown = iTotalFiles-1; break; case DEL: iFDlgState = DIALOG_DELETE; break; default: //This case handles jumping the file list to display the file with the letter pressed. if( pEvent->usParam >= 'a' && pEvent->usParam <= 'z' || pEvent->usParam >= 'A' && pEvent->usParam <= 'Z' ) { if( pEvent->usParam >= 'A' && pEvent->usParam <= 'Z' ) //convert upper case to lower case pEvent->usParam += 32; // A = 65, a = 97 (difference of 32) SetTopFileToLetter( (UINT16)pEvent->usParam ); } break; } //Update the text field if the file value has changed. if( iCurrFileShown != iPrevFileShown ) { INT32 x; FDLG_LIST *curr; x = 0; curr = FileList; while( curr && x != iCurrFileShown ) { curr = curr->pNext; x++; } if( curr ) { SetInputFieldStringWith8BitString( 0, curr->FileInfo.zFileName ); swprintf( gzFilename, L"%S", curr->FileInfo.zFileName ); //dnl ch84 290114 if(ValidFilename()) SetInputFieldStringWith16BitString(0, gzFilename); else { SetInputFieldStringWith16BitString(0, L""); wcscpy(gzFilename, L""); } gzProfileName[0] = 0; while(curr = curr->pPrev) { if(curr->FileInfo.zFileName[0] == '<') { strcpy(gzProfileName, &curr->FileInfo.zFileName[2]); gzProfileName[strlen(gzProfileName)-2] = 0; break; } } } } } void HandleMouseWheelEvents(void)//dnl ch36 150909 { if(_WheelValue > 0) { while(_WheelValue--) { if(iTopFileShown > 0) iTopFileShown--; } } else if(_WheelValue < 0) { while(_WheelValue++) { if((iTopFileShown+7) < iTotalFiles) iTopFileShown++; } } _WheelValue = 0; } void InitErrorCatchDialog() { SGPRect CenteringRect= {0 + xResOffset, 0, SCREEN_WIDTH - xResOffset, SCREEN_HEIGHT }; // do message box and return giErrorCatchMessageBox = DoMessageBox( MSG_BOX_BASIC_STYLE, gzErrorCatchString, EDIT_SCREEN, MSG_BOX_FLAG_OK, NULL, &CenteringRect ); gfErrorCatch = FALSE; } extern BOOLEAN ReEvaluateWorld( const STR8 puiFilename ); //Because loading and saving the map takes a few seconds, we want to post a message //on the screen and then update it which requires passing the screen back to the main loop. //When we come back for the next frame, we then actually save or load the map. So this //process takes two full screen cycles. UINT32 ProcessFileIO() { INT16 usStartX, usStartY; CHAR8 ubNewFilename[FILENAME_BUFLEN];//dnl ch81 021213 BOOLEAN fAltMap;//dnl ch31 150909 switch( gbCurrentFileIOStatus ) { case INITIATE_MAP_SAVE: //draw save message StartFrameBufferRender( ); SaveFontSettings(); SetFont( GetHugeFont() ); SetFontForeground( FONT_LTKHAKI ); SetFontShadow( FONT_DKKHAKI ); SetFontBackground( 0 ); swprintf( zOrigName, L"Saving map: %s", gzFilename ); usStartX = iScreenWidthOffset + 320 - StringPixLength( zOrigName, LARGEFONT1 ) / 2; usStartY = iScreenHeightOffset + 180 - GetFontHeight( LARGEFONT1 ) / 2; mprintf( usStartX, usStartY, zOrigName ); InvalidateScreen( ); EndFrameBufferRender( ); gbCurrentFileIOStatus = SAVING_MAP; return LOADSAVE_SCREEN; case SAVING_MAP: //save map sprintf( ubNewFilename, "%S", gzFilename ); RaiseWorldLand(); if( gfShowPits ) RemoveAllPits(); OptimizeSchedules(); ShowHighGround(4);//dnl ch41 210909 //dnl ch33 091009 BOOLEAN fRet; if(gfVanillaMode && iNewMapWorldRows == OLD_WORLD_ROWS && iNewMapWorldCols == OLD_WORLD_COLS) fRet = SaveWorld(ubNewFilename, VANILLA_MAJOR_MAP_VERSION, VANILLA_MINOR_MAP_VERSION); else fRet = SaveWorld(ubNewFilename); if(!fRet) { //dnl ch37 150909 gfSaveError = TRUE; if(gfErrorCatch) { InitErrorCatchDialog(); return(EDIT_SCREEN); } gbCurrentFileIOStatus = IOSTATUS_NONE; CreateMessageBox((STR16)(_BS(L" Error saving ") << (const char*)ubNewFilename << L" file. Try another filename? " << _BS::wget).c_str() ); return(guiCurrentScreen); } if(gfShowExitGrids)//dnl ch86 190214 { gfShowExitGrids = FALSE; ShowExitGrids(); } if( gfShowPits ) AddAllPits(); GetSectorFromFileName(gzFilename, gWorldSectorX, gWorldSectorY, gbWorldSectorZ, fAltMap);//dnl ch31 140909 if( gfGlobalSummaryExists ) UpdateSectorSummary( gzFilename, gfUpdateSummaryInfo ); else//dnl ch30 150909 ReEvaluateWorld(ubNewFilename); iCurrentAction = ACTION_NULL; gbCurrentFileIOStatus = IOSTATUS_NONE; gfRenderWorld = TRUE; gfRenderTaskbar = TRUE; fEnteringLoadSaveScreen = TRUE; RestoreFontSettings(); if( gfErrorCatch ) { InitErrorCatchDialog(); return EDIT_SCREEN; } fNewMapSaved = TRUE; return EDIT_SCREEN; case INITIATE_MAP_LOAD: //draw load message SaveFontSettings(); gbCurrentFileIOStatus = LOADING_MAP; if( gfEditMode && iCurrentTaskbar == TASK_MERCS ) IndicateSelectedMerc( SELECT_NO_MERC ); SpecifyItemToEdit( NULL, -1 ); return LOADSAVE_SCREEN; case LOADING_MAP: //load map DisableUndo(); sprintf( ubNewFilename, "%S", gzFilename ); RemoveMercsInSector( ); // Want to override crash, so user can do something else. if(!ReEvaluateWorld(ubNewFilename) || !LoadWorld(ubNewFilename))//dnl ch36 140909 { EnableUndo(); gbCurrentFileIOStatus = IOSTATUS_NONE; gfGlobalError = FALSE; gfLoadError = TRUE; CreateMessageBox((STR16)(_BS(L" Error loading ") << (const char*)ubNewFilename << L" file. Try another filename? " << _BS::wget).c_str()); return(guiCurrentScreen); } //ADB these are NOT set yet! but they need to be, duh CompileWorldMovementCosts(); GetSectorFromFileName(gzFilename, gWorldSectorX, gWorldSectorY, gbWorldSectorZ, fAltMap);//dnl ch31 140909 RestoreFontSettings(); //Load successful, update necessary information. //ATE: Any current mercs are transfered here... //UpdateMercsInSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); AddSoldierInitListTeamToWorld( ENEMY_TEAM, TOTAL_SOLDIERS + 1 ); AddSoldierInitListTeamToWorld( CREATURE_TEAM, TOTAL_SOLDIERS + 1 ); AddSoldierInitListTeamToWorld( MILITIA_TEAM, TOTAL_SOLDIERS + 1 ); AddSoldierInitListTeamToWorld( CIV_TEAM, TOTAL_SOLDIERS + 1 ); iCurrentAction = ACTION_NULL; gbCurrentFileIOStatus = IOSTATUS_NONE; if( !gfCaves && !gfBasement ) { gusLightLevel = 12; if( ubAmbientLightLevel != 4 ) { ubAmbientLightLevel = 4; LightSetBaseLevel( ubAmbientLightLevel ); } } else gusLightLevel = (UINT16)(EDITOR_LIGHT_MAX - ubAmbientLightLevel ); gEditorLightColor = gpLightColors[ 0 ]; gfRenderWorld = TRUE; gfRenderTaskbar = TRUE; fEnteringLoadSaveScreen = TRUE; InitJA2SelectionWindow(); ShowEntryPoints(); EnableUndo(); RemoveAllFromUndoList(); SetEditorSmoothingMode( gMapInformation.ubEditorSmoothingType ); if( gMapInformation.ubEditorSmoothingType == SMOOTHING_CAVES ) AnalyseCaveMapForStructureInfo(); AddLockedDoorCursors(); gusCurrRoomNumber = gusMaxRoomNumber; UpdateRoofsView(); UpdateWallsView(); ShowLightPositionHandles(); SetMercTeamVisibility( ENEMY_TEAM, gfShowEnemies ); SetMercTeamVisibility( CREATURE_TEAM, gfShowCreatures ); SetMercTeamVisibility( MILITIA_TEAM, gfShowRebels ); SetMercTeamVisibility( CIV_TEAM, gfShowCivilians ); BuildItemPoolList(); gpItemPool = NULL;//dnl ch26 210909 fShowHighGround = FALSE;//dnl ch2 210909 fRaiseWorld = FALSE;//dnl ch3 210909 ShowHighGround(4);//dnl ch41 210909 SetRenderCenter(WORLD_COLS/2, WORLD_ROWS/2);//dnl ch43 280909 gsSelectedMercGridNo = 0;//dnl ch74 241013 to prevent CTD in IndicateSelectedMerc after loading if(gfShowExitGrids)//dnl ch86 190214 { gfShowExitGrids = FALSE; ShowExitGrids(); } if( gfShowPits ) AddAllPits(); if( iCurrentTaskbar == TASK_MAPINFO ) { //We have to temporarily remove the current textinput mode, //update the disabled text field values, then restore the current //text input fields. SaveAndRemoveCurrentTextInputMode(); UpdateMapInfoFields(); RestoreSavedTextInputMode(); } return EDIT_SCREEN; } gbCurrentFileIOStatus = IOSTATUS_NONE; return LOADSAVE_SCREEN; } //LOADSCREEN void FDlgNamesCallback( GUI_BUTTON *butn, INT32 reason ) { if( reason & (MSYS_CALLBACK_REASON_LBUTTON_UP) ) { SelectFileDialogYPos( butn->Area.RelativeYPos ); } } void FDlgOkCallback( GUI_BUTTON *butn, INT32 reason ) { if( reason & (MSYS_CALLBACK_REASON_LBUTTON_UP) ) { gfDestroyFDlg = TRUE; iFDlgState = iCurrentAction == ACTION_SAVE_MAP ? DIALOG_SAVE : DIALOG_LOAD; } } void FDlgCancelCallback( GUI_BUTTON *butn, INT32 reason ) { if( reason & (MSYS_CALLBACK_REASON_LBUTTON_UP) ) { gfDestroyFDlg = TRUE; iFDlgState = DIALOG_CANCEL; } } void FDlgUpCallback( GUI_BUTTON *butn, INT32 reason ) { if( reason & (MSYS_CALLBACK_REASON_LBUTTON_UP) ) { if(iTopFileShown > 0) iTopFileShown--; } } void FDlgDwnCallback( GUI_BUTTON *butn, INT32 reason ) { if( reason & (MSYS_CALLBACK_REASON_LBUTTON_UP) ) { if( (iTopFileShown+7) < iTotalFiles ) iTopFileShown++; } } //dnl ch36 200909 BOOLEAN ExtractFilenameFromFields(void) { Get16BitStringFromField(0, gzFilename, FILENAME_BUFLEN); size_t len = wcslen(gzFilename); if(gzFilename[len-4] != L'.' && len < (FILENAME_BUFLEN-4)) wcscat(gzFilename, L".dat"); return(ValidFilename()); } //dnl ch31 140909 BOOLEAN ValidMapFileName(STR16 szFileName) { CHAR16 szFileExt[4+1]; size_t len = wcslen(szFileName); if(len >= 5) { wcscpy(szFileExt, szFileName+len-4); for(int i=0; i<4; i++) szFileExt[i] = towupper(szFileExt[i]); if(wcscmp(szFileExt, L".DAT") == 0) return(TRUE); } return(FALSE); } //dnl ch37 200909 BOOLEAN ExternalLoadMap(STR16 szFilename) { gfLoadError = FALSE; Assert(szFilename); if(!wcslen( szFilename)) return(FALSE); wcscpy(gzFilename, szFilename); if(!ValidFilename()) return(FALSE); gbCurrentFileIOStatus = INITIATE_MAP_LOAD; ProcessFileIO(); ExecuteBaseDirtyRectQueue(); EndFrameBufferRender(); RefreshScreen(NULL); ProcessFileIO(); if(gfLoadError) return(FALSE); return(TRUE); } BOOLEAN ExternalSaveMap(STR16 szFilename) { gfSaveError = FALSE; Assert(szFilename); if(!wcslen(szFilename)) return(FALSE); wcscpy(gzFilename, szFilename); if(!ValidFilename()) return(FALSE); gbCurrentFileIOStatus = INITIATE_MAP_SAVE; ProcessFileIO(); if(gfSaveError) return(FALSE); ExecuteBaseDirtyRectQueue(); EndFrameBufferRender(); RefreshScreen(NULL); ProcessFileIO(); if(gfSaveError) return(FALSE); return(TRUE); } #else //non-editor version #include "types.h" #include "screenids.h" UINT32 LoadSaveScreenInit() { return TRUE ; } UINT32 LoadSaveScreenHandle( ) { //If this screen ever gets set, then this is a bad thing -- endless loop return ERROR_SCREEN ; } UINT32 LoadSaveScreenShutdown( ) { return TRUE ; } #endif