/*
FinalSun/FinalAlert 2 Mission Editor
Copyright (C) 1999-2024 Electronic Arts, Inc.
Authored by Matthias Wagner
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
// TriggerEventsDlg.cpp: Implementierungsdatei
//
#include "stdafx.h"
#include "finalsun.h"
#include "TriggerEventsDlg.h"
#include "mapdata.h"
#include "variables.h"
#include "functions.h"
#include "inlines.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Dialogfeld CTriggerEventsDlg
CTriggerEventsDlg::CTriggerEventsDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTriggerEventsDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CTriggerEventsDlg)
// HINWEIS: Der Klassen-Assistent fügt hier Elementinitialisierung ein
//}}AFX_DATA_INIT
}
BOOL CTriggerEventsDlg::OnInitDialog()
{
auto const ret = CDialog::OnInitDialog();
TranslateUI();
return ret;
}
void CTriggerEventsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTriggerEventsDlg)
DDX_Control(pDX, IDC_PARAMVALUE, m_ParamValue);
DDX_Control(pDX, IDC_PARAMETER, m_Parameter);
DDX_Control(pDX, IDC_EVENTTYPE, m_EventType);
DDX_Control(pDX, IDC_EVENTDESCRIPTION, m_EventDescription);
DDX_Control(pDX, IDC_EVENT, m_Event);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTriggerEventsDlg, CDialog)
//{{AFX_MSG_MAP(CTriggerEventsDlg)
ON_BN_CLICKED(IDC_NEWEVENT, OnNewevent)
ON_BN_CLICKED(IDC_DELETEEVENT, OnDeleteevent)
ON_CBN_SELCHANGE(IDC_EVENT, OnSelchangeEvent)
ON_CBN_EDITCHANGE(IDC_EVENTTYPE, OnEditchangeEventtype)
ON_LBN_SELCHANGE(IDC_PARAMETER, OnSelchangeParameter)
ON_CBN_EDITCHANGE(IDC_PARAMVALUE, OnEditchangeParamvalue)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CTriggerEventsDlg::TranslateUI()
{
TranslateDlgItem(*this, IDC_EVENT_CUR_TXT, "TriggerEventCurrent");
TranslateDlgItem(*this, IDC_NEWEVENT, "TriggerEventNew");
TranslateDlgItem(*this, IDC_DELETEEVENT, "TriggerEventDelete");
TranslateDlgItem(*this, IDC_EVENT_OPT_TXT, "TriggerEventOptions");
TranslateDlgItem(*this, IDC_EVENT_TYPE_TXT, "TriggerEventType");
TranslateDlgItem(*this, IDC_EVENT_PARAM_TXT, "TriggerEventParams");
TranslateDlgItem(*this, IDC_EVENT_VAL_TXT, "TriggerEventParamValue");
TranslateDlgItem(*this, IDC_EVENT_DESC, "TriggerEventDesc");
}
/////////////////////////////////////////////////////////////////////////////
// Behandlungsroutinen für Nachrichten CTriggerEventsDlg
// MW 07/23/01: Added this because startpos=1+curev*3 isn´t anymore valid for calculating the next event
int GetEventParamStart(const CString& EventData, int param)
{
int count = atoi(GetParam(EventData, 0));
if (param >= count) {
return -1;
}
int pos = 1;
int i;
for (i = 0; i < param; i++) {
pos += 1; // jump to first eventtype param
int needs = atoi(GetParam(EventData, pos));
pos += 2; // jump to next usual eventtype
// if needs of last eventtype is 2, we need to add 1
if (needs == 2) {
pos += 1;
}
}
return pos;
}
void CTriggerEventsDlg::OnNewevent()
{
CIniFile& ini = Map->GetIniFile();
if (m_currentTrigger.GetLength() == 0) {
return;
}
CIniFileSection& sec = ini.AddSection("Events");
int cval = atoi(GetParam(sec.GetString(m_currentTrigger), 0));
cval++;
char c[50];
itoa(cval, c, 10);
auto&& defParam = SetParam(sec[m_currentTrigger], 0, c) + ",0,0,0";
sec.SetString(m_currentTrigger, std::move(defParam));
UpdateDialog();
m_Event.SetCurSel(cval - 1);
OnSelchangeEvent();
}
int FindTokenX(CString data, char token, int n)
{
if (n <= 0) return -1;
int found = 0;
int pos = 0;
while (found < n) {
if (!pos)
pos = data.Find(token, 0);
else
pos = data.Find(token, pos + 1);
if (pos < 0) {
return -1;
}
found++;
}
return pos;
}
void CTriggerEventsDlg::OnDeleteevent()
{
char d[50];
//itoa(FindTokenX("0,1,2,3,4", ',', 3),d,10);
//MessageBox(d);
CIniFile& ini = Map->GetIniFile();
if (m_currentTrigger.GetLength() == 0) {
return;
}
int sel2 = m_Event.GetCurSel();
if (sel2 < 0) {
return;
}
int curev = m_Event.GetItemData(sel2);
auto const title = TranslateStringACP("Delete event");
auto const content = TranslateStringACP("Do you really want to delete this event?");
if (MessageBox(content, title, MB_YESNO) == IDNO) {
return;
}
auto const& orig_data = ini["Events"][m_currentTrigger];
CString data = orig_data;
int v = atoi(GetParam(data, 0));
char c[50];
v--;
itoa(v, c, 10);
data = SetParam(data, 0, c);
int pos = GetEventParamStart(orig_data, curev);//1+curev*3;
//int posc=GetEventParamStart(orig_data, v);//1+v*3;
// MW 07/23/01:
// NEW DELETE EVENT CODE...
// Now check for those 2 param + code events...
BOOL bEvent1Needs4 = FALSE;
if (GetParam(data, pos + 1) == "2") {
bEvent1Needs4 = TRUE;
}
int count = 3;
if (bEvent1Needs4) {
count = 4;
}
int del_start = FindTokenX(data, ',', pos);
int del_end = FindTokenX(data, ',', pos + count);
if (del_end < 0) {
// beyond end, so delete all...
del_end = data.GetLength();
}
data.Delete(del_start, del_end - del_start);
/*
old delete event code, that used replacement. Not possible anymore because of 4 values/event sometimes now
int i;
for(i=0;i<3;i++)
data=SetParam(data,pos+i, GetParam(data,posc+i));
char* cupos=(char*)(LPCTSTR)data;
for(i=0;iGetIniFile();
if (m_currentTrigger.GetLength() == 0) {
return;
}
int selev = m_Event.GetCurSel();
if (selev < 0) {
return;
}
int curev = m_Event.GetItemData(selev);
int i;
auto const& EventData = ini["Events"][m_currentTrigger];
int startpos = GetEventParamStart(EventData, curev); //1+curev*3;
CString EventType = GetParam(EventData, startpos);
m_EventType.SetWindowText(EventType);
for (i = 0; i < m_EventType.GetCount(); i++) {
CString tmp;
m_EventType.GetLBText(i, tmp);
TruncSpace(tmp);
if (tmp == EventType) {
m_EventType.SetCurSel(i);
}
}
OnEditchangeEventtype();
}
void CTriggerEventsDlg::OnEditchangeEventtype()
{
CIniFile& ini = Map->GetIniFile();
if (m_currentTrigger.GetLength() == 0) {
return;
}
int selev = m_Event.GetCurSel();
if (selev < 0) {
return;
}
int curev = m_Event.GetItemData(selev);
CString e1, e2;
while (m_Parameter.DeleteString(0) != CB_ERR);
CString eventtype, eventdata;
m_EventType.GetWindowText(eventtype);
TruncSpace(eventtype);
if (eventtype.GetLength() == 0) {
eventtype = "0";
m_EventType.SetWindowText(eventtype);
}
int pos = GetEventParamStart(ini["Events"][m_currentTrigger], curev); //1+3*curev;
BOOL bAlready4 = FALSE;
if (atoi(GetParam(ini["Events"][m_currentTrigger], pos + 1)) == 2) {
bAlready4 = TRUE;
}
ini.SetString("Events", m_currentTrigger, SetParam(ini["Events"][m_currentTrigger], pos, eventtype));
CString evsec = "Events";
#ifdef RA2_MODE
evsec = "EventsRA2";
#endif
if (!g_data[evsec].Exists(eventtype)) {
return;
}
eventdata = g_data[evsec][eventtype];
#ifdef RA2_MODE
auto const ra2EventConf = g_data.GetString("EventsRA2", eventtype);
if (!ra2EventConf.IsEmpty()) {
eventdata = ra2EventConf;
}
#endif
CString desc = GetParam(eventdata, 5);
desc.Replace("%1", ",");
m_EventDescription.SetWindowText(desc);
CString ptype[2];
ptype[0] = GetParam(eventdata, 1);
ptype[1] = GetParam(eventdata, 2);
int pListType[2];
pListType[0] = atoi(GetParam(g_data["ParamTypes"][ptype[0]], 1));
pListType[1] = atoi(GetParam(g_data["ParamTypes"][ptype[1]], 1));
int code = atoi(GetParam(g_data["ParamTypes"][ptype[0]], 2)); // usually 0
// **************************************
// MW ADD SUPPORT FOR 2 PARAMS+CODE
if (code == 2) {
// add code + event 0 ONLY IF THEY DO NOT ALREADY EXIST
if (!bAlready4) {
ini.SetString("Events", m_currentTrigger, SetParam(ini["Events"][m_currentTrigger], pos + 1, "2,0"));
}
} else {
// remove code + event 0
char c[50];
itoa(code, c, 10);
ini.SetString("Events", m_currentTrigger, SetParam(ini["Events"][m_currentTrigger], pos + 1, c));
if (bAlready4) {
CString data = ini["Events"][m_currentTrigger];
int del_start = FindTokenX(data, ',', pos + 2);
int del_end = FindTokenX(data, ',', pos + 3);
if (del_end < 0) {
// beyond end, so delete all...
del_end = data.GetLength();
}
data.Delete(del_start, del_end - del_start);
ini.SetString("Events", m_currentTrigger, data);
}
}
// **************************************
int i;
for (i = 0; i < 2; i++) {
int add = 0;
if (code == 2) {
add = 1;
}
if (atoi(ptype[i]) != 0 && atoi(ptype[i]) > 0 && atoi(ptype[i]) != 47) {
CString paramname = GetParam(g_data["ParamTypes"][ptype[i]], 0);
m_Parameter.SetItemData(m_Parameter.AddString(paramname), i + add);
}
}
m_ParamValue.SetWindowText("");
if (m_Parameter.GetCount() > 0) {
m_Parameter.SetCurSel(0);
OnSelchangeParameter();
}
auto triggerInfoCopy = ini["Triggers"][m_currentTrigger];
if (RepairTrigger(triggerInfoCopy)) {
ini.SetString("Triggers", m_currentTrigger, triggerInfoCopy);
}
}
void CTriggerEventsDlg::OnSelchangeParameter()
{
CIniFile& ini = Map->GetIniFile();
if (m_currentTrigger.GetLength() == 0) {
return;
}
int selev = m_Event.GetCurSel();
if (selev < 0) {
return;
}
int curev = m_Event.GetItemData(selev);
int curselparam = m_Parameter.GetCurSel();
if (curselparam < 0) {
m_ParamValue.SetWindowText("");
return;
}
int curparam = m_Parameter.GetItemData(curselparam);
auto const EventData = ini["Events"][m_currentTrigger];
int startpos = GetEventParamStart(EventData, curev);//1+curev*3;
// MW FIX FOR CODE!=0
int original_cuparam = curparam;
#ifdef RA2_MODE
CString Param1 = GetParam(g_data["EventsRA2"][GetParam(EventData, startpos)], 1);
// 3rd position control code
CString Code = GetParam(g_data["ParamTypes"][Param1], 2);
// means there are parameters taken up 2 slots, even if only 1 is meaningful
if (atoi(Code) == 2) {
curparam--;
}
#endif
// END FIx
CString ParamType = GetParam(g_data["Events"][GetParam(EventData, startpos)], 1 + curparam);
#ifdef RA2_MODE
if (g_data["EventsRA2"].FindIndex(GetParam(EventData, startpos)) >= 0) {
ParamType = GetParam(g_data["EventsRA2"][GetParam(EventData, startpos)], 1 + curparam);
}
#endif
if (atoi(ParamType) < 0) {
return;
}
CString ListType = GetParam(g_data["ParamTypes"][ParamType], 1);
HandleParamList(m_ParamValue, atoi(ListType));
m_ParamValue.SetWindowText(GetParam(EventData, startpos + 1 + original_cuparam));
int i;
BOOL bFound = FALSE;
for (i = 0; i < m_ParamValue.GetCount(); i++) {
CString tmp;
m_ParamValue.GetLBText(i, tmp);
TruncSpace(tmp);
if (tmp == GetParam(EventData, startpos + 1 + original_cuparam)) {
m_ParamValue.SetCurSel(i);
bFound = TRUE;
break;
}
}
/*if(!bFound)
{
// not found, change it...
if(m_ParamValue.GetCount()) {
m_ParamValue.SetCurSel(0);
OnEditchangeParamvalue();
}
else
{
// not numeric value?
CString p=GetParam(EventData,startpos+1+original_cuparam);
char c[50];
itoa(atoi(p), c, 10);
if(c!=p) {
m_ParamValue.SetWindowText("0");
OnEditchangeParamvalue();
}
}
}*/
}
void CTriggerEventsDlg::OnEditchangeParamvalue()
{
CIniFile& ini = Map->GetIniFile();
if (m_currentTrigger.GetLength() == 0) {
return;
}
int selev = m_Event.GetCurSel();
if (selev < 0) {
return;
}
int curev = m_Event.GetItemData(selev);
int curselparam = m_Parameter.GetCurSel();
if (curselparam < 0) {
m_ParamValue.SetWindowText("");
return;
}
int curparam = m_Parameter.GetItemData(curselparam);
auto const& eventData = ini["Events"][m_currentTrigger];
int startpos = GetEventParamStart(eventData, curev);// 1+curev*3;
CString newVal;
m_ParamValue.GetWindowText(newVal);
TruncSpace(newVal);
newVal.TrimLeft();
if (newVal.Find(",", 0) >= 0) {
newVal.SetAt(newVal.Find(",", 0), 0);
}
ini.SetString("Events", m_currentTrigger, SetParam(eventData, startpos + 1 + curparam, newVal));
}
void CTriggerEventsDlg::UpdateDialog()
{
// MW 07/20/01
Clear();
if (m_currentTrigger.GetLength() == 0) {
while (m_Event.DeleteString(0) != CB_ERR);
return;
}
CIniFile& ini = Map->GetIniFile();
while (m_EventType.DeleteString(0) != CB_ERR);
int i;
//9.3.2001: Only use specified section, do not merge
#ifndef RA2_MODE
CString sec = "Events";
#else
CString sec = "EventsRA2";
#endif
for (auto const& [eventid, eventdata] : g_data[sec]) {
//GetParam(*g_data.sections["Events"].GetValue(i),8);
/*#ifdef RA2_MODE
if(g_data.sections["EventsRA2"].FindIndex(eventid)>=0)
eventdata=g_data.sections["EventsRA2"].values[eventid];
#endif*/
CString text = eventid + " " + GetParam(eventdata, 0);
text.Replace("%1", ",");
#ifdef RA2_MODE
// MW 07/18/01
// for yuri mode, only check if it´s for RA2, else support it only if YR isnt´needed...
if (GetParam(eventdata, 7) == "1" && (yuri_mode || !atoi(GetParam(eventdata, 9)))) {
#else
if (GetParam(eventdata, 6) == "1") {
#endif
m_EventType.AddString(text);
}
}
int cur_sel = m_Event.GetCurSel();
while (m_Event.DeleteString(0) != CB_ERR);
auto const& data = ini["Events"][m_currentTrigger];
int count = atoi(GetParam(data, 0));
for (i = 0; i < count; i++) {
char c[50];
itoa(i, c, 10);
CString s = TranslateStringACP("Event");
s += " ";
s += c;
m_Event.SetItemData(m_Event.AddString(s), i);
}
if (cur_sel < 0) {
cur_sel = 0;
}
if (cur_sel >= count) {
cur_sel = count - 1;
}
m_Event.SetCurSel(cur_sel);
OnSelchangeEvent();
}
// MW 07/20/01
void CTriggerEventsDlg::Clear()
{
m_EventType.SetWindowText("");
while (m_Parameter.DeleteString(0) != LB_ERR);
m_ParamValue.SetWindowText("");
m_EventDescription.SetWindowText("");
}