TechTreeWindow *TechTreeWindow::Constructor(Window *underlyingWindow, int unknownGameAndPlayerData, int selectedCivId) { // Needed for window management and proper cleanup in other places base::Constructor("One Button Tech Tree Screen"); // Save underlying window _underlyingWindow = underlyingWindow; // Save game data _unknownGameAndPlayerData = unknownGameAndPlayerData; // Set virtual function table address _VTable = reinterpret_cast<ControlVTable *>(0x00645118); // Cast virtual function table to be able to access all functions PanelVTable *vTable = static_cast<PanelVTable *>(_VTable); // Get design data _designData = _staticNewTechTreeDataObject->GetDesignData(); // Load style file DirectDrawBufferData *backBuffer = underlyingWindow->_VTable->GetBackBufferData(underlyingWindow); if(!PrepareParentWindowAndLoadStyleData(backBuffer, "scr6", 50007, 1)) _initializationError = 1; // Start with top left corner _horizontalScrollOffset = 0; _verticalScrollOffset = 0; _lastScrollActionTime = 0; // Create vanilla style tech tree renderer // TODO: May be changed to allow various renderers using completely different layout approaches _renderer = new VanillaTechTreeRenderer((*_staticGameObjectPointer)->GetGameDataHandler(), Size(_width1, _height1), unknownGameAndPlayerData); // Get the renderer's age count _ageCount = _renderer->GetAgeCount(); // Create close button and its buffer static_cast<PanelVTable *>(_VTable)->CreateButtonWithOneFontWithTextFromDll(this, this, &_closeButton, 20101, 0, _width1 - _designData->_closeButtonRelativeRectangle.X, _height1 - _designData->_closeButtonRelativeRectangle.Y, _designData->_closeButtonRelativeRectangle.Width, _designData->_closeButtonRelativeRectangle.Height, 9, 0, 0); _closeButton->_VTable->InvalidateAndRedrawControl1(_closeButton, 1); _closeButton->AssignIdToControlAndMoveInParentChildrenList(1, 0); _closeButton->SetHotKey(VK_ESCAPE, 0, 0, 0); _closeButtonDrawBuffer = new DirectDrawBufferData("TechTree Close Button Buffer", 1); _closeButtonDrawBuffer->InsertIntoBufferListAndCreateSurfaceAndDoUnknownStuff(_backBufferData->GetDirectDrawHandler(), _designData->_closeButtonRelativeRectangle.Width, _designData->_closeButtonRelativeRectangle.Height, 0, 0); _closeButtonDrawBuffer->sub_5A30A0(0, 0, _designData->_closeButtonRelativeRectangle.Width, _designData->_closeButtonRelativeRectangle.Height); UpdateSelectedSubControl(_closeButton); // Create scroll buttons and their buffers static_cast<PanelVTable *>(_VTable)->CreateButton(this, this, &_scrollLeftButton, "<-", 0, _width1 - _designData->_scrollLeftButtonRelativeRectangle.X, _height1 - _designData->_scrollLeftButtonRelativeRectangle.Y, _designData->_scrollLeftButtonRelativeRectangle.Width, _designData->_scrollLeftButtonRelativeRectangle.Height, 9, 0, 0); _scrollLeftButton->_VTable->InvalidateAndRedrawControl1(_scrollLeftButton, 1); _scrollLeftButton->AssignIdToControlAndMoveInParentChildrenList(1, 0); _scrollLeftButtonDrawBuffer = new DirectDrawBufferData("TechTree ScrollLeft Button Buffer", 1); _scrollLeftButtonDrawBuffer->InsertIntoBufferListAndCreateSurfaceAndDoUnknownStuff(_backBufferData->GetDirectDrawHandler(), _designData->_scrollLeftButtonRelativeRectangle.Width, _designData->_scrollLeftButtonRelativeRectangle.Height, 0, 0); _scrollLeftButtonDrawBuffer->sub_5A30A0(0, 0, _designData->_scrollLeftButtonRelativeRectangle.Width, _designData->_scrollLeftButtonRelativeRectangle.Height); static_cast<PanelVTable *>(_VTable)->CreateButton(this, this, &_scrollRightButton, "->", 0, _width1 - _designData->_scrollRightButtonRelativeRectangle.X, _height1 - _designData->_scrollRightButtonRelativeRectangle.Y, _designData->_scrollRightButtonRelativeRectangle.Width, _designData->_scrollRightButtonRelativeRectangle.Height, 9, 0, 0); _scrollRightButton->_VTable->InvalidateAndRedrawControl1(_scrollRightButton, 1); _scrollRightButton->AssignIdToControlAndMoveInParentChildrenList(1, 0); _scrollRightButtonDrawBuffer = new DirectDrawBufferData("TechTree ScrollRight Button Buffer", 1); _scrollRightButtonDrawBuffer->InsertIntoBufferListAndCreateSurfaceAndDoUnknownStuff(_backBufferData->GetDirectDrawHandler(), _designData->_scrollRightButtonRelativeRectangle.Width, _designData->_scrollRightButtonRelativeRectangle.Height, 0, 0); _scrollRightButtonDrawBuffer->sub_5A30A0(0, 0, _designData->_scrollRightButtonRelativeRectangle.Width, _designData->_scrollRightButtonRelativeRectangle.Height); // Load arrow SLP for scroll buttons and assign frames to them _arrowSlp = new SlpFileElement(_designData->_scrollSlpFileName, _designData->_scrollSlpId); _scrollLeftButton->SetBackgroundSlpAtIndex(0, _arrowSlp, 1); _scrollLeftButton->SetDisplayMode(9); _scrollLeftButton->AssignLabelString(0, ""); _scrollRightButton->SetBackgroundSlpAtIndex(0, _arrowSlp, 0); _scrollRightButton->SetDisplayMode(9); _scrollRightButton->AssignLabelString(0, ""); // Create civ bonus label /*static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, &_civBonusLabel, 0, 2, 20, 100, 20, 10, 0, 0, 1); _civBonusLabel->_VTable->InvalidateAndRedrawControl1(_civBonusLabel, 0); _civBonusLabel->AssignIdToControlAndMoveInParentChildrenList(1, 0); _civBonusLabel->SetStyleText2Colors(0, 0); _civBonusLabel->sub_545D70(0);*/ FontData *civBonusLabelBaseFont = (*_staticGameObjectPointer)->GetFontWithIndex(10); HFONT civBonusLabelFonts[4]; civBonusLabelFonts[0] = civBonusLabelBaseFont->GetFontHandle(); civBonusLabelFonts[1] = (*_staticGameObjectPointer)->GetFontWithIndex(17)->GetFontHandle(); civBonusLabelFonts[2] = (*_staticGameObjectPointer)->GetFontWithIndex(18)->GetFontHandle(); civBonusLabelFonts[3] = (*_staticGameObjectPointer)->GetFontWithIndex(19)->GetFontHandle(); _civBonusLabel = new LabelControl(); _civBonusLabel->sub_5444B0(_backBufferData, this, 2, 20, 100, 20, civBonusLabelFonts, civBonusLabelBaseFont->GetAverageCharWidth(), civBonusLabelBaseFont->GetCharHeightWithRowSpace(), nullptr, 0, 0, 0, 0, 0, nullptr); _civBonusLabel->SetTextAlignment(3, 1); _civBonusLabel->sub_545D50(1); _civBonusLabel->sub_545D70(0); _civBonusLabel->SetStyleText2Colors(0x000000, 0x00E7E7); // Create civ selection combo box static_cast<PanelVTable *>(_VTable)->CreateComboBox(this, this, &_civSelectionComboBox, 230, 0, 2, 20, 200, 25, 10); _civSelectionComboBox->_VTable->InvalidateAndRedrawControl1(_civSelectionComboBox, 1); _civSelectionComboBox->SetDropDownListSortingMode(1); _civSelectionComboBox->AssignIdToControlAndMoveInParentChildrenList(1, 1); _civSelectionComboBox->SetStyleText2Colors(0, 0); _civSelectionComboBox->GetDropDownScrollBar()->SetFillBackground(-1); _civSelectionComboBox->GetValueLabel()->SetBackgroundSlp("tech_tile.slp", 50343); _civSelectionComboBox->GetDropDownList()->SetBackgroundSlp("tech_tile.slp", 50343); // Create "game civs" label static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, &_gameCivsLabel, 0, 2, 20, 200, 25, 10, 0, 0, 1); _gameCivsLabel->_VTable->InvalidateAndRedrawControl1(_gameCivsLabel, 0); _gameCivsLabel->AssignIdToControlAndMoveInParentChildrenList(1, 0); _gameCivsLabel->SetStyleText2Colors(0, 0); _gameCivsLabel->sub_545D70(0); static_cast<LabelControlVTable *>(_gameCivsLabel->_VTable)->AssignTextFromLanguageDlls(_gameCivsLabel, 20125); // Create "Not researched" label static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, &_legendNotResearchedLabel, 0, 2, 2, 160, 25, 13, 0, 0, 0); _legendNotResearchedLabel->_VTable->InvalidateAndRedrawControl1(_legendNotResearchedLabel, 0); _legendNotResearchedLabel->AssignIdToControlAndMoveInParentChildrenList(1, 0); _legendNotResearchedLabel->SetStyleText2Colors(0, 0); _legendNotResearchedLabel->sub_545D70(0); static_cast<LabelControlVTable *>(_legendNotResearchedLabel->_VTable)->AssignTextFromLanguageDlls(_legendNotResearchedLabel, 20124); // Create "Researched" label static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, &_legendResearchedLabel, 0, 2, 2, 160, 25, 13, 0, 0, 0); _legendResearchedLabel->_VTable->InvalidateAndRedrawControl1(_legendResearchedLabel, 0); _legendResearchedLabel->AssignIdToControlAndMoveInParentChildrenList(1, 0); _legendResearchedLabel->SetStyleText2Colors(0, 0); _legendResearchedLabel->sub_545D70(0); static_cast<LabelControlVTable *>(_legendResearchedLabel->_VTable)->AssignTextFromLanguageDlls(_legendResearchedLabel, 20128); // Create node type labels _legendNodeTypeLabels = new std::vector<LabelControl *>(); int nodeTypeLabelCount = _renderer->GetLegendNodeTypeCount(); for(int i = 0; i < nodeTypeLabelCount; ++i) { // Create label LabelControl *legendNodeTypeLabel; static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, &legendNodeTypeLabel, 0, 2, 2, 160, 25, 13, 0, 0, 0); legendNodeTypeLabel->_VTable->InvalidateAndRedrawControl1(legendNodeTypeLabel, 0); legendNodeTypeLabel->AssignIdToControlAndMoveInParentChildrenList(1, 0); legendNodeTypeLabel->SetStyleText2Colors(0, 0); legendNodeTypeLabel->sub_545D70(0); static_cast<LabelControlVTable *>(legendNodeTypeLabel->_VTable)->AssignTextFromLanguageDlls(legendNodeTypeLabel, _renderer->GetLegendNodeTypeLabelDllId(i)); _legendNodeTypeLabels->push_back(legendNodeTypeLabel); } // Create "Disabled" label static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, &_legendDisabledLabel, 0, 2, 2, 160, 25, 13, 0, 0, 0); _legendDisabledLabel->_VTable->InvalidateAndRedrawControl1(_legendDisabledLabel, 0); _legendDisabledLabel->AssignIdToControlAndMoveInParentChildrenList(1, 0); _legendDisabledLabel->SetStyleText2Colors(0, 0); _legendDisabledLabel->sub_545D70(0); static_cast<LabelControlVTable *>(_legendDisabledLabel->_VTable)->AssignTextFromLanguageDlls(_legendDisabledLabel, 20119); // Fill civ selection combo box int civCount = (*_staticGameObjectPointer)->GetGameDataHandler()->_civCount; char civNameBuffer[128]; char civNameSuffixBuffer[128]; char civNameMergedBuffer[256]; for(int c = 1; c < civCount; ++c) { // Clear strings civNameBuffer[0] = '\0'; civNameSuffixBuffer[0] = '\0'; civNameMergedBuffer[0] = '\0'; // Load civ name (*_staticGameObjectPointer)->GetIndexedDllString(105, c, 0, civNameBuffer, sizeof(civNameBuffer)); // Load civ suffix " (Player)" or " (Ally)", if neccessary if(_unknownGameAndPlayerData != 0) if(reinterpret_cast<char *>(_unknownGameAndPlayerData)[349] == c) // Check player (*_staticGameObjectPointer)->GetStringFromLanguageDllsWithBuffer(20126, civNameSuffixBuffer, sizeof(civNameSuffixBuffer)); else { // Check allies GameDataHandler *gdh = (*_staticGameObjectPointer)->GetGameDataHandler(); for(int p = 1; p < 9; ++p) if(reinterpret_cast<char *>(_unknownGameAndPlayerData + 6458)[p] == 4 && reinterpret_cast<char *>(gdh->_dword4C[p])[349] == c) { // Get suffix and break (*_staticGameObjectPointer)->GetStringFromLanguageDllsWithBuffer(20127, civNameSuffixBuffer, sizeof(civNameSuffixBuffer)); break; } } // Merge civ name and suffix sprintf(civNameMergedBuffer, "%s%s", civNameBuffer, civNameSuffixBuffer); // Add civ to list _civSelectionComboBox->AddItem(civNameMergedBuffer, c); } _civSelectionComboBox->SetSelectedIndex(0); // Create age labels _ageLabels = new LabelControl*[_ageCount][2][2]; for(int i = 0; i < _ageCount; ++i) { // Create 4 labels for this age for(int j = 0; j < 4; ++j) { // Create and initialize label LabelControl **currAgeLabelPointer = &_ageLabels[i][j >> 1][j & 1]; static_cast<PanelVTable *>(_VTable)->CreateLabelWithOneFontWithTextFromDll(this, this, currAgeLabelPointer, 0, 2, 2, 150, 25, 11, 1, 0, 1); (*currAgeLabelPointer)->_VTable->InvalidateAndRedrawControl1(*currAgeLabelPointer, 0); (*currAgeLabelPointer)->AssignIdToControlAndMoveInParentChildrenList(1, 0); (*currAgeLabelPointer)->SetStyleText2Colors(0, 0); (*currAgeLabelPointer)->sub_545D70(0); } // Set label texts static_cast<LabelControlVTable *>(_ageLabels[i][0][0]->_VTable)->AssignTextFromLanguageDlls(_ageLabels[i][0][0], _designData->_firstLineBaseDllId + i); static_cast<LabelControlVTable *>(_ageLabels[i][0][1]->_VTable)->AssignTextFromLanguageDlls(_ageLabels[i][0][1], _designData->_secondLineDllId + (_designData->_incrementSecondLineDllId ? i : 0)); static_cast<LabelControlVTable *>(_ageLabels[i][1][0]->_VTable)->AssignTextFromLanguageDlls(_ageLabels[i][1][0], _designData->_firstLineBaseDllId + i); static_cast<LabelControlVTable *>(_ageLabels[i][1][1]->_VTable)->AssignTextFromLanguageDlls(_ageLabels[i][1][1], _designData->_secondLineDllId + (_designData->_incrementSecondLineDllId ? i : 0)); } // Create popup label _popupLabelBaseFont = (*_staticGameObjectPointer)->GetFontWithIndex(10); HFONT popupLabelFonts[4]; popupLabelFonts[0] = _popupLabelBaseFont->GetFontHandle(); popupLabelFonts[1] = (*_staticGameObjectPointer)->GetFontWithIndex(17)->GetFontHandle(); popupLabelFonts[2] = (*_staticGameObjectPointer)->GetFontWithIndex(18)->GetFontHandle(); popupLabelFonts[3] = (*_staticGameObjectPointer)->GetFontWithIndex(19)->GetFontHandle(); _popupLabel = new LabelControl(); _popupLabel->sub_5444B0(_backBufferData, this, 0, 0, _designData->_popupLabelWidth, 50, popupLabelFonts, _popupLabelBaseFont->GetAverageCharWidth(), _popupLabelBaseFont->GetCharHeightWithRowSpace(), nullptr, 0, 0, 0, 0, 0, nullptr); _popupLabel->SetTextAlignment(3, 1); _popupLabel->sub_545D50(1); _popupLabel->sub_545D70(0); _popupLabel->SetStyleText2Colors(0x000000, 0x00E7E7); // Set current civ if(unknownGameAndPlayerData != 0) selectedCivId = reinterpret_cast<char *>(unknownGameAndPlayerData)[349]; if(selectedCivId < 1) selectedCivId = 1; _civSelectionComboBox->SetSelectedItemId(selectedCivId); SetCurrentCiv(selectedCivId); // No element is selected _selectedElement = nullptr; _drawPopupLabelBox = false; _selectedElementChangedTime = 0; // Issue redraw _VTable->InvalidateAndRedrawControl2(this, 2); // Return reference to self return this; }