Skip to content

Commit ef5c512

Browse files
committed
Completed support of custom node backgrounds
1 parent ef7c5bf commit ef5c512

12 files changed

Lines changed: 102 additions & 89 deletions

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Thumbs.db
2525
*.lib
2626
*.sbr
2727
obj/
28+
.vs/
2829
[Rr]elease*/
2930
_ReSharper*/
3031
[Tt]est[Rr]esult*

‎AoKHBlacksmith.txt‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ A modded sample empires2_x1_p1.dat is in the "DATA" folder. "Editor" contains a
3434
[b]Requirements[/b]
3535
The tech tree view itself was built with Microsoft Visual Studio 2015, so you'll need [url=https://www.microsoft.com/de-de/download/details.aspx?id=48145]the appropiate Visual C++ redistributable[/url].
3636

37-
The editor depends on the .NET Framework 4.0. It should already be installed on current windows systems; if not, you can find it [url=https://www.microsoft.com/en-us/download/details.aspx?id=17718]here[/url].
37+
The editor depends on the .NET Framework 4.5. It should already be installed on current windows systems; if not, you can find it [url=https://www.microsoft.com/en-us/download/details.aspx?id=30653]here[/url].
3838

3939
To find out if all requirements are installed just start the programs, they will tell you when some dependencies are not found.
4040

@@ -45,5 +45,16 @@ This software is published under the MIT/X11 license. Please read the LICENSE fo
4545

4646
[b]Updates[/b]
4747

48+
[u]1.2.0[/u]
49+
- Added support for custom tree element backgrounds
50+
- Upgraded editor to .NET 4.5
51+
52+
[u]1.1.1[/u]
53+
View:
54+
- Fixed crash when switching civs in the tech tree view
55+
- Removed leftover vertical line below elements with hidden children
56+
Editor:
57+
- Fixed a few crashes when copying, pasting, moving and deleting nodes
58+
4859
[u]1.1.0[/u]
49-
Implemented customizable designs and tree compression.
60+
Implemented customizable designs and tree compression

‎LICENSE‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2015-2016 Jan Wichelmann
3+
Copyright (c) 2015-2017 Jan Wichelmann
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

‎README.md‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ As a consequence, the DAT tech tree structure used by this implementation is inc
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

11+
I created this software while working on the (german) Agearena AddOn (http://www.agearena.de/forum/index.php?mode=viewforum&forum_id=7) and will update it periodically.
12+
1113

1214
## USAGE
1315

1416
Unpack the EXE and DLL files to the age2_x1 folder of Age of Empires II. If you haven't already created a custom empires2_x1_p1.dat with the new tech tree, you can unpack the empires2_x1_p1.dat of the archive into the DATA folder, replacing the old one (do not forget a backup!).
1517

1618
The launcher starts the age2_x1.exe process and injects the TechTree.dll containing the code changes to add a new age.
17-
I created this software while working on the (german) Agearena AddOn (http://www.agearena.de/forum/index.php?mode=viewforum&forum_id=7) and will update it periodically.
1819

1920
> AoETechTree.exe PARAMS
2021
@@ -30,12 +31,7 @@ As this software is build with Microsoft Visual Studio 2015, you'll need the app
3031

3132
This software was tested with the UserPatch v1.4 installed, so there should be no incompabilities.
3233

33-
Also some virus scanners may have problems with this software, as it uses DLL injection to patch the running Age of Empires II process. This method is also used by many viruses, so some virus scanners block it by default. If you have problems running this software, try to create an exception in the scanners filter rules.
34-
35-
36-
## TODO
37-
38-
* Add another renderer that is easier moddable and less hardcoded than the vanilla one in terms of age count, resolution and background images.
34+
Also some virus scanners may have problems with this software, as it uses DLL injection to patch the running Age of Empires II process. This method is also used by many viruses, so some virus scanners block it by default. If you have problems running this software, try to create an exception in the scanner's filter rules.
3935

4036

4137
## LEGAL INFO & CREDITS

‎TechTree/TechTree.cpp‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,40 @@
1616
// Override new operator with game new operator.
1717
void *operator new(unsigned int size)
1818
{
19+
// Debug code for buffer overflow detection
20+
// Puts two large 256 marker byte chunks before and after the allocated memory, which are then checked on deallocation.
21+
// This will likely crash the game when destructing some controls, because the game destructor doesn't call the modified delete[] operator.
22+
// But as long as one doesn't close the tech tree window, these lines shouldn't cause any further problems.
23+
/*void *mem = ((void *(__cdecl *)(unsigned int))0x006137B0)(4 + 256 + size + 256 + 1);
24+
reinterpret_cast<int *>(mem)[0] = size;
25+
for(int i = 0; i < 256; ++i)
26+
reinterpret_cast<unsigned char *>(mem)[4 + i] = 0xF0;
27+
for(int i = 0; i < 256; ++i)
28+
reinterpret_cast<unsigned char *>(mem)[4 + 256 + size + i] = 0xF1;
29+
reinterpret_cast<unsigned char *>(mem)[4 + 256 + size + 256] = 0x00; // Deleted flag
30+
return (void*)((int)mem + 4 + 256);*/
31+
1932
// Call game new
2033
return ((void *(__cdecl *)(unsigned int))0x006137B0)(size);
2134
}
2235

2336
// Override delete operator with game delete operator.
2437
void operator delete(void *ptr)
2538
{
39+
// Debug code for buffer overflow detection
40+
/*void *mem = (void *)((int)ptr - 4 - 256);
41+
int size = ((int *)mem)[0];
42+
for(int i = 0; i < 256; ++i)
43+
if(reinterpret_cast<unsigned char *>(mem)[4 + i] != 0xF0)
44+
__asm int 3;
45+
for(int i = 0; i < 256; ++i)
46+
if(reinterpret_cast<unsigned char *>(mem)[4 + 256 + size + i] != 0xF1)
47+
__asm int 3;
48+
if(reinterpret_cast<unsigned char *>(mem)[4 + 256 + size + 256] != 0x00)
49+
__asm int 3;
50+
reinterpret_cast<unsigned char *>(mem)[4 + 256 + size + 256] = 0x01;
51+
((void(__cdecl *)(void *))0x006137BE)(mem);*/
52+
2653
// Call game delete
2754
((void(__cdecl *)(void *))0x006137BE)(ptr);
2855
}

‎TechTree/TechTreeData.cpp‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ void TechTreeData::__Install()
3838
CopyBytesToAddr(0x004268DD, patch1, sizeof(patch1));
3939
INSTALL_WRAPPER_DIRECT(Constructor, 0x004268ED);
4040

41-
// Patch version number (no page protection change needed)
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';
44-
4541
// Install destructor (overwrite VTable address assignment as that isn't neccessary)
4642
BYTE patch2[] =
4743
{
@@ -61,15 +57,18 @@ TechTreeData::TechTreeData(int datFileHandle)
6157
// -> dataBufferSize: The size of the data buffer.
6258
int(__cdecl *ReadDataFromCompressedFile)(int fileHandle, char *dataBuffer, unsigned int dataBufferSize) = reinterpret_cast<int(__cdecl *)(int, char *, unsigned int)>(0x00542850);
6359

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)
60+
// Read marker
61+
const unsigned char TECH_TREE_VERSION = 1;
62+
char techTreeMarker[4];
63+
unsigned char techTreeVersion;
64+
ReadDataFromCompressedFile(datFileHandle, techTreeMarker, 3);
65+
techTreeMarker[3] = '\0';
66+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&techTreeVersion), 1);
67+
if(std::string("NTT").compare(techTreeMarker) != 0 || techTreeVersion != TECH_TREE_VERSION)
6968
{
7069
// 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);
70+
std::string errorMessage = "Invalid tech tree marker (expected NTT, version " + std::to_string(TECH_TREE_VERSION) + "): " + techTreeMarker + ", version " + std::to_string(techTreeVersion);
71+
MessageBoxA(NULL, errorMessage.c_str(), "Error reading DAT file", MB_OK | MB_ICONERROR);
7372
ExitProcess(1);
7473
}
7574

‎TechTree/TechTreeDesign.cpp‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,23 @@ TechTreeDesign::TechTreeDesign(int datFileHandle)
8989
// Read popup bevel data
9090
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(_popupBoxBevelColorIndices), 6);
9191

92-
// Read remaining data
92+
// Read node data
9393
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_nodeFontIndex), 1);
94+
int nodeBackgroundCount;
95+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&nodeBackgroundCount), 4);
96+
for(int i = 0; i < nodeBackgroundCount; i++)
97+
{
98+
// Read and discard name
99+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&len), 4);
100+
char *garbage = new char[len];
101+
ReadDataFromCompressedFile(datFileHandle, garbage, len);
102+
delete[] garbage;
103+
104+
// Read and save frame index
105+
int frameIndex;
106+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&frameIndex), 4);
107+
_nodeBackgrounds.push_back(frameIndex);
108+
}
94109
}
95110

