Skip to content

Commit ad013fa

Browse files
committed
Implemented design customization
1 parent fb6e263 commit ad013fa

13 files changed

Lines changed: 472 additions & 190 deletions

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
This is a new implementation of the ingame tech tree view (F2) completely replacing the old one. It is much easier moddable, as there are no hardcoded elements. Basically each element only requires its ID, type, age and rendering mode. The positioning is done by the rendering algorithm completely.
44

5-
At the moment there is only one renderer, the "vanilla renderer". It uses the original tech tree SLPs, hence has hardcoded resolutions and age count. It is planned to add another renderer that uses modular graphics, so the tree appearance is more customizable.
5+
At the moment there is only one renderer, the "vanilla renderer". It uses the original tech tree node placement (including compression using spare place in subtrees of the same parent building), everything else like background graphics, control positions and sizes, age count and much more is completely customizable. This design data is also stored in the DAT file.
66

7-
As a consequence, the DAT tech tree structure used by this implementation is incompatible with the original one.
7+
As a consequence, the DAT tech tree structure used by this implementation is incompatible with the original one (but an unmodified game executable will still work with the new DAT file format, because the old tech tree data persists).
88
You can edit it with this tool: https://github.com/Janworks/AoETechTreeTool
99
If you want to do more modding than just changing the tech tree view itself, use the TechTreeEditor, which also exports the new tech tree format: https://github.com/Janworks/TechTreeEditor
1010

‎TechTree/TechTree.vcxproj‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
<ClCompile Include="functions.cpp" />
116116
<ClCompile Include="ControlListElement.cpp" />
117117
<ClCompile Include="TechTreeData.cpp" />
118+
<ClCompile Include="TechTreeDesign.cpp" />
118119
<ClCompile Include="TechTreeElement.cpp" />
119120
<ClCompile Include="TechTreeRenderer.cpp" />
120121
<ClCompile Include="TechTreeWindow.cpp" />
@@ -155,6 +156,7 @@
155156
<ClInclude Include="ControlListElement.h" />
156157
<ClInclude Include="StaticControlContainer.h" />
157158
<ClInclude Include="TechTreeData.h" />
159+
<ClInclude Include="TechTreeDesign.h" />
158160
<ClInclude Include="TechTreeElement.h" />
159161
<ClInclude Include="TechTreeRenderer.h" />
160162
<ClInclude Include="TechTreeWindow.h" />

‎TechTree/TechTree.vcxproj.filters‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@
126126
<ClCompile Include="ResearchDataItem.cpp">
127127
<Filter>Quelldateien</Filter>
128128
</ClCompile>
129+
<ClCompile Include="TechTreeDesign.cpp">
130+
<Filter>Quelldateien</Filter>
131+
</ClCompile>
129132
</ItemGroup>
130133
<ItemGroup>
131134
<ClInclude Include="functions.h">
@@ -245,5 +248,8 @@
245248
<ClInclude Include="DrawUtilities.h">
246249
<Filter>Headerdateien</Filter>
247250
</ClInclude>
251+
<ClInclude Include="TechTreeDesign.h">
252+
<Filter>Headerdateien</Filter>
253+
</ClInclude>
248254
</ItemGroup>
249255
</Project>

‎TechTree/TechTreeData.cpp‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@
44
#define CLASS TechTreeData
55
#include "TechTreeData.h"
66

7+
// C++ string class
8+
#include <string>
9+
10+
711
/* STATIC WRAPPER FUNCTIONS */
812

913
STATIC_WRAPPER(Constructor, void, int)
1014
STATIC_WRAPPER(Destructor, void)
1115

16+
1217
/* FUNCTIONS */
1318

1419
// Set static data object
@@ -34,7 +39,8 @@ void TechTreeData::__Install()
3439
INSTALL_WRAPPER_DIRECT(Constructor, 0x004268ED);
3540

3641
// Patch version number (no page protection change needed)
37-
*reinterpret_cast<char *>(0x0066B15A) = 'T';
42+
// NOTE: Replaced by special marker string after regular tech tree data to maintain compability with unpatched game versions
43+
//*reinterpret_cast<char *>(0x0066B15A) = 'T';
3844

3945
// Install destructor (overwrite VTable address assignment as that isn't neccessary)
4046
BYTE patch2[] =
@@ -55,11 +61,26 @@ TechTreeData::TechTreeData(int datFileHandle)
5561
// -> dataBufferSize: The size of the data buffer.
5662
int(__cdecl *ReadDataFromCompressedFile)(int fileHandle, char *dataBuffer, unsigned int dataBufferSize) = reinterpret_cast<int(__cdecl *)(int, char *, unsigned int)>(0x00542850);
5763

