mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
726 lines
27 KiB
C++
726 lines
27 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/ScriptCompilerAPI.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003-08-26 03:57:38 $
|
|
* $Author: kevinb $
|
|
*
|
|
* Implementation files for for the script compiler API
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
*
|
|
* 16 6/17/99 10:24a Kevin
|
|
* Made things work in a release build
|
|
*
|
|
* 15 6/08/99 4:14p Jeff
|
|
* added some #ifdefs for new editor, so it can be used in the new editor
|
|
* project
|
|
*
|
|
* 14 2/23/99 11:52p Jeff
|
|
* new script dll sync dialog
|
|
*
|
|
* 13 2/17/99 6:54p Jeff
|
|
* added check box for auto check in/out scripts with levels...fix
|
|
* checksum mprintf bug
|
|
*
|
|
* 12 2/17/99 3:24a Jeff
|
|
* added checksum parameter
|
|
*
|
|
* 11 1/15/99 5:27p Jeff
|
|
* possible long filename fix
|
|
*
|
|
* 10 1/13/99 5:00p Jeff
|
|
* auto generate string table stuff
|
|
*
|
|
* 9 1/05/99 4:33p Jeff
|
|
* oops, forgot STDCALL when making SaveRestoreState
|
|
*
|
|
* 8 12/31/98 2:37p Jeff
|
|
* added SaveRestoreState import function
|
|
*
|
|
* 7 12/21/98 6:21p Jeff
|
|
* added comments to generated blank scripts
|
|
*
|
|
* 6 12/18/98 4:32p Jeff
|
|
* fixed code that creates empty script
|
|
*
|
|
* 5 12/18/98 2:37p Jeff
|
|
* updated the create new script file
|
|
*
|
|
* 4 12/14/98 11:32a Jeff
|
|
* started work on osiris load and bind functions
|
|
*
|
|
* 3 12/13/98 7:50p Jeff
|
|
* automatically add new DLLs that aren't in the manage
|
|
* system...implemented create new script function, even though it's still
|
|
* in infancy.
|
|
*
|
|
* 2 12/13/98 3:09a Jeff
|
|
* Initial creation, added ScriptCompile() function
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "ScriptCompilerAPI.h"
|
|
#include "appdatabase.h"
|
|
#include "descent.h"
|
|
#include "cfile.h"
|
|
#include "manage.h"
|
|
#include "pserror.h"
|
|
#include "mem.h"
|
|
#include "ddio.h"
|
|
#include "osiris_dll.h"
|
|
#include <stdarg.h>
|
|
|
|
#ifdef NEWEDITOR
|
|
#include "../neweditor/globals.h"
|
|
#endif
|
|
|
|
int ScriptCompile(tCompilerInfo *ci) {
|
|
char Compiler_path[_MAX_PATH];
|
|
int Warning_level = -1;
|
|
int Debug_type = -1;
|
|
int len = _MAX_PATH;
|
|
|
|
if (!cfexist(ci->source_filename))
|
|
return CERR_SOURCENOEXIST;
|
|
|
|
#ifndef NEWEDITOR
|
|
// make sure there is a compiler defined
|
|
if (Database->read("EditorCompiler", Compiler_path, &len)) {
|
|
if (!cfexist(Compiler_path)) {
|
|
OutrageMessageBox(
|
|
"The configured virtual compiler (%s)\ncannot be found. Please make sure\nyou have specified a proper path "
|
|
"and\nthe file exists. Go into the Script and\nLevel dialog to configure your compiler.",
|
|
Compiler_path);
|
|
return CERR_COMPILERMISSING;
|
|
}
|
|
} else {
|
|
OutrageMessageBox(
|
|
"You haven't configured a virtual compiler to use.\nPlease go into the Script and Level Interface\nof the "
|
|
"editor and select the configure button\nto configure a virtual compiler to use.\nFind Jeff for help on this.");
|
|
return CERR_NOCOMPILERDEFINED;
|
|
}
|
|
|
|
Database->read_int("EditorVCWarningLevel", &Warning_level);
|
|
Database->read_int("EditorVCDebugLevel", &Debug_type);
|
|
#else
|
|
// New Editor setup
|
|
|
|
// Determine the compiler
|
|
CString cs_Compiler_Path = AfxGetApp()->GetProfileString("settings", "EditorCompiler", "");
|
|
if (cs_Compiler_Path.GetLength() > 1) {
|
|
if (!cfexist(cs_Compiler_Path.GetBuffer(0))) {
|
|
OutrageMessageBox(
|
|
"The configured virtual compiler (%s)\ncannot be found. Please make sure\nyou have specified a proper path "
|
|
"and\nthe file exists. Select the configure button\nto configure your virtual compiler.",
|
|
cs_Compiler_Path.GetBuffer(0));
|
|
return CERR_COMPILERMISSING;
|
|
} else {
|
|
// valid compiler
|
|
strcpy(Compiler_path, cs_Compiler_Path.GetBuffer(0));
|
|
}
|
|
} else {
|
|
OutrageMessageBox("You haven't configured a virtual compiler to use.\nPlease select the configure option\nto "
|
|
"configure a virtual compiler to use.");
|
|
return CERR_NOCOMPILERDEFINED;
|
|
}
|
|
|
|
// Determine the Warning level
|
|
Warning_level = AfxGetApp()->GetProfileInt("settings", "EditorVCWarningLevel", 3);
|
|
ASSERT(Warning_level >= 0 && Warning_level <= 4);
|
|
if (Warning_level < 0 || Warning_level > 4)
|
|
Warning_level = 3;
|
|
|
|
// Determine the Debug type
|
|
Debug_type = AfxGetApp()->GetProfileInt("settings", "EditorVCDebugLevel", 2);
|
|
ASSERT(Debug_type >= 0 && Debug_type <= 2);
|
|
if (Debug_type < 0 || Debug_type > 2)
|
|
Debug_type = 2;
|
|
|
|
#endif
|
|
|
|
SECURITY_ATTRIBUTES sa = {0};
|
|
STARTUPINFO si = {0};
|
|
PROCESS_INFORMATION pi = {0};
|
|
HANDLE hPipeOutputRead = NULL;
|
|
HANDLE hPipeOutputWrite = NULL;
|
|
HANDLE hPipeInputRead = NULL;
|
|
HANDLE hPipeInputWrite = NULL;
|
|
BOOL bTest = 0;
|
|
DWORD dwNumberOfBytesRead = 0;
|
|
CHAR szBuffer[256];
|
|
|
|
sa.nLength = sizeof(sa);
|
|
sa.bInheritHandle = TRUE;
|
|
sa.lpSecurityDescriptor = NULL;
|
|
|
|
// Create pipe for standard output redirection.
|
|
CreatePipe(&hPipeOutputRead, // read handle
|
|
&hPipeOutputWrite, // write handle
|
|
&sa, // security attributes
|
|
0 // number of bytes reserved for pipe - 0 default
|
|
); // Create pipe for standard input redirection.
|
|
|
|
CreatePipe(&hPipeInputRead, // read handle
|
|
&hPipeInputWrite, // write handle
|
|
&sa, // security attributes
|
|
0 // number of bytes reserved for pipe - 0 default
|
|
);
|
|
|
|
// Make child process use hPipeOutputWrite as standard out,
|
|
// and make sure it does not show on screen.
|
|
si.cb = sizeof(si);
|
|
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
|
si.wShowWindow = SW_HIDE;
|
|
si.hStdInput = hPipeInputRead;
|
|
si.hStdOutput = hPipeOutputWrite;
|
|
si.hStdError = hPipeOutputWrite;
|
|
|
|
CString cline;
|
|
|
|
cline = Compiler_path;
|
|
cline += " -f ";
|
|
cline += "\"";
|
|
cline += ci->source_filename;
|
|
cline += "\"";
|
|
cline += " -dir ";
|
|
cline += LocalScriptDir;
|
|
if (ci->script_type == ST_LEVEL)
|
|
cline += " -level";
|
|
switch (Warning_level) {
|
|
case 0:
|
|
cline += " -w 0";
|
|
break;
|
|
case 1:
|
|
cline += " -w 1";
|
|
break;
|
|
case 2:
|
|
cline += " -w 2";
|
|
break;
|
|
case 3:
|
|
cline += " -w 3";
|
|
break;
|
|
case 4:
|
|
cline += " -w 4";
|
|
break;
|
|
default:
|
|
cline += " -w 3";
|
|
break;
|
|
}
|
|
switch (Debug_type) {
|
|
case 1:
|
|
cline += " -d coff";
|
|
break;
|
|
case 2:
|
|
cline += " -d c7";
|
|
break;
|
|
}
|
|
|
|
// Game structure checksum
|
|
#ifndef NEWEDITOR
|
|
char temp_c[128];
|
|
sprintf(temp_c, " -checksum %lu", Osiris_game_checksum);
|
|
cline += temp_c;
|
|
#endif
|
|
|
|
CreateProcess(NULL, cline.GetBuffer(0), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
|
|
|
|
// Now that handles have been inherited, close it to be safe.
|
|
// You don't want to read or write to them accidentally.
|
|
CloseHandle(hPipeOutputWrite);
|
|
CloseHandle(hPipeInputRead);
|
|
|
|
// Now test to capture DOS application output by reading
|
|
// hPipeOutputRead. Could also write to DOS application
|
|
// standard input by writing to hPipeInputWrite.
|
|
CString temp;
|
|
while (TRUE) {
|
|
bTest = ReadFile(hPipeOutputRead, // handle of the read end of our pipe
|
|
&szBuffer, // address of buffer that receives data
|
|
256, // number of bytes to read
|
|
&dwNumberOfBytesRead, // address of number of bytes read
|
|
NULL // non-overlapped.
|
|
);
|
|
|
|
if (!bTest) {
|
|
break;
|
|
}
|
|
|
|
// do something with data.
|
|
szBuffer[dwNumberOfBytesRead] = 0; // null terminate
|
|
|
|
if (ci->callback) {
|
|
int new_line_count = 0;
|
|
char *ptr = szBuffer;
|
|
while (*ptr) {
|
|
if (*ptr == '\n')
|
|
new_line_count++;
|
|
ptr++;
|
|
}
|
|
char *data, *d_ptr;
|
|
d_ptr = data = (char *)mem_malloc(dwNumberOfBytesRead + 1 + new_line_count);
|
|
if (data) {
|
|
ptr = (char *)szBuffer;
|
|
|
|
while (*ptr) {
|
|
if (*ptr == '\n') {
|
|
*d_ptr = '\r';
|
|
d_ptr++;
|
|
*d_ptr = '\n';
|
|
d_ptr++;
|
|
} else if (*ptr != '\r') {
|
|
*d_ptr = *ptr;
|
|
d_ptr++;
|
|
}
|
|
ptr++;
|
|
}
|
|
*d_ptr = '\0';
|
|
|
|
(*ci->callback)(data);
|
|
mem_free(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait for spawn to finish.
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
// Close all remaining handles
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(hPipeOutputRead);
|
|
CloseHandle(hPipeInputWrite);
|
|
|
|
return CERR_NOERR;
|
|
}
|
|
|
|
bool ScriptCreateEmptyLevelScript(char *filename);
|
|
bool ScriptCreateEmptyGameScript(char *filename);
|
|
bool ScriptCreateEmptyScript(char *filename, uint8_t script_type) {
|
|
if (cfexist(filename)) {
|
|
char buffer[512];
|
|
sprintf(buffer, "A script by the name of %s\nalready exists.", filename);
|
|
AfxMessageBox(buffer, MB_OK);
|
|
return false;
|
|
}
|
|
|
|
switch (script_type) {
|
|
case ST_GAME:
|
|
return ScriptCreateEmptyGameScript(filename);
|
|
break;
|
|
case ST_LEVEL:
|
|
return ScriptCreateEmptyLevelScript(filename);
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#define VERSION "0.1"
|
|
#define O(x) outputtofile x
|
|
CFILE *CurrentFile;
|
|
|
|
void outputtofile(char *format, ...) {
|
|
char buffer[1024];
|
|
va_list marker;
|
|
va_start(marker, format);
|
|
std::vsprintf(buffer, format, marker);
|
|
cf_WriteString(CurrentFile, buffer);
|
|
va_end(marker);
|
|
}
|
|
|
|
bool ScriptCreateEmptyLevelScript(char *filename) {
|
|
char fullpath[_MAX_PATH];
|
|
ddio_MakePath(fullpath, LocalScriptDir, filename, NULL);
|
|
CurrentFile = cfopen(fullpath, "wt");
|
|
if (!CurrentFile)
|
|
return false;
|
|
|
|
O(("// %s", filename));
|
|
O(("// %s", VERSION));
|
|
O(("#include <stdio.h>"));
|
|
O(("#include <stdlib.h>"));
|
|
O(("#include <string.h>"));
|
|
O(("#include \"osiris_import.h\""));
|
|
O(("#include \"osiris_common.h\""));
|
|
O((""));
|
|
|
|
O(("#ifdef _MSC_VER //Visual C++ Build"));
|
|
O(("#define STDCALL __stdcall"));
|
|
O(("#define STDCALLPTR *STDCALL"));
|
|
O(("#else //Non-Visual C++ Build"));
|
|
O(("#define STDCALL __attribute__((stdcall))"));
|
|
O(("#define STDCALLPTR STDCALL*"));
|
|
O(("#endif"));
|
|
O((""));
|
|
|
|
O(("#ifdef __cplusplus"));
|
|
O(("extern \"C\"{"));
|
|
O(("#endif"));
|
|
O(("char STDCALL InitializeDLL(tOSIRISModuleInit *func_list);"));
|
|
O(("void STDCALL ShutdownDLL(void);"));
|
|
O(("int STDCALL GetGOScriptID(const char *name,uint8_t is_door);"));
|
|
O(("void STDCALLPTR CreateInstance(int id);"));
|
|
O(("void STDCALL DestroyInstance(int id,void *ptr);"));
|
|
O(("int16_t STDCALL CallInstanceEvent(int id,void *ptr,int event,tOSIRISEventInfo *data);"));
|
|
O(("int STDCALL GetTriggerScriptID(int trigger_room, int trigger_face );"));
|
|
O(("int STDCALL GetCOScriptList( int **list, int **id_list );"));
|
|
O(("int STDCALL SaveRestoreState( void *file_ptr, uint8_t saving_state );"));
|
|
O(("#ifdef __cplusplus"));
|
|
O(("}"));
|
|
O(("#endif"));
|
|
O((""));
|
|
|
|
O(("int String_table_size = 0;"));
|
|
O(("char **String_table = NULL;"));
|
|
O(("static const char *_Error_string = \"!!ERROR MISSING STRING!!\";"));
|
|
O(("static const char *_Empty_string = \"\";"));
|
|
O(("const char *GetStringFromTable(int index)"));
|
|
O(("{"));
|
|
O((" if( (index<0) || (index>=String_table_size) )"));
|
|
O((" return _Error_string;"));
|
|
O((" if(!String_table[index])"));
|
|
O((" return _Empty_string;"));
|
|
O((" return String_table[index];"));
|
|
O(("}"));
|
|
O(("#define TXT(x) GetStringFromTable(x)"));
|
|
|
|
O(("// InitializeDLL"));
|
|
O(("// Purpose:"));
|
|
O(("// This function gets called when the DLL first gets loaded. It will only be called once (until "
|
|
"the"));
|
|
O(("// DLL is unloaded). Passed in is a struct of data passed from the game needed for the DLL to interact"));
|
|
O(("// with D3. Usually this function will just call osicommon_Initialize(), which sets up the imported"));
|
|
O(("// functions. However, you can alloc some memory or whatever in this function, and free it in "
|
|
"ShutdownDLL()."));
|
|
O(("// Note: You cannot call any imported functions until osicommon_Initialize() is called."));
|
|
O(("// Returns 1 if initialization went ok, 0 if there was an error and the DLL should not be loaded."));
|
|
O(("char STDCALL InitializeDLL(tOSIRISModuleInit *func_list)"));
|
|
O(("{"));
|
|
O((" osicommon_Initialize(func_list);"));
|
|
O((" String_table_size = func_list->string_count;"));
|
|
O((" String_table = func_list->string_table;"));
|
|
O((" if(func_list->game_checksum!=CHECKSUM)"));
|
|
O((" { "));
|
|
O((" mprintf(0,\"Game-Checksum FAIL!!! (%%ul!=%%ul)\\n\",func_list->game_checksum,CHECKSUM);"));
|
|
O((" mprintf(0,\"RECOMPILE YOUR SCRIPTS!!!\\n\");"));
|
|
O((" return 0;"));
|
|
O((" }"));
|
|
O((" return 1;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// ShutdownDLL"));
|
|
O(("// Purpose:"));
|
|
O(("// This function is called right before a DLL is about to be unloaded from memory. You can "
|
|
"free"));
|
|
O(("// any unfree'd memory, or anything else you need to do. Don't worry about destroying any instances"));
|
|
O(("// of scripts, as they will all be automatically destroyed before this function is called. The"));
|
|
O(("// same goes for any memory allocated with Scrpt_MemAlloc(), as this will automatically be freed"));
|
|
O(("// when a scripts instance is destroyed."));
|
|
O(("void STDCALL ShutdownDLL(void)"));
|
|
O(("{"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// GetGOScriptID"));
|
|
O(("// Purpose:"));
|
|
O(("// Given the name of the object (from it's pagename), this function will search through it's"));
|
|
O(("// list of General Object Scripts for a script with a matching name (to see if there is a script"));
|
|
O(("// for that type/id of object within this DLL). If a matching scriptname is found, a UNIQUE ID"));
|
|
O(("// is to be returned back to Descent 3. This ID will be used from here on out for all future"));
|
|
O(("// interaction with the DLL. Since doors are not part of the generic object's, it's possible"));
|
|
O(("// for a door to have the same name as a generic object (OBJ_POWERUP, OBJ_BUILDING, OBJ_CLUTTER"));
|
|
O(("// or OBJ_ROBOT), therefore, a 1 is passed in for isdoor if the given object name refers to a"));
|
|
O(("// door, else it is a 0. The return value is the unique identifier, else -1 if the script"));
|
|
O(("// does not exist in the DLL."));
|
|
O(("// The only reserved ID is 0, which must be used for the level script"));
|
|
O(("int STDCALL GetGOScriptID(const char *name,uint8_t isdoor)"));
|
|
O(("{"));
|
|
O((" return -1;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// CreateInstance"));
|
|
O(("// Purpose:"));
|
|
O(("// Given an ID from a call to GetGOScriptID(), GetTriggerScriptID() or GetCOScriptList(), this"));
|
|
O(("// function will create a new instance for that particular script (by allocating and initializing"));
|
|
O(("// memory, etc.). A pointer to this instance is to be returned back to Descent 3. This pointer will"));
|
|
O(("// be passed around, along with the ID for CallInstanceEvent() and DestroyInstance(). Return NULL"));
|
|
O(("// if there was an error."));
|
|
O(("// The only reserved ID is 0, which must be used for the level script"));
|
|
O(("void STDCALLPTR CreateInstance(int id)"));
|
|
O(("{"));
|
|
O((" return NULL;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// DestroyInstance"));
|
|
O(("// Purpose:"));
|
|
O(("// Given an ID, and a pointer to a particular instance of a script, this function will delete "
|
|
"and"));
|
|
O(("// destruct all information associated with that script, so it will no longer exist."));
|
|
O(("void STDCALL DestroyInstance(int id,void *ptr)"));
|
|
O(("{"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// CallInstanceEvent"));
|
|
O(("// Purpose:"));
|
|
O(("// Given an ID, a pointer to a script instance, an event and a pointer to the struct of"));
|
|
O(("// information about the event, this function will translate who this event belongs to and"));
|
|
O(("// passes the event to that instance of the script to be handled. Return a combination of"));
|
|
O(("// CONTINUE_CHAIN and CONTINUE_DEFAULT, to give instructions on what to do based on the"));
|
|
O(("// event. CONTINUE_CHAIN means to continue through the chain of scripts (custom script, level"));
|
|
O(("// script, mission script, and finally default script). If CONTINUE_CHAIN is not specified,"));
|
|
O(("// than the chain is broken and those scripts of lower priority will never get the event. Return"));
|
|
O(("// CONTINUE_DEFAULT in order to tell D3 if you want process the normal action that is built into"));
|
|
O(("// the game for that event. This only pertains to certain events. If the chain continues"));
|
|
O(("// after this script, than the CONTINUE_DEFAULT setting will be overridden by lower priority"));
|
|
O(("// scripts return value."));
|
|
O(("// The only reserved ID is 0, which must be used for the level script"));
|
|
O(("int16_t STDCALL CallInstanceEvent(int id,void *ptr,int event,tOSIRISEventInfo *data)"));
|
|
O(("{"));
|
|
O((" return CONTINUE_CHAIN|CONTINUE_DEFAULT;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// GetTriggerScriptID"));
|
|
O(("// Purpose:"));
|
|
O(("// Given a room and face number, this function will return a unique ID (global DLL unique)"));
|
|
O(("// in which Descent 3 should use for all future interaction will the DLL when refering to"));
|
|
O(("// this trigger. Return -1 if there is no trigger script available for the specified trigger."));
|
|
O(("// The only reserved ID is 0, which must be used for the level script"));
|
|
O(("int STDCALL GetTriggerScriptID(int trigger_room,int trigger_face)"));
|
|
O(("{"));
|
|
O((" return -1;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// GetCOScriptList"));
|
|
O(("// Purpose:"));
|
|
O(("// This function returns the pointers to the 2 arrays that Descent 3 should use to determine"));
|
|
O(("// what object's have custom scripts in this level DLL. list should be set to point to the array"));
|
|
O(("// of object handles that have custom scripts in this DLL. id_list should be set to point to the"));
|
|
O(("// corresponding array of unique IDs that match with the object handle list. This function should"));
|
|
O(("// return the size of the arrays returned...if no custom scripts are available, than this function"));
|
|
O(("// returns 0."));
|
|
O(("// The only reserved ID is 0, which must be used for the level script"));
|
|
O(("int STDCALL GetCOScriptList( int **list, int **id_list )"));
|
|
O(("{"));
|
|
O((" return 0;"));
|
|
O(("}"));
|
|
|
|
O(("// SaveRestoreState"));
|
|
O(("// Purpose:"));
|
|
O(("// This function is called when Descent 3 is saving or restoring the game state. In this "
|
|
"function"));
|
|
O(("// you should save/restore any global data that you want preserved through load/save (which includes"));
|
|
O(("// demos). You must be very careful with this function, corrupting the file (reading or writing too"));
|
|
O(("// much or too little) may be hazardous to the game (possibly making it impossible to restore the"));
|
|
O(("// state). It would be best to use version information to keep older versions of saved states still"));
|
|
O(("// able to be used. IT IS VERY IMPORTANT WHEN SAVING THE STATE TO RETURN THE NUMBER OF _BYTES_ WROTE"));
|
|
O(("// TO THE FILE. When restoring the data, the return value is ignored. saving_state is 1 when you "
|
|
"should"));
|
|
O(("// write data to the file_ptr, 0 when you should read in the data."));
|
|
O(("int STDCALL SaveRestoreState( void *file_ptr, uint8_t saving_state )"));
|
|
O(("{"));
|
|
O((" return 0;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
cfclose(CurrentFile);
|
|
return true;
|
|
}
|
|
|
|
bool ScriptCreateEmptyGameScript(char *filename) {
|
|
char fullpath[_MAX_PATH];
|
|
ddio_MakePath(fullpath, LocalScriptDir, filename, NULL);
|
|
CurrentFile = cfopen(fullpath, "wt");
|
|
if (!CurrentFile)
|
|
return false;
|
|
|
|
O(("// %s", filename));
|
|
O(("// %s", VERSION));
|
|
O(("#include <stdio.h>"));
|
|
O(("#include <stdlib.h>"));
|
|
O(("#include <string.h>"));
|
|
O(("#include \"osiris_import.h\""));
|
|
O(("#include \"osiris_common.h\""));
|
|
O((""));
|
|
|
|
O(("#ifdef _MSC_VER //Visual C++ Build"));
|
|
O(("#define STDCALL __stdcall"));
|
|
O(("#define STDCALLPTR *STDCALL"));
|
|
O(("#else //Non-Visual C++ Build"));
|
|
O(("#define STDCALL __attribute__((stdcall))"));
|
|
O(("#define STDCALLPTR STDCALL*"));
|
|
O(("#endif"));
|
|
O((""));
|
|
|
|
O(("#ifdef __cplusplus"));
|
|
O(("extern \"C\"{"));
|
|
O(("#endif"));
|
|
O(("char STDCALL InitializeDLL(tOSIRISModuleInit *func_list);"));
|
|
O(("void STDCALL ShutdownDLL(void);"));
|
|
O(("int STDCALL GetGOScriptID(const char *name,uint8_t isdoor);"));
|
|
O(("void STDCALLPTR CreateInstance(int id);"));
|
|
O(("void STDCALL DestroyInstance(int id,void *ptr);"));
|
|
O(("int16_t STDCALL CallInstanceEvent(int id,void *ptr,int event,tOSIRISEventInfo *data);"));
|
|
O(("int STDCALL SaveRestoreState( void *file_ptr, uint8_t saving_state );"));
|
|
O(("#ifdef __cplusplus"));
|
|
O(("}"));
|
|
O(("#endif"));
|
|
O((""));
|
|
|
|
O(("int String_table_size = 0;"));
|
|
O(("char **String_table = NULL;"));
|
|
O(("static char *_Error_string = \"!!ERROR MISSING STRING!!\";"));
|
|
O(("static char *_Empty_string = \"\";"));
|
|
O(("const char *GetStringFromTable(int index)"));
|
|
O(("{"));
|
|
O((" if( (index<0) || (index>=String_table_size) )"));
|
|
O((" return _Error_string;"));
|
|
O((" if(!String_table[index])"));
|
|
O((" return _Empty_string;"));
|
|
O((" return String_table[index];"));
|
|
O(("}"));
|
|
O(("#define TXT(x) GetStringFromTable(x)"));
|
|
|
|
O(("// InitializeDLL"));
|
|
O(("// Purpose:"));
|
|
O(("// This function gets called when the DLL first gets loaded. It will only be called once (until "
|
|
"the"));
|
|
O(("// DLL is unloaded). Passed in is a struct of data passed from the game needed for the DLL to interact"));
|
|
O(("// with D3. Usually this function will just call osicommon_Initialize(), which sets up the imported"));
|
|
O(("// functions. However, you can alloc some memory or whatever in this function, and free it in "
|
|
"ShutdownDLL()."));
|
|
O(("// Note: You cannot call any imported functions until osicommon_Initialize() is called."));
|
|
O(("// Returns 1 if initialization went ok, 0 if there was an error and the DLL should not be loaded."));
|
|
O(("char STDCALL InitializeDLL(tOSIRISModuleInit *func_list)"));
|
|
O(("{"));
|
|
O((" osicommon_Initialize((tOSIRISModuleInit *)func_list);"));
|
|
O((" String_table_size = func_list->string_count;"));
|
|
O((" String_table = func_list->string_table;"));
|
|
O((" if(func_list->game_checksum!=CHECKSUM)"));
|
|
O((" { "));
|
|
O((" mprintf(0,\"Game-Checksum FAIL!!! (%%ul!=%%ul)\\n\",func_list->game_checksum,CHECKSUM);"));
|
|
O((" mprintf(0,\"RECOMPILE YOUR SCRIPTS!!!\\n\");"));
|
|
O((" return 0;"));
|
|
O((" }"));
|
|
O((" return 1;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// ShutdownDLL"));
|
|
O(("// Purpose:"));
|
|
O(("// This function is called right before a DLL is about to be unloaded from memory. You can "
|
|
"free"));
|
|
O(("// any unfree'd memory, or anything else you need to do. Don't worry about destroying any instances"));
|
|
O(("// of scripts, as they will all be automatically destroyed before this function is called. The"));
|
|
O(("// same goes for any memory allocated with Scrpt_MemAlloc(), as this will automatically be freed"));
|
|
O(("// when a scripts instance is destroyed."));
|
|
O(("void STDCALL ShutdownDLL(void)"));
|
|
O(("{"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// GetGOScriptID"));
|
|
O(("// Purpose:"));
|
|
O(("// Given the name of the object (from it's pagename), this function will search through it's"));
|
|
O(("// list of General Object Scripts for a script with a matching name (to see if there is a script"));
|
|
O(("// for that type/id of object within this DLL). If a matching scriptname is found, a UNIQUE ID"));
|
|
O(("// is to be returned back to Descent 3. This ID will be used from here on out for all future"));
|
|
O(("// interaction with the DLL. Since doors are not part of the generic object's, it's possible"));
|
|
O(("// for a door to have the same name as a generic object (OBJ_POWERUP, OBJ_BUILDING, OBJ_CLUTTER"));
|
|
O(("// or OBJ_ROBOT), therefore, a 1 is passed in for isdoor if the given object name refers to a"));
|
|
O(("// door, else it is a 0. The return value is the unique identifier, else -1 if the script"));
|
|
O(("// does not exist in the DLL."));
|
|
O(("int STDCALL GetGOScriptID(const char *name,uint8_t isdoor)"));
|
|
O(("{"));
|
|
O((" return -1;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// CreateInstance"));
|
|
O(("// Purpose:"));
|
|
O(("// Given an ID from a call to GetGOScriptID(), this function will create a new instance for "
|
|
"that"));
|
|
O(("// particular script (by allocating and initializing memory, etc.). A pointer to this instance"));
|
|
O(("// is to be returned back to Descent 3. This pointer will be passed around, along with the ID"));
|
|
O(("// for CallInstanceEvent() and DestroyInstance(). Return NULL if there was an error."));
|
|
O(("void STDCALLPTR CreateInstance(int id)"));
|
|
O(("{"));
|
|
O((" return NULL;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// DestroyInstance"));
|
|
O(("// Purpose:"));
|
|
O(("// Given an ID, and a pointer to a particular instance of a script, this function will delete "
|
|
"and"));
|
|
O(("// destruct all information associated with that script, so it will no longer exist."));
|
|
O(("void STDCALL DestroyInstance(int id,void *ptr)"));
|
|
O(("{"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// CallInstanceEvent"));
|
|
O(("// Purpose:"));
|
|
O(("// Given an ID, a pointer to a script instance, an event and a pointer to the struct of"));
|
|
O(("// information about the event, this function will translate who this event belongs to and"));
|
|
O(("// passes the event to that instance of the script to be handled. Return a combination of"));
|
|
O(("// CONTINUE_CHAIN and CONTINUE_DEFAULT, to give instructions on what to do based on the"));
|
|
O(("// event. CONTINUE_CHAIN means to continue through the chain of scripts (custom script, level"));
|
|
O(("// script, mission script, and finally default script). If CONTINUE_CHAIN is not specified,"));
|
|
O(("// than the chain is broken and those scripts of lower priority will never get the event. Return"));
|
|
O(("// CONTINUE_DEFAULT in order to tell D3 if you want process the normal action that is built into"));
|
|
O(("// the game for that event. This only pertains to certain events. If the chain continues"));
|
|
O(("// after this script, than the CONTINUE_DEFAULT setting will be overridden by lower priority"));
|
|
O(("// scripts return value."));
|
|
O(("int16_t STDCALL CallInstanceEvent(int id,void *ptr,int event,tOSIRISEventInfo *data)"));
|
|
O(("{"));
|
|
O((" return CONTINUE_CHAIN|CONTINUE_DEFAULT;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
O(("// SaveRestoreState"));
|
|
O(("// Purpose:"));
|
|
O(("// This function is called when Descent 3 is saving or restoring the game state. In this "
|
|
"function"));
|
|
O(("// you should save/restore any global data that you want preserved through load/save (which includes"));
|
|
O(("// demos). You must be very careful with this function, corrupting the file (reading or writing too"));
|
|
O(("// much or too little) may be hazardous to the game (possibly making it impossible to restore the"));
|
|
O(("// state). It would be best to use version information to keep older versions of saved states still"));
|
|
O(("// able to be used. IT IS VERY IMPORTANT WHEN SAVING THE STATE TO RETURN THE NUMBER OF _BYTES_ WROTE"));
|
|
O(("// TO THE FILE. When restoring the data, the return value is ignored. saving_state is 1 when you "
|
|
"should"));
|
|
O(("// write data to the file_ptr, 0 when you should read in the data."));
|
|
O(("int STDCALL SaveRestoreState( void *file_ptr, uint8_t saving_state )"));
|
|
O(("{"));
|
|
O((" return 0;"));
|
|
O(("}"));
|
|
O((""));
|
|
|
|
cfclose(CurrentFile);
|
|
return true;
|
|
}
|