96111
TechTreeDesign::~TechTreeDesign()

‎TechTree/TechTreeDesign.h‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,13 @@ class TechTreeDesign
131131
// The bevel (border) colors of the popup box.
132132
unsigned char _popupBoxBevelColorIndices[6];
133133

134-
// The Index
134+
// The font index of the tree node labels.
135135
unsigned char _nodeFontIndex;
136136

137+
// The different node backgrounds; here only the frame indices for the node SLP are needed.
138+
// The first three indices match the TechTreeElement::ItemType members, so each node type has a default background design.
139+
std::vector<int> _nodeBackgrounds;
140+
137141
public:
138142
// Constructor. Reads the tech tree element data from the given DAT file handle.
139143
// Parameters:

‎TechTree/TechTreeElement.cpp‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,17 @@ TechTreeElement::TechTreeElement(int datFileHandle, TechTreeElement *parentBuild
4545
short childElementCount;
4646
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&childElementCount), 2);
4747
for(int i = 0; i < childElementCount; ++i)
48-
_children.push_back(new TechTreeElement(datFileHandle, ((_elementType == ItemType::Building || _elementType == ItemType::UniqueBuilding || _elementType == ItemType::SupportBuilding) ? this : parentBuilding)));
48+
_children.push_back(new TechTreeElement(datFileHandle, (_elementType == ItemType::Building ? this : parentBuilding)));
4949