64+
// Read version marker
65+
char techTreeVersionMarker[5];
66+
ReadDataFromCompressedFile(datFileHandle, techTreeVersionMarker, 4);
67+
techTreeVersionMarker[4] = '\0';
68+
if(std::string("NTT1").compare(techTreeVersionMarker) != 0)
69+
{
70+
// Malformed data file, exit process with error message and let the OS do the cleanup (the game would have crashed anyway...)
71+
std::string errorMessage = "Invalid tech tree version marker (expected NTT1): ";
72+
MessageBoxA(NULL, (errorMessage + techTreeVersionMarker).c_str(), "Error reading DAT file", MB_OK | MB_ICONERROR);
73+
ExitProcess(1);
74+
}
75+
5876
// Read root elements
5977
short rootElementCount;
6078
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&rootElementCount), 2);
6179
for(int i = 0; i < rootElementCount; ++i)
6280
_rootElements.push_back(new TechTreeElement(datFileHandle, nullptr));
81+
82+
// Read design
83+
_design = new TechTreeDesign(datFileHandle);
6384
}
6485

6586
void TechTreeData::Constructor(int datFileHandle)
@@ -95,4 +116,10 @@ const std::vector<TechTreeElement *> &TechTreeData::GetRootElements()
95116
{
96117
// Return root elements
97118
return _rootElements;
119+
}
120+
121+
const TechTreeDesign *TechTreeData::GetDesignData()
122+
{
123+
// Return design data
124+
return _design;
98125
}

‎TechTree/TechTreeData.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
// Other includes
99
#include "TechTreeElement.h"
10+
#include "TechTreeDesign.h"
1011
#include <vector>
1112

1213
/* DEFINITIONS */
@@ -21,6 +22,9 @@ class TechTreeData : GameType
2122
// The root elements of the tech tree.
2223
std::vector<TechTreeElement *> _rootElements;
2324

25+
// The design data of the tech tree.
26+
TechTreeDesign *_design;
27+
2428
public:
2529
// Hide base class install function.
2630
static void __Install();
@@ -43,6 +47,9 @@ class TechTreeData : GameType
4347

4448
// Returns the root elements of the tech tree.
4549
const std::vector<TechTreeElement *> &GetRootElements();
50+
51+
// Returns the design data of the tech tree.
52+
const TechTreeDesign *GetDesignData();
4653
};
4754

4855
// The data of the new tech tree. This variable is initialized when the game data is loaded, else its value is nullptr.

