Skip to content

Commit

Permalink
WIP mods menu
Browse files Browse the repository at this point in the history
  • Loading branch information
IonAgorria committed Sep 26, 2023
1 parent 48cfcb1 commit 25150ea
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 18 deletions.
29 changes: 27 additions & 2 deletions Source/Game/GameContent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace scripts_export {
#include "BelligerentSelect.h"
#include "qd_textdb.h"
#include "Localization.h"
#include "codepages/codepages.h"

#include <map>
#include <set>
Expand Down Expand Up @@ -601,11 +602,15 @@ void detectGameContent() {
data.mod_name = mod_ini.get("Mod", "name");
data.mod_version = mod_ini.get("Mod", "version");
if (data.mod_name.empty()) {
fprintf(stderr, "Missing name in Mod section at %s, not loading\n", path_ini.c_str());
data.available = false;
fprintf(stderr, "Missing name in Mod section at %s, not loading\n", path_ini.c_str());
data.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorMissingAttribute");
data.errors += " [Mod] name\n";
} else if (data.mod_version.empty()) {
fprintf(stderr, "Missing version in Mod section at %s, not loading\n", path_ini.c_str());
data.available = false;
fprintf(stderr, "Missing version in Mod section at %s, not loading\n", path_ini.c_str());
data.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorMissingAttribute");
data.errors += " [Mod] version\n";
}

//Load optional fields
Expand All @@ -617,6 +622,16 @@ void detectGameContent() {
if (data.mod_description.empty() && locale != "english") {
data.mod_description = mod_ini.get("Mod", "description_english");
}
if (!data.mod_description.empty()) {
data.mod_description = convertToCodepage(data.mod_description.c_str(), "english");
}
} else {
data.mod_description = convertToCodepage(data.mod_description.c_str(), locale);
}
if (!data.mod_description.empty()) {
string_replace_all(data.mod_description, "\\r", "");
string_replace_all(data.mod_description, "\\n", "\n");
string_replace_all(data.mod_description, "\\\\", "\\");
}
data.mod_authors = mod_ini.get("Mod", "authors");
data.mod_url = mod_ini.get("Mod", "url");
Expand All @@ -628,6 +643,8 @@ void detectGameContent() {
if (0 < diff) {
fprintf(stderr, "Minimum game version '%s' requirement not satisfied for %s, not loading\n",
data.content_game_minimum_version.c_str(), data.path.c_str());
data.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorGameTooOld");
data.errors += " " + data.content_game_minimum_version + "\n";
data.available = false;
}
}
Expand All @@ -646,6 +663,7 @@ void detectGameContent() {
data.mod_url = "https://kdlab.com";
} else {
fprintf(stderr, "Mod folder %s has missing info file %s, not loading\n", data.path.c_str(), path_ini.c_str());
data.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorMissingModInfo");
}

//Force disable all mods
Expand All @@ -656,6 +674,7 @@ void detectGameContent() {
//Avoid possible duplicates of ET
if (data.available && is_content_ET && (terGameContentAvailable & PERIMETER_ET)) {
fprintf(stderr, "ET is already loaded when loading ET content at %s, not loading", data.path.c_str());
data.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorDuplicateContent");
data.available = false;
}

Expand Down Expand Up @@ -693,9 +712,13 @@ void detectGameContent() {
if (!getMissingGameContent(terGameContentAvailable, required).empty()) {
fprintf(stderr, "Game content '%s' not installed which is a requirement for %s, not loading\n",
mod.content_required_content.c_str(), mod.path.c_str());
mod.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorRequiredContentMissing");
mod.errors += " " + mod.content_required_content + "\n";
} else {
fprintf(stderr, "Game content '%s' installed but not enabled which is a requirement for %s, not loading\n",
mod.content_required_content.c_str(), mod.path.c_str());
mod.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorRequiredContentDisabled");
mod.errors += " " + mod.content_required_content + "\n";
}
mod.available = mod.enabled = false;
}
Expand All @@ -705,6 +728,8 @@ void detectGameContent() {
if (terGameContentSelect == disallowed) {
fprintf(stderr, "Game content '%s' is enabled which is not compatible for %s, not loading\n",
mod.content_disallowed_content.c_str(), mod.path.c_str());
mod.errors += qdTextDB::instance().getText("Interface.Menu.Mods.ErrorDisallowedContentEnabled");
mod.errors += " " + mod.content_disallowed_content + "\n";
mod.available = mod.enabled = false;
}
}
Expand Down
2 changes: 2 additions & 0 deletions Source/Game/GameContent.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class ModMetadata {
public:
/// Path for this mod
std::string path = {};
/// Errors when loading mod if any
std::string errors = {};
/// Has campaign missions?
//TODO use this on "Change Campaign"
bool campaign = false;
Expand Down
14 changes: 14 additions & 0 deletions Source/Game/Texts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,13 @@ void qdTextDB::load_supplementary_texts(const std::string& locale) {
load_lines({
"GAME_CONTENT.PERIMETER=Периметр",
"GAME_CONTENT.PERIMETER_ET=Периметр: Завет Императора",
"Interface.Menu.Mods.ErrorMissingAttribute=Отсутствует атрибут в mod.ini:",
"Interface.Menu.Mods.ErrorGameTooOld=Игра слишком старая, нужна версия:",
"Interface.Menu.Mods.ErrorMissingModInfo=Отсутствует mod.ini\n",
"Interface.Menu.Mods.ErrorDuplicateContent=Содержимое уже загружено\n",
"Interface.Menu.Mods.ErrorRequiredContentMissing=Мод требует контента, который не установлен",
"Interface.Menu.Mods.ErrorRequiredContentDisabled=Мод требует отключенного контента",
"Interface.Menu.Mods.ErrorDisallowedContentEnabled=Мод несовместим с активным в данный момент контентом",
"Interface.Menu.Messages.ReplayGameVersionDifferent=Этот повтор был сохранен в другой версии и может отображаться неправильно. Использованная версия игры:",
"Interface.Menu.Messages.GameContentMissing=Содержит ресурсы, которые не представлены или не включены в этой копии игры, убедитесь, что они установлены и включены:\n",
"Interface.Menu.Messages.GameContentSwitch=Содержит неактивные ресурсы. Переключите кампанию на следующую:",
Expand Down Expand Up @@ -760,6 +767,13 @@ void qdTextDB::load_supplementary_texts(const std::string& locale) {
load_lines({
"GAME_CONTENT.PERIMETER=Perimeter",
"GAME_CONTENT.PERIMETER_ET=Perimeter: Emperor's Testament",
"Interface.Menu.Mods.ErrorMissingAttribute=Missing attribute in mod.ini:",
"Interface.Menu.Mods.ErrorGameTooOld=Game is too old, needs version:",
"Interface.Menu.Mods.ErrorMissingModInfo=Missing mod.ini\n",
"Interface.Menu.Mods.ErrorDuplicateContent=Content is already loaded\n",
"Interface.Menu.Mods.ErrorRequiredContentMissing=Mod requires content that is not installed",
"Interface.Menu.Mods.ErrorRequiredContentDisabled=Mod requires content that is disabled",
"Interface.Menu.Mods.ErrorDisallowedContentEnabled=Mod is not compatible with currently enabled content",
"Interface.Menu.Messages.ReplayGameVersionDifferent=This replay was saved with a different version and may not display correctly, used game version:",
"Interface.Menu.Messages.GameContentMissing=Contains game content that is not present or enabled in your installation, make sure these are installed and enabled in your game:\n",
"Interface.Menu.Messages.GameContentSwitch=Contains game content that is not selected, please change the campaign to the following content:\n",
Expand Down
5 changes: 1 addition & 4 deletions Source/UserInterface/HistoryScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,9 @@ void HistoryScene::drawPopup() {
Vect2f mousePos = historyCamera->getMousePos();
World* w = traceWorld(mousePos);

sPoint pt = {xm::round((mousePos.x + 0.5f) * terRenderDevice->GetSizeX()),
Vect2i pt = {xm::round((mousePos.x + 0.5f) * terRenderDevice->GetSizeX()),
xm::round((mousePos.y + 0.5f) * terRenderDevice->GetSizeY()) };

//TODO is this needed to port?
//ClientToScreen(hWndVisGeneric, &pt);

if (w) {
std::string frameNames;
std::map <std::string, Frame*>::iterator it;
Expand Down
63 changes: 63 additions & 0 deletions Source/UserInterface/Menu/AddonsMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,69 @@ void onMMAddonsList(CShellWindow* pWnd, InterfaceEventCode code, int param) {
}
} else if ( code == EVENT_DOUBLECLICK && param == VK_LBUTTON) {
addonEnableSwitch(list);
} else if ( code == EVENT_DRAWWND ) {
Vect2f mousePos = gameShell->mousePosition();
mousePos.x += 0.5f;
mousePos.y += 0.5f;

if (!list->HitTest(mousePos.x, mousePos.y)) {
return;
}

Vect2i pt = {
xm::round(mousePos.x * terRenderDevice->GetSizeX()),
xm::round(mousePos.y * terRenderDevice->GetSizeY())
};

int pos = list->ItemFromPoint(pt.y);
if (pos >= 0 && pos < gameModInfoList.size()) {
ModMetadata* mod = gameModInfoList[pos].mod;

std::string popupTxt = mod->mod_name;
popupTxt += " [" + mod->mod_version + "]";
if (!mod->mod_authors.empty()) {
popupTxt += "\n" + mod->mod_authors;
}
if (!mod->mod_url.empty()) {
popupTxt += "\n" + mod->mod_url;
}
if (!mod->errors.empty()) {
popupTxt += "\n&FF0000" + mod->errors;
}
if (!mod->mod_description.empty()) {
const int MAX_LEN = 1000;
if (mod->mod_description.length() > MAX_LEN) {
mod->mod_description = mod->mod_description.substr(0, MAX_LEN) + "...";
}
popupTxt += "\n\n&FFFFFF" + BreakLongLines(mod->mod_description.c_str(), 160);
}

//Draw rect
terRenderDevice->SetFont(pWnd->m_hFont);

Vect2f v1;
Vect2f v2;
terRenderDevice->OutTextRect(0, 0, popupTxt.c_str(), -1, v1, v2);

const float pad = 5;
Vect2f rectsize = {
v2.x - v1.x + pad * 2,
v2.y - v1.y + pad * 2
};
float x_max = terRenderDevice->GetSizeX() - rectsize.x - pad;
float y_max = terRenderDevice->GetSizeY() - rectsize.y - pad;
float y_move = rectsize.y + pad;
Vect2f rectpos = {
min(max(pad, pt.x - rectsize.x / 2.0f), x_max),
min(max(pad, pt.y + (mousePos.y > 0 ? -y_move : (pad + 40))), y_max)
};

terRenderDevice->DrawRectangle(rectpos.x, rectpos.y, rectsize.x, rectsize.y, sColor4c(32, 32, 32, 72), 0);
terRenderDevice->DrawRectangle(rectpos.x, rectpos.y, rectsize.x, rectsize.y, sColor4c(255, 255, 255, 255), 1);
terRenderDevice->OutText(rectpos.x + pad, rectpos.y + pad, popupTxt.c_str(), sColor4f(1, 1, 1, 1), -1);
terRenderDevice->SetFont(nullptr);
terRenderDevice->FlushPrimitive2D();
}
}
}

Expand Down
18 changes: 9 additions & 9 deletions Source/UserInterface/PerimeterShellUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3401,18 +3401,18 @@ int CListBoxWindow::CheckClick(float fx,float fy)

int CListBoxWindow::ItemFromPoint(float _y)
{
if(m_pItem[0].m_data.empty())
return -1;
if (m_pItem[0].m_data.empty()) {
return -1;
}
if (y > _y) {
return 0;
}

int i = int((_y - y)/m_fStringHeight) + m_nTopItem;

if(i >= m_pItem[0].m_data.size())
i = m_pItem[0].m_data.size()-1;

//TEMP
// if (i > lastAccessibleMissionNumber) {
// i = lastAccessibleMissionNumber;
// }
if (i >= m_pItem[0].m_data.size()) {
i = m_pItem[0].m_data.size() - 1;
}
return i;
}

Expand Down
3 changes: 2 additions & 1 deletion Source/UserInterface/PerimeterShellUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,6 @@ class CListBoxWindow : public CShellWindow
};

int CheckClick(float _x,float _y);
int ItemFromPoint(float _y);
public:
CListBoxWindow(int id, CShellWindow* pParent, EVENTPROC p = 0);
~CListBoxWindow();
Expand All @@ -904,6 +903,8 @@ class CListBoxWindow : public CShellWindow

void SetCurSel(int n);
void SetCurSelPassive(int n);

int ItemFromPoint(float _y);

const char* GetCurSelString();

Expand Down
4 changes: 2 additions & 2 deletions Source/Util/SystemUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,10 @@ std::string IniManager::getFilePath() {

const char* IniManager::get(const char* section, const char* key)
{
static char buf[256];
static char buf[10240];
std::string path = getFilePath();

if(!ReadIniString(section, key, NULL, buf, 256, path)){
if(!ReadIniString(section, key, NULL, buf, 10240, path)){
*buf = 0;
if (check_existence) {
fprintf(stderr, "INI key not found %s %s %s\n", path.c_str(), section, key);
Expand Down

0 comments on commit 25150ea

Please sign in to comment.