Descent3/legacy/editor/ScriptWizard.cpp
2024-05-24 08:49:04 -04:00

686 lines
18 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* 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 <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/Main/editor/ScriptWizard.cpp $
* $Revision: 1.1.1.1 $
* $Date: 2003-08-26 03:57:39 $
* $Author: kevinb $
*
* Script Wizard
*
* $Log: not supported by cvs2svn $
*
* 20 11/06/98 12:34p Jason
* more speedups for manage system
*
* 19 10/08/98 4:24p Kevin
* Changed code to comply with memory library usage. Always use mem_malloc
* , mem_free and mem_strdup
*
* 18 8/31/98 4:12p Samir
* select level script by default in listbox.
*
* 17 6/23/98 3:04p Samir
* sped up script list generation.
*
* 16 6/23/98 2:43p Matt
* Changed calls to OutrageMessageBox() & Debug_MessageBox() to deal with
* int return value (instead of bool).
*
* 15 4/14/98 7:31p Matt
* Changed code to use ddio_MakePath() instead of sprintf() to create file
* spec
*
* 14 1/23/98 4:45p Samir
* Make level.scr be the default.
*
* 13 9/26/97 4:15p Samir
* Mostly working system to go to a certain script in a file.
*
* 12 9/25/97 5:28p Samir
* Even newer script code due to more changes in ObjCScript.cpp
*
* 11 9/24/97 6:18p Samir
* Fix some memory leakage probs.
*
* 10 9/24/97 2:57p Samir
* New ScriptWizard functionality, without extra commenting in files.
*
* 9 9/22/97 5:59p Samir
* Changed ObjCScript system, so everything is broken, but it shouldn't
* crash the game.
*
* 8 9/10/97 1:58p Samir
* Fixed up some code to select multiple script files.
*
* 7 9/04/97 4:39p Matt
* Added includes needed as a result of removing includes from d3edit.h
*
* 6 9/02/97 3:28p Matt
* Got rid of warnings
*
* 5 8/21/97 6:00p Samir
* A whole lot of script editing stuff added for ScriptWizard.
*
* 4 8/20/97 3:35p Samir
* Enhanced ScriptStudio to use tabs! Use new ScriptStudio instead of
* ScriptEditor.
*
* $NoKeywords: $
*/
// ScriptWizard.cpp : implementation file
//
#include "stdafx.h"
#include "editor.h"
#include "ScriptWizard.h"
#include "ObjCScript.h"
#include "manage.h"
#include "EditLineDialog.h"
#include "ScriptEditorDlg.h"
#include "gamefile.h"
#include "manage\gamefilepage.h"
#include "ScriptStudio.h"
#include "AddScriptDialog.h"
#include "pserror.h"
#include "ddio.h"
#include "mem.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScriptWizard dialog
CScriptWizard::CScriptWizard(CWnd* pParent /*=NULL*/)
: CDialog(CScriptWizard::IDD, pParent)
{
//{{AFX_DATA_INIT(CScriptWizard)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_ScriptSource = NULL;
m_ScriptCode = NULL;
}
void CScriptWizard::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CScriptWizard)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CScriptWizard, CDialog)
//{{AFX_MSG_MAP(CScriptWizard)
ON_BN_CLICKED(IDC_ADDSCRIPT, OnAddScript)
ON_BN_CLICKED(IDC_LOCK, OnLock)
ON_BN_CLICKED(IDC_UNLOCK, OnUnlock)
ON_BN_CLICKED(IDC_EDITSCRIPT, OnEditScript)
ON_LBN_SELCHANGE(IDC_SCR_LISTBOX, OnSelChangeScrListbox)
ON_BN_CLICKED(IDC_ADDEVENT, OnAddEvent)
ON_LBN_SELCHANGE(IDC_SCREVT_LISTBOX, OnSelchangeScrevtListbox)
ON_CBN_SELCHANGE(IDC_SCRMOD_BOX, OnSelchangeScrmodBox)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScriptWizard message handlers
BOOL CScriptWizard::OnInitDialog()
{
CDialog::OnInitDialog();
// Place all valid script files into the module combo box, then
// place all script names relating to the current script file into the script
// listbox.
CComboBox *modcbox = (CComboBox *)GetDlgItem(IDC_SCRMOD_BOX);
m_ScriptCode = D3XReallocProgram(NULL, 0, 0, 0);
ResetScriptList();
// place all filenames of scripts into combo box
char scrfilename[64];
char *filename;
scrfilename[0] = 0;
filename = StartScriptFileList();
while (filename)
{
strcpy(scrfilename, filename);
modcbox->AddString(filename);
filename = GetNextScriptFile();
}
EndScriptFileList();
modcbox->SelectString(-1, LEVEL_SCRIPT_NAME);
// update listboxes accordingly to current script module
ScriptFileName[0] = 0;
ScriptCodeName[0] = 0;
CScriptWizard::LoadCurrentModule();
// Updates the buttons
UpdateDialogButtons();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CScriptWizard::OnDestroy()
{
CDialog::OnDestroy();
if (m_ScriptCode)
D3XFreeProgram(m_ScriptCode);
ResetScriptList();
}
// We save whatever was added to the script. This does not include text added via edit
// (that's done in the internal script editor.) It does include text added from operations like
// Add Script, Add Event, etc.
void CScriptWizard::OnOK()
{
SaveScript(ScriptFileName, m_ScriptSource);
FreeScript(m_ScriptSource);
CDialog::OnOK();
}
// We just don't save anything. We free the script, if there is one
void CScriptWizard::OnCancel()
{
FreeScript(m_ScriptSource);
CDialog::OnCancel();
}
// Adds a script to the current editable script. We will not allow this if the script is not locked,
// so we should allow then to unlock it at this point.
void CScriptWizard::OnAddScript()
{
char scrname[MAX_SCRNAME];
scrname[0] = 0;
if (strlen(ScriptFileName) == 0) {
OutrageMessageBox("There is no script file to add a script to! You must make one.");
return;
}
// check if current module is locked by us.
if (mng_FindTrackLock(ScriptFileName, PAGETYPE_GAMEFILE) == -1)
OutrageMessageBox("Warning: This script is not locked by you.\nAny changes you make will not be permanent.");
// request a name for this new script!
CAddScriptDialog dlg(this);
if (dlg.DoModal() == IDOK) {
// add script to listbox, then select it, then run editor
CListBox *lb = (CListBox *)GetDlgItem(IDC_SCR_LISTBOX);
char *tempstr = AddScriptBlockToScript(m_ScriptSource, (LPCSTR)dlg.m_Name, (LPCSTR)dlg.m_TypeName);
mem_free(m_ScriptSource);
m_ScriptSource = tempstr;
UpdateScriptListbox();
lb->SelectString(-1, (LPCSTR)dlg.m_Name);
OnEditScript();
}
else {
OutrageMessageBox("A script name is required to continue. Cancelling action.");
}
}
void CScriptWizard::OnAddEvent()
{
CListBox *listbox = (CListBox *)GetDlgItem(IDC_SCREVT_LISTBOX);
CListBox *scrlb = (CListBox *)GetDlgItem(IDC_SCR_LISTBOX);
char *tempstr;
char evtname[MAX_EVTNAME];
char scrname[MAX_SCRNAME];
ASSERT(listbox->GetCurSel() != LB_ERR);
ASSERT(scrlb->GetCurSel() != LB_ERR);
scrlb->GetText(scrlb->GetCurSel(), scrname);
listbox->GetText(listbox->GetCurSel(), evtname);
tempstr = AddEventBlockToScript(m_ScriptSource, evtname, scrname);
if (!tempstr) {
OutrageMessageBox("Failed to add event to script.\nScript text possibly corrupted.");
return;
}
mem_free(m_ScriptSource);
m_ScriptSource = tempstr;
}
// This code invokes the original OSIRIS editor dialog with the currently loaded script file.
void CScriptWizard::OnEditScript()
{
CScriptStudio studio;
CScriptEditorDlg editor;
if (strlen(ScriptFileName) == 0) {
OutrageMessageBox("There is no script file to add a script to! You must make one.");
return;
}
// check if current module is locked by us.
if (FindGamefileName(ScriptFileName) != -1) {
if (mng_FindTrackLock(ScriptFileName, PAGETYPE_GAMEFILE) == -1) {
OutrageMessageBox("Warning: This script is not locked by you.\nAny changes you make will not be permanent.");
}
}
//@@**
//@@**// Do default external editor stuff. Jeff Slutter's code.
//@@** if(strlen(Default_external_editor)==0)
//@@** {
//@@** char buffer[256];
//@@** CString default_path;
//@@** int size=GetWindowsDirectory(buffer,256);
//@@** ASSERT(size<256);
//@@** buffer[size]='\\';
//@@** buffer[size+1]='\0';
//@@**
//@@** default_path=buffer;
//@@** default_path+="Notepad.exe";
//@@** editor.SetExternalEditor(default_path.GetBuffer(1));
//@@** }
//@@** else
//@@** {
//@@** editor.SetExternalEditor(Default_external_editor);
//@@** }
// Now just set the current source loaded as the editor's source
// Also create a program so that the compiler can
char buf[64];
CListBox *scrlistbox = (CListBox *)GetDlgItem(IDC_SCR_LISTBOX);
scrlistbox->GetText(scrlistbox->GetCurSel(), buf);
studio.SelectText(buf);
studio.SetD3XObject(m_ScriptCode);
studio.SetText(CString(m_ScriptSource));
if (studio.DoModal() == IDOK) {
//Try and compile now
CString tempstr;
FreeScript(m_ScriptSource);
studio.GetText(tempstr);
m_ScriptSource = (char *) mem_malloc(tempstr.GetLength()+1);
if(m_ScriptSource) {
strcpy(m_ScriptSource, (LPCSTR)tempstr);
SaveScript(ScriptFileName, m_ScriptSource);
FreeScript(m_ScriptSource);
m_ScriptSource = LoadScript(ScriptFileName); // After this, Source_script has new edited script.
if (!CompileScript(studio.GetD3XObject(), m_ScriptSource)) {
OutrageMessageBox("Your script did not compile. Unless you fix it, the script will not work.");
}
else {
SaveScriptCode(ScriptCodeName, studio.GetD3XObject());
}
}
else {
OutrageMessageBox("Couldn't allocate memory to save script!");
}
}
m_ScriptCode = studio.GetD3XObject();
// rebuild list of scripts from changes in source code that may have happened.
ResetScriptList();
if (stricmp(ScriptFileName, DEFAULT_SCRIPT_NAME) == 0)
GenerateScriptWizardInfo(m_ScriptSource, false);
else
GenerateScriptWizardInfo(m_ScriptSource, true);
UpdateScriptListbox();
//@@** if(strcmp(editor.m_ExternalEditor,Default_external_editor))
//@@** {
//@@** strcpy(Default_external_editor,editor.m_ExternalEditor.GetBuffer(1));
//@@** }
}
// Uses gamefile locking code!
// This is taken from FilePageDialog.cpp, with some modifications to the outputted text, but uses the GameFile
// page scheme, emulating a script page.
void CScriptWizard::OnLock()
{
int n, r;
mngs_Pagelock temp_pl;
mngs_gamefile_page gamefilepage;
n = FindGamefileName(ScriptFileName);
if (n == -1) {
OutrageMessageBox("Unable to find script file page in the table file.\nOperation can't be completed.");
return;
}
// start the really involved locking process.
if (!mng_MakeLocker()) return;
// Make sure it can be locked
strcpy (temp_pl.name,Gamefiles[n].name);
temp_pl.pagetype=PAGETYPE_GAMEFILE;
r=mng_CheckIfPageLocked (&temp_pl);
if (r==2) {
int answer = OutrageMessageBox (MBOX_YESNO, "This script is not even in the table file, or the database maybe corrupt. Override to 'Unlocked'? (Select NO if you don't know what you're doing)");
if (answer==IDYES) {
strcpy (temp_pl.holder,"UNLOCKED");
if (!mng_ReplacePagelock (temp_pl.name,&temp_pl))
MessageBox (ErrorString,"Error!");
}
}
else if (r<0)
OutrageMessageBox (ErrorString);
else if (r==1)
OutrageMessageBox (InfoString);
else {
// Everything is ok. Tell the network we're locking it and get a copy to
// our local drive
strcpy (temp_pl.holder,TableUser);
if (!mng_ReplacePagelock (temp_pl.name,&temp_pl)) {
MessageBox (ErrorString,"Error!");
mng_EraseLocker();
return;
}
else {
// Search thru the net pagefile and get a new copy in RAM in case anyone
// changed it since we started the editor
if ( mng_FindSpecificGamefilePage (temp_pl.name,&gamefilepage,0)) {
if (mng_AssignGamefilePageToGamefile (&gamefilepage,n)) {
if (!mng_ReplacePage (Gamefiles[n].name,Gamefiles[n].name,n,PAGETYPE_GAMEFILE,1)) {
OutrageMessageBox ("There was problem writing that page locally!");
mng_EraseLocker();
return;
}
OutrageMessageBox ("Script locked.");
}
else
OutrageMessageBox ("There was a problem loading this script. You might encounter problems in dealing with it. Good luck!");
mng_AllocTrackLock(Gamefiles[n].name,PAGETYPE_GAMEFILE);
UpdateDialogButtons();
}
else
OutrageMessageBox ("Couldn't find that script in the table file!");
}
}
mng_EraseLocker();
}
// Uses gamefile unlocking code!
void CScriptWizard::OnUnlock()
{
int n, r;
mngs_Pagelock temp_pl;
n = FindGamefileName(ScriptFileName);
if (n == -1) {
OutrageMessageBox("Unable to find script file page in the table file.\nOperation can't be completed.");
return;
}
if (!mng_MakeLocker())
return;
// Make sure we own this gamefile
strcpy (temp_pl.name,Gamefiles[n].name);
temp_pl.pagetype=PAGETYPE_GAMEFILE;
r=mng_CheckIfPageOwned (&temp_pl,TableUser);
if (r<0)
OutrageMessageBox (ErrorString);
else if (r==0)
OutrageMessageBox (InfoString);
else {
// Change the pagelock state to UNLOCKED
strcpy (temp_pl.holder,"UNLOCKED");
if (!mng_ReplacePagelock (temp_pl.name,&temp_pl)) {
MessageBox (ErrorString,"Error!");
mng_EraseLocker();
return;
}
else {
// Now actually replace the copy on the net with our local one
if (!mng_ReplacePage (Gamefiles[n].name,Gamefiles[n].name,n,PAGETYPE_GAMEFILE,0))
OutrageMessageBox (ErrorString);
else {
// Save this gamefile file to the network for all
// Force the save of the current script file so this actually works
char destname[100],srcname[100];
SaveScript(ScriptFileName, m_ScriptSource);
ddio_MakePath(srcname,LocalD3Dir,"data",Gamefiles[n].dir_name,Gamefiles[n].name,NULL);
ddio_MakePath(destname,NetD3Dir,"data",Gamefiles[n].dir_name,Gamefiles[n].name,NULL);
cf_CopyFile (destname,srcname);
OutrageMessageBox ("Script checked in.");
// Delete it from local pagefile if its there
int dret=mng_DeletePage (Gamefiles[n].name,PAGETYPE_GAMEFILE,1);
ASSERT (dret==1);
mng_EraseLocker();
// Free the tracklock
int p=mng_FindTrackLock (Gamefiles[n].name,PAGETYPE_GAMEFILE);
ASSERT (p!=-1);
mng_FreeTrackLock (p);
UpdateDialogButtons();
}
}
}
}
void CScriptWizard::OnSelChangeScrListbox()
{
CListBox *lb = (CListBox *)GetDlgItem(IDC_SCR_LISTBOX);
m_CurScriptSel = lb->GetCurSel();
if (m_CurScriptSel == LB_ERR) m_CurScriptSel = -1;
}
void CScriptWizard::OnSelchangeScrevtListbox()
{
CListBox *lb = (CListBox *)GetDlgItem(IDC_SCREVT_LISTBOX);
m_CurEventSel = lb->GetCurSel();
UpdateDialogButtons();
}
// User Interface Update Controllers
// ListBox
// ComboBox
void CScriptWizard::LoadCurrentModule()
{
CComboBox *modcbox = (CComboBox *)GetDlgItem(IDC_SCRMOD_BOX);
char str[MAX_SCRNAME];
// Get current module select and load it in.
if (m_ScriptSource)
FreeScript(m_ScriptSource);
m_ScriptSource = NULL;
if (modcbox->GetLBText(modcbox->GetCurSel(), str) != CB_ERR) {
char *ptr;
m_ScriptSource = LoadScript(str);
strcpy(ScriptFileName, str);
strcpy(ScriptCodeName, str);
ptr = strtok(ScriptCodeName, ".");
strcat(ptr, ".d3x");
}
// new script file, set current script to 0
m_CurScriptSel = 0;
// compile and generate list of script names.
ResetScriptList();
if (m_ScriptSource) {
if (stricmp(ScriptFileName, DEFAULT_SCRIPT_NAME) == 0)
GenerateScriptWizardInfo(m_ScriptSource, false);
else
GenerateScriptWizardInfo(m_ScriptSource, true);
}
UpdateScriptListbox();
}
void CScriptWizard::UpdateScriptListbox()
{
CListBox *scrlistbox = (CListBox *)GetDlgItem(IDC_SCR_LISTBOX);
int i;
// Add script names to list box
scrlistbox->ResetContent();
for (i = 0; i < MAX_SCRIPTS; i++)
{
if (Script_names[i].used)
if (!stricmp(ScriptFileName, DEFAULT_SCRIPT_NAME) && !Script_names[i].iscustom)
scrlistbox->AddString(Script_names[i].name);
else if (stricmp(ScriptFileName, DEFAULT_SCRIPT_NAME) && Script_names[i].iscustom)
scrlistbox->AddString(Script_names[i].name);
}
// make sure we reselect the current string.
if (scrlistbox->GetCount() > 0)
scrlistbox->SetCurSel(m_CurScriptSel);
else
m_CurScriptSel = -1;
m_CurEventSel = 0;
UpdateEventListbox();
}
void CScriptWizard::UpdateEventListbox()
{
CListBox *listbox = (CListBox *)GetDlgItem(IDC_SCREVT_LISTBOX);
CListBox *scrlistbox = (CListBox *)GetDlgItem(IDC_SCR_LISTBOX);
int i, id;
char scrname[MAX_SCRNAME];
// Add script names to list box
listbox->ResetContent();
if (m_CurScriptSel > -1) {
// get text from listbox, then get script ID from that name, since names are sorted alphabetically
// in the listbox.
scrlistbox->GetText(m_CurScriptSel, scrname);
id = FindScriptIDFromName(scrname);
for (i = 0; i < MAX_SCREVTS; i++)
listbox->AddString(Script_evt_names[i]);
listbox->SetCurSel(m_CurEventSel);
}
}
void CScriptWizard::OnSelchangeScrmodBox()
{
LoadCurrentModule();
UpdateDialogButtons();
}
void CScriptWizard::UpdateDialogButtons()
{
CButton *btnunlock = (CButton *) GetDlgItem (IDC_UNLOCK);
CButton *btnlock = (CButton *)GetDlgItem(IDC_LOCK);
CButton *btnedit = (CButton *)GetDlgItem(IDC_EDITSCRIPT);
CButton *btnevt = (CButton *)GetDlgItem(IDC_ADDEVENT);
CButton *btnundolock = (CButton *)GetDlgItem(IDC_UNDOLOCK);
CListBox *evtlb = (CListBox *)GetDlgItem(IDC_SCREVT_LISTBOX);
int n;
char str[128];
// take care of script locking and unlocking buttons
if (stricmp(ScriptFileName, DEFAULT_SCRIPT_NAME) == 0)
n = FindGamefileName(ScriptFileName);
else
n = -1;
if (n == -1) {
btnunlock->EnableWindow(FALSE);
btnlock->EnableWindow(FALSE);
btnundolock->EnableWindow(FALSE);
}
else if (mng_FindTrackLock (Gamefiles[n].name,PAGETYPE_GAMEFILE)==-1) {
btnunlock->EnableWindow (FALSE);
btnlock->EnableWindow (TRUE);
btnundolock->EnableWindow(FALSE);
}
else {
btnunlock->EnableWindow(TRUE);
btnlock->EnableWindow (FALSE);
btnundolock->EnableWindow(TRUE);
}
// take care of Editing buttons
if (evtlb->GetCurSel() == LB_ERR)
btnevt->EnableWindow(FALSE);
else {
evtlb->GetText(m_CurEventSel, str);
btnevt->EnableWindow(TRUE);
}
if (strlen(ScriptFileName) > 0)
btnedit->EnableWindow(TRUE);
else
btnedit->EnableWindow(FALSE);
}