From 00753d2ff2ae712af8a668c9ea80f7787d59ee94 Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Thu, 25 Apr 2024 19:11:06 -0400 Subject: [PATCH 1/8] restrict "std" namespace using . --- MissionEditor/Basic.cpp | 2 +- MissionEditor/ComboUInputDlg.h | 2 +- MissionEditor/FinalSun.cpp | 2 +- MissionEditor/FinalSunDlg.cpp | 2 ++ MissionEditor/IniFile.h | 3 ++- MissionEditor/IsoView.cpp | 20 ++++++++++---------- MissionEditor/Loading.cpp | 4 ++-- MissionEditor/MapData.h | 2 +- MissionEditor/MiniMap.cpp | 8 ++++---- MissionEditor/MissionEditor.vcxproj | 4 ++-- MissionEditor/StdAfx.h | 5 ++--- MissionEditor/TextDrawer.cpp | 2 +- MissionEditor/functions.cpp | 4 ++-- MissionEditor/functions.h | 2 ++ MissionEditor/inlines.h | 2 +- MissionEditor/variables.cpp | 2 +- MissionEditor/variables.h | 2 +- 17 files changed, 36 insertions(+), 32 deletions(-) diff --git a/MissionEditor/Basic.cpp b/MissionEditor/Basic.cpp index ceac04e..058b5ed 100644 --- a/MissionEditor/Basic.cpp +++ b/MissionEditor/Basic.cpp @@ -163,7 +163,7 @@ void CBasic::OnChangeName() void CBasic::UpdateData() { // MessageBox("This function ( UpdateData() ) should not be called here... please report to the author."); - errstream << "CBasic::UpdateData() called - should not be called" << endl; + errstream << "CBasic::UpdateData() called - should not be called" << std::endl; errstream.flush(); } diff --git a/MissionEditor/ComboUInputDlg.h b/MissionEditor/ComboUInputDlg.h index be00df2..5b5fa3a 100644 --- a/MissionEditor/ComboUInputDlg.h +++ b/MissionEditor/ComboUInputDlg.h @@ -32,7 +32,7 @@ #include -using namespace std; +using std::vector; #define COMBOUINPUT_HOUSES 0 #define COMBOUINPUT_COUNTRIES 1 diff --git a/MissionEditor/FinalSun.cpp b/MissionEditor/FinalSun.cpp index 48520c5..c507c11 100644 --- a/MissionEditor/FinalSun.cpp +++ b/MissionEditor/FinalSun.cpp @@ -112,7 +112,7 @@ CFinalSunApp::CFinalSunApp() log += "finalalert2log.txt"; #endif m_u8LogFileName = log; - errstream.open(m_u8LogFileName, ios_base::trunc); + errstream.open(m_u8LogFileName, std::ios_base::trunc); errstream << "\uFEFF"; // BOM #ifdef TS_MODE diff --git a/MissionEditor/FinalSunDlg.cpp b/MissionEditor/FinalSunDlg.cpp index 4952b47..e4e4452 100644 --- a/MissionEditor/FinalSunDlg.cpp +++ b/MissionEditor/FinalSunDlg.cpp @@ -69,6 +69,8 @@ static char THIS_FILE[] = __FILE__; #include #include +using std::endl; + extern ACTIONDATA AD; extern BOOL bNoDraw; diff --git a/MissionEditor/IniFile.h b/MissionEditor/IniFile.h index 55807b2..4ad31ba 100644 --- a/MissionEditor/IniFile.h +++ b/MissionEditor/IniFile.h @@ -38,7 +38,8 @@ #include #include "IniHelper.h" -using namespace std; +using std::vector; +using std::map; class CIniFileSection { diff --git a/MissionEditor/IsoView.cpp b/MissionEditor/IsoView.cpp index 7517a85..d2b69d6 100644 --- a/MissionEditor/IsoView.cpp +++ b/MissionEditor/IsoView.cpp @@ -358,8 +358,8 @@ __forceinline void BlitTerrain(void* dst, int x, int y, int dleft, int dtop, int short& left = st.vborder[e].left; short& right = st.vborder[e].right; - auto l = max(left, srcRect.left); - auto r = min(right, static_cast(srcRect.right - 1)); + auto l = std::max(left, srcRect.left); + auto r = std::min(right, static_cast(srcRect.right - 1)); for (i = l; i <= r; i++) { //if (i < srcRect.left || i >= srcRect.right) { @@ -640,7 +640,7 @@ __forceinline void BlitPic(void* dst, int x, int y, int dleft, int dtop, int dpi int l = pLighting[spos]; BYTE* bc = reinterpret_cast(&c); for (int i = 0; i < 4; ++i) - bc[i] = min(255, bc[i] * (200 + l * 300 / 255) / 255); // game seems to overbrighten and have a lot of ambient - if you change this, also change Loading.cpp shp lighting value so that shp light stays at 1.0 + bc[i] = std::min(255, bc[i] * (200 + l * 300 / 255) / 255); // game seems to overbrighten and have a lot of ambient - if you change this, also change Loading.cpp shp lighting value so that shp light stays at 1.0 //bc[i] = min(255, bc[i] * (0 + l * (255 - 0) / 255) / 255); } memcpy(dest, &c, bpp); @@ -3674,7 +3674,7 @@ void CIsoView::DrawTube(const CTube& tube, const DDSURFACEDESC2* lockedDDSD, con const auto col = color ? m_color_converter->GetColor(*color) : (type0 ? m_color_converter->GetColor(255, 0, 0) : m_color_converter->GetColor(0, 0, 255)); ProjectedVec lineOffset = type0 ? ProjectedVec() : ProjectedVec(1, 1); - int lowestHeight = min(Map->GetHeightAt(tube.getStartCoords()), Map->GetHeightAt(tube.getEndCoords())); + int lowestHeight = std::min(Map->GetHeightAt(tube.getStartCoords()), Map->GetHeightAt(tube.getEndCoords())); LineDrawer ld(lockedDDSD->lpSurface, bpp, lockedDDSD->dwWidth, lockedDDSD->dwHeight, lockedDDSD->lPitch); auto startDraw = GetRenderTargetCoordinates(tube.getStartCoords(), lowestHeight); ld.MoveTo(startDraw.x + f_x / 2 + lineOffset.x, startDraw.y + f_y / 2 + lineOffset.y); @@ -4681,7 +4681,7 @@ void CIsoView::OnTimer(UINT_PTR nIDEvent) InvalidateRect(NULL, FALSE); } else { - errstream << "Timer calls InitTMPs()" << endl; + errstream << "Timer calls InitTMPs()" << std::endl; errstream.flush(); theApp.m_loading->InitTMPs(); @@ -5062,10 +5062,10 @@ void CIsoView::DrawMap() auto topRight = GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, 0), false, true); auto bottomLeft = GetMapCoordinatesFromClientCoordinates(CPoint(0, cr.bottom), false, true); auto bottomRight = GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, cr.bottom), false, true); - left = min(topLeft.x, topRight.x); - top = min(topLeft.y, topRight.y); - right = max(bottomLeft.x, bottomRight.x); - bottom = max(bottomLeft.y, bottomRight.y); + left = std::min(topLeft.x, topRight.x); + top = std::min(topLeft.y, topRight.y); + right = std::max(bottomLeft.x, bottomRight.x); + bottom = std::max(bottomLeft.y, bottomRight.y); } // some large buildings may be out of reach: @@ -6029,7 +6029,7 @@ void CIsoView::OnKillFocus(CWnd* pNewWnd) CView::OnKillFocus(pNewWnd); if (rscroll) { - errstream << "Killing scroll" << endl; + errstream << "Killing scroll" << std::endl; errstream.flush(); ReleaseCapture(); diff --git a/MissionEditor/Loading.cpp b/MissionEditor/Loading.cpp index 1b77b1e..cf6339b 100644 --- a/MissionEditor/Loading.cpp +++ b/MissionEditor/Loading.cpp @@ -4562,7 +4562,7 @@ void CLoading::LoadStrings() BYTE* lpData = NULL; DWORD dwSize; if (DoesFileExist((std::string(TSPath) + "\\" + file).c_str())) { - std::ifstream f(std::string(TSPath) + "\\" + file, ios::binary); + std::ifstream f(std::string(TSPath) + "\\" + file, std::ios::binary); if (f.good()) { f.seekg(0, std::ios::end); auto size = f.tellg(); @@ -4582,7 +4582,7 @@ void CLoading::LoadStrings() //HMIXFILE hMix=m_hLanguage; if (hMix) { if (FSunPackLib::XCC_ExtractFile(file, u8AppDataPath + "\\RA2Tmp.csf", hMix)) { - std::ifstream f(u8AppDataPath + "\\RA2Tmp.csf", ios::binary); + std::ifstream f(u8AppDataPath + "\\RA2Tmp.csf", std::ios::binary); if (f.good()) { f.seekg(0, std::ios::end); auto size = f.tellg(); diff --git a/MissionEditor/MapData.h b/MissionEditor/MapData.h index 31aa735..8e8fd29 100644 --- a/MissionEditor/MapData.h +++ b/MissionEditor/MapData.h @@ -34,7 +34,7 @@ extern TILEDATA** tiledata; extern DWORD* tiledata_count; -extern ofstream errstream; +extern std::ofstream errstream; extern map tilesets_start; extern CIniFile* tiles; extern CFinalSunApp theApp; diff --git a/MissionEditor/MiniMap.cpp b/MissionEditor/MiniMap.cpp index 2825009..5e8c74d 100644 --- a/MissionEditor/MiniMap.cpp +++ b/MissionEditor/MiniMap.cpp @@ -97,10 +97,10 @@ void CMiniMap::OnDraw(CDC* pDC) auto topRight = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, 0), false, true)); auto bottomLeft = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(0, cr.bottom), false, true)); auto bottomRight = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, cr.bottom), false, true)); - auto left = min(topLeft.x, topRight.x); - auto top = min(topLeft.y, topRight.y); - auto right = max(bottomLeft.x, bottomRight.x); - auto bottom = max(bottomLeft.y, bottomRight.y); + auto left = std::min(topLeft.x, topRight.x); + auto top = std::min(topLeft.y, topRight.y); + auto right = std::max(bottomLeft.x, bottomRight.x); + auto bottom = std::max(bottomLeft.y, bottomRight.y); CPoint center(r.right / 2, r.bottom / 2); selRect.left = left * m_scale; diff --git a/MissionEditor/MissionEditor.vcxproj b/MissionEditor/MissionEditor.vcxproj index 79bd618..2f8674e 100644 --- a/MissionEditor/MissionEditor.vcxproj +++ b/MissionEditor/MissionEditor.vcxproj @@ -347,7 +347,7 @@ - RA2_MODE;YR_MODE;%(PreprocessorDefinitions) + NOMINMAX;RA2_MODE;YR_MODE;%(PreprocessorDefinitions) ..\MissionEditorPackLib @@ -419,7 +419,7 @@ - RA2_MODE;YR_MODE;%(PreprocessorDefinitions) + NOMINMAX;RA2_MODE;YR_MODE;%(PreprocessorDefinitions) ..\MissionEditorPackLib diff --git a/MissionEditor/StdAfx.h b/MissionEditor/StdAfx.h index 9433283..0622b6f 100644 --- a/MissionEditor/StdAfx.h +++ b/MissionEditor/StdAfx.h @@ -28,8 +28,7 @@ #pragma once #endif -#define VC_EXTRALEAN -#define NOMINMAX +#define VC_EXTRALEAN #pragma warning(disable: 4503) #pragma warning(disable: 4786) @@ -56,7 +55,7 @@ #include "resource.h" #include "TipDlg.h" - +using std::endl; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ inserts additional declarations exactly above this line. diff --git a/MissionEditor/TextDrawer.cpp b/MissionEditor/TextDrawer.cpp index 05209e7..bbe9ad4 100644 --- a/MissionEditor/TextDrawer.cpp +++ b/MissionEditor/TextDrawer.cpp @@ -164,7 +164,7 @@ ProjectedVec TextDrawer::GetExtent(const std::string& text) const cur.set(0, cur.y + ch + lineOffset); } else if (c >= 32 && c <= 126) { cur.x += cw; - maxpos.set(max(maxpos.x, cur.x), max(maxpos.y, cur.y + ch)); + maxpos.set(std::max(maxpos.x, cur.x), std::max(maxpos.y, cur.y + ch)); } } diff --git a/MissionEditor/functions.cpp b/MissionEditor/functions.cpp index aa5f21f..943a24a 100644 --- a/MissionEditor/functions.cpp +++ b/MissionEditor/functions.cpp @@ -1280,10 +1280,10 @@ CString GetFreeID() "Actions", "AITriggerTypes", }; - if (find(std::begin(typeListSections), std::end(typeListSections), input) != std::end(typeListSections)) { + if (std::find(std::begin(typeListSections), std::end(typeListSections), input) != std::end(typeListSections)) { return true; } - if (find(std::begin(idListSections), std::end(idListSections), input) != std::end(idListSections)) { + if (std::find(std::begin(idListSections), std::end(idListSections), input) != std::end(idListSections)) { return true; } return false; diff --git a/MissionEditor/functions.h b/MissionEditor/functions.h index f4f6156..beadde5 100644 --- a/MissionEditor/functions.h +++ b/MissionEditor/functions.h @@ -25,6 +25,8 @@ #include #include +using std::string; + bool deleteFile(const std::string& u8FilePath); // set the status bar text in the main dialog diff --git a/MissionEditor/inlines.h b/MissionEditor/inlines.h index 07f3c88..91b92d2 100644 --- a/MissionEditor/inlines.h +++ b/MissionEditor/inlines.h @@ -195,7 +195,7 @@ inline CString SetParam(const CString& data, const int param, const CString& val if (param < 0) return data; std::vector params = SplitParams(data); - params.resize(max(param + 1, static_cast(params.size()))); + params.resize(std::max(param + 1, static_cast(params.size()))); params[param] = value; return Join(",", params); } diff --git a/MissionEditor/variables.cpp b/MissionEditor/variables.cpp index 7096691..d3685f5 100644 --- a/MissionEditor/variables.cpp +++ b/MissionEditor/variables.cpp @@ -183,7 +183,7 @@ SMUDGE_INFO smudgeinfo[0x0F00]; #endif /* error output */ -ofstream errstream; +std::ofstream errstream; /* the finalsun app object */ CFinalSunApp theApp; diff --git a/MissionEditor/variables.h b/MissionEditor/variables.h index da8ef19..4bc6295 100644 --- a/MissionEditor/variables.h +++ b/MissionEditor/variables.h @@ -114,7 +114,7 @@ extern SMUDGE_INFO smudgeinfo[0x0F00]; extern CFinalSunApp theApp; /* error output */ -extern ofstream errstream; +extern std::ofstream errstream; // application path extern char AppPath[MAX_PATH + 1]; From d1a32df54b44c7a9fd9021518bd3387f7981b13f Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Thu, 25 Apr 2024 22:12:25 -0400 Subject: [PATCH 2/8] safe compile . --- MissionEditor/Structs.h | 8 ++++---- MissionEditor/ViewObjects.cpp | 2 +- MissionEditor/inlines.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MissionEditor/Structs.h b/MissionEditor/Structs.h index e2d8d86..f6a5a27 100644 --- a/MissionEditor/Structs.h +++ b/MissionEditor/Structs.h @@ -323,10 +323,10 @@ struct XCString bUsedDefault = FALSE; wString = new(WCHAR[len + 1]); - memset(wString, 0, (len + 1) * 2); + memset(wString, 0, (len + 1) * sizeof(WCHAR)); - //MultiByteToWideChar(CP_ACP, WC_COMPOSITECHECK, cString, len, wString, len+1); - mbstowcs(wString, cString, len); + size_t convertedSize = 0; + mbstowcs_s(&convertedSize, wString, len + 1, cString, len); } void SetString(const WCHAR* wString, int len) @@ -358,7 +358,7 @@ struct XCString CString cString; WCHAR* wString; BOOL bUsedDefault; - int len; + size_t len; }; diff --git a/MissionEditor/ViewObjects.cpp b/MissionEditor/ViewObjects.cpp index 635bbfa..8eef05d 100644 --- a/MissionEditor/ViewObjects.cpp +++ b/MissionEditor/ViewObjects.cpp @@ -42,7 +42,7 @@ static char THIS_FILE[] = __FILE__; ///////////////////////////////////////////////////////////////////////////// // CViewObjects -const int valadded = 10000; +const size_t valadded = 10000; IMPLEMENT_DYNCREATE(CViewObjects, CTreeView) diff --git a/MissionEditor/inlines.h b/MissionEditor/inlines.h index 91b92d2..960aa89 100644 --- a/MissionEditor/inlines.h +++ b/MissionEditor/inlines.h @@ -78,7 +78,7 @@ inline CString GetUnitPictureFilename(LPCTSTR lpUnitName, DWORD dwPicIndex) } char n[50]; - itoa(dwPicIndex, n, 10); + _itoa_s(dwPicIndex, n, 10); if (pics.find(artname + n) != pics.end()) { From 90fa8eb408abcaf6e6965cf8699f60811588c291 Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Thu, 25 Apr 2024 22:14:06 -0400 Subject: [PATCH 3/8] Implemented IniMeta helpers to fetch combination of ini files . --- MissionEditor/INIMeta.cpp | 39 ++++++ MissionEditor/INIMeta.h | 142 ++++++++++++++++++++ MissionEditor/IniFile.h | 5 +- MissionEditor/MissionEditor.vcxproj | 3 + MissionEditor/MissionEditor.vcxproj.filters | 9 ++ MissionEditor/StringHelper.h | 25 ++++ UnitTest/CIni_Meta_Test.cpp | 70 ++++++++++ UnitTest/StdAfx.h | 3 + UnitTest/UnitTest.vcxproj | 7 +- UnitTest/UnitTest.vcxproj.filters | 9 ++ 10 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 MissionEditor/INIMeta.cpp create mode 100644 MissionEditor/INIMeta.h create mode 100644 MissionEditor/StringHelper.h create mode 100644 UnitTest/CIni_Meta_Test.cpp diff --git a/MissionEditor/INIMeta.cpp b/MissionEditor/INIMeta.cpp new file mode 100644 index 0000000..cdfdf0e --- /dev/null +++ b/MissionEditor/INIMeta.cpp @@ -0,0 +1,39 @@ +#include "StdAfx.h" +#include "INIMeta.h" +#include + +void IniFileGroup::Append(const CIniFile& INI) +{ + m_group.push_back(&INI); +} + + +const CIniFile* IniFileGroup::Nth(int idx) const +{ + return m_group.at(idx); +} + +const CString& IniFileGroup::GetString(const CString & section, const CString & key) const +{ + for (auto it = m_group.rbegin(); it != m_group.rend(); ++it) { + auto const& got = (*it)->GetString(section, key); + if (!got.IsEmpty()) { + return got; + } + } + return CIniFileSection::EmptyValue; +} + +CString IniFileGroup::GetStringOr(const CString & section, const CString & key, const CString& def) const +{ + auto const& got = this->GetString(section, key); + if (!got.IsEmpty()) { + return got; + } + return def; +} + +IniSectionGroup IniFileGroup::GetSection(const CString& section) const +{ + return IniSectionGroup(*this, section); +} \ No newline at end of file diff --git a/MissionEditor/INIMeta.h b/MissionEditor/INIMeta.h new file mode 100644 index 0000000..deffb31 --- /dev/null +++ b/MissionEditor/INIMeta.h @@ -0,0 +1,142 @@ +#pragma once + +#include +#include "IniFile.h" +#include +#include + +using IndiceStorage = std::vector; +using SequencedSection = std::vector; +class IniSectionGroup; + +/* +* @brief This class uses to simulation a combination of a few ini dictionaries, to + act as they are inside a same ini +*/ +class IniFileGroup +{ + friend class IniMegaFile; +public: + + using StorageType = std::vector; + + IniFileGroup() = default; + + + const CString& GetString(const CString& section, const CString& key) const; + CString GetStringOr(const CString& section, const CString& key, const CString& def) const; + IniSectionGroup GetSection(const CString& section) const; + + auto Size() const { return m_group.size(); } + + void Append(const CIniFile& INI); + const CIniFile* Nth(int idx) const; + + auto begin() const { return m_group.begin(); } + auto end() const { return m_group.end(); } + bool empty() const { return m_group.empty(); } + +private: + StorageType m_group; +}; + +class IniSectionGroup +{ + using KvIter = CIniFileSection::Container::const_iterator; + using GroupIter = IniFileGroup::StorageType::const_iterator; +public: + class Iterator; + friend class Iterator; + class Iterator { + public: + Iterator(const CString& section, + GroupIter groupIter, + GroupIter groupIterEnd, + KvIter kvIter, + KvIter kvIterEnd + ) : + m_section(section), + m_groupIter(groupIter), + m_groupIterEnd(groupIterEnd), + m_kvIter(kvIter), + m_kvIterEnd(kvIterEnd) + { + } + Iterator& operator++() { + // section content still working + if (m_kvIter != std::prev(m_kvIterEnd)) { + m_kvIter++; + return *this; + } + m_groupIter++; + if (m_groupIter != m_groupIterEnd) { + auto [beg, end] = IniSectionGroup::acquireNextKvGroup(m_section, m_groupIter, m_groupIterEnd); + m_kvIter = beg; + m_kvIterEnd = end; + } else { + m_kvIter = m_kvIterEnd;// to make (==) works + } + return *this; + } + + auto const& operator*() const { + return *m_kvIter; + } + bool operator==(const Iterator& rhs) const { + return m_groupIter == rhs.m_groupIter; + } + + private: + GroupIter m_groupIter; + GroupIter m_groupIterEnd; + KvIter m_kvIter; + KvIter m_kvIterEnd; + const CString& m_section; + }; + + IniSectionGroup(const IniFileGroup& source, const CString& secName) : + m_source(source), + m_section(secName) + { + } + + Iterator begin() const { + auto groupBeg = m_source.begin(); + auto [secItBeg, secItEnd] = acquireNextKvGroup(groupBeg); + return Iterator(m_section, groupBeg, m_source.end(), secItBeg, secItEnd); + } + + Iterator end() const { + auto secItEnd = KvIter{}; + if (!m_source.empty()) { + auto const& sec = (*std::prev(m_source.end()))->GetSection(m_section); + secItEnd = sec.end(); + } + return Iterator(m_section, m_source.end(), m_source.end(), secItEnd, secItEnd); + } + +private: + // attention: beginning iter + static std::pair< KvIter, KvIter> acquireNextKvGroup(const CString& section, GroupIter& beg, const GroupIter end) { + + auto secItBeg = KvIter{}; + auto secItEnd = KvIter{}; + for (; beg != end; ++beg) { + auto const& sec = (*beg)->GetSection(section); + if (sec.Size() == 0) { + continue; + } + secItBeg = sec.begin(); + secItEnd = sec.end(); + break; + } + return { secItBeg, secItEnd }; + } + + std::pair< KvIter, KvIter> acquireNextKvGroup(GroupIter& beg) const { + return acquireNextKvGroup(m_section, beg, m_source.end()); + } + + const IniFileGroup& m_source; + CString m_section; +}; diff --git a/MissionEditor/IniFile.h b/MissionEditor/IniFile.h index 4ad31ba..e00c108 100644 --- a/MissionEditor/IniFile.h +++ b/MissionEditor/IniFile.h @@ -43,8 +43,9 @@ using std::map; class CIniFileSection { - static const CString EmptyValue; public: + using Container = vector>; + static const CString EmptyValue; CIniFileSection(); virtual ~CIniFileSection(); @@ -198,7 +199,7 @@ public: private: map value_pos{}; - vector> value_pairs{};// sequenced + Container value_pairs{};// sequenced }; class CIniFile diff --git a/MissionEditor/MissionEditor.vcxproj b/MissionEditor/MissionEditor.vcxproj index 2f8674e..81bdb17 100644 --- a/MissionEditor/MissionEditor.vcxproj +++ b/MissionEditor/MissionEditor.vcxproj @@ -498,6 +498,7 @@ + @@ -609,6 +610,7 @@ + @@ -660,6 +662,7 @@ + diff --git a/MissionEditor/MissionEditor.vcxproj.filters b/MissionEditor/MissionEditor.vcxproj.filters index d54b83f..23f6af9 100644 --- a/MissionEditor/MissionEditor.vcxproj.filters +++ b/MissionEditor/MissionEditor.vcxproj.filters @@ -282,6 +282,9 @@ Source Files + + Source Files + @@ -568,6 +571,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/MissionEditor/StringHelper.h b/MissionEditor/StringHelper.h new file mode 100644 index 0000000..82f9d88 --- /dev/null +++ b/MissionEditor/StringHelper.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace utilities { + static std::vector split_string(const CString& pSource, TCHAR cSplit = ',') + { + std::vector ret; + CString tmp = pSource; + int pos = 0; + + while ((pos = tmp.Find(cSplit)) != -1) { + ret.push_back(tmp.Left(pos)); + tmp = tmp.Mid(pos + 1); + } + + if (!tmp.IsEmpty()) { + ret.push_back(tmp); + } + + return ret; + } +} + diff --git a/UnitTest/CIni_Meta_Test.cpp b/UnitTest/CIni_Meta_Test.cpp new file mode 100644 index 0000000..41a6142 --- /dev/null +++ b/UnitTest/CIni_Meta_Test.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "../MissionEditor/INIMeta.h" + +#if 1 +TEST(IniFileGroup, ValidIniWithValidContentTest) { + CIniFile iniFile1; + CIniFile iniFile2; + + const CString referenceList[] = { + CString("GANCST"), + CString("GAPOWR"), + CString("NACNST"), + CString("NAPOWR"), + }; + + iniFile1.SetString("BuildingTypes", "0", "GANCST"); + iniFile1.SetString("BuildingTypes", "1", "GAPOWR"); + iniFile1.SetString("GACNST", "Strength", "1000"); + iniFile1.SetString("E2", "Strength", "100"); + + iniFile2.SetString("BuildingTypes", "2", "NACNST"); + iniFile2.SetString("BuildingTypes", "3", "NAPOWR"); + iniFile2.SetString("GACNST", "Strength", "2000"); + iniFile2.SetString("NEWIFV", "Cost", "1000"); + + IniFileGroup group; + group.Append(iniFile1); + group.Append(iniFile2); + + auto const bldTypes = group.GetSection("BuildingTypes"); + auto idx = 0; + //for (auto const& [key, val] : bldTypes) { + for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) { + auto const& [key, val] = *it; + EXPECT_EQ(val, referenceList[idx++]); + } + + EXPECT_EQ(group.GetString("GACNST", "Strength"), "2000"); +} +#endif + +TEST(IniFileGroup, EmptyIniContentTest) { + CIniFile iniFile1; + CIniFile iniFile2; + IniFileGroup group; + + group.Append(iniFile1); + group.Append(iniFile2); + + auto const bldTypes = group.GetSection("BuildingTypes"); + auto contentCount = 0; + for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) { + auto const& [key, val] = *it; + cout << key << "=" << val << endl; + contentCount++; + } + + EXPECT_EQ(contentCount, 0); + + iniFile1.SetString("BuildingTypes", "0", "GANCST"); + + contentCount = 0; + for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) { + auto const& [key, val] = *it; + cout << key << "=" << val << endl; + contentCount++; + } + + EXPECT_EQ(contentCount, 1); +} \ No newline at end of file diff --git a/UnitTest/StdAfx.h b/UnitTest/StdAfx.h index 457cae7..fe450d1 100644 --- a/UnitTest/StdAfx.h +++ b/UnitTest/StdAfx.h @@ -27,6 +27,9 @@ #include #include +using std::cout; +using std::endl; + #if !defined(ASSERT) #define ASSERT(x) if (!(x)) throw("assertion failed"); #endif \ No newline at end of file diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index 76b6c5c..077815a 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -102,9 +102,9 @@ Level3 true - _DEBUG;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions) + _DEBUG;NOMINMAX;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions) true - $(SolutionDir)googletest\x64\include;%(AdditionalIncludeDirectories) + $(SolutionDir)googletest\x64\include;$(SolutionDir)MissionEditorPackLib;%(AdditionalIncludeDirectories) Create MultiThreadedDebugDLL stdcpp20 @@ -133,11 +133,14 @@ + + + diff --git a/UnitTest/UnitTest.vcxproj.filters b/UnitTest/UnitTest.vcxproj.filters index 37e3ea3..9de5faa 100644 --- a/UnitTest/UnitTest.vcxproj.filters +++ b/UnitTest/UnitTest.vcxproj.filters @@ -24,6 +24,12 @@ 源文件 + + 源文件 + + + 源文件 + @@ -32,5 +38,8 @@ 头文件 + + 头文件 + \ No newline at end of file From 78b79a6c401463c7a4ae7628fd167cdf6e48fe27 Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Sun, 28 Apr 2024 20:13:54 -0400 Subject: [PATCH 4/8] some refactor progress for tree view techno item category . --- MissionEditor/ViewObjects.cpp | 871 +++++++++++++++------------------- MissionEditor/ViewObjects.h | 131 +++++ 2 files changed, 526 insertions(+), 476 deletions(-) diff --git a/MissionEditor/ViewObjects.cpp b/MissionEditor/ViewObjects.cpp index 8eef05d..d50e96d 100644 --- a/MissionEditor/ViewObjects.cpp +++ b/MissionEditor/ViewObjects.cpp @@ -32,6 +32,8 @@ #include "inlines.h" #include "rtpdlg.h" #include "TubeTool.h" +#include "StringHelper.h" +#include "INIMeta.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -514,28 +516,304 @@ __inline HTREEITEM TV_InsertItemW(HWND hWnd, WCHAR* lpString, int len, HTREEITEM return res; } -using vecSideNodeInfo = std::vector>; -vecSideNodeInfo collectSides() +IniFileGroup IniMegaFile::GetRules() { - vecSideNodeInfo ret; + IniFileGroup m_group; + m_group.Append(rules); + m_group.Append(Map->GetIniFile()); + return m_group; +} + +bool IniMegaFile::isNullOrEmpty(const CString& value) +{ + return !value.GetLength() || value == "none" || value == ""; +} + +const IgnoreSet CollectIgnoreSet() +{ + IgnoreSet ret; + auto addToIgnoreSet = [&ret](const CString& section) { + for (auto& [seq, id] : g_data[section]) { + ret.insert(std::string(id)); + } + }; + +#if defined(RA2_MODE) + addToIgnoreSet("IgnoreRA2"); + if (Map->GetTheater() == THEATER0) { + addToIgnoreSet("IgnoreTemperateRA2"); + } + if (Map->GetTheater() == THEATER1) { + addToIgnoreSet("IgnoreSnowRA2"); + } + if (Map->GetTheater() == THEATER2) { + addToIgnoreSet("IgnoreUrbanRA2"); + } + if (Map->GetTheater() == THEATER3) { + addToIgnoreSet("IgnoreNewUrbanRA2"); + } + if (Map->GetTheater() == THEATER4) { + addToIgnoreSet("IgnoreLunarRA2"); + } + if (Map->GetTheater() == THEATER5) { + addToIgnoreSet("IgnoreDesertRA2"); + } +#else + addToIgnoreSet("IgnoreTS"); + if (Map->GetTheater() == THEATER0) { + addToIgnoreSet("IgnoreTemperateTS"); + } + if (Map->GetTheater() == THEATER1) { + addToIgnoreSet("IgnoreSnowTS"); + } +#endif + return ret; +} + +TreeViewBuilder::mapSideNodeInfo TreeViewBuilder::collectCategoryInfo() +{ + mapSideNodeInfo ret; auto toType = [](const CString& str) -> TechnoTypeMask { return TechnoTypeMask(atoi(str)); }; CString typeStr; + auto count = 0; + + auto const otherCategoryName = GetLanguageStringACP("Other"); + for (auto& [seq, def] : g_data["Sides"]) { auto const commaPos = def.Find(','); //now parse real type if (commaPos >= 0) { typeStr = def.Mid(commaPos + 1); - ret.push_back({ def.Mid(0, commaPos), toType(typeStr) }); } + if (typeStr == otherCategoryName) { + continue; + } + auto&& info = CatetoryDefinition{ def.Mid(0, commaPos), toType(typeStr) }; + ret.insert({ count++, info }); } + // now parse side definition in Ini if it has more than editor setting + auto const& mmh = IniMegaFile::GetRules(); + auto const& sides = mmh.GetSection("Sides"); + count = 0; + for (auto it = sides.begin(); it != sides.end(); ++it) { + // skip already defined ones + if (count++ < ret.size()) { + continue; + } + ret.insert({ count - 1, CatetoryDefinition{ (*it).first, TechnoTypeMask(-1) } }); + } + + // insert other first + ret.insert({ -1, CatetoryDefinition { otherCategoryName, TechnoTypeMask(-1) } }); + return ret; } +const TreeViewBuilder::houseMap TreeViewBuilder::collectOwners() +{ + houseMap ret; + auto const& mmh = IniMegaFile::GetRules(); + auto const& sides = mmh.GetSection("Sides"); + size_t i = 0; + for (auto it = sides.begin(); it != sides.end(); ++it) { + for (auto const& owner : utilities::split_string((*it).second)) { + ret[(std::string)owner] = i; + } + ++i; + } + return ret; +} + +const CString& GuessSideHelper::GetSideName(const CString& regName, TreeViewTechnoType technoType, const CIniFile& inWhichIni) +{ + auto const sideIdx = GuessSide(regName, technoType, inWhichIni); + auto const& [name, mask] = builder.sideInfo.at(sideIdx); + if (mask & technoType) { + return name; + } + // -1 means other + return builder.sideInfo.at(-1).CategoryName; +} + +int GuessSideHelper::GuessSide(const CString& pRegName, TreeViewTechnoType nType, const CIniFile& inWhichIni) +{ + auto const& knownIterator = KnownItem.find(pRegName.operator LPCSTR()); + if (knownIterator != KnownItem.end()) + return knownIterator->second; + + int result = -1; + switch (nType) { + case TreeViewTechnoType::Set_None: + default: + break; + case TreeViewTechnoType::Building: + result = guessBuildingSide(pRegName, inWhichIni); + break; + case TreeViewTechnoType::Infantry: + case TreeViewTechnoType::Vehicle: + case TreeViewTechnoType::Aircraft: + result = guessGenericSide(pRegName); + break; + } + KnownItem.insert_or_assign(pRegName.operator LPCSTR(), result); + return result; +} + +int GuessSideHelper::guessBuildingSide(const CString& typeId, const CIniFile& inWhichIni) +{ + int planning; + planning = inWhichIni.GetInteger(typeId, "AIBasePlanningSide", -1); + if (planning >= rules.GetSection("Sides").Size()) { + return -1; + } + if (planning >= 0) { + return planning; + } + auto const& cons = utilities::split_string(rules.GetString("AI", "BuildConst")); + size_t i = 0; + for (; i < cons.size(); ++i) { + if (cons[i] == typeId) { + return i; + } + } + if (i >= rules.GetSection("Sides").Size()) { + return -1; + } + return guessGenericSide(typeId); +} + +int GuessSideHelper::guessGenericSide(const CString& pRegName) +{ + auto const& mmh = IniMegaFile::GetRules(); + auto const& owners = utilities::split_string(mmh.GetString(pRegName, "Owner")); + if (owners.size() <= 0) { + return -1; + } + auto const& itr = builder.m_owners.find((std::string)owners[0]); + if (itr == builder.m_owners.end()) { + return -1; + } + return itr->second; +} + +void TreeViewBuilder::updateBuildingTypes(HTREEITEM parentNode) { + TreeViewCategoryHandler structhouses(this->tree, parentNode); + GuessSideHelper sideHelper(*this); + auto baseOffset = valadded * 2; + + auto const& bldTypeSec = rules["BuildingTypes"]; + for (auto i = 0; i < bldTypeSec.Size(); i++) { + + auto const& unitname = bldTypeSec.Nth(i).second; + + if (unitname.IsEmpty()) { + continue; + } + + if (m_ignoreSet.find((std::string)unitname) != m_ignoreSet.end()) { + continue; + } + + if (!g_data.GetBool("Debug", "ShowBuildingsWithToTile") && !rules[unitname]["ToTile"].IsEmpty()) { + continue; + } + + WCHAR* addedString = Map->GetUnitName(unitname); + if (!addedString) { + continue; + } + + int id = Map->GetBuildingID(unitname); + if (id < 0 /*|| (buildinginfo[id].pic[0].bTerrain!=0 && buildinginfo[id].pic[0].bTerrain!=needed_terrain)*/) + continue; + + if (theater == THEATER0 && !buildinginfo[id].bTemp) { /*MessageBox("Ignored", unitname,0);*/ continue; } + if (theater == THEATER1 && !buildinginfo[id].bSnow) { /*MessageBox("Ignored", unitname,0);*/ continue; } + if (theater == THEATER2 && !buildinginfo[id].bUrban) { /*MessageBox("Ignored", unitname,0);*/ continue; } + + + auto const& name = sideHelper.GetSideName(unitname, TreeViewTechnoType::Building); + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, structhouses.GetOrAdd(name), baseOffset + i); + } + + // okay, now the user-defined types: + baseOffset += rules["BuildingTypes"].Size(); + auto const& localbldTypeSec = ini["BuildingTypes"]; + for (auto i = 0; i < localbldTypeSec.Size(); i++) { + auto const& typeId = localbldTypeSec.Nth(i).second; + if (typeId.IsEmpty()) { + continue; + } + int id = Map->GetBuildingID(typeId); + if (id < 0 || (buildinginfo[id].pic[0].bTerrain != TheaterChar::None && buildinginfo[id].pic[0].bTerrain != needed_terrain)) { + continue; + } + CString undefinedName; + auto const& name = ini[typeId]["Name"]; + auto addedString = std::ref(name); + if (name.IsEmpty()) { + undefinedName = typeId + " UNDEFINED"; + addedString = undefinedName; + } + auto const& sideName = sideHelper.GetSideName(typeId, TreeViewTechnoType::Building); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString.get(), 0, 0, 0, 0, baseOffset + i, structhouses.GetOrAdd(sideName), TVI_LAST); + } +} + +void TreeViewBuilder::updateUnitTypes(HTREEITEM parentNode, const char* typeListId, TreeViewTechnoType technoType, int multiple) +{ + TreeViewCategoryHandler structhouses(this->tree, parentNode); + GuessSideHelper sideHelper(*this); + auto baseOffset = valadded * multiple; + + for (auto i = 0; i < rules[typeListId].Size(); i++) { + auto const& typeId = rules[typeListId].Nth(i).second; + if (typeId.IsEmpty()) { + continue; + } + if (m_ignoreSet.find((std::string)typeId) != m_ignoreSet.end()) { + continue; + } + WCHAR* addedString = Map->GetUnitName(typeId); + if (!addedString) { + continue; + } + auto const& name = sideHelper.GetSideName(typeId, technoType); + TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, structhouses.GetOrAdd(name), baseOffset + i); + } + // okay, now the user-defined types: + baseOffset += rules[typeListId].Size(); + auto const& infTypeSec = ini[typeListId]; + for (auto i = 0; i < infTypeSec.Size(); i++) { + auto const& typeId = infTypeSec.Nth(i).second; + if (typeId.IsEmpty()) { + continue; + } + + CString undefinedName; + auto const& name = ini[typeId]["Name"]; + auto addedString = std::ref(name); + auto const& sideName = sideHelper.GetSideName(typeId, technoType); + if (name.IsEmpty()) { + undefinedName = typeId + " UNDEFINED"; + addedString = undefinedName; + } + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString.get(), 0, 0, 0, 0, baseOffset + i, structhouses.GetOrAdd(sideName), TVI_LAST); + } +} + +void TreeViewBuilder::updateTechnoItems() { + updateBuildingTypes(rootitems[TreeRoot::Building]); + updateUnitTypes(rootitems[TreeRoot::Infantry], "InfantryTypes", TreeViewTechnoType::Infantry, 1); + updateUnitTypes(rootitems[TreeRoot::Aircraft], "AircraftTypes", TreeViewTechnoType::Aircraft, 3); + updateUnitTypes(rootitems[TreeRoot::Vehicle], "VehicleTypes", TreeViewTechnoType::Vehicle, 4); +} + void CViewObjects::UpdateDialog() { OutputDebugString("Objectbrowser redrawn\n"); @@ -547,42 +825,42 @@ void CViewObjects::UpdateDialog() tree.DeleteAllItems(); CString sTreeRoots[15]; - sTreeRoots[0] = GetLanguageStringACP("InfantryObList"); - sTreeRoots[1] = GetLanguageStringACP("VehiclesObList"); - sTreeRoots[2] = GetLanguageStringACP("AircraftObList"); - sTreeRoots[3] = GetLanguageStringACP("StructuresObList"); - sTreeRoots[4] = GetLanguageStringACP("TerrainObList"); - sTreeRoots[5] = GetLanguageStringACP("OverlayObList"); - sTreeRoots[6] = GetLanguageStringACP("WaypointsObList"); - sTreeRoots[7] = GetLanguageStringACP("CelltagsObList"); - sTreeRoots[8] = GetLanguageStringACP("BaseNodesObList"); - sTreeRoots[9] = GetLanguageStringACP("TunnelObList"); - sTreeRoots[10] = GetLanguageStringACP("DelObjObList"); - sTreeRoots[11] = GetLanguageStringACP("ChangeOwnerObList"); - sTreeRoots[12] = GetLanguageStringACP("StartpointsObList"); - sTreeRoots[13] = GetLanguageStringACP("GroundObList"); - sTreeRoots[14] = GetLanguageStringACP("SmudgesObList"); + sTreeRoots[TreeRoot::Infantry] = GetLanguageStringACP("InfantryObList"); + sTreeRoots[TreeRoot::Vehicle] = GetLanguageStringACP("VehiclesObList"); + sTreeRoots[TreeRoot::Aircraft] = GetLanguageStringACP("AircraftObList"); + sTreeRoots[TreeRoot::Building] = GetLanguageStringACP("StructuresObList"); + sTreeRoots[TreeRoot::Terrain] = GetLanguageStringACP("TerrainObList"); + sTreeRoots[TreeRoot::Overlay] = GetLanguageStringACP("OverlayObList"); + sTreeRoots[TreeRoot::Waypoint] = GetLanguageStringACP("WaypointsObList"); + sTreeRoots[TreeRoot::Celltag] = GetLanguageStringACP("CelltagsObList"); + sTreeRoots[TreeRoot::Basenode] = GetLanguageStringACP("BaseNodesObList"); + sTreeRoots[TreeRoot::Tunnel] = GetLanguageStringACP("TunnelObList"); + sTreeRoots[TreeRoot::Delete] = GetLanguageStringACP("DelObjObList"); + sTreeRoots[TreeRoot::Owner] = GetLanguageStringACP("ChangeOwnerObList"); + sTreeRoots[TreeRoot::PlayerLocation] = GetLanguageStringACP("StartpointsObList"); + sTreeRoots[TreeRoot::Ground] = GetLanguageStringACP("GroundObList"); + sTreeRoots[TreeRoot::Smudge] = GetLanguageStringACP("SmudgesObList"); int i = 0; - //TV_InsertItemW(tree.m_hWnd, L"HELLO", 5, TVI_LAST, TVI_ROOT, -2); auto const translatedNoObj = GetLanguageStringACP("NothingObList"); HTREEITEM first = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, translatedNoObj, i, i, 0, 0, -2, TVI_ROOT, TVI_LAST); - HTREEITEM rootitems[15]; + HTREEITEM rootitems[TreeRoot::Count]; // we want the change owner at the top - if (!Map->IsMultiplayer() || !theApp.m_Options.bEasy) - rootitems[11] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, - sTreeRoots[11], i, i, 0, 0, i, TVI_ROOT, TVI_LAST); + if (!Map->IsMultiplayer() || !theApp.m_Options.bEasy) { + rootitems[TreeRoot::Owner] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + sTreeRoots[TreeRoot::Owner], i, i, 0, 0, i, TVI_ROOT, TVI_LAST); + } - for (i = 0; i < 10; i++) { + for (int i = TreeRoot::Begin; i < TreeRoot::Delete; i++) { BOOL bAllow = TRUE; if (theApp.m_Options.bEasy) { - if (i >= 6 && i <= 9) + if (i >= TreeRoot::Waypoint && i <= TreeRoot::Tunnel) bAllow = FALSE; } @@ -598,52 +876,27 @@ void CViewObjects::UpdateDialog() } - rootitems[13] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, sTreeRoots[13], 13, 13, 0, 0, 13, TVI_ROOT, first); + rootitems[TreeRoot::Ground] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, sTreeRoots[TreeRoot::Ground], 13, 13, 0, 0, 13, TVI_ROOT, first); - rootitems[12] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, - sTreeRoots[12], 12, 12, 0, 0, 12, TVI_ROOT, TVI_LAST); + rootitems[TreeRoot::PlayerLocation] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + sTreeRoots[TreeRoot::PlayerLocation], 12, 12, 0, 0, 12, TVI_ROOT, TVI_LAST); - rootitems[10] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, - sTreeRoots[10], 10, 10, 0, 0, 10, TVI_ROOT, TVI_LAST); + rootitems[TreeRoot::Delete] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + sTreeRoots[TreeRoot::Delete], 10, 10, 0, 0, 10, TVI_ROOT, TVI_LAST); #ifdef SMUDGE_SUPP - rootitems[14] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, - sTreeRoots[14], 14, 14, 0, 0, 10, TVI_ROOT, rootitems[4]); + rootitems[TreeRoot::Smudge] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, + sTreeRoots[TreeRoot::Smudge], 14, 14, 0, 0, 10, TVI_ROOT, rootitems[TreeRoot::Terrain]); #endif - HTREEITEM structhouses[64]; -#ifdef RA2_MODE - HTREEITEM hAllied = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Allied"), 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); - HTREEITEM hSoviet = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Soviet"), 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); - HTREEITEM hYuri = NULL; - if (yuri_mode) { - hYuri = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Yuri"), 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); - } - for (i = 0; i < sides.size(); i++) { - if (sides[i].orig_n == 0) - structhouses[i] = hAllied; - else if (yuri_mode && sides[i].orig_n == 2) - structhouses[i] = hYuri; - else - structhouses[i] = hSoviet; - - } - - structhouses[sides.size()] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("Other"), 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); -#else - for (i = 0; i < sides.size(); i++) { - structhouses[i] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, sides[i].name, 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); - } - structhouses[sides.size()] = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, "Other", 0, 0, 0, 0, -1, rootitems[3], TVI_LAST); -#endif if (!theApp.m_Options.bEasy) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateWaypObList"), 0, 0, 0, 0, 20, rootitems[6], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateSpecWaypObList"), 0, 0, 0, 0, 22, rootitems[6], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelWaypObList"), 0, 0, 0, 0, 21, rootitems[6], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateWaypObList"), 0, 0, 0, 0, 20, rootitems[TreeRoot::Waypoint], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateSpecWaypObList"), 0, 0, 0, 0, 22, rootitems[TreeRoot::Waypoint], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelWaypObList"), 0, 0, 0, 0, 21, rootitems[TreeRoot::Waypoint], TVI_LAST); } @@ -660,54 +913,54 @@ void CViewObjects::UpdateDialog() char c[50]; itoa(e + 1, c, 10); ins = TranslateStringVariables(1, ins, c); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ins, 0, 0, 0, 0, 23 + e, rootitems[12], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ins, 0, 0, 0, 0, 23 + e, rootitems[TreeRoot::PlayerLocation], TVI_LAST); } - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("StartpointsDelete"), 0, 0, 0, 0, 21, rootitems[12], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("StartpointsDelete"), 0, 0, 0, 0, 21, rootitems[TreeRoot::PlayerLocation], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundClearObList"), 0, 0, 0, 0, 61, rootitems[13], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundSandObList"), 0, 0, 0, 0, 62, rootitems[13], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundRoughObList"), 0, 0, 0, 0, 63, rootitems[13], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundGreenObList"), 0, 0, 0, 0, 65, rootitems[13], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundPaveObList"), 0, 0, 0, 0, 66, rootitems[13], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundWaterObList"), 0, 0, 0, 0, 64, rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundClearObList"), 0, 0, 0, 0, 61, rootitems[TreeRoot::Ground], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundSandObList"), 0, 0, 0, 0, 62, rootitems[TreeRoot::Ground], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundRoughObList"), 0, 0, 0, 0, 63, rootitems[TreeRoot::Ground], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundGreenObList"), 0, 0, 0, 0, 65, rootitems[TreeRoot::Ground], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundPaveObList"), 0, 0, 0, 0, 66, rootitems[TreeRoot::Ground], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundWaterObList"), 0, 0, 0, 0, 64, rootitems[TreeRoot::Ground], TVI_LAST); #ifdef RA2_MODE if (Map->GetTheater() == THEATER3) - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundPave2ObList"), 0, 0, 0, 0, 67, rootitems[13], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetTheaterLanguageString("GroundPave2ObList"), 0, 0, 0, 0, 67, rootitems[TreeRoot::Ground], TVI_LAST); #endif if (!theApp.m_Options.bEasy) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateCelltagObList"), 0, 0, 0, 0, 36, rootitems[7], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelCelltagObList"), 0, 0, 0, 0, 37, rootitems[7], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CelltagPropObList"), 0, 0, 0, 0, 38, rootitems[7], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateCelltagObList"), 0, 0, 0, 0, 36, rootitems[TreeRoot::Celltag], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelCelltagObList"), 0, 0, 0, 0, 37, rootitems[TreeRoot::Celltag], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CelltagPropObList"), 0, 0, 0, 0, 38, rootitems[TreeRoot::Celltag], TVI_LAST); } if (!theApp.m_Options.bEasy) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateNodeNoDelObList"), 0, 0, 0, 0, 40, rootitems[8], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateNodeDelObList"), 0, 0, 0, 0, 41, rootitems[8], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelNodeObList"), 0, 0, 0, 0, 42, rootitems[8], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateNodeNoDelObList"), 0, 0, 0, 0, 40, rootitems[TreeRoot::Basenode], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("CreateNodeDelObList"), 0, 0, 0, 0, 41, rootitems[TreeRoot::Basenode], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelNodeObList"), 0, 0, 0, 0, 42, rootitems[TreeRoot::Basenode], TVI_LAST); } - HTREEITEM deleteoverlay = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrlObList"), 0, 0, 0, 0, -1, rootitems[5], TVI_LAST); - HTREEITEM tiberium = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("GrTibObList"), 0, 0, 0, 0, -1, rootitems[5], TVI_LAST); - //HTREEITEM bluetiberium=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BlTibObList"), 0,0,0,0, -1, rootitems[5], TVI_LAST ); + HTREEITEM deleteoverlay = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrlObList"), 0, 0, 0, 0, -1, rootitems[TreeRoot::Overlay], TVI_LAST); + HTREEITEM tiberium = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("GrTibObList"), 0, 0, 0, 0, -1, rootitems[TreeRoot::Overlay], TVI_LAST); + //HTREEITEM bluetiberium=tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BlTibObList"), 0,0,0,0, -1, rootitems[TreeRoot::Overlay], TVI_LAST ); #ifndef RA2_MODE - HTREEITEM veinhole = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("VeinholeObList"), 0, 0, 0, 0, -1, rootitems[5], TVI_LAST); + HTREEITEM veinhole = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("VeinholeObList"), 0, 0, 0, 0, -1, rootitems[TreeRoot::Overlay], TVI_LAST); #endif - HTREEITEM bridges = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BridgesObList"), 0, 0, 0, 0, -1, rootitems[5], TVI_LAST); - HTREEITEM alloverlay = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OthObList"), 0, 0, 0, 0, -1, rootitems[5], TVI_LAST); + HTREEITEM bridges = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("BridgesObList"), 0, 0, 0, 0, -1, rootitems[TreeRoot::Overlay], TVI_LAST); + HTREEITEM alloverlay = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OthObList"), 0, 0, 0, 0, -1, rootitems[TreeRoot::Overlay], TVI_LAST); HTREEITEM everyoverlay = NULL; if (!theApp.m_Options.bEasy) { - everyoverlay = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("AllObList"), 0, 0, 0, 0, -1, rootitems[5], TVI_LAST); + everyoverlay = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("AllObList"), 0, 0, 0, 0, -1, rootitems[TreeRoot::Overlay], TVI_LAST); } if (!theApp.m_Options.bEasy) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OvrlManuallyObList"), 0, 0, 0, 0, valadded * 6 + 1, rootitems[5], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OvrlDataManuallyObList"), 0, 0, 0, 0, valadded * 6 + 2, rootitems[5], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OvrlManuallyObList"), 0, 0, 0, 0, valadded * 6 + 1, rootitems[TreeRoot::Overlay], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("OvrlDataManuallyObList"), 0, 0, 0, 0, valadded * 6 + 2, rootitems[TreeRoot::Overlay], TVI_LAST); } tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelOvrl0ObList"), 0, 0, 0, 0, valadded * 6 + 100 + 0, deleteoverlay, TVI_LAST); @@ -748,23 +1001,23 @@ void CViewObjects::UpdateDialog() #ifndef RA2_MODE if (!theApp.m_Options.bEasy && isTrue(g_data["Debug"]["AllowTunnels"])) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelObList"), 0, 0, 0, 0, 50, rootitems[9], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelObList"), 0, 0, 0, 0, 51, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelObList"), 0, 0, 0, 0, 50, rootitems[TreeRoot::Tunnel], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelObList"), 0, 0, 0, 0, 51, rootitems[TreeRoot::Tunnel], TVI_LAST); if (isTrue(g_data["Debug"]["AllowUnidirectionalTunnels"])) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelSingleObList"), 0, 0, 0, 0, 52, rootitems[9], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelSingleObList"), 0, 0, 0, 0, 53, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelSingleObList"), 0, 0, 0, 0, 52, rootitems[TreeRoot::Tunnel], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelSingleObList"), 0, 0, 0, 0, 53, rootitems[TreeRoot::Tunnel], TVI_LAST); } - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelTunnelObList"), 0, 0, 0, 0, 54, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelTunnelObList"), 0, 0, 0, 0, 54, rootitems[TreeRoot::Tunnel], TVI_LAST); } #else if (!theApp.m_Options.bEasy && g_data.GetBool("Debug", "AllowTunnels")) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelObList"), 0, 0, 0, 0, 50, rootitems[9], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelObList"), 0, 0, 0, 0, 51, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelObList"), 0, 0, 0, 0, 50, rootitems[TreeRoot::Tunnel], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelObList"), 0, 0, 0, 0, 51, rootitems[TreeRoot::Tunnel], TVI_LAST); if (g_data.GetBool("Debug", "AllowUnidirectionalTunnels")) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelSingleObList"), 0, 0, 0, 0, 52, rootitems[9], TVI_LAST); - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelSingleObList"), 0, 0, 0, 0, 53, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("NewTunnelSingleObList"), 0, 0, 0, 0, 52, rootitems[TreeRoot::Tunnel], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("ModifyTunnelSingleObList"), 0, 0, 0, 0, 53, rootitems[TreeRoot::Tunnel], TVI_LAST); } - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelTunnelObList"), 0, 0, 0, 0, 54, rootitems[9], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("DelTunnelObList"), 0, 0, 0, 0, 54, rootitems[TreeRoot::Tunnel], TVI_LAST); } #endif @@ -778,20 +1031,20 @@ void CViewObjects::UpdateDialog() } #endif - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, TranslateHouse(name, TRUE), 0, 0, 0, 0, valadded * 7 + i, rootitems[11], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, TranslateHouse(name, TRUE), 0, 0, 0, 0, valadded * 7 + i, rootitems[TreeRoot::Owner], TVI_LAST); } } else { for (i = 0; i < rules[HOUSES].Size(); i++) { //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, CCStrings[*rules[HOUSES].Nth(i)].cString, - //0,0,0,0, valadded*7+i, rootitems[11], TVI_LAST ); + //0,0,0,0, valadded*7+i, rootitems[TreeRoot::Owner], TVI_LAST ); #ifdef RA2_MODE auto const& name = rules[HOUSES].Nth(i).second; if (!name.CompareNoCase("nod") || !name.CompareNoCase("gdi")) { continue; } #endif - TV_InsertItemW(tree.m_hWnd, CCStrings[name].wString, CCStrings[name].len, TVI_LAST, rootitems[11], valadded * 7 + i); + TV_InsertItemW(tree.m_hWnd, CCStrings[name].wString, CCStrings[name].len, TVI_LAST, rootitems[TreeRoot::Owner], valadded * 7 + i); } } } else { @@ -814,6 +1067,8 @@ void CViewObjects::UpdateDialog() } } + auto const ignoreSet = CollectIgnoreSet(); + e = 0; if (!theApp.m_Options.bEasy) { for (i = 0; i < rules["OverlayTypes"].Size(); i++) { @@ -825,95 +1080,29 @@ void CViewObjects::UpdateDialog() if (id.Find(' ') >= 0) { id = id.Left(id.Find(' ')); } - if (id.GetLength() > 0) { - - -#ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; -#endif - -#ifdef RA2_MODE - if ((i >= 39 && i <= 60) || (i >= 180 && i <= 201) || i == 239 || i == 178 || i == 167 || i == 126 - || (i >= 122 && i <= 125) || i == 1 || (i >= 0x03 && i <= 0x17) || (i >= 0x3d && i <= 0x43) - || (i >= 0x4a && i <= 0x65) || (i >= 0xcd && i <= 0xec)) { - if (!g_data.GetBool("Debug", "DisplayAllOverlay")) { - e++; - continue; - } - } - - -#endif - - CString val = unitname; -#ifdef RA2_MODE - val.Replace("TIB", "ORE"); -#endif - - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, val, 0, 0, 0, 0, valadded * 6 + 3000 + e, everyoverlay, TVI_LAST); - e++; + if (id.IsEmpty()) { + continue; + } + if (ignoreSet.contains(std::string(unitname))) { + continue; } - } - } - - - for (i = 0; i < rules["InfantryTypes"].Size(); i++) { - auto const& unitname = rules["InfantryTypes"].Nth(i).second; - - if (unitname.IsEmpty()) { - continue; - } - #ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; + if ((i >= 39 && i <= 60) || (i >= 180 && i <= 201) || i == 239 || i == 178 || i == 167 || i == 126 + || (i >= 122 && i <= 125) || i == 1 || (i >= 0x03 && i <= 0x17) || (i >= 0x3d && i <= 0x43) + || (i >= 0x4a && i <= 0x65) || (i >= 0xcd && i <= 0xec)) { + if (!g_data.GetBool("Debug", "DisplayAllOverlay")) { + e++; + continue; + } + } #endif + CString val = unitname; #ifdef RA2_MODE - if (g_data["IgnoreRA2"].FindValue(unitname) >= 0) continue; -#else - if (g_data["IgnoreTS"].FindValue(unitname) >= 0) continue; + val.Replace("TIB", "ORE"); #endif - - WCHAR* addedString = Map->GetUnitName(unitname); - if (!addedString) continue; - - //addedString=TranslateStringACP(addedString); - - //addedString+=" ("; - //addedString+=unitname+")"; - - TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, rootitems[0], valadded * 1 + i); - - //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*1+i, rootitems[0], TVI_LAST ); - } - // okay, now the user-defined types: - auto const& infTypeSec = ini["InfantryTypes"]; - for (i = 0; i < infTypeSec.Size(); i++) { - auto const& id = infTypeSec.Nth(i).second; - if (id.IsEmpty()) { - continue; - } - - if (strlen(ini[id]["Name"]) > 0) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, ini[id]["Name"], 0, 0, 0, 0, valadded * 1 + rules["InfantryTypes"].Size() + i, rootitems[0], TVI_LAST); - } else { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (id + " NOTDEFINED"), 0, 0, 0, 0, valadded * 1 + rules["InfantryTypes"].Size() + i, rootitems[0], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, val, 0, 0, 0, 0, valadded * 6 + 3000 + e, everyoverlay, TVI_LAST); + e++; } } @@ -926,270 +1115,21 @@ void CViewObjects::UpdateDialog() } else if (tiledata == &t_tiledata) { needed_terrain = TheaterChar::T; } - auto const& bldTypeSec = rules["BuildingTypes"]; - for (i = 0; i < bldTypeSec.Size(); i++) { - auto const& unitname = bldTypeSec.Nth(i).second; - - if (unitname.IsEmpty()) { - continue; - } + TreeViewBuilder b(tree, ini, ignoreSet, theater, needed_terrain, rootitems); #ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; -#endif - -#ifdef RA2_MODE - if (g_data["IgnoreRA2"].FindValue(unitname) >= 0) continue; -#else - if (g_data["IgnoreTS"].FindValue(unitname) >= 0) continue; -#endif - if (!g_data.GetBool("Debug", "ShowBuildingsWithToTile") && !rules[unitname]["ToTile"].IsEmpty()) { - continue; - } - - WCHAR* addedString = Map->GetUnitName(unitname); - if (!addedString) { - continue; - } - - CString owner = rules[unitname]["Owner"]; - int baseplanningside = -1; -#ifdef RA2_MODE - baseplanningside = -1; -#endif - baseplanningside = rules.GetInteger(unitname, "AIBasePlanningSide", baseplanningside); - baseplanningside = g_data.GetInteger(unitname, "AIBasePlanningSide", baseplanningside); - - - int id = Map->GetBuildingID(unitname); - if (id < 0 /*|| (buildinginfo[id].pic[0].bTerrain!=0 && buildinginfo[id].pic[0].bTerrain!=needed_terrain)*/) - continue; - - if (theater == THEATER0 && !buildinginfo[id].bTemp) { /*MessageBox("Ignored", unitname,0);*/ continue; } - if (theater == THEATER1 && !buildinginfo[id].bSnow) { /*MessageBox("Ignored", unitname,0);*/ continue; } - if (theater == THEATER2 && !buildinginfo[id].bUrban) { /*MessageBox("Ignored", unitname,0);*/ continue; } - - // check if mapfile contains other value for owner - owner = ini.GetStringOr(unitname, "Owner", owner); - - //addedString=TranslateStringACP(addedString); - - //addedString+=" ("; - //addedString+=unitname+")"; - - BOOL addedfor[3] = { FALSE,FALSE,FALSE }; - - // MW fixed below for YR... uhhh... - int e; - BOOL bAdded = FALSE; - for (e = 0; e < sides.size(); e++) { - //MessageBox(sides[e].name); - - if (isIncluded(owner, sides[e].name)) { - -#ifdef RA2_MODE - if (!addedfor[sides[e].orig_n]) -#endif - if (baseplanningside == -1 || baseplanningside == sides[e].orig_n) { - - //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e], TVI_LAST ); - TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, structhouses[e], valadded * 2 + i); - bAdded = TRUE; - addedfor[sides[e].orig_n] = TRUE; - - } - } - - - } - - if (bAdded == FALSE) { - //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*2+i, structhouses[e+1], TVI_LAST ); - TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, structhouses[sides.size()], valadded * 2 + i); - } - } - - // okay, now the user-defined types: - auto const& localbldTypeSec = ini["BuildingTypes"]; - for (i = 0; i < localbldTypeSec.Size(); i++) { - auto const& typeId = localbldTypeSec.Nth(i).second; - if (localbldTypeSec.Nth(i).second.IsEmpty()) { - continue; - } - - int id = Map->GetBuildingID(typeId); - if (id < 0 || (buildinginfo[id].pic[0].bTerrain != TheaterChar::None && buildinginfo[id].pic[0].bTerrain != needed_terrain)) { - continue; - } - - int e = 2; - BOOL bAdded = FALSE; - auto owner = ini[typeId]["Owner"]; - owner.MakeUpper(); - - auto const& name = ini[typeId]["Name"]; - if (!name.IsEmpty()) { - auto const& addedString = name; - int e; - for (e = 0; e < sides.size(); e++) { - if (isIncluded(owner, sides[e].name)) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0, 0, 0, 0, valadded * 2 + i, structhouses[e], TVI_LAST); - bAdded = TRUE; - } else if (e == sides.size() - 1 && bAdded == FALSE) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0, 0, 0, 0, valadded * 2 + i, structhouses[e + 1], TVI_LAST); - } - } - } else { - CString addedString = (typeId + " UNDEFINED"); - BOOL addedfor[2] = { FALSE,FALSE }; - - int e; - for (e = 0; e < sides.size(); e++) { -#ifdef RA2_MODE - if (!addedfor[sides[e].orig_n]) -#endif - if (isIncluded(owner, sides[e].name) || (yuri_mode && e == 2 && owner == "YuriCountry")) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0, 0, 0, 0, valadded * 2 + i, structhouses[e], TVI_LAST); - bAdded = TRUE; - addedfor[sides[e].orig_n] = TRUE; - - } else if (e == sides.size() - 1 && bAdded == FALSE) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0, 0, 0, 0, valadded * 2 + i, structhouses[e + 1], TVI_LAST); - } - } - } - - } - - - auto const& aircraftTypeSec = rules["AircraftTypes"]; - for (i = 0; i < aircraftTypeSec.Size(); i++) { - auto const& unitname = aircraftTypeSec.Nth(i).second; - if (unitname.IsEmpty()) { - continue; - } - -#ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; -#endif - -#ifdef RA2_MODE - if (g_data["IgnoreRA2"].FindValue(unitname) >= 0) continue; -#else - if (g_data["IgnoreTS"].FindValue(unitname) >= 0) continue; -#endif - - WCHAR* addedString = Map->GetUnitName(unitname); - if (!addedString) continue; - - //addedString=TranslateStringACP(addedString); - - //addedString+=" ("; - //addedString+=unitname+")"; - - TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, rootitems[2], valadded * 3 + i); - - //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*3+i, rootitems[2], TVI_LAST ); - } - - // okay, now the user-defined types: - auto const localAircraftTypeSec = ini["AircraftTypes"]; - for (i = 0; i < localAircraftTypeSec.Size(); i++) { - auto const& typeId = localAircraftTypeSec.Nth(i).second; - if (typeId.IsEmpty()) { - continue; - } - - auto const& name = ini[typeId]["Name"]; - if (!name.IsEmpty()) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, name, 0, 0, 0, 0, valadded * 3 + i + rules["AircraftTypes"].Size(), rootitems[2], TVI_LAST); - } else { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (typeId + " NOTDEFINED"), 0, 0, 0, 0, valadded * 3 + i + rules["AircraftTypes"].Size(), rootitems[2], TVI_LAST); - } - } - - - auto const& vehTypeSec = rules["VehicleTypes"]; - for (i = 0; i < vehTypeSec.Size(); i++) { - auto const& unitname = vehTypeSec.Nth(i).second; - if (unitname.GetLength() == 0) { - continue; - } -#ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; -#endif - -#ifdef RA2_MODE - if (g_data["IgnoreRA2"].FindValue(unitname) >= 0) continue; -#else - if (g_data["IgnoreTS"].FindValue(unitname) >= 0) continue; -#endif - - WCHAR* addedString = Map->GetUnitName(unitname); - if (!addedString) continue; - - //addedString=TranslateStringACP(addedString); - - //addedString+=" ("; - //addedString+=unitname+")"; - - TV_InsertItemW(tree.m_hWnd, addedString, wcslen(addedString), TVI_LAST, rootitems[1], valadded * 4 + i); - - //tree.InsertItem(TVIF_PARAM | TVIF_TEXT, addedString, 0,0,0,0, valadded*4+i, rootitems[1], TVI_LAST ); - } - // okay, now the user-defined types: - auto const localVehTypeSec = ini["VehicleTypes"]; - for (i = 0; i < localVehTypeSec.Size(); i++) { - auto const& typeId = localVehTypeSec.Nth(i).second; - if (typeId.IsEmpty()) { - continue; - } - auto const& name = ini[typeId]["Name"]; - if (!name.IsEmpty()) { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, name, 0, 0, 0, 0, valadded * 4 + i + rules["VehicleTypes"].Size(), rootitems[1], TVI_LAST); - } else { - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, (typeId + " NOTDEFINED"), 0, 0, 0, 0, valadded * 4 + i + rules["VehicleTypes"].Size(), rootitems[1], TVI_LAST); - } - } - - -#ifdef RA2_MODE - HTREEITEM hTrees = tree.InsertItem(GetLanguageStringACP("TreesObList"), rootitems[4], TVI_LAST); - HTREEITEM hTL = tree.InsertItem(GetLanguageStringACP("TrafficLightsObList"), rootitems[4], TVI_LAST); - HTREEITEM hSigns = tree.InsertItem(GetLanguageStringACP("SignsObList"), rootitems[4], TVI_LAST); - HTREEITEM hLightPosts = tree.InsertItem(GetLanguageStringACP("LightPostsObList"), rootitems[4], TVI_LAST); + HTREEITEM hTrees = tree.InsertItem(GetLanguageStringACP("TreesObList"), rootitems[TreeRoot::Terrain], TVI_LAST); + HTREEITEM hTL = tree.InsertItem(GetLanguageStringACP("TrafficLightsObList"), rootitems[TreeRoot::Terrain], TVI_LAST); + HTREEITEM hSigns = tree.InsertItem(GetLanguageStringACP("SignsObList"), rootitems[TreeRoot::Terrain], TVI_LAST); + HTREEITEM hLightPosts = tree.InsertItem(GetLanguageStringACP("LightPostsObList"), rootitems[TreeRoot::Terrain], TVI_LAST); #endif // random tree placer #ifdef RA2_MODE tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("RndTreeObList"), 0, 0, 0, 0, valadded * 5 + 999, hTrees, TVI_LAST); #else - tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("RndTreeObList"), 0, 0, 0, 0, valadded * 5 + 999, rootitems[4], TVI_LAST); + tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP("RndTreeObList"), 0, 0, 0, 0, valadded * 5 + 999, rootitems[TreeRoot::Terrain], TVI_LAST); #endif auto const& terrainTypeSec = rules["TerrainTypes"]; @@ -1197,23 +1137,9 @@ void CViewObjects::UpdateDialog() auto const& unitname = terrainTypeSec.Nth(i).second; CString addedString = Map->GetUnitName(unitname); -#ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; -#endif - -#ifdef RA2_MODE - if (g_data["IgnoreRA2"].FindValue(unitname) >= 0) continue; -#else - if (g_data["IgnoreTS"].FindValue(unitname) >= 0) continue; -#endif + if (ignoreSet.contains(std::string(unitname))) { + continue; + } #ifdef RA2_MODE if (g_data["IgnoreTerrainRA2"].FindValue(unitname) >= 0) continue; #else @@ -1224,7 +1150,7 @@ void CViewObjects::UpdateDialog() UINT flags = MF_STRING; - HTREEITEM howner = rootitems[4]; + HTREEITEM howner = rootitems[TreeRoot::Terrain]; #ifdef RA2_MODE if (unitname.Find("SIGN") >= 0) howner = hSigns; @@ -1256,29 +1182,15 @@ void CViewObjects::UpdateDialog() auto const& unitname = smudgeTypeSec.Nth(i).second; CString addedString = unitname; -#ifdef RA2_MODE - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER2 && g_data["IgnoreUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER3 && g_data["IgnoreNewUrbanRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER4 && g_data["IgnoreLunarRA2"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER5 && g_data["IgnoreDesertRA2"].FindValue(unitname) >= 0) continue; -#else - if (Map->GetTheater() == THEATER0 && g_data["IgnoreTemperateTS"].FindValue(unitname) >= 0) continue; - if (Map->GetTheater() == THEATER1 && g_data["IgnoreSnowTS"].FindValue(unitname) >= 0) continue; -#endif - -#ifdef RA2_MODE - if (g_data["IgnoreRA2"].FindValue(unitname) >= 0) continue; -#else - if (g_data["IgnoreTS"].FindValue(unitname) >= 0) continue; -#endif + if (ignoreSet.contains(std::string(unitname))) { + continue; + } addedString = TranslateStringACP(addedString); UINT flags = MF_STRING; - HTREEITEM howner = rootitems[14]; + HTREEITEM howner = rootitems[TreeRoot::Smudge]; if (unitname.GetLength() > 0) { @@ -1287,11 +1199,7 @@ void CViewObjects::UpdateDialog() } #endif - - OutputDebugString("Objectbrowser redraw finished\n"); - - } int CViewObjects::OnCreate(LPCREATESTRUCT lpCreateStruct) @@ -1347,3 +1255,14 @@ void CViewObjects::HandleBrushSize(int iTile) } } + +HTREEITEM TreeViewCategoryHandler::GetOrAdd(const CString& name) +{ + auto const it = structhouses.find((std::string)name); + if (it != structhouses.end()) { + return it->second; + } + auto newItem = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP(name), 0, 0, 0, 0, -1, parentNode, TVI_LAST); + structhouses.insert({ (std::string)name, newItem }); + return newItem; +} \ No newline at end of file diff --git a/MissionEditor/ViewObjects.h b/MissionEditor/ViewObjects.h index b4019ca..05ad06b 100644 --- a/MissionEditor/ViewObjects.h +++ b/MissionEditor/ViewObjects.h @@ -27,9 +27,45 @@ // ViewObjects.h : Header-Datei // #include +#include #define MAKE_MASK(refVal) 1 << static_cast(refVal) +class TreeViewBuilder; +class CViewObjects; +class IniFileGroup; + +using IgnoreSet = std::unordered_set; + +static const IgnoreSet CollectIgnoreSet(); + +extern CIniFile rules; + +class TreeRoot { + friend class TreeViewBuilder; + friend class CViewObjects; + enum _ : int { + Nothing = -1, + Infantry, + Vehicle, + Aircraft, + Building, + Terrain, + Overlay, + Waypoint, + Celltag, + Basenode, + Tunnel, + Delete, + Owner, + PlayerLocation, + Ground, + Smudge, + Count, + Begin = 0, + }; +}; + enum class TreeViewTechnoType { Set_None = -1, Building = 0, @@ -62,6 +98,87 @@ inline bool operator&(TreeViewTechnoType lhs, TechnoTypeMask rhs) return rhs & static_cast(MAKE_MASK(lhs)); } +class TreeViewCategoryHandler { + using categoryNodeMap = std::unordered_map; + +public: + TreeViewCategoryHandler(CTreeCtrl& tree, HTREEITEM parentNode) : + tree(tree), + parentNode(parentNode) + {} + + HTREEITEM GetOrAdd(const CString& name); + +private: + CTreeCtrl& tree; + HTREEITEM parentNode; + categoryNodeMap structhouses; +}; + +class GuessSideHelper { +public: + GuessSideHelper(const TreeViewBuilder& builder) : + builder(builder) + {} + + const CString& GetSideName(const CString& regName, TreeViewTechnoType technoType, const CIniFile& inWhichIni = rules); + int GuessSide(const CString& pRegName, TreeViewTechnoType nType, const CIniFile& inWhichIni); + int guessGenericSide(const CString& typeId); + +private: + int guessBuildingSide(const CString& typeId, const CIniFile& inWhichIni); + + std::unordered_map KnownItem; + const TreeViewBuilder& builder; +}; + +class TreeViewBuilder { + using houseMap = std::unordered_map; + + struct CatetoryDefinition { + CString CategoryName;// or side name + TechnoTypeMask CategoryMask; + }; + + using mapSideNodeInfo = std::unordered_map; + +public: + TreeViewBuilder(CTreeCtrl& tree, + const CIniFile& ini, + const IgnoreSet& ignoreSet, + const CString& theater, + const TheaterChar needed_terrain, + const HTREEITEM rootitems[]) : + tree(tree), + ini(ini), + theater(theater), + needed_terrain(needed_terrain), + rootitems(rootitems), + m_ignoreSet(ignoreSet), + m_owners(collectOwners()), + sideInfo(collectCategoryInfo()) + { + updateTechnoItems(); + } + + const houseMap m_owners; + const mapSideNodeInfo sideInfo; + +private: + static mapSideNodeInfo collectCategoryInfo(); + static const houseMap collectOwners(); + void updateTechnoItems(); + void updateBuildingTypes(HTREEITEM parentNode); + void updateUnitTypes(HTREEITEM parentNode, const char* typeListId, TreeViewTechnoType technoType, int multiple); + + const IgnoreSet& m_ignoreSet; + CTreeCtrl& tree; + const CIniFile& ini; + const CString& theater; + const TheaterChar needed_terrain; + const HTREEITEM* rootitems; +}; + ///////////////////////////////////////////////////////////////////////////// // Ansicht CViewObjects @@ -110,6 +227,20 @@ private: void HandleBrushSize(int iTile); }; +class IniMegaFile +{ + friend class IniFileGroup; +public: + static IniFileGroup GetRules(); + + static bool IsNullOrEmpty(const CString& value) { return isNullOrEmpty(value); } + +private: + static bool isNullOrEmpty(const CString& value); + + +}; + ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} From 7eaf7e9a0ec958b473ed3793c0d9e7032d14972f Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Tue, 30 Apr 2024 21:24:00 -0400 Subject: [PATCH 5/8] fixed some sorting logic issues, enriched side category definition in INI file . --- MissionEditor/ViewObjects.cpp | 53 ++++++++++++++----- MissionEditor/data/FinalAlert2/FAData.ini | 14 +++++ MissionEditor/data/FinalAlert2/FALanguage.ini | 8 +-- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/MissionEditor/ViewObjects.cpp b/MissionEditor/ViewObjects.cpp index d50e96d..940de86 100644 --- a/MissionEditor/ViewObjects.cpp +++ b/MissionEditor/ViewObjects.cpp @@ -575,6 +575,9 @@ TreeViewBuilder::mapSideNodeInfo TreeViewBuilder::collectCategoryInfo() mapSideNodeInfo ret; auto toType = [](const CString& str) -> TechnoTypeMask { + if (str.IsEmpty()) { + return TechnoTypeMask(-1); + } return TechnoTypeMask(atoi(str)); }; @@ -584,15 +587,18 @@ TreeViewBuilder::mapSideNodeInfo TreeViewBuilder::collectCategoryInfo() auto const otherCategoryName = GetLanguageStringACP("Other"); for (auto& [seq, def] : g_data["Sides"]) { + auto sideName = def; auto const commaPos = def.Find(','); //now parse real type if (commaPos >= 0) { + sideName = def.Mid(0, commaPos); typeStr = def.Mid(commaPos + 1); } if (typeStr == otherCategoryName) { continue; } - auto&& info = CatetoryDefinition{ def.Mid(0, commaPos), toType(typeStr) }; + + auto&& info = CatetoryDefinition{ TranslateStringACP(sideName), toType(typeStr) }; ret.insert({ count++, info }); } @@ -640,27 +646,27 @@ const CString& GuessSideHelper::GetSideName(const CString& regName, TreeViewTech return builder.sideInfo.at(-1).CategoryName; } -int GuessSideHelper::GuessSide(const CString& pRegName, TreeViewTechnoType nType, const CIniFile& inWhichIni) +int GuessSideHelper::GuessSide(const CString& regName, TreeViewTechnoType type, const CIniFile& inWhichIni) { - auto const& knownIterator = KnownItem.find(pRegName.operator LPCSTR()); + auto const& knownIterator = KnownItem.find(regName.operator LPCSTR()); if (knownIterator != KnownItem.end()) return knownIterator->second; int result = -1; - switch (nType) { + switch (type) { case TreeViewTechnoType::Set_None: default: break; case TreeViewTechnoType::Building: - result = guessBuildingSide(pRegName, inWhichIni); + result = guessBuildingSide(regName, inWhichIni); break; case TreeViewTechnoType::Infantry: case TreeViewTechnoType::Vehicle: case TreeViewTechnoType::Aircraft: - result = guessGenericSide(pRegName); + result = guessGenericSide(regName); break; } - KnownItem.insert_or_assign(pRegName.operator LPCSTR(), result); + KnownItem.insert_or_assign(std::string(regName), result); return result; } @@ -668,10 +674,10 @@ int GuessSideHelper::guessBuildingSide(const CString& typeId, const CIniFile& in { int planning; planning = inWhichIni.GetInteger(typeId, "AIBasePlanningSide", -1); - if (planning >= rules.GetSection("Sides").Size()) { - return -1; - } if (planning >= 0) { + if (planning >= rules.GetSection("Sides").Size()) { + planning = -1; + } return planning; } auto const& cons = utilities::split_string(rules.GetString("AI", "BuildConst")); @@ -687,13 +693,14 @@ int GuessSideHelper::guessBuildingSide(const CString& typeId, const CIniFile& in return guessGenericSide(typeId); } -int GuessSideHelper::guessGenericSide(const CString& pRegName) +int GuessSideHelper::guessGenericSide(const CString& regName) { auto const& mmh = IniMegaFile::GetRules(); - auto const& owners = utilities::split_string(mmh.GetString(pRegName, "Owner")); + auto const& owners = utilities::split_string(mmh.GetString(regName, "Owner")); if (owners.size() <= 0) { return -1; } + auto const& itr = builder.m_owners.find((std::string)owners[0]); if (itr == builder.m_owners.end()) { return -1; @@ -706,6 +713,8 @@ void TreeViewBuilder::updateBuildingTypes(HTREEITEM parentNode) { GuessSideHelper sideHelper(*this); auto baseOffset = valadded * 2; + structhouses.Preallocate(sideInfo, TreeViewTechnoType::Building); + auto const& bldTypeSec = rules["BuildingTypes"]; for (auto i = 0; i < bldTypeSec.Size(); i++) { @@ -771,6 +780,8 @@ void TreeViewBuilder::updateUnitTypes(HTREEITEM parentNode, const char* typeList GuessSideHelper sideHelper(*this); auto baseOffset = valadded * multiple; + structhouses.Preallocate(sideInfo, technoType); + for (auto i = 0; i < rules[typeListId].Size(); i++) { auto const& typeId = rules[typeListId].Nth(i).second; if (typeId.IsEmpty()) { @@ -1256,13 +1267,27 @@ void CViewObjects::HandleBrushSize(int iTile) } +void TreeViewCategoryHandler::Preallocate(const TreeViewBuilder::mapSideNodeInfo& sideInfo, TreeViewTechnoType type) +{ + for (auto const& [idx, def] : sideInfo) { + if (idx < 0) { + continue; + } + if (!(def.CategoryMask & type)) { + continue; + } + GetOrAdd(def.CategoryName); + } +} + HTREEITEM TreeViewCategoryHandler::GetOrAdd(const CString& name) { - auto const it = structhouses.find((std::string)name); + auto&& nameStd = std::string(name); + auto const it = structhouses.find(nameStd); if (it != structhouses.end()) { return it->second; } auto newItem = tree.InsertItem(TVIF_PARAM | TVIF_TEXT, GetLanguageStringACP(name), 0, 0, 0, 0, -1, parentNode, TVI_LAST); - structhouses.insert({ (std::string)name, newItem }); + structhouses.insert({ std::move(nameStd), newItem }); return newItem; } \ No newline at end of file diff --git a/MissionEditor/data/FinalAlert2/FAData.ini b/MissionEditor/data/FinalAlert2/FAData.ini index 16d63d0..57d796b 100644 --- a/MissionEditor/data/FinalAlert2/FAData.ini +++ b/MissionEditor/data/FinalAlert2/FAData.ini @@ -11,6 +11,20 @@ AllowTunnels=yes AllowUnidirectionalTunnels=yes ;ShowBuildingsWithToTile=no +[Sides] +0=Allied +1=Soviet +2=Yuri +3=安塔列星 +4=科技功能建筑,1 +5=地标建筑类,1 +6=大城市建筑,1 +7=中小城市建筑,1 +8=村庄建筑,1 +9=工业建筑,1 +10=小型装饰摆件,1 +11=中立特殊建筑,1 + [ForceUnitPalettePrefix] 0=TIBTRE diff --git a/MissionEditor/data/FinalAlert2/FALanguage.ini b/MissionEditor/data/FinalAlert2/FALanguage.ini index b0d2028..3081562 100644 --- a/MissionEditor/data/FinalAlert2/FALanguage.ini +++ b/MissionEditor/data/FinalAlert2/FALanguage.ini @@ -1061,10 +1061,10 @@ No=否 NeedsYR=要用此地图进行游戏,需要尤里的复仇。 ; name replacements -;N_AMRADR=American Air Force Command HQ -;N_SENGINEER=Soviet Engineer -;N_ENGINEER=Allied Engineer -;N_YENGINEER=Yuri Engineer +N_AMRADR=美国空指部 +N_SENGINEER=苏军工程师 +N_ENGINEER=盟军工程师 +N_YENGINEER=尤里工程师 ;N_SCHD=Deployed Siege Helicopter ;N_GACSPH=Chronosphere ;N_CALOND04=London Parliament From a64b11d6a42835b7cf372cdb2801a5a58c686882 Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Tue, 30 Apr 2024 22:27:53 -0400 Subject: [PATCH 6/8] resolved compile issue . --- MissionEditor/ViewObjects.h | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/MissionEditor/ViewObjects.h b/MissionEditor/ViewObjects.h index 05ad06b..8c22193 100644 --- a/MissionEditor/ViewObjects.h +++ b/MissionEditor/ViewObjects.h @@ -98,23 +98,6 @@ inline bool operator&(TreeViewTechnoType lhs, TechnoTypeMask rhs) return rhs & static_cast(MAKE_MASK(lhs)); } -class TreeViewCategoryHandler { - using categoryNodeMap = std::unordered_map; - -public: - TreeViewCategoryHandler(CTreeCtrl& tree, HTREEITEM parentNode) : - tree(tree), - parentNode(parentNode) - {} - - HTREEITEM GetOrAdd(const CString& name); - -private: - CTreeCtrl& tree; - HTREEITEM parentNode; - categoryNodeMap structhouses; -}; - class GuessSideHelper { public: GuessSideHelper(const TreeViewBuilder& builder) : @@ -134,15 +117,14 @@ private: class TreeViewBuilder { using houseMap = std::unordered_map; - +public: struct CatetoryDefinition { CString CategoryName;// or side name TechnoTypeMask CategoryMask; }; - using mapSideNodeInfo = std::unordered_map; + using mapSideNodeInfo = std::map; -public: TreeViewBuilder(CTreeCtrl& tree, const CIniFile& ini, const IgnoreSet& ignoreSet, @@ -179,6 +161,24 @@ private: const HTREEITEM* rootitems; }; +class TreeViewCategoryHandler { + using categoryNodeMap = std::unordered_map; + +public: + TreeViewCategoryHandler(CTreeCtrl& tree, HTREEITEM parentNode) : + tree(tree), + parentNode(parentNode) + {} + + void Preallocate(const TreeViewBuilder::mapSideNodeInfo& sideInfo, TreeViewTechnoType type); + HTREEITEM GetOrAdd(const CString& name); + +private: + CTreeCtrl& tree; + HTREEITEM parentNode; + categoryNodeMap structhouses; +}; + ///////////////////////////////////////////////////////////////////////////// // Ansicht CViewObjects From eefb3c28bd8a7d93d07da2a173101a684033b95b Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Tue, 30 Apr 2024 22:28:13 -0400 Subject: [PATCH 7/8] removed useless variables . --- MissionEditor/ViewObjects.cpp | 5 ----- MissionEditor/ViewObjects.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/MissionEditor/ViewObjects.cpp b/MissionEditor/ViewObjects.cpp index 940de86..a93d5e6 100644 --- a/MissionEditor/ViewObjects.cpp +++ b/MissionEditor/ViewObjects.cpp @@ -50,8 +50,6 @@ IMPLEMENT_DYNCREATE(CViewObjects, CTreeView) CViewObjects::CViewObjects() { - m_ready = FALSE; - } CViewObjects::~CViewObjects() @@ -1226,9 +1224,6 @@ int CViewObjects::OnCreate(LPCREATESTRUCT lpCreateStruct) void CViewObjects::OnInitialUpdate() { CTreeView::OnInitialUpdate(); - - - m_ready = TRUE; } void CViewObjects::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) diff --git a/MissionEditor/ViewObjects.h b/MissionEditor/ViewObjects.h index 8c22193..833f2e1 100644 --- a/MissionEditor/ViewObjects.h +++ b/MissionEditor/ViewObjects.h @@ -193,8 +193,6 @@ public: // Operationen public: - CTreeCtrl* tree; - BOOL m_ready; void UpdateDialog(); // Überschreibungen From cbe646214815f1f59d8840fb6e24f9911df5740c Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Tue, 30 Apr 2024 22:29:29 -0400 Subject: [PATCH 8/8] valadded expanded to high WORD (actually it is 64bit value now). --- MissionEditor/ViewObjects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MissionEditor/ViewObjects.cpp b/MissionEditor/ViewObjects.cpp index a93d5e6..35318e4 100644 --- a/MissionEditor/ViewObjects.cpp +++ b/MissionEditor/ViewObjects.cpp @@ -44,7 +44,7 @@ static char THIS_FILE[] = __FILE__; ///////////////////////////////////////////////////////////////////////////// // CViewObjects -const size_t valadded = 10000; +const size_t valadded = 2 << 16; IMPLEMENT_DYNCREATE(CViewObjects, CTreeView)