From dcae37fecae9afdd05cb3e2943f061b38ea5dcc3 Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Tue, 2 Jul 2024 11:06:43 +0800 Subject: [PATCH] Feature/taskforce (#74) --- MissionEditor/MissionEditor.rc | 33 ++- MissionEditor/TaskForce.cpp | 212 +++++++++++------- MissionEditor/TaskForce.h | 14 +- MissionEditor/data/FinalAlert2/FALanguage.ini | 16 ++ MissionEditor/functions.cpp | 6 + MissionEditor/functions.h | 3 + MissionEditor/resource.h | 13 +- 7 files changed, 200 insertions(+), 97 deletions(-) diff --git a/MissionEditor/MissionEditor.rc b/MissionEditor/MissionEditor.rc index 8939e2f..2a2ee99 100644 --- a/MissionEditor/MissionEditor.rc +++ b/MissionEditor/MissionEditor.rc @@ -768,28 +768,30 @@ BEGIN END #endif -IDD_TASKFORCES DIALOG 0, 0, 303, 205 +IDD_TASKFORCES DIALOGEX 0, 0, 303, 205 STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU CAPTION "Taskforces" -FONT 8, "Tahoma" +FONT 8, "Tahoma", 0, 0, 0x0 BEGIN - LTEXT "Task forces:",IDC_STATIC,7,7,71,10 + LTEXT "Task forces:",IDC_TASKFORCE_T_TYPE,7,7,71,10 COMBOBOX IDC_TASKFORCES,87,7,199,130,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Units in task force:",IDC_STATIC,17,88,61,13 + LTEXT "Units in task force:",IDC_TASKFORCE_T_MEMBERS,17,88,61,13 LISTBOX IDC_UNITS,87,88,199,68,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Add",IDC_ADDUNIT,17,102,61,14 - PUSHBUTTON "Delete",IDC_DELETEUNIT,17,121,61,15 - LTEXT "Group:",IDC_STATIC,17,69,61,13 + PUSHBUTTON "Delete",IDC_DELETEUNIT,17,135,61,15 + LTEXT "Group:",IDC_TASKFORCE_T_GROUP,17,69,61,13 EDITTEXT IDC_GROUP,87,69,199,13,ES_AUTOHSCROLL - LTEXT "Number of units:",IDC_STATIC,16,160,62,12 + LTEXT "Number of units:",IDC_TASKFORCE_T_U_NUM,16,160,62,12 EDITTEXT IDC_NUMBERUNITS,87,160,199,14,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Unit type:",IDC_STATIC,17,179,62,12 + LTEXT "Unit type:",IDC_TASKFORCE_T_U_TYPE,17,179,62,12 COMBOBOX IDC_UNITTYPE,87,179,199,183,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Selected task force",IDC_STATIC,7,45,290,153 + GROUPBOX "Selected task force",IDC_TASKFORCE_G_SELECTED,7,45,290,153 PUSHBUTTON "Delete",IDC_DELETETASKFORCE,222,23,64,15 - PUSHBUTTON "Add",IDC_ADDTASKFORCE,153,23,64,15 - LTEXT "Name:",IDC_STATIC,17,56,61,12 + PUSHBUTTON "Add",IDC_ADDTASKFORCE,89,22,64,15 + LTEXT "Name:",IDC_TASKFORCE_T_NAME,17,56,61,12 EDITTEXT IDC_NAME,87,54,199,13,ES_AUTOHSCROLL + PUSHBUTTON "Clone",IDC_COPYTASKFORCE,156,23,64,15 + PUSHBUTTON "Clone",IDC_COPYUNIT,17,118,61,15 END IDD_TAGS DIALOG 0, 0, 303, 204 @@ -1817,6 +1819,8 @@ BEGIN IDD_TASKFORCES, DIALOG BEGIN + VERTGUIDE, 17 + HORZGUIDE, 37 END IDD_TAGS, DIALOG @@ -1984,8 +1988,8 @@ BEGIN HORZGUIDE, 165 HORZGUIDE, 180 HORZGUIDE, 196 - HORZGUIDE, 232 HORZGUIDE, 230 + HORZGUIDE, 232 HORZGUIDE, 240 HORZGUIDE, 250 HORZGUIDE, 260 @@ -3588,6 +3592,11 @@ BEGIN END #endif +IDD_TASKFORCES AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/MissionEditor/TaskForce.cpp b/MissionEditor/TaskForce.cpp index 6360b84..b12daaa 100644 --- a/MissionEditor/TaskForce.cpp +++ b/MissionEditor/TaskForce.cpp @@ -36,6 +36,8 @@ static char THIS_FILE[] = __FILE__; #endif +CString GetFree(const char* section); + ///////////////////////////////////////////////////////////////////////////// // Eigenschaftenseite CTaskForce @@ -54,6 +56,13 @@ CTaskForce::~CTaskForce() { } +BOOL CTaskForce::OnInitDialog() +{ + auto const ret = CDialog::OnInitDialog(); + translateUI(); + return ret; +} + void CTaskForce::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); @@ -83,11 +92,41 @@ BEGIN_MESSAGE_MAP(CTaskForce, CDialog) ON_BN_CLICKED(IDC_ADDTASKFORCE, OnAddtaskforce) ON_EN_KILLFOCUS(IDC_GROUP, OnChangeGroup) //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_COPYTASKFORCE, &CTaskForce::OnBnClickedCopytaskforce) + ON_BN_CLICKED(IDC_COPYUNIT, &CTaskForce::OnBnClickedCopyunit) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // Behandlungsroutinen für Nachrichten CTaskForce +CString CTaskForce::getCurrrentID() +{ + CString tf; + tf = GetText(&m_TaskForces); + TruncSpace(tf); + return tf; +} + +void CTaskForce::translateUI() +{ + TranslateWindowCaption(*this, "TaskforcesCaption"); + + TranslateDlgItem(*this, IDC_TASKFORCE_T_TYPE, "TaskforcesType"); + TranslateDlgItem(*this, IDC_ADDTASKFORCE, "TaskforcesAdd"); + TranslateDlgItem(*this, IDC_COPYTASKFORCE, "TaskforcesCopy"); + TranslateDlgItem(*this, IDC_DELETETASKFORCE, "TaskforcesDelete"); + TranslateDlgItem(*this, IDC_TASKFORCE_G_SELECTED, "TaskforcesSelected"); + TranslateDlgItem(*this, IDC_TASKFORCE_T_NAME, "TaskforcesName"); + TranslateDlgItem(*this, IDC_TASKFORCE_T_GROUP, "TaskforcesGroup"); + TranslateDlgItem(*this, IDC_TASKFORCE_T_MEMBERS, "TaskforcesMembers"); + + TranslateDlgItem(*this, IDC_ADDUNIT, "TaskforcesAddUnit"); + TranslateDlgItem(*this, IDC_COPYUNIT, "TaskforcesCopyUnit"); + TranslateDlgItem(*this, IDC_DELETEUNIT, "TaskforcesDeleteUnit"); + TranslateDlgItem(*this, IDC_TASKFORCE_T_U_NUM, "TaskforcesUnitNumber"); + TranslateDlgItem(*this, IDC_TASKFORCE_T_U_TYPE, "TaskforcesUnitType"); +} + void CTaskForce::UpdateDialog() { CIniFile& ini = Map->GetIniFile(); @@ -171,10 +210,7 @@ void CTaskForce::OnSelchangeTaskforces() { CIniFile& ini = Map->GetIniFile(); - CString tf; - tf = GetText(&m_TaskForces); - - TruncSpace(tf); + auto const tf = getCurrrentID(); auto const& sec = ini[tf]; m_Name = sec.GetString("Name"); m_Group = sec.GetString("Group"); @@ -208,10 +244,7 @@ void CTaskForce::OnSelchangeUnits() int sel = m_Units.GetCurSel(); int u = m_Units.GetItemData(sel); - CString tf; - tf = GetText(&m_TaskForces); - TruncSpace(tf); - + auto const tf = getCurrrentID(); CString indexStr; indexStr.Format("%d", u); @@ -237,10 +270,8 @@ void CTaskForce::OnDeleteunit() return; } int u = m_Units.GetItemData(sel); - CString tf; - tf = GetText(&m_TaskForces); + auto const tf = getCurrrentID(); - TruncSpace(tf); auto sec = ini.TryGetSection(tf); ASSERT(sec != nullptr); CString numberStrToDelete; @@ -283,10 +314,7 @@ void CTaskForce::OnChangeNumberunits() return; } int u = m_Units.GetItemData(sel); - CString tf; - tf = GetText(&m_TaskForces); - - TruncSpace(tf); + auto const tf = getCurrrentID(); auto sec = ini.TryGetSection(tf); CString k, n; @@ -311,11 +339,7 @@ void CTaskForce::OnChangeName() if (m_TaskForces.GetCurSel() < 0) { return; } - CString tf; - tf = GetText(&m_TaskForces); - - TruncSpace(tf); - + auto const tf = getCurrrentID(); ini.SetString(tf, "Name", m_Name); UpdateDialog(); @@ -327,6 +351,8 @@ void CTaskForce::OnEditchangeUnittype() CIniFile& ini = Map->GetIniFile(); CString type = GetText(&m_UnitType); + TruncSpace(type); + if (type.IsEmpty()) { return; } @@ -336,10 +362,7 @@ void CTaskForce::OnEditchangeUnittype() return; } int u = m_Units.GetItemData(sel); - CString tf; - tf = GetText(&m_TaskForces); - - TruncSpace(tf); + auto const tf = getCurrrentID(); auto sec = ini.TryGetSection(tf); ASSERT(sec != nullptr); @@ -351,7 +374,7 @@ void CTaskForce::OnEditchangeUnittype() k.Format("%d", u); CString count = GetParam(sec->GetString(k), 0); - TruncSpace(type); + sec->SetString(k, count + "," + type); @@ -372,10 +395,7 @@ void CTaskForce::OnSelchangeUnittype() return; } int u = m_Units.GetItemData(sel); - CString tf; - tf = GetText(&m_TaskForces); - - TruncSpace(tf); + auto const tf = getCurrrentID(); auto sec = ini.TryGetSection(tf); ASSERT(sec != nullptr); @@ -401,13 +421,10 @@ void CTaskForce::OnAddunit() { CIniFile& ini = Map->GetIniFile(); - CString tf; if (m_TaskForces.GetCurSel() < 0) { return; } - tf = GetText(&m_TaskForces); - - TruncSpace(tf); + auto const tf = getCurrrentID(); auto sec = ini.TryGetSection(tf); ASSERT(sec != nullptr); @@ -423,18 +440,33 @@ void CTaskForce::OnAddunit() UpdateDialog(); } +void CTaskForce::OnBnClickedCopyunit() +{ + auto& ini = Map->GetIniFile(); + + auto const tf = getCurrrentID(); + if (tf.IsEmpty()) { + return; + } + auto const selected = m_Units.GetCurSel(); + + if (selected < 0) { + return; + } + auto const curCount = m_Units.GetCount(); + auto const& content = ini.GetString(tf, INIHelper::ToString(selected)); + ini.SetString(tf, INIHelper::ToString(curCount), content); + UpdateDialog(); + m_Units.SetCurSel(curCount); +} + void CTaskForce::OnDeletetaskforce() { CIniFile& ini = Map->GetIniFile(); - - CString tf; if (m_TaskForces.GetCurSel() < 0) { return; } - tf = GetText(&m_TaskForces); - - TruncSpace(tf); - + auto const tf = getCurrrentID(); int res; res = MessageBox("Are you sure to delete the selected task force? If you delete it, make sure to eliminate ANY references to this task force in team-types.", "Delete task force", MB_YESNO); if (res == IDNO) { @@ -448,8 +480,7 @@ void CTaskForce::OnDeletetaskforce() ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); } -CString GetFree(const char* section); -void CTaskForce::OnAddtaskforce() +void CTaskForce::addTaskforce(CString&& name, int group, std::vector&& members) { CIniFile& ini = Map->GetIniFile(); @@ -457,44 +488,69 @@ void CTaskForce::OnAddtaskforce() CString tf = GetFree("TaskForces"); ini.SetString("TaskForces", tf, ID); - ini.SetString(ID, "Name", "New task force"); - ini.SetString(ID, "Group", "-1"); + auto& sec = ini.AddSection(ID); + sec.SetString("Name", std::move(name)); + sec.SetInteger("Group", group); - //UpdateDialog(); + int idx = 0; + CString idxStr; + for (auto&& member : members) { + idxStr.Format("%d", idx++); + sec.SetString(idxStr, std::move(member)); + } ((CFinalSunDlg*)theApp.m_pMainWnd)->UpdateDialogs(TRUE); - int i; - for (i = 0; i < m_TaskForces.GetCount(); i++) { - CString tf2; + CString tf2; + for (auto i = 0; i < m_TaskForces.GetCount(); i++) { m_TaskForces.GetLBText(i, tf2); - TruncSpace(tf2); - if (strcmp(ID, tf2) == NULL) { m_TaskForces.SetCurSel(i); OnSelchangeTaskforces(); // MW bugfix break; } } - - } + +void CTaskForce::OnAddtaskforce() +{ + addTaskforce("New task force", -1, {}); +} + +void CTaskForce::OnBnClickedCopytaskforce() +{ + auto const id = getCurrrentID(); + if (id.IsEmpty()) { + return; + } + std::vector content; + auto const& ini = Map->GetIniFile(); + auto const& sec = ini[id]; + for (auto const& [key, val] : sec) { + if (IsNumeric(key)) { + content.push_back(val); + } + } + addTaskforce( + sec.GetString("Name") + " Clone", + sec.GetInteger("Group"), + std::move(content) + ); +} + + void CTaskForce::OnChangeGroup() { CIniFile& ini = Map->GetIniFile(); UpdateData(); - CString tf; if (m_TaskForces.GetCurSel() < 0) { return; } - tf = GetText(&m_TaskForces); - - TruncSpace(tf); - + auto const tf = getCurrrentID(); ini.SetString(tf, "Group", m_Group); UpdateDialog(); @@ -505,31 +561,31 @@ BOOL CTaskForce::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN) { switch (pMsg->wParam) { - case VK_RETURN: - { - auto pEdit = this->m_UnitType.GetWindow(GW_CHILD); - if (pMsg->hwnd == pEdit->m_hWnd) { - this->OnEditchangeUnittype(); - } + case VK_RETURN: + { + auto pEdit = this->m_UnitType.GetWindow(GW_CHILD); + if (pMsg->hwnd == pEdit->m_hWnd) { + this->OnEditchangeUnittype(); + } - switch (::GetDlgCtrlID(pMsg->hwnd)) { - case IDC_NAME: - this->OnChangeName(); - break; - case IDC_NUMBERUNITS: - this->OnChangeNumberunits(); - break; - case IDC_GROUP: - this->OnChangeGroup(); - break; + switch (::GetDlgCtrlID(pMsg->hwnd)) { + case IDC_NAME: + this->OnChangeName(); + break; + case IDC_NUMBERUNITS: + this->OnChangeNumberunits(); + break; + case IDC_GROUP: + this->OnChangeGroup(); + break; + default: + break; + } + } + //do not exit dialog when enter key pressed + return TRUE; default: break; - } - } - //do not exit dialog when enter key pressed - return TRUE; - default: - break; } } diff --git a/MissionEditor/TaskForce.h b/MissionEditor/TaskForce.h index 4cb83f3..131f986 100644 --- a/MissionEditor/TaskForce.h +++ b/MissionEditor/TaskForce.h @@ -56,13 +56,17 @@ public: // Der Klassen-Assistent generiert virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CTaskForce) protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung + virtual BOOL OnInitDialog() override; + virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV-Unterstützung + virtual BOOL PreTranslateMessage(MSG* pMsg) override; //}}AFX_VIRTUAL // Implementierung -protected: + CString getCurrrentID(); + void translateUI(); + void addTaskforce(CString&& name, int group, std::vector&& members); - BOOL PreTranslateMessage(MSG* pMsg) override; + DECLARE_MESSAGE_MAP() // Generierte Nachrichtenzuordnungsfunktionen //{{AFX_MSG(CTaskForce) @@ -75,12 +79,12 @@ protected: afx_msg void OnEditchangeUnittype(); afx_msg void OnSelchangeUnittype(); afx_msg void OnAddunit(); + afx_msg void OnBnClickedCopyunit(); afx_msg void OnDeletetaskforce(); afx_msg void OnAddtaskforce(); + afx_msg void OnBnClickedCopytaskforce(); afx_msg void OnChangeGroup(); //}}AFX_MSG - DECLARE_MESSAGE_MAP() - }; //{{AFX_INSERT_LOCATION}} diff --git a/MissionEditor/data/FinalAlert2/FALanguage.ini b/MissionEditor/data/FinalAlert2/FALanguage.ini index b062867..27062f8 100644 --- a/MissionEditor/data/FinalAlert2/FALanguage.ini +++ b/MissionEditor/data/FinalAlert2/FALanguage.ini @@ -1344,6 +1344,22 @@ TriggerOptionHouse=所属方: TriggerOptionAttachedTrigger=关联的触发 TriggerOptionDisableTip=被禁止的触发必须由其它触发激活后才能继续运作 +; taskforces +TaskforcesCaption=成员组 +TaskforcesType=成员组类型: +TaskforcesAdd=添加 +TaskforcesCopy=复制 +TaskforcesDelete=删除 +TaskforcesSelected=选定的成员组 +TaskforcesName=名称: +TaskforcesGroup=分组: +TaskforcesMembers=成员构成: +TaskforcesAddUnit=添加 +TaskforcesCopyUnit=复制 +TaskforcesDeleteUnit=删除 +TaskforcesUnitNumber=单位数量: +TaskforcesUnitType=单位类型: + ; team scripts ScriptTypesAddScript=添加 ScriptTypesCopyScript=复制 diff --git a/MissionEditor/functions.cpp b/MissionEditor/functions.cpp index 6b288c4..89212b1 100644 --- a/MissionEditor/functions.cpp +++ b/MissionEditor/functions.cpp @@ -663,6 +663,12 @@ void PosToXY(const char* pos, int* X, int* Y) } +bool IsNumeric(const CString& str) { + return std::all_of(str.operator LPCSTR(), str.operator LPCSTR() + str.GetLength(), [](char c) { + return std::isdigit(c); + }); +} + bool HSVToRGB(const float h, const float s, const float v, float& r, float& g, float& b) { if (h < 0.0 || h >= 360.0 || s < 0.0 || s > 1.0 || v < 0.0 || v > 1.0) diff --git a/MissionEditor/functions.h b/MissionEditor/functions.h index 2789aa4..da7ed88 100644 --- a/MissionEditor/functions.h +++ b/MissionEditor/functions.h @@ -49,6 +49,9 @@ bool RepairTrigger(CString& triggerdata); // coordinate functions void PosToXY(const char* pos, int* X, int* Y); +// check whether is string is all made of digit numbers +bool IsNumeric(const CString& str); + // HSV -> RGB void HSVToRGB(const unsigned char hsv[3], unsigned char rgb[3]); std::array HSVToRGB(float h, float s, float v); diff --git a/MissionEditor/resource.h b/MissionEditor/resource.h index 544abb6..5b90274 100644 --- a/MissionEditor/resource.h +++ b/MissionEditor/resource.h @@ -256,6 +256,8 @@ #define IDC_UNITTYPE 1149 #define IDC_DELETETASKFORCE 1150 #define IDC_ADDTASKFORCE 1151 +#define IDC_COPYTASKFORCE 1152 +#define IDC_COPYUNIT 1153 #define IDC_ADD 1154 #define IDC_REPEAT 1156 #define IDC_TRIGGER 1157 @@ -551,6 +553,13 @@ #define IDC_TEAMTYPE_P_TAG 1479 #define IDC_TEAMTYPE_P_SCRIPT 1480 #define IDC_TEAMTYPE_P_TASKFORCE 1481 +#define IDC_TASKFORCE_T_TYPE 1482 +#define IDC_TASKFORCE_G_SELECTED 1483 +#define IDC_TASKFORCE_T_NAME 1484 +#define IDC_TASKFORCE_T_GROUP 1485 +#define IDC_TASKFORCE_T_MEMBERS 1486 +#define IDC_TASKFORCE_T_U_NUM 1487 +#define IDC_TASKFORCE_T_U_TYPE 1488 #define ID_FILE_OPENMAP 40001 #define ID_FILE_SAVEAS 40002 #define ID_FILE_QUIT 40003 @@ -645,9 +654,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 301 +#define _APS_NEXT_RESOURCE_VALUE 302 #define _APS_NEXT_COMMAND_VALUE 40144 -#define _APS_NEXT_CONTROL_VALUE 1482 +#define _APS_NEXT_CONTROL_VALUE 1489 #define _APS_NEXT_SYMED_VALUE 111 #endif #endif