mirror of
https://github.com/Q3Rally-Team/q3rally.git
synced 2024-12-11 04:51:01 +00:00
399 lines
8.2 KiB
C
399 lines
8.2 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
Copyright (C) 2002-2021 Q3Rally Team (Per Thormann - q3rally@gmail.com)
|
|
|
|
This file is part of q3rally source code.
|
|
|
|
q3rally source code 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 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
q3rally source code 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 q3rally; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "cg_local.h"
|
|
|
|
#define MAX_SCRIPT_TEXT 8192
|
|
|
|
qboolean SeekToSection( char **pointer, char *str ){
|
|
char *token;
|
|
|
|
// UPDATE: using strstr instead?
|
|
// UPDATE: check if end of file is inside of a bracket (ie bad brackets in script file)
|
|
|
|
// seek to 'str {'
|
|
while ( 1 ) {
|
|
token = COM_Parse( pointer );
|
|
|
|
if( !token || token[0] == 0 )
|
|
return qfalse;
|
|
|
|
if ( !Q_stricmp( token, "{" ) ){
|
|
// loop through this
|
|
while ( 1 ) {
|
|
token = COM_Parse( pointer );
|
|
|
|
if( !token || token[0] == 0 )
|
|
return qfalse;
|
|
|
|
if ( !Q_stricmp( token, "}" ) )
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !Q_stricmp( token, str ) )
|
|
break;
|
|
}
|
|
|
|
if( !token || token[0] == 0 ) // not found
|
|
return qfalse;
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean CG_ParseScriptedObject( centity_t *cent, const char *scriptName ){
|
|
char *text_p;
|
|
int len, i;
|
|
char *token;
|
|
char text[MAX_SCRIPT_TEXT];
|
|
char filename[MAX_QPATH];
|
|
char model[MAX_QPATH];
|
|
char deadmodel[MAX_QPATH];
|
|
fileHandle_t f;
|
|
|
|
// setup defaults
|
|
// ent->takedamage = qfalse;
|
|
// VectorLength(ent->r.mins);
|
|
// VectorLength(ent->r.maxs);
|
|
// ent->elasticity = 0.1f;
|
|
// ent->mass = 100;
|
|
// ent->moveable = qfalse;
|
|
// ent->number = 0;
|
|
|
|
if (!scriptName || scriptName[0] == 0){
|
|
Com_Printf("No Script file specified\n");
|
|
return qfalse;
|
|
}
|
|
|
|
Q_strncpyz(filename, scriptName, sizeof(filename));
|
|
token = strchr(filename, '.');
|
|
if (!token)
|
|
Q_strcat(filename, sizeof(filename), ".script");
|
|
|
|
// Com_Printf("Attempting to load script %s\n", filename);
|
|
|
|
// load the file
|
|
len = trap_FS_FOpenFile( filename, &f, FS_READ );
|
|
|
|
if ( !f ){
|
|
Com_Printf("Could not find script %s\n", filename);
|
|
return qfalse;
|
|
}
|
|
|
|
if ( len >= MAX_SCRIPT_TEXT ) {
|
|
len = MAX_SCRIPT_TEXT - 1;
|
|
}
|
|
|
|
trap_FS_Read( text, len, f );
|
|
text[len] = 0;
|
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
// parse the text
|
|
text_p = text;
|
|
|
|
// seek to "rally_scripted_object {"
|
|
if ( !SeekToSection( &text_p, "rally_scripted_object" ) ){
|
|
Com_Printf( "Script file '%s' did not contain rally_scripted_object\n", filename );
|
|
return qfalse;
|
|
}
|
|
|
|
model[0] = 0;
|
|
deadmodel[0] = 0;
|
|
|
|
// read optional parameters
|
|
while ( 1 ) {
|
|
token = COM_Parse( &text_p );
|
|
|
|
if( !token || token[0] == 0 || !Q_stricmp( token, "}" ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( !Q_stricmp( token, "{" ) )
|
|
continue;
|
|
|
|
// Com_Printf("Found token: %s\n", token);
|
|
|
|
if ( !Q_stricmp( token, "type" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
if ( !Q_stricmp( token, "model" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
Q_strncpyz( model, token, sizeof(model) );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "deadmodel" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
Q_strncpyz( deadmodel, token, sizeof(deadmodel) );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "moveable" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "elasticity" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "mass" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
else if ( !Q_stricmp( token, "frames" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
// ent->number = atoi(token);
|
|
|
|
continue;
|
|
}
|
|
|
|
else if ( !Q_stricmp( token, "health" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "mins" ) ){
|
|
for (i = 0; i < 3; i++){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "maxs" ) ){
|
|
for (i = 0; i < 3; i++){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "hitsound" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
cent->hitSound = trap_S_RegisterSound( token, qfalse );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "presound" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
cent->preSoundLoop = trap_S_RegisterSound( token, qfalse );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "postsound" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
cent->postSoundLoop = trap_S_RegisterSound( token, qfalse );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "destroysound" ) ){
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
cent->destroySound = trap_S_RegisterSound( token, qfalse );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmp( token, "gibs" ) ) {
|
|
// skip gibs part of script (it is only used client side)
|
|
token = COM_Parse( &text_p );
|
|
if ( !token ) {
|
|
break;
|
|
}
|
|
|
|
if ( !Q_stricmp( token, "{" ) ){
|
|
// FIXME: add code to load gibs
|
|
|
|
// loop through this
|
|
while ( 1 ) {
|
|
token = COM_Parse( &text_p );
|
|
|
|
if( !token || token[0] == 0 )
|
|
return qfalse;
|
|
|
|
if ( !Q_stricmp( token, "}" ) )
|
|
break;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else {
|
|
Com_Printf("Warning: Skipping unknown token %s in %s\n", token, filename);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( model[0] ){
|
|
// reset the pointer
|
|
text_p = text;
|
|
|
|
if ( !SeekToSection( &text_p, model ) ){
|
|
// Com_Printf( "'%s' section not found in script file, assuming it was an actual filename\n", model );
|
|
|
|
cent->modelHandle = trap_R_RegisterModel( model );
|
|
}
|
|
else {
|
|
Com_Printf( "Loading model info for '%s'\n", model );
|
|
// load model info
|
|
}
|
|
}
|
|
|
|
if ( deadmodel[0] ){
|
|
// reset the pointer
|
|
text_p = text;
|
|
|
|
if ( !SeekToSection( &text_p, deadmodel ) ){
|
|
// Com_Printf( "'%s' section not found in script file, assuming it was an actual filename\n", model );
|
|
|
|
cent->deadModelHandle = trap_R_RegisterModel( model );
|
|
}
|
|
else {
|
|
Com_Printf( "Loading deadmodel info for '%s'\n", deadmodel );
|
|
// load deadmodel info
|
|
}
|
|
}
|
|
|
|
// Com_Printf("Successfully parsed script file\n");
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
void CG_ScriptedObject_Destroy( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ){
|
|
}
|
|
|
|
|
|
void CG_ScriptedObject_Touch ( gentity_t *self, gentity_t *other, trace_t *trace ){
|
|
}
|
|
|
|
|
|
void CG_ScriptedObject_Think ( gentity_t *self ){
|
|
self->nextthink = cg.time + 100;
|
|
}
|
|
|
|
|
|
void CG_ScriptedObject_Pain ( gentity_t *self, gentity_t *attacker, int damage ){
|
|
}
|
|
*/
|
|
|
|
|
|
void CG_Scripted_Object( centity_t *cent ){
|
|
refEntity_t ent;
|
|
entityState_t *s1;
|
|
const char *scriptName;
|
|
|
|
s1 = ¢->currentState;
|
|
|
|
// CG_LogPrintf("Spawning a rally_scripted_object\n");
|
|
|
|
// if no script file for it then return
|
|
if (!s1->modelindex) {
|
|
return;
|
|
}
|
|
|
|
if ( !cent->scriptLoadTime ){
|
|
scriptName = CG_ConfigString( CS_SCRIPTS + s1->modelindex );
|
|
if ( !scriptName[0] ) {
|
|
return;
|
|
}
|
|
|
|
if ( CG_ParseScriptedObject( cent, scriptName ) )
|
|
cent->scriptLoadTime = cg.time;
|
|
else
|
|
return;
|
|
}
|
|
|
|
memset (&ent, 0, sizeof(ent));
|
|
|
|
if ( cent->currentState.eFlags & EF_DEAD )
|
|
ent.hModel = cent->deadModelHandle;
|
|
else
|
|
ent.hModel = cent->modelHandle;
|
|
|
|
if ( !ent.hModel )
|
|
return;
|
|
|
|
// set frame
|
|
// ent.oldframe = ent.frame;
|
|
// ent.frame = s1->frame;
|
|
ent.frame = ent.oldframe = 0;
|
|
ent.backlerp = 0;
|
|
|
|
VectorCopy( cent->lerpOrigin, ent.origin);
|
|
VectorCopy( cent->lerpOrigin, ent.oldorigin);
|
|
|
|
// convert angles to axis
|
|
AnglesToAxis( cent->lerpAngles, ent.axis );
|
|
|
|
// add to refresh list
|
|
trap_R_AddRefEntityToScene (&ent);
|
|
}
|