This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Scripts/scripts.cpp

699 lines
14 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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/>.
*/
/******************************************************************************
*
* FILE
*
* DESCRIPTION
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* VERSION INFO
* $Author: Byon_g $
* $Revision: 85 $
* $Modtime: 7/05/01 12:12p $
* $Archive: /Commando/Code/Scripts/scripts.cpp $
*
******************************************************************************/
#include "scripts.h"
#include "scriptfactory.h"
#include "dprint.h"
#include "strtrim.h"
#include <string.h>
#include <stdio.h>
#define CHUNKID_SCRIPTHEADER 'shdr'
#define CHUNKID_SCRIPTDATA 'sdat'
#define CHUNKID_SCRIPT_AUTO_VARIABLES 'csav'
enum {
DATAID_PARAMETER_STRING = 1,
DATAID_OWNERPTR,
};
// Script commands
ScriptCommands* Commands = NULL;
void (*ScriptImpClass::Request_Destroy_Script)(ScriptClass*) = NULL;
void ScriptImpClass::Set_Request_Destroy_Func(void (*function)(ScriptClass*))
{
Request_Destroy_Script = function;
}
/******************************************************************************
*
* NAME
* ScriptImpClass::ScriptImpClass
*
* DESCRIPTION
* Constructor for concrete script implementation class
*
* INPUTS
* NONE
*
* RESULTS
* NONE
*
******************************************************************************/
ScriptImpClass::ScriptImpClass()
: mOwner(NULL),
mArgC(0),
mArgV(NULL),
AutoVariableList( NULL )
{
}
/******************************************************************************
*
* NAME
* ScriptImpClass::~ScriptImpClass
*
* DESCRIPTION
* Destructor
*
* INPUTS
* NONE
*
* RESULTS
* NONE
*
******************************************************************************/
ScriptImpClass::~ScriptImpClass()
{
#ifdef _DEBUG
if (Commands != NULL) {
DebugPrint("Script '%s' for object '%d' deleted.\n",
Get_Name(), ((mOwner != NULL) ? Commands->Get_ID(mOwner) : 0 ));
}
#endif
Clear_Parameters();
// Delete the auto variables
while ( AutoVariableList != NULL ) {
ScriptVariableClass * next = AutoVariableList->Get_Next();
delete AutoVariableList;
AutoVariableList = next;
}
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Name
*
* DESCRIPTION
* Retrieve name of script
*
* INPUTS
* NONE
*
* RESULTS
* Name - Script name string.
*
******************************************************************************/
const char* ScriptImpClass::Get_Name(void)
{
return mFactory->GetName();
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Destroy
*
* DESCRIPTION
* Destroy script
*
* INPUTS
* NONE
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Destroy_Script(void)
{
if (Request_Destroy_Script != NULL) {
Request_Destroy_Script(this);
}
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Attach
*
* DESCRIPTION
* Handle attachment of script to an object
*
* INPUTS
* Object - Object script is attaching to.
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Attach(GameObject* obj)
{
#ifdef _DEBUG
if (Commands != NULL) {
DebugPrint("Attaching script '%s' to object %d\n",
Get_Name(), Commands->Get_ID(obj));
}
#endif
mOwner = obj;
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Detach
*
* DESCRIPTION
* Handle detachment of script from an object.
*
* INPUTS
* Object - Object script is detaching from.
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Detach(GameObject* obj)
{
mOwner = NULL;
Destroy_Script();
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Set_Parameters_String
*
* DESCRIPTION
* Set script parameters.
*
* INPUTS
* Params - Parameter string
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Set_Parameters_String(const char* params)
{
if ((params == NULL) || (strlen(params) == 0)) {
return;
}
DebugPrint("Setting parameters for script '%s', params = '%s'\n",
Get_Name(), params);
char* working = strdup(params);
if ( strlen( working ) && working[ strlen( working ) - 1 ] == '\n' ) {
working[ strlen( working ) - 1 ] = 0;
}
// Count the parameters
int count = 0;
char * param_ptr = working;
if ( *param_ptr ) count++;
for ( param_ptr = working; *param_ptr; param_ptr++ ) {
if ( *param_ptr == ',' ) count++;
}
if (count == 0) {
return;
}
// Release old argument vector
Clear_Parameters();
// Create new argument vector
mArgC = count;
mArgV = new char*[count];
assert(mArgV != NULL);
memset(mArgV, 0, (sizeof(char*) * count));
// Copy the parameters
strcpy(working, params);
count = 0;
param_ptr = working;
while ( *param_ptr ) {
// Find where this parameter ends
char * next = param_ptr;
while ( *next && *next != ',' ) next++;
if ( *next ) *next++ = 0;
// Set param
Set_Parameter(count++, param_ptr);
param_ptr = next;
}
if (count == mArgC - 1) {
Set_Parameter(count, "");
}
free(working);
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Parameters_String
*
* DESCRIPTION
* Retrieve a copy of the scripts parameters string.
*
* INPUTS
* Buffer - Buffer to copy parameter string into.
* Size - Size of buffer.
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Get_Parameters_String(char* buffer, unsigned int size)
{
assert(buffer != NULL);
buffer[0] = '\0';
// Build parameter string (comma seperated)
int count = Get_Parameter_Count();
int i = 0;
unsigned int stringLen = 0;
while ((i < count) && (stringLen < size)) {
if (i > 0) {
stringLen++;
strcat(buffer, ",");
}
const char* param = Get_Parameter(i);
stringLen += strlen(param);
if (stringLen <= size) {
strcat(buffer, param);
i++;
}
}
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Clear_Parameters
*
* DESCRIPTION
* Release script parameters
*
* INPUTS
* NONE
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Clear_Parameters(void)
{
if (mArgV != NULL) {
while (mArgC--) {
if (mArgV[mArgC] != NULL) {
free((void*)mArgV[mArgC]);
}
}
delete (void*)mArgV;
}
mArgC = 0;
mArgV = NULL;
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Set_Parameter
*
* DESCRIPTION
* Set a script parameter
*
* INPUTS
* Index - Ordinal position of parameter
* Param - Parameter string
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Set_Parameter(int index, const char* str)
{
// Release old parameter
if (mArgV[index] != NULL) {
free((void*)mArgV[index]);
}
mArgV[index] = strdup(str);
assert(mArgV[index] != NULL);
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Parameter
*
* DESCRIPTION
* Retrieve paramter by name
*
* INPUTS
* Name - Paramter name
*
* RESULTS
* Param - Parameter
*
******************************************************************************/
const char* ScriptImpClass::Get_Parameter(const char* name)
{
int index = Get_Parameter_Index(name);
return Get_Parameter(index);
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Parameter
*
* DESCRIPTION
* Retrieve parameter at specified index.
*
* INPUTS
* Index - Ordinal position of paramater
*
* RESULTS
* Param - Parameter string.
*
******************************************************************************/
const char* ScriptImpClass::Get_Parameter(int index)
{
if ((index < 0) || (index >= mArgC)) {
return "";
}
return mArgV[index];
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Int_Parameter
*
* DESCRIPTION
* Retrieve parameter as an integer.
*
* INPUTS
* Name - Name of parameter
*
* RESULTS
* Value - Integer value.
*
******************************************************************************/
int ScriptImpClass::Get_Int_Parameter(const char* parameterName)
{
int index = Get_Parameter_Index(parameterName);
return Get_Int_Parameter(index);
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Float_Parameter
*
* DESCRIPTION
* Retrieve parameter as a floating point number.
*
* INPUTS
* Name - Name of parameter
*
* RESULTS
* Value - Floating point value
*
******************************************************************************/
float ScriptImpClass::Get_Float_Parameter(const char* parameterName)
{
int index = Get_Parameter_Index(parameterName);
return Get_Float_Parameter(index);
}
/******************************************************************************
**
******************************************************************************/
Vector3 ScriptImpClass::Get_Vector3_Parameter( int index )
{
float x,y,z;
::sscanf( Get_Parameter( index ), "%f %f %f", &x, &y, &z );
return Vector3( x,y,z );
}
Vector3 ScriptImpClass::Get_Vector3_Parameter(const char* parameterName)
{
int index = Get_Parameter_Index(parameterName);
return Get_Vector3_Parameter(index);
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Get_Parameter_Index
*
* DESCRIPTION
* Obtain index of parameter with specified name.
*
* INPUTS
* Name - Name of parameter
*
* RESULTS
* Index - Ordinal position of parameter
*
******************************************************************************/
int ScriptImpClass::Get_Parameter_Index(const char* parameterName)
{
const char* paramDesc = mFactory->GetParamDescription();
// Make copy of parameter description string to work with.
char string[512];
strncpy(string, paramDesc, (sizeof(string) - 1));
string[sizeof(string)-1] = '\0';
// Search for the specified parameter
int index = 0;
char * param_ptr = string;
while ( *param_ptr ) {
// Find where this parameter ends
char * next = param_ptr;
while ( *next && *next != ',' ) next++;
if ( *next ) *next++ = 0;
// Strip the name portion from the parameter definition
char* tokenEnd = strpbrk(param_ptr, "=:\n");
if (tokenEnd != NULL) {
*tokenEnd = '\0';
}
// Check for specified parameter
strtrim(param_ptr);
if (stricmp(param_ptr, parameterName) == 0) {
return index;
}
// Advance to next parameter definition
index++;
param_ptr = next;
}
return -1;
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Save
*
* DESCRIPTION
* Save script data
*
* INPUTS
* ScriptSaver& saver
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Save(ScriptSaver& saver)
{
/* Commands->Begin_Chunk(saver, CHUNKID_SCRIPTDATA);
Save_Data(saver);
Commands->End_Chunk(saver);
*/
ScriptVariableClass * var = AutoVariableList;
if ( var != NULL ) {
Commands->Begin_Chunk(saver, CHUNKID_SCRIPT_AUTO_VARIABLES);
while ( var != NULL ) {
Commands->Save_Data(saver, var->Get_ID(), var->Get_Data_Size(), var->Get_Data_Ptr() );
var = var->Get_Next();
}
Commands->End_Chunk(saver);
}
}
/******************************************************************************
*
* NAME
* ScriptImpClass::Load
*
* DESCRIPTION
* Load script data
*
* INPUTS
* ScriptLoader& loader
*
* RESULTS
* NONE
*
******************************************************************************/
void ScriptImpClass::Load(ScriptLoader& loader)
{
unsigned int chunkID;
while (Commands->Open_Chunk(loader, &chunkID)) {
switch (chunkID) {
/* case CHUNKID_SCRIPTDATA:
DebugPrint("Encountered data chunk.\n");
Load_Data(loader);
break;
*/
case CHUNKID_SCRIPT_AUTO_VARIABLES:
{
int id;
while (Commands->Load_Begin(loader, &id)) {
// If we find this ID, load it
ScriptVariableClass * var = AutoVariableList;
while ( var != NULL ) {
if ( var->Get_ID() == id ) {
Commands->Load_Data(loader, var->Get_Data_Size(), var->Get_Data_Ptr() );
}
var = var->Get_Next();
}
Commands->Load_End(loader);
}
}
break;
default:
DebugPrint("***** ScriptImpClass::Load() - Unrecognized chunk %0x!\n", chunkID);
break;
}
Commands->Close_Chunk(loader);
}
}
/*
**
*/
void ScriptImpClass::Auto_Save_Variable( void * data_ptr, int data_size, int id )
{
if ( ( id < 0 ) || ( id > 255 ) ) {
DebugPrint("***** ScriptImpClass::Auto_Save_Variable Bad ID %d\n", id );
return;
}
// First be sure we don't already have this ID
ScriptVariableClass * var = AutoVariableList;
while ( var != NULL ) {
if ( var->Get_ID() == id ) {
DebugPrint("***** ScriptImpClass::Auto_Save_Variable Dupe ID %d\n", id );
return;
}
var = var->Get_Next();
}
// Never save more than 250 bytes
if ( data_size > 250 ) {
DebugPrint("***** ScriptImpClass::Too Much Save Data on ID %d\n", id );
return;
}
// Then create and add the variable;
AutoVariableList = new ScriptVariableClass( data_ptr, data_size, id, AutoVariableList );
}