/* * 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 . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/ScriptStudio.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:39 $ * $Author: kevinb $ * * Script Studio New Editor * * $Log: not supported by cvs2svn $ * * 17 10/13/98 11:42a Samir * this may fix things? * * 16 10/08/98 4:24p Kevin * Changed code to comply with memory library usage. Always use mem_malloc * , mem_free and mem_strdup * * 15 7/13/98 11:13a Chris * Fixed the 65535 charactor limit with Kevin's help * * 14 6/23/98 2:43p Matt * Changed calls to OutrageMessageBox() & Debug_MessageBox() to deal with * int return value (instead of bool). * * 13 4/06/98 4:55p Samir * no bold text. * * 12 4/06/98 2:49p Samir * Fixed width font. * * 11 3/24/98 6:35p Samir * added script studio exit * * 10 3/24/98 4:29p Samir * report correct line number. * * 9 3/04/98 5:54p Samir * Added line number gauge to script studio. * * 8 3/02/98 4:03p Samir * Created a function to open up a script studio window. * * 7 10/15/97 3:05p Samir * Improved paste a little bit. * * 6 9/26/97 4:15p Samir * Mostly working system to go to a certain script in a file. * * 5 9/25/97 5:28p Samir * Even newer script code due to more changes in ObjCScript.cpp * * 4 9/04/97 4:39p Matt * Added includes needed as a result of removing includes from d3edit.h * * 3 8/20/97 3:35p Samir * Enhanced ScriptStudio to use tabs! Use new ScriptStudio instead of * ScriptEditor. * * $NoKeywords: $ */ // ScriptStudio.cpp : implementation file // #include "stdafx.h" #include "editor.h" #include "ScriptStudio.h" #include "OsirisStatusDlg.h" #include "ObjCScript.h" #include "mem.h" #include "pserror.h" #include "d3x.h" #include "ddio.h" #include "cfile.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define MAX_SCRIPT_LINE_SIZE 800 static UINT WM_FINDREPLACE =RegisterWindowMessage(FINDMSGSTRING); ///////////////////////////////////////////////////////////////////////////// // CScriptStudio dialog CScriptStudio::CScriptStudio(CWnd* pParent /*=NULL*/) : CDialog(CScriptStudio::IDD, pParent) { //{{AFX_DATA_INIT(CScriptStudio) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_pdlgFindReplace = NULL; } void CScriptStudio::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CScriptStudio) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } void CScriptStudio::SetText(const CString& text) { m_EditText = text; m_EditInitial = text; } void CScriptStudio::SetD3XObject(tD3XProgram *prog) { m_D3XProgram = prog; } void CScriptStudio::GetText(CString& text) { text = m_EditText; } void CScriptStudio::UpdateEditText() { CHARRANGE chr; m_RichEdit.HideCaret(); m_RichEdit.GetSel(chr); m_RichEdit.SetSel(0,-1); m_EditText = m_RichEdit.GetSelText(); m_RichEdit.SetSel(chr); m_RichEdit.ShowCaret(); // m_RichEdit.GetWindowText(m_EditText); } void CScriptStudio::SelectText(const char *txt) { m_SelectText = txt; } BEGIN_MESSAGE_MAP(CScriptStudio, CDialog) //{{AFX_MSG_MAP(CScriptStudio) ON_COMMAND(ID_OSIRIS_COMPILE_SCRIPT, OnOsirisCompileScript) ON_COMMAND(ID_OSIRIS_COPY, OnOsirisCopy) ON_COMMAND(ID_OSIRIS_CUT, OnOsirisCut) ON_COMMAND(ID_OSIRIS_EXPORT_SCRIPT, OnOsirisExportScript) ON_COMMAND(ID_OSIRIS_FIND, OnOsirisFind) ON_COMMAND(ID_OSIRIS_FIND_AND_REPLACE, OnOsirisFindAndReplace) ON_COMMAND(ID_OSIRIS_IMPORT_SCRIPT, OnOsirisImportScript) ON_COMMAND(ID_OSIRIS_PASTE, OnOsirisPaste) ON_COMMAND(ID_OSIRIS_SAVE_EXIT, OnOsirisSaveExit) ON_COMMAND(ID_OSIRIS_SET_EXTERNAL, OnOsirisSetExternal) ON_COMMAND(ID_OSIRIS_USE_EXTERNAL, OnOsirisUseExternal) ON_UPDATE_COMMAND_UI(ID_OSIRIS_PASTE, OnUpdateOsirisPaste) ON_NOTIFY(EN_MSGFILTER, IDC_SCRIPTVIEW, OnMsgfilterScriptView) ON_WM_DESTROY() ON_COMMAND(ID_EXIT, OnExit) //}}AFX_MSG_MAP ON_REGISTERED_MESSAGE(WM_FINDREPLACE,OnFindReplace) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CScriptStudio message handlers BOOL CScriptStudio::OnInitDialog() { RECT rect; CWnd *wnd; PARAFORMAT pf; CHARFORMAT cf; m_RichEditInit = false; CDialog::OnInitDialog(); // Create our Rich Edit Control add keyboard handler for those SPECIAL keys like TAB. wnd = GetDlgItem(IDC_SCRMOD_BOX); wnd->GetWindowRect(&rect); rect.left += 2; rect.right -= 2; rect.top += 2; rect.bottom-=2; ScreenToClient(&rect); m_RichEdit.Create(WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_SAVESEL | ES_NOHIDESEL | WS_VSCROLL, rect, this, IDC_SCRIPTVIEW); m_RichEdit.SetEventMask(ENM_KEYEVENTS | ENM_MOUSEEVENTS); m_RichEdit.LimitText(0); m_RichEdit.GetParaFormat(pf); pf.cbSize = sizeof(pf); pf.dwMask = PFM_TABSTOPS; pf.cTabCount = MAX_TAB_STOPS; for (int i = 0; i < pf.cTabCount; i++) pf.rgxTabs[i] = 360 * (i+1); m_RichEdit.SetParaFormat(pf); m_RichEdit.SetWindowText((LPCSTR)m_EditText); FindNext((char *)(LPCSTR)m_SelectText); // sets character format ZeroMemory(&cf, sizeof(cf)); cf.dwMask = CFM_FACE | CFM_CHARSET | CFM_BOLD; strcpy(cf.szFaceName, "Courier"); cf.bCharSet = DEFAULT_CHARSET; cf.bPitchAndFamily = FIXED_PITCH | FF_DONTCARE; m_RichEdit.SetDefaultCharFormat(cf); // set linenumber CStatic *linenum = (CStatic *)GetDlgItem(IDC_LINENUM); char buf[8]; sprintf(buf, "%d", m_RichEdit.LineFromChar(-1)+1); linenum->SetWindowText(buf); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CScriptStudio::OnDestroy() { CDialog::OnDestroy(); } // The Key handler for the editor. Handles TAB chars. void CScriptStudio::OnMsgfilterScriptView(NMHDR* pNMHDR, LRESULT* pResult) { MSGFILTER *pMsgFilter = reinterpret_cast(pNMHDR); // TODO: The control will not send this notification unless you override the // CDialog::OnInitDialog() function to send the EM_SETEVENTMASK message // to the control with either the ENM_KEYEVENTS or ENM_MOUSEEVENTS flag // ORed into the lParam mask. switch (pMsgFilter->msg) { case WM_KEYDOWN: if (pMsgFilter->wParam == VK_TAB) m_RichEdit.ReplaceSel("\t"); *pResult = 0; break; } CStatic *linenum = (CStatic *)GetDlgItem(IDC_LINENUM); char buf[8]; sprintf(buf, "%d", m_RichEdit.LineFromChar(-1)+1); linenum->SetWindowText(buf); } // Process all commands to and from Rich Edit Control here. BOOL CScriptStudio::OnCommand(WPARAM wParam, LPARAM lParam) { int nCode = HIWORD(wParam); int nID = LOWORD(wParam); switch (nID) { case IDC_SCRIPTVIEW: HandleEditControl(nID, nCode); break; } return CDialog::OnCommand(wParam, lParam); } void CScriptStudio::OnOK() { ddio_KeyFlush(); UpdateEditText(); CDialog::OnOK(); } void CScriptStudio::OnCancel() { ddio_KeyFlush(); if (m_EditInitial != m_EditText) if (OutrageMessageBox(MBOX_YESNO, "You have made changes to this script that won't be saved. Are you sure?") != IDYES) return; CDialog::OnCancel(); } ///////////////////////////////////////////////////////////////////////////////////////////// // Menu functions. void CScriptStudio::OnOsirisSaveExit() { m_EditInitial = m_EditText; OnOK(); } void CScriptStudio::OnOsirisSetExternal() { // OnSetExternalViewer(); } void CScriptStudio::OnOsirisUseExternal() { // OnUseExternal(); } void CScriptStudio::OnOsirisCompileScript() { COsirisStatusDlg progress_status; UpdateEditText(); progress_status.SetScript(m_EditText.GetBuffer(1), m_D3XProgram); progress_status.DoModal(); } void CScriptStudio::OnOsirisImportScript() { CString path; CString filter = "All Files (*.*)|*.*||"; CFileDialog dlg(true, 0,0, OFN_FILEMUSTEXIST, (LPCTSTR)filter, this); if(dlg.DoModal()==IDOK) { path=dlg.GetPathName(); ImportScript(path.GetBuffer(1)); } } void CScriptStudio::OnOsirisExportScript() { CString path; CString filter = "All Files (*.*)|*.*||"; CFileDialog dlg(false, 0,0, OFN_OVERWRITEPROMPT, (LPCTSTR)filter, this); if(dlg.DoModal()==IDOK) { path=dlg.GetPathName(); ExportScript(path.GetBuffer(1)); } } ////////////////////////////////////////////////////////////////////////////// // Editing and Clipboard functionality void CScriptStudio::OnOsirisFind() { InitFindReplace(true); } void CScriptStudio::OnOsirisFindAndReplace() { // TODO: Add your command handler code here InitFindReplace(false); } void CScriptStudio::OnOsirisPaste() { m_RichEdit.Paste(); m_RichEdit.RedrawWindow(); } void CScriptStudio::OnOsirisCopy() { m_RichEdit.Copy(); } void CScriptStudio::OnOsirisCut() { m_RichEdit.Cut(); } void CScriptStudio::OnUpdateOsirisPaste(CCmdUI* pCmdUI) { //this doesn't work right...don't know why if(IsClipboardFormatAvailable(CF_TEXT)) pCmdUI->Enable(true); else pCmdUI->Enable(false); } ///////////////////////////////////////////////////////////////////////////////////////////// // These Functions deal with user interface issues within the editor like Find-Replace. //This is the message handler of sorts for the Find/Replace dialog, it interprets the message and passes the control //to the appropriate function LONG CScriptStudio::OnFindReplace(WPARAM wParam, LPARAM lParam) { // Get a pointer to the calling dialog CFindReplaceDialog* pDlg = CFindReplaceDialog::GetNotifier(lParam); ASSERT(pDlg != NULL); // See what the user is up to out there... if (pDlg->IsTerminating()) { // Time to kill the dialog box return 0; } if (pDlg->ReplaceAll()) { // Put a call to your ReplaceAll() method here... CString find,repl; find=pDlg->GetFindString(); repl=pDlg->GetReplaceString(); if(pDlg->MatchCase()) m_FindMatchCase=true; else m_FindMatchCase=false; ReplaceAll(find.GetBuffer(1),repl.GetBuffer(1)); return 0; } if (pDlg->ReplaceCurrent()) { // Put a call to your ReplaceCurrent() method here... CString repl; repl=pDlg->GetReplaceString(); if(pDlg->MatchCase()) m_FindMatchCase=true; else m_FindMatchCase=false; ReplaceCurrent(repl.GetBuffer(1)); return 0; } CString str; if(pDlg->MatchCase()) m_FindMatchCase=true; else m_FindMatchCase=false; str=pDlg->GetFindString(); FindNext(str.GetBuffer(1)); return 0; } //This initializes a Find/Replace dialog box (if bFind==false it sets up a Find and Replace, else it's just Find) void CScriptStudio::InitFindReplace(BOOL bFind) { // // If the dialog has been called already, and then closed, // the pointer is still non-NULL, but the object is already // dead, so reset the pointer! // m_pdlgFindReplace = NULL; m_LastWord=" "; // Construct the dialog m_pdlgFindReplace = new CFindReplaceDialog; ASSERT(m_pdlgFindReplace != NULL); // Initialize the dialog if (!m_pdlgFindReplace->Create(bFind, 0, 0, FR_DOWN, this)) { mprintf(0,"Error allocating find/replace dialog!"); m_pdlgFindReplace = NULL; return; } // Display the dialog ASSERT(m_pdlgFindReplace != NULL); m_pdlgFindReplace->SetActiveWindow(); m_pdlgFindReplace->ShowWindow(SW_SHOW); } //This will look for the next series of charaters (given by the null terminated w) //If it finds the string, it will highlight/select it and move the caret to the beginning of the word //returns true if it found the string //else false bool CScriptStudio::FindNext(char *w) { int index,max; bool word_found; bool new_word; static int start=0; word_found=false; //See if this is a new word to look for (as compared to the last searched word) if(m_LastWord!=w) { m_LastWord=w; start=0; new_word=true; } else new_word=false; //This will update the m_sScript string so it has the current script in it UpdateEditText(); //Make a copy of the script to work with char *text; text = (char *) mem_malloc(m_EditText.GetLength()+1); if (!text) Int3(); strcpy(text,(LPCSTR)m_EditText); max=m_EditText.GetLength(); //Make sure we aren't gonna try to go past the end of the buffer, start at 0 if we are if(start+(signed)strlen(w)>=max-1) start=0; //Here we begin the search for(index=start;index=buffer_size) return false; if(text[index+count]!=w[count]) return false; } } else { for(count=0;count=buffer_size) return false; if(toupper(text[index+count])!=toupper(w[count])) return false; } } return true; } ///////////////////////////////////////////////////////////////////////////////////////////// // These function deal with importing and exporting script files. void CScriptStudio::ExportScript(char *filename) { CFILE *file; UpdateEditText(); file=cfopen(filename,"wt"); mprintf(0,"Exporting Script to file %s\n",filename); cf_WriteString(file, m_EditText.GetBuffer(1)); cfclose(file); } void CScriptStudio::ImportScript(char *filename) { CFILE *file; CString temp; int size; char buffer[MAX_SCRIPT_LINE_SIZE]; memset(buffer,0,MAX_SCRIPT_LINE_SIZE); if(!cfexist(filename)) { OutrageMessageBox("File not found!"); return; } file=cfopen(filename,"rt"); mprintf(0,"Importing Script from file %s\n",filename); do { size=cf_ReadString(buffer,MAX_SCRIPT_LINE_SIZE-2,file); buffer[size]='\xd'; buffer[size+1]='\xa'; buffer[size+2]='\0'; temp+=buffer; memset(buffer,0,size); }while(!cfeof(file)); cfclose(file); m_EditText=temp; m_RichEdit.SetWindowText((LPCSTR)m_EditText); } void CScriptStudio::HandleEditControl(int id, int code) { CRichEditCtrl *rec = (CRichEditCtrl *)GetDlgItem(id); switch (code) { case EN_UPDATE: break; } } bool InvokeScriptStudio(const char *filename, const char *scrname) { char *source; CScriptStudio studio; tD3XProgram *script; bool ret = false; // initialize script studio. script = D3XReallocProgram(NULL, 0, 0, 0); if (!script) { OutrageMessageBox("Failure to compile script! Something is wrong!"); return false; } source = LoadScript(filename); if (!source) { OutrageMessageBox("Unable to find script for level. Something is wrong!"); return false; } studio.SelectText(scrname); studio.SetD3XObject(script); studio.SetText(CString(source)); FreeScript(source); if (studio.DoModal() == IDOK) { CString tempstr; studio.GetText(tempstr); source = (char *) mem_malloc(tempstr.GetLength()+1); strcpy(source, tempstr); SaveScript(filename, source); mem_free(source); ret = true; } else { OutrageMessageBox("The level script could not compile and is invalid until corrected."); ret = false; } D3XFreeProgram(script); return ret; } void CScriptStudio::OnExit() { // TODO: Add your command handler code here CDialog::OnOK(); }