| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- /*
- FinalSun/FinalAlert 2 Mission Editor
- Copyright (C) 1999-2024 Electronic Arts, Inc.
- Authored by Matthias Wagner
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- //
- // This is the application code. Mainly shows the main dialog and initializes some application global stuff
- //
- #include "stdafx.h"
- #include "FinalSun.h"
- #include "FinalSunDlg.h"
- #include "structs.h"
- #include "mapdata.h"
- #include "variables.h"
- #include "functions.h"
- #include "inlines.h"
- #include <ShlObj.h>
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- #define APPID "FinalSun App"
- extern char AppPath[];
- extern ACTIONDATA AD;
- /////////////////////////////////////////////////////////////////////////////
- // CFinalSunApp
- BEGIN_MESSAGE_MAP(CFinalSunApp, CWinApp)
- //{{AFX_MSG_MAP(CFinalSunApp)
- //}}AFX_MSG_MAP
- ON_COMMAND(ID_HELP, CWinApp::OnHelp)
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CFinalSunApp construction
- void __cdecl term_func()
- {
- if (MessageBox(0, "Fatal error. Exit FinalSun?", "Fatal error", MB_YESNO) == IDCANCEL) return;
- exit(-1);
- }
- CFinalSunApp::CFinalSunApp()
- {
- m_cf = RegisterClipboardFormat("FINAL*FORMAT");
- if (!m_cf) MessageBox(0, "Failed to register clipboard format, clipboard functions not available", "", 0);
- tiledata_count = &t_tiledata_count;
- tiledata = &t_tiledata;
- // first: set up global variable AppPath
- // [02/16/2000] using GetModuleFileName() instead of GetCurrentDirectory(): always the correct path
- wchar_t AppPathUtf16[MAX_PATH] = { 0 };
- GetModuleFileNameW(NULL, AppPathUtf16, MAX_PATH);
- strcpy_s(AppPath, utf16ToUtf8(AppPathUtf16).c_str());
- *(strrchr(AppPath, '\\') + 1) = 0;
- // Initialize AppData
- const std::wstring AppDataPathFolder = utf8ToUtf16(u8AppDataPath.substr(0, u8AppDataPath.size() - 1));
- auto create_dir_res = SHCreateDirectoryExW(NULL, AppDataPathFolder.c_str(), nullptr);
- if (ERROR_SUCCESS != create_dir_res && ERROR_ALREADY_EXISTS != create_dir_res)
- {
- wchar_t err_msg[1025] = { 0 };
- FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, create_dir_res, 0, err_msg, 1024, NULL);
- MessageBoxW(NULL, err_msg, (std::wstring(L"Failed to open ") + AppDataPathFolder).c_str(), 0);
- exit(1);
- }
- if ((GetFileAttributesW(AppDataPathFolder.c_str()) & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
- {
- MessageBoxW(NULL, (AppDataPathFolder + L" must be a directory, not a file").c_str(), (std::wstring(L"Failed to open ") + AppDataPathFolder).c_str(), 0);
- exit(1);
- }
- /*memset(t_tilepics, 0, sizeof(TILEPICDATA)*10000);
- memset(s_tilepics, 0, sizeof(TILEPICDATA)*10000);*/
- m_Options.LanguageName = "English";
- m_Options.bFlat = FALSE;
- m_Options.bEasy = FALSE;
- m_Options.bSupportMarbleMadness = FALSE;
- m_Options.bMarbleMadness = FALSE;
- auto log = u8AppDataPath;
- #ifdef TS_MODE
- log += "finalsunlog.txt";
- #else
- log += "finalalert2log.txt";
- #endif
- m_u8LogFileName = log;
- errstream.open(m_u8LogFileName, ios_base::trunc);
- errstream << "\uFEFF"; // BOM
- #ifdef TS_MODE
- errstream << "FinalSun log file" << std::endl << "----------------------" << std::endl << std::endl;
- #else
- errstream << "FinalAlert 2 log file" << std::endl << "----------------------" << std::endl << std::endl;
- #endif
- errstream << "CFinalSunApp::CFinalSunApp() called" << std::endl;
- errstream << "App Path: " << AppPath << std::endl;
- errstream << "AppData Path: " << u8AppDataPath << std::endl;
- errstream << "Locale: " << setlocale(LC_ALL, nullptr) << std::endl;
- errstream << "Windows ACP: " << GetACP() << std::endl;
- INITCOMMONCONTROLSEX ctr;
- ctr.dwSize = sizeof(INITCOMMONCONTROLSEX);
- ctr.dwICC = ICC_STANDARD_CLASSES;
- if (!InitCommonControlsEx(&ctr))
- {
- errstream << "Error: Common controls could not be initialized" << std::endl;
- MessageBox(0, "Common controls could not be initialized.", "Error", 0);
- }
- errstream << std::endl << std::endl << std::endl;
- errstream.flush();
- }
- /////////////////////////////////////////////////////////////////////////////
- // CFinalSunApp initialization
- BOOL CFinalSunApp::InitInstance()
- {
- m_hAccel = LoadAccelerators(this->m_hInstance, MAKEINTRESOURCE(IDR_MAIN));
- #ifndef NOSURFACES
- if (GetDeviceCaps(GetDC(GetDesktopWindow()), BITSPIXEL) <= 8)
- {
- MessageBox(0, "You currently only have 8 bit color mode enabled. This is not recommended. You can continue, but this will cause a significant slowdown while loading graphics, and result in poor graphics quality", "Error", 0);
- //exit(0);
- }
- #else
- if (GetDeviceCaps(GetDC(GetDesktopWindow()), BITSPIXEL) <= 8)
- {
- MessageBox(0, "You currently only have 8 bit color mode enabled. FinalSun/FinalAlert 2 will not work in 8 bit color mode. See readme.txt for further information!", "Error", 0);
- exit(0);
- }
- #endif
- ParseCommandLine();
- // Load application data
- std::string datafile = AppPath;
- #ifdef TS_MODE
- datafile += "\\FSData.ini";
- #else
- datafile += "\\FAData.ini";
- #endif
- g_data.LoadFile(datafile);
- // Load language data
- std::string languagefile = AppPath;
- #ifndef RA2_MODE
- languagefile += "\\FSLanguage.ini";
- #else
- languagefile += "\\FALanguage.ini";
- #endif
- language.LoadFile(languagefile);
- if (language.sections.size() == 0)
- {
- MessageBox(0, "FALanguage.ini does not exist or is not valid (download corrupt?)", "", 0);
- exit(0);
- }
- #ifndef RA2_MODE
- const std::string iniName = "FinalSun.ini";
- const std::string defaultIniName = "FinalSunDefaults.ini";
- #else
- const std::string iniName = "FinalAlert.ini";
- const std::string defaultIniName = "FinalAlertDefaults.ini";
- #endif
- // ok lets get some options
- CIniFile optini;
- std::string iniFile = u8AppDataPath + iniName;
- std::string templateIniFile = std::string(AppPath) + defaultIniName;
- bool copiedDefaultFile = false;
- if (!DoesFileExist(iniFile.c_str()))
- {
- if (CopyFileW(utf8ToUtf16(templateIniFile).c_str(), utf8ToUtf16(iniFile).c_str(), TRUE))
- copiedDefaultFile = true;
- }
- optini.LoadFile(iniFile);
- #ifdef RA2_MODE
- CString game = "RA2";
- CString app = "FinalAlert";
- #else
- CString game = "TS";
- CString app = "FinalSun";
- #endif
- std::wstring key;
- #ifdef RA2_MODE
- key = L"Software\\Westwood\\Red Alert 2";
- #else
- key = L"Software\\Westwood\\Tiberian Sun";
- #endif
- auto& opts = m_Options;
- HKEY hKey = 0;
- int res;
- res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_EXECUTE/*KEY_ALL_ACCESS*/, &hKey);
- if (res != ERROR_SUCCESS)
- {
- std::wstring s = L"Failed to access registry. Using manual setting. Error was:\n";
- wchar_t c[1024] = { 0 };
- FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, res, 0, c, 1023, NULL);
- MessageBoxW(0, (s + c).c_str(), L"Error", 0);
- opts.TSExe = optini.sections[game].values["Exe"];
- }
- else
- {
- // key opened
- wchar_t path[MAX_PATH + 1] = { 0 };
- DWORD pathsize = MAX_PATH;
- DWORD type = REG_SZ;
- if ((res = RegQueryValueExW(hKey, L"InstallPath", 0, &type, (unsigned char*)path, &pathsize)) != ERROR_SUCCESS)
- {
- std::wstring s = L"Failed to access registry. Using manual setting. Error was:\n";
- wchar_t c[1024] = { 0 };
- FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, res, 0, c, 1023, NULL);
- MessageBoxW(0, (s + c).c_str(), L"Error", 0);
- opts.TSExe = optini.sections[game].values["Exe"];
- }
- else
- opts.TSExe = path;
- }
- if (copiedDefaultFile ||
- optini.sections.size() == 0 ||
- opts.TSExe.GetLength() == 0 ||
- optini.sections[app].values["Language"].GetLength() == 0 ||
- optini.sections[app].values.find("FileSearchLikeGame") == optini.sections[app].values.end() ||
- optini.sections[app].values.find("PreferLocalTheaterFiles") == optini.sections[app].values.end())
- {
- opts.bSearchLikeTS = TRUE;
- bOptionsStartup = TRUE;
- ShowOptionsDialog();
- bOptionsStartup = FALSE;
- }
- else
- {
- opts.LanguageName = optini.sections[app].values["Language"];
- if (optini.sections[app].values["FileSearchLikeGame"] != "no")
- opts.bSearchLikeTS = TRUE;
- else opts.bSearchLikeTS = FALSE;
- }
- opts.bPreferLocalTheaterFiles = optini.sections[app].values.emplace("PreferLocalTheaterFiles", opts.bPreferLocalTheaterFiles ? "1" : "0").first->second == "1";
- opts.bDoNotLoadAircraftGraphics = optini.sections["Graphics"].values["NoAircraftGraphics"] == "1";
- opts.bDoNotLoadVehicleGraphics = optini.sections["Graphics"].values["NoVehicleGraphics"] == "1";
- opts.bDoNotLoadBuildingGraphics = optini.sections["Graphics"].values["NoBuildingGraphics"] == "1";
- opts.bDoNotLoadInfantryGraphics = optini.sections["Graphics"].values["NoInfantryGraphics"] == "1";
- opts.bDoNotLoadTreeGraphics = optini.sections["Graphics"].values["NoTreeGraphics"] == "1";
- opts.bDoNotLoadSnowGraphics = optini.sections["Graphics"].values["NoSnowGraphics"] == "1";
- opts.bDoNotLoadTemperateGraphics = optini.sections["Graphics"].values["NoTemperateGraphics"] == "1";
- opts.bDoNotLoadBMPs = optini.sections["Graphics"].values["NoBMPs"] == "1";
- opts.bDoNotLoadOverlayGraphics = optini.sections["Graphics"].values["NoOverlayGraphics"] == "1";
- opts.bVSync = optini.sections["Graphics"].values.emplace("VSync", opts.bVSync ? "1" : "0").first->second == "1";
- opts.bDisableAutoShore = optini.sections["UserInterface"].values["DisableAutoShore"] == "1";
- opts.bDisableAutoLat = optini.sections["UserInterface"].values["DisableAutoLat"] == "1";
- opts.bNoSounds = optini.sections["UserInterface"].values["Sounds"] != "1";
- opts.bDisableSlopeCorrection = optini.sections["UserInterface"].values["DisableSlopeCorrection"] == "1";
- opts.fLoadScreenDelayInSeconds = static_cast<float>(atof(optini.sections["UserInterface"].values.emplace("LoadScreenDelay", std::to_string(opts.fLoadScreenDelayInSeconds).c_str()).first->second));
- opts.bShowStats = optini.sections["UserInterface"].values.emplace("ShowStats", opts.bShowStats ? "1" : "0").first->second == "1";
- opts.bHighResUI = optini.sections["UserInterface"].values.emplace("HighRes", opts.bHighResUI ? "1" : "0").first->second == "1";
- opts.useDefaultMouseCursor = optini.sections["UserInterface"].values.emplace("UseDefaultMouseCursor", opts.useDefaultMouseCursor ? "1" : "0").first->second == "1";
- opts.fMiniMapScale = static_cast<float>(atof(optini.sections["MiniMap"].values.emplace("Scale", std::to_string(opts.fMiniMapScale).c_str()).first->second));
- auto defaultViewSteps = CString(Join(",", opts.viewScaleSteps | std::views::transform([](auto v) {return std::to_string(v); })).c_str());
- auto viewScaleStepsRange = SplitParams(optini.sections["UserInterface"].values.emplace("ViewScaleSteps", defaultViewSteps).first->second) | std::views::transform([](auto v) { return static_cast<float>(std::atof(v)); });
- opts.viewScaleSteps.assign(viewScaleStepsRange.begin(), viewScaleStepsRange.end());
- opts.viewScaleUseSteps = optini.sections["UserInterface"].values.emplace("ViewScaleUseSteps", opts.viewScaleUseSteps ? "1" : "0").first->second == "1";
- opts.viewScaleSpeed = static_cast<float>(atof(optini.sections["UserInterface"].values.emplace("ViewScaleSpeed", std::to_string(opts.viewScaleSpeed).c_str()).first->second));
- // MW 07/19/01
- opts.bShowCells = optini.sections["UserInterface"].values["ShowBuildingCells"] == "1";
- optini.SaveFile(iniFile);
- // MW 07/20/01: Load file list
- int i;
- for (i = 0;i < 4;i++)
- {
- char c[50];
- itoa(i, c, 10);
- opts.prev_maps[i] = optini.sections["Files"].values[c];
- }
- if (opts.bDoNotLoadTemperateGraphics && opts.bDoNotLoadSnowGraphics)
- {
- MessageBox(0, "You have turned off loading of both snow and temperate terrain in 'FinalAlert.ini'. At least one of these must be loaded. The application will now quit.", "Error", 0);
- exit(-982);
- }
- int EasyView;
- if (optini.sections["UserInterface"].FindName("EasyView") < 0)
- {
- MessageBox(0, GetLanguageStringACP("ExplainEasyView"), GetLanguageStringACP("ExplainEasyViewCap"), 0);
- EasyView = 1;
- optini.LoadFile(iniFile);
- optini.sections["UserInterface"].values["EasyView"] = "1";
- optini.SaveFile(iniFile);
- }
- else
- {
- EasyView = atoi(optini.sections["UserInterface"].values["EasyView"]);
- }
- if (EasyView != 0) theApp.m_Options.bEasy = TRUE;
- CString cTSPath = theApp.m_Options.TSExe;
- auto lastSlash = cTSPath.ReverseFind('\\');
- if (lastSlash >= 0)
- cTSPath.SetAt(lastSlash + 1, 0);
- strcpy(TSPath, cTSPath);
- // MW 01/23/2013: changed the global CMapData Map to a global CMapData* to get rid of static initialization/shutdown problems
- {
- std::unique_ptr<CMapData> mapData(new CMapData());
- Map = mapData.get();
- CLoading loading(NULL);
- m_loading = &loading;
- CFinalSunDlg dlg;
- m_pMainWnd = &dlg;
- dlg.DoModal();
- }
- // Map and dialog closed, do further work if required
- return FALSE;
- }
- void CFinalSunApp::ParseCommandLine()
- {
- #if 0 // Removed as it can conflict with Steam game arguments! -LF 23.02.2024
- char data[MAX_PATH + 30];
- strcpy(data, theApp.m_lpCmdLine);
- if (strlen(data) == 0)
- {
- strcpy(currentMapFile, "");
- return;
- }
- strcpy(currentMapFile, data);
- #endif
- }
- void CFinalSunApp::ShowTipAtStartup(void)
- {
- CTipDlg dlg;
- if (dlg.m_bStartup)
- dlg.DoModal();
- }
- void CFinalSunApp::ShowTipOfTheDay(void)
- {
- CTipDlg dlg;
- dlg.DoModal();
- }
- int CFinalSunApp::Run()
- {
- return CWinApp::Run();
- }
- BOOL CFinalSunApp::ProcessMessageFilter(int code, LPMSG lpMsg)
- {
- if (lpMsg->message == WM_KEYDOWN)
- {
- /*if(lpMsg->wParam==VK_F1)
- {
- if(ShellExecute(0, NULL, (CString)AppPath+"/help/index.htm", NULL, NULL, SW_NORMAL)==0)
- {
- MessageBox(0,(CString)"Could not open manual! Try opening "+(CString)AppPath+(CString)"/help/index.htm manually","Error",0);
- }
- return TRUE;
- }*/
- // check AD mode
- if (lpMsg->wParam == VK_PRIOR || lpMsg->wParam == VK_NEXT)
- {
- if (lpMsg->wParam == VK_PRIOR)
- {
- AD.z_data += 1;
- }
- if (lpMsg->wParam == VK_NEXT)
- {
- AD.z_data -= 1;
- }
- if (AD.mode == ACTIONMODE_SETTILE || AD.mode == ACTIONMODE_PASTE)
- {
- CIsoView* v = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview;
- CTerrainDlg& tdlg = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_browser->m_bar;
- WORD isox, isoy;
- RECT r;
- POINT p;
- v->GetWindowRect(&r);
- GetCursorPos(&p);
- isox = p.x - r.left;
- isoy = p.y - r.top;
- if (isox > r.right - r.left || isoy > r.bottom - r.top)
- {
- }
- else
- {
- LPARAM lParam;
- memcpy(&lParam, &isox, 2);
- memcpy((BYTE*)&lParam + 2, &isoy, 2);
- v->SendMessage(WM_MOUSEMOVE, 0, lParam);
- }
- }
- }
- if (AD.mode == ACTIONMODE_SETTILE)
- {
- CIsoView* v = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview;
- CTerrainDlg& tdlg = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_browser->m_bar;
- WORD isox, isoy;
- RECT r;
- POINT p;
- v->GetWindowRect(&r);
- GetCursorPos(&p);
- isox = p.x - r.left;
- isoy = p.y - r.top;
- if (isox > r.right - r.left || isoy > r.bottom - r.top)
- {
- }
- else
- {
- LPARAM lParam;
- memcpy(&lParam, &isox, 2);
- memcpy((BYTE*)&lParam + 2, &isoy, 2);
- int searchedTileSet;
- int z;
- switch (lpMsg->wParam)
- {
- case VK_LEFT:
- if (AD.type > 0 && (*tiledata)[AD.type].wTileSet == (*tiledata)[AD.type - 1].wTileSet) { AD.type -= 1; AD.z_data = 0; }
- v->SendMessage(WM_MOUSEMOVE, 0, lParam);
- return 0;
- break;
- case VK_RIGHT:
- if (AD.type < (*tiledata_count) - 1 && (*tiledata)[AD.type].wTileSet == (*tiledata)[AD.type + 1].wTileSet) { AD.type += 1; AD.z_data = 0; }
- v->SendMessage(WM_MOUSEMOVE, 0, lParam);
- return 0;
- break;
- case VK_UP:
- searchedTileSet = (*tiledata)[AD.type].wTileSet - 1;
- case VK_DOWN:
- if (lpMsg->wParam == VK_DOWN)
- searchedTileSet = (*tiledata)[AD.type].wTileSet + 1;
- if (searchedTileSet >= 0 && searchedTileSet < tilesets_start.size())
- {
- int i;
- int s = 1;
- int start = 0;
- int count = tilesets_start.size() - searchedTileSet;
- if (searchedTileSet < (*tiledata)[AD.type].wTileSet)
- {
- s = -1;
- start = 0;
- count = searchedTileSet + 1;
- }
- for (i = start;i < count;i += 1)
- {
- if (searchedTileSet + i * s < 0 || searchedTileSet + i * s >= tilesets_start.size()) continue;
- int pos = tilesets_start[searchedTileSet + i * s];
- int e;
- CComboBox* cb = ((CComboBox*)tdlg.GetDlgItem(IDC_TILESET));
- BOOL bFound = FALSE;
- for (e = 0;e < cb->GetCount();e++)
- {
- if (cb->GetItemData(e) == searchedTileSet + i * s)
- {
- cb->SendMessage(CB_SETCURSEL, e, 0);
- bFound = TRUE;
- break;
- }
- }
- if (bFound)
- {
- AD.type = tilesets_start[searchedTileSet + i * s];
- AD.data = 0;
- AD.data2 = 0;
- AD.data3 = 0;
- AD.data_s = "";
- v->SendMessage(WM_MOUSEMOVE, 0, lParam);
- return 0;
- }
- }
- return 0;
- break;
- }
- return 0;
- break;
- }
- }
- }
- }
- return CWinApp::ProcessMessageFilter(code, lpMsg);
- }
- LRESULT CFinalSunApp::ProcessWndProcException(CException* e, const MSG* pMsg)
- {
- // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
- e->ReportError(MB_YESNO);
- return TRUE;
- //return CWinApp::ProcessWndProcException(e, pMsg);
- }
- BOOL CFinalSunApp::PreTranslateMessage(MSG* pMsg)
- {
- if (!TranslateAccelerator(
- *this->m_pMainWnd, // handle to receiving window
- m_hAccel, // handle to active accelerator table
- pMsg)) // message data
- return CWinApp::PreTranslateMessage(pMsg);
- return FALSE;
- }
- BOOL CFinalSunApp::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- return CWinApp::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
- }
- BOOL CFinalSunApp::OnIdle(LONG lCount)
- {
- ((CFinalSunDlg*)m_pMainWnd)->m_view.m_isoview->UpdateWindow();
- //MessageBox(0,"Idled","",0);
- return CWinApp::OnIdle(lCount);
- }
|