5050
// Read required elements
5151
short requiredCount;
5252
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&requiredCount), 2);
5353
for(int i = 0; i < requiredCount; ++i)
5454
_requiredElements.push_back(new RequiredElement(datFileHandle));
5555

56+
// Read background index
57+
ReadDataFromCompressedFile(datFileHandle, reinterpret_cast<char *>(&_backgroundIndex), 4);
58+
5659
// Initialize name variables
5760
_elementNameFirstLine[0] = '\0';
5861
_elementNameSecondLine[0] = '\0';
@@ -145,7 +148,7 @@ void TechTreeElement::UpdateRenderState(char selectedCivId, int unknownGameAndPl
145148

146149
// Calculate DLL index
147150
int dllIndex = -1;
148-
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable || (_elementType >= ItemType::UniqueUnit && _elementType <= ItemType::MercenaryUnit) || _elementType == ItemType::UniqueBuilding || _elementType == ItemType::SupportBuilding)
151+
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable)
149152
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_civs[selectedCivId]->_units[_elementObjectID]->_languageDllNameId + 9000;
150153
else if(_elementType == TechTreeElement::ItemType::Research)
151154
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_researches->_researches[_elementObjectID]._languageDLLName1 + 10000;
@@ -157,7 +160,7 @@ void TechTreeElement::UpdateRenderState(char selectedCivId, int unknownGameAndPl
157160
if(elementNameBuffer[0] == '\0')
158161
{
159162
// Determine ID
160-
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable || (_elementType >= ItemType::UniqueUnit && _elementType <= ItemType::MercenaryUnit) || _elementType == ItemType::UniqueBuilding || _elementType == ItemType::SupportBuilding)
163+
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable)
161164
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_civs[selectedCivId]->_units[_elementObjectID]->_languageDllNameId;
162165
else if(_elementType == TechTreeElement::ItemType::Research)
163166
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_researches->_researches[_elementObjectID]._languageDLLName1;
@@ -234,7 +237,7 @@ void TechTreeElement::RequiredElement::UpdateDisplayName(char selectedCivId)
234237

235238
// Calculate DLL index
236239
int dllIndex = -1;
237-
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable || (_elementType >= ItemType::UniqueUnit && _elementType <= ItemType::MercenaryUnit) || _elementType == ItemType::UniqueBuilding || _elementType == ItemType::SupportBuilding)
240+
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable)
238241
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_civs[selectedCivId]->_units[_elementObjectID]->_languageDllNameId + 9000;
239242
else if(_elementType == TechTreeElement::ItemType::Research)
240243
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_researches->_researches[_elementObjectID]._languageDLLName1 + 10000;
@@ -246,7 +249,7 @@ void TechTreeElement::RequiredElement::UpdateDisplayName(char selectedCivId)
246249
if(elementNameBuffer[0] == '\0')
247250
{
248251
// Determine ID
249-
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable || (_elementType >= ItemType::UniqueUnit && _elementType <= ItemType::MercenaryUnit) || _elementType == ItemType::UniqueBuilding || _elementType == ItemType::SupportBuilding)
252+
if(_elementType == TechTreeElement::ItemType::Building || _elementType == TechTreeElement::ItemType::Creatable)
250253
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_civs[selectedCivId]->_units[_elementObjectID]->_languageDllNameId;
251254
else if(_elementType == TechTreeElement::ItemType::Research)
252255
dllIndex = (*_staticGameObjectPointer)->GetGameDataHandler()->_researches->_researches[_elementObjectID]._languageDLLName1;

‎TechTree/TechTreeElement.h‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,7 @@ class TechTreeElement
2222
{
2323
Research = 0,
2424
Creatable = 1,
25-
Building = 2,
26-
UniqueUnit = 3,
27-
SupportUnit = 4,
28-
RaiderUnit = 5,
29-
MercenaryUnit = 6,
30-
UniqueBuilding = 7,
31-
SupportBuilding = 8
25+
Building = 2
3226
};
3327

3428
// The possible tech tree element render modes.
@@ -107,6 +101,9 @@ class TechTreeElement
107101
// The types and IDs of required elements. These don't need to be real tree elements.
108102
std::vector<RequiredElement *> _requiredElements;
109103

104+
// The element render background index.
105+
int _backgroundIndex;
106+
110107
// The element render position (precomputed for performance reasons).
111108
// This does not need to be a absolute pixel position; that depends on the renderer.
112109
Point _renderPosition;

0 commit comments

Comments
 (0)