‎TechTree/TechTreeDesign.cpp‎

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/* INCLUDES */
2+
3+
// Class header
4+
#include "TechTreeDesign.h"
5+
6+
// Other includes
7+
#include <algorithm>
8+
#include "Game.h"
9+
#include <mbstring.h>
10+
11+
/* DEFINITIONS */
12+
13+
// The DAT read function. Defined in TechTreeElement.cpp.
14+
extern int(__cdecl *ReadDataFromCompressedFile)(int fileHandle, char *dataBuffer, unsigned int dataBufferSize);
15+
16+
/* FUNCTIONS */
17+
18+
TechTreeDesign::TechTreeDesign(int datFileHandle)
19+
{
20+
// Read SLPs
21+
int len;
22+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
23+
_nodeSlpFileName = new char[len + 1];
24+
ReadDataFromCompressedFile(datFileHandle, _nodeSlpFileName, len);
25+
_nodeSlpFileName[len] = '\0';
26+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_nodeSlpId), 4);
27+
28+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
29+
_scrollSlpFileName = new char[len + 1];
30+
ReadDataFromCompressedFile(datFileHandle, _scrollSlpFileName, len);
31+
_scrollSlpFileName[len] = '\0';
32+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollSlpId), 4);
33+
34+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
35+
_tileSlpFileName = new char[len + 1];
36+
ReadDataFromCompressedFile(datFileHandle, _tileSlpFileName, len);
37+
_tileSlpFileName[len] = '\0';
38+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_tileSlpId), 4);
39+
40+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
41+
_legendAgesSlpFileName = new char[len + 1];
42+
ReadDataFromCompressedFile(datFileHandle, _legendAgesSlpFileName, len);
43+
_legendAgesSlpFileName[len] = '\0';
44+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendAgesSlpId), 4);
45+
46+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
47+
_legendDisableSlpFileName = new char[len + 1];
48+
ReadDataFromCompressedFile(datFileHandle, _legendDisableSlpFileName, len);
49+
_legendDisableSlpFileName[len] = '\0';
50+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendDisableSlpId), 4);
51+
52+
// Read scroll data
53+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_mouseScrollArea), 4);
54+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_mouseScrollDelay), 4);
55+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_mouseScrollOffset), 4);
56+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_keyScrollOffset), 4);
57+
58+
// Read button rectangles
59+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_closeButtonRelativeRectangle.X), 4);
60+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_closeButtonRelativeRectangle.Y), 4);
61+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_closeButtonRelativeRectangle.Width), 4);
62+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_closeButtonRelativeRectangle.Height), 4);
63+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollLeftButtonRelativeRectangle.X), 4);
64+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollLeftButtonRelativeRectangle.Y), 4);
65+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollLeftButtonRelativeRectangle.Width), 4);
66+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollLeftButtonRelativeRectangle.Height), 4);
67+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollRightButtonRelativeRectangle.X), 4);
68+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollRightButtonRelativeRectangle.Y), 4);
69+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollRightButtonRelativeRectangle.Width), 4);
70+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_scrollRightButtonRelativeRectangle.Height), 4);
71+
72+
// Read resolution data
73+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
74+
for(int i = 0; i < len; ++i)
75+
{
76+
// Read minimum height
77+
int minHeight;
78+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&minHeight), 4);
79+
80+
// Read data and store results in local map
81+
_resolutionData[minHeight] = new ResolutionConfiguration(datFileHandle);
82+
}
83+
84+
// Read popup data
85+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_popupLabelDelay), 4);
86+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_popupLabelWidth), 4);
87+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_popupInnerPadding), 4);
88+
89+
// Read popup bevel data
90+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(_popupBoxBevelColorIndices), 6);
91+
92+
// Read remaining data
93+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_nodeFontIndex), 1);
94+
}
95+
96+
TechTreeDesign::~TechTreeDesign()
97+
{
98+
// Delete strings
99+
delete[] _nodeSlpFileName;
100+
delete[] _scrollSlpFileName;
101+
delete[] _tileSlpFileName;
102+
delete[] _legendAgesSlpFileName;
103+
delete[] _legendDisableSlpFileName;
104+
105+
// Delete resolution list
106+
for(auto &rc : _resolutionData)
107+
delete rc.second;
108+
}
109+
110+
TechTreeDesign::ResolutionConfiguration::ResolutionConfiguration(int datFileHandle)
111+
{
112+
// Read values
113+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendFrameIndex), 4);
114+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_ageFrameIndex), 4);
115+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_tileFrameIndex), 4);
116+
117+
// Read point
118+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendDisableSlpDrawPosition.X), 4);
119+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendDisableSlpDrawPosition.Y), 4);
120+
121+
// Read rectangles
122+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civBonusLabelRectangle.X), 4);
123+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civBonusLabelRectangle.Y), 4);
124+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civBonusLabelRectangle.Width), 4);
125+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civBonusLabelRectangle.Height), 4);
126+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionComboBoxRectangle.X), 4);
127+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionComboBoxRectangle.Y), 4);
128+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionComboBoxRectangle.Width), 4);
129+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionComboBoxRectangle.Height), 4);
130+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionTitleLabelRectangle.X), 4);
131+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionTitleLabelRectangle.Y), 4);
132+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionTitleLabelRectangle.Width), 4);
133+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_civSelectionTitleLabelRectangle.Height), 4);
134+
135+
// Read rectangles
136+
for(int i = 0; i < 6; ++i)
137+
{
138+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendLabelRectangles[i].X), 4);
139+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendLabelRectangles[i].Y), 4);
140+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendLabelRectangles[i].Width), 4);
141+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_legendLabelRectangles[i].Height), 4);
142+
}
143+
144+
// Read rectangles
145+
int len;
146+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
147+
for(int i = 0; i < len; ++i)
148+
{
149+
Rect aLR;
150+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&aLR.X), 4);
151+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&aLR.Y), 4);
152+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&aLR.Width), 4);
153+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&aLR.Height), 4);
154+
_ageLabelRectangles.push_back(aLR);
155+
}
156+
157+
// Read draw offsets
158+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
159+
for(int i = 0; i < len; ++i)
160+
{
161+
int vDO;
162+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&vDO), 4);
163+
_verticalDrawOffsets.push_back(vDO);
164+
}
165+
}
166+
167+
TechTreeDesign::ResolutionConfiguration::~ResolutionConfiguration()
168+
{
169+
// Nothing to do here
170+
}

0 commit comments

Comments
 (0)