mirror of
https://github.com/electronicarts/CNC_TS_and_RA2_Mission_Editor.git
synced 2025-05-06 11:41:42 -04:00
Merge pull request #6 from revengenowstudio/feature/tree-view
Feature/tree view
This commit is contained in:
commit
3c3464801b
30 changed files with 919 additions and 529 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using std::vector;
|
||||
|
||||
#define COMBOUINPUT_HOUSES 0
|
||||
#define COMBOUINPUT_COUNTRIES 1
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -69,6 +69,8 @@ static char THIS_FILE[] = __FILE__;
|
|||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using std::endl;
|
||||
|
||||
extern ACTIONDATA AD;
|
||||
extern BOOL bNoDraw;
|
||||
|
||||
|
|
39
MissionEditor/INIMeta.cpp
Normal file
39
MissionEditor/INIMeta.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "StdAfx.h"
|
||||
#include "INIMeta.h"
|
||||
#include <set>
|
||||
|
||||
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);
|
||||
}
|
142
MissionEditor/INIMeta.h
Normal file
142
MissionEditor/INIMeta.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
#pragma once
|
||||
|
||||
#include <afx.h>
|
||||
#include "IniFile.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using IndiceStorage = std::vector<CString>;
|
||||
using SequencedSection = std::vector<CString>;
|
||||
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<const CIniFile*>;
|
||||
|
||||
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;
|
||||
};
|
|
@ -38,12 +38,14 @@
|
|||
#include <ios>
|
||||
#include "IniHelper.h"
|
||||
|
||||
using namespace std;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
|
||||
class CIniFileSection
|
||||
{
|
||||
static const CString EmptyValue;
|
||||
public:
|
||||
using Container = vector<std::pair<CString, CString>>;
|
||||
static const CString EmptyValue;
|
||||
|
||||
CIniFileSection();
|
||||
virtual ~CIniFileSection();
|
||||
|
@ -197,7 +199,7 @@ public:
|
|||
|
||||
private:
|
||||
map<CString, int64_t> value_pos{};
|
||||
vector<std::pair<CString, CString>> value_pairs{};// sequenced
|
||||
Container value_pairs{};// sequenced
|
||||
};
|
||||
|
||||
class CIniFile
|
||||
|
|
|
@ -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<short>(srcRect.right - 1));
|
||||
auto l = std::max(left, srcRect.left);
|
||||
auto r = std::min(right, static_cast<short>(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<BYTE*>(&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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
extern TILEDATA** tiledata;
|
||||
extern DWORD* tiledata_count;
|
||||
extern ofstream errstream;
|
||||
extern std::ofstream errstream;
|
||||
extern map<int, int> tilesets_start;
|
||||
extern CIniFile* tiles;
|
||||
extern CFinalSunApp theApp;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -347,7 +347,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='FinalAlertDebug YR|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NOMINMAX;RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\MissionEditorPackLib</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
|
@ -419,7 +419,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='FinalAlertRelease YR|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NOMINMAX;RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\MissionEditorPackLib</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
|
@ -498,6 +498,7 @@
|
|||
<ClCompile Include="Infantry.cpp" />
|
||||
<ClCompile Include="Info.cpp" />
|
||||
<ClCompile Include="IniFile.cpp" />
|
||||
<ClCompile Include="INIMeta.cpp" />
|
||||
<ClCompile Include="InputBox.cpp" />
|
||||
<ClCompile Include="IsoView.cpp" />
|
||||
<ClCompile Include="Lighting.cpp" />
|
||||
|
@ -609,6 +610,7 @@
|
|||
<ClInclude Include="ComboUInputDlg.h" />
|
||||
<ClInclude Include="defines.h" />
|
||||
<ClInclude Include="IniHelper.h" />
|
||||
<ClInclude Include="INIMeta.h" />
|
||||
<ClInclude Include="LineDrawer.h" />
|
||||
<ClInclude Include="DynamicGraphDlg.h" />
|
||||
<ClInclude Include="FinalSun.h" />
|
||||
|
@ -660,6 +662,7 @@
|
|||
<ClInclude Include="SingleplayerSettings.h" />
|
||||
<ClInclude Include="SpecialFlags.h" />
|
||||
<ClInclude Include="StdAfx.h" />
|
||||
<ClInclude Include="StringHelper.h" />
|
||||
<ClInclude Include="structs.h" />
|
||||
<ClInclude Include="Tags.h" />
|
||||
<ClInclude Include="TaskForce.h" />
|
||||
|
|
|
@ -282,6 +282,9 @@
|
|||
<ClCompile Include="TextDrawer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="INIMeta.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MissionEditor.rc">
|
||||
|
@ -568,6 +571,12 @@
|
|||
<ClInclude Include="IniHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StringHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="INIMeta.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\clifftoo.bmp">
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
25
MissionEditor/StringHelper.h
Normal file
25
MissionEditor/StringHelper.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <afx.h>
|
||||
#include <vector>
|
||||
|
||||
namespace utilities {
|
||||
static std::vector<CString> split_string(const CString& pSource, TCHAR cSplit = ',')
|
||||
{
|
||||
std::vector<CString> 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,9 +27,45 @@
|
|||
// ViewObjects.h : Header-Datei
|
||||
//
|
||||
#include <afxcview.h>
|
||||
#include <unordered_set>
|
||||
|
||||
#define MAKE_MASK(refVal) 1 << static_cast<int>(refVal)
|
||||
|
||||
class TreeViewBuilder;
|
||||
class CViewObjects;
|
||||
class IniFileGroup;
|
||||
|
||||
using IgnoreSet = std::unordered_set<std::string>;
|
||||
|
||||
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<TechnoTypeMask>(MAKE_MASK(lhs));
|
||||
}
|
||||
|
||||
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<std::string, int> KnownItem;
|
||||
const TreeViewBuilder& builder;
|
||||
};
|
||||
|
||||
class TreeViewBuilder {
|
||||
using houseMap = std::unordered_map<std::string, int>;
|
||||
public:
|
||||
struct CatetoryDefinition {
|
||||
CString CategoryName;// or side name
|
||||
TechnoTypeMask CategoryMask;
|
||||
};
|
||||
|
||||
using mapSideNodeInfo = std::map<int, CatetoryDefinition>;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class TreeViewCategoryHandler {
|
||||
using categoryNodeMap = std::unordered_map<std::string, HTREEITEM>;
|
||||
|
||||
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
|
||||
|
||||
|
@ -76,8 +193,6 @@ public:
|
|||
|
||||
// Operationen
|
||||
public:
|
||||
CTreeCtrl* tree;
|
||||
BOOL m_ready;
|
||||
void UpdateDialog();
|
||||
|
||||
// Überschreibungen
|
||||
|
@ -110,6 +225,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}}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
using std::string;
|
||||
|
||||
bool deleteFile(const std::string& u8FilePath);
|
||||
|
||||
// set the status bar text in the main dialog
|
||||
|
|
|
@ -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()) {
|
||||
|
@ -195,7 +195,7 @@ inline CString SetParam(const CString& data, const int param, const CString& val
|
|||
if (param < 0)
|
||||
return data;
|
||||
std::vector<CString> params = SplitParams(data);
|
||||
params.resize(max(param + 1, static_cast<int>(params.size())));
|
||||
params.resize(std::max(param + 1, static_cast<int>(params.size())));
|
||||
params[param] = value;
|
||||
return Join(",", params);
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ SMUDGE_INFO smudgeinfo[0x0F00];
|
|||
#endif
|
||||
|
||||
/* error output */
|
||||
ofstream errstream;
|
||||
std::ofstream errstream;
|
||||
|
||||
/* the finalsun app object */
|
||||
CFinalSunApp theApp;
|
||||
|
|
|
@ -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];
|
||||
|
|
70
UnitTest/CIni_Meta_Test.cpp
Normal file
70
UnitTest/CIni_Meta_Test.cpp
Normal file
|
@ -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);
|
||||
}
|
|
@ -27,6 +27,9 @@
|
|||
#include <iostream>
|
||||
#include <afxwin.h>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
#if !defined(ASSERT)
|
||||
#define ASSERT(x) if (!(x)) throw("assertion failed");
|
||||
#endif
|
|
@ -102,9 +102,9 @@
|
|||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_DEBUG;NOMINMAX;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)googletest\x64\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)googletest\x64\include;$(SolutionDir)MissionEditorPackLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
|
@ -133,11 +133,14 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\MissionEditor\IniFile.cpp" />
|
||||
<ClCompile Include="..\MissionEditor\INIMeta.cpp" />
|
||||
<ClCompile Include="CIni_Meta_Test.cpp" />
|
||||
<ClCompile Include="CIni_Test.cpp" />
|
||||
<ClCompile Include="UnitTest.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\MissionEditor\IniFile.h" />
|
||||
<ClInclude Include="..\MissionEditor\INIMeta.h" />
|
||||
<ClInclude Include="StdAfx.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
<ClCompile Include="..\MissionEditor\IniFile.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CIni_Meta_Test.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\MissionEditor\INIMeta.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="StdAfx.h">
|
||||
|
@ -32,5 +38,8 @@
|
|||
<ClInclude Include="..\MissionEditor\IniFile.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\MissionEditor\INIMeta.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Add table
Reference in a